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