/* $NetBSD: save_v2trap.c,v 1.2 2014/12/20 13:15:48 prlw1 Exp $ */ #include "ipf.h" #include "netinet/ipl.h" #include "ipmon.h" #include static u_char sysuptime[] = { 6, 8, 0x2b, 6, 1, 2, 1, 1, 3, 0 }; /* * Enterprise number OID: * 1.3.6.1.4.1.9932 */ static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 }; static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 }; static int writeint __P((u_char *, int)); static int writelength __P((u_char *, u_int)); static int maketrap_v2 __P((char *, u_char *, int, u_char *, int)); static void snmpv2_destroy __P((void *)); static void *snmpv2_dup __P((void *)); static int snmpv2_match __P((void *, void *)); static void *snmpv2_parse __P((char **)); static void snmpv2_print __P((void *)); static int snmpv2_send __P((void *, ipmon_msg_t *)); int sendtrap_v2_0 __P((int, char *, char *, int)); static char def_community[] = "public"; /* ublic */ typedef struct snmpv2_opts_s { char *community; char *server; int fd; int v6; int ref; #ifdef USE_INET6 struct sockaddr_in6 sin6; #endif struct sockaddr_in sin; } snmpv2_opts_t; ipmon_saver_t snmpv2saver = { "snmpv2", snmpv2_destroy, snmpv2_dup, /* dup */ snmpv2_match, /* match */ snmpv2_parse, snmpv2_print, snmpv2_send }; static int snmpv2_match(ctx1, ctx2) void *ctx1, *ctx2; { snmpv2_opts_t *s1 = ctx1, *s2 = ctx2; if (s1->v6 != s2->v6) return 1; if (strcmp(s1->community, s2->community)) return 1; #ifdef USE_INET6 if (s1->v6 == 1) { if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6))) return 1; } else #endif { if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin))) return 1; } return 0; } static void * snmpv2_dup(ctx) void *ctx; { snmpv2_opts_t *s = ctx; s->ref++; return s; } static void snmpv2_print(ctx) void *ctx; { snmpv2_opts_t *snmpv2 = ctx; printf("%s ", snmpv2->community); #ifdef USE_INET6 if (snmpv2->v6 == 1) { char buf[80]; printf("%s", inet_ntop(AF_INET6, &snmpv2->sin6.sin6_addr, buf, sizeof(snmpv2->sin6.sin6_addr))); } else #endif { printf("%s", inet_ntoa(snmpv2->sin.sin_addr)); } } static void * snmpv2_parse(char **strings) { snmpv2_opts_t *ctx; int result; char *str; char *s; if (strings[0] == NULL || strings[0][0] == '\0') return NULL; if (strchr(*strings, ' ') == NULL) return NULL; str = strdup(*strings); ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->fd = -1; s = strchr(str, ' '); *s++ = '\0'; ctx->community = str; while (ISSPACE(*s)) s++; if (!*s) { free(str); free(ctx); return NULL; } #ifdef USE_INET6 if (strchr(s, ':') == NULL) { result = inet_pton(AF_INET, s, &ctx->sin.sin_addr); if (result == 1) { ctx->fd = socket(AF_INET, SOCK_DGRAM, 0); if (ctx->fd >= 0) { ctx->sin.sin_family = AF_INET; ctx->sin.sin_port = htons(162); if (connect(ctx->fd, (struct sockaddr *)&ctx->sin, sizeof(ctx->sin)) != 0) { snmpv2_destroy(ctx); return NULL; } } } } else { result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr); if (result == 1) { ctx->v6 = 1; ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0); if (ctx->fd >= 0) { ctx->sin6.sin6_family = AF_INET6; ctx->sin6.sin6_port = htons(162); if (connect(ctx->fd, (struct sockaddr *)&ctx->sin6, sizeof(ctx->sin6)) != 0) { snmpv2_destroy(ctx); return NULL; } } } } #else result = inet_aton(s, &ctx->sin.sin_addr); if (result == 1) { ctx->fd = socket(AF_INET, SOCK_DGRAM, 0); if (ctx->fd >= 0) { ctx->sin.sin_family = AF_INET; ctx->sin.sin_port = htons(162); if (connect(ctx->fd, (struct sockaddr *)&ctx->sin, sizeof(ctx->sin)) != 0) { snmpv2_destroy(ctx); return NULL; } } } #endif if (result != 1) { free(str); free(ctx); return NULL; } ctx->ref = 1; return ctx; } static void snmpv2_destroy(ctx) void *ctx; { snmpv2_opts_t *v2 = ctx; v2->ref--; if (v2->ref > 0) return; if (v2->community) free(v2->community); if (v2->fd >= 0) close(v2->fd); free(v2); } static int snmpv2_send(ctx, msg) void *ctx; ipmon_msg_t *msg; { snmpv2_opts_t *v2 = ctx; return sendtrap_v2_0(v2->fd, v2->community, msg->imm_msg, msg->imm_msglen); } static int writelength(buffer, value) u_char *buffer; u_int value; { u_int n = htonl(value); int len; if (value < 128) { *buffer = value; return 1; } if (value > 0xffffff) len = 4; else if (value > 0xffff) len = 3; else if (value > 0xff) len = 2; else len = 1; *buffer = 0x80 | len; bcopy((u_char *)&n + 4 - len, buffer + 1, len); return len + 1; } static int writeint(buffer, value) u_char *buffer; int value; { u_char *s = buffer; u_int n = value; if (value == 0) { *buffer = 0; return 1; } if (n > 4194304) { *s++ = 0x80 | (n / 4194304); n -= 4194304 * (n / 4194304); } if (n > 32768) { *s++ = 0x80 | (n / 32768); n -= 32768 * (n / 327678); } if (n > 128) { *s++ = 0x80 | (n / 128); n -= (n / 128) * 128; } *s++ = (u_char)n; return s - buffer; } /* * First style of traps is: * 1.3.6.1.4.1.9932.1.1 */ static int maketrap_v2(community, buffer, bufsize, msg, msglen) char *community; u_char *buffer; int bufsize; u_char *msg; int msglen; { u_char *s = buffer, *t, *pdulen; u_char *varlen; int basesize = 77; u_short len; int trapmsglen; int pdulensz; int varlensz; int baselensz; int n; if (community == NULL || *community == '\0') community = def_community; basesize += strlen(community) + msglen; if (basesize + 8 > bufsize) return 0; memset(buffer, 0xff, bufsize); *s++ = 0x30; /* Sequence */ if (basesize - 1 >= 128) { baselensz = 2; basesize++; } else { baselensz = 1; } s += baselensz; *s++ = 0x02; /* Integer32 */ *s++ = 0x01; /* length 1 */ *s++ = 0x01; /* version 2 */ *s++ = 0x04; /* octet string */ *s++ = strlen(community); /* length of "public" */ bcopy(community, s, s[-1]); s += s[-1]; *s++ = 0xA7; /* PDU(7) */ pdulen = s++; if (basesize - (s - buffer) >= 128) { pdulensz = 2; basesize++; s++; } else { pdulensz = 1; } /* request id */ *s++ = 0x2; /* integer */ *s++ = 0x4; /* len 4 */ *s++ = 0x0; /* noError */ *s++ = 0x0; /* noError */ *s++ = 0x0; /* noError */ *s++ = 0x0; /* noError */ /* error status */ *s++ = 0x2; /* integer */ *s++ = 0x1; /* len 1 */ *s++ = 0x0; /* noError */ /* error-index */ *s++ = 0x2; /* integer */ *s++ = 0x1; /* len 1 */ *s++ = 0x0; /* noError */ *s++ = 0x30; /* sequence */ varlen = s++; if (basesize - (s - buffer) >= 128) { varlensz = 2; basesize++; s++; } else { varlensz = 1; } *s++ = 0x30; /* sequence */ *s++ = sizeof(sysuptime) + 6; bcopy(sysuptime, s, sizeof(sysuptime)); s += sizeof(sysuptime); *s++ = 0x43; /* Timestamp */ *s++ = 0x04; /* TimeTicks */ *s++ = 0x0; *s++ = 0x0; *s++ = 0x0; *s++ = 0x0; *s++ = 0x30; t = s + 1; bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1)); t += sizeof(ipf_trap0_1); *t++ = 0x2; /* Integer */ n = writeint(t + 1, IPFILTER_VERSION); *t = n; t += n + 1; len = t - s - 1; writelength(s, len); s = t; *s++ = 0x30; if (msglen < 128) { if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128) trapmsglen = 2; else trapmsglen = 1; } else { if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128) trapmsglen = 2; else trapmsglen = 1; } t = s + trapmsglen; bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2)); t += sizeof(ipf_trap0_2); *t++ = 0x4; /* Octet string */ n = writelength(t, msglen); t += n; bcopy(msg, t, msglen); t += msglen; len = t - s - trapmsglen; writelength(s, len); len = t - varlen - varlensz; writelength(varlen, len); /* pdu length */ len = t - pdulen - pdulensz; writelength(pdulen, len); /* pdu length */ len = t - buffer - baselensz - 1; writelength(buffer + 1, len); /* length of trap */ return t - buffer; } int sendtrap_v2_0(fd, community, msg, msglen) int fd; char *community, *msg; int msglen; { u_char buffer[1500]; int n; n = maketrap_v2(community, buffer, sizeof(buffer), (u_char *)msg, msglen); if (n > 0) { return send(fd, buffer, n, 0); } return 0; }