fil.c revision 72680cf5a1002d05d9daaa30635598ea7db543d1
/* Parameters: fin(I) - pointer to packet information */ /* This is function enforces the 'is a packet too short to be legit' rule */ /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ /* for frpr_short() for more details. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frpr_ipv6hdr */ /* Parameters: fin(I) - pointer to packet information */ /* Copy values from the IPv6 header into the fr_info_t struct and call the */ /* per-protocol analyzer if it exists. */ /* ------------------------------------------------------------------------ */ * hop by hop ext header is only allowed * right after IPv6 header. * It is important to note that at this point, for the * extension headers (go != 0), the entire header may not have * been pulled up when the code gets to this point. This is * only done for "go != 0" because the other header handlers * will all pullup their complete header. The other indicator * of an incomplete packet is that this was just an extension /* ------------------------------------------------------------------------ */ /* Function: frpr_ipv6exthdr */ /* Returns: int - value of the next header or IPPROTO_NONE if error */ /* Parameters: fin(I) - pointer to packet information */ /* multiple(I) - flag indicating yes/no if multiple occurances */ /* of this extension header are allowed. */ /* proto(I) - protocol number for this extension header */ /* This function expects to find an IPv6 extension header at fin_dp. */ /* There must be at least 8 bytes of data at fin_dp for there to be a valid */ /* extension header present. If a good one is found, fin_dp is advanced to */ /* point at the first piece of data after the extension header, fin_exthdr */ /* points to the start of the extension header and the "protocol" of the */ /* *NEXT* header is returned. */ /* ------------------------------------------------------------------------ */ /* 8 is default length of extension hdr */ * Most IPv6 extension headers are only allowed once. /* ------------------------------------------------------------------------ */ /* Function: frpr_hopopts6 */ /* Returns: int - value of the next header or IPPROTO_NONE if error */ /* Parameters: fin(I) - pointer to packet information */ /* This is function checks pending hop by hop options extension header */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frpr_routing6 */ /* Returns: int - value of the next header or IPPROTO_NONE if error */ /* Parameters: fin(I) - pointer to packet information */ /* This is function checks pending routing extension header */ /* ------------------------------------------------------------------------ */ * Nasty extension header length? * Compensate for the changes made in frpr_ipv6exthdr() /* ------------------------------------------------------------------------ */ /* Function: frpr_fragment6 */ /* Returns: int - value of the next header or IPPROTO_NONE if error */ /* Parameters: fin(I) - pointer to packet information */ /* Examine the IPv6 fragment header and extract fragment offset information.*/ /* We don't know where the transport layer header (or whatever is next is), */ /* as it could be behind destination options (amongst others). Because */ /* there is no fragment cache, there is no knowledge about whether or not an*/ /* upper layer header has been seen (or where it ends) and thus we are not */ /* able to continue processing beyond this header with any confidence. */ /* ------------------------------------------------------------------------ */ * A fragmented IPv6 packet implies that there must be something * else after the fragment. * Fragment but no fragmentation info set? Bad packet... /* length of hdrs(after frag hdr) + data */ * If the frag is not the last one and the payload length * is not multiple of 8, it must be dropped. /* ------------------------------------------------------------------------ */ /* Function: frpr_dstopts6 */ /* Returns: int - value of the next header or IPPROTO_NONE if error */ /* Parameters: fin(I) - pointer to packet information */ /* nextheader(I) - stores next header value */ /* This is function checks pending destination options extension header */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frpr_icmp6 */ /* Parameters: fin(I) - pointer to packet information */ /* This routine is mainly concerned with determining the minimum valid size */ /* for an ICMPv6 packet. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frpr_udp6 */ /* Parameters: fin(I) - pointer to packet information */ /* Analyse the packet for IPv6/UDP properties. */ /* Is not expected to be called for fragmented packets. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frpr_tcp6 */ /* Parameters: fin(I) - pointer to packet information */ /* Analyse the packet for IPv6/TCP properties. */ /* Is not expected to be called for fragmented packets. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frpr_esp6 */ /* Parameters: fin(I) - pointer to packet information */ /* Analyse the packet for ESP properties. */ /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ /* even though the newer ESP packets must also have a sequence number that */ /* is 32bits as well, it is not possible(?) to determine the version from a */ /* simple packet header. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Parameters: fin(I) - pointer to packet information */ /* Analyse the packet for AH properties. */ /* The minimum length is taken to be the combination of all fields in the */ /* header being present and no authentication data (null algorithm used.) */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frpr_gre6 */ /* Parameters: fin(I) - pointer to packet information */ /* Analyse the packet for GRE properties. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frpr_pullup */ /* Returns: int - 0 == pullup succeeded, -1 == failure */ /* Parameters: fin(I) - pointer to packet information */ /* plen(I) - length (excluding L3 header) to pullup */ /* Short inline function to cut down on code duplication to perform a call */ /* to fr_pullup to ensure there is the required amount of data, */ /* consecutively in the packet buffer. */ /* ------------------------------------------------------------------------ */ * We don't do 'plen += ipoff;' here. The fr_pullup() will /* ------------------------------------------------------------------------ */ /* Function: frpr_short */ /* Parameters: fin(I) - pointer to packet information */ /* xmin(I) - minimum header size */ /* Check if a packet is "short" as defined by xmin. The rule we are */ /* applying here is that the packet must not be fragmented within the layer */ /* 4 header. That is, it must not be a fragment that has its offset set to */ /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ /* entire layer 4 header must be present (min). */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frpr_icmp */ /* Parameters: fin(I) - pointer to packet information */ /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ /* except extrememly bad packets, both type and code will be present. */ /* The expected minimum size of an ICMP packet is very much dependent on */ /* XXX - other ICMP sanity checks? */ /* ------------------------------------------------------------------------ */ * This is a right place to set icmp pointer, since the memory * referenced by fin_dp could get reallocated. The code down below can * rely on fact icmp variable always points to ICMP header. /* Router discovery messaes - RFC 1256 */ * type(1) + code(1) + cksum(2) + id(2) seq(2) + * type(1) + code(1) + cksum(2) + id(2) seq(2) + * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) * ICMP error packets should not be generated for IP * packets that are a fragment that isn't the first /* ------------------------------------------------------------------------ */ /* Function: frpr_tcpcommon */ /* Parameters: fin(I) - pointer to packet information */ /* TCP header sanity checking. Look for bad combinations of TCP flags, */ /* and make some checks with how they interact with other fields. */ /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ /* valid and mark the packet as bad if not. */ /* ------------------------------------------------------------------------ */ * Use of the TCP data offset *must* result in a value that is at * least the same size as the TCP header. * If the urgent flag is set, then the urgent pointer must * also be set and vice versa. Good TCP packets do not have /* Ignore this case, it shows up in "real" traffic with */ /* bogus values in the urgent pointer field. */ /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ * If the ack bit isn't set, then either the SYN or * RST bit must be set. If the SYN bit is set, then * we expect the ACK field to be 0. If the ACK is * not set and if URG, PSH or FIN are set, consdier * that to indicate a bad TCP packet. * Cisco PIX sets the ACK field to a random value. * In light of this, do not set FI_BAD until a patch * is available from Cisco to ensure that * interoperability between existing systems is /*fin->fin_flx |= FI_BAD*/;
* At this point, it's not exactly clear what is to be gained by * marking up which TCP options are and are not present. The one we * are most interested in is the TCP window scale. This is only in * a SYN packet [RFC1323] so we don't need this here...? * Now if we were to analyse the header for passive fingerprinting, * then that might add some weight to adding this... for (i =
9,
mv =
4;
mv >= 0; ) {
/* ------------------------------------------------------------------------ */ /* Function: frpr_udpcommon */ /* Parameters: fin(I) - pointer to packet information */ /* Extract the UDP source and destination ports, if present. If compiled */ /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Parameters: fin(I) - pointer to packet information */ /* Analyse the packet for IPv4/TCP properties. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Parameters: fin(I) - pointer to packet information */ /* Analyse the packet for IPv4/UDP properties. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Parameters: fin(I) - pointer to packet information */ /* Analyse the packet for ESP properties. */ /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ /* even though the newer ESP packets must also have a sequence number that */ /* is 32bits as well, it is not possible(?) to determine the version from a */ /* simple packet header. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Parameters: fin(I) - pointer to packet information */ /* Analyse the packet for AH properties. */ /* The minimum length is taken to be the combination of all fields in the */ /* header being present and no authentication data (null algorithm used.) */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Parameters: fin(I) - pointer to packet information */ /* Analyse the packet for GRE properties. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frpr_ipv4hdr */ /* Parameters: fin(I) - pointer to packet information */ /* Analyze the IPv4 header and set fields in the fr_info_t structure. */ /* Check all options present and flag their presence if any exist. */ /* ------------------------------------------------------------------------ */ /* Get both TTL and protocol */ /* Zero out bits not used in IPv6 address */ * set packet attribute flags based on the offset and * calculate the byte offset that it represents. * The length of the packet, starting at its * offset cannot exceed 65535 (0xffff) as the * length of an IP packet is only 16 bits. * Any fragment that isn't the last fragment * must have a length greater than 0 and it * must be an even multiple of 8. * Call per-protocol setup and checking * If it is a standard IP header (no options), set the flag fields * which relate to options to 0. * So the IP header has some IP options attached. Walk the entire * list of options present with this packet and set flags to indicate * which ones are here and which ones are not. For the somewhat out * of date and obscure security classification options, set a flag to * represent which classification is present. for (i =
9,
mv =
4;
mv >= 0; ) {
sec = *(s +
2);
/* classification */ for (j =
3, m =
2; m >= 0; ) {
/* ------------------------------------------------------------------------ */ /* Function: fr_makefrip */ /* Returns: int - 1 == hdr checking error, 0 == OK */ /* Parameters: hlen(I) - length of IP packet header */ /* ip(I) - pointer to the IP header */ /* fin(IO) - pointer to packet information */ /* Compact the IP header into a structure which contains just the info. */ /* which is useful for comparing IP headers with and store this information */ /* in the fr_info_t structure pointer to by fin. At present, it is assumed */ /* this function will be called with either an IPv4 or IPv6 packet. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_portcheck */ /* Returns: int - 1 == port matched, 0 == port match failed */ /* Parameters: frp(I) - pointer to port check `expression' */ /* pop(I) - pointer to port number to evaluate */ /* Perform a comparison of a port number against some other(s), using a */ /* structure with compare information stored in it. */ /* ------------------------------------------------------------------------ */ * Do opposite test to that required and continue if that succeeds. if (
tup !=
po)
/* EQUAL */ if (
tup ==
po)
/* NOTEQUAL */ if (
tup >=
po)
/* LESSTHAN */ if (
tup <=
po)
/* GREATERTHAN */ if (
tup >
po)
/* LT or EQ */ if (
tup <
po)
/* GT or EQ */ /* ------------------------------------------------------------------------ */ /* Function: fr_tcpudpchk */ /* Returns: int - 1 == protocol matched, 0 == check failed */ /* Parameters: fin(I) - pointer to packet information */ /* ft(I) - pointer to structure with comparison data */ /* Compares the current pcket (assuming it is TCP/UDP) information with a */ /* structure containing information that we want to match against. */ /* ------------------------------------------------------------------------ */ * Both ports should *always* be in the first fragment. * So far, I cannot find any cases where they can not be. * compare destination ports * If we don't have all the TCP/UDP header, then how can we * expect to do any sort of match on it ? If we were looking for * TCP flags, then NO match. If not, then match (which should * satisfy the "short" class too). * Match the flags ? If not, abort this match. /* ------------------------------------------------------------------------ */ /* Function: fr_ipfcheck */ /* Returns: int - 0 == match, 1 == no match */ /* Parameters: fin(I) - pointer to packet information */ /* fr(I) - pointer to filter rule */ /* portcmp(I) - flag indicating whether to attempt matching on */ /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ /* ------------------------------------------------------------------------ */ * first 32 bits to check coversion: * IP version, TOS, TTL, protocol FR_DEBUG((
"0. %#08x & %#08x != %#08x\n",
* Next 32 bits is a constructed bitmask indicating which IP options * are present (if any) in this packet. FR_DEBUG((
"1. %#08x & %#08x != %#08x\n",
* Unrolled loops (4 each, for 32 bits) for address checks. * Check the source address. FR_DEBUG((
"2a. %#08x & %#08x != %#08x\n",
FR_DEBUG((
"2b. %#08x & %#08x != %#08x\n",
FR_DEBUG((
"2c. %#08x & %#08x != %#08x\n",
FR_DEBUG((
"2d. %#08x & %#08x != %#08x\n",
* Check the destination address. FR_DEBUG((
"3a. %#08x & %#08x != %#08x\n",
FR_DEBUG((
"3b. %#08x & %#08x != %#08x\n",
FR_DEBUG((
"3c. %#08x & %#08x != %#08x\n",
FR_DEBUG((
"3d. %#08x & %#08x != %#08x\n",
* IP addresses matched. The next 32bits contains: * mast of old IP header security & authentication bits. FR_DEBUG((
"4. %#08x & %#08x != %#08x\n",
* Next we have 32 bits of packet flags. FR_DEBUG((
"5. %#08x & %#08x != %#08x\n",
* If a fragment, then only the first has what we're /* ------------------------------------------------------------------------ */ /* Function: fr_scanlist */ /* Returns: int - result flags of scanning filter list */ /* Parameters: fin(I) - pointer to packet information */ /* pass(I) - default result to return for filtering */ /* Check the input/output list of rules for a match to the current packet. */ /* If a match is found, the value of fr_flags from the rule becomes the */ /* return value and fin->fin_fr points to the matched rule. */ /* This function may be called recusively upto 16 times (limit inbuilt.) */ /* When unwinding, it should finish up with fin_depth as 0. */ /* Could be per interface, but this gets real nasty when you don't have, */ /* or can't easily change, the kernel source code to . */ /* ------------------------------------------------------------------------ */ * Do not allow nesting deeper than 16 levels. * If there are no rules in this list, return now. * In all checks below, a null (zero) value in the * filter struture is taken to mean a wildcard. * check that we are working for the right interface * Allowing a rule with the "keep state" flag set to match * packets that have been tagged "out of window" by the TCP * state tracking is foolish as the attempt to add a new * state entry to the table will fail. * If the rule is a "call now" rule, then call the function * in the rule, if it exists and use the results from that. * If the function pointer is bad, just make like we ignore * it, except for increasing the hit counter. * Just log this packet... #
endif /* IPFILTER_LOG */ * Finally, if we've asked to track state for this * packet, set it up. Add state for "quick" rules * here so that if the action fails we can consider * the rule to "not match" and keep on processing /* ------------------------------------------------------------------------ */ /* Function: fr_acctpkt */ /* Returns: frentry_t* - always returns NULL */ /* Parameters: fin(I) - pointer to packet information */ /* passp(IO) - pointer to current/new filter decision (unused) */ /* Checks a packet against accounting rules, if there are any for the given */ /* IP protocol version. */ /* N.B.: this function returns NULL to match the prototype used by other */ /* functions called from the IPFilter "mainline" in fr_check(). */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_firewall */ /* Returns: frentry_t* - returns pointer to matched rule, if no matches */ /* were found, returns NULL. */ /* Parameters: fin(I) - pointer to packet information */ /* passp(IO) - pointer to current/new filter decision (unused) */ /* Applies an appropriate set of firewall rules to the packet, to see if */ /* there are any matches. The first check is to see if a match can be seen */ /* in the cache. If not, then search an appropriate list of rules. Once a */ /* matching rule is found, take any appropriate actions as defined by the */ /* rule - except logging. */ /* ------------------------------------------------------------------------ */ * Apply packets per second rate-limiting to a rule as required. * If we fail to add a packet to the authorization queue, then we * drop the packet later. However, if it was added then pretend * we've dropped it already. * If a rule is a pre-auth rule, check again in the list of rules * loaded for authenticated use. It does not particulary matter * if this search fails because a "preauth" result, from a rule, * is treated as "not a pass", hence the packet is blocked. * If the rule has "keep frag" and the packet is actually a fragment, * then create a fragment state entry. * Finally, if we've asked to track state for this packet, set it up. /* ------------------------------------------------------------------------ */ /* Returns: int - 0 == packet allowed through, */ /* -1 == packet blocked */ /* 1 == packet not matched */ /* -2 == requires authentication */ /* > 0 == filter error # for packet */ /* Parameters: ip(I) - pointer to start of IPv4/6 packet */ /* hlen(I) - length of header */ /* ifp(I) - pointer to interface this packet is on */ /* out(I) - 0 == packet going in, 1 == packet going out */ /* mp(IO) - pointer to caller's buffer pointer that holds this */ /* Solaris & HP-UX ONLY : */ /* qpi(I) - pointer to STREAMS queue information for this */ /* interface & direction. */ /* fr_check() is the master function for all IPFilter packet processing. */ /* It orchestrates: Network Address Translation (NAT), checking for packet */ /* authorisation (or pre-authorisation), presence of related state info., */ /* generating log entries, IP packet accounting, routing of packets as */ /* directed by firewall rules and of course whether or not to allow the */ /* packet to be further processed by the kernel. */ /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ /* freed. Packets passed may be returned with the pointer pointed to by */ /* by "mp" changed to a new buffer. */ /* ------------------------------------------------------------------------ */ * The above really sucks, but short of writing a diff * The first part of fr_check() deals with making sure that what goes * into the filtering engine makes some sense. Information about the * the packet is distilled, collected into a fr_info_t structure and * the an attempt to ensure the buffer the packet is in is big enough * to hold all the required packet headers. * XXX For now, IP Filter and fast-forwarding of cached flows * XXX are mutually exclusive. Eventually, IP Filter should * XXX get a "can-fast-forward" filter rule. #
endif /* M_CANFASTFWD */ * disable delayed checksums. #
endif /* CSUM_DELAY_DATA */ * Jumbo grams are quite likely too big for internal buffer * structures to handle comfortably, for now, so just drop * For at least IPv6 packets, if a m_pullup() fails then this pointer * becomes NULL and so we have no packet to free. * Check auth now. This, combined with the check below to see if apass * is 0 is to ensure that we don't count the packet twice, which can * otherwise occur when we reprocess it. As it is, we only count it * after it has no auth. table matchup. This also stops NAT from * occuring until after the packet has been auth'd. * The FI_STATE flag is cleared here so that calling fr_checkstate * will work when called from inside of fr_fastroute. Although * there is a similar flag, FI_NATED, for NAT, it does have the same * impact on code execution. * Only allow FR_DUP to work if a rule matched - it makes no sense to * set FR_DUP as a "default" as there are no instructions about where * to send the packet. Use fin_m here because it may have changed * (without an update of 'm') in prior processing. * Should we return an ICMP packet to indicate error * status passing through the packet filter ? * WARNING: ICMP error packets AND TCP RST packets should * ONLY be sent in repsonse to incoming packets. Sending them * in response to outbound packets can result in a panic on * some operating systems. * Assume it's possible to enter insane rule: * pass return-icmp in proto udp ... * then we have no other option than to forward * packet on loopback and give up any attempt * to create a fake response. * we drop packet silently in case we * failed assemble fake response for it #
endif /* _KERNEL && SOLARIS2 >= 10 */ * Assume it's possible to enter insane rule: * pass return-rst in proto tcp ... * then we have no other option than to forward * packet on loopback and give up any attempt * to create a fake response. * we drop packet silently in case we * failed assemble fake response for it #
endif /* _KERNEL && _SOLARIS2 >= 10 */ * If we didn't drop off the bottom of the list of rules (and thus * the 'current' rule fr is not NULL), then we may have some extra * instructions about what to do with a packet. * Once we're finished return to our caller, freeing the packet if * we are dropping it (* BSD ONLY *). * Reassign m from fin_m as we may have a new buffer, now. * For fastroute rule, no destioation interface defined * so pass NULL as the frdest_t parameter /* this is for to rules: */ * Generate a duplicated packet. * This late because the likes of fr_fastroute() use fin_fr. /* ------------------------------------------------------------------------ */ /* Returns: frentry_t* - returns contents of fin_fr (no change made) */ /* Parameters: fin(I) - pointer to packet information */ /* passp(IO) - pointer to current/new filter decision (unused) */ /* Checks flags set to see how a packet should be logged, if it is to be */ /* logged. Adjust statistics based on its success or not. */ /* ------------------------------------------------------------------------ */ * If the "or-block" option has been used then * block the packet if we failed to log it. #
endif /* IPFILTER_LOG *//* ------------------------------------------------------------------------ */ /* Function: ipf_cksum */ /* Returns: u_short - IP header checksum */ /* Parameters: addr(I) - pointer to start of buffer to checksum */ /* len(I) - length of buffer in bytes */ /* Calculate the two's complement 16 bit checksum of the buffer passed. */ /* N.B.: addr should be 16bit aligned. */ /* ------------------------------------------------------------------------ */ /* mop up an odd byte, if necessary */ * add back carry outs from top 16 bits to low 16 bits sum = (
sum >>
16) + (
sum &
0xffff);
/* add hi 16 to low 16 */ sum += (
sum >>
16);
/* add carry */ /* ------------------------------------------------------------------------ */ /* Returns: u_short - layer 4 checksum */ /* Parameters: m(I ) - pointer to buffer holding packet */ /* ip(I) - pointer to IP header */ /* l4proto(I) - protocol to caclulate checksum for */ /* l4hdr(I) - pointer to layer 4 header */ /* Calculates the TCP checksum for the packet held in "m", using the data */ /* in the IP header "ip" to seed it. */ /* NB: This function assumes we've pullup'd enough for all of the IP header */ /* and the TCP header. We also assume that data blocks aren't allocated in */ /* Expects ip_len to be in host byte order when called. */ /* ------------------------------------------------------------------------ */ * Add up IP Header portion sum += *
sp++;
/* ip_src */ sum += *
sp++;
/* ip_dst */ sum += *
sp++;
/* ip6_src */ sum += *
sp++;
/* ip6_dst */ #
if defined(
BSD) ||
defined(
sun)
* Both sum and sum2 are partial sums, so combine them together. #
else /* defined(BSD) || defined(sun) */ * Add up IP Header portion sum += *
sp++;
/* sport */ sum += *
sp++;
/* dport */ sum += *
sp++;
/* udp length */ sum += *
sp++;
/* checksum */ sum += *
sp++;
/* sport */ sum += *
sp++;
/* dport */ sum += *
sp++;
/* checksum */ sum += *
sp++;
/* checksum */ * In case we had to copy the IP & TCP header out of mbufs, * skip over the mbuf bits which are the header PANIC((!m),(
"fr_cksum(1): not enough data"));
PANIC((!m),(
"fr_cksum(2): not enough data"));
PANIC((!m),(
"fr_cksum(3): not enough data"));
#
endif /* defined(BSD) || defined(sun) */ * Copyright (c) 1982, 1986, 1988, 1991, 1993 * The Regents of the University of California. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * $Id: fil.c,v 2.243.2.64 2005/08/13 05:19:59 darrenr Exp $ * Copy data from an mbuf chain starting "off" bytes from the beginning, * continuing for "len" bytes, into the indicated buffer. * Copy data from a buffer back into the indicated mbuf chain, * starting "off" bytes from the beginning, extending the mbuf #
endif /* (_KERNEL) && ( ((BSD < 199103) && !MENTAT) || __sgi) *//* ------------------------------------------------------------------------ */ /* Function: fr_findgroup */ /* Returns: frgroup_t * - NULL = group not found, else pointer to group */ /* Parameters: group(I) - group name to search for */ /* unit(I) - device to which this group belongs */ /* fgpp(O) - pointer to place to store pointer to the pointer */ /* to where to add the next (last) group or where */ /* to delete group from. */ /* Search amongst the defined groups for a particular group number. */ /* ------------------------------------------------------------------------ */ * Which list of groups to search in is dependent on which list of * rules are being operated on. /* ------------------------------------------------------------------------ */ /* Function: fr_addgroup */ /* Returns: frgroup_t * - NULL == did not create group, */ /* != NULL == pointer to the group */ /* Parameters: num(I) - group number to add */ /* head(I) - rule pointer that is using this as the head */ /* flags(I) - rule flags which describe the type of rule it is */ /* unit(I) - device to which this group will belong to */ /* Write Locks: ipf_mutex */ /* Add a new group head, or if it already exists, increase the reference */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_delgroup */ /* Parameters: group(I) - group name to delete */ /* unit(I) - device to which this group belongs */ /* Write Locks: ipf_mutex */ /* Attempt to delete a group head. */ /* Only do this when its reference count reaches 0. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_getrulen */ /* Returns: frentry_t * - NULL == not found, else pointer to rule n */ /* Parameters: unit(I) - device for which to count the rule's number */ /* flags(I) - which set of rules to find the rule in */ /* group(I) - group name */ /* n(I) - rule number to find */ /* Find rule # n in group # g and return a pointer to it. Return NULl if */ /* group # g doesn't exist or there are less than n rules in the group. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Returns: int - >= 0 - rule number, -1 == search failed */ /* Parameters: unit(I) - device for which to count the rule's number */ /* fr(I) - pointer to rule to match */ /* Return the number for a rule on a specific filtering device. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frflushlist */ /* Returns: int - >= 0 - number of flushed rules */ /* unit(I) - device for which to flush rules */ /* flags(I) - which set of rules to flush */ /* nfreedp(O) - pointer to int where flush count is stored */ /* listp(I) - pointer to list to flush pointer */ /* Write Locks: ipf_mutex */ /* Recursively flush rules from the list, descending groups as they are */ /* encountered. if a rule is the head of a group and it has lost all its */ /* group members, then also delete the group reference. nfreedp is needed */ /* to store the accumulating count of rules removed, whereas the returned */ /* value is just the number removed from the current list. The latter is */ /* needed to correctly adjust reference counts on rules that define groups. */ /* NOTE: Rules not loaded from user space cannot be flushed. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Returns: int - >= 0 - number of flushed rules */ /* Parameters: unit(I) - device for which to flush rules */ /* flags(I) - which set of rules to flush */ /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ /* and IPv6) as defined by the value of flags. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ /* Parameters: src(I) - pointer to byte sequence to match */ /* dst(I) - pointer to byte sequence to search */ /* slen(I) - match length */ /* dlen(I) - length available to search in */ /* Search dst for a sequence of bytes matching those at src and extend for */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_fixskip */ /* Parameters: listp(IO) - pointer to start of list with skip rule */ /* addremove(I) - adjustment (-1/+1) to make to skip count, */ /* depending on whether a rule was just added */ /* Adjust all the rules in a list which would have skip'd past the position */ /* where we are inserting to skip to the right place given the change. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: count4bits */ /* Returns: int - >= 0 - number of consecutive bits in input */ /* Parameters: ip(I) - 32bit IP address */ /* count consecutive 1's in bit mask. If the mask generated by counting */ /* consecutive 1's is different to that passed, return -1, else return # */ /* ------------------------------------------------------------------------ */ for (i =
32; i; i--,
ipn *=
2)
for (i =
32, j =
cnt; i; i--, j--) {
/* ------------------------------------------------------------------------ */ /* Function: count6bits */ /* Returns: int - >= 0 - number of consecutive bits in input */ /* Parameters: msk(I) - pointer to start of IPv6 bitmask */ /* count consecutive 1's in bit mask. */ /* ------------------------------------------------------------------------ */ if (
msk[k] ==
0xffffffff)
for (j =
msk[k]; j; j <<=
1)
/* ------------------------------------------------------------------------ */ /* Function: fr_ifsync */ /* Returns: void * - new interface identifier */ /* Parameters: action(I) - type of synchronisation to do */ /* v(I) - IP version being sync'd (v4 or v6) */ /* oldifp(I) - interface identifier in a filter rule */ /* newname(I) - name associated with newifp interface */ /* oldname(I) - name associated with oldifp interface */ /* ifs - pointer to IPF stack instance */ /* This function returns what the new value for "oldifp" should be for its */ /* caller. In some cases it will not change, in some it will. */ /* action == IPFSYNC_RESYNC */ /* a new value for oldifp will always be looked up, according to oldname, */ /* the values of newname and newifp are ignored. */ /* action == IPFSYNC_NEWIFP */ /* if oldname matches newname then we are doing a sync for the matching */ /* interface, so we return newifp to be used in place of oldifp. If the */ /* the names don't match, just return oldifp. */ /* action == IPFSYNC_OLDIFP */ /* if oldifp matches newifp then we are are doing a sync to remove any */ /* references to oldifp, so we return "-1". */ /* This function processes NIC event from PF_HOOKS. The action parameter */ /* is set in ipf_nic_event_v4()/ipf_nic_event_v6() function. There is */ /* one single switch statement() in ipf_nic_event_vx() function, which */ /* translates the HOOK event type to action parameter passed to fr_ifsync. */ /* The translation table looks as follows: */ /* ----------------+------------- */ /* NE_PLUMB | IPFSYNC_NEWIFP */ /* NE_UNPLUMB | IPFSYNC_OLDIFP */ /* NE_ADDRESS_CHANGE | IPFSYNC_RESYNC */ /* The oldname and oldifp parameters are taken from IPF entry (rule, state */ /* table entry, NAT table entry, fragment ...). The newname and newifp */ /* parameters come from hook event data, parameters are taken from event */ /* in ipf_nic_event_vx() functions. Any time NIC changes, the IPF is */ /* notified by hook function. */ /* We get NE_UNPLUMB event from PF_HOOKS even if someone coincidently tries */ /* to plumb the interface, which is already plumbed. In such case we always */ /* get the event from PF_HOOKS as follows: */ /* ------------------------------------------------------------------------ */ * If interface gets unplumbed it must be invalidated, which * means set all existing references to the interface to -1. * We don't want to invalidate references for wildcard * (unbound) rules (entries). /* ------------------------------------------------------------------------ */ /* Function: frsynclist */ /* Parameters: action(I) - type of synchronisation to do */ /* v(I) - IP version being sync'd (v4 or v6) */ /* ifp(I) - interface identifier associated with action */ /* ifname(I) - name associated with ifp parameter */ /* fr(I) - pointer to filter rule */ /* ifs - pointer to IPF stack instance */ /* Write Locks: ipf_mutex */ /* Walk through a list of filter rules and resolve any interface names into */ /* pointers. Where dynamic addresses are used, also update the IP address */ /* used in the rule. The interface pointer is used to limit the lookups to */ /* a specific set of matching names if it is non-NULL. */ /* ------------------------------------------------------------------------ */ * Lookup all the interface names that are part of the rule. for (i = 0; i <
4; i++) {
/* ------------------------------------------------------------------------ */ /* Parameters: action(I) - type of synchronisation to do */ /* v(I) - IP version being sync'd (v4 or v6) */ /* ifp(I) - interface identifier associated with action */ /* name(I) - name associated with ifp parameter */ /* frsync() is called when we suspect that the interface list or */ /* information about interfaces (like IP#) has changed. Go through all */ /* filter rules, NAT entries and the state table and check if anything */ /* With the filtering hooks added to Solaris, we needed to change the manner*/ /* in which this was done to support three different types of sync: */ /* - new interface being announced with its name and identifier */ /* - interface removal being announced by only its identifier */ /* ------------------------------------------------------------------------ */ * In the functions below, bcopy() is called because the pointer being * copied _from_ in this instance is a pointer to a char buf (which could * end up being unaligned) and on the kernel's local stack. /* ------------------------------------------------------------------------ */ /* Function: copyinptr */ /* Returns: int - 0 = success, else failure */ /* Parameters: src(I) - pointer to the source address */ /* dst(I) - destination address */ /* size(I) - number of bytes to copy */ /* Copy a block of data in from user space, given a pointer to the pointer */ /* to start copying from (src) and a pointer to where to store it (dst). */ /* NB: src - pointer to user space pointer, dst - kernel space pointer */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: copyoutptr */ /* Returns: int - 0 = success, else failure */ /* Parameters: src(I) - pointer to the source address */ /* dst(I) - destination address */ /* size(I) - number of bytes to copy */ /* Copy a block of data out to user space, given a pointer to the pointer */ /* to start copying from (src) and a pointer to where to store it (dst). */ /* NB: src - kernel space pointer, dst - pointer to user space pointer. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Returns: int - 0 = success, else error */ /* Parameters: data(I) - pointer to lock value to set */ /* lockp(O) - pointer to location to store old lock value */ /* Get the new value for the lock integer, set it and return the old value */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_getstat */ /* Parameters: fiop(I) - pointer to ipfilter stats structure */ /* Stores a copy of current pointers, counters, etc, in the friostat */ /* ------------------------------------------------------------------------ */ for (j = 0; j <
2; j++) {
-
1,
/* 4: ICMP_SOURCEQUENCH */ -
1,
/* 13: ICMP_TSTAMP */ -
1,
/* 14: ICMP_TSTAMPREPLY */ -
1,
/* 16: ICMP_IREQREPLY */ -
1,
/* 17: ICMP_MASKREQ */ -
1,
/* 18: ICMP_MASKREPLY */ -
1,
/* 2: ICMP_UNREACH_PROTOCOL */ -
1,
/* 4: ICMP_UNREACH_NEEDFRAG */ -
1,
/* 8: ICMP_UNREACH_ISOLATED */ -
1,
/* 11: ICMP_UNREACH_TOSNET */ -
1,
/* 12: ICMP_UNREACH_TOSHOST *//* ------------------------------------------------------------------------ */ /* Function: fr_matchicmpqueryreply */ /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ /* Parameters: v(I) - IP protocol version (4 or 6) */ /* ic(I) - ICMP information */ /* icmp(I) - ICMP packet header */ /* rev(I) - direction (0 = forward/1 = reverse) of packet */ /* Check if the ICMP packet defined by the header pointed to by icmp is a */ /* reply to one as described by what's in ic. If it is a match, return 1, */ /* else return 0 for no match. */ /* ------------------------------------------------------------------------ */ * If we matched its type on the way in, then when going out * it will still be the same type. /* ------------------------------------------------------------------------ */ /* Function: fr_resolvelookup */ /* Returns: void * - NULL = failure, else success. */ /* Parameters: type(I) - type of lookup these parameters are for. */ /* number(I) - table number to use when searching */ /* funcptr(IO) - pointer to pointer for storing IP address */ /* searching function. */ /* Search for the "table" number passed in amongst those configured for */ /* that particular type. If the type is recognised then the function to */ /* call to do the IP address search will be change, regardless of whether */ /* or not the "table" number exists. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: frrequest */ /* Returns: int - 0 == success, > 0 == errno value */ /* Parameters: unit(I) - device for which this is for */ /* req(I) - ioctl command (SIOC*) */ /* data(I) - pointr to ioctl data */ /* set(I) - 1 or 0 (filter set) */ /* makecopy(I) - flag indicating whether data points to a rule */ /* in kernel space & hence doesn't need copying. */ /* This function handles all the requests which operate on the list of */ /* filter rules. This includes adding, deleting, insertion. It is also */ /* responsible for creating groups when a "head" rule is loaded. Interface */ /* names are resolved here and other sanity checks are made on the content */ /* of the rule structure being loaded. If a rule has user defined timeouts */ /* then make sure they are created and initialised before exiting. */ /* ------------------------------------------------------------------------ */ * Only filter rules for IPv4 or IPv6 are accepted. * If the rule is being loaded from user space, i.e. we had to copy it * into kernel space, then do not trust the function pointer in the * Check that the group number does exist and that its use (in/out) * matches what the rule is. * Work out which rule list this change is being applied to. * Copy in extra data for the rule. * Perform per-rule type sanity checks of their members. * Allowing a rule with both "keep state" and "with oow" is * pointless because adding a state entry to the table will * fail with the out of window (oow) flag set. * Lookup all the interface names that are part of the rule. * Look for an existing matching filter rule, but don't include the * next or interface pointer in the comparison (fr_next, fr_ifa). * This elminates rules which are indentical being loaded. Checksum * the constant part of the filter rule to make comparisons quicker * (this meaning no pointers are included). * If zero'ing statistics, copy current to caller and zero. * Copy and reduce lock because of impending copyout. * Well we should, but if we do then the atomicity of * this call and the correctness of fr_hits and * fr_bytes cannot be guaranteed. As it is, this code * only resets them to 0 if they are successfully * copied out into user space. bcopy((
char *)f, (
char *)
fp,
sizeof(*f));
* When we copy this rule back out, set the data * pointer to be what it was in user space. * At the end of this, ftail must point to the place where the * For SIOCAD*FR, this should be the last rule in the group of * rules that have equal fr_collect fields. * Request to remove a rule. * Do not allow activity from user space to interfere * with rules not loaded that way. * Return EBUSY if the rule is being reference by * something else (eg state information. /* ------------------------------------------------------------------------ */ /* Function: fr_funcinit */ /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ /* Parameters: fr(I) - pointer to filter rule */ /* If a rule is a call rule, then check if the function it points to needs */ /* an init function to be called now the rule has been loaded. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_findfunc */ /* Returns: ipfunc_t - pointer to function if found, else NULL */ /* Parameters: funcptr(I) - function pointer to lookup */ /* Look for a function in the table of known functions. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_resolvefunc */ /* Returns: int - 0 == success, else error */ /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ /* This will either be the function name (if the pointer is set) or the */ /* function pointer if the name is set. When found, fill in the other one */ /* so that the entire, complete, structure can be copied back to user space.*/ /* ------------------------------------------------------------------------ */ * ppsratecheck(): packets (or events) per second limitation. int maxpps;
/* maximum pps allowed */ * check for 0,0 is so that the message will be seen at least once. * if more than one second have passed since the last update of * lasttime, reset the counter. * we do increment *curpps even in *curpps < maxpps case, as some may * try to use *curpps for stat purposes as well. /* ------------------------------------------------------------------------ */ /* Function: fr_derefrule */ /* Returns: int - 0 == rule freed up, else rule not freed */ /* Parameters: fr(I) - pointer to filter rule */ /* Decrement the reference counter to a rule by one. If it reaches zero, */ /* free it and any associated storage space being used by it. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_grpmapinit */ /* Returns: int - 0 == success, else ESRCH because table entry not found*/ /* Parameters: fr(I) - pointer to rule to find hash table for */ /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ /* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_srcgrpmap */ /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ /* Parameters: fin(I) - pointer to packet information */ /* passp(IO) - pointer to current/new filter decision (unused) */ /* Look for a rule group head in a hash table, using the source address as */ /* the key, and descend into that group and continue matching rules against */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_dstgrpmap */ /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ /* Parameters: fin(I) - pointer to packet information */ /* passp(IO) - pointer to current/new filter decision (unused) */ /* Look for a rule group head in a hash table, using the destination */ /* address as the key, and descend into that group and continue matching */ /* rules against the packet. */ /* ------------------------------------------------------------------------ */ #
endif /* IPFILTER_LOOKUP */ * These functions manage objects on queues for efficient timeouts. There are * a number of system defined queues as well as user defined timeouts. It is * expected that a lock is held in the domain in which the queue belongs * (i.e. either state or NAT) when calling any of these functions that prevents * fr_freetimeoutqueue() from being called at the same time as any other. /* ------------------------------------------------------------------------ */ /* Function: fr_addtimeoutqueue */ /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ /* timeout queue with given interval. */ /* Parameters: parent(I) - pointer to pointer to parent node of this list */ /* of interface queues. */ /* seconds(I) - timeout value in seconds for this queue. */ /* This routine first looks for a timeout queue that matches the interval */ /* being requested. If it finds one, increments the reference counter and */ /* returns a pointer to it. If none are found, it allocates a new one and */ /* inserts it at the top of the list. */ /* It is assumed that the caller of this function has an appropriate lock */ /* held (exclusively) in the domain that encompases 'parent'. */ /* ------------------------------------------------------------------------ */ * Reset the delete flag, if set, so the structure * gets reused rather than freed and reallocated. /* ------------------------------------------------------------------------ */ /* Function: fr_deletetimeoutqueue */ /* Returns: int - new reference count value of the timeout queue */ /* Parameters: ifq(I) - timeout queue which is losing a reference. */ /* Locks: ifq->ifq_lock */ /* This routine must be called when we're discarding a pointer to a timeout */ /* queue object, taking care of the reference counter. */ /* Now that this just sets a DELETE flag, it requires the expire code to */ /* check the list of user defined timeout queues and call the free function */ /* below (currently commented out) to stop memory leaking. It is done this */ /* way because the locking may not be sufficient to safely do a free when */ /* this function is called. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_freetimeoutqueue */ /* Parameters: ifq(I) - timeout queue which is losing a reference. */ /* It is assumed that the caller of this function has an appropriate lock */ /* held (exclusively) in the domain that encompases the callers "domain". */ /* The ifq_lock for this structure should not be held. */ /* Remove a user definde timeout queue from the list of queues it is in and */ /* tidy up after this is done. */ /* ------------------------------------------------------------------------ */ printf(
"fr_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
* Remove from its position in the list. /* ------------------------------------------------------------------------ */ /* Function: fr_deletequeueentry */ /* Parameters: tqe(I) - timeout queue entry to delete */ /* ifq(I) - timeout queue to remove entry from */ /* Remove a tail queue entry from its queue and make it an orphan. */ /* fr_deletetimeoutqueue is called to make sure the reference count on the */ /* queue is correct. We can't, however, call fr_freetimeoutqueue because */ /* the correct lock(s) may not be held that would make it safe to do so. */ /* ------------------------------------------------------------------------ */ else /* we must be the tail anyway */ /* ------------------------------------------------------------------------ */ /* Function: fr_queuefront */ /* Parameters: tqe(I) - pointer to timeout queue entry */ /* Move a queue entry to the front of the queue, if it isn't already there. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_queueback */ /* Parameters: tqe(I) - pointer to timeout queue entry */ /* Move a queue entry to the back of the queue, if it isn't already there. */ /* ------------------------------------------------------------------------ */ * Make it the last entry. /* ------------------------------------------------------------------------ */ /* Function: fr_queueappend */ /* Parameters: tqe(I) - pointer to timeout queue entry */ /* ifq(I) - pointer to timeout queue */ /* parent(I) - owing object pointer */ /* Add a new item to this queue and put it on the very end. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_movequeue */ /* Parameters: tq(I) - pointer to timeout queue information */ /* oifp(I) - old timeout queue entry was on */ /* nifp(I) - new timeout queue to put entry on */ /* ifs - ipf stack instance */ /* Move a queue entry from one timeout queue to another timeout queue. */ /* If it notices that the current entry is already last and does not need */ /* to move queue, the return. */ /* ------------------------------------------------------------------------ */ * If the queue isn't changing, and the clock hasn't ticked * since the last update, the operation will be a no-op. * Grab the lock and update the timers. * The remainder of the operation can still be a no-op. * If the queue isn't changing, check to see if * an update would be meaningless. * Remove from the old queue * If we're moving from one queue to another, release the lock on the * old queue and get a lock on the new queue. For user defined queues, * if we're moving off it, call delete in case it can now be freed. * Add to the bottom of the new queue /* ------------------------------------------------------------------------ */ /* Function: fr_updateipid */ /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ /* Parameters: fin(I) - pointer to packet information */ /* When we are doing NAT, change the IP of every packet to represent a */ /* single sequence of packets coming from the host, hiding any host */ /* specific sequencing that might otherwise be revealed. If the packet is */ /* a fragment, then store the 'new' IPid in the fragment cache and look up */ /* the fragment cache for non-leading fragments. If a non-leading fragment */ /* has no match in the cache, return an error. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_getifname */ /* Returns: char * - pointer to interface name */ /* Parameters: ifp(I) - pointer to network interface */ /* buffer(O) - pointer to where to store interface name */ /* Constructs an interface name in the buffer passed. The buffer passed is */ /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ /* as a NULL pointer then return a pointer to a static array. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_ioctlswitch */ /* Returns: int - -1 continue processing, else ioctl return value */ /* Parameters: unit(I) - device unit opened */ /* data(I) - pointer to ioctl data */ /* cmd(I) - ioctl command */ /* mode(I) - mode value */ /* Based on the value of unit, call the appropriate ioctl handler or return */ /* EIO if ipfilter is not running. Also checks if write perms are req'd */ /* for the device in order to execute the ioctl. */ /* ------------------------------------------------------------------------ */ * This array defines the expected size of objects coming into the kernel * for the various recognised object types. {
1,
sizeof(
struct frentry) },
/* frentry */ { 0,
sizeof(
struct ipnat) },
{
1,
sizeof(
struct nat_save) },
/* nat_save */ {
1,
sizeof(
struct ipstate) },
/* ipstate */ { 0,
sizeof(
struct nat) },
/* nat_t *//* ------------------------------------------------------------------------ */ /* Returns: int - 0 = success, else failure */ /* Parameters: data(I) - pointer to ioctl data */ /* ptr(I) - pointer to store real data in */ /* type(I) - type of structure being moved */ /* Copy in the contents of what the ipfobj_t points to. In future, we */ /* add things to check for version numbers, sizes, etc, to make it backward */ /* compatible at the ABI for user land. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_inobjsz */ /* Returns: int - 0 = success, else failure */ /* Parameters: data(I) - pointer to ioctl data */ /* ptr(I) - pointer to store real data in */ /* type(I) - type of structure being moved */ /* sz(I) - size of data to copy */ /* As per fr_inobj, except the size of the object to copy in is passed in */ /* but it must not be smaller than the size defined for the type and the */ /* type must allow for varied sized objects. The extra requirement here is */ /* that sz must match the size of the object being passed in - this is not */ /* not possible nor required in fr_inobj(). */ /* ------------------------------------------------------------------------ */ /*XXX compatibility hook here */ /* XXX compatibility hook here */ /* ------------------------------------------------------------------------ */ /* Function: fr_outobjsz */ /* Returns: int - 0 = success, else failure */ /* Parameters: data(I) - pointer to ioctl data */ /* ptr(I) - pointer to store real data in */ /* type(I) - type of structure being moved */ /* sz(I) - size of data to copy */ /* As per fr_outobj, except the size of the object to copy out is passed in */ /* but it must not be smaller than the size defined for the type and the */ /* type must allow for varied sized objects. The extra requirement here is */ /* that sz must match the size of the object being passed in - this is not */ /* not possible nor required in fr_outobj(). */ /* ------------------------------------------------------------------------ */ /* XXX compatibility hook here */ /* XXX compatibility hook here */ /* ------------------------------------------------------------------------ */ /* Function: fr_outobj */ /* Returns: int - 0 = success, else failure */ /* Parameters: data(I) - pointer to ioctl data */ /* ptr(I) - pointer to store real data in */ /* type(I) - type of structure being moved */ /* Copy out the contents of what ptr is to where ipfobj points to. In */ /* future, we add things to check for version numbers, sizes, etc, to make */ /* it backward compatible at the ABI for user land. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_checkl4sum */ /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ /* Parameters: fin(I) - pointer to packet information */ /* If possible, calculate the layer 4 checksum for the packet. If this is */ /* not possible, return without indicating a failure or success but in a */ /* way that is ditinguishable. */ /* ------------------------------------------------------------------------ */ * If the TCP packet isn't a fragment, isn't too short and otherwise * isn't already considered "bad", then validate the checksum. If * this check fails then considered the packet to be "bad". /* ------------------------------------------------------------------------ */ /* Function: fr_ifpfillv4addr */ /* Returns: int - 0 = address update, -1 = address not updated */ /* Parameters: atype(I) - type of network address update to perform */ /* sin(I) - pointer to source of address information */ /* mask(I) - pointer to source of netmask information */ /* inp(I) - pointer to destination address store */ /* inpmask(I) - pointer to destination netmask store */ /* Given a type of network address update (atype) to perform, copy */ /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ /* which case the operation fails. For all values of atype other than */ /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_ifpfillv6addr */ /* Returns: int - 0 = address update, -1 = address not updated */ /* Parameters: atype(I) - type of network address update to perform */ /* sin(I) - pointer to source of address information */ /* mask(I) - pointer to source of netmask information */ /* inp(I) - pointer to destination address store */ /* inpmask(I) - pointer to destination netmask store */ /* Given a type of network address update (atype) to perform, copy */ /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ /* which case the operation fails. For all values of atype other than */ /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_matchtag */ /* Returns: 0 == mismatch, 1 == match. */ /* Parameters: tag1(I) - pointer to first tag to compare */ /* tag2(I) - pointer to second tag to compare */ /* Returns true (non-zero) or false(0) if the two tag structures can be */ /* considered to be a match or not match, respectively. The tag is 16 */ /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ /* compare the ints instead, for speed. tag1 is the master of the */ /* comparison. This function should only be called with both tag1 and tag2 */ /* as non-NULL pointers. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_coalesce */ /* Returns: 1 == success, -1 == failure, 0 == no change */ /* Parameters: fin(I) - pointer to packet information */ /* Attempt to get all of the packet data into a single, contiguous buffer. */ /* If this call returns a failure then the buffers have also been freed. */ /* ------------------------------------------------------------------------ */ * If the mbuf pointers indicate that there is no mbuf to work with, * return but do not indicate success or failure. * The following table lists all of the tunable variables that can be * in the table below is as follows: * pointer to value, name of value, minimum, maximum, size of the value's * container, value attribute flags * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED * means the value can only be written to when IPFilter is loaded but disabled. * The obvious implication is if neither of these are set then the value can be * changed at any time without harm. { {
NULL },
"fr_flags", 0,
0xffffffff,
{ {
NULL },
"fr_active", 0, 0,
{ {
NULL },
"fr_control_forwarding", 0,
1,
{ {
NULL },
"fr_update_ipid", 0,
1,
{ {
NULL },
"fr_chksrc", 0,
1,
{ {
NULL },
"fr_minttl", 0,
1,
{ {
NULL },
"fr_icmpminfragmtu", 0,
1,
{ {
NULL },
"fr_pass", 0,
0xffffffff,
{ {
NULL },
"ipf_loopback", 0,
1,
{ {
NULL },
"fr_tcpidletimeout",
1,
0x7fffffff,
{ {
NULL },
"fr_tcpclosewait",
1,
0x7fffffff,
{ {
NULL },
"fr_tcplastack",
1,
0x7fffffff,
{ {
NULL },
"fr_tcptimeout",
1,
0x7fffffff,
{ {
NULL },
"fr_tcpclosed",
1,
0x7fffffff,
{ {
NULL },
"fr_tcphalfclosed",
1,
0x7fffffff,
{ {
NULL },
"fr_udptimeout",
1,
0x7fffffff,
{ {
NULL },
"fr_udpacktimeout",
1,
0x7fffffff,
{ {
NULL },
"fr_icmptimeout",
1,
0x7fffffff,
{ {
NULL },
"fr_icmpacktimeout",
1,
0x7fffffff,
{ {
NULL },
"fr_iptimeout",
1,
0x7fffffff,
{ {
NULL },
"fr_statemax",
1,
0x7fffffff,
{ {
NULL },
"fr_statesize",
1,
0x7fffffff,
{ {
NULL },
"fr_state_lock", 0,
1,
{ {
NULL },
"fr_state_maxbucket",
1,
0x7fffffff,
{ {
NULL },
"fr_state_maxbucket_reset", 0,
1,
{ {
NULL },
"ipstate_logging", 0,
1,
{ {
NULL },
"state_flush_level_hi",
1,
100,
{ {
NULL },
"state_flush_level_lo",
1,
100,
{ {
NULL },
"fr_nat_lock", 0,
1,
{ {
NULL },
"ipf_nattable_sz",
1,
0x7fffffff,
{ {
NULL },
"ipf_nattable_max",
1,
0x7fffffff,
{ {
NULL },
"ipf_natrules_sz",
1,
0x7fffffff,
{ {
NULL },
"ipf_rdrrules_sz",
1,
0x7fffffff,
{ {
NULL },
"ipf_hostmap_sz",
1,
0x7fffffff,
{ {
NULL },
"fr_nat_maxbucket",
1,
0x7fffffff,
{ {
NULL },
"fr_nat_maxbucket_reset", 0,
1,
{ {
NULL },
"nat_logging", 0,
1,
{ {
NULL },
"fr_defnatage",
1,
0x7fffffff,
{ {
NULL },
"fr_defnatipage",
1,
0x7fffffff,
{ {
NULL },
"fr_defnaticmpage",
1,
0x7fffffff,
{ {
NULL },
"nat_flush_level_hi",
1,
100,
{ {
NULL },
"nat_flush_level_lo",
1,
100,
{ {
NULL },
"ipfr_size",
1,
0x7fffffff,
{ {
NULL },
"fr_ipfrttl",
1,
0x7fffffff,
{ {
NULL },
"ipl_suppress", 0,
1,
{ {
NULL },
"ipl_buffer_sz", 0, 0,
{ {
NULL },
"ipl_logmax", 0,
0x7fffffff,
{ {
NULL },
"ipl_logall", 0,
1,
{ {
NULL },
"ipl_logsize", 0,
0x80000,
/* -------------------------------------------------------------------- */ /* Function: ipftuneable_setdefs() */ /* Parameters: ifs - pointer to newly allocated IPF instance */ /* assigned to IP instance */ /* Function initializes IPF instance variables. Function is invoked */ /* from ipftuneable_alloc(). ipftuneable_alloc() is called only one */ /* time during IP instance lifetime - at the time of IP instance */ /* creation. Anytime IP instance is being created new private IPF */ /* instance is allocated and assigned to it. The moment of IP */ /* instance creation is the right time to initialize those IPF */ /* -------------------------------------------------------------------- */ /* it comes from fr_authinit() in IPF auth */ /* it comes from fr_stateinit() in IPF state */ /* it comes from fr_natinit() in ipnat */ /* it comes from fr_loginit() in IPF log */ /* from fr_stateinit() */ /* from fr_stateinit() */ * Allocate a per-stack tuneable and copy in the names. Then * set it to point to each of the per-stack tunables. /* ------------------------------------------------------------------------ */ /* Function: fr_findtunebycookie */ /* Returns: NULL = search failed, else pointer to tune struct */ /* Parameters: cookie(I) - cookie value to search for amongst tuneables */ /* next(O) - pointer to place to store the cookie for the */ /* "next" tuneable, if it is desired. */ /* This function is used to walk through all of the existing tunables with */ /* successive calls. It searches the known tunables for the one which has */ /* a matching value for "cookie" - ie its address. When returning a match, */ /* the next one to be found may be returned inside next. */ /* ------------------------------------------------------------------------ */ * If the next entry in the array has a name * present, then return a pointer to it for * where to go next, else return a pointer to * the dynaminc list as a key to search there * next. This facilitates a weak linking of * the two "lists" together. /* ------------------------------------------------------------------------ */ /* Function: fr_findtunebyname */ /* Returns: NULL = search failed, else pointer to tune struct */ /* Parameters: name(I) - name of the tuneable entry to find. */ /* Search the static array of tuneables and the list of dynamic tuneables */ /* for an entry with a matching name. If we can find one, return a pointer */ /* to the matching structure. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_addipftune */ /* Returns: int - 0 == success, else failure */ /* Parameters: newtune - pointer to new tune struct to add to tuneables */ /* Appends the tune structure pointer to by "newtune" to the end of the */ /* current list of "dynamic" tuneable parameters. Once added, the owner */ /* of the object is not expected to ever change "ipft_next". */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_delipftune */ /* Returns: int - 0 == success, else failure */ /* Parameters: oldtune - pointer to tune struct to remove from the list of */ /* current dynamic tuneables */ /* Search for the tune structure, by pointer, in the list of those that are */ /* dynamically added at run time. If found, adjust the list so that this */ /* structure is no longer part of it. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_ipftune */ /* Returns: int - 0 == success, else failure */ /* Parameters: cmd(I) - ioctl command number */ /* data(I) - pointer to ioctl data structure */ /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ /* three ioctls provide the means to access and control global variables */ /* within IPFilter, allowing (for example) timeouts and table sizes to be */ /* changed without rebooting, reloading or recompiling. The initialisation */ /* and 'destruction' routines of the various components of ipfilter are all */ /* each responsible for handling their own values being too big. */ /* ------------------------------------------------------------------------ */ * If cookie is non-NULL, assume it to be a pointer to the last * entry we looked at, so find it (if possible) and return a * pointer to the next one after it. The last entry in the * the table is a NULL entry, so when we get to it, set cookie * to NULL and return that, indicating end of list, erstwhile * if we come in with cookie set to NULL, we are starting anew * at the front of the list. * Entry found, but does the data pointed to by that * row fit in what we can return? * Search by name or by cookie value for a particular entry * in the tuning paramter table. * Fetch the tuning parameters for a particular value * Set an internal parameter. The hard part here is * getting the new value safely and correctly out of * the kernel (given we only know its size, not type.) /* ------------------------------------------------------------------------ */ /* Function: fr_initialise */ /* Returns: int - 0 == success, < 0 == failure */ /* Call of the initialise functions for all the various subsystems inside */ /* of IPFilter. If any of them should fail, return immeadiately a failure */ /* BUT do not try to recover from the error here. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_deinitialise */ /* Call all the various subsystem cleanup routines to deallocate memory or */ /* destroy locks or whatever they've done that they need to now undo. */ /* The order here IS important as there are some cross references of */ /* internal data structures. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_zerostats */ /* Returns: int - 0 = success, else failure */ /* Parameters: data(O) - pointer to pointer for copying data back to */ /* Copies the current statistics out to userspace and then zero's the */ /* current ones in the kernel. The lock is only held across the bzero() as */ /* the copyout may result in paging (ie network activity.) */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_resolvedest */ /* Parameters: fdp(IO) - pointer to destination information to resolve */ /* v(I) - IP protocol version to match */ /* Looks up an interface name in the frdest structure pointed to by fdp and */ /* if a matching name can be found for the particular IP protocol version */ /* then store the interface pointer in the frdest struct. If no match is */ /* found, then set the interface pointer to be -1 as NULL is considered to */ /* indicate there is no information at all in the structure. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: fr_resolvenic */ /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ /* pointer to interface structure for NIC */ /* Parameters: name(I) - complete interface name */ /* v(I) - IP protocol version */ /* Look for a network interface structure that firstly has a matching name */ /* to that passed in and that is also being used for that IP protocol */ /* version (necessary on some platforms where there are separate listings */ /* for both IPv4 and IPv6 on the same physical NIC. */ /* One might wonder why name gets terminated with a \0 byte in here. The */ /* reason is an interface name could get into the kernel structures of ipf */ /* in any number of ways and so long as they all use the same sized array */ /* to put the name in, it makes sense to ensure it gets null terminated */ /* before it is used for its intended purpose - finding its match in the */ /* kernel's list of configured interfaces. */ /* NOTE: This SHOULD ONLY be used with IPFilter structures that have an */ /* array for the name that is LIFNAMSIZ bytes (at least) in length. */ /* ------------------------------------------------------------------------ */ if ((
name[
1] ==
'\0') && ((
name[0] ==
'-') || (
name[0] ==
'*'))) {
/* ------------------------------------------------------------------------ */ /* Function: ipf_expiretokens */ /* Parameters: ifs - ipf stack instance */ /* This function is run every ipf tick to see if there are any tokens that */ /* have been held for too long and need to be freed up. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: ipf_deltoken */ /* Returns: int - 0 = success, else error */ /* Parameters: type(I) - the token type to match */ /* uid(I) - uid owning the token */ /* ptr(I) - context pointer for the token */ /* ifs - ipf stack instance */ /* This function looks for a a token in the current list that matches up */ /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ /* call ipf_freetoken() to remove it from the list. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: ipf_unlinktoken */ /* Parameters: token(I) - pointer to token structure */ /* ifs - ipf stack instance */ /* This function unlinks a token structure from the linked list of tokens */ /* that it belongs to. The head pointer never needs to be explicitly */ /* adjusted, but the tail does due to the linked list implementation. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: ipf_findtoken */ /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ /* Parameters: type(I) - the token type to match */ /* uid(I) - uid owning the token */ /* ptr(I) - context pointer for the token */ /* ifs - ipf stack instance */ /* This function looks for a live token in the list of current tokens that */ /* matches the tuple (type, uid, ptr). If one cannot be found then one is */ /* allocated. If one is found then it is moved to the top of the list of */ /* currently active tokens. */ /* NOTE: It is by design that this function returns holding a read lock on */ /* ipf_tokens. Callers must make sure they release it! */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: ipf_freetoken */ /* Parameters: token(I) - pointer to token structure */ /* ifs - ipf stack instance */ /* This function unlinks a token from the linked list and on the path to */ /* free'ing the data, it calls the dereference function that is associated */ /* with the type of data pointed to by the token as it is considered to */ /* hold a reference to it. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: ipf_getnextrule */ /* Returns: int - 0 = success, else error */ /* Parameters: t(I) - pointer to destination information to resolve */ /* ptr(I) - pointer to ipfobj_t to copyin from user space */ /* ifs - ipf stack instance */ /* This function's first job is to bring in the ipfruleiter_t structure via */ /* the ipfobj_t structure to determine what should be the next rule to */ /* return. Once the ipfruleiter_t has been brought in, it then tries to */ /* find the 'next rule'. This may include searching rule group lists or */ /* just be as simple as looking at the 'next' field in the rule structure. */ /* When we have found the rule to return, increase its reference count and */ /* if we used an existing rule to get here, decrease its reference count. */ /* ------------------------------------------------------------------------ */ * Use bitmask on it.iri_inout to determine direction. * F_OUT (1) and F_ACOUT (3) mask to out = 1, while * F_IN (0) and F_ACIN (2) mask to out = 0. * Retrieve "previous" entry from token and find the next entry. * Use bitmask again to determine accounting or not. * F_ACIN will mask to accounting cases F_ACIN (2) * or F_ACOUT (3), but not F_IN or F_OUT. * The ipfruleiter may ask for more than 1 rule at a time to be * copied out, so long as that many exist in the list to start with! * If we found an entry, add reference to it and update token. * Otherwise, zero out data to be returned and NULL out token. * Now that we have ref, it's save to give up lock. * Copy out data and clean up references and token as needed. /* ------------------------------------------------------------------------ */ /* Function: fr_frruleiter */ /* Returns: int - 0 = success, else error */ /* Parameters: data(I) - the token type to match */ /* uid(I) - uid owning the token */ /* ptr(I) - context pointer for the token */ /* ifs - ipf stack instance */ /* This function serves as a stepping stone between fr_ipf_ioctl and */ /* ipf_getnextrule. It's role is to find the right token in the kernel for */ /* the process doing the ioctl and use that to ask for the next rule. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: ipf_geniter */ /* Returns: int - 0 = success, else error */ /* Parameters: token(I) - pointer to ipftoken structure */ /* itp(I) - pointer to ipfgeniter structure */ /* ifs - ipf stack instance */ /* Generic iterator called from ipf_genericiter. Currently only used for */ /* walking through list of fragments. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* Function: ipf_genericiter */ /* Returns: int - 0 = success, else error */ /* Parameters: data(I) - the token type to match */ /* uid(I) - uid owning the token */ /* ptr(I) - context pointer for the token */ /* ifs - ipf stack instance */ /* This function serves as a stepping stone between fr_ipf_ioctl and */ /* ipf_geniter when handling SIOCGENITER. It's role is to find the right */ /* token in the kernel for the process using the ioctl, and to use that */ /* token when calling ipf_geniter. */ /* ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- */ /* Function: ipf_earlydrop */ /* Parameters: flushtype - which table we're cleaning (NAT or State) */ /* ifq - pointer to queue with entries to be deleted */ /* idletime - entry must be idle this long to be deleted */ /* ifs - ipf stack instance */ /* Function is invoked from state/NAT flush routines to remove entries */ /* from specified timeout queue, based on how long they've sat idle, */ /* without waiting for it to happen on its own. */ /* --------------------------------------------------------------------- */ * Determine the tick representing the idle time we're interested * in. If an entry exists in the queue, and it was touched before * that tick, then it's been idle longer than idletime, so it should /* --------------------------------------------------------------------- */ /* Function: ipf_flushclosing */ /* Returns: int - number of entries deleted */ /* Parameters: flushtype - which table we're cleaning (NAT or State) */ /* stateval - TCP state at which to start removing entries */ /* ipfqs - pointer to timeout queues */ /* userqs - pointer to user defined queues */ /* ifs - ipf stack instance */ /* Remove state/NAT table entries for TCP connections which are in the */ /* process of closing, and have at least reached the state specified by */ /* the 'stateval' parameter. */ /* --------------------------------------------------------------------- */ * Start by deleting any entries in specific timeout queues. * Next, look through user defined queues for closing entries. /* --------------------------------------------------------------------- */ /* Function: ipf_extraflush */ /* Returns: int - number of entries flushed (0 = none) */ /* Parameters: flushtype - which table we're cleaning (NAT or State) */ /* ipfqs - pointer to 'established' timeout queue */ /* userqs - pointer to user defined queues */ /* ifs - ipf stack instance */ /* This function gets called when either NAT or state tables fill up. */ /* We need to try a bit harder to free up some space. The function will */ /* flush entries for TCP connections which have been idle a long time. */ /* Currently, the idle time is checked using values from ideltime_tab[] */ /* --------------------------------------------------------------------- */ * Determine initial threshold for minimum idle time based on * how long ipfilter has been running. Ipfilter needs to have * been up as long as the smallest interval to continue on. * Minimum idle times stored in idletime_tab and indexed by * idle_idx. Start at upper end of array and work backwards. * Once the index is found, set the initial idle time to the * first interval before the current ipfilter run time. * Check to see if we need to delete more entries. * If we do, start with appropriate timeout queue. * Next, check the user defined queues. But first, make * certain that timeout queue deletions didn't do enough. * Adjust the granularity of idle time. * If we reach an interval boundary, we need to * either adjust the idle time accordingly or exit * the loop altogether (if this is very last check).