xref: /freebsd/sbin/ipf/libipf/save_v2trap.c (revision 4d846d26)
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(void *ctx1, void *ctx2)
54 {
55 	snmpv2_opts_t *s1 = ctx1, *s2 = ctx2;
56 
57 	if (s1->v6 != s2->v6)
58 		return (1);
59 
60 	if (strcmp(s1->community, s2->community))
61 		return (1);
62 
63 #ifdef USE_INET6
64 	if (s1->v6 == 1) {
65 		if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
66 			return (1);
67 	} else
68 #endif
69 	{
70 		if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
71 			return (1);
72 	}
73 
74 	return (0);
75 }
76 
77 
78 static void *
79 snmpv2_dup(void *ctx)
80 {
81 	snmpv2_opts_t *s = ctx;
82 
83 	s->ref++;
84 	return (s);
85 }
86 
87 
88 static void
89 snmpv2_print(void *ctx)
90 {
91 	snmpv2_opts_t *snmpv2 = ctx;
92 
93 	printf("%s ", snmpv2->community);
94 #ifdef USE_INET6
95 	if (snmpv2->v6 == 1) {
96 		char buf[80];
97 
98 		printf("%s", inet_ntop(AF_INET6, &snmpv2->sin6.sin6_addr, buf,
99 				       sizeof(snmpv2->sin6.sin6_addr)));
100 	} else
101 #endif
102 	{
103 		printf("%s", inet_ntoa(snmpv2->sin.sin_addr));
104 	}
105 }
106 
107 
108 static void *
109 snmpv2_parse(char **strings)
110 {
111 	snmpv2_opts_t *ctx;
112 	int result;
113 	char *str;
114 	char *s;
115 
116 	if (strings[0] == NULL || strings[0][0] == '\0')
117 		return (NULL);
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 		free(str);
126 		return (NULL);
127 	}
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 						snmpv2_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 						snmpv2_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 					snmpv2_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
205 snmpv2_destroy(void *ctx)
206 {
207 	snmpv2_opts_t *v2 = ctx;
208 
209 	v2->ref--;
210 	if (v2->ref > 0)
211 		return;
212 
213 	if (v2->community)
214 		free(v2->community);
215 	if (v2->fd >= 0)
216 		close(v2->fd);
217 	free(v2);
218 }
219 
220 
221 static int
222 snmpv2_send(void *ctx, ipmon_msg_t *msg)
223 {
224 	snmpv2_opts_t *v2 = ctx;
225 
226 	return (sendtrap_v2_0(v2->fd, v2->community,
227 			     msg->imm_msg, msg->imm_msglen));
228 }
229 static int
230 writelength(u_char *buffer, u_int value)
231 {
232 	u_int n = htonl(value);
233 	int len;
234 
235 	if (value < 128) {
236 		*buffer = value;
237 		return (1);
238 	}
239 	if (value > 0xffffff)
240 		len = 4;
241 	else if (value > 0xffff)
242 		len = 3;
243 	else if (value > 0xff)
244 		len = 2;
245 	else
246 		len = 1;
247 
248 	*buffer = 0x80 | len;
249 
250 	bcopy((u_char *)&n + 4 - len, buffer + 1, len);
251 
252 	return (len + 1);
253 }
254 
255 
256 static int
257 writeint(u_char *buffer, int value)
258 {
259 	u_char *s = buffer;
260 	u_int n = value;
261 
262 	if (value == 0) {
263 		*buffer = 0;
264 		return (1);
265 	}
266 
267 	if (n >  4194304) {
268 		*s++ = 0x80 | (n / 4194304);
269 		n -= 4194304 * (n / 4194304);
270 	}
271 	if (n >  32768) {
272 		*s++ = 0x80 | (n / 32768);
273 		n -= 32768 * (n / 327678);
274 	}
275 	if (n > 128) {
276 		*s++ = 0x80 | (n / 128);
277 		n -= (n / 128) * 128;
278 	}
279 	*s++ = (u_char)n;
280 
281 	return (s - buffer);
282 }
283 
284 
285 
286 /*
287  * First style of traps is:
288  * 1.3.6.1.4.1.9932.1.1
289  */
290 static int
291 maketrap_v2(char *community, u_char *buffer, int bufsize, u_char *msg,
292 	int msglen)
293 {
294 	u_char *s = buffer, *t, *pdulen;
295 	u_char *varlen;
296 	int basesize = 77;
297 	u_short len;
298 	int trapmsglen;
299 	int pdulensz;
300 	int varlensz;
301 	int baselensz;
302 	int n;
303 
304 	if (community == NULL || *community == '\0')
305 		community = def_community;
306 	basesize += strlen(community) + msglen;
307 
308 	if (basesize + 8 > bufsize)
309 		return (0);
310 
311 	memset(buffer, 0xff, bufsize);
312 	*s++ = 0x30;		/* Sequence */
313 
314 	if (basesize - 1 >= 128) {
315 		baselensz = 2;
316 		basesize++;
317 	} else {
318 		baselensz = 1;
319 	}
320 	s += baselensz;
321 	*s++ = 0x02;		/* Integer32 */
322 	*s++ = 0x01;		/* length 1 */
323 	*s++ = 0x01;		/* version 2 */
324 	*s++ = 0x04;		/* octet string */
325 	*s++ = strlen(community);		/* length of "public" */
326 	bcopy(community, s, s[-1]);
327 	s += s[-1];
328 	*s++ = 0xA7;		/* PDU(7) */
329 	pdulen = s++;
330 	if (basesize - (s - buffer) >= 128) {
331 		pdulensz = 2;
332 		basesize++;
333 		s++;
334 	} else {
335 		pdulensz = 1;
336 	}
337 	/* request id */
338 	*s++ = 0x2;	/* integer */
339 	*s++ = 0x4;	/* len 4 */
340 	*s++ = 0x0;	/* noError */
341 	*s++ = 0x0;	/* noError */
342 	*s++ = 0x0;	/* noError */
343 	*s++ = 0x0;	/* noError */
344 
345 	/* error status */
346 	*s++ = 0x2;	/* integer */
347 	*s++ = 0x1;	/* len 1 */
348 	*s++ = 0x0;	/* noError */
349 
350 	/* error-index */
351 	*s++ = 0x2;	/* integer */
352 	*s++ = 0x1;	/* len 1 */
353 	*s++ = 0x0;	/* noError */
354 
355 	*s++ = 0x30;	/* sequence */
356 	varlen = s++;
357 	if (basesize - (s - buffer) >= 128) {
358 		varlensz = 2;
359 		basesize++;
360 		s++;
361 	} else {
362 		varlensz = 1;
363 	}
364 
365 	*s++ = 0x30;	/* sequence */
366 	*s++ = sizeof(sysuptime) + 6;
367 
368 	bcopy(sysuptime, s, sizeof(sysuptime));
369 	s += sizeof(sysuptime);
370 
371 	*s++ = 0x43;	/* Timestamp */
372 	*s++ = 0x04;	/* TimeTicks */
373 	*s++ = 0x0;
374 	*s++ = 0x0;
375 	*s++ = 0x0;
376 	*s++ = 0x0;
377 
378 	*s++ = 0x30;
379 	t = s + 1;
380 	bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
381 	t += sizeof(ipf_trap0_1);
382 
383 	*t++ = 0x2;		/* Integer */
384 	n = writeint(t + 1, IPFILTER_VERSION);
385 	*t = n;
386 	t += n + 1;
387 
388 	len = t - s - 1;
389 	writelength(s, len);
390 
391 	s = t;
392 	*s++ = 0x30;
393 	if (msglen < 128) {
394 		if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128)
395 			trapmsglen = 2;
396 		else
397 			trapmsglen = 1;
398 	} else {
399 		if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128)
400 			trapmsglen = 2;
401 		else
402 			trapmsglen = 1;
403 	}
404 	t = s + trapmsglen;
405 	bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
406 	t += sizeof(ipf_trap0_2);
407 
408 	*t++ = 0x4;		/* Octet string */
409 	n = writelength(t, msglen);
410 	t += n;
411 	bcopy(msg, t, msglen);
412 	t += msglen;
413 
414 	len = t - s - trapmsglen;
415 	writelength(s, len);
416 
417 	len = t - varlen - varlensz;
418 	writelength(varlen, len);		/* pdu length */
419 
420 	len = t - pdulen - pdulensz;
421 	writelength(pdulen, len);		/* pdu length */
422 
423 	len = t - buffer - baselensz - 1;
424 	writelength(buffer + 1, len);	/* length of trap */
425 
426 	return (t - buffer);
427 }
428 
429 
430 int
431 sendtrap_v2_0(int fd, char *community, char *msg, int msglen)
432 {
433 
434 	u_char buffer[1500];
435 	int n;
436 
437 	n = maketrap_v2(community, buffer, sizeof(buffer),
438 			(u_char *)msg, msglen);
439 	if (n > 0) {
440 		return (send(fd, buffer, n, 0));
441 	}
442 
443 	return (0);
444 }
445