diff options
Diffstat (limited to 'apps/snmpnetstat/inet6.c')
-rw-r--r-- | apps/snmpnetstat/inet6.c | 516 |
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 |