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