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