1145516Sdarrenr/* 2255332Scy * Copyright (C) 2012 by Darren Reed. 3145516Sdarrenr * 4145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 5145516Sdarrenr */ 6145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 7145516Sdarrenr# undef KERNEL 8145516Sdarrenr# undef _KERNEL 9145516Sdarrenr# define KERNEL 1 10145516Sdarrenr# define _KERNEL 1 11145516Sdarrenr#endif 12145516Sdarrenr#include <sys/param.h> 13145516Sdarrenr#if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL) 14145516Sdarrenr# include <sys/kern_svcs.h> 15145516Sdarrenr#endif 16145516Sdarrenr#include <sys/types.h> 17145516Sdarrenr#include <sys/time.h> 18145516Sdarrenr#include <sys/errno.h> 19145516Sdarrenr#if !defined(_KERNEL) 20145516Sdarrenr# include <stdlib.h> 21145516Sdarrenr# include <string.h> 22145516Sdarrenr# define _KERNEL 23145516Sdarrenr# ifdef __OpenBSD__ 24145516Sdarrenrstruct file; 25145516Sdarrenr# endif 26145516Sdarrenr# include <sys/uio.h> 27145516Sdarrenr# undef _KERNEL 28145516Sdarrenr#else 29145516Sdarrenr# include <sys/systm.h> 30145516Sdarrenr# if !defined(__svr4__) && !defined(__SVR4) 31145516Sdarrenr# include <sys/mbuf.h> 32145516Sdarrenr# endif 33145516Sdarrenr#endif 34145516Sdarrenr#include <sys/socket.h> 35153872Sguido#if !defined(__hpux) && !defined(__osf__) && !defined(linux) && !defined(AIX) 36145516Sdarrenr# include <sys/ioccom.h> 37145516Sdarrenr#endif 38145516Sdarrenr#ifdef __FreeBSD__ 39145516Sdarrenr# include <sys/filio.h> 40145516Sdarrenr# include <sys/malloc.h> 41145516Sdarrenr#else 42145516Sdarrenr# include <sys/ioctl.h> 43145516Sdarrenr#endif 44145516Sdarrenr 45145516Sdarrenr#include <netinet/in.h> 46145516Sdarrenr#include <netinet/in_systm.h> 47145516Sdarrenr#include <netinet/ip.h> 48145516Sdarrenr#include <netinet/tcp.h> 49145516Sdarrenr 50145516Sdarrenr#include <net/if.h> 51145516Sdarrenr 52145516Sdarrenr 53145516Sdarrenr#include "netinet/ip_compat.h" 54145516Sdarrenr#include "netinet/ip_fil.h" 55145516Sdarrenr#include "netinet/ip_state.h" 56145516Sdarrenr#include "netinet/ip_scan.h" 57145516Sdarrenr/* END OF INCLUDES */ 58145516Sdarrenr 59145516Sdarrenr#if !defined(lint) 60145516Sdarrenrstatic const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; 61255332Scystatic const char rcsid[] = "@(#)$Id$"; 62145516Sdarrenr#endif 63145516Sdarrenr 64145516Sdarrenr#ifdef IPFILTER_SCAN /* endif at bottom of file */ 65145516Sdarrenr 66145516Sdarrenr 67255332Scyipscan_t *ipf_scan_list = NULL, 68255332Scy *ipf_scan_tail = NULL; 69255332Scyipscanstat_t ipf_scan_stat; 70145516Sdarrenr# ifdef USE_MUTEXES 71255332Scyipfrwlock_t ipf_scan_rwlock; 72145516Sdarrenr# endif 73145516Sdarrenr 74145516Sdarrenr# ifndef isalpha 75145516Sdarrenr# define isalpha(x) (((x) >= 'A' && 'Z' >= (x)) || \ 76145516Sdarrenr ((x) >= 'a' && 'z' >= (x))) 77145516Sdarrenr# endif 78145516Sdarrenr 79145516Sdarrenr 80255332Scyint ipf_scan_add __P((caddr_t)); 81255332Scyint ipf_scan_remove __P((caddr_t)); 82255332Scystruct ipscan *ipf_scan_lookup __P((char *)); 83255332Scyint ipf_scan_matchstr __P((sinfo_t *, char *, int)); 84255332Scyint ipf_scan_matchisc __P((ipscan_t *, ipstate_t *, int, int, int *)); 85255332Scyint ipf_scan_match __P((ipstate_t *)); 86145516Sdarrenr 87255332Scystatic int ipf_scan_inited = 0; 88145516Sdarrenr 89145516Sdarrenr 90255332Scyint 91255332Scyipf_scan_init() 92145516Sdarrenr{ 93255332Scy RWLOCK_INIT(&ipf_scan_rwlock, "ip scan rwlock"); 94255332Scy ipf_scan_inited = 1; 95145516Sdarrenr return 0; 96145516Sdarrenr} 97145516Sdarrenr 98145516Sdarrenr 99255332Scyvoid 100255332Scyipf_scan_unload(ipf_main_softc_t *arg) 101145516Sdarrenr{ 102255332Scy if (ipf_scan_inited == 1) { 103255332Scy RW_DESTROY(&ipf_scan_rwlock); 104255332Scy ipf_scan_inited = 0; 105161351Sguido } 106145516Sdarrenr} 107145516Sdarrenr 108145516Sdarrenr 109255332Scyint 110255332Scyipf_scan_add(data) 111255332Scy caddr_t data; 112145516Sdarrenr{ 113145516Sdarrenr ipscan_t *i, *isc; 114145516Sdarrenr int err; 115145516Sdarrenr 116145516Sdarrenr KMALLOC(isc, ipscan_t *); 117255332Scy if (!isc) { 118255332Scy ipf_interror = 90001; 119145516Sdarrenr return ENOMEM; 120255332Scy } 121145516Sdarrenr 122145516Sdarrenr err = copyinptr(data, isc, sizeof(*isc)); 123170263Sdarrenr if (err) { 124170263Sdarrenr KFREE(isc); 125145516Sdarrenr return err; 126170263Sdarrenr } 127145516Sdarrenr 128255332Scy WRITE_ENTER(&ipf_scan_rwlock); 129145516Sdarrenr 130255332Scy i = ipf_scan_lookup(isc->ipsc_tag); 131255332Scy if (i != NULL) { 132255332Scy RWLOCK_EXIT(&ipf_scan_rwlock); 133145516Sdarrenr KFREE(isc); 134255332Scy ipf_interror = 90002; 135145516Sdarrenr return EEXIST; 136145516Sdarrenr } 137145516Sdarrenr 138255332Scy if (ipf_scan_tail) { 139255332Scy ipf_scan_tail->ipsc_next = isc; 140255332Scy isc->ipsc_pnext = &ipf_scan_tail->ipsc_next; 141255332Scy ipf_scan_tail = isc; 142145516Sdarrenr } else { 143255332Scy ipf_scan_list = isc; 144255332Scy ipf_scan_tail = isc; 145255332Scy isc->ipsc_pnext = &ipf_scan_list; 146145516Sdarrenr } 147145516Sdarrenr isc->ipsc_next = NULL; 148145516Sdarrenr 149145516Sdarrenr isc->ipsc_hits = 0; 150145516Sdarrenr isc->ipsc_fref = 0; 151145516Sdarrenr isc->ipsc_sref = 0; 152145516Sdarrenr isc->ipsc_active = 0; 153145516Sdarrenr 154255332Scy ipf_scan_stat.iscs_entries++; 155255332Scy RWLOCK_EXIT(&ipf_scan_rwlock); 156145516Sdarrenr return 0; 157145516Sdarrenr} 158145516Sdarrenr 159145516Sdarrenr 160255332Scyint 161255332Scyipf_scan_remove(data) 162255332Scy caddr_t data; 163145516Sdarrenr{ 164145516Sdarrenr ipscan_t isc, *i; 165145516Sdarrenr int err; 166145516Sdarrenr 167145516Sdarrenr err = copyinptr(data, &isc, sizeof(isc)); 168145516Sdarrenr if (err) 169145516Sdarrenr return err; 170145516Sdarrenr 171255332Scy WRITE_ENTER(&ipf_scan_rwlock); 172145516Sdarrenr 173255332Scy i = ipf_scan_lookup(isc.ipsc_tag); 174145516Sdarrenr if (i == NULL) 175145516Sdarrenr err = ENOENT; 176145516Sdarrenr else { 177145516Sdarrenr if (i->ipsc_fref) { 178255332Scy RWLOCK_EXIT(&ipf_scan_rwlock); 179255332Scy ipf_interror = 90003; 180145516Sdarrenr return EBUSY; 181145516Sdarrenr } 182145516Sdarrenr 183145516Sdarrenr *i->ipsc_pnext = i->ipsc_next; 184145516Sdarrenr if (i->ipsc_next) 185145516Sdarrenr i->ipsc_next->ipsc_pnext = i->ipsc_pnext; 186145516Sdarrenr else { 187255332Scy if (i->ipsc_pnext == &ipf_scan_list) 188255332Scy ipf_scan_tail = NULL; 189145516Sdarrenr else 190255332Scy ipf_scan_tail = *(*i->ipsc_pnext)->ipsc_pnext; 191145516Sdarrenr } 192145516Sdarrenr 193255332Scy ipf_scan_stat.iscs_entries--; 194145516Sdarrenr KFREE(i); 195145516Sdarrenr } 196255332Scy RWLOCK_EXIT(&ipf_scan_rwlock); 197145516Sdarrenr return err; 198145516Sdarrenr} 199145516Sdarrenr 200145516Sdarrenr 201255332Scystruct ipscan * 202255332Scyipf_scan_lookup(tag) 203255332Scy char *tag; 204145516Sdarrenr{ 205145516Sdarrenr ipscan_t *i; 206145516Sdarrenr 207255332Scy for (i = ipf_scan_list; i; i = i->ipsc_next) 208145516Sdarrenr if (!strcmp(i->ipsc_tag, tag)) 209145516Sdarrenr return i; 210145516Sdarrenr return NULL; 211145516Sdarrenr} 212145516Sdarrenr 213145516Sdarrenr 214255332Scyint 215255332Scyipf_scan_attachfr(fr) 216255332Scy struct frentry *fr; 217145516Sdarrenr{ 218145516Sdarrenr ipscan_t *i; 219145516Sdarrenr 220255332Scy if (fr->fr_isctag != -1) { 221255332Scy READ_ENTER(&ipf_scan_rwlock); 222255332Scy i = ipf_scan_lookup(fr->fr_isctag + fr->fr_names); 223145516Sdarrenr if (i != NULL) { 224145516Sdarrenr ATOMIC_INC32(i->ipsc_fref); 225145516Sdarrenr } 226255332Scy RWLOCK_EXIT(&ipf_scan_rwlock); 227255332Scy if (i == NULL) { 228255332Scy ipf_interror = 90004; 229145516Sdarrenr return ENOENT; 230255332Scy } 231145516Sdarrenr fr->fr_isc = i; 232145516Sdarrenr } 233145516Sdarrenr return 0; 234145516Sdarrenr} 235145516Sdarrenr 236145516Sdarrenr 237255332Scyint 238255332Scyipf_scan_attachis(is) 239255332Scy struct ipstate *is; 240145516Sdarrenr{ 241145516Sdarrenr frentry_t *fr; 242145516Sdarrenr ipscan_t *i; 243145516Sdarrenr 244255332Scy READ_ENTER(&ipf_scan_rwlock); 245145516Sdarrenr fr = is->is_rule; 246255332Scy if (fr != NULL) { 247145516Sdarrenr i = fr->fr_isc; 248170263Sdarrenr if ((i != NULL) && (i != (ipscan_t *)-1)) { 249145516Sdarrenr is->is_isc = i; 250170263Sdarrenr ATOMIC_INC32(i->ipsc_sref); 251170263Sdarrenr if (i->ipsc_clen) 252170263Sdarrenr is->is_flags |= IS_SC_CLIENT; 253170263Sdarrenr else 254170263Sdarrenr is->is_flags |= IS_SC_MATCHC; 255170263Sdarrenr if (i->ipsc_slen) 256170263Sdarrenr is->is_flags |= IS_SC_SERVER; 257170263Sdarrenr else 258170263Sdarrenr is->is_flags |= IS_SC_MATCHS; 259145516Sdarrenr } 260145516Sdarrenr } 261255332Scy RWLOCK_EXIT(&ipf_scan_rwlock); 262145516Sdarrenr return 0; 263145516Sdarrenr} 264145516Sdarrenr 265145516Sdarrenr 266255332Scyint 267255332Scyipf_scan_detachfr(fr) 268255332Scy struct frentry *fr; 269145516Sdarrenr{ 270145516Sdarrenr ipscan_t *i; 271145516Sdarrenr 272145516Sdarrenr i = fr->fr_isc; 273145516Sdarrenr if (i != NULL) { 274145516Sdarrenr ATOMIC_DEC32(i->ipsc_fref); 275145516Sdarrenr } 276145516Sdarrenr return 0; 277145516Sdarrenr} 278145516Sdarrenr 279145516Sdarrenr 280255332Scyint 281255332Scyipf_scan_detachis(is) 282255332Scy struct ipstate *is; 283145516Sdarrenr{ 284145516Sdarrenr ipscan_t *i; 285145516Sdarrenr 286255332Scy READ_ENTER(&ipf_scan_rwlock); 287145516Sdarrenr if ((i = is->is_isc) && (i != (ipscan_t *)-1)) { 288145516Sdarrenr ATOMIC_DEC32(i->ipsc_sref); 289145516Sdarrenr is->is_isc = NULL; 290145516Sdarrenr is->is_flags &= ~(IS_SC_CLIENT|IS_SC_SERVER); 291145516Sdarrenr } 292255332Scy RWLOCK_EXIT(&ipf_scan_rwlock); 293145516Sdarrenr return 0; 294145516Sdarrenr} 295145516Sdarrenr 296145516Sdarrenr 297145516Sdarrenr/* 298145516Sdarrenr * 'string' compare for scanning 299145516Sdarrenr */ 300255332Scyint 301255332Scyipf_scan_matchstr(sp, str, n) 302255332Scy sinfo_t *sp; 303255332Scy char *str; 304255332Scy int n; 305145516Sdarrenr{ 306145516Sdarrenr char *s, *t, *up; 307145516Sdarrenr int i = n; 308145516Sdarrenr 309145516Sdarrenr if (i > sp->s_len) 310145516Sdarrenr i = sp->s_len; 311145516Sdarrenr up = str; 312145516Sdarrenr 313145516Sdarrenr for (s = sp->s_txt, t = sp->s_msk; i; i--, s++, t++, up++) 314145516Sdarrenr switch ((int)*t) 315145516Sdarrenr { 316145516Sdarrenr case '.' : 317145516Sdarrenr if (*s != *up) 318145516Sdarrenr return 1; 319145516Sdarrenr break; 320145516Sdarrenr case '?' : 321145516Sdarrenr if (!ISALPHA(*up) || ((*s & 0x5f) != (*up & 0x5f))) 322145516Sdarrenr return 1; 323145516Sdarrenr break; 324145516Sdarrenr case '*' : 325145516Sdarrenr break; 326145516Sdarrenr } 327145516Sdarrenr return 0; 328145516Sdarrenr} 329145516Sdarrenr 330145516Sdarrenr 331145516Sdarrenr/* 332145516Sdarrenr * Returns 3 if both server and client match, 2 if just server, 333145516Sdarrenr * 1 if just client 334145516Sdarrenr */ 335255332Scyint 336255332Scyipf_scan_matchisc(isc, is, cl, sl, maxm) 337255332Scy ipscan_t *isc; 338255332Scy ipstate_t *is; 339255332Scy int cl, sl, maxm[2]; 340145516Sdarrenr{ 341145516Sdarrenr int i, j, k, n, ret = 0, flags; 342145516Sdarrenr 343145516Sdarrenr flags = is->is_flags; 344145516Sdarrenr 345145516Sdarrenr /* 346145516Sdarrenr * If we've already matched more than what is on offer, then 347145516Sdarrenr * assume we have a better match already and forget this one. 348145516Sdarrenr */ 349145516Sdarrenr if (maxm != NULL) { 350145516Sdarrenr if (isc->ipsc_clen < maxm[0]) 351145516Sdarrenr return 0; 352145516Sdarrenr if (isc->ipsc_slen < maxm[1]) 353145516Sdarrenr return 0; 354145516Sdarrenr j = maxm[0]; 355145516Sdarrenr k = maxm[1]; 356145516Sdarrenr } else { 357145516Sdarrenr j = 0; 358145516Sdarrenr k = 0; 359145516Sdarrenr } 360145516Sdarrenr 361145516Sdarrenr if (!isc->ipsc_clen) 362145516Sdarrenr ret = 1; 363145516Sdarrenr else if (((flags & (IS_SC_MATCHC|IS_SC_CLIENT)) == IS_SC_CLIENT) && 364145516Sdarrenr cl && isc->ipsc_clen) { 365145516Sdarrenr i = 0; 366145516Sdarrenr n = MIN(cl, isc->ipsc_clen); 367145516Sdarrenr if ((n > 0) && (!maxm || (n >= maxm[1]))) { 368255332Scy if (!ipf_scan_matchstr(&isc->ipsc_cl, 369255332Scy is->is_sbuf[0], n)) { 370145516Sdarrenr i++; 371145516Sdarrenr ret |= 1; 372145516Sdarrenr if (n > j) 373145516Sdarrenr j = n; 374145516Sdarrenr } 375145516Sdarrenr } 376145516Sdarrenr } 377145516Sdarrenr 378145516Sdarrenr if (!isc->ipsc_slen) 379145516Sdarrenr ret |= 2; 380145516Sdarrenr else if (((flags & (IS_SC_MATCHS|IS_SC_SERVER)) == IS_SC_SERVER) && 381145516Sdarrenr sl && isc->ipsc_slen) { 382145516Sdarrenr i = 0; 383145516Sdarrenr n = MIN(cl, isc->ipsc_slen); 384145516Sdarrenr if ((n > 0) && (!maxm || (n >= maxm[1]))) { 385255332Scy if (!ipf_scan_matchstr(&isc->ipsc_sl, 386255332Scy is->is_sbuf[1], n)) { 387145516Sdarrenr i++; 388145516Sdarrenr ret |= 2; 389145516Sdarrenr if (n > k) 390145516Sdarrenr k = n; 391145516Sdarrenr } 392145516Sdarrenr } 393145516Sdarrenr } 394145516Sdarrenr 395145516Sdarrenr if (maxm && (ret == 3)) { 396145516Sdarrenr maxm[0] = j; 397145516Sdarrenr maxm[1] = k; 398145516Sdarrenr } 399145516Sdarrenr return ret; 400145516Sdarrenr} 401145516Sdarrenr 402145516Sdarrenr 403255332Scyint 404255332Scyipf_scan_match(is) 405255332Scy ipstate_t *is; 406145516Sdarrenr{ 407145516Sdarrenr int i, j, k, n, cl, sl, maxm[2]; 408145516Sdarrenr ipscan_t *isc, *lm; 409145516Sdarrenr tcpdata_t *t; 410145516Sdarrenr 411145516Sdarrenr for (cl = 0, n = is->is_smsk[0]; n & 1; n >>= 1) 412145516Sdarrenr cl++; 413145516Sdarrenr for (sl = 0, n = is->is_smsk[1]; n & 1; n >>= 1) 414145516Sdarrenr sl++; 415145516Sdarrenr 416145516Sdarrenr j = 0; 417145516Sdarrenr isc = is->is_isc; 418145516Sdarrenr if (isc != NULL) { 419145516Sdarrenr /* 420145516Sdarrenr * Known object to scan for. 421145516Sdarrenr */ 422255332Scy i = ipf_scan_matchisc(isc, is, cl, sl, NULL); 423145516Sdarrenr if (i & 1) { 424145516Sdarrenr is->is_flags |= IS_SC_MATCHC; 425145516Sdarrenr is->is_flags &= ~IS_SC_CLIENT; 426145516Sdarrenr } else if (cl >= isc->ipsc_clen) 427145516Sdarrenr is->is_flags &= ~IS_SC_CLIENT; 428145516Sdarrenr if (i & 2) { 429145516Sdarrenr is->is_flags |= IS_SC_MATCHS; 430145516Sdarrenr is->is_flags &= ~IS_SC_SERVER; 431145516Sdarrenr } else if (sl >= isc->ipsc_slen) 432145516Sdarrenr is->is_flags &= ~IS_SC_SERVER; 433145516Sdarrenr } else { 434145516Sdarrenr i = 0; 435145516Sdarrenr lm = NULL; 436145516Sdarrenr maxm[0] = 0; 437145516Sdarrenr maxm[1] = 0; 438255332Scy for (k = 0, isc = ipf_scan_list; isc; isc = isc->ipsc_next) { 439255332Scy i = ipf_scan_matchisc(isc, is, cl, sl, maxm); 440145516Sdarrenr if (i) { 441145516Sdarrenr /* 442145516Sdarrenr * We only want to remember the best match 443145516Sdarrenr * and the number of times we get a best 444145516Sdarrenr * match. 445145516Sdarrenr */ 446145516Sdarrenr if ((j == 3) && (i < 3)) 447145516Sdarrenr continue; 448145516Sdarrenr if ((i == 3) && (j != 3)) 449145516Sdarrenr k = 1; 450145516Sdarrenr else 451145516Sdarrenr k++; 452145516Sdarrenr j = i; 453145516Sdarrenr lm = isc; 454145516Sdarrenr } 455145516Sdarrenr } 456145516Sdarrenr if (k == 1) 457145516Sdarrenr isc = lm; 458161351Sguido if (isc == NULL) 459161351Sguido return 0; 460145516Sdarrenr 461145516Sdarrenr /* 462145516Sdarrenr * No matches or partial matches, so reset the respective 463145516Sdarrenr * search flag. 464145516Sdarrenr */ 465145516Sdarrenr if (!(j & 1)) 466145516Sdarrenr is->is_flags &= ~IS_SC_CLIENT; 467145516Sdarrenr 468145516Sdarrenr if (!(j & 2)) 469145516Sdarrenr is->is_flags &= ~IS_SC_SERVER; 470145516Sdarrenr 471145516Sdarrenr /* 472145516Sdarrenr * If we found the best match, then set flags appropriately. 473145516Sdarrenr */ 474145516Sdarrenr if ((j == 3) && (k == 1)) { 475145516Sdarrenr is->is_flags &= ~(IS_SC_SERVER|IS_SC_CLIENT); 476145516Sdarrenr is->is_flags |= (IS_SC_MATCHS|IS_SC_MATCHC); 477145516Sdarrenr } 478145516Sdarrenr } 479145516Sdarrenr 480145516Sdarrenr /* 481145516Sdarrenr * If the acknowledged side of a connection has moved past the data in 482145516Sdarrenr * which we are interested, then reset respective flag. 483145516Sdarrenr */ 484145516Sdarrenr t = &is->is_tcp.ts_data[0]; 485145516Sdarrenr if (t->td_end > is->is_s0[0] + 15) 486145516Sdarrenr is->is_flags &= ~IS_SC_CLIENT; 487145516Sdarrenr 488145516Sdarrenr t = &is->is_tcp.ts_data[1]; 489145516Sdarrenr if (t->td_end > is->is_s0[1] + 15) 490145516Sdarrenr is->is_flags &= ~IS_SC_SERVER; 491145516Sdarrenr 492145516Sdarrenr /* 493145516Sdarrenr * Matching complete ? 494145516Sdarrenr */ 495145516Sdarrenr j = ISC_A_NONE; 496145516Sdarrenr if ((is->is_flags & IS_SC_MATCHALL) == IS_SC_MATCHALL) { 497145516Sdarrenr j = isc->ipsc_action; 498255332Scy ipf_scan_stat.iscs_acted++; 499145516Sdarrenr } else if ((is->is_isc != NULL) && 500145516Sdarrenr ((is->is_flags & IS_SC_MATCHALL) != IS_SC_MATCHALL) && 501145516Sdarrenr !(is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER))) { 502145516Sdarrenr /* 503145516Sdarrenr * Matching failed... 504145516Sdarrenr */ 505145516Sdarrenr j = isc->ipsc_else; 506255332Scy ipf_scan_stat.iscs_else++; 507145516Sdarrenr } 508145516Sdarrenr 509145516Sdarrenr switch (j) 510145516Sdarrenr { 511145516Sdarrenr case ISC_A_CLOSE : 512145516Sdarrenr /* 513145516Sdarrenr * If as a result of a successful match we are to 514145516Sdarrenr * close a connection, change the "keep state" info. 515145516Sdarrenr * to block packets and generate TCP RST's. 516145516Sdarrenr */ 517145516Sdarrenr is->is_pass &= ~FR_RETICMP; 518145516Sdarrenr is->is_pass |= FR_RETRST; 519145516Sdarrenr break; 520145516Sdarrenr default : 521145516Sdarrenr break; 522145516Sdarrenr } 523145516Sdarrenr 524145516Sdarrenr return i; 525145516Sdarrenr} 526145516Sdarrenr 527145516Sdarrenr 528145516Sdarrenr/* 529145516Sdarrenr * check if a packet matches what we're scanning for 530145516Sdarrenr */ 531255332Scyint 532255332Scyipf_scan_packet(fin, is) 533255332Scy fr_info_t *fin; 534255332Scy ipstate_t *is; 535145516Sdarrenr{ 536145516Sdarrenr int i, j, rv, dlen, off, thoff; 537145516Sdarrenr u_32_t seq, s0; 538145516Sdarrenr tcphdr_t *tcp; 539145516Sdarrenr 540145516Sdarrenr rv = !IP6_EQ(&fin->fin_fi.fi_src, &is->is_src); 541145516Sdarrenr tcp = fin->fin_dp; 542145516Sdarrenr seq = ntohl(tcp->th_seq); 543145516Sdarrenr 544145516Sdarrenr if (!is->is_s0[rv]) 545145516Sdarrenr return 1; 546145516Sdarrenr 547145516Sdarrenr /* 548145516Sdarrenr * check if this packet has more data that falls within the first 549145516Sdarrenr * 16 bytes sent in either direction. 550145516Sdarrenr */ 551145516Sdarrenr s0 = is->is_s0[rv]; 552145516Sdarrenr off = seq - s0; 553145516Sdarrenr if ((off > 15) || (off < 0)) 554145516Sdarrenr return 1; 555145516Sdarrenr thoff = TCP_OFF(tcp) << 2; 556145516Sdarrenr dlen = fin->fin_dlen - thoff; 557145516Sdarrenr if (dlen <= 0) 558145516Sdarrenr return 1; 559145516Sdarrenr if (dlen > 16) 560145516Sdarrenr dlen = 16; 561145516Sdarrenr if (off + dlen > 16) 562145516Sdarrenr dlen = 16 - off; 563145516Sdarrenr 564145516Sdarrenr j = 0xffff >> (16 - dlen); 565145516Sdarrenr i = (0xffff & j) << off; 566145516Sdarrenr#ifdef _KERNEL 567153872Sguido COPYDATA(*(mb_t **)fin->fin_mp, fin->fin_plen - fin->fin_dlen + thoff, 568153872Sguido dlen, (caddr_t)is->is_sbuf[rv] + off); 569145516Sdarrenr#endif 570145516Sdarrenr is->is_smsk[rv] |= i; 571145516Sdarrenr for (j = 0, i = is->is_smsk[rv]; i & 1; i >>= 1) 572145516Sdarrenr j++; 573145516Sdarrenr if (j == 0) 574145516Sdarrenr return 1; 575145516Sdarrenr 576255332Scy (void) ipf_scan_match(is); 577145516Sdarrenr#if 0 578145516Sdarrenr /* 579145516Sdarrenr * There is the potential here for plain text passwords to get 580145516Sdarrenr * buffered and stored for some time... 581145516Sdarrenr */ 582145516Sdarrenr if (!(is->is_flags & IS_SC_CLIENT)) 583145516Sdarrenr bzero(is->is_sbuf[0], sizeof(is->is_sbuf[0])); 584145516Sdarrenr if (!(is->is_flags & IS_SC_SERVER)) 585145516Sdarrenr bzero(is->is_sbuf[1], sizeof(is->is_sbuf[1])); 586145516Sdarrenr#endif 587145516Sdarrenr return 0; 588145516Sdarrenr} 589145516Sdarrenr 590145516Sdarrenr 591255332Scyint 592255332Scyipf_scan_ioctl(data, cmd, mode, uid, ctx) 593255332Scy caddr_t data; 594255332Scy ioctlcmd_t cmd; 595255332Scy int mode, uid; 596255332Scy void *ctx; 597145516Sdarrenr{ 598145516Sdarrenr ipscanstat_t ipscs; 599145516Sdarrenr int err = 0; 600145516Sdarrenr 601145516Sdarrenr switch (cmd) 602145516Sdarrenr { 603145516Sdarrenr case SIOCADSCA : 604255332Scy err = ipf_scan_add(data); 605145516Sdarrenr break; 606145516Sdarrenr case SIOCRMSCA : 607255332Scy err = ipf_scan_remove(data); 608145516Sdarrenr break; 609145516Sdarrenr case SIOCGSCST : 610255332Scy bcopy((char *)&ipf_scan_stat, (char *)&ipscs, sizeof(ipscs)); 611255332Scy ipscs.iscs_list = ipf_scan_list; 612172771Sdarrenr err = BCOPYOUT(&ipscs, data, sizeof(ipscs)); 613255332Scy if (err != 0) { 614255332Scy ipf_interror = 90005; 615172771Sdarrenr err = EFAULT; 616255332Scy } 617145516Sdarrenr break; 618145516Sdarrenr default : 619145516Sdarrenr err = EINVAL; 620145516Sdarrenr break; 621145516Sdarrenr } 622145516Sdarrenr 623145516Sdarrenr return err; 624145516Sdarrenr} 625145516Sdarrenr#endif /* IPFILTER_SCAN */ 626