593 lines
18 KiB
C
593 lines
18 KiB
C
/* $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 "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 {
|
|
unsigned int entry; /* entry number in table */
|
|
/*
|
|
* format string to printf(description, value)
|
|
* warning: the %d must be before the %s
|
|
*/
|
|
char description[80];
|
|
};
|
|
|
|
void inetxprint(int, struct sockaddr_in6 , int, const char *, int);
|
|
|
|
/*
|
|
* Print a summary of TCP connections
|
|
* Listening processes are suppressed unless the
|
|
* -a (all) flag is specified.
|
|
*/
|
|
const char *tcpxstates[] = {
|
|
"",
|
|
"CLOSED",
|
|
"LISTEN",
|
|
"SYNSENT",
|
|
"SYNRECEIVED",
|
|
"ESTABLISHED",
|
|
"FINWAIT1",
|
|
"FINWAIT2",
|
|
"CLOSEWAIT",
|
|
"LASTACK",
|
|
"CLOSING",
|
|
"TIMEWAIT"
|
|
};
|
|
#define TCP_NSTATES 11
|
|
|
|
typedef struct {
|
|
int stat;
|
|
int hcstat;
|
|
const char *str;
|
|
} systemstats_t;
|
|
|
|
systemstats_t systemstats[] = {
|
|
{ 3, 4, "datagrams input" },
|
|
{ 5, 6, "octets received" },
|
|
{ 7, 0, "hdr errors input" },
|
|
{ 8, 0, "no routes input" },
|
|
{ 9, 0, "address errors input" },
|
|
{ 10, 0, "unknown protocol input" },
|
|
{ 12, 13, "input datagrams forwarded" },
|
|
{ 11, 0, "truncated datagrams input" },
|
|
{ 14, 0, "input reassembly required" },
|
|
{ 15, 0, "input reassemled OK" },
|
|
{ 16, 0, "input reassembly failed" },
|
|
{ 17, 0, "input datagrams discarded" },
|
|
{ 18, 19, "input datagrams received" },
|
|
{ 20, 21, "output datagram requests" },
|
|
{ 22, 0, "output no route" },
|
|
{ 23, 24, "datagrams forwarded" },
|
|
{ 25, 0, "output datagrams discarded" },
|
|
{ 26, 0, "output datagrams fragmentation required" },
|
|
{ 27, 0, "output datagrams fragmented" },
|
|
{ 28, 0, "output fragmentation failed" },
|
|
{ 29, 0, "fragments created" },
|
|
{ 30, 31, "datagrams transmitted" },
|
|
{ 32, 33, "octets transmitted" },
|
|
{ 0 }
|
|
};
|
|
|
|
systemstats_t icmpstats[] = {
|
|
{ 2, 0, "input messages" },
|
|
{ 3, 0, "input errors" },
|
|
{ 4, 0, "output messages" },
|
|
{ 5, 0, "output errors" },
|
|
{ 0 }
|
|
};
|
|
|
|
typedef struct {
|
|
int code;
|
|
const char *name;
|
|
} codelist_t;
|
|
|
|
codelist_t icmpcodes[] = {
|
|
{ 0, "Echo reply" },
|
|
{ 3, "Destination unreachable" },
|
|
{ 4, "Source quench" },
|
|
{ 5, "Redirect" },
|
|
{ 6, "Alternate host address" },
|
|
{ 8, "Echo request" },
|
|
{ 9, "Router advertisement" },
|
|
{ 10, "Router selection" },
|
|
{ 11, "Time exceeded" },
|
|
{ 12, "Parameter problem" },
|
|
{ 13, "Timestamp request" },
|
|
{ 14, "Timestamp reply" },
|
|
{ 15, "Information request" },
|
|
{ 16, "Information reply" },
|
|
{ 17, "Address mask request" },
|
|
{ 18, "Address mask reply" },
|
|
{ 0 }
|
|
};
|
|
|
|
codelist_t icmp6codes[] = {
|
|
{ 1, "Destination Unreachable" },
|
|
{ 2, "Packet Too Big" },
|
|
{ 3, "Time Exceeded" },
|
|
{ 4, "Parameter Problem" },
|
|
{ 100, "Private experimentation 100" },
|
|
{ 101, "Private experimentation 101" },
|
|
{ 127, "Reserved for expansion of ICMPv6 error messages" },
|
|
{ 128, "Echo Request" },
|
|
{ 129, "Echo Reply" },
|
|
{ 130, "Multicast Listener Query" },
|
|
{ 131, "Multicast Listener Report" },
|
|
{ 132, "Multicast Listener Done" },
|
|
{ 133, "Router Solicitation" },
|
|
{ 134, "Router Advertisement" },
|
|
{ 135, "Neighbor Solicitation" },
|
|
{ 136, "Neighbor Advertisement" },
|
|
{ 137, "Redirect Message" },
|
|
{ 138, "Router Renumbering" },
|
|
{ 139, "ICMP Node Information Query" },
|
|
{ 140, "ICMP Node Information Response" },
|
|
{ 141, "Inverse Neighbor Discovery Solicitation Message" },
|
|
{ 142, "Inverse Neighbor Discovery Advertisement Message" },
|
|
{ 143, "Version 2 Multicast Listener Report" },
|
|
{ 144, "Home Agent Address Discovery Request Message" },
|
|
{ 145, "Home Agent Address Discovery Reply Message" },
|
|
{ 146, "Mobile Prefix Solicitation" },
|
|
{ 147, "Mobile Prefix Advertisement" },
|
|
{ 148, "Certification Path Solicitation Message" },
|
|
{ 149, "Certification Path Advertisement Message" },
|
|
{ 151, "Multicast Router Advertisement" },
|
|
{ 152, "Multicast Router Solicitation" },
|
|
{ 153, "Multicast Router Termination" },
|
|
{ 154, "FMIPv6 Messages" },
|
|
{ 155, "RPL Control Message" },
|
|
{ 0 }
|
|
};
|
|
|
|
|
|
void
|
|
tcpxprotopr(const char *name)
|
|
{
|
|
netsnmp_variable_list *var, *vp, *pvar;
|
|
oid tcpConnectionState_oid[] = { 1,3,6,1,2,1,6,19,1,7 };
|
|
size_t tcpConnectionState_len = OID_LENGTH( tcpConnectionState_oid );
|
|
int state, i;
|
|
struct sockaddr_in6 localAddr, remoteAddr;
|
|
int localPort, remotePort, pid = 0;
|
|
int localType, remoteType, inx;
|
|
int first = 1;
|
|
static int done = 0;
|
|
|
|
if (done++) return;
|
|
|
|
/*
|
|
* Walking the v6 tcpConnectionState column will provide all
|
|
* the necessary information.
|
|
*/
|
|
var = NULL;
|
|
snmp_varlist_add_variable( &var, tcpConnectionState_oid,
|
|
tcpConnectionState_len,
|
|
ASN_NULL, NULL, 0);
|
|
if (netsnmp_query_walk( var, ss ) != SNMP_ERR_NOERROR) {
|
|
snmp_free_varbind(var);
|
|
return;
|
|
}
|
|
if ((var->type & 0xF0) == 0x80) { /* Exception */
|
|
snmp_free_varbind(var);
|
|
return;
|
|
}
|
|
|
|
for (vp = var; vp ; vp=vp->next_variable) {
|
|
char lname[5];
|
|
state = *vp->val.integer;
|
|
inx = tcpConnectionState_len;
|
|
pvar = NULL;
|
|
|
|
vp->name[inx-1] = 8;
|
|
snmp_varlist_add_variable( &pvar, vp->name, vp->name_length,
|
|
ASN_NULL, NULL, 0);
|
|
if (netsnmp_query_get( pvar, ss ) != SNMP_ERR_NOERROR) {
|
|
snmp_free_var( pvar );
|
|
return;
|
|
}
|
|
if ((pvar->type & 0xF0) != 0x80) /* Exception */
|
|
pid = *pvar->val.integer;
|
|
|
|
/* Extract the local/remote information from the index values */
|
|
localType = vp->name[inx++];
|
|
for (i = 0; i < vp->name[inx]; i++)
|
|
localAddr.sin6_addr.s6_addr[i] = vp->name[inx+i+1];
|
|
inx += vp->name[inx] + 1;
|
|
localPort = vp->name[inx++];
|
|
remoteType = vp->name[inx++];
|
|
for (i = 0; i < vp->name[inx]; i++)
|
|
remoteAddr.sin6_addr.s6_addr[i] = vp->name[inx+i+1];
|
|
inx += vp->name[inx] + 1;
|
|
remotePort = vp->name[inx++];
|
|
|
|
snmp_free_varbind(pvar);
|
|
|
|
if (af == AF_INET && localType == 2) continue;
|
|
if (af == AF_INET6 && localType != 2) continue;
|
|
|
|
if (first) {
|
|
printf("Active Internet (%s) Connections", "tcp");
|
|
putchar('\n');
|
|
printf("%-5.5s %-27.27s %-27.27s %11.11s %5.5s\n",
|
|
"Proto", "Local Address", "Remote Address", "State", "PID");
|
|
first = 0;
|
|
}
|
|
|
|
strcpy(lname, "tcp");
|
|
if (localType == 2) lname[3] = '6';
|
|
else lname[3] = '4';
|
|
lname[4] = 0;
|
|
printf("%-5.5s", lname);
|
|
inetxprint(localType, localAddr, localPort, "tcp", 1);
|
|
inetxprint(remoteType, remoteAddr, remotePort, "tcp", 0);
|
|
if ( state < 1 || state > TCP_NSTATES )
|
|
printf(" %11d %5d\n", state, pid);
|
|
else
|
|
printf(" %11s %5d\n", tcpxstates[ state ], pid);
|
|
}
|
|
snmp_free_varbind( var );
|
|
|
|
if (aflag)
|
|
listenxprotopr(name);
|
|
}
|
|
|
|
/*
|
|
* Print a summary of listening "connections"
|
|
*/
|
|
void
|
|
listenxprotopr(const char *name)
|
|
{
|
|
netsnmp_variable_list *var, *vp;
|
|
oid tcpListenerProcess_oid[] = { 1,3,6,1,2,1,6,20,1,4 };
|
|
size_t tcpListenerProcess_len = OID_LENGTH( tcpListenerProcess_oid );
|
|
struct sockaddr_in6 localAddr;
|
|
int localType, localPort, pid;
|
|
int i, inx;
|
|
|
|
/*
|
|
* Walking a single column of the udpTable will provide
|
|
* all the necessary information from the index values.
|
|
*/
|
|
var = NULL;
|
|
snmp_varlist_add_variable( &var, tcpListenerProcess_oid,
|
|
tcpListenerProcess_len,
|
|
ASN_NULL, NULL, 0);
|
|
if (netsnmp_query_walk( var, ss ) != SNMP_ERR_NOERROR)
|
|
return;
|
|
if ((var->type & 0xF0) == 0x80) /* Exception */
|
|
return;
|
|
|
|
printf("Listening Internet (%s) Connections\n", "tcp");
|
|
printf("%-5.5s %-27.27s %5s\n", "Proto", "Local Address", "PID");
|
|
for (vp = var; vp ; vp=vp->next_variable) {
|
|
char lname[5];
|
|
inx = tcpListenerProcess_len;
|
|
/*
|
|
* 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)
|
|
*/
|
|
localType = vp->name[inx++];
|
|
if (af == AF_INET && localType == 2) continue;
|
|
if (af == AF_INET6 && localType != 2) continue;
|
|
|
|
for (i = 0; i < vp->name[inx]; i++)
|
|
localAddr.sin6_addr.s6_addr[i] = vp->name[inx+i+1];
|
|
inx += vp->name[inx]+1;
|
|
localPort = vp->name[ inx++ ];
|
|
pid = *vp->val.integer;
|
|
strcpy(lname, "tcp");
|
|
if (localType == 2) lname[3] = '6';
|
|
else lname[3] = '4';
|
|
lname[4] = 0;
|
|
printf("%-5.5s", lname);
|
|
inetxprint(localType, localAddr, localPort, "tcp", 1);
|
|
printf(" %5d\n", pid);
|
|
}
|
|
snmp_free_varbind( var );
|
|
}
|
|
|
|
/*
|
|
* Print a summary of UDPv6 "connections"
|
|
* XXX - what about "listening" services ??
|
|
*/
|
|
void
|
|
udpxprotopr(const char *name)
|
|
{
|
|
netsnmp_variable_list *var, *vp;
|
|
oid udpEndpointProcess_oid[] = { 1,3,6,1,2,1,7,7,1,8 };
|
|
size_t udpEndpointProcess_len = OID_LENGTH( udpEndpointProcess_oid );
|
|
struct sockaddr_in6 localAddr, remoteAddr;
|
|
int localType, remoteType, localPort, remotePort, pid;
|
|
int i, inx;
|
|
static int done = 0;
|
|
|
|
if (done++) return;
|
|
|
|
/*
|
|
* Walking a single column of the udpTable will provide
|
|
* all the necessary information from the index values.
|
|
*/
|
|
var = NULL;
|
|
snmp_varlist_add_variable( &var, udpEndpointProcess_oid,
|
|
udpEndpointProcess_len,
|
|
ASN_NULL, NULL, 0);
|
|
if (netsnmp_query_walk( var, ss ) != SNMP_ERR_NOERROR) {
|
|
snmp_free_varbind(var);
|
|
return;
|
|
}
|
|
if ((var->type & 0xF0) == 0x80) { /* Exception */
|
|
snmp_free_varbind(var);
|
|
return;
|
|
}
|
|
|
|
printf("Active Internet (%s) Connections\n", "udp");
|
|
printf("%-5.5s %-27.27s %-27.27s %5s\n", "Proto", "Local Address", "Remote Address", "PID");
|
|
for (vp = var; vp ; vp=vp->next_variable) {
|
|
char lname[5];
|
|
inx = udpEndpointProcess_len;
|
|
/*
|
|
* 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)
|
|
*/
|
|
localType = vp->name[inx++];
|
|
if (af == AF_INET && localType == 2) continue;
|
|
if (af == AF_INET6 && localType != 2) continue;
|
|
for (i = 0; i < vp->name[inx]; i++)
|
|
localAddr.sin6_addr.s6_addr[i] = vp->name[inx+i+1];
|
|
inx += vp->name[inx]+1;
|
|
localPort = vp->name[ inx++ ];
|
|
remoteType = vp->name[inx++];
|
|
for (i = 0; i < vp->name[inx]; i++)
|
|
remoteAddr.sin6_addr.s6_addr[i] = vp->name[inx+i+1];
|
|
inx += vp->name[inx]+1;
|
|
remotePort = vp->name[ inx++ ];
|
|
pid = *vp->val.integer;
|
|
strcpy(lname, "udp");
|
|
if (localType == 2) lname[3] = '6';
|
|
else lname[3] = '4';
|
|
lname[4] = 0;
|
|
printf("%-5.5s", lname);
|
|
inetxprint(localType, localAddr, localPort, "udp", 1);
|
|
inetxprint(remoteType, remoteAddr, remotePort, "udp", 1);
|
|
printf(" %5d\n", pid);
|
|
}
|
|
snmp_free_varbind( var );
|
|
}
|
|
|
|
static void
|
|
statsprint(const char *name, const systemstats_t *st, int proto,
|
|
const oid *tbl, size_t tbllen)
|
|
{
|
|
oid var[32];
|
|
size_t len;
|
|
netsnmp_variable_list *vb;
|
|
|
|
memcpy(var, tbl, tbllen*sizeof(oid));
|
|
var[tbllen+1] = proto;
|
|
len = tbllen+2;
|
|
|
|
printf("%s:\n", name);
|
|
while (st->stat) {
|
|
vb = NULL;
|
|
if (st->hcstat) {
|
|
var[tbllen] = st->hcstat;
|
|
snmp_varlist_add_variable( &vb, var, len, ASN_NULL, NULL, 0);
|
|
if (netsnmp_query_get( vb, ss ) != SNMP_ERR_NOERROR) {
|
|
snmp_free_var( vb );
|
|
vb = NULL;
|
|
}
|
|
}
|
|
if (!vb) {
|
|
var[tbllen] = st->stat;
|
|
snmp_varlist_add_variable( &vb, var, len, ASN_NULL, NULL, 0);
|
|
if (netsnmp_query_get( vb, ss ) != SNMP_ERR_NOERROR) {
|
|
snmp_free_var( vb );
|
|
vb = NULL;
|
|
}
|
|
}
|
|
if (vb) {
|
|
if (vb->type == ASN_COUNTER) {
|
|
if (*vb->val.integer > 0 || sflag == 1)
|
|
printf("%14lu %s\n", *vb->val.integer, st->str);
|
|
}
|
|
else if (vb->type == ASN_COUNTER64) {
|
|
char a64buf[I64CHARSZ + 1];
|
|
printU64(a64buf, vb->val.counter64);
|
|
if (strcmp(a64buf, "0") != 0 || sflag == 1)
|
|
printf("%14s %s\n", a64buf, st->str);
|
|
}
|
|
else
|
|
printf("%14s %s\n", "-", st->str);
|
|
snmp_free_varbind(vb);
|
|
}
|
|
else {
|
|
printf("%14s %s\n", "-", st->str);
|
|
}
|
|
st++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
prhisto(const char *name, const oid *var, size_t len, int ver, codelist_t *cs)
|
|
{
|
|
netsnmp_variable_list *vb = NULL, *vp;
|
|
codelist_t *cp;
|
|
int code;
|
|
char nocode[32];
|
|
|
|
snmp_varlist_add_variable( &vb, var, len, ASN_NULL, NULL, 0);
|
|
if (netsnmp_query_walk( vb, ss ) != SNMP_ERR_NOERROR) {
|
|
snmp_free_var( vb );
|
|
return;
|
|
}
|
|
printf(" %s histogram:\n", name);
|
|
printf(" %10s %10s %s\n", "input", "output", "type");
|
|
for (code = 0; code < 256; code++) {
|
|
unsigned long inp = 0, out = 0;
|
|
int found = 0;
|
|
vp = vb;
|
|
while (vp && found != 2) {
|
|
if (vp->name[11] == code && vp->name[10] == ver) {
|
|
if (vp->name[9] == 3) inp = *vp->val.integer;
|
|
else out = *vp->val.integer;
|
|
found++;
|
|
}
|
|
vp = vp->next_variable;
|
|
}
|
|
if (found) {
|
|
cp = cs;
|
|
while (cp->name && cp->code != code) cp++;
|
|
if (inp || out || sflag == 1) {
|
|
if (!cp->code)
|
|
snprintf(nocode, sizeof nocode, "type %d", code);
|
|
printf(" %10lu %10lu %s\n", inp, out, cp->name ? cp->name : nocode);
|
|
}
|
|
}
|
|
}
|
|
snmp_free_varbind(vb);
|
|
}
|
|
|
|
void
|
|
ipx_stats(const char *name)
|
|
{
|
|
oid ipsysstat_oid[] = { 1, 3, 6, 1, 2, 1, 4, 31, 1, 1 };
|
|
size_t ipsysstat_len = sizeof(ipsysstat_oid) / sizeof(ipsysstat_oid[0]);
|
|
static int first = 1;
|
|
|
|
if (!first) return;
|
|
first = 0;
|
|
|
|
if (!name || strcmp(name, "ip") == 0)
|
|
statsprint("ip", systemstats, 1, ipsysstat_oid, ipsysstat_len);
|
|
if (!name || strcmp(name, "ip6") == 0)
|
|
statsprint("ip6", systemstats, 2, ipsysstat_oid, ipsysstat_len);
|
|
}
|
|
|
|
void
|
|
icmpx_stats(const char *name)
|
|
{
|
|
oid icmpstat_oid[] = { 1, 3, 6, 1, 2, 1, 5, 29, 1 };
|
|
size_t icmpstat_len = sizeof(icmpstat_oid) / sizeof(icmpstat_oid[0]);
|
|
oid icmpmsg_oid[] = { 1, 3, 6, 1, 2, 1, 5, 30, 1 };
|
|
size_t icmpmsg_len = sizeof(icmpmsg_oid) / sizeof(icmpmsg_oid[0]);
|
|
static int first = 1;
|
|
|
|
if (!first)
|
|
return;
|
|
first = 0;
|
|
|
|
if (!name || strcmp(name, "icmp") == 0) {
|
|
statsprint("icmp", icmpstats, 1, icmpstat_oid, icmpstat_len);
|
|
prhisto("icmp", icmpmsg_oid, icmpmsg_len, 1, icmpcodes);
|
|
}
|
|
if (!name || strcmp(name, "icmp6") == 0) {
|
|
statsprint("icmp6", icmpstats, 2, icmpstat_oid, icmpstat_len);
|
|
prhisto("icmp6", icmpmsg_oid, icmpmsg_len, 2, icmp6codes);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
unknownprint(void)
|
|
{
|
|
char line[80], *cp;
|
|
int width = 27;
|
|
|
|
if (vflag)
|
|
snprintf(line, sizeof line, "%s.", "*");
|
|
else
|
|
snprintf(line, sizeof line, "%.*s.", width-9, "*");
|
|
cp = strchr(line, '\0');
|
|
snprintf(cp, line + sizeof line - cp, vflag ? "%s" : "%.8s", "*");
|
|
if (vflag && width < strlen(line))
|
|
width = strlen(line);
|
|
printf(" %-*.*s", width, width, line);
|
|
}
|
|
|
|
/*
|
|
* Pretty print an Internet address (net address + port).
|
|
* If the nflag was specified, use numbers instead of names.
|
|
*/
|
|
|
|
void
|
|
inetxprint(int proto, struct sockaddr_in6 in6, int port, const char *name, int local)
|
|
{
|
|
|
|
if (proto == 2)
|
|
inet6print((u_char *)&in6.sin6_addr.s6_addr, port, name, local);
|
|
else if (proto == 1)
|
|
inetprint((struct in_addr *)&in6.sin6_addr.s6_addr, port, name, local);
|
|
else if (proto == 0)
|
|
unknownprint();
|
|
else abort();
|
|
}
|