summaryrefslogtreecommitdiff
path: root/sbin/isakmpd/log.c
diff options
context:
space:
mode:
authorHakan Olsson <ho@cvs.openbsd.org>2001-04-09 21:21:59 +0000
committerHakan Olsson <ho@cvs.openbsd.org>2001-04-09 21:21:59 +0000
commit6e5fd4a8b572c00359a4c486c5d17ca41c147f5b (patch)
treef0f6a9c657b8d7908d5da659e4d1b95d58cd0fd9 /sbin/isakmpd/log.c
parent5992f6def85167a8348043abe1d64c19a4f3f325 (diff)
isakmpd can now capture un-encrypted IKE negotiation packets to a
file. In pcap(3) format, so tcpdump(8) can read it. Idea by Tim Newsham <newsham@lava.net>, work by him and me. Ok angelos@, niklas@
Diffstat (limited to 'sbin/isakmpd/log.c')
-rw-r--r--sbin/isakmpd/log.c298
1 files changed, 296 insertions, 2 deletions
diff --git a/sbin/isakmpd/log.c b/sbin/isakmpd/log.c
index 11f03980545..0b443b897a0 100644
--- a/sbin/isakmpd/log.c
+++ b/sbin/isakmpd/log.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.c,v 1.16 2001/01/27 12:03:33 niklas Exp $ */
+/* $OpenBSD: log.c,v 1.17 2001/04/09 21:21:57 ho Exp $ */
/* $EOM: log.c,v 1.30 2000/09/29 08:19:23 niklas Exp $ */
/*
@@ -35,25 +35,75 @@
* This code was written under funding by Ericsson Radio Systems.
*/
+#include <sys/types.h>
#include <sys/time.h>
+
+#ifdef USE_DEBUG
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_PCAP
+#include <pcap.h>
+#else
+#include "sysdep/common/pcap.h"
+#endif
+
+#endif /* USE_DEBUG */
+
#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <syslog.h>
+
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
+#include "isakmp_num.h"
#include "log.h"
static void _log_print (int, int, const char *, va_list, int, int);
static FILE *log_output;
+
#ifdef USE_DEBUG
static int log_level[LOG_ENDCLASS];
-#endif
+
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+#define SNAPLEN (64 * 1024)
+
+struct packhdr {
+ struct pcap_pkthdr pcap; /* pcap file packet header */
+ struct {
+ u_int32_t null_family; /* NULL encapsulation */
+ } null;
+ struct ip ip; /* IP header (w/o options) */
+ struct udphdr udp; /* UDP header */
+};
+
+struct isakmp_hdr {
+ u_int8_t icookie[8], rcookie[8];
+ u_int8_t next, ver, type, flags;
+ u_int32_t msgid, len;
+};
+
+static char *pcaplog_file = NULL;
+static FILE *packet_log;
+static u_int8_t pack[SNAPLEN + sizeof (struct packhdr)];
+static struct packhdr *hdr;
+
+static int udp_cksum (const struct ip *, const struct udphdr *, int);
+static u_int16_t in_cksum (const struct ip *, int);
+#endif /* USE_DEBUG */
void
log_init (void)
@@ -306,3 +356,247 @@ log_fatal (fmt, va_alist)
va_end (ap);
exit (1);
}
+
+#ifdef USE_DEBUG
+void
+log_packet_init (char *newname)
+{
+ struct pcap_file_header sf_hdr;
+ mode_t old_umask;
+
+ if (pcaplog_file && strcmp (pcaplog_file, PCAP_FILE_DEFAULT) != 0)
+ free (pcaplog_file);
+
+ pcaplog_file = strdup (newname);
+ if (!pcaplog_file)
+ {
+ log_error ("log_packet_init: strdup (\"%s\") failed", newname);
+ return;
+ }
+
+ old_umask = umask (S_IRWXG | S_IRWXO);
+ packet_log = fopen (pcaplog_file, "w");
+ umask (old_umask);
+
+ if (!packet_log)
+ {
+ log_error ("log_packet_init: fopen (\"%s\", \"w\") failed",
+ pcaplog_file);
+ return;
+ }
+
+ log_print ("log_packet_init: starting IKE packet capture to file \"%s\"",
+ pcaplog_file);
+
+ sf_hdr.magic = TCPDUMP_MAGIC;
+ sf_hdr.version_major = PCAP_VERSION_MAJOR;
+ sf_hdr.version_minor = PCAP_VERSION_MINOR;
+ sf_hdr.thiszone = 0;
+ sf_hdr.snaplen = SNAPLEN;
+ sf_hdr.sigfigs = 0;
+ sf_hdr.linktype = DLT_NULL;
+
+ fwrite ((char *)&sf_hdr, sizeof sf_hdr, 1, packet_log);
+ fflush (packet_log);
+
+ /* prep dummy header prepended to each packet */
+ hdr = (struct packhdr *)pack;
+ hdr->null.null_family = AF_INET;
+ hdr->ip.ip_v = 0x4;
+ hdr->ip.ip_hl = 0x5;
+ hdr->ip.ip_p = IPPROTO_UDP;
+ hdr->udp.uh_sport = htons (500);
+ hdr->udp.uh_dport = htons (500);
+}
+
+void
+log_packet_restart (char *newname)
+{
+ struct stat st;
+
+ if (packet_log)
+ {
+ log_print ("log_packet_restart: capture already active on file \"%s\"",
+ pcaplog_file);
+ return;
+ }
+
+ if (newname)
+ {
+ if (stat (newname, &st) == 0)
+ log_print ("log_packet_restart: won't overwrite existing \"%s\"",
+ newname);
+ else
+ log_packet_init (newname);
+ }
+ else if (!pcaplog_file)
+ log_packet_init (PCAP_FILE_DEFAULT);
+ else if (stat (pcaplog_file, &st) != 0)
+ log_packet_init (pcaplog_file);
+ else
+ {
+ /* Re-activate capture on current file. */
+ packet_log = fopen (pcaplog_file, "a");
+ if (!packet_log)
+ log_error ("log_packet_restart: fopen (\"%s\", \"a\") failed",
+ pcaplog_file);
+ else
+ log_print ("log_packet_restart: capture restarted on file \"%s\"",
+ pcaplog_file);
+ }
+}
+
+void
+log_packet_stop (void)
+{
+ /* Stop capture. */
+ if (packet_log)
+ {
+ fclose (packet_log);
+ log_print ("log_packet_stop: stopped capture");
+ }
+ packet_log = 0;
+}
+
+void
+log_packet_iov (struct sockaddr *src, struct sockaddr *dst, struct iovec *iov,
+ int iovcnt)
+{
+ struct isakmp_hdr *isakmphdr;
+ int off, len, i;
+
+ len = 0;
+ for (i = 0; i < iovcnt; i++)
+ len += iov[i].iov_len;
+
+ if (!packet_log || len > SNAPLEN)
+ return;
+
+ /* copy packet into buffer */
+ off = sizeof *hdr;
+ for (i = 0; i < iovcnt; i++)
+ {
+ memcpy (pack + off, iov[i].iov_base, iov[i].iov_len);
+ off += iov[i].iov_len;
+ }
+
+ /* isakmp - turn off the encryption bit in the isakmp hdr */
+ isakmphdr = (struct isakmp_hdr *)(pack + sizeof *hdr);
+ isakmphdr->flags &= ~(ISAKMP_FLAGS_ENC);
+
+ /* udp */
+ len += sizeof hdr->udp;
+ hdr->udp.uh_ulen = htons (len);
+
+ /* ip */
+ len += sizeof hdr->ip;
+ hdr->ip.ip_len = htons (len);
+
+ switch (src->sa_family)
+ {
+ case AF_INET:
+ hdr->ip.ip_src.s_addr = ((struct sockaddr_in *)src)->sin_addr.s_addr;
+ hdr->ip.ip_dst.s_addr = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
+ break;
+ case AF_INET6:
+ /* XXX TBD */
+ default:
+ hdr->ip.ip_src.s_addr = 0x02020202;
+ hdr->ip.ip_dst.s_addr = 0x01010101;
+ }
+
+ /* Let's use the IP ID as a "packet counter". */
+ i = ntohs (hdr->ip.ip_id) + 1;
+ hdr->ip.ip_id = htons (i);
+
+ /* Calculate UDP checksum. */
+ hdr->udp.uh_sum = 0;
+ hdr->udp.uh_sum = udp_cksum (&hdr->ip, &hdr->udp, len);
+
+ /* Calculate IP header checksum. */
+ hdr->ip.ip_sum = 0;
+ hdr->ip.ip_sum = in_cksum (&hdr->ip, hdr->ip.ip_hl << 2);
+
+ /* null header */
+ len += sizeof hdr->null;
+
+ /* pcap file packet header */
+ gettimeofday (&hdr->pcap.ts, 0);
+ hdr->pcap.caplen = len;
+ hdr->pcap.len = len;
+ len += sizeof hdr->pcap;
+
+ fwrite (pack, len, 1, packet_log);
+ fflush (packet_log);
+ return;
+}
+
+/* Copied from tcpdump/print-udp.c */
+static int
+udp_cksum (const struct ip *ip, const struct udphdr *up, int len)
+{
+ int i, tlen;
+ union phu {
+ struct phdr {
+ u_int32_t src;
+ u_int32_t dst;
+ u_char mbz;
+ u_char proto;
+ u_int16_t len;
+ } ph;
+ u_int16_t pa[6];
+ } phu;
+ const u_int16_t *sp;
+ u_int32_t sum;
+ tlen = ntohs (ip->ip_len) - ((const char *)up-(const char*)ip);
+
+ /* pseudo-header.. */
+ phu.ph.len = htons (tlen);
+ phu.ph.mbz = 0;
+ phu.ph.proto = ip->ip_p;
+ memcpy (&phu.ph.src, &ip->ip_src.s_addr, sizeof (u_int32_t));
+ memcpy (&phu.ph.dst, &ip->ip_dst.s_addr, sizeof (u_int32_t));
+
+ sp = &phu.pa[0];
+ sum = sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5];
+
+ sp = (const u_int16_t *)up;
+
+ for (i = 0; i < (tlen&~1); i += 2)
+ sum += *sp++;
+
+ if (tlen & 1) {
+ sum += htons ((*(const char *)sp) << 8);
+ }
+
+ while (sum > 0xffff)
+ sum = (sum & 0xffff) + (sum >> 16);
+ sum = ~sum & 0xffff;
+
+ return sum;
+}
+
+/* Copied from tcpdump/print-ip.c, modified. */
+static u_int16_t
+in_cksum (const struct ip *ip, int len)
+{
+ int nleft = len;
+ const u_short *w = (const u_short *)ip;
+ u_short answer;
+ int sum = 0;
+
+ while (nleft > 1) {
+ sum += *w++;
+ nleft -= 2;
+ }
+ if (nleft == 1)
+ sum += htons (*(u_char *)w<<8);
+
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return answer;
+}
+
+
+#endif /* USE_DEBUG */