xref: /freebsd/contrib/bsnmp/snmp_mibII/mibII_ip.c (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
1 /*
2  * Copyright (c) 2001-2003
3  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *	All rights reserved.
5  *
6  * Author: Harti Brandt <harti@freebsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $Begemot: bsnmp/snmp_mibII/mibII_ip.c,v 1.11 2005/05/23 09:03:40 brandt_h Exp $
30  *
31  * ip group scalars.
32  */
33 #include "mibII.h"
34 #include "mibII_oid.h"
35 #include <netinet/in_systm.h>
36 #include <netinet/ip.h>
37 #include <netinet/ip_var.h>
38 #include <netinet/ip_icmp.h>
39 #include <netinet/icmp_var.h>
40 
41 static struct ipstat ipstat;
42 static u_int	ip_idrop;
43 static struct icmpstat icmpstat;
44 
45 static int	ip_forwarding;
46 static int	ip_defttl;
47 static uint64_t ip_tick;
48 
49 static uint64_t ipstat_tick;
50 
51 static int
52 fetch_ipstat(void)
53 {
54 	size_t len;
55 
56 	len = sizeof(ipstat);
57 	if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, NULL, 0) == -1) {
58 		syslog(LOG_ERR, "net.inet.ip.stats: %m");
59 		return (-1);
60 	}
61 	if (len != sizeof(ipstat)) {
62 		syslog(LOG_ERR, "net.inet.ip.stats: wrong size");
63 		return (-1);
64 	}
65 	len = sizeof(ip_idrop);
66 	if (sysctlbyname("net.inet.ip.intr_queue_drops", &ip_idrop, &len, NULL, 0) == -1)
67 		syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: %m");
68 	if (len != sizeof(ip_idrop)) {
69 		syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: wrong size");
70 		ip_idrop = 0;
71 	}
72 	len = sizeof(icmpstat);
73 	if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &len, NULL, 0) == -1) {
74 		syslog(LOG_ERR, "net.inet.icmp.stats: %m");
75 		return (-1);
76 	}
77 	if (len != sizeof(icmpstat)) {
78 		syslog(LOG_ERR, "net.inet.icmp.stats: wrong size");
79 		return (-1);
80 	}
81 
82 	ipstat_tick = get_ticks();
83 	return (0);
84 }
85 
86 static int
87 fetch_ip(void)
88 {
89 	size_t len;
90 
91 	len = sizeof(ip_forwarding);
92 	if (sysctlbyname("net.inet.ip.forwarding", &ip_forwarding, &len,
93 	    NULL, 0) == -1) {
94 		syslog(LOG_ERR, "net.inet.ip.forwarding: %m");
95 		return (-1);
96 	}
97 	if (len != sizeof(ip_forwarding)) {
98 		syslog(LOG_ERR, "net.inet.ip.forwarding: wrong size");
99 		return (-1);
100 	}
101 
102 	len = sizeof(ip_defttl);
103 	if (sysctlbyname("net.inet.ip.ttl", &ip_defttl, &len,
104 	    NULL, 0) == -1) {
105 		syslog(LOG_ERR, "net.inet.ip.ttl: %m");
106 		return (-1);
107 	}
108 	if (len != sizeof(ip_defttl)) {
109 		syslog(LOG_ERR, "net.inet.ip.ttl: wrong size");
110 		return (-1);
111 	}
112 
113 	ip_tick = get_ticks();
114 	return (0);
115 }
116 
117 static int
118 ip_forward(int forw, int *old)
119 {
120 	size_t olen;
121 
122 	olen = sizeof(*old);
123 	if (sysctlbyname("net.inet.ip.forwarding", old, old ? &olen : NULL,
124 	    &forw, sizeof(forw)) == -1) {
125 		syslog(LOG_ERR, "set net.inet.ip.forwarding: %m");
126 		return (-1);
127 	}
128 	ip_forwarding = forw;
129 	return (0);
130 }
131 
132 static int
133 ip_setttl(int ttl, int *old)
134 {
135 	size_t olen;
136 
137 	olen = sizeof(*old);
138 	if (sysctlbyname("net.inet.ip.ttl", old, old ? &olen : NULL,
139 	    &ttl, sizeof(ttl)) == -1) {
140 		syslog(LOG_ERR, "set net.inet.ip.ttl: %m");
141 		return (-1);
142 	}
143 	ip_defttl = ttl;
144 	return (0);
145 }
146 
147 /*
148  * READ/WRITE ip group.
149  */
150 int
151 op_ip(struct snmp_context *ctx, struct snmp_value *value,
152     u_int sub, u_int idx __unused, enum snmp_op op)
153 {
154 	int old = 0;
155 
156 	switch (op) {
157 
158 	  case SNMP_OP_GETNEXT:
159 		abort();
160 
161 	  case SNMP_OP_GET:
162 		break;
163 
164 	  case SNMP_OP_SET:
165 		if (ip_tick < this_tick)
166 			if (fetch_ip() == -1)
167 				return (SNMP_ERR_GENERR);
168 
169 		switch (value->var.subs[sub - 1]) {
170 
171 		  case LEAF_ipForwarding:
172 			ctx->scratch->int1 = ip_forwarding ? 1 : 2;
173 			ctx->scratch->int2 = value->v.integer;
174 			if (value->v.integer == 1) {
175 				if (!ip_forwarding && ip_forward(1, &old))
176 					return (SNMP_ERR_GENERR);
177 				ctx->scratch->int1 = old ? 1 : 2;
178 			} else if (value->v.integer == 2) {
179 				if (ip_forwarding && ip_forward(0, &old))
180 					return (SNMP_ERR_GENERR);
181 				ctx->scratch->int1 = old;
182 			} else
183 				return (SNMP_ERR_WRONG_VALUE);
184 			break;
185 
186 		  case LEAF_ipDefaultTTL:
187 			ctx->scratch->int1 = ip_defttl;
188 			ctx->scratch->int2 = value->v.integer;
189 			if (value->v.integer < 1 || value->v.integer > 255)
190 				return (SNMP_ERR_WRONG_VALUE);
191 			if (ip_defttl != value->v.integer &&
192 			    ip_setttl(value->v.integer, &old))
193 				return (SNMP_ERR_GENERR);
194 			ctx->scratch->int1 = old;
195 			break;
196 		}
197 		return (SNMP_ERR_NOERROR);
198 
199 	  case SNMP_OP_ROLLBACK:
200 		switch (value->var.subs[sub - 1]) {
201 
202 		  case LEAF_ipForwarding:
203 			if (ctx->scratch->int1 == 1) {
204 				if (ctx->scratch->int2 == 2)
205 					(void)ip_forward(1, NULL);
206 			} else {
207 				if (ctx->scratch->int2 == 1)
208 					(void)ip_forward(0, NULL);
209 			}
210 			break;
211 
212 		  case LEAF_ipDefaultTTL:
213 			if (ctx->scratch->int1 != ctx->scratch->int2)
214 				(void)ip_setttl(ctx->scratch->int1, NULL);
215 			break;
216 		}
217 		return (SNMP_ERR_NOERROR);
218 
219 	  case SNMP_OP_COMMIT:
220 		return (SNMP_ERR_NOERROR);
221 	}
222 
223 	if (ip_tick < this_tick)
224 		if (fetch_ip() == -1)
225 			return (SNMP_ERR_GENERR);
226 
227 	switch (value->var.subs[sub - 1]) {
228 
229 	  case LEAF_ipForwarding:
230 		value->v.integer = ip_forwarding ? 1 : 2;
231 		break;
232 
233 	  case LEAF_ipDefaultTTL:
234 		value->v.integer = ip_defttl;
235 		break;
236 	}
237 	return (SNMP_ERR_NOERROR);
238 }
239 
240 /*
241  * READ-ONLY statistics ip group.
242  */
243 int
244 op_ipstat(struct snmp_context *ctx __unused, struct snmp_value *value,
245     u_int sub, u_int idx __unused, enum snmp_op op)
246 {
247 	switch (op) {
248 
249 	  case SNMP_OP_GETNEXT:
250 		abort();
251 
252 	  case SNMP_OP_GET:
253 		break;
254 
255 	  case SNMP_OP_SET:
256 		return (SNMP_ERR_NOT_WRITEABLE);
257 
258 	  case SNMP_OP_ROLLBACK:
259 	  case SNMP_OP_COMMIT:
260 		abort();
261 	}
262 
263 	if (ipstat_tick < this_tick)
264 		fetch_ipstat();
265 
266 	switch (value->var.subs[sub - 1]) {
267 
268 	  case LEAF_ipInReceives:
269 		value->v.uint32 = ipstat.ips_total;
270 		break;
271 
272 	  case LEAF_ipInHdrErrors:
273 		value->v.uint32 = ipstat.ips_badsum + ipstat.ips_tooshort
274 		    + ipstat.ips_toosmall + ipstat.ips_badhlen
275 		    + ipstat.ips_badlen + ipstat.ips_badvers +
276 		    + ipstat.ips_toolong;
277 		break;
278 
279 	  case LEAF_ipInAddrErrors:
280 		value->v.uint32 = ipstat.ips_cantforward;
281 		break;
282 
283 	  case LEAF_ipForwDatagrams:
284 		value->v.uint32 = ipstat.ips_forward;
285 		break;
286 
287 	  case LEAF_ipInUnknownProtos:
288 		value->v.uint32 = ipstat.ips_noproto;
289 		break;
290 
291 	  case LEAF_ipInDiscards:
292 		value->v.uint32 = ip_idrop;
293 		break;
294 
295 	  case LEAF_ipInDelivers:
296 		value->v.uint32 = ipstat.ips_delivered;
297 		break;
298 
299 	  case LEAF_ipOutRequests:
300 		value->v.uint32 = ipstat.ips_localout;
301 		break;
302 
303 	  case LEAF_ipOutDiscards:
304 		value->v.uint32 = ipstat.ips_odropped;
305 		break;
306 
307 	  case LEAF_ipOutNoRoutes:
308 		value->v.uint32 = ipstat.ips_noroute;
309 		break;
310 
311 	  case LEAF_ipReasmTimeout:
312 		value->v.integer = IPFRAGTTL;
313 		break;
314 
315 	  case LEAF_ipReasmReqds:
316 		value->v.uint32 = ipstat.ips_fragments;
317 		break;
318 
319 	  case LEAF_ipReasmOKs:
320 		value->v.uint32 = ipstat.ips_reassembled;
321 		break;
322 
323 	  case LEAF_ipReasmFails:
324 		value->v.uint32 = ipstat.ips_fragdropped
325 		    + ipstat.ips_fragtimeout;
326 		break;
327 
328 	  case LEAF_ipFragOKs:
329 		value->v.uint32 = ipstat.ips_fragmented;
330 		break;
331 
332 	  case LEAF_ipFragFails:
333 		value->v.uint32 = ipstat.ips_cantfrag;
334 		break;
335 
336 	  case LEAF_ipFragCreates:
337 		value->v.uint32 = ipstat.ips_ofragments;
338 		break;
339 	}
340 	return (SNMP_ERR_NOERROR);
341 }
342 
343 /*
344  * READ-ONLY statistics icmp group.
345  */
346 int
347 op_icmpstat(struct snmp_context *ctx __unused, struct snmp_value *value,
348     u_int sub, u_int idx __unused, enum snmp_op op)
349 {
350 	u_int i;
351 
352 	switch (op) {
353 
354 	  case SNMP_OP_GETNEXT:
355 		abort();
356 
357 	  case SNMP_OP_GET:
358 		break;
359 
360 	  case SNMP_OP_SET:
361 		return (SNMP_ERR_NOT_WRITEABLE);
362 
363 	  case SNMP_OP_ROLLBACK:
364 	  case SNMP_OP_COMMIT:
365 		abort();
366 	}
367 
368 	if (ipstat_tick < this_tick)
369 		fetch_ipstat();
370 
371 	switch (value->var.subs[sub - 1]) {
372 
373 	  case LEAF_icmpInMsgs:
374 		value->v.integer = 0;
375 		for (i = 0; i <= ICMP_MAXTYPE; i++)
376 			value->v.integer += icmpstat.icps_inhist[i];
377 		value->v.integer += icmpstat.icps_tooshort +
378 		    icmpstat.icps_checksum;
379 		/* missing: bad type and packets on faith */
380 		break;
381 
382 	  case LEAF_icmpInErrors:
383 		value->v.integer = icmpstat.icps_tooshort +
384 		    icmpstat.icps_checksum +
385 		    icmpstat.icps_badlen +
386 		    icmpstat.icps_badcode +
387 		    icmpstat.icps_bmcastecho +
388 		    icmpstat.icps_bmcasttstamp;
389 		break;
390 
391 	  case LEAF_icmpInDestUnreachs:
392 		value->v.integer = icmpstat.icps_inhist[ICMP_UNREACH];
393 		break;
394 
395 	  case LEAF_icmpInTimeExcds:
396 		value->v.integer = icmpstat.icps_inhist[ICMP_TIMXCEED];
397 		break;
398 
399 	  case LEAF_icmpInParmProbs:
400 		value->v.integer = icmpstat.icps_inhist[ICMP_PARAMPROB];
401 		break;
402 
403 	  case LEAF_icmpInSrcQuenchs:
404 		value->v.integer = icmpstat.icps_inhist[ICMP_SOURCEQUENCH];
405 		break;
406 
407 	  case LEAF_icmpInRedirects:
408 		value->v.integer = icmpstat.icps_inhist[ICMP_REDIRECT];
409 		break;
410 
411 	  case LEAF_icmpInEchos:
412 		value->v.integer = icmpstat.icps_inhist[ICMP_ECHO];
413 		break;
414 
415 	  case LEAF_icmpInEchoReps:
416 		value->v.integer = icmpstat.icps_inhist[ICMP_ECHOREPLY];
417 		break;
418 
419 	  case LEAF_icmpInTimestamps:
420 		value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMP];
421 		break;
422 
423 	  case LEAF_icmpInTimestampReps:
424 		value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMPREPLY];
425 		break;
426 
427 	  case LEAF_icmpInAddrMasks:
428 		value->v.integer = icmpstat.icps_inhist[ICMP_MASKREQ];
429 		break;
430 
431 	  case LEAF_icmpInAddrMaskReps:
432 		value->v.integer = icmpstat.icps_inhist[ICMP_MASKREPLY];
433 		break;
434 
435 	  case LEAF_icmpOutMsgs:
436 		value->v.integer = 0;
437 		for (i = 0; i <= ICMP_MAXTYPE; i++)
438 			value->v.integer += icmpstat.icps_outhist[i];
439 		value->v.integer += icmpstat.icps_badaddr +
440 		    icmpstat.icps_noroute;
441 		break;
442 
443 	  case LEAF_icmpOutErrors:
444 		value->v.integer = icmpstat.icps_badaddr +
445 		    icmpstat.icps_noroute;
446 		break;
447 
448 	  case LEAF_icmpOutDestUnreachs:
449 		value->v.integer = icmpstat.icps_outhist[ICMP_UNREACH];
450 		break;
451 
452 	  case LEAF_icmpOutTimeExcds:
453 		value->v.integer = icmpstat.icps_outhist[ICMP_TIMXCEED];
454 		break;
455 
456 	  case LEAF_icmpOutParmProbs:
457 		value->v.integer = icmpstat.icps_outhist[ICMP_PARAMPROB];
458 		break;
459 
460 	  case LEAF_icmpOutSrcQuenchs:
461 		value->v.integer = icmpstat.icps_outhist[ICMP_SOURCEQUENCH];
462 		break;
463 
464 	  case LEAF_icmpOutRedirects:
465 		value->v.integer = icmpstat.icps_outhist[ICMP_REDIRECT];
466 		break;
467 
468 	  case LEAF_icmpOutEchos:
469 		value->v.integer = icmpstat.icps_outhist[ICMP_ECHO];
470 		break;
471 
472 	  case LEAF_icmpOutEchoReps:
473 		value->v.integer = icmpstat.icps_outhist[ICMP_ECHOREPLY];
474 		break;
475 
476 	  case LEAF_icmpOutTimestamps:
477 		value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMP];
478 		break;
479 
480 	  case LEAF_icmpOutTimestampReps:
481 		value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMPREPLY];
482 		break;
483 
484 	  case LEAF_icmpOutAddrMasks:
485 		value->v.integer = icmpstat.icps_outhist[ICMP_MASKREQ];
486 		break;
487 
488 	  case LEAF_icmpOutAddrMaskReps:
489 		value->v.integer = icmpstat.icps_outhist[ICMP_MASKREPLY];
490 		break;
491 	}
492 	return (SNMP_ERR_NOERROR);
493 }
494