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