📄 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 "config.h"#include "snmp_alarm.h"#include "callback.h"#include "default_store.h"#include "asn1.h"#include "snmp.h"#include "snmp_debug.h"#include "snmp_api.h"#include "snmp_impl.h"#include "snmp_vars.h"#include "var_struct.h"#include "agent_read_config.h"#include "tools.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/* This is used, because the TUNNEL-MIB augments ifTable. */extern unsigned char *var_ifEntry(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **);/* * 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;void deinit_tunnel(void){ unregister_sysORTable(sysORTable_reg, sysORTable_reglen);}int term_tunnel(int majorID, int minorID, void *serverarg, void *clientarg){ deinit_tunnel(); return 0;}void init_tunnel(void){ register_sysORTable(sysORTable_reg, sysORTable_reglen, "RFC 2667 TUNNEL-MIB implementation for " "Linux 2.2.x kernels."); ds_set_string(DS_LIBRARY_ID, DS_LIB_APPTYPE, "snmpd"); /* 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 int getType(int index){ 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;}static char *getName(int index){ 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;}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;}int setTunnelParm(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 { 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 void updateTunnels(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->ifname); 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; DEBUGMSG(("tunnel", "getNextTunnelByIfIndex(%d): ", index)); for (tunnel = tunnels; tunnel; tunnel = tunnel->next) { if (tunnel->ifindex > index) { if (!tunnel->active) continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -