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 __P((u_char *, int));
15 static int writelength __P((u_char *, u_int));
16 static int maketrap_v2 __P((char *, u_char *, int, u_char *, int));
17 static void snmpv2_destroy __P((void *));
18 static void *snmpv2_dup __P((void *));
19 static int snmpv2_match __P((void *, void *));
20 static void *snmpv2_parse __P((char **));
21 static void snmpv2_print __P((void *));
22 static int snmpv2_send __P((void *, ipmon_msg_t *));
23
24
25 int sendtrap_v2_0 __P((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
snmpv2_match(ctx1,ctx2)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 *
snmpv2_dup(ctx)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
snmpv2_print(ctx)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 *
snmpv2_parse(char ** strings)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 return NULL;
129
130 ctx->fd = -1;
131
132 s = strchr(str, ' ');
133 *s++ = '\0';
134 ctx->community = str;
135
136 while (ISSPACE(*s))
137 s++;
138 if (!*s) {
139 free(str);
140 free(ctx);
141 return NULL;
142 }
143
144 #ifdef USE_INET6
145 if (strchr(s, ':') == NULL) {
146 result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
147 if (result == 1) {
148 ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
149 if (ctx->fd >= 0) {
150 ctx->sin.sin_family = AF_INET;
151 ctx->sin.sin_port = htons(162);
152 if (connect(ctx->fd,
153 (struct sockaddr *)&ctx->sin,
154 sizeof(ctx->sin)) != 0) {
155 snmpv2_destroy(ctx);
156 return NULL;
157 }
158 }
159 }
160 } else {
161 result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
162 if (result == 1) {
163 ctx->v6 = 1;
164 ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
165 if (ctx->fd >= 0) {
166 ctx->sin6.sin6_family = AF_INET6;
167 ctx->sin6.sin6_port = htons(162);
168 if (connect(ctx->fd,
169 (struct sockaddr *)&ctx->sin6,
170 sizeof(ctx->sin6)) != 0) {
171 snmpv2_destroy(ctx);
172 return NULL;
173 }
174 }
175 }
176 }
177 #else
178 result = inet_aton(s, &ctx->sin.sin_addr);
179 if (result == 1) {
180 ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
181 if (ctx->fd >= 0) {
182 ctx->sin.sin_family = AF_INET;
183 ctx->sin.sin_port = htons(162);
184 if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
185 sizeof(ctx->sin)) != 0) {
186 snmpv2_destroy(ctx);
187 return NULL;
188 }
189 }
190 }
191 #endif
192
193 if (result != 1) {
194 free(str);
195 free(ctx);
196 return NULL;
197 }
198
199 ctx->ref = 1;
200
201 return ctx;
202 }
203
204
205 static void
snmpv2_destroy(ctx)206 snmpv2_destroy(ctx)
207 void *ctx;
208 {
209 snmpv2_opts_t *v2 = ctx;
210
211 v2->ref--;
212 if (v2->ref > 0)
213 return;
214
215 if (v2->community)
216 free(v2->community);
217 if (v2->fd >= 0)
218 close(v2->fd);
219 free(v2);
220 }
221
222
223 static int
snmpv2_send(ctx,msg)224 snmpv2_send(ctx, msg)
225 void *ctx;
226 ipmon_msg_t *msg;
227 {
228 snmpv2_opts_t *v2 = ctx;
229
230 return sendtrap_v2_0(v2->fd, v2->community,
231 msg->imm_msg, msg->imm_msglen);
232 }
233 static int
writelength(buffer,value)234 writelength(buffer, value)
235 u_char *buffer;
236 u_int value;
237 {
238 u_int n = htonl(value);
239 int len;
240
241 if (value < 128) {
242 *buffer = value;
243 return 1;
244 }
245 if (value > 0xffffff)
246 len = 4;
247 else if (value > 0xffff)
248 len = 3;
249 else if (value > 0xff)
250 len = 2;
251 else
252 len = 1;
253
254 *buffer = 0x80 | len;
255
256 bcopy((u_char *)&n + 4 - len, buffer + 1, len);
257
258 return len + 1;
259 }
260
261
262 static int
writeint(buffer,value)263 writeint(buffer, value)
264 u_char *buffer;
265 int value;
266 {
267 u_char *s = buffer;
268 u_int n = value;
269
270 if (value == 0) {
271 *buffer = 0;
272 return 1;
273 }
274
275 if (n > 4194304) {
276 *s++ = 0x80 | (n / 4194304);
277 n -= 4194304 * (n / 4194304);
278 }
279 if (n > 32768) {
280 *s++ = 0x80 | (n / 32768);
281 n -= 32768 * (n / 327678);
282 }
283 if (n > 128) {
284 *s++ = 0x80 | (n / 128);
285 n -= (n / 128) * 128;
286 }
287 *s++ = (u_char)n;
288
289 return s - buffer;
290 }
291
292
293
294 /*
295 * First style of traps is:
296 * 1.3.6.1.4.1.9932.1.1
297 */
298 static int
maketrap_v2(community,buffer,bufsize,msg,msglen)299 maketrap_v2(community, buffer, bufsize, msg, msglen)
300 char *community;
301 u_char *buffer;
302 int bufsize;
303 u_char *msg;
304 int msglen;
305 {
306 u_char *s = buffer, *t, *pdulen;
307 u_char *varlen;
308 int basesize = 77;
309 u_short len;
310 int trapmsglen;
311 int pdulensz;
312 int varlensz;
313 int baselensz;
314 int n;
315
316 if (community == NULL || *community == '\0')
317 community = def_community;
318 basesize += strlen(community) + msglen;
319
320 if (basesize + 8 > bufsize)
321 return 0;
322
323 memset(buffer, 0xff, bufsize);
324 *s++ = 0x30; /* Sequence */
325
326 if (basesize - 1 >= 128) {
327 baselensz = 2;
328 basesize++;
329 } else {
330 baselensz = 1;
331 }
332 s += baselensz;
333 *s++ = 0x02; /* Integer32 */
334 *s++ = 0x01; /* length 1 */
335 *s++ = 0x01; /* version 2 */
336 *s++ = 0x04; /* octet string */
337 *s++ = strlen(community); /* length of "public" */
338 bcopy(community, s, s[-1]);
339 s += s[-1];
340 *s++ = 0xA7; /* PDU(7) */
341 pdulen = s++;
342 if (basesize - (s - buffer) >= 128) {
343 pdulensz = 2;
344 basesize++;
345 s++;
346 } else {
347 pdulensz = 1;
348 }
349 /* request id */
350 *s++ = 0x2; /* integer */
351 *s++ = 0x4; /* len 4 */
352 *s++ = 0x0; /* noError */
353 *s++ = 0x0; /* noError */
354 *s++ = 0x0; /* noError */
355 *s++ = 0x0; /* noError */
356
357 /* error status */
358 *s++ = 0x2; /* integer */
359 *s++ = 0x1; /* len 1 */
360 *s++ = 0x0; /* noError */
361
362 /* error-index */
363 *s++ = 0x2; /* integer */
364 *s++ = 0x1; /* len 1 */
365 *s++ = 0x0; /* noError */
366
367 *s++ = 0x30; /* sequence */
368 varlen = s++;
369 if (basesize - (s - buffer) >= 128) {
370 varlensz = 2;
371 basesize++;
372 s++;
373 } else {
374 varlensz = 1;
375 }
376
377 *s++ = 0x30; /* sequence */
378 *s++ = sizeof(sysuptime) + 6;
379
380 bcopy(sysuptime, s, sizeof(sysuptime));
381 s += sizeof(sysuptime);
382
383 *s++ = 0x43; /* Timestamp */
384 *s++ = 0x04; /* TimeTicks */
385 *s++ = 0x0;
386 *s++ = 0x0;
387 *s++ = 0x0;
388 *s++ = 0x0;
389
390 *s++ = 0x30;
391 t = s + 1;
392 bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
393 t += sizeof(ipf_trap0_1);
394
395 *t++ = 0x2; /* Integer */
396 n = writeint(t + 1, IPFILTER_VERSION);
397 *t = n;
398 t += n + 1;
399
400 len = t - s - 1;
401 writelength(s, len);
402
403 s = t;
404 *s++ = 0x30;
405 if (msglen < 128) {
406 if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128)
407 trapmsglen = 2;
408 else
409 trapmsglen = 1;
410 } else {
411 if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128)
412 trapmsglen = 2;
413 else
414 trapmsglen = 1;
415 }
416 t = s + trapmsglen;
417 bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
418 t += sizeof(ipf_trap0_2);
419
420 *t++ = 0x4; /* Octet string */
421 n = writelength(t, msglen);
422 t += n;
423 bcopy(msg, t, msglen);
424 t += msglen;
425
426 len = t - s - trapmsglen;
427 writelength(s, len);
428
429 len = t - varlen - varlensz;
430 writelength(varlen, len); /* pdu length */
431
432 len = t - pdulen - pdulensz;
433 writelength(pdulen, len); /* pdu length */
434
435 len = t - buffer - baselensz - 1;
436 writelength(buffer + 1, len); /* length of trap */
437
438 return t - buffer;
439 }
440
441
442 int
sendtrap_v2_0(fd,community,msg,msglen)443 sendtrap_v2_0(fd, community, msg, msglen)
444 int fd;
445 char *community, *msg;
446 int msglen;
447 {
448
449 u_char buffer[1500];
450 int n;
451
452 n = maketrap_v2(community, buffer, sizeof(buffer),
453 (u_char *)msg, msglen);
454 if (n > 0) {
455 return send(fd, buffer, n, 0);
456 }
457
458 return 0;
459 }
460