1 /* $NetBSD: save_v2trap.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 static u_char sysuptime[] = { 6, 8, 0x2b, 6, 1, 2, 1, 1, 3, 0 };
9 /*
10 * Enterprise number OID:
11 * 1.3.6.1.4.1.9932
12 */
13 static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 };
14 static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 };
15
16 static int writeint __P((u_char *, int));
17 static int writelength __P((u_char *, u_int));
18 static int maketrap_v2 __P((char *, u_char *, int, u_char *, int));
19 static void snmpv2_destroy __P((void *));
20 static void *snmpv2_dup __P((void *));
21 static int snmpv2_match __P((void *, void *));
22 static void *snmpv2_parse __P((char **));
23 static void snmpv2_print __P((void *));
24 static int snmpv2_send __P((void *, ipmon_msg_t *));
25
26
27 int sendtrap_v2_0 __P((int, char *, char *, int));
28
29 static char def_community[] = "public"; /* ublic */
30
31 typedef struct snmpv2_opts_s {
32 char *community;
33 char *server;
34 int fd;
35 int v6;
36 int ref;
37 #ifdef USE_INET6
38 struct sockaddr_in6 sin6;
39 #endif
40 struct sockaddr_in sin;
41 } snmpv2_opts_t;
42
43 ipmon_saver_t snmpv2saver = {
44 "snmpv2",
45 snmpv2_destroy,
46 snmpv2_dup, /* dup */
47 snmpv2_match, /* match */
48 snmpv2_parse,
49 snmpv2_print,
50 snmpv2_send
51 };
52
53
54 static int
snmpv2_match(ctx1,ctx2)55 snmpv2_match(ctx1, ctx2)
56 void *ctx1, *ctx2;
57 {
58 snmpv2_opts_t *s1 = ctx1, *s2 = ctx2;
59
60 if (s1->v6 != s2->v6)
61 return 1;
62
63 if (strcmp(s1->community, s2->community))
64 return 1;
65
66 #ifdef USE_INET6
67 if (s1->v6 == 1) {
68 if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
69 return 1;
70 } else
71 #endif
72 {
73 if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
74 return 1;
75 }
76
77 return 0;
78 }
79
80
81 static void *
snmpv2_dup(ctx)82 snmpv2_dup(ctx)
83 void *ctx;
84 {
85 snmpv2_opts_t *s = ctx;
86
87 s->ref++;
88 return s;
89 }
90
91
92 static void
snmpv2_print(ctx)93 snmpv2_print(ctx)
94 void *ctx;
95 {
96 snmpv2_opts_t *snmpv2 = ctx;
97
98 printf("%s ", snmpv2->community);
99 #ifdef USE_INET6
100 if (snmpv2->v6 == 1) {
101 char buf[80];
102
103 printf("%s", inet_ntop(AF_INET6, &snmpv2->sin6.sin6_addr, buf,
104 sizeof(snmpv2->sin6.sin6_addr)));
105 } else
106 #endif
107 {
108 printf("%s", inet_ntoa(snmpv2->sin.sin_addr));
109 }
110 }
111
112
113 static void *
snmpv2_parse(char ** strings)114 snmpv2_parse(char **strings)
115 {
116 snmpv2_opts_t *ctx;
117 int result;
118 char *str;
119 char *s;
120
121 if (strings[0] == NULL || strings[0][0] == '\0')
122 return NULL;
123 if (strchr(*strings, ' ') == NULL)
124 return NULL;
125
126 str = strdup(*strings);
127
128 ctx = calloc(1, sizeof(*ctx));
129 if (ctx == NULL)
130 return NULL;
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
snmpv2_destroy(ctx)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
snmpv2_send(ctx,msg)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
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_v2(community,buffer,bufsize,msg,msglen)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
sendtrap_v2_0(fd,community,msg,msglen)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