155714Skris/*	$FreeBSD$	*/
255714Skris
355714Skris/*
455714Skris * (C)opyright 1992-1998 Darren Reed. (from tcplog)
555714Skris *
655714Skris * See the IPFILTER.LICENCE file for details on licencing.
755714Skris *
8280304Sjkim */
955714Skris
1055714Skris#include <stdio.h>
1155714Skris#include <netdb.h>
1255714Skris#include <ctype.h>
1355714Skris#include <fcntl.h>
1455714Skris#include <signal.h>
15280304Sjkim#include <errno.h>
1655714Skris#include <sys/types.h>
1755714Skris#include <sys/time.h>
1855714Skris#include <sys/timeb.h>
1955714Skris#include <sys/socket.h>
2055714Skris#include <sys/file.h>
2155714Skris#include <sys/ioctl.h>
22280304Sjkim#include <sys/stropts.h>
2355714Skris
2455714Skris#include <sys/pfmod.h>
2555714Skris#include <sys/bufmod.h>
2655714Skris#include <sys/dlpi.h>
2755714Skris
2855714Skris#include <net/if.h>
2955714Skris#include <netinet/in.h>
3055714Skris#include <netinet/in_systm.h>
3155714Skris#include <netinet/ip.h>
3255714Skris#include <netinet/if_ether.h>
3355714Skris#include <netinet/ip_var.h>
3455714Skris#include <netinet/udp.h>
3555714Skris#include <netinet/udp_var.h>
3655714Skris#include <netinet/tcp.h>
37280304Sjkim#include <netinet/tcpip.h>
3855714Skris
3955714Skris#include "ip_compat.h"
40280304Sjkim
4155714Skris#ifndef	lint
4255714Skrisstatic	char	snitid[] = "%W% %G% (C)1995 Darren Reed";
4355714Skris#endif
4455714Skris
4555714Skris#define BUFSPACE	32768
4655714Skris
4755714Skrisstatic	int	solfd;
4855714Skris
4955714Skris/*
5055714Skris * Be careful to only include those defined in the flags option for the
5155714Skris * interface are included in the header size.
52280304Sjkim */
5355714Skrisstatic	int	timeout;
5455714Skris
5555714Skris
5655714Skrisvoid	nullbell()
5755714Skris{
5855714Skris	return 0;
5955714Skris}
6055714Skris
6155714Skris
6255714Skrisint	ack_recv(ep)
6355714Skris	char	*ep;
6455714Skris{
65280304Sjkim	struct	tcpiphdr	tip;
66280304Sjkim	tcphdr_t	*tcp;
67280304Sjkim	ip_t	*ip;
68280304Sjkim
6955714Skris	ip = (ip_t *)&tip;
70280304Sjkim	tcp = (tcphdr_t *)(ip + 1);
7155714Skris	bcopy(ep, (char *)ip, sizeof(*ip));
7255714Skris	bcopy(ep + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp));
73109998Smarkm
7455714Skris	if (ip->ip_off & 0x1fff != 0)
75109998Smarkm		return 0;
7655714Skris	if (0 == detect(ip, tcp))
7755714Skris		return 1;
7855714Skris	return 0;
7955714Skris}
8055714Skris
8155714Skris
8255714Skrisint	readloop(fd, port, dst)
8355714Skris	int 	fd, port;
8455714Skris	struct	in_addr dst;
8555714Skris{
86109998Smarkm	static	u_char	buf[BUFSPACE];
87280304Sjkim	register u_char	*bp, *cp, *bufend;
88280304Sjkim	register struct	sb_hdr	*hp;
89238405Sjkim	register int	cc;
90280304Sjkim	struct	strbuf	dbuf;
91238405Sjkim	ether_header_t	eh;
92280304Sjkim	time_t	now = time(NULL);
93280304Sjkim	int	flags = 0, i, done = 0;
94280304Sjkim
95280304Sjkim	fd = solfd;
96280304Sjkim	dbuf.len = 0;
97280304Sjkim	dbuf.buf = buf;
98280304Sjkim	dbuf.maxlen = sizeof(buf);
99280304Sjkim	/*
100280304Sjkim	 * no control data buffer...
101280304Sjkim	 */
102280304Sjkim	while (1) {
103280304Sjkim		(void) signal(SIGALRM, nullbell);
104280304Sjkim		alarm(1);
105280304Sjkim		i = getmsg(fd, NULL, &dbuf, &flags);
10655714Skris		alarm(0);
107280304Sjkim		(void) signal(SIGALRM, nullbell);
108280304Sjkim
109280304Sjkim		cc = dbuf.len;
110280304Sjkim		if ((time(NULL) - now) > timeout)
111280304Sjkim			return done;
112280304Sjkim		if (i == -1)
113280304Sjkim			if (errno == EINTR)
114280304Sjkim				continue;
115280304Sjkim			else
116280304Sjkim				break;
117280304Sjkim		bp = buf;
118280304Sjkim		bufend = buf + cc;
119280304Sjkim		/*
120280304Sjkim		 * loop through each snapshot in the chunk
121280304Sjkim		 */
122280304Sjkim		while (bp < bufend) {
123280304Sjkim			/*
124280304Sjkim			 * get past bufmod header
125280304Sjkim			 */
126280304Sjkim			hp = (struct sb_hdr *)bp;
127280304Sjkim			cp = (u_char *)((char *)bp + sizeof(*hp));
128280304Sjkim			bcopy(cp, (char *)&eh, sizeof(eh));
129280304Sjkim			/*
130280304Sjkim			 * next snapshot
131280304Sjkim			 */
132280304Sjkim			bp += hp->sbh_totlen;
133280304Sjkim			cc -= hp->sbh_totlen;
134280304Sjkim
135280304Sjkim			if (eh.ether_type != ETHERTYPE_IP)
136280304Sjkim				continue;
137280304Sjkim
138280304Sjkim			cp += sizeof(eh);
139280304Sjkim			done += ack_recv(cp);
140280304Sjkim		}
141280304Sjkim		alarm(1);
142280304Sjkim	}
14355714Skris	perror("getmsg");
144280304Sjkim	exit(-1);
145280304Sjkim}
146280304Sjkim
14755714Skrisint	initdevice(device, tout)
148280304Sjkim	char	*device;
149280304Sjkim	int	tout;
150280304Sjkim{
151280304Sjkim	struct	strioctl si;
152280304Sjkim	struct	timeval to;
153280304Sjkim	struct	ifreq ifr;
154280304Sjkim	struct	packetfilt pfil;
155280304Sjkim	u_long	if_flags;
156280304Sjkim	u_short	*fwp = pfil.Pf_Filter;
157280304Sjkim	char	devname[16], *s, buf[256];
158280304Sjkim	int	i, offset, fd, snaplen= 58, chunksize = BUFSPACE;
159280304Sjkim
160280304Sjkim	(void) sprintf(devname, "/dev/%s", device);
161280304Sjkim
162280304Sjkim	s = devname + 5;
16355714Skris	while (*s && !ISDIGIT(*s))
164280304Sjkim		s++;
165280304Sjkim	if (!*s)
166280304Sjkim	    {
167280304Sjkim		fprintf(stderr, "bad device name %s\n", devname);
168280304Sjkim		exit(-1);
169280304Sjkim	    }
170280304Sjkim	i = atoi(s);
171280304Sjkim	*s = '\0';
172280304Sjkim	/*
173280304Sjkim	 * For reading
174280304Sjkim	 */
17555714Skris	if ((fd = open(devname, O_RDWR)) < 0)
176280304Sjkim	    {
177280304Sjkim		fprintf(stderr, "O_RDWR(0) ");
178280304Sjkim		perror(devname);
179280304Sjkim		exit(-1);
180280304Sjkim	    }
181280304Sjkim	if (dlattachreq(fd, i) == -1 || dlokack(fd, buf) == -1)
182280304Sjkim	    {
183280304Sjkim		fprintf(stderr, "DLPI error\n");
184280304Sjkim		exit(-1);
185280304Sjkim	    }
186280304Sjkim	dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0);
187280304Sjkim	dlbindack(fd, buf);
188280304Sjkim	/*
189280304Sjkim	 * read full headers
190280304Sjkim	 */
19155714Skris	if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1)
192280304Sjkim	    {
193280304Sjkim		fprintf(stderr, "DLIOCRAW error\n");
194280304Sjkim		exit(-1);
195280304Sjkim	    }
196280304Sjkim	/*
197280304Sjkim	 * Create some filter rules for our TCP watcher. We only want ethernet
198280304Sjkim	 * pacets which are IP protocol and only the TCP packets from IP.
199280304Sjkim	 */
200280304Sjkim	offset = 6;
20155714Skris	*fwp++ = ENF_PUSHWORD + offset;
202280304Sjkim	*fwp++ = ENF_PUSHLIT | ENF_CAND;
203280304Sjkim	*fwp++ = htons(ETHERTYPE_IP);
204280304Sjkim	*fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4;
205280304Sjkim	*fwp++ = ENF_PUSHLIT | ENF_AND;
206280304Sjkim	*fwp++ = htons(0x00ff);
207280304Sjkim	*fwp++ = ENF_PUSHLIT | ENF_COR;
208280304Sjkim	*fwp++ = htons(IPPROTO_TCP);
209280304Sjkim	*fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4;
210280304Sjkim	*fwp++ = ENF_PUSHLIT | ENF_AND;
211280304Sjkim	*fwp++ = htons(0x00ff);
212280304Sjkim	*fwp++ = ENF_PUSHLIT | ENF_CAND;
213280304Sjkim	*fwp++ = htons(IPPROTO_UDP);
214280304Sjkim	pfil.Pf_FilterLen = (fwp - &pfil.Pf_Filter[0]);
21555714Skris	/*
216280304Sjkim	 * put filter in place.
217280304Sjkim	 */
218280304Sjkim
219280304Sjkim	if (ioctl(fd, I_PUSH, "pfmod") == -1)
22055714Skris	    {
221280304Sjkim		perror("ioctl: I_PUSH pf");
222280304Sjkim		exit(1);
223280304Sjkim	    }
224280304Sjkim	if (strioctl(fd, PFIOCSETF, -1, sizeof(pfil), (char *)&pfil) == -1)
225280304Sjkim	    {
226280304Sjkim		perror("ioctl: PFIOCSETF");
227280304Sjkim		exit(1);
228280304Sjkim	    }
229280304Sjkim
230280304Sjkim	/*
231280304Sjkim	 * arrange to get messages from the NIT STREAM and use NIT_BUF option
232280304Sjkim	 */
233280304Sjkim	if (ioctl(fd, I_PUSH, "bufmod") == -1)
234280304Sjkim	    {
235280304Sjkim		perror("ioctl: I_PUSH bufmod");
236		exit(1);
237	    }
238	i = 128;
239	strioctl(fd, SBIOCSSNAP, -1, sizeof(i), (char *)&i);
240	/*
241	 * set the timeout
242	 */
243	to.tv_sec = 1;
244	to.tv_usec = 0;
245	if (strioctl(fd, SBIOCSTIME, -1, sizeof(to), (char *)&to) == -1)
246	    {
247		perror("strioctl(SBIOCSTIME)");
248		exit(-1);
249	    }
250	/*
251	 * flush read queue
252	 */
253	if (ioctl(fd, I_FLUSH, FLUSHR) == -1)
254	    {
255		perror("I_FLUSHR");
256		exit(-1);
257	    }
258	timeout = tout;
259	solfd = fd;
260	return fd;
261}
262