]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ipfilter/lib/save_v1trap.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ipfilter / lib / save_v1trap.c
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 __P((u_char *, int));
16 static int writelength __P((u_char *, u_int));
17 static int maketrap_v1 __P((char *, u_char *, int, u_char *, int, u_32_t,
18                             time_t));
19 static void snmpv1_destroy __P((void *));
20 static void *snmpv1_dup __P((void *));
21 static int snmpv1_match __P((void *, void *));
22 static void *snmpv1_parse __P((char **));
23 static void snmpv1_print __P((void *));
24 static int snmpv1_send __P((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
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 *
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
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 *
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
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
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
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
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
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
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 }