1145519Sdarrenr/*	$FreeBSD$	*/
2145510Sdarrenr
3145510Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5145510Sdarrenr *
6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145510Sdarrenr *
8255332Scy * $Id$
9145510Sdarrenr */
10145510Sdarrenr#include "ipf.h"
11145510Sdarrenr#include "ipt.h"
12145510Sdarrenr
13145510Sdarrenr#if !defined(lint)
14255332Scystatic const char rcsid[] = "@(#)$Id$";
15145510Sdarrenr#endif
16145510Sdarrenr
17145510Sdarrenrstruct	llc	{
18145510Sdarrenr	int	lc_type;
19145510Sdarrenr	int	lc_sz;	/* LLC header length */
20145510Sdarrenr	int	lc_to;	/* LLC Type offset */
21145510Sdarrenr	int	lc_tl;	/* LLC Type length */
22145510Sdarrenr};
23145510Sdarrenr
24145510Sdarrenr/*
25145510Sdarrenr * While many of these maybe the same, some do have different header formats
26145510Sdarrenr * which make this useful.
27145510Sdarrenr */
28145510Sdarrenr
29145510Sdarrenrstatic	struct	llc	llcs[] = {
30255332Scy	{ 0, 0, 0, 0 },				/* DLT_NULL */
31255332Scy	{ 1, 14, 12, 2 },			/* DLT_Ethernet */
32255332Scy	{ 10, 0, 0, 0 },			/* DLT_FDDI */
33255332Scy	{ 12, 0, 0, 0 },			/* DLT_RAW */
34145510Sdarrenr	{ -1, -1, -1, -1 }
35145510Sdarrenr};
36145510Sdarrenr
37255332Scytypedef struct {
38255332Scy	u_int	id;
39255332Scy	u_short	major;
40255332Scy	u_short	minor;
41255332Scy	u_int	timezone;
42255332Scy	u_int	sigfigs;
43255332Scy	u_int	snaplen;
44255332Scy	u_int	type;
45255332Scy} fileheader_t;
46145510Sdarrenr
47255332Scytypedef struct {
48255332Scy	u_32_t	seconds;
49255332Scy	u_32_t	microseconds;
50255332Scy	u_32_t	caplen;
51255332Scy	u_32_t	wirelen;
52255332Scy} packetheader_t;
53255332Scy
54255332Scystatic	int	ipcap_open __P((char *));
55255332Scystatic	int	ipcap_close __P((void));
56255332Scystatic	int	ipcap_readip __P((mb_t *, char **, int *));
57255332Scystatic	int	ipcap_read_rec __P((packetheader_t *));
58255332Scystatic	void	iswap_hdr __P((fileheader_t *));
59255332Scy
60145510Sdarrenrstatic	int	pfd = -1, swapped = 0;
61145510Sdarrenrstatic	struct llc	*llcp = NULL;
62145510Sdarrenr
63255332Scystruct	ipread	pcap = { ipcap_open, ipcap_close, ipcap_readip, 0 };
64145510Sdarrenr
65145510Sdarrenr#define	SWAPLONG(y)	\
66145510Sdarrenr	((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
67145510Sdarrenr#define	SWAPSHORT(y)	\
68145510Sdarrenr	( (((y)&0xff)<<8) | (((y)&0xff00)>>8) )
69145510Sdarrenr
70255332Scystatic	void	iswap_hdr(p)
71255332Scy	fileheader_t	*p;
72145510Sdarrenr{
73255332Scy	p->major = SWAPSHORT(p->major);
74255332Scy	p->minor = SWAPSHORT(p->minor);
75255332Scy	p->timezone = SWAPLONG(p->timezone);
76255332Scy	p->sigfigs = SWAPLONG(p->sigfigs);
77255332Scy	p->snaplen = SWAPLONG(p->snaplen);
78255332Scy	p->type = SWAPLONG(p->type);
79145510Sdarrenr}
80145510Sdarrenr
81255332Scystatic	int	ipcap_open(fname)
82255332Scy	char	*fname;
83145510Sdarrenr{
84255332Scy	fileheader_t ph;
85145510Sdarrenr	int fd, i;
86145510Sdarrenr
87145510Sdarrenr	if (pfd != -1)
88145510Sdarrenr		return pfd;
89145510Sdarrenr
90145510Sdarrenr	if (!strcmp(fname, "-"))
91145510Sdarrenr		fd = 0;
92145510Sdarrenr	else if ((fd = open(fname, O_RDONLY)) == -1)
93145510Sdarrenr		return -1;
94145510Sdarrenr
95145510Sdarrenr	if (read(fd, (char *)&ph, sizeof(ph)) != sizeof(ph))
96145510Sdarrenr		return -2;
97145510Sdarrenr
98255332Scy	if (ph.id != 0xa1b2c3d4) {
99255332Scy		if (SWAPLONG(ph.id) != 0xa1b2c3d4) {
100145510Sdarrenr			(void) close(fd);
101145510Sdarrenr			return -2;
102145510Sdarrenr		}
103145510Sdarrenr		swapped = 1;
104255332Scy		iswap_hdr(&ph);
105145510Sdarrenr	}
106145510Sdarrenr
107145510Sdarrenr	for (i = 0; llcs[i].lc_type != -1; i++)
108255332Scy		if (llcs[i].lc_type == ph.type) {
109145510Sdarrenr			llcp = llcs + i;
110145510Sdarrenr			break;
111145510Sdarrenr		}
112145510Sdarrenr
113145510Sdarrenr	if (llcp == NULL) {
114145510Sdarrenr		(void) close(fd);
115145510Sdarrenr		return -2;
116145510Sdarrenr	}
117145510Sdarrenr
118145510Sdarrenr	pfd = fd;
119145510Sdarrenr	printf("opened pcap file %s:\n", fname);
120145510Sdarrenr	printf("\tid: %08x version: %d.%d type: %d snap %d\n",
121255332Scy		ph.id, ph.major, ph.minor, ph.type, ph.snaplen);
122145510Sdarrenr
123145510Sdarrenr	return fd;
124145510Sdarrenr}
125145510Sdarrenr
126145510Sdarrenr
127255332Scystatic	int	ipcap_close()
128145510Sdarrenr{
129145510Sdarrenr	return close(pfd);
130145510Sdarrenr}
131145510Sdarrenr
132145510Sdarrenr
133145510Sdarrenr/*
134145510Sdarrenr * read in the header (and validate) which should be the first record
135145510Sdarrenr * in a pcap file.
136145510Sdarrenr */
137255332Scystatic	int	ipcap_read_rec(rec)
138255332Scy	packetheader_t *rec;
139145510Sdarrenr{
140153881Sguido	int	n, p, i;
141153881Sguido	char	*s;
142145510Sdarrenr
143153881Sguido	s = (char *)rec;
144153881Sguido	n = sizeof(*rec);
145145510Sdarrenr
146153881Sguido	while (n > 0) {
147153881Sguido		i = read(pfd, (char *)rec, sizeof(*rec));
148153881Sguido		if (i <= 0)
149153881Sguido			return -2;
150153881Sguido		s += i;
151153881Sguido		n -= i;
152153881Sguido	}
153153881Sguido
154145510Sdarrenr	if (swapped) {
155255332Scy		rec->caplen = SWAPLONG(rec->caplen);
156255332Scy		rec->wirelen = SWAPLONG(rec->wirelen);
157255332Scy		rec->seconds = SWAPLONG(rec->seconds);
158255332Scy		rec->microseconds = SWAPLONG(rec->microseconds);
159145510Sdarrenr	}
160255332Scy	p = rec->caplen;
161255332Scy	n = MIN(p, rec->wirelen);
162145510Sdarrenr	if (!n || n < 0)
163145510Sdarrenr		return -3;
164145510Sdarrenr
165153881Sguido	if (p < 0 || p > 65536)
166153881Sguido		return -4;
167145510Sdarrenr	return p;
168145510Sdarrenr}
169145510Sdarrenr
170145510Sdarrenr
171145510Sdarrenr#ifdef	notyet
172145510Sdarrenr/*
173145510Sdarrenr * read an entire pcap packet record.  only the data part is copied into
174145510Sdarrenr * the available buffer, with the number of bytes copied returned.
175145510Sdarrenr */
176255332Scystatic	int	ipcap_read(buf, cnt)
177255332Scy	char	*buf;
178255332Scy	int	cnt;
179145510Sdarrenr{
180255332Scy	packetheader_t rec;
181145510Sdarrenr	static	char	*bufp = NULL;
182145510Sdarrenr	int	i, n;
183145510Sdarrenr
184255332Scy	if ((i = ipcap_read_rec(&rec)) <= 0)
185145510Sdarrenr		return i;
186145510Sdarrenr
187145510Sdarrenr	if (!bufp)
188145510Sdarrenr		bufp = malloc(i);
189145510Sdarrenr	else
190145510Sdarrenr		bufp = realloc(bufp, i);
191145510Sdarrenr
192145510Sdarrenr	if (read(pfd, bufp, i) != i)
193145510Sdarrenr		return -2;
194145510Sdarrenr
195145510Sdarrenr	n = MIN(i, cnt);
196145510Sdarrenr	bcopy(bufp, buf, n);
197145510Sdarrenr	return n;
198145510Sdarrenr}
199145510Sdarrenr#endif
200145510Sdarrenr
201145510Sdarrenr
202145510Sdarrenr/*
203145510Sdarrenr * return only an IP packet read into buf
204145510Sdarrenr */
205255332Scystatic	int	ipcap_readip(mb, ifn, dir)
206255332Scy	mb_t	*mb;
207255332Scy	char	**ifn;
208255332Scy	int	*dir;
209145510Sdarrenr{
210145510Sdarrenr	static	char	*bufp = NULL;
211255332Scy	packetheader_t	rec;
212145510Sdarrenr	struct	llc	*l;
213145510Sdarrenr	char	*s, ty[4];
214153881Sguido	int	i, j, n;
215255332Scy	char	*buf;
216255332Scy	int	cnt;
217145510Sdarrenr
218255332Scy#if 0
219255332Scy	ifn = ifn;	/* gcc -Wextra */
220255332Scy	dir = dir;	/* gcc -Wextra */
221255332Scy#endif
222255332Scy	buf = (char *)mb->mb_buf;
223255332Scy	cnt = sizeof(mb->mb_buf);
224145510Sdarrenr	l = llcp;
225145510Sdarrenr
226145510Sdarrenr	/* do { */
227255332Scy		if ((i = ipcap_read_rec(&rec)) <= 0)
228145510Sdarrenr			return i;
229145510Sdarrenr
230145510Sdarrenr		if (!bufp)
231145510Sdarrenr			bufp = malloc(i);
232145510Sdarrenr		else
233145510Sdarrenr			bufp = realloc(bufp, i);
234145510Sdarrenr		s = bufp;
235145510Sdarrenr
236153881Sguido		for (j = i, n = 0; j > 0; ) {
237153881Sguido			n = read(pfd, s, j);
238153881Sguido			if (n <= 0)
239153881Sguido				return -2;
240153881Sguido			j -= n;
241153881Sguido			s += n;
242153881Sguido		}
243153881Sguido		s = bufp;
244145510Sdarrenr
245145510Sdarrenr		i -= l->lc_sz;
246145510Sdarrenr		s += l->lc_to;
247145510Sdarrenr		bcopy(s, ty, l->lc_tl);
248145510Sdarrenr		s += l->lc_tl;
249145510Sdarrenr	/* } while (ty[0] != 0x8 && ty[1] != 0); */
250145510Sdarrenr	n = MIN(i, cnt);
251145510Sdarrenr	bcopy(s, buf, n);
252255332Scy	mb->mb_len = n;
253145510Sdarrenr	return n;
254145510Sdarrenr}
255