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