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