save_v2trap.c revision 268563
1#include "ipf.h" 2#include "netinet/ipl.h" 3#include "ipmon.h" 4#include <ctype.h> 5 6static u_char sysuptime[] = { 6, 8, 0x2b, 6, 1, 2, 1, 1, 3, 0 }; 7/* 8 * Enterprise number OID: 9 * 1.3.6.1.4.1.9932 10 */ 11static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 }; 12static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 }; 13 14static int writeint __P((u_char *, int)); 15static int writelength __P((u_char *, u_int)); 16static int maketrap_v2 __P((char *, u_char *, int, u_char *, int)); 17static void snmpv2_destroy __P((void *)); 18static void *snmpv2_dup __P((void *)); 19static int snmpv2_match __P((void *, void *)); 20static void *snmpv2_parse __P((char **)); 21static void snmpv2_print __P((void *)); 22static int snmpv2_send __P((void *, ipmon_msg_t *)); 23 24 25int sendtrap_v2_0 __P((int, char *, char *, int)); 26 27static char def_community[] = "public"; /* ublic */ 28 29typedef struct snmpv2_opts_s { 30 char *community; 31 char *server; 32 int fd; 33 int v6; 34 int ref; 35#ifdef USE_INET6 36 struct sockaddr_in6 sin6; 37#endif 38 struct sockaddr_in sin; 39} snmpv2_opts_t; 40 41ipmon_saver_t snmpv2saver = { 42 "snmpv2", 43 snmpv2_destroy, 44 snmpv2_dup, /* dup */ 45 snmpv2_match, /* match */ 46 snmpv2_parse, 47 snmpv2_print, 48 snmpv2_send 49}; 50 51 52static int 53snmpv2_match(ctx1, ctx2) 54 void *ctx1, *ctx2; 55{ 56 snmpv2_opts_t *s1 = ctx1, *s2 = ctx2; 57 58 if (s1->v6 != s2->v6) 59 return 1; 60 61 if (strcmp(s1->community, s2->community)) 62 return 1; 63 64#ifdef USE_INET6 65 if (s1->v6 == 1) { 66 if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6))) 67 return 1; 68 } else 69#endif 70 { 71 if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin))) 72 return 1; 73 } 74 75 return 0; 76} 77 78 79static void * 80snmpv2_dup(ctx) 81 void *ctx; 82{ 83 snmpv2_opts_t *s = ctx; 84 85 s->ref++; 86 return s; 87} 88 89 90static void 91snmpv2_print(ctx) 92 void *ctx; 93{ 94 snmpv2_opts_t *snmpv2 = ctx; 95 96 printf("%s ", snmpv2->community); 97#ifdef USE_INET6 98 if (snmpv2->v6 == 1) { 99 char buf[80]; 100 101 printf("%s", inet_ntop(AF_INET6, &snmpv2->sin6.sin6_addr, buf, 102 sizeof(snmpv2->sin6.sin6_addr))); 103 } else 104#endif 105 { 106 printf("%s", inet_ntoa(snmpv2->sin.sin_addr)); 107 } 108} 109 110 111static void * 112snmpv2_parse(char **strings) 113{ 114 snmpv2_opts_t *ctx; 115 int result; 116 char *str; 117 char *s; 118 119 if (strings[0] == NULL || strings[0][0] == '\0') 120 return NULL; 121 if (strchr(*strings, ' ') == NULL) 122 return NULL; 123 124 str = strdup(*strings); 125 126 ctx = calloc(1, sizeof(*ctx)); 127 if (ctx == NULL) 128 return NULL; 129 130 ctx->fd = -1; 131 132 s = strchr(str, ' '); 133 *s++ = '\0'; 134 ctx->community = str; 135 136 while (ISSPACE(*s)) 137 s++; 138 if (!*s) { 139 free(str); 140 free(ctx); 141 return NULL; 142 } 143 144#ifdef USE_INET6 145 if (strchr(s, ':') == NULL) { 146 result = inet_pton(AF_INET, s, &ctx->sin.sin_addr); 147 if (result == 1) { 148 ctx->fd = socket(AF_INET, SOCK_DGRAM, 0); 149 if (ctx->fd >= 0) { 150 ctx->sin.sin_family = AF_INET; 151 ctx->sin.sin_port = htons(162); 152 if (connect(ctx->fd, 153 (struct sockaddr *)&ctx->sin, 154 sizeof(ctx->sin)) != 0) { 155 snmpv2_destroy(ctx); 156 return NULL; 157 } 158 } 159 } 160 } else { 161 result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr); 162 if (result == 1) { 163 ctx->v6 = 1; 164 ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0); 165 if (ctx->fd >= 0) { 166 ctx->sin6.sin6_family = AF_INET6; 167 ctx->sin6.sin6_port = htons(162); 168 if (connect(ctx->fd, 169 (struct sockaddr *)&ctx->sin6, 170 sizeof(ctx->sin6)) != 0) { 171 snmpv2_destroy(ctx); 172 return NULL; 173 } 174 } 175 } 176 } 177#else 178 result = inet_aton(s, &ctx->sin.sin_addr); 179 if (result == 1) { 180 ctx->fd = socket(AF_INET, SOCK_DGRAM, 0); 181 if (ctx->fd >= 0) { 182 ctx->sin.sin_family = AF_INET; 183 ctx->sin.sin_port = htons(162); 184 if (connect(ctx->fd, (struct sockaddr *)&ctx->sin, 185 sizeof(ctx->sin)) != 0) { 186 snmpv2_destroy(ctx); 187 return NULL; 188 } 189 } 190 } 191#endif 192 193 if (result != 1) { 194 free(str); 195 free(ctx); 196 return NULL; 197 } 198 199 ctx->ref = 1; 200 201 return ctx; 202} 203 204 205static void 206snmpv2_destroy(ctx) 207 void *ctx; 208{ 209 snmpv2_opts_t *v2 = ctx; 210 211 v2->ref--; 212 if (v2->ref > 0) 213 return; 214 215 if (v2->community) 216 free(v2->community); 217 if (v2->fd >= 0) 218 close(v2->fd); 219 free(v2); 220} 221 222 223static int 224snmpv2_send(ctx, msg) 225 void *ctx; 226 ipmon_msg_t *msg; 227{ 228 snmpv2_opts_t *v2 = ctx; 229 230 return sendtrap_v2_0(v2->fd, v2->community, 231 msg->imm_msg, msg->imm_msglen); 232} 233static int 234writelength(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 262static int 263writeint(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 */ 298static int 299maketrap_v2(community, buffer, bufsize, msg, msglen) 300 char *community; 301 u_char *buffer; 302 int bufsize; 303 u_char *msg; 304 int msglen; 305{ 306 u_char *s = buffer, *t, *pdulen; 307 u_char *varlen; 308 int basesize = 77; 309 u_short len; 310 int trapmsglen; 311 int pdulensz; 312 int varlensz; 313 int baselensz; 314 int n; 315 316 if (community == NULL || *community == '\0') 317 community = def_community; 318 basesize += strlen(community) + msglen; 319 320 if (basesize + 8 > bufsize) 321 return 0; 322 323 memset(buffer, 0xff, bufsize); 324 *s++ = 0x30; /* Sequence */ 325 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++ = 0x01; /* version 2 */ 336 *s++ = 0x04; /* octet string */ 337 *s++ = strlen(community); /* length of "public" */ 338 bcopy(community, s, s[-1]); 339 s += s[-1]; 340 *s++ = 0xA7; /* PDU(7) */ 341 pdulen = s++; 342 if (basesize - (s - buffer) >= 128) { 343 pdulensz = 2; 344 basesize++; 345 s++; 346 } else { 347 pdulensz = 1; 348 } 349 /* request id */ 350 *s++ = 0x2; /* integer */ 351 *s++ = 0x4; /* len 4 */ 352 *s++ = 0x0; /* noError */ 353 *s++ = 0x0; /* noError */ 354 *s++ = 0x0; /* noError */ 355 *s++ = 0x0; /* noError */ 356 357 /* error status */ 358 *s++ = 0x2; /* integer */ 359 *s++ = 0x1; /* len 1 */ 360 *s++ = 0x0; /* noError */ 361 362 /* error-index */ 363 *s++ = 0x2; /* integer */ 364 *s++ = 0x1; /* len 1 */ 365 *s++ = 0x0; /* noError */ 366 367 *s++ = 0x30; /* sequence */ 368 varlen = s++; 369 if (basesize - (s - buffer) >= 128) { 370 varlensz = 2; 371 basesize++; 372 s++; 373 } else { 374 varlensz = 1; 375 } 376 377 *s++ = 0x30; /* sequence */ 378 *s++ = sizeof(sysuptime) + 6; 379 380 bcopy(sysuptime, s, sizeof(sysuptime)); 381 s += sizeof(sysuptime); 382 383 *s++ = 0x43; /* Timestamp */ 384 *s++ = 0x04; /* TimeTicks */ 385 *s++ = 0x0; 386 *s++ = 0x0; 387 *s++ = 0x0; 388 *s++ = 0x0; 389 390 *s++ = 0x30; 391 t = s + 1; 392 bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1)); 393 t += sizeof(ipf_trap0_1); 394 395 *t++ = 0x2; /* Integer */ 396 n = writeint(t + 1, IPFILTER_VERSION); 397 *t = n; 398 t += n + 1; 399 400 len = t - s - 1; 401 writelength(s, len); 402 403 s = t; 404 *s++ = 0x30; 405 if (msglen < 128) { 406 if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128) 407 trapmsglen = 2; 408 else 409 trapmsglen = 1; 410 } else { 411 if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128) 412 trapmsglen = 2; 413 else 414 trapmsglen = 1; 415 } 416 t = s + trapmsglen; 417 bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2)); 418 t += sizeof(ipf_trap0_2); 419 420 *t++ = 0x4; /* Octet string */ 421 n = writelength(t, msglen); 422 t += n; 423 bcopy(msg, t, msglen); 424 t += msglen; 425 426 len = t - s - trapmsglen; 427 writelength(s, len); 428 429 len = t - varlen - varlensz; 430 writelength(varlen, len); /* pdu length */ 431 432 len = t - pdulen - pdulensz; 433 writelength(pdulen, len); /* pdu length */ 434 435 len = t - buffer - baselensz - 1; 436 writelength(buffer + 1, len); /* length of trap */ 437 438 return t - buffer; 439} 440 441 442int 443sendtrap_v2_0(fd, community, msg, msglen) 444 int fd; 445 char *community, *msg; 446 int msglen; 447{ 448 449 u_char buffer[1500]; 450 int n; 451 452 n = maketrap_v2(community, buffer, sizeof(buffer), 453 (u_char *)msg, msglen); 454 if (n > 0) { 455 return send(fd, buffer, n, 0); 456 } 457 458 return 0; 459} 460