1/*	$NetBSD: dump.c,v 1.3 2006/09/09 16:22:09 manu Exp $	*/
2
3/*	$KAME: dump.c,v 1.3 2000/09/23 15:31:05 itojun Exp $	*/
4
5/*
6 * Copyright (C) 2000 WIDE Project.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "config.h"
35
36#include <sys/types.h>
37#include <sys/param.h>
38#include <sys/socket.h>
39#include <sys/queue.h>
40
41#include <netinet/in.h>
42#include <netinet/in_systm.h>
43#include <netinet/ip.h>
44#include <netinet/ip6.h>
45#include <netinet/udp.h>
46
47#include <stdlib.h>
48#include <stdio.h>
49#include <string.h>
50#include <errno.h>
51#if TIME_WITH_SYS_TIME
52# include <sys/time.h>
53# include <time.h>
54#else
55# if HAVE_SYS_TIME_H
56#  include <sys/time.h>
57# else
58#  include <time.h>
59# endif
60#endif
61#include <netdb.h>
62#ifdef HAVE_UNISTD_H
63#include <unistd.h>
64#endif
65#include <pcap.h>
66#include <fcntl.h>
67
68#include "vmbuf.h"
69
70/* copied from pcap-int.h */
71struct pcap_timeval {
72	u_int32_t tv_sec;	/* seconds */
73	u_int32_t tv_usec;	/* microseconds */
74};
75
76struct pcap_sf_pkthdr {
77	struct pcap_timeval ts;	/* time stamp */
78	u_int32_t caplen;	/* length of portion present */
79	u_int32_t len;		/* length this packet (off wire) */
80};
81
82#define TCPDUMP_MAGIC	0xa1b2c3d4
83
84static int fd = -1;
85
86int
87isakmp_dump_open(path)
88	char *path;
89{
90	struct pcap_file_header hdr;
91
92	path = "isakmp.dump";
93
94	if (fd >= 0)
95		return EBUSY;
96
97	fd = open(path, O_WRONLY|O_CREAT|O_APPEND, 0600);
98	if (fd < 0)
99		return errno;
100
101	memset(&hdr, 0, sizeof(hdr));
102	hdr.magic = TCPDUMP_MAGIC;
103	hdr.version_major = PCAP_VERSION_MAJOR;
104	hdr.version_minor = PCAP_VERSION_MINOR;
105
106	hdr.thiszone = 0;
107	hdr.snaplen = 60000;	/* should be enough */
108	hdr.sigfigs = 0;
109	hdr.linktype = DLT_NULL;
110
111	if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
112		return errno;
113
114	return 0;
115}
116
117int
118isakmp_dump_close()
119{
120	close(fd);
121	fd = -1;
122	return 0;
123}
124
125int
126isakmp_dump(msg, from, my)
127	vchar_t *msg;
128	struct sockaddr *from;
129	struct sockaddr *my;
130{
131	struct ip ip;
132#ifdef INET6
133	struct ip6_hdr ip6;
134#endif
135	struct udphdr uh;
136	int32_t af;	/*llhdr for DLT_NULL*/
137	struct pcap_sf_pkthdr sf_hdr;
138	struct timeval tv;
139
140	/* af validation */
141	if (from && my) {
142		if (from->sa_family == my->sa_family)
143			af = from->sa_family;
144		else
145			return EAFNOSUPPORT;
146	} else if (from)
147		af = from->sa_family;
148	else if (my)
149		af = my->sa_family;
150	else
151		af = AF_INET;	/*assume it*/
152	switch (af) {
153	case AF_INET:
154#ifdef INET6
155	case AF_INET6:
156#endif
157		break;
158	default:
159		return EAFNOSUPPORT;
160	}
161
162	memset(&sf_hdr, 0, sizeof(sf_hdr));
163	gettimeofday(&tv, NULL);
164	sf_hdr.ts.tv_sec = tv.tv_sec;
165	sf_hdr.ts.tv_usec = tv.tv_usec;
166
167	/* write out timestamp and llhdr */
168	switch (af == AF_INET) {
169	case AF_INET:
170		sf_hdr.caplen = sf_hdr.len = sizeof(ip);
171		break;
172	case AF_INET6:
173		sf_hdr.caplen = sf_hdr.len = sizeof(ip6);
174		break;
175	}
176	sf_hdr.caplen += sizeof(af) + sizeof(uh) + msg->l;
177	sf_hdr.len += sizeof(af) + sizeof(uh) + msg->l;
178	if (write(fd, &sf_hdr, sizeof(sf_hdr)) < sizeof(sf_hdr))
179		return errno;
180	if (write(fd, &af, sizeof(af)) < sizeof(af))
181		return errno;
182
183	/* write out llhdr and ip header */
184	if (af == AF_INET) {
185		memset(&ip, 0, sizeof(ip));
186		ip.ip_v = IPVERSION;
187		ip.ip_hl = sizeof(ip) >> 2;
188		if (from)
189			ip.ip_src = ((struct sockaddr_in *)from)->sin_addr;
190		if (my)
191			ip.ip_dst = ((struct sockaddr_in *)my)->sin_addr;
192		ip.ip_p = IPPROTO_UDP;
193		ip.ip_ttl = 1;
194		ip.ip_len = htons(sizeof(ip) + sizeof(uh) + msg->l);
195		if (write(fd, &ip, sizeof(ip)) < sizeof(ip))
196			return errno;
197	} else if (af == AF_INET6) {
198		memset(&ip6, 0, sizeof(ip6));
199		ip6.ip6_vfc = IPV6_VERSION;
200		if (from)
201			ip6.ip6_src = ((struct sockaddr_in6 *)from)->sin6_addr;
202		if (my)
203			ip6.ip6_dst = ((struct sockaddr_in6 *)my)->sin6_addr;
204		ip6.ip6_nxt = IPPROTO_UDP;
205		ip6.ip6_plen = htons(sizeof(uh) + msg->l);
206		ip6.ip6_hlim = 1;
207		if (write(fd, &ip6, sizeof(ip6)) < sizeof(ip6))
208			return errno;
209	}
210
211	/* write out udp header */
212	memset(&uh, 0, sizeof(uh));
213	uh.uh_sport = htons(500);
214	uh.uh_dport = htons(500);
215	uh.uh_ulen = htons(msg->l & 0xffff);
216	uh.uh_sum = htons(0x0000);	/*no checksum - invalid for IPv6*/
217	if (write(fd, &uh, sizeof(uh)) < sizeof(uh))
218		return errno;
219
220	/* write out payload */
221	if (write(fd, msg->v, msg->l) != msg->l)
222		return errno;
223
224	return 0;
225}
226