summaryrefslogtreecommitdiff
path: root/apps/snmpnetstat/inet6.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/snmpnetstat/inet6.c')
-rw-r--r--apps/snmpnetstat/inet6.c516
1 files changed, 516 insertions, 0 deletions
diff --git a/apps/snmpnetstat/inet6.c b/apps/snmpnetstat/inet6.c
new file mode 100644
index 0000000..5760522
--- /dev/null
+++ b/apps/snmpnetstat/inet6.c
@@ -0,0 +1,516 @@
+/* $OpenBSD: inet6.c,v 1.31 2004/11/17 01:47:20 itojun Exp $ */
+/* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef INHERITED_CODE
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)inet.c 8.4 (Berkeley) 4/20/94";
+#else
+/*__RCSID("$OpenBSD: inet6.c,v 1.31 2004/11/17 01:47:20 itojun Exp $");*/
+/*__RCSID("KAME Id: inet6.c,v 1.10 2000/02/09 10:49:31 itojun Exp");*/
+#endif
+#endif /* not lint */
+#endif
+
+#include <net-snmp/net-snmp-config.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_WINSOCK_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include "winstub.h"
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include <net-snmp/net-snmp-includes.h>
+
+#include "main.h"
+#include "netstat.h"
+
+struct stat_table {
+ int entry; /* entry number in table */
+ /*
+ * format string to printf(description, value)
+ * warning: the %d must be before the %s
+ */
+ char description[80];
+};
+
+char *inet6name(const unsigned char *);
+void inet6print(unsigned char *, int, const char *, int);
+
+/*
+ * Print a summary of TCPv6 connections
+ * Listening processes are suppressed unless the
+ * -a (all) flag is specified.
+ */
+const char *tcp6states[] = {
+ "",
+ "CLOSED",
+ "LISTEN",
+ "SYNSENT",
+ "SYNRECEIVED",
+ "ESTABLISHED",
+ "FINWAIT1",
+ "FINWAIT2",
+ "CLOSEWAIT",
+ "LASTACK",
+ "CLOSING",
+ "TIMEWAIT"
+};
+#define TCP_NSTATES 11
+
+void
+tcp6protopr(const char *name)
+{
+ netsnmp_variable_list *var, *vp;
+ oid ipv6TcpConnState_oid[] = { 1,3,6,1,2,1,6,16,1,6 };
+ size_t ipv6TcpConnState_len = OID_LENGTH( ipv6TcpConnState_oid );
+ int state, i;
+ unsigned char localAddr[16], remoteAddr[16];
+ int localPort, remotePort, ifIndex;
+ int first = 1;
+
+ /*
+ * Walking the v6 tcpConnState column will provide all
+ * the necessary information.
+ */
+ var = NULL;
+ snmp_varlist_add_variable( &var, ipv6TcpConnState_oid,
+ ipv6TcpConnState_len,
+ ASN_NULL, NULL, 0);
+ if (netsnmp_query_walk( var, ss ) != SNMP_ERR_NOERROR)
+ return;
+ if (var->type == ASN_NULL) /* No entries */
+ return;
+
+ for (vp = var; vp ; vp=vp->next_variable) {
+ state = *var->val.integer;
+ if (!aflag && state == MIB_TCPCONNSTATE_LISTEN)
+ continue;
+
+ if (first) {
+ printf("Active Internet Connections");
+ if (aflag)
+ printf(" (including servers)");
+ putchar('\n');
+ printf("%-5.5s %-28.28s %-28.28s %4s %s\n",
+ "Proto", "Local Address", "Remote Address", "I/F", "(state)");
+ first = 0;
+ }
+
+ /* Extract the local/remote information from the index values */
+ for (i=0; i<16; i++)
+ localAddr[i] = var->name[ 10+i ];
+ localPort = var->name[ 26 ];
+ for (i=0; i<16; i++)
+ remoteAddr[i] = var->name[ 27+i ];
+ remotePort = var->name[ 43 ];
+ ifIndex = var->name[ 44 ];
+
+ printf("%-5.5s", name);
+ inet6print(localAddr, localPort, name, 1);
+ inet6print(remoteAddr, remotePort, name, 0);
+ if ( state < 1 || state > TCP_NSTATES )
+ printf(" %4d %d\n", ifIndex, state );
+ else
+ printf(" %4d %s\n", ifIndex, tcp6states[ state ]);
+ }
+ snmp_free_varbind( var );
+}
+
+/*
+ * Print a summary of UDPv6 "connections"
+ * XXX - what about "listening" services ??
+ */
+void
+udp6protopr(const char *name)
+{
+ netsnmp_variable_list *var, *vp;
+ oid ipv6UdpLocalAddress_oid[] = { 1,3,6,1,2,1,7,6,1,1 };
+ size_t ipv6UdpLocalAddress_len = OID_LENGTH( ipv6UdpLocalAddress_oid );
+ int localPort, ifIndex;
+
+ /*
+ * Walking a single column of the udpTable will provide
+ * all the necessary information from the index values.
+ */
+ var = NULL;
+ snmp_varlist_add_variable( &var, ipv6UdpLocalAddress_oid,
+ ipv6UdpLocalAddress_len,
+ ASN_NULL, NULL, 0);
+ if (netsnmp_query_walk( var, ss ) != SNMP_ERR_NOERROR)
+ return;
+ if (var->type == ASN_NULL) /* No entries */
+ return;
+
+ printf("Active Internet Connections\n");
+ printf("%-5.5s %-28.28s %4s\n", "Proto", "Local Address", "I/F");
+ for (vp = var; vp ; vp=vp->next_variable) {
+ printf("%-5.5s", name);
+ /*
+ * Extract the local port from the index values, but take
+ * the IP address from the varbind value, (which is why
+ * we walked udpLocalAddress rather than udpLocalPort)
+ */
+ localPort = var->name[ var->name_length-2 ];
+ ifIndex = var->name[ var->name_length-1 ];
+ inet6print(var->val.string, localPort, name, 1);
+ printf(" %4d\n", ifIndex );
+ }
+ snmp_free_varbind( var );
+}
+
+
+ /*********************
+ *
+ * IPv6 statistics
+ *
+ *********************/
+
+/*
+ * Unlike the equivalent IPv4 statistics display routine,
+ * the IPv6 version must walk the columns of a table
+ * and total the statistics for each column (rather
+ * than simply retrieving individual scalar values)
+ */
+void
+_dump_v6stats( const char *name, oid *oid_buf, size_t buf_len,
+ struct stat_table *stable )
+{
+ netsnmp_variable_list *var, *vp;
+ struct stat_table *sp;
+ oid *stats, stat;
+ int max_stat = 0;
+ int active = 0;
+
+ var = NULL;
+ for (sp=stable; sp->entry; sp++) {
+ oid_buf[buf_len-1] = sp->entry;
+ if (sp->entry>max_stat)
+ max_stat = sp->entry;
+ snmp_varlist_add_variable( &var, oid_buf, buf_len,
+ ASN_NULL, NULL, 0);
+ }
+ oid_buf[buf_len-1] = stable[0].entry;
+ stats = (oid *)calloc(max_stat+1, sizeof(oid));
+
+ /*
+ * Walk the specified column(s), and total the individual statistics
+ */
+ while (1) {
+ if (netsnmp_query_getnext( var, ss ) != SNMP_ERR_NOERROR)
+ break;
+ if ( snmp_oid_compare( oid_buf, buf_len-1,
+ var->name, buf_len-1) != 0 )
+ break; /* End of Table */
+
+ for ( vp=var; vp; vp=vp->next_variable ) {
+ stat = var->name[ buf_len-1 ];
+ stats[stat] += *vp->val.integer;
+ }
+ active=1;
+ }
+ if (!active) {
+ free( stats );
+ snmp_free_varbind( var );
+ return; /* No statistics to display */
+ }
+
+ /*
+ * Display the results
+ */
+ printf("%s:\n", name);
+ for (sp=stable; sp->entry; sp++) {
+ /*
+ * If '-Cs' was specified twice,
+ * then only display non-zero stats.
+ */
+ if ( stats[sp->entry] > 0 || sflag == 1 ) {
+ putchar('\t');
+ printf(sp->description, stats[sp->entry],
+ plural(stats[sp->entry]));
+ putchar('\n');
+ }
+ }
+ free( stats );
+ snmp_free_varbind( var );
+}
+
+
+/*
+ * Dump IP6 statistics.
+ */
+void
+ip6_stats(const char *name)
+{
+ oid ip6stats_oid[] = { 1, 3, 6, 1, 2, 1, 55, 1, 6, 1, 0 };
+ size_t ip6stats_len = OID_LENGTH( ip6stats_oid );
+ struct stat_table ip6stats_tbl[] = {
+ {1, "%d total datagram%s received"},
+ {2, "%d datagram%s with header errors"},
+ {3, "%d oversized datagram%s"},
+ {4, "%d datagram%s with no route"},
+ {5, "%d datagram%s with an invalid destination address"},
+ {6, "%d datagram%s with unknown protocol"},
+ {7, "%d short datagram%s discarded"},
+ {8, "%d datagram%s discarded"},
+ {9, "%d datagram%s delivered"},
+ {10, "%d datagram%s forwarded"},
+ {11, "%d output datagram request%s"},
+ {12, "%d output datagram%s discarded"},
+ {13, "%d datagram%s fragmented"},
+ {14, "%d fragmentation failure%s"},
+ {15, "%d fragment%s created"},
+ {16, "%d fragment%s received"},
+ {17, "%d datagram%s reassembled"},
+ {18, "%d reassembly failure%s"},
+ {19, "%d multicast datagram%s received"},
+ {20, "%d multicast datagram%s transmitted"},
+ {0, ""}
+ };
+
+ _dump_v6stats( name, ip6stats_oid, ip6stats_len, ip6stats_tbl );
+}
+
+/*
+ * Dump IPv6 per-interface statistics - Omitted
+ */
+
+
+/*
+ * Dump ICMP6 statistics.
+ */
+void
+icmp6_stats(const char *name)
+{
+ oid icmp6stats_oid[] = { 1, 3, 6, 1, 2, 1, 56, 1, 1, 1, 0 };
+ size_t icmp6stats_len = OID_LENGTH( icmp6stats_oid );
+ struct stat_table icmp6stats_tbl[] = {
+ {1, "%d total message%s received"},
+ {2, "%d message%s dropped due to errors"},
+ {18, "%d ouput message request%s"},
+ {19, "%d output message%s discarded"},
+ {0, ""}
+ };
+ struct stat_table icmp6_inhistogram[] = {
+ {3, "Destination unreachable: %d"},
+ {4, "Admin Prohibit: %d"},
+ {5, "Time Exceeded: %d"},
+ {6, "Parameter Problem: %d"},
+ {7, "Too Big: %d"},
+ {8, "Echo Request: %d"},
+ {9, "Echo Reply: %d"},
+ {10, "Router Solicit: %d"},
+ {11, "Router Advert: %d"},
+ {12, "Neighbor Solicit: %d"},
+ {13, "Neighbor Advert: %d"},
+ {14, "Redirect: %d"},
+ {15, "Group Member Request: %d"},
+ {16, "Group Member Reply:%d"},
+ {17, "Group Member Reduce:%d"},
+ {0, ""}
+ };
+ struct stat_table icmp6_outhistogram[] = {
+ {20, "Destination unreachable: %d"},
+ {21, "Admin Prohibit: %d"},
+ {22, "Time Exceeded: %d"},
+ {23, "Parameter Problem: %d"},
+ {24, "Too Big: %d"},
+ {25, "Echo Request: %d"},
+ {26, "Echo Reply: %d"},
+ {27, "Router Solicit: %d"},
+ {28, "Router Advert: %d"},
+ {29, "Neighbor Solicit: %d"},
+ {30, "Neighbor Advert: %d"},
+ {31, "Redirect: %d"},
+ {32, "Group Member Request: %d"},
+ {33, "Group Member Reply:%d"},
+ {34, "Group Member Reduce:%d"},
+ {0, ""}
+ };
+
+ _dump_v6stats( name, icmp6stats_oid, icmp6stats_len, icmp6stats_tbl );
+ _dump_v6stats( " Input Histogram",
+ icmp6stats_oid, icmp6stats_len, icmp6_inhistogram );
+ _dump_v6stats( " Output Histogram",
+ icmp6stats_oid, icmp6stats_len, icmp6_outhistogram );
+}
+
+/*
+ * Dump ICMPv6 per-interface statistics - Omitted
+ */
+
+
+/*
+ * Ommitted:
+ * Dump PIM statistics
+ * Dump raw ip6 statistics
+ */
+
+
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+
+void
+inet6print(unsigned char *in6, int port, const char *proto, int local)
+{
+
+#define GETSERVBYPORT6(port, proto, ret) do { \
+ if (strcmp((proto), "tcp6") == 0) \
+ (ret) = getservbyport((int)(port), "tcp"); \
+ else if (strcmp((proto), "udp6") == 0) \
+ (ret) = getservbyport((int)(port), "udp"); \
+ else \
+ (ret) = getservbyport((int)(port), (proto)); \
+ } while (0)
+
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+ int len = sizeof line;
+
+ width = Aflag ? 12 : 16;
+ if (vflag && width < strlen(inet6name(in6)))
+ width = strlen(inet6name(in6));
+ snprintf(line, len, "%.*s.", width, inet6name(in6));
+ len -= strlen(line);
+ if (len <= 0)
+ goto bail;
+
+ cp = strchr(line, '\0');
+ if (!nflag && port && local)
+ GETSERVBYPORT6(port, proto, sp);
+ if (sp || port == 0)
+ snprintf(cp, len, "%.8s", sp ? sp->s_name : "*");
+ else
+ snprintf(cp, len, "%d", ntohs((u_short)port));
+ width = Aflag ? 18 : 22;
+ if (vflag && width < strlen(line))
+ width = strlen(line);
+bail:
+ printf(" %-*.*s", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+
+char *
+inet6name(const unsigned char *in6)
+{
+ char *cp;
+ static char line[NI_MAXHOST];
+ static char domain[MAXHOSTNAMELEN];
+ static int first = 1;
+#ifdef NETSNMP_ENABLE_IPV6
+ struct hostent *hp;
+ char hbuf[NI_MAXHOST];
+ const int niflag = NI_NUMERICHOST;
+ struct sockaddr_in6 sin6;
+ const struct in6_addr *in6p = (const struct in6_addr *)in6;
+#endif
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, sizeof(domain)) == 0 &&
+ (cp = strchr(domain, '.')))
+ (void) strlcpy(domain, cp + 1, sizeof domain);
+ else
+ domain[0] = '\0';
+ }
+#ifdef NETSNMP_ENABLE_IPV6
+ cp = 0;
+ if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
+ hp = gethostbyaddr((const char *)in6p, sizeof(*in6p), AF_INET6);
+ if (hp) {
+ if ((cp = strchr(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED(in6p))
+ strlcpy(line, "*", sizeof(line));
+ else if (cp)
+ strlcpy(line, cp, sizeof(line));
+ else {
+ memset(&sin6, 0, sizeof(sin6));
+/* sin6.sin6_len = sizeof(sin6); */
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = *in6p;
+#ifdef __KAME__
+ if (IN6_IS_ADDR_LINKLOCAL(in6p) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(in6p)) {
+ sin6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&in6p->s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+ if (getnameinfo((struct sockaddr *)&sin6, sizeof(sin6),
+ hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
+ strlcpy(hbuf, "?", sizeof hbuf);
+ strlcpy(line, hbuf, sizeof(line));
+ }
+#else
+ strlcpy(line, "[[XXX - inet6 address]]", sizeof(line));
+#endif
+ return (line);
+}
+
+#ifdef TCP6
+/*
+ * Dump the contents of a TCP6 PCB - Omitted
+ */
+#endif