# BRCM_VERSION=3
[bcm963xx.git] / userapps / opensource / net-snmp / apps / snmpnetstat / route.c
1 /*****************************************************************
2         Copyright 1989, 1991, 1992 by Carnegie Mellon University
3
4                       All Rights Reserved
5
6 Permission to use, copy, modify, and distribute this software and its 
7 documentation for any purpose and without fee is hereby granted, 
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in 
10 supporting documentation, and that the name of CMU not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.  
13
14 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 ******************************************************************/
22 /*
23  * Copyright (c) 1983,1988 Regents of the University of California.
24  * All rights reserved.
25  *
26  * Redistribution and use in source and binary forms are permitted
27  * provided that this notice is preserved and that due credit is given
28  * to the University of California at Berkeley. The name of the University
29  * may not be used to endorse or promote products derived from this
30  * software without specific prior written permission. This software
31  * is provided ``as is'' without express or implied warranty.
32  */
33
34 #include <net-snmp/net-snmp-config.h>
35
36 #if HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39 #if HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #if HAVE_STRING_H
43 #include <string.h>
44 #else
45 #include <strings.h>
46 #endif
47
48 #include <stdio.h>
49 #include <ctype.h>
50
51 #if HAVE_SYS_PARAM_H
52 #include <sys/param.h>
53 #endif
54
55 #if HAVE_SYS_SELECT_H
56 #include <sys/select.h>
57 #endif
58 #if HAVE_NETINET_IN_H
59 #include <netinet/in.h>
60 #endif
61 #if HAVE_ARPA_INET_H
62 #include <arpa/inet.h>
63 #endif
64 #define LOOPBACKNET 127
65
66 #if HAVE_WINSOCK_H
67 #include <winsock.h>
68 #include "winstub.h"
69 #endif
70 #if HAVE_SYS_SOCKET_H
71 #include <sys/socket.h>
72 #endif
73 #if HAVE_NETDB_H
74 #include <netdb.h>
75 #endif
76
77 #include "main.h"
78 #include <net-snmp/net-snmp-includes.h>
79 #include "netstat.h"
80
81 struct route_entry {
82     oid             instance[4];
83     struct in_addr  destination;
84     int             set_destination;
85     struct in_addr  mask;
86     int             set_mask;
87     struct in_addr  gateway;
88     int             set_gateway;
89     int             ifNumber;
90     int             set_ifNumber;
91     int             type;
92     int             set_type;
93     int             proto;
94     int             set_proto;
95     char            ifname[64];
96     int             set_name;
97 };
98
99 #define RTDEST      1
100 #define RTIFINDEX   2
101 #define RTNEXTHOP   7
102 #define RTTYPE      8
103 #define RTPROTO     9
104 #define RTMASK     11
105
106 static oid      oid_rttable[] = { 1, 3, 6, 1, 2, 1, 4, 21, 1 };
107 static oid      oid_rtdest[] = { 1, 3, 6, 1, 2, 1, 4, 21, 1, 1 };
108 static oid      oid_rtifindex[] = { 1, 3, 6, 1, 2, 1, 4, 21, 1, 2 };
109 static oid      oid_rtnexthop[] = { 1, 3, 6, 1, 2, 1, 4, 21, 1, 7 };
110 static oid      oid_rttype[] = { 1, 3, 6, 1, 2, 1, 4, 21, 1, 8 };
111 static oid      oid_rtproto[] = { 1, 3, 6, 1, 2, 1, 4, 21, 1, 9 };
112 static oid      oid_rtmask[] = { 1, 3, 6, 1, 2, 1, 4, 21, 1, 11 };
113 static oid      oid_ifdescr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 2 };
114 static oid      oid_ipnoroutes[] = { 1, 3, 6, 1, 2, 1, 4, 12, 0 };
115
116
117 /*
118  * Print routing tables.
119  */
120 void
121 routepr(void)
122 {
123     struct route_entry route, *rp = &route;
124     netsnmp_pdu    *request, *response;
125     netsnmp_variable_list *vp;
126     char            name[16], *flags;
127     oid            *instance, type;
128     int             toloopback, status;
129     char            ch;
130
131     printf("Routing tables\n");
132     printf("%-26.26s %-18.18s %-6.6s  %s\n",
133            "Destination", "Gateway", "Flags", "Interface");
134
135
136     request = snmp_pdu_create(SNMP_MSG_GETNEXT);
137
138     snmp_add_null_var(request, oid_rtdest,
139                       sizeof(oid_rtdest) / sizeof(oid));
140     snmp_add_null_var(request, oid_rtmask,
141                       sizeof(oid_rtmask) / sizeof(oid));
142     snmp_add_null_var(request, oid_rtifindex,
143                       sizeof(oid_rtifindex) / sizeof(oid));
144     snmp_add_null_var(request, oid_rtnexthop,
145                       sizeof(oid_rtnexthop) / sizeof(oid));
146     snmp_add_null_var(request, oid_rttype,
147                       sizeof(oid_rttype) / sizeof(oid));
148     snmp_add_null_var(request, oid_rtproto,
149                       sizeof(oid_rtproto) / sizeof(oid));
150
151     while (request) {
152         status = snmp_synch_response(Session, request, &response);
153         if (status != STAT_SUCCESS
154             || response->errstat != SNMP_ERR_NOERROR) {
155             fprintf(stderr, "SNMP request failed\n");
156             break;
157         }
158         instance = NULL;
159         request = NULL;
160         rp->set_destination = 0;
161         rp->set_mask = 0;
162         rp->set_ifNumber = 0;
163         rp->set_gateway = 0;
164         rp->set_type = 0;
165         rp->set_proto = 0;
166         for (vp = response->variables; vp; vp = vp->next_variable) {
167             if (vp->name_length != 14 ||
168                 memcmp(vp->name, oid_rttable, sizeof(oid_rttable))) {
169                 continue;       /* if it isn't in this subtree, just continue */
170             }
171
172             if (instance != NULL) {
173                 oid            *ip, *op;
174                 int             count;
175
176                 ip = instance;
177                 op = vp->name + 10;
178                 for (count = 0; count < 4; count++) {
179                     if (*ip++ != *op++)
180                         break;
181                 }
182                 if (count < 4)
183                     continue;   /* not the right instance, ignore */
184             } else {
185                 instance = vp->name + 10;
186             }
187             /*
188              * At this point, this variable is known to be in the routing table
189              * subtree, and is of the right instance for this transaction.
190              */
191
192             if (request == NULL)
193                 request = snmp_pdu_create(SNMP_MSG_GETNEXT);
194             snmp_add_null_var(request, vp->name, vp->name_length);
195
196             type = vp->name[9];
197             switch ((char) type) {
198             case RTDEST:
199                 memmove(&rp->destination, vp->val.string, sizeof(u_long));
200                 rp->set_destination = 1;
201                 break;
202             case RTMASK:
203                 memmove(&rp->mask, vp->val.string, sizeof(u_long));
204                 rp->set_mask = 1;
205                 break;
206             case RTIFINDEX:
207                 rp->ifNumber = *vp->val.integer;
208                 rp->set_ifNumber = 1;
209                 break;
210             case RTNEXTHOP:
211                 memmove(&rp->gateway, vp->val.string, sizeof(u_long));
212                 rp->set_gateway = 1;
213                 break;
214             case RTTYPE:
215                 rp->type = *vp->val.integer;
216                 rp->set_type = 1;
217                 break;
218             case RTPROTO:
219                 rp->proto = *vp->val.integer;
220                 rp->set_proto = 1;
221                 break;
222             }
223         }
224         snmp_free_pdu(response);
225         if (!(rp->set_destination && rp->set_gateway
226               && rp->set_type && rp->set_ifNumber)) {
227             if (request)
228                 snmp_free_pdu(request);
229             request = NULL;
230             continue;
231         }
232         toloopback = *(char *) &rp->gateway == LOOPBACKNET;
233         printf("%-26.26s ",
234                (rp->destination.s_addr == INADDR_ANY) ? "default" :
235                (toloopback) ? routename(rp->destination) :
236                rp->set_mask ? netname(rp->destination, rp->mask.s_addr) :
237                netname(rp->destination, 0L));
238         printf("%-18.18s ", routename(rp->gateway));
239         flags = name;
240         *flags++ = 'U';         /* route is in use */
241         /*
242          * this !toloopback shouldnt be necessary 
243          */
244         if (!toloopback && rp->type == MIB_IPROUTETYPE_REMOTE)
245             *flags++ = 'G';
246         if (toloopback)
247             *flags++ = 'H';
248         if (rp->proto == MIB_IPROUTEPROTO_ICMP)
249             *flags++ = 'D';     /* redirect */
250         *flags = '\0';
251         printf("%-6.6s ", name);
252         get_ifname(rp->ifname, rp->ifNumber);
253         ch = rp->ifname[strlen(rp->ifname) - 1];
254         ch = '5';               /* force the if statement */
255         if (isdigit(ch))
256             printf(" %.32s\n", rp->ifname);
257         else
258             printf(" %.32s%d\n", rp->ifname, rp->ifNumber);
259
260     }
261 }
262
263 struct iflist {
264     int             index;
265     char            name[64];
266     struct iflist  *next;
267 }              *Iflist = NULL;
268
269 void
270 get_ifname(char *name, int ifIndex)
271 {
272     netsnmp_pdu    *pdu, *response;
273     netsnmp_variable_list *vp;
274     struct iflist  *ip;
275     oid             varname[MAX_OID_LEN];
276     int             status;
277
278     for (ip = Iflist; ip; ip = ip->next) {
279         if (ip->index == ifIndex)
280             break;
281     }
282     if (ip) {
283         strcpy(name, ip->name);
284         return;
285     }
286     ip = (struct iflist *) malloc(sizeof(struct iflist));
287     if (ip == NULL)
288         return;
289     ip->next = Iflist;
290     Iflist = ip;
291     ip->index = ifIndex;
292     pdu = snmp_pdu_create(SNMP_MSG_GET);
293     memmove(varname, oid_ifdescr, sizeof(oid_ifdescr));
294     varname[10] = (oid) ifIndex;
295     snmp_add_null_var(pdu, varname, sizeof(oid_ifdescr) / sizeof(oid) + 1);
296     status = snmp_synch_response(Session, pdu, &response);
297     if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) {
298         vp = response->variables;
299         if (vp->val_len >= sizeof(ip->name))
300             vp->val_len = sizeof(ip->name) - 1;
301         memmove(ip->name, vp->val.string, vp->val_len);
302         ip->name[vp->val_len] = '\0';
303         snmp_free_pdu(response);
304     } else {
305         sprintf(ip->name, "if%d", ifIndex);
306     }
307     strcpy(name, ip->name);
308 }
309
310 static          u_long
311 forgemask(u_long a)
312 {
313     u_long          m;
314     if (IN_CLASSA(a))
315         m = IN_CLASSA_NET;
316     else if (IN_CLASSB(a))
317         m = IN_CLASSB_NET;
318     else
319         m = IN_CLASSC_NET;
320     return m;
321 }
322
323 static void
324 domask(char *dst, u_long addr, u_long mask)
325 {
326     int             b, i;
327     if (!mask || forgemask(addr) == mask) {
328         *dst = '\0';
329         return;
330     }
331     i = 0;
332     for (b = 0; b < 32; b++)
333         if (mask & (1 << b)) {
334             int             bb;
335             i = b;
336             for (bb = b + 1; bb < 32; bb++)
337                 if (!(mask & (1 << bb))) {
338                     i = -1;     /* non-contig */
339                     break;
340                 }
341             break;
342         }
343     if (i == -1)
344         sprintf(dst, "&0x%lx", mask);
345     else
346         sprintf(dst, "/%d", 32 - i);
347 }
348
349 char           *
350 routename(struct in_addr in)
351 {
352     register char  *cp;
353     static char     line[MAXHOSTNAMELEN + 1];
354     struct hostent *hp;
355     static char     domain[MAXHOSTNAMELEN + 1];
356     static int      first = 1;
357
358     if (first) {
359         first = 0;
360         if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
361             (cp = (char *) strchr(domain, '.')))
362             (void) strcpy(domain, cp + 1);
363         else
364             domain[0] = 0;
365     }
366     cp = 0;
367     if (!nflag) {
368         hp = gethostbyaddr((char *) &in, sizeof(struct in_addr), AF_INET);
369         if (hp) {
370             if ((cp = (char *) strchr(hp->h_name, '.')) &&
371                 !strcmp(cp + 1, domain))
372                 *cp = 0;
373             cp = (char *) hp->h_name;
374         }
375     }
376     if (cp)
377         strncpy(line, cp, sizeof(line) - 1);
378     else {
379 #define C(x)    (unsigned)((x) & 0xff)
380         in.s_addr = ntohl(in.s_addr);
381         sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
382                 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
383     }
384     return (line);
385 }
386
387 /*
388  * Return the name of the network whose address is given.
389  * The address is assumed to be that of a net or subnet, not a host.
390  */
391 char           *
392 netname(struct in_addr in, u_long mask)
393 {
394     char           *cp = NULL;
395     static char     line[MAXHOSTNAMELEN + 1];
396     struct netent  *np = 0;
397     u_long          net, omask;
398     u_long          i;
399     int             subnetshift;
400
401     i = ntohl(in.s_addr);
402     omask = mask = ntohl(mask);
403     if (!nflag && i != INADDR_ANY) {
404         if (mask == INADDR_ANY) {
405             if (IN_CLASSA(i)) {
406                 mask = IN_CLASSA_NET;
407                 subnetshift = 8;
408             } else if (IN_CLASSB(i)) {
409                 mask = IN_CLASSB_NET;
410                 subnetshift = 8;
411             } else {
412                 mask = IN_CLASSC_NET;
413                 subnetshift = 4;
414             }
415             /*
416              * If there are more bits than the standard mask
417              * would suggest, subnets must be in use.
418              * Guess at the subnet mask, assuming reasonable
419              * width subnet fields.
420              */
421             while (i & ~mask)
422                 mask = (long) mask >> subnetshift;
423         }
424         net = i & mask;
425         while ((mask & 1) == 0)
426             mask >>= 1, net >>= 1;
427         np = getnetbyaddr(net, AF_INET);
428         if (np)
429             cp = np->n_name;
430     }
431     if (cp)
432         strncpy(line, cp, sizeof(line) - 1);
433     else if ((i & 0xffffff) == 0)
434         sprintf(line, "%u", C(i >> 24));
435     else if ((i & 0xffff) == 0)
436         sprintf(line, "%u.%u", C(i >> 24), C(i >> 16));
437     else if ((i & 0xff) == 0)
438         sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8));
439     else
440         sprintf(line, "%u.%u.%u.%u", C(i >> 24),
441                 C(i >> 16), C(i >> 8), C(i));
442     domask(line + strlen(line), i, omask);
443     return (line);
444 }
445
446 /*
447  * Print routing statistics
448  */
449 void
450 rt_stats(void)
451 {
452     netsnmp_variable_list *var;
453
454     printf("routing:\n");
455     var =
456         getvarbyname(Session, oid_ipnoroutes,
457                      sizeof(oid_ipnoroutes) / sizeof(oid));
458     if (var) {
459         printf("\t%lu destination%s found unreachable\n",
460                *var->val.integer, plural((int) *var->val.integer));
461         snmp_free_var(var);
462     } else {
463         printf("\tCouldn't get ipOutNoRoutes variable\n");
464     }
465 }
466
467 /*
468  * Request a variable with a GET REQUEST message on the given
469  * session.  If the variable is found, a
470  * pointer to a netsnmp_variable_list object will be returned.
471  * Otherwise, NULL is returned.  The caller must free the returned
472  * variable_list object when done with it.
473  */
474 netsnmp_variable_list *
475 getvarbyname(netsnmp_session * sp, oid * name, size_t len)
476 {
477     netsnmp_pdu    *request, *response;
478     netsnmp_variable_list *var = NULL, *vp;
479     int             status;
480
481     request = snmp_pdu_create(SNMP_MSG_GET);
482
483     snmp_add_null_var(request, name, len);
484
485     status = snmp_synch_response(sp, request, &response);
486
487     if (status == STAT_SUCCESS) {
488         if (response->errstat == SNMP_ERR_NOERROR) {
489             for (var = response->variables; var; var = var->next_variable) {
490                 if (var->name_length == len
491                     && !memcmp(name, var->name, len * sizeof(oid)))
492                     break;      /* found our match */
493             }
494             if (var != NULL) {
495                 /*
496                  * Now unlink this var from pdu chain so it doesn't get freed.
497                  * The caller will free the var.
498                  */
499                 if (response->variables == var) {
500                     response->variables = var->next_variable;
501                 } else {
502                     for (vp = response->variables; vp;
503                          vp = vp->next_variable) {
504                         if (vp->next_variable == var) {
505                             vp->next_variable = var->next_variable;
506                             break;
507                         }
508                     }
509                 }
510                 if (var->type == SNMP_NOSUCHOBJECT ||
511                     var->type == SNMP_NOSUCHINSTANCE ||
512                     var->type == SNMP_ENDOFMIBVIEW) {
513                        snmp_free_var(var);
514                        var =  NULL;
515                 }
516             }
517         }
518     } else if (status != STAT_TIMEOUT)
519         snmp_sess_perror("snmpnetstat", sp);
520     if (response)
521         snmp_free_pdu(response);
522     return var;
523 }