fil.c revision 57096
1/* 2 * Copyright (C) 1993-1998 by Darren Reed. 3 * 4 * Redistribution and use in source and binary forms are permitted 5 * provided that this notice is preserved and due credit is given 6 * to the original author and the contributors. 7 */ 8#if !defined(lint) 9static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed"; 10static const char rcsid[] = "@(#)$Id: fil.c,v 2.3.2.16 2000/01/27 08:49:37 darrenr Exp $"; 11#endif 12 13#include <sys/errno.h> 14#include <sys/types.h> 15#include <sys/param.h> 16#include <sys/time.h> 17#include <sys/file.h> 18#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ 19 defined(_KERNEL) 20# include "opt_ipfilter_log.h" 21#endif 22#if defined(_KERNEL) && defined(__FreeBSD_version) && \ 23 (__FreeBSD_version >= 220000) 24# include <sys/filio.h> 25# include <sys/fcntl.h> 26#else 27# include <sys/ioctl.h> 28#endif 29#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) 30# include <sys/systm.h> 31#else 32# include <stdio.h> 33# include <string.h> 34# include <stdlib.h> 35#endif 36#include <sys/uio.h> 37#if !defined(__SVR4) && !defined(__svr4__) 38# ifndef linux 39# include <sys/mbuf.h> 40# endif 41#else 42# include <sys/byteorder.h> 43# if SOLARIS2 < 5 44# include <sys/dditypes.h> 45# endif 46# include <sys/stream.h> 47#endif 48#ifndef linux 49# include <sys/protosw.h> 50# include <sys/socket.h> 51#endif 52#include <net/if.h> 53#ifdef sun 54# include <net/af.h> 55#endif 56#include <net/route.h> 57#include <netinet/in.h> 58#include <netinet/in_systm.h> 59#include <netinet/ip.h> 60#ifndef linux 61# include <netinet/ip_var.h> 62#endif 63#if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ 64# include <sys/hashing.h> 65# include <netinet/in_var.h> 66#endif 67#include <netinet/tcp.h> 68#include <netinet/udp.h> 69#include <netinet/ip_icmp.h> 70#include "netinet/ip_compat.h" 71#include <netinet/tcpip.h> 72#include "netinet/ip_fil.h" 73#include "netinet/ip_proxy.h" 74#include "netinet/ip_nat.h" 75#include "netinet/ip_frag.h" 76#include "netinet/ip_state.h" 77#include "netinet/ip_auth.h" 78# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 79# include <sys/malloc.h> 80# if defined(_KERNEL) && !defined(IPFILTER_LKM) 81# include "opt_ipfilter.h" 82# endif 83# endif 84#ifndef MIN 85# define MIN(a,b) (((a)<(b))?(a):(b)) 86#endif 87#include "netinet/ipl.h" 88 89#ifndef _KERNEL 90# include "ipf.h" 91# include "ipt.h" 92extern int opts; 93 94# define FR_IFVERBOSE(ex,second,verb_pr) if (ex) { verbose verb_pr; \ 95 second; } 96# define FR_IFDEBUG(ex,second,verb_pr) if (ex) { debug verb_pr; \ 97 second; } 98# define FR_VERBOSE(verb_pr) verbose verb_pr 99# define FR_DEBUG(verb_pr) debug verb_pr 100# define SEND_RESET(ip, qif, if, m, fin) send_reset(ip, if) 101# define IPLLOG(a, c, d, e) ipllog() 102# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) 103#else /* #ifndef _KERNEL */ 104# define FR_IFVERBOSE(ex,second,verb_pr) ; 105# define FR_IFDEBUG(ex,second,verb_pr) ; 106# define FR_VERBOSE(verb_pr) 107# define FR_DEBUG(verb_pr) 108# define IPLLOG(a, c, d, e) ipflog(a, c, d, e) 109# if SOLARIS || defined(__sgi) 110extern KRWLOCK_T ipf_mutex, ipf_auth, ipf_nat; 111extern kmutex_t ipf_rw; 112# endif 113# if SOLARIS 114# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, \ 115 ip, qif) 116# define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip, qif) 117# define ICMP_ERROR(b, ip, t, c, if, dst) \ 118 icmp_error(ip, t, c, if, dst) 119# else /* SOLARIS */ 120# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) 121# ifdef linux 122# define SEND_RESET(ip, qif, if, fin) send_reset(ip, ifp) 123# define ICMP_ERROR(b, ip, t, c, if, dst) icmp_send(b,t,c,0,if) 124# else 125# define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip) 126# define ICMP_ERROR(b, ip, t, c, if, dst) \ 127 send_icmp_err(ip, t, c, if, dst) 128# endif /* linux */ 129# endif /* SOLARIS || __sgi */ 130#endif /* _KERNEL */ 131 132 133struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}}; 134struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } }, 135 *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } }; 136struct frgroup *ipfgroups[3][2]; 137int fr_flags = IPF_LOGGING, fr_active = 0; 138#if defined(IPFILTER_DEFAULT_BLOCK) 139int fr_pass = FR_NOMATCH|FR_BLOCK; 140#else 141int fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH); 142#endif 143char ipfilter_version[] = IPL_VERSION; 144 145fr_info_t frcache[2]; 146 147static int fr_tcpudpchk __P((frentry_t *, fr_info_t *)); 148static int frflushlist __P((int, minor_t, int *, frentry_t **)); 149#ifdef _KERNEL 150static void frsynclist __P((frentry_t *)); 151#endif 152 153 154/* 155 * bit values for identifying presence of individual IP options 156 */ 157struct optlist ipopts[20] = { 158 { IPOPT_NOP, 0x000001 }, 159 { IPOPT_RR, 0x000002 }, 160 { IPOPT_ZSU, 0x000004 }, 161 { IPOPT_MTUP, 0x000008 }, 162 { IPOPT_MTUR, 0x000010 }, 163 { IPOPT_ENCODE, 0x000020 }, 164 { IPOPT_TS, 0x000040 }, 165 { IPOPT_TR, 0x000080 }, 166 { IPOPT_SECURITY, 0x000100 }, 167 { IPOPT_LSRR, 0x000200 }, 168 { IPOPT_E_SEC, 0x000400 }, 169 { IPOPT_CIPSO, 0x000800 }, 170 { IPOPT_SATID, 0x001000 }, 171 { IPOPT_SSRR, 0x002000 }, 172 { IPOPT_ADDEXT, 0x004000 }, 173 { IPOPT_VISA, 0x008000 }, 174 { IPOPT_IMITD, 0x010000 }, 175 { IPOPT_EIP, 0x020000 }, 176 { IPOPT_FINN, 0x040000 }, 177 { 0, 0x000000 } 178}; 179 180/* 181 * bit values for identifying presence of individual IP security options 182 */ 183struct optlist secopt[8] = { 184 { IPSO_CLASS_RES4, 0x01 }, 185 { IPSO_CLASS_TOPS, 0x02 }, 186 { IPSO_CLASS_SECR, 0x04 }, 187 { IPSO_CLASS_RES3, 0x08 }, 188 { IPSO_CLASS_CONF, 0x10 }, 189 { IPSO_CLASS_UNCL, 0x20 }, 190 { IPSO_CLASS_RES2, 0x40 }, 191 { IPSO_CLASS_RES1, 0x80 } 192}; 193 194 195/* 196 * compact the IP header into a structure which contains just the info. 197 * which is useful for comparing IP headers with. 198 */ 199void fr_makefrip(hlen, ip, fin) 200int hlen; 201ip_t *ip; 202fr_info_t *fin; 203{ 204 struct optlist *op; 205 tcphdr_t *tcp; 206 fr_ip_t *fi = &fin->fin_fi; 207 u_short optmsk = 0, secmsk = 0, auth = 0; 208 int i, mv, ol, off; 209 u_char *s, opt; 210 211 fin->fin_rev = 0; 212 fin->fin_fr = NULL; 213 fin->fin_tcpf = 0; 214 fin->fin_data[0] = 0; 215 fin->fin_data[1] = 0; 216 fin->fin_rule = -1; 217 fin->fin_group = -1; 218 fin->fin_id = ip->ip_id; 219#ifdef _KERNEL 220 fin->fin_icode = ipl_unreach; 221#endif 222 fi->fi_v = ip->ip_v; 223 fi->fi_tos = ip->ip_tos; 224 fin->fin_hlen = hlen; 225 fin->fin_dlen = ip->ip_len - hlen; 226 tcp = (tcphdr_t *)((char *)ip + hlen); 227 fin->fin_dp = (void *)tcp; 228 (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); 229 fi->fi_src.s_addr = ip->ip_src.s_addr; 230 fi->fi_dst.s_addr = ip->ip_dst.s_addr; 231 232 fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; 233 off = (ip->ip_off & IP_OFFMASK) << 3; 234 if (ip->ip_off & 0x3fff) 235 fi->fi_fl |= FI_FRAG; 236 switch (ip->ip_p) 237 { 238 case IPPROTO_ICMP : 239 { 240 int minicmpsz = sizeof(struct icmp); 241 icmphdr_t *icmp; 242 243 icmp = (icmphdr_t *)tcp; 244 245 if (!off && (icmp->icmp_type == ICMP_ECHOREPLY || 246 icmp->icmp_type == ICMP_ECHO)) 247 minicmpsz = ICMP_MINLEN; 248 if (!off && (icmp->icmp_type == ICMP_TSTAMP || 249 icmp->icmp_type == ICMP_TSTAMPREPLY)) 250 minicmpsz = 20; /* type(1) + code(1) + cksum(2) + id(2) + seq(2) + 3*timestamp(3*4) */ 251 if (!off && (icmp->icmp_type == ICMP_MASKREQ || 252 icmp->icmp_type == ICMP_MASKREPLY)) 253 minicmpsz = 12; /* type(1) + code(1) + cksum(2) + id(2) + seq(2) + mask(4) */ 254 if ((!(ip->ip_len >= hlen + minicmpsz) && !off) || 255 (off && off < sizeof(struct icmp))) 256 fi->fi_fl |= FI_SHORT; 257 if (fin->fin_dlen > 1) 258 fin->fin_data[0] = *(u_short *)tcp; 259 break; 260 } 261 case IPPROTO_TCP : 262 fi->fi_fl |= FI_TCPUDP; 263 if ((!IPMINLEN(ip, tcphdr) && !off) || 264 (off && off < sizeof(struct tcphdr))) 265 fi->fi_fl |= FI_SHORT; 266 if (!(fi->fi_fl & FI_SHORT) && !off) 267 fin->fin_tcpf = tcp->th_flags; 268 goto getports; 269 case IPPROTO_UDP : 270 fi->fi_fl |= FI_TCPUDP; 271 if ((!IPMINLEN(ip, udphdr) && !off) || 272 (off && off < sizeof(struct udphdr))) 273 fi->fi_fl |= FI_SHORT; 274getports: 275 if (!off && (fin->fin_dlen > 3)) { 276 fin->fin_data[0] = ntohs(tcp->th_sport); 277 fin->fin_data[1] = ntohs(tcp->th_dport); 278 } 279 break; 280 default : 281 break; 282 } 283 284 285 for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen; ) { 286 opt = *s; 287 if (opt == '\0') 288 break; 289 ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1); 290 if (opt > 1 && (ol < 2 || ol > hlen)) 291 break; 292 for (i = 9, mv = 4; mv >= 0; ) { 293 op = ipopts + i; 294 if (opt == (u_char)op->ol_val) { 295 optmsk |= op->ol_bit; 296 if (opt == IPOPT_SECURITY) { 297 struct optlist *sp; 298 u_char sec; 299 int j, m; 300 301 sec = *(s + 2); /* classification */ 302 for (j = 3, m = 2; m >= 0; ) { 303 sp = secopt + j; 304 if (sec == sp->ol_val) { 305 secmsk |= sp->ol_bit; 306 auth = *(s + 3); 307 auth *= 256; 308 auth += *(s + 4); 309 break; 310 } 311 if (sec < sp->ol_val) 312 j -= m--; 313 else 314 j += m--; 315 } 316 } 317 break; 318 } 319 if (opt < op->ol_val) 320 i -= mv--; 321 else 322 i += mv--; 323 } 324 hlen -= ol; 325 s += ol; 326 } 327 if (auth && !(auth & 0x0100)) 328 auth &= 0xff00; 329 fi->fi_optmsk = optmsk; 330 fi->fi_secmsk = secmsk; 331 fi->fi_auth = auth; 332} 333 334 335/* 336 * check an IP packet for TCP/UDP characteristics such as ports and flags. 337 */ 338static int fr_tcpudpchk(fr, fin) 339frentry_t *fr; 340fr_info_t *fin; 341{ 342 register u_short po, tup; 343 register char i; 344 register int err = 1; 345 346 /* 347 * Both ports should *always* be in the first fragment. 348 * So far, I cannot find any cases where they can not be. 349 * 350 * compare destination ports 351 */ 352 if ((i = (int)fr->fr_dcmp)) { 353 po = fr->fr_dport; 354 tup = fin->fin_data[1]; 355 /* 356 * Do opposite test to that required and 357 * continue if that succeeds. 358 */ 359 if (!--i && tup != po) /* EQUAL */ 360 err = 0; 361 else if (!--i && tup == po) /* NOTEQUAL */ 362 err = 0; 363 else if (!--i && tup >= po) /* LESSTHAN */ 364 err = 0; 365 else if (!--i && tup <= po) /* GREATERTHAN */ 366 err = 0; 367 else if (!--i && tup > po) /* LT or EQ */ 368 err = 0; 369 else if (!--i && tup < po) /* GT or EQ */ 370 err = 0; 371 else if (!--i && /* Out of range */ 372 (tup >= po && tup <= fr->fr_dtop)) 373 err = 0; 374 else if (!--i && /* In range */ 375 (tup <= po || tup >= fr->fr_dtop)) 376 err = 0; 377 } 378 /* 379 * compare source ports 380 */ 381 if (err && (i = (int)fr->fr_scmp)) { 382 po = fr->fr_sport; 383 tup = fin->fin_data[0]; 384 if (!--i && tup != po) 385 err = 0; 386 else if (!--i && tup == po) 387 err = 0; 388 else if (!--i && tup >= po) 389 err = 0; 390 else if (!--i && tup <= po) 391 err = 0; 392 else if (!--i && tup > po) 393 err = 0; 394 else if (!--i && tup < po) 395 err = 0; 396 else if (!--i && /* Out of range */ 397 (tup >= po && tup <= fr->fr_stop)) 398 err = 0; 399 else if (!--i && /* In range */ 400 (tup <= po || tup >= fr->fr_stop)) 401 err = 0; 402 } 403 404 /* 405 * If we don't have all the TCP/UDP header, then how can we 406 * expect to do any sort of match on it ? If we were looking for 407 * TCP flags, then NO match. If not, then match (which should 408 * satisfy the "short" class too). 409 */ 410 if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) { 411 if (fin->fin_fi.fi_fl & FI_SHORT) 412 return !(fr->fr_tcpf | fr->fr_tcpfm); 413 /* 414 * Match the flags ? If not, abort this match. 415 */ 416 if (fr->fr_tcpfm && 417 fr->fr_tcpf != (fin->fin_tcpf & fr->fr_tcpfm)) { 418 FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf, 419 fr->fr_tcpfm, fr->fr_tcpf)); 420 err = 0; 421 } 422 } 423 return err; 424} 425 426/* 427 * Check the input/output list of rules for a match and result. 428 * Could be per interface, but this gets real nasty when you don't have 429 * kernel sauce. 430 */ 431int fr_scanlist(pass, ip, fin, m) 432u_32_t pass; 433ip_t *ip; 434register fr_info_t *fin; 435void *m; 436{ 437 register struct frentry *fr; 438 register fr_ip_t *fi = &fin->fin_fi; 439 int rulen, portcmp = 0, off, skip = 0, logged = 0; 440 u_32_t passt; 441 442 fr = fin->fin_fr; 443 fin->fin_fr = NULL; 444 fin->fin_rule = 0; 445 fin->fin_group = 0; 446 off = ip->ip_off & IP_OFFMASK; 447 pass |= (fi->fi_fl << 24); 448 449 if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) 450 portcmp = 1; 451 452 for (rulen = 0; fr; fr = fr->fr_next, rulen++) { 453 if (skip) { 454 skip--; 455 continue; 456 } 457 /* 458 * In all checks below, a null (zero) value in the 459 * filter struture is taken to mean a wildcard. 460 * 461 * check that we are working for the right interface 462 */ 463#ifdef _KERNEL 464# if BSD >= 199306 465 if (fin->fin_out != 0) { 466 if ((fr->fr_oifa && 467 fr->fr_oifa != ((mb_t *)m)->m_pkthdr.rcvif) || 468 (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)) 469 continue; 470 } else 471# endif 472 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 473 continue; 474#else 475 if (opts & (OPT_VERBOSE|OPT_DEBUG)) 476 printf("\n"); 477 FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : 478 (pass & FR_AUTH) ? 'a' : 'b')); 479 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 480 continue; 481 FR_VERBOSE((":i")); 482#endif 483 { 484 register u_32_t *ld, *lm, *lip; 485 register int i; 486 487 lip = (u_32_t *)fi; 488 lm = (u_32_t *)&fr->fr_mip; 489 ld = (u_32_t *)&fr->fr_ip; 490 i = ((lip[0] & lm[0]) != ld[0]); 491 FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n", 492 lip[0], lm[0], ld[0])); 493 i |= ((lip[1] & lm[1]) != ld[1]) << 19; 494 i ^= (fr->fr_flags & FR_NOTSRCIP); 495 FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n", 496 lip[1], lm[1], ld[1])); 497 i |= ((lip[2] & lm[2]) != ld[2]) << 20; 498 i ^= (fr->fr_flags & FR_NOTDSTIP); 499 FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n", 500 lip[2], lm[2], ld[2])); 501 i |= ((lip[3] & lm[3]) != ld[3]); 502 FR_IFDEBUG(i,continue,("3. %#08x & %#08x != %#08x\n", 503 lip[3], lm[3], ld[3])); 504 i |= ((lip[4] & lm[4]) != ld[4]); 505 FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n", 506 lip[4], lm[4], ld[4])); 507 if (i) 508 continue; 509 } 510 511 /* 512 * If a fragment, then only the first has what we're looking 513 * for here... 514 */ 515 if (!portcmp && (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf || 516 fr->fr_tcpfm)) 517 continue; 518 if (fi->fi_fl & FI_TCPUDP) { 519 if (!fr_tcpudpchk(fr, fin)) 520 continue; 521 } else if (fr->fr_icmpm || fr->fr_icmp) { 522 if ((fi->fi_p != IPPROTO_ICMP) || off || 523 (fin->fin_dlen < 2)) 524 continue; 525 if ((fin->fin_data[0] & fr->fr_icmpm) != fr->fr_icmp) { 526 FR_DEBUG(("i. %#x & %#x != %#x\n", 527 fin->fin_data[0], fr->fr_icmpm, 528 fr->fr_icmp)); 529 continue; 530 } 531 } 532 FR_VERBOSE(("*")); 533 /* 534 * Just log this packet... 535 */ 536 passt = fr->fr_flags; 537 if ((passt & FR_CALLNOW) && fr->fr_func) 538 passt = (*fr->fr_func)(passt, ip, fin); 539 fin->fin_fr = fr; 540#ifdef IPFILTER_LOG 541 if ((passt & FR_LOGMASK) == FR_LOG) { 542 if (!IPLLOG(passt, ip, fin, m)) { 543 ATOMIC_INC(frstats[fin->fin_out].fr_skip); 544 } 545 ATOMIC_INC(frstats[fin->fin_out].fr_pkl); 546 logged = 1; 547 } 548#endif /* IPFILTER_LOG */ 549 if (!(skip = fr->fr_skip) && (passt & FR_LOGMASK) != FR_LOG) 550 pass = passt; 551 FR_DEBUG(("pass %#x\n", pass)); 552 ATOMIC_INC(fr->fr_hits); 553 if (pass & FR_ACCOUNT) 554 fr->fr_bytes += (U_QUAD_T)ip->ip_len; 555 else 556 fin->fin_icode = fr->fr_icode; 557 fin->fin_rule = rulen; 558 fin->fin_group = fr->fr_group; 559 if (fr->fr_grp) { 560 fin->fin_fr = fr->fr_grp; 561 pass = fr_scanlist(pass, ip, fin, m); 562 if (fin->fin_fr == NULL) { 563 fin->fin_rule = rulen; 564 fin->fin_group = fr->fr_group; 565 fin->fin_fr = fr; 566 } 567 if (pass & FR_DONTCACHE) 568 logged = 1; 569 } 570 if (pass & FR_QUICK) 571 break; 572 } 573 if (logged) 574 pass |= FR_DONTCACHE; 575 return pass; 576} 577 578 579/* 580 * frcheck - filter check 581 * check using source and destination addresses/ports in a packet whether 582 * or not to pass it on or not. 583 */ 584int fr_check(ip, hlen, ifp, out 585#if defined(_KERNEL) && SOLARIS 586, qif, mp) 587qif_t *qif; 588#else 589, mp) 590#endif 591mb_t **mp; 592ip_t *ip; 593int hlen; 594void *ifp; 595int out; 596{ 597 /* 598 * The above really sucks, but short of writing a diff 599 */ 600 fr_info_t frinfo, *fc; 601 register fr_info_t *fin = &frinfo; 602 frentry_t *fr = NULL; 603 int changed, error = EHOSTUNREACH; 604 u_32_t pass, apass; 605#if !SOLARIS || !defined(_KERNEL) 606 register mb_t *m = *mp; 607#endif 608 609#ifdef _KERNEL 610 mb_t *mc = NULL; 611# if !defined(__SVR4) && !defined(__svr4__) 612# ifdef __sgi 613 char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8]; 614# endif 615 int up; 616 617# ifdef M_CANFASTFWD 618 /* 619 * XXX For now, IP Filter and fast-forwarding of cached flows 620 * XXX are mutually exclusive. Eventually, IP Filter should 621 * XXX get a "can-fast-forward" filter rule. 622 */ 623 m->m_flags &= ~M_CANFASTFWD; 624# endif /* M_CANFASTFWD */ 625 626 if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP || 627 ip->ip_p == IPPROTO_ICMP)) { 628 int plen = 0; 629 630 if ((ip->ip_off & IP_OFFMASK) == 0) 631 switch(ip->ip_p) 632 { 633 case IPPROTO_TCP: 634 plen = sizeof(tcphdr_t); 635 break; 636 case IPPROTO_UDP: 637 plen = sizeof(udphdr_t); 638 break; 639 /* 96 - enough for complete ICMP error IP header */ 640 case IPPROTO_ICMP: 641 plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); 642 break; 643 } 644 up = MIN(hlen + plen, ip->ip_len); 645 646 if (up > m->m_len) { 647# ifdef __sgi 648 /* Under IRIX, avoid m_pullup as it makes ping <hostname> panic */ 649 if ((up > sizeof(hbuf)) || (m_length(m) < up)) { 650 ATOMIC_INC(frstats[out].fr_pull[1]); 651 return -1; 652 } 653 m_copydata(m, 0, up, hbuf); 654 ATOMIC_INC(frstats[out].fr_pull[0]); 655 ip = (ip_t *)hbuf; 656# else /* __ sgi */ 657# ifndef linux 658 if ((*mp = m_pullup(m, up)) == 0) { 659 ATOMIC_INC(frstats[out].fr_pull[1]); 660 return -1; 661 } else { 662 ATOMIC_INC(frstats[out].fr_pull[0]); 663 m = *mp; 664 ip = mtod(m, ip_t *); 665 } 666# endif /* !linux */ 667# endif /* __sgi */ 668 } else 669 up = 0; 670 } else 671 up = 0; 672# endif /* !defined(__SVR4) && !defined(__svr4__) */ 673# if SOLARIS 674 mb_t *m = qif->qf_m; 675 676 if ((u_int)ip & 0x3) 677 return 2; 678 fin->fin_qfm = m; 679 fin->fin_qif = qif; 680# endif 681#endif /* _KERNEL */ 682 683 /* 684 * Be careful here: ip_id is in network byte order when called 685 * from ip_output() 686 */ 687 if (out) 688 ip->ip_id = ntohs(ip->ip_id); 689 fr_makefrip(hlen, ip, fin); 690 fin->fin_ifp = ifp; 691 fin->fin_out = out; 692 fin->fin_mp = mp; 693 pass = fr_pass; 694 695 READ_ENTER(&ipf_mutex); 696 697 if (fin->fin_fi.fi_fl & FI_SHORT) 698 ATOMIC_INC(frstats[out].fr_short); 699 700 /* 701 * Check auth now. This, combined with the check below to see if apass 702 * is 0 is to ensure that we don't count the packet twice, which can 703 * otherwise occur when we reprocess it. As it is, we only count it 704 * after it has no auth. table matchup. This also stops NAT from 705 * occuring until after the packet has been auth'd. 706 */ 707 apass = fr_checkauth(ip, fin); 708 709 if (!out) { 710 changed = ip_natin(ip, fin); 711 if (!apass && (fin->fin_fr = ipacct[0][fr_active]) && 712 (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { 713 ATOMIC_INC(frstats[0].fr_acct); 714 } 715 } 716 717 if (apass || (!(fr = ipfr_knownfrag(ip, fin)) && 718 !(fr = fr_checkstate(ip, fin)))) { 719 /* 720 * If a packet is found in the auth table, then skip checking 721 * the access lists for permission but we do need to consider 722 * the result as if it were from the ACL's. 723 */ 724 if (!apass) { 725 fc = frcache + out; 726 if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) { 727 /* 728 * copy cached data so we can unlock the mutex 729 * earlier. 730 */ 731 bcopy((char *)fc, (char *)fin, FI_COPYSIZE); 732 ATOMIC_INC(frstats[out].fr_chit); 733 if ((fr = fin->fin_fr)) { 734 ATOMIC_INC(fr->fr_hits); 735 pass = fr->fr_flags; 736 } 737 } else { 738 if ((fin->fin_fr = ipfilter[out][fr_active])) 739 pass = fr_scanlist(fr_pass, ip, fin, m); 740 if (!(pass & (FR_KEEPSTATE|FR_DONTCACHE))) 741 bcopy((char *)fin, (char *)fc, 742 FI_COPYSIZE); 743 if (pass & FR_NOMATCH) { 744 ATOMIC_INC(frstats[out].fr_nom); 745 } 746 } 747 fr = fin->fin_fr; 748 } else 749 pass = apass; 750 751 /* 752 * If we fail to add a packet to the authorization queue, 753 * then we drop the packet later. However, if it was added 754 * then pretend we've dropped it already. 755 */ 756 if ((pass & FR_AUTH)) 757 if (FR_NEWAUTH(m, fin, ip, qif) != 0) 758#ifdef _KERNEL 759 m = *mp = NULL; 760#else 761 ; 762#endif 763 764 if (pass & FR_PREAUTH) { 765 READ_ENTER(&ipf_auth); 766 if ((fin->fin_fr = ipauth) && 767 (pass = fr_scanlist(0, ip, fin, m))) { 768 ATOMIC_INC(fr_authstats.fas_hits); 769 } else { 770 ATOMIC_INC(fr_authstats.fas_miss); 771 } 772 RWLOCK_EXIT(&ipf_auth); 773 } 774 775 fin->fin_fr = fr; 776 if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { 777 if (fin->fin_fi.fi_fl & FI_FRAG) { 778 if (ipfr_newfrag(ip, fin, pass) == -1) { 779 ATOMIC_INC(frstats[out].fr_bnfr); 780 } else { 781 ATOMIC_INC(frstats[out].fr_nfr); 782 } 783 } else { 784 ATOMIC_INC(frstats[out].fr_cfr); 785 } 786 } 787 if (pass & FR_KEEPSTATE) { 788 if (fr_addstate(ip, fin, 0) == NULL) { 789 ATOMIC_INC(frstats[out].fr_bads); 790 } else { 791 ATOMIC_INC(frstats[out].fr_ads); 792 } 793 } 794 } else if (fr != NULL) { 795 pass = fr->fr_flags; 796 if (pass & FR_LOGFIRST) 797 pass &= ~(FR_LOGFIRST|FR_LOG); 798 } 799 800 if (fr && fr->fr_func && !(pass & FR_CALLNOW)) 801 pass = (*fr->fr_func)(pass, ip, fin); 802 803 /* 804 * Only count/translate packets which will be passed on, out the 805 * interface. 806 */ 807 if (out && (pass & FR_PASS)) { 808 if ((fin->fin_fr = ipacct[1][fr_active]) && 809 (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { 810 ATOMIC_INC(frstats[1].fr_acct); 811 } 812 fin->fin_fr = fr; 813 changed = ip_natout(ip, fin); 814 } else 815 fin->fin_fr = fr; 816 RWLOCK_EXIT(&ipf_mutex); 817 818#ifdef IPFILTER_LOG 819 if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { 820 if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { 821 pass |= FF_LOGNOMATCH; 822 ATOMIC_INC(frstats[out].fr_npkl); 823 goto logit; 824 } else if (((pass & FR_LOGMASK) == FR_LOGP) || 825 ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) { 826 if ((pass & FR_LOGMASK) != FR_LOGP) 827 pass |= FF_LOGPASS; 828 ATOMIC_INC(frstats[out].fr_ppkl); 829 goto logit; 830 } else if (((pass & FR_LOGMASK) == FR_LOGB) || 831 ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) { 832 if ((pass & FR_LOGMASK) != FR_LOGB) 833 pass |= FF_LOGBLOCK; 834 ATOMIC_INC(frstats[out].fr_bpkl); 835logit: 836 if (!IPLLOG(pass, ip, fin, m)) { 837 ATOMIC_INC(frstats[out].fr_skip); 838 if ((pass & (FR_PASS|FR_LOGORBLOCK)) == 839 (FR_PASS|FR_LOGORBLOCK)) 840 pass ^= FR_PASS|FR_BLOCK; 841 } 842 } 843 } 844#endif /* IPFILTER_LOG */ 845 846 if (out) 847 ip->ip_id = htons(ip->ip_id); 848 849#ifdef _KERNEL 850 /* 851 * Only allow FR_DUP to work if a rule matched - it makes no sense to 852 * set FR_DUP as a "default" as there are no instructions about where 853 * to send the packet. 854 */ 855 if (fr && (pass & FR_DUP)) 856# if SOLARIS 857 mc = dupmsg(m); 858# else 859# ifndef linux 860 mc = m_copy(m, 0, M_COPYALL); 861# else 862 ; 863# endif 864# endif 865#endif 866 if (pass & FR_PASS) { 867 ATOMIC_INC(frstats[out].fr_pass); 868 } else if (pass & FR_BLOCK) { 869 ATOMIC_INC(frstats[out].fr_block); 870 /* 871 * Should we return an ICMP packet to indicate error 872 * status passing through the packet filter ? 873 * WARNING: ICMP error packets AND TCP RST packets should 874 * ONLY be sent in repsonse to incoming packets. Sending them 875 * in response to outbound packets can result in a panic on 876 * some operating systems. 877 */ 878 if (!out) { 879#ifdef _KERNEL 880 if (pass & FR_RETICMP) { 881 struct in_addr dst; 882 883 if ((pass & FR_RETMASK) == FR_FAKEICMP) 884 dst = ip->ip_dst; 885 else 886 dst.s_addr = 0; 887# if SOLARIS 888 ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode, 889 qif, dst); 890# else 891 ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode, 892 ifp, dst); 893# endif 894 ATOMIC_INC(frstats[0].fr_ret); 895 } else if (((pass & FR_RETMASK) == FR_RETRST) && 896 !(fin->fin_fi.fi_fl & FI_SHORT)) { 897 if (SEND_RESET(ip, qif, ifp, fin) == 0) { 898 ATOMIC_INC(frstats[1].fr_ret); 899 } 900 } 901#else 902 if ((pass & FR_RETMASK) == FR_RETICMP) { 903 verbose("- ICMP unreachable sent\n"); 904 ATOMIC_INC(frstats[0].fr_ret); 905 } else if ((pass & FR_RETMASK) == FR_FAKEICMP) { 906 verbose("- forged ICMP unreachable sent\n"); 907 ATOMIC_INC(frstats[0].fr_ret); 908 } else if (((pass & FR_RETMASK) == FR_RETRST) && 909 !(fin->fin_fi.fi_fl & FI_SHORT)) { 910 verbose("- TCP RST sent\n"); 911 ATOMIC_INC(frstats[1].fr_ret); 912 } 913#endif 914 } else { 915 if (pass & FR_RETRST) 916 error = ECONNRESET; 917 } 918 } 919 920 /* 921 * If we didn't drop off the bottom of the list of rules (and thus 922 * the 'current' rule fr is not NULL), then we may have some extra 923 * instructions about what to do with a packet. 924 * Once we're finished return to our caller, freeing the packet if 925 * we are dropping it (* BSD ONLY *). 926 */ 927#if defined(_KERNEL) 928# if !SOLARIS 929# if !defined(linux) 930 if (fr) { 931 frdest_t *fdp = &fr->fr_tif; 932 933 if (((pass & FR_FASTROUTE) && !out) || 934 (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { 935 if (ipfr_fastroute(m, fin, fdp) == 0) 936 m = *mp = NULL; 937 } 938 if (mc) 939 ipfr_fastroute(mc, fin, &fr->fr_dif); 940 } 941 if (!(pass & FR_PASS) && m) 942 m_freem(m); 943# ifdef __sgi 944 else if (changed && up && m) 945 m_copyback(m, 0, up, hbuf); 946# endif 947# endif /* !linux */ 948# else /* !SOLARIS */ 949 if (fr) { 950 frdest_t *fdp = &fr->fr_tif; 951 952 if (((pass & FR_FASTROUTE) && !out) || 953 (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { 954 if (ipfr_fastroute(qif, ip, m, mp, fin, fdp) == 0) 955 m = *mp = NULL; 956 } 957 if (mc) 958 ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif); 959 } 960# endif /* !SOLARIS */ 961 return (pass & FR_PASS) ? 0 : error; 962#else /* _KERNEL */ 963 if (pass & FR_NOMATCH) 964 return 1; 965 if (pass & FR_PASS) 966 return 0; 967 if (pass & FR_AUTH) 968 return -2; 969 return -1; 970#endif /* _KERNEL */ 971} 972 973 974/* 975 * ipf_cksum 976 * addr should be 16bit aligned and len is in bytes. 977 * length is in bytes 978 */ 979u_short ipf_cksum(addr, len) 980register u_short *addr; 981register int len; 982{ 983 register u_32_t sum = 0; 984 985 for (sum = 0; len > 1; len -= 2) 986 sum += *addr++; 987 988 /* mop up an odd byte, if necessary */ 989 if (len == 1) 990 sum += *(u_char *)addr; 991 992 /* 993 * add back carry outs from top 16 bits to low 16 bits 994 */ 995 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 996 sum += (sum >> 16); /* add carry */ 997 return (u_short)(~sum); 998} 999 1000 1001/* 1002 * NB: This function assumes we've pullup'd enough for all of the IP header 1003 * and the TCP header. We also assume that data blocks aren't allocated in 1004 * odd sizes. 1005 */ 1006u_short fr_tcpsum(m, ip, tcp) 1007mb_t *m; 1008ip_t *ip; 1009tcphdr_t *tcp; 1010{ 1011 u_short *sp, slen, ts; 1012 u_int sum, sum2; 1013 int hlen; 1014 1015 /* 1016 * Add up IP Header portion 1017 */ 1018 hlen = ip->ip_hl << 2; 1019 slen = ip->ip_len - hlen; 1020 sum = htons((u_short)ip->ip_p); 1021 sum += htons(slen); 1022 sp = (u_short *)&ip->ip_src; 1023 sum += *sp++; /* ip_src */ 1024 sum += *sp++; 1025 sum += *sp++; /* ip_dst */ 1026 sum += *sp++; 1027 ts = tcp->th_sum; 1028 tcp->th_sum = 0; 1029#ifdef KERNEL 1030# if SOLARIS 1031 sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */ 1032 sum2 = (sum2 & 0xffff) + (sum2 >> 16); 1033 sum2 = ~sum2 & 0xffff; 1034# else /* SOLARIS */ 1035# if defined(BSD) || defined(sun) 1036# if BSD >= 199306 1037 m->m_data += hlen; 1038# else 1039 m->m_off += hlen; 1040# endif 1041 m->m_len -= hlen; 1042 sum2 = in_cksum(m, slen); 1043 m->m_len += hlen; 1044# if BSD >= 199306 1045 m->m_data -= hlen; 1046# else 1047 m->m_off -= hlen; 1048# endif 1049 /* 1050 * Both sum and sum2 are partial sums, so combine them together. 1051 */ 1052 sum = (sum & 0xffff) + (sum >> 16); 1053 sum = ~sum & 0xffff; 1054 sum2 += sum; 1055 sum2 = (sum2 & 0xffff) + (sum2 >> 16); 1056# else /* defined(BSD) || defined(sun) */ 1057{ 1058 union { 1059 u_char c[2]; 1060 u_short s; 1061 } bytes; 1062 u_short len = ip->ip_len; 1063# if defined(__sgi) 1064 int add; 1065# endif 1066 1067 /* 1068 * Add up IP Header portion 1069 */ 1070 sp = (u_short *)&ip->ip_src; 1071 len -= (ip->ip_hl << 2); 1072 sum = ntohs(IPPROTO_TCP); 1073 sum += htons(len); 1074 sum += *sp++; /* ip_src */ 1075 sum += *sp++; 1076 sum += *sp++; /* ip_dst */ 1077 sum += *sp++; 1078 if (sp != (u_short *)tcp) 1079 sp = (u_short *)tcp; 1080 sum += *sp++; /* sport */ 1081 sum += *sp++; /* dport */ 1082 sum += *sp++; /* seq */ 1083 sum += *sp++; 1084 sum += *sp++; /* ack */ 1085 sum += *sp++; 1086 sum += *sp++; /* off */ 1087 sum += *sp++; /* win */ 1088 sum += *sp++; /* Skip over checksum */ 1089 sum += *sp++; /* urp */ 1090 1091# ifdef __sgi 1092 /* 1093 * In case we had to copy the IP & TCP header out of mbufs, 1094 * skip over the mbuf bits which are the header 1095 */ 1096 if ((caddr_t)ip != mtod(m, caddr_t)) { 1097 hlen = (caddr_t)sp - (caddr_t)ip; 1098 while (hlen) { 1099 add = MIN(hlen, m->m_len); 1100 sp = (u_short *)(mtod(m, caddr_t) + add); 1101 hlen -= add; 1102 if (add == m->m_len) { 1103 m = m->m_next; 1104 if (!hlen) { 1105 if (!m) 1106 break; 1107 sp = mtod(m, u_short *); 1108 } 1109 PANIC((!m),("fr_tcpsum(1): not enough data")); 1110 } 1111 } 1112 } 1113# endif 1114 1115 if (!(len -= sizeof(*tcp))) 1116 goto nodata; 1117 while (len > 1) { 1118 if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) { 1119 m = m->m_next; 1120 PANIC((!m),("fr_tcpsum(2): not enough data")); 1121 sp = mtod(m, u_short *); 1122 } 1123 if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) { 1124 bytes.c[0] = *(u_char *)sp; 1125 m = m->m_next; 1126 PANIC((!m),("fr_tcpsum(3): not enough data")); 1127 sp = mtod(m, u_short *); 1128 bytes.c[1] = *(u_char *)sp; 1129 sum += bytes.s; 1130 sp = (u_short *)((u_char *)sp + 1); 1131 } 1132 if ((u_long)sp & 1) { 1133 bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s)); 1134 sum += bytes.s; 1135 } else 1136 sum += *sp++; 1137 len -= 2; 1138 } 1139 if (len) 1140 sum += ntohs(*(u_char *)sp << 8); 1141nodata: 1142 while (sum > 0xffff) 1143 sum = (sum & 0xffff) + (sum >> 16); 1144 sum2 = (u_short)(~sum & 0xffff); 1145} 1146# endif /* defined(BSD) || defined(sun) */ 1147# endif /* SOLARIS */ 1148#else /* KERNEL */ 1149 sum2 = 0; 1150#endif /* KERNEL */ 1151 tcp->th_sum = ts; 1152 return sum2; 1153} 1154 1155 1156#if defined(_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || defined(__sgi) ) 1157/* 1158 * Copyright (c) 1982, 1986, 1988, 1991, 1993 1159 * The Regents of the University of California. All rights reserved. 1160 * 1161 * Redistribution and use in source and binary forms, with or without 1162 * modification, are permitted provided that the following conditions 1163 * are met: 1164 * 1. Redistributions of source code must retain the above copyright 1165 * notice, this list of conditions and the following disclaimer. 1166 * 2. Redistributions in binary form must reproduce the above copyright 1167 * notice, this list of conditions and the following disclaimer in the 1168 * documentation and/or other materials provided with the distribution. 1169 * 3. All advertising materials mentioning features or use of this software 1170 * must display the following acknowledgement: 1171 * This product includes software developed by the University of 1172 * California, Berkeley and its contributors. 1173 * 4. Neither the name of the University nor the names of its contributors 1174 * may be used to endorse or promote products derived from this software 1175 * without specific prior written permission. 1176 * 1177 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1178 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1179 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1180 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1181 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1182 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1183 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1184 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1185 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1186 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1187 * SUCH DAMAGE. 1188 * 1189 * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 1190 * $Id: fil.c,v 2.3.2.16 2000/01/27 08:49:37 darrenr Exp $ 1191 */ 1192/* 1193 * Copy data from an mbuf chain starting "off" bytes from the beginning, 1194 * continuing for "len" bytes, into the indicated buffer. 1195 */ 1196void 1197m_copydata(m, off, len, cp) 1198 register mb_t *m; 1199 register int off; 1200 register int len; 1201 caddr_t cp; 1202{ 1203 register unsigned count; 1204 1205 if (off < 0 || len < 0) 1206 panic("m_copydata"); 1207 while (off > 0) { 1208 if (m == 0) 1209 panic("m_copydata"); 1210 if (off < m->m_len) 1211 break; 1212 off -= m->m_len; 1213 m = m->m_next; 1214 } 1215 while (len > 0) { 1216 if (m == 0) 1217 panic("m_copydata"); 1218 count = MIN(m->m_len - off, len); 1219 bcopy(mtod(m, caddr_t) + off, cp, count); 1220 len -= count; 1221 cp += count; 1222 off = 0; 1223 m = m->m_next; 1224 } 1225} 1226 1227 1228# ifndef linux 1229/* 1230 * Copy data from a buffer back into the indicated mbuf chain, 1231 * starting "off" bytes from the beginning, extending the mbuf 1232 * chain if necessary. 1233 */ 1234void 1235m_copyback(m0, off, len, cp) 1236 struct mbuf *m0; 1237 register int off; 1238 register int len; 1239 caddr_t cp; 1240{ 1241 register int mlen; 1242 register struct mbuf *m = m0, *n; 1243 int totlen = 0; 1244 1245 if (m0 == 0) 1246 return; 1247 while (off > (mlen = m->m_len)) { 1248 off -= mlen; 1249 totlen += mlen; 1250 if (m->m_next == 0) { 1251 n = m_getclr(M_DONTWAIT, m->m_type); 1252 if (n == 0) 1253 goto out; 1254 n->m_len = min(MLEN, len + off); 1255 m->m_next = n; 1256 } 1257 m = m->m_next; 1258 } 1259 while (len > 0) { 1260 mlen = min (m->m_len - off, len); 1261 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 1262 cp += mlen; 1263 len -= mlen; 1264 mlen += off; 1265 off = 0; 1266 totlen += mlen; 1267 if (len == 0) 1268 break; 1269 if (m->m_next == 0) { 1270 n = m_get(M_DONTWAIT, m->m_type); 1271 if (n == 0) 1272 break; 1273 n->m_len = min(MLEN, len); 1274 m->m_next = n; 1275 } 1276 m = m->m_next; 1277 } 1278out: 1279#if 0 1280 if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 1281 m->m_pkthdr.len = totlen; 1282#endif 1283 return; 1284} 1285# endif /* linux */ 1286#endif /* (_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || __sgi) */ 1287 1288 1289frgroup_t *fr_findgroup(num, flags, which, set, fgpp) 1290u_int num; 1291u_32_t flags; 1292minor_t which; 1293int set; 1294frgroup_t ***fgpp; 1295{ 1296 frgroup_t *fg, **fgp; 1297 1298 if (which == IPL_LOGAUTH) 1299 fgp = &ipfgroups[2][set]; 1300 else if (flags & FR_ACCOUNT) 1301 fgp = &ipfgroups[1][set]; 1302 else if (flags & (FR_OUTQUE|FR_INQUE)) 1303 fgp = &ipfgroups[0][set]; 1304 else 1305 return NULL; 1306 num &= 0xffff; 1307 1308 while ((fg = *fgp)) 1309 if (fg->fg_num == num) 1310 break; 1311 else 1312 fgp = &fg->fg_next; 1313 if (fgpp) 1314 *fgpp = fgp; 1315 return fg; 1316} 1317 1318 1319frgroup_t *fr_addgroup(num, fp, which, set) 1320u_int num; 1321frentry_t *fp; 1322minor_t which; 1323int set; 1324{ 1325 frgroup_t *fg, **fgp; 1326 1327 if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp))) 1328 return fg; 1329 1330 KMALLOC(fg, frgroup_t *); 1331 if (fg) { 1332 fg->fg_num = num & 0xffff; 1333 fg->fg_next = *fgp; 1334 fg->fg_head = fp; 1335 fg->fg_start = &fp->fr_grp; 1336 *fgp = fg; 1337 } 1338 return fg; 1339} 1340 1341 1342void fr_delgroup(num, flags, which, set) 1343u_int num; 1344u_32_t flags; 1345minor_t which; 1346int set; 1347{ 1348 frgroup_t *fg, **fgp; 1349 1350 if (!(fg = fr_findgroup(num, flags, which, set, &fgp))) 1351 return; 1352 1353 *fgp = fg->fg_next; 1354 KFREE(fg); 1355} 1356 1357 1358 1359/* 1360 * recursively flush rules from the list, descending groups as they are 1361 * encountered. if a rule is the head of a group and it has lost all its 1362 * group members, then also delete the group reference. 1363 */ 1364static int frflushlist(set, unit, nfreedp, listp) 1365int set; 1366minor_t unit; 1367int *nfreedp; 1368frentry_t **listp; 1369{ 1370 register int freed = 0, i; 1371 register frentry_t *fp; 1372 1373 while ((fp = *listp)) { 1374 *listp = fp->fr_next; 1375 if (fp->fr_grp) { 1376 i = frflushlist(set, unit, nfreedp, &fp->fr_grp); 1377 MUTEX_ENTER(&ipf_rw); 1378 fp->fr_ref -= i; 1379 MUTEX_EXIT(&ipf_rw); 1380 } 1381 1382 ATOMIC_DEC(fp->fr_ref); 1383 if (fp->fr_grhead) { 1384 fr_delgroup((u_int)fp->fr_grhead, fp->fr_flags, 1385 unit, set); 1386 fp->fr_grhead = NULL; 1387 } 1388 if (fp->fr_ref == 0) { 1389 KFREE(fp); 1390 freed++; 1391 } else 1392 fp->fr_next = NULL; 1393 } 1394 *nfreedp += freed; 1395 return freed; 1396} 1397 1398 1399int frflush(unit, flags) 1400minor_t unit; 1401int flags; 1402{ 1403 int flushed = 0, set; 1404 1405 if (unit != IPL_LOGIPF) 1406 return 0; 1407 WRITE_ENTER(&ipf_mutex); 1408 bzero((char *)frcache, sizeof(frcache[0]) * 2); 1409 1410 set = fr_active; 1411 if (flags & FR_INACTIVE) 1412 set = 1 - set; 1413 1414 if (flags & FR_OUTQUE) { 1415 (void) frflushlist(set, unit, &flushed, &ipfilter[1][set]); 1416 (void) frflushlist(set, unit, &flushed, &ipacct[1][set]); 1417 } 1418 if (flags & FR_INQUE) { 1419 (void) frflushlist(set, unit, &flushed, &ipfilter[0][set]); 1420 (void) frflushlist(set, unit, &flushed, &ipacct[0][set]); 1421 } 1422 RWLOCK_EXIT(&ipf_mutex); 1423 return flushed; 1424} 1425 1426 1427char *memstr(src, dst, slen, dlen) 1428char *src, *dst; 1429int slen, dlen; 1430{ 1431 char *s = NULL; 1432 1433 while (dlen >= slen) { 1434 if (bcmp(src, dst, slen) == 0) { 1435 s = dst; 1436 break; 1437 } 1438 dst++; 1439 dlen--; 1440 } 1441 return s; 1442} 1443 1444 1445void fixskip(listp, rp, addremove) 1446frentry_t **listp, *rp; 1447int addremove; 1448{ 1449 frentry_t *fp; 1450 int rules = 0, rn = 0; 1451 1452 for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rules++) 1453 ; 1454 1455 if (!fp) 1456 return; 1457 1458 for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) 1459 if (fp->fr_skip && (rn + fp->fr_skip >= rules)) 1460 fp->fr_skip += addremove; 1461} 1462 1463 1464#ifdef _KERNEL 1465/* 1466 * count consecutive 1's in bit mask. If the mask generated by counting 1467 * consecutive 1's is different to that passed, return -1, else return # 1468 * of bits. 1469 */ 1470int countbits(ip) 1471u_32_t ip; 1472{ 1473 u_32_t ipn; 1474 int cnt = 0, i, j; 1475 1476 ip = ipn = ntohl(ip); 1477 for (i = 32; i; i--, ipn *= 2) 1478 if (ipn & 0x80000000) 1479 cnt++; 1480 else 1481 break; 1482 ipn = 0; 1483 for (i = 32, j = cnt; i; i--, j--) { 1484 ipn *= 2; 1485 if (j > 0) 1486 ipn++; 1487 } 1488 if (ipn == ip) 1489 return cnt; 1490 return -1; 1491} 1492 1493 1494/* 1495 * return the first IP Address associated with an interface 1496 */ 1497int fr_ifpaddr(ifptr, inp) 1498void *ifptr; 1499struct in_addr *inp; 1500{ 1501# if SOLARIS 1502 ill_t *ill = ifptr; 1503# else 1504 struct ifnet *ifp = ifptr; 1505# endif 1506 struct in_addr in; 1507 1508# if SOLARIS 1509 in.s_addr = ill->ill_ipif->ipif_local_addr; 1510# else /* SOLARIS */ 1511# if linux 1512 ; 1513# else /* linux */ 1514 struct ifaddr *ifa; 1515 struct sockaddr_in *sin; 1516 1517# if (__FreeBSD_version >= 300000) 1518 ifa = TAILQ_FIRST(&ifp->if_addrhead); 1519# else 1520# if defined(__NetBSD__) || defined(__OpenBSD__) 1521 ifa = ifp->if_addrlist.tqh_first; 1522# else 1523# if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ 1524 ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa; 1525# else 1526 ifa = ifp->if_addrlist; 1527# endif 1528# endif /* __NetBSD__ || __OpenBSD__ */ 1529# endif /* __FreeBSD_version >= 300000 */ 1530# if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK)) 1531 sin = (struct sockaddr_in *)&ifa->ifa_addr; 1532# else 1533 sin = (struct sockaddr_in *)ifa->ifa_addr; 1534 while (sin && ifa && 1535 sin->sin_family != AF_INET) { 1536# if (__FreeBSD_version >= 300000) 1537 ifa = TAILQ_NEXT(ifa, ifa_link); 1538# else 1539# if defined(__NetBSD__) || defined(__OpenBSD__) 1540 ifa = ifa->ifa_list.tqe_next; 1541# else 1542 ifa = ifa->ifa_next; 1543# endif 1544# endif /* __FreeBSD_version >= 300000 */ 1545 if (ifa) 1546 sin = (struct sockaddr_in *)ifa->ifa_addr; 1547 } 1548 if (ifa == NULL) 1549 sin = NULL; 1550 if (sin == NULL) 1551 return -1; 1552# endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */ 1553 in = sin->sin_addr; 1554# endif /* linux */ 1555# endif /* SOLARIS */ 1556 *inp = in; 1557 return 0; 1558} 1559 1560 1561static void frsynclist(fr) 1562register frentry_t *fr; 1563{ 1564 for (; fr; fr = fr->fr_next) { 1565 if (fr->fr_ifa != NULL) { 1566 fr->fr_ifa = GETUNIT(fr->fr_ifname); 1567 if (fr->fr_ifa == NULL) 1568 fr->fr_ifa = (void *)-1; 1569 } 1570 if (fr->fr_grp) 1571 frsynclist(fr->fr_grp); 1572 } 1573} 1574 1575 1576void frsync() 1577{ 1578 register struct ifnet *ifp; 1579 1580# if !SOLARIS 1581# if defined(__OpenBSD__) || ((NetBSD >= 199511) && (NetBSD < 1991011)) || \ 1582 (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)) 1583# if (NetBSD >= 199905) || defined(__OpenBSD__) 1584 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) 1585# else 1586 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) 1587# endif 1588# else 1589 for (ifp = ifnet; ifp; ifp = ifp->if_next) 1590# endif 1591 { 1592 ip_natsync(ifp); 1593 ip_statesync(ifp); 1594 } 1595# endif 1596 1597 WRITE_ENTER(&ipf_mutex); 1598 frsynclist(ipacct[0][fr_active]); 1599 frsynclist(ipacct[1][fr_active]); 1600 frsynclist(ipfilter[0][fr_active]); 1601 frsynclist(ipfilter[1][fr_active]); 1602 RWLOCK_EXIT(&ipf_mutex); 1603} 1604 1605#else 1606 1607 1608/* 1609 * return the first IP Address associated with an interface 1610 */ 1611int fr_ifpaddr(ifptr, inp) 1612void *ifptr; 1613struct in_addr *inp; 1614{ 1615 return 0; 1616} 1617#endif 1618