| #include "ipf.h" |
| #include "netinet/ipl.h" |
| #include "ipmon.h" |
| #include <ctype.h> |
| |
| #define IPF_ENTERPRISE 9932 |
| /* |
| * Enterprise number OID: |
| * 1.3.6.1.4.1.9932 |
| */ |
| static u_char ipf_enterprise[] = { 6, 7, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c }; |
| 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_v1 __P((char *, u_char *, int, u_char *, int, u_32_t, |
| u_int, time_t)); |
| static void snmpv1_destroy __P((void *)); |
| static void *snmpv1_dup __P((void *)); |
| static int snmpv1_match __P((void *, void *)); |
| static void *snmpv1_parse __P((char **)); |
| static void snmpv1_print __P((void *)); |
| static int snmpv1_send __P((void *, ipmon_msg_t *)); |
| |
| typedef struct snmpv1_opts_s { |
| char *community; |
| int fd; |
| int v6; |
| int ref; |
| #ifdef USE_INET6 |
| struct sockaddr_in6 sin6; |
| #endif |
| struct sockaddr_in sin; |
| } snmpv1_opts_t; |
| |
| ipmon_saver_t snmpv1saver = { |
| "snmpv1", |
| snmpv1_destroy, |
| snmpv1_dup, /* dup */ |
| snmpv1_match, /* match */ |
| snmpv1_parse, |
| snmpv1_print, |
| snmpv1_send |
| }; |
| |
| |
| static int |
| snmpv1_match(ctx1, ctx2) |
| void *ctx1, *ctx2; |
| { |
| snmpv1_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 * |
| snmpv1_dup(ctx) |
| void *ctx; |
| { |
| snmpv1_opts_t *s = ctx; |
| |
| s->ref++; |
| return s; |
| } |
| |
| |
| static void |
| snmpv1_print(ctx) |
| void *ctx; |
| { |
| snmpv1_opts_t *snmpv1 = ctx; |
| |
| printf("%s ", snmpv1->community); |
| #ifdef USE_INET6 |
| if (snmpv1->v6 == 1) { |
| char buf[80]; |
| |
| printf("%s", inet_ntop(AF_INET6, &snmpv1->sin6.sin6_addr, buf, |
| sizeof(snmpv1->sin6.sin6_addr))); |
| } else |
| #endif |
| { |
| printf("%s", inet_ntoa(snmpv1->sin.sin_addr)); |
| } |
| } |
| |
| |
| static void * |
| snmpv1_parse(char **strings) |
| { |
| snmpv1_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) { |
| snmpv1_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) { |
| snmpv1_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, &ctx->sin, |
| sizeof(ctx->sin)) != 0) { |
| snmpv1_destroy(ctx); |
| return NULL; |
| } |
| } |
| } |
| #endif |
| |
| if (result != 1) { |
| free(str); |
| free(ctx); |
| return NULL; |
| } |
| |
| ctx->ref = 1; |
| |
| return ctx; |
| } |
| |
| |
| static void |
| snmpv1_destroy(ctx) |
| void *ctx; |
| { |
| snmpv1_opts_t *v1 = ctx; |
| |
| v1->ref--; |
| if (v1->ref > 0) |
| return; |
| |
| if (v1->community) |
| free(v1->community); |
| if (v1->fd >= 0) |
| close(v1->fd); |
| free(v1); |
| } |
| |
| |
| static int |
| snmpv1_send(ctx, msg) |
| void *ctx; |
| ipmon_msg_t *msg; |
| { |
| snmpv1_opts_t *v1 = ctx; |
| |
| return sendtrap_v1_0(v1->fd, v1->community, |
| msg->imm_msg, msg->imm_msglen, msg->imm_when); |
| } |
| |
| static char def_community[] = "public"; /* ublic */ |
| |
| 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_v1(community, buffer, bufsize, msg, msglen, ipaddr, code, when) |
| char *community; |
| u_char *buffer; |
| int bufsize; |
| u_char *msg; |
| int msglen; |
| u_32_t ipaddr; |
| u_int code; |
| time_t when; |
| { |
| u_char *s = buffer, *t, *pdulen, *varlen; |
| int basesize = 73; |
| 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++ = 0x00; /* version 1 */ |
| *s++ = 0x04; /* octet string */ |
| *s++ = strlen(community); /* length of "public" */ |
| bcopy(community, s, s[-1]); |
| s += s[-1]; |
| *s++ = 0xA4; /* PDU(4) */ |
| pdulen = s++; |
| if (basesize - (s - buffer) >= 128) { |
| pdulensz = 2; |
| basesize++; |
| s++; |
| } else { |
| pdulensz = 1; |
| } |
| |
| /* enterprise */ |
| bcopy(ipf_enterprise, s, sizeof(ipf_enterprise)); |
| s += sizeof(ipf_enterprise); |
| |
| /* Agent address */ |
| *s++ = 0x40; |
| *s++ = 0x4; |
| bcopy(&ipaddr, s, 4); |
| s += 4; |
| |
| /* Generic Trap code */ |
| *s++ = 0x2; |
| n = writeint(s + 1, 6); |
| if (n == 0) |
| return 0; |
| *s = n; |
| s += n + 1; |
| |
| /* Specific Trap code */ |
| *s++ = 0x2; |
| n = writeint(s + 1, 0); |
| if (n == 0) |
| return 0; |
| *s = n; |
| s += n + 1; |
| |
| /* Time stamp */ |
| *s++ = 0x43; /* TimeTicks */ |
| *s++ = 0x04; /* TimeTicks */ |
| s[0] = when >> 24; |
| s[1] = when >> 16; |
| s[2] = when >> 8; |
| s[3] = when & 0xff; |
| s += 4; |
| |
| /* |
| * The trap0 message is "ipfilter_version" followed by the message |
| */ |
| *s++ = 0x30; |
| varlen = s; |
| if (basesize - (s - buffer) >= 128) { |
| varlensz = 2; |
| basesize++; |
| } else { |
| varlensz = 1; |
| } |
| s += varlensz; |
| |
| *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 (basesize - (s - buffer) >= 128) { |
| trapmsglen = 2; |
| basesize++; |
| } 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_v1_0(fd, community, msg, msglen, when) |
| int fd; |
| char *community, *msg; |
| int msglen; |
| time_t when; |
| { |
| |
| u_char buffer[1500]; |
| int n; |
| |
| n = maketrap_v1(community, buffer, sizeof(buffer), |
| (u_char *)msg, msglen, 0, 0, when); |
| if (n > 0) { |
| return send(fd, buffer, n, 0); |
| } |
| |
| return 0; |
| } |