log.c revision 1.62
1/* $OpenBSD: log.c,v 1.62 2014/10/25 03:18:13 lteo 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
61static void	_log_print(int, int, const char *, va_list, int, int);
62
63static FILE	*log_output;
64
65int		verbose_logging = 0;
66static int	log_level[LOG_ENDCLASS];
67
68#define TCPDUMP_MAGIC	0xa1b2c3d4
69#define SNAPLEN		(64 * 1024)
70
71struct 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
80struct 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
86static char    *pcaplog_file = NULL;
87static FILE    *packet_log;
88static u_int8_t *packet_buf = NULL;
89
90static int      udp_cksum(struct packhdr *, const struct udphdr *,
91    u_int16_t *);
92static u_int16_t in_cksum(const u_int16_t *, int);
93
94void
95log_init(int debug)
96{
97	if (debug)
98		log_output = stderr;
99	else
100		log_to(0);	/* syslog */
101}
102
103void
104log_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
136void
137log_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
146FILE *
147log_current(void)
148{
149	return log_output;
150}
151
152static 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
166static 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
228void
229log_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
244void
245log_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
277void
278log_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
299void
300log_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
317void
318log_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
327void
328log_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
340void
341log_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
350void
351log_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
360void
361log_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
371void
372log_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
382void
383log_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
456void
457log_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
472void
473log_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
483void
484log_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
541setup_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.  */
595static int
596udp_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.  */
675static u_int16_t
676in_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