📄 tunnel.c
字号:
/* * tunnel.c -- * * An implementation of the TUNNEL-MIB for the UCD-SNMP 4.2 * agent running on Linux 2.2.x. * * Copyright (c) 2000 Frank Strauss <strauss@ibr.cs.tu-bs.de> * * All Rights Reserved * * Permission to use, copy, modify and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies and * that both that copyright notice and this permission notice appear in * supporting documentation, and that the name of the author and CMU and * The Regents of the University of California not be used in advertising * or publicity pertaining to distribution of the software without * specific written permission. * * THE AUTHOR AND CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA * DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * THE AUTHOR OR CMU OR THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY * DAMAGES WHATSOEVER RESULTING FROM THE LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * *//* * NOTE: This TUNNEL-MIB implementation * * (a) DOES NOT implement write access on the tunnelConfigTable, * i.e. no new tunnels can be created and no existing tunnels * can be removed through SET operations. * * (b) DOES implement write access on some tunnelIfTable objects * to allow reconfiguring established tunnels. This violates * RFC 2667! However, the author thinks it makes sense. ;-) */#include <string.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/ioctl.h>#include <signal.h>#include <netinet/in.h>#include <arpa/inet.h>#include <linux/if.h>#include <linux/ip.h>#include <linux/sockios.h>#include <linux/if_tunnel.h>#include <linux/if_arp.h>#include <net-snmp/net-snmp-config.h>#include <net-snmp/net-snmp-includes.h>#include <net-snmp/agent/net-snmp-agent-includes.h>#include "util_funcs.h"#include "tunnel.h"#ifndef MIN#define MIN(a, b) (((a) < (b)) ? (a) : (b))#endif#ifndef MAX#define MAX(a, b) (((a) > (b)) ? (a) : (b))#endif#ifdef USING_IF_MIB_IFTABLE_IFTABLE_MODULE#include "if-mib/ifTable/ifTable.h"#include "if-mib/ifTable/ifTable_defs.h"#else/* * This is used, because the TUNNEL-MIB augments ifTable. */extern unsigned char *var_ifEntry(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **);#endif/* * tunnel_variables_oid: * this is the top level oid that we want to register under. This * is essentially a prefix, with the suffix appearing in the * variable below. */oid tunnel_variables_oid[] = { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1 };const int tunnel_len = 10;oid tunnel_ifEntry_oid[] = { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1, 1, 1 };const int tunnel_ifEntry_len = 12;oid tunnel_configEntry_oid[] = { 1, 3, 6, 1, 2, 1, 10, 131, 1, 1, 2, 1 };const int tunnel_configEntry_len = 12;struct tunnel { oid ifindex; int id; char *ifname; int active; unsigned long local; unsigned long remote; int encaps; int hoplimit; int security; int tos; oid config_name[MAX_OID_LEN]; size_t config_length; struct tunnel *next;};/* * variable4 tunnel_variables: * this variable defines function callbacks and type return information * for the tunnel mib section */struct variable4 tunnel_variables[] = { /* * magic number , variable type , ro/rw , callback fn , L, oidsuffix */#define LOCALADDRESS 1 {LOCALADDRESS, ASN_IPADDRESS, RWRITE, var_tunnelIfEntry, 3, {1, 1, 1}},#define REMOTEADDRESS 2 {REMOTEADDRESS, ASN_IPADDRESS, RWRITE, var_tunnelIfEntry, 3, {1, 1, 2}},#define ENCAPSMETHOD 3 {ENCAPSMETHOD, ASN_INTEGER, RONLY, var_tunnelIfEntry, 3, {1, 1, 3}},#define HOPLIMIT 4 {HOPLIMIT, ASN_INTEGER, RWRITE, var_tunnelIfEntry, 3, {1, 1, 4}},#define SECURITY 5 {SECURITY, ASN_INTEGER, RONLY, var_tunnelIfEntry, 3, {1, 1, 5}},#define TOS 6 {TOS, ASN_INTEGER, RWRITE, var_tunnelIfEntry, 3, {1, 1, 6}},#define IFINDEX 7 {IFINDEX, ASN_INTEGER, RONLY, var_tunnelConfigEntry, 3, {2, 1, 5}},#define ROWSTATUS 8 {ROWSTATUS, ASN_INTEGER, RWRITE, var_tunnelConfigEntry, 3, {2, 1, 6}},};extern int register_sysORTable(oid *, size_t, const char *);extern int unregister_sysORTable(oid *, size_t);static oid sysORTable_reg[] = { 1, 3, 6, 1, 2, 1, 10, 131 };static size_t sysORTable_reglen = 8;static struct tunnel *tunnels;voiddeinit_tunnel(void){ unregister_sysORTable(sysORTable_reg, sysORTable_reglen);}intterm_tunnel(int majorID, int minorID, void *serverarg, void *clientarg){ deinit_tunnel(); return 0;}voidinit_tunnel(void){ register_sysORTable(sysORTable_reg, sysORTable_reglen, "RFC 2667 TUNNEL-MIB implementation for " "Linux 2.2.x kernels."); /* * register ourselves with the agent to handle our mib tree */ REGISTER_MIB("tunnel", tunnel_variables, variable4, tunnel_variables_oid); snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN, term_tunnel, NULL); tunnels = NULL;}static intgetType(int index){#ifndef USING_IF_MIB_IFTABLE_IFTABLE_MODULE oid name[MAX_OID_LEN] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 }; size_t length = 10; struct variable ifType_variable = { 3, ASN_INTEGER, RONLY, var_ifEntry, 10, {1, 3, 6, 1, 2, 1, 2, 2, 1, 3} }; unsigned char *p; size_t var_len; WriteMethod *write_method; name[length] = index; length++; p = var_ifEntry(&ifType_variable, name, &length, 1 /* exact */ , &var_len, &write_method); if (!p) return 0; return *(int *) p;#else ifTable_mib_index imi; ifTable_rowreq_ctx *rr; imi.ifIndex = index; rr = ifTable_row_find_by_mib_index(&imi); if (NULL == rr) return 0; return rr->data.ifType;#endif}static char *getName(int index){#ifndef USING_IF_MIB_IFTABLE_IFTABLE_MODULE oid name[MAX_OID_LEN] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 2 }; size_t length = 10; struct variable ifName_variable = { 2, ASN_INTEGER, RONLY, var_ifEntry, 10, {1, 3, 6, 1, 2, 1, 2, 2, 1, 2} }; unsigned char *p; size_t var_len; WriteMethod *write_method; name[length] = index; length++; p = var_ifEntry(&ifName_variable, name, &length, 1 /* exact */ , &var_len, &write_method); if (!p) return NULL; return p;#else return netsnmp_access_interface_name_find(index);#endif}static struct ip_tunnel_parm *getTunnelParm(char *ifname){ struct ifreq ifrq; int fd; static struct ip_tunnel_parm parm; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { return NULL; } memset(&parm, 0, sizeof(struct ip_tunnel_parm)); strcpy(ifrq.ifr_name, ifname); ifrq.ifr_ifru.ifru_data = (void *) &parm; if (ioctl(fd, SIOCGETTUNNEL, &ifrq) < 0) { /* * try again with the last char of the device name cut off. * it might have been a zero digit appended by the agent. */ ifrq.ifr_name[strlen(ifrq.ifr_name) - 1] = 0; if (ioctl(fd, SIOCGETTUNNEL, &ifrq) < 0) { close(fd); return NULL; } ifname[strlen(ifname) - 1] = 0; } close(fd); return &parm;}intsetTunnelParm(char *ifname, struct ip_tunnel_parm *parm){ struct ifreq ifrq; int fd; int err; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { return -1; } strcpy(ifrq.ifr_name, ifname); ifrq.ifr_ifru.ifru_data = (void *) parm; err = ioctl(fd, SIOCCHGTUNNEL, &ifrq); close(fd); return err;}/* * update a struct tunnel. its index and ifname elements have to be set. */static struct tunnel *updateTunnel(struct tunnel *tunnel){ struct ip_tunnel_parm *parm; int fd; struct ifreq ifrq; /* * NOTE: getTunnelParm() may adjust the passed ifname. */ parm = getTunnelParm(tunnel->ifname); if (!parm) { DEBUGMSGTL(("tunnel", "updateTunnel(): getTunnelParm(\"%s\") returned NULL\n", tunnel->ifname)); tunnel->active = 0; return NULL; } tunnel->active = 1; tunnel->local = parm->iph.saddr; tunnel->remote = parm->iph.daddr; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { DEBUGMSGTL(("snmpd", "socket open failure in updateTunnels()\n")); return NULL; } else { /* * NOTE: this ioctl does not guarantee 6 bytes of a physaddr. * In particular, a 'sit0' interface only appears to get back * 4 bytes of sa_data. We don't use sa_data here, or we'd * need to memset it to 0 before the ioct. */ strcpy(ifrq.ifr_name, tunnel->ifname); if (ioctl(fd, SIOCGIFHWADDR, &ifrq) == 0) switch (ifrq.ifr_hwaddr.sa_family) { case ARPHRD_TUNNEL: tunnel->encaps = 2; break;; /* direct */ case ARPHRD_TUNNEL6: tunnel->encaps = 2; break;; /* direct */ case ARPHRD_IPGRE: tunnel->encaps = 3; break;; /* gre */ case ARPHRD_SIT: tunnel->encaps = 2; break;; /* direct */ default: tunnel->encaps = 1; /* other */ } close(fd); } tunnel->hoplimit = parm->iph.ttl; tunnel->security = 1; tunnel->tos = (parm->iph.tos & 1) ? -1 : parm->iph.tos; /* * XXX: adjust tos mapping (kernel <-> TUNNEL-MIB::tunnelIfTOS) */ return tunnel;}static voidupdateTunnels(void){ static int max_index = 1; static struct tunnel *last_tunnel = NULL; struct tunnel *tunnel; char *ifname; int type; /* * uptime the tunnels we have so far */ for (tunnel = tunnels; tunnel; tunnel = tunnel->next) { DEBUGMSG(("tunnel", "updateTunnels(): updating %s (index=%d)\n", tunnel->ifname, tunnel->ifindex)); updateTunnel(tunnel); } /* * look for new tunnels */ for (; max_index < 256; max_index++) { DEBUGMSG(("tunnel", "updateTunnels(): looking for new index=%d\n", max_index)); type = getType(max_index); if (type == 131) { tunnel = (struct tunnel *) malloc(sizeof(struct tunnel)); if (!tunnel) continue; tunnel->ifindex = max_index; tunnel->id = 1; ifname = getName(max_index); if (!ifname) { free(tunnel); continue; } tunnel->ifname = strdup(ifname); if (!tunnel->ifname) { free(tunnel); continue; } if (!updateTunnel(tunnel)) { free(tunnel); continue; } if (last_tunnel) last_tunnel->next = tunnel; if (!tunnels) tunnels = last_tunnel = tunnel; tunnel->next = NULL; last_tunnel = tunnel; DEBUGMSG(("tunnel", "updateTunnels(): added %s (index=%d state=%d)\n", tunnel->ifname, tunnel->ifindex, tunnel->active)); } if (type == 0) break; }}static struct tunnel *getTunnelByIfIndex(int index){ struct tunnel *tunnel; DEBUGMSG(("tunnel", "getTunnelByIfIndex(%d): ", index)); for (tunnel = tunnels; tunnel; tunnel = tunnel->next) { if (tunnel->ifindex == index) { if (!tunnel->active) break; DEBUGMSG(("tunnel", "%s (index=%d)\n", tunnel->ifname, tunnel->ifindex)); return tunnel; } } DEBUGMSG(("tunnel", "NONE\n")); return NULL;}static struct tunnel *getNextTunnelByIfIndex(int index){ struct tunnel *tunnel;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -