xref: /netbsd-src/sys/external/bsd/ipf/netinet/ip_scan.c (revision 13885a665959c62f13a82b3caedf986eaa17aa31)
1*13885a66Sdarrenr /*	$NetBSD: ip_scan.c,v 1.3 2012/07/22 14:27:51 darrenr Exp $	*/
2c2aa585cSchristos 
3c2aa585cSchristos /*
4*13885a66Sdarrenr  * Copyright (C) 2012 by Darren Reed.
5c2aa585cSchristos  *
6c2aa585cSchristos  * See the IPFILTER.LICENCE file for details on licencing.
7c2aa585cSchristos  */
8c2aa585cSchristos #if defined(KERNEL) || defined(_KERNEL)
9c2aa585cSchristos # undef KERNEL
10c2aa585cSchristos # undef _KERNEL
11c2aa585cSchristos # define        KERNEL	1
12c2aa585cSchristos # define        _KERNEL	1
13c2aa585cSchristos #endif
14c2aa585cSchristos #include <sys/param.h>
15c2aa585cSchristos #if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL)
16c2aa585cSchristos # include <sys/kern_svcs.h>
17c2aa585cSchristos #endif
18c2aa585cSchristos #include <sys/types.h>
19c2aa585cSchristos #include <sys/time.h>
20c2aa585cSchristos #include <sys/errno.h>
21c2aa585cSchristos #if !defined(_KERNEL)
22c2aa585cSchristos # include <stdlib.h>
23c2aa585cSchristos # include <string.h>
24c2aa585cSchristos # define _KERNEL
25c2aa585cSchristos # ifdef __OpenBSD__
26c2aa585cSchristos struct file;
27c2aa585cSchristos # endif
28c2aa585cSchristos # include <sys/uio.h>
29c2aa585cSchristos # undef _KERNEL
30c2aa585cSchristos #else
31c2aa585cSchristos # include <sys/systm.h>
32c2aa585cSchristos # if !defined(__svr4__) && !defined(__SVR4)
33c2aa585cSchristos #  include <sys/mbuf.h>
34c2aa585cSchristos # endif
35c2aa585cSchristos #endif
36c2aa585cSchristos #include <sys/socket.h>
37c2aa585cSchristos #if !defined(__hpux) && !defined(__osf__) && !defined(linux) && !defined(AIX)
38c2aa585cSchristos # include <sys/ioccom.h>
39c2aa585cSchristos #endif
40c2aa585cSchristos #ifdef __FreeBSD__
41c2aa585cSchristos # include <sys/filio.h>
42c2aa585cSchristos # include <sys/malloc.h>
43c2aa585cSchristos #else
44c2aa585cSchristos # include <sys/ioctl.h>
45c2aa585cSchristos #endif
46c2aa585cSchristos 
47c2aa585cSchristos #include <netinet/in.h>
48c2aa585cSchristos #include <netinet/in_systm.h>
49c2aa585cSchristos #include <netinet/ip.h>
50c2aa585cSchristos #include <netinet/tcp.h>
51c2aa585cSchristos 
52c2aa585cSchristos #include <net/if.h>
53c2aa585cSchristos 
54c2aa585cSchristos 
55c2aa585cSchristos #include "netinet/ip_compat.h"
56c2aa585cSchristos #include "netinet/ip_fil.h"
57c2aa585cSchristos #include "netinet/ip_state.h"
58c2aa585cSchristos #include "netinet/ip_scan.h"
59c2aa585cSchristos /* END OF INCLUDES */
60c2aa585cSchristos 
61c2aa585cSchristos #if !defined(lint)
620c6adecaSchristos #if defined(__NetBSD__)
630c6adecaSchristos #include <sys/cdefs.h>
64*13885a66Sdarrenr __KERNEL_RCSID(0, "$NetBSD: ip_scan.c,v 1.3 2012/07/22 14:27:51 darrenr Exp $");
650c6adecaSchristos #else
66c2aa585cSchristos static const char sccsid[] = "@(#)ip_state.c	1.8 6/5/96 (C) 1993-2000 Darren Reed";
67*13885a66Sdarrenr static const char rcsid[] = "@(#)Id: ip_scan.c,v 1.1.1.2 2012/07/22 13:45:34 darrenr Exp";
680c6adecaSchristos #endif
69c2aa585cSchristos #endif
70c2aa585cSchristos 
71c2aa585cSchristos #ifdef	IPFILTER_SCAN	/* endif at bottom of file */
72c2aa585cSchristos 
73c2aa585cSchristos 
74c2aa585cSchristos ipscan_t	*ipf_scan_list = NULL,
75c2aa585cSchristos 		*ipf_scan_tail = NULL;
76c2aa585cSchristos ipscanstat_t	ipf_scan_stat;
77c2aa585cSchristos # ifdef USE_MUTEXES
78c2aa585cSchristos ipfrwlock_t	ipf_scan_rwlock;
79c2aa585cSchristos # endif
80c2aa585cSchristos 
81c2aa585cSchristos # ifndef isalpha
82c2aa585cSchristos #  define	isalpha(x)	(((x) >= 'A' && 'Z' >= (x)) || \
83c2aa585cSchristos 				 ((x) >= 'a' && 'z' >= (x)))
84c2aa585cSchristos # endif
85c2aa585cSchristos 
86c2aa585cSchristos 
870c6adecaSchristos int ipf_scan_add(void *);
880c6adecaSchristos int ipf_scan_remove(void *);
890c6adecaSchristos struct ipscan *ipf_scan_lookup(char *);
900c6adecaSchristos int ipf_scan_matchstr(sinfo_t *, char *, int);
910c6adecaSchristos int ipf_scan_matchisc(ipscan_t *, ipstate_t *, int, int, int *);
920c6adecaSchristos int ipf_scan_match(ipstate_t *);
93c2aa585cSchristos 
94c2aa585cSchristos static int	ipf_scan_inited = 0;
95c2aa585cSchristos 
96c2aa585cSchristos 
97c2aa585cSchristos int
ipf_scan_init()98c2aa585cSchristos ipf_scan_init()
99c2aa585cSchristos {
100c2aa585cSchristos 	RWLOCK_INIT(&ipf_scan_rwlock, "ip scan rwlock");
101c2aa585cSchristos 	ipf_scan_inited = 1;
102c2aa585cSchristos 	return 0;
103c2aa585cSchristos }
104c2aa585cSchristos 
105c2aa585cSchristos 
106c2aa585cSchristos void
ipf_scan_unload(void * arg)107c2aa585cSchristos ipf_scan_unload(void *arg)
108c2aa585cSchristos {
109c2aa585cSchristos 	if (ipf_scan_inited == 1) {
110c2aa585cSchristos 		RW_DESTROY(&ipf_scan_rwlock);
111c2aa585cSchristos 		ipf_scan_inited = 0;
112c2aa585cSchristos 	}
113c2aa585cSchristos }
114c2aa585cSchristos 
115c2aa585cSchristos 
116c2aa585cSchristos int
ipf_scan_add(data)117c2aa585cSchristos ipf_scan_add(data)
1180c6adecaSchristos 	void *data;
119c2aa585cSchristos {
120c2aa585cSchristos 	ipscan_t *i, *isc;
121c2aa585cSchristos 	int err;
122c2aa585cSchristos 
123c2aa585cSchristos 	KMALLOC(isc, ipscan_t *);
124c2aa585cSchristos 	if (!isc) {
125c2aa585cSchristos 		ipf_interror = 90001;
126c2aa585cSchristos 		return ENOMEM;
127c2aa585cSchristos 	}
128c2aa585cSchristos 
129c2aa585cSchristos 	err = copyinptr(data, isc, sizeof(*isc));
130c2aa585cSchristos 	if (err) {
131c2aa585cSchristos 		KFREE(isc);
132c2aa585cSchristos 		return err;
133c2aa585cSchristos 	}
134c2aa585cSchristos 
135c2aa585cSchristos 	WRITE_ENTER(&ipf_scan_rwlock);
136c2aa585cSchristos 
137c2aa585cSchristos 	i = ipf_scan_lookup(isc->ipsc_tag);
138c2aa585cSchristos 	if (i != NULL) {
139c2aa585cSchristos 		RWLOCK_EXIT(&ipf_scan_rwlock);
140c2aa585cSchristos 		KFREE(isc);
141c2aa585cSchristos 		ipf_interror = 90002;
142c2aa585cSchristos 		return EEXIST;
143c2aa585cSchristos 	}
144c2aa585cSchristos 
145c2aa585cSchristos 	if (ipf_scan_tail) {
146c2aa585cSchristos 		ipf_scan_tail->ipsc_next = isc;
147c2aa585cSchristos 		isc->ipsc_pnext = &ipf_scan_tail->ipsc_next;
148c2aa585cSchristos 		ipf_scan_tail = isc;
149c2aa585cSchristos 	} else {
150c2aa585cSchristos 		ipf_scan_list = isc;
151c2aa585cSchristos 		ipf_scan_tail = isc;
152c2aa585cSchristos 		isc->ipsc_pnext = &ipf_scan_list;
153c2aa585cSchristos 	}
154c2aa585cSchristos 	isc->ipsc_next = NULL;
155c2aa585cSchristos 
156c2aa585cSchristos 	isc->ipsc_hits = 0;
157c2aa585cSchristos 	isc->ipsc_fref = 0;
158c2aa585cSchristos 	isc->ipsc_sref = 0;
159c2aa585cSchristos 	isc->ipsc_active = 0;
160c2aa585cSchristos 
161c2aa585cSchristos 	ipf_scan_stat.iscs_entries++;
162c2aa585cSchristos 	RWLOCK_EXIT(&ipf_scan_rwlock);
163c2aa585cSchristos 	return 0;
164c2aa585cSchristos }
165c2aa585cSchristos 
166c2aa585cSchristos 
167c2aa585cSchristos int
ipf_scan_remove(data)168c2aa585cSchristos ipf_scan_remove(data)
1690c6adecaSchristos 	void *data;
170c2aa585cSchristos {
171c2aa585cSchristos 	ipscan_t isc, *i;
172c2aa585cSchristos 	int err;
173c2aa585cSchristos 
174c2aa585cSchristos 	err = copyinptr(data, &isc, sizeof(isc));
175c2aa585cSchristos 	if (err)
176c2aa585cSchristos 		return err;
177c2aa585cSchristos 
178c2aa585cSchristos 	WRITE_ENTER(&ipf_scan_rwlock);
179c2aa585cSchristos 
180c2aa585cSchristos 	i = ipf_scan_lookup(isc.ipsc_tag);
181c2aa585cSchristos 	if (i == NULL)
182c2aa585cSchristos 		err = ENOENT;
183c2aa585cSchristos 	else {
184c2aa585cSchristos 		if (i->ipsc_fref) {
185c2aa585cSchristos 			RWLOCK_EXIT(&ipf_scan_rwlock);
186c2aa585cSchristos 			ipf_interror = 90003;
187c2aa585cSchristos 			return EBUSY;
188c2aa585cSchristos 		}
189c2aa585cSchristos 
190c2aa585cSchristos 		*i->ipsc_pnext = i->ipsc_next;
191c2aa585cSchristos 		if (i->ipsc_next)
192c2aa585cSchristos 			i->ipsc_next->ipsc_pnext = i->ipsc_pnext;
193c2aa585cSchristos 		else {
194c2aa585cSchristos 			if (i->ipsc_pnext == &ipf_scan_list)
195c2aa585cSchristos 				ipf_scan_tail = NULL;
196c2aa585cSchristos 			else
197c2aa585cSchristos 				ipf_scan_tail = *(*i->ipsc_pnext)->ipsc_pnext;
198c2aa585cSchristos 		}
199c2aa585cSchristos 
200c2aa585cSchristos 		ipf_scan_stat.iscs_entries--;
201c2aa585cSchristos 		KFREE(i);
202c2aa585cSchristos 	}
203c2aa585cSchristos 	RWLOCK_EXIT(&ipf_scan_rwlock);
204c2aa585cSchristos 	return err;
205c2aa585cSchristos }
206c2aa585cSchristos 
207c2aa585cSchristos 
208c2aa585cSchristos struct ipscan *
ipf_scan_lookup(tag)209c2aa585cSchristos ipf_scan_lookup(tag)
210c2aa585cSchristos 	char *tag;
211c2aa585cSchristos {
212c2aa585cSchristos 	ipscan_t *i;
213c2aa585cSchristos 
214c2aa585cSchristos 	for (i = ipf_scan_list; i; i = i->ipsc_next)
215c2aa585cSchristos 		if (!strcmp(i->ipsc_tag, tag))
216c2aa585cSchristos 			return i;
217c2aa585cSchristos 	return NULL;
218c2aa585cSchristos }
219c2aa585cSchristos 
220c2aa585cSchristos 
221c2aa585cSchristos int
ipf_scan_attachfr(fr)222c2aa585cSchristos ipf_scan_attachfr(fr)
223c2aa585cSchristos 	struct frentry *fr;
224c2aa585cSchristos {
225c2aa585cSchristos 	ipscan_t *i;
226c2aa585cSchristos 
227c2aa585cSchristos 	if (fr->fr_isctag != -1) {
228c2aa585cSchristos 		READ_ENTER(&ipf_scan_rwlock);
229c2aa585cSchristos 		i = ipf_scan_lookup(fr->fr_isctag + fr->fr_names);
230c2aa585cSchristos 		if (i != NULL) {
231c2aa585cSchristos 			ATOMIC_INC32(i->ipsc_fref);
232c2aa585cSchristos 		}
233c2aa585cSchristos 		RWLOCK_EXIT(&ipf_scan_rwlock);
234c2aa585cSchristos 		if (i == NULL) {
235c2aa585cSchristos 			ipf_interror = 90004;
236c2aa585cSchristos 			return ENOENT;
237c2aa585cSchristos 		}
238c2aa585cSchristos 		fr->fr_isc = i;
239c2aa585cSchristos 	}
240c2aa585cSchristos 	return 0;
241c2aa585cSchristos }
242c2aa585cSchristos 
243c2aa585cSchristos 
244c2aa585cSchristos int
ipf_scan_attachis(is)245c2aa585cSchristos ipf_scan_attachis(is)
246c2aa585cSchristos 	struct ipstate *is;
247c2aa585cSchristos {
248c2aa585cSchristos 	frentry_t *fr;
249c2aa585cSchristos 	ipscan_t *i;
250c2aa585cSchristos 
251c2aa585cSchristos 	READ_ENTER(&ipf_scan_rwlock);
252c2aa585cSchristos 	fr = is->is_rule;
253c2aa585cSchristos 	if (fr != NULL) {
254c2aa585cSchristos 		i = fr->fr_isc;
255c2aa585cSchristos 		if ((i != NULL) && (i != (ipscan_t *)-1)) {
256c2aa585cSchristos 			is->is_isc = i;
257c2aa585cSchristos 			ATOMIC_INC32(i->ipsc_sref);
258c2aa585cSchristos 			if (i->ipsc_clen)
259c2aa585cSchristos 				is->is_flags |= IS_SC_CLIENT;
260c2aa585cSchristos 			else
261c2aa585cSchristos 				is->is_flags |= IS_SC_MATCHC;
262c2aa585cSchristos 			if (i->ipsc_slen)
263c2aa585cSchristos 				is->is_flags |= IS_SC_SERVER;
264c2aa585cSchristos 			else
265c2aa585cSchristos 				is->is_flags |= IS_SC_MATCHS;
266c2aa585cSchristos 		}
267c2aa585cSchristos 	}
268c2aa585cSchristos 	RWLOCK_EXIT(&ipf_scan_rwlock);
269c2aa585cSchristos 	return 0;
270c2aa585cSchristos }
271c2aa585cSchristos 
272c2aa585cSchristos 
273c2aa585cSchristos int
ipf_scan_detachfr(fr)274c2aa585cSchristos ipf_scan_detachfr(fr)
275c2aa585cSchristos 	struct frentry *fr;
276c2aa585cSchristos {
277c2aa585cSchristos 	ipscan_t *i;
278c2aa585cSchristos 
279c2aa585cSchristos 	i = fr->fr_isc;
280c2aa585cSchristos 	if (i != NULL) {
281c2aa585cSchristos 		ATOMIC_DEC32(i->ipsc_fref);
282c2aa585cSchristos 	}
283c2aa585cSchristos 	return 0;
284c2aa585cSchristos }
285c2aa585cSchristos 
286c2aa585cSchristos 
287c2aa585cSchristos int
ipf_scan_detachis(is)288c2aa585cSchristos ipf_scan_detachis(is)
289c2aa585cSchristos 	struct ipstate *is;
290c2aa585cSchristos {
291c2aa585cSchristos 	ipscan_t *i;
292c2aa585cSchristos 
293c2aa585cSchristos 	READ_ENTER(&ipf_scan_rwlock);
294c2aa585cSchristos 	if ((i = is->is_isc) && (i != (ipscan_t *)-1)) {
295c2aa585cSchristos 		ATOMIC_DEC32(i->ipsc_sref);
296c2aa585cSchristos 		is->is_isc = NULL;
297c2aa585cSchristos 		is->is_flags &= ~(IS_SC_CLIENT|IS_SC_SERVER);
298c2aa585cSchristos 	}
299c2aa585cSchristos 	RWLOCK_EXIT(&ipf_scan_rwlock);
300c2aa585cSchristos 	return 0;
301c2aa585cSchristos }
302c2aa585cSchristos 
303c2aa585cSchristos 
304c2aa585cSchristos /*
305c2aa585cSchristos  * 'string' compare for scanning
306c2aa585cSchristos  */
307c2aa585cSchristos int
ipf_scan_matchstr(sp,str,n)308c2aa585cSchristos ipf_scan_matchstr(sp, str, n)
309c2aa585cSchristos 	sinfo_t *sp;
310c2aa585cSchristos 	char *str;
311c2aa585cSchristos 	int n;
312c2aa585cSchristos {
313c2aa585cSchristos 	char *s, *t, *up;
314c2aa585cSchristos 	int i = n;
315c2aa585cSchristos 
316c2aa585cSchristos 	if (i > sp->s_len)
317c2aa585cSchristos 		i = sp->s_len;
318c2aa585cSchristos 	up = str;
319c2aa585cSchristos 
320c2aa585cSchristos 	for (s = sp->s_txt, t = sp->s_msk; i; i--, s++, t++, up++)
321c2aa585cSchristos 		switch ((int)*t)
322c2aa585cSchristos 		{
323c2aa585cSchristos 		case '.' :
324c2aa585cSchristos 			if (*s != *up)
325c2aa585cSchristos 				return 1;
326c2aa585cSchristos 			break;
327c2aa585cSchristos 		case '?' :
328c2aa585cSchristos 			if (!ISALPHA(*up) || ((*s & 0x5f) != (*up & 0x5f)))
329c2aa585cSchristos 				return 1;
330c2aa585cSchristos 			break;
331c2aa585cSchristos 		case '*' :
332c2aa585cSchristos 			break;
333c2aa585cSchristos 		}
334c2aa585cSchristos 	return 0;
335c2aa585cSchristos }
336c2aa585cSchristos 
337c2aa585cSchristos 
338c2aa585cSchristos /*
339c2aa585cSchristos  * Returns 3 if both server and client match, 2 if just server,
340c2aa585cSchristos  * 1 if just client
341c2aa585cSchristos  */
342c2aa585cSchristos int
ipf_scan_matchisc(isc,is,cl,sl,maxm)343c2aa585cSchristos ipf_scan_matchisc(isc, is, cl, sl, maxm)
344c2aa585cSchristos 	ipscan_t *isc;
345c2aa585cSchristos 	ipstate_t *is;
346c2aa585cSchristos 	int cl, sl, maxm[2];
347c2aa585cSchristos {
348c2aa585cSchristos 	int i, j, k, n, ret = 0, flags;
349c2aa585cSchristos 
350c2aa585cSchristos 	flags = is->is_flags;
351c2aa585cSchristos 
352c2aa585cSchristos 	/*
353c2aa585cSchristos 	 * If we've already matched more than what is on offer, then
354c2aa585cSchristos 	 * assume we have a better match already and forget this one.
355c2aa585cSchristos 	 */
356c2aa585cSchristos 	if (maxm != NULL) {
357c2aa585cSchristos 		if (isc->ipsc_clen < maxm[0])
358c2aa585cSchristos 			return 0;
359c2aa585cSchristos 		if (isc->ipsc_slen < maxm[1])
360c2aa585cSchristos 			return 0;
361c2aa585cSchristos 		j = maxm[0];
362c2aa585cSchristos 		k = maxm[1];
363c2aa585cSchristos 	} else {
364c2aa585cSchristos 		j = 0;
365c2aa585cSchristos 		k = 0;
366c2aa585cSchristos 	}
367c2aa585cSchristos 
368c2aa585cSchristos 	if (!isc->ipsc_clen)
369c2aa585cSchristos 		ret = 1;
370c2aa585cSchristos 	else if (((flags & (IS_SC_MATCHC|IS_SC_CLIENT)) == IS_SC_CLIENT) &&
371c2aa585cSchristos 		 cl && isc->ipsc_clen) {
372c2aa585cSchristos 		i = 0;
373c2aa585cSchristos 		n = MIN(cl, isc->ipsc_clen);
374c2aa585cSchristos 		if ((n > 0) && (!maxm || (n >= maxm[1]))) {
375c2aa585cSchristos 			if (!ipf_scan_matchstr(&isc->ipsc_cl,
376c2aa585cSchristos 					       is->is_sbuf[0], n)) {
377c2aa585cSchristos 				i++;
378c2aa585cSchristos 				ret |= 1;
379c2aa585cSchristos 				if (n > j)
380c2aa585cSchristos 					j = n;
381c2aa585cSchristos 			}
382c2aa585cSchristos 		}
383c2aa585cSchristos 	}
384c2aa585cSchristos 
385c2aa585cSchristos 	if (!isc->ipsc_slen)
386c2aa585cSchristos 		ret |= 2;
387c2aa585cSchristos 	else if (((flags & (IS_SC_MATCHS|IS_SC_SERVER)) == IS_SC_SERVER) &&
388c2aa585cSchristos 		 sl && isc->ipsc_slen) {
389c2aa585cSchristos 		i = 0;
390c2aa585cSchristos 		n = MIN(cl, isc->ipsc_slen);
391c2aa585cSchristos 		if ((n > 0) && (!maxm || (n >= maxm[1]))) {
392c2aa585cSchristos 			if (!ipf_scan_matchstr(&isc->ipsc_sl,
393c2aa585cSchristos 					       is->is_sbuf[1], n)) {
394c2aa585cSchristos 				i++;
395c2aa585cSchristos 				ret |= 2;
396c2aa585cSchristos 				if (n > k)
397c2aa585cSchristos 					k = n;
398c2aa585cSchristos 			}
399c2aa585cSchristos 		}
400c2aa585cSchristos 	}
401c2aa585cSchristos 
402c2aa585cSchristos 	if (maxm && (ret == 3)) {
403c2aa585cSchristos 		maxm[0] = j;
404c2aa585cSchristos 		maxm[1] = k;
405c2aa585cSchristos 	}
406c2aa585cSchristos 	return ret;
407c2aa585cSchristos }
408c2aa585cSchristos 
409c2aa585cSchristos 
410c2aa585cSchristos int
ipf_scan_match(is)411c2aa585cSchristos ipf_scan_match(is)
412c2aa585cSchristos 	ipstate_t *is;
413c2aa585cSchristos {
414c2aa585cSchristos 	int i, j, k, n, cl, sl, maxm[2];
415c2aa585cSchristos 	ipscan_t *isc, *lm;
416c2aa585cSchristos 	tcpdata_t *t;
417c2aa585cSchristos 
418c2aa585cSchristos 	for (cl = 0, n = is->is_smsk[0]; n & 1; n >>= 1)
419c2aa585cSchristos 		cl++;
420c2aa585cSchristos 	for (sl = 0, n = is->is_smsk[1]; n & 1; n >>= 1)
421c2aa585cSchristos 		sl++;
422c2aa585cSchristos 
423c2aa585cSchristos 	j = 0;
424c2aa585cSchristos 	isc = is->is_isc;
425c2aa585cSchristos 	if (isc != NULL) {
426c2aa585cSchristos 		/*
427c2aa585cSchristos 		 * Known object to scan for.
428c2aa585cSchristos 		 */
429c2aa585cSchristos 		i = ipf_scan_matchisc(isc, is, cl, sl, NULL);
430c2aa585cSchristos 		if (i & 1) {
431c2aa585cSchristos 			is->is_flags |= IS_SC_MATCHC;
432c2aa585cSchristos 			is->is_flags &= ~IS_SC_CLIENT;
433c2aa585cSchristos 		} else if (cl >= isc->ipsc_clen)
434c2aa585cSchristos 			is->is_flags &= ~IS_SC_CLIENT;
435c2aa585cSchristos 		if (i & 2) {
436c2aa585cSchristos 			is->is_flags |= IS_SC_MATCHS;
437c2aa585cSchristos 			is->is_flags &= ~IS_SC_SERVER;
438c2aa585cSchristos 		} else if (sl >= isc->ipsc_slen)
439c2aa585cSchristos 			is->is_flags &= ~IS_SC_SERVER;
440c2aa585cSchristos 	} else {
441c2aa585cSchristos 		i = 0;
442c2aa585cSchristos 		lm = NULL;
443c2aa585cSchristos 		maxm[0] = 0;
444c2aa585cSchristos 		maxm[1] = 0;
445c2aa585cSchristos 		for (k = 0, isc = ipf_scan_list; isc; isc = isc->ipsc_next) {
446c2aa585cSchristos 			i = ipf_scan_matchisc(isc, is, cl, sl, maxm);
447c2aa585cSchristos 			if (i) {
448c2aa585cSchristos 				/*
449c2aa585cSchristos 				 * We only want to remember the best match
450c2aa585cSchristos 				 * and the number of times we get a best
451c2aa585cSchristos 				 * match.
452c2aa585cSchristos 				 */
453c2aa585cSchristos 				if ((j == 3) && (i < 3))
454c2aa585cSchristos 					continue;
455c2aa585cSchristos 				if ((i == 3) && (j != 3))
456c2aa585cSchristos 					k = 1;
457c2aa585cSchristos 				else
458c2aa585cSchristos 					k++;
459c2aa585cSchristos 				j = i;
460c2aa585cSchristos 				lm = isc;
461c2aa585cSchristos 			}
462c2aa585cSchristos 		}
463c2aa585cSchristos 		if (k == 1)
464c2aa585cSchristos 			isc = lm;
465c2aa585cSchristos 		if (isc == NULL)
466c2aa585cSchristos 			return 0;
467c2aa585cSchristos 
468c2aa585cSchristos 		/*
469c2aa585cSchristos 		 * No matches or partial matches, so reset the respective
470c2aa585cSchristos 		 * search flag.
471c2aa585cSchristos 		 */
472c2aa585cSchristos 		if (!(j & 1))
473c2aa585cSchristos 			is->is_flags &= ~IS_SC_CLIENT;
474c2aa585cSchristos 
475c2aa585cSchristos 		if (!(j & 2))
476c2aa585cSchristos 			is->is_flags &= ~IS_SC_SERVER;
477c2aa585cSchristos 
478c2aa585cSchristos 		/*
479c2aa585cSchristos 		 * If we found the best match, then set flags appropriately.
480c2aa585cSchristos 		 */
481c2aa585cSchristos 		if ((j == 3) && (k == 1)) {
482c2aa585cSchristos 			is->is_flags &= ~(IS_SC_SERVER|IS_SC_CLIENT);
483c2aa585cSchristos 			is->is_flags |= (IS_SC_MATCHS|IS_SC_MATCHC);
484c2aa585cSchristos 		}
485c2aa585cSchristos 	}
486c2aa585cSchristos 
487c2aa585cSchristos 	/*
488c2aa585cSchristos 	 * If the acknowledged side of a connection has moved past the data in
489c2aa585cSchristos 	 * which we are interested, then reset respective flag.
490c2aa585cSchristos 	 */
491c2aa585cSchristos 	t = &is->is_tcp.ts_data[0];
492c2aa585cSchristos 	if (t->td_end > is->is_s0[0] + 15)
493c2aa585cSchristos 		is->is_flags &= ~IS_SC_CLIENT;
494c2aa585cSchristos 
495c2aa585cSchristos 	t = &is->is_tcp.ts_data[1];
496c2aa585cSchristos 	if (t->td_end > is->is_s0[1] + 15)
497c2aa585cSchristos 		is->is_flags &= ~IS_SC_SERVER;
498c2aa585cSchristos 
499c2aa585cSchristos 	/*
500c2aa585cSchristos 	 * Matching complete ?
501c2aa585cSchristos 	 */
502c2aa585cSchristos 	j = ISC_A_NONE;
503c2aa585cSchristos 	if ((is->is_flags & IS_SC_MATCHALL) == IS_SC_MATCHALL) {
504c2aa585cSchristos 		j = isc->ipsc_action;
505c2aa585cSchristos 		ipf_scan_stat.iscs_acted++;
506c2aa585cSchristos 	} else if ((is->is_isc != NULL) &&
507c2aa585cSchristos 		   ((is->is_flags & IS_SC_MATCHALL) != IS_SC_MATCHALL) &&
508c2aa585cSchristos 		   !(is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER))) {
509c2aa585cSchristos 		/*
510c2aa585cSchristos 		 * Matching failed...
511c2aa585cSchristos 		 */
512c2aa585cSchristos 		j = isc->ipsc_else;
513c2aa585cSchristos 		ipf_scan_stat.iscs_else++;
514c2aa585cSchristos 	}
515c2aa585cSchristos 
516c2aa585cSchristos 	switch (j)
517c2aa585cSchristos 	{
518c2aa585cSchristos 	case  ISC_A_CLOSE :
519c2aa585cSchristos 		/*
520c2aa585cSchristos 		 * If as a result of a successful match we are to
521c2aa585cSchristos 		 * close a connection, change the "keep state" info.
522c2aa585cSchristos 		 * to block packets and generate TCP RST's.
523c2aa585cSchristos 		 */
524c2aa585cSchristos 		is->is_pass &= ~FR_RETICMP;
525c2aa585cSchristos 		is->is_pass |= FR_RETRST;
526c2aa585cSchristos 		break;
527c2aa585cSchristos 	default :
528c2aa585cSchristos 		break;
529c2aa585cSchristos 	}
530c2aa585cSchristos 
531c2aa585cSchristos 	return i;
532c2aa585cSchristos }
533c2aa585cSchristos 
534c2aa585cSchristos 
535c2aa585cSchristos /*
536c2aa585cSchristos  * check if a packet matches what we're scanning for
537c2aa585cSchristos  */
538c2aa585cSchristos int
ipf_scan_packet(fin,is)539c2aa585cSchristos ipf_scan_packet(fin, is)
540c2aa585cSchristos 	fr_info_t *fin;
541c2aa585cSchristos 	ipstate_t *is;
542c2aa585cSchristos {
543c2aa585cSchristos 	int i, j, rv, dlen, off, thoff;
544c2aa585cSchristos 	u_32_t seq, s0;
545c2aa585cSchristos 	tcphdr_t *tcp;
546c2aa585cSchristos 
547c2aa585cSchristos 	rv = !IP6_EQ(&fin->fin_fi.fi_src, &is->is_src);
548c2aa585cSchristos 	tcp = fin->fin_dp;
549c2aa585cSchristos 	seq = ntohl(tcp->th_seq);
550c2aa585cSchristos 
551c2aa585cSchristos 	if (!is->is_s0[rv])
552c2aa585cSchristos 		return 1;
553c2aa585cSchristos 
554c2aa585cSchristos 	/*
555c2aa585cSchristos 	 * check if this packet has more data that falls within the first
556c2aa585cSchristos 	 * 16 bytes sent in either direction.
557c2aa585cSchristos 	 */
558c2aa585cSchristos 	s0 = is->is_s0[rv];
559c2aa585cSchristos 	off = seq - s0;
560c2aa585cSchristos 	if ((off > 15) || (off < 0))
561c2aa585cSchristos 		return 1;
562c2aa585cSchristos 	thoff = TCP_OFF(tcp) << 2;
563c2aa585cSchristos 	dlen = fin->fin_dlen - thoff;
564c2aa585cSchristos 	if (dlen <= 0)
565c2aa585cSchristos 		return 1;
566c2aa585cSchristos 	if (dlen > 16)
567c2aa585cSchristos 		dlen = 16;
568c2aa585cSchristos 	if (off + dlen > 16)
569c2aa585cSchristos 		dlen = 16 - off;
570c2aa585cSchristos 
571c2aa585cSchristos 	j = 0xffff >> (16 - dlen);
572c2aa585cSchristos 	i = (0xffff & j) << off;
573c2aa585cSchristos #ifdef _KERNEL
574c2aa585cSchristos 	COPYDATA(*(mb_t **)fin->fin_mp, fin->fin_plen - fin->fin_dlen + thoff,
5750c6adecaSchristos 		 dlen, (void *)is->is_sbuf[rv] + off);
576c2aa585cSchristos #endif
577c2aa585cSchristos 	is->is_smsk[rv] |= i;
578c2aa585cSchristos 	for (j = 0, i = is->is_smsk[rv]; i & 1; i >>= 1)
579c2aa585cSchristos 		j++;
580c2aa585cSchristos 	if (j == 0)
581c2aa585cSchristos 		return 1;
582c2aa585cSchristos 
583c2aa585cSchristos 	(void) ipf_scan_match(is);
584c2aa585cSchristos #if 0
585c2aa585cSchristos 	/*
586c2aa585cSchristos 	 * There is the potential here for plain text passwords to get
587c2aa585cSchristos 	 * buffered and stored for some time...
588c2aa585cSchristos 	 */
589c2aa585cSchristos 	if (!(is->is_flags & IS_SC_CLIENT))
590c2aa585cSchristos 		bzero(is->is_sbuf[0], sizeof(is->is_sbuf[0]));
591c2aa585cSchristos 	if (!(is->is_flags & IS_SC_SERVER))
592c2aa585cSchristos 		bzero(is->is_sbuf[1], sizeof(is->is_sbuf[1]));
593c2aa585cSchristos #endif
594c2aa585cSchristos 	return 0;
595c2aa585cSchristos }
596c2aa585cSchristos 
597c2aa585cSchristos 
598c2aa585cSchristos int
ipf_scan_ioctl(data,cmd,mode,uid,ctx)599c2aa585cSchristos ipf_scan_ioctl(data, cmd, mode, uid, ctx)
6000c6adecaSchristos 	void *data;
601c2aa585cSchristos 	ioctlcmd_t cmd;
602c2aa585cSchristos 	int mode, uid;
603c2aa585cSchristos 	void *ctx;
604c2aa585cSchristos {
605c2aa585cSchristos 	ipscanstat_t ipscs;
606c2aa585cSchristos 	int err = 0;
607c2aa585cSchristos 
608c2aa585cSchristos 	switch (cmd)
609c2aa585cSchristos 	{
610c2aa585cSchristos 	case SIOCADSCA :
611c2aa585cSchristos 		err = ipf_scan_add(data);
612c2aa585cSchristos 		break;
613c2aa585cSchristos 	case SIOCRMSCA :
614c2aa585cSchristos 		err = ipf_scan_remove(data);
615c2aa585cSchristos 		break;
616c2aa585cSchristos 	case SIOCGSCST :
617c2aa585cSchristos 		bcopy((char *)&ipf_scan_stat, (char *)&ipscs, sizeof(ipscs));
618c2aa585cSchristos 		ipscs.iscs_list = ipf_scan_list;
619c2aa585cSchristos 		err = BCOPYOUT(&ipscs, data, sizeof(ipscs));
620c2aa585cSchristos 		if (err != 0) {
621c2aa585cSchristos 			ipf_interror = 90005;
622c2aa585cSchristos 			err = EFAULT;
623c2aa585cSchristos 		}
624c2aa585cSchristos 		break;
625c2aa585cSchristos 	default :
626c2aa585cSchristos 		err = EINVAL;
627c2aa585cSchristos 		break;
628c2aa585cSchristos 	}
629c2aa585cSchristos 
630c2aa585cSchristos 	return err;
631c2aa585cSchristos }
632c2aa585cSchristos #endif	/* IPFILTER_SCAN */
633