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
fetch_ipstat(void)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
fetch_ip(void)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
ip_forward(int forw,int * old)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
ip_setttl(int ttl,int * old)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
op_ip(struct snmp_context * ctx,struct snmp_value * value,u_int sub,u_int idx __unused,enum snmp_op op)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
op_ipstat(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int idx __unused,enum snmp_op op)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
op_icmpstat(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int idx __unused,enum snmp_op op)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