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(void *ctx1, void *ctx2) 54 { 55 snmpv2_opts_t *s1 = ctx1, *s2 = ctx2; 56 57 if (s1->v6 != s2->v6) 58 return (1); 59 60 if (strcmp(s1->community, s2->community)) 61 return (1); 62 63 #ifdef USE_INET6 64 if (s1->v6 == 1) { 65 if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6))) 66 return (1); 67 } else 68 #endif 69 { 70 if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin))) 71 return (1); 72 } 73 74 return (0); 75 } 76 77 78 static void * 79 snmpv2_dup(void *ctx) 80 { 81 snmpv2_opts_t *s = ctx; 82 83 s->ref++; 84 return (s); 85 } 86 87 88 static void 89 snmpv2_print(void *ctx) 90 { 91 snmpv2_opts_t *snmpv2 = ctx; 92 93 printf("%s ", snmpv2->community); 94 #ifdef USE_INET6 95 if (snmpv2->v6 == 1) { 96 char buf[80]; 97 98 printf("%s", inet_ntop(AF_INET6, &snmpv2->sin6.sin6_addr, buf, 99 sizeof(snmpv2->sin6.sin6_addr))); 100 } else 101 #endif 102 { 103 printf("%s", inet_ntoa(snmpv2->sin.sin_addr)); 104 } 105 } 106 107 108 static void * 109 snmpv2_parse(char **strings) 110 { 111 snmpv2_opts_t *ctx; 112 int result; 113 char *str; 114 char *s; 115 116 if (strings[0] == NULL || strings[0][0] == '\0') 117 return (NULL); 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 free(str); 126 return (NULL); 127 } 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 snmpv2_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 snmpv2_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 snmpv2_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 snmpv2_destroy(void *ctx) 206 { 207 snmpv2_opts_t *v2 = ctx; 208 209 v2->ref--; 210 if (v2->ref > 0) 211 return; 212 213 if (v2->community) 214 free(v2->community); 215 if (v2->fd >= 0) 216 close(v2->fd); 217 free(v2); 218 } 219 220 221 static int 222 snmpv2_send(void *ctx, ipmon_msg_t *msg) 223 { 224 snmpv2_opts_t *v2 = ctx; 225 226 return (sendtrap_v2_0(v2->fd, v2->community, 227 msg->imm_msg, msg->imm_msglen)); 228 } 229 static int 230 writelength(u_char *buffer, u_int value) 231 { 232 u_int n = htonl(value); 233 int len; 234 235 if (value < 128) { 236 *buffer = value; 237 return (1); 238 } 239 if (value > 0xffffff) 240 len = 4; 241 else if (value > 0xffff) 242 len = 3; 243 else if (value > 0xff) 244 len = 2; 245 else 246 len = 1; 247 248 *buffer = 0x80 | len; 249 250 bcopy((u_char *)&n + 4 - len, buffer + 1, len); 251 252 return (len + 1); 253 } 254 255 256 static int 257 writeint(u_char *buffer, int value) 258 { 259 u_char *s = buffer; 260 u_int n = value; 261 262 if (value == 0) { 263 *buffer = 0; 264 return (1); 265 } 266 267 if (n > 4194304) { 268 *s++ = 0x80 | (n / 4194304); 269 n -= 4194304 * (n / 4194304); 270 } 271 if (n > 32768) { 272 *s++ = 0x80 | (n / 32768); 273 n -= 32768 * (n / 327678); 274 } 275 if (n > 128) { 276 *s++ = 0x80 | (n / 128); 277 n -= (n / 128) * 128; 278 } 279 *s++ = (u_char)n; 280 281 return (s - buffer); 282 } 283 284 285 286 /* 287 * First style of traps is: 288 * 1.3.6.1.4.1.9932.1.1 289 */ 290 static int 291 maketrap_v2(char *community, u_char *buffer, int bufsize, u_char *msg, 292 int msglen) 293 { 294 u_char *s = buffer, *t, *pdulen; 295 u_char *varlen; 296 int basesize = 77; 297 u_short len; 298 int trapmsglen; 299 int pdulensz; 300 int varlensz; 301 int baselensz; 302 int n; 303 304 if (community == NULL || *community == '\0') 305 community = def_community; 306 basesize += strlen(community) + msglen; 307 308 if (basesize + 8 > bufsize) 309 return (0); 310 311 memset(buffer, 0xff, bufsize); 312 *s++ = 0x30; /* Sequence */ 313 314 if (basesize - 1 >= 128) { 315 baselensz = 2; 316 basesize++; 317 } else { 318 baselensz = 1; 319 } 320 s += baselensz; 321 *s++ = 0x02; /* Integer32 */ 322 *s++ = 0x01; /* length 1 */ 323 *s++ = 0x01; /* version 2 */ 324 *s++ = 0x04; /* octet string */ 325 *s++ = strlen(community); /* length of "public" */ 326 bcopy(community, s, s[-1]); 327 s += s[-1]; 328 *s++ = 0xA7; /* PDU(7) */ 329 pdulen = s++; 330 if (basesize - (s - buffer) >= 128) { 331 pdulensz = 2; 332 basesize++; 333 s++; 334 } else { 335 pdulensz = 1; 336 } 337 /* request id */ 338 *s++ = 0x2; /* integer */ 339 *s++ = 0x4; /* len 4 */ 340 *s++ = 0x0; /* noError */ 341 *s++ = 0x0; /* noError */ 342 *s++ = 0x0; /* noError */ 343 *s++ = 0x0; /* noError */ 344 345 /* error status */ 346 *s++ = 0x2; /* integer */ 347 *s++ = 0x1; /* len 1 */ 348 *s++ = 0x0; /* noError */ 349 350 /* error-index */ 351 *s++ = 0x2; /* integer */ 352 *s++ = 0x1; /* len 1 */ 353 *s++ = 0x0; /* noError */ 354 355 *s++ = 0x30; /* sequence */ 356 varlen = s++; 357 if (basesize - (s - buffer) >= 128) { 358 varlensz = 2; 359 basesize++; 360 s++; 361 } else { 362 varlensz = 1; 363 } 364 365 *s++ = 0x30; /* sequence */ 366 *s++ = sizeof(sysuptime) + 6; 367 368 bcopy(sysuptime, s, sizeof(sysuptime)); 369 s += sizeof(sysuptime); 370 371 *s++ = 0x43; /* Timestamp */ 372 *s++ = 0x04; /* TimeTicks */ 373 *s++ = 0x0; 374 *s++ = 0x0; 375 *s++ = 0x0; 376 *s++ = 0x0; 377 378 *s++ = 0x30; 379 t = s + 1; 380 bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1)); 381 t += sizeof(ipf_trap0_1); 382 383 *t++ = 0x2; /* Integer */ 384 n = writeint(t + 1, IPFILTER_VERSION); 385 *t = n; 386 t += n + 1; 387 388 len = t - s - 1; 389 writelength(s, len); 390 391 s = t; 392 *s++ = 0x30; 393 if (msglen < 128) { 394 if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128) 395 trapmsglen = 2; 396 else 397 trapmsglen = 1; 398 } else { 399 if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128) 400 trapmsglen = 2; 401 else 402 trapmsglen = 1; 403 } 404 t = s + trapmsglen; 405 bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2)); 406 t += sizeof(ipf_trap0_2); 407 408 *t++ = 0x4; /* Octet string */ 409 n = writelength(t, msglen); 410 t += n; 411 bcopy(msg, t, msglen); 412 t += msglen; 413 414 len = t - s - trapmsglen; 415 writelength(s, len); 416 417 len = t - varlen - varlensz; 418 writelength(varlen, len); /* pdu length */ 419 420 len = t - pdulen - pdulensz; 421 writelength(pdulen, len); /* pdu length */ 422 423 len = t - buffer - baselensz - 1; 424 writelength(buffer + 1, len); /* length of trap */ 425 426 return (t - buffer); 427 } 428 429 430 int 431 sendtrap_v2_0(int fd, char *community, char *msg, int msglen) 432 { 433 434 u_char buffer[1500]; 435 int n; 436 437 n = maketrap_v2(community, buffer, sizeof(buffer), 438 (u_char *)msg, msglen); 439 if (n > 0) { 440 return (send(fd, buffer, n, 0)); 441 } 442 443 return (0); 444 } 445