# BRCM_VERSION=3
[bcm963xx.git] / userapps / opensource / net-snmp / apps / snmpnetstat / inet.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
50 #if HAVE_SYS_PARAM_H
51 #include <sys/param.h>
52 #endif
53 #if HAVE_SYS_SELECT_H
54 #include <sys/select.h>
55 #endif
56 #if HAVE_NETINET_IN_H
57 #include <netinet/in.h>
58 #endif
59 #if HAVE_ARPA_INET_H
60 #include <arpa/inet.h>
61 #endif
62 #if HAVE_WINSOCK_H
63 #include <winsock.h>
64 #include "winstub.h"
65 #endif
66 #if HAVE_SYS_SOCKET_H
67 #include <sys/socket.h>
68 #endif
69 #if HAVE_NETDB_H
70 #include <netdb.h>
71 #endif
72
73 #include "main.h"
74 #include <net-snmp/net-snmp-includes.h>
75 #include "netstat.h"
76
77 static char    *inetname(struct in_addr);
78
79 struct stat_table {
80     int             entry;      /* entry number in table */
81     /*
82      * format string to printf(description, value, plural(value)); 
83      */
84     /*
85      * warning: the %d must be before the %s 
86      */
87     char            description[80];
88 };
89
90 static oid      oid_ipstats[] = { 1, 3, 6, 1, 2, 1, 4, 0, 0 };
91 struct stat_table ip_stattab[] = {
92     {3, "%d total datagram%s received"},
93     {4, "%d datagram%s with header errors"},
94     {5, "%d datagram%s with an invalid destination address"},
95     {6, "%d datagram%s forwarded"},
96     {7, "%d datagram%s with unknown protocol"},
97     {8, "%d datagram%s discarded"},
98     {9, "%d datagram%s delivered"},
99     {10, "%d output datagram request%s"},
100     {11, "%d output datagram%s discarded"},
101     {12, "%d datagram%s with no route"},
102     {14, "%d fragment%s received"},
103     {15, "%d datagram%s reassembled"},
104     {16, "%d reassembly failure%s"},
105     {17, "%d datagram%s fragmented"},
106     {18, "%d fragmentation failure%s"},
107     {19, "%d fragment%s created"}
108 };
109
110 static oid      oid_udpstats[] = { 1, 3, 6, 1, 2, 1, 7, 0, 0 };
111 struct stat_table udp_stattab[] = {
112     {1, "%d total datagram%s received"},
113     {2, "%d datagram%s to invalid port"},
114     {3, "%d datagram%s dropped due to errors"},
115     {4, "%d output datagram request%s"}
116 };
117
118 static oid      oid_tcpstats[] = { 1, 3, 6, 1, 2, 1, 6, 0, 0 };
119 struct stat_table tcp_stattab[] = {
120     {5, "%d active open%s"},
121     {6, "%d passive open%s"},
122     {7, "%d failed attempt%s"},
123     {8, "%d reset%s of established connections"},
124     {9, "%d current established connection%s"},
125     {10, "%d segment%s received"},
126     {11, "%d segment%s sent"},
127     {12, "%d segment%s retransmitted"}
128 };
129
130 static oid      oid_icmpstats[] = { 1, 3, 6, 1, 2, 1, 5, 0, 0 };
131 struct stat_table icmp_stattab[] = {
132     {1, "%d total message%s received"},
133     {2, "%d message%s dropped due to errors"},
134     {14, "%d ouput message request%s"},
135     {15, "%d output message%s discarded"}
136 };
137
138 struct stat_table icmp_inhistogram[] = {
139     {3, "Destination unreachable: %d"},
140     {4, "Time Exceeded: %d"},
141     {5, "Parameter Problem: %d"},
142     {6, "Source Quench: %d"},
143     {7, "Redirect: %d"},
144     {8, "Echo Request: %d"},
145     {9, "Echo Reply: %d"},
146     {10, "Timestamp Request: %d"},
147     {11, "Timestamp Reply: %d"},
148     {12, "Address Mask Request: %d"},
149     {13, "Addrss Mask Reply:%d"},
150 };
151
152 struct stat_table icmp_outhistogram[] = {
153     {16, "Destination unreachable: %d"},
154     {17, "Time Exceeded: %d"},
155     {18, "Parameter Problem: %d"},
156     {19, "Source Quench: %d"},
157     {20, "Redirect: %d"},
158     {21, "Echo Request: %d"},
159     {22, "Echo Reply: %d"},
160     {23, "Timestamp Request: %d"},
161     {24, "Timestamp Reply: %d"},
162     {25, "Address Mask Request: %d"},
163     {26, "Addrss Mask Reply:%d"},
164 };
165
166 struct tcpconn_entry {
167     oid             instance[10];
168     struct in_addr  localAddress;
169     int             locAddrSet;
170     u_short         localPort;
171     int             locPortSet;
172     struct in_addr  remoteAddress;
173     int             remAddrSet;
174     u_short         remotePort;
175     int             remPortSet;
176     int             state;
177     int             stateSet;
178     struct tcpconn_entry *next;
179 };
180
181 struct udp_entry {
182     oid             instance[5];
183     struct in_addr  localAddress;
184     int             locAddrSet;
185     u_short         localPort;
186     int             locPortSet;
187     struct udp_entry *next;
188 };
189
190 #define TCPCONN_STATE   1
191 #define TCPCONN_LOCADDR 2
192 #define TCPCONN_LOCPORT 3
193 #define TCPCONN_REMADDR 4
194 #define TCPCONN_REMPORT 5
195
196 static oid      oid_tcpconntable[] = { 1, 3, 6, 1, 2, 1, 6, 13, 1 };
197 #define TCP_ENTRY 9
198
199 #define UDP_LOCADDR     1
200 #define UDP_LOCPORT     2
201
202 static oid      oid_udptable[] = { 1, 3, 6, 1, 2, 1, 7, 5, 1 };
203 #define UDP_ENTRY 9
204
205 const char     *tcpstates[] = {
206     "",
207     "CLOSED",
208     "LISTEN",
209     "SYNSENT",
210     "SYNRECEIVED",
211     "ESTABLISHED",
212     "FINWAIT1",
213     "FINWAIT2",
214     "CLOSEWAIT",
215     "LASTACK",
216     "CLOSING",
217     "TIMEWAIT"
218 };
219 #define TCP_NSTATES 11
220
221 int             validUShortAssign(unsigned short *, int, const char *);
222
223 /*
224  * Print a summary of connections related to an Internet
225  * protocol (currently only TCP).  For TCP, also give state of connection.
226  */
227 void
228 protopr(const char *name)
229 {
230     struct tcpconn_entry *tcpconn = NULL, *tcplast = NULL, *tp, *newtp;
231     struct udp_entry *udpconn = NULL, *udplast = NULL, *up, *newup;
232     netsnmp_pdu    *request = NULL, *response = NULL;
233     netsnmp_variable_list *vp;
234     oid            *instance;
235     int             first, status;
236
237
238     response = NULL;
239     if (strcmp(name, "tcp") == 0) {
240         request = snmp_pdu_create(SNMP_MSG_GETNEXT);
241         snmp_add_null_var(request, oid_tcpconntable,
242                           sizeof(oid_tcpconntable) / sizeof(oid));
243         status = STAT_SUCCESS;
244     } else
245         status = STAT_TIMEOUT;
246     while (status == STAT_SUCCESS) {
247         if (response)
248             snmp_free_pdu(response);
249         response = NULL;
250         status = snmp_synch_response(Session, request, &response);
251         if (status != STAT_SUCCESS
252             || response->errstat != SNMP_ERR_NOERROR) {
253             snmp_sess_perror("SNMP request failed", Session);
254             break;
255         }
256         vp = response->variables;
257         if (!vp)
258             break;
259         if (vp->name_length != 20 ||
260             memcmp(vp->name, oid_tcpconntable, sizeof(oid_tcpconntable))) {
261             break;
262         }
263
264         request = snmp_pdu_create(SNMP_MSG_GETNEXT);
265         snmp_add_null_var(request, vp->name, vp->name_length);
266
267         instance = vp->name + 10;
268         for (tp = tcpconn; tp != NULL; tp = tp->next) {
269             if (!memcmp(instance, tp->instance, sizeof(tp->instance)))
270                 break;
271         }
272         if (tp == NULL) {
273             tp = (struct tcpconn_entry *) calloc(1,
274                                                  sizeof(struct
275                                                         tcpconn_entry));
276             if (tp == NULL)
277                 break;
278             if (tcplast != NULL)
279                 tcplast->next = tp;
280             tcplast = tp;
281             if (tcpconn == NULL)
282                 tcpconn = tp;
283             memmove(tp->instance, instance, sizeof(tp->instance));
284         }
285
286         if (vp->name[TCP_ENTRY] == TCPCONN_STATE) {
287             tp->state = *vp->val.integer;
288             tp->stateSet = 1;
289         }
290
291         if (vp->name[TCP_ENTRY] == TCPCONN_LOCADDR) {
292             memmove(&tp->localAddress, vp->val.string, sizeof(u_long));
293             tp->locAddrSet = 1;
294         }
295
296         if (vp->name[TCP_ENTRY] == TCPCONN_LOCPORT) {
297             if (validUShortAssign(&tp->localPort, *vp->val.integer,
298                                   "TCPCONN_LOCPORT"))
299                 tp->locPortSet = 1;
300         }
301
302         if (vp->name[TCP_ENTRY] == TCPCONN_REMADDR) {
303             memmove(&tp->remoteAddress, vp->val.string, sizeof(u_long));
304             tp->remAddrSet = 1;
305         }
306
307         if (vp->name[TCP_ENTRY] == TCPCONN_REMPORT) {
308             if (validUShortAssign(&tp->remotePort, *vp->val.integer,
309                                   "TCPCONN_REMPORT"))
310                 tp->remPortSet = 1;
311         }
312     }
313     if (response)
314         snmp_free_pdu(response);
315     response = NULL;
316
317     for (first = 1, tp = tcpconn, newtp = NULL; tp != NULL; tp = tp->next) {
318         if (newtp)
319             free(newtp);
320         newtp = tp;
321         if (!(tp->stateSet && tp->locAddrSet
322               && tp->locPortSet && tp->remAddrSet && tp->remPortSet)) {
323             printf("incomplete entry\n");
324             continue;
325         }
326         if (!aflag && tp->state == MIB_TCPCONNSTATE_LISTEN)
327             continue;
328         if (first) {
329             printf("Active Internet (%s) Connections", name);
330             if (aflag)
331                 printf(" (including servers)");
332             putchar('\n');
333             printf("%-5.5s %-28.28s %-28.28s %s\n",
334                    "Proto", "Local Address", "Foreign Address", "(state)");
335             first = 0;
336         }
337         printf("%-5.5s ", "tcp");
338         inetprint(&tp->localAddress, tp->localPort, "tcp");
339         inetprint(&tp->remoteAddress, tp->remotePort, "tcp");
340         if (tp->state < 1 || tp->state > TCP_NSTATES)
341             printf(" %d", tp->state);
342         else
343             printf(" %s", tcpstates[tp->state]);
344         putchar('\n');
345     }
346     if (newtp)
347         free(newtp);
348
349
350     response = NULL;
351     if (strcmp(name, "udp") == 0) {
352         request = snmp_pdu_create(SNMP_MSG_GETNEXT);
353         snmp_add_null_var(request, oid_udptable,
354                           sizeof(oid_udptable) / sizeof(oid));
355         status = STAT_SUCCESS;
356     } else
357         status = STAT_TIMEOUT;
358     while (status == STAT_SUCCESS) {
359         if (response)
360             snmp_free_pdu(response);
361         response = NULL;
362         status = snmp_synch_response(Session, request, &response);
363         if (status != STAT_SUCCESS
364             || response->errstat != SNMP_ERR_NOERROR) {
365             fprintf(stderr, "SNMP request failed\n");
366             break;
367         }
368         vp = response->variables;
369         if (!vp)
370             break;
371         if (vp->name_length != 15 ||
372             memcmp(vp->name, oid_udptable, sizeof(oid_udptable))) {
373             break;
374         }
375
376         request = snmp_pdu_create(SNMP_MSG_GETNEXT);
377         snmp_add_null_var(request, vp->name, vp->name_length);
378
379         instance = vp->name + 10;
380         for (up = udpconn; up != NULL; up = up->next) {
381             if (!memcmp(instance, up->instance, sizeof(up->instance)))
382                 break;
383         }
384         if (up == NULL) {
385             up = (struct udp_entry *) calloc(1, sizeof(struct udp_entry));
386             if (up == NULL)
387                 break;
388             if (udplast != NULL)
389                 udplast->next = up;
390             udplast = up;
391             if (udpconn == NULL)
392                 udpconn = up;
393             memmove(up->instance, instance, sizeof(up->instance));
394         }
395
396         if (vp->name[UDP_ENTRY] == UDP_LOCADDR) {
397             memmove(&up->localAddress, vp->val.string, sizeof(u_long));
398             up->locAddrSet = 1;
399         }
400
401         if (vp->name[UDP_ENTRY] == UDP_LOCPORT) {
402             if (validUShortAssign(&up->localPort, *vp->val.integer,
403                                   "UDP_LOCPORT"))
404                 up->locPortSet = 1;
405         }
406     }
407     if (response)
408         snmp_free_pdu(response);
409     response = NULL;
410
411     for (first = 1, up = udpconn, newup = NULL; up != NULL; up = up->next) {
412         if (newup)
413             free(newup);
414         newup = up;
415         if (!(up->locAddrSet && up->locPortSet)) {
416             printf("incomplete entry\n");
417             continue;
418         }
419         if (first) {
420             printf("Active Internet (%s) Connections", name);
421             putchar('\n');
422             printf("%-5.5s %-28.28s\n", "Proto", "Local Address");
423             first = 0;
424         }
425         printf("%-5.5s ", "udp");
426         inetprint(&up->localAddress, up->localPort, "udp");
427         putchar('\n');
428     }
429     if (newup)
430         free(newup);
431
432 }
433
434 int
435 validUShortAssign(unsigned short *pushort, int ival, const char *errstr)
436 {
437     u_long          ulval = (u_long) ival;
438     if (ival > 65535) {
439         printf("Warning: %s value %ld (0x%lx) is not a port address\n",
440                errstr, ulval, ulval);
441         return 0;
442     }
443     *pushort = (unsigned short) ulval;
444     return 1;
445 }
446
447
448 /*
449  * Dump UDP statistics structure.
450  */
451 void
452 udp_stats(void)
453 {
454     oid             varname[MAX_OID_LEN], *udpentry;
455     size_t          varname_len;
456     netsnmp_variable_list *var;
457     int             count;
458     struct stat_table *sp = udp_stattab;
459
460     memmove(varname, oid_udpstats, sizeof(oid_udpstats));
461     varname_len = sizeof(oid_udpstats) / sizeof(oid);
462     udpentry = varname + 7;
463     printf("udp:\n");
464     count = sizeof(udp_stattab) / sizeof(struct stat_table);
465     while (count--) {
466         *udpentry = sp->entry;
467         var = getvarbyname(Session, varname, varname_len);
468         if (var && var->val.integer) {
469             putchar('\t');
470             printf(sp->description, *var->val.integer,
471                    plural((int) *var->val.integer));
472             putchar('\n');
473         }
474         if (var)
475             snmp_free_var(var);
476         sp++;
477     }
478
479 }
480
481 /*
482  * Dump TCP statistics structure.
483  */
484 void
485 tcp_stats(void)
486 {
487     oid             varname[MAX_OID_LEN], *tcpentry;
488     size_t          varname_len;
489     netsnmp_variable_list *var;
490     int             count;
491     struct stat_table *sp = tcp_stattab;
492
493     memmove(varname, oid_tcpstats, sizeof(oid_tcpstats));
494     varname_len = sizeof(oid_tcpstats) / sizeof(oid);
495     tcpentry = varname + 7;
496     printf("tcp:\n");
497     count = sizeof(tcp_stattab) / sizeof(struct stat_table);
498     while (count--) {
499         *tcpentry = sp->entry;
500         var = getvarbyname(Session, varname, varname_len);
501         if (var && var->val.integer) {
502             putchar('\t');
503             printf(sp->description, *var->val.integer,
504                    plural((int) *var->val.integer));
505             putchar('\n');
506         }
507         if (var)
508             snmp_free_var(var);
509         sp++;
510     }
511
512 }
513
514 /*
515  * Dump IP statistics structure.
516  */
517 void
518 ip_stats(void)
519 {
520     oid             varname[MAX_OID_LEN], *ipentry;
521     size_t          varname_len;
522     netsnmp_variable_list *var;
523     int             count;
524     struct stat_table *sp = ip_stattab;
525
526     memmove(varname, oid_ipstats, sizeof(oid_ipstats));
527     varname_len = sizeof(oid_ipstats) / sizeof(oid);
528     ipentry = varname + 7;
529     printf("ip:\n");
530     count = sizeof(ip_stattab) / sizeof(struct stat_table);
531     while (count--) {
532         *ipentry = sp->entry;
533         var = getvarbyname(Session, varname, varname_len);
534         if (var && var->val.integer) {
535             putchar('\t');
536             printf(sp->description, *var->val.integer,
537                    plural((int) *var->val.integer));
538             putchar('\n');
539         }
540         if (var)
541             snmp_free_var(var);
542         sp++;
543     }
544
545 }
546
547 /*
548  * Dump ICMP statistics.
549  */
550 void
551 icmp_stats(void)
552 {
553     oid             varname[MAX_OID_LEN], *icmpentry;
554     size_t          varname_len;
555     netsnmp_variable_list *var;
556     int             count, first;
557     struct stat_table *sp;
558
559     memmove(varname, oid_icmpstats, sizeof(oid_icmpstats));
560     varname_len = sizeof(oid_icmpstats) / sizeof(oid);
561     icmpentry = varname + 7;
562     printf("icmp:\n");
563     sp = icmp_stattab;
564     count = sizeof(icmp_stattab) / sizeof(struct stat_table);
565     while (count--) {
566         *icmpentry = sp->entry;
567         var = getvarbyname(Session, varname, varname_len);
568         if (var && var->val.integer) {
569             putchar('\t');
570             printf(sp->description, *var->val.integer,
571                    plural((int) *var->val.integer));
572             putchar('\n');
573         }
574         if (var)
575             snmp_free_var(var);
576         sp++;
577     }
578
579     sp = icmp_outhistogram;
580     first = 1;
581     count = sizeof(icmp_outhistogram) / sizeof(struct stat_table);
582     while (count--) {
583         *icmpentry = sp->entry;
584         var = getvarbyname(Session, varname, varname_len);
585         if (var && var->val.integer && *var->val.integer != 0) {
586             if (first) {
587                 printf("\tOutput Histogram:\n");
588                 first = 0;
589             }
590             printf("\t\t");
591             printf(sp->description, *var->val.integer,
592                    plural((int) *var->val.integer));
593             putchar('\n');
594         }
595         if (var)
596             snmp_free_var(var);
597         sp++;
598     }
599
600     sp = icmp_inhistogram;
601     first = 1;
602     count = sizeof(icmp_inhistogram) / sizeof(struct stat_table);
603     while (count--) {
604         *icmpentry = sp->entry;
605         var = getvarbyname(Session, varname, varname_len);
606         if (var && var->val.integer && *var->val.integer != 0) {
607             if (first) {
608                 printf("\tInput Histogram:\n");
609                 first = 0;
610             }
611             printf("\t\t");
612             printf(sp->description, *var->val.integer,
613                    plural((int) *var->val.integer));
614             putchar('\n');
615         }
616         if (var)
617             snmp_free_var(var);
618         sp++;
619     }
620 }
621
622 /*
623  * Pretty print an Internet address (net address + port).
624  * If the nflag was specified, use numbers instead of names.
625  */
626 void
627 inetprint(struct in_addr *in, u_short port, const char *proto)
628 {
629     struct servent *sp = 0;
630     char            line[80], *cp;
631     int             width;
632
633     sprintf(line, "%.*s.", 22, inetname(*in));
634     cp = (char *) strchr(line, '\0');
635     if (!nflag && port)
636         sp = getservbyport(htons(port), proto);
637     if (sp || port == 0)
638         sprintf(cp, "%.8s", sp ? sp->s_name : "*");
639     else
640         sprintf(cp, "%d", port);
641     width = 28;
642     printf(" %-*.*s", width, width, line);
643 }
644
645 /*
646  * Construct an Internet address representation.
647  * If the nflag has been supplied, give 
648  * numeric value, otherwise try for symbolic name.
649  */
650 static char    *
651 inetname(struct in_addr in)
652 {
653     register char  *cp;
654     static char     line[50];
655     struct hostent *hp;
656     struct netent  *np;
657     static char     domain[MAXHOSTNAMELEN + 1];
658     static int      first = 1;
659
660     if (first && !nflag) {
661         first = 0;
662         if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
663             (cp = (char *) strchr(domain, '.')))
664             (void) strcpy(domain, cp + 1);
665         else
666             domain[0] = 0;
667     }
668     cp = 0;
669     if (!nflag && in.s_addr != INADDR_ANY) {
670         u_long          net = inet_netof(in);
671         u_long          lna = inet_lnaof(in);
672
673         if (lna == INADDR_ANY) {
674             np = getnetbyaddr(net, AF_INET);
675             if (np)
676                 cp = np->n_name;
677         }
678         if (cp == 0) {
679             hp = gethostbyaddr((char *) &in, sizeof(in), AF_INET);
680             if (hp) {
681                 if ((cp = (char *) strchr(hp->h_name, '.')) &&
682                     !strcmp(cp + 1, domain))
683                     *cp = 0;
684                 cp = (char *) hp->h_name;
685             }
686         }
687     }
688     if (in.s_addr == INADDR_ANY)
689         strcpy(line, "*");
690     else if (cp) {
691         strncpy(line, cp, sizeof(line));
692         line[ sizeof(line)-1 ] = 0;
693     } else {
694         in.s_addr = ntohl(in.s_addr);
695 #define C(x)    (unsigned)((x) & 0xff)
696         sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
697                 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
698     }
699     return (line);
700 }