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