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