xref: /NextBSD/contrib/ipfilter/lib/save_v2trap.c (revision e1dd16d965b177f109afb771e59432e36f335d0a)
1 #include "ipf.h"
2 #include "netinet/ipl.h"
3 #include "ipmon.h"
4 #include <ctype.h>
5 
6 static u_char sysuptime[] = { 6, 8, 0x2b, 6, 1, 2, 1, 1, 3, 0 };
7 /*
8  * Enterprise number OID:
9  * 1.3.6.1.4.1.9932
10  */
11 static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 };
12 static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 };
13 
14 static int writeint __P((u_char *, int));
15 static int writelength __P((u_char *, u_int));
16 static int maketrap_v2 __P((char *, u_char *, int, u_char *, int));
17 static void snmpv2_destroy __P((void *));
18 static void *snmpv2_dup __P((void *));
19 static int snmpv2_match __P((void *, void *));
20 static void *snmpv2_parse __P((char **));
21 static void snmpv2_print __P((void *));
22 static int snmpv2_send __P((void *, ipmon_msg_t *));
23 
24 
25 int sendtrap_v2_0 __P((int, char *, char *, int));
26 
27 static char def_community[] = "public";	/* ublic */
28 
29 typedef struct snmpv2_opts_s {
30 	char			*community;
31 	char			*server;
32 	int			fd;
33 	int			v6;
34 	int			ref;
35 #ifdef USE_INET6
36 	struct sockaddr_in6	sin6;
37 #endif
38 	struct sockaddr_in	sin;
39 } snmpv2_opts_t;
40 
41 ipmon_saver_t snmpv2saver = {
42 	"snmpv2",
43 	snmpv2_destroy,
44 	snmpv2_dup,		/* dup */
45 	snmpv2_match,		/* match */
46 	snmpv2_parse,
47 	snmpv2_print,
48 	snmpv2_send
49 };
50 
51 
52 static int
snmpv2_match(ctx1,ctx2)53 snmpv2_match(ctx1, ctx2)
54 	void *ctx1, *ctx2;
55 {
56 	snmpv2_opts_t *s1 = ctx1, *s2 = ctx2;
57 
58 	if (s1->v6 != s2->v6)
59 		return 1;
60 
61 	if (strcmp(s1->community, s2->community))
62 		return 1;
63 
64 #ifdef USE_INET6
65 	if (s1->v6 == 1) {
66 		if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
67 			return 1;
68 	} else
69 #endif
70 	{
71 		if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
72 			return 1;
73 	}
74 
75 	return 0;
76 }
77 
78 
79 static void *
snmpv2_dup(ctx)80 snmpv2_dup(ctx)
81 	void *ctx;
82 {
83 	snmpv2_opts_t *s = ctx;
84 
85 	s->ref++;
86 	return s;
87 }
88 
89 
90 static void
snmpv2_print(ctx)91 snmpv2_print(ctx)
92         void *ctx;
93 {
94 	snmpv2_opts_t *snmpv2 = ctx;
95 
96 	printf("%s ", snmpv2->community);
97 #ifdef USE_INET6
98 	if (snmpv2->v6 == 1) {
99 		char buf[80];
100 
101 		printf("%s", inet_ntop(AF_INET6, &snmpv2->sin6.sin6_addr, buf,
102 				       sizeof(snmpv2->sin6.sin6_addr)));
103 	} else
104 #endif
105 	{
106 		printf("%s", inet_ntoa(snmpv2->sin.sin_addr));
107 	}
108 }
109 
110 
111 static void *
snmpv2_parse(char ** strings)112 snmpv2_parse(char **strings)
113 {
114 	snmpv2_opts_t *ctx;
115 	int result;
116 	char *str;
117 	char *s;
118 
119 	if (strings[0] == NULL || strings[0][0] == '\0')
120 		return NULL;
121 	if (strchr(*strings, ' ') == NULL)
122 		return NULL;
123 
124 	str = strdup(*strings);
125 
126 	ctx = calloc(1, sizeof(*ctx));
127 	if (ctx == NULL)
128 		return NULL;
129 
130 	ctx->fd = -1;
131 
132 	s = strchr(str, ' ');
133 	*s++ = '\0';
134 	ctx->community = str;
135 
136 	while (ISSPACE(*s))
137 		s++;
138 	if (!*s) {
139 		free(str);
140 		free(ctx);
141 		return NULL;
142 	}
143 
144 #ifdef USE_INET6
145 	if (strchr(s, ':') == NULL) {
146 		result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
147 		if (result == 1) {
148 			ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
149 			if (ctx->fd >= 0) {
150 				ctx->sin.sin_family = AF_INET;
151 				ctx->sin.sin_port = htons(162);
152 				if (connect(ctx->fd,
153 					    (struct sockaddr *)&ctx->sin,
154 					    sizeof(ctx->sin)) != 0) {
155 						snmpv2_destroy(ctx);
156 						return NULL;
157 				}
158 			}
159 		}
160 	} else {
161 		result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
162 		if (result == 1) {
163 			ctx->v6 = 1;
164 			ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
165 			if (ctx->fd >= 0) {
166 				ctx->sin6.sin6_family = AF_INET6;
167 				ctx->sin6.sin6_port = htons(162);
168 				if (connect(ctx->fd,
169 					    (struct sockaddr *)&ctx->sin6,
170 					    sizeof(ctx->sin6)) != 0) {
171 						snmpv2_destroy(ctx);
172 						return NULL;
173 				}
174 			}
175 		}
176 	}
177 #else
178 	result = inet_aton(s, &ctx->sin.sin_addr);
179 	if (result == 1) {
180 		ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
181 		if (ctx->fd >= 0) {
182 			ctx->sin.sin_family = AF_INET;
183 			ctx->sin.sin_port = htons(162);
184 			if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
185 				    sizeof(ctx->sin)) != 0) {
186 					snmpv2_destroy(ctx);
187 					return NULL;
188 			}
189 		}
190 	}
191 #endif
192 
193 	if (result != 1) {
194 		free(str);
195 		free(ctx);
196 		return NULL;
197 	}
198 
199 	ctx->ref = 1;
200 
201 	return ctx;
202 }
203 
204 
205 static void
snmpv2_destroy(ctx)206 snmpv2_destroy(ctx)
207 	void *ctx;
208 {
209 	snmpv2_opts_t *v2 = ctx;
210 
211 	v2->ref--;
212 	if (v2->ref > 0)
213 		return;
214 
215 	if (v2->community)
216 		free(v2->community);
217 	if (v2->fd >= 0)
218 		close(v2->fd);
219 	free(v2);
220 }
221 
222 
223 static int
snmpv2_send(ctx,msg)224 snmpv2_send(ctx, msg)
225 	void *ctx;
226 	ipmon_msg_t *msg;
227 {
228 	snmpv2_opts_t *v2 = ctx;
229 
230 	return sendtrap_v2_0(v2->fd, v2->community,
231 			     msg->imm_msg, msg->imm_msglen);
232 }
233 static int
writelength(buffer,value)234 writelength(buffer, value)
235 	u_char *buffer;
236 	u_int value;
237 {
238 	u_int n = htonl(value);
239 	int len;
240 
241 	if (value < 128) {
242 		*buffer = value;
243 		return 1;
244 	}
245 	if (value > 0xffffff)
246 		len = 4;
247 	else if (value > 0xffff)
248 		len = 3;
249 	else if (value > 0xff)
250 		len = 2;
251 	else
252 		len = 1;
253 
254 	*buffer = 0x80 | len;
255 
256 	bcopy((u_char *)&n + 4 - len, buffer + 1, len);
257 
258 	return len + 1;
259 }
260 
261 
262 static int
writeint(buffer,value)263 writeint(buffer, value)
264 	u_char *buffer;
265 	int value;
266 {
267 	u_char *s = buffer;
268 	u_int n = value;
269 
270 	if (value == 0) {
271 		*buffer = 0;
272 		return 1;
273 	}
274 
275 	if (n >  4194304) {
276 		*s++ = 0x80 | (n / 4194304);
277 		n -= 4194304 * (n / 4194304);
278 	}
279 	if (n >  32768) {
280 		*s++ = 0x80 | (n / 32768);
281 		n -= 32768 * (n / 327678);
282 	}
283 	if (n > 128) {
284 		*s++ = 0x80 | (n / 128);
285 		n -= (n / 128) * 128;
286 	}
287 	*s++ = (u_char)n;
288 
289 	return s - buffer;
290 }
291 
292 
293 
294 /*
295  * First style of traps is:
296  * 1.3.6.1.4.1.9932.1.1
297  */
298 static int
maketrap_v2(community,buffer,bufsize,msg,msglen)299 maketrap_v2(community, buffer, bufsize, msg, msglen)
300 	char *community;
301 	u_char *buffer;
302 	int bufsize;
303 	u_char *msg;
304 	int msglen;
305 {
306 	u_char *s = buffer, *t, *pdulen;
307 	u_char *varlen;
308 	int basesize = 77;
309 	u_short len;
310 	int trapmsglen;
311 	int pdulensz;
312 	int varlensz;
313 	int baselensz;
314 	int n;
315 
316 	if (community == NULL || *community == '\0')
317 		community = def_community;
318 	basesize += strlen(community) + msglen;
319 
320 	if (basesize + 8 > bufsize)
321 		return 0;
322 
323 	memset(buffer, 0xff, bufsize);
324 	*s++ = 0x30;		/* Sequence */
325 
326 	if (basesize - 1 >= 128) {
327 		baselensz = 2;
328 		basesize++;
329 	} else {
330 		baselensz = 1;
331 	}
332 	s += baselensz;
333 	*s++ = 0x02;		/* Integer32 */
334 	*s++ = 0x01;		/* length 1 */
335 	*s++ = 0x01;		/* version 2 */
336 	*s++ = 0x04;		/* octet string */
337 	*s++ = strlen(community);		/* length of "public" */
338 	bcopy(community, s, s[-1]);
339 	s += s[-1];
340 	*s++ = 0xA7;		/* PDU(7) */
341 	pdulen = s++;
342 	if (basesize - (s - buffer) >= 128) {
343 		pdulensz = 2;
344 		basesize++;
345 		s++;
346 	} else {
347 		pdulensz = 1;
348 	}
349 	/* request id */
350 	*s++ = 0x2;	/* integer */
351 	*s++ = 0x4;	/* len 4 */
352 	*s++ = 0x0;	/* noError */
353 	*s++ = 0x0;	/* noError */
354 	*s++ = 0x0;	/* noError */
355 	*s++ = 0x0;	/* noError */
356 
357 	/* error status */
358 	*s++ = 0x2;	/* integer */
359 	*s++ = 0x1;	/* len 1 */
360 	*s++ = 0x0;	/* noError */
361 
362 	/* error-index */
363 	*s++ = 0x2;	/* integer */
364 	*s++ = 0x1;	/* len 1 */
365 	*s++ = 0x0;	/* noError */
366 
367 	*s++ = 0x30;	/* sequence */
368 	varlen = s++;
369 	if (basesize - (s - buffer) >= 128) {
370 		varlensz = 2;
371 		basesize++;
372 		s++;
373 	} else {
374 		varlensz = 1;
375 	}
376 
377 	*s++ = 0x30;	/* sequence */
378 	*s++ = sizeof(sysuptime) + 6;
379 
380 	bcopy(sysuptime, s, sizeof(sysuptime));
381 	s += sizeof(sysuptime);
382 
383 	*s++ = 0x43;	/* Timestamp */
384 	*s++ = 0x04;	/* TimeTicks */
385 	*s++ = 0x0;
386 	*s++ = 0x0;
387 	*s++ = 0x0;
388 	*s++ = 0x0;
389 
390 	*s++ = 0x30;
391 	t = s + 1;
392 	bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
393 	t += sizeof(ipf_trap0_1);
394 
395 	*t++ = 0x2;		/* Integer */
396 	n = writeint(t + 1, IPFILTER_VERSION);
397 	*t = n;
398 	t += n + 1;
399 
400 	len = t - s - 1;
401 	writelength(s, len);
402 
403 	s = t;
404 	*s++ = 0x30;
405 	if (msglen < 128) {
406 		if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128)
407 			trapmsglen = 2;
408 		else
409 			trapmsglen = 1;
410 	} else {
411 		if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128)
412 			trapmsglen = 2;
413 		else
414 			trapmsglen = 1;
415 	}
416 	t = s + trapmsglen;
417 	bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
418 	t += sizeof(ipf_trap0_2);
419 
420 	*t++ = 0x4;		/* Octet string */
421 	n = writelength(t, msglen);
422 	t += n;
423 	bcopy(msg, t, msglen);
424 	t += msglen;
425 
426 	len = t - s - trapmsglen;
427 	writelength(s, len);
428 
429 	len = t - varlen - varlensz;
430 	writelength(varlen, len);		/* pdu length */
431 
432 	len = t - pdulen - pdulensz;
433 	writelength(pdulen, len);		/* pdu length */
434 
435 	len = t - buffer - baselensz - 1;
436 	writelength(buffer + 1, len);	/* length of trap */
437 
438 	return t - buffer;
439 }
440 
441 
442 int
sendtrap_v2_0(fd,community,msg,msglen)443 sendtrap_v2_0(fd, community, msg, msglen)
444 	int fd;
445 	char *community, *msg;
446 	int msglen;
447 {
448 
449 	u_char buffer[1500];
450 	int n;
451 
452 	n = maketrap_v2(community, buffer, sizeof(buffer),
453 			(u_char *)msg, msglen);
454 	if (n > 0) {
455 		return send(fd, buffer, n, 0);
456 	}
457 
458 	return 0;
459 }
460