xref: /freebsd/contrib/bsnmp/snmp_mibII/mibII_ip.c (revision e0c4386e)
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 u_int	ip_fragttl;
48 static uint64_t ip_tick;
49 
50 static uint64_t ipstat_tick;
51 
52 static int
53 fetch_ipstat(void)
54 {
55 	size_t len;
56 
57 	len = sizeof(ipstat);
58 	if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, NULL, 0) == -1) {
59 		syslog(LOG_ERR, "net.inet.ip.stats: %m");
60 		return (-1);
61 	}
62 	if (len != sizeof(ipstat)) {
63 		syslog(LOG_ERR, "net.inet.ip.stats: wrong size");
64 		return (-1);
65 	}
66 	len = sizeof(ip_idrop);
67 	if (sysctlbyname("net.inet.ip.intr_queue_drops", &ip_idrop, &len, NULL, 0) == -1)
68 		syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: %m");
69 	if (len != sizeof(ip_idrop)) {
70 		syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: wrong size");
71 		ip_idrop = 0;
72 	}
73 	len = sizeof(icmpstat);
74 	if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &len, NULL, 0) == -1) {
75 		syslog(LOG_ERR, "net.inet.icmp.stats: %m");
76 		return (-1);
77 	}
78 	if (len != sizeof(icmpstat)) {
79 		syslog(LOG_ERR, "net.inet.icmp.stats: wrong size");
80 		return (-1);
81 	}
82 
83 	len = sizeof(ip_fragttl);
84 	if (sysctlbyname("net.inet.ip.fragttl", &ip_fragttl, &len,
85 	    NULL, 0) == -1) {
86 		syslog(LOG_ERR, "net.inet.ip.fragttl: %m");
87 		return (-1);
88 	}
89 	if (len != sizeof(ip_fragttl)) {
90 		syslog(LOG_ERR, "net.inet.ip.fragttl: wrong size");
91 		return (-1);
92 	}
93 
94 	ipstat_tick = get_ticks();
95 	return (0);
96 }
97 
98 static int
99 fetch_ip(void)
100 {
101 	size_t len;
102 
103 	len = sizeof(ip_forwarding);
104 	if (sysctlbyname("net.inet.ip.forwarding", &ip_forwarding, &len,
105 	    NULL, 0) == -1) {
106 		syslog(LOG_ERR, "net.inet.ip.forwarding: %m");
107 		return (-1);
108 	}
109 	if (len != sizeof(ip_forwarding)) {
110 		syslog(LOG_ERR, "net.inet.ip.forwarding: wrong size");
111 		return (-1);
112 	}
113 
114 	len = sizeof(ip_defttl);
115 	if (sysctlbyname("net.inet.ip.ttl", &ip_defttl, &len,
116 	    NULL, 0) == -1) {
117 		syslog(LOG_ERR, "net.inet.ip.ttl: %m");
118 		return (-1);
119 	}
120 	if (len != sizeof(ip_defttl)) {
121 		syslog(LOG_ERR, "net.inet.ip.ttl: wrong size");
122 		return (-1);
123 	}
124 
125 	ip_tick = get_ticks();
126 	return (0);
127 }
128 
129 static int
130 ip_forward(int forw, int *old)
131 {
132 	size_t olen;
133 
134 	olen = sizeof(*old);
135 	if (sysctlbyname("net.inet.ip.forwarding", old, old ? &olen : NULL,
136 	    &forw, sizeof(forw)) == -1) {
137 		syslog(LOG_ERR, "set net.inet.ip.forwarding: %m");
138 		return (-1);
139 	}
140 	ip_forwarding = forw;
141 	return (0);
142 }
143 
144 static int
145 ip_setttl(int ttl, int *old)
146 {
147 	size_t olen;
148 
149 	olen = sizeof(*old);
150 	if (sysctlbyname("net.inet.ip.ttl", old, old ? &olen : NULL,
151 	    &ttl, sizeof(ttl)) == -1) {
152 		syslog(LOG_ERR, "set net.inet.ip.ttl: %m");
153 		return (-1);
154 	}
155 	ip_defttl = ttl;
156 	return (0);
157 }
158 
159 /*
160  * READ/WRITE ip group.
161  */
162 int
163 op_ip(struct snmp_context *ctx, struct snmp_value *value,
164     u_int sub, u_int idx __unused, enum snmp_op op)
165 {
166 	int old = 0;
167 
168 	switch (op) {
169 
170 	  case SNMP_OP_GETNEXT:
171 		abort();
172 
173 	  case SNMP_OP_GET:
174 		break;
175 
176 	  case SNMP_OP_SET:
177 		if (ip_tick < this_tick)
178 			if (fetch_ip() == -1)
179 				return (SNMP_ERR_GENERR);
180 
181 		switch (value->var.subs[sub - 1]) {
182 
183 		  case LEAF_ipForwarding:
184 			ctx->scratch->int1 = ip_forwarding ? 1 : 2;
185 			ctx->scratch->int2 = value->v.integer;
186 			if (value->v.integer == 1) {
187 				if (!ip_forwarding && ip_forward(1, &old))
188 					return (SNMP_ERR_GENERR);
189 				ctx->scratch->int1 = old ? 1 : 2;
190 			} else if (value->v.integer == 2) {
191 				if (ip_forwarding && ip_forward(0, &old))
192 					return (SNMP_ERR_GENERR);
193 				ctx->scratch->int1 = old;
194 			} else
195 				return (SNMP_ERR_WRONG_VALUE);
196 			break;
197 
198 		  case LEAF_ipDefaultTTL:
199 			ctx->scratch->int1 = ip_defttl;
200 			ctx->scratch->int2 = value->v.integer;
201 			if (value->v.integer < 1 || value->v.integer > 255)
202 				return (SNMP_ERR_WRONG_VALUE);
203 			if (ip_defttl != value->v.integer &&
204 			    ip_setttl(value->v.integer, &old))
205 				return (SNMP_ERR_GENERR);
206 			ctx->scratch->int1 = old;
207 			break;
208 		}
209 		return (SNMP_ERR_NOERROR);
210 
211 	  case SNMP_OP_ROLLBACK:
212 		switch (value->var.subs[sub - 1]) {
213 
214 		  case LEAF_ipForwarding:
215 			if (ctx->scratch->int1 == 1) {
216 				if (ctx->scratch->int2 == 2)
217 					(void)ip_forward(1, NULL);
218 			} else {
219 				if (ctx->scratch->int2 == 1)
220 					(void)ip_forward(0, NULL);
221 			}
222 			break;
223 
224 		  case LEAF_ipDefaultTTL:
225 			if (ctx->scratch->int1 != ctx->scratch->int2)
226 				(void)ip_setttl(ctx->scratch->int1, NULL);
227 			break;
228 		}
229 		return (SNMP_ERR_NOERROR);
230 
231 	  case SNMP_OP_COMMIT:
232 		return (SNMP_ERR_NOERROR);
233 	}
234 
235 	if (ip_tick < this_tick)
236 		if (fetch_ip() == -1)
237 			return (SNMP_ERR_GENERR);
238 
239 	switch (value->var.subs[sub - 1]) {
240 
241 	  case LEAF_ipForwarding:
242 		value->v.integer = ip_forwarding ? 1 : 2;
243 		break;
244 
245 	  case LEAF_ipDefaultTTL:
246 		value->v.integer = ip_defttl;
247 		break;
248 	}
249 	return (SNMP_ERR_NOERROR);
250 }
251 
252 /*
253  * READ-ONLY statistics ip group.
254  */
255 int
256 op_ipstat(struct snmp_context *ctx __unused, struct snmp_value *value,
257     u_int sub, u_int idx __unused, enum snmp_op op)
258 {
259 	switch (op) {
260 
261 	  case SNMP_OP_GETNEXT:
262 		abort();
263 
264 	  case SNMP_OP_GET:
265 		break;
266 
267 	  case SNMP_OP_SET:
268 		return (SNMP_ERR_NOT_WRITEABLE);
269 
270 	  case SNMP_OP_ROLLBACK:
271 	  case SNMP_OP_COMMIT:
272 		abort();
273 	}
274 
275 	if (ipstat_tick < this_tick)
276 		fetch_ipstat();
277 
278 	switch (value->var.subs[sub - 1]) {
279 
280 	  case LEAF_ipInReceives:
281 		value->v.uint32 = ipstat.ips_total;
282 		break;
283 
284 	  case LEAF_ipInHdrErrors:
285 		value->v.uint32 = ipstat.ips_badsum + ipstat.ips_tooshort
286 		    + ipstat.ips_toosmall + ipstat.ips_badhlen
287 		    + ipstat.ips_badlen + ipstat.ips_badvers +
288 		    + ipstat.ips_toolong;
289 		break;
290 
291 	  case LEAF_ipInAddrErrors:
292 		value->v.uint32 = ipstat.ips_cantforward;
293 		break;
294 
295 	  case LEAF_ipForwDatagrams:
296 		value->v.uint32 = ipstat.ips_forward;
297 		break;
298 
299 	  case LEAF_ipInUnknownProtos:
300 		value->v.uint32 = ipstat.ips_noproto;
301 		break;
302 
303 	  case LEAF_ipInDiscards:
304 		value->v.uint32 = ip_idrop;
305 		break;
306 
307 	  case LEAF_ipInDelivers:
308 		value->v.uint32 = ipstat.ips_delivered;
309 		break;
310 
311 	  case LEAF_ipOutRequests:
312 		value->v.uint32 = ipstat.ips_localout;
313 		break;
314 
315 	  case LEAF_ipOutDiscards:
316 		value->v.uint32 = ipstat.ips_odropped;
317 		break;
318 
319 	  case LEAF_ipOutNoRoutes:
320 		value->v.uint32 = ipstat.ips_noroute;
321 		break;
322 
323 	  case LEAF_ipReasmTimeout:
324 		value->v.integer = ip_fragttl;
325 		break;
326 
327 	  case LEAF_ipReasmReqds:
328 		value->v.uint32 = ipstat.ips_fragments;
329 		break;
330 
331 	  case LEAF_ipReasmOKs:
332 		value->v.uint32 = ipstat.ips_reassembled;
333 		break;
334 
335 	  case LEAF_ipReasmFails:
336 		value->v.uint32 = ipstat.ips_fragdropped
337 		    + ipstat.ips_fragtimeout;
338 		break;
339 
340 	  case LEAF_ipFragOKs:
341 		value->v.uint32 = ipstat.ips_fragmented;
342 		break;
343 
344 	  case LEAF_ipFragFails:
345 		value->v.uint32 = ipstat.ips_cantfrag;
346 		break;
347 
348 	  case LEAF_ipFragCreates:
349 		value->v.uint32 = ipstat.ips_ofragments;
350 		break;
351 	}
352 	return (SNMP_ERR_NOERROR);
353 }
354 
355 /*
356  * READ-ONLY statistics icmp group.
357  */
358 int
359 op_icmpstat(struct snmp_context *ctx __unused, struct snmp_value *value,
360     u_int sub, u_int idx __unused, enum snmp_op op)
361 {
362 	u_int i;
363 
364 	switch (op) {
365 
366 	  case SNMP_OP_GETNEXT:
367 		abort();
368 
369 	  case SNMP_OP_GET:
370 		break;
371 
372 	  case SNMP_OP_SET:
373 		return (SNMP_ERR_NOT_WRITEABLE);
374 
375 	  case SNMP_OP_ROLLBACK:
376 	  case SNMP_OP_COMMIT:
377 		abort();
378 	}
379 
380 	if (ipstat_tick < this_tick)
381 		fetch_ipstat();
382 
383 	switch (value->var.subs[sub - 1]) {
384 
385 	  case LEAF_icmpInMsgs:
386 		value->v.integer = 0;
387 		for (i = 0; i <= ICMP_MAXTYPE; i++)
388 			value->v.integer += icmpstat.icps_inhist[i];
389 		value->v.integer += icmpstat.icps_tooshort +
390 		    icmpstat.icps_checksum;
391 		/* missing: bad type and packets on faith */
392 		break;
393 
394 	  case LEAF_icmpInErrors:
395 		value->v.integer = icmpstat.icps_tooshort +
396 		    icmpstat.icps_checksum +
397 		    icmpstat.icps_badlen +
398 		    icmpstat.icps_badcode +
399 		    icmpstat.icps_bmcastecho +
400 		    icmpstat.icps_bmcasttstamp;
401 		break;
402 
403 	  case LEAF_icmpInDestUnreachs:
404 		value->v.integer = icmpstat.icps_inhist[ICMP_UNREACH];
405 		break;
406 
407 	  case LEAF_icmpInTimeExcds:
408 		value->v.integer = icmpstat.icps_inhist[ICMP_TIMXCEED];
409 		break;
410 
411 	  case LEAF_icmpInParmProbs:
412 		value->v.integer = icmpstat.icps_inhist[ICMP_PARAMPROB];
413 		break;
414 
415 	  case LEAF_icmpInSrcQuenchs:
416 		value->v.integer = icmpstat.icps_inhist[ICMP_SOURCEQUENCH];
417 		break;
418 
419 	  case LEAF_icmpInRedirects:
420 		value->v.integer = icmpstat.icps_inhist[ICMP_REDIRECT];
421 		break;
422 
423 	  case LEAF_icmpInEchos:
424 		value->v.integer = icmpstat.icps_inhist[ICMP_ECHO];
425 		break;
426 
427 	  case LEAF_icmpInEchoReps:
428 		value->v.integer = icmpstat.icps_inhist[ICMP_ECHOREPLY];
429 		break;
430 
431 	  case LEAF_icmpInTimestamps:
432 		value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMP];
433 		break;
434 
435 	  case LEAF_icmpInTimestampReps:
436 		value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMPREPLY];
437 		break;
438 
439 	  case LEAF_icmpInAddrMasks:
440 		value->v.integer = icmpstat.icps_inhist[ICMP_MASKREQ];
441 		break;
442 
443 	  case LEAF_icmpInAddrMaskReps:
444 		value->v.integer = icmpstat.icps_inhist[ICMP_MASKREPLY];
445 		break;
446 
447 	  case LEAF_icmpOutMsgs:
448 		value->v.integer = 0;
449 		for (i = 0; i <= ICMP_MAXTYPE; i++)
450 			value->v.integer += icmpstat.icps_outhist[i];
451 		value->v.integer += icmpstat.icps_badaddr +
452 		    icmpstat.icps_noroute;
453 		break;
454 
455 	  case LEAF_icmpOutErrors:
456 		value->v.integer = icmpstat.icps_badaddr +
457 		    icmpstat.icps_noroute;
458 		break;
459 
460 	  case LEAF_icmpOutDestUnreachs:
461 		value->v.integer = icmpstat.icps_outhist[ICMP_UNREACH];
462 		break;
463 
464 	  case LEAF_icmpOutTimeExcds:
465 		value->v.integer = icmpstat.icps_outhist[ICMP_TIMXCEED];
466 		break;
467 
468 	  case LEAF_icmpOutParmProbs:
469 		value->v.integer = icmpstat.icps_outhist[ICMP_PARAMPROB];
470 		break;
471 
472 	  case LEAF_icmpOutSrcQuenchs:
473 		value->v.integer = icmpstat.icps_outhist[ICMP_SOURCEQUENCH];
474 		break;
475 
476 	  case LEAF_icmpOutRedirects:
477 		value->v.integer = icmpstat.icps_outhist[ICMP_REDIRECT];
478 		break;
479 
480 	  case LEAF_icmpOutEchos:
481 		value->v.integer = icmpstat.icps_outhist[ICMP_ECHO];
482 		break;
483 
484 	  case LEAF_icmpOutEchoReps:
485 		value->v.integer = icmpstat.icps_outhist[ICMP_ECHOREPLY];
486 		break;
487 
488 	  case LEAF_icmpOutTimestamps:
489 		value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMP];
490 		break;
491 
492 	  case LEAF_icmpOutTimestampReps:
493 		value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMPREPLY];
494 		break;
495 
496 	  case LEAF_icmpOutAddrMasks:
497 		value->v.integer = icmpstat.icps_outhist[ICMP_MASKREQ];
498 		break;
499 
500 	  case LEAF_icmpOutAddrMaskReps:
501 		value->v.integer = icmpstat.icps_outhist[ICMP_MASKREPLY];
502 		break;
503 	}
504 	return (SNMP_ERR_NOERROR);
505 }
506