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