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