1
/* Portions of this file are subject to the following copyright(s). See
2
* the Net-SNMP's COPYING file for more details and other copyrights
6
* Portions of this file are copyrighted by:
7
* Copyright ļæ½ 2003 Sun Microsystems, Inc. All rights reserved.
8
* Use is subject to license terms specified in the COPYING file
9
* distributed with the Net-SNMP package.
11
#include <net-snmp/net-snmp-config.h>
13
#include <sys/types.h>
15
#include <sys/param.h>
21
#include <sys/socket.h>
24
#include <sys/sockio.h>
27
#include <sys/ioctl.h>
35
#include <sys/stream.h>
38
#include <net/route.h>
41
#include <netinet/in.h>
44
#include <arpa/inet.h>
71
#include <net-snmp/net-snmp-includes.h>
72
#include <net-snmp/agent/net-snmp-agent-includes.h>
75
#include "route_write.h"
84
#ifndef STRUCT_RTENTRY_HAS_RT_DST
85
#define rt_dst rt_nodes->rn_key
87
#ifndef STRUCT_RTENTRY_HAS_RT_HASH
88
#define rt_hash rt_pad1
92
#define SIOCADDRT SIOCADDMULTI
93
#define SIOCDELRT SIOCDELMULTI
97
addRoute(u_long dstip, u_long gwip, u_long iff, u_short flags)
100
struct sockaddr_in dst;
101
struct sockaddr_in gateway;
105
s = socket(AF_INET, SOCK_RAW, 0);
107
snmp_log_perror("socket");
114
dst.sin_family = AF_INET;
115
dst.sin_addr.s_addr = htonl(dstip);
118
gateway.sin_family = AF_INET;
119
gateway.sin_addr.s_addr = htonl(gwip);
121
memcpy(&route.rt_dst, &dst, sizeof(struct sockaddr_in));
122
memcpy(&route.rt_gateway, &gateway, sizeof(struct sockaddr_in));
124
route.rt_flags = flags;
131
return (ioctl(s, SIOCADDRT, (caddr_t) & route));
136
* Throws up the following errors:
138
* "mibII/route_write.c", line 113: undefined struct/union member: rt_nodes
139
* "mibII/route_write.c", line 113: undefined struct/union member: rn_key
140
* "mibII/route_write.c", line 113: left operand of "->" must be pointer to struct/union
141
* "mibII/route_write.c", line 118: undefined struct/union member: rt_pad1
142
* "mibII/route_write.c", line 123: undefined symbol: SIOCADDRT
143
* "mibII/route_write.c", line 155: undefined struct/union member: rt_nodes
144
* "mibII/route_write.c", line 155: undefined struct/union member: rn_key
145
* "mibII/route_write.c", line 155: left operand of "->" must be pointer to struct/union
146
* "mibII/route_write.c", line 160: undefined struct/union member: rt_pad1
147
* "mibII/route_write.c", line 166: undefined symbol: SIOCDELRT
157
delRoute(u_long dstip, u_long gwip, u_long iff, u_short flags)
161
struct sockaddr_in dst;
162
struct sockaddr_in gateway;
166
s = socket(AF_INET, SOCK_RAW, 0);
168
snmp_log_perror("socket");
175
dst.sin_family = AF_INET;
176
dst.sin_addr.s_addr = htonl(dstip);
179
gateway.sin_family = AF_INET;
180
gateway.sin_addr.s_addr = htonl(gwip);
182
memcpy(&route.rt_dst, &dst, sizeof(struct sockaddr_in));
183
memcpy(&route.rt_gateway, &gateway, sizeof(struct sockaddr_in));
185
route.rt_flags = flags;
193
return (ioctl(s, SIOCDELRT, (caddr_t) & route));
198
* See 'addRoute' for the list of errors.
205
#ifndef STRUCT_RTENTRY_HAS_RT_DST
220
u_long rt_dst; /* main entries */
228
u_long xx_dst; /* shadow entries */
236
struct rtent rtcache[MAX_CACHE];
239
findCacheRTE(u_long dst)
243
for (i = 0; i < MAX_CACHE; i++) {
245
if (rtcache[i].in_use && (rtcache[i].rt_dst == dst)) { /* valid & match? */
246
return (&rtcache[i]);
258
for (i = 0; i < MAX_CACHE; i++) {
260
if (!rtcache[i].in_use) {
261
rtcache[i].in_use = 1;
262
return (&rtcache[i]);
270
delCacheRTE(u_long dst)
274
rt = findCacheRTE(dst);
285
cacheKernelRTE(u_long dst)
287
return 0; /* for now */
294
* If statP is non-NULL, the referenced object is at that location.
295
* If statP is NULL and ap is non-NULL, the instance exists, but not this variable.
296
* If statP is NULL and ap is NULL, then neither this instance nor the variable exists.
300
write_rte(int action,
303
size_t var_val_len, u_char * statP, oid * name, size_t length)
314
* object identifier is of form:
315
* 1.3.6.1.2.1.4.21.1.X.A.B.C.D , where A.B.C.D is IP address.
316
* IPADDR starts at offset 10.
320
snmp_log(LOG_ERR, "length error\n");
321
return SNMP_ERR_NOCREATION;
324
#ifdef solaris2 /* not implemented */
325
return SNMP_ERR_NOTWRITABLE;
330
dst = *((u_long *) & name[10]);
332
rp = findCacheRTE(dst);
335
rp = cacheKernelRTE(dst);
339
if (action == RESERVE1 && !rp) {
343
snmp_log(LOG_ERR, "newCacheRTE");
344
return SNMP_ERR_RESOURCEUNAVAILABLE;
346
rp->rt_type = rp->xx_type = 2;
348
} else if (action == COMMIT) {
351
} else if (action == FREE) {
352
if (rp->rt_type == 2) { /* was invalid before */
364
if (action == RESERVE1) {
366
if (var_val_type != ASN_OCTET_STR) {
367
snmp_log(LOG_ERR, "not octet");
368
return SNMP_ERR_WRONGTYPE;
371
memcpy(buf, var_val, (var_val_len > 8) ? 8 : var_val_len);
373
if (var_val_type != ASN_OCTET_STR) {
374
snmp_log(LOG_ERR, "not octet2");
375
return SNMP_ERR_WRONGTYPE;
378
rp->xx_dst = *((u_long *) buf);
381
} else if (action == COMMIT) {
382
rp->rt_dst = rp->xx_dst;
388
if (action == RESERVE1) {
389
if (var_val_type != ASN_INTEGER) {
390
snmp_log(LOG_ERR, "not int1");
391
return SNMP_ERR_WRONGTYPE;
394
val = *((long *) var_val);
397
snmp_log(LOG_ERR, "not right1");
398
return SNMP_ERR_WRONGVALUE;
401
rp->xx_metric1 = val;
403
} else if (action == RESERVE2) {
405
if ((rp->xx_metric1 == 1) && (rp->xx_type != 4)) {
406
snmp_log(LOG_ERR, "reserve2 failed\n");
407
return SNMP_ERR_WRONGVALUE;
410
} else if (action == COMMIT) {
411
rp->rt_metric1 = rp->xx_metric1;
417
if (action == RESERVE1) {
418
if (var_val_type != ASN_INTEGER) {
419
snmp_log(LOG_ERR, "not right2");
420
return SNMP_ERR_WRONGTYPE;
423
val = *((long *) var_val);
426
snmp_log(LOG_ERR, "not right3");
427
return SNMP_ERR_WRONGVALUE;
432
} else if (action == COMMIT) {
433
rp->rt_ifix = rp->xx_ifix;
439
if (action == RESERVE1) {
441
if (var_val_type != ASN_OCTET_STR) {
442
snmp_log(LOG_ERR, "not right4");
443
return SNMP_ERR_WRONGTYPE;
446
memcpy(buf, var_val, (var_val_len > 8) ? 8 : var_val_len);
448
if (var_val_type != ASN_OCTET_STR) {
449
snmp_log(LOG_ERR, "not right5");
450
return SNMP_ERR_WRONGTYPE;
453
rp->xx_nextIR = *((u_long *) buf);
455
} else if (action == COMMIT) {
456
rp->rt_nextIR = rp->xx_nextIR;
465
* IPROUTEPROTO (rt_proto): none: (cant set == 3 (netmgmt))
467
* IPROUTEMETRIC1: 1 iff gateway, 0 otherwise
468
* IPROUTETYPE: 4 iff gateway, 3 otherwise
471
if (action == RESERVE1) {
472
if (var_val_type != ASN_INTEGER) {
473
return SNMP_ERR_WRONGTYPE;
476
val = *((long *) var_val);
478
if ((val < 2) || (val > 4)) { /* only accept invalid, direct, indirect */
479
snmp_log(LOG_ERR, "not right6");
480
return SNMP_ERR_WRONGVALUE;
485
} else if (action == COMMIT) {
488
rp->rt_type = rp->xx_type;
490
if (rp->rt_type == 2) { /* invalid, so delete from kernel */
493
(rp->rt_dst, rp->rt_nextIR, rp->rt_ifix,
494
rp->old_flags) < 0) {
495
snmp_log_perror("delRoute");
501
* it must be valid now, so flush to kernel
504
if (oldty != 2) { /* was the old entry valid ? */
506
(rp->old_dst, rp->old_nextIR, rp->old_ifix,
507
rp->old_flags) < 0) {
508
snmp_log_perror("delRoute");
513
* not invalid, so remove from cache
516
flags = (rp->rt_type == 4 ? RTF_GATEWAY : 0);
518
if (addRoute(rp->rt_dst, rp->rt_nextIR, rp->rt_ifix, flags)
520
snmp_log_perror("addRoute");
523
delCacheRTE(rp->rt_type);
532
DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_rte\n", var));
533
return SNMP_ERR_NOCREATION;
538
return SNMP_ERR_NOERROR;
542
#include <iphlpapi.h>
544
extern PMIB_IPFORWARDROW route_row;
545
extern int create_flag;
548
write_rte(int action,
551
size_t var_val_len, u_char * statP, oid * name, size_t length)
553
int var, retval = NO_ERROR;
554
static PMIB_IPFORWARDROW oldroute_row = NULL;
555
static int mask_flag = 0, nexthop_flag = 0;
556
static int index_flag = 0, metric_flag = 0;
557
static int dest_flag = 0;
558
DWORD status = NO_ERROR;
560
* object identifier is of form:
561
* 1.3.6.1.2.1.4.21.1.X.A.B.C.D , where A.B.C.D is IP address.
562
* IPADDR starts at offset 10.
566
snmp_log(LOG_ERR, "length error\n");
567
return SNMP_ERR_NOCREATION;
570
* #define for ipRouteTable entries are 1 less than corresponding sub-id in MIB
571
* * i.e. IPROUTEDEST defined as 0, but ipRouteDest registered as 1
586
if (var_val_type != ASN_INTEGER) {
587
snmp_log(LOG_ERR, "not integer\n");
588
return SNMP_ERR_WRONGTYPE;
590
if (var_val_len > sizeof(int)) {
591
snmp_log(LOG_ERR, "bad length\n");
592
return SNMP_ERR_WRONGLENGTH;
594
if (var == IPROUTETYPE) {
595
if ((*((int *) var_val)) < 2 || (*((int *) var_val)) > 4) {
596
snmp_log(LOG_ERR, "invalid ipRouteType\n");
597
return SNMP_ERR_WRONGVALUE;
599
} else if ((var == IPROUTEIFINDEX) || (var == IPROUTEAGE)) {
600
if ((*((int *) var_val)) < 0) {
601
snmp_log(LOG_ERR, "invalid ipRouteIfIndex\n");
602
return SNMP_ERR_WRONGVALUE;
605
if ((*((int *) var_val)) < -1) {
606
snmp_log(LOG_ERR, "not right1");
607
return SNMP_ERR_WRONGVALUE;
614
if (var_val_type != ASN_IPADDRESS) {
615
snmp_log(LOG_ERR, "not right4");
616
return SNMP_ERR_WRONGTYPE;
618
if (var_val_len != 4) {
619
snmp_log(LOG_ERR, "incorrect ipAddress length");
620
return SNMP_ERR_WRONGLENGTH;
624
DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_rte\n",
626
retval = SNMP_ERR_NOTWRITABLE;
632
* Save the old value, in case of UNDO
634
if (oldroute_row == NULL) {
636
(PMIB_IPFORWARDROW) malloc(sizeof(MIB_IPFORWARDROW));
637
*oldroute_row = *route_row;
641
case ACTION: /* Perform the SET action (if reversible) */
645
route_row->dwForwardMetric1 = *((int *) var_val);
648
route_row->dwForwardMetric2 = *((int *) var_val);
651
route_row->dwForwardMetric3 = *((int *) var_val);
654
route_row->dwForwardMetric4 = *((int *) var_val);
657
route_row->dwForwardMetric5 = *((int *) var_val);
660
route_row->dwForwardType = *((int *) var_val);
664
* Irrespective of suppied value, this will be set with 0.
665
* * As row will be updated and this field gives the number of
666
* * seconds since this route was last updated
668
route_row->dwForwardAge = *((int *) var_val);
672
route_row->dwForwardIfIndex = *((int *) var_val);
677
route_row->dwForwardNextHop = *((DWORD *) var_val);
681
route_row->dwForwardMask = *((DWORD *) var_val);
685
route_row->dwForwardDest = *((DWORD *) var_val);
688
DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_rte\n",
690
retval = SNMP_ERR_NOTWRITABLE;
695
* Reverse the SET action and free resources
698
*route_row = *oldroute_row;
708
* When this case entered 'route_row' will have user supplied values for asked entries.
709
* * Thats why it is enough if we call SetIpForwardEntry/CreateIpForwardEntry only once
710
* * SetIpForwardENtry is not done in ACTION phase, as that will reset ipRouteAge on success
711
* * and if any varbind fails, then we can't UNDO the change for ipROuteAge.
716
if (SetIpForwardEntry(route_row) != NO_ERROR) {
718
"Can't set route table's row with specified value\n");
719
retval = SNMP_ERR_COMMITFAILED;
722
* SET on IpRouteNextHop, IpRouteMask & ipRouteDest creates new row.
723
* *If Set succeeds, then delete the old row.
724
* * Don't know yet whether SET on ipRouteIfIndex creates new row.
725
* * If it creates then index_flag should be added to following if statement
728
if (dest_flag || nexthop_flag || mask_flag) {
729
oldroute_row->dwForwardType = 2;
730
if (SetIpForwardEntry(oldroute_row) != NO_ERROR) {
732
"Set on ipRouteTable created new row, but failed to delete the old row\n");
733
retval = SNMP_ERR_GENERR;
739
* Only if create_flag, mask, nexthop, ifIndex and metric are specified, create new entry
742
if (mask_flag && nexthop_flag && metric_flag && index_flag) {
744
CreateIpForwardEntry(route_row)) != NO_ERROR) {
746
"Inside COMMIT: CreateIpNetEntry failed, status %d\n",
748
retval = SNMP_ERR_COMMITFAILED;
752
* For new entry, mask, nexthop, ifIndex and metric must be supplied
755
"case COMMIT, can't create without index, mask, nextHop and metric\n");
756
retval = SNMP_ERR_WRONGVALUE;
763
* Free any resources allocated
769
mask_flag = nexthop_flag = metric_flag = index_flag = dest_flag =