2 * Copyright (C) 1995-2001 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
6 #if defined(KERNEL) || defined(_KERNEL)
12 #include <sys/param.h>
13 #if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL)
14 # include <sys/kern_svcs.h>
16 #include <sys/types.h>
18 #include <sys/errno.h>
29 # include <sys/systm.h>
30 # if !defined(__svr4__) && !defined(__SVR4)
31 # include <sys/mbuf.h>
34 #include <sys/socket.h>
35 #if !defined(__hpux) && !defined(__osf__) && !defined(linux) && !defined(AIX)
36 # include <sys/ioccom.h>
39 # include <sys/filio.h>
40 # include <sys/malloc.h>
42 # include <sys/ioctl.h>
45 #include <netinet/in.h>
46 #include <netinet/in_systm.h>
47 #include <netinet/ip.h>
48 #include <netinet/tcp.h>
53 #include "netinet/ip_compat.h"
54 #include "netinet/ip_fil.h"
55 #include "netinet/ip_state.h"
56 #include "netinet/ip_scan.h"
60 static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed";
61 static const char rcsid[] = "@(#)$Id: ip_scan.c,v 2.40.2.6 2006/03/26 23:06:49 darrenr Exp $";
64 #ifdef IPFILTER_SCAN /* endif at bottom of file */
67 ipscan_t *ipsc_list = NULL,
69 ipscanstat_t ipsc_stat;
71 ipfrwlock_t ipsc_rwlock;
75 # define isalpha(x) (((x) >= 'A' && 'Z' >= (x)) || \
76 ((x) >= 'a' && 'z' >= (x)))
80 int ipsc_add __P((caddr_t));
81 int ipsc_delete __P((caddr_t));
82 struct ipscan *ipsc_lookup __P((char *));
83 int ipsc_matchstr __P((sinfo_t *, char *, int));
84 int ipsc_matchisc __P((ipscan_t *, ipstate_t *, int, int, int *));
85 int ipsc_match __P((ipstate_t *));
87 static int ipsc_inited = 0;
92 RWLOCK_INIT(&ipsc_rwlock, "ip scan rwlock");
100 if (ipsc_inited == 1) {
101 RW_DESTROY(&ipsc_rwlock);
113 KMALLOC(isc, ipscan_t *);
117 err = copyinptr(data, isc, sizeof(*isc));
121 WRITE_ENTER(&ipsc_rwlock);
123 i = ipsc_lookup(isc->ipsc_tag);
125 RWLOCK_EXIT(&ipsc_rwlock);
131 ipsc_tail->ipsc_next = isc;
132 isc->ipsc_pnext = &ipsc_tail->ipsc_next;
137 isc->ipsc_pnext = &ipsc_list;
139 isc->ipsc_next = NULL;
144 isc->ipsc_active = 0;
146 ipsc_stat.iscs_entries++;
147 RWLOCK_EXIT(&ipsc_rwlock);
152 int ipsc_delete(data)
158 err = copyinptr(data, &isc, sizeof(isc));
162 WRITE_ENTER(&ipsc_rwlock);
164 i = ipsc_lookup(isc.ipsc_tag);
169 RWLOCK_EXIT(&ipsc_rwlock);
173 *i->ipsc_pnext = i->ipsc_next;
175 i->ipsc_next->ipsc_pnext = i->ipsc_pnext;
177 if (i->ipsc_pnext == &ipsc_list)
180 ipsc_tail = *(*i->ipsc_pnext)->ipsc_pnext;
183 ipsc_stat.iscs_entries--;
186 RWLOCK_EXIT(&ipsc_rwlock);
191 struct ipscan *ipsc_lookup(tag)
196 for (i = ipsc_list; i; i = i->ipsc_next)
197 if (!strcmp(i->ipsc_tag, tag))
203 int ipsc_attachfr(fr)
208 if (fr->fr_isctag[0]) {
209 READ_ENTER(&ipsc_rwlock);
210 i = ipsc_lookup(fr->fr_isctag);
212 ATOMIC_INC32(i->ipsc_fref);
214 RWLOCK_EXIT(&ipsc_rwlock);
223 int ipsc_attachis(is)
229 READ_ENTER(&ipsc_rwlock);
233 if (!i || (i != (ipscan_t *)-1)) {
236 ATOMIC_INC32(i->ipsc_sref);
238 is->is_flags |= IS_SC_CLIENT;
240 is->is_flags |= IS_SC_MATCHC;
242 is->is_flags |= IS_SC_SERVER;
244 is->is_flags |= IS_SC_MATCHS;
246 is->is_flags |= (IS_SC_CLIENT|IS_SC_SERVER);
249 RWLOCK_EXIT(&ipsc_rwlock);
254 int ipsc_detachfr(fr)
261 ATOMIC_DEC32(i->ipsc_fref);
267 int ipsc_detachis(is)
272 READ_ENTER(&ipsc_rwlock);
273 if ((i = is->is_isc) && (i != (ipscan_t *)-1)) {
274 ATOMIC_DEC32(i->ipsc_sref);
276 is->is_flags &= ~(IS_SC_CLIENT|IS_SC_SERVER);
278 RWLOCK_EXIT(&ipsc_rwlock);
284 * 'string' compare for scanning
286 int ipsc_matchstr(sp, str, n)
298 for (s = sp->s_txt, t = sp->s_msk; i; i--, s++, t++, up++)
306 if (!ISALPHA(*up) || ((*s & 0x5f) != (*up & 0x5f)))
317 * Returns 3 if both server and client match, 2 if just server,
320 int ipsc_matchisc(isc, is, cl, sl, maxm)
325 int i, j, k, n, ret = 0, flags;
327 flags = is->is_flags;
330 * If we've already matched more than what is on offer, then
331 * assume we have a better match already and forget this one.
334 if (isc->ipsc_clen < maxm[0])
336 if (isc->ipsc_slen < maxm[1])
347 else if (((flags & (IS_SC_MATCHC|IS_SC_CLIENT)) == IS_SC_CLIENT) &&
348 cl && isc->ipsc_clen) {
350 n = MIN(cl, isc->ipsc_clen);
351 if ((n > 0) && (!maxm || (n >= maxm[1]))) {
352 if (!ipsc_matchstr(&isc->ipsc_cl, is->is_sbuf[0], n)) {
363 else if (((flags & (IS_SC_MATCHS|IS_SC_SERVER)) == IS_SC_SERVER) &&
364 sl && isc->ipsc_slen) {
366 n = MIN(cl, isc->ipsc_slen);
367 if ((n > 0) && (!maxm || (n >= maxm[1]))) {
368 if (!ipsc_matchstr(&isc->ipsc_sl, is->is_sbuf[1], n)) {
377 if (maxm && (ret == 3)) {
388 int i, j, k, n, cl, sl, maxm[2];
392 for (cl = 0, n = is->is_smsk[0]; n & 1; n >>= 1)
394 for (sl = 0, n = is->is_smsk[1]; n & 1; n >>= 1)
401 * Known object to scan for.
403 i = ipsc_matchisc(isc, is, cl, sl, NULL);
405 is->is_flags |= IS_SC_MATCHC;
406 is->is_flags &= ~IS_SC_CLIENT;
407 } else if (cl >= isc->ipsc_clen)
408 is->is_flags &= ~IS_SC_CLIENT;
410 is->is_flags |= IS_SC_MATCHS;
411 is->is_flags &= ~IS_SC_SERVER;
412 } else if (sl >= isc->ipsc_slen)
413 is->is_flags &= ~IS_SC_SERVER;
419 for (k = 0, isc = ipsc_list; isc; isc = isc->ipsc_next) {
420 i = ipsc_matchisc(isc, is, cl, sl, maxm);
423 * We only want to remember the best match
424 * and the number of times we get a best
427 if ((j == 3) && (i < 3))
429 if ((i == 3) && (j != 3))
443 * No matches or partial matches, so reset the respective
447 is->is_flags &= ~IS_SC_CLIENT;
450 is->is_flags &= ~IS_SC_SERVER;
453 * If we found the best match, then set flags appropriately.
455 if ((j == 3) && (k == 1)) {
456 is->is_flags &= ~(IS_SC_SERVER|IS_SC_CLIENT);
457 is->is_flags |= (IS_SC_MATCHS|IS_SC_MATCHC);
462 * If the acknowledged side of a connection has moved past the data in
463 * which we are interested, then reset respective flag.
465 t = &is->is_tcp.ts_data[0];
466 if (t->td_end > is->is_s0[0] + 15)
467 is->is_flags &= ~IS_SC_CLIENT;
469 t = &is->is_tcp.ts_data[1];
470 if (t->td_end > is->is_s0[1] + 15)
471 is->is_flags &= ~IS_SC_SERVER;
474 * Matching complete ?
477 if ((is->is_flags & IS_SC_MATCHALL) == IS_SC_MATCHALL) {
478 j = isc->ipsc_action;
479 ipsc_stat.iscs_acted++;
480 } else if ((is->is_isc != NULL) &&
481 ((is->is_flags & IS_SC_MATCHALL) != IS_SC_MATCHALL) &&
482 !(is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER))) {
487 ipsc_stat.iscs_else++;
494 * If as a result of a successful match we are to
495 * close a connection, change the "keep state" info.
496 * to block packets and generate TCP RST's.
498 is->is_pass &= ~FR_RETICMP;
499 is->is_pass |= FR_RETRST;
510 * check if a packet matches what we're scanning for
512 int ipsc_packet(fin, is)
516 int i, j, rv, dlen, off, thoff;
520 rv = !IP6_EQ(&fin->fin_fi.fi_src, &is->is_src);
522 seq = ntohl(tcp->th_seq);
528 * check if this packet has more data that falls within the first
529 * 16 bytes sent in either direction.
533 if ((off > 15) || (off < 0))
535 thoff = TCP_OFF(tcp) << 2;
536 dlen = fin->fin_dlen - thoff;
544 j = 0xffff >> (16 - dlen);
545 i = (0xffff & j) << off;
547 COPYDATA(*(mb_t **)fin->fin_mp, fin->fin_plen - fin->fin_dlen + thoff,
548 dlen, (caddr_t)is->is_sbuf[rv] + off);
550 is->is_smsk[rv] |= i;
551 for (j = 0, i = is->is_smsk[rv]; i & 1; i >>= 1)
556 (void) ipsc_match(is);
559 * There is the potential here for plain text passwords to get
560 * buffered and stored for some time...
562 if (!(is->is_flags & IS_SC_CLIENT))
563 bzero(is->is_sbuf[0], sizeof(is->is_sbuf[0]));
564 if (!(is->is_flags & IS_SC_SERVER))
565 bzero(is->is_sbuf[1], sizeof(is->is_sbuf[1]));
571 int fr_scan_ioctl(data, cmd, mode)
582 err = ipsc_add(data);
585 err = ipsc_delete(data);
588 bcopy((char *)&ipsc_stat, (char *)&ipscs, sizeof(ipscs));
589 ipscs.iscs_list = ipsc_list;
590 BCOPYOUT(&ipscs, data, sizeof(ipscs));
599 #endif /* IPFILTER_SCAN */