/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: debug.c,v 1.1.1.1 2017/06/12 07:58:55 misho Exp $
*/
/*
* Part of this program has been derived from mrouted.
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted".
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*/
#include "defs.h"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
extern int haveterminal;
extern char *progname;
int log_nmsgs = 0;
unsigned long debug = 0x00000000; /* If (long) is smaller than
* 4 bytes, then we are in
* trouble.
*/
static char dumpfilename[] = _PATH_PIMD_DUMP;
static char cachefilename[] = _PATH_PIMD_CACHE; /* TODO: notused */
char *
packet_kind(proto, type, code)
u_int proto, type, code;
{
static char unknown[60];
switch (proto) {
case IPPROTO_IGMP:
switch (type) {
case IGMP_MEMBERSHIP_QUERY: return "IGMP Membership Query ";
case IGMP_V1_MEMBERSHIP_REPORT:return "IGMP v1 Member Report ";
case IGMP_V2_MEMBERSHIP_REPORT:return "IGMP v2 Member Report ";
case IGMP_V2_LEAVE_GROUP: return "IGMP Leave message ";
case IGMP_DVMRP:
switch (code) {
case DVMRP_PROBE: return "DVMRP Neighbor Probe ";
case DVMRP_REPORT: return "DVMRP Route Report ";
case DVMRP_ASK_NEIGHBORS: return "DVMRP Neighbor Request ";
case DVMRP_NEIGHBORS: return "DVMRP Neighbor List ";
case DVMRP_ASK_NEIGHBORS2: return "DVMRP Neighbor request 2 ";
case DVMRP_NEIGHBORS2: return "DVMRP Neighbor list 2 ";
case DVMRP_PRUNE: return "DVMRP Prune message ";
case DVMRP_GRAFT: return "DVMRP Graft message ";
case DVMRP_GRAFT_ACK: return "DVMRP Graft message ack ";
case DVMRP_INFO_REQUEST: return "DVMRP Info Request ";
case DVMRP_INFO_REPLY: return "DVMRP Info Reply ";
default:
sprintf(unknown, "UNKNOWN DVMRP message code = %3d ", code);
return unknown;
}
case IGMP_PIM:
/* The old style (PIM v1) encapsulation of PIM messages
* inside IGMP messages.
*/
/* PIM v1 is not implemented but we just inform that a message
* has arrived.
*/
switch (code) {
case PIM_V1_QUERY: return "PIM v1 Router-Query ";
case PIM_V1_REGISTER: return "PIM v1 Register ";
case PIM_V1_REGISTER_STOP: return "PIM v1 Register-Stop ";
case PIM_V1_JOIN_PRUNE: return "PIM v1 Join/Prune ";
case PIM_V1_RP_REACHABILITY:
return "PIM v1 RP-Reachability ";
case PIM_V1_ASSERT: return "PIM v1 Assert ";
case PIM_V1_GRAFT: return "PIM v1 Graft ";
case PIM_V1_GRAFT_ACK: return "PIM v1 Graft_Ack ";
default:
sprintf(unknown, "UNKNOWN PIM v1 message type =%3d ", code);
return unknown;
}
case IGMP_MTRACE: return "IGMP trace query ";
case IGMP_MTRACE_RESP: return "IGMP trace reply ";
default:
sprintf(unknown,
"UNKNOWN IGMP message: type = 0x%02x, code = 0x%02x ",
type, code);
return unknown;
}
case IPPROTO_PIM: /* PIM v2 */
switch (type) {
case PIM_V2_HELLO: return "PIM v2 Hello ";
case PIM_V2_REGISTER: return "PIM v2 Register ";
case PIM_V2_REGISTER_STOP: return "PIM v2 Register_Stop ";
case PIM_V2_JOIN_PRUNE: return "PIM v2 Join/Prune ";
case PIM_V2_BOOTSTRAP: return "PIM v2 Bootstrap ";
case PIM_V2_ASSERT: return "PIM v2 Assert ";
case PIM_V2_GRAFT: return "PIM-DM v2 Graft ";
case PIM_V2_GRAFT_ACK: return "PIM-DM v2 Graft_Ack ";
case PIM_V2_CAND_RP_ADV: return "PIM v2 Cand. RP Adv. ";
default:
sprintf(unknown, "UNKNOWN PIM v2 message type =%3d ", type);
return unknown;
}
default:
sprintf(unknown, "UNKNOWN proto =%3d ", proto);
return unknown;
}
}
/*
* Used for debugging particular type of messages.
*/
int
debug_kind(proto, type, code)
u_int proto, type, code;
{
switch (proto) {
case IPPROTO_IGMP:
switch (type) {
case IGMP_MEMBERSHIP_QUERY: return DEBUG_IGMP;
case IGMP_V1_MEMBERSHIP_REPORT: return DEBUG_IGMP;
case IGMP_V2_MEMBERSHIP_REPORT: return DEBUG_IGMP;
case IGMP_V2_LEAVE_GROUP: return DEBUG_IGMP;
case IGMP_DVMRP:
switch (code) {
case DVMRP_PROBE: return DEBUG_DVMRP_PEER;
case DVMRP_REPORT: return DEBUG_DVMRP_ROUTE;
case DVMRP_ASK_NEIGHBORS: return 0;
case DVMRP_NEIGHBORS: return 0;
case DVMRP_ASK_NEIGHBORS2: return 0;
case DVMRP_NEIGHBORS2: return 0;
case DVMRP_PRUNE: return DEBUG_DVMRP_PRUNE;
case DVMRP_GRAFT: return DEBUG_DVMRP_PRUNE;
case DVMRP_GRAFT_ACK: return DEBUG_DVMRP_PRUNE;
case DVMRP_INFO_REQUEST: return 0;
case DVMRP_INFO_REPLY: return 0;
default: return 0;
}
case IGMP_PIM:
/* PIM v1 is not implemented */
switch (code) {
case PIM_V1_QUERY: return DEBUG_PIM;
case PIM_V1_REGISTER: return DEBUG_PIM;
case PIM_V1_REGISTER_STOP: return DEBUG_PIM;
case PIM_V1_JOIN_PRUNE: return DEBUG_PIM;
case PIM_V1_RP_REACHABILITY: return DEBUG_PIM;
case PIM_V1_ASSERT: return DEBUG_PIM;
case PIM_V1_GRAFT: return DEBUG_PIM;
case PIM_V1_GRAFT_ACK: return DEBUG_PIM;
default: return DEBUG_PIM;
}
case IGMP_MTRACE: return DEBUG_TRACE;
case IGMP_MTRACE_RESP: return DEBUG_TRACE;
default: return DEBUG_IGMP;
}
case IPPROTO_PIM: /* PIM v2 */
/* TODO: modify? */
switch (type) {
case PIM_V2_HELLO: return DEBUG_PIM;
case PIM_V2_REGISTER: return DEBUG_PIM_REGISTER;
case PIM_V2_REGISTER_STOP: return DEBUG_PIM_REGISTER;
case PIM_V2_JOIN_PRUNE: return DEBUG_PIM;
case PIM_V2_BOOTSTRAP: return DEBUG_PIM_BOOTSTRAP;
case PIM_V2_ASSERT: return DEBUG_PIM;
case PIM_V2_GRAFT: return DEBUG_PIM;
case PIM_V2_GRAFT_ACK: return DEBUG_PIM;
case PIM_V2_CAND_RP_ADV: return DEBUG_PIM_CAND_RP;
default: return DEBUG_PIM;
}
default: return 0;
}
return 0;
}
/*
* Some messages are more important than others. This routine
* determines the logging level at which to log a send error (often
* "No route to host"). This is important when there is asymmetric
* reachability and someone is trying to, i.e., mrinfo me periodically.
*/
int
log_level(proto, type, code)
u_int proto, type, code;
{
switch (proto) {
case IPPROTO_IGMP:
switch (type) {
case IGMP_MTRACE_RESP:
return LOG_INFO;
case IGMP_DVMRP:
switch (code) {
case DVMRP_NEIGHBORS:
case DVMRP_NEIGHBORS2:
return LOG_INFO;
}
case IGMP_PIM:
/* PIM v1 */
switch (code) {
default:
return LOG_INFO;
}
default:
return LOG_WARNING;
}
case IPPROTO_PIM:
/* PIM v2 */
switch (type) {
default:
return LOG_INFO;
}
default:
return LOG_WARNING;
}
return LOG_WARNING;
}
/*
* Dump internal data structures to stderr.
*/
/* TODO: currently not used
void
dump(int i)
{
dump_vifs(stderr);
dump_pim_mrt(stderr);
}
*/
/*
* Dump internal data structures to a file.
*/
void
fdump(i)
int i;
{
FILE *fp;
fp = fopen(dumpfilename, "w");
if (fp != NULL) {
dump_vifs(fp);
dump_pim_mrt(fp);
(void) fclose(fp);
}
}
/* TODO: dummy, to be used in the future. */
/*
* Dump local cache contents to a file.
*/
void
cdump(i)
int i;
{
FILE *fp;
fp = fopen(cachefilename, "w");
if (fp != NULL) {
/* TODO: implement it:
dump_cache(fp);
*/
(void) fclose(fp);
}
}
void
dump_vifs(fp)
FILE *fp;
{
vifi_t vifi;
register struct uvif *v;
pim_nbr_entry_t *n;
int width;
int i;
fprintf(fp, "\nVirtual Interface Table\n %-4s %-17s %-16s %-8s %-14s %s",
"Vif", "Local-Address", "Subnet", "Thresh", "Flags",
"Neighbors\n");
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
fprintf(fp, " %-3u %-17s ", vifi, inet_fmt(v->uv_lcl_addr, s1));
if (v->uv_flags & VIFF_REGISTER)
fprintf(fp, "%-16s ", v->uv_name);
else
fprintf(fp,"%-16.16s ", netname(v->uv_subnet, v->uv_subnetmask));
fprintf(fp, "%-5u ", v->uv_threshold);
width = 0;
if (v->uv_flags & VIFF_DISABLED)
fprintf(fp, " DISABLED");
if (v->uv_flags & VIFF_DOWN)
fprintf(fp, " DOWN");
if (v->uv_flags & VIFF_DR) {
fprintf(fp, " DR");
width += 3;
}
if (v->uv_flags & VIFF_PIM_NBR) {
fprintf(fp, " PIM");
width += 4;
}
if (v->uv_flags & VIFF_DVMRP_NBR) {
fprintf(fp, " DVMRP");
width += 6;
}
if (v->uv_flags & VIFF_NONBRS) {
fprintf(fp, " %-12s", "NO-NBR");
width += 6;
}
if ((n = v->uv_pim_neighbors) != NULL) {
/* Print the first neighbor on the same line */
for (i = width; i <= 15; i++)
fprintf(fp, " ");
fprintf(fp, "%-12s\n", inet_fmt(n->address, s1));
for (n = n->next; n != NULL; n = n->next)
fprintf(fp, "%64s %-15s\n", "", inet_fmt(n->address, s1));
}
else
fprintf(fp, "\n");
}
fprintf(fp, "\n");
}
/*
* Log errors and other messages to the system log daemon and to stderr,
* according to the severity of the message and the current debug level.
* For errors of severity LOG_ERR or worse, terminate the program.
*/
#ifdef __STDC__
void
log(int severity, int syserr, char *format, ...)
{
va_list ap;
static char fmt[211] = "warning - ";
char *msg;
struct timeval now;
struct tm *thyme;
va_start(ap, format);
#else
/*VARARGS3*/
void
log(severity, syserr, format, va_alist)
int severity, syserr;
char *format;
va_dcl
{
va_list ap;
static char fmt[311] = "warning - ";
char *msg;
char tbuf[20];
struct timeval now;
struct tm *thyme;
va_start(ap);
#endif
vsprintf(&fmt[10], format, ap);
va_end(ap);
msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
/*
* Log to stderr if we haven't forked yet and it's a warning or worse,
* or if we're debugging.
*/
if (haveterminal && (debug || severity <= LOG_WARNING)) {
gettimeofday(&now,NULL);
thyme = localtime(&now.tv_sec);
if (!debug)
fprintf(stderr, "%s: ", progname);
fprintf(stderr, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour,
thyme->tm_min, thyme->tm_sec, now.tv_usec / 1000, msg);
if (syserr == 0)
fprintf(stderr, "\n");
else if (syserr < sys_nerr)
fprintf(stderr, ": %s\n", sys_errlist[syserr]);
else
fprintf(stderr, ": errno %d\n", syserr);
}
/*
* Always log things that are worse than warnings, no matter what
* the log_nmsgs rate limiter says.
* Only count things worse than debugging in the rate limiter
* (since if you put daemon.debug in syslog.conf you probably
* actually want to log the debugging messages so they shouldn't
* be rate-limited)
*/
if ((severity < LOG_WARNING) || (log_nmsgs < LOG_MAX_MSGS)) {
if (severity < LOG_DEBUG)
log_nmsgs++;
if (syserr != 0) {
errno = syserr;
syslog(severity, "%s: %m", msg);
} else
syslog(severity, "%s", msg);
}
if (severity <= LOG_ERR) exit(-1);
}
/* TODO: format the output for better readability */
void
dump_pim_mrt(fp)
FILE *fp;
{
grpentry_t *g;
register mrtentry_t *r;
register vifi_t vifi;
u_int number_of_groups = 0;
char oifs[(sizeof(vifbitmap_t)<<3)+1];
char pruned_oifs[(sizeof(vifbitmap_t)<<3)+1];
char leaves_oifs[(sizeof(vifbitmap_t)<<3)+1];
char incoming_iif[(sizeof(vifbitmap_t)<<3)+1];
fprintf(fp, "Multicast Routing Table\n%s",
" Source Group Flags\n");
/* TODO: remove the dummy 0.0.0.0 group (first in the chain) */
for (g = grplist->next; g != (grpentry_t *)NULL; g = g->next) {
number_of_groups++;
/* Print all (S,G) routing info */
for (r = g->mrtlink; r != (mrtentry_t *)NULL; r = r->grpnext) {
fprintf(fp, "---------------------------(S,G)----------------------------\n");
/* Print the routing info */
fprintf(fp, " %-15s", inet_fmt(r->source->address, s1));
fprintf(fp, " %-15s", inet_fmt(g->group, s2));
for (vifi = 0; vifi < numvifs; vifi++) {
oifs[vifi] =
VIFM_ISSET(vifi, r->oifs) ? 'o' : '.';
pruned_oifs[vifi] =
VIFM_ISSET(vifi, r->pruned_oifs) ? 'p' : '.';
leaves_oifs[vifi] =
VIFM_ISSET(vifi, r->leaves) ? 'l' : '.';
incoming_iif[vifi] = '.';
}
oifs[vifi] = 0x0; /* End of string */
pruned_oifs[vifi] = 0x0;
leaves_oifs[vifi] = 0x0;
incoming_iif[vifi] = 0x0;
incoming_iif[r->incoming] = 'I';
/* TODO: don't need some of the flags */
if (r->flags & MRTF_SPT) fprintf(fp, " SPT");
if (r->flags & MRTF_WC) fprintf(fp, " WC");
if (r->flags & MRTF_RP) fprintf(fp, " RP");
if (r->flags & MRTF_REGISTER) fprintf(fp, " REG");
if (r->flags & MRTF_IIF_REGISTER) fprintf(fp, " IIF_REG");
if (r->flags & MRTF_NULL_OIF) fprintf(fp, " NULL_OIF");
if (r->flags & MRTF_KERNEL_CACHE) fprintf(fp, " CACHE");
if (r->flags & MRTF_ASSERTED) fprintf(fp, " ASSERTED");
if (r->flags & MRTF_REG_SUPP) fprintf(fp, " REG_SUPP");
if (r->flags & MRTF_SG) fprintf(fp, " SG");
if (r->flags & MRTF_PMBR) fprintf(fp, " PMBR");
fprintf(fp, "\n");
fprintf(fp, "Pruned oifs: %-20s\n", pruned_oifs);
fprintf(fp, "Leaves oifs: %-20s\n", leaves_oifs);
fprintf(fp, "Outgoing oifs: %-20s\n", oifs);
fprintf(fp, "Incoming : %-20s\n", incoming_iif);
fprintf(fp, "Upstream nbr: %s\n",
r->upstream ? inet_fmt(r->upstream->address, s1) : "NONE");
fprintf(fp, "\nTIMERS: Entry Prune VIFS:");
for (vifi = 0; vifi < numvifs; vifi++)
fprintf(fp, " %2d", vifi);
fprintf(fp, "\n %3d ",
r->timer);
for (vifi = 0; vifi < numvifs; vifi++)
fprintf(fp, " %3d", r->prune_timers[vifi]);
fprintf(fp, "\n");
}
}/* for all groups */
fprintf(fp, "Number of Groups: %u\n", number_of_groups);
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>