1ab25eeb5Syz155240 /* 2ab25eeb5Syz155240 * Copyright (C) 1993-2003 by Darren Reed. 3ab25eeb5Syz155240 * 4ab25eeb5Syz155240 * See the IPFILTER.LICENCE file for details on licencing. 5ab25eeb5Syz155240 * 672680cf5SDarren Reed * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 7ab25eeb5Syz155240 * Use is subject to license terms. 8ab25eeb5Syz155240 */ 9ab25eeb5Syz155240 10ab25eeb5Syz155240 #if defined(KERNEL) || defined(_KERNEL) 11ab25eeb5Syz155240 # undef KERNEL 12ab25eeb5Syz155240 # undef _KERNEL 13ab25eeb5Syz155240 # define KERNEL 1 14ab25eeb5Syz155240 # define _KERNEL 1 15ab25eeb5Syz155240 #endif 16ab25eeb5Syz155240 #include <sys/errno.h> 17ab25eeb5Syz155240 #include <sys/types.h> 18ab25eeb5Syz155240 #include <sys/param.h> 19ab25eeb5Syz155240 #include <sys/time.h> 20ab25eeb5Syz155240 #include <sys/file.h> 21ab25eeb5Syz155240 #ifdef __hpux 22ab25eeb5Syz155240 # include <sys/timeout.h> 23ab25eeb5Syz155240 #endif 24ab25eeb5Syz155240 #if !defined(_KERNEL) 25ab25eeb5Syz155240 # include <stdio.h> 26ab25eeb5Syz155240 # include <string.h> 27ab25eeb5Syz155240 # include <stdlib.h> 28ab25eeb5Syz155240 # define _KERNEL 29ab25eeb5Syz155240 # ifdef __OpenBSD__ 30ab25eeb5Syz155240 struct file; 31ab25eeb5Syz155240 # endif 32ab25eeb5Syz155240 # include <sys/uio.h> 33ab25eeb5Syz155240 # undef _KERNEL 34ab25eeb5Syz155240 #endif 35ab25eeb5Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 36ab25eeb5Syz155240 # include <sys/filio.h> 37ab25eeb5Syz155240 # include <sys/fcntl.h> 38ab25eeb5Syz155240 #else 39ab25eeb5Syz155240 # include <sys/ioctl.h> 40ab25eeb5Syz155240 #endif 41ab25eeb5Syz155240 #if !defined(linux) 42ab25eeb5Syz155240 # include <sys/protosw.h> 43ab25eeb5Syz155240 #endif 44ab25eeb5Syz155240 #include <sys/socket.h> 45ab25eeb5Syz155240 #if defined(_KERNEL) 46ab25eeb5Syz155240 # include <sys/systm.h> 47ab25eeb5Syz155240 # if !defined(__SVR4) && !defined(__svr4__) 48ab25eeb5Syz155240 # include <sys/mbuf.h> 49ab25eeb5Syz155240 # endif 50ab25eeb5Syz155240 #endif 51ab25eeb5Syz155240 #if !defined(__SVR4) && !defined(__svr4__) 52ab25eeb5Syz155240 # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX) 53ab25eeb5Syz155240 # include <sys/kernel.h> 54ab25eeb5Syz155240 # endif 55ab25eeb5Syz155240 #else 56ab25eeb5Syz155240 # include <sys/byteorder.h> 57ab25eeb5Syz155240 # ifdef _KERNEL 58ab25eeb5Syz155240 # include <sys/dditypes.h> 59ab25eeb5Syz155240 # endif 60ab25eeb5Syz155240 # include <sys/stream.h> 61ab25eeb5Syz155240 # include <sys/kmem.h> 62ab25eeb5Syz155240 #endif 63ab25eeb5Syz155240 #include <net/if.h> 64ab25eeb5Syz155240 #ifdef sun 65ab25eeb5Syz155240 # include <net/af.h> 66ab25eeb5Syz155240 #endif 67ab25eeb5Syz155240 #include <net/route.h> 68ab25eeb5Syz155240 #include <netinet/in.h> 69ab25eeb5Syz155240 #include <netinet/in_systm.h> 70ab25eeb5Syz155240 #include <netinet/ip.h> 71ab25eeb5Syz155240 #if !defined(linux) 72ab25eeb5Syz155240 # include <netinet/ip_var.h> 73ab25eeb5Syz155240 #endif 74ab25eeb5Syz155240 #include <netinet/tcp.h> 75ab25eeb5Syz155240 #include <netinet/udp.h> 76ab25eeb5Syz155240 #include <netinet/ip_icmp.h> 77ab25eeb5Syz155240 #include "netinet/ip_compat.h" 78ab25eeb5Syz155240 #include <netinet/tcpip.h> 79ab25eeb5Syz155240 #include "netinet/ip_fil.h" 80ab25eeb5Syz155240 #include "netinet/ip_nat.h" 81ab25eeb5Syz155240 #include "netinet/ip_frag.h" 82ab25eeb5Syz155240 #include "netinet/ip_state.h" 83ab25eeb5Syz155240 #include "netinet/ip_auth.h" 84f4b3ec61Sdh155122 #include "netinet/ipf_stack.h" 85ab25eeb5Syz155240 #if (__FreeBSD_version >= 300000) 86ab25eeb5Syz155240 # include <sys/malloc.h> 87ab25eeb5Syz155240 # if defined(_KERNEL) 88ab25eeb5Syz155240 # ifndef IPFILTER_LKM 89ab25eeb5Syz155240 # include <sys/libkern.h> 90ab25eeb5Syz155240 # include <sys/systm.h> 91ab25eeb5Syz155240 # endif 92ab25eeb5Syz155240 extern struct callout_handle fr_slowtimer_ch; 93ab25eeb5Syz155240 # endif 94ab25eeb5Syz155240 #endif 95ab25eeb5Syz155240 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) 96ab25eeb5Syz155240 # include <sys/callout.h> 97ab25eeb5Syz155240 extern struct callout fr_slowtimer_ch; 98ab25eeb5Syz155240 #endif 99ab25eeb5Syz155240 #if defined(__OpenBSD__) 100ab25eeb5Syz155240 # include <sys/timeout.h> 101ab25eeb5Syz155240 extern struct timeout fr_slowtimer_ch; 102ab25eeb5Syz155240 #endif 103ab25eeb5Syz155240 /* END OF INCLUDES */ 104ab25eeb5Syz155240 105ab25eeb5Syz155240 #if !defined(lint) 106ab25eeb5Syz155240 static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; 107ab25eeb5Syz155240 static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.5 2005/08/11 14:33:10 darrenr Exp $"; 108ab25eeb5Syz155240 #endif 109ab25eeb5Syz155240 11072680cf5SDarren Reed static INLINE int ipfr_index __P((fr_info_t *, ipfr_t *)); 111ab25eeb5Syz155240 static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **)); 112ab25eeb5Syz155240 static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **)); 113f4b3ec61Sdh155122 static void fr_fragdelete __P((ipfr_t *, ipfr_t ***, ipf_stack_t *)); 114ab25eeb5Syz155240 115ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 116ab25eeb5Syz155240 /* Function: fr_fraginit */ 117ab25eeb5Syz155240 /* Returns: int - 0 == success, -1 == error */ 118ab25eeb5Syz155240 /* Parameters: Nil */ 119ab25eeb5Syz155240 /* */ 120ab25eeb5Syz155240 /* Initialise the hash tables for the fragment cache lookups. */ 121ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 122f4b3ec61Sdh155122 int fr_fraginit(ifs) 123f4b3ec61Sdh155122 ipf_stack_t *ifs; 124ab25eeb5Syz155240 { 125f4b3ec61Sdh155122 ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list; 126f4b3ec61Sdh155122 ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist; 127f4b3ec61Sdh155122 ifs->ifs_ipfr_ipidtail = &ifs->ifs_ipfr_ipidlist; 1288128a42dSan207044 /* the IP frag related variables are set in ipftuneable_setdefs() to 1298128a42dSan207044 * their default values 1308128a42dSan207044 */ 131ab25eeb5Syz155240 132f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_ipfr_heads, ipfr_t **, 133f4b3ec61Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 134f4b3ec61Sdh155122 if (ifs->ifs_ipfr_heads == NULL) 135ab25eeb5Syz155240 return -1; 136f4b3ec61Sdh155122 bzero((char *)ifs->ifs_ipfr_heads, 137f4b3ec61Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 138ab25eeb5Syz155240 139f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_ipfr_nattab, ipfr_t **, 140f4b3ec61Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 141f4b3ec61Sdh155122 if (ifs->ifs_ipfr_nattab == NULL) 142ab25eeb5Syz155240 return -1; 143f4b3ec61Sdh155122 bzero((char *)ifs->ifs_ipfr_nattab, 144f4b3ec61Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 145ab25eeb5Syz155240 146f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_ipfr_ipidtab, ipfr_t **, 147f4b3ec61Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 148f4b3ec61Sdh155122 if (ifs->ifs_ipfr_ipidtab == NULL) 149f4b3ec61Sdh155122 return -1; 150f4b3ec61Sdh155122 bzero((char *)ifs->ifs_ipfr_ipidtab, 151f4b3ec61Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 152f4b3ec61Sdh155122 153f4b3ec61Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_frag, "ipf fragment rwlock"); 154ab25eeb5Syz155240 155ab25eeb5Syz155240 /* Initialise frblock with "block in all" */ 156f4b3ec61Sdh155122 bzero((char *)&ifs->ifs_frblock, sizeof(ifs->ifs_frblock)); 157f4b3ec61Sdh155122 ifs->ifs_frblock.fr_flags = FR_BLOCK|FR_INQUE; /* block in */ 158f4b3ec61Sdh155122 ifs->ifs_frblock.fr_ref = 1; 159ab25eeb5Syz155240 160f4b3ec61Sdh155122 ifs->ifs_fr_frag_init = 1; 161ab25eeb5Syz155240 162ab25eeb5Syz155240 return 0; 163ab25eeb5Syz155240 } 164ab25eeb5Syz155240 165ab25eeb5Syz155240 166ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 167ab25eeb5Syz155240 /* Function: fr_fragunload */ 168ab25eeb5Syz155240 /* Returns: Nil */ 169ab25eeb5Syz155240 /* Parameters: Nil */ 170ab25eeb5Syz155240 /* */ 171ab25eeb5Syz155240 /* Free all memory allocated whilst running and from initialisation. */ 172ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 173f4b3ec61Sdh155122 void fr_fragunload(ifs) 174f4b3ec61Sdh155122 ipf_stack_t *ifs; 175ab25eeb5Syz155240 { 176f4b3ec61Sdh155122 if (ifs->ifs_fr_frag_init == 1) { 177f4b3ec61Sdh155122 fr_fragclear(ifs); 178ab25eeb5Syz155240 179f4b3ec61Sdh155122 RW_DESTROY(&ifs->ifs_ipf_frag); 180f4b3ec61Sdh155122 ifs->ifs_fr_frag_init = 0; 181ab25eeb5Syz155240 } 182ab25eeb5Syz155240 183f4b3ec61Sdh155122 if (ifs->ifs_ipfr_heads != NULL) { 184f4b3ec61Sdh155122 KFREES(ifs->ifs_ipfr_heads, 185f4b3ec61Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 186f4b3ec61Sdh155122 } 187f4b3ec61Sdh155122 ifs->ifs_ipfr_heads = NULL; 188ab25eeb5Syz155240 189f4b3ec61Sdh155122 if (ifs->ifs_ipfr_nattab != NULL) { 190f4b3ec61Sdh155122 KFREES(ifs->ifs_ipfr_nattab, 191f4b3ec61Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 192f4b3ec61Sdh155122 } 193f4b3ec61Sdh155122 ifs->ifs_ipfr_nattab = NULL; 194ab25eeb5Syz155240 195f4b3ec61Sdh155122 if (ifs->ifs_ipfr_ipidtab != NULL) { 196f4b3ec61Sdh155122 KFREES(ifs->ifs_ipfr_ipidtab, 197f4b3ec61Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 198f4b3ec61Sdh155122 } 199f4b3ec61Sdh155122 ifs->ifs_ipfr_ipidtab = NULL; 200ab25eeb5Syz155240 } 201ab25eeb5Syz155240 202ab25eeb5Syz155240 203ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 204ab25eeb5Syz155240 /* Function: fr_fragstats */ 205ab25eeb5Syz155240 /* Returns: ipfrstat_t* - pointer to struct with current frag stats */ 206ab25eeb5Syz155240 /* Parameters: Nil */ 207ab25eeb5Syz155240 /* */ 208ab25eeb5Syz155240 /* Updates ipfr_stats with current information and returns a pointer to it */ 209ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 210f4b3ec61Sdh155122 ipfrstat_t *fr_fragstats(ifs) 211f4b3ec61Sdh155122 ipf_stack_t *ifs; 212ab25eeb5Syz155240 { 213f4b3ec61Sdh155122 ifs->ifs_ipfr_stats.ifs_table = ifs->ifs_ipfr_heads; 214f4b3ec61Sdh155122 ifs->ifs_ipfr_stats.ifs_nattab = ifs->ifs_ipfr_nattab; 215f4b3ec61Sdh155122 ifs->ifs_ipfr_stats.ifs_inuse = ifs->ifs_ipfr_inuse; 216f4b3ec61Sdh155122 return &ifs->ifs_ipfr_stats; 217ab25eeb5Syz155240 } 218ab25eeb5Syz155240 219ab25eeb5Syz155240 220ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 22172680cf5SDarren Reed /* Function: ipfr_index */ 22272680cf5SDarren Reed /* Returns: int - index in fragment table for given packet */ 22372680cf5SDarren Reed /* Parameters: fin(I) - pointer to packet information */ 22472680cf5SDarren Reed /* frag(O) - pointer to ipfr_t structure to fill */ 22572680cf5SDarren Reed /* */ 22672680cf5SDarren Reed /* Compute the index in the fragment table while filling the per packet */ 22772680cf5SDarren Reed /* part of the fragment state. */ 22872680cf5SDarren Reed /* ------------------------------------------------------------------------ */ 22972680cf5SDarren Reed static INLINE int ipfr_index(fin, frag) 23072680cf5SDarren Reed fr_info_t *fin; 23172680cf5SDarren Reed ipfr_t *frag; 23272680cf5SDarren Reed { 23372680cf5SDarren Reed u_int idx; 23472680cf5SDarren Reed 23572680cf5SDarren Reed /* 23672680cf5SDarren Reed * For fragments, we record protocol, packet id, TOS and both IP#'s 23772680cf5SDarren Reed * (these should all be the same for all fragments of a packet). 23872680cf5SDarren Reed * 23972680cf5SDarren Reed * build up a hash value to index the table with. 24072680cf5SDarren Reed */ 24172680cf5SDarren Reed 24272680cf5SDarren Reed #ifdef USE_INET6 24372680cf5SDarren Reed if (fin->fin_v == 6) { 24472680cf5SDarren Reed ip6_t *ip6 = (ip6_t *)fin->fin_ip; 24572680cf5SDarren Reed 24672680cf5SDarren Reed frag->ipfr_p = fin->fin_fi.fi_p; 24772680cf5SDarren Reed frag->ipfr_id = fin->fin_id; 24872680cf5SDarren Reed frag->ipfr_tos = ip6->ip6_flow & IPV6_FLOWINFO_MASK; 24972680cf5SDarren Reed frag->ipfr_src.in6 = ip6->ip6_src; 25072680cf5SDarren Reed frag->ipfr_dst.in6 = ip6->ip6_dst; 25172680cf5SDarren Reed } else 25272680cf5SDarren Reed #endif 25372680cf5SDarren Reed { 25472680cf5SDarren Reed ip_t *ip = fin->fin_ip; 25572680cf5SDarren Reed 25672680cf5SDarren Reed frag->ipfr_p = ip->ip_p; 25772680cf5SDarren Reed frag->ipfr_id = ip->ip_id; 25872680cf5SDarren Reed frag->ipfr_tos = ip->ip_tos; 25972680cf5SDarren Reed frag->ipfr_src.in4.s_addr = ip->ip_src.s_addr; 26072680cf5SDarren Reed frag->ipfr_src.i6[1] = 0; 26172680cf5SDarren Reed frag->ipfr_src.i6[2] = 0; 26272680cf5SDarren Reed frag->ipfr_src.i6[3] = 0; 26372680cf5SDarren Reed frag->ipfr_dst.in4.s_addr = ip->ip_dst.s_addr; 26472680cf5SDarren Reed frag->ipfr_dst.i6[1] = 0; 26572680cf5SDarren Reed frag->ipfr_dst.i6[2] = 0; 26672680cf5SDarren Reed frag->ipfr_dst.i6[3] = 0; 26772680cf5SDarren Reed } 26872680cf5SDarren Reed frag->ipfr_ifp = fin->fin_ifp; 26972680cf5SDarren Reed frag->ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 27072680cf5SDarren Reed frag->ipfr_secmsk = fin->fin_fi.fi_secmsk; 27172680cf5SDarren Reed frag->ipfr_auth = fin->fin_fi.fi_auth; 27272680cf5SDarren Reed 27372680cf5SDarren Reed idx = frag->ipfr_p; 27472680cf5SDarren Reed idx += frag->ipfr_id; 27572680cf5SDarren Reed idx += frag->ipfr_src.i6[0]; 27672680cf5SDarren Reed idx += frag->ipfr_src.i6[1]; 27772680cf5SDarren Reed idx += frag->ipfr_src.i6[2]; 27872680cf5SDarren Reed idx += frag->ipfr_src.i6[3]; 27972680cf5SDarren Reed idx += frag->ipfr_dst.i6[0]; 28072680cf5SDarren Reed idx += frag->ipfr_dst.i6[1]; 28172680cf5SDarren Reed idx += frag->ipfr_dst.i6[2]; 28272680cf5SDarren Reed idx += frag->ipfr_dst.i6[3]; 28372680cf5SDarren Reed idx *= 127; 28472680cf5SDarren Reed idx %= IPFT_SIZE; 28572680cf5SDarren Reed 28672680cf5SDarren Reed return idx; 28772680cf5SDarren Reed } 28872680cf5SDarren Reed 28972680cf5SDarren Reed 29072680cf5SDarren Reed /* ------------------------------------------------------------------------ */ 291ab25eeb5Syz155240 /* Function: ipfr_newfrag */ 292ab25eeb5Syz155240 /* Returns: ipfr_t * - pointer to fragment cache state info or NULL */ 293ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 294ab25eeb5Syz155240 /* table(I) - pointer to frag table to add to */ 295ab25eeb5Syz155240 /* */ 296ab25eeb5Syz155240 /* Add a new entry to the fragment cache, registering it as having come */ 297ab25eeb5Syz155240 /* through this box, with the result of the filter operation. */ 298ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 299ab25eeb5Syz155240 static ipfr_t *ipfr_newfrag(fin, pass, table) 300ab25eeb5Syz155240 fr_info_t *fin; 301ab25eeb5Syz155240 u_32_t pass; 302ab25eeb5Syz155240 ipfr_t *table[]; 303ab25eeb5Syz155240 { 304ab25eeb5Syz155240 ipfr_t *fra, frag; 305ab25eeb5Syz155240 u_int idx, off; 306f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 307ab25eeb5Syz155240 308bd5ba10fSan207044 if (ifs->ifs_ipfr_inuse >= ifs->ifs_ipfr_size) 309ab25eeb5Syz155240 return NULL; 310ab25eeb5Syz155240 311ab25eeb5Syz155240 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 312ab25eeb5Syz155240 return NULL; 313ab25eeb5Syz155240 314ab25eeb5Syz155240 if (pass & FR_FRSTRICT) 315ab25eeb5Syz155240 if (fin->fin_off != 0) 316ab25eeb5Syz155240 return NULL; 317ab25eeb5Syz155240 31872680cf5SDarren Reed idx = ipfr_index(fin, &frag); 319ab25eeb5Syz155240 320ab25eeb5Syz155240 /* 321ab25eeb5Syz155240 * first, make sure it isn't already there... 322ab25eeb5Syz155240 */ 323ab25eeb5Syz155240 for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext) 324ab25eeb5Syz155240 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, 325ab25eeb5Syz155240 IPFR_CMPSZ)) { 326f4b3ec61Sdh155122 ifs->ifs_ipfr_stats.ifs_exists++; 327ab25eeb5Syz155240 return NULL; 328ab25eeb5Syz155240 } 329ab25eeb5Syz155240 330ab25eeb5Syz155240 /* 331ab25eeb5Syz155240 * allocate some memory, if possible, if not, just record that we 332ab25eeb5Syz155240 * failed to do so. 333ab25eeb5Syz155240 */ 334ab25eeb5Syz155240 KMALLOC(fra, ipfr_t *); 335ab25eeb5Syz155240 if (fra == NULL) { 336f4b3ec61Sdh155122 ifs->ifs_ipfr_stats.ifs_nomem++; 337ab25eeb5Syz155240 return NULL; 338ab25eeb5Syz155240 } 339ab25eeb5Syz155240 340ab25eeb5Syz155240 fra->ipfr_rule = fin->fin_fr; 341ab25eeb5Syz155240 if (fra->ipfr_rule != NULL) { 342ab25eeb5Syz155240 343ab25eeb5Syz155240 frentry_t *fr; 344ab25eeb5Syz155240 345ab25eeb5Syz155240 fr = fin->fin_fr; 346ab25eeb5Syz155240 MUTEX_ENTER(&fr->fr_lock); 347ab25eeb5Syz155240 fr->fr_ref++; 348ab25eeb5Syz155240 MUTEX_EXIT(&fr->fr_lock); 349ab25eeb5Syz155240 } 350ab25eeb5Syz155240 351ab25eeb5Syz155240 /* 352ab25eeb5Syz155240 * Insert the fragment into the fragment table, copy the struct used 353ab25eeb5Syz155240 * in the search using bcopy rather than reassign each field. 354ab25eeb5Syz155240 * Set the ttl to the default. 355ab25eeb5Syz155240 */ 356ab25eeb5Syz155240 if ((fra->ipfr_hnext = table[idx]) != NULL) 357ab25eeb5Syz155240 table[idx]->ipfr_hprev = &fra->ipfr_hnext; 358ab25eeb5Syz155240 fra->ipfr_hprev = table + idx; 359ab25eeb5Syz155240 fra->ipfr_data = NULL; 360ab25eeb5Syz155240 table[idx] = fra; 361ab25eeb5Syz155240 bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); 362f4b3ec61Sdh155122 fra->ipfr_ttl = ifs->ifs_fr_ticks + ifs->ifs_fr_ipfrttl; 363ab25eeb5Syz155240 364ab25eeb5Syz155240 /* 365ab25eeb5Syz155240 * Compute the offset of the expected start of the next packet. 366ab25eeb5Syz155240 */ 36772680cf5SDarren Reed off = fin->fin_off >> 3; 368ab25eeb5Syz155240 if (off == 0) { 369ab25eeb5Syz155240 fra->ipfr_seen0 = 1; 370ab25eeb5Syz155240 } else { 371ab25eeb5Syz155240 fra->ipfr_seen0 = 0; 372ab25eeb5Syz155240 } 373ab25eeb5Syz155240 fra->ipfr_off = off + fin->fin_dlen; 374ab25eeb5Syz155240 fra->ipfr_pass = pass; 375f4b3ec61Sdh155122 fra->ipfr_ref = 1; 376f4b3ec61Sdh155122 ifs->ifs_ipfr_stats.ifs_new++; 377f4b3ec61Sdh155122 ifs->ifs_ipfr_inuse++; 378ab25eeb5Syz155240 return fra; 379ab25eeb5Syz155240 } 380ab25eeb5Syz155240 381ab25eeb5Syz155240 382ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 383ab25eeb5Syz155240 /* Function: fr_newfrag */ 384ab25eeb5Syz155240 /* Returns: int - 0 == success, -1 == error */ 385ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 386ab25eeb5Syz155240 /* */ 387ab25eeb5Syz155240 /* Add a new entry to the fragment cache table based on the current packet */ 388ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 389ab25eeb5Syz155240 int fr_newfrag(fin, pass) 390ab25eeb5Syz155240 u_32_t pass; 391ab25eeb5Syz155240 fr_info_t *fin; 392ab25eeb5Syz155240 { 393ab25eeb5Syz155240 ipfr_t *fra; 394f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 395ab25eeb5Syz155240 396f4b3ec61Sdh155122 if (ifs->ifs_fr_frag_lock != 0) 397ab25eeb5Syz155240 return -1; 398ab25eeb5Syz155240 399f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag); 400f4b3ec61Sdh155122 fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_heads); 401ab25eeb5Syz155240 if (fra != NULL) { 402f4b3ec61Sdh155122 *ifs->ifs_ipfr_tail = fra; 403f4b3ec61Sdh155122 fra->ipfr_prev = ifs->ifs_ipfr_tail; 404f4b3ec61Sdh155122 ifs->ifs_ipfr_tail = &fra->ipfr_next; 405f4b3ec61Sdh155122 if (ifs->ifs_ipfr_list == NULL) 406f4b3ec61Sdh155122 ifs->ifs_ipfr_list = fra; 407ab25eeb5Syz155240 fra->ipfr_next = NULL; 408ab25eeb5Syz155240 } 409f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag); 410ab25eeb5Syz155240 return fra ? 0 : -1; 411ab25eeb5Syz155240 } 412ab25eeb5Syz155240 413ab25eeb5Syz155240 414ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 415ab25eeb5Syz155240 /* Function: fr_nat_newfrag */ 416ab25eeb5Syz155240 /* Returns: int - 0 == success, -1 == error */ 417ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 418ab25eeb5Syz155240 /* nat(I) - pointer to NAT structure */ 419ab25eeb5Syz155240 /* */ 420ab25eeb5Syz155240 /* Create a new NAT fragment cache entry based on the current packet and */ 421ab25eeb5Syz155240 /* the NAT structure for this "session". */ 422ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 423ab25eeb5Syz155240 int fr_nat_newfrag(fin, pass, nat) 424ab25eeb5Syz155240 fr_info_t *fin; 425ab25eeb5Syz155240 u_32_t pass; 426ab25eeb5Syz155240 nat_t *nat; 427ab25eeb5Syz155240 { 428ab25eeb5Syz155240 ipfr_t *fra; 429f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 430ab25eeb5Syz155240 43172680cf5SDarren Reed if (ifs->ifs_fr_frag_lock != 0) 432ab25eeb5Syz155240 return 0; 433ab25eeb5Syz155240 434f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag); 435f4b3ec61Sdh155122 fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_nattab); 436ab25eeb5Syz155240 if (fra != NULL) { 437ab25eeb5Syz155240 fra->ipfr_data = nat; 438ab25eeb5Syz155240 nat->nat_data = fra; 439f4b3ec61Sdh155122 *ifs->ifs_ipfr_nattail = fra; 440f4b3ec61Sdh155122 fra->ipfr_prev = ifs->ifs_ipfr_nattail; 441f4b3ec61Sdh155122 ifs->ifs_ipfr_nattail = &fra->ipfr_next; 442ab25eeb5Syz155240 fra->ipfr_next = NULL; 443ab25eeb5Syz155240 } 444f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 445ab25eeb5Syz155240 return fra ? 0 : -1; 446ab25eeb5Syz155240 } 447ab25eeb5Syz155240 448ab25eeb5Syz155240 449ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 450ab25eeb5Syz155240 /* Function: fr_ipid_newfrag */ 451ab25eeb5Syz155240 /* Returns: int - 0 == success, -1 == error */ 452ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 453ab25eeb5Syz155240 /* ipid(I) - new IP ID for this fragmented packet */ 454ab25eeb5Syz155240 /* */ 455ab25eeb5Syz155240 /* Create a new fragment cache entry for this packet and store, as a data */ 456ab25eeb5Syz155240 /* pointer, the new IP ID value. */ 457ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 458ab25eeb5Syz155240 int fr_ipid_newfrag(fin, ipid) 459ab25eeb5Syz155240 fr_info_t *fin; 460ab25eeb5Syz155240 u_32_t ipid; 461ab25eeb5Syz155240 { 462ab25eeb5Syz155240 ipfr_t *fra; 463f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 464ab25eeb5Syz155240 465f4b3ec61Sdh155122 if (ifs->ifs_fr_frag_lock) 466ab25eeb5Syz155240 return 0; 467ab25eeb5Syz155240 468f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_ipidfrag); 469f4b3ec61Sdh155122 fra = ipfr_newfrag(fin, 0, ifs->ifs_ipfr_ipidtab); 470ab25eeb5Syz155240 if (fra != NULL) { 471ab25eeb5Syz155240 fra->ipfr_data = (void *)(uintptr_t)ipid; 472f4b3ec61Sdh155122 *ifs->ifs_ipfr_ipidtail = fra; 473f4b3ec61Sdh155122 fra->ipfr_prev = ifs->ifs_ipfr_ipidtail; 474f4b3ec61Sdh155122 ifs->ifs_ipfr_ipidtail = &fra->ipfr_next; 475ab25eeb5Syz155240 fra->ipfr_next = NULL; 476ab25eeb5Syz155240 } 477f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 478ab25eeb5Syz155240 return fra ? 0 : -1; 479ab25eeb5Syz155240 } 480ab25eeb5Syz155240 481ab25eeb5Syz155240 482ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 483ab25eeb5Syz155240 /* Function: fr_fraglookup */ 484ab25eeb5Syz155240 /* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */ 485ab25eeb5Syz155240 /* matching entry in the frag table, else NULL */ 486ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 487ab25eeb5Syz155240 /* table(I) - pointer to fragment cache table to search */ 488ab25eeb5Syz155240 /* */ 489ab25eeb5Syz155240 /* Check the fragment cache to see if there is already a record of this */ 490ab25eeb5Syz155240 /* packet with its filter result known. */ 491ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 492ab25eeb5Syz155240 static ipfr_t *fr_fraglookup(fin, table) 493ab25eeb5Syz155240 fr_info_t *fin; 494ab25eeb5Syz155240 ipfr_t *table[]; 495ab25eeb5Syz155240 { 496ab25eeb5Syz155240 ipfr_t *f, frag; 497ab25eeb5Syz155240 u_int idx; 498f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 499ab25eeb5Syz155240 500ab25eeb5Syz155240 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 501ab25eeb5Syz155240 return NULL; 502ab25eeb5Syz155240 503ab25eeb5Syz155240 /* 504ab25eeb5Syz155240 * For fragments, we record protocol, packet id, TOS and both IP#'s 505ab25eeb5Syz155240 * (these should all be the same for all fragments of a packet). 506ab25eeb5Syz155240 * 507ab25eeb5Syz155240 * build up a hash value to index the table with. 508ab25eeb5Syz155240 */ 50972680cf5SDarren Reed idx = ipfr_index(fin, &frag); 510ab25eeb5Syz155240 511ab25eeb5Syz155240 /* 512ab25eeb5Syz155240 * check the table, careful to only compare the right amount of data 513ab25eeb5Syz155240 */ 514ab25eeb5Syz155240 for (f = table[idx]; f; f = f->ipfr_hnext) 515ab25eeb5Syz155240 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp, 516ab25eeb5Syz155240 IPFR_CMPSZ)) { 517ab25eeb5Syz155240 u_short off; 518ab25eeb5Syz155240 519ab25eeb5Syz155240 /* 520ab25eeb5Syz155240 * We don't want to let short packets match because 521ab25eeb5Syz155240 * they could be compromising the security of other 522ab25eeb5Syz155240 * rules that want to match on layer 4 fields (and 523ab25eeb5Syz155240 * can't because they have been fragmented off.) 524ab25eeb5Syz155240 * Why do this check here? The counter acts as an 525ab25eeb5Syz155240 * indicator of this kind of attack, whereas if it was 526ab25eeb5Syz155240 * elsewhere, it wouldn't know if other matching 527ab25eeb5Syz155240 * packets had been seen. 528ab25eeb5Syz155240 */ 529ab25eeb5Syz155240 if (fin->fin_flx & FI_SHORT) { 530f4b3ec61Sdh155122 ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_short); 531ab25eeb5Syz155240 continue; 532ab25eeb5Syz155240 } 533ab25eeb5Syz155240 534ab25eeb5Syz155240 /* 535ab25eeb5Syz155240 * XXX - We really need to be guarding against the 536ab25eeb5Syz155240 * retransmission of (src,dst,id,offset-range) here 537ab25eeb5Syz155240 * because a fragmented packet is never resent with 538ab25eeb5Syz155240 * the same IP ID# (or shouldn't). 539ab25eeb5Syz155240 */ 54072680cf5SDarren Reed off = fin->fin_off >> 3; 541ab25eeb5Syz155240 if (f->ipfr_seen0) { 542ab25eeb5Syz155240 if (off == 0) { 543f4b3ec61Sdh155122 ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_retrans0); 544ab25eeb5Syz155240 continue; 545ab25eeb5Syz155240 } 546ab25eeb5Syz155240 } else if (off == 0) { 547ab25eeb5Syz155240 f->ipfr_seen0 = 1; 548ab25eeb5Syz155240 } 549ab25eeb5Syz155240 550ab25eeb5Syz155240 if (f != table[idx]) { 551ab25eeb5Syz155240 ipfr_t **fp; 552ab25eeb5Syz155240 553ab25eeb5Syz155240 /* 554ab25eeb5Syz155240 * Move fragment info. to the top of the list 555ab25eeb5Syz155240 * to speed up searches. First, delink... 556ab25eeb5Syz155240 */ 557ab25eeb5Syz155240 fp = f->ipfr_hprev; 558ab25eeb5Syz155240 (*fp) = f->ipfr_hnext; 559ab25eeb5Syz155240 if (f->ipfr_hnext != NULL) 560ab25eeb5Syz155240 f->ipfr_hnext->ipfr_hprev = fp; 561ab25eeb5Syz155240 /* 562ab25eeb5Syz155240 * Then put back at the top of the chain. 563ab25eeb5Syz155240 */ 564ab25eeb5Syz155240 f->ipfr_hnext = table[idx]; 565ab25eeb5Syz155240 table[idx]->ipfr_hprev = &f->ipfr_hnext; 566ab25eeb5Syz155240 f->ipfr_hprev = table + idx; 567ab25eeb5Syz155240 table[idx] = f; 568ab25eeb5Syz155240 } 569ab25eeb5Syz155240 570ab25eeb5Syz155240 /* 571ab25eeb5Syz155240 * If we've follwed the fragments, and this is the 572ab25eeb5Syz155240 * last (in order), shrink expiration time. 573ab25eeb5Syz155240 */ 574ab25eeb5Syz155240 if (off == f->ipfr_off) { 57572680cf5SDarren Reed if (!(fin->fin_flx & FI_MOREFRAG)) 576f4b3ec61Sdh155122 f->ipfr_ttl = ifs->ifs_fr_ticks + 1; 577ab25eeb5Syz155240 f->ipfr_off = fin->fin_dlen + off; 578ab25eeb5Syz155240 } else if (f->ipfr_pass & FR_FRSTRICT) 579ab25eeb5Syz155240 continue; 580f4b3ec61Sdh155122 ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_hits); 581ab25eeb5Syz155240 return f; 582ab25eeb5Syz155240 } 583ab25eeb5Syz155240 return NULL; 584ab25eeb5Syz155240 } 585ab25eeb5Syz155240 586ab25eeb5Syz155240 587ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 588ab25eeb5Syz155240 /* Function: fr_nat_knownfrag */ 589ab25eeb5Syz155240 /* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ 590ab25eeb5Syz155240 /* match found, else NULL */ 591ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 592ab25eeb5Syz155240 /* */ 593ab25eeb5Syz155240 /* Functional interface for NAT lookups of the NAT fragment cache */ 594ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 595ab25eeb5Syz155240 nat_t *fr_nat_knownfrag(fin) 596ab25eeb5Syz155240 fr_info_t *fin; 597ab25eeb5Syz155240 { 598ab25eeb5Syz155240 nat_t *nat; 599ab25eeb5Syz155240 ipfr_t *ipf; 600f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 601ab25eeb5Syz155240 60272680cf5SDarren Reed if (ifs->ifs_fr_frag_lock || !ifs->ifs_ipfr_natlist) 603ab25eeb5Syz155240 return NULL; 604f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_natfrag); 605f4b3ec61Sdh155122 ipf = fr_fraglookup(fin, ifs->ifs_ipfr_nattab); 606ab25eeb5Syz155240 if (ipf != NULL) { 607ab25eeb5Syz155240 nat = ipf->ipfr_data; 608ab25eeb5Syz155240 /* 609ab25eeb5Syz155240 * This is the last fragment for this packet. 610ab25eeb5Syz155240 */ 611f4b3ec61Sdh155122 if ((ipf->ipfr_ttl == ifs->ifs_fr_ticks + 1) && (nat != NULL)) { 612ab25eeb5Syz155240 nat->nat_data = NULL; 613ab25eeb5Syz155240 ipf->ipfr_data = NULL; 614ab25eeb5Syz155240 } 615ab25eeb5Syz155240 } else 616ab25eeb5Syz155240 nat = NULL; 617f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 618ab25eeb5Syz155240 return nat; 619ab25eeb5Syz155240 } 620ab25eeb5Syz155240 621ab25eeb5Syz155240 622ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 623ab25eeb5Syz155240 /* Function: fr_ipid_knownfrag */ 624ab25eeb5Syz155240 /* Returns: u_32_t - IPv4 ID for this packet if match found, else */ 625ab25eeb5Syz155240 /* return 0xfffffff to indicate no match. */ 626ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 627ab25eeb5Syz155240 /* */ 628ab25eeb5Syz155240 /* Functional interface for IP ID lookups of the IP ID fragment cache */ 629ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 630ab25eeb5Syz155240 u_32_t fr_ipid_knownfrag(fin) 631ab25eeb5Syz155240 fr_info_t *fin; 632ab25eeb5Syz155240 { 633ab25eeb5Syz155240 ipfr_t *ipf; 634ab25eeb5Syz155240 u_32_t id; 635f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 636ab25eeb5Syz155240 63772680cf5SDarren Reed if (ifs->ifs_fr_frag_lock || !ifs->ifs_ipfr_ipidlist) 638ab25eeb5Syz155240 return 0xffffffff; 639ab25eeb5Syz155240 640f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_ipidfrag); 641f4b3ec61Sdh155122 ipf = fr_fraglookup(fin, ifs->ifs_ipfr_ipidtab); 642ab25eeb5Syz155240 if (ipf != NULL) 643ab25eeb5Syz155240 id = (u_32_t)(uintptr_t)ipf->ipfr_data; 644ab25eeb5Syz155240 else 645ab25eeb5Syz155240 id = 0xffffffff; 646f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 647ab25eeb5Syz155240 return id; 648ab25eeb5Syz155240 } 649ab25eeb5Syz155240 650ab25eeb5Syz155240 651ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 652ab25eeb5Syz155240 /* Function: fr_knownfrag */ 653ab25eeb5Syz155240 /* Returns: frentry_t* - pointer to filter rule if a match is found in */ 654ab25eeb5Syz155240 /* the frag cache table, else NULL. */ 655ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 656ab25eeb5Syz155240 /* passp(O) - pointer to where to store rule flags resturned */ 657ab25eeb5Syz155240 /* */ 658ab25eeb5Syz155240 /* Functional interface for normal lookups of the fragment cache. If a */ 659ab25eeb5Syz155240 /* match is found, return the rule pointer and flags from the rule, except */ 660ab25eeb5Syz155240 /* that if FR_LOGFIRST is set, reset FR_LOG. */ 661ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 662ab25eeb5Syz155240 frentry_t *fr_knownfrag(fin, passp) 663ab25eeb5Syz155240 fr_info_t *fin; 664ab25eeb5Syz155240 u_32_t *passp; 665ab25eeb5Syz155240 { 666ab25eeb5Syz155240 frentry_t *fr = NULL; 667ab25eeb5Syz155240 ipfr_t *fra; 668ab25eeb5Syz155240 u_32_t pass, oflx; 669f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 670ab25eeb5Syz155240 67172680cf5SDarren Reed if (ifs->ifs_fr_frag_lock || (ifs->ifs_ipfr_list == NULL)) 672ab25eeb5Syz155240 return NULL; 673ab25eeb5Syz155240 674f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_frag); 675ab25eeb5Syz155240 oflx = fin->fin_flx; 676f4b3ec61Sdh155122 fra = fr_fraglookup(fin, ifs->ifs_ipfr_heads); 677ab25eeb5Syz155240 if (fra != NULL) { 678ab25eeb5Syz155240 fr = fra->ipfr_rule; 679ab25eeb5Syz155240 fin->fin_fr = fr; 680ab25eeb5Syz155240 if (fr != NULL) { 681ab25eeb5Syz155240 pass = fr->fr_flags; 682ab25eeb5Syz155240 if ((pass & FR_LOGFIRST) != 0) 683ab25eeb5Syz155240 pass &= ~(FR_LOGFIRST|FR_LOG); 684ab25eeb5Syz155240 *passp = pass; 685ab25eeb5Syz155240 } 686ab25eeb5Syz155240 } 687ab25eeb5Syz155240 if (!(oflx & FI_BAD) && (fin->fin_flx & FI_BAD)) { 688ab25eeb5Syz155240 *passp &= ~FR_CMDMASK; 689ab25eeb5Syz155240 *passp |= FR_BLOCK; 690f4b3ec61Sdh155122 fr = &ifs->ifs_frblock; 691ab25eeb5Syz155240 } 692f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag); 693ab25eeb5Syz155240 return fr; 694ab25eeb5Syz155240 } 695ab25eeb5Syz155240 696ab25eeb5Syz155240 697ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 698ab25eeb5Syz155240 /* Function: fr_forget */ 699ab25eeb5Syz155240 /* Returns: Nil */ 700ab25eeb5Syz155240 /* Parameters: ptr(I) - pointer to data structure */ 701ab25eeb5Syz155240 /* */ 702ab25eeb5Syz155240 /* Search through all of the fragment cache entries and wherever a pointer */ 703ab25eeb5Syz155240 /* is found to match ptr, reset it to NULL. */ 704ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 705f4b3ec61Sdh155122 void fr_forget(ptr, ifs) 706ab25eeb5Syz155240 void *ptr; 707f4b3ec61Sdh155122 ipf_stack_t *ifs; 708ab25eeb5Syz155240 { 709ab25eeb5Syz155240 ipfr_t *fr; 710ab25eeb5Syz155240 711f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag); 712f4b3ec61Sdh155122 for (fr = ifs->ifs_ipfr_list; fr; fr = fr->ipfr_next) 713ab25eeb5Syz155240 if (fr->ipfr_data == ptr) 714ab25eeb5Syz155240 fr->ipfr_data = NULL; 715f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag); 716ab25eeb5Syz155240 } 717ab25eeb5Syz155240 718ab25eeb5Syz155240 719ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 720ab25eeb5Syz155240 /* Function: fr_forgetnat */ 721ab25eeb5Syz155240 /* Returns: Nil */ 722ab25eeb5Syz155240 /* Parameters: ptr(I) - pointer to data structure */ 723ab25eeb5Syz155240 /* */ 724ab25eeb5Syz155240 /* Search through all of the fragment cache entries for NAT and wherever a */ 725ab25eeb5Syz155240 /* pointer is found to match ptr, reset it to NULL. */ 726ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 727f4b3ec61Sdh155122 void fr_forgetnat(ptr, ifs) 728ab25eeb5Syz155240 void *ptr; 729f4b3ec61Sdh155122 ipf_stack_t *ifs; 730ab25eeb5Syz155240 { 731ab25eeb5Syz155240 ipfr_t *fr; 732ab25eeb5Syz155240 733f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag); 734f4b3ec61Sdh155122 for (fr = ifs->ifs_ipfr_natlist; fr; fr = fr->ipfr_next) 735ab25eeb5Syz155240 if (fr->ipfr_data == ptr) 736ab25eeb5Syz155240 fr->ipfr_data = NULL; 737f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 738ab25eeb5Syz155240 } 739ab25eeb5Syz155240 740ab25eeb5Syz155240 741ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 742ab25eeb5Syz155240 /* Function: fr_fragdelete */ 743ab25eeb5Syz155240 /* Returns: Nil */ 744ab25eeb5Syz155240 /* Parameters: fra(I) - pointer to fragment structure to delete */ 745ab25eeb5Syz155240 /* tail(IO) - pointer to the pointer to the tail of the frag */ 746ab25eeb5Syz155240 /* list */ 747ab25eeb5Syz155240 /* */ 748ab25eeb5Syz155240 /* Remove a fragment cache table entry from the table & list. Also free */ 749ab25eeb5Syz155240 /* the filter rule it is associated with it if it is no longer used as a */ 750ab25eeb5Syz155240 /* result of decreasing the reference count. */ 751ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 752f4b3ec61Sdh155122 static void fr_fragdelete(fra, tail, ifs) 753ab25eeb5Syz155240 ipfr_t *fra, ***tail; 754f4b3ec61Sdh155122 ipf_stack_t *ifs; 755ab25eeb5Syz155240 { 756ab25eeb5Syz155240 frentry_t *fr; 757ab25eeb5Syz155240 758ab25eeb5Syz155240 fr = fra->ipfr_rule; 759ab25eeb5Syz155240 if (fr != NULL) 760f4b3ec61Sdh155122 (void)fr_derefrule(&fr, ifs); 761ab25eeb5Syz155240 762ab25eeb5Syz155240 if (fra->ipfr_next) 763ab25eeb5Syz155240 fra->ipfr_next->ipfr_prev = fra->ipfr_prev; 764ab25eeb5Syz155240 *fra->ipfr_prev = fra->ipfr_next; 765ab25eeb5Syz155240 if (*tail == &fra->ipfr_next) 766ab25eeb5Syz155240 *tail = fra->ipfr_prev; 767ab25eeb5Syz155240 768ab25eeb5Syz155240 if (fra->ipfr_hnext) 769ab25eeb5Syz155240 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; 770ab25eeb5Syz155240 *fra->ipfr_hprev = fra->ipfr_hnext; 771f4b3ec61Sdh155122 772f4b3ec61Sdh155122 if (fra->ipfr_ref <= 0) 773ab25eeb5Syz155240 KFREE(fra); 774ab25eeb5Syz155240 } 775ab25eeb5Syz155240 776ab25eeb5Syz155240 777ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 778ab25eeb5Syz155240 /* Function: fr_fragclear */ 779ab25eeb5Syz155240 /* Returns: Nil */ 780ab25eeb5Syz155240 /* Parameters: Nil */ 781ab25eeb5Syz155240 /* */ 782ab25eeb5Syz155240 /* Free memory in use by fragment state information kept. Do the normal */ 783ab25eeb5Syz155240 /* fragment state stuff first and then the NAT-fragment table. */ 784ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 785f4b3ec61Sdh155122 void fr_fragclear(ifs) 786f4b3ec61Sdh155122 ipf_stack_t *ifs; 787ab25eeb5Syz155240 { 788ab25eeb5Syz155240 ipfr_t *fra; 789ab25eeb5Syz155240 nat_t *nat; 790ab25eeb5Syz155240 791f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag); 792f4b3ec61Sdh155122 while ((fra = ifs->ifs_ipfr_list) != NULL) { 793f4b3ec61Sdh155122 fra->ipfr_ref--; 794f4b3ec61Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs); 795f4b3ec61Sdh155122 } 796f4b3ec61Sdh155122 ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list; 797f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag); 798ab25eeb5Syz155240 799f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 800f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag); 801f4b3ec61Sdh155122 while ((fra = ifs->ifs_ipfr_natlist) != NULL) { 802ab25eeb5Syz155240 nat = fra->ipfr_data; 803ab25eeb5Syz155240 if (nat != NULL) { 804ab25eeb5Syz155240 if (nat->nat_data == fra) 805ab25eeb5Syz155240 nat->nat_data = NULL; 806ab25eeb5Syz155240 } 807f4b3ec61Sdh155122 fra->ipfr_ref--; 808f4b3ec61Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs); 809ab25eeb5Syz155240 } 810f4b3ec61Sdh155122 ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist; 811f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 812f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 813ab25eeb5Syz155240 } 814ab25eeb5Syz155240 815ab25eeb5Syz155240 816ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 817ab25eeb5Syz155240 /* Function: fr_fragexpire */ 818ab25eeb5Syz155240 /* Returns: Nil */ 819ab25eeb5Syz155240 /* Parameters: Nil */ 820ab25eeb5Syz155240 /* */ 821ab25eeb5Syz155240 /* Expire entries in the fragment cache table that have been there too long */ 822ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 823f4b3ec61Sdh155122 void fr_fragexpire(ifs) 824f4b3ec61Sdh155122 ipf_stack_t *ifs; 825ab25eeb5Syz155240 { 826ab25eeb5Syz155240 ipfr_t **fp, *fra; 827ab25eeb5Syz155240 nat_t *nat; 828ab25eeb5Syz155240 SPL_INT(s); 829ab25eeb5Syz155240 830f4b3ec61Sdh155122 if (ifs->ifs_fr_frag_lock) 831ab25eeb5Syz155240 return; 832ab25eeb5Syz155240 833ab25eeb5Syz155240 SPL_NET(s); 834f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag); 835ab25eeb5Syz155240 /* 836ab25eeb5Syz155240 * Go through the entire table, looking for entries to expire, 837f4b3ec61Sdh155122 * which is indicated by the ttl being less than or equal to 838f4b3ec61Sdh155122 * ifs_fr_ticks. 839ab25eeb5Syz155240 */ 840f4b3ec61Sdh155122 for (fp = &ifs->ifs_ipfr_list; ((fra = *fp) != NULL); ) { 841f4b3ec61Sdh155122 if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 842ab25eeb5Syz155240 break; 843f4b3ec61Sdh155122 fra->ipfr_ref--; 844f4b3ec61Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs); 845f4b3ec61Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++; 846f4b3ec61Sdh155122 ifs->ifs_ipfr_inuse--; 847ab25eeb5Syz155240 } 848f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag); 849ab25eeb5Syz155240 850f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_ipidfrag); 851f4b3ec61Sdh155122 for (fp = &ifs->ifs_ipfr_ipidlist; ((fra = *fp) != NULL); ) { 852f4b3ec61Sdh155122 if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 853ab25eeb5Syz155240 break; 854f4b3ec61Sdh155122 fra->ipfr_ref--; 855f4b3ec61Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_ipidtail, ifs); 856f4b3ec61Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++; 857f4b3ec61Sdh155122 ifs->ifs_ipfr_inuse--; 858ab25eeb5Syz155240 } 859f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 860ab25eeb5Syz155240 861ab25eeb5Syz155240 /* 862ab25eeb5Syz155240 * Same again for the NAT table, except that if the structure also 863ab25eeb5Syz155240 * still points to a NAT structure, and the NAT structure points back 864ab25eeb5Syz155240 * at the one to be free'd, NULL the reference from the NAT struct. 865ab25eeb5Syz155240 * NOTE: We need to grab both mutex's early, and in this order so as 866ab25eeb5Syz155240 * to prevent a deadlock if both try to expire at the same time. 867ab25eeb5Syz155240 */ 868f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 869f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag); 870f4b3ec61Sdh155122 for (fp = &ifs->ifs_ipfr_natlist; ((fra = *fp) != NULL); ) { 871f4b3ec61Sdh155122 if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 872ab25eeb5Syz155240 break; 873ab25eeb5Syz155240 nat = fra->ipfr_data; 874ab25eeb5Syz155240 if (nat != NULL) { 875ab25eeb5Syz155240 if (nat->nat_data == fra) 876ab25eeb5Syz155240 nat->nat_data = NULL; 877ab25eeb5Syz155240 } 878f4b3ec61Sdh155122 fra->ipfr_ref--; 879f4b3ec61Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs); 880f4b3ec61Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++; 881f4b3ec61Sdh155122 ifs->ifs_ipfr_inuse--; 882ab25eeb5Syz155240 } 883f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 884f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 885ab25eeb5Syz155240 SPL_X(s); 886ab25eeb5Syz155240 } 887ab25eeb5Syz155240 888ab25eeb5Syz155240 889ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 890ab25eeb5Syz155240 /* Function: fr_slowtimer */ 891ab25eeb5Syz155240 /* Returns: Nil */ 892ab25eeb5Syz155240 /* Parameters: Nil */ 893ab25eeb5Syz155240 /* */ 894ab25eeb5Syz155240 /* Slowly expire held state for fragments. Timeouts are set * in */ 895ab25eeb5Syz155240 /* expectation of this being called twice per second. */ 896ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 897*f56257d8SToomas Soome #if !defined(_KERNEL) || (!defined(SOLARIS) && !defined(__hpux) && \ 898*f56257d8SToomas Soome !defined(__sgi) && !defined(__osf__) && !defined(linux)) 899ab25eeb5Syz155240 # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi)) 900f4b3ec61Sdh155122 void fr_slowtimer __P((void *arg)) 901ab25eeb5Syz155240 # else 902f4b3ec61Sdh155122 int fr_slowtimer(void *arg) 903ab25eeb5Syz155240 # endif 904ab25eeb5Syz155240 { 905f4b3ec61Sdh155122 ipf_stack_t *ifs = arg; 906ab25eeb5Syz155240 907f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_global); 908f4b3ec61Sdh155122 909f4b3ec61Sdh155122 fr_fragexpire(ifs); 910f4b3ec61Sdh155122 fr_timeoutstate(ifs); 911f4b3ec61Sdh155122 fr_natexpire(ifs); 912f4b3ec61Sdh155122 fr_authexpire(ifs); 913f4b3ec61Sdh155122 ifs->ifs_fr_ticks++; 914f4b3ec61Sdh155122 if (ifs->ifs_fr_running <= 0) 915ab25eeb5Syz155240 goto done; 916ab25eeb5Syz155240 # ifdef _KERNEL 917ab25eeb5Syz155240 # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000) 918ab25eeb5Syz155240 callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL); 919ab25eeb5Syz155240 # else 920ab25eeb5Syz155240 # if defined(__OpenBSD__) 921ab25eeb5Syz155240 timeout_add(&fr_slowtimer_ch, hz/2); 922ab25eeb5Syz155240 # else 923ab25eeb5Syz155240 # if (__FreeBSD_version >= 300000) 924ab25eeb5Syz155240 fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2); 925ab25eeb5Syz155240 # else 926ab25eeb5Syz155240 # ifdef linux 927ab25eeb5Syz155240 ; 928ab25eeb5Syz155240 # else 929ab25eeb5Syz155240 timeout(fr_slowtimer, NULL, hz/2); 930ab25eeb5Syz155240 # endif 931ab25eeb5Syz155240 # endif /* FreeBSD */ 932ab25eeb5Syz155240 # endif /* OpenBSD */ 933ab25eeb5Syz155240 # endif /* NetBSD */ 934ab25eeb5Syz155240 # endif 935ab25eeb5Syz155240 done: 936f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 937ab25eeb5Syz155240 # if (BSD < 199103) || !defined(_KERNEL) 938ab25eeb5Syz155240 return 0; 939ab25eeb5Syz155240 # endif 940ab25eeb5Syz155240 } 941ab25eeb5Syz155240 #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ 942f4b3ec61Sdh155122 943f4b3ec61Sdh155122 /*ARGSUSED*/ 944f4b3ec61Sdh155122 int fr_nextfrag(token, itp, top, tail, lock, ifs) 945f4b3ec61Sdh155122 ipftoken_t *token; 946f4b3ec61Sdh155122 ipfgeniter_t *itp; 947f4b3ec61Sdh155122 ipfr_t **top, ***tail; 948f4b3ec61Sdh155122 ipfrwlock_t *lock; 949f4b3ec61Sdh155122 ipf_stack_t *ifs; 950f4b3ec61Sdh155122 { 951f4b3ec61Sdh155122 ipfr_t *frag, *next, zero; 952f4b3ec61Sdh155122 int error = 0; 953f4b3ec61Sdh155122 954f4b3ec61Sdh155122 READ_ENTER(lock); 955786c7074Sjojemann 956786c7074Sjojemann /* 957786c7074Sjojemann * Retrieve "previous" entry from token and find the next entry. 958786c7074Sjojemann */ 959786c7074Sjojemann frag = token->ipt_data; 960f4b3ec61Sdh155122 if (frag == NULL) 961f4b3ec61Sdh155122 next = *top; 962f4b3ec61Sdh155122 else 963f4b3ec61Sdh155122 next = frag->ipfr_next; 964f4b3ec61Sdh155122 965786c7074Sjojemann /* 966786c7074Sjojemann * If we found an entry, add reference to it and update token. 967786c7074Sjojemann * Otherwise, zero out data to be returned and NULL out token. 968786c7074Sjojemann */ 969f4b3ec61Sdh155122 if (next != NULL) { 970f4b3ec61Sdh155122 ATOMIC_INC(next->ipfr_ref); 971f4b3ec61Sdh155122 token->ipt_data = next; 972f4b3ec61Sdh155122 } else { 973f4b3ec61Sdh155122 bzero(&zero, sizeof(zero)); 974f4b3ec61Sdh155122 next = &zero; 975786c7074Sjojemann token->ipt_data = NULL; 976f4b3ec61Sdh155122 } 977786c7074Sjojemann 978786c7074Sjojemann /* 979786c7074Sjojemann * Now that we have ref, it's save to give up lock. 980786c7074Sjojemann */ 981f4b3ec61Sdh155122 RWLOCK_EXIT(lock); 982f4b3ec61Sdh155122 983786c7074Sjojemann /* 984786c7074Sjojemann * Copy out data and clean up references and token as needed. 985786c7074Sjojemann */ 986f4b3ec61Sdh155122 error = COPYOUT(next, itp->igi_data, sizeof(*next)); 987f4b3ec61Sdh155122 if (error != 0) 988f4b3ec61Sdh155122 error = EFAULT; 989786c7074Sjojemann if (token->ipt_data == NULL) { 990786c7074Sjojemann ipf_freetoken(token, ifs); 991786c7074Sjojemann } else { 992786c7074Sjojemann if (frag != NULL) 993786c7074Sjojemann fr_fragderef(&frag, lock, ifs); 994786c7074Sjojemann if (next->ipfr_next == NULL) 995786c7074Sjojemann ipf_freetoken(token, ifs); 996786c7074Sjojemann } 997f4b3ec61Sdh155122 return error; 998f4b3ec61Sdh155122 } 999f4b3ec61Sdh155122 1000f4b3ec61Sdh155122 1001f4b3ec61Sdh155122 void fr_fragderef(frp, lock, ifs) 1002f4b3ec61Sdh155122 ipfr_t **frp; 1003f4b3ec61Sdh155122 ipfrwlock_t *lock; 1004f4b3ec61Sdh155122 ipf_stack_t *ifs; 1005f4b3ec61Sdh155122 { 1006f4b3ec61Sdh155122 ipfr_t *fra; 1007f4b3ec61Sdh155122 1008f4b3ec61Sdh155122 fra = *frp; 1009f4b3ec61Sdh155122 *frp = NULL; 1010f4b3ec61Sdh155122 1011f4b3ec61Sdh155122 WRITE_ENTER(lock); 1012f4b3ec61Sdh155122 fra->ipfr_ref--; 1013f4b3ec61Sdh155122 if (fra->ipfr_ref <= 0) { 1014f4b3ec61Sdh155122 KFREE(fra); 1015f4b3ec61Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++; 1016f4b3ec61Sdh155122 ifs->ifs_ipfr_inuse--; 1017f4b3ec61Sdh155122 } 1018f4b3ec61Sdh155122 RWLOCK_EXIT(lock); 1019f4b3ec61Sdh155122 } 1020