diff options
author | Hakan Olsson <ho@cvs.openbsd.org> | 2001-04-09 21:21:59 +0000 |
---|---|---|
committer | Hakan Olsson <ho@cvs.openbsd.org> | 2001-04-09 21:21:59 +0000 |
commit | 6e5fd4a8b572c00359a4c486c5d17ca41c147f5b (patch) | |
tree | f0f6a9c657b8d7908d5da659e4d1b95d58cd0fd9 /sbin/isakmpd/log.c | |
parent | 5992f6def85167a8348043abe1d64c19a4f3f325 (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.c | 298 |
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 */ |