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