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