1 /* $OpenBSD: log.c,v 1.64 2018/01/15 09:54:48 mpi Exp $ */ 2 /* $EOM: log.c,v 1.30 2000/09/29 08:19:23 niklas Exp $ */ 3 4 /* 5 * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. 6 * Copyright (c) 1999, 2000, 2001, 2003 H�kan Olsson. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * This code was written under funding by Ericsson Radio Systems. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/time.h> 35 36 #include <sys/socket.h> 37 #include <sys/stat.h> 38 #include <sys/uio.h> 39 #include <netinet/in.h> 40 #include <netinet/ip.h> 41 #include <netinet/ip6.h> 42 #include <netinet/udp.h> 43 #include <arpa/inet.h> 44 45 #include <pcap.h> 46 47 #include <errno.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <syslog.h> 52 #include <stdarg.h> 53 #include <unistd.h> 54 55 #include "conf.h" 56 #include "isakmp_num.h" 57 #include "log.h" 58 #include "monitor.h" 59 #include "util.h" 60 61 static void _log_print(int, int, const char *, va_list, int, int); 62 63 static FILE *log_output; 64 65 int verbose_logging = 0; 66 static int log_level[LOG_ENDCLASS]; 67 68 #define TCPDUMP_MAGIC 0xa1b2c3d4 69 #define SNAPLEN (64 * 1024) 70 71 struct packhdr { 72 struct pcap_pkthdr pcap;/* pcap file packet header */ 73 u_int32_t sa_family; /* address family */ 74 union { 75 struct ip ip4; /* IPv4 header (w/o options) */ 76 struct ip6_hdr ip6; /* IPv6 header */ 77 } ip; 78 }; 79 80 struct isakmp_hdr { 81 u_int8_t icookie[8], rcookie[8]; 82 u_int8_t next, ver, type, flags; 83 u_int32_t msgid, len; 84 }; 85 86 static char *pcaplog_file = NULL; 87 static FILE *packet_log; 88 static u_int8_t *packet_buf = NULL; 89 90 static int udp_cksum(struct packhdr *, const struct udphdr *, 91 u_int16_t *); 92 static u_int16_t in_cksum(const u_int16_t *, int); 93 94 void 95 log_init(int debug) 96 { 97 if (debug) 98 log_output = stderr; 99 else 100 log_to(0); /* syslog */ 101 } 102 103 void 104 log_reinit(void) 105 { 106 struct conf_list *logging; 107 struct conf_list_node *logclass; 108 int class, level; 109 110 logging = conf_get_list("General", "Logverbose"); 111 if (logging) { 112 verbose_logging = 1; 113 conf_free_list(logging); 114 } 115 logging = conf_get_list("General", "Loglevel"); 116 if (!logging) 117 return; 118 119 for (logclass = TAILQ_FIRST(&logging->fields); logclass; 120 logclass = TAILQ_NEXT(logclass, link)) { 121 if (sscanf(logclass->field, "%d=%d", &class, &level) != 2) { 122 if (sscanf(logclass->field, "A=%d", &level) == 1) 123 for (class = 0; class < LOG_ENDCLASS; class++) 124 log_debug_cmd(class, level); 125 else { 126 log_print("init: invalid logging class or " 127 "level: %s", logclass->field); 128 continue; 129 } 130 } else 131 log_debug_cmd(class, level); 132 } 133 conf_free_list(logging); 134 } 135 136 void 137 log_to(FILE *f) 138 { 139 if (!log_output && f) 140 closelog(); 141 log_output = f; 142 if (!f) 143 openlog("isakmpd", LOG_PID | LOG_CONS, LOG_DAEMON); 144 } 145 146 FILE * 147 log_current(void) 148 { 149 return log_output; 150 } 151 152 static char * 153 _log_get_class(int error_class) 154 { 155 /* XXX For test purposes. To be removed later on? */ 156 static char *class_text[] = LOG_CLASSES_TEXT; 157 158 if (error_class < 0) 159 return "Dflt"; 160 else if (error_class >= LOG_ENDCLASS) 161 return "Unkn"; 162 else 163 return class_text[error_class]; 164 } 165 166 static void 167 _log_print(int error, int syslog_level, const char *fmt, va_list ap, 168 int class, int level) 169 { 170 char buffer[LOG_SIZE], nbuf[LOG_SIZE + 32]; 171 static const char fallback_msg[] = 172 "write to log file failed (errno %d), redirecting to syslog"; 173 int len; 174 struct tm *tm; 175 struct timeval now; 176 time_t t; 177 178 len = vsnprintf(buffer, sizeof buffer, fmt, ap); 179 if (len > 0 && len < (int) sizeof buffer - 1 && error) 180 snprintf(buffer + len, sizeof buffer - len, ": %s", 181 strerror(errno)); 182 if (log_output) { 183 gettimeofday(&now, 0); 184 t = now.tv_sec; 185 tm = localtime(&t); 186 if (class >= 0) 187 snprintf(nbuf, sizeof nbuf, 188 "%02d%02d%02d.%06ld %s %02d ", 189 tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec, 190 _log_get_class(class), level); 191 else /* LOG_PRINT (-1) or LOG_REPORT (-2) */ 192 snprintf(nbuf, sizeof nbuf, "%02d%02d%02d.%06ld %s ", 193 tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec, 194 class == LOG_PRINT ? "Default" : "Report>"); 195 strlcat(nbuf, buffer, sizeof nbuf); 196 strlcat(nbuf, getuid() ? "" : " [priv]", LOG_SIZE + 32); 197 strlcat(nbuf, "\n", sizeof nbuf); 198 199 if (fwrite(nbuf, strlen(nbuf), 1, log_output) == 0) { 200 /* Report fallback. */ 201 syslog(LOG_ALERT, fallback_msg, errno); 202 fprintf(log_output, fallback_msg, errno); 203 204 /* 205 * Close log_output to prevent isakmpd from locking 206 * the file. We may need to explicitly close stdout 207 * to do this properly. 208 * XXX - Figure out how to match two FILE *'s and 209 * rewrite. 210 */ 211 if (fileno(log_output) != -1 && 212 fileno(stdout) == fileno(log_output)) 213 fclose(stdout); 214 fclose(log_output); 215 216 /* Fallback to syslog. */ 217 log_to(0); 218 219 /* (Re)send current message to syslog(). */ 220 syslog(class == LOG_REPORT ? LOG_ALERT : 221 syslog_level, "%s", buffer); 222 } 223 } else 224 syslog(class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s", 225 buffer); 226 } 227 228 void 229 log_debug(int cls, int level, const char *fmt, ...) 230 { 231 va_list ap; 232 233 /* 234 * If we are not debugging this class, or the level is too low, just 235 * return. 236 */ 237 if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) 238 return; 239 va_start(ap, fmt); 240 _log_print(0, LOG_INFO, fmt, ap, cls, level); 241 va_end(ap); 242 } 243 244 void 245 log_debug_buf(int cls, int level, const char *header, const u_int8_t *buf, 246 size_t sz) 247 { 248 size_t i, j; 249 char s[73]; 250 251 /* 252 * If we are not debugging this class, or the level is too low, just 253 * return. 254 */ 255 if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) 256 return; 257 258 log_debug(cls, level, "%s:", header); 259 for (i = j = 0; i < sz;) { 260 snprintf(s + j, sizeof s - j, "%02x", buf[i++]); 261 j += strlen(s + j); 262 if (i % 4 == 0) { 263 if (i % 32 == 0) { 264 s[j] = '\0'; 265 log_debug(cls, level, "%s", s); 266 j = 0; 267 } else 268 s[j++] = ' '; 269 } 270 } 271 if (j) { 272 s[j] = '\0'; 273 log_debug(cls, level, "%s", s); 274 } 275 } 276 277 void 278 log_debug_cmd(int cls, int level) 279 { 280 if (cls < 0 || cls >= LOG_ENDCLASS) { 281 log_print("log_debug_cmd: invalid debugging class %d", cls); 282 return; 283 } 284 if (level < 0) { 285 log_print("log_debug_cmd: invalid debugging level %d for " 286 "class %d", level, cls); 287 return; 288 } 289 if (level == log_level[cls]) 290 log_print("log_debug_cmd: log level unchanged for class %d", 291 cls); 292 else { 293 log_print("log_debug_cmd: log level changed from %d to %d " 294 "for class %d", log_level[cls], level, cls); 295 log_level[cls] = level; 296 } 297 } 298 299 void 300 log_debug_toggle(void) 301 { 302 static int log_level_copy[LOG_ENDCLASS], toggle = 0; 303 304 if (!toggle) { 305 LOG_DBG((LOG_MISC, 50, "log_debug_toggle: " 306 "debug levels cleared")); 307 memcpy(&log_level_copy, &log_level, sizeof log_level); 308 bzero(&log_level, sizeof log_level); 309 } else { 310 memcpy(&log_level, &log_level_copy, sizeof log_level); 311 LOG_DBG((LOG_MISC, 50, "log_debug_toggle: " 312 "debug levels restored")); 313 } 314 toggle = !toggle; 315 } 316 317 void 318 log_print(const char *fmt, ...) 319 { 320 va_list ap; 321 322 va_start(ap, fmt); 323 _log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0); 324 va_end(ap); 325 } 326 327 void 328 log_verbose(const char *fmt, ...) 329 { 330 va_list ap; 331 332 if (verbose_logging == 0) 333 return; 334 335 va_start(ap, fmt); 336 _log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0); 337 va_end(ap); 338 } 339 340 void 341 log_error(const char *fmt, ...) 342 { 343 va_list ap; 344 345 va_start(ap, fmt); 346 _log_print(1, LOG_ERR, fmt, ap, LOG_PRINT, 0); 347 va_end(ap); 348 } 349 350 void 351 log_errorx(const char *fmt, ...) 352 { 353 va_list ap; 354 355 va_start(ap, fmt); 356 _log_print(0, LOG_ERR, fmt, ap, LOG_PRINT, 0); 357 va_end(ap); 358 } 359 360 void 361 log_fatal(const char *fmt, ...) 362 { 363 va_list ap; 364 365 va_start(ap, fmt); 366 _log_print(1, LOG_CRIT, fmt, ap, LOG_PRINT, 0); 367 va_end(ap); 368 monitor_exit(1); 369 } 370 371 void 372 log_fatalx(const char *fmt, ...) 373 { 374 va_list ap; 375 376 va_start(ap, fmt); 377 _log_print(0, LOG_CRIT, fmt, ap, LOG_PRINT, 0); 378 va_end(ap); 379 monitor_exit(1); 380 } 381 382 void 383 log_packet_init(char *newname) 384 { 385 struct pcap_file_header sf_hdr; 386 struct stat st; 387 mode_t old_umask; 388 char *mode; 389 390 /* Allocate packet buffer first time through. */ 391 if (!packet_buf) 392 packet_buf = malloc(SNAPLEN); 393 394 if (!packet_buf) { 395 log_error("log_packet_init: malloc (%d) failed", SNAPLEN); 396 return; 397 } 398 if (pcaplog_file && strcmp(pcaplog_file, PCAP_FILE_DEFAULT) != 0) 399 free(pcaplog_file); 400 401 pcaplog_file = strdup(newname); 402 if (!pcaplog_file) { 403 log_error("log_packet_init: strdup (\"%s\") failed", newname); 404 return; 405 } 406 /* Does the file already exist? XXX lstat() or stat()? */ 407 /* XXX This is a fstat! */ 408 if (monitor_stat(pcaplog_file, &st) == 0) { 409 /* Sanity checks. */ 410 if (!S_ISREG(st.st_mode)) { 411 log_print("log_packet_init: existing capture file is " 412 "not a regular file"); 413 return; 414 } 415 if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) { 416 log_print("log_packet_init: existing capture " 417 "file has bad modes"); 418 return; 419 } 420 /* 421 * XXX It would be nice to check if it actually is a pcap 422 * file... 423 */ 424 425 mode = "a"; 426 } else 427 mode = "w"; 428 429 old_umask = umask(S_IRWXG | S_IRWXO); 430 packet_log = monitor_fopen(pcaplog_file, mode); 431 umask(old_umask); 432 433 if (!packet_log) { 434 log_error("log_packet_init: fopen (\"%s\", \"%s\") failed", 435 pcaplog_file, mode); 436 return; 437 } 438 log_print("log_packet_init: " 439 "starting IKE packet capture to file \"%s\"", pcaplog_file); 440 441 /* If this is a new file, we need to write a PCAP header to it. */ 442 if (*mode == 'w') { 443 sf_hdr.magic = TCPDUMP_MAGIC; 444 sf_hdr.version_major = PCAP_VERSION_MAJOR; 445 sf_hdr.version_minor = PCAP_VERSION_MINOR; 446 sf_hdr.thiszone = 0; 447 sf_hdr.snaplen = SNAPLEN; 448 sf_hdr.sigfigs = 0; 449 sf_hdr.linktype = DLT_LOOP; 450 451 fwrite((char *) &sf_hdr, sizeof sf_hdr, 1, packet_log); 452 fflush(packet_log); 453 } 454 } 455 456 void 457 log_packet_restart(char *newname) 458 { 459 if (packet_log) { 460 log_print("log_packet_restart: capture already active on " 461 "file \"%s\"", pcaplog_file); 462 return; 463 } 464 if (newname) 465 log_packet_init(newname); 466 else if (!pcaplog_file) 467 log_packet_init(PCAP_FILE_DEFAULT); 468 else 469 log_packet_init(pcaplog_file); 470 } 471 472 void 473 log_packet_stop(void) 474 { 475 /* Stop capture. */ 476 if (packet_log) { 477 fclose(packet_log); 478 log_print("log_packet_stop: stopped capture"); 479 } 480 packet_log = 0; 481 } 482 483 void 484 log_packet_iov(struct sockaddr *src, struct sockaddr *dst, struct iovec *iov, 485 int iovcnt) 486 { 487 struct isakmp_hdr *isakmphdr; 488 struct packhdr hdr; 489 struct udphdr udp; 490 struct timeval tv; 491 int off, datalen, hdrlen, i, add_espmarker = 0; 492 const u_int32_t espmarker = 0; 493 494 for (i = 0, datalen = 0; i < iovcnt; i++) 495 datalen += iov[i].iov_len; 496 497 if (!packet_log || datalen > SNAPLEN) 498 return; 499 500 /* copy packet into buffer */ 501 for (i = 0, off = 0; i < iovcnt; i++) { 502 memcpy(packet_buf + off, iov[i].iov_base, iov[i].iov_len); 503 off += iov[i].iov_len; 504 } 505 506 bzero(&hdr, sizeof hdr); 507 bzero(&udp, sizeof udp); 508 509 /* isakmp - turn off the encryption bit in the isakmp hdr */ 510 isakmphdr = (struct isakmp_hdr *) packet_buf; 511 isakmphdr->flags &= ~(ISAKMP_FLAGS_ENC); 512 513 /* udp */ 514 udp.uh_sport = sockaddr_port(src); 515 udp.uh_dport = sockaddr_port(dst); 516 datalen += sizeof udp; 517 if (ntohs(udp.uh_sport) == 4500 || 518 ntohs(udp.uh_dport) == 4500) { /* XXX Quick and dirty */ 519 add_espmarker = 1; 520 datalen += sizeof espmarker; 521 } 522 udp.uh_ulen = htons(datalen); 523 524 /* ip */ 525 hdr.sa_family = htonl(src->sa_family); 526 switch (src->sa_family) { 527 default: 528 /* Assume IPv4. XXX Can 'default' ever happen here? */ 529 hdr.sa_family = htonl(AF_INET); 530 hdr.ip.ip4.ip_src.s_addr = 0x02020202; 531 hdr.ip.ip4.ip_dst.s_addr = 0x01010101; 532 /* The rest of the setup is common to AF_INET. */ 533 goto setup_ip4; 534 535 case AF_INET: 536 hdr.ip.ip4.ip_src.s_addr = 537 ((struct sockaddr_in *)src)->sin_addr.s_addr; 538 hdr.ip.ip4.ip_dst.s_addr = 539 ((struct sockaddr_in *)dst)->sin_addr.s_addr; 540 541 setup_ip4: 542 hdrlen = sizeof hdr.ip.ip4; 543 hdr.ip.ip4.ip_v = 0x4; 544 hdr.ip.ip4.ip_hl = 0x5; 545 hdr.ip.ip4.ip_p = IPPROTO_UDP; 546 hdr.ip.ip4.ip_len = htons(datalen + hdrlen); 547 /* Let's use the IP ID as a "packet counter". */ 548 i = ntohs(hdr.ip.ip4.ip_id) + 1; 549 hdr.ip.ip4.ip_id = htons(i); 550 /* Calculate IP header checksum. */ 551 hdr.ip.ip4.ip_sum = in_cksum((u_int16_t *) & hdr.ip.ip4, 552 hdr.ip.ip4.ip_hl << 2); 553 break; 554 555 case AF_INET6: 556 hdrlen = sizeof(hdr.ip.ip6); 557 hdr.ip.ip6.ip6_vfc = IPV6_VERSION; 558 hdr.ip.ip6.ip6_nxt = IPPROTO_UDP; 559 hdr.ip.ip6.ip6_plen = udp.uh_ulen; 560 memcpy(&hdr.ip.ip6.ip6_src, 561 &((struct sockaddr_in6 *)src)->sin6_addr, 562 sizeof hdr.ip.ip6.ip6_src); 563 memcpy(&hdr.ip.ip6.ip6_dst, 564 &((struct sockaddr_in6 *)dst)->sin6_addr, 565 sizeof hdr.ip.ip6.ip6_dst); 566 break; 567 } 568 569 /* Calculate UDP checksum. */ 570 udp.uh_sum = udp_cksum(&hdr, &udp, (u_int16_t *) packet_buf); 571 hdrlen += sizeof hdr.sa_family; 572 573 /* pcap file packet header */ 574 gettimeofday(&tv, 0); 575 hdr.pcap.ts.tv_sec = tv.tv_sec; 576 hdr.pcap.ts.tv_usec = tv.tv_usec; 577 hdr.pcap.caplen = datalen + hdrlen; 578 hdr.pcap.len = datalen + hdrlen; 579 580 hdrlen += sizeof(struct pcap_pkthdr); 581 datalen -= sizeof(struct udphdr); 582 583 /* Write to pcap file. */ 584 fwrite(&hdr, hdrlen, 1, packet_log); /* pcap + IP */ 585 fwrite(&udp, sizeof(struct udphdr), 1, packet_log); /* UDP */ 586 if (add_espmarker) { 587 fwrite(&espmarker, sizeof espmarker, 1, packet_log); 588 datalen -= sizeof espmarker; 589 } 590 fwrite(packet_buf, datalen, 1, packet_log); /* IKE-data */ 591 fflush(packet_log); 592 } 593 594 /* Copied from tcpdump/print-udp.c, mostly rewritten. */ 595 static int 596 udp_cksum(struct packhdr *hdr, const struct udphdr *u, u_int16_t *d) 597 { 598 struct ip *ip4; 599 struct ip6_hdr *ip6; 600 int i, hdrlen, tlen = ntohs(u->uh_ulen) - sizeof(struct udphdr); 601 602 union phu { 603 struct ip4pseudo { 604 struct in_addr src; 605 struct in_addr dst; 606 u_int8_t z; 607 u_int8_t proto; 608 u_int16_t len; 609 } ip4p; 610 struct ip6pseudo { 611 struct in6_addr src; 612 struct in6_addr dst; 613 u_int32_t plen; 614 u_int16_t z0; 615 u_int8_t z1; 616 u_int8_t nxt; 617 } ip6p; 618 u_int16_t pa[20]; 619 } phu; 620 const u_int16_t *sp; 621 u_int32_t sum; 622 623 /* Setup pseudoheader. */ 624 bzero(phu.pa, sizeof phu); 625 switch (ntohl(hdr->sa_family)) { 626 case AF_INET: 627 ip4 = &hdr->ip.ip4; 628 memcpy(&phu.ip4p.src, &ip4->ip_src, sizeof(struct in_addr)); 629 memcpy(&phu.ip4p.dst, &ip4->ip_dst, sizeof(struct in_addr)); 630 phu.ip4p.proto = ip4->ip_p; 631 phu.ip4p.len = u->uh_ulen; 632 hdrlen = sizeof phu.ip4p; 633 break; 634 635 case AF_INET6: 636 ip6 = &hdr->ip.ip6; 637 memcpy(&phu.ip6p.src, &ip6->ip6_src, sizeof(phu.ip6p.src)); 638 memcpy(&phu.ip6p.dst, &ip6->ip6_dst, sizeof(phu.ip6p.dst)); 639 phu.ip6p.plen = u->uh_ulen; 640 phu.ip6p.nxt = ip6->ip6_nxt; 641 hdrlen = sizeof phu.ip6p; 642 break; 643 644 default: 645 return 0; 646 } 647 648 /* IPv6 wants a 0xFFFF checksum "on error", not 0x0. */ 649 if (tlen < 0) 650 return (ntohl(hdr->sa_family) == AF_INET ? 0 : 0xFFFF); 651 652 sum = 0; 653 for (i = 0; i < hdrlen; i += 2) 654 sum += phu.pa[i / 2]; 655 656 sp = (const u_int16_t *)u; 657 for (i = 0; i < (int)sizeof(struct udphdr); i += 2) 658 sum += *sp++; 659 660 sp = d; 661 for (i = 0; i < (tlen & ~1); i += 2) 662 sum += *sp++; 663 664 if (tlen & 1) 665 sum += htons((*(const char *)sp) << 8); 666 667 while (sum > 0xffff) 668 sum = (sum & 0xffff) + (sum >> 16); 669 sum = ~sum & 0xffff; 670 671 return sum; 672 } 673 674 /* Copied from tcpdump/print-ip.c, modified. */ 675 static u_int16_t 676 in_cksum(const u_int16_t *w, int len) 677 { 678 int nleft = len, sum = 0; 679 u_int16_t answer; 680 681 while (nleft > 1) { 682 sum += *w++; 683 nleft -= 2; 684 } 685 if (nleft == 1) 686 sum += htons(*(const u_char *)w << 8); 687 688 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 689 sum += (sum >> 16); /* add carry */ 690 answer = ~sum; /* truncate to 16 bits */ 691 return answer; 692 } 693