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