📄 if.c
字号:
/* $OpenBSD: if.c,v 1.42 2005/03/13 16:05:50 mpf Exp $ *//* $NetBSD: if.c,v 1.16.4.2 1996/06/07 21:46:46 thorpej 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 0static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94";#elsestatic char *rcsid = "$OpenBSD: if.c,v 1.42 2005/03/13 16:05:50 mpf Exp $";#endif#endif /* not lint */#endif#include <net-snmp/net-snmp-config.h>#include <net-snmp/net-snmp-includes.h>#if HAVE_UNISTD_H#include <unistd.h>#endif#if HAVE_NET_IF_H#include <net/if.h>#endif#define __USE_XOPEN#define __USE_XOPEN_EXTENDED#include <signal.h>#include "main.h"#include "netstat.h"#define YES 1#define NO 0static void sidewaysintpr(u_int);static void timerSet(int interval_seconds);static void timerPause(void); struct _if_info { char name[128]; char ip[128], route[128]; int mtu; int drops; int ifindex; /* * Save "expandable" fields as string values * rather than integer statistics */ char s_ipkts[20], s_ierrs[20]; char s_opkts[20], s_oerrs[20]; char s_ibytes[20], s_obytes[20]; char s_outq[20]; unsigned long ipkts, opkts; /* Need to combine 2 MIB values */ int operstatus;/* u_long netmask; struct in_addr ifip, ifroute; */ struct _if_info *next; };/* * Retrieve the interface addressing information * XXX - This could also be extended to handle non-IP interfaces */void_set_address( struct _if_info *cur_if ){ oid ipaddr_oid[] = { 1,3,6,1,2,1,4,20,1,0 }; size_t ipaddr_len = OID_LENGTH( ipaddr_oid ); static netsnmp_variable_list *addr_if_var =NULL; static netsnmp_variable_list *addr_mask_var=NULL; netsnmp_variable_list *vp, *vp2; union { in_addr_t addr; char data[4]; } tmpAddr; char *cp; in_addr_t ifAddr, mask; /* * Note that this information only needs to be retrieved * once, and can be re-used for subsequent calls. */ if ( addr_if_var == NULL ) { ipaddr_oid[ 9 ] = 2; /* ipAdEntIfIndex */ snmp_varlist_add_variable( &addr_if_var, ipaddr_oid, ipaddr_len, ASN_NULL, NULL, 0); netsnmp_query_walk( addr_if_var, ss ); ipaddr_oid[ 9 ] = 3; /* ipAdEntNetMask */ snmp_varlist_add_variable( &addr_mask_var, ipaddr_oid, ipaddr_len, ASN_NULL, NULL, 0); netsnmp_query_walk( addr_mask_var, ss ); } /* * Find the address row relevant to this interface */ for (vp=addr_if_var, vp2=addr_mask_var; vp; vp=vp->next_variable, vp2=vp2->next_variable) { if ( vp->val.integer && *vp->val.integer == cur_if->ifindex ) break; } if (vp2) { /* * Always want a numeric interface IP address */ snprintf( cur_if->ip, 128, "%lu.%lu.%lu.%lu", vp2->name[10], vp2->name[11], vp2->name[12], vp2->name[13]); /* * But re-use the routing table utilities/code for * displaying the local network information */ cp = tmpAddr.data; cp[0] = vp2->name[ 10 ] & 0xff; cp[1] = vp2->name[ 11 ] & 0xff; cp[2] = vp2->name[ 12 ] & 0xff; cp[3] = vp2->name[ 13 ] & 0xff; ifAddr = tmpAddr.addr; cp = tmpAddr.data; cp[0] = vp2->val.string[ 0 ] & 0xff; cp[1] = vp2->val.string[ 1 ] & 0xff; cp[2] = vp2->val.string[ 2 ] & 0xff; cp[3] = vp2->val.string[ 3 ] & 0xff; mask = tmpAddr.addr; snprintf( cur_if->route, 128, "%s", netname(ifAddr, mask)); }}/* * Print a description of the network interfaces. */voidintpr(int interval){ oid ifcol_oid[] = { 1,3,6,1,2,1,2,2,1,0 }; size_t ifcol_len = OID_LENGTH( ifcol_oid ); struct _if_info *if_head, *if_tail, *cur_if; netsnmp_variable_list *var, *vp; /* * Track maximum field widths, expanding as necessary * This is one reason why results can't be * displayed immediately they are retrieved. */ int max_name = 4, max_ip = 7, max_route = 7, max_outq = 5; int max_ipkts = 5, max_ierrs = 5, max_opkts = 5, max_oerrs = 5; int max_ibytes = 6, max_obytes = 6; int i; if (interval) { sidewaysintpr((unsigned)interval); return; } /* * The traditional "netstat -i" output combines information * from two SNMP tables: * ipAddrTable (for the IP address/network) * ifTable (for the interface statistics) * * The previous approach was to retrieve (and save) the * address information first. Then walk the main ifTable, * add the relevant stored addresses, and saving the * full information for each interface, before displaying * the results as a separate pass. * * This code reverses this general structure, by first retrieving * (and storing) the interface statistics for the whole table, * then inserting the address information obtained from the * ipAddrTable, and finally displaying the results. * Such an arrangement should make it easier to extend this * to handle non-IP interfaces (hence not in ipAddrTable) */ if_head = NULL; if_tail = NULL; var = NULL;#define ADD_IFVAR( x ) ifcol_oid[ ifcol_len-1 ] = x; \ snmp_varlist_add_variable( &var, ifcol_oid, ifcol_len, ASN_NULL, NULL, 0) ADD_IFVAR( 2 ); /* ifName */ ADD_IFVAR( 4 ); /* ifMtu */ ADD_IFVAR( 8 ); /* ifOperStatus */ /* * The Net/Open-BSD behaviour is to display *either* byte * counts *or* packet/error counts (but not both). FreeBSD * integrates the byte counts into the traditional display. * * The previous 'snmpnetstat' implementation followed the * separatist model. This re-write offers an opportunity * to adopt the (more useful, IMO) Free-BSD approach. * * Or we could perhaps support both styles? :-) */ if (bflag || oflag) { ADD_IFVAR( 10 ); /* ifInOctets */ ADD_IFVAR( 16 ); /* ifOutOctets */ } if (!oflag) { ADD_IFVAR( 11 ); /* ifInUcastPkts */ ADD_IFVAR( 12 ); /* ifInNUcastPkts */ ADD_IFVAR( 14 ); /* ifInErrors */ ADD_IFVAR( 17 ); /* ifOutUcastPkts */ ADD_IFVAR( 18 ); /* ifOutNUcastPkts */ ADD_IFVAR( 20 ); /* ifOutErrors */ ADD_IFVAR( 21 ); /* ifOutQLen */ }#if 0 if (tflag) { ADD_IFVAR( XX ); /* ??? */ }#endif if (dflag) { ADD_IFVAR( 19 ); /* ifOutDiscards */ }#undef ADD_IFVAR /* * Now walk the ifTable, creating a list of interfaces */ while ( 1 ) { if (netsnmp_query_getnext( var, ss ) != SNMP_ERR_NOERROR) break; ifcol_oid[ ifcol_len-1 ] = 2; /* ifDescr */ if ( snmp_oid_compare( ifcol_oid, ifcol_len, var->name, ifcol_len) != 0 ) break; /* End of Table */ cur_if = SNMP_MALLOC_TYPEDEF( struct _if_info ); if (!cur_if) break; cur_if->ifindex = var->name[ var->name_length-1 ]; for ( vp=var; vp; vp=vp->next_variable ) { if ( ! vp->val.integer ) continue; if ( var->name[ var->name_length-1 ] != cur_if->ifindex ) { /* * Inconsistent index information * XXX - Try to recover ? */ SNMP_FREE( cur_if ); cur_if = NULL; break; /* not for now, no */ } switch ( vp->name[ var->name_length-2 ] ) { case 2: /* ifDescr */ if (vp->val_len >= sizeof(cur_if->name)) vp->val_len = sizeof(cur_if->name)-1; memmove( cur_if->name, vp->val.string, vp->val_len ); cur_if->name[vp->val_len] = 0; if ((i = strlen(cur_if->name) + 1) > max_name) max_name = i; break; case 4: /* ifMtu */ cur_if->mtu = *vp->val.integer; break; case 8: /* ifOperStatus */ cur_if->operstatus = *vp->val.integer; /* XXX - any special processing ?? */ break; case 10: /* ifInOctets */ sprintf(cur_if->s_ibytes, "%lu", *vp->val.integer); i = strlen(cur_if->s_ibytes); if (i > max_ibytes) max_ibytes = i; break; case 11: /* ifInUcastPkts */ cur_if->ipkts += *vp->val.integer; sprintf(cur_if->s_ipkts, "%lu", cur_if->ipkts); i = strlen(cur_if->s_ipkts); if (i > max_ipkts) max_ipkts = i; break; case 12: /* ifInNUcastPkts */ cur_if->ipkts += *vp->val.integer; sprintf(cur_if->s_ipkts, "%lu", cur_if->ipkts); i = strlen(cur_if->s_ipkts); if (i > max_ipkts) max_ipkts = i; break; case 14: /* ifInErrors */ sprintf(cur_if->s_ierrs, "%lu", *vp->val.integer); i = strlen(cur_if->s_ierrs); if (i > max_ierrs) max_ierrs = i; break; case 16: /* ifOutOctets */ sprintf(cur_if->s_obytes, "%lu", *vp->val.integer); i = strlen(cur_if->s_obytes); if (i > max_obytes) max_obytes = i; break; case 17: /* ifOutUcastPkts */ cur_if->opkts += *vp->val.integer; sprintf(cur_if->s_opkts, "%lu", cur_if->opkts); i = strlen(cur_if->s_opkts); if (i > max_opkts) max_opkts = i; break; case 18: /* ifOutNUcastPkts */ cur_if->opkts += *vp->val.integer; sprintf(cur_if->s_opkts, "%lu", cur_if->opkts); i = strlen(cur_if->s_opkts); if (i > max_opkts) max_opkts = i; break; case 19: /* ifOutDiscards */ cur_if->drops = *vp->val.integer; break; case 20: /* ifOutErrors */ sprintf(cur_if->s_oerrs, "%lu", *vp->val.integer); i = strlen(cur_if->s_oerrs); if (i > max_oerrs) max_oerrs = i; break; case 21: /* ifOutQLen */ sprintf(cur_if->s_outq, "%lu", *vp->val.integer); i = strlen(cur_if->s_outq); if (i > max_outq) max_outq = i; break; } } /* * XXX - Perhaps query ifXTable for additional info ?? * (ifName/ifAlias, or HC counters) */ /* * If we're to monitor a particular interface, then * ignore all others. It would be more efficient * to check this earlier (as part of processing * the varbind list). But performing this test here * means we can recognise ifXTable names as well) */ if ( intrface && strcmp( cur_if->name, intrface ) != 0) { SNMP_FREE( cur_if ); cur_if = NULL; } /* * Insert the IP address and network settings, and * add the new _if_stat structure to the list. */ if ( cur_if ) { _set_address( cur_if ); i = strlen(cur_if->ip); if (i > max_ip) max_ip = i; i = strlen(cur_if->route); if (i > max_route) max_route = i; if ( if_tail ) { if_tail->next = cur_if; if_tail = cur_if; } else { if_head = cur_if; if_tail = cur_if; } } } /* while (1) */ /* * Now display the specified results (in Free-BSD format) * setting the field widths appropriately.... */ printf("%*.*s %5.5s %*.*s %*.*s", -max_name, max_name, "Name", "Mtu", -max_route, max_route, "Network", -max_ip, max_ip, "Address"); if (oflag) { printf(" %*s %*s", max_ibytes, "Ibytes", max_obytes, "Obytes"); } else { printf(" %*s %*s", max_ipkts, "Ipkts", max_ierrs, "Ierrs"); if (bflag) printf(" %*s", max_ibytes, "Ibytes"); printf(" %*s %*s", max_opkts, "Opkts", max_oerrs, "Oerrs"); if (bflag) printf(" %*s", max_obytes, "Obytes"); printf(" %*s", max_outq, "Queue"); } /* if (tflag) printf(" %s", "Time"); */ if (dflag) printf(" %s", "Drop"); putchar('\n'); for (cur_if = if_head; cur_if; cur_if=cur_if->next) { if (cur_if->name[0] == 0) continue; printf( "%*.*s %5d", -max_name, max_name, cur_if->name, cur_if->mtu); printf(" %*.*s", -max_route, max_route, cur_if->route);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -