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