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(void * ctx1,void * ctx2)49 snmpv1_match(void *ctx1, void *ctx2)
50 {
51 snmpv1_opts_t *s1 = ctx1, *s2 = ctx2;
52
53 if (s1->v6 != s2->v6)
54 return (1);
55
56 if (strcmp(s1->community, s2->community))
57 return (1);
58
59 #ifdef USE_INET6
60 if (s1->v6 == 1) {
61 if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
62 return (1);
63 } else
64 #endif
65 {
66 if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
67 return (1);
68 }
69
70 return (0);
71 }
72
73
74 static void *
snmpv1_dup(void * ctx)75 snmpv1_dup(void *ctx)
76 {
77 snmpv1_opts_t *s = ctx;
78
79 s->ref++;
80 return (s);
81 }
82
83
84 static void
snmpv1_print(void * ctx)85 snmpv1_print(void *ctx)
86 {
87 snmpv1_opts_t *snmpv1 = ctx;
88
89 printf("%s ", snmpv1->community);
90 #ifdef USE_INET6
91 if (snmpv1->v6 == 1) {
92 char buf[80];
93
94 printf("%s", inet_ntop(AF_INET6, &snmpv1->sin6.sin6_addr, buf,
95 sizeof(snmpv1->sin6.sin6_addr)));
96 } else
97 #endif
98 {
99 printf("%s", inet_ntoa(snmpv1->sin.sin_addr));
100 }
101 }
102
103
104 static void *
snmpv1_parse(char ** strings)105 snmpv1_parse(char **strings)
106 {
107 snmpv1_opts_t *ctx;
108 int result;
109 char *str;
110 char *s;
111
112 if (strings[0] == NULL || strings[0][0] == '\0')
113 return (NULL);
114
115 if (strchr(*strings, ' ') == NULL)
116 return (NULL);
117
118 str = strdup(*strings);
119
120 ctx = calloc(1, sizeof(*ctx));
121 if (ctx == NULL)
122 return (NULL);
123
124 ctx->fd = -1;
125
126 s = strchr(str, ' ');
127 *s++ = '\0';
128 ctx->community = str;
129
130 while (ISSPACE(*s))
131 s++;
132 if (!*s) {
133 free(str);
134 free(ctx);
135 return (NULL);
136 }
137
138 #ifdef USE_INET6
139 if (strchr(s, ':') == NULL) {
140 result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
141 if (result == 1) {
142 ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
143 if (ctx->fd >= 0) {
144 ctx->sin.sin_family = AF_INET;
145 ctx->sin.sin_port = htons(162);
146 if (connect(ctx->fd,
147 (struct sockaddr *)&ctx->sin,
148 sizeof(ctx->sin)) != 0) {
149 snmpv1_destroy(ctx);
150 return (NULL);
151 }
152 }
153 }
154 } else {
155 result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
156 if (result == 1) {
157 ctx->v6 = 1;
158 ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
159 if (ctx->fd >= 0) {
160 ctx->sin6.sin6_family = AF_INET6;
161 ctx->sin6.sin6_port = htons(162);
162 if (connect(ctx->fd,
163 (struct sockaddr *)&ctx->sin6,
164 sizeof(ctx->sin6)) != 0) {
165 snmpv1_destroy(ctx);
166 return (NULL);
167 }
168 }
169 }
170 }
171 #else
172 result = inet_aton(s, &ctx->sin.sin_addr);
173 if (result == 1) {
174 ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
175 if (ctx->fd >= 0) {
176 ctx->sin.sin_family = AF_INET;
177 ctx->sin.sin_port = htons(162);
178 if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
179 sizeof(ctx->sin)) != 0) {
180 snmpv1_destroy(ctx);
181 return (NULL);
182 }
183 }
184 }
185 #endif
186
187 if (result != 1) {
188 free(str);
189 free(ctx);
190 return (NULL);
191 }
192
193 ctx->ref = 1;
194
195 return (ctx);
196 }
197
198
199 static void
snmpv1_destroy(void * ctx)200 snmpv1_destroy(void *ctx)
201 {
202 snmpv1_opts_t *v1 = ctx;
203
204 v1->ref--;
205 if (v1->ref > 0)
206 return;
207
208 if (v1->community)
209 free(v1->community);
210 if (v1->fd >= 0)
211 close(v1->fd);
212 free(v1);
213 }
214
215
216 static int
snmpv1_send(void * ctx,ipmon_msg_t * msg)217 snmpv1_send(void *ctx, ipmon_msg_t *msg)
218 {
219 snmpv1_opts_t *v1 = ctx;
220
221 return (sendtrap_v1_0(v1->fd, v1->community,
222 msg->imm_msg, msg->imm_msglen, msg->imm_when));
223 }
224
225 static char def_community[] = "public"; /* ublic */
226
227 static int
writelength(u_char * buffer,u_int value)228 writelength(u_char *buffer, u_int value)
229 {
230 u_int n = htonl(value);
231 int len;
232
233 if (value < 128) {
234 *buffer = value;
235 return (1);
236 }
237 if (value > 0xffffff)
238 len = 4;
239 else if (value > 0xffff)
240 len = 3;
241 else if (value > 0xff)
242 len = 2;
243 else
244 len = 1;
245
246 *buffer = 0x80 | len;
247
248 bcopy((u_char *)&n + 4 - len, buffer + 1, len);
249
250 return (len + 1);
251 }
252
253
254 static int
writeint(u_char * buffer,int value)255 writeint(u_char *buffer, int value)
256 {
257 u_char *s = buffer;
258 u_int n = value;
259
260 if (value == 0) {
261 *buffer = 0;
262 return (1);
263 }
264
265 if (n > 4194304) {
266 *s++ = 0x80 | (n / 4194304);
267 n -= 4194304 * (n / 4194304);
268 }
269 if (n > 32768) {
270 *s++ = 0x80 | (n / 32768);
271 n -= 32768 * (n / 327678);
272 }
273 if (n > 128) {
274 *s++ = 0x80 | (n / 128);
275 n -= (n / 128) * 128;
276 }
277 *s++ = (u_char)n;
278
279 return (s - buffer);
280 }
281
282
283
284 /*
285 * First style of traps is:
286 * 1.3.6.1.4.1.9932.1.1
287 */
288 static int
maketrap_v1(char * community,u_char * buffer,int bufsize,u_char * msg,int msglen,u_32_t ipaddr,time_t when)289 maketrap_v1(char *community, u_char *buffer, int bufsize, u_char *msg,
290 int msglen, u_32_t ipaddr, time_t when)
291 {
292 u_char *s = buffer, *t, *pdulen, *varlen;
293 int basesize = 73;
294 u_short len;
295 int trapmsglen;
296 int pdulensz;
297 int varlensz;
298 int baselensz;
299 int n;
300
301 if (community == NULL || *community == '\0')
302 community = def_community;
303 basesize += strlen(community) + msglen;
304
305 if (basesize + 8 > bufsize)
306 return (0);
307
308 memset(buffer, 0xff, bufsize);
309 *s++ = 0x30; /* Sequence */
310 if (basesize - 1 >= 128) {
311 baselensz = 2;
312 basesize++;
313 } else {
314 baselensz = 1;
315 }
316 s += baselensz;
317 *s++ = 0x02; /* Integer32 */
318 *s++ = 0x01; /* length 1 */
319 *s++ = 0x00; /* version 1 */
320 *s++ = 0x04; /* octet string */
321 *s++ = strlen(community); /* length of "public" */
322 bcopy(community, s, s[-1]);
323 s += s[-1];
324 *s++ = 0xA4; /* PDU(4) */
325 pdulen = s++;
326 if (basesize - (s - buffer) >= 128) {
327 pdulensz = 2;
328 basesize++;
329 s++;
330 } else {
331 pdulensz = 1;
332 }
333
334 /* enterprise */
335 bcopy(ipf_enterprise, s, sizeof(ipf_enterprise));
336 s += sizeof(ipf_enterprise);
337
338 /* Agent address */
339 *s++ = 0x40;
340 *s++ = 0x4;
341 bcopy(&ipaddr, s, 4);
342 s += 4;
343
344 /* Generic Trap code */
345 *s++ = 0x2;
346 n = writeint(s + 1, 6);
347 if (n == 0)
348 return (0);
349 *s = n;
350 s += n + 1;
351
352 /* Specific Trap code */
353 *s++ = 0x2;
354 n = writeint(s + 1, 0);
355 if (n == 0)
356 return (0);
357 *s = n;
358 s += n + 1;
359
360 /* Time stamp */
361 *s++ = 0x43; /* TimeTicks */
362 *s++ = 0x04; /* TimeTicks */
363 s[0] = when >> 24;
364 s[1] = when >> 16;
365 s[2] = when >> 8;
366 s[3] = when & 0xff;
367 s += 4;
368
369 /*
370 * The trap0 message is "ipfilter_version" followed by the message
371 */
372 *s++ = 0x30;
373 varlen = s;
374 if (basesize - (s - buffer) >= 128) {
375 varlensz = 2;
376 basesize++;
377 } else {
378 varlensz = 1;
379 }
380 s += varlensz;
381
382 *s++ = 0x30;
383 t = s + 1;
384 bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
385 t += sizeof(ipf_trap0_1);
386
387 *t++ = 0x2; /* Integer */
388 n = writeint(t + 1, IPFILTER_VERSION);
389 *t = n;
390 t += n + 1;
391
392 len = t - s - 1;
393 writelength(s, len);
394
395 s = t;
396 *s++ = 0x30;
397 if (basesize - (s - buffer) >= 128) {
398 trapmsglen = 2;
399 basesize++;
400 } else {
401 trapmsglen = 1;
402 }
403 t = s + trapmsglen;
404 bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
405 t += sizeof(ipf_trap0_2);
406
407 *t++ = 0x4; /* Octet string */
408 n = writelength(t, msglen);
409 t += n;
410 bcopy(msg, t, msglen);
411 t += msglen;
412
413 len = t - s - trapmsglen;
414 writelength(s, len);
415
416 len = t - varlen - varlensz;
417 writelength(varlen, len); /* pdu length */
418
419 len = t - pdulen - pdulensz;
420 writelength(pdulen, len); /* pdu length */
421
422 len = t - buffer - baselensz - 1;
423 writelength(buffer + 1, len); /* length of trap */
424
425 return (t - buffer);
426 }
427
428
429 int
sendtrap_v1_0(int fd,char * community,char * msg,int msglen,time_t when)430 sendtrap_v1_0(int fd, char *community, char *msg, int msglen, time_t when)
431 {
432
433 u_char buffer[1500];
434 int n;
435
436 n = maketrap_v1(community, buffer, sizeof(buffer),
437 (u_char *)msg, msglen, 0, when);
438 if (n > 0) {
439 return (send(fd, buffer, n, 0));
440 }
441
442 return (0);
443 }
444