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