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