17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * Copyright (C) 1993-2003 by Darren Reed. 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * See the IPFILTER.LICENCE file for details on licencing. 5ab25eeb5Syz * 6*bd5ba10fSan * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 77c478bd9Sstevel@tonic-gate * Use is subject to license terms. 87c478bd9Sstevel@tonic-gate */ 97c478bd9Sstevel@tonic-gate 107c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 117c478bd9Sstevel@tonic-gate 127c478bd9Sstevel@tonic-gate #if defined(KERNEL) || defined(_KERNEL) 137c478bd9Sstevel@tonic-gate # undef KERNEL 147c478bd9Sstevel@tonic-gate # undef _KERNEL 157c478bd9Sstevel@tonic-gate # define KERNEL 1 167c478bd9Sstevel@tonic-gate # define _KERNEL 1 177c478bd9Sstevel@tonic-gate #endif 187c478bd9Sstevel@tonic-gate #include <sys/errno.h> 197c478bd9Sstevel@tonic-gate #include <sys/types.h> 207c478bd9Sstevel@tonic-gate #include <sys/param.h> 217c478bd9Sstevel@tonic-gate #include <sys/time.h> 227c478bd9Sstevel@tonic-gate #include <sys/file.h> 237c478bd9Sstevel@tonic-gate #ifdef __hpux 247c478bd9Sstevel@tonic-gate # include <sys/timeout.h> 257c478bd9Sstevel@tonic-gate #endif 267c478bd9Sstevel@tonic-gate #if !defined(_KERNEL) 277c478bd9Sstevel@tonic-gate # include <stdio.h> 287c478bd9Sstevel@tonic-gate # include <string.h> 297c478bd9Sstevel@tonic-gate # include <stdlib.h> 307c478bd9Sstevel@tonic-gate # define _KERNEL 317c478bd9Sstevel@tonic-gate # ifdef __OpenBSD__ 327c478bd9Sstevel@tonic-gate struct file; 337c478bd9Sstevel@tonic-gate # endif 347c478bd9Sstevel@tonic-gate # include <sys/uio.h> 357c478bd9Sstevel@tonic-gate # undef _KERNEL 367c478bd9Sstevel@tonic-gate #endif 377c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 387c478bd9Sstevel@tonic-gate # include <sys/filio.h> 397c478bd9Sstevel@tonic-gate # include <sys/fcntl.h> 407c478bd9Sstevel@tonic-gate #else 417c478bd9Sstevel@tonic-gate # include <sys/ioctl.h> 427c478bd9Sstevel@tonic-gate #endif 43ab25eeb5Syz #if !defined(linux) 44ab25eeb5Syz # include <sys/protosw.h> 45ab25eeb5Syz #endif 467c478bd9Sstevel@tonic-gate #include <sys/socket.h> 477c478bd9Sstevel@tonic-gate #if defined(_KERNEL) 487c478bd9Sstevel@tonic-gate # include <sys/systm.h> 497c478bd9Sstevel@tonic-gate # if !defined(__SVR4) && !defined(__svr4__) 507c478bd9Sstevel@tonic-gate # include <sys/mbuf.h> 517c478bd9Sstevel@tonic-gate # endif 527c478bd9Sstevel@tonic-gate #endif 537c478bd9Sstevel@tonic-gate #if !defined(__SVR4) && !defined(__svr4__) 54ab25eeb5Syz # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX) 557c478bd9Sstevel@tonic-gate # include <sys/kernel.h> 567c478bd9Sstevel@tonic-gate # endif 577c478bd9Sstevel@tonic-gate #else 587c478bd9Sstevel@tonic-gate # include <sys/byteorder.h> 597c478bd9Sstevel@tonic-gate # ifdef _KERNEL 607c478bd9Sstevel@tonic-gate # include <sys/dditypes.h> 617c478bd9Sstevel@tonic-gate # endif 627c478bd9Sstevel@tonic-gate # include <sys/stream.h> 637c478bd9Sstevel@tonic-gate # include <sys/kmem.h> 647c478bd9Sstevel@tonic-gate #endif 657c478bd9Sstevel@tonic-gate #include <net/if.h> 667c478bd9Sstevel@tonic-gate #ifdef sun 677c478bd9Sstevel@tonic-gate # include <net/af.h> 687c478bd9Sstevel@tonic-gate #endif 697c478bd9Sstevel@tonic-gate #include <net/route.h> 707c478bd9Sstevel@tonic-gate #include <netinet/in.h> 717c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 727c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 73ab25eeb5Syz #if !defined(linux) 74ab25eeb5Syz # include <netinet/ip_var.h> 75ab25eeb5Syz #endif 767c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 777c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 787c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 797c478bd9Sstevel@tonic-gate #include "netinet/ip_compat.h" 80ab25eeb5Syz #include <netinet/tcpip.h> 817c478bd9Sstevel@tonic-gate #include "netinet/ip_fil.h" 827c478bd9Sstevel@tonic-gate #include "netinet/ip_nat.h" 837c478bd9Sstevel@tonic-gate #include "netinet/ip_frag.h" 847c478bd9Sstevel@tonic-gate #include "netinet/ip_state.h" 857c478bd9Sstevel@tonic-gate #include "netinet/ip_auth.h" 86f4b3ec61Sdh #include "netinet/ipf_stack.h" 877c478bd9Sstevel@tonic-gate #if (__FreeBSD_version >= 300000) 887c478bd9Sstevel@tonic-gate # include <sys/malloc.h> 897c478bd9Sstevel@tonic-gate # if defined(_KERNEL) 907c478bd9Sstevel@tonic-gate # ifndef IPFILTER_LKM 917c478bd9Sstevel@tonic-gate # include <sys/libkern.h> 927c478bd9Sstevel@tonic-gate # include <sys/systm.h> 937c478bd9Sstevel@tonic-gate # endif 947c478bd9Sstevel@tonic-gate extern struct callout_handle fr_slowtimer_ch; 957c478bd9Sstevel@tonic-gate # endif 967c478bd9Sstevel@tonic-gate #endif 977c478bd9Sstevel@tonic-gate #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) 987c478bd9Sstevel@tonic-gate # include <sys/callout.h> 997c478bd9Sstevel@tonic-gate extern struct callout fr_slowtimer_ch; 1007c478bd9Sstevel@tonic-gate #endif 1017c478bd9Sstevel@tonic-gate #if defined(__OpenBSD__) 1027c478bd9Sstevel@tonic-gate # include <sys/timeout.h> 1037c478bd9Sstevel@tonic-gate extern struct timeout fr_slowtimer_ch; 1047c478bd9Sstevel@tonic-gate #endif 105ab25eeb5Syz /* END OF INCLUDES */ 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate #if !defined(lint) 1087c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; 109ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.5 2005/08/11 14:33:10 darrenr Exp $"; 1107c478bd9Sstevel@tonic-gate #endif 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **)); 1137c478bd9Sstevel@tonic-gate static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **)); 114f4b3ec61Sdh static void fr_fragdelete __P((ipfr_t *, ipfr_t ***, ipf_stack_t *)); 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1177c478bd9Sstevel@tonic-gate /* Function: fr_fraginit */ 1187c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error */ 1197c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 1207c478bd9Sstevel@tonic-gate /* */ 1217c478bd9Sstevel@tonic-gate /* Initialise the hash tables for the fragment cache lookups. */ 1227c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 123f4b3ec61Sdh int fr_fraginit(ifs) 124f4b3ec61Sdh ipf_stack_t *ifs; 1257c478bd9Sstevel@tonic-gate { 126f4b3ec61Sdh ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list; 127f4b3ec61Sdh ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist; 128f4b3ec61Sdh ifs->ifs_ipfr_ipidtail = &ifs->ifs_ipfr_ipidlist; 1298128a42dSan /* the IP frag related variables are set in ipftuneable_setdefs() to 1308128a42dSan * their default values 1318128a42dSan */ 132f4b3ec61Sdh 133f4b3ec61Sdh KMALLOCS(ifs->ifs_ipfr_heads, ipfr_t **, 134f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 135f4b3ec61Sdh if (ifs->ifs_ipfr_heads == NULL) 1367c478bd9Sstevel@tonic-gate return -1; 137f4b3ec61Sdh bzero((char *)ifs->ifs_ipfr_heads, 138f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 1397c478bd9Sstevel@tonic-gate 140f4b3ec61Sdh KMALLOCS(ifs->ifs_ipfr_nattab, ipfr_t **, 141f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 142f4b3ec61Sdh if (ifs->ifs_ipfr_nattab == NULL) 1437c478bd9Sstevel@tonic-gate return -1; 144f4b3ec61Sdh bzero((char *)ifs->ifs_ipfr_nattab, 145f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 1467c478bd9Sstevel@tonic-gate 147f4b3ec61Sdh KMALLOCS(ifs->ifs_ipfr_ipidtab, ipfr_t **, 148f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 149f4b3ec61Sdh if (ifs->ifs_ipfr_ipidtab == NULL) 1507c478bd9Sstevel@tonic-gate return -1; 151f4b3ec61Sdh bzero((char *)ifs->ifs_ipfr_ipidtab, 152f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 1537c478bd9Sstevel@tonic-gate 154f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_frag, "ipf fragment rwlock"); 1557663b816Sml 1567663b816Sml /* Initialise frblock with "block in all" */ 157f4b3ec61Sdh bzero((char *)&ifs->ifs_frblock, sizeof(ifs->ifs_frblock)); 158f4b3ec61Sdh ifs->ifs_frblock.fr_flags = FR_BLOCK|FR_INQUE; /* block in */ 159f4b3ec61Sdh ifs->ifs_frblock.fr_ref = 1; 1607663b816Sml 161f4b3ec61Sdh ifs->ifs_fr_frag_init = 1; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate return 0; 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1687c478bd9Sstevel@tonic-gate /* Function: fr_fragunload */ 1697c478bd9Sstevel@tonic-gate /* Returns: Nil */ 1707c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 1717c478bd9Sstevel@tonic-gate /* */ 1727c478bd9Sstevel@tonic-gate /* Free all memory allocated whilst running and from initialisation. */ 1737c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 174f4b3ec61Sdh void fr_fragunload(ifs) 175f4b3ec61Sdh ipf_stack_t *ifs; 1767c478bd9Sstevel@tonic-gate { 177f4b3ec61Sdh if (ifs->ifs_fr_frag_init == 1) { 178f4b3ec61Sdh fr_fragclear(ifs); 1797c478bd9Sstevel@tonic-gate 180f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_frag); 181f4b3ec61Sdh ifs->ifs_fr_frag_init = 0; 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 184f4b3ec61Sdh if (ifs->ifs_ipfr_heads != NULL) { 185f4b3ec61Sdh KFREES(ifs->ifs_ipfr_heads, 186f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 187f4b3ec61Sdh } 188f4b3ec61Sdh ifs->ifs_ipfr_heads = NULL; 1897c478bd9Sstevel@tonic-gate 190f4b3ec61Sdh if (ifs->ifs_ipfr_nattab != NULL) { 191f4b3ec61Sdh KFREES(ifs->ifs_ipfr_nattab, 192f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 193f4b3ec61Sdh } 194f4b3ec61Sdh ifs->ifs_ipfr_nattab = NULL; 1957c478bd9Sstevel@tonic-gate 196f4b3ec61Sdh if (ifs->ifs_ipfr_ipidtab != NULL) { 197f4b3ec61Sdh KFREES(ifs->ifs_ipfr_ipidtab, 198f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 199f4b3ec61Sdh } 200f4b3ec61Sdh ifs->ifs_ipfr_ipidtab = NULL; 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 2057c478bd9Sstevel@tonic-gate /* Function: fr_fragstats */ 206ab25eeb5Syz /* Returns: ipfrstat_t* - pointer to struct with current frag stats */ 2077c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 2087c478bd9Sstevel@tonic-gate /* */ 2097c478bd9Sstevel@tonic-gate /* Updates ipfr_stats with current information and returns a pointer to it */ 2107c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 211f4b3ec61Sdh ipfrstat_t *fr_fragstats(ifs) 212f4b3ec61Sdh ipf_stack_t *ifs; 2137c478bd9Sstevel@tonic-gate { 214f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_table = ifs->ifs_ipfr_heads; 215f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_nattab = ifs->ifs_ipfr_nattab; 216f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_inuse = ifs->ifs_ipfr_inuse; 217f4b3ec61Sdh return &ifs->ifs_ipfr_stats; 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 2227c478bd9Sstevel@tonic-gate /* Function: ipfr_newfrag */ 2237c478bd9Sstevel@tonic-gate /* Returns: ipfr_t * - pointer to fragment cache state info or NULL */ 2247c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 2257c478bd9Sstevel@tonic-gate /* table(I) - pointer to frag table to add to */ 2267c478bd9Sstevel@tonic-gate /* */ 2277c478bd9Sstevel@tonic-gate /* Add a new entry to the fragment cache, registering it as having come */ 2287c478bd9Sstevel@tonic-gate /* through this box, with the result of the filter operation. */ 2297c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 2307c478bd9Sstevel@tonic-gate static ipfr_t *ipfr_newfrag(fin, pass, table) 2317c478bd9Sstevel@tonic-gate fr_info_t *fin; 2327c478bd9Sstevel@tonic-gate u_32_t pass; 2337c478bd9Sstevel@tonic-gate ipfr_t *table[]; 2347c478bd9Sstevel@tonic-gate { 2357c478bd9Sstevel@tonic-gate ipfr_t *fra, frag; 2367c478bd9Sstevel@tonic-gate u_int idx, off; 237f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 2387c478bd9Sstevel@tonic-gate 239*bd5ba10fSan if (ifs->ifs_ipfr_inuse >= ifs->ifs_ipfr_size) 2407c478bd9Sstevel@tonic-gate return NULL; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 2437c478bd9Sstevel@tonic-gate return NULL; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (pass & FR_FRSTRICT) 2467663b816Sml if (fin->fin_off != 0) 2477c478bd9Sstevel@tonic-gate return NULL; 2487c478bd9Sstevel@tonic-gate 2497663b816Sml frag.ipfr_p = fin->fin_p; 2507663b816Sml idx = fin->fin_p; 2517663b816Sml frag.ipfr_id = fin->fin_id; 2527663b816Sml idx += fin->fin_id; 2537663b816Sml frag.ipfr_source = fin->fin_fi.fi_src; 2547663b816Sml idx += frag.ipfr_src.s_addr; 2557663b816Sml frag.ipfr_dest = fin->fin_fi.fi_dst; 2567663b816Sml idx += frag.ipfr_dst.s_addr; 2577c478bd9Sstevel@tonic-gate frag.ipfr_ifp = fin->fin_ifp; 2587c478bd9Sstevel@tonic-gate idx *= 127; 259*bd5ba10fSan idx %= ifs->ifs_ipfr_size; 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 2627c478bd9Sstevel@tonic-gate frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 2637c478bd9Sstevel@tonic-gate frag.ipfr_auth = fin->fin_fi.fi_auth; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * first, make sure it isn't already there... 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext) 2697c478bd9Sstevel@tonic-gate if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, 2707c478bd9Sstevel@tonic-gate IPFR_CMPSZ)) { 271f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_exists++; 2727c478bd9Sstevel@tonic-gate return NULL; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * allocate some memory, if possible, if not, just record that we 2777c478bd9Sstevel@tonic-gate * failed to do so. 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate KMALLOC(fra, ipfr_t *); 2807c478bd9Sstevel@tonic-gate if (fra == NULL) { 281f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_nomem++; 2827c478bd9Sstevel@tonic-gate return NULL; 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate 285ab25eeb5Syz fra->ipfr_rule = fin->fin_fr; 286ab25eeb5Syz if (fra->ipfr_rule != NULL) { 287ab25eeb5Syz 288ab25eeb5Syz frentry_t *fr; 289ab25eeb5Syz 290ab25eeb5Syz fr = fin->fin_fr; 291ab25eeb5Syz MUTEX_ENTER(&fr->fr_lock); 292ab25eeb5Syz fr->fr_ref++; 293ab25eeb5Syz MUTEX_EXIT(&fr->fr_lock); 2947663b816Sml } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Insert the fragment into the fragment table, copy the struct used 2987c478bd9Sstevel@tonic-gate * in the search using bcopy rather than reassign each field. 2997c478bd9Sstevel@tonic-gate * Set the ttl to the default. 3007c478bd9Sstevel@tonic-gate */ 3017c478bd9Sstevel@tonic-gate if ((fra->ipfr_hnext = table[idx]) != NULL) 3027c478bd9Sstevel@tonic-gate table[idx]->ipfr_hprev = &fra->ipfr_hnext; 3037c478bd9Sstevel@tonic-gate fra->ipfr_hprev = table + idx; 3047c478bd9Sstevel@tonic-gate fra->ipfr_data = NULL; 3057c478bd9Sstevel@tonic-gate table[idx] = fra; 3067c478bd9Sstevel@tonic-gate bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); 307f4b3ec61Sdh fra->ipfr_ttl = ifs->ifs_fr_ticks + ifs->ifs_fr_ipfrttl; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * Compute the offset of the expected start of the next packet. 3117c478bd9Sstevel@tonic-gate */ 312ab25eeb5Syz off = fin->fin_off; 3137663b816Sml if (off == 0) { 3147c478bd9Sstevel@tonic-gate fra->ipfr_seen0 = 1; 3157663b816Sml fra->ipfr_firstend = fin->fin_flen; 3167663b816Sml } else { 3177663b816Sml fra->ipfr_seen0 = 0; 3187663b816Sml fra->ipfr_firstend = 0; 3197663b816Sml } 320ab25eeb5Syz fra->ipfr_off = off + fin->fin_dlen; 3217c478bd9Sstevel@tonic-gate fra->ipfr_pass = pass; 322f4b3ec61Sdh fra->ipfr_ref = 1; 323f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_new++; 324f4b3ec61Sdh ifs->ifs_ipfr_inuse++; 3257c478bd9Sstevel@tonic-gate return fra; 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3307c478bd9Sstevel@tonic-gate /* Function: fr_newfrag */ 3317c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error */ 3327c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 3337c478bd9Sstevel@tonic-gate /* */ 3347c478bd9Sstevel@tonic-gate /* Add a new entry to the fragment cache table based on the current packet */ 3357c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3367c478bd9Sstevel@tonic-gate int fr_newfrag(fin, pass) 3377c478bd9Sstevel@tonic-gate u_32_t pass; 3387c478bd9Sstevel@tonic-gate fr_info_t *fin; 3397c478bd9Sstevel@tonic-gate { 3407c478bd9Sstevel@tonic-gate ipfr_t *fra; 341f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 3427c478bd9Sstevel@tonic-gate 343f4b3ec61Sdh if (ifs->ifs_fr_frag_lock != 0) 344ab25eeb5Syz return -1; 3457c478bd9Sstevel@tonic-gate 346f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_frag); 347f4b3ec61Sdh fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_heads); 3487c478bd9Sstevel@tonic-gate if (fra != NULL) { 349f4b3ec61Sdh *ifs->ifs_ipfr_tail = fra; 350f4b3ec61Sdh fra->ipfr_prev = ifs->ifs_ipfr_tail; 351f4b3ec61Sdh ifs->ifs_ipfr_tail = &fra->ipfr_next; 352f4b3ec61Sdh if (ifs->ifs_ipfr_list == NULL) 353f4b3ec61Sdh ifs->ifs_ipfr_list = fra; 3547c478bd9Sstevel@tonic-gate fra->ipfr_next = NULL; 3557c478bd9Sstevel@tonic-gate } 356f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_frag); 3577c478bd9Sstevel@tonic-gate return fra ? 0 : -1; 3587c478bd9Sstevel@tonic-gate } 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3627c478bd9Sstevel@tonic-gate /* Function: fr_nat_newfrag */ 3637c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error */ 3647c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 3657c478bd9Sstevel@tonic-gate /* nat(I) - pointer to NAT structure */ 3667c478bd9Sstevel@tonic-gate /* */ 3677c478bd9Sstevel@tonic-gate /* Create a new NAT fragment cache entry based on the current packet and */ 3687c478bd9Sstevel@tonic-gate /* the NAT structure for this "session". */ 3697c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3707c478bd9Sstevel@tonic-gate int fr_nat_newfrag(fin, pass, nat) 3717c478bd9Sstevel@tonic-gate fr_info_t *fin; 3727c478bd9Sstevel@tonic-gate u_32_t pass; 3737c478bd9Sstevel@tonic-gate nat_t *nat; 3747c478bd9Sstevel@tonic-gate { 3757c478bd9Sstevel@tonic-gate ipfr_t *fra; 376f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 3777c478bd9Sstevel@tonic-gate 378f4b3ec61Sdh if ((fin->fin_v != 4) || (ifs->ifs_fr_frag_lock != 0)) 3797c478bd9Sstevel@tonic-gate return 0; 3807c478bd9Sstevel@tonic-gate 381f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_natfrag); 382f4b3ec61Sdh fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_nattab); 3837c478bd9Sstevel@tonic-gate if (fra != NULL) { 3847c478bd9Sstevel@tonic-gate fra->ipfr_data = nat; 3857c478bd9Sstevel@tonic-gate nat->nat_data = fra; 386f4b3ec61Sdh *ifs->ifs_ipfr_nattail = fra; 387f4b3ec61Sdh fra->ipfr_prev = ifs->ifs_ipfr_nattail; 388f4b3ec61Sdh ifs->ifs_ipfr_nattail = &fra->ipfr_next; 3897c478bd9Sstevel@tonic-gate fra->ipfr_next = NULL; 3907c478bd9Sstevel@tonic-gate } 391f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 3927c478bd9Sstevel@tonic-gate return fra ? 0 : -1; 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3977c478bd9Sstevel@tonic-gate /* Function: fr_ipid_newfrag */ 3987c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error */ 3997c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 4007c478bd9Sstevel@tonic-gate /* ipid(I) - new IP ID for this fragmented packet */ 4017c478bd9Sstevel@tonic-gate /* */ 4027c478bd9Sstevel@tonic-gate /* Create a new fragment cache entry for this packet and store, as a data */ 4037c478bd9Sstevel@tonic-gate /* pointer, the new IP ID value. */ 4047c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4057c478bd9Sstevel@tonic-gate int fr_ipid_newfrag(fin, ipid) 4067c478bd9Sstevel@tonic-gate fr_info_t *fin; 4077c478bd9Sstevel@tonic-gate u_32_t ipid; 4087c478bd9Sstevel@tonic-gate { 4097c478bd9Sstevel@tonic-gate ipfr_t *fra; 410f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 4117c478bd9Sstevel@tonic-gate 412f4b3ec61Sdh if (ifs->ifs_fr_frag_lock) 4137c478bd9Sstevel@tonic-gate return 0; 4147c478bd9Sstevel@tonic-gate 415f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_ipidfrag); 416f4b3ec61Sdh fra = ipfr_newfrag(fin, 0, ifs->ifs_ipfr_ipidtab); 4177c478bd9Sstevel@tonic-gate if (fra != NULL) { 4187c478bd9Sstevel@tonic-gate fra->ipfr_data = (void *)(uintptr_t)ipid; 419f4b3ec61Sdh *ifs->ifs_ipfr_ipidtail = fra; 420f4b3ec61Sdh fra->ipfr_prev = ifs->ifs_ipfr_ipidtail; 421f4b3ec61Sdh ifs->ifs_ipfr_ipidtail = &fra->ipfr_next; 4227c478bd9Sstevel@tonic-gate fra->ipfr_next = NULL; 4237c478bd9Sstevel@tonic-gate } 424f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 4257c478bd9Sstevel@tonic-gate return fra ? 0 : -1; 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4307c478bd9Sstevel@tonic-gate /* Function: fr_fraglookup */ 4317c478bd9Sstevel@tonic-gate /* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */ 4327c478bd9Sstevel@tonic-gate /* matching entry in the frag table, else NULL */ 4337c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 4347c478bd9Sstevel@tonic-gate /* table(I) - pointer to fragment cache table to search */ 4357c478bd9Sstevel@tonic-gate /* */ 4367c478bd9Sstevel@tonic-gate /* Check the fragment cache to see if there is already a record of this */ 4377c478bd9Sstevel@tonic-gate /* packet with its filter result known. */ 4387c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4397c478bd9Sstevel@tonic-gate static ipfr_t *fr_fraglookup(fin, table) 4407c478bd9Sstevel@tonic-gate fr_info_t *fin; 4417c478bd9Sstevel@tonic-gate ipfr_t *table[]; 4427c478bd9Sstevel@tonic-gate { 4437c478bd9Sstevel@tonic-gate ipfr_t *f, frag; 4447c478bd9Sstevel@tonic-gate u_int idx; 445f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 4487c478bd9Sstevel@tonic-gate return NULL; 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * For fragments, we record protocol, packet id, TOS and both IP#'s 4527c478bd9Sstevel@tonic-gate * (these should all be the same for all fragments of a packet). 4537c478bd9Sstevel@tonic-gate * 4547c478bd9Sstevel@tonic-gate * build up a hash value to index the table with. 4557c478bd9Sstevel@tonic-gate */ 4567663b816Sml frag.ipfr_p = fin->fin_p; 4577663b816Sml idx = fin->fin_p; 4587663b816Sml frag.ipfr_id = fin->fin_id; 4597663b816Sml idx += fin->fin_id; 4607663b816Sml frag.ipfr_source = fin->fin_fi.fi_src; 4617663b816Sml idx += frag.ipfr_src.s_addr; 4627663b816Sml frag.ipfr_dest = fin->fin_fi.fi_dst; 4637663b816Sml idx += frag.ipfr_dst.s_addr; 4647c478bd9Sstevel@tonic-gate frag.ipfr_ifp = fin->fin_ifp; 4657c478bd9Sstevel@tonic-gate idx *= 127; 4667c478bd9Sstevel@tonic-gate idx %= IPFT_SIZE; 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 4697c478bd9Sstevel@tonic-gate frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 4707c478bd9Sstevel@tonic-gate frag.ipfr_auth = fin->fin_fi.fi_auth; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* 4737c478bd9Sstevel@tonic-gate * check the table, careful to only compare the right amount of data 4747c478bd9Sstevel@tonic-gate */ 4757c478bd9Sstevel@tonic-gate for (f = table[idx]; f; f = f->ipfr_hnext) 4767c478bd9Sstevel@tonic-gate if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp, 4777c478bd9Sstevel@tonic-gate IPFR_CMPSZ)) { 4787c478bd9Sstevel@tonic-gate u_short off; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* 4817c478bd9Sstevel@tonic-gate * We don't want to let short packets match because 4827c478bd9Sstevel@tonic-gate * they could be compromising the security of other 4837c478bd9Sstevel@tonic-gate * rules that want to match on layer 4 fields (and 4847c478bd9Sstevel@tonic-gate * can't because they have been fragmented off.) 4857c478bd9Sstevel@tonic-gate * Why do this check here? The counter acts as an 4867c478bd9Sstevel@tonic-gate * indicator of this kind of attack, whereas if it was 4877c478bd9Sstevel@tonic-gate * elsewhere, it wouldn't know if other matching 4887c478bd9Sstevel@tonic-gate * packets had been seen. 4897c478bd9Sstevel@tonic-gate */ 4907c478bd9Sstevel@tonic-gate if (fin->fin_flx & FI_SHORT) { 491f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_short); 4927c478bd9Sstevel@tonic-gate continue; 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate /* 4967c478bd9Sstevel@tonic-gate * XXX - We really need to be guarding against the 4977c478bd9Sstevel@tonic-gate * retransmission of (src,dst,id,offset-range) here 4987c478bd9Sstevel@tonic-gate * because a fragmented packet is never resent with 4997c478bd9Sstevel@tonic-gate * the same IP ID# (or shouldn't). 5007c478bd9Sstevel@tonic-gate */ 501ab25eeb5Syz off = fin->fin_off; /* same as in ipfr_newfrag() */ 5027c478bd9Sstevel@tonic-gate if (f->ipfr_seen0) { 5037c478bd9Sstevel@tonic-gate if (off == 0) { 504f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_retrans0); 5057c478bd9Sstevel@tonic-gate continue; 5067c478bd9Sstevel@tonic-gate } 5077663b816Sml } else if (off == 0) { 5087c478bd9Sstevel@tonic-gate f->ipfr_seen0 = 1; 5097663b816Sml f->ipfr_firstend = fin->fin_flen; 5107663b816Sml } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate if (f != table[idx]) { 5137c478bd9Sstevel@tonic-gate ipfr_t **fp; 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* 5167c478bd9Sstevel@tonic-gate * Move fragment info. to the top of the list 5177c478bd9Sstevel@tonic-gate * to speed up searches. First, delink... 5187c478bd9Sstevel@tonic-gate */ 5197c478bd9Sstevel@tonic-gate fp = f->ipfr_hprev; 5207c478bd9Sstevel@tonic-gate (*fp) = f->ipfr_hnext; 5217c478bd9Sstevel@tonic-gate if (f->ipfr_hnext != NULL) 5227c478bd9Sstevel@tonic-gate f->ipfr_hnext->ipfr_hprev = fp; 5237c478bd9Sstevel@tonic-gate /* 5247c478bd9Sstevel@tonic-gate * Then put back at the top of the chain. 5257c478bd9Sstevel@tonic-gate */ 5267c478bd9Sstevel@tonic-gate f->ipfr_hnext = table[idx]; 5277c478bd9Sstevel@tonic-gate table[idx]->ipfr_hprev = &f->ipfr_hnext; 5287c478bd9Sstevel@tonic-gate f->ipfr_hprev = table + idx; 5297c478bd9Sstevel@tonic-gate table[idx] = f; 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate 5327663b816Sml if (fin->fin_v == 6) { 533ab25eeb5Syz if (f->ipfr_seen0 && (off < f->ipfr_firstend)) 5347663b816Sml fin->fin_flx |= FI_BAD; 5357663b816Sml } 5367c478bd9Sstevel@tonic-gate /* 5377c478bd9Sstevel@tonic-gate * If we've follwed the fragments, and this is the 5387c478bd9Sstevel@tonic-gate * last (in order), shrink expiration time. 5397c478bd9Sstevel@tonic-gate */ 5407c478bd9Sstevel@tonic-gate if (off == f->ipfr_off) { 541ab25eeb5Syz if (!(fin->fin_ip->ip_off & IP_MF)) 542f4b3ec61Sdh f->ipfr_ttl = ifs->ifs_fr_ticks + 1; 543ab25eeb5Syz f->ipfr_off = fin->fin_dlen + off; 5447c478bd9Sstevel@tonic-gate } else if (f->ipfr_pass & FR_FRSTRICT) 5457c478bd9Sstevel@tonic-gate continue; 546f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_hits); 5477c478bd9Sstevel@tonic-gate return f; 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate return NULL; 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5547c478bd9Sstevel@tonic-gate /* Function: fr_nat_knownfrag */ 5557c478bd9Sstevel@tonic-gate /* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ 5567c478bd9Sstevel@tonic-gate /* match found, else NULL */ 5577c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 5587c478bd9Sstevel@tonic-gate /* */ 5597c478bd9Sstevel@tonic-gate /* Functional interface for NAT lookups of the NAT fragment cache */ 5607c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5617c478bd9Sstevel@tonic-gate nat_t *fr_nat_knownfrag(fin) 5627c478bd9Sstevel@tonic-gate fr_info_t *fin; 5637c478bd9Sstevel@tonic-gate { 5647c478bd9Sstevel@tonic-gate nat_t *nat; 5657c478bd9Sstevel@tonic-gate ipfr_t *ipf; 566f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 5677c478bd9Sstevel@tonic-gate 568f4b3ec61Sdh if ((fin->fin_v != 4) || (ifs->ifs_fr_frag_lock) || !ifs->ifs_ipfr_natlist) 5697c478bd9Sstevel@tonic-gate return NULL; 570f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_natfrag); 571f4b3ec61Sdh ipf = fr_fraglookup(fin, ifs->ifs_ipfr_nattab); 5727c478bd9Sstevel@tonic-gate if (ipf != NULL) { 5737c478bd9Sstevel@tonic-gate nat = ipf->ipfr_data; 5747c478bd9Sstevel@tonic-gate /* 5757c478bd9Sstevel@tonic-gate * This is the last fragment for this packet. 5767c478bd9Sstevel@tonic-gate */ 577f4b3ec61Sdh if ((ipf->ipfr_ttl == ifs->ifs_fr_ticks + 1) && (nat != NULL)) { 5787c478bd9Sstevel@tonic-gate nat->nat_data = NULL; 5797c478bd9Sstevel@tonic-gate ipf->ipfr_data = NULL; 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate } else 5827c478bd9Sstevel@tonic-gate nat = NULL; 583f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 5847c478bd9Sstevel@tonic-gate return nat; 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5897c478bd9Sstevel@tonic-gate /* Function: fr_ipid_knownfrag */ 5907c478bd9Sstevel@tonic-gate /* Returns: u_32_t - IPv4 ID for this packet if match found, else */ 5917c478bd9Sstevel@tonic-gate /* return 0xfffffff to indicate no match. */ 5927c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 5937c478bd9Sstevel@tonic-gate /* */ 5947c478bd9Sstevel@tonic-gate /* Functional interface for IP ID lookups of the IP ID fragment cache */ 5957c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5967c478bd9Sstevel@tonic-gate u_32_t fr_ipid_knownfrag(fin) 5977c478bd9Sstevel@tonic-gate fr_info_t *fin; 5987c478bd9Sstevel@tonic-gate { 5997c478bd9Sstevel@tonic-gate ipfr_t *ipf; 6007c478bd9Sstevel@tonic-gate u_32_t id; 601f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 6027c478bd9Sstevel@tonic-gate 603f4b3ec61Sdh if ((fin->fin_v != 4) || (ifs->ifs_fr_frag_lock) || !ifs->ifs_ipfr_ipidlist) 6047c478bd9Sstevel@tonic-gate return 0xffffffff; 6057c478bd9Sstevel@tonic-gate 606f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_ipidfrag); 607f4b3ec61Sdh ipf = fr_fraglookup(fin, ifs->ifs_ipfr_ipidtab); 6087c478bd9Sstevel@tonic-gate if (ipf != NULL) 6097c478bd9Sstevel@tonic-gate id = (u_32_t)(uintptr_t)ipf->ipfr_data; 6107c478bd9Sstevel@tonic-gate else 6117c478bd9Sstevel@tonic-gate id = 0xffffffff; 612f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 6137c478bd9Sstevel@tonic-gate return id; 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6187c478bd9Sstevel@tonic-gate /* Function: fr_knownfrag */ 6197c478bd9Sstevel@tonic-gate /* Returns: frentry_t* - pointer to filter rule if a match is found in */ 6207c478bd9Sstevel@tonic-gate /* the frag cache table, else NULL. */ 6217c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 6227c478bd9Sstevel@tonic-gate /* passp(O) - pointer to where to store rule flags resturned */ 6237c478bd9Sstevel@tonic-gate /* */ 6247c478bd9Sstevel@tonic-gate /* Functional interface for normal lookups of the fragment cache. If a */ 6257c478bd9Sstevel@tonic-gate /* match is found, return the rule pointer and flags from the rule, except */ 6267c478bd9Sstevel@tonic-gate /* that if FR_LOGFIRST is set, reset FR_LOG. */ 6277c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6287c478bd9Sstevel@tonic-gate frentry_t *fr_knownfrag(fin, passp) 6297c478bd9Sstevel@tonic-gate fr_info_t *fin; 6307c478bd9Sstevel@tonic-gate u_32_t *passp; 6317c478bd9Sstevel@tonic-gate { 6327c478bd9Sstevel@tonic-gate frentry_t *fr = NULL; 6337c478bd9Sstevel@tonic-gate ipfr_t *fra; 6347663b816Sml u_32_t pass, oflx; 635f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 6367c478bd9Sstevel@tonic-gate 637f4b3ec61Sdh if ((ifs->ifs_fr_frag_lock) || (ifs->ifs_ipfr_list == NULL)) 6387c478bd9Sstevel@tonic-gate return NULL; 6397c478bd9Sstevel@tonic-gate 640f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_frag); 6417663b816Sml oflx = fin->fin_flx; 642f4b3ec61Sdh fra = fr_fraglookup(fin, ifs->ifs_ipfr_heads); 6437c478bd9Sstevel@tonic-gate if (fra != NULL) { 6447c478bd9Sstevel@tonic-gate fr = fra->ipfr_rule; 6457c478bd9Sstevel@tonic-gate fin->fin_fr = fr; 6467c478bd9Sstevel@tonic-gate if (fr != NULL) { 6477c478bd9Sstevel@tonic-gate pass = fr->fr_flags; 6487c478bd9Sstevel@tonic-gate if ((pass & FR_LOGFIRST) != 0) 6497c478bd9Sstevel@tonic-gate pass &= ~(FR_LOGFIRST|FR_LOG); 6507c478bd9Sstevel@tonic-gate *passp = pass; 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate } 6537663b816Sml if (!(oflx & FI_BAD) && (fin->fin_flx & FI_BAD)) { 6547663b816Sml *passp &= ~FR_CMDMASK; 6557663b816Sml *passp |= FR_BLOCK; 656f4b3ec61Sdh fr = &ifs->ifs_frblock; 6577663b816Sml } 658f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_frag); 6597c478bd9Sstevel@tonic-gate return fr; 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6647c478bd9Sstevel@tonic-gate /* Function: fr_forget */ 6657c478bd9Sstevel@tonic-gate /* Returns: Nil */ 6667c478bd9Sstevel@tonic-gate /* Parameters: ptr(I) - pointer to data structure */ 6677c478bd9Sstevel@tonic-gate /* */ 6687c478bd9Sstevel@tonic-gate /* Search through all of the fragment cache entries and wherever a pointer */ 6697c478bd9Sstevel@tonic-gate /* is found to match ptr, reset it to NULL. */ 6707c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 671f4b3ec61Sdh void fr_forget(ptr, ifs) 6727c478bd9Sstevel@tonic-gate void *ptr; 673f4b3ec61Sdh ipf_stack_t *ifs; 6747c478bd9Sstevel@tonic-gate { 6757c478bd9Sstevel@tonic-gate ipfr_t *fr; 6767c478bd9Sstevel@tonic-gate 677f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_frag); 678f4b3ec61Sdh for (fr = ifs->ifs_ipfr_list; fr; fr = fr->ipfr_next) 6797c478bd9Sstevel@tonic-gate if (fr->ipfr_data == ptr) 6807c478bd9Sstevel@tonic-gate fr->ipfr_data = NULL; 681f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_frag); 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6867c478bd9Sstevel@tonic-gate /* Function: fr_forgetnat */ 6877c478bd9Sstevel@tonic-gate /* Returns: Nil */ 6887c478bd9Sstevel@tonic-gate /* Parameters: ptr(I) - pointer to data structure */ 6897c478bd9Sstevel@tonic-gate /* */ 6907c478bd9Sstevel@tonic-gate /* Search through all of the fragment cache entries for NAT and wherever a */ 6917c478bd9Sstevel@tonic-gate /* pointer is found to match ptr, reset it to NULL. */ 6927c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 693f4b3ec61Sdh void fr_forgetnat(ptr, ifs) 6947c478bd9Sstevel@tonic-gate void *ptr; 695f4b3ec61Sdh ipf_stack_t *ifs; 6967c478bd9Sstevel@tonic-gate { 6977c478bd9Sstevel@tonic-gate ipfr_t *fr; 6987c478bd9Sstevel@tonic-gate 699f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_natfrag); 700f4b3ec61Sdh for (fr = ifs->ifs_ipfr_natlist; fr; fr = fr->ipfr_next) 7017c478bd9Sstevel@tonic-gate if (fr->ipfr_data == ptr) 7027c478bd9Sstevel@tonic-gate fr->ipfr_data = NULL; 703f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 7087c478bd9Sstevel@tonic-gate /* Function: fr_fragdelete */ 7097c478bd9Sstevel@tonic-gate /* Returns: Nil */ 7107c478bd9Sstevel@tonic-gate /* Parameters: fra(I) - pointer to fragment structure to delete */ 7117c478bd9Sstevel@tonic-gate /* tail(IO) - pointer to the pointer to the tail of the frag */ 7127c478bd9Sstevel@tonic-gate /* list */ 7137c478bd9Sstevel@tonic-gate /* */ 7147c478bd9Sstevel@tonic-gate /* Remove a fragment cache table entry from the table & list. Also free */ 7157c478bd9Sstevel@tonic-gate /* the filter rule it is associated with it if it is no longer used as a */ 7167c478bd9Sstevel@tonic-gate /* result of decreasing the reference count. */ 7177c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 718f4b3ec61Sdh static void fr_fragdelete(fra, tail, ifs) 7197c478bd9Sstevel@tonic-gate ipfr_t *fra, ***tail; 720f4b3ec61Sdh ipf_stack_t *ifs; 7217c478bd9Sstevel@tonic-gate { 7227c478bd9Sstevel@tonic-gate frentry_t *fr; 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate fr = fra->ipfr_rule; 7257c478bd9Sstevel@tonic-gate if (fr != NULL) 726f4b3ec61Sdh (void)fr_derefrule(&fr, ifs); 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate if (fra->ipfr_next) 7297c478bd9Sstevel@tonic-gate fra->ipfr_next->ipfr_prev = fra->ipfr_prev; 7307c478bd9Sstevel@tonic-gate *fra->ipfr_prev = fra->ipfr_next; 7317c478bd9Sstevel@tonic-gate if (*tail == &fra->ipfr_next) 7327c478bd9Sstevel@tonic-gate *tail = fra->ipfr_prev; 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate if (fra->ipfr_hnext) 7357c478bd9Sstevel@tonic-gate fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; 7367c478bd9Sstevel@tonic-gate *fra->ipfr_hprev = fra->ipfr_hnext; 737f4b3ec61Sdh 738f4b3ec61Sdh if (fra->ipfr_ref <= 0) 739f4b3ec61Sdh KFREE(fra); 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 7447c478bd9Sstevel@tonic-gate /* Function: fr_fragclear */ 7457c478bd9Sstevel@tonic-gate /* Returns: Nil */ 7467c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 7477c478bd9Sstevel@tonic-gate /* */ 7487c478bd9Sstevel@tonic-gate /* Free memory in use by fragment state information kept. Do the normal */ 7497c478bd9Sstevel@tonic-gate /* fragment state stuff first and then the NAT-fragment table. */ 7507c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 751f4b3ec61Sdh void fr_fragclear(ifs) 752f4b3ec61Sdh ipf_stack_t *ifs; 7537c478bd9Sstevel@tonic-gate { 7547c478bd9Sstevel@tonic-gate ipfr_t *fra; 7557c478bd9Sstevel@tonic-gate nat_t *nat; 7567c478bd9Sstevel@tonic-gate 757f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_frag); 758f4b3ec61Sdh while ((fra = ifs->ifs_ipfr_list) != NULL) { 759f4b3ec61Sdh fra->ipfr_ref--; 760f4b3ec61Sdh fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs); 761f4b3ec61Sdh } 762f4b3ec61Sdh ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list; 763f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_frag); 7647c478bd9Sstevel@tonic-gate 765f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_nat); 766f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_natfrag); 767f4b3ec61Sdh while ((fra = ifs->ifs_ipfr_natlist) != NULL) { 7687c478bd9Sstevel@tonic-gate nat = fra->ipfr_data; 7697c478bd9Sstevel@tonic-gate if (nat != NULL) { 7707c478bd9Sstevel@tonic-gate if (nat->nat_data == fra) 7717c478bd9Sstevel@tonic-gate nat->nat_data = NULL; 7727c478bd9Sstevel@tonic-gate } 773f4b3ec61Sdh fra->ipfr_ref--; 774f4b3ec61Sdh fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs); 7757c478bd9Sstevel@tonic-gate } 776f4b3ec61Sdh ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist; 777f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 778f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_nat); 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 7837c478bd9Sstevel@tonic-gate /* Function: fr_fragexpire */ 7847c478bd9Sstevel@tonic-gate /* Returns: Nil */ 7857c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 7867c478bd9Sstevel@tonic-gate /* */ 7877c478bd9Sstevel@tonic-gate /* Expire entries in the fragment cache table that have been there too long */ 7887c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 789f4b3ec61Sdh void fr_fragexpire(ifs) 790f4b3ec61Sdh ipf_stack_t *ifs; 7917c478bd9Sstevel@tonic-gate { 7927c478bd9Sstevel@tonic-gate ipfr_t **fp, *fra; 7937c478bd9Sstevel@tonic-gate nat_t *nat; 794ab25eeb5Syz SPL_INT(s); 7957c478bd9Sstevel@tonic-gate 796f4b3ec61Sdh if (ifs->ifs_fr_frag_lock) 7977c478bd9Sstevel@tonic-gate return; 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate SPL_NET(s); 800f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_frag); 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * Go through the entire table, looking for entries to expire, 803f4b3ec61Sdh * which is indicated by the ttl being less than or equal to 804f4b3ec61Sdh * ifs_fr_ticks. 8057c478bd9Sstevel@tonic-gate */ 806f4b3ec61Sdh for (fp = &ifs->ifs_ipfr_list; ((fra = *fp) != NULL); ) { 807f4b3ec61Sdh if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 8087c478bd9Sstevel@tonic-gate break; 809f4b3ec61Sdh fra->ipfr_ref--; 810f4b3ec61Sdh fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs); 811f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_expire++; 812f4b3ec61Sdh ifs->ifs_ipfr_inuse--; 8137c478bd9Sstevel@tonic-gate } 814f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_frag); 8157c478bd9Sstevel@tonic-gate 816f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_ipidfrag); 817f4b3ec61Sdh for (fp = &ifs->ifs_ipfr_ipidlist; ((fra = *fp) != NULL); ) { 818f4b3ec61Sdh if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 8197c478bd9Sstevel@tonic-gate break; 820f4b3ec61Sdh fra->ipfr_ref--; 821f4b3ec61Sdh fr_fragdelete(fra, &ifs->ifs_ipfr_ipidtail, ifs); 822f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_expire++; 823f4b3ec61Sdh ifs->ifs_ipfr_inuse--; 8247c478bd9Sstevel@tonic-gate } 825f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate /* 8287c478bd9Sstevel@tonic-gate * Same again for the NAT table, except that if the structure also 8297c478bd9Sstevel@tonic-gate * still points to a NAT structure, and the NAT structure points back 8307c478bd9Sstevel@tonic-gate * at the one to be free'd, NULL the reference from the NAT struct. 8317c478bd9Sstevel@tonic-gate * NOTE: We need to grab both mutex's early, and in this order so as 8327c478bd9Sstevel@tonic-gate * to prevent a deadlock if both try to expire at the same time. 8337c478bd9Sstevel@tonic-gate */ 834f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_nat); 835f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_natfrag); 836f4b3ec61Sdh for (fp = &ifs->ifs_ipfr_natlist; ((fra = *fp) != NULL); ) { 837f4b3ec61Sdh if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 8387c478bd9Sstevel@tonic-gate break; 8397c478bd9Sstevel@tonic-gate nat = fra->ipfr_data; 8407c478bd9Sstevel@tonic-gate if (nat != NULL) { 8417c478bd9Sstevel@tonic-gate if (nat->nat_data == fra) 8427c478bd9Sstevel@tonic-gate nat->nat_data = NULL; 8437c478bd9Sstevel@tonic-gate } 844f4b3ec61Sdh fra->ipfr_ref--; 845f4b3ec61Sdh fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs); 846f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_expire++; 847f4b3ec61Sdh ifs->ifs_ipfr_inuse--; 8487c478bd9Sstevel@tonic-gate } 849f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 850f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_nat); 8517c478bd9Sstevel@tonic-gate SPL_X(s); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 8567c478bd9Sstevel@tonic-gate /* Function: fr_slowtimer */ 8577c478bd9Sstevel@tonic-gate /* Returns: Nil */ 8587c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 8597c478bd9Sstevel@tonic-gate /* */ 8607c478bd9Sstevel@tonic-gate /* Slowly expire held state for fragments. Timeouts are set * in */ 8617c478bd9Sstevel@tonic-gate /* expectation of this being called twice per second. */ 8627c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 8637c478bd9Sstevel@tonic-gate #if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \ 864ab25eeb5Syz !defined(__osf__) && !defined(linux)) 8657c478bd9Sstevel@tonic-gate # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi)) 866f4b3ec61Sdh void fr_slowtimer __P((void *arg)) 8677c478bd9Sstevel@tonic-gate # else 868f4b3ec61Sdh int fr_slowtimer(void *arg) 8697c478bd9Sstevel@tonic-gate # endif 8707c478bd9Sstevel@tonic-gate { 871f4b3ec61Sdh ipf_stack_t *ifs = arg; 872f4b3ec61Sdh 873f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_global); 874f4b3ec61Sdh 875f4b3ec61Sdh fr_fragexpire(ifs); 876f4b3ec61Sdh fr_timeoutstate(ifs); 877f4b3ec61Sdh fr_natexpire(ifs); 878f4b3ec61Sdh fr_authexpire(ifs); 879f4b3ec61Sdh ifs->ifs_fr_ticks++; 880f4b3ec61Sdh if (ifs->ifs_fr_running <= 0) 8817c478bd9Sstevel@tonic-gate goto done; 8827c478bd9Sstevel@tonic-gate # ifdef _KERNEL 8837c478bd9Sstevel@tonic-gate # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000) 8847c478bd9Sstevel@tonic-gate callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL); 8857c478bd9Sstevel@tonic-gate # else 8867c478bd9Sstevel@tonic-gate # if defined(__OpenBSD__) 8877c478bd9Sstevel@tonic-gate timeout_add(&fr_slowtimer_ch, hz/2); 8887c478bd9Sstevel@tonic-gate # else 8897c478bd9Sstevel@tonic-gate # if (__FreeBSD_version >= 300000) 8907c478bd9Sstevel@tonic-gate fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2); 8917c478bd9Sstevel@tonic-gate # else 892ab25eeb5Syz # ifdef linux 893ab25eeb5Syz ; 894ab25eeb5Syz # else 8957c478bd9Sstevel@tonic-gate timeout(fr_slowtimer, NULL, hz/2); 896ab25eeb5Syz # endif 8977c478bd9Sstevel@tonic-gate # endif /* FreeBSD */ 8987c478bd9Sstevel@tonic-gate # endif /* OpenBSD */ 8997c478bd9Sstevel@tonic-gate # endif /* NetBSD */ 9007c478bd9Sstevel@tonic-gate # endif 9017c478bd9Sstevel@tonic-gate done: 902f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 9037c478bd9Sstevel@tonic-gate # if (BSD < 199103) || !defined(_KERNEL) 9047c478bd9Sstevel@tonic-gate return 0; 9057c478bd9Sstevel@tonic-gate # endif 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ 908f4b3ec61Sdh 909f4b3ec61Sdh /*ARGSUSED*/ 910f4b3ec61Sdh int fr_nextfrag(token, itp, top, tail, lock, ifs) 911f4b3ec61Sdh ipftoken_t *token; 912f4b3ec61Sdh ipfgeniter_t *itp; 913f4b3ec61Sdh ipfr_t **top, ***tail; 914f4b3ec61Sdh ipfrwlock_t *lock; 915f4b3ec61Sdh ipf_stack_t *ifs; 916f4b3ec61Sdh { 917f4b3ec61Sdh ipfr_t *frag, *next, zero; 918f4b3ec61Sdh int error = 0; 919f4b3ec61Sdh 920f4b3ec61Sdh frag = token->ipt_data; 921f4b3ec61Sdh if (frag == (ipfr_t *)-1) { 922f4b3ec61Sdh ipf_freetoken(token, ifs); 923f4b3ec61Sdh return ESRCH; 924f4b3ec61Sdh } 925f4b3ec61Sdh 926f4b3ec61Sdh READ_ENTER(lock); 927f4b3ec61Sdh if (frag == NULL) 928f4b3ec61Sdh next = *top; 929f4b3ec61Sdh else 930f4b3ec61Sdh next = frag->ipfr_next; 931f4b3ec61Sdh 932f4b3ec61Sdh if (next != NULL) { 933f4b3ec61Sdh ATOMIC_INC(next->ipfr_ref); 934f4b3ec61Sdh token->ipt_data = next; 935f4b3ec61Sdh } else { 936f4b3ec61Sdh bzero(&zero, sizeof(zero)); 937f4b3ec61Sdh next = &zero; 938f4b3ec61Sdh token->ipt_data = (void *)-1; 939f4b3ec61Sdh } 940f4b3ec61Sdh RWLOCK_EXIT(lock); 941f4b3ec61Sdh 942f4b3ec61Sdh if (frag != NULL) { 943f4b3ec61Sdh fr_fragderef(&frag, lock, ifs); 944f4b3ec61Sdh } 945f4b3ec61Sdh 946f4b3ec61Sdh error = COPYOUT(next, itp->igi_data, sizeof(*next)); 947f4b3ec61Sdh if (error != 0) 948f4b3ec61Sdh error = EFAULT; 949f4b3ec61Sdh 950f4b3ec61Sdh return error; 951f4b3ec61Sdh } 952f4b3ec61Sdh 953f4b3ec61Sdh 954f4b3ec61Sdh void fr_fragderef(frp, lock, ifs) 955f4b3ec61Sdh ipfr_t **frp; 956f4b3ec61Sdh ipfrwlock_t *lock; 957f4b3ec61Sdh ipf_stack_t *ifs; 958f4b3ec61Sdh { 959f4b3ec61Sdh ipfr_t *fra; 960f4b3ec61Sdh 961f4b3ec61Sdh fra = *frp; 962f4b3ec61Sdh *frp = NULL; 963f4b3ec61Sdh 964f4b3ec61Sdh WRITE_ENTER(lock); 965f4b3ec61Sdh fra->ipfr_ref--; 966f4b3ec61Sdh if (fra->ipfr_ref <= 0) { 967f4b3ec61Sdh KFREE(fra); 968f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_expire++; 969f4b3ec61Sdh ifs->ifs_ipfr_inuse--; 970f4b3ec61Sdh } 971f4b3ec61Sdh RWLOCK_EXIT(lock); 972f4b3ec61Sdh } 973