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