mibII_ip.c revision 122394
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.8 2003/01/28 13:44:35 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
45static struct ipstat ipstat;
46static u_int	ip_idrop;
47static struct icmpstat icmpstat;
48
49static int	ip_forwarding;
50static int	ip_defttl;
51static u_int32_t ip_tick;
52
53static u_int32_t ipstat_tick;
54
55static int
56fetch_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
90static int
91fetch_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
121static int
122ip_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
136static int
137ip_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 */
154int
155op_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 */
247int
248op_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 */
350int
351op_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