xref: /freebsd/sbin/ipf/libipf/save_v2trap.c (revision b3d14eaccc5f606690d99b1998bfdf32a22404f6)
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(u_char *, int);
15 static int writelength(u_char *, u_int);
16 static int maketrap_v2(char *, u_char *, int, u_char *, int);
17 static void snmpv2_destroy(void *);
18 static void *snmpv2_dup(void *);
19 static int snmpv2_match(void *, void *);
20 static void *snmpv2_parse(char **);
21 static void snmpv2_print(void *);
22 static int snmpv2_send(void *, ipmon_msg_t *);
23 
24 
25 int sendtrap_v2_0(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
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 *
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
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 *
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 		free(str);
129 		return NULL;
130 	}
131 
132 	ctx->fd = -1;
133 
134 	s = strchr(str, ' ');
135 	*s++ = '\0';
136 	ctx->community = str;
137 
138 	while (ISSPACE(*s))
139 		s++;
140 	if (!*s) {
141 		free(str);
142 		free(ctx);
143 		return NULL;
144 	}
145 
146 #ifdef USE_INET6
147 	if (strchr(s, ':') == NULL) {
148 		result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
149 		if (result == 1) {
150 			ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
151 			if (ctx->fd >= 0) {
152 				ctx->sin.sin_family = AF_INET;
153 				ctx->sin.sin_port = htons(162);
154 				if (connect(ctx->fd,
155 					    (struct sockaddr *)&ctx->sin,
156 					    sizeof(ctx->sin)) != 0) {
157 						snmpv2_destroy(ctx);
158 						return NULL;
159 				}
160 			}
161 		}
162 	} else {
163 		result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
164 		if (result == 1) {
165 			ctx->v6 = 1;
166 			ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
167 			if (ctx->fd >= 0) {
168 				ctx->sin6.sin6_family = AF_INET6;
169 				ctx->sin6.sin6_port = htons(162);
170 				if (connect(ctx->fd,
171 					    (struct sockaddr *)&ctx->sin6,
172 					    sizeof(ctx->sin6)) != 0) {
173 						snmpv2_destroy(ctx);
174 						return NULL;
175 				}
176 			}
177 		}
178 	}
179 #else
180 	result = inet_aton(s, &ctx->sin.sin_addr);
181 	if (result == 1) {
182 		ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
183 		if (ctx->fd >= 0) {
184 			ctx->sin.sin_family = AF_INET;
185 			ctx->sin.sin_port = htons(162);
186 			if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
187 				    sizeof(ctx->sin)) != 0) {
188 					snmpv2_destroy(ctx);
189 					return NULL;
190 			}
191 		}
192 	}
193 #endif
194 
195 	if (result != 1) {
196 		free(str);
197 		free(ctx);
198 		return NULL;
199 	}
200 
201 	ctx->ref = 1;
202 
203 	return ctx;
204 }
205 
206 
207 static void
208 snmpv2_destroy(ctx)
209 	void *ctx;
210 {
211 	snmpv2_opts_t *v2 = ctx;
212 
213 	v2->ref--;
214 	if (v2->ref > 0)
215 		return;
216 
217 	if (v2->community)
218 		free(v2->community);
219 	if (v2->fd >= 0)
220 		close(v2->fd);
221 	free(v2);
222 }
223 
224 
225 static int
226 snmpv2_send(ctx, msg)
227 	void *ctx;
228 	ipmon_msg_t *msg;
229 {
230 	snmpv2_opts_t *v2 = ctx;
231 
232 	return sendtrap_v2_0(v2->fd, v2->community,
233 			     msg->imm_msg, msg->imm_msglen);
234 }
235 static int
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
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
301 maketrap_v2(community, buffer, bufsize, msg, msglen)
302 	char *community;
303 	u_char *buffer;
304 	int bufsize;
305 	u_char *msg;
306 	int msglen;
307 {
308 	u_char *s = buffer, *t, *pdulen;
309 	u_char *varlen;
310 	int basesize = 77;
311 	u_short len;
312 	int trapmsglen;
313 	int pdulensz;
314 	int varlensz;
315 	int baselensz;
316 	int n;
317 
318 	if (community == NULL || *community == '\0')
319 		community = def_community;
320 	basesize += strlen(community) + msglen;
321 
322 	if (basesize + 8 > bufsize)
323 		return 0;
324 
325 	memset(buffer, 0xff, bufsize);
326 	*s++ = 0x30;		/* Sequence */
327 
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++ = 0x01;		/* version 2 */
338 	*s++ = 0x04;		/* octet string */
339 	*s++ = strlen(community);		/* length of "public" */
340 	bcopy(community, s, s[-1]);
341 	s += s[-1];
342 	*s++ = 0xA7;		/* PDU(7) */
343 	pdulen = s++;
344 	if (basesize - (s - buffer) >= 128) {
345 		pdulensz = 2;
346 		basesize++;
347 		s++;
348 	} else {
349 		pdulensz = 1;
350 	}
351 	/* request id */
352 	*s++ = 0x2;	/* integer */
353 	*s++ = 0x4;	/* len 4 */
354 	*s++ = 0x0;	/* noError */
355 	*s++ = 0x0;	/* noError */
356 	*s++ = 0x0;	/* noError */
357 	*s++ = 0x0;	/* noError */
358 
359 	/* error status */
360 	*s++ = 0x2;	/* integer */
361 	*s++ = 0x1;	/* len 1 */
362 	*s++ = 0x0;	/* noError */
363 
364 	/* error-index */
365 	*s++ = 0x2;	/* integer */
366 	*s++ = 0x1;	/* len 1 */
367 	*s++ = 0x0;	/* noError */
368 
369 	*s++ = 0x30;	/* sequence */
370 	varlen = s++;
371 	if (basesize - (s - buffer) >= 128) {
372 		varlensz = 2;
373 		basesize++;
374 		s++;
375 	} else {
376 		varlensz = 1;
377 	}
378 
379 	*s++ = 0x30;	/* sequence */
380 	*s++ = sizeof(sysuptime) + 6;
381 
382 	bcopy(sysuptime, s, sizeof(sysuptime));
383 	s += sizeof(sysuptime);
384 
385 	*s++ = 0x43;	/* Timestamp */
386 	*s++ = 0x04;	/* TimeTicks */
387 	*s++ = 0x0;
388 	*s++ = 0x0;
389 	*s++ = 0x0;
390 	*s++ = 0x0;
391 
392 	*s++ = 0x30;
393 	t = s + 1;
394 	bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
395 	t += sizeof(ipf_trap0_1);
396 
397 	*t++ = 0x2;		/* Integer */
398 	n = writeint(t + 1, IPFILTER_VERSION);
399 	*t = n;
400 	t += n + 1;
401 
402 	len = t - s - 1;
403 	writelength(s, len);
404 
405 	s = t;
406 	*s++ = 0x30;
407 	if (msglen < 128) {
408 		if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128)
409 			trapmsglen = 2;
410 		else
411 			trapmsglen = 1;
412 	} else {
413 		if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128)
414 			trapmsglen = 2;
415 		else
416 			trapmsglen = 1;
417 	}
418 	t = s + trapmsglen;
419 	bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
420 	t += sizeof(ipf_trap0_2);
421 
422 	*t++ = 0x4;		/* Octet string */
423 	n = writelength(t, msglen);
424 	t += n;
425 	bcopy(msg, t, msglen);
426 	t += msglen;
427 
428 	len = t - s - trapmsglen;
429 	writelength(s, len);
430 
431 	len = t - varlen - varlensz;
432 	writelength(varlen, len);		/* pdu length */
433 
434 	len = t - pdulen - pdulensz;
435 	writelength(pdulen, len);		/* pdu length */
436 
437 	len = t - buffer - baselensz - 1;
438 	writelength(buffer + 1, len);	/* length of trap */
439 
440 	return t - buffer;
441 }
442 
443 
444 int
445 sendtrap_v2_0(fd, community, msg, msglen)
446 	int fd;
447 	char *community, *msg;
448 	int msglen;
449 {
450 
451 	u_char buffer[1500];
452 	int n;
453 
454 	n = maketrap_v2(community, buffer, sizeof(buffer),
455 			(u_char *)msg, msglen);
456 	if (n > 0) {
457 		return send(fd, buffer, n, 0);
458 	}
459 
460 	return 0;
461 }
462