diff options
Diffstat (limited to 'agent/mibgroup/mibII/route_write.c')
-rw-r--r-- | agent/mibgroup/mibII/route_write.c | 759 |
1 files changed, 759 insertions, 0 deletions
diff --git a/agent/mibgroup/mibII/route_write.c b/agent/mibgroup/mibII/route_write.c new file mode 100644 index 0000000..6f4d8ca --- /dev/null +++ b/agent/mibgroup/mibII/route_write.c @@ -0,0 +1,759 @@ +/* Portions of this file are subject to the following copyright(s). See + * the Net-SNMP's COPYING file for more details and other copyrights + * that may apply: + */ +/* + * Portions of this file are copyrighted by: + * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms specified in the COPYING file + * distributed with the Net-SNMP package. + */ +#include <net-snmp/net-snmp-config.h> + +#include <sys/types.h> +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if HAVE_SYS_SOCKIO_H +#include <sys/sockio.h> +#endif +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif +#if HAVE_SYS_MBUF_H +#include <sys/mbuf.h> +#endif + + +#if HAVE_SYS_STREAM_H +#include <sys/stream.h> +#endif +#if HAVE_NET_ROUTE_H +#include <net/route.h> +#endif +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#if HAVE_NETDB_H +#include <netdb.h> +#endif + +#include <errno.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdio.h> +#include <ctype.h> +#if HAVE_STRING_H +#include <string.h> +#endif +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#if HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> + +#include "ip.h" +#include "route_write.h" + +#ifdef cygwin +#include <windows.h> +#endif + +#if !defined (WIN32) && !defined (cygwin) + +#ifndef STRUCT_RTENTRY_HAS_RT_DST +#define rt_dst rt_nodes->rn_key +#endif +#ifndef STRUCT_RTENTRY_HAS_RT_HASH +#define rt_hash rt_pad1 +#endif + +#ifdef irix6 +#define SIOCADDRT SIOCADDMULTI +#define SIOCDELRT SIOCDELMULTI +#endif + +#ifdef linux +#define NETSNMP_ROUTE_WRITE_PROTOCOL PF_ROUTE +#else +#define NETSNMP_ROUTE_WRITE_PROTOCOL 0 +#endif + +int +addRoute(u_long dstip, u_long gwip, u_long iff, u_short flags) +{ +#if defined SIOCADDRT && !defined(irix6) + struct sockaddr_in dst; + struct sockaddr_in gateway; + int s, rc; + RTENTRY route; + + s = socket(AF_INET, SOCK_RAW, NETSNMP_ROUTE_WRITE_PROTOCOL); + if (s < 0) { + snmp_log_perror("socket"); + return -1; + } + + + flags |= RTF_UP; + + dst.sin_family = AF_INET; + dst.sin_addr.s_addr = htonl(dstip); + + + gateway.sin_family = AF_INET; + gateway.sin_addr.s_addr = htonl(gwip); + + memcpy(&route.rt_dst, &dst, sizeof(struct sockaddr_in)); + memcpy(&route.rt_gateway, &gateway, sizeof(struct sockaddr_in)); + + route.rt_flags = flags; +#ifndef RTENTRY_4_4 + route.rt_hash = iff; +#endif + + rc = ioctl(s, SIOCADDRT, (caddr_t) & route); + close(s); + if (rc < 0) + snmp_log_perror("ioctl"); + return rc; + +#else /* SIOCADDRT */ + return -1; +#endif +} + + + +int +delRoute(u_long dstip, u_long gwip, u_long iff, u_short flags) +{ +#if defined SIOCDELRT && !defined(irix6) + + struct sockaddr_in dst; + struct sockaddr_in gateway; + int s, rc; + RTENTRY route; + + s = socket(AF_INET, SOCK_RAW, NETSNMP_ROUTE_WRITE_PROTOCOL); + if (s < 0) { + snmp_log_perror("socket"); + return 0; + } + + + flags |= RTF_UP; + + dst.sin_family = AF_INET; + dst.sin_addr.s_addr = htonl(dstip); + + + gateway.sin_family = AF_INET; + gateway.sin_addr.s_addr = htonl(gwip); + + memcpy(&route.rt_dst, &dst, sizeof(struct sockaddr_in)); + memcpy(&route.rt_gateway, &gateway, sizeof(struct sockaddr_in)); + + route.rt_flags = flags; +#ifndef RTENTRY_4_4 + route.rt_hash = iff; +#endif + + rc = ioctl(s, SIOCDELRT, (caddr_t) & route); + close(s); + return rc; + +#else /* SIOCDELRT */ + return 0; +#endif +} + + +#ifndef STRUCT_RTENTRY_HAS_RT_DST +#undef rt_dst +#endif + + +#define MAX_CACHE 8 + +struct rtent { + + u_long in_use; + u_long old_dst; + u_long old_nextIR; + u_long old_ifix; + u_long old_flags; + + u_long rt_dst; /* main entries */ + u_long rt_ifix; + u_long rt_metric1; + u_long rt_nextIR; + u_long rt_type; + u_long rt_proto; + + + u_long xx_dst; /* shadow entries */ + u_long xx_ifix; + u_long xx_metric1; + u_long xx_nextIR; + u_long xx_type; + u_long xx_proto; +}; + +struct rtent rtcache[MAX_CACHE]; + +struct rtent * +findCacheRTE(u_long dst) +{ + int i; + + for (i = 0; i < MAX_CACHE; i++) { + + if (rtcache[i].in_use && (rtcache[i].rt_dst == dst)) { /* valid & match? */ + return (&rtcache[i]); + } + } + return 0; +} + +struct rtent * +newCacheRTE(void) +{ + + int i; + + for (i = 0; i < MAX_CACHE; i++) { + + if (!rtcache[i].in_use) { + rtcache[i].in_use = 1; + return (&rtcache[i]); + } + } + return 0; + +} + +int +delCacheRTE(u_long dst) +{ + struct rtent *rt; + + rt = findCacheRTE(dst); + if (!rt) { + return 0; + } + + rt->in_use = 0; + return 1; +} + + +struct rtent * +cacheKernelRTE(u_long dst) +{ + return 0; /* for now */ + /* + * ...... + */ +} + +/* + * If statP is non-NULL, the referenced object is at that location. + * If statP is NULL and ap is non-NULL, the instance exists, but not this variable. + * If statP is NULL and ap is NULL, then neither this instance nor the variable exists. + */ + +int +write_rte(int action, + u_char * var_val, + u_char var_val_type, + size_t var_val_len, u_char * statP, oid * name, size_t length) +{ + struct rtent *rp; + int var; + long val; + u_long dst; + char buf[8]; + u_short flags; + int oldty; + + /* + * object identifier is of form: + * 1.3.6.1.2.1.4.21.1.X.A.B.C.D , where A.B.C.D is IP address. + * IPADDR starts at offset 10. + */ + + if (length != 14) { + snmp_log(LOG_ERR, "length error\n"); + return SNMP_ERR_NOCREATION; + } + +#ifdef solaris2 /* not implemented */ + return SNMP_ERR_NOTWRITABLE; +#endif + + var = name[9]; + + dst = *((u_long *) & name[10]); + + rp = findCacheRTE(dst); + + if (!rp) { + rp = cacheKernelRTE(dst); + } + + + if (action == RESERVE1 && !rp) { + + rp = newCacheRTE(); + if (!rp) { + snmp_log(LOG_ERR, "newCacheRTE"); + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + rp->rt_dst = dst; + rp->rt_type = rp->xx_type = 2; + + } else if (action == COMMIT) { + + + } else if (action == FREE) { + if (rp && rp->rt_type == 2) { /* was invalid before */ + delCacheRTE(dst); + } + } + + netsnmp_assert(NULL != rp); /* should have found or created rp */ + + + switch (var) { + + case IPROUTEDEST: + + if (action == RESERVE1) { + + if (var_val_type != ASN_IPADDRESS) { + snmp_log(LOG_ERR, "not IP address"); + return SNMP_ERR_WRONGTYPE; + } + + memcpy(buf, var_val, (var_val_len > 8) ? 8 : var_val_len); + + if (var_val_type != ASN_IPADDRESS) { + snmp_log(LOG_ERR, "not IP address 2"); + return SNMP_ERR_WRONGTYPE; + } + + rp->xx_dst = *((u_long *) buf); + + + } else if (action == COMMIT) { + rp->rt_dst = rp->xx_dst; + } + break; + + case IPROUTEMETRIC1: + + if (action == RESERVE1) { + if (var_val_type != ASN_INTEGER) { + snmp_log(LOG_ERR, "not int1"); + return SNMP_ERR_WRONGTYPE; + } + + val = *((long *) var_val); + + if (val < -1) { + snmp_log(LOG_ERR, "not right1"); + return SNMP_ERR_WRONGVALUE; + } + + rp->xx_metric1 = val; + + } else if (action == RESERVE2) { + + if ((rp->xx_metric1 == 1) && (rp->xx_type != 4)) { + snmp_log(LOG_ERR, "reserve2 failed\n"); + return SNMP_ERR_WRONGVALUE; + } + + } else if (action == COMMIT) { + rp->rt_metric1 = rp->xx_metric1; + } + break; + + case IPROUTEIFINDEX: + + if (action == RESERVE1) { + if (var_val_type != ASN_INTEGER) { + snmp_log(LOG_ERR, "not right2"); + return SNMP_ERR_WRONGTYPE; + } + + val = *((long *) var_val); + + if (val <= 0) { + snmp_log(LOG_ERR, "not right3"); + return SNMP_ERR_WRONGVALUE; + } + + rp->xx_ifix = val; + + } else if (action == COMMIT) { + rp->rt_ifix = rp->xx_ifix; + } + break; + + case IPROUTENEXTHOP: + + if (action == RESERVE1) { + + if (var_val_type != ASN_IPADDRESS) { + snmp_log(LOG_ERR, "not right4"); + return SNMP_ERR_WRONGTYPE; + } + + memcpy(buf, var_val, (var_val_len > 8) ? 8 : var_val_len); + + if (var_val_type != ASN_IPADDRESS) { + snmp_log(LOG_ERR, "not right5"); + return SNMP_ERR_WRONGTYPE; + } + + rp->xx_nextIR = *((u_long *) buf); + + } else if (action == COMMIT) { + rp->rt_nextIR = rp->xx_nextIR; + } + + + case IPROUTETYPE: + + /* + * flag meaning: + * + * IPROUTEPROTO (rt_proto): none: (cant set == 3 (netmgmt)) + * + * IPROUTEMETRIC1: 1 iff gateway, 0 otherwise + * IPROUTETYPE: 4 iff gateway, 3 otherwise + */ + + if (action == RESERVE1) { + if (var_val_type != ASN_INTEGER) { + return SNMP_ERR_WRONGTYPE; + } + + val = *((long *) var_val); + + if ((val < 2) || (val > 4)) { /* only accept invalid, direct, indirect */ + snmp_log(LOG_ERR, "not right6"); + return SNMP_ERR_WRONGVALUE; + } + + rp->xx_type = val; + + } else if (action == COMMIT) { + + oldty = rp->rt_type; + rp->rt_type = rp->xx_type; + + if (rp->rt_type == 2) { /* invalid, so delete from kernel */ + + if (delRoute + (rp->rt_dst, rp->rt_nextIR, rp->rt_ifix, + rp->old_flags) < 0) { + snmp_log_perror("delRoute"); + } + + } else { + + /* + * it must be valid now, so flush to kernel + */ + + if (oldty != 2) { /* was the old entry valid ? */ + if (delRoute + (rp->old_dst, rp->old_nextIR, rp->old_ifix, + rp->old_flags) < 0) { + snmp_log_perror("delRoute"); + } + } + + /* + * not invalid, so remove from cache + */ + + flags = (rp->rt_type == 4 ? RTF_GATEWAY : 0); + + if (addRoute(rp->rt_dst, rp->rt_nextIR, rp->rt_ifix, flags) + < 0) { + snmp_log_perror("addRoute"); + } + + delCacheRTE(rp->rt_type); + } + } + break; + + + case IPROUTEPROTO: + + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_rte\n", var)); + return SNMP_ERR_NOCREATION; + + + } + + return SNMP_ERR_NOERROR; +} + +#else /* WIN32 cygwin */ +#include <iphlpapi.h> + +extern PMIB_IPFORWARDROW route_row; +extern int create_flag; + +int +write_rte(int action, + u_char * var_val, + u_char var_val_type, + size_t var_val_len, u_char * statP, oid * name, size_t length) +{ + int var, retval = NO_ERROR; + static PMIB_IPFORWARDROW oldroute_row = NULL; + static int mask_flag = 0, nexthop_flag = 0; + static int index_flag = 0, metric_flag = 0; + static int dest_flag = 0; + DWORD status = NO_ERROR; + /* + * object identifier is of form: + * 1.3.6.1.2.1.4.21.1.X.A.B.C.D , where A.B.C.D is IP address. + * IPADDR starts at offset 10. + */ + + if (length != 14) { + snmp_log(LOG_ERR, "length error\n"); + return SNMP_ERR_NOCREATION; + } + /* + * #define for ipRouteTable entries are 1 less than corresponding sub-id in MIB + * * i.e. IPROUTEDEST defined as 0, but ipRouteDest registered as 1 + */ + var = name[9] - 1; + + switch (action) { + case RESERVE1: + switch (var) { + case IPROUTEMETRIC1: + case IPROUTEMETRIC2: + case IPROUTEMETRIC3: + case IPROUTEMETRIC4: + case IPROUTEMETRIC5: + case IPROUTETYPE: + case IPROUTEAGE: + case IPROUTEIFINDEX: + if (var_val_type != ASN_INTEGER) { + snmp_log(LOG_ERR, "not integer\n"); + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len > sizeof(int)) { + snmp_log(LOG_ERR, "bad length\n"); + return SNMP_ERR_WRONGLENGTH; + } + if (var == IPROUTETYPE) { + if ((*((int *) var_val)) < 2 || (*((int *) var_val)) > 4) { + snmp_log(LOG_ERR, "invalid ipRouteType\n"); + return SNMP_ERR_WRONGVALUE; + } + } else if ((var == IPROUTEIFINDEX) || (var == IPROUTEAGE)) { + if ((*((int *) var_val)) < 0) { + snmp_log(LOG_ERR, "invalid ipRouteIfIndex\n"); + return SNMP_ERR_WRONGVALUE; + } + } else { + if ((*((int *) var_val)) < -1) { + snmp_log(LOG_ERR, "not right1"); + return SNMP_ERR_WRONGVALUE; + } + } + break; + case IPROUTENEXTHOP: + case IPROUTEMASK: + case IPROUTEDEST: + if (var_val_type != ASN_IPADDRESS) { + snmp_log(LOG_ERR, "not right4"); + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len != 4) { + snmp_log(LOG_ERR, "incorrect ipAddress length"); + return SNMP_ERR_WRONGLENGTH; + } + break; + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_rte\n", + var + 1)); + retval = SNMP_ERR_NOTWRITABLE; + } + break; + + case RESERVE2: + /* + * Save the old value, in case of UNDO + */ + if (oldroute_row == NULL) { + oldroute_row = + (PMIB_IPFORWARDROW) malloc(sizeof(MIB_IPFORWARDROW)); + *oldroute_row = *route_row; + } + break; + + case ACTION: /* Perform the SET action (if reversible) */ + switch (var) { + case IPROUTEMETRIC1: + metric_flag = 1; + route_row->dwForwardMetric1 = *((int *) var_val); + break; + case IPROUTEMETRIC2: + route_row->dwForwardMetric2 = *((int *) var_val); + break; + case IPROUTEMETRIC3: + route_row->dwForwardMetric3 = *((int *) var_val); + break; + case IPROUTEMETRIC4: + route_row->dwForwardMetric4 = *((int *) var_val); + break; + case IPROUTEMETRIC5: + route_row->dwForwardMetric5 = *((int *) var_val); + break; + case IPROUTETYPE: + route_row->dwForwardType = *((int *) var_val); + break; + case IPROUTEAGE: + /* + * Irrespective of suppied value, this will be set with 0. + * * As row will be updated and this field gives the number of + * * seconds since this route was last updated + */ + route_row->dwForwardAge = *((int *) var_val); + break; + case IPROUTEIFINDEX: + index_flag = 1; + route_row->dwForwardIfIndex = *((int *) var_val); + break; + + case IPROUTENEXTHOP: + nexthop_flag = 1; + route_row->dwForwardNextHop = *((DWORD *) var_val); + break; + case IPROUTEMASK: + mask_flag = 1; + route_row->dwForwardMask = *((DWORD *) var_val); + break; + case IPROUTEDEST: + dest_flag = 1; + route_row->dwForwardDest = *((DWORD *) var_val); + break; + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_rte\n", + var + 1)); + retval = SNMP_ERR_NOTWRITABLE; + } + return retval; + case UNDO: + /* + * Reverse the SET action and free resources + */ + if (oldroute_row) { + *route_row = *oldroute_row; + free(oldroute_row); + oldroute_row = NULL; + free(route_row); + route_row = NULL; + } + break; + + case COMMIT: + /* + * When this case entered 'route_row' will have user supplied values for asked entries. + * * Thats why it is enough if we call SetIpForwardEntry/CreateIpForwardEntry only once + * * SetIpForwardENtry is not done in ACTION phase, as that will reset ipRouteAge on success + * * and if any varbind fails, then we can't UNDO the change for ipROuteAge. + */ + if (route_row) { + if (!create_flag) { + + if (SetIpForwardEntry(route_row) != NO_ERROR) { + snmp_log(LOG_ERR, + "Can't set route table's row with specified value\n"); + retval = SNMP_ERR_COMMITFAILED; + } else { + /* + * SET on IpRouteNextHop, IpRouteMask & ipRouteDest creates new row. + * *If Set succeeds, then delete the old row. + * * Don't know yet whether SET on ipRouteIfIndex creates new row. + * * If it creates then index_flag should be added to following if statement + */ + + if (dest_flag || nexthop_flag || mask_flag) { + oldroute_row->dwForwardType = 2; + if (SetIpForwardEntry(oldroute_row) != NO_ERROR) { + snmp_log(LOG_ERR, + "Set on ipRouteTable created new row, but failed to delete the old row\n"); + retval = SNMP_ERR_GENERR; + } + } + } + } + /* + * Only if create_flag, mask, nexthop, ifIndex and metric are specified, create new entry + */ + if (create_flag) { + if (mask_flag && nexthop_flag && metric_flag && index_flag) { + if ((status = + CreateIpForwardEntry(route_row)) != NO_ERROR) { + snmp_log(LOG_ERR, + "Inside COMMIT: CreateIpNetEntry failed, status %d\n", + status); + retval = SNMP_ERR_COMMITFAILED; + } + } else { + /* + * For new entry, mask, nexthop, ifIndex and metric must be supplied + */ + snmp_log(LOG_ERR, + "case COMMIT, can't create without index, mask, nextHop and metric\n"); + retval = SNMP_ERR_WRONGVALUE; + } + } + } + + case FREE: + /* + * Free any resources allocated + */ + free(oldroute_row); + oldroute_row = NULL; + free(route_row); + route_row = NULL; + mask_flag = nexthop_flag = metric_flag = index_flag = dest_flag = + 0; + break; + } + return retval; +} + +#endif /* WIN32 cygwin */ |