]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/ipfilter/lib/save_v2trap.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / contrib / ipfilter / lib / save_v2trap.c
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
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 *
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
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 *
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                 free(str);
129                 return NULL;
130         }
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
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
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
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
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
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
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 }