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