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