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