ip_fw2.c revision 121816
198943Sluigi/* 298943Sluigi * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa 398943Sluigi * 498943Sluigi * Redistribution and use in source and binary forms, with or without 598943Sluigi * modification, are permitted provided that the following conditions 698943Sluigi * are met: 798943Sluigi * 1. Redistributions of source code must retain the above copyright 898943Sluigi * notice, this list of conditions and the following disclaimer. 9116763Sluigi * 2. Redistributions in binary form must reproduce the above copyright 1098943Sluigi * notice, this list of conditions and the following disclaimer in the 1198943Sluigi * documentation and/or other materials provided with the distribution. 12105775Smaxim * 1398943Sluigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1498943Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1598943Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1698943Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1798943Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1898943Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1998943Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2098943Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2198943Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2298943Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2398943Sluigi * SUCH DAMAGE. 2498943Sluigi * 2598943Sluigi * $FreeBSD: head/sys/netinet/ip_fw2.c 121816 2003-10-31 18:32:15Z brooks $ 2698943Sluigi */ 2798943Sluigi 2898943Sluigi#define DEB(x) 2998943Sluigi#define DDB(x) x 3098943Sluigi 3198943Sluigi/* 3299622Sluigi * Implement IP packet firewall (new version) 3398943Sluigi */ 3498943Sluigi 3598943Sluigi#if !defined(KLD_MODULE) 3698943Sluigi#include "opt_ipfw.h" 3798943Sluigi#include "opt_ipdn.h" 3898943Sluigi#include "opt_ipdivert.h" 3998943Sluigi#include "opt_inet.h" 4098943Sluigi#ifndef INET 4198943Sluigi#error IPFIREWALL requires INET. 4298943Sluigi#endif /* INET */ 4398943Sluigi#endif 4498943Sluigi 4599622Sluigi#define IPFW2 1 4699622Sluigi#if IPFW2 4798943Sluigi#include <sys/param.h> 4898943Sluigi#include <sys/systm.h> 4998943Sluigi#include <sys/malloc.h> 5098943Sluigi#include <sys/mbuf.h> 5198943Sluigi#include <sys/kernel.h> 5298943Sluigi#include <sys/proc.h> 5398943Sluigi#include <sys/socket.h> 5498943Sluigi#include <sys/socketvar.h> 5598943Sluigi#include <sys/sysctl.h> 5698943Sluigi#include <sys/syslog.h> 5798943Sluigi#include <sys/ucred.h> 5898943Sluigi#include <net/if.h> 5998943Sluigi#include <net/route.h> 6098943Sluigi#include <netinet/in.h> 6198943Sluigi#include <netinet/in_systm.h> 6298943Sluigi#include <netinet/in_var.h> 6398943Sluigi#include <netinet/in_pcb.h> 6498943Sluigi#include <netinet/ip.h> 6598943Sluigi#include <netinet/ip_var.h> 6698943Sluigi#include <netinet/ip_icmp.h> 6798943Sluigi#include <netinet/ip_fw.h> 6898943Sluigi#include <netinet/ip_dummynet.h> 6998943Sluigi#include <netinet/tcp.h> 7098943Sluigi#include <netinet/tcp_timer.h> 7198943Sluigi#include <netinet/tcp_var.h> 7298943Sluigi#include <netinet/tcpip.h> 7398943Sluigi#include <netinet/udp.h> 7498943Sluigi#include <netinet/udp_var.h> 7598943Sluigi 76117241Sluigi#ifdef IPSEC 77117241Sluigi#include <netinet6/ipsec.h> 78117241Sluigi#endif 79117241Sluigi 8098943Sluigi#include <netinet/if_ether.h> /* XXX for ETHERTYPE_IP */ 8198943Sluigi 8299475Sluigi#include <machine/in_cksum.h> /* XXX for in_cksum */ 8399475Sluigi 84101628Sluigi/* 85101978Sluigi * XXX This one should go in sys/mbuf.h. It is used to avoid that 86101978Sluigi * a firewall-generated packet loops forever through the firewall. 87101978Sluigi */ 88101978Sluigi#ifndef M_SKIP_FIREWALL 89101978Sluigi#define M_SKIP_FIREWALL 0x4000 90101978Sluigi#endif 91101978Sluigi 92101978Sluigi/* 93101628Sluigi * set_disable contains one bit per set value (0..31). 94101628Sluigi * If the bit is set, all rules with the corresponding set 95117654Sluigi * are disabled. Set RESVD_SET(31) is reserved for the default rule 96117654Sluigi * and rules that are not deleted by the flush command, 97101628Sluigi * and CANNOT be disabled. 98117654Sluigi * Rules in set RESVD_SET can only be deleted explicitly. 99101628Sluigi */ 100101628Sluigistatic u_int32_t set_disable; 101101628Sluigi 10299622Sluigistatic int fw_verbose; 10399622Sluigistatic int verbose_limit; 10498943Sluigi 105120141Ssamstatic struct callout ipfw_timeout; 10698943Sluigi#define IPFW_DEFAULT_RULE 65535 10798943Sluigi 108120141Ssamstruct ip_fw_chain { 109120141Ssam struct ip_fw *rules; /* list of rules */ 110120141Ssam struct ip_fw *reap; /* list of rules to reap */ 111120141Ssam struct mtx mtx; /* lock guarding rule list */ 112120141Ssam}; 113120141Ssam#define IPFW_LOCK_INIT(_chain) \ 114120182Ssam mtx_init(&(_chain)->mtx, "IPFW static rules", NULL, \ 115120182Ssam MTX_DEF | MTX_RECURSE) 116120141Ssam#define IPFW_LOCK_DESTROY(_chain) mtx_destroy(&(_chain)->mtx) 117120141Ssam#define IPFW_LOCK(_chain) mtx_lock(&(_chain)->mtx) 118120141Ssam#define IPFW_UNLOCK(_chain) mtx_unlock(&(_chain)->mtx) 119120141Ssam#define IPFW_LOCK_ASSERT(_chain) mtx_assert(&(_chain)->mtx, MA_OWNED) 120120141Ssam 12198943Sluigi/* 12298943Sluigi * list of rules for layer 3 12398943Sluigi */ 124120141Ssamstatic struct ip_fw_chain layer3_chain; 12598943Sluigi 12698943SluigiMALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); 12798943Sluigi 12898943Sluigistatic int fw_debug = 1; 12998943Sluigistatic int autoinc_step = 100; /* bounded to 1..1000 in add_rule() */ 13098943Sluigi 13198943Sluigi#ifdef SYSCTL_NODE 13298943SluigiSYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); 133102397ScjcSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, enable, 134109246Sdillon CTLFLAG_RW | CTLFLAG_SECURE3, 13598943Sluigi &fw_enable, 0, "Enable ipfw"); 13698943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, CTLFLAG_RW, 13798943Sluigi &autoinc_step, 0, "Rule number autincrement step"); 138102397ScjcSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, one_pass, 139109246Sdillon CTLFLAG_RW | CTLFLAG_SECURE3, 140105775Smaxim &fw_one_pass, 0, 14198943Sluigi "Only do a single pass through ipfw when using dummynet(4)"); 142105775SmaximSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, 14398943Sluigi &fw_debug, 0, "Enable printing of debug ip_fw statements"); 144102397ScjcSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, 145109246Sdillon CTLFLAG_RW | CTLFLAG_SECURE3, 14698943Sluigi &fw_verbose, 0, "Log matches to ipfw rules"); 147105775SmaximSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, 14898943Sluigi &verbose_limit, 0, "Set upper limit of matches of ipfw rules logged"); 14998943Sluigi 15098943Sluigi/* 15198943Sluigi * Description of dynamic rules. 15298943Sluigi * 15398943Sluigi * Dynamic rules are stored in lists accessed through a hash table 15498943Sluigi * (ipfw_dyn_v) whose size is curr_dyn_buckets. This value can 15598943Sluigi * be modified through the sysctl variable dyn_buckets which is 15698943Sluigi * updated when the table becomes empty. 15798943Sluigi * 15898943Sluigi * XXX currently there is only one list, ipfw_dyn. 15998943Sluigi * 16098943Sluigi * When a packet is received, its address fields are first masked 16198943Sluigi * with the mask defined for the rule, then hashed, then matched 16298943Sluigi * against the entries in the corresponding list. 16398943Sluigi * Dynamic rules can be used for different purposes: 16498943Sluigi * + stateful rules; 16598943Sluigi * + enforcing limits on the number of sessions; 16698943Sluigi * + in-kernel NAT (not implemented yet) 16798943Sluigi * 16898943Sluigi * The lifetime of dynamic rules is regulated by dyn_*_lifetime, 16998943Sluigi * measured in seconds and depending on the flags. 17098943Sluigi * 17198943Sluigi * The total number of dynamic rules is stored in dyn_count. 17298943Sluigi * The max number of dynamic rules is dyn_max. When we reach 17398943Sluigi * the maximum number of rules we do not create anymore. This is 17498943Sluigi * done to avoid consuming too much memory, but also too much 17598943Sluigi * time when searching on each packet (ideally, we should try instead 17698943Sluigi * to put a limit on the length of the list on each bucket...). 17798943Sluigi * 17898943Sluigi * Each dynamic rule holds a pointer to the parent ipfw rule so 17998943Sluigi * we know what action to perform. Dynamic rules are removed when 18098943Sluigi * the parent rule is deleted. XXX we should make them survive. 18198943Sluigi * 18298943Sluigi * There are some limitations with dynamic rules -- we do not 18398943Sluigi * obey the 'randomized match', and we do not do multiple 18498943Sluigi * passes through the firewall. XXX check the latter!!! 18598943Sluigi */ 18698943Sluigistatic ipfw_dyn_rule **ipfw_dyn_v = NULL; 18798943Sluigistatic u_int32_t dyn_buckets = 256; /* must be power of 2 */ 18898943Sluigistatic u_int32_t curr_dyn_buckets = 256; /* must be power of 2 */ 18998943Sluigi 190120141Ssamstatic struct mtx ipfw_dyn_mtx; /* mutex guarding dynamic rules */ 191120141Ssam#define IPFW_DYN_LOCK_INIT() \ 192120141Ssam mtx_init(&ipfw_dyn_mtx, "IPFW dynamic rules", NULL, MTX_DEF) 193120141Ssam#define IPFW_DYN_LOCK_DESTROY() mtx_destroy(&ipfw_dyn_mtx) 194120141Ssam#define IPFW_DYN_LOCK() mtx_lock(&ipfw_dyn_mtx) 195120141Ssam#define IPFW_DYN_UNLOCK() mtx_unlock(&ipfw_dyn_mtx) 196120141Ssam#define IPFW_DYN_LOCK_ASSERT() mtx_assert(&ipfw_dyn_mtx, MA_OWNED) 197120141Ssam 19898943Sluigi/* 19998943Sluigi * Timeouts for various events in handing dynamic rules. 20098943Sluigi */ 20198943Sluigistatic u_int32_t dyn_ack_lifetime = 300; 20298943Sluigistatic u_int32_t dyn_syn_lifetime = 20; 20398943Sluigistatic u_int32_t dyn_fin_lifetime = 1; 20498943Sluigistatic u_int32_t dyn_rst_lifetime = 1; 20598943Sluigistatic u_int32_t dyn_udp_lifetime = 10; 20698943Sluigistatic u_int32_t dyn_short_lifetime = 5; 20798943Sluigi 208101978Sluigi/* 209101978Sluigi * Keepalives are sent if dyn_keepalive is set. They are sent every 210101978Sluigi * dyn_keepalive_period seconds, in the last dyn_keepalive_interval 211101978Sluigi * seconds of lifetime of a rule. 212101978Sluigi * dyn_rst_lifetime and dyn_fin_lifetime should be strictly lower 213101978Sluigi * than dyn_keepalive_period. 214101978Sluigi */ 215105775Smaxim 216101978Sluigistatic u_int32_t dyn_keepalive_interval = 20; 217101978Sluigistatic u_int32_t dyn_keepalive_period = 5; 218100004Sluigistatic u_int32_t dyn_keepalive = 1; /* do send keepalives */ 21998943Sluigi 22099622Sluigistatic u_int32_t static_count; /* # of static rules */ 22199622Sluigistatic u_int32_t static_len; /* size in bytes of static rules */ 22299622Sluigistatic u_int32_t dyn_count; /* # of dynamic rules */ 223101978Sluigistatic u_int32_t dyn_max = 4096; /* max # of dynamic rules */ 22498943Sluigi 22598943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_buckets, CTLFLAG_RW, 22698943Sluigi &dyn_buckets, 0, "Number of dyn. buckets"); 22798943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, curr_dyn_buckets, CTLFLAG_RD, 22898943Sluigi &curr_dyn_buckets, 0, "Current Number of dyn. buckets"); 22998943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_count, CTLFLAG_RD, 23098943Sluigi &dyn_count, 0, "Number of dyn. rules"); 23198943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_max, CTLFLAG_RW, 23298943Sluigi &dyn_max, 0, "Max number of dyn. rules"); 23398943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, static_count, CTLFLAG_RD, 23498943Sluigi &static_count, 0, "Number of static rules"); 23598943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_ack_lifetime, CTLFLAG_RW, 23698943Sluigi &dyn_ack_lifetime, 0, "Lifetime of dyn. rules for acks"); 23798943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_syn_lifetime, CTLFLAG_RW, 23898943Sluigi &dyn_syn_lifetime, 0, "Lifetime of dyn. rules for syn"); 23998943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_fin_lifetime, CTLFLAG_RW, 24098943Sluigi &dyn_fin_lifetime, 0, "Lifetime of dyn. rules for fin"); 24198943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_rst_lifetime, CTLFLAG_RW, 24298943Sluigi &dyn_rst_lifetime, 0, "Lifetime of dyn. rules for rst"); 24398943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_udp_lifetime, CTLFLAG_RW, 24498943Sluigi &dyn_udp_lifetime, 0, "Lifetime of dyn. rules for UDP"); 24598943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime, CTLFLAG_RW, 24698943Sluigi &dyn_short_lifetime, 0, "Lifetime of dyn. rules for other situations"); 247100004SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive, CTLFLAG_RW, 248100004Sluigi &dyn_keepalive, 0, "Enable keepalives for dyn. rules"); 24998943Sluigi 25098943Sluigi#endif /* SYSCTL_NODE */ 25198943Sluigi 25298943Sluigi 25398943Sluigistatic ip_fw_chk_t ipfw_chk; 25498943Sluigi 25598943Sluigiip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL; /* hook into dummynet */ 25698943Sluigi 25798943Sluigi/* 25898943Sluigi * This macro maps an ip pointer into a layer3 header pointer of type T 25998943Sluigi */ 26098943Sluigi#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl)) 26198943Sluigi 26299622Sluigistatic __inline int 26398943Sluigiicmptype_match(struct ip *ip, ipfw_insn_u32 *cmd) 26498943Sluigi{ 26598943Sluigi int type = L3HDR(struct icmp,ip)->icmp_type; 26698943Sluigi 26798943Sluigi return (type <= ICMP_MAXTYPE && (cmd->d[0] & (1<<type)) ); 26898943Sluigi} 26998943Sluigi 27098943Sluigi#define TT ( (1 << ICMP_ECHO) | (1 << ICMP_ROUTERSOLICIT) | \ 27198943Sluigi (1 << ICMP_TSTAMP) | (1 << ICMP_IREQ) | (1 << ICMP_MASKREQ) ) 27298943Sluigi 27398943Sluigistatic int 27498943Sluigiis_icmp_query(struct ip *ip) 27598943Sluigi{ 27698943Sluigi int type = L3HDR(struct icmp, ip)->icmp_type; 27798943Sluigi return (type <= ICMP_MAXTYPE && (TT & (1<<type)) ); 27898943Sluigi} 27998943Sluigi#undef TT 28098943Sluigi 28198943Sluigi/* 28298943Sluigi * The following checks use two arrays of 8 or 16 bits to store the 28398943Sluigi * bits that we want set or clear, respectively. They are in the 28498943Sluigi * low and high half of cmd->arg1 or cmd->d[0]. 28598943Sluigi * 28698943Sluigi * We scan options and store the bits we find set. We succeed if 28798943Sluigi * 28898943Sluigi * (want_set & ~bits) == 0 && (want_clear & ~bits) == want_clear 28998943Sluigi * 29098943Sluigi * The code is sometimes optimized not to store additional variables. 29198943Sluigi */ 29298943Sluigi 29398943Sluigistatic int 29498943Sluigiflags_match(ipfw_insn *cmd, u_int8_t bits) 29598943Sluigi{ 29698943Sluigi u_char want_clear; 29798943Sluigi bits = ~bits; 29898943Sluigi 29998943Sluigi if ( ((cmd->arg1 & 0xff) & bits) != 0) 30098943Sluigi return 0; /* some bits we want set were clear */ 30198943Sluigi want_clear = (cmd->arg1 >> 8) & 0xff; 30298943Sluigi if ( (want_clear & bits) != want_clear) 30398943Sluigi return 0; /* some bits we want clear were set */ 30498943Sluigi return 1; 30598943Sluigi} 30698943Sluigi 30798943Sluigistatic int 30898943Sluigiipopts_match(struct ip *ip, ipfw_insn *cmd) 30998943Sluigi{ 31098943Sluigi int optlen, bits = 0; 31198943Sluigi u_char *cp = (u_char *)(ip + 1); 31298943Sluigi int x = (ip->ip_hl << 2) - sizeof (struct ip); 31398943Sluigi 31498943Sluigi for (; x > 0; x -= optlen, cp += optlen) { 31598943Sluigi int opt = cp[IPOPT_OPTVAL]; 31698943Sluigi 31798943Sluigi if (opt == IPOPT_EOL) 31898943Sluigi break; 31998943Sluigi if (opt == IPOPT_NOP) 32098943Sluigi optlen = 1; 32198943Sluigi else { 32298943Sluigi optlen = cp[IPOPT_OLEN]; 32398943Sluigi if (optlen <= 0 || optlen > x) 32498943Sluigi return 0; /* invalid or truncated */ 32598943Sluigi } 32698943Sluigi switch (opt) { 32798943Sluigi 32898943Sluigi default: 32998943Sluigi break; 33098943Sluigi 33198943Sluigi case IPOPT_LSRR: 33298943Sluigi bits |= IP_FW_IPOPT_LSRR; 33398943Sluigi break; 33498943Sluigi 33598943Sluigi case IPOPT_SSRR: 33698943Sluigi bits |= IP_FW_IPOPT_SSRR; 33798943Sluigi break; 33898943Sluigi 33998943Sluigi case IPOPT_RR: 34098943Sluigi bits |= IP_FW_IPOPT_RR; 34198943Sluigi break; 34298943Sluigi 34398943Sluigi case IPOPT_TS: 34498943Sluigi bits |= IP_FW_IPOPT_TS; 34598943Sluigi break; 34698943Sluigi } 34798943Sluigi } 34898943Sluigi return (flags_match(cmd, bits)); 34998943Sluigi} 35098943Sluigi 35198943Sluigistatic int 35298943Sluigitcpopts_match(struct ip *ip, ipfw_insn *cmd) 35398943Sluigi{ 35498943Sluigi int optlen, bits = 0; 35598943Sluigi struct tcphdr *tcp = L3HDR(struct tcphdr,ip); 35698943Sluigi u_char *cp = (u_char *)(tcp + 1); 35798943Sluigi int x = (tcp->th_off << 2) - sizeof(struct tcphdr); 35898943Sluigi 35998943Sluigi for (; x > 0; x -= optlen, cp += optlen) { 36098943Sluigi int opt = cp[0]; 36198943Sluigi if (opt == TCPOPT_EOL) 36298943Sluigi break; 36398943Sluigi if (opt == TCPOPT_NOP) 36498943Sluigi optlen = 1; 36598943Sluigi else { 36698943Sluigi optlen = cp[1]; 36798943Sluigi if (optlen <= 0) 36898943Sluigi break; 36998943Sluigi } 37098943Sluigi 37198943Sluigi switch (opt) { 37298943Sluigi 37398943Sluigi default: 37498943Sluigi break; 37598943Sluigi 37698943Sluigi case TCPOPT_MAXSEG: 37798943Sluigi bits |= IP_FW_TCPOPT_MSS; 37898943Sluigi break; 37998943Sluigi 38098943Sluigi case TCPOPT_WINDOW: 38198943Sluigi bits |= IP_FW_TCPOPT_WINDOW; 38298943Sluigi break; 38398943Sluigi 38498943Sluigi case TCPOPT_SACK_PERMITTED: 38598943Sluigi case TCPOPT_SACK: 38698943Sluigi bits |= IP_FW_TCPOPT_SACK; 38798943Sluigi break; 38898943Sluigi 38998943Sluigi case TCPOPT_TIMESTAMP: 39098943Sluigi bits |= IP_FW_TCPOPT_TS; 39198943Sluigi break; 39298943Sluigi 39398943Sluigi case TCPOPT_CC: 39498943Sluigi case TCPOPT_CCNEW: 39598943Sluigi case TCPOPT_CCECHO: 39698943Sluigi bits |= IP_FW_TCPOPT_CC; 39798943Sluigi break; 39898943Sluigi } 39998943Sluigi } 40098943Sluigi return (flags_match(cmd, bits)); 40198943Sluigi} 40298943Sluigi 40398943Sluigistatic int 40498943Sluigiiface_match(struct ifnet *ifp, ipfw_insn_if *cmd) 40598943Sluigi{ 40698943Sluigi if (ifp == NULL) /* no iface with this packet, match fails */ 40798943Sluigi return 0; 40898943Sluigi /* Check by name or by IP address */ 40999475Sluigi if (cmd->name[0] != '\0') { /* match by name */ 41098943Sluigi /* Check name */ 411121816Sbrooks if (cmd->p.glob) { 412121816Sbrooks if (fnmatch(cmd->name, ifp->if_xname, 0) == 0) 413121816Sbrooks return(1); 414121816Sbrooks } else { 415121816Sbrooks if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0) 416121816Sbrooks return(1); 417121816Sbrooks } 41898943Sluigi } else { 41998943Sluigi struct ifaddr *ia; 42098943Sluigi 421120141Ssam /* XXX lock? */ 42298943Sluigi TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { 42398943Sluigi if (ia->ifa_addr == NULL) 42498943Sluigi continue; 42598943Sluigi if (ia->ifa_addr->sa_family != AF_INET) 42698943Sluigi continue; 42798943Sluigi if (cmd->p.ip.s_addr == ((struct sockaddr_in *) 42898943Sluigi (ia->ifa_addr))->sin_addr.s_addr) 42998943Sluigi return(1); /* match */ 43098943Sluigi } 43198943Sluigi } 43298943Sluigi return(0); /* no match, fail ... */ 43398943Sluigi} 43498943Sluigi 435112250Scjc/* 436112250Scjc * The 'verrevpath' option checks that the interface that an IP packet 437116763Sluigi * arrives on is the same interface that traffic destined for the 438112250Scjc * packet's source address would be routed out of. This is a measure 439112250Scjc * to block forged packets. This is also commonly known as "anti-spoofing" 440112250Scjc * or Unicast Reverse Path Forwarding (Unicast RFP) in Cisco-ese. The 441112250Scjc * name of the knob is purposely reminisent of the Cisco IOS command, 442112250Scjc * 443112250Scjc * ip verify unicast reverse-path 444112250Scjc * 445112250Scjc * which implements the same functionality. But note that syntax is 446112250Scjc * misleading. The check may be performed on all IP packets whether unicast, 447112250Scjc * multicast, or broadcast. 448112250Scjc */ 449112250Scjcstatic int 450112250Scjcverify_rev_path(struct in_addr src, struct ifnet *ifp) 451112250Scjc{ 452112250Scjc static struct route ro; 453112250Scjc struct sockaddr_in *dst; 454112250Scjc 455112250Scjc dst = (struct sockaddr_in *)&(ro.ro_dst); 456112250Scjc 457112250Scjc /* Check if we've cached the route from the previous call. */ 458112250Scjc if (src.s_addr != dst->sin_addr.s_addr) { 459112250Scjc ro.ro_rt = NULL; 460112250Scjc 461112250Scjc bzero(dst, sizeof(*dst)); 462112250Scjc dst->sin_family = AF_INET; 463112250Scjc dst->sin_len = sizeof(*dst); 464112250Scjc dst->sin_addr = src; 465112250Scjc 466112250Scjc rtalloc_ign(&ro, RTF_CLONING|RTF_PRCLONING); 467112250Scjc } 468112250Scjc 469112250Scjc if ((ro.ro_rt == NULL) || (ifp == NULL) || 470112250Scjc (ro.ro_rt->rt_ifp->if_index != ifp->if_index)) 471112250Scjc return 0; 472116763Sluigi 473116981Sluigi return 1; 474112250Scjc} 475112250Scjc 476112250Scjc 47798943Sluigistatic u_int64_t norule_counter; /* counter for ipfw_log(NULL...) */ 47898943Sluigi 47998943Sluigi#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0 48099622Sluigi#define SNP(buf) buf, sizeof(buf) 481100004Sluigi 48298943Sluigi/* 48398943Sluigi * We enter here when we have a rule with O_LOG. 48499622Sluigi * XXX this function alone takes about 2Kbytes of code! 48598943Sluigi */ 48698943Sluigistatic void 48798943Sluigiipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh, 48898943Sluigi struct mbuf *m, struct ifnet *oif) 48998943Sluigi{ 49098943Sluigi char *action; 49198943Sluigi int limit_reached = 0; 49299622Sluigi char action2[40], proto[48], fragment[28]; 49398943Sluigi 49498943Sluigi fragment[0] = '\0'; 49598943Sluigi proto[0] = '\0'; 49698943Sluigi 49798943Sluigi if (f == NULL) { /* bogus pkt */ 49898943Sluigi if (verbose_limit != 0 && norule_counter >= verbose_limit) 49998943Sluigi return; 50098943Sluigi norule_counter++; 50198943Sluigi if (norule_counter == verbose_limit) 50298943Sluigi limit_reached = verbose_limit; 50398943Sluigi action = "Refuse"; 50498943Sluigi } else { /* O_LOG is the first action, find the real one */ 50598943Sluigi ipfw_insn *cmd = ACTION_PTR(f); 50698943Sluigi ipfw_insn_log *l = (ipfw_insn_log *)cmd; 50798943Sluigi 50898943Sluigi if (l->max_log != 0 && l->log_left == 0) 50998943Sluigi return; 51098943Sluigi l->log_left--; 51198943Sluigi if (l->log_left == 0) 51298943Sluigi limit_reached = l->max_log; 51398943Sluigi cmd += F_LEN(cmd); /* point to first action */ 51498943Sluigi if (cmd->opcode == O_PROB) 51598943Sluigi cmd += F_LEN(cmd); 51698943Sluigi 51798943Sluigi action = action2; 51898943Sluigi switch (cmd->opcode) { 51998943Sluigi case O_DENY: 52098943Sluigi action = "Deny"; 52198943Sluigi break; 52299475Sluigi 52398943Sluigi case O_REJECT: 52499475Sluigi if (cmd->arg1==ICMP_REJECT_RST) 52599475Sluigi action = "Reset"; 52699475Sluigi else if (cmd->arg1==ICMP_UNREACH_HOST) 52799475Sluigi action = "Reject"; 52899475Sluigi else 52999475Sluigi snprintf(SNPARGS(action2, 0), "Unreach %d", 53099475Sluigi cmd->arg1); 53198943Sluigi break; 53299475Sluigi 53398943Sluigi case O_ACCEPT: 53498943Sluigi action = "Accept"; 53598943Sluigi break; 53698943Sluigi case O_COUNT: 53798943Sluigi action = "Count"; 53898943Sluigi break; 53998943Sluigi case O_DIVERT: 54098943Sluigi snprintf(SNPARGS(action2, 0), "Divert %d", 54198943Sluigi cmd->arg1); 54298943Sluigi break; 54398943Sluigi case O_TEE: 54498943Sluigi snprintf(SNPARGS(action2, 0), "Tee %d", 54598943Sluigi cmd->arg1); 54698943Sluigi break; 54798943Sluigi case O_SKIPTO: 54898943Sluigi snprintf(SNPARGS(action2, 0), "SkipTo %d", 54998943Sluigi cmd->arg1); 55098943Sluigi break; 55198943Sluigi case O_PIPE: 55298943Sluigi snprintf(SNPARGS(action2, 0), "Pipe %d", 55398943Sluigi cmd->arg1); 55498943Sluigi break; 55598943Sluigi case O_QUEUE: 55698943Sluigi snprintf(SNPARGS(action2, 0), "Queue %d", 55798943Sluigi cmd->arg1); 55898943Sluigi break; 55998943Sluigi case O_FORWARD_IP: { 56098943Sluigi ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd; 561100004Sluigi int len; 56298943Sluigi 563100004Sluigi len = snprintf(SNPARGS(action2, 0), "Forward to %s", 564100004Sluigi inet_ntoa(sa->sa.sin_addr)); 56598943Sluigi if (sa->sa.sin_port) 566100004Sluigi snprintf(SNPARGS(action2, len), ":%d", 567107897Smaxim sa->sa.sin_port); 56898943Sluigi } 56998943Sluigi break; 570105775Smaxim default: 57198943Sluigi action = "UNKNOWN"; 57298943Sluigi break; 57398943Sluigi } 57498943Sluigi } 57598943Sluigi 57698943Sluigi if (hlen == 0) { /* non-ip */ 57798943Sluigi snprintf(SNPARGS(proto, 0), "MAC"); 57898943Sluigi } else { 57998943Sluigi struct ip *ip = mtod(m, struct ip *); 58098943Sluigi /* these three are all aliases to the same thing */ 58198943Sluigi struct icmp *const icmp = L3HDR(struct icmp, ip); 58298943Sluigi struct tcphdr *const tcp = (struct tcphdr *)icmp; 58398943Sluigi struct udphdr *const udp = (struct udphdr *)icmp; 58498943Sluigi 58598943Sluigi int ip_off, offset, ip_len; 58698943Sluigi 58798943Sluigi int len; 58898943Sluigi 58998943Sluigi if (eh != NULL) { /* layer 2 packets are as on the wire */ 59098943Sluigi ip_off = ntohs(ip->ip_off); 59198943Sluigi ip_len = ntohs(ip->ip_len); 59298943Sluigi } else { 59398943Sluigi ip_off = ip->ip_off; 59498943Sluigi ip_len = ip->ip_len; 59598943Sluigi } 59698943Sluigi offset = ip_off & IP_OFFMASK; 59798943Sluigi switch (ip->ip_p) { 59898943Sluigi case IPPROTO_TCP: 59998943Sluigi len = snprintf(SNPARGS(proto, 0), "TCP %s", 60098943Sluigi inet_ntoa(ip->ip_src)); 60198943Sluigi if (offset == 0) 602100004Sluigi snprintf(SNPARGS(proto, len), ":%d %s:%d", 603100004Sluigi ntohs(tcp->th_sport), 604100004Sluigi inet_ntoa(ip->ip_dst), 605100004Sluigi ntohs(tcp->th_dport)); 60698943Sluigi else 607100004Sluigi snprintf(SNPARGS(proto, len), " %s", 608100004Sluigi inet_ntoa(ip->ip_dst)); 60998943Sluigi break; 61098943Sluigi 61198943Sluigi case IPPROTO_UDP: 61298943Sluigi len = snprintf(SNPARGS(proto, 0), "UDP %s", 61398943Sluigi inet_ntoa(ip->ip_src)); 61498943Sluigi if (offset == 0) 615100004Sluigi snprintf(SNPARGS(proto, len), ":%d %s:%d", 616100004Sluigi ntohs(udp->uh_sport), 617100004Sluigi inet_ntoa(ip->ip_dst), 618100004Sluigi ntohs(udp->uh_dport)); 61998943Sluigi else 620100004Sluigi snprintf(SNPARGS(proto, len), " %s", 621100004Sluigi inet_ntoa(ip->ip_dst)); 62298943Sluigi break; 62398943Sluigi 62498943Sluigi case IPPROTO_ICMP: 62598943Sluigi if (offset == 0) 62698943Sluigi len = snprintf(SNPARGS(proto, 0), 62798943Sluigi "ICMP:%u.%u ", 62898943Sluigi icmp->icmp_type, icmp->icmp_code); 62998943Sluigi else 63098943Sluigi len = snprintf(SNPARGS(proto, 0), "ICMP "); 63198943Sluigi len += snprintf(SNPARGS(proto, len), "%s", 63298943Sluigi inet_ntoa(ip->ip_src)); 63398943Sluigi snprintf(SNPARGS(proto, len), " %s", 63498943Sluigi inet_ntoa(ip->ip_dst)); 63598943Sluigi break; 63698943Sluigi 63798943Sluigi default: 63898943Sluigi len = snprintf(SNPARGS(proto, 0), "P:%d %s", ip->ip_p, 63998943Sluigi inet_ntoa(ip->ip_src)); 64098943Sluigi snprintf(SNPARGS(proto, len), " %s", 64198943Sluigi inet_ntoa(ip->ip_dst)); 64298943Sluigi break; 64398943Sluigi } 64498943Sluigi 64598943Sluigi if (ip_off & (IP_MF | IP_OFFMASK)) 64698943Sluigi snprintf(SNPARGS(fragment, 0), " (frag %d:%d@%d%s)", 64798943Sluigi ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2), 64898943Sluigi offset << 3, 64998943Sluigi (ip_off & IP_MF) ? "+" : ""); 65098943Sluigi } 65198943Sluigi if (oif || m->m_pkthdr.rcvif) 65298943Sluigi log(LOG_SECURITY | LOG_INFO, 653121816Sbrooks "ipfw: %d %s %s %s via %s%s\n", 65498943Sluigi f ? f->rulenum : -1, 65598943Sluigi action, proto, oif ? "out" : "in", 656121816Sbrooks oif ? oif->if_xname : m->m_pkthdr.rcvif->if_xname, 65798943Sluigi fragment); 65898943Sluigi else 65998943Sluigi log(LOG_SECURITY | LOG_INFO, 66098943Sluigi "ipfw: %d %s %s [no if info]%s\n", 66198943Sluigi f ? f->rulenum : -1, 66298943Sluigi action, proto, fragment); 66398943Sluigi if (limit_reached) 66498943Sluigi log(LOG_SECURITY | LOG_NOTICE, 66598943Sluigi "ipfw: limit %d reached on entry %d\n", 66698943Sluigi limit_reached, f ? f->rulenum : -1); 66798943Sluigi} 66898943Sluigi 66998943Sluigi/* 67098943Sluigi * IMPORTANT: the hash function for dynamic rules must be commutative 67199475Sluigi * in source and destination (ip,port), because rules are bidirectional 67298943Sluigi * and we want to find both in the same bucket. 67398943Sluigi */ 67498943Sluigistatic __inline int 67598943Sluigihash_packet(struct ipfw_flow_id *id) 67698943Sluigi{ 67798943Sluigi u_int32_t i; 67898943Sluigi 67998943Sluigi i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port); 68098943Sluigi i &= (curr_dyn_buckets - 1); 68198943Sluigi return i; 68298943Sluigi} 68398943Sluigi 68498943Sluigi/** 68598943Sluigi * unlink a dynamic rule from a chain. prev is a pointer to 68698943Sluigi * the previous one, q is a pointer to the rule to delete, 68798943Sluigi * head is a pointer to the head of the queue. 68898943Sluigi * Modifies q and potentially also head. 68998943Sluigi */ 69098943Sluigi#define UNLINK_DYN_RULE(prev, head, q) { \ 69198943Sluigi ipfw_dyn_rule *old_q = q; \ 69298943Sluigi \ 69398943Sluigi /* remove a refcount to the parent */ \ 69498943Sluigi if (q->dyn_type == O_LIMIT) \ 69598943Sluigi q->parent->count--; \ 696108258Smaxim DEB(printf("ipfw: unlink entry 0x%08x %d -> 0x%08x %d, %d left\n",\ 69798943Sluigi (q->id.src_ip), (q->id.src_port), \ 69898943Sluigi (q->id.dst_ip), (q->id.dst_port), dyn_count-1 ); ) \ 69998943Sluigi if (prev != NULL) \ 70098943Sluigi prev->next = q = q->next; \ 70198943Sluigi else \ 70298943Sluigi head = q = q->next; \ 70398943Sluigi dyn_count--; \ 70498943Sluigi free(old_q, M_IPFW); } 70598943Sluigi 70698943Sluigi#define TIME_LEQ(a,b) ((int)((a)-(b)) <= 0) 70798943Sluigi 70898943Sluigi/** 70998943Sluigi * Remove dynamic rules pointing to "rule", or all of them if rule == NULL. 71098943Sluigi * 71198943Sluigi * If keep_me == NULL, rules are deleted even if not expired, 71298943Sluigi * otherwise only expired rules are removed. 71398943Sluigi * 71498943Sluigi * The value of the second parameter is also used to point to identify 71598943Sluigi * a rule we absolutely do not want to remove (e.g. because we are 71698943Sluigi * holding a reference to it -- this is the case with O_LIMIT_PARENT 71798943Sluigi * rules). The pointer is only used for comparison, so any non-null 71898943Sluigi * value will do. 71998943Sluigi */ 72098943Sluigistatic void 72198943Sluigiremove_dyn_rule(struct ip_fw *rule, ipfw_dyn_rule *keep_me) 72298943Sluigi{ 72398943Sluigi static u_int32_t last_remove = 0; 72498943Sluigi 72598943Sluigi#define FORCE (keep_me == NULL) 72698943Sluigi 72798943Sluigi ipfw_dyn_rule *prev, *q; 72898943Sluigi int i, pass = 0, max_pass = 0; 72998943Sluigi 730120141Ssam IPFW_DYN_LOCK_ASSERT(); 731120141Ssam 73298943Sluigi if (ipfw_dyn_v == NULL || dyn_count == 0) 73398943Sluigi return; 73498943Sluigi /* do not expire more than once per second, it is useless */ 73598943Sluigi if (!FORCE && last_remove == time_second) 73698943Sluigi return; 73798943Sluigi last_remove = time_second; 73898943Sluigi 73998943Sluigi /* 74098943Sluigi * because O_LIMIT refer to parent rules, during the first pass only 74198943Sluigi * remove child and mark any pending LIMIT_PARENT, and remove 74298943Sluigi * them in a second pass. 74398943Sluigi */ 74498943Sluiginext_pass: 74598943Sluigi for (i = 0 ; i < curr_dyn_buckets ; i++) { 74698943Sluigi for (prev=NULL, q = ipfw_dyn_v[i] ; q ; ) { 74798943Sluigi /* 74898943Sluigi * Logic can become complex here, so we split tests. 74998943Sluigi */ 75098943Sluigi if (q == keep_me) 75198943Sluigi goto next; 75298943Sluigi if (rule != NULL && rule != q->rule) 75398943Sluigi goto next; /* not the one we are looking for */ 75498943Sluigi if (q->dyn_type == O_LIMIT_PARENT) { 75598943Sluigi /* 75698943Sluigi * handle parent in the second pass, 75798943Sluigi * record we need one. 75898943Sluigi */ 75998943Sluigi max_pass = 1; 76098943Sluigi if (pass == 0) 76198943Sluigi goto next; 76298943Sluigi if (FORCE && q->count != 0 ) { 76398943Sluigi /* XXX should not happen! */ 764108258Smaxim printf("ipfw: OUCH! cannot remove rule," 76598943Sluigi " count %d\n", q->count); 76698943Sluigi } 76798943Sluigi } else { 76898943Sluigi if (!FORCE && 76998943Sluigi !TIME_LEQ( q->expire, time_second )) 77098943Sluigi goto next; 77198943Sluigi } 772121123Smckusick if (q->dyn_type != O_LIMIT_PARENT || !q->count) { 773121123Smckusick UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q); 774121123Smckusick continue; 775121123Smckusick } 77698943Sluiginext: 77798943Sluigi prev=q; 77898943Sluigi q=q->next; 77998943Sluigi } 78098943Sluigi } 78198943Sluigi if (pass++ < max_pass) 78298943Sluigi goto next_pass; 78398943Sluigi} 78498943Sluigi 78598943Sluigi 78698943Sluigi/** 78798943Sluigi * lookup a dynamic rule. 78898943Sluigi */ 78998943Sluigistatic ipfw_dyn_rule * 790120141Ssamlookup_dyn_rule_locked(struct ipfw_flow_id *pkt, int *match_direction, 791100004Sluigi struct tcphdr *tcp) 79298943Sluigi{ 79398943Sluigi /* 79498943Sluigi * stateful ipfw extensions. 79598943Sluigi * Lookup into dynamic session queue 79698943Sluigi */ 79798943Sluigi#define MATCH_REVERSE 0 79898943Sluigi#define MATCH_FORWARD 1 79998943Sluigi#define MATCH_NONE 2 80098943Sluigi#define MATCH_UNKNOWN 3 80198943Sluigi int i, dir = MATCH_NONE; 80298943Sluigi ipfw_dyn_rule *prev, *q=NULL; 80398943Sluigi 804120141Ssam IPFW_DYN_LOCK_ASSERT(); 805120141Ssam 80698943Sluigi if (ipfw_dyn_v == NULL) 80798943Sluigi goto done; /* not found */ 80898943Sluigi i = hash_packet( pkt ); 80998943Sluigi for (prev=NULL, q = ipfw_dyn_v[i] ; q != NULL ; ) { 810121123Smckusick if (q->dyn_type == O_LIMIT_PARENT && q->count) 81198943Sluigi goto next; 81298943Sluigi if (TIME_LEQ( q->expire, time_second)) { /* expire entry */ 81398943Sluigi UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q); 81498943Sluigi continue; 81598943Sluigi } 816121123Smckusick if (pkt->proto == q->id.proto && 817121123Smckusick q->dyn_type != O_LIMIT_PARENT) { 81898943Sluigi if (pkt->src_ip == q->id.src_ip && 81998943Sluigi pkt->dst_ip == q->id.dst_ip && 82098943Sluigi pkt->src_port == q->id.src_port && 82198943Sluigi pkt->dst_port == q->id.dst_port ) { 82298943Sluigi dir = MATCH_FORWARD; 82398943Sluigi break; 82498943Sluigi } 82598943Sluigi if (pkt->src_ip == q->id.dst_ip && 82698943Sluigi pkt->dst_ip == q->id.src_ip && 82798943Sluigi pkt->src_port == q->id.dst_port && 82898943Sluigi pkt->dst_port == q->id.src_port ) { 82998943Sluigi dir = MATCH_REVERSE; 83098943Sluigi break; 83198943Sluigi } 83298943Sluigi } 83398943Sluiginext: 83498943Sluigi prev = q; 83598943Sluigi q = q->next; 83698943Sluigi } 83798943Sluigi if (q == NULL) 83898943Sluigi goto done; /* q = NULL, not found */ 83998943Sluigi 84098943Sluigi if ( prev != NULL) { /* found and not in front */ 84198943Sluigi prev->next = q->next; 84298943Sluigi q->next = ipfw_dyn_v[i]; 84398943Sluigi ipfw_dyn_v[i] = q; 84498943Sluigi } 84598943Sluigi if (pkt->proto == IPPROTO_TCP) { /* update state according to flags */ 84698943Sluigi u_char flags = pkt->flags & (TH_FIN|TH_SYN|TH_RST); 84798943Sluigi 84898943Sluigi#define BOTH_SYN (TH_SYN | (TH_SYN << 8)) 84998943Sluigi#define BOTH_FIN (TH_FIN | (TH_FIN << 8)) 85098943Sluigi q->state |= (dir == MATCH_FORWARD ) ? flags : (flags << 8); 85198943Sluigi switch (q->state) { 85298943Sluigi case TH_SYN: /* opening */ 85398943Sluigi q->expire = time_second + dyn_syn_lifetime; 85498943Sluigi break; 855101978Sluigi 85698943Sluigi case BOTH_SYN: /* move to established */ 85798943Sluigi case BOTH_SYN | TH_FIN : /* one side tries to close */ 85898943Sluigi case BOTH_SYN | (TH_FIN << 8) : 859100004Sluigi if (tcp) { 860100004Sluigi#define _SEQ_GE(a,b) ((int)(a) - (int)(b) >= 0) 861100004Sluigi u_int32_t ack = ntohl(tcp->th_ack); 862100004Sluigi if (dir == MATCH_FORWARD) { 863100004Sluigi if (q->ack_fwd == 0 || _SEQ_GE(ack, q->ack_fwd)) 864100004Sluigi q->ack_fwd = ack; 865100004Sluigi else { /* ignore out-of-sequence */ 866100004Sluigi break; 867100004Sluigi } 868100004Sluigi } else { 869100004Sluigi if (q->ack_rev == 0 || _SEQ_GE(ack, q->ack_rev)) 870100004Sluigi q->ack_rev = ack; 871100004Sluigi else { /* ignore out-of-sequence */ 872100004Sluigi break; 873100004Sluigi } 874100004Sluigi } 875100004Sluigi } 87698943Sluigi q->expire = time_second + dyn_ack_lifetime; 87798943Sluigi break; 878101978Sluigi 87998943Sluigi case BOTH_SYN | BOTH_FIN: /* both sides closed */ 880101978Sluigi if (dyn_fin_lifetime >= dyn_keepalive_period) 881101978Sluigi dyn_fin_lifetime = dyn_keepalive_period - 1; 88298943Sluigi q->expire = time_second + dyn_fin_lifetime; 88398943Sluigi break; 884101978Sluigi 88598943Sluigi default: 88698943Sluigi#if 0 88798943Sluigi /* 88898943Sluigi * reset or some invalid combination, but can also 88998943Sluigi * occur if we use keep-state the wrong way. 89098943Sluigi */ 89198943Sluigi if ( (q->state & ((TH_RST << 8)|TH_RST)) == 0) 89298943Sluigi printf("invalid state: 0x%x\n", q->state); 89398943Sluigi#endif 894101978Sluigi if (dyn_rst_lifetime >= dyn_keepalive_period) 895101978Sluigi dyn_rst_lifetime = dyn_keepalive_period - 1; 89698943Sluigi q->expire = time_second + dyn_rst_lifetime; 89798943Sluigi break; 89898943Sluigi } 89998943Sluigi } else if (pkt->proto == IPPROTO_UDP) { 90098943Sluigi q->expire = time_second + dyn_udp_lifetime; 90198943Sluigi } else { 90298943Sluigi /* other protocols */ 90398943Sluigi q->expire = time_second + dyn_short_lifetime; 90498943Sluigi } 90598943Sluigidone: 90698943Sluigi if (match_direction) 90798943Sluigi *match_direction = dir; 90898943Sluigi return q; 90998943Sluigi} 91098943Sluigi 911120141Ssamstatic ipfw_dyn_rule * 912120141Ssamlookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction, 913120141Ssam struct tcphdr *tcp) 914120141Ssam{ 915120141Ssam ipfw_dyn_rule *q; 916120141Ssam 917120141Ssam IPFW_DYN_LOCK(); 918120141Ssam q = lookup_dyn_rule_locked(pkt, match_direction, tcp); 919120141Ssam if (q == NULL) 920120141Ssam IPFW_DYN_UNLOCK(); 921120141Ssam /* NB: return table locked when q is not NULL */ 922120141Ssam return q; 923120141Ssam} 924120141Ssam 92598943Sluigistatic void 92698943Sluigirealloc_dynamic_table(void) 92798943Sluigi{ 928120141Ssam IPFW_DYN_LOCK_ASSERT(); 929120141Ssam 930101978Sluigi /* 931101978Sluigi * Try reallocation, make sure we have a power of 2 and do 932101978Sluigi * not allow more than 64k entries. In case of overflow, 933101978Sluigi * default to 1024. 934101978Sluigi */ 93598943Sluigi 936101978Sluigi if (dyn_buckets > 65536) 937101978Sluigi dyn_buckets = 1024; 93898943Sluigi if ((dyn_buckets & (dyn_buckets-1)) != 0) { /* not a power of 2 */ 93998943Sluigi dyn_buckets = curr_dyn_buckets; /* reset */ 94098943Sluigi return; 94198943Sluigi } 94298943Sluigi curr_dyn_buckets = dyn_buckets; 94398943Sluigi if (ipfw_dyn_v != NULL) 94498943Sluigi free(ipfw_dyn_v, M_IPFW); 945101978Sluigi for (;;) { 946101978Sluigi ipfw_dyn_v = malloc(curr_dyn_buckets * sizeof(ipfw_dyn_rule *), 947105440Smux M_IPFW, M_NOWAIT | M_ZERO); 948101978Sluigi if (ipfw_dyn_v != NULL || curr_dyn_buckets <= 2) 949101978Sluigi break; 950101978Sluigi curr_dyn_buckets /= 2; 951101978Sluigi } 95298943Sluigi} 95398943Sluigi 95498943Sluigi/** 95598943Sluigi * Install state of type 'type' for a dynamic session. 95698943Sluigi * The hash table contains two type of rules: 95798943Sluigi * - regular rules (O_KEEP_STATE) 95898943Sluigi * - rules for sessions with limited number of sess per user 95998943Sluigi * (O_LIMIT). When they are created, the parent is 96098943Sluigi * increased by 1, and decreased on delete. In this case, 96198943Sluigi * the third parameter is the parent rule and not the chain. 96298943Sluigi * - "parent" rules for the above (O_LIMIT_PARENT). 96398943Sluigi */ 96498943Sluigistatic ipfw_dyn_rule * 96598943Sluigiadd_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule) 96698943Sluigi{ 96798943Sluigi ipfw_dyn_rule *r; 96898943Sluigi int i; 96998943Sluigi 970120141Ssam IPFW_DYN_LOCK_ASSERT(); 971120141Ssam 97298943Sluigi if (ipfw_dyn_v == NULL || 97398943Sluigi (dyn_count == 0 && dyn_buckets != curr_dyn_buckets)) { 97498943Sluigi realloc_dynamic_table(); 97598943Sluigi if (ipfw_dyn_v == NULL) 97698943Sluigi return NULL; /* failed ! */ 97798943Sluigi } 97898943Sluigi i = hash_packet(id); 97998943Sluigi 980105440Smux r = malloc(sizeof *r, M_IPFW, M_NOWAIT | M_ZERO); 98198943Sluigi if (r == NULL) { 982108258Smaxim printf ("ipfw: sorry cannot allocate state\n"); 98398943Sluigi return NULL; 98498943Sluigi } 98598943Sluigi 98698943Sluigi /* increase refcount on parent, and set pointer */ 98798943Sluigi if (dyn_type == O_LIMIT) { 98898943Sluigi ipfw_dyn_rule *parent = (ipfw_dyn_rule *)rule; 98998943Sluigi if ( parent->dyn_type != O_LIMIT_PARENT) 99098943Sluigi panic("invalid parent"); 99198943Sluigi parent->count++; 99298943Sluigi r->parent = parent; 99398943Sluigi rule = parent->rule; 99498943Sluigi } 99598943Sluigi 99698943Sluigi r->id = *id; 99798943Sluigi r->expire = time_second + dyn_syn_lifetime; 99898943Sluigi r->rule = rule; 99998943Sluigi r->dyn_type = dyn_type; 100098943Sluigi r->pcnt = r->bcnt = 0; 100198943Sluigi r->count = 0; 100298943Sluigi 100398943Sluigi r->bucket = i; 100498943Sluigi r->next = ipfw_dyn_v[i]; 100598943Sluigi ipfw_dyn_v[i] = r; 100698943Sluigi dyn_count++; 1007108258Smaxim DEB(printf("ipfw: add dyn entry ty %d 0x%08x %d -> 0x%08x %d, total %d\n", 100898943Sluigi dyn_type, 100998943Sluigi (r->id.src_ip), (r->id.src_port), 101098943Sluigi (r->id.dst_ip), (r->id.dst_port), 101198943Sluigi dyn_count ); ) 101298943Sluigi return r; 101398943Sluigi} 101498943Sluigi 101598943Sluigi/** 101698943Sluigi * lookup dynamic parent rule using pkt and rule as search keys. 101798943Sluigi * If the lookup fails, then install one. 101898943Sluigi */ 101998943Sluigistatic ipfw_dyn_rule * 102098943Sluigilookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule) 102198943Sluigi{ 102298943Sluigi ipfw_dyn_rule *q; 102398943Sluigi int i; 102498943Sluigi 1025120141Ssam IPFW_DYN_LOCK_ASSERT(); 1026120141Ssam 102798943Sluigi if (ipfw_dyn_v) { 102898943Sluigi i = hash_packet( pkt ); 102998943Sluigi for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next) 103098943Sluigi if (q->dyn_type == O_LIMIT_PARENT && 103198943Sluigi rule== q->rule && 103298943Sluigi pkt->proto == q->id.proto && 103398943Sluigi pkt->src_ip == q->id.src_ip && 103498943Sluigi pkt->dst_ip == q->id.dst_ip && 103598943Sluigi pkt->src_port == q->id.src_port && 103698943Sluigi pkt->dst_port == q->id.dst_port) { 103798943Sluigi q->expire = time_second + dyn_short_lifetime; 1038108258Smaxim DEB(printf("ipfw: lookup_dyn_parent found 0x%p\n",q);) 103998943Sluigi return q; 104098943Sluigi } 104198943Sluigi } 104298943Sluigi return add_dyn_rule(pkt, O_LIMIT_PARENT, rule); 104398943Sluigi} 104498943Sluigi 104598943Sluigi/** 104698943Sluigi * Install dynamic state for rule type cmd->o.opcode 104798943Sluigi * 104898943Sluigi * Returns 1 (failure) if state is not installed because of errors or because 104998943Sluigi * session limitations are enforced. 105098943Sluigi */ 105198943Sluigistatic int 105298943Sluigiinstall_state(struct ip_fw *rule, ipfw_insn_limit *cmd, 105398943Sluigi struct ip_fw_args *args) 105498943Sluigi{ 105598943Sluigi static int last_log; 105698943Sluigi 105798943Sluigi ipfw_dyn_rule *q; 105898943Sluigi 1059108258Smaxim DEB(printf("ipfw: install state type %d 0x%08x %u -> 0x%08x %u\n", 106098943Sluigi cmd->o.opcode, 106198943Sluigi (args->f_id.src_ip), (args->f_id.src_port), 106298943Sluigi (args->f_id.dst_ip), (args->f_id.dst_port) );) 106398943Sluigi 1064120141Ssam IPFW_DYN_LOCK(); 106598943Sluigi 1066120141Ssam q = lookup_dyn_rule_locked(&args->f_id, NULL, NULL); 1067120141Ssam 106898943Sluigi if (q != NULL) { /* should never occur */ 106998943Sluigi if (last_log != time_second) { 107098943Sluigi last_log = time_second; 1071108258Smaxim printf("ipfw: install_state: entry already present, done\n"); 107298943Sluigi } 1073120141Ssam IPFW_DYN_UNLOCK(); 107498943Sluigi return 0; 107598943Sluigi } 107698943Sluigi 107798943Sluigi if (dyn_count >= dyn_max) 107898943Sluigi /* 107998943Sluigi * Run out of slots, try to remove any expired rule. 108098943Sluigi */ 108198943Sluigi remove_dyn_rule(NULL, (ipfw_dyn_rule *)1); 108298943Sluigi 108398943Sluigi if (dyn_count >= dyn_max) { 108498943Sluigi if (last_log != time_second) { 108598943Sluigi last_log = time_second; 1086108258Smaxim printf("ipfw: install_state: Too many dynamic rules\n"); 108798943Sluigi } 1088120141Ssam IPFW_DYN_UNLOCK(); 108998943Sluigi return 1; /* cannot install, notify caller */ 109098943Sluigi } 109198943Sluigi 109298943Sluigi switch (cmd->o.opcode) { 109398943Sluigi case O_KEEP_STATE: /* bidir rule */ 109498943Sluigi add_dyn_rule(&args->f_id, O_KEEP_STATE, rule); 109598943Sluigi break; 109698943Sluigi 109798943Sluigi case O_LIMIT: /* limit number of sessions */ 109898943Sluigi { 109998943Sluigi u_int16_t limit_mask = cmd->limit_mask; 110098943Sluigi struct ipfw_flow_id id; 110198943Sluigi ipfw_dyn_rule *parent; 110298943Sluigi 1103108258Smaxim DEB(printf("ipfw: installing dyn-limit rule %d\n", 1104108258Smaxim cmd->conn_limit);) 110598943Sluigi 110698943Sluigi id.dst_ip = id.src_ip = 0; 110798943Sluigi id.dst_port = id.src_port = 0; 110898943Sluigi id.proto = args->f_id.proto; 110998943Sluigi 111098943Sluigi if (limit_mask & DYN_SRC_ADDR) 111198943Sluigi id.src_ip = args->f_id.src_ip; 111298943Sluigi if (limit_mask & DYN_DST_ADDR) 111398943Sluigi id.dst_ip = args->f_id.dst_ip; 111498943Sluigi if (limit_mask & DYN_SRC_PORT) 111598943Sluigi id.src_port = args->f_id.src_port; 111698943Sluigi if (limit_mask & DYN_DST_PORT) 111798943Sluigi id.dst_port = args->f_id.dst_port; 111898943Sluigi parent = lookup_dyn_parent(&id, rule); 111998943Sluigi if (parent == NULL) { 1120108258Smaxim printf("ipfw: add parent failed\n"); 112198943Sluigi return 1; 112298943Sluigi } 112398943Sluigi if (parent->count >= cmd->conn_limit) { 112498943Sluigi /* 112598943Sluigi * See if we can remove some expired rule. 112698943Sluigi */ 112798943Sluigi remove_dyn_rule(rule, parent); 112898943Sluigi if (parent->count >= cmd->conn_limit) { 112998943Sluigi if (fw_verbose && last_log != time_second) { 113098943Sluigi last_log = time_second; 1131106118Smaxim log(LOG_SECURITY | LOG_DEBUG, 113298943Sluigi "drop session, too many entries\n"); 113398943Sluigi } 1134120141Ssam IPFW_DYN_UNLOCK(); 113598943Sluigi return 1; 113698943Sluigi } 113798943Sluigi } 113898943Sluigi add_dyn_rule(&args->f_id, O_LIMIT, (struct ip_fw *)parent); 113998943Sluigi } 114098943Sluigi break; 114198943Sluigi default: 1142108258Smaxim printf("ipfw: unknown dynamic rule type %u\n", cmd->o.opcode); 1143120141Ssam IPFW_DYN_UNLOCK(); 114498943Sluigi return 1; 114598943Sluigi } 1146120141Ssam lookup_dyn_rule_locked(&args->f_id, NULL, NULL); /* XXX just set lifetime */ 1147120141Ssam IPFW_DYN_UNLOCK(); 114898943Sluigi return 0; 114998943Sluigi} 115098943Sluigi 1151100004Sluigi/* 1152100004Sluigi * Transmit a TCP packet, containing either a RST or a keepalive. 1153100004Sluigi * When flags & TH_RST, we are sending a RST packet, because of a 1154100004Sluigi * "reset" action matched the packet. 1155100004Sluigi * Otherwise we are sending a keepalive, and flags & TH_ 1156100004Sluigi */ 115799475Sluigistatic void 1158100004Sluigisend_pkt(struct ipfw_flow_id *id, u_int32_t seq, u_int32_t ack, int flags) 115999475Sluigi{ 116099475Sluigi struct mbuf *m; 1161100004Sluigi struct ip *ip; 116299475Sluigi struct tcphdr *tcp; 116399475Sluigi struct route sro; /* fake route */ 116499475Sluigi 1165111119Simp MGETHDR(m, M_DONTWAIT, MT_HEADER); 1166105775Smaxim if (m == 0) 116799475Sluigi return; 116899475Sluigi m->m_pkthdr.rcvif = (struct ifnet *)0; 116999475Sluigi m->m_pkthdr.len = m->m_len = sizeof(struct ip) + sizeof(struct tcphdr); 117099475Sluigi m->m_data += max_linkhdr; 117199475Sluigi 1172100004Sluigi ip = mtod(m, struct ip *); 1173100004Sluigi bzero(ip, m->m_len); 1174100004Sluigi tcp = (struct tcphdr *)(ip + 1); /* no IP options */ 117599475Sluigi ip->ip_p = IPPROTO_TCP; 1176100004Sluigi tcp->th_off = 5; 1177100004Sluigi /* 1178100004Sluigi * Assume we are sending a RST (or a keepalive in the reverse 1179100004Sluigi * direction), swap src and destination addresses and ports. 1180100004Sluigi */ 1181100004Sluigi ip->ip_src.s_addr = htonl(id->dst_ip); 1182100004Sluigi ip->ip_dst.s_addr = htonl(id->src_ip); 1183100004Sluigi tcp->th_sport = htons(id->dst_port); 1184100004Sluigi tcp->th_dport = htons(id->src_port); 1185100004Sluigi if (flags & TH_RST) { /* we are sending a RST */ 1186100004Sluigi if (flags & TH_ACK) { 1187100004Sluigi tcp->th_seq = htonl(ack); 1188100004Sluigi tcp->th_ack = htonl(0); 1189100004Sluigi tcp->th_flags = TH_RST; 1190100004Sluigi } else { 1191100004Sluigi if (flags & TH_SYN) 1192100004Sluigi seq++; 1193100004Sluigi tcp->th_seq = htonl(0); 1194100004Sluigi tcp->th_ack = htonl(seq); 1195100004Sluigi tcp->th_flags = TH_RST | TH_ACK; 1196100004Sluigi } 119799475Sluigi } else { 1198100004Sluigi /* 1199100004Sluigi * We are sending a keepalive. flags & TH_SYN determines 1200100004Sluigi * the direction, forward if set, reverse if clear. 1201100004Sluigi * NOTE: seq and ack are always assumed to be correct 1202100004Sluigi * as set by the caller. This may be confusing... 1203100004Sluigi */ 1204100004Sluigi if (flags & TH_SYN) { 1205100004Sluigi /* 1206100004Sluigi * we have to rewrite the correct addresses! 1207100004Sluigi */ 1208100004Sluigi ip->ip_dst.s_addr = htonl(id->dst_ip); 1209100004Sluigi ip->ip_src.s_addr = htonl(id->src_ip); 1210100004Sluigi tcp->th_dport = htons(id->dst_port); 1211100004Sluigi tcp->th_sport = htons(id->src_port); 1212100004Sluigi } 1213100004Sluigi tcp->th_seq = htonl(seq); 1214100004Sluigi tcp->th_ack = htonl(ack); 1215100004Sluigi tcp->th_flags = TH_ACK; 121699475Sluigi } 1217100004Sluigi /* 1218100004Sluigi * set ip_len to the payload size so we can compute 1219100004Sluigi * the tcp checksum on the pseudoheader 1220100004Sluigi * XXX check this, could save a couple of words ? 1221100004Sluigi */ 1222100004Sluigi ip->ip_len = htons(sizeof(struct tcphdr)); 122399475Sluigi tcp->th_sum = in_cksum(m, m->m_pkthdr.len); 1224100004Sluigi /* 1225100004Sluigi * now fill fields left out earlier 1226100004Sluigi */ 122799475Sluigi ip->ip_ttl = ip_defttl; 122899475Sluigi ip->ip_len = m->m_pkthdr.len; 122999475Sluigi bzero (&sro, sizeof (sro)); 123099475Sluigi ip_rtaddr(ip->ip_dst, &sro); 1231101978Sluigi m->m_flags |= M_SKIP_FIREWALL; 1232105194Ssam ip_output(m, NULL, &sro, 0, NULL, NULL); 123399475Sluigi if (sro.ro_rt) 123499475Sluigi RTFREE(sro.ro_rt); 123599475Sluigi} 123699475Sluigi 123798943Sluigi/* 123898943Sluigi * sends a reject message, consuming the mbuf passed as an argument. 123998943Sluigi */ 124098943Sluigistatic void 124199475Sluigisend_reject(struct ip_fw_args *args, int code, int offset, int ip_len) 124298943Sluigi{ 1243101843Sphk 1244108327Siedowse if (code != ICMP_REJECT_RST) { /* Send an ICMP unreach */ 1245108327Siedowse /* We need the IP header in host order for icmp_error(). */ 1246108327Siedowse if (args->eh != NULL) { 1247108327Siedowse struct ip *ip = mtod(args->m, struct ip *); 1248108327Siedowse ip->ip_len = ntohs(ip->ip_len); 1249108327Siedowse ip->ip_off = ntohs(ip->ip_off); 1250108327Siedowse } 125199475Sluigi icmp_error(args->m, ICMP_UNREACH, code, 0L, 0); 1252108327Siedowse } else if (offset == 0 && args->f_id.proto == IPPROTO_TCP) { 125399475Sluigi struct tcphdr *const tcp = 125499475Sluigi L3HDR(struct tcphdr, mtod(args->m, struct ip *)); 125599475Sluigi if ( (tcp->th_flags & TH_RST) == 0) 1256100004Sluigi send_pkt(&(args->f_id), ntohl(tcp->th_seq), 1257100004Sluigi ntohl(tcp->th_ack), 1258100004Sluigi tcp->th_flags | TH_RST); 125999475Sluigi m_freem(args->m); 126099475Sluigi } else 126199475Sluigi m_freem(args->m); 126299475Sluigi args->m = NULL; 126398943Sluigi} 126498943Sluigi 126598943Sluigi/** 126698943Sluigi * 126798943Sluigi * Given an ip_fw *, lookup_next_rule will return a pointer 126898943Sluigi * to the next rule, which can be either the jump 126998943Sluigi * target (for skipto instructions) or the next one in the list (in 127098943Sluigi * all other cases including a missing jump target). 127198943Sluigi * The result is also written in the "next_rule" field of the rule. 127298943Sluigi * Backward jumps are not allowed, so start looking from the next 127398943Sluigi * rule... 127498943Sluigi * 127598943Sluigi * This never returns NULL -- in case we do not have an exact match, 127698943Sluigi * the next rule is returned. When the ruleset is changed, 127798943Sluigi * pointers are flushed so we are always correct. 1278105775Smaxim */ 127998943Sluigi 128098943Sluigistatic struct ip_fw * 128198943Sluigilookup_next_rule(struct ip_fw *me) 128298943Sluigi{ 128398943Sluigi struct ip_fw *rule = NULL; 128498943Sluigi ipfw_insn *cmd; 128598943Sluigi 128698943Sluigi /* look for action, in case it is a skipto */ 128798943Sluigi cmd = ACTION_PTR(me); 1288109566Smaxim if (cmd->opcode == O_LOG) 1289109566Smaxim cmd += F_LEN(cmd); 129098943Sluigi if ( cmd->opcode == O_SKIPTO ) 129198943Sluigi for (rule = me->next; rule ; rule = rule->next) 129298943Sluigi if (rule->rulenum >= cmd->arg1) 129398943Sluigi break; 129498943Sluigi if (rule == NULL) /* failure or not a skipto */ 129598943Sluigi rule = me->next; 129698943Sluigi me->next_rule = rule; 129798943Sluigi return rule; 129898943Sluigi} 129998943Sluigi 130098943Sluigi/* 130198943Sluigi * The main check routine for the firewall. 130298943Sluigi * 130398943Sluigi * All arguments are in args so we can modify them and return them 130498943Sluigi * back to the caller. 130598943Sluigi * 130698943Sluigi * Parameters: 130798943Sluigi * 130898943Sluigi * args->m (in/out) The packet; we set to NULL when/if we nuke it. 130998943Sluigi * Starts with the IP header. 131098943Sluigi * args->eh (in) Mac header if present, or NULL for layer3 packet. 131198943Sluigi * args->oif Outgoing interface, or NULL if packet is incoming. 131298943Sluigi * The incoming interface is in the mbuf. (in) 131398943Sluigi * args->divert_rule (in/out) 131498943Sluigi * Skip up to the first rule past this rule number; 131598943Sluigi * upon return, non-zero port number for divert or tee. 131698943Sluigi * 131798943Sluigi * args->rule Pointer to the last matching rule (in/out) 131898943Sluigi * args->next_hop Socket we are forwarding to (out). 131998943Sluigi * args->f_id Addresses grabbed from the packet (out) 132098943Sluigi * 132198943Sluigi * Return value: 132298943Sluigi * 132398943Sluigi * IP_FW_PORT_DENY_FLAG the packet must be dropped. 132498943Sluigi * 0 The packet is to be accepted and routed normally OR 132598943Sluigi * the packet was denied/rejected and has been dropped; 132698943Sluigi * in the latter case, *m is equal to NULL upon return. 132798943Sluigi * port Divert the packet to port, with these caveats: 132898943Sluigi * 132998943Sluigi * - If IP_FW_PORT_TEE_FLAG is set, tee the packet instead 133098943Sluigi * of diverting it (ie, 'ipfw tee'). 133198943Sluigi * 133298943Sluigi * - If IP_FW_PORT_DYNT_FLAG is set, interpret the lower 133398943Sluigi * 16 bits as a dummynet pipe number instead of diverting 133498943Sluigi */ 133598943Sluigi 1336105775Smaximstatic int 133798943Sluigiipfw_chk(struct ip_fw_args *args) 133898943Sluigi{ 133998943Sluigi /* 134098943Sluigi * Local variables hold state during the processing of a packet. 134198943Sluigi * 134298943Sluigi * IMPORTANT NOTE: to speed up the processing of rules, there 134398943Sluigi * are some assumption on the values of the variables, which 134498943Sluigi * are documented here. Should you change them, please check 134598943Sluigi * the implementation of the various instructions to make sure 134698943Sluigi * that they still work. 1347101978Sluigi * 134898943Sluigi * args->eh The MAC header. It is non-null for a layer2 134998943Sluigi * packet, it is NULL for a layer-3 packet. 135098943Sluigi * 135198943Sluigi * m | args->m Pointer to the mbuf, as received from the caller. 135298943Sluigi * It may change if ipfw_chk() does an m_pullup, or if it 135398943Sluigi * consumes the packet because it calls send_reject(). 135498943Sluigi * XXX This has to change, so that ipfw_chk() never modifies 135598943Sluigi * or consumes the buffer. 135698943Sluigi * ip is simply an alias of the value of m, and it is kept 135798943Sluigi * in sync with it (the packet is supposed to start with 135898943Sluigi * the ip header). 135998943Sluigi */ 136098943Sluigi struct mbuf *m = args->m; 136198943Sluigi struct ip *ip = mtod(m, struct ip *); 136298943Sluigi 136398943Sluigi /* 136498943Sluigi * oif | args->oif If NULL, ipfw_chk has been called on the 136598943Sluigi * inbound path (ether_input, bdg_forward, ip_input). 136698943Sluigi * If non-NULL, ipfw_chk has been called on the outbound path 136798943Sluigi * (ether_output, ip_output). 136898943Sluigi */ 136998943Sluigi struct ifnet *oif = args->oif; 137098943Sluigi 137198943Sluigi struct ip_fw *f = NULL; /* matching rule */ 137298943Sluigi int retval = 0; 137398943Sluigi 137498943Sluigi /* 137598943Sluigi * hlen The length of the IPv4 header. 137698943Sluigi * hlen >0 means we have an IPv4 packet. 137798943Sluigi */ 137898943Sluigi u_int hlen = 0; /* hlen >0 means we have an IP pkt */ 137998943Sluigi 138098943Sluigi /* 138198943Sluigi * offset The offset of a fragment. offset != 0 means that 138298943Sluigi * we have a fragment at this offset of an IPv4 packet. 138398943Sluigi * offset == 0 means that (if this is an IPv4 packet) 138498943Sluigi * this is the first or only fragment. 138598943Sluigi */ 138698943Sluigi u_short offset = 0; 138798943Sluigi 138898943Sluigi /* 138998943Sluigi * Local copies of addresses. They are only valid if we have 139098943Sluigi * an IP packet. 139198943Sluigi * 139298943Sluigi * proto The protocol. Set to 0 for non-ip packets, 139398943Sluigi * or to the protocol read from the packet otherwise. 139498943Sluigi * proto != 0 means that we have an IPv4 packet. 139598943Sluigi * 139698943Sluigi * src_port, dst_port port numbers, in HOST format. Only 139798943Sluigi * valid for TCP and UDP packets. 139898943Sluigi * 139998943Sluigi * src_ip, dst_ip ip addresses, in NETWORK format. 140098943Sluigi * Only valid for IPv4 packets. 140198943Sluigi */ 140298943Sluigi u_int8_t proto; 140398943Sluigi u_int16_t src_port = 0, dst_port = 0; /* NOTE: host format */ 140498943Sluigi struct in_addr src_ip, dst_ip; /* NOTE: network format */ 140598943Sluigi u_int16_t ip_len=0; 1406115750Skbyanc int pktlen; 140798943Sluigi int dyn_dir = MATCH_UNKNOWN; 140898943Sluigi ipfw_dyn_rule *q = NULL; 1409120141Ssam struct ip_fw_chain *chain = &layer3_chain; 141098943Sluigi 1411101978Sluigi if (m->m_flags & M_SKIP_FIREWALL) 1412101978Sluigi return 0; /* accept */ 141398943Sluigi /* 141498943Sluigi * dyn_dir = MATCH_UNKNOWN when rules unchecked, 141598943Sluigi * MATCH_NONE when checked and not matched (q = NULL), 141698943Sluigi * MATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL) 141798943Sluigi */ 141898943Sluigi 1419115750Skbyanc pktlen = m->m_pkthdr.len; 142098943Sluigi if (args->eh == NULL || /* layer 3 packet */ 142198943Sluigi ( m->m_pkthdr.len >= sizeof(struct ip) && 142298943Sluigi ntohs(args->eh->ether_type) == ETHERTYPE_IP)) 142398943Sluigi hlen = ip->ip_hl << 2; 142498943Sluigi 142598943Sluigi /* 142698943Sluigi * Collect parameters into local variables for faster matching. 142798943Sluigi */ 142898943Sluigi if (hlen == 0) { /* do not grab addresses for non-ip pkts */ 142998943Sluigi proto = args->f_id.proto = 0; /* mark f_id invalid */ 143098943Sluigi goto after_ip_checks; 143198943Sluigi } 143298943Sluigi 143398943Sluigi proto = args->f_id.proto = ip->ip_p; 143498943Sluigi src_ip = ip->ip_src; 143598943Sluigi dst_ip = ip->ip_dst; 143698943Sluigi if (args->eh != NULL) { /* layer 2 packets are as on the wire */ 143798943Sluigi offset = ntohs(ip->ip_off) & IP_OFFMASK; 143898943Sluigi ip_len = ntohs(ip->ip_len); 143998943Sluigi } else { 144098943Sluigi offset = ip->ip_off & IP_OFFMASK; 144198943Sluigi ip_len = ip->ip_len; 144298943Sluigi } 1443115750Skbyanc pktlen = ip_len < pktlen ? ip_len : pktlen; 144498943Sluigi 144598943Sluigi#define PULLUP_TO(len) \ 144698943Sluigi do { \ 144798943Sluigi if ((m)->m_len < (len)) { \ 144898943Sluigi args->m = m = m_pullup(m, (len)); \ 144998943Sluigi if (m == 0) \ 145098943Sluigi goto pullup_failed; \ 145198943Sluigi ip = mtod(m, struct ip *); \ 145298943Sluigi } \ 145398943Sluigi } while (0) 145498943Sluigi 145598943Sluigi if (offset == 0) { 145698943Sluigi switch (proto) { 145798943Sluigi case IPPROTO_TCP: 145898943Sluigi { 145998943Sluigi struct tcphdr *tcp; 146098943Sluigi 146198943Sluigi PULLUP_TO(hlen + sizeof(struct tcphdr)); 146298943Sluigi tcp = L3HDR(struct tcphdr, ip); 146398943Sluigi dst_port = tcp->th_dport; 146498943Sluigi src_port = tcp->th_sport; 146598943Sluigi args->f_id.flags = tcp->th_flags; 146698943Sluigi } 146798943Sluigi break; 146898943Sluigi 146998943Sluigi case IPPROTO_UDP: 147098943Sluigi { 147198943Sluigi struct udphdr *udp; 147298943Sluigi 147398943Sluigi PULLUP_TO(hlen + sizeof(struct udphdr)); 147498943Sluigi udp = L3HDR(struct udphdr, ip); 147598943Sluigi dst_port = udp->uh_dport; 147698943Sluigi src_port = udp->uh_sport; 147798943Sluigi } 147898943Sluigi break; 147998943Sluigi 148098943Sluigi case IPPROTO_ICMP: 148198943Sluigi PULLUP_TO(hlen + 4); /* type, code and checksum. */ 148298943Sluigi args->f_id.flags = L3HDR(struct icmp, ip)->icmp_type; 148398943Sluigi break; 148498943Sluigi 148598943Sluigi default: 148698943Sluigi break; 148798943Sluigi } 148898943Sluigi#undef PULLUP_TO 148998943Sluigi } 149098943Sluigi 149198943Sluigi args->f_id.src_ip = ntohl(src_ip.s_addr); 149298943Sluigi args->f_id.dst_ip = ntohl(dst_ip.s_addr); 149398943Sluigi args->f_id.src_port = src_port = ntohs(src_port); 149498943Sluigi args->f_id.dst_port = dst_port = ntohs(dst_port); 149598943Sluigi 149698943Sluigiafter_ip_checks: 1497120141Ssam IPFW_LOCK(chain); /* XXX expensive? can we run lock free? */ 149898943Sluigi if (args->rule) { 149998943Sluigi /* 150098943Sluigi * Packet has already been tagged. Look for the next rule 150198943Sluigi * to restart processing. 150298943Sluigi * 150398943Sluigi * If fw_one_pass != 0 then just accept it. 150498943Sluigi * XXX should not happen here, but optimized out in 150598943Sluigi * the caller. 150698943Sluigi */ 1507120141Ssam if (fw_one_pass) { 1508120141Ssam IPFW_UNLOCK(chain); /* XXX optimize */ 150998943Sluigi return 0; 1510120141Ssam } 151198943Sluigi 151298943Sluigi f = args->rule->next_rule; 151398943Sluigi if (f == NULL) 151498943Sluigi f = lookup_next_rule(args->rule); 151598943Sluigi } else { 151698943Sluigi /* 151798943Sluigi * Find the starting rule. It can be either the first 151898943Sluigi * one, or the one after divert_rule if asked so. 151998943Sluigi */ 152098943Sluigi int skipto = args->divert_rule; 152198943Sluigi 1522120141Ssam f = chain->rules; 152398943Sluigi if (args->eh == NULL && skipto != 0) { 1524120141Ssam if (skipto >= IPFW_DEFAULT_RULE) { 1525120141Ssam IPFW_UNLOCK(chain); 152698943Sluigi return(IP_FW_PORT_DENY_FLAG); /* invalid */ 1527120141Ssam } 152898943Sluigi while (f && f->rulenum <= skipto) 152998943Sluigi f = f->next; 1530120141Ssam if (f == NULL) { /* drop packet */ 1531120141Ssam IPFW_UNLOCK(chain); 153298943Sluigi return(IP_FW_PORT_DENY_FLAG); 1533120141Ssam } 153498943Sluigi } 153598943Sluigi } 153698943Sluigi args->divert_rule = 0; /* reset to avoid confusion later */ 153798943Sluigi 153898943Sluigi /* 153998943Sluigi * Now scan the rules, and parse microinstructions for each rule. 154098943Sluigi */ 154198943Sluigi for (; f; f = f->next) { 154298943Sluigi int l, cmdlen; 154398943Sluigi ipfw_insn *cmd; 154498943Sluigi int skip_or; /* skip rest of OR block */ 154598943Sluigi 154698943Sluigiagain: 1547101628Sluigi if (set_disable & (1 << f->set) ) 1548101628Sluigi continue; 1549101628Sluigi 155098943Sluigi skip_or = 0; 155198943Sluigi for (l = f->cmd_len, cmd = f->cmd ; l > 0 ; 155298943Sluigi l -= cmdlen, cmd += cmdlen) { 155399622Sluigi int match; 155498943Sluigi 155598943Sluigi /* 155698943Sluigi * check_body is a jump target used when we find a 155798943Sluigi * CHECK_STATE, and need to jump to the body of 155898943Sluigi * the target rule. 155998943Sluigi */ 156098943Sluigi 156198943Sluigicheck_body: 156298943Sluigi cmdlen = F_LEN(cmd); 156398943Sluigi /* 156498943Sluigi * An OR block (insn_1 || .. || insn_n) has the 156598943Sluigi * F_OR bit set in all but the last instruction. 156698943Sluigi * The first match will set "skip_or", and cause 156798943Sluigi * the following instructions to be skipped until 156898943Sluigi * past the one with the F_OR bit clear. 156998943Sluigi */ 157098943Sluigi if (skip_or) { /* skip this instruction */ 157198943Sluigi if ((cmd->len & F_OR) == 0) 157298943Sluigi skip_or = 0; /* next one is good */ 157398943Sluigi continue; 157498943Sluigi } 157599622Sluigi match = 0; /* set to 1 if we succeed */ 157699622Sluigi 157798943Sluigi switch (cmd->opcode) { 157899622Sluigi /* 157999622Sluigi * The first set of opcodes compares the packet's 158099622Sluigi * fields with some pattern, setting 'match' if a 158199622Sluigi * match is found. At the end of the loop there is 158299622Sluigi * logic to deal with F_NOT and F_OR flags associated 158399622Sluigi * with the opcode. 158499622Sluigi */ 158598943Sluigi case O_NOP: 158699622Sluigi match = 1; 158799622Sluigi break; 158898943Sluigi 158998943Sluigi case O_FORWARD_MAC: 159098943Sluigi printf("ipfw: opcode %d unimplemented\n", 159198943Sluigi cmd->opcode); 159299622Sluigi break; 159398943Sluigi 159498943Sluigi case O_GID: 159598943Sluigi case O_UID: 159698943Sluigi /* 159798943Sluigi * We only check offset == 0 && proto != 0, 159898943Sluigi * as this ensures that we have an IPv4 159998943Sluigi * packet with the ports info. 160098943Sluigi */ 160198943Sluigi if (offset!=0) 160299622Sluigi break; 160398943Sluigi { 160498943Sluigi struct inpcbinfo *pi; 160598943Sluigi int wildcard; 160698943Sluigi struct inpcb *pcb; 160798943Sluigi 160898943Sluigi if (proto == IPPROTO_TCP) { 160998943Sluigi wildcard = 0; 161098943Sluigi pi = &tcbinfo; 161198943Sluigi } else if (proto == IPPROTO_UDP) { 161298943Sluigi wildcard = 1; 161398943Sluigi pi = &udbinfo; 161498943Sluigi } else 161599622Sluigi break; 161698943Sluigi 1617120141Ssam /* XXX locking? */ 161898943Sluigi pcb = (oif) ? 161998943Sluigi in_pcblookup_hash(pi, 162098943Sluigi dst_ip, htons(dst_port), 162198943Sluigi src_ip, htons(src_port), 162298943Sluigi wildcard, oif) : 162398943Sluigi in_pcblookup_hash(pi, 162498943Sluigi src_ip, htons(src_port), 162598943Sluigi dst_ip, htons(dst_port), 162698943Sluigi wildcard, NULL); 162798943Sluigi 162898943Sluigi if (pcb == NULL || pcb->inp_socket == NULL) 162999622Sluigi break; 163099622Sluigi#if __FreeBSD_version < 500034 1631111037Smaxim#define socheckuid(a,b) ((a)->so_cred->cr_uid != (b)) 163299622Sluigi#endif 163398943Sluigi if (cmd->opcode == O_UID) { 163499622Sluigi match = 1635111037Smaxim !socheckuid(pcb->inp_socket, 163699622Sluigi (uid_t)((ipfw_insn_u32 *)cmd)->d[0]); 163798943Sluigi } else { 163899622Sluigi match = groupmember( 163998943Sluigi (uid_t)((ipfw_insn_u32 *)cmd)->d[0], 164099622Sluigi pcb->inp_socket->so_cred); 164198943Sluigi } 164298943Sluigi } 164399622Sluigi break; 164498943Sluigi 164598943Sluigi case O_RECV: 164699622Sluigi match = iface_match(m->m_pkthdr.rcvif, 164799622Sluigi (ipfw_insn_if *)cmd); 164899622Sluigi break; 164998943Sluigi 165098943Sluigi case O_XMIT: 165199622Sluigi match = iface_match(oif, (ipfw_insn_if *)cmd); 165299622Sluigi break; 165398943Sluigi 165498943Sluigi case O_VIA: 165599622Sluigi match = iface_match(oif ? oif : 165699622Sluigi m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd); 165799622Sluigi break; 165898943Sluigi 165998943Sluigi case O_MACADDR2: 166098943Sluigi if (args->eh != NULL) { /* have MAC header */ 166198943Sluigi u_int32_t *want = (u_int32_t *) 166298943Sluigi ((ipfw_insn_mac *)cmd)->addr; 166398943Sluigi u_int32_t *mask = (u_int32_t *) 166498943Sluigi ((ipfw_insn_mac *)cmd)->mask; 166598943Sluigi u_int32_t *hdr = (u_int32_t *)args->eh; 166698943Sluigi 166799622Sluigi match = 166899622Sluigi ( want[0] == (hdr[0] & mask[0]) && 166999622Sluigi want[1] == (hdr[1] & mask[1]) && 167099622Sluigi want[2] == (hdr[2] & mask[2]) ); 167198943Sluigi } 167299622Sluigi break; 167398943Sluigi 167498943Sluigi case O_MAC_TYPE: 167598943Sluigi if (args->eh != NULL) { 167699622Sluigi u_int16_t t = 167798943Sluigi ntohs(args->eh->ether_type); 167898943Sluigi u_int16_t *p = 167998943Sluigi ((ipfw_insn_u16 *)cmd)->ports; 168098943Sluigi int i; 168198943Sluigi 168299622Sluigi for (i = cmdlen - 1; !match && i>0; 168399622Sluigi i--, p += 2) 168499622Sluigi match = (t>=p[0] && t<=p[1]); 168598943Sluigi } 168699622Sluigi break; 168798943Sluigi 168898943Sluigi case O_FRAG: 168999622Sluigi match = (hlen > 0 && offset != 0); 169099622Sluigi break; 169198943Sluigi 169298943Sluigi case O_IN: /* "out" is "not in" */ 169399622Sluigi match = (oif == NULL); 169499622Sluigi break; 169598943Sluigi 169698943Sluigi case O_LAYER2: 169799622Sluigi match = (args->eh != NULL); 169899622Sluigi break; 169998943Sluigi 170098943Sluigi case O_PROTO: 170198943Sluigi /* 170298943Sluigi * We do not allow an arg of 0 so the 170398943Sluigi * check of "proto" only suffices. 170498943Sluigi */ 170599622Sluigi match = (proto == cmd->arg1); 170699622Sluigi break; 170798943Sluigi 170898943Sluigi case O_IP_SRC: 170999622Sluigi match = (hlen > 0 && 171098943Sluigi ((ipfw_insn_ip *)cmd)->addr.s_addr == 171199622Sluigi src_ip.s_addr); 171299622Sluigi break; 1713105775Smaxim 171498943Sluigi case O_IP_SRC_MASK: 1715117327Sluigi case O_IP_DST_MASK: 1716117327Sluigi if (hlen > 0) { 1717117327Sluigi uint32_t a = 1718117327Sluigi (cmd->opcode == O_IP_DST_MASK) ? 1719117327Sluigi dst_ip.s_addr : src_ip.s_addr; 1720117327Sluigi uint32_t *p = ((ipfw_insn_u32 *)cmd)->d; 1721117327Sluigi int i = cmdlen-1; 1722117327Sluigi 1723117327Sluigi for (; !match && i>0; i-= 2, p+= 2) 1724117327Sluigi match = (p[0] == (a & p[1])); 1725117327Sluigi } 172699622Sluigi break; 172798943Sluigi 172898943Sluigi case O_IP_SRC_ME: 172999622Sluigi if (hlen > 0) { 173099622Sluigi struct ifnet *tif; 173198943Sluigi 173299622Sluigi INADDR_TO_IFP(src_ip, tif); 173399622Sluigi match = (tif != NULL); 173499622Sluigi } 173599622Sluigi break; 1736105775Smaxim 173798943Sluigi case O_IP_DST_SET: 173898943Sluigi case O_IP_SRC_SET: 173999622Sluigi if (hlen > 0) { 174099622Sluigi u_int32_t *d = (u_int32_t *)(cmd+1); 174199622Sluigi u_int32_t addr = 174299622Sluigi cmd->opcode == O_IP_DST_SET ? 1743105886Sluigi args->f_id.dst_ip : 1744105886Sluigi args->f_id.src_ip; 174598943Sluigi 174699622Sluigi if (addr < d[0]) 174799622Sluigi break; 174899622Sluigi addr -= d[0]; /* subtract base */ 174999622Sluigi match = (addr < cmd->arg1) && 175099622Sluigi ( d[ 1 + (addr>>5)] & 175199622Sluigi (1<<(addr & 0x1f)) ); 175299622Sluigi } 175399622Sluigi break; 175498943Sluigi 175598943Sluigi case O_IP_DST: 175699622Sluigi match = (hlen > 0 && 175798943Sluigi ((ipfw_insn_ip *)cmd)->addr.s_addr == 175899622Sluigi dst_ip.s_addr); 175999622Sluigi break; 176098943Sluigi 176198943Sluigi case O_IP_DST_ME: 176299622Sluigi if (hlen > 0) { 176399622Sluigi struct ifnet *tif; 176499622Sluigi 176599622Sluigi INADDR_TO_IFP(dst_ip, tif); 176699622Sluigi match = (tif != NULL); 176799622Sluigi } 176899622Sluigi break; 1769105775Smaxim 177098943Sluigi case O_IP_SRCPORT: 177198943Sluigi case O_IP_DSTPORT: 177298943Sluigi /* 177398943Sluigi * offset == 0 && proto != 0 is enough 177498943Sluigi * to guarantee that we have an IPv4 177598943Sluigi * packet with port info. 177698943Sluigi */ 177799622Sluigi if ((proto==IPPROTO_UDP || proto==IPPROTO_TCP) 177899622Sluigi && offset == 0) { 177999622Sluigi u_int16_t x = 178098943Sluigi (cmd->opcode == O_IP_SRCPORT) ? 178199622Sluigi src_port : dst_port ; 178298943Sluigi u_int16_t *p = 178398943Sluigi ((ipfw_insn_u16 *)cmd)->ports; 178498943Sluigi int i; 178598943Sluigi 178699622Sluigi for (i = cmdlen - 1; !match && i>0; 178799622Sluigi i--, p += 2) 178899622Sluigi match = (x>=p[0] && x<=p[1]); 178998943Sluigi } 179099622Sluigi break; 179198943Sluigi 179298943Sluigi case O_ICMPTYPE: 179399622Sluigi match = (offset == 0 && proto==IPPROTO_ICMP && 179499622Sluigi icmptype_match(ip, (ipfw_insn_u32 *)cmd) ); 179599622Sluigi break; 179698943Sluigi 179798943Sluigi case O_IPOPT: 179899622Sluigi match = (hlen > 0 && ipopts_match(ip, cmd) ); 179999622Sluigi break; 180098943Sluigi 180198943Sluigi case O_IPVER: 180299622Sluigi match = (hlen > 0 && cmd->arg1 == ip->ip_v); 180399622Sluigi break; 180498943Sluigi 1805116690Sluigi case O_IPID: 1806116690Sluigi case O_IPLEN: 180798943Sluigi case O_IPTTL: 1808116690Sluigi if (hlen > 0) { /* only for IP packets */ 1809116690Sluigi uint16_t x; 1810116690Sluigi uint16_t *p; 1811116690Sluigi int i; 181298943Sluigi 1813116690Sluigi if (cmd->opcode == O_IPLEN) 1814116690Sluigi x = ip_len; 1815116690Sluigi else if (cmd->opcode == O_IPTTL) 1816116690Sluigi x = ip->ip_ttl; 1817116690Sluigi else /* must be IPID */ 1818116690Sluigi x = ntohs(ip->ip_id); 1819116690Sluigi if (cmdlen == 1) { 1820116690Sluigi match = (cmd->arg1 == x); 1821116690Sluigi break; 1822116690Sluigi } 1823116690Sluigi /* otherwise we have ranges */ 1824116690Sluigi p = ((ipfw_insn_u16 *)cmd)->ports; 1825116690Sluigi i = cmdlen - 1; 1826116690Sluigi for (; !match && i>0; i--, p += 2) 1827116690Sluigi match = (x >= p[0] && x <= p[1]); 1828116690Sluigi } 182999622Sluigi break; 183098943Sluigi 183199475Sluigi case O_IPPRECEDENCE: 183299622Sluigi match = (hlen > 0 && 183399622Sluigi (cmd->arg1 == (ip->ip_tos & 0xe0)) ); 183499622Sluigi break; 183599475Sluigi 183698943Sluigi case O_IPTOS: 183799622Sluigi match = (hlen > 0 && 183899622Sluigi flags_match(cmd, ip->ip_tos)); 183999622Sluigi break; 184098943Sluigi 184198943Sluigi case O_TCPFLAGS: 184299622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 184399622Sluigi flags_match(cmd, 184499622Sluigi L3HDR(struct tcphdr,ip)->th_flags)); 184599622Sluigi break; 184698943Sluigi 184798943Sluigi case O_TCPOPTS: 184899622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 184999622Sluigi tcpopts_match(ip, cmd)); 185099622Sluigi break; 185198943Sluigi 185298943Sluigi case O_TCPSEQ: 185399622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 185499622Sluigi ((ipfw_insn_u32 *)cmd)->d[0] == 185599622Sluigi L3HDR(struct tcphdr,ip)->th_seq); 185699622Sluigi break; 185798943Sluigi 185898943Sluigi case O_TCPACK: 185999622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 186099622Sluigi ((ipfw_insn_u32 *)cmd)->d[0] == 186199622Sluigi L3HDR(struct tcphdr,ip)->th_ack); 186299622Sluigi break; 186398943Sluigi 186498943Sluigi case O_TCPWIN: 186599622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 186699622Sluigi cmd->arg1 == 186799622Sluigi L3HDR(struct tcphdr,ip)->th_win); 186899622Sluigi break; 186998943Sluigi 187098943Sluigi case O_ESTAB: 187198943Sluigi /* reject packets which have SYN only */ 187299622Sluigi /* XXX should i also check for TH_ACK ? */ 187399622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 187499622Sluigi (L3HDR(struct tcphdr,ip)->th_flags & 187599622Sluigi (TH_RST | TH_ACK | TH_SYN)) != TH_SYN); 187699622Sluigi break; 187798943Sluigi 187898943Sluigi case O_LOG: 1879100589Sluigi if (fw_verbose) 1880100589Sluigi ipfw_log(f, hlen, args->eh, m, oif); 188199622Sluigi match = 1; 188299622Sluigi break; 188398943Sluigi 188499475Sluigi case O_PROB: 188599622Sluigi match = (random()<((ipfw_insn_u32 *)cmd)->d[0]); 188699622Sluigi break; 188798943Sluigi 1888112250Scjc case O_VERREVPATH: 1889112250Scjc /* Outgoing packets automatically pass/match */ 1890112250Scjc match = ((oif != NULL) || 1891116763Sluigi (m->m_pkthdr.rcvif == NULL) || 1892112250Scjc verify_rev_path(src_ip, m->m_pkthdr.rcvif)); 1893112250Scjc break; 1894112250Scjc 1895117241Sluigi case O_IPSEC: 1896117241Sluigi#ifdef FAST_IPSEC 1897117241Sluigi match = (m_tag_find(m, 1898117241Sluigi PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL); 1899117241Sluigi#endif 1900117241Sluigi#ifdef IPSEC 1901117241Sluigi match = (ipsec_gethist(m, NULL) != NULL); 1902117241Sluigi#endif 1903117241Sluigi /* otherwise no match */ 1904117241Sluigi break; 1905117241Sluigi 190699622Sluigi /* 190799622Sluigi * The second set of opcodes represents 'actions', 190899622Sluigi * i.e. the terminal part of a rule once the packet 190999622Sluigi * matches all previous patterns. 191099622Sluigi * Typically there is only one action for each rule, 191199622Sluigi * and the opcode is stored at the end of the rule 191299622Sluigi * (but there are exceptions -- see below). 191399622Sluigi * 191499622Sluigi * In general, here we set retval and terminate the 191599622Sluigi * outer loop (would be a 'break 3' in some language, 191699622Sluigi * but we need to do a 'goto done'). 191799622Sluigi * 191899622Sluigi * Exceptions: 191999622Sluigi * O_COUNT and O_SKIPTO actions: 192099622Sluigi * instead of terminating, we jump to the next rule 192199622Sluigi * ('goto next_rule', equivalent to a 'break 2'), 192299622Sluigi * or to the SKIPTO target ('goto again' after 192399622Sluigi * having set f, cmd and l), respectively. 192499622Sluigi * 192599622Sluigi * O_LIMIT and O_KEEP_STATE: these opcodes are 192699622Sluigi * not real 'actions', and are stored right 192799622Sluigi * before the 'action' part of the rule. 192899622Sluigi * These opcodes try to install an entry in the 192999622Sluigi * state tables; if successful, we continue with 193099622Sluigi * the next opcode (match=1; break;), otherwise 193199622Sluigi * the packet * must be dropped 193299622Sluigi * ('goto done' after setting retval); 193399622Sluigi * 193499622Sluigi * O_PROBE_STATE and O_CHECK_STATE: these opcodes 193599622Sluigi * cause a lookup of the state table, and a jump 193699622Sluigi * to the 'action' part of the parent rule 193799622Sluigi * ('goto check_body') if an entry is found, or 193899622Sluigi * (CHECK_STATE only) a jump to the next rule if 193999622Sluigi * the entry is not found ('goto next_rule'). 194099622Sluigi * The result of the lookup is cached to make 194199622Sluigi * further instances of these opcodes are 194299622Sluigi * effectively NOPs. 194399622Sluigi */ 194498943Sluigi case O_LIMIT: 194598943Sluigi case O_KEEP_STATE: 194698943Sluigi if (install_state(f, 194799622Sluigi (ipfw_insn_limit *)cmd, args)) { 194899622Sluigi retval = IP_FW_PORT_DENY_FLAG; 194999622Sluigi goto done; /* error/limit violation */ 195099622Sluigi } 195199622Sluigi match = 1; 195299622Sluigi break; 195398943Sluigi 195498943Sluigi case O_PROBE_STATE: 195598943Sluigi case O_CHECK_STATE: 195698943Sluigi /* 195798943Sluigi * dynamic rules are checked at the first 195899622Sluigi * keep-state or check-state occurrence, 195999622Sluigi * with the result being stored in dyn_dir. 196099622Sluigi * The compiler introduces a PROBE_STATE 196198943Sluigi * instruction for us when we have a 196299622Sluigi * KEEP_STATE (because PROBE_STATE needs 196398943Sluigi * to be run first). 196498943Sluigi */ 196599622Sluigi if (dyn_dir == MATCH_UNKNOWN && 196699622Sluigi (q = lookup_dyn_rule(&args->f_id, 1967100004Sluigi &dyn_dir, proto == IPPROTO_TCP ? 1968100004Sluigi L3HDR(struct tcphdr, ip) : NULL)) 1969100004Sluigi != NULL) { 197099622Sluigi /* 197199622Sluigi * Found dynamic entry, update stats 197299622Sluigi * and jump to the 'action' part of 197399622Sluigi * the parent rule. 197499622Sluigi */ 197599622Sluigi q->pcnt++; 1976115750Skbyanc q->bcnt += pktlen; 197799622Sluigi f = q->rule; 197899622Sluigi cmd = ACTION_PTR(f); 197999622Sluigi l = f->cmd_len - f->act_ofs; 1980120141Ssam IPFW_DYN_UNLOCK(); 198199622Sluigi goto check_body; 198298943Sluigi } 198399622Sluigi /* 198499622Sluigi * Dynamic entry not found. If CHECK_STATE, 198599622Sluigi * skip to next rule, if PROBE_STATE just 198699622Sluigi * ignore and continue with next opcode. 198799622Sluigi */ 198898943Sluigi if (cmd->opcode == O_CHECK_STATE) 198998943Sluigi goto next_rule; 199099622Sluigi match = 1; 199199622Sluigi break; 199298943Sluigi 199398943Sluigi case O_ACCEPT: 199498943Sluigi retval = 0; /* accept */ 199599622Sluigi goto done; 199698943Sluigi 199798943Sluigi case O_PIPE: 199898943Sluigi case O_QUEUE: 199998943Sluigi args->rule = f; /* report matching rule */ 200098943Sluigi retval = cmd->arg1 | IP_FW_PORT_DYNT_FLAG; 200199622Sluigi goto done; 2002105775Smaxim 200398943Sluigi case O_DIVERT: 200498943Sluigi case O_TEE: 200598943Sluigi if (args->eh) /* not on layer 2 */ 200699622Sluigi break; 200798943Sluigi args->divert_rule = f->rulenum; 200899622Sluigi retval = (cmd->opcode == O_DIVERT) ? 200999622Sluigi cmd->arg1 : 201099622Sluigi cmd->arg1 | IP_FW_PORT_TEE_FLAG; 201199622Sluigi goto done; 201298943Sluigi 201398943Sluigi case O_COUNT: 201498943Sluigi case O_SKIPTO: 201598943Sluigi f->pcnt++; /* update stats */ 2016115750Skbyanc f->bcnt += pktlen; 201798943Sluigi f->timestamp = time_second; 201898943Sluigi if (cmd->opcode == O_COUNT) 201998943Sluigi goto next_rule; 202098943Sluigi /* handle skipto */ 202198943Sluigi if (f->next_rule == NULL) 202298943Sluigi lookup_next_rule(f); 202398943Sluigi f = f->next_rule; 202498943Sluigi goto again; 202598943Sluigi 202698943Sluigi case O_REJECT: 202798943Sluigi /* 202898943Sluigi * Drop the packet and send a reject notice 202998943Sluigi * if the packet is not ICMP (or is an ICMP 203098943Sluigi * query), and it is not multicast/broadcast. 203198943Sluigi */ 203298943Sluigi if (hlen > 0 && 203398943Sluigi (proto != IPPROTO_ICMP || 203499475Sluigi is_icmp_query(ip)) && 203598943Sluigi !(m->m_flags & (M_BCAST|M_MCAST)) && 203698943Sluigi !IN_MULTICAST(dst_ip.s_addr)) { 203799475Sluigi send_reject(args, cmd->arg1, 203899475Sluigi offset,ip_len); 203999475Sluigi m = args->m; 204098943Sluigi } 204199622Sluigi /* FALLTHROUGH */ 204299622Sluigi case O_DENY: 204399622Sluigi retval = IP_FW_PORT_DENY_FLAG; 204499622Sluigi goto done; 204598943Sluigi 204698943Sluigi case O_FORWARD_IP: 204798943Sluigi if (args->eh) /* not valid on layer2 pkts */ 204899622Sluigi break; 204998943Sluigi if (!q || dyn_dir == MATCH_FORWARD) 205098943Sluigi args->next_hop = 205198943Sluigi &((ipfw_insn_sa *)cmd)->sa; 205298943Sluigi retval = 0; 205399622Sluigi goto done; 205498943Sluigi 205598943Sluigi default: 205698943Sluigi panic("-- unknown opcode %d\n", cmd->opcode); 205799622Sluigi } /* end of switch() on opcodes */ 205898943Sluigi 205999622Sluigi if (cmd->len & F_NOT) 206099622Sluigi match = !match; 206198943Sluigi 206299622Sluigi if (match) { 206399622Sluigi if (cmd->len & F_OR) 206499622Sluigi skip_or = 1; 206599622Sluigi } else { 206699622Sluigi if (!(cmd->len & F_OR)) /* not an OR block, */ 206799622Sluigi break; /* try next rule */ 206898943Sluigi } 206998943Sluigi 207098943Sluigi } /* end of inner for, scan opcodes */ 207198943Sluigi 207298965Sdfrnext_rule:; /* try next rule */ 2073105775Smaxim 207498943Sluigi } /* end of outer for, scan rules */ 2075108258Smaxim printf("ipfw: ouch!, skip past end of rules, denying packet\n"); 2076120141Ssam IPFW_UNLOCK(chain); 2077101628Sluigi return(IP_FW_PORT_DENY_FLAG); 207898943Sluigi 207999622Sluigidone: 208098943Sluigi /* Update statistics */ 208198943Sluigi f->pcnt++; 2082115750Skbyanc f->bcnt += pktlen; 208398943Sluigi f->timestamp = time_second; 2084120141Ssam IPFW_UNLOCK(chain); 208598943Sluigi return retval; 208698943Sluigi 208798943Sluigipullup_failed: 208898943Sluigi if (fw_verbose) 2089108258Smaxim printf("ipfw: pullup failed\n"); 209098943Sluigi return(IP_FW_PORT_DENY_FLAG); 209198943Sluigi} 209298943Sluigi 209398943Sluigi/* 209498943Sluigi * When a rule is added/deleted, clear the next_rule pointers in all rules. 209598943Sluigi * These will be reconstructed on the fly as packets are matched. 209698943Sluigi */ 209798943Sluigistatic void 2098120141Ssamflush_rule_ptrs(struct ip_fw_chain *chain) 209998943Sluigi{ 210098943Sluigi struct ip_fw *rule; 210198943Sluigi 2102120141Ssam IPFW_LOCK_ASSERT(chain); 2103120141Ssam 2104120141Ssam for (rule = chain->rules; rule; rule = rule->next) 210598943Sluigi rule->next_rule = NULL; 210698943Sluigi} 210798943Sluigi 210898943Sluigi/* 210998943Sluigi * When pipes/queues are deleted, clear the "pipe_ptr" pointer to a given 211098943Sluigi * pipe/queue, or to all of them (match == NULL). 211198943Sluigi */ 211298943Sluigivoid 211398943Sluigiflush_pipe_ptrs(struct dn_flow_set *match) 211498943Sluigi{ 211598943Sluigi struct ip_fw *rule; 211698943Sluigi 2117120141Ssam IPFW_LOCK(&layer3_chain); 2118120141Ssam for (rule = layer3_chain.rules; rule; rule = rule->next) { 211998943Sluigi ipfw_insn_pipe *cmd = (ipfw_insn_pipe *)ACTION_PTR(rule); 2120105775Smaxim 212198943Sluigi if (cmd->o.opcode != O_PIPE && cmd->o.opcode != O_QUEUE) 212298943Sluigi continue; 2123115793Sticso /* 2124115793Sticso * XXX Use bcmp/bzero to handle pipe_ptr to overcome 2125115793Sticso * possible alignment problems on 64-bit architectures. 2126115793Sticso * This code is seldom used so we do not worry too 2127115793Sticso * much about efficiency. 2128115793Sticso */ 2129115793Sticso if (match == NULL || 2130115793Sticso !bcmp(&cmd->pipe_ptr, &match, sizeof(match)) ) 2131115793Sticso bzero(&cmd->pipe_ptr, sizeof(cmd->pipe_ptr)); 213298943Sluigi } 2133120141Ssam IPFW_UNLOCK(&layer3_chain); 213498943Sluigi} 213598943Sluigi 213698943Sluigi/* 213798943Sluigi * Add a new rule to the list. Copy the rule into a malloc'ed area, then 213898943Sluigi * possibly create a rule number and add the rule to the list. 213998943Sluigi * Update the rule_number in the input struct so the caller knows it as well. 214098943Sluigi */ 214198943Sluigistatic int 2142120141Ssamadd_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule) 214398943Sluigi{ 214498943Sluigi struct ip_fw *rule, *f, *prev; 214598943Sluigi int l = RULESIZE(input_rule); 214698943Sluigi 2147120141Ssam if (chain->rules == NULL && input_rule->rulenum != IPFW_DEFAULT_RULE) 214898943Sluigi return (EINVAL); 214998943Sluigi 2150105440Smux rule = malloc(l, M_IPFW, M_NOWAIT | M_ZERO); 215198943Sluigi if (rule == NULL) 215298943Sluigi return (ENOSPC); 215398943Sluigi 215498943Sluigi bcopy(input_rule, rule, l); 215598943Sluigi 215698943Sluigi rule->next = NULL; 215798943Sluigi rule->next_rule = NULL; 215898943Sluigi 215998943Sluigi rule->pcnt = 0; 216098943Sluigi rule->bcnt = 0; 216198943Sluigi rule->timestamp = 0; 216298943Sluigi 2163120141Ssam IPFW_LOCK(chain); 216498943Sluigi 2165120141Ssam if (chain->rules == NULL) { /* default rule */ 2166120141Ssam chain->rules = rule; 216798943Sluigi goto done; 216898943Sluigi } 216998943Sluigi 217098943Sluigi /* 217198943Sluigi * If rulenum is 0, find highest numbered rule before the 217298943Sluigi * default rule, and add autoinc_step 217398943Sluigi */ 217498943Sluigi if (autoinc_step < 1) 217598943Sluigi autoinc_step = 1; 217698943Sluigi else if (autoinc_step > 1000) 217798943Sluigi autoinc_step = 1000; 217898943Sluigi if (rule->rulenum == 0) { 217998943Sluigi /* 218098943Sluigi * locate the highest numbered rule before default 218198943Sluigi */ 2182120141Ssam for (f = chain->rules; f; f = f->next) { 218398943Sluigi if (f->rulenum == IPFW_DEFAULT_RULE) 218498943Sluigi break; 218598943Sluigi rule->rulenum = f->rulenum; 218698943Sluigi } 218798943Sluigi if (rule->rulenum < IPFW_DEFAULT_RULE - autoinc_step) 218898943Sluigi rule->rulenum += autoinc_step; 218998943Sluigi input_rule->rulenum = rule->rulenum; 219098943Sluigi } 219198943Sluigi 219298943Sluigi /* 219398943Sluigi * Now insert the new rule in the right place in the sorted list. 219498943Sluigi */ 2195120141Ssam for (prev = NULL, f = chain->rules; f; prev = f, f = f->next) { 219698943Sluigi if (f->rulenum > rule->rulenum) { /* found the location */ 219798943Sluigi if (prev) { 219898943Sluigi rule->next = f; 219998943Sluigi prev->next = rule; 220098943Sluigi } else { /* head insert */ 2201120141Ssam rule->next = chain->rules; 2202120141Ssam chain->rules = rule; 220398943Sluigi } 220498943Sluigi break; 220598943Sluigi } 220698943Sluigi } 2207120141Ssam flush_rule_ptrs(chain); 220898943Sluigidone: 220998943Sluigi static_count++; 221098943Sluigi static_len += l; 2211120141Ssam IPFW_UNLOCK(chain); 2212108258Smaxim DEB(printf("ipfw: installed rule %d, static count now %d\n", 221398943Sluigi rule->rulenum, static_count);) 221498943Sluigi return (0); 221598943Sluigi} 221698943Sluigi 221798943Sluigi/** 2218120141Ssam * Remove a static rule (including derived * dynamic rules) 2219120141Ssam * and place it on the ``reap list'' for later reclamation. 222098943Sluigi * The caller is in charge of clearing rule pointers to avoid 222198943Sluigi * dangling pointers. 222298943Sluigi * @return a pointer to the next entry. 222398943Sluigi * Arguments are not checked, so they better be correct. 222498943Sluigi */ 222598943Sluigistatic struct ip_fw * 2226120141Ssamremove_rule(struct ip_fw_chain *chain, struct ip_fw *rule, struct ip_fw *prev) 222798943Sluigi{ 222898943Sluigi struct ip_fw *n; 222998943Sluigi int l = RULESIZE(rule); 223098943Sluigi 2231120141Ssam IPFW_LOCK_ASSERT(chain); 2232120141Ssam 223398943Sluigi n = rule->next; 2234120141Ssam IPFW_DYN_LOCK(); 223598943Sluigi remove_dyn_rule(rule, NULL /* force removal */); 2236120141Ssam IPFW_DYN_UNLOCK(); 223798943Sluigi if (prev == NULL) 2238120141Ssam chain->rules = n; 223998943Sluigi else 224098943Sluigi prev->next = n; 224198943Sluigi static_count--; 224298943Sluigi static_len -= l; 224398943Sluigi 2244120141Ssam rule->next = chain->reap; 2245120141Ssam chain->reap = rule; 2246120141Ssam 224798943Sluigi return n; 224898943Sluigi} 224998943Sluigi 2250120141Ssam/** 2251120141Ssam * Reclaim storage associated with a list of rules. This is 2252120141Ssam * typically the list created using remove_rule. 2253120141Ssam */ 2254120141Ssamstatic void 2255120141Ssamreap_rules(struct ip_fw *head) 2256120141Ssam{ 2257120141Ssam struct ip_fw *rule; 2258120141Ssam 2259120141Ssam while ((rule = head) != NULL) { 2260120141Ssam head = head->next; 2261120141Ssam if (DUMMYNET_LOADED) 2262120141Ssam ip_dn_ruledel_ptr(rule); 2263120141Ssam free(rule, M_IPFW); 2264120141Ssam } 2265120141Ssam} 2266120141Ssam 226798943Sluigi/* 2268120141Ssam * Remove all rules from a chain (except rules in set RESVD_SET 2269120141Ssam * unless kill_default = 1). The caller is responsible for 2270120141Ssam * reclaiming storage for the rules left in chain->reap. 227198943Sluigi */ 227298943Sluigistatic void 2273120141Ssamfree_chain(struct ip_fw_chain *chain, int kill_default) 227498943Sluigi{ 2275117654Sluigi struct ip_fw *prev, *rule; 227698943Sluigi 2277120141Ssam IPFW_LOCK_ASSERT(chain); 2278120141Ssam 2279120141Ssam flush_rule_ptrs(chain); /* more efficient to do outside the loop */ 2280120141Ssam for (prev = NULL, rule = chain->rules; rule ; ) 2281117654Sluigi if (kill_default || rule->set != RESVD_SET) 2282120141Ssam rule = remove_rule(chain, rule, prev); 2283117654Sluigi else { 2284117654Sluigi prev = rule; 2285117654Sluigi rule = rule->next; 2286117654Sluigi } 228798943Sluigi} 228898943Sluigi 228998943Sluigi/** 2290101628Sluigi * Remove all rules with given number, and also do set manipulation. 2291117654Sluigi * Assumes chain != NULL && *chain != NULL. 2292101628Sluigi * 2293101978Sluigi * The argument is an u_int32_t. The low 16 bit are the rule or set number, 2294101978Sluigi * the next 8 bits are the new set, the top 8 bits are the command: 2295105775Smaxim * 2296101978Sluigi * 0 delete rules with given number 2297101978Sluigi * 1 delete rules with given set number 2298101978Sluigi * 2 move rules with given number to new set 2299101978Sluigi * 3 move rules with given set number to new set 2300101978Sluigi * 4 swap sets with given numbers 230198943Sluigi */ 230298943Sluigistatic int 2303120141Ssamdel_entry(struct ip_fw_chain *chain, u_int32_t arg) 230498943Sluigi{ 2305120141Ssam struct ip_fw *prev = NULL, *rule; 2306117654Sluigi u_int16_t rulenum; /* rule or old_set */ 2307101978Sluigi u_int8_t cmd, new_set; 230898943Sluigi 2309101628Sluigi rulenum = arg & 0xffff; 2310101978Sluigi cmd = (arg >> 24) & 0xff; 2311101978Sluigi new_set = (arg >> 16) & 0xff; 2312101628Sluigi 2313101978Sluigi if (cmd > 4) 231498943Sluigi return EINVAL; 2315117654Sluigi if (new_set > RESVD_SET) 2316101628Sluigi return EINVAL; 2317101978Sluigi if (cmd == 0 || cmd == 2) { 2318117654Sluigi if (rulenum >= IPFW_DEFAULT_RULE) 2319101978Sluigi return EINVAL; 2320101978Sluigi } else { 2321117654Sluigi if (rulenum > RESVD_SET) /* old_set */ 2322101978Sluigi return EINVAL; 2323101978Sluigi } 2324105775Smaxim 2325120141Ssam IPFW_LOCK(chain); 2326120141Ssam rule = chain->rules; 2327120141Ssam chain->reap = NULL; 2328101628Sluigi switch (cmd) { 2329101978Sluigi case 0: /* delete rules with given number */ 2330101628Sluigi /* 2331101628Sluigi * locate first rule to delete 2332101628Sluigi */ 2333117654Sluigi for (; rule->rulenum < rulenum; prev = rule, rule = rule->next) 2334101628Sluigi ; 2335120141Ssam if (rule->rulenum != rulenum) { 2336120141Ssam IPFW_UNLOCK(chain); 2337101628Sluigi return EINVAL; 2338120141Ssam } 2339101628Sluigi 2340101628Sluigi /* 2341101978Sluigi * flush pointers outside the loop, then delete all matching 2342101978Sluigi * rules. prev remains the same throughout the cycle. 2343101628Sluigi */ 2344120141Ssam flush_rule_ptrs(chain); 2345117654Sluigi while (rule->rulenum == rulenum) 2346120141Ssam rule = remove_rule(chain, rule, prev); 2347101628Sluigi break; 2348101628Sluigi 2349101978Sluigi case 1: /* delete all rules with given set number */ 2350120141Ssam flush_rule_ptrs(chain); 2351120141Ssam rule = chain->rules; 2352117654Sluigi while (rule->rulenum < IPFW_DEFAULT_RULE) 2353101628Sluigi if (rule->set == rulenum) 2354120141Ssam rule = remove_rule(chain, rule, prev); 2355101628Sluigi else { 2356101628Sluigi prev = rule; 2357101628Sluigi rule = rule->next; 2358101628Sluigi } 2359101628Sluigi break; 2360101628Sluigi 2361101978Sluigi case 2: /* move rules with given number to new set */ 2362120141Ssam rule = chain->rules; 2363117654Sluigi for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next) 2364101978Sluigi if (rule->rulenum == rulenum) 2365101978Sluigi rule->set = new_set; 2366101628Sluigi break; 2367101628Sluigi 2368101978Sluigi case 3: /* move rules with given set number to new set */ 2369117654Sluigi for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next) 2370101978Sluigi if (rule->set == rulenum) 2371101978Sluigi rule->set = new_set; 2372101628Sluigi break; 2373101978Sluigi 2374101978Sluigi case 4: /* swap two sets */ 2375117654Sluigi for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next) 2376101978Sluigi if (rule->set == rulenum) 2377101978Sluigi rule->set = new_set; 2378101978Sluigi else if (rule->set == new_set) 2379101978Sluigi rule->set = rulenum; 2380101978Sluigi break; 2381101628Sluigi } 2382120141Ssam /* 2383120141Ssam * Look for rules to reclaim. We grab the list before 2384120141Ssam * releasing the lock then reclaim them w/o the lock to 2385120141Ssam * avoid a LOR with dummynet. 2386120141Ssam */ 2387120141Ssam rule = chain->reap; 2388120141Ssam chain->reap = NULL; 2389120141Ssam IPFW_UNLOCK(chain); 2390120141Ssam if (rule) 2391120141Ssam reap_rules(rule); 239298943Sluigi return 0; 239398943Sluigi} 239498943Sluigi 239598943Sluigi/* 239698943Sluigi * Clear counters for a specific rule. 2397120141Ssam * The enclosing "table" is assumed locked. 239898943Sluigi */ 239998943Sluigistatic void 240098943Sluigiclear_counters(struct ip_fw *rule, int log_only) 240198943Sluigi{ 240298943Sluigi ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule); 240398943Sluigi 240498943Sluigi if (log_only == 0) { 240598943Sluigi rule->bcnt = rule->pcnt = 0; 240698943Sluigi rule->timestamp = 0; 240798943Sluigi } 240898943Sluigi if (l->o.opcode == O_LOG) 240998943Sluigi l->log_left = l->max_log; 241098943Sluigi} 241198943Sluigi 241298943Sluigi/** 241398943Sluigi * Reset some or all counters on firewall rules. 241498943Sluigi * @arg frwl is null to clear all entries, or contains a specific 241598943Sluigi * rule number. 241698943Sluigi * @arg log_only is 1 if we only want to reset logs, zero otherwise. 241798943Sluigi */ 241898943Sluigistatic int 2419120141Ssamzero_entry(struct ip_fw_chain *chain, int rulenum, int log_only) 242098943Sluigi{ 242198943Sluigi struct ip_fw *rule; 242298943Sluigi char *msg; 242398943Sluigi 2424120141Ssam IPFW_LOCK(chain); 242598943Sluigi if (rulenum == 0) { 242698943Sluigi norule_counter = 0; 2427120141Ssam for (rule = chain->rules; rule; rule = rule->next) 242898943Sluigi clear_counters(rule, log_only); 242998943Sluigi msg = log_only ? "ipfw: All logging counts reset.\n" : 243098943Sluigi "ipfw: Accounting cleared.\n"; 243198943Sluigi } else { 243298943Sluigi int cleared = 0; 243398943Sluigi /* 243498943Sluigi * We can have multiple rules with the same number, so we 243598943Sluigi * need to clear them all. 243698943Sluigi */ 2437120141Ssam for (rule = chain->rules; rule; rule = rule->next) 243898943Sluigi if (rule->rulenum == rulenum) { 243998943Sluigi while (rule && rule->rulenum == rulenum) { 244098943Sluigi clear_counters(rule, log_only); 244198943Sluigi rule = rule->next; 244298943Sluigi } 244398943Sluigi cleared = 1; 244498943Sluigi break; 244598943Sluigi } 2446120141Ssam if (!cleared) { /* we did not find any matching rules */ 2447120141Ssam IPFW_UNLOCK(chain); 244898943Sluigi return (EINVAL); 2449120141Ssam } 245098943Sluigi msg = log_only ? "ipfw: Entry %d logging count reset.\n" : 245198943Sluigi "ipfw: Entry %d cleared.\n"; 245298943Sluigi } 2453120141Ssam IPFW_UNLOCK(chain); 2454120141Ssam 245598943Sluigi if (fw_verbose) 245698943Sluigi log(LOG_SECURITY | LOG_NOTICE, msg, rulenum); 245798943Sluigi return (0); 245898943Sluigi} 245998943Sluigi 246098943Sluigi/* 246198943Sluigi * Check validity of the structure before insert. 246298943Sluigi * Fortunately rules are simple, so this mostly need to check rule sizes. 246398943Sluigi */ 246498943Sluigistatic int 246598943Sluigicheck_ipfw_struct(struct ip_fw *rule, int size) 246698943Sluigi{ 246798943Sluigi int l, cmdlen = 0; 246898943Sluigi int have_action=0; 246998943Sluigi ipfw_insn *cmd; 247098943Sluigi 247198943Sluigi if (size < sizeof(*rule)) { 247299622Sluigi printf("ipfw: rule too short\n"); 247398943Sluigi return (EINVAL); 247498943Sluigi } 247598943Sluigi /* first, check for valid size */ 247698943Sluigi l = RULESIZE(rule); 247798943Sluigi if (l != size) { 247899622Sluigi printf("ipfw: size mismatch (have %d want %d)\n", size, l); 247998943Sluigi return (EINVAL); 248098943Sluigi } 248198943Sluigi /* 248298943Sluigi * Now go for the individual checks. Very simple ones, basically only 248398943Sluigi * instruction sizes. 248498943Sluigi */ 248598943Sluigi for (l = rule->cmd_len, cmd = rule->cmd ; 248698943Sluigi l > 0 ; l -= cmdlen, cmd += cmdlen) { 248798943Sluigi cmdlen = F_LEN(cmd); 248898943Sluigi if (cmdlen > l) { 248999622Sluigi printf("ipfw: opcode %d size truncated\n", 249098943Sluigi cmd->opcode); 249198943Sluigi return EINVAL; 249298943Sluigi } 249399622Sluigi DEB(printf("ipfw: opcode %d\n", cmd->opcode);) 249498943Sluigi switch (cmd->opcode) { 249598943Sluigi case O_PROBE_STATE: 249698943Sluigi case O_KEEP_STATE: 249798943Sluigi case O_PROTO: 249898943Sluigi case O_IP_SRC_ME: 249998943Sluigi case O_IP_DST_ME: 250098943Sluigi case O_LAYER2: 250198943Sluigi case O_IN: 250298943Sluigi case O_FRAG: 250398943Sluigi case O_IPOPT: 250498943Sluigi case O_IPTOS: 250599475Sluigi case O_IPPRECEDENCE: 250698943Sluigi case O_IPVER: 250798943Sluigi case O_TCPWIN: 250898943Sluigi case O_TCPFLAGS: 250998943Sluigi case O_TCPOPTS: 251098943Sluigi case O_ESTAB: 2511112250Scjc case O_VERREVPATH: 2512117241Sluigi case O_IPSEC: 251398943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn)) 251498943Sluigi goto bad_size; 251598943Sluigi break; 251698943Sluigi 251798943Sluigi case O_UID: 251898943Sluigi case O_GID: 251998943Sluigi case O_IP_SRC: 252098943Sluigi case O_IP_DST: 252198943Sluigi case O_TCPSEQ: 252298943Sluigi case O_TCPACK: 252398943Sluigi case O_PROB: 252498943Sluigi case O_ICMPTYPE: 252598943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 252698943Sluigi goto bad_size; 252798943Sluigi break; 252898943Sluigi 252998943Sluigi case O_LIMIT: 253098943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) 253198943Sluigi goto bad_size; 253298943Sluigi break; 253398943Sluigi 253498943Sluigi case O_LOG: 253598943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_log)) 253698943Sluigi goto bad_size; 2537105775Smaxim 253898943Sluigi ((ipfw_insn_log *)cmd)->log_left = 253998943Sluigi ((ipfw_insn_log *)cmd)->max_log; 254098943Sluigi 254198943Sluigi break; 254298943Sluigi 254398943Sluigi case O_IP_SRC_MASK: 254498943Sluigi case O_IP_DST_MASK: 2545117327Sluigi /* only odd command lengths */ 2546117327Sluigi if ( !(cmdlen & 1) || cmdlen > 31) 254798943Sluigi goto bad_size; 254898943Sluigi break; 254998943Sluigi 255098943Sluigi case O_IP_SRC_SET: 255198943Sluigi case O_IP_DST_SET: 255298943Sluigi if (cmd->arg1 == 0 || cmd->arg1 > 256) { 255399622Sluigi printf("ipfw: invalid set size %d\n", 255498943Sluigi cmd->arg1); 255598943Sluigi return EINVAL; 255698943Sluigi } 255798943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 255898943Sluigi (cmd->arg1+31)/32 ) 255998943Sluigi goto bad_size; 256098943Sluigi break; 256198943Sluigi 256298943Sluigi case O_MACADDR2: 256398943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) 256498943Sluigi goto bad_size; 256598943Sluigi break; 256698943Sluigi 2567117468Sluigi case O_NOP: 2568116690Sluigi case O_IPID: 2569116690Sluigi case O_IPTTL: 2570116690Sluigi case O_IPLEN: 2571116690Sluigi if (cmdlen < 1 || cmdlen > 31) 2572116690Sluigi goto bad_size; 2573116690Sluigi break; 2574116690Sluigi 257598943Sluigi case O_MAC_TYPE: 257698943Sluigi case O_IP_SRCPORT: 2577102086Sluigi case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */ 2578102086Sluigi if (cmdlen < 2 || cmdlen > 31) 257998943Sluigi goto bad_size; 258098943Sluigi break; 258198943Sluigi 258298943Sluigi case O_RECV: 258398943Sluigi case O_XMIT: 258498943Sluigi case O_VIA: 258598943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) 258698943Sluigi goto bad_size; 258798943Sluigi break; 258898943Sluigi 258998943Sluigi case O_PIPE: 259098943Sluigi case O_QUEUE: 259198943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_pipe)) 259298943Sluigi goto bad_size; 259398943Sluigi goto check_action; 259498943Sluigi 259599475Sluigi case O_FORWARD_IP: 259698943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) 259798943Sluigi goto bad_size; 259898943Sluigi goto check_action; 259998943Sluigi 260099475Sluigi case O_FORWARD_MAC: /* XXX not implemented yet */ 260198943Sluigi case O_CHECK_STATE: 260298943Sluigi case O_COUNT: 260398943Sluigi case O_ACCEPT: 260498943Sluigi case O_DENY: 260598943Sluigi case O_REJECT: 260698943Sluigi case O_SKIPTO: 260798943Sluigi case O_DIVERT: 260898943Sluigi case O_TEE: 260998943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn)) 261098943Sluigi goto bad_size; 261198943Sluigicheck_action: 261298943Sluigi if (have_action) { 261399622Sluigi printf("ipfw: opcode %d, multiple actions" 261498943Sluigi " not allowed\n", 261598943Sluigi cmd->opcode); 261698943Sluigi return EINVAL; 261798943Sluigi } 261898943Sluigi have_action = 1; 261998943Sluigi if (l != cmdlen) { 262099622Sluigi printf("ipfw: opcode %d, action must be" 262198943Sluigi " last opcode\n", 262298943Sluigi cmd->opcode); 262398943Sluigi return EINVAL; 262498943Sluigi } 262598943Sluigi break; 262698943Sluigi default: 262799622Sluigi printf("ipfw: opcode %d, unknown opcode\n", 262898943Sluigi cmd->opcode); 262998943Sluigi return EINVAL; 263098943Sluigi } 263198943Sluigi } 263298943Sluigi if (have_action == 0) { 263399622Sluigi printf("ipfw: missing action\n"); 263498943Sluigi return EINVAL; 263598943Sluigi } 263698943Sluigi return 0; 263798943Sluigi 263898943Sluigibad_size: 263999622Sluigi printf("ipfw: opcode %d size %d wrong\n", 264098943Sluigi cmd->opcode, cmdlen); 264198943Sluigi return EINVAL; 264298943Sluigi} 264398943Sluigi 2644120141Ssam/* 2645120141Ssam * Copy the static and dynamic rules to the supplied buffer 2646120141Ssam * and return the amount of space actually used. 2647120141Ssam */ 2648120141Ssamstatic size_t 2649120141Ssamipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) 2650120141Ssam{ 2651120141Ssam char *bp = buf; 2652120141Ssam char *ep = bp + space; 2653120141Ssam struct ip_fw *rule; 2654120141Ssam int i; 265598943Sluigi 2656120141Ssam /* XXX this can take a long time and locking will block packet flow */ 2657120141Ssam IPFW_LOCK(chain); 2658120141Ssam for (rule = chain->rules; rule ; rule = rule->next) { 2659120141Ssam /* 2660120141Ssam * Verify the entry fits in the buffer in case the 2661120141Ssam * rules changed between calculating buffer space and 2662120141Ssam * now. This would be better done using a generation 2663120141Ssam * number but should suffice for now. 2664120141Ssam */ 2665120141Ssam i = RULESIZE(rule); 2666120141Ssam if (bp + i <= ep) { 2667120141Ssam bcopy(rule, bp, i); 2668120141Ssam bcopy(&set_disable, &(((struct ip_fw *)bp)->next_rule), 2669120141Ssam sizeof(set_disable)); 2670120141Ssam bp += i; 2671120141Ssam } 2672120141Ssam } 2673120141Ssam IPFW_UNLOCK(chain); 2674120141Ssam if (ipfw_dyn_v) { 2675120141Ssam ipfw_dyn_rule *p, *last = NULL; 2676120141Ssam 2677120141Ssam IPFW_DYN_LOCK(); 2678120141Ssam for (i = 0 ; i < curr_dyn_buckets; i++) 2679120141Ssam for (p = ipfw_dyn_v[i] ; p != NULL; p = p->next) { 2680120141Ssam if (bp + sizeof *p <= ep) { 2681120141Ssam ipfw_dyn_rule *dst = 2682120141Ssam (ipfw_dyn_rule *)bp; 2683120141Ssam bcopy(p, dst, sizeof *p); 2684120141Ssam bcopy(&(p->rule->rulenum), &(dst->rule), 2685120141Ssam sizeof(p->rule->rulenum)); 2686120141Ssam /* 2687120141Ssam * store a non-null value in "next". 2688120141Ssam * The userland code will interpret a 2689120141Ssam * NULL here as a marker 2690120141Ssam * for the last dynamic rule. 2691120141Ssam */ 2692120141Ssam bcopy(&dst, &dst->next, sizeof(dst)); 2693120141Ssam last = dst; 2694120141Ssam dst->expire = 2695120141Ssam TIME_LEQ(dst->expire, time_second) ? 2696120141Ssam 0 : dst->expire - time_second ; 2697120141Ssam bp += sizeof(ipfw_dyn_rule); 2698120141Ssam } 2699120141Ssam } 2700120141Ssam IPFW_DYN_UNLOCK(); 2701120141Ssam if (last != NULL) /* mark last dynamic rule */ 2702120141Ssam bzero(&last->next, sizeof(last)); 2703120141Ssam } 2704120141Ssam return (bp - (char *)buf); 2705120141Ssam} 2706120141Ssam 2707120141Ssam 270898943Sluigi/** 270998943Sluigi * {set|get}sockopt parser. 271098943Sluigi */ 271198943Sluigistatic int 271298943Sluigiipfw_ctl(struct sockopt *sopt) 271398943Sluigi{ 2714120141Ssam#define RULE_MAXSIZE (256*sizeof(u_int32_t)) 2715120141Ssam int error, rule_num; 271698943Sluigi size_t size; 2717120141Ssam struct ip_fw *buf, *rule; 2718120141Ssam u_int32_t rulenum[2]; 271998943Sluigi 272098943Sluigi /* 272198943Sluigi * Disallow modifications in really-really secure mode, but still allow 272298943Sluigi * the logging counters to be reset. 272398943Sluigi */ 272498943Sluigi if (sopt->sopt_name == IP_FW_ADD || 272598943Sluigi (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) { 272698943Sluigi#if __FreeBSD_version >= 500034 272798943Sluigi error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 272898943Sluigi if (error) 272998943Sluigi return (error); 273098943Sluigi#else /* FreeBSD 4.x */ 273198943Sluigi if (securelevel >= 3) 273298943Sluigi return (EPERM); 273398943Sluigi#endif 273498943Sluigi } 273598943Sluigi 273698943Sluigi error = 0; 273798943Sluigi 273898943Sluigi switch (sopt->sopt_name) { 273998943Sluigi case IP_FW_GET: 274098943Sluigi /* 274198943Sluigi * pass up a copy of the current rules. Static rules 274298943Sluigi * come first (the last of which has number IPFW_DEFAULT_RULE), 274398943Sluigi * followed by a possibly empty list of dynamic rule. 274498943Sluigi * The last dynamic rule has NULL in the "next" field. 2745120141Ssam * 2746120141Ssam * Note that the calculated size is used to bound the 2747120141Ssam * amount of data returned to the user. The rule set may 2748120141Ssam * change between calculating the size and returning the 2749120141Ssam * data in which case we'll just return what fits. 275098943Sluigi */ 275198943Sluigi size = static_len; /* size of static rules */ 275298943Sluigi if (ipfw_dyn_v) /* add size of dyn.rules */ 275398943Sluigi size += (dyn_count * sizeof(ipfw_dyn_rule)); 275498943Sluigi 275598943Sluigi /* 275698943Sluigi * XXX todo: if the user passes a short length just to know 275798943Sluigi * how much room is needed, do not bother filling up the 275898943Sluigi * buffer, just jump to the sooptcopyout. 275998943Sluigi */ 2760111119Simp buf = malloc(size, M_TEMP, M_WAITOK); 2761120141Ssam error = sooptcopyout(sopt, buf, 2762120141Ssam ipfw_getrules(&layer3_chain, buf, size)); 276398943Sluigi free(buf, M_TEMP); 276498943Sluigi break; 276598943Sluigi 276698943Sluigi case IP_FW_FLUSH: 276798943Sluigi /* 276898943Sluigi * Normally we cannot release the lock on each iteration. 276998943Sluigi * We could do it here only because we start from the head all 277098943Sluigi * the times so there is no risk of missing some entries. 277198943Sluigi * On the other hand, the risk is that we end up with 277298943Sluigi * a very inconsistent ruleset, so better keep the lock 277398943Sluigi * around the whole cycle. 2774105775Smaxim * 277598943Sluigi * XXX this code can be improved by resetting the head of 277698943Sluigi * the list to point to the default rule, and then freeing 277798943Sluigi * the old list without the need for a lock. 277898943Sluigi */ 277998943Sluigi 2780120141Ssam IPFW_LOCK(&layer3_chain); 2781120141Ssam layer3_chain.reap = NULL; 278298943Sluigi free_chain(&layer3_chain, 0 /* keep default rule */); 2783120141Ssam rule = layer3_chain.reap, layer3_chain.reap = NULL; 2784120141Ssam IPFW_UNLOCK(&layer3_chain); 2785120141Ssam if (layer3_chain.reap != NULL) 2786120141Ssam reap_rules(rule); 278798943Sluigi break; 278898943Sluigi 278998943Sluigi case IP_FW_ADD: 2790120141Ssam rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK); 2791120141Ssam error = sooptcopyin(sopt, rule, RULE_MAXSIZE, 279298943Sluigi sizeof(struct ip_fw) ); 2793120141Ssam if (error == 0) 2794120141Ssam error = check_ipfw_struct(rule, sopt->sopt_valsize); 2795120141Ssam if (error == 0) { 2796120141Ssam error = add_rule(&layer3_chain, rule); 2797120141Ssam size = RULESIZE(rule); 2798120141Ssam if (!error && sopt->sopt_dir == SOPT_GET) 2799120141Ssam error = sooptcopyout(sopt, rule, size); 2800120141Ssam } 2801120141Ssam free(rule, M_TEMP); 280298943Sluigi break; 280398943Sluigi 2804101978Sluigi case IP_FW_DEL: 2805101628Sluigi /* 2806101978Sluigi * IP_FW_DEL is used for deleting single rules or sets, 2807101978Sluigi * and (ab)used to atomically manipulate sets. Argument size 2808101978Sluigi * is used to distinguish between the two: 2809101978Sluigi * sizeof(u_int32_t) 2810101978Sluigi * delete single rule or set of rules, 2811101978Sluigi * or reassign rules (or sets) to a different set. 2812101978Sluigi * 2*sizeof(u_int32_t) 2813101978Sluigi * atomic disable/enable sets. 2814101978Sluigi * first u_int32_t contains sets to be disabled, 2815101978Sluigi * second u_int32_t contains sets to be enabled. 2816101628Sluigi */ 2817120141Ssam error = sooptcopyin(sopt, rulenum, 2818101978Sluigi 2*sizeof(u_int32_t), sizeof(u_int32_t)); 281998943Sluigi if (error) 282098943Sluigi break; 2821101978Sluigi size = sopt->sopt_valsize; 2822101978Sluigi if (size == sizeof(u_int32_t)) /* delete or reassign */ 2823120141Ssam error = del_entry(&layer3_chain, rulenum[0]); 2824101978Sluigi else if (size == 2*sizeof(u_int32_t)) /* set enable/disable */ 2825101978Sluigi set_disable = 2826120141Ssam (set_disable | rulenum[0]) & ~rulenum[1] & 2827117654Sluigi ~(1<<RESVD_SET); /* set RESVD_SET always enabled */ 2828101978Sluigi else 282998943Sluigi error = EINVAL; 283098943Sluigi break; 283198943Sluigi 283298943Sluigi case IP_FW_ZERO: 283398943Sluigi case IP_FW_RESETLOG: /* argument is an int, the rule number */ 2834120141Ssam rule_num = 0; 283598943Sluigi if (sopt->sopt_val != 0) { 2836120141Ssam error = sooptcopyin(sopt, &rule_num, 283798943Sluigi sizeof(int), sizeof(int)); 283898943Sluigi if (error) 283998943Sluigi break; 284098943Sluigi } 2841120141Ssam error = zero_entry(&layer3_chain, rule_num, 2842120141Ssam sopt->sopt_name == IP_FW_RESETLOG); 284398943Sluigi break; 284498943Sluigi 284598943Sluigi default: 2846108258Smaxim printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); 284798943Sluigi error = EINVAL; 284898943Sluigi } 284998943Sluigi 285098943Sluigi return (error); 2851120141Ssam#undef RULE_MAXSIZE 285298943Sluigi} 285398943Sluigi 285498943Sluigi/** 285598943Sluigi * dummynet needs a reference to the default rule, because rules can be 285698943Sluigi * deleted while packets hold a reference to them. When this happens, 285798943Sluigi * dummynet changes the reference to the default rule (it could well be a 285898943Sluigi * NULL pointer, but this way we do not need to check for the special 285998943Sluigi * case, plus here he have info on the default behaviour). 286098943Sluigi */ 286198943Sluigistruct ip_fw *ip_fw_default_rule; 286298943Sluigi 2863101978Sluigi/* 2864101978Sluigi * This procedure is only used to handle keepalives. It is invoked 2865101978Sluigi * every dyn_keepalive_period 2866101978Sluigi */ 286798943Sluigistatic void 2868100004Sluigiipfw_tick(void * __unused unused) 2869100004Sluigi{ 2870100004Sluigi int i; 2871100004Sluigi ipfw_dyn_rule *q; 2872100004Sluigi 2873100004Sluigi if (dyn_keepalive == 0 || ipfw_dyn_v == NULL || dyn_count == 0) 2874100004Sluigi goto done; 2875100004Sluigi 2876120141Ssam IPFW_DYN_LOCK(); 2877100004Sluigi for (i = 0 ; i < curr_dyn_buckets ; i++) { 2878100004Sluigi for (q = ipfw_dyn_v[i] ; q ; q = q->next ) { 2879100004Sluigi if (q->dyn_type == O_LIMIT_PARENT) 2880100004Sluigi continue; 2881100004Sluigi if (q->id.proto != IPPROTO_TCP) 2882100004Sluigi continue; 2883100004Sluigi if ( (q->state & BOTH_SYN) != BOTH_SYN) 2884100004Sluigi continue; 2885101978Sluigi if (TIME_LEQ( time_second+dyn_keepalive_interval, 2886101978Sluigi q->expire)) 2887100004Sluigi continue; /* too early */ 2888100004Sluigi if (TIME_LEQ(q->expire, time_second)) 2889100004Sluigi continue; /* too late, rule expired */ 2890100004Sluigi 2891100004Sluigi send_pkt(&(q->id), q->ack_rev - 1, q->ack_fwd, TH_SYN); 2892100004Sluigi send_pkt(&(q->id), q->ack_fwd - 1, q->ack_rev, 0); 2893100004Sluigi } 2894100004Sluigi } 2895120141Ssam IPFW_DYN_UNLOCK(); 2896100004Sluigidone: 2897120141Ssam callout_reset(&ipfw_timeout, dyn_keepalive_period*hz, ipfw_tick, NULL); 2898100004Sluigi} 2899100004Sluigi 2900120141Ssamstatic int 290198943Sluigiipfw_init(void) 290298943Sluigi{ 290398943Sluigi struct ip_fw default_rule; 2904120141Ssam int error; 290598943Sluigi 2906120141Ssam layer3_chain.rules = NULL; 2907120141Ssam IPFW_LOCK_INIT(&layer3_chain); 2908120141Ssam IPFW_DYN_LOCK_INIT(); 2909120141Ssam callout_init(&ipfw_timeout, CALLOUT_MPSAFE); 291098943Sluigi 291198943Sluigi bzero(&default_rule, sizeof default_rule); 291298943Sluigi 291398943Sluigi default_rule.act_ofs = 0; 291498943Sluigi default_rule.rulenum = IPFW_DEFAULT_RULE; 291598943Sluigi default_rule.cmd_len = 1; 2916117654Sluigi default_rule.set = RESVD_SET; 291798943Sluigi 291898943Sluigi default_rule.cmd[0].len = 1; 291998943Sluigi default_rule.cmd[0].opcode = 292098943Sluigi#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT 292198943Sluigi 1 ? O_ACCEPT : 292298943Sluigi#endif 292398943Sluigi O_DENY; 292498943Sluigi 2925120141Ssam error = add_rule(&layer3_chain, &default_rule); 2926120141Ssam if (error != 0) { 2927120141Ssam printf("ipfw2: error %u initializing default rule " 2928120141Ssam "(support disabled)\n", error); 2929120141Ssam IPFW_DYN_LOCK_DESTROY(); 2930120141Ssam IPFW_LOCK_DESTROY(&layer3_chain); 2931120141Ssam return (error); 2932120141Ssam } 293398943Sluigi 2934120141Ssam ip_fw_default_rule = layer3_chain.rules; 2935102086Sluigi printf("ipfw2 initialized, divert %s, " 2936102086Sluigi "rule-based forwarding enabled, default to %s, logging ", 293798943Sluigi#ifdef IPDIVERT 293898943Sluigi "enabled", 293998943Sluigi#else 294098943Sluigi "disabled", 294198943Sluigi#endif 294298943Sluigi default_rule.cmd[0].opcode == O_ACCEPT ? "accept" : "deny"); 294398943Sluigi 294498943Sluigi#ifdef IPFIREWALL_VERBOSE 294598943Sluigi fw_verbose = 1; 294698943Sluigi#endif 294798943Sluigi#ifdef IPFIREWALL_VERBOSE_LIMIT 294898943Sluigi verbose_limit = IPFIREWALL_VERBOSE_LIMIT; 294998943Sluigi#endif 295098943Sluigi if (fw_verbose == 0) 295198943Sluigi printf("disabled\n"); 295298943Sluigi else if (verbose_limit == 0) 295398943Sluigi printf("unlimited\n"); 295498943Sluigi else 295598943Sluigi printf("limited to %d packets/entry by default\n", 295698943Sluigi verbose_limit); 2957120141Ssam 2958120141Ssam ip_fw_chk_ptr = ipfw_chk; 2959120141Ssam ip_fw_ctl_ptr = ipfw_ctl; 2960120141Ssam callout_reset(&ipfw_timeout, hz, ipfw_tick, NULL); 2961120141Ssam 2962120141Ssam return (0); 296398943Sluigi} 296498943Sluigi 2965120141Ssamstatic void 2966120141Ssamipfw_destroy(void) 2967120141Ssam{ 2968120141Ssam struct ip_fw *reap; 2969120141Ssam 2970120141Ssam IPFW_LOCK(&layer3_chain); 2971120141Ssam callout_stop(&ipfw_timeout); 2972120141Ssam ip_fw_chk_ptr = NULL; 2973120141Ssam ip_fw_ctl_ptr = NULL; 2974120141Ssam layer3_chain.reap = NULL; 2975120141Ssam free_chain(&layer3_chain, 1 /* kill default rule */); 2976120141Ssam reap = layer3_chain.reap, layer3_chain.reap = NULL; 2977120141Ssam IPFW_UNLOCK(&layer3_chain); 2978120141Ssam if (reap != NULL) 2979120141Ssam reap_rules(reap); 2980120141Ssam 2981120141Ssam IPFW_DYN_LOCK_DESTROY(); 2982120141Ssam IPFW_LOCK_DESTROY(&layer3_chain); 2983120141Ssam printf("IP firewall unloaded\n"); 2984120141Ssam} 2985120141Ssam 298698943Sluigistatic int 298798943Sluigiipfw_modevent(module_t mod, int type, void *unused) 298898943Sluigi{ 298998943Sluigi int err = 0; 2990105775Smaxim 299198943Sluigi switch (type) { 299298943Sluigi case MOD_LOAD: 299398943Sluigi if (IPFW_LOADED) { 299498943Sluigi printf("IP firewall already loaded\n"); 299598943Sluigi err = EEXIST; 299698943Sluigi } else { 2997120141Ssam err = ipfw_init(); 299898943Sluigi } 299998943Sluigi break; 300098943Sluigi 300198943Sluigi case MOD_UNLOAD: 3002120141Ssam ipfw_destroy(); 3003120141Ssam err = 0; 300498943Sluigi break; 300598943Sluigi default: 300698943Sluigi break; 300798943Sluigi } 300898943Sluigi return err; 300998943Sluigi} 301098943Sluigi 301198943Sluigistatic moduledata_t ipfwmod = { 301298943Sluigi "ipfw", 301398943Sluigi ipfw_modevent, 301498943Sluigi 0 301598943Sluigi}; 301698943SluigiDECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY); 301798943SluigiMODULE_VERSION(ipfw, 1); 301899622Sluigi#endif /* IPFW2 */ 3019