2 * Copyright (C) 2012 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$";
64 #ifdef IPFILTER_SCAN /* endif at bottom of file */
67 ipscan_t *ipf_scan_list = NULL,
68 *ipf_scan_tail = NULL;
69 ipscanstat_t ipf_scan_stat;
71 ipfrwlock_t ipf_scan_rwlock;
75 # define isalpha(x) (((x) >= 'A' && 'Z' >= (x)) || \
76 ((x) >= 'a' && 'z' >= (x)))
80 int ipf_scan_add __P((caddr_t));
81 int ipf_scan_remove __P((caddr_t));
82 struct ipscan *ipf_scan_lookup __P((char *));
83 int ipf_scan_matchstr __P((sinfo_t *, char *, int));
84 int ipf_scan_matchisc __P((ipscan_t *, ipstate_t *, int, int, int *));
85 int ipf_scan_match __P((ipstate_t *));
87 static int ipf_scan_inited = 0;
93 RWLOCK_INIT(&ipf_scan_rwlock, "ip scan rwlock");
100 ipf_scan_unload(ipf_main_softc_t *arg)
102 if (ipf_scan_inited == 1) {
103 RW_DESTROY(&ipf_scan_rwlock);
116 KMALLOC(isc, ipscan_t *);
118 ipf_interror = 90001;
122 err = copyinptr(data, isc, sizeof(*isc));
128 WRITE_ENTER(&ipf_scan_rwlock);
130 i = ipf_scan_lookup(isc->ipsc_tag);
132 RWLOCK_EXIT(&ipf_scan_rwlock);
134 ipf_interror = 90002;
139 ipf_scan_tail->ipsc_next = isc;
140 isc->ipsc_pnext = &ipf_scan_tail->ipsc_next;
145 isc->ipsc_pnext = &ipf_scan_list;
147 isc->ipsc_next = NULL;
152 isc->ipsc_active = 0;
154 ipf_scan_stat.iscs_entries++;
155 RWLOCK_EXIT(&ipf_scan_rwlock);
161 ipf_scan_remove(data)
167 err = copyinptr(data, &isc, sizeof(isc));
171 WRITE_ENTER(&ipf_scan_rwlock);
173 i = ipf_scan_lookup(isc.ipsc_tag);
178 RWLOCK_EXIT(&ipf_scan_rwlock);
179 ipf_interror = 90003;
183 *i->ipsc_pnext = i->ipsc_next;
185 i->ipsc_next->ipsc_pnext = i->ipsc_pnext;
187 if (i->ipsc_pnext == &ipf_scan_list)
188 ipf_scan_tail = NULL;
190 ipf_scan_tail = *(*i->ipsc_pnext)->ipsc_pnext;
193 ipf_scan_stat.iscs_entries--;
196 RWLOCK_EXIT(&ipf_scan_rwlock);
207 for (i = ipf_scan_list; i; i = i->ipsc_next)
208 if (!strcmp(i->ipsc_tag, tag))
215 ipf_scan_attachfr(fr)
220 if (fr->fr_isctag != -1) {
221 READ_ENTER(&ipf_scan_rwlock);
222 i = ipf_scan_lookup(fr->fr_isctag + fr->fr_names);
224 ATOMIC_INC32(i->ipsc_fref);
226 RWLOCK_EXIT(&ipf_scan_rwlock);
228 ipf_interror = 90004;
238 ipf_scan_attachis(is)
244 READ_ENTER(&ipf_scan_rwlock);
248 if ((i != NULL) && (i != (ipscan_t *)-1)) {
250 ATOMIC_INC32(i->ipsc_sref);
252 is->is_flags |= IS_SC_CLIENT;
254 is->is_flags |= IS_SC_MATCHC;
256 is->is_flags |= IS_SC_SERVER;
258 is->is_flags |= IS_SC_MATCHS;
261 RWLOCK_EXIT(&ipf_scan_rwlock);
267 ipf_scan_detachfr(fr)
274 ATOMIC_DEC32(i->ipsc_fref);
281 ipf_scan_detachis(is)
286 READ_ENTER(&ipf_scan_rwlock);
287 if ((i = is->is_isc) && (i != (ipscan_t *)-1)) {
288 ATOMIC_DEC32(i->ipsc_sref);
290 is->is_flags &= ~(IS_SC_CLIENT|IS_SC_SERVER);
292 RWLOCK_EXIT(&ipf_scan_rwlock);
298 * 'string' compare for scanning
301 ipf_scan_matchstr(sp, str, n)
313 for (s = sp->s_txt, t = sp->s_msk; i; i--, s++, t++, up++)
321 if (!ISALPHA(*up) || ((*s & 0x5f) != (*up & 0x5f)))
332 * Returns 3 if both server and client match, 2 if just server,
336 ipf_scan_matchisc(isc, is, cl, sl, maxm)
341 int i, j, k, n, ret = 0, flags;
343 flags = is->is_flags;
346 * If we've already matched more than what is on offer, then
347 * assume we have a better match already and forget this one.
350 if (isc->ipsc_clen < maxm[0])
352 if (isc->ipsc_slen < maxm[1])
363 else if (((flags & (IS_SC_MATCHC|IS_SC_CLIENT)) == IS_SC_CLIENT) &&
364 cl && isc->ipsc_clen) {
366 n = MIN(cl, isc->ipsc_clen);
367 if ((n > 0) && (!maxm || (n >= maxm[1]))) {
368 if (!ipf_scan_matchstr(&isc->ipsc_cl,
369 is->is_sbuf[0], n)) {
380 else if (((flags & (IS_SC_MATCHS|IS_SC_SERVER)) == IS_SC_SERVER) &&
381 sl && isc->ipsc_slen) {
383 n = MIN(cl, isc->ipsc_slen);
384 if ((n > 0) && (!maxm || (n >= maxm[1]))) {
385 if (!ipf_scan_matchstr(&isc->ipsc_sl,
386 is->is_sbuf[1], n)) {
395 if (maxm && (ret == 3)) {
407 int i, j, k, n, cl, sl, maxm[2];
411 for (cl = 0, n = is->is_smsk[0]; n & 1; n >>= 1)
413 for (sl = 0, n = is->is_smsk[1]; n & 1; n >>= 1)
420 * Known object to scan for.
422 i = ipf_scan_matchisc(isc, is, cl, sl, NULL);
424 is->is_flags |= IS_SC_MATCHC;
425 is->is_flags &= ~IS_SC_CLIENT;
426 } else if (cl >= isc->ipsc_clen)
427 is->is_flags &= ~IS_SC_CLIENT;
429 is->is_flags |= IS_SC_MATCHS;
430 is->is_flags &= ~IS_SC_SERVER;
431 } else if (sl >= isc->ipsc_slen)
432 is->is_flags &= ~IS_SC_SERVER;
438 for (k = 0, isc = ipf_scan_list; isc; isc = isc->ipsc_next) {
439 i = ipf_scan_matchisc(isc, is, cl, sl, maxm);
442 * We only want to remember the best match
443 * and the number of times we get a best
446 if ((j == 3) && (i < 3))
448 if ((i == 3) && (j != 3))
462 * No matches or partial matches, so reset the respective
466 is->is_flags &= ~IS_SC_CLIENT;
469 is->is_flags &= ~IS_SC_SERVER;
472 * If we found the best match, then set flags appropriately.
474 if ((j == 3) && (k == 1)) {
475 is->is_flags &= ~(IS_SC_SERVER|IS_SC_CLIENT);
476 is->is_flags |= (IS_SC_MATCHS|IS_SC_MATCHC);
481 * If the acknowledged side of a connection has moved past the data in
482 * which we are interested, then reset respective flag.
484 t = &is->is_tcp.ts_data[0];
485 if (t->td_end > is->is_s0[0] + 15)
486 is->is_flags &= ~IS_SC_CLIENT;
488 t = &is->is_tcp.ts_data[1];
489 if (t->td_end > is->is_s0[1] + 15)
490 is->is_flags &= ~IS_SC_SERVER;
493 * Matching complete ?
496 if ((is->is_flags & IS_SC_MATCHALL) == IS_SC_MATCHALL) {
497 j = isc->ipsc_action;
498 ipf_scan_stat.iscs_acted++;
499 } else if ((is->is_isc != NULL) &&
500 ((is->is_flags & IS_SC_MATCHALL) != IS_SC_MATCHALL) &&
501 !(is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER))) {
506 ipf_scan_stat.iscs_else++;
513 * If as a result of a successful match we are to
514 * close a connection, change the "keep state" info.
515 * to block packets and generate TCP RST's.
517 is->is_pass &= ~FR_RETICMP;
518 is->is_pass |= FR_RETRST;
529 * check if a packet matches what we're scanning for
532 ipf_scan_packet(fin, is)
536 int i, j, rv, dlen, off, thoff;
540 rv = !IP6_EQ(&fin->fin_fi.fi_src, &is->is_src);
542 seq = ntohl(tcp->th_seq);
548 * check if this packet has more data that falls within the first
549 * 16 bytes sent in either direction.
553 if ((off > 15) || (off < 0))
555 thoff = TCP_OFF(tcp) << 2;
556 dlen = fin->fin_dlen - thoff;
564 j = 0xffff >> (16 - dlen);
565 i = (0xffff & j) << off;
567 COPYDATA(*(mb_t **)fin->fin_mp, fin->fin_plen - fin->fin_dlen + thoff,
568 dlen, (caddr_t)is->is_sbuf[rv] + off);
570 is->is_smsk[rv] |= i;
571 for (j = 0, i = is->is_smsk[rv]; i & 1; i >>= 1)
576 (void) ipf_scan_match(is);
579 * There is the potential here for plain text passwords to get
580 * buffered and stored for some time...
582 if (!(is->is_flags & IS_SC_CLIENT))
583 bzero(is->is_sbuf[0], sizeof(is->is_sbuf[0]));
584 if (!(is->is_flags & IS_SC_SERVER))
585 bzero(is->is_sbuf[1], sizeof(is->is_sbuf[1]));
592 ipf_scan_ioctl(data, cmd, mode, uid, ctx)
604 err = ipf_scan_add(data);
607 err = ipf_scan_remove(data);
610 bcopy((char *)&ipf_scan_stat, (char *)&ipscs, sizeof(ipscs));
611 ipscs.iscs_list = ipf_scan_list;
612 err = BCOPYOUT(&ipscs, data, sizeof(ipscs));
614 ipf_interror = 90005;
625 #endif /* IPFILTER_SCAN */