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
snmpv1_match(ctx1,ctx2)49 snmpv1_match(ctx1, ctx2)
50 void *ctx1, *ctx2;
51 {
52 snmpv1_opts_t *s1 = ctx1, *s2 = ctx2;
53
54 if (s1->v6 != s2->v6)
55 return 1;
56
57 if (strcmp(s1->community, s2->community))
58 return 1;
59
60 #ifdef USE_INET6
61 if (s1->v6 == 1) {
62 if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
63 return 1;
64 } else
65 #endif
66 {
67 if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
68 return 1;
69 }
70
71 return 0;
72 }
73
74
75 static void *
snmpv1_dup(ctx)76 snmpv1_dup(ctx)
77 void *ctx;
78 {
79 snmpv1_opts_t *s = ctx;
80
81 s->ref++;
82 return s;
83 }
84
85
86 static void
snmpv1_print(ctx)87 snmpv1_print(ctx)
88 void *ctx;
89 {
90 snmpv1_opts_t *snmpv1 = ctx;
91
92 printf("%s ", snmpv1->community);
93 #ifdef USE_INET6
94 if (snmpv1->v6 == 1) {
95 char buf[80];
96
97 printf("%s", inet_ntop(AF_INET6, &snmpv1->sin6.sin6_addr, buf,
98 sizeof(snmpv1->sin6.sin6_addr)));
99 } else
100 #endif
101 {
102 printf("%s", inet_ntoa(snmpv1->sin.sin_addr));
103 }
104 }
105
106
107 static void *
snmpv1_parse(char ** strings)108 snmpv1_parse(char **strings)
109 {
110 snmpv1_opts_t *ctx;
111 int result;
112 char *str;
113 char *s;
114
115 if (strings[0] == NULL || strings[0][0] == '\0')
116 return NULL;
117
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 return NULL;
126
127 ctx->fd = -1;
128
129 s = strchr(str, ' ');
130 *s++ = '\0';
131 ctx->community = str;
132
133 while (ISSPACE(*s))
134 s++;
135 if (!*s) {
136 free(str);
137 free(ctx);
138 return NULL;
139 }
140
141 #ifdef USE_INET6
142 if (strchr(s, ':') == NULL) {
143 result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
144 if (result == 1) {
145 ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
146 if (ctx->fd >= 0) {
147 ctx->sin.sin_family = AF_INET;
148 ctx->sin.sin_port = htons(162);
149 if (connect(ctx->fd,
150 (struct sockaddr *)&ctx->sin,
151 sizeof(ctx->sin)) != 0) {
152 snmpv1_destroy(ctx);
153 return NULL;
154 }
155 }
156 }
157 } else {
158 result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
159 if (result == 1) {
160 ctx->v6 = 1;
161 ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
162 if (ctx->fd >= 0) {
163 ctx->sin6.sin6_family = AF_INET6;
164 ctx->sin6.sin6_port = htons(162);
165 if (connect(ctx->fd,
166 (struct sockaddr *)&ctx->sin6,
167 sizeof(ctx->sin6)) != 0) {
168 snmpv1_destroy(ctx);
169 return NULL;
170 }
171 }
172 }
173 }
174 #else
175 result = inet_aton(s, &ctx->sin.sin_addr);
176 if (result == 1) {
177 ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
178 if (ctx->fd >= 0) {
179 ctx->sin.sin_family = AF_INET;
180 ctx->sin.sin_port = htons(162);
181 if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
182 sizeof(ctx->sin)) != 0) {
183 snmpv1_destroy(ctx);
184 return NULL;
185 }
186 }
187 }
188 #endif
189
190 if (result != 1) {
191 free(str);
192 free(ctx);
193 return NULL;
194 }
195
196 ctx->ref = 1;
197
198 return ctx;
199 }
200
201
202 static void
snmpv1_destroy(ctx)203 snmpv1_destroy(ctx)
204 void *ctx;
205 {
206 snmpv1_opts_t *v1 = ctx;
207
208 v1->ref--;
209 if (v1->ref > 0)
210 return;
211
212 if (v1->community)
213 free(v1->community);
214 if (v1->fd >= 0)
215 close(v1->fd);
216 free(v1);
217 }
218
219
220 static int
snmpv1_send(ctx,msg)221 snmpv1_send(ctx, msg)
222 void *ctx;
223 ipmon_msg_t *msg;
224 {
225 snmpv1_opts_t *v1 = ctx;
226
227 return sendtrap_v1_0(v1->fd, v1->community,
228 msg->imm_msg, msg->imm_msglen, msg->imm_when);
229 }
230
231 static char def_community[] = "public"; /* ublic */
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_v1(community,buffer,bufsize,msg,msglen,ipaddr,when)299 maketrap_v1(community, buffer, bufsize, msg, msglen, ipaddr, when)
300 char *community;
301 u_char *buffer;
302 int bufsize;
303 u_char *msg;
304 int msglen;
305 u_32_t ipaddr;
306 time_t when;
307 {
308 u_char *s = buffer, *t, *pdulen, *varlen;
309 int basesize = 73;
310 u_short len;
311 int trapmsglen;
312 int pdulensz;
313 int varlensz;
314 int baselensz;
315 int n;
316
317 if (community == NULL || *community == '\0')
318 community = def_community;
319 basesize += strlen(community) + msglen;
320
321 if (basesize + 8 > bufsize)
322 return 0;
323
324 memset(buffer, 0xff, bufsize);
325 *s++ = 0x30; /* Sequence */
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++ = 0x00; /* version 1 */
336 *s++ = 0x04; /* octet string */
337 *s++ = strlen(community); /* length of "public" */
338 bcopy(community, s, s[-1]);
339 s += s[-1];
340 *s++ = 0xA4; /* PDU(4) */
341 pdulen = s++;
342 if (basesize - (s - buffer) >= 128) {
343 pdulensz = 2;
344 basesize++;
345 s++;
346 } else {
347 pdulensz = 1;
348 }
349
350 /* enterprise */
351 bcopy(ipf_enterprise, s, sizeof(ipf_enterprise));
352 s += sizeof(ipf_enterprise);
353
354 /* Agent address */
355 *s++ = 0x40;
356 *s++ = 0x4;
357 bcopy(&ipaddr, s, 4);
358 s += 4;
359
360 /* Generic Trap code */
361 *s++ = 0x2;
362 n = writeint(s + 1, 6);
363 if (n == 0)
364 return 0;
365 *s = n;
366 s += n + 1;
367
368 /* Specific Trap code */
369 *s++ = 0x2;
370 n = writeint(s + 1, 0);
371 if (n == 0)
372 return 0;
373 *s = n;
374 s += n + 1;
375
376 /* Time stamp */
377 *s++ = 0x43; /* TimeTicks */
378 *s++ = 0x04; /* TimeTicks */
379 s[0] = when >> 24;
380 s[1] = when >> 16;
381 s[2] = when >> 8;
382 s[3] = when & 0xff;
383 s += 4;
384
385 /*
386 * The trap0 message is "ipfilter_version" followed by the message
387 */
388 *s++ = 0x30;
389 varlen = s;
390 if (basesize - (s - buffer) >= 128) {
391 varlensz = 2;
392 basesize++;
393 } else {
394 varlensz = 1;
395 }
396 s += varlensz;
397
398 *s++ = 0x30;
399 t = s + 1;
400 bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
401 t += sizeof(ipf_trap0_1);
402
403 *t++ = 0x2; /* Integer */
404 n = writeint(t + 1, IPFILTER_VERSION);
405 *t = n;
406 t += n + 1;
407
408 len = t - s - 1;
409 writelength(s, len);
410
411 s = t;
412 *s++ = 0x30;
413 if (basesize - (s - buffer) >= 128) {
414 trapmsglen = 2;
415 basesize++;
416 } else {
417 trapmsglen = 1;
418 }
419 t = s + trapmsglen;
420 bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
421 t += sizeof(ipf_trap0_2);
422
423 *t++ = 0x4; /* Octet string */
424 n = writelength(t, msglen);
425 t += n;
426 bcopy(msg, t, msglen);
427 t += msglen;
428
429 len = t - s - trapmsglen;
430 writelength(s, len);
431
432 len = t - varlen - varlensz;
433 writelength(varlen, len); /* pdu length */
434
435 len = t - pdulen - pdulensz;
436 writelength(pdulen, len); /* pdu length */
437
438 len = t - buffer - baselensz - 1;
439 writelength(buffer + 1, len); /* length of trap */
440
441 return t - buffer;
442 }
443
444
445 int
sendtrap_v1_0(fd,community,msg,msglen,when)446 sendtrap_v1_0(fd, community, msg, msglen, when)
447 int fd;
448 char *community, *msg;
449 int msglen;
450 time_t when;
451 {
452
453 u_char buffer[1500];
454 int n;
455
456 n = maketrap_v1(community, buffer, sizeof(buffer),
457 (u_char *)msg, msglen, 0, when);
458 if (n > 0) {
459 return send(fd, buffer, n, 0);
460 }
461
462 return 0;
463 }
464