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