1 /****************************************************************
2 Copyright 1989, 1991, 1992 by Carnegie Mellon University
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.
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
21 ******************************************************************/
23 * Copyright (c) 1983,1988 Regents of the University of California.
24 * All rights reserved.
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.
34 #include <net-snmp/net-snmp-config.h>
53 #include <sys/param.h>
56 #include <sys/select.h>
59 #include <netinet/in.h>
62 #include <arpa/inet.h>
68 #include <sys/socket.h>
73 #include <net-snmp/net-snmp-includes.h>
76 static char *inet6name(struct in6_addr *);
79 int entry; /* entry number in table */
81 * format string to printf(description, value, plural(value));
84 * warning: the %d must be before the %s
89 #if DEBUGGING_INFORMATION
91 * The following tables provide useful debugging information.
92 * This isn't normally needed or easily accessible,
93 * but could potentially be very useful.
94 * Rather than delete it totally, it's commented out
96 static oid oid_ipstats[] = { 1, 3, 6, 1, 2, 1, 4, 0, 0 };
97 struct stat_table ip_stattab[] = {
98 {3, "%d total datagram%s received"},
99 {4, "%d datagram%s with header errors"},
100 {5, "%d datagram%s with an invalid destination address"},
101 {6, "%d datagram%s forwarded"},
102 {7, "%d datagram%s with unknown protocol"},
103 {8, "%d datagram%s discarded"},
104 {9, "%d datagram%s delivered"},
105 {10, "%d output datagram request%s"},
106 {11, "%d output datagram%s discarded"},
107 {12, "%d datagram%s with no route"},
108 {14, "%d fragment%s received"},
109 {15, "%d datagram%s reassembled"},
110 {16, "%d reassembly failure%s"},
111 {17, "%d datagram%s fragmented"},
112 {18, "%d fragmentation failure%s"},
113 {19, "%d fragment%s created"}
116 static oid oid_udpstats[] = { 1, 3, 6, 1, 2, 1, 7, 0, 0 };
117 struct stat_table udp_stattab[] = {
118 {1, "%d total datagram%s received"},
119 {2, "%d datagram%s to invalid port"},
120 {3, "%d datagram%s dropped due to errors"},
121 {4, "%d output datagram request%s"}
124 static oid oid_tcpstats[] = { 1, 3, 6, 1, 2, 1, 6, 0, 0 };
125 struct stat_table tcp_stattab[] = {
126 {5, "%d active open%s"},
127 {6, "%d passive open%s"},
128 {7, "%d failed attempt%s"},
129 {8, "%d reset%s of established connections"},
130 {9, "%d current established connection%s"},
131 {10, "%d segment%s received"},
132 {11, "%d segment%s sent"},
133 {12, "%d segment%s retransmitted"}
136 static oid oid_icmpstats[] = { 1, 3, 6, 1, 2, 1, 5, 0, 0 };
137 struct stat_table icmp_stattab[] = {
138 {1, "%d total message%s received"},
139 {2, "%d message%s dropped due to errors"},
140 {14, "%d ouput message request%s"},
141 {15, "%d output message%s discarded"}
144 struct stat_table icmp_inhistogram[] = {
145 {3, "Destination unreachable: %d"},
146 {4, "Time Exceeded: %d"},
147 {5, "Parameter Problem: %d"},
148 {6, "Source Quench: %d"},
150 {8, "Echo Request: %d"},
151 {9, "Echo Reply: %d"},
152 {10, "Timestamp Request: %d"},
153 {11, "Timestamp Reply: %d"},
154 {12, "Address Mask Request: %d"},
155 {13, "Addrss Mask Reply:%d"},
158 struct stat_table icmp_outhistogram[] = {
159 {16, "Destination unreachable: %d"},
160 {17, "Time Exceeded: %d"},
161 {18, "Parameter Problem: %d"},
162 {19, "Source Quench: %d"},
163 {20, "Redirect: %d"},
164 {21, "Echo Request: %d"},
165 {22, "Echo Reply: %d"},
166 {23, "Timestamp Request: %d"},
167 {24, "Timestamp Reply: %d"},
168 {25, "Address Mask Request: %d"},
169 {26, "Addrss Mask Reply:%d"},
173 struct tcpconn_entry {
174 oid instance[16 + 1 + 16 + 1 + 1];
175 struct in6_addr localAddress;
179 struct in6_addr remoteAddress;
185 struct tcpconn_entry *next;
189 oid instance[16 + 1 + 1];
190 struct in6_addr localAddress;
194 struct udp_entry *next;
197 #define TCPCONN_LOCADDR 1
198 #define TCPCONN_LOCPORT 2
199 #define TCPCONN_REMADDR 3
200 #define TCPCONN_REMPORT 4
201 #define TCPCONN_IFINDEX 5
202 #define TCPCONN_STATE 6
204 static oid oid_tcpconntable[] = { 1, 3, 6, 1, 3, 86, 1, 16, 1 };
207 #define UDP_LOCADDR 1
208 #define UDP_LOCPORT 2
209 #define UDP_IFINDEX 3
211 static oid oid_udptable[] = { 1, 3, 6, 1, 3, 87, 1, 1, 1 };
214 static const char *tcpstates[] = {
228 #define TCP_NSTATES 11
230 static int validUShortAssign(unsigned short *, int, const char *);
233 * Print a summary of connections related to an Internet
234 * protocol (currently only TCP). For TCP, also give state of connection.
237 protopr6(const char *name)
239 struct tcpconn_entry *tcpconn = NULL, *tcplast = NULL, *tp, *newtp;
240 struct udp_entry *udpconn = NULL, *udplast = NULL, *up, *newup;
241 netsnmp_pdu *request = NULL, *response = NULL;
242 netsnmp_variable_list *vp;
247 if (strncmp(name, "tcp", 3) == 0) {
248 request = snmp_pdu_create(SNMP_MSG_GETNEXT);
249 snmp_add_null_var(request, oid_tcpconntable,
250 sizeof(oid_tcpconntable) / sizeof(oid));
251 status = STAT_SUCCESS;
253 status = STAT_TIMEOUT;
254 while (status == STAT_SUCCESS) {
256 snmp_free_pdu(response);
258 status = snmp_synch_response(Session, request, &response);
259 if (status != STAT_SUCCESS
260 || response->errstat != SNMP_ERR_NOERROR) {
261 snmp_perror("SNMP request failed");
264 vp = response->variables;
267 if (vp->name_length != 46 ||
268 memcmp(vp->name, oid_tcpconntable, sizeof(oid_tcpconntable))) {
272 request = snmp_pdu_create(SNMP_MSG_GETNEXT);
273 snmp_add_null_var(request, vp->name, vp->name_length);
275 instance = vp->name + 10;
276 for (tp = tcpconn; tp != NULL; tp = tp->next) {
277 if (!memcmp(instance, tp->instance, sizeof(tp->instance)))
281 tp = (struct tcpconn_entry *) calloc(1,
291 memmove(tp->instance, instance, sizeof(tp->instance));
294 if (vp->name[TCP_ENTRY] == TCPCONN_STATE) {
295 tp->state = *vp->val.integer;
299 if (vp->name[TCP_ENTRY] == TCPCONN_LOCADDR) {
300 memmove(&tp->localAddress, vp->val.string,
301 sizeof(struct in6_addr));
305 if (vp->name[TCP_ENTRY] == TCPCONN_LOCPORT) {
306 if (validUShortAssign(&tp->localPort, *vp->val.integer,
311 if (vp->name[TCP_ENTRY] == TCPCONN_REMADDR) {
312 memmove(&tp->remoteAddress, vp->val.string,
313 sizeof(struct in6_addr));
317 if (vp->name[TCP_ENTRY] == TCPCONN_REMPORT) {
318 if (validUShortAssign(&tp->remotePort, *vp->val.integer,
324 snmp_free_pdu(response);
327 for (first = 1, tp = tcpconn, newtp = NULL; tp != NULL; tp = tp->next) {
331 if (!(tp->stateSet && tp->locAddrSet
332 && tp->locPortSet && tp->remAddrSet && tp->remPortSet)) {
333 printf("incomplete entry\n");
336 if (!aflag && tp->state == MIB_TCPCONNSTATE_LISTEN)
339 printf("Active Internet (%s) Connections", name);
341 printf(" (including servers)");
343 printf("%-5.5s %-28.28s %-28.28s %s\n",
344 "Proto", "Local Address", "Foreign Address", "(state)");
347 printf("%-5.5s ", name);
348 inet6print(&tp->localAddress, tp->localPort, name);
349 inet6print(&tp->remoteAddress, tp->remotePort, name);
350 if (tp->state < 1 || tp->state > TCP_NSTATES)
351 printf(" %d", tp->state);
353 printf(" %s", tcpstates[tp->state]);
360 if (strncmp(name, "udp", 3) == 0) {
361 request = snmp_pdu_create(SNMP_MSG_GETNEXT);
362 snmp_add_null_var(request, oid_udptable,
363 sizeof(oid_udptable) / sizeof(oid));
364 status = STAT_SUCCESS;
366 status = STAT_TIMEOUT;
367 while (status == STAT_SUCCESS) {
369 snmp_free_pdu(response);
371 status = snmp_synch_response(Session, request, &response);
372 if (status != STAT_SUCCESS
373 || response->errstat != SNMP_ERR_NOERROR) {
374 fprintf(stderr, "SNMP request failed\n");
377 vp = response->variables;
380 if (vp->name_length != 28 ||
381 memcmp(vp->name, oid_udptable, sizeof(oid_udptable))) {
385 request = snmp_pdu_create(SNMP_MSG_GETNEXT);
386 snmp_add_null_var(request, vp->name, vp->name_length);
388 instance = vp->name + 10;
389 for (up = udpconn; up != NULL; up = up->next) {
390 if (!memcmp(instance, up->instance, sizeof(up->instance)))
394 up = (struct udp_entry *) calloc(1, sizeof(struct udp_entry));
402 memmove(up->instance, instance, sizeof(up->instance));
405 if (vp->name[UDP_ENTRY] == UDP_LOCADDR) {
406 memmove(&up->localAddress, vp->val.string,
407 sizeof(struct in6_addr));
411 if (vp->name[UDP_ENTRY] == UDP_LOCPORT) {
412 if (validUShortAssign(&up->localPort, *vp->val.integer,
418 snmp_free_pdu(response);
421 for (first = 1, up = udpconn, newup = NULL; up != NULL; up = up->next) {
425 if (!(up->locAddrSet && up->locPortSet)) {
426 printf("incomplete entry\n");
430 printf("Active Internet (%s) Connections", name);
432 printf("%-5.5s %-28.28s\n", "Proto", "Local Address");
435 printf("%-5.5s ", name);
436 inet6print(&up->localAddress, up->localPort, name);
445 validUShortAssign(unsigned short *pushort, int ival, const char *errstr)
447 u_long ulval = (u_long) ival;
449 printf("Warning: %s value %ld (0x%lx) is not a port address\n",
450 errstr, ulval, ulval);
453 *pushort = (unsigned short) ulval;
458 #if DEBUGGING_INFORMATION
460 * The following routines print out useful debugging information.
461 * This isn't normally needed or easily accessible,
462 * but could potentially be very useful.
463 * Rather than delete it totally, it's commented out
466 * Dump UDP statistics structure.
471 oid varname[MAX_OID_LEN], *udpentry;
473 netsnmp_variable_list *var;
475 struct stat_table *sp = udp_stattab;
477 memmove(varname, oid_udpstats, sizeof(oid_udpstats));
478 varname_len = sizeof(oid_udpstats) / sizeof(oid);
479 udpentry = varname + 7;
481 count = sizeof(udp_stattab) / sizeof(struct stat_table);
483 *udpentry = sp->entry;
484 var = getvarbyname(Session, varname, varname_len);
485 if (var && var->val.integer) {
487 printf(sp->description, *var->val.integer,
488 plural((int) *var->val.integer));
499 * Dump TCP statistics structure.
504 oid varname[MAX_OID_LEN], *tcpentry;
506 netsnmp_variable_list *var;
508 struct stat_table *sp = tcp_stattab;
510 memmove(varname, oid_tcpstats, sizeof(oid_tcpstats));
511 varname_len = sizeof(oid_tcpstats) / sizeof(oid);
512 tcpentry = varname + 7;
514 count = sizeof(tcp_stattab) / sizeof(struct stat_table);
516 *tcpentry = sp->entry;
517 var = getvarbyname(Session, varname, varname_len);
518 if (var && var->val.integer) {
520 printf(sp->description, *var->val.integer,
521 plural((int) *var->val.integer));
532 * Dump IP statistics structure.
537 oid varname[MAX_OID_LEN], *ipentry;
539 netsnmp_variable_list *var;
541 struct stat_table *sp = ip_stattab;
543 memmove(varname, oid_ipstats, sizeof(oid_ipstats));
544 varname_len = sizeof(oid_ipstats) / sizeof(oid);
545 ipentry = varname + 7;
547 count = sizeof(ip_stattab) / sizeof(struct stat_table);
549 *ipentry = sp->entry;
550 var = getvarbyname(Session, varname, varname_len);
551 if (var && var->val.integer) {
553 printf(sp->description, *var->val.integer,
554 plural((int) *var->val.integer));
565 * Dump ICMP statistics.
570 oid varname[MAX_OID_LEN], *icmpentry;
572 netsnmp_variable_list *var;
574 struct stat_table *sp;
576 memmove(varname, oid_icmpstats, sizeof(oid_icmpstats));
577 varname_len = sizeof(oid_icmpstats) / sizeof(oid);
578 icmpentry = varname + 7;
581 count = sizeof(icmp_stattab) / sizeof(struct stat_table);
583 *icmpentry = sp->entry;
584 var = getvarbyname(Session, varname, varname_len);
585 if (var && var->val.integer) {
587 printf(sp->description, *var->val.integer,
588 plural((int) *var->val.integer));
596 sp = icmp_outhistogram;
598 count = sizeof(icmp_outhistogram) / sizeof(struct stat_table);
600 *icmpentry = sp->entry;
601 var = getvarbyname(Session, varname, varname_len);
602 if (var && var->val.integer && *var->val.integer != 0) {
604 printf("\tOutput Histogram:\n");
608 printf(sp->description, *var->val.integer,
609 plural((int) *var->val.integer));
617 sp = icmp_inhistogram;
619 count = sizeof(icmp_inhistogram) / sizeof(struct stat_table);
621 *icmpentry = sp->entry;
622 var = getvarbyname(Session, varname, varname_len);
623 if (var && var->val.integer && *var->val.integer != 0) {
625 printf("\tInput Histogram:\n");
629 printf(sp->description, *var->val.integer,
630 plural((int) *var->val.integer));
641 * Pretty print an Internet address (net address + port).
642 * If the nflag was specified, use numbers instead of names.
645 inet6print(struct in6_addr *in, u_short port, const char *proto)
647 struct servent *sp = 0;
651 sprintf(line, "%.*s.", 22, inet6name(in));
652 cp = strchr(line, '\0');
654 sp = getservbyport(htons(port), proto);
656 sprintf(cp, "%.8s", sp ? sp->s_name : "*");
658 sprintf(cp, "%d", port);
660 printf(" %-*.*s", width, width, line);
664 * Construct an Internet address representation.
665 * If the nflag has been supplied, give
666 * numeric value, otherwise try for symbolic name.
669 inet6name(struct in6_addr *in)
672 static char line[50];
674 static char domain[MAXHOSTNAMELEN + 1];
675 static int first = 1;
677 if (first && !nflag) {
679 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
680 (cp = strchr(domain, '.')))
681 (void) strcpy(domain, cp + 1);
686 if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in)) {
687 hp = gethostbyaddr((char *) in, sizeof(*in), AF_INET6);
689 if ((cp = strchr(hp->h_name, '.')) && !strcmp(cp + 1, domain))
694 if (IN6_IS_ADDR_UNSPECIFIED(in))
697 strncpy(line, cp, sizeof(line));
698 line[ sizeof(line)-1 ] = 0;
700 inet_ntop(AF_INET6, in, line, sizeof(line));