1 #include "ipf.h" 2 #include "netinet/ipl.h" 3 #include "ipmon.h" 4 #include <ctype.h> 5 6 static 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 */ 11 static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 }; 12 static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 }; 13 14 static int writeint(u_char *, int); 15 static int writelength(u_char *, u_int); 16 static int maketrap_v2(char *, u_char *, int, u_char *, int); 17 static void snmpv2_destroy(void *); 18 static void *snmpv2_dup(void *); 19 static int snmpv2_match(void *, void *); 20 static void *snmpv2_parse(char **); 21 static void snmpv2_print(void *); 22 static int snmpv2_send(void *, ipmon_msg_t *); 23 24 25 int sendtrap_v2_0(int, char *, char *, int); 26 27 static char def_community[] = "public"; /* ublic */ 28 29 typedef 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 41 ipmon_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 52 static int 53 snmpv2_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 79 static void * 80 snmpv2_dup(ctx) 81 void *ctx; 82 { 83 snmpv2_opts_t *s = ctx; 84 85 s->ref++; 86 return s; 87 } 88 89 90 static void 91 snmpv2_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 111 static void * 112 snmpv2_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 free(str); 129 return NULL; 130 } 131 132 ctx->fd = -1; 133 134 s = strchr(str, ' '); 135 *s++ = '\0'; 136 ctx->community = str; 137 138 while (ISSPACE(*s)) 139 s++; 140 if (!*s) { 141 free(str); 142 free(ctx); 143 return NULL; 144 } 145 146 #ifdef USE_INET6 147 if (strchr(s, ':') == NULL) { 148 result = inet_pton(AF_INET, s, &ctx->sin.sin_addr); 149 if (result == 1) { 150 ctx->fd = socket(AF_INET, SOCK_DGRAM, 0); 151 if (ctx->fd >= 0) { 152 ctx->sin.sin_family = AF_INET; 153 ctx->sin.sin_port = htons(162); 154 if (connect(ctx->fd, 155 (struct sockaddr *)&ctx->sin, 156 sizeof(ctx->sin)) != 0) { 157 snmpv2_destroy(ctx); 158 return NULL; 159 } 160 } 161 } 162 } else { 163 result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr); 164 if (result == 1) { 165 ctx->v6 = 1; 166 ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0); 167 if (ctx->fd >= 0) { 168 ctx->sin6.sin6_family = AF_INET6; 169 ctx->sin6.sin6_port = htons(162); 170 if (connect(ctx->fd, 171 (struct sockaddr *)&ctx->sin6, 172 sizeof(ctx->sin6)) != 0) { 173 snmpv2_destroy(ctx); 174 return NULL; 175 } 176 } 177 } 178 } 179 #else 180 result = inet_aton(s, &ctx->sin.sin_addr); 181 if (result == 1) { 182 ctx->fd = socket(AF_INET, SOCK_DGRAM, 0); 183 if (ctx->fd >= 0) { 184 ctx->sin.sin_family = AF_INET; 185 ctx->sin.sin_port = htons(162); 186 if (connect(ctx->fd, (struct sockaddr *)&ctx->sin, 187 sizeof(ctx->sin)) != 0) { 188 snmpv2_destroy(ctx); 189 return NULL; 190 } 191 } 192 } 193 #endif 194 195 if (result != 1) { 196 free(str); 197 free(ctx); 198 return NULL; 199 } 200 201 ctx->ref = 1; 202 203 return ctx; 204 } 205 206 207 static void 208 snmpv2_destroy(ctx) 209 void *ctx; 210 { 211 snmpv2_opts_t *v2 = ctx; 212 213 v2->ref--; 214 if (v2->ref > 0) 215 return; 216 217 if (v2->community) 218 free(v2->community); 219 if (v2->fd >= 0) 220 close(v2->fd); 221 free(v2); 222 } 223 224 225 static int 226 snmpv2_send(ctx, msg) 227 void *ctx; 228 ipmon_msg_t *msg; 229 { 230 snmpv2_opts_t *v2 = ctx; 231 232 return sendtrap_v2_0(v2->fd, v2->community, 233 msg->imm_msg, msg->imm_msglen); 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_v2(community, buffer, bufsize, msg, msglen) 302 char *community; 303 u_char *buffer; 304 int bufsize; 305 u_char *msg; 306 int msglen; 307 { 308 u_char *s = buffer, *t, *pdulen; 309 u_char *varlen; 310 int basesize = 77; 311 u_short len; 312 int trapmsglen; 313 int pdulensz; 314 int varlensz; 315 int baselensz; 316 int n; 317 318 if (community == NULL || *community == '\0') 319 community = def_community; 320 basesize += strlen(community) + msglen; 321 322 if (basesize + 8 > bufsize) 323 return 0; 324 325 memset(buffer, 0xff, bufsize); 326 *s++ = 0x30; /* Sequence */ 327 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++ = 0x01; /* version 2 */ 338 *s++ = 0x04; /* octet string */ 339 *s++ = strlen(community); /* length of "public" */ 340 bcopy(community, s, s[-1]); 341 s += s[-1]; 342 *s++ = 0xA7; /* PDU(7) */ 343 pdulen = s++; 344 if (basesize - (s - buffer) >= 128) { 345 pdulensz = 2; 346 basesize++; 347 s++; 348 } else { 349 pdulensz = 1; 350 } 351 /* request id */ 352 *s++ = 0x2; /* integer */ 353 *s++ = 0x4; /* len 4 */ 354 *s++ = 0x0; /* noError */ 355 *s++ = 0x0; /* noError */ 356 *s++ = 0x0; /* noError */ 357 *s++ = 0x0; /* noError */ 358 359 /* error status */ 360 *s++ = 0x2; /* integer */ 361 *s++ = 0x1; /* len 1 */ 362 *s++ = 0x0; /* noError */ 363 364 /* error-index */ 365 *s++ = 0x2; /* integer */ 366 *s++ = 0x1; /* len 1 */ 367 *s++ = 0x0; /* noError */ 368 369 *s++ = 0x30; /* sequence */ 370 varlen = s++; 371 if (basesize - (s - buffer) >= 128) { 372 varlensz = 2; 373 basesize++; 374 s++; 375 } else { 376 varlensz = 1; 377 } 378 379 *s++ = 0x30; /* sequence */ 380 *s++ = sizeof(sysuptime) + 6; 381 382 bcopy(sysuptime, s, sizeof(sysuptime)); 383 s += sizeof(sysuptime); 384 385 *s++ = 0x43; /* Timestamp */ 386 *s++ = 0x04; /* TimeTicks */ 387 *s++ = 0x0; 388 *s++ = 0x0; 389 *s++ = 0x0; 390 *s++ = 0x0; 391 392 *s++ = 0x30; 393 t = s + 1; 394 bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1)); 395 t += sizeof(ipf_trap0_1); 396 397 *t++ = 0x2; /* Integer */ 398 n = writeint(t + 1, IPFILTER_VERSION); 399 *t = n; 400 t += n + 1; 401 402 len = t - s - 1; 403 writelength(s, len); 404 405 s = t; 406 *s++ = 0x30; 407 if (msglen < 128) { 408 if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128) 409 trapmsglen = 2; 410 else 411 trapmsglen = 1; 412 } else { 413 if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128) 414 trapmsglen = 2; 415 else 416 trapmsglen = 1; 417 } 418 t = s + trapmsglen; 419 bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2)); 420 t += sizeof(ipf_trap0_2); 421 422 *t++ = 0x4; /* Octet string */ 423 n = writelength(t, msglen); 424 t += n; 425 bcopy(msg, t, msglen); 426 t += msglen; 427 428 len = t - s - trapmsglen; 429 writelength(s, len); 430 431 len = t - varlen - varlensz; 432 writelength(varlen, len); /* pdu length */ 433 434 len = t - pdulen - pdulensz; 435 writelength(pdulen, len); /* pdu length */ 436 437 len = t - buffer - baselensz - 1; 438 writelength(buffer + 1, len); /* length of trap */ 439 440 return t - buffer; 441 } 442 443 444 int 445 sendtrap_v2_0(fd, community, msg, msglen) 446 int fd; 447 char *community, *msg; 448 int msglen; 449 { 450 451 u_char buffer[1500]; 452 int n; 453 454 n = maketrap_v2(community, buffer, sizeof(buffer), 455 (u_char *)msg, msglen); 456 if (n > 0) { 457 return send(fd, buffer, n, 0); 458 } 459 460 return 0; 461 } 462