ip_fw2.c revision 117241
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 117241 2003-07-04 21:42:32Z luigi $ 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 95101628Sluigi * are disabled. Set 31 is reserved for the default rule 96101628Sluigi * and CANNOT be disabled. 97101628Sluigi */ 98101628Sluigistatic u_int32_t set_disable; 99101628Sluigi 10099622Sluigistatic int fw_verbose; 10199622Sluigistatic int verbose_limit; 10298943Sluigi 103100004Sluigistatic struct callout_handle ipfw_timeout_h; 10498943Sluigi#define IPFW_DEFAULT_RULE 65535 10598943Sluigi 10698943Sluigi/* 10798943Sluigi * list of rules for layer 3 10898943Sluigi */ 10998943Sluigistatic struct ip_fw *layer3_chain; 11098943Sluigi 11198943SluigiMALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); 11298943Sluigi 11398943Sluigistatic int fw_debug = 1; 11498943Sluigistatic int autoinc_step = 100; /* bounded to 1..1000 in add_rule() */ 11598943Sluigi 11698943Sluigi#ifdef SYSCTL_NODE 11798943SluigiSYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); 118102397ScjcSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, enable, 119109246Sdillon CTLFLAG_RW | CTLFLAG_SECURE3, 12098943Sluigi &fw_enable, 0, "Enable ipfw"); 12198943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, CTLFLAG_RW, 12298943Sluigi &autoinc_step, 0, "Rule number autincrement step"); 123102397ScjcSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, one_pass, 124109246Sdillon CTLFLAG_RW | CTLFLAG_SECURE3, 125105775Smaxim &fw_one_pass, 0, 12698943Sluigi "Only do a single pass through ipfw when using dummynet(4)"); 127105775SmaximSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, 12898943Sluigi &fw_debug, 0, "Enable printing of debug ip_fw statements"); 129102397ScjcSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, 130109246Sdillon CTLFLAG_RW | CTLFLAG_SECURE3, 13198943Sluigi &fw_verbose, 0, "Log matches to ipfw rules"); 132105775SmaximSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, 13398943Sluigi &verbose_limit, 0, "Set upper limit of matches of ipfw rules logged"); 13498943Sluigi 13598943Sluigi/* 13698943Sluigi * Description of dynamic rules. 13798943Sluigi * 13898943Sluigi * Dynamic rules are stored in lists accessed through a hash table 13998943Sluigi * (ipfw_dyn_v) whose size is curr_dyn_buckets. This value can 14098943Sluigi * be modified through the sysctl variable dyn_buckets which is 14198943Sluigi * updated when the table becomes empty. 14298943Sluigi * 14398943Sluigi * XXX currently there is only one list, ipfw_dyn. 14498943Sluigi * 14598943Sluigi * When a packet is received, its address fields are first masked 14698943Sluigi * with the mask defined for the rule, then hashed, then matched 14798943Sluigi * against the entries in the corresponding list. 14898943Sluigi * Dynamic rules can be used for different purposes: 14998943Sluigi * + stateful rules; 15098943Sluigi * + enforcing limits on the number of sessions; 15198943Sluigi * + in-kernel NAT (not implemented yet) 15298943Sluigi * 15398943Sluigi * The lifetime of dynamic rules is regulated by dyn_*_lifetime, 15498943Sluigi * measured in seconds and depending on the flags. 15598943Sluigi * 15698943Sluigi * The total number of dynamic rules is stored in dyn_count. 15798943Sluigi * The max number of dynamic rules is dyn_max. When we reach 15898943Sluigi * the maximum number of rules we do not create anymore. This is 15998943Sluigi * done to avoid consuming too much memory, but also too much 16098943Sluigi * time when searching on each packet (ideally, we should try instead 16198943Sluigi * to put a limit on the length of the list on each bucket...). 16298943Sluigi * 16398943Sluigi * Each dynamic rule holds a pointer to the parent ipfw rule so 16498943Sluigi * we know what action to perform. Dynamic rules are removed when 16598943Sluigi * the parent rule is deleted. XXX we should make them survive. 16698943Sluigi * 16798943Sluigi * There are some limitations with dynamic rules -- we do not 16898943Sluigi * obey the 'randomized match', and we do not do multiple 16998943Sluigi * passes through the firewall. XXX check the latter!!! 17098943Sluigi */ 17198943Sluigistatic ipfw_dyn_rule **ipfw_dyn_v = NULL; 17298943Sluigistatic u_int32_t dyn_buckets = 256; /* must be power of 2 */ 17398943Sluigistatic u_int32_t curr_dyn_buckets = 256; /* must be power of 2 */ 17498943Sluigi 17598943Sluigi/* 17698943Sluigi * Timeouts for various events in handing dynamic rules. 17798943Sluigi */ 17898943Sluigistatic u_int32_t dyn_ack_lifetime = 300; 17998943Sluigistatic u_int32_t dyn_syn_lifetime = 20; 18098943Sluigistatic u_int32_t dyn_fin_lifetime = 1; 18198943Sluigistatic u_int32_t dyn_rst_lifetime = 1; 18298943Sluigistatic u_int32_t dyn_udp_lifetime = 10; 18398943Sluigistatic u_int32_t dyn_short_lifetime = 5; 18498943Sluigi 185101978Sluigi/* 186101978Sluigi * Keepalives are sent if dyn_keepalive is set. They are sent every 187101978Sluigi * dyn_keepalive_period seconds, in the last dyn_keepalive_interval 188101978Sluigi * seconds of lifetime of a rule. 189101978Sluigi * dyn_rst_lifetime and dyn_fin_lifetime should be strictly lower 190101978Sluigi * than dyn_keepalive_period. 191101978Sluigi */ 192105775Smaxim 193101978Sluigistatic u_int32_t dyn_keepalive_interval = 20; 194101978Sluigistatic u_int32_t dyn_keepalive_period = 5; 195100004Sluigistatic u_int32_t dyn_keepalive = 1; /* do send keepalives */ 19698943Sluigi 19799622Sluigistatic u_int32_t static_count; /* # of static rules */ 19899622Sluigistatic u_int32_t static_len; /* size in bytes of static rules */ 19999622Sluigistatic u_int32_t dyn_count; /* # of dynamic rules */ 200101978Sluigistatic u_int32_t dyn_max = 4096; /* max # of dynamic rules */ 20198943Sluigi 20298943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_buckets, CTLFLAG_RW, 20398943Sluigi &dyn_buckets, 0, "Number of dyn. buckets"); 20498943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, curr_dyn_buckets, CTLFLAG_RD, 20598943Sluigi &curr_dyn_buckets, 0, "Current Number of dyn. buckets"); 20698943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_count, CTLFLAG_RD, 20798943Sluigi &dyn_count, 0, "Number of dyn. rules"); 20898943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_max, CTLFLAG_RW, 20998943Sluigi &dyn_max, 0, "Max number of dyn. rules"); 21098943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, static_count, CTLFLAG_RD, 21198943Sluigi &static_count, 0, "Number of static rules"); 21298943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_ack_lifetime, CTLFLAG_RW, 21398943Sluigi &dyn_ack_lifetime, 0, "Lifetime of dyn. rules for acks"); 21498943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_syn_lifetime, CTLFLAG_RW, 21598943Sluigi &dyn_syn_lifetime, 0, "Lifetime of dyn. rules for syn"); 21698943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_fin_lifetime, CTLFLAG_RW, 21798943Sluigi &dyn_fin_lifetime, 0, "Lifetime of dyn. rules for fin"); 21898943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_rst_lifetime, CTLFLAG_RW, 21998943Sluigi &dyn_rst_lifetime, 0, "Lifetime of dyn. rules for rst"); 22098943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_udp_lifetime, CTLFLAG_RW, 22198943Sluigi &dyn_udp_lifetime, 0, "Lifetime of dyn. rules for UDP"); 22298943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime, CTLFLAG_RW, 22398943Sluigi &dyn_short_lifetime, 0, "Lifetime of dyn. rules for other situations"); 224100004SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive, CTLFLAG_RW, 225100004Sluigi &dyn_keepalive, 0, "Enable keepalives for dyn. rules"); 22698943Sluigi 22798943Sluigi#endif /* SYSCTL_NODE */ 22898943Sluigi 22998943Sluigi 23098943Sluigistatic ip_fw_chk_t ipfw_chk; 23198943Sluigi 23298943Sluigiip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL; /* hook into dummynet */ 23398943Sluigi 23498943Sluigi/* 23598943Sluigi * This macro maps an ip pointer into a layer3 header pointer of type T 23698943Sluigi */ 23798943Sluigi#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl)) 23898943Sluigi 23999622Sluigistatic __inline int 24098943Sluigiicmptype_match(struct ip *ip, ipfw_insn_u32 *cmd) 24198943Sluigi{ 24298943Sluigi int type = L3HDR(struct icmp,ip)->icmp_type; 24398943Sluigi 24498943Sluigi return (type <= ICMP_MAXTYPE && (cmd->d[0] & (1<<type)) ); 24598943Sluigi} 24698943Sluigi 24798943Sluigi#define TT ( (1 << ICMP_ECHO) | (1 << ICMP_ROUTERSOLICIT) | \ 24898943Sluigi (1 << ICMP_TSTAMP) | (1 << ICMP_IREQ) | (1 << ICMP_MASKREQ) ) 24998943Sluigi 25098943Sluigistatic int 25198943Sluigiis_icmp_query(struct ip *ip) 25298943Sluigi{ 25398943Sluigi int type = L3HDR(struct icmp, ip)->icmp_type; 25498943Sluigi return (type <= ICMP_MAXTYPE && (TT & (1<<type)) ); 25598943Sluigi} 25698943Sluigi#undef TT 25798943Sluigi 25898943Sluigi/* 25998943Sluigi * The following checks use two arrays of 8 or 16 bits to store the 26098943Sluigi * bits that we want set or clear, respectively. They are in the 26198943Sluigi * low and high half of cmd->arg1 or cmd->d[0]. 26298943Sluigi * 26398943Sluigi * We scan options and store the bits we find set. We succeed if 26498943Sluigi * 26598943Sluigi * (want_set & ~bits) == 0 && (want_clear & ~bits) == want_clear 26698943Sluigi * 26798943Sluigi * The code is sometimes optimized not to store additional variables. 26898943Sluigi */ 26998943Sluigi 27098943Sluigistatic int 27198943Sluigiflags_match(ipfw_insn *cmd, u_int8_t bits) 27298943Sluigi{ 27398943Sluigi u_char want_clear; 27498943Sluigi bits = ~bits; 27598943Sluigi 27698943Sluigi if ( ((cmd->arg1 & 0xff) & bits) != 0) 27798943Sluigi return 0; /* some bits we want set were clear */ 27898943Sluigi want_clear = (cmd->arg1 >> 8) & 0xff; 27998943Sluigi if ( (want_clear & bits) != want_clear) 28098943Sluigi return 0; /* some bits we want clear were set */ 28198943Sluigi return 1; 28298943Sluigi} 28398943Sluigi 28498943Sluigistatic int 28598943Sluigiipopts_match(struct ip *ip, ipfw_insn *cmd) 28698943Sluigi{ 28798943Sluigi int optlen, bits = 0; 28898943Sluigi u_char *cp = (u_char *)(ip + 1); 28998943Sluigi int x = (ip->ip_hl << 2) - sizeof (struct ip); 29098943Sluigi 29198943Sluigi for (; x > 0; x -= optlen, cp += optlen) { 29298943Sluigi int opt = cp[IPOPT_OPTVAL]; 29398943Sluigi 29498943Sluigi if (opt == IPOPT_EOL) 29598943Sluigi break; 29698943Sluigi if (opt == IPOPT_NOP) 29798943Sluigi optlen = 1; 29898943Sluigi else { 29998943Sluigi optlen = cp[IPOPT_OLEN]; 30098943Sluigi if (optlen <= 0 || optlen > x) 30198943Sluigi return 0; /* invalid or truncated */ 30298943Sluigi } 30398943Sluigi switch (opt) { 30498943Sluigi 30598943Sluigi default: 30698943Sluigi break; 30798943Sluigi 30898943Sluigi case IPOPT_LSRR: 30998943Sluigi bits |= IP_FW_IPOPT_LSRR; 31098943Sluigi break; 31198943Sluigi 31298943Sluigi case IPOPT_SSRR: 31398943Sluigi bits |= IP_FW_IPOPT_SSRR; 31498943Sluigi break; 31598943Sluigi 31698943Sluigi case IPOPT_RR: 31798943Sluigi bits |= IP_FW_IPOPT_RR; 31898943Sluigi break; 31998943Sluigi 32098943Sluigi case IPOPT_TS: 32198943Sluigi bits |= IP_FW_IPOPT_TS; 32298943Sluigi break; 32398943Sluigi } 32498943Sluigi } 32598943Sluigi return (flags_match(cmd, bits)); 32698943Sluigi} 32798943Sluigi 32898943Sluigistatic int 32998943Sluigitcpopts_match(struct ip *ip, ipfw_insn *cmd) 33098943Sluigi{ 33198943Sluigi int optlen, bits = 0; 33298943Sluigi struct tcphdr *tcp = L3HDR(struct tcphdr,ip); 33398943Sluigi u_char *cp = (u_char *)(tcp + 1); 33498943Sluigi int x = (tcp->th_off << 2) - sizeof(struct tcphdr); 33598943Sluigi 33698943Sluigi for (; x > 0; x -= optlen, cp += optlen) { 33798943Sluigi int opt = cp[0]; 33898943Sluigi if (opt == TCPOPT_EOL) 33998943Sluigi break; 34098943Sluigi if (opt == TCPOPT_NOP) 34198943Sluigi optlen = 1; 34298943Sluigi else { 34398943Sluigi optlen = cp[1]; 34498943Sluigi if (optlen <= 0) 34598943Sluigi break; 34698943Sluigi } 34798943Sluigi 34898943Sluigi switch (opt) { 34998943Sluigi 35098943Sluigi default: 35198943Sluigi break; 35298943Sluigi 35398943Sluigi case TCPOPT_MAXSEG: 35498943Sluigi bits |= IP_FW_TCPOPT_MSS; 35598943Sluigi break; 35698943Sluigi 35798943Sluigi case TCPOPT_WINDOW: 35898943Sluigi bits |= IP_FW_TCPOPT_WINDOW; 35998943Sluigi break; 36098943Sluigi 36198943Sluigi case TCPOPT_SACK_PERMITTED: 36298943Sluigi case TCPOPT_SACK: 36398943Sluigi bits |= IP_FW_TCPOPT_SACK; 36498943Sluigi break; 36598943Sluigi 36698943Sluigi case TCPOPT_TIMESTAMP: 36798943Sluigi bits |= IP_FW_TCPOPT_TS; 36898943Sluigi break; 36998943Sluigi 37098943Sluigi case TCPOPT_CC: 37198943Sluigi case TCPOPT_CCNEW: 37298943Sluigi case TCPOPT_CCECHO: 37398943Sluigi bits |= IP_FW_TCPOPT_CC; 37498943Sluigi break; 37598943Sluigi } 37698943Sluigi } 37798943Sluigi return (flags_match(cmd, bits)); 37898943Sluigi} 37998943Sluigi 38098943Sluigistatic int 38198943Sluigiiface_match(struct ifnet *ifp, ipfw_insn_if *cmd) 38298943Sluigi{ 38398943Sluigi if (ifp == NULL) /* no iface with this packet, match fails */ 38498943Sluigi return 0; 38598943Sluigi /* Check by name or by IP address */ 38699475Sluigi if (cmd->name[0] != '\0') { /* match by name */ 38798943Sluigi /* Check unit number (-1 is wildcard) */ 38898943Sluigi if (cmd->p.unit != -1 && cmd->p.unit != ifp->if_unit) 38998943Sluigi return(0); 39098943Sluigi /* Check name */ 39198943Sluigi if (!strncmp(ifp->if_name, cmd->name, IFNAMSIZ)) 39298943Sluigi return(1); 39398943Sluigi } else { 39498943Sluigi struct ifaddr *ia; 39598943Sluigi 39698943Sluigi TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { 39798943Sluigi if (ia->ifa_addr == NULL) 39898943Sluigi continue; 39998943Sluigi if (ia->ifa_addr->sa_family != AF_INET) 40098943Sluigi continue; 40198943Sluigi if (cmd->p.ip.s_addr == ((struct sockaddr_in *) 40298943Sluigi (ia->ifa_addr))->sin_addr.s_addr) 40398943Sluigi return(1); /* match */ 40498943Sluigi } 40598943Sluigi } 40698943Sluigi return(0); /* no match, fail ... */ 40798943Sluigi} 40898943Sluigi 409112250Scjc/* 410112250Scjc * The 'verrevpath' option checks that the interface that an IP packet 411116763Sluigi * arrives on is the same interface that traffic destined for the 412112250Scjc * packet's source address would be routed out of. This is a measure 413112250Scjc * to block forged packets. This is also commonly known as "anti-spoofing" 414112250Scjc * or Unicast Reverse Path Forwarding (Unicast RFP) in Cisco-ese. The 415112250Scjc * name of the knob is purposely reminisent of the Cisco IOS command, 416112250Scjc * 417112250Scjc * ip verify unicast reverse-path 418112250Scjc * 419112250Scjc * which implements the same functionality. But note that syntax is 420112250Scjc * misleading. The check may be performed on all IP packets whether unicast, 421112250Scjc * multicast, or broadcast. 422112250Scjc */ 423112250Scjcstatic int 424112250Scjcverify_rev_path(struct in_addr src, struct ifnet *ifp) 425112250Scjc{ 426112250Scjc static struct route ro; 427112250Scjc struct sockaddr_in *dst; 428112250Scjc 429112250Scjc dst = (struct sockaddr_in *)&(ro.ro_dst); 430112250Scjc 431112250Scjc /* Check if we've cached the route from the previous call. */ 432112250Scjc if (src.s_addr != dst->sin_addr.s_addr) { 433112250Scjc ro.ro_rt = NULL; 434112250Scjc 435112250Scjc bzero(dst, sizeof(*dst)); 436112250Scjc dst->sin_family = AF_INET; 437112250Scjc dst->sin_len = sizeof(*dst); 438112250Scjc dst->sin_addr = src; 439112250Scjc 440112250Scjc rtalloc_ign(&ro, RTF_CLONING|RTF_PRCLONING); 441112250Scjc } 442112250Scjc 443112250Scjc if ((ro.ro_rt == NULL) || (ifp == NULL) || 444112250Scjc (ro.ro_rt->rt_ifp->if_index != ifp->if_index)) 445112250Scjc return 0; 446116763Sluigi 447116981Sluigi return 1; 448112250Scjc} 449112250Scjc 450112250Scjc 45198943Sluigistatic u_int64_t norule_counter; /* counter for ipfw_log(NULL...) */ 45298943Sluigi 45398943Sluigi#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0 45499622Sluigi#define SNP(buf) buf, sizeof(buf) 455100004Sluigi 45698943Sluigi/* 45798943Sluigi * We enter here when we have a rule with O_LOG. 45899622Sluigi * XXX this function alone takes about 2Kbytes of code! 45998943Sluigi */ 46098943Sluigistatic void 46198943Sluigiipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh, 46298943Sluigi struct mbuf *m, struct ifnet *oif) 46398943Sluigi{ 46498943Sluigi char *action; 46598943Sluigi int limit_reached = 0; 46699622Sluigi char action2[40], proto[48], fragment[28]; 46798943Sluigi 46898943Sluigi fragment[0] = '\0'; 46998943Sluigi proto[0] = '\0'; 47098943Sluigi 47198943Sluigi if (f == NULL) { /* bogus pkt */ 47298943Sluigi if (verbose_limit != 0 && norule_counter >= verbose_limit) 47398943Sluigi return; 47498943Sluigi norule_counter++; 47598943Sluigi if (norule_counter == verbose_limit) 47698943Sluigi limit_reached = verbose_limit; 47798943Sluigi action = "Refuse"; 47898943Sluigi } else { /* O_LOG is the first action, find the real one */ 47998943Sluigi ipfw_insn *cmd = ACTION_PTR(f); 48098943Sluigi ipfw_insn_log *l = (ipfw_insn_log *)cmd; 48198943Sluigi 48298943Sluigi if (l->max_log != 0 && l->log_left == 0) 48398943Sluigi return; 48498943Sluigi l->log_left--; 48598943Sluigi if (l->log_left == 0) 48698943Sluigi limit_reached = l->max_log; 48798943Sluigi cmd += F_LEN(cmd); /* point to first action */ 48898943Sluigi if (cmd->opcode == O_PROB) 48998943Sluigi cmd += F_LEN(cmd); 49098943Sluigi 49198943Sluigi action = action2; 49298943Sluigi switch (cmd->opcode) { 49398943Sluigi case O_DENY: 49498943Sluigi action = "Deny"; 49598943Sluigi break; 49699475Sluigi 49798943Sluigi case O_REJECT: 49899475Sluigi if (cmd->arg1==ICMP_REJECT_RST) 49999475Sluigi action = "Reset"; 50099475Sluigi else if (cmd->arg1==ICMP_UNREACH_HOST) 50199475Sluigi action = "Reject"; 50299475Sluigi else 50399475Sluigi snprintf(SNPARGS(action2, 0), "Unreach %d", 50499475Sluigi cmd->arg1); 50598943Sluigi break; 50699475Sluigi 50798943Sluigi case O_ACCEPT: 50898943Sluigi action = "Accept"; 50998943Sluigi break; 51098943Sluigi case O_COUNT: 51198943Sluigi action = "Count"; 51298943Sluigi break; 51398943Sluigi case O_DIVERT: 51498943Sluigi snprintf(SNPARGS(action2, 0), "Divert %d", 51598943Sluigi cmd->arg1); 51698943Sluigi break; 51798943Sluigi case O_TEE: 51898943Sluigi snprintf(SNPARGS(action2, 0), "Tee %d", 51998943Sluigi cmd->arg1); 52098943Sluigi break; 52198943Sluigi case O_SKIPTO: 52298943Sluigi snprintf(SNPARGS(action2, 0), "SkipTo %d", 52398943Sluigi cmd->arg1); 52498943Sluigi break; 52598943Sluigi case O_PIPE: 52698943Sluigi snprintf(SNPARGS(action2, 0), "Pipe %d", 52798943Sluigi cmd->arg1); 52898943Sluigi break; 52998943Sluigi case O_QUEUE: 53098943Sluigi snprintf(SNPARGS(action2, 0), "Queue %d", 53198943Sluigi cmd->arg1); 53298943Sluigi break; 53398943Sluigi case O_FORWARD_IP: { 53498943Sluigi ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd; 535100004Sluigi int len; 53698943Sluigi 537100004Sluigi len = snprintf(SNPARGS(action2, 0), "Forward to %s", 538100004Sluigi inet_ntoa(sa->sa.sin_addr)); 53998943Sluigi if (sa->sa.sin_port) 540100004Sluigi snprintf(SNPARGS(action2, len), ":%d", 541107897Smaxim sa->sa.sin_port); 54298943Sluigi } 54398943Sluigi break; 544105775Smaxim default: 54598943Sluigi action = "UNKNOWN"; 54698943Sluigi break; 54798943Sluigi } 54898943Sluigi } 54998943Sluigi 55098943Sluigi if (hlen == 0) { /* non-ip */ 55198943Sluigi snprintf(SNPARGS(proto, 0), "MAC"); 55298943Sluigi } else { 55398943Sluigi struct ip *ip = mtod(m, struct ip *); 55498943Sluigi /* these three are all aliases to the same thing */ 55598943Sluigi struct icmp *const icmp = L3HDR(struct icmp, ip); 55698943Sluigi struct tcphdr *const tcp = (struct tcphdr *)icmp; 55798943Sluigi struct udphdr *const udp = (struct udphdr *)icmp; 55898943Sluigi 55998943Sluigi int ip_off, offset, ip_len; 56098943Sluigi 56198943Sluigi int len; 56298943Sluigi 56398943Sluigi if (eh != NULL) { /* layer 2 packets are as on the wire */ 56498943Sluigi ip_off = ntohs(ip->ip_off); 56598943Sluigi ip_len = ntohs(ip->ip_len); 56698943Sluigi } else { 56798943Sluigi ip_off = ip->ip_off; 56898943Sluigi ip_len = ip->ip_len; 56998943Sluigi } 57098943Sluigi offset = ip_off & IP_OFFMASK; 57198943Sluigi switch (ip->ip_p) { 57298943Sluigi case IPPROTO_TCP: 57398943Sluigi len = snprintf(SNPARGS(proto, 0), "TCP %s", 57498943Sluigi inet_ntoa(ip->ip_src)); 57598943Sluigi if (offset == 0) 576100004Sluigi snprintf(SNPARGS(proto, len), ":%d %s:%d", 577100004Sluigi ntohs(tcp->th_sport), 578100004Sluigi inet_ntoa(ip->ip_dst), 579100004Sluigi ntohs(tcp->th_dport)); 58098943Sluigi else 581100004Sluigi snprintf(SNPARGS(proto, len), " %s", 582100004Sluigi inet_ntoa(ip->ip_dst)); 58398943Sluigi break; 58498943Sluigi 58598943Sluigi case IPPROTO_UDP: 58698943Sluigi len = snprintf(SNPARGS(proto, 0), "UDP %s", 58798943Sluigi inet_ntoa(ip->ip_src)); 58898943Sluigi if (offset == 0) 589100004Sluigi snprintf(SNPARGS(proto, len), ":%d %s:%d", 590100004Sluigi ntohs(udp->uh_sport), 591100004Sluigi inet_ntoa(ip->ip_dst), 592100004Sluigi ntohs(udp->uh_dport)); 59398943Sluigi else 594100004Sluigi snprintf(SNPARGS(proto, len), " %s", 595100004Sluigi inet_ntoa(ip->ip_dst)); 59698943Sluigi break; 59798943Sluigi 59898943Sluigi case IPPROTO_ICMP: 59998943Sluigi if (offset == 0) 60098943Sluigi len = snprintf(SNPARGS(proto, 0), 60198943Sluigi "ICMP:%u.%u ", 60298943Sluigi icmp->icmp_type, icmp->icmp_code); 60398943Sluigi else 60498943Sluigi len = snprintf(SNPARGS(proto, 0), "ICMP "); 60598943Sluigi len += snprintf(SNPARGS(proto, len), "%s", 60698943Sluigi inet_ntoa(ip->ip_src)); 60798943Sluigi snprintf(SNPARGS(proto, len), " %s", 60898943Sluigi inet_ntoa(ip->ip_dst)); 60998943Sluigi break; 61098943Sluigi 61198943Sluigi default: 61298943Sluigi len = snprintf(SNPARGS(proto, 0), "P:%d %s", ip->ip_p, 61398943Sluigi inet_ntoa(ip->ip_src)); 61498943Sluigi snprintf(SNPARGS(proto, len), " %s", 61598943Sluigi inet_ntoa(ip->ip_dst)); 61698943Sluigi break; 61798943Sluigi } 61898943Sluigi 61998943Sluigi if (ip_off & (IP_MF | IP_OFFMASK)) 62098943Sluigi snprintf(SNPARGS(fragment, 0), " (frag %d:%d@%d%s)", 62198943Sluigi ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2), 62298943Sluigi offset << 3, 62398943Sluigi (ip_off & IP_MF) ? "+" : ""); 62498943Sluigi } 62598943Sluigi if (oif || m->m_pkthdr.rcvif) 62698943Sluigi log(LOG_SECURITY | LOG_INFO, 62798943Sluigi "ipfw: %d %s %s %s via %s%d%s\n", 62898943Sluigi f ? f->rulenum : -1, 62998943Sluigi action, proto, oif ? "out" : "in", 63098943Sluigi oif ? oif->if_name : m->m_pkthdr.rcvif->if_name, 63198943Sluigi oif ? oif->if_unit : m->m_pkthdr.rcvif->if_unit, 63298943Sluigi fragment); 63398943Sluigi else 63498943Sluigi log(LOG_SECURITY | LOG_INFO, 63598943Sluigi "ipfw: %d %s %s [no if info]%s\n", 63698943Sluigi f ? f->rulenum : -1, 63798943Sluigi action, proto, fragment); 63898943Sluigi if (limit_reached) 63998943Sluigi log(LOG_SECURITY | LOG_NOTICE, 64098943Sluigi "ipfw: limit %d reached on entry %d\n", 64198943Sluigi limit_reached, f ? f->rulenum : -1); 64298943Sluigi} 64398943Sluigi 64498943Sluigi/* 64598943Sluigi * IMPORTANT: the hash function for dynamic rules must be commutative 64699475Sluigi * in source and destination (ip,port), because rules are bidirectional 64798943Sluigi * and we want to find both in the same bucket. 64898943Sluigi */ 64998943Sluigistatic __inline int 65098943Sluigihash_packet(struct ipfw_flow_id *id) 65198943Sluigi{ 65298943Sluigi u_int32_t i; 65398943Sluigi 65498943Sluigi i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port); 65598943Sluigi i &= (curr_dyn_buckets - 1); 65698943Sluigi return i; 65798943Sluigi} 65898943Sluigi 65998943Sluigi/** 66098943Sluigi * unlink a dynamic rule from a chain. prev is a pointer to 66198943Sluigi * the previous one, q is a pointer to the rule to delete, 66298943Sluigi * head is a pointer to the head of the queue. 66398943Sluigi * Modifies q and potentially also head. 66498943Sluigi */ 66598943Sluigi#define UNLINK_DYN_RULE(prev, head, q) { \ 66698943Sluigi ipfw_dyn_rule *old_q = q; \ 66798943Sluigi \ 66898943Sluigi /* remove a refcount to the parent */ \ 66998943Sluigi if (q->dyn_type == O_LIMIT) \ 67098943Sluigi q->parent->count--; \ 671108258Smaxim DEB(printf("ipfw: unlink entry 0x%08x %d -> 0x%08x %d, %d left\n",\ 67298943Sluigi (q->id.src_ip), (q->id.src_port), \ 67398943Sluigi (q->id.dst_ip), (q->id.dst_port), dyn_count-1 ); ) \ 67498943Sluigi if (prev != NULL) \ 67598943Sluigi prev->next = q = q->next; \ 67698943Sluigi else \ 67798943Sluigi head = q = q->next; \ 67898943Sluigi dyn_count--; \ 67998943Sluigi free(old_q, M_IPFW); } 68098943Sluigi 68198943Sluigi#define TIME_LEQ(a,b) ((int)((a)-(b)) <= 0) 68298943Sluigi 68398943Sluigi/** 68498943Sluigi * Remove dynamic rules pointing to "rule", or all of them if rule == NULL. 68598943Sluigi * 68698943Sluigi * If keep_me == NULL, rules are deleted even if not expired, 68798943Sluigi * otherwise only expired rules are removed. 68898943Sluigi * 68998943Sluigi * The value of the second parameter is also used to point to identify 69098943Sluigi * a rule we absolutely do not want to remove (e.g. because we are 69198943Sluigi * holding a reference to it -- this is the case with O_LIMIT_PARENT 69298943Sluigi * rules). The pointer is only used for comparison, so any non-null 69398943Sluigi * value will do. 69498943Sluigi */ 69598943Sluigistatic void 69698943Sluigiremove_dyn_rule(struct ip_fw *rule, ipfw_dyn_rule *keep_me) 69798943Sluigi{ 69898943Sluigi static u_int32_t last_remove = 0; 69998943Sluigi 70098943Sluigi#define FORCE (keep_me == NULL) 70198943Sluigi 70298943Sluigi ipfw_dyn_rule *prev, *q; 70398943Sluigi int i, pass = 0, max_pass = 0; 70498943Sluigi 70598943Sluigi if (ipfw_dyn_v == NULL || dyn_count == 0) 70698943Sluigi return; 70798943Sluigi /* do not expire more than once per second, it is useless */ 70898943Sluigi if (!FORCE && last_remove == time_second) 70998943Sluigi return; 71098943Sluigi last_remove = time_second; 71198943Sluigi 71298943Sluigi /* 71398943Sluigi * because O_LIMIT refer to parent rules, during the first pass only 71498943Sluigi * remove child and mark any pending LIMIT_PARENT, and remove 71598943Sluigi * them in a second pass. 71698943Sluigi */ 71798943Sluiginext_pass: 71898943Sluigi for (i = 0 ; i < curr_dyn_buckets ; i++) { 71998943Sluigi for (prev=NULL, q = ipfw_dyn_v[i] ; q ; ) { 72098943Sluigi /* 72198943Sluigi * Logic can become complex here, so we split tests. 72298943Sluigi */ 72398943Sluigi if (q == keep_me) 72498943Sluigi goto next; 72598943Sluigi if (rule != NULL && rule != q->rule) 72698943Sluigi goto next; /* not the one we are looking for */ 72798943Sluigi if (q->dyn_type == O_LIMIT_PARENT) { 72898943Sluigi /* 72998943Sluigi * handle parent in the second pass, 73098943Sluigi * record we need one. 73198943Sluigi */ 73298943Sluigi max_pass = 1; 73398943Sluigi if (pass == 0) 73498943Sluigi goto next; 73598943Sluigi if (FORCE && q->count != 0 ) { 73698943Sluigi /* XXX should not happen! */ 737108258Smaxim printf("ipfw: OUCH! cannot remove rule," 73898943Sluigi " count %d\n", q->count); 73998943Sluigi } 74098943Sluigi } else { 74198943Sluigi if (!FORCE && 74298943Sluigi !TIME_LEQ( q->expire, time_second )) 74398943Sluigi goto next; 74498943Sluigi } 74598943Sluigi UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q); 74698943Sluigi continue; 74798943Sluiginext: 74898943Sluigi prev=q; 74998943Sluigi q=q->next; 75098943Sluigi } 75198943Sluigi } 75298943Sluigi if (pass++ < max_pass) 75398943Sluigi goto next_pass; 75498943Sluigi} 75598943Sluigi 75698943Sluigi 75798943Sluigi/** 75898943Sluigi * lookup a dynamic rule. 75998943Sluigi */ 76098943Sluigistatic ipfw_dyn_rule * 761100004Sluigilookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction, 762100004Sluigi struct tcphdr *tcp) 76398943Sluigi{ 76498943Sluigi /* 76598943Sluigi * stateful ipfw extensions. 76698943Sluigi * Lookup into dynamic session queue 76798943Sluigi */ 76898943Sluigi#define MATCH_REVERSE 0 76998943Sluigi#define MATCH_FORWARD 1 77098943Sluigi#define MATCH_NONE 2 77198943Sluigi#define MATCH_UNKNOWN 3 77298943Sluigi int i, dir = MATCH_NONE; 77398943Sluigi ipfw_dyn_rule *prev, *q=NULL; 77498943Sluigi 77598943Sluigi if (ipfw_dyn_v == NULL) 77698943Sluigi goto done; /* not found */ 77798943Sluigi i = hash_packet( pkt ); 77898943Sluigi for (prev=NULL, q = ipfw_dyn_v[i] ; q != NULL ; ) { 77998943Sluigi if (q->dyn_type == O_LIMIT_PARENT) 78098943Sluigi goto next; 78198943Sluigi if (TIME_LEQ( q->expire, time_second)) { /* expire entry */ 78298943Sluigi UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q); 78398943Sluigi continue; 78498943Sluigi } 78598943Sluigi if ( pkt->proto == q->id.proto) { 78698943Sluigi if (pkt->src_ip == q->id.src_ip && 78798943Sluigi pkt->dst_ip == q->id.dst_ip && 78898943Sluigi pkt->src_port == q->id.src_port && 78998943Sluigi pkt->dst_port == q->id.dst_port ) { 79098943Sluigi dir = MATCH_FORWARD; 79198943Sluigi break; 79298943Sluigi } 79398943Sluigi if (pkt->src_ip == q->id.dst_ip && 79498943Sluigi pkt->dst_ip == q->id.src_ip && 79598943Sluigi pkt->src_port == q->id.dst_port && 79698943Sluigi pkt->dst_port == q->id.src_port ) { 79798943Sluigi dir = MATCH_REVERSE; 79898943Sluigi break; 79998943Sluigi } 80098943Sluigi } 80198943Sluiginext: 80298943Sluigi prev = q; 80398943Sluigi q = q->next; 80498943Sluigi } 80598943Sluigi if (q == NULL) 80698943Sluigi goto done; /* q = NULL, not found */ 80798943Sluigi 80898943Sluigi if ( prev != NULL) { /* found and not in front */ 80998943Sluigi prev->next = q->next; 81098943Sluigi q->next = ipfw_dyn_v[i]; 81198943Sluigi ipfw_dyn_v[i] = q; 81298943Sluigi } 81398943Sluigi if (pkt->proto == IPPROTO_TCP) { /* update state according to flags */ 81498943Sluigi u_char flags = pkt->flags & (TH_FIN|TH_SYN|TH_RST); 81598943Sluigi 81698943Sluigi#define BOTH_SYN (TH_SYN | (TH_SYN << 8)) 81798943Sluigi#define BOTH_FIN (TH_FIN | (TH_FIN << 8)) 81898943Sluigi q->state |= (dir == MATCH_FORWARD ) ? flags : (flags << 8); 81998943Sluigi switch (q->state) { 82098943Sluigi case TH_SYN: /* opening */ 82198943Sluigi q->expire = time_second + dyn_syn_lifetime; 82298943Sluigi break; 823101978Sluigi 82498943Sluigi case BOTH_SYN: /* move to established */ 82598943Sluigi case BOTH_SYN | TH_FIN : /* one side tries to close */ 82698943Sluigi case BOTH_SYN | (TH_FIN << 8) : 827100004Sluigi if (tcp) { 828100004Sluigi#define _SEQ_GE(a,b) ((int)(a) - (int)(b) >= 0) 829100004Sluigi u_int32_t ack = ntohl(tcp->th_ack); 830100004Sluigi if (dir == MATCH_FORWARD) { 831100004Sluigi if (q->ack_fwd == 0 || _SEQ_GE(ack, q->ack_fwd)) 832100004Sluigi q->ack_fwd = ack; 833100004Sluigi else { /* ignore out-of-sequence */ 834100004Sluigi break; 835100004Sluigi } 836100004Sluigi } else { 837100004Sluigi if (q->ack_rev == 0 || _SEQ_GE(ack, q->ack_rev)) 838100004Sluigi q->ack_rev = ack; 839100004Sluigi else { /* ignore out-of-sequence */ 840100004Sluigi break; 841100004Sluigi } 842100004Sluigi } 843100004Sluigi } 84498943Sluigi q->expire = time_second + dyn_ack_lifetime; 84598943Sluigi break; 846101978Sluigi 84798943Sluigi case BOTH_SYN | BOTH_FIN: /* both sides closed */ 848101978Sluigi if (dyn_fin_lifetime >= dyn_keepalive_period) 849101978Sluigi dyn_fin_lifetime = dyn_keepalive_period - 1; 85098943Sluigi q->expire = time_second + dyn_fin_lifetime; 85198943Sluigi break; 852101978Sluigi 85398943Sluigi default: 85498943Sluigi#if 0 85598943Sluigi /* 85698943Sluigi * reset or some invalid combination, but can also 85798943Sluigi * occur if we use keep-state the wrong way. 85898943Sluigi */ 85998943Sluigi if ( (q->state & ((TH_RST << 8)|TH_RST)) == 0) 86098943Sluigi printf("invalid state: 0x%x\n", q->state); 86198943Sluigi#endif 862101978Sluigi if (dyn_rst_lifetime >= dyn_keepalive_period) 863101978Sluigi dyn_rst_lifetime = dyn_keepalive_period - 1; 86498943Sluigi q->expire = time_second + dyn_rst_lifetime; 86598943Sluigi break; 86698943Sluigi } 86798943Sluigi } else if (pkt->proto == IPPROTO_UDP) { 86898943Sluigi q->expire = time_second + dyn_udp_lifetime; 86998943Sluigi } else { 87098943Sluigi /* other protocols */ 87198943Sluigi q->expire = time_second + dyn_short_lifetime; 87298943Sluigi } 87398943Sluigidone: 87498943Sluigi if (match_direction) 87598943Sluigi *match_direction = dir; 87698943Sluigi return q; 87798943Sluigi} 87898943Sluigi 87998943Sluigistatic void 88098943Sluigirealloc_dynamic_table(void) 88198943Sluigi{ 882101978Sluigi /* 883101978Sluigi * Try reallocation, make sure we have a power of 2 and do 884101978Sluigi * not allow more than 64k entries. In case of overflow, 885101978Sluigi * default to 1024. 886101978Sluigi */ 88798943Sluigi 888101978Sluigi if (dyn_buckets > 65536) 889101978Sluigi dyn_buckets = 1024; 89098943Sluigi if ((dyn_buckets & (dyn_buckets-1)) != 0) { /* not a power of 2 */ 89198943Sluigi dyn_buckets = curr_dyn_buckets; /* reset */ 89298943Sluigi return; 89398943Sluigi } 89498943Sluigi curr_dyn_buckets = dyn_buckets; 89598943Sluigi if (ipfw_dyn_v != NULL) 89698943Sluigi free(ipfw_dyn_v, M_IPFW); 897101978Sluigi for (;;) { 898101978Sluigi ipfw_dyn_v = malloc(curr_dyn_buckets * sizeof(ipfw_dyn_rule *), 899105440Smux M_IPFW, M_NOWAIT | M_ZERO); 900101978Sluigi if (ipfw_dyn_v != NULL || curr_dyn_buckets <= 2) 901101978Sluigi break; 902101978Sluigi curr_dyn_buckets /= 2; 903101978Sluigi } 90498943Sluigi} 90598943Sluigi 90698943Sluigi/** 90798943Sluigi * Install state of type 'type' for a dynamic session. 90898943Sluigi * The hash table contains two type of rules: 90998943Sluigi * - regular rules (O_KEEP_STATE) 91098943Sluigi * - rules for sessions with limited number of sess per user 91198943Sluigi * (O_LIMIT). When they are created, the parent is 91298943Sluigi * increased by 1, and decreased on delete. In this case, 91398943Sluigi * the third parameter is the parent rule and not the chain. 91498943Sluigi * - "parent" rules for the above (O_LIMIT_PARENT). 91598943Sluigi */ 91698943Sluigistatic ipfw_dyn_rule * 91798943Sluigiadd_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule) 91898943Sluigi{ 91998943Sluigi ipfw_dyn_rule *r; 92098943Sluigi int i; 92198943Sluigi 92298943Sluigi if (ipfw_dyn_v == NULL || 92398943Sluigi (dyn_count == 0 && dyn_buckets != curr_dyn_buckets)) { 92498943Sluigi realloc_dynamic_table(); 92598943Sluigi if (ipfw_dyn_v == NULL) 92698943Sluigi return NULL; /* failed ! */ 92798943Sluigi } 92898943Sluigi i = hash_packet(id); 92998943Sluigi 930105440Smux r = malloc(sizeof *r, M_IPFW, M_NOWAIT | M_ZERO); 93198943Sluigi if (r == NULL) { 932108258Smaxim printf ("ipfw: sorry cannot allocate state\n"); 93398943Sluigi return NULL; 93498943Sluigi } 93598943Sluigi 93698943Sluigi /* increase refcount on parent, and set pointer */ 93798943Sluigi if (dyn_type == O_LIMIT) { 93898943Sluigi ipfw_dyn_rule *parent = (ipfw_dyn_rule *)rule; 93998943Sluigi if ( parent->dyn_type != O_LIMIT_PARENT) 94098943Sluigi panic("invalid parent"); 94198943Sluigi parent->count++; 94298943Sluigi r->parent = parent; 94398943Sluigi rule = parent->rule; 94498943Sluigi } 94598943Sluigi 94698943Sluigi r->id = *id; 94798943Sluigi r->expire = time_second + dyn_syn_lifetime; 94898943Sluigi r->rule = rule; 94998943Sluigi r->dyn_type = dyn_type; 95098943Sluigi r->pcnt = r->bcnt = 0; 95198943Sluigi r->count = 0; 95298943Sluigi 95398943Sluigi r->bucket = i; 95498943Sluigi r->next = ipfw_dyn_v[i]; 95598943Sluigi ipfw_dyn_v[i] = r; 95698943Sluigi dyn_count++; 957108258Smaxim DEB(printf("ipfw: add dyn entry ty %d 0x%08x %d -> 0x%08x %d, total %d\n", 95898943Sluigi dyn_type, 95998943Sluigi (r->id.src_ip), (r->id.src_port), 96098943Sluigi (r->id.dst_ip), (r->id.dst_port), 96198943Sluigi dyn_count ); ) 96298943Sluigi return r; 96398943Sluigi} 96498943Sluigi 96598943Sluigi/** 96698943Sluigi * lookup dynamic parent rule using pkt and rule as search keys. 96798943Sluigi * If the lookup fails, then install one. 96898943Sluigi */ 96998943Sluigistatic ipfw_dyn_rule * 97098943Sluigilookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule) 97198943Sluigi{ 97298943Sluigi ipfw_dyn_rule *q; 97398943Sluigi int i; 97498943Sluigi 97598943Sluigi if (ipfw_dyn_v) { 97698943Sluigi i = hash_packet( pkt ); 97798943Sluigi for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next) 97898943Sluigi if (q->dyn_type == O_LIMIT_PARENT && 97998943Sluigi rule== q->rule && 98098943Sluigi pkt->proto == q->id.proto && 98198943Sluigi pkt->src_ip == q->id.src_ip && 98298943Sluigi pkt->dst_ip == q->id.dst_ip && 98398943Sluigi pkt->src_port == q->id.src_port && 98498943Sluigi pkt->dst_port == q->id.dst_port) { 98598943Sluigi q->expire = time_second + dyn_short_lifetime; 986108258Smaxim DEB(printf("ipfw: lookup_dyn_parent found 0x%p\n",q);) 98798943Sluigi return q; 98898943Sluigi } 98998943Sluigi } 99098943Sluigi return add_dyn_rule(pkt, O_LIMIT_PARENT, rule); 99198943Sluigi} 99298943Sluigi 99398943Sluigi/** 99498943Sluigi * Install dynamic state for rule type cmd->o.opcode 99598943Sluigi * 99698943Sluigi * Returns 1 (failure) if state is not installed because of errors or because 99798943Sluigi * session limitations are enforced. 99898943Sluigi */ 99998943Sluigistatic int 100098943Sluigiinstall_state(struct ip_fw *rule, ipfw_insn_limit *cmd, 100198943Sluigi struct ip_fw_args *args) 100298943Sluigi{ 100398943Sluigi static int last_log; 100498943Sluigi 100598943Sluigi ipfw_dyn_rule *q; 100698943Sluigi 1007108258Smaxim DEB(printf("ipfw: install state type %d 0x%08x %u -> 0x%08x %u\n", 100898943Sluigi cmd->o.opcode, 100998943Sluigi (args->f_id.src_ip), (args->f_id.src_port), 101098943Sluigi (args->f_id.dst_ip), (args->f_id.dst_port) );) 101198943Sluigi 1012100004Sluigi q = lookup_dyn_rule(&args->f_id, NULL, NULL); 101398943Sluigi 101498943Sluigi if (q != NULL) { /* should never occur */ 101598943Sluigi if (last_log != time_second) { 101698943Sluigi last_log = time_second; 1017108258Smaxim printf("ipfw: install_state: entry already present, done\n"); 101898943Sluigi } 101998943Sluigi return 0; 102098943Sluigi } 102198943Sluigi 102298943Sluigi if (dyn_count >= dyn_max) 102398943Sluigi /* 102498943Sluigi * Run out of slots, try to remove any expired rule. 102598943Sluigi */ 102698943Sluigi remove_dyn_rule(NULL, (ipfw_dyn_rule *)1); 102798943Sluigi 102898943Sluigi if (dyn_count >= dyn_max) { 102998943Sluigi if (last_log != time_second) { 103098943Sluigi last_log = time_second; 1031108258Smaxim printf("ipfw: install_state: Too many dynamic rules\n"); 103298943Sluigi } 103398943Sluigi return 1; /* cannot install, notify caller */ 103498943Sluigi } 103598943Sluigi 103698943Sluigi switch (cmd->o.opcode) { 103798943Sluigi case O_KEEP_STATE: /* bidir rule */ 103898943Sluigi add_dyn_rule(&args->f_id, O_KEEP_STATE, rule); 103998943Sluigi break; 104098943Sluigi 104198943Sluigi case O_LIMIT: /* limit number of sessions */ 104298943Sluigi { 104398943Sluigi u_int16_t limit_mask = cmd->limit_mask; 104498943Sluigi struct ipfw_flow_id id; 104598943Sluigi ipfw_dyn_rule *parent; 104698943Sluigi 1047108258Smaxim DEB(printf("ipfw: installing dyn-limit rule %d\n", 1048108258Smaxim cmd->conn_limit);) 104998943Sluigi 105098943Sluigi id.dst_ip = id.src_ip = 0; 105198943Sluigi id.dst_port = id.src_port = 0; 105298943Sluigi id.proto = args->f_id.proto; 105398943Sluigi 105498943Sluigi if (limit_mask & DYN_SRC_ADDR) 105598943Sluigi id.src_ip = args->f_id.src_ip; 105698943Sluigi if (limit_mask & DYN_DST_ADDR) 105798943Sluigi id.dst_ip = args->f_id.dst_ip; 105898943Sluigi if (limit_mask & DYN_SRC_PORT) 105998943Sluigi id.src_port = args->f_id.src_port; 106098943Sluigi if (limit_mask & DYN_DST_PORT) 106198943Sluigi id.dst_port = args->f_id.dst_port; 106298943Sluigi parent = lookup_dyn_parent(&id, rule); 106398943Sluigi if (parent == NULL) { 1064108258Smaxim printf("ipfw: add parent failed\n"); 106598943Sluigi return 1; 106698943Sluigi } 106798943Sluigi if (parent->count >= cmd->conn_limit) { 106898943Sluigi /* 106998943Sluigi * See if we can remove some expired rule. 107098943Sluigi */ 107198943Sluigi remove_dyn_rule(rule, parent); 107298943Sluigi if (parent->count >= cmd->conn_limit) { 107398943Sluigi if (fw_verbose && last_log != time_second) { 107498943Sluigi last_log = time_second; 1075106118Smaxim log(LOG_SECURITY | LOG_DEBUG, 107698943Sluigi "drop session, too many entries\n"); 107798943Sluigi } 107898943Sluigi return 1; 107998943Sluigi } 108098943Sluigi } 108198943Sluigi add_dyn_rule(&args->f_id, O_LIMIT, (struct ip_fw *)parent); 108298943Sluigi } 108398943Sluigi break; 108498943Sluigi default: 1085108258Smaxim printf("ipfw: unknown dynamic rule type %u\n", cmd->o.opcode); 108698943Sluigi return 1; 108798943Sluigi } 1088100004Sluigi lookup_dyn_rule(&args->f_id, NULL, NULL); /* XXX just set lifetime */ 108998943Sluigi return 0; 109098943Sluigi} 109198943Sluigi 1092100004Sluigi/* 1093100004Sluigi * Transmit a TCP packet, containing either a RST or a keepalive. 1094100004Sluigi * When flags & TH_RST, we are sending a RST packet, because of a 1095100004Sluigi * "reset" action matched the packet. 1096100004Sluigi * Otherwise we are sending a keepalive, and flags & TH_ 1097100004Sluigi */ 109899475Sluigistatic void 1099100004Sluigisend_pkt(struct ipfw_flow_id *id, u_int32_t seq, u_int32_t ack, int flags) 110099475Sluigi{ 110199475Sluigi struct mbuf *m; 1102100004Sluigi struct ip *ip; 110399475Sluigi struct tcphdr *tcp; 110499475Sluigi struct route sro; /* fake route */ 110599475Sluigi 1106111119Simp MGETHDR(m, M_DONTWAIT, MT_HEADER); 1107105775Smaxim if (m == 0) 110899475Sluigi return; 110999475Sluigi m->m_pkthdr.rcvif = (struct ifnet *)0; 111099475Sluigi m->m_pkthdr.len = m->m_len = sizeof(struct ip) + sizeof(struct tcphdr); 111199475Sluigi m->m_data += max_linkhdr; 111299475Sluigi 1113100004Sluigi ip = mtod(m, struct ip *); 1114100004Sluigi bzero(ip, m->m_len); 1115100004Sluigi tcp = (struct tcphdr *)(ip + 1); /* no IP options */ 111699475Sluigi ip->ip_p = IPPROTO_TCP; 1117100004Sluigi tcp->th_off = 5; 1118100004Sluigi /* 1119100004Sluigi * Assume we are sending a RST (or a keepalive in the reverse 1120100004Sluigi * direction), swap src and destination addresses and ports. 1121100004Sluigi */ 1122100004Sluigi ip->ip_src.s_addr = htonl(id->dst_ip); 1123100004Sluigi ip->ip_dst.s_addr = htonl(id->src_ip); 1124100004Sluigi tcp->th_sport = htons(id->dst_port); 1125100004Sluigi tcp->th_dport = htons(id->src_port); 1126100004Sluigi if (flags & TH_RST) { /* we are sending a RST */ 1127100004Sluigi if (flags & TH_ACK) { 1128100004Sluigi tcp->th_seq = htonl(ack); 1129100004Sluigi tcp->th_ack = htonl(0); 1130100004Sluigi tcp->th_flags = TH_RST; 1131100004Sluigi } else { 1132100004Sluigi if (flags & TH_SYN) 1133100004Sluigi seq++; 1134100004Sluigi tcp->th_seq = htonl(0); 1135100004Sluigi tcp->th_ack = htonl(seq); 1136100004Sluigi tcp->th_flags = TH_RST | TH_ACK; 1137100004Sluigi } 113899475Sluigi } else { 1139100004Sluigi /* 1140100004Sluigi * We are sending a keepalive. flags & TH_SYN determines 1141100004Sluigi * the direction, forward if set, reverse if clear. 1142100004Sluigi * NOTE: seq and ack are always assumed to be correct 1143100004Sluigi * as set by the caller. This may be confusing... 1144100004Sluigi */ 1145100004Sluigi if (flags & TH_SYN) { 1146100004Sluigi /* 1147100004Sluigi * we have to rewrite the correct addresses! 1148100004Sluigi */ 1149100004Sluigi ip->ip_dst.s_addr = htonl(id->dst_ip); 1150100004Sluigi ip->ip_src.s_addr = htonl(id->src_ip); 1151100004Sluigi tcp->th_dport = htons(id->dst_port); 1152100004Sluigi tcp->th_sport = htons(id->src_port); 1153100004Sluigi } 1154100004Sluigi tcp->th_seq = htonl(seq); 1155100004Sluigi tcp->th_ack = htonl(ack); 1156100004Sluigi tcp->th_flags = TH_ACK; 115799475Sluigi } 1158100004Sluigi /* 1159100004Sluigi * set ip_len to the payload size so we can compute 1160100004Sluigi * the tcp checksum on the pseudoheader 1161100004Sluigi * XXX check this, could save a couple of words ? 1162100004Sluigi */ 1163100004Sluigi ip->ip_len = htons(sizeof(struct tcphdr)); 116499475Sluigi tcp->th_sum = in_cksum(m, m->m_pkthdr.len); 1165100004Sluigi /* 1166100004Sluigi * now fill fields left out earlier 1167100004Sluigi */ 116899475Sluigi ip->ip_ttl = ip_defttl; 116999475Sluigi ip->ip_len = m->m_pkthdr.len; 117099475Sluigi bzero (&sro, sizeof (sro)); 117199475Sluigi ip_rtaddr(ip->ip_dst, &sro); 1172101978Sluigi m->m_flags |= M_SKIP_FIREWALL; 1173105194Ssam ip_output(m, NULL, &sro, 0, NULL, NULL); 117499475Sluigi if (sro.ro_rt) 117599475Sluigi RTFREE(sro.ro_rt); 117699475Sluigi} 117799475Sluigi 117898943Sluigi/* 117998943Sluigi * sends a reject message, consuming the mbuf passed as an argument. 118098943Sluigi */ 118198943Sluigistatic void 118299475Sluigisend_reject(struct ip_fw_args *args, int code, int offset, int ip_len) 118398943Sluigi{ 1184101843Sphk 1185108327Siedowse if (code != ICMP_REJECT_RST) { /* Send an ICMP unreach */ 1186108327Siedowse /* We need the IP header in host order for icmp_error(). */ 1187108327Siedowse if (args->eh != NULL) { 1188108327Siedowse struct ip *ip = mtod(args->m, struct ip *); 1189108327Siedowse ip->ip_len = ntohs(ip->ip_len); 1190108327Siedowse ip->ip_off = ntohs(ip->ip_off); 1191108327Siedowse } 119299475Sluigi icmp_error(args->m, ICMP_UNREACH, code, 0L, 0); 1193108327Siedowse } else if (offset == 0 && args->f_id.proto == IPPROTO_TCP) { 119499475Sluigi struct tcphdr *const tcp = 119599475Sluigi L3HDR(struct tcphdr, mtod(args->m, struct ip *)); 119699475Sluigi if ( (tcp->th_flags & TH_RST) == 0) 1197100004Sluigi send_pkt(&(args->f_id), ntohl(tcp->th_seq), 1198100004Sluigi ntohl(tcp->th_ack), 1199100004Sluigi tcp->th_flags | TH_RST); 120099475Sluigi m_freem(args->m); 120199475Sluigi } else 120299475Sluigi m_freem(args->m); 120399475Sluigi args->m = NULL; 120498943Sluigi} 120598943Sluigi 120698943Sluigi/** 120798943Sluigi * 120898943Sluigi * Given an ip_fw *, lookup_next_rule will return a pointer 120998943Sluigi * to the next rule, which can be either the jump 121098943Sluigi * target (for skipto instructions) or the next one in the list (in 121198943Sluigi * all other cases including a missing jump target). 121298943Sluigi * The result is also written in the "next_rule" field of the rule. 121398943Sluigi * Backward jumps are not allowed, so start looking from the next 121498943Sluigi * rule... 121598943Sluigi * 121698943Sluigi * This never returns NULL -- in case we do not have an exact match, 121798943Sluigi * the next rule is returned. When the ruleset is changed, 121898943Sluigi * pointers are flushed so we are always correct. 1219105775Smaxim */ 122098943Sluigi 122198943Sluigistatic struct ip_fw * 122298943Sluigilookup_next_rule(struct ip_fw *me) 122398943Sluigi{ 122498943Sluigi struct ip_fw *rule = NULL; 122598943Sluigi ipfw_insn *cmd; 122698943Sluigi 122798943Sluigi /* look for action, in case it is a skipto */ 122898943Sluigi cmd = ACTION_PTR(me); 1229109566Smaxim if (cmd->opcode == O_LOG) 1230109566Smaxim cmd += F_LEN(cmd); 123198943Sluigi if ( cmd->opcode == O_SKIPTO ) 123298943Sluigi for (rule = me->next; rule ; rule = rule->next) 123398943Sluigi if (rule->rulenum >= cmd->arg1) 123498943Sluigi break; 123598943Sluigi if (rule == NULL) /* failure or not a skipto */ 123698943Sluigi rule = me->next; 123798943Sluigi me->next_rule = rule; 123898943Sluigi return rule; 123998943Sluigi} 124098943Sluigi 124198943Sluigi/* 124298943Sluigi * The main check routine for the firewall. 124398943Sluigi * 124498943Sluigi * All arguments are in args so we can modify them and return them 124598943Sluigi * back to the caller. 124698943Sluigi * 124798943Sluigi * Parameters: 124898943Sluigi * 124998943Sluigi * args->m (in/out) The packet; we set to NULL when/if we nuke it. 125098943Sluigi * Starts with the IP header. 125198943Sluigi * args->eh (in) Mac header if present, or NULL for layer3 packet. 125298943Sluigi * args->oif Outgoing interface, or NULL if packet is incoming. 125398943Sluigi * The incoming interface is in the mbuf. (in) 125498943Sluigi * args->divert_rule (in/out) 125598943Sluigi * Skip up to the first rule past this rule number; 125698943Sluigi * upon return, non-zero port number for divert or tee. 125798943Sluigi * 125898943Sluigi * args->rule Pointer to the last matching rule (in/out) 125998943Sluigi * args->next_hop Socket we are forwarding to (out). 126098943Sluigi * args->f_id Addresses grabbed from the packet (out) 126198943Sluigi * 126298943Sluigi * Return value: 126398943Sluigi * 126498943Sluigi * IP_FW_PORT_DENY_FLAG the packet must be dropped. 126598943Sluigi * 0 The packet is to be accepted and routed normally OR 126698943Sluigi * the packet was denied/rejected and has been dropped; 126798943Sluigi * in the latter case, *m is equal to NULL upon return. 126898943Sluigi * port Divert the packet to port, with these caveats: 126998943Sluigi * 127098943Sluigi * - If IP_FW_PORT_TEE_FLAG is set, tee the packet instead 127198943Sluigi * of diverting it (ie, 'ipfw tee'). 127298943Sluigi * 127398943Sluigi * - If IP_FW_PORT_DYNT_FLAG is set, interpret the lower 127498943Sluigi * 16 bits as a dummynet pipe number instead of diverting 127598943Sluigi */ 127698943Sluigi 1277105775Smaximstatic int 127898943Sluigiipfw_chk(struct ip_fw_args *args) 127998943Sluigi{ 128098943Sluigi /* 128198943Sluigi * Local variables hold state during the processing of a packet. 128298943Sluigi * 128398943Sluigi * IMPORTANT NOTE: to speed up the processing of rules, there 128498943Sluigi * are some assumption on the values of the variables, which 128598943Sluigi * are documented here. Should you change them, please check 128698943Sluigi * the implementation of the various instructions to make sure 128798943Sluigi * that they still work. 1288101978Sluigi * 128998943Sluigi * args->eh The MAC header. It is non-null for a layer2 129098943Sluigi * packet, it is NULL for a layer-3 packet. 129198943Sluigi * 129298943Sluigi * m | args->m Pointer to the mbuf, as received from the caller. 129398943Sluigi * It may change if ipfw_chk() does an m_pullup, or if it 129498943Sluigi * consumes the packet because it calls send_reject(). 129598943Sluigi * XXX This has to change, so that ipfw_chk() never modifies 129698943Sluigi * or consumes the buffer. 129798943Sluigi * ip is simply an alias of the value of m, and it is kept 129898943Sluigi * in sync with it (the packet is supposed to start with 129998943Sluigi * the ip header). 130098943Sluigi */ 130198943Sluigi struct mbuf *m = args->m; 130298943Sluigi struct ip *ip = mtod(m, struct ip *); 130398943Sluigi 130498943Sluigi /* 130598943Sluigi * oif | args->oif If NULL, ipfw_chk has been called on the 130698943Sluigi * inbound path (ether_input, bdg_forward, ip_input). 130798943Sluigi * If non-NULL, ipfw_chk has been called on the outbound path 130898943Sluigi * (ether_output, ip_output). 130998943Sluigi */ 131098943Sluigi struct ifnet *oif = args->oif; 131198943Sluigi 131298943Sluigi struct ip_fw *f = NULL; /* matching rule */ 131398943Sluigi int retval = 0; 131498943Sluigi 131598943Sluigi /* 131698943Sluigi * hlen The length of the IPv4 header. 131798943Sluigi * hlen >0 means we have an IPv4 packet. 131898943Sluigi */ 131998943Sluigi u_int hlen = 0; /* hlen >0 means we have an IP pkt */ 132098943Sluigi 132198943Sluigi /* 132298943Sluigi * offset The offset of a fragment. offset != 0 means that 132398943Sluigi * we have a fragment at this offset of an IPv4 packet. 132498943Sluigi * offset == 0 means that (if this is an IPv4 packet) 132598943Sluigi * this is the first or only fragment. 132698943Sluigi */ 132798943Sluigi u_short offset = 0; 132898943Sluigi 132998943Sluigi /* 133098943Sluigi * Local copies of addresses. They are only valid if we have 133198943Sluigi * an IP packet. 133298943Sluigi * 133398943Sluigi * proto The protocol. Set to 0 for non-ip packets, 133498943Sluigi * or to the protocol read from the packet otherwise. 133598943Sluigi * proto != 0 means that we have an IPv4 packet. 133698943Sluigi * 133798943Sluigi * src_port, dst_port port numbers, in HOST format. Only 133898943Sluigi * valid for TCP and UDP packets. 133998943Sluigi * 134098943Sluigi * src_ip, dst_ip ip addresses, in NETWORK format. 134198943Sluigi * Only valid for IPv4 packets. 134298943Sluigi */ 134398943Sluigi u_int8_t proto; 134498943Sluigi u_int16_t src_port = 0, dst_port = 0; /* NOTE: host format */ 134598943Sluigi struct in_addr src_ip, dst_ip; /* NOTE: network format */ 134698943Sluigi u_int16_t ip_len=0; 1347115750Skbyanc int pktlen; 134898943Sluigi int dyn_dir = MATCH_UNKNOWN; 134998943Sluigi ipfw_dyn_rule *q = NULL; 135098943Sluigi 1351101978Sluigi if (m->m_flags & M_SKIP_FIREWALL) 1352101978Sluigi return 0; /* accept */ 135398943Sluigi /* 135498943Sluigi * dyn_dir = MATCH_UNKNOWN when rules unchecked, 135598943Sluigi * MATCH_NONE when checked and not matched (q = NULL), 135698943Sluigi * MATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL) 135798943Sluigi */ 135898943Sluigi 1359115750Skbyanc pktlen = m->m_pkthdr.len; 136098943Sluigi if (args->eh == NULL || /* layer 3 packet */ 136198943Sluigi ( m->m_pkthdr.len >= sizeof(struct ip) && 136298943Sluigi ntohs(args->eh->ether_type) == ETHERTYPE_IP)) 136398943Sluigi hlen = ip->ip_hl << 2; 136498943Sluigi 136598943Sluigi /* 136698943Sluigi * Collect parameters into local variables for faster matching. 136798943Sluigi */ 136898943Sluigi if (hlen == 0) { /* do not grab addresses for non-ip pkts */ 136998943Sluigi proto = args->f_id.proto = 0; /* mark f_id invalid */ 137098943Sluigi goto after_ip_checks; 137198943Sluigi } 137298943Sluigi 137398943Sluigi proto = args->f_id.proto = ip->ip_p; 137498943Sluigi src_ip = ip->ip_src; 137598943Sluigi dst_ip = ip->ip_dst; 137698943Sluigi if (args->eh != NULL) { /* layer 2 packets are as on the wire */ 137798943Sluigi offset = ntohs(ip->ip_off) & IP_OFFMASK; 137898943Sluigi ip_len = ntohs(ip->ip_len); 137998943Sluigi } else { 138098943Sluigi offset = ip->ip_off & IP_OFFMASK; 138198943Sluigi ip_len = ip->ip_len; 138298943Sluigi } 1383115750Skbyanc pktlen = ip_len < pktlen ? ip_len : pktlen; 138498943Sluigi 138598943Sluigi#define PULLUP_TO(len) \ 138698943Sluigi do { \ 138798943Sluigi if ((m)->m_len < (len)) { \ 138898943Sluigi args->m = m = m_pullup(m, (len)); \ 138998943Sluigi if (m == 0) \ 139098943Sluigi goto pullup_failed; \ 139198943Sluigi ip = mtod(m, struct ip *); \ 139298943Sluigi } \ 139398943Sluigi } while (0) 139498943Sluigi 139598943Sluigi if (offset == 0) { 139698943Sluigi switch (proto) { 139798943Sluigi case IPPROTO_TCP: 139898943Sluigi { 139998943Sluigi struct tcphdr *tcp; 140098943Sluigi 140198943Sluigi PULLUP_TO(hlen + sizeof(struct tcphdr)); 140298943Sluigi tcp = L3HDR(struct tcphdr, ip); 140398943Sluigi dst_port = tcp->th_dport; 140498943Sluigi src_port = tcp->th_sport; 140598943Sluigi args->f_id.flags = tcp->th_flags; 140698943Sluigi } 140798943Sluigi break; 140898943Sluigi 140998943Sluigi case IPPROTO_UDP: 141098943Sluigi { 141198943Sluigi struct udphdr *udp; 141298943Sluigi 141398943Sluigi PULLUP_TO(hlen + sizeof(struct udphdr)); 141498943Sluigi udp = L3HDR(struct udphdr, ip); 141598943Sluigi dst_port = udp->uh_dport; 141698943Sluigi src_port = udp->uh_sport; 141798943Sluigi } 141898943Sluigi break; 141998943Sluigi 142098943Sluigi case IPPROTO_ICMP: 142198943Sluigi PULLUP_TO(hlen + 4); /* type, code and checksum. */ 142298943Sluigi args->f_id.flags = L3HDR(struct icmp, ip)->icmp_type; 142398943Sluigi break; 142498943Sluigi 142598943Sluigi default: 142698943Sluigi break; 142798943Sluigi } 142898943Sluigi#undef PULLUP_TO 142998943Sluigi } 143098943Sluigi 143198943Sluigi args->f_id.src_ip = ntohl(src_ip.s_addr); 143298943Sluigi args->f_id.dst_ip = ntohl(dst_ip.s_addr); 143398943Sluigi args->f_id.src_port = src_port = ntohs(src_port); 143498943Sluigi args->f_id.dst_port = dst_port = ntohs(dst_port); 143598943Sluigi 143698943Sluigiafter_ip_checks: 143798943Sluigi if (args->rule) { 143898943Sluigi /* 143998943Sluigi * Packet has already been tagged. Look for the next rule 144098943Sluigi * to restart processing. 144198943Sluigi * 144298943Sluigi * If fw_one_pass != 0 then just accept it. 144398943Sluigi * XXX should not happen here, but optimized out in 144498943Sluigi * the caller. 144598943Sluigi */ 144698943Sluigi if (fw_one_pass) 144798943Sluigi return 0; 144898943Sluigi 144998943Sluigi f = args->rule->next_rule; 145098943Sluigi if (f == NULL) 145198943Sluigi f = lookup_next_rule(args->rule); 145298943Sluigi } else { 145398943Sluigi /* 145498943Sluigi * Find the starting rule. It can be either the first 145598943Sluigi * one, or the one after divert_rule if asked so. 145698943Sluigi */ 145798943Sluigi int skipto = args->divert_rule; 145898943Sluigi 145998943Sluigi f = layer3_chain; 146098943Sluigi if (args->eh == NULL && skipto != 0) { 146198943Sluigi if (skipto >= IPFW_DEFAULT_RULE) 146298943Sluigi return(IP_FW_PORT_DENY_FLAG); /* invalid */ 146398943Sluigi while (f && f->rulenum <= skipto) 146498943Sluigi f = f->next; 146598943Sluigi if (f == NULL) /* drop packet */ 146698943Sluigi return(IP_FW_PORT_DENY_FLAG); 146798943Sluigi } 146898943Sluigi } 146998943Sluigi args->divert_rule = 0; /* reset to avoid confusion later */ 147098943Sluigi 147198943Sluigi /* 147298943Sluigi * Now scan the rules, and parse microinstructions for each rule. 147398943Sluigi */ 147498943Sluigi for (; f; f = f->next) { 147598943Sluigi int l, cmdlen; 147698943Sluigi ipfw_insn *cmd; 147798943Sluigi int skip_or; /* skip rest of OR block */ 147898943Sluigi 147998943Sluigiagain: 1480101628Sluigi if (set_disable & (1 << f->set) ) 1481101628Sluigi continue; 1482101628Sluigi 148398943Sluigi skip_or = 0; 148498943Sluigi for (l = f->cmd_len, cmd = f->cmd ; l > 0 ; 148598943Sluigi l -= cmdlen, cmd += cmdlen) { 148699622Sluigi int match; 148798943Sluigi 148898943Sluigi /* 148998943Sluigi * check_body is a jump target used when we find a 149098943Sluigi * CHECK_STATE, and need to jump to the body of 149198943Sluigi * the target rule. 149298943Sluigi */ 149398943Sluigi 149498943Sluigicheck_body: 149598943Sluigi cmdlen = F_LEN(cmd); 149698943Sluigi /* 149798943Sluigi * An OR block (insn_1 || .. || insn_n) has the 149898943Sluigi * F_OR bit set in all but the last instruction. 149998943Sluigi * The first match will set "skip_or", and cause 150098943Sluigi * the following instructions to be skipped until 150198943Sluigi * past the one with the F_OR bit clear. 150298943Sluigi */ 150398943Sluigi if (skip_or) { /* skip this instruction */ 150498943Sluigi if ((cmd->len & F_OR) == 0) 150598943Sluigi skip_or = 0; /* next one is good */ 150698943Sluigi continue; 150798943Sluigi } 150899622Sluigi match = 0; /* set to 1 if we succeed */ 150999622Sluigi 151098943Sluigi switch (cmd->opcode) { 151199622Sluigi /* 151299622Sluigi * The first set of opcodes compares the packet's 151399622Sluigi * fields with some pattern, setting 'match' if a 151499622Sluigi * match is found. At the end of the loop there is 151599622Sluigi * logic to deal with F_NOT and F_OR flags associated 151699622Sluigi * with the opcode. 151799622Sluigi */ 151898943Sluigi case O_NOP: 151999622Sluigi match = 1; 152099622Sluigi break; 152198943Sluigi 152298943Sluigi case O_FORWARD_MAC: 152398943Sluigi printf("ipfw: opcode %d unimplemented\n", 152498943Sluigi cmd->opcode); 152599622Sluigi break; 152698943Sluigi 152798943Sluigi case O_GID: 152898943Sluigi case O_UID: 152998943Sluigi /* 153098943Sluigi * We only check offset == 0 && proto != 0, 153198943Sluigi * as this ensures that we have an IPv4 153298943Sluigi * packet with the ports info. 153398943Sluigi */ 153498943Sluigi if (offset!=0) 153599622Sluigi break; 153698943Sluigi { 153798943Sluigi struct inpcbinfo *pi; 153898943Sluigi int wildcard; 153998943Sluigi struct inpcb *pcb; 154098943Sluigi 154198943Sluigi if (proto == IPPROTO_TCP) { 154298943Sluigi wildcard = 0; 154398943Sluigi pi = &tcbinfo; 154498943Sluigi } else if (proto == IPPROTO_UDP) { 154598943Sluigi wildcard = 1; 154698943Sluigi pi = &udbinfo; 154798943Sluigi } else 154899622Sluigi break; 154998943Sluigi 155098943Sluigi pcb = (oif) ? 155198943Sluigi in_pcblookup_hash(pi, 155298943Sluigi dst_ip, htons(dst_port), 155398943Sluigi src_ip, htons(src_port), 155498943Sluigi wildcard, oif) : 155598943Sluigi in_pcblookup_hash(pi, 155698943Sluigi src_ip, htons(src_port), 155798943Sluigi dst_ip, htons(dst_port), 155898943Sluigi wildcard, NULL); 155998943Sluigi 156098943Sluigi if (pcb == NULL || pcb->inp_socket == NULL) 156199622Sluigi break; 156299622Sluigi#if __FreeBSD_version < 500034 1563111037Smaxim#define socheckuid(a,b) ((a)->so_cred->cr_uid != (b)) 156499622Sluigi#endif 156598943Sluigi if (cmd->opcode == O_UID) { 156699622Sluigi match = 1567111037Smaxim !socheckuid(pcb->inp_socket, 156899622Sluigi (uid_t)((ipfw_insn_u32 *)cmd)->d[0]); 156998943Sluigi } else { 157099622Sluigi match = groupmember( 157198943Sluigi (uid_t)((ipfw_insn_u32 *)cmd)->d[0], 157299622Sluigi pcb->inp_socket->so_cred); 157398943Sluigi } 157498943Sluigi } 157599622Sluigi break; 157698943Sluigi 157798943Sluigi case O_RECV: 157899622Sluigi match = iface_match(m->m_pkthdr.rcvif, 157999622Sluigi (ipfw_insn_if *)cmd); 158099622Sluigi break; 158198943Sluigi 158298943Sluigi case O_XMIT: 158399622Sluigi match = iface_match(oif, (ipfw_insn_if *)cmd); 158499622Sluigi break; 158598943Sluigi 158698943Sluigi case O_VIA: 158799622Sluigi match = iface_match(oif ? oif : 158899622Sluigi m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd); 158999622Sluigi break; 159098943Sluigi 159198943Sluigi case O_MACADDR2: 159298943Sluigi if (args->eh != NULL) { /* have MAC header */ 159398943Sluigi u_int32_t *want = (u_int32_t *) 159498943Sluigi ((ipfw_insn_mac *)cmd)->addr; 159598943Sluigi u_int32_t *mask = (u_int32_t *) 159698943Sluigi ((ipfw_insn_mac *)cmd)->mask; 159798943Sluigi u_int32_t *hdr = (u_int32_t *)args->eh; 159898943Sluigi 159999622Sluigi match = 160099622Sluigi ( want[0] == (hdr[0] & mask[0]) && 160199622Sluigi want[1] == (hdr[1] & mask[1]) && 160299622Sluigi want[2] == (hdr[2] & mask[2]) ); 160398943Sluigi } 160499622Sluigi break; 160598943Sluigi 160698943Sluigi case O_MAC_TYPE: 160798943Sluigi if (args->eh != NULL) { 160899622Sluigi u_int16_t t = 160998943Sluigi ntohs(args->eh->ether_type); 161098943Sluigi u_int16_t *p = 161198943Sluigi ((ipfw_insn_u16 *)cmd)->ports; 161298943Sluigi int i; 161398943Sluigi 161499622Sluigi for (i = cmdlen - 1; !match && i>0; 161599622Sluigi i--, p += 2) 161699622Sluigi match = (t>=p[0] && t<=p[1]); 161798943Sluigi } 161899622Sluigi break; 161998943Sluigi 162098943Sluigi case O_FRAG: 162199622Sluigi match = (hlen > 0 && offset != 0); 162299622Sluigi break; 162398943Sluigi 162498943Sluigi case O_IN: /* "out" is "not in" */ 162599622Sluigi match = (oif == NULL); 162699622Sluigi break; 162798943Sluigi 162898943Sluigi case O_LAYER2: 162999622Sluigi match = (args->eh != NULL); 163099622Sluigi break; 163198943Sluigi 163298943Sluigi case O_PROTO: 163398943Sluigi /* 163498943Sluigi * We do not allow an arg of 0 so the 163598943Sluigi * check of "proto" only suffices. 163698943Sluigi */ 163799622Sluigi match = (proto == cmd->arg1); 163899622Sluigi break; 163998943Sluigi 164098943Sluigi case O_IP_SRC: 164199622Sluigi match = (hlen > 0 && 164298943Sluigi ((ipfw_insn_ip *)cmd)->addr.s_addr == 164399622Sluigi src_ip.s_addr); 164499622Sluigi break; 1645105775Smaxim 164698943Sluigi case O_IP_SRC_MASK: 164799622Sluigi match = (hlen > 0 && 164898943Sluigi ((ipfw_insn_ip *)cmd)->addr.s_addr == 164999622Sluigi (src_ip.s_addr & 165099622Sluigi ((ipfw_insn_ip *)cmd)->mask.s_addr)); 165199622Sluigi break; 165298943Sluigi 165398943Sluigi case O_IP_SRC_ME: 165499622Sluigi if (hlen > 0) { 165599622Sluigi struct ifnet *tif; 165698943Sluigi 165799622Sluigi INADDR_TO_IFP(src_ip, tif); 165899622Sluigi match = (tif != NULL); 165999622Sluigi } 166099622Sluigi break; 1661105775Smaxim 166298943Sluigi case O_IP_DST_SET: 166398943Sluigi case O_IP_SRC_SET: 166499622Sluigi if (hlen > 0) { 166599622Sluigi u_int32_t *d = (u_int32_t *)(cmd+1); 166699622Sluigi u_int32_t addr = 166799622Sluigi cmd->opcode == O_IP_DST_SET ? 1668105886Sluigi args->f_id.dst_ip : 1669105886Sluigi args->f_id.src_ip; 167098943Sluigi 167199622Sluigi if (addr < d[0]) 167299622Sluigi break; 167399622Sluigi addr -= d[0]; /* subtract base */ 167499622Sluigi match = (addr < cmd->arg1) && 167599622Sluigi ( d[ 1 + (addr>>5)] & 167699622Sluigi (1<<(addr & 0x1f)) ); 167799622Sluigi } 167899622Sluigi break; 167998943Sluigi 168098943Sluigi case O_IP_DST: 168199622Sluigi match = (hlen > 0 && 168298943Sluigi ((ipfw_insn_ip *)cmd)->addr.s_addr == 168399622Sluigi dst_ip.s_addr); 168499622Sluigi break; 168598943Sluigi 168698943Sluigi case O_IP_DST_MASK: 168799622Sluigi match = (hlen > 0) && 168899622Sluigi (((ipfw_insn_ip *)cmd)->addr.s_addr == 168999622Sluigi (dst_ip.s_addr & 169099622Sluigi ((ipfw_insn_ip *)cmd)->mask.s_addr)); 169199622Sluigi break; 169298943Sluigi 169398943Sluigi case O_IP_DST_ME: 169499622Sluigi if (hlen > 0) { 169599622Sluigi struct ifnet *tif; 169699622Sluigi 169799622Sluigi INADDR_TO_IFP(dst_ip, tif); 169899622Sluigi match = (tif != NULL); 169999622Sluigi } 170099622Sluigi break; 1701105775Smaxim 170298943Sluigi case O_IP_SRCPORT: 170398943Sluigi case O_IP_DSTPORT: 170498943Sluigi /* 170598943Sluigi * offset == 0 && proto != 0 is enough 170698943Sluigi * to guarantee that we have an IPv4 170798943Sluigi * packet with port info. 170898943Sluigi */ 170999622Sluigi if ((proto==IPPROTO_UDP || proto==IPPROTO_TCP) 171099622Sluigi && offset == 0) { 171199622Sluigi u_int16_t x = 171298943Sluigi (cmd->opcode == O_IP_SRCPORT) ? 171399622Sluigi src_port : dst_port ; 171498943Sluigi u_int16_t *p = 171598943Sluigi ((ipfw_insn_u16 *)cmd)->ports; 171698943Sluigi int i; 171798943Sluigi 171899622Sluigi for (i = cmdlen - 1; !match && i>0; 171999622Sluigi i--, p += 2) 172099622Sluigi match = (x>=p[0] && x<=p[1]); 172198943Sluigi } 172299622Sluigi break; 172398943Sluigi 172498943Sluigi case O_ICMPTYPE: 172599622Sluigi match = (offset == 0 && proto==IPPROTO_ICMP && 172699622Sluigi icmptype_match(ip, (ipfw_insn_u32 *)cmd) ); 172799622Sluigi break; 172898943Sluigi 172998943Sluigi case O_IPOPT: 173099622Sluigi match = (hlen > 0 && ipopts_match(ip, cmd) ); 173199622Sluigi break; 173298943Sluigi 173398943Sluigi case O_IPVER: 173499622Sluigi match = (hlen > 0 && cmd->arg1 == ip->ip_v); 173599622Sluigi break; 173698943Sluigi 1737116690Sluigi case O_IPID: 1738116690Sluigi case O_IPLEN: 173998943Sluigi case O_IPTTL: 1740116690Sluigi if (hlen > 0) { /* only for IP packets */ 1741116690Sluigi uint16_t x; 1742116690Sluigi uint16_t *p; 1743116690Sluigi int i; 174498943Sluigi 1745116690Sluigi if (cmd->opcode == O_IPLEN) 1746116690Sluigi x = ip_len; 1747116690Sluigi else if (cmd->opcode == O_IPTTL) 1748116690Sluigi x = ip->ip_ttl; 1749116690Sluigi else /* must be IPID */ 1750116690Sluigi x = ntohs(ip->ip_id); 1751116690Sluigi if (cmdlen == 1) { 1752116690Sluigi match = (cmd->arg1 == x); 1753116690Sluigi break; 1754116690Sluigi } 1755116690Sluigi /* otherwise we have ranges */ 1756116690Sluigi p = ((ipfw_insn_u16 *)cmd)->ports; 1757116690Sluigi i = cmdlen - 1; 1758116690Sluigi for (; !match && i>0; i--, p += 2) 1759116690Sluigi match = (x >= p[0] && x <= p[1]); 1760116690Sluigi } 176199622Sluigi break; 176298943Sluigi 176399475Sluigi case O_IPPRECEDENCE: 176499622Sluigi match = (hlen > 0 && 176599622Sluigi (cmd->arg1 == (ip->ip_tos & 0xe0)) ); 176699622Sluigi break; 176799475Sluigi 176898943Sluigi case O_IPTOS: 176999622Sluigi match = (hlen > 0 && 177099622Sluigi flags_match(cmd, ip->ip_tos)); 177199622Sluigi break; 177298943Sluigi 177398943Sluigi case O_TCPFLAGS: 177499622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 177599622Sluigi flags_match(cmd, 177699622Sluigi L3HDR(struct tcphdr,ip)->th_flags)); 177799622Sluigi break; 177898943Sluigi 177998943Sluigi case O_TCPOPTS: 178099622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 178199622Sluigi tcpopts_match(ip, cmd)); 178299622Sluigi break; 178398943Sluigi 178498943Sluigi case O_TCPSEQ: 178599622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 178699622Sluigi ((ipfw_insn_u32 *)cmd)->d[0] == 178799622Sluigi L3HDR(struct tcphdr,ip)->th_seq); 178899622Sluigi break; 178998943Sluigi 179098943Sluigi case O_TCPACK: 179199622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 179299622Sluigi ((ipfw_insn_u32 *)cmd)->d[0] == 179399622Sluigi L3HDR(struct tcphdr,ip)->th_ack); 179499622Sluigi break; 179598943Sluigi 179698943Sluigi case O_TCPWIN: 179799622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 179899622Sluigi cmd->arg1 == 179999622Sluigi L3HDR(struct tcphdr,ip)->th_win); 180099622Sluigi break; 180198943Sluigi 180298943Sluigi case O_ESTAB: 180398943Sluigi /* reject packets which have SYN only */ 180499622Sluigi /* XXX should i also check for TH_ACK ? */ 180599622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 180699622Sluigi (L3HDR(struct tcphdr,ip)->th_flags & 180799622Sluigi (TH_RST | TH_ACK | TH_SYN)) != TH_SYN); 180899622Sluigi break; 180998943Sluigi 181098943Sluigi case O_LOG: 1811100589Sluigi if (fw_verbose) 1812100589Sluigi ipfw_log(f, hlen, args->eh, m, oif); 181399622Sluigi match = 1; 181499622Sluigi break; 181598943Sluigi 181699475Sluigi case O_PROB: 181799622Sluigi match = (random()<((ipfw_insn_u32 *)cmd)->d[0]); 181899622Sluigi break; 181998943Sluigi 1820112250Scjc case O_VERREVPATH: 1821112250Scjc /* Outgoing packets automatically pass/match */ 1822112250Scjc match = ((oif != NULL) || 1823116763Sluigi (m->m_pkthdr.rcvif == NULL) || 1824112250Scjc verify_rev_path(src_ip, m->m_pkthdr.rcvif)); 1825112250Scjc break; 1826112250Scjc 1827117241Sluigi case O_IPSEC: 1828117241Sluigi#ifdef FAST_IPSEC 1829117241Sluigi match = (m_tag_find(m, 1830117241Sluigi PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL); 1831117241Sluigi#endif 1832117241Sluigi#ifdef IPSEC 1833117241Sluigi match = (ipsec_gethist(m, NULL) != NULL); 1834117241Sluigi#endif 1835117241Sluigi /* otherwise no match */ 1836117241Sluigi break; 1837117241Sluigi 183899622Sluigi /* 183999622Sluigi * The second set of opcodes represents 'actions', 184099622Sluigi * i.e. the terminal part of a rule once the packet 184199622Sluigi * matches all previous patterns. 184299622Sluigi * Typically there is only one action for each rule, 184399622Sluigi * and the opcode is stored at the end of the rule 184499622Sluigi * (but there are exceptions -- see below). 184599622Sluigi * 184699622Sluigi * In general, here we set retval and terminate the 184799622Sluigi * outer loop (would be a 'break 3' in some language, 184899622Sluigi * but we need to do a 'goto done'). 184999622Sluigi * 185099622Sluigi * Exceptions: 185199622Sluigi * O_COUNT and O_SKIPTO actions: 185299622Sluigi * instead of terminating, we jump to the next rule 185399622Sluigi * ('goto next_rule', equivalent to a 'break 2'), 185499622Sluigi * or to the SKIPTO target ('goto again' after 185599622Sluigi * having set f, cmd and l), respectively. 185699622Sluigi * 185799622Sluigi * O_LIMIT and O_KEEP_STATE: these opcodes are 185899622Sluigi * not real 'actions', and are stored right 185999622Sluigi * before the 'action' part of the rule. 186099622Sluigi * These opcodes try to install an entry in the 186199622Sluigi * state tables; if successful, we continue with 186299622Sluigi * the next opcode (match=1; break;), otherwise 186399622Sluigi * the packet * must be dropped 186499622Sluigi * ('goto done' after setting retval); 186599622Sluigi * 186699622Sluigi * O_PROBE_STATE and O_CHECK_STATE: these opcodes 186799622Sluigi * cause a lookup of the state table, and a jump 186899622Sluigi * to the 'action' part of the parent rule 186999622Sluigi * ('goto check_body') if an entry is found, or 187099622Sluigi * (CHECK_STATE only) a jump to the next rule if 187199622Sluigi * the entry is not found ('goto next_rule'). 187299622Sluigi * The result of the lookup is cached to make 187399622Sluigi * further instances of these opcodes are 187499622Sluigi * effectively NOPs. 187599622Sluigi */ 187698943Sluigi case O_LIMIT: 187798943Sluigi case O_KEEP_STATE: 187898943Sluigi if (install_state(f, 187999622Sluigi (ipfw_insn_limit *)cmd, args)) { 188099622Sluigi retval = IP_FW_PORT_DENY_FLAG; 188199622Sluigi goto done; /* error/limit violation */ 188299622Sluigi } 188399622Sluigi match = 1; 188499622Sluigi break; 188598943Sluigi 188698943Sluigi case O_PROBE_STATE: 188798943Sluigi case O_CHECK_STATE: 188898943Sluigi /* 188998943Sluigi * dynamic rules are checked at the first 189099622Sluigi * keep-state or check-state occurrence, 189199622Sluigi * with the result being stored in dyn_dir. 189299622Sluigi * The compiler introduces a PROBE_STATE 189398943Sluigi * instruction for us when we have a 189499622Sluigi * KEEP_STATE (because PROBE_STATE needs 189598943Sluigi * to be run first). 189698943Sluigi */ 189799622Sluigi if (dyn_dir == MATCH_UNKNOWN && 189899622Sluigi (q = lookup_dyn_rule(&args->f_id, 1899100004Sluigi &dyn_dir, proto == IPPROTO_TCP ? 1900100004Sluigi L3HDR(struct tcphdr, ip) : NULL)) 1901100004Sluigi != NULL) { 190299622Sluigi /* 190399622Sluigi * Found dynamic entry, update stats 190499622Sluigi * and jump to the 'action' part of 190599622Sluigi * the parent rule. 190699622Sluigi */ 190799622Sluigi q->pcnt++; 1908115750Skbyanc q->bcnt += pktlen; 190999622Sluigi f = q->rule; 191099622Sluigi cmd = ACTION_PTR(f); 191199622Sluigi l = f->cmd_len - f->act_ofs; 191299622Sluigi goto check_body; 191398943Sluigi } 191499622Sluigi /* 191599622Sluigi * Dynamic entry not found. If CHECK_STATE, 191699622Sluigi * skip to next rule, if PROBE_STATE just 191799622Sluigi * ignore and continue with next opcode. 191899622Sluigi */ 191998943Sluigi if (cmd->opcode == O_CHECK_STATE) 192098943Sluigi goto next_rule; 192199622Sluigi match = 1; 192299622Sluigi break; 192398943Sluigi 192498943Sluigi case O_ACCEPT: 192598943Sluigi retval = 0; /* accept */ 192699622Sluigi goto done; 192798943Sluigi 192898943Sluigi case O_PIPE: 192998943Sluigi case O_QUEUE: 193098943Sluigi args->rule = f; /* report matching rule */ 193198943Sluigi retval = cmd->arg1 | IP_FW_PORT_DYNT_FLAG; 193299622Sluigi goto done; 1933105775Smaxim 193498943Sluigi case O_DIVERT: 193598943Sluigi case O_TEE: 193698943Sluigi if (args->eh) /* not on layer 2 */ 193799622Sluigi break; 193898943Sluigi args->divert_rule = f->rulenum; 193999622Sluigi retval = (cmd->opcode == O_DIVERT) ? 194099622Sluigi cmd->arg1 : 194199622Sluigi cmd->arg1 | IP_FW_PORT_TEE_FLAG; 194299622Sluigi goto done; 194398943Sluigi 194498943Sluigi case O_COUNT: 194598943Sluigi case O_SKIPTO: 194698943Sluigi f->pcnt++; /* update stats */ 1947115750Skbyanc f->bcnt += pktlen; 194898943Sluigi f->timestamp = time_second; 194998943Sluigi if (cmd->opcode == O_COUNT) 195098943Sluigi goto next_rule; 195198943Sluigi /* handle skipto */ 195298943Sluigi if (f->next_rule == NULL) 195398943Sluigi lookup_next_rule(f); 195498943Sluigi f = f->next_rule; 195598943Sluigi goto again; 195698943Sluigi 195798943Sluigi case O_REJECT: 195898943Sluigi /* 195998943Sluigi * Drop the packet and send a reject notice 196098943Sluigi * if the packet is not ICMP (or is an ICMP 196198943Sluigi * query), and it is not multicast/broadcast. 196298943Sluigi */ 196398943Sluigi if (hlen > 0 && 196498943Sluigi (proto != IPPROTO_ICMP || 196599475Sluigi is_icmp_query(ip)) && 196698943Sluigi !(m->m_flags & (M_BCAST|M_MCAST)) && 196798943Sluigi !IN_MULTICAST(dst_ip.s_addr)) { 196899475Sluigi send_reject(args, cmd->arg1, 196999475Sluigi offset,ip_len); 197099475Sluigi m = args->m; 197198943Sluigi } 197299622Sluigi /* FALLTHROUGH */ 197399622Sluigi case O_DENY: 197499622Sluigi retval = IP_FW_PORT_DENY_FLAG; 197599622Sluigi goto done; 197698943Sluigi 197798943Sluigi case O_FORWARD_IP: 197898943Sluigi if (args->eh) /* not valid on layer2 pkts */ 197999622Sluigi break; 198098943Sluigi if (!q || dyn_dir == MATCH_FORWARD) 198198943Sluigi args->next_hop = 198298943Sluigi &((ipfw_insn_sa *)cmd)->sa; 198398943Sluigi retval = 0; 198499622Sluigi goto done; 198598943Sluigi 198698943Sluigi default: 198798943Sluigi panic("-- unknown opcode %d\n", cmd->opcode); 198899622Sluigi } /* end of switch() on opcodes */ 198998943Sluigi 199099622Sluigi if (cmd->len & F_NOT) 199199622Sluigi match = !match; 199298943Sluigi 199399622Sluigi if (match) { 199499622Sluigi if (cmd->len & F_OR) 199599622Sluigi skip_or = 1; 199699622Sluigi } else { 199799622Sluigi if (!(cmd->len & F_OR)) /* not an OR block, */ 199899622Sluigi break; /* try next rule */ 199998943Sluigi } 200098943Sluigi 200198943Sluigi } /* end of inner for, scan opcodes */ 200298943Sluigi 200398965Sdfrnext_rule:; /* try next rule */ 2004105775Smaxim 200598943Sluigi } /* end of outer for, scan rules */ 2006108258Smaxim printf("ipfw: ouch!, skip past end of rules, denying packet\n"); 2007101628Sluigi return(IP_FW_PORT_DENY_FLAG); 200898943Sluigi 200999622Sluigidone: 201098943Sluigi /* Update statistics */ 201198943Sluigi f->pcnt++; 2012115750Skbyanc f->bcnt += pktlen; 201398943Sluigi f->timestamp = time_second; 201498943Sluigi return retval; 201598943Sluigi 201698943Sluigipullup_failed: 201798943Sluigi if (fw_verbose) 2018108258Smaxim printf("ipfw: pullup failed\n"); 201998943Sluigi return(IP_FW_PORT_DENY_FLAG); 202098943Sluigi} 202198943Sluigi 202298943Sluigi/* 202398943Sluigi * When a rule is added/deleted, clear the next_rule pointers in all rules. 202498943Sluigi * These will be reconstructed on the fly as packets are matched. 202598943Sluigi * Must be called at splimp(). 202698943Sluigi */ 202798943Sluigistatic void 202898943Sluigiflush_rule_ptrs(void) 202998943Sluigi{ 203098943Sluigi struct ip_fw *rule; 203198943Sluigi 203298943Sluigi for (rule = layer3_chain; rule; rule = rule->next) 203398943Sluigi rule->next_rule = NULL; 203498943Sluigi} 203598943Sluigi 203698943Sluigi/* 203798943Sluigi * When pipes/queues are deleted, clear the "pipe_ptr" pointer to a given 203898943Sluigi * pipe/queue, or to all of them (match == NULL). 203998943Sluigi * Must be called at splimp(). 204098943Sluigi */ 204198943Sluigivoid 204298943Sluigiflush_pipe_ptrs(struct dn_flow_set *match) 204398943Sluigi{ 204498943Sluigi struct ip_fw *rule; 204598943Sluigi 204698943Sluigi for (rule = layer3_chain; rule; rule = rule->next) { 204798943Sluigi ipfw_insn_pipe *cmd = (ipfw_insn_pipe *)ACTION_PTR(rule); 2048105775Smaxim 204998943Sluigi if (cmd->o.opcode != O_PIPE && cmd->o.opcode != O_QUEUE) 205098943Sluigi continue; 2051115793Sticso /* 2052115793Sticso * XXX Use bcmp/bzero to handle pipe_ptr to overcome 2053115793Sticso * possible alignment problems on 64-bit architectures. 2054115793Sticso * This code is seldom used so we do not worry too 2055115793Sticso * much about efficiency. 2056115793Sticso */ 2057115793Sticso if (match == NULL || 2058115793Sticso !bcmp(&cmd->pipe_ptr, &match, sizeof(match)) ) 2059115793Sticso bzero(&cmd->pipe_ptr, sizeof(cmd->pipe_ptr)); 206098943Sluigi } 206198943Sluigi} 206298943Sluigi 206398943Sluigi/* 206498943Sluigi * Add a new rule to the list. Copy the rule into a malloc'ed area, then 206598943Sluigi * possibly create a rule number and add the rule to the list. 206698943Sluigi * Update the rule_number in the input struct so the caller knows it as well. 206798943Sluigi */ 206898943Sluigistatic int 206998943Sluigiadd_rule(struct ip_fw **head, struct ip_fw *input_rule) 207098943Sluigi{ 207198943Sluigi struct ip_fw *rule, *f, *prev; 207298943Sluigi int s; 207398943Sluigi int l = RULESIZE(input_rule); 207498943Sluigi 207598943Sluigi if (*head == NULL && input_rule->rulenum != IPFW_DEFAULT_RULE) 207698943Sluigi return (EINVAL); 207798943Sluigi 2078105440Smux rule = malloc(l, M_IPFW, M_NOWAIT | M_ZERO); 207998943Sluigi if (rule == NULL) 208098943Sluigi return (ENOSPC); 208198943Sluigi 208298943Sluigi bcopy(input_rule, rule, l); 208398943Sluigi 208498943Sluigi rule->next = NULL; 208598943Sluigi rule->next_rule = NULL; 208698943Sluigi 208798943Sluigi rule->pcnt = 0; 208898943Sluigi rule->bcnt = 0; 208998943Sluigi rule->timestamp = 0; 209098943Sluigi 209198943Sluigi s = splimp(); 209298943Sluigi 209398943Sluigi if (*head == NULL) { /* default rule */ 209498943Sluigi *head = rule; 209598943Sluigi goto done; 209698943Sluigi } 209798943Sluigi 209898943Sluigi /* 209998943Sluigi * If rulenum is 0, find highest numbered rule before the 210098943Sluigi * default rule, and add autoinc_step 210198943Sluigi */ 210298943Sluigi if (autoinc_step < 1) 210398943Sluigi autoinc_step = 1; 210498943Sluigi else if (autoinc_step > 1000) 210598943Sluigi autoinc_step = 1000; 210698943Sluigi if (rule->rulenum == 0) { 210798943Sluigi /* 210898943Sluigi * locate the highest numbered rule before default 210998943Sluigi */ 211098943Sluigi for (f = *head; f; f = f->next) { 211198943Sluigi if (f->rulenum == IPFW_DEFAULT_RULE) 211298943Sluigi break; 211398943Sluigi rule->rulenum = f->rulenum; 211498943Sluigi } 211598943Sluigi if (rule->rulenum < IPFW_DEFAULT_RULE - autoinc_step) 211698943Sluigi rule->rulenum += autoinc_step; 211798943Sluigi input_rule->rulenum = rule->rulenum; 211898943Sluigi } 211998943Sluigi 212098943Sluigi /* 212198943Sluigi * Now insert the new rule in the right place in the sorted list. 212298943Sluigi */ 212398943Sluigi for (prev = NULL, f = *head; f; prev = f, f = f->next) { 212498943Sluigi if (f->rulenum > rule->rulenum) { /* found the location */ 212598943Sluigi if (prev) { 212698943Sluigi rule->next = f; 212798943Sluigi prev->next = rule; 212898943Sluigi } else { /* head insert */ 212998943Sluigi rule->next = *head; 213098943Sluigi *head = rule; 213198943Sluigi } 213298943Sluigi break; 213398943Sluigi } 213498943Sluigi } 213598943Sluigi flush_rule_ptrs(); 213698943Sluigidone: 213798943Sluigi static_count++; 213898943Sluigi static_len += l; 213998943Sluigi splx(s); 2140108258Smaxim DEB(printf("ipfw: installed rule %d, static count now %d\n", 214198943Sluigi rule->rulenum, static_count);) 214298943Sluigi return (0); 214398943Sluigi} 214498943Sluigi 214598943Sluigi/** 214698943Sluigi * Free storage associated with a static rule (including derived 214798943Sluigi * dynamic rules). 214898943Sluigi * The caller is in charge of clearing rule pointers to avoid 214998943Sluigi * dangling pointers. 215098943Sluigi * @return a pointer to the next entry. 215198943Sluigi * Arguments are not checked, so they better be correct. 215298943Sluigi * Must be called at splimp(). 215398943Sluigi */ 215498943Sluigistatic struct ip_fw * 215598943Sluigidelete_rule(struct ip_fw **head, struct ip_fw *prev, struct ip_fw *rule) 215698943Sluigi{ 215798943Sluigi struct ip_fw *n; 215898943Sluigi int l = RULESIZE(rule); 215998943Sluigi 216098943Sluigi n = rule->next; 216198943Sluigi remove_dyn_rule(rule, NULL /* force removal */); 216298943Sluigi if (prev == NULL) 216398943Sluigi *head = n; 216498943Sluigi else 216598943Sluigi prev->next = n; 216698943Sluigi static_count--; 216798943Sluigi static_len -= l; 216898943Sluigi 216998943Sluigi if (DUMMYNET_LOADED) 217098943Sluigi ip_dn_ruledel_ptr(rule); 217198943Sluigi free(rule, M_IPFW); 217298943Sluigi return n; 217398943Sluigi} 217498943Sluigi 217598943Sluigi/* 217698943Sluigi * Deletes all rules from a chain (including the default rule 217798943Sluigi * if the second argument is set). 217898943Sluigi * Must be called at splimp(). 217998943Sluigi */ 218098943Sluigistatic void 218198943Sluigifree_chain(struct ip_fw **chain, int kill_default) 218298943Sluigi{ 218398943Sluigi struct ip_fw *rule; 218498943Sluigi 218598943Sluigi flush_rule_ptrs(); /* more efficient to do outside the loop */ 218698943Sluigi 218798943Sluigi while ( (rule = *chain) != NULL && 218898943Sluigi (kill_default || rule->rulenum != IPFW_DEFAULT_RULE) ) 218998943Sluigi delete_rule(chain, NULL, rule); 219098943Sluigi} 219198943Sluigi 219298943Sluigi/** 2193101628Sluigi * Remove all rules with given number, and also do set manipulation. 2194101628Sluigi * 2195101978Sluigi * The argument is an u_int32_t. The low 16 bit are the rule or set number, 2196101978Sluigi * the next 8 bits are the new set, the top 8 bits are the command: 2197105775Smaxim * 2198101978Sluigi * 0 delete rules with given number 2199101978Sluigi * 1 delete rules with given set number 2200101978Sluigi * 2 move rules with given number to new set 2201101978Sluigi * 3 move rules with given set number to new set 2202101978Sluigi * 4 swap sets with given numbers 220398943Sluigi */ 220498943Sluigistatic int 2205101628Sluigidel_entry(struct ip_fw **chain, u_int32_t arg) 220698943Sluigi{ 220798943Sluigi struct ip_fw *prev, *rule; 220898943Sluigi int s; 2209101978Sluigi u_int16_t rulenum; 2210101978Sluigi u_int8_t cmd, new_set; 221198943Sluigi 2212101628Sluigi rulenum = arg & 0xffff; 2213101978Sluigi cmd = (arg >> 24) & 0xff; 2214101978Sluigi new_set = (arg >> 16) & 0xff; 2215101628Sluigi 2216101978Sluigi if (cmd > 4) 221798943Sluigi return EINVAL; 2218101978Sluigi if (new_set > 30) 2219101628Sluigi return EINVAL; 2220101978Sluigi if (cmd == 0 || cmd == 2) { 2221101978Sluigi if (rulenum == IPFW_DEFAULT_RULE) 2222101978Sluigi return EINVAL; 2223101978Sluigi } else { 2224101978Sluigi if (rulenum > 30) 2225101978Sluigi return EINVAL; 2226101978Sluigi } 2227105775Smaxim 2228101628Sluigi switch (cmd) { 2229101978Sluigi case 0: /* delete rules with given number */ 2230101628Sluigi /* 2231101628Sluigi * locate first rule to delete 2232101628Sluigi */ 2233101628Sluigi for (prev = NULL, rule = *chain; 2234101628Sluigi rule && rule->rulenum < rulenum; 2235101628Sluigi prev = rule, rule = rule->next) 2236101628Sluigi ; 2237101628Sluigi if (rule->rulenum != rulenum) 2238101628Sluigi return EINVAL; 2239101628Sluigi 2240101628Sluigi s = splimp(); /* no access to rules while removing */ 2241101628Sluigi /* 2242101978Sluigi * flush pointers outside the loop, then delete all matching 2243101978Sluigi * rules. prev remains the same throughout the cycle. 2244101628Sluigi */ 2245101978Sluigi flush_rule_ptrs(); 2246101628Sluigi while (rule && rule->rulenum == rulenum) 2247101628Sluigi rule = delete_rule(chain, prev, rule); 2248101628Sluigi splx(s); 2249101628Sluigi break; 2250101628Sluigi 2251101978Sluigi case 1: /* delete all rules with given set number */ 2252101978Sluigi s = splimp(); 2253101978Sluigi flush_rule_ptrs(); 2254101628Sluigi for (prev = NULL, rule = *chain; rule ; ) 2255101628Sluigi if (rule->set == rulenum) 2256101628Sluigi rule = delete_rule(chain, prev, rule); 2257101628Sluigi else { 2258101628Sluigi prev = rule; 2259101628Sluigi rule = rule->next; 2260101628Sluigi } 2261101628Sluigi splx(s); 2262101628Sluigi break; 2263101628Sluigi 2264101978Sluigi case 2: /* move rules with given number to new set */ 2265101628Sluigi s = splimp(); 2266101978Sluigi for (rule = *chain; rule ; rule = rule->next) 2267101978Sluigi if (rule->rulenum == rulenum) 2268101978Sluigi rule->set = new_set; 2269101628Sluigi splx(s); 2270101628Sluigi break; 2271101628Sluigi 2272101978Sluigi case 3: /* move rules with given set number to new set */ 2273101628Sluigi s = splimp(); 2274101978Sluigi for (rule = *chain; rule ; rule = rule->next) 2275101978Sluigi if (rule->set == rulenum) 2276101978Sluigi rule->set = new_set; 2277101628Sluigi splx(s); 2278101628Sluigi break; 2279101978Sluigi 2280101978Sluigi case 4: /* swap two sets */ 2281101978Sluigi s = splimp(); 2282101978Sluigi for (rule = *chain; rule ; rule = rule->next) 2283101978Sluigi if (rule->set == rulenum) 2284101978Sluigi rule->set = new_set; 2285101978Sluigi else if (rule->set == new_set) 2286101978Sluigi rule->set = rulenum; 2287101978Sluigi splx(s); 2288101978Sluigi break; 2289101628Sluigi } 229098943Sluigi return 0; 229198943Sluigi} 229298943Sluigi 229398943Sluigi/* 229498943Sluigi * Clear counters for a specific rule. 229598943Sluigi */ 229698943Sluigistatic void 229798943Sluigiclear_counters(struct ip_fw *rule, int log_only) 229898943Sluigi{ 229998943Sluigi ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule); 230098943Sluigi 230198943Sluigi if (log_only == 0) { 230298943Sluigi rule->bcnt = rule->pcnt = 0; 230398943Sluigi rule->timestamp = 0; 230498943Sluigi } 230598943Sluigi if (l->o.opcode == O_LOG) 230698943Sluigi l->log_left = l->max_log; 230798943Sluigi} 230898943Sluigi 230998943Sluigi/** 231098943Sluigi * Reset some or all counters on firewall rules. 231198943Sluigi * @arg frwl is null to clear all entries, or contains a specific 231298943Sluigi * rule number. 231398943Sluigi * @arg log_only is 1 if we only want to reset logs, zero otherwise. 231498943Sluigi */ 231598943Sluigistatic int 231698943Sluigizero_entry(int rulenum, int log_only) 231798943Sluigi{ 231898943Sluigi struct ip_fw *rule; 231998943Sluigi int s; 232098943Sluigi char *msg; 232198943Sluigi 232298943Sluigi if (rulenum == 0) { 232398943Sluigi s = splimp(); 232498943Sluigi norule_counter = 0; 232598943Sluigi for (rule = layer3_chain; rule; rule = rule->next) 232698943Sluigi clear_counters(rule, log_only); 232798943Sluigi splx(s); 232898943Sluigi msg = log_only ? "ipfw: All logging counts reset.\n" : 232998943Sluigi "ipfw: Accounting cleared.\n"; 233098943Sluigi } else { 233198943Sluigi int cleared = 0; 233298943Sluigi /* 233398943Sluigi * We can have multiple rules with the same number, so we 233498943Sluigi * need to clear them all. 233598943Sluigi */ 233698943Sluigi for (rule = layer3_chain; rule; rule = rule->next) 233798943Sluigi if (rule->rulenum == rulenum) { 233898943Sluigi s = splimp(); 233998943Sluigi while (rule && rule->rulenum == rulenum) { 234098943Sluigi clear_counters(rule, log_only); 234198943Sluigi rule = rule->next; 234298943Sluigi } 234398943Sluigi splx(s); 234498943Sluigi cleared = 1; 234598943Sluigi break; 234698943Sluigi } 234798943Sluigi if (!cleared) /* we did not find any matching rules */ 234898943Sluigi return (EINVAL); 234998943Sluigi msg = log_only ? "ipfw: Entry %d logging count reset.\n" : 235098943Sluigi "ipfw: Entry %d cleared.\n"; 235198943Sluigi } 235298943Sluigi if (fw_verbose) 235398943Sluigi log(LOG_SECURITY | LOG_NOTICE, msg, rulenum); 235498943Sluigi return (0); 235598943Sluigi} 235698943Sluigi 235798943Sluigi/* 235898943Sluigi * Check validity of the structure before insert. 235998943Sluigi * Fortunately rules are simple, so this mostly need to check rule sizes. 236098943Sluigi */ 236198943Sluigistatic int 236298943Sluigicheck_ipfw_struct(struct ip_fw *rule, int size) 236398943Sluigi{ 236498943Sluigi int l, cmdlen = 0; 236598943Sluigi int have_action=0; 236698943Sluigi ipfw_insn *cmd; 236798943Sluigi 236898943Sluigi if (size < sizeof(*rule)) { 236999622Sluigi printf("ipfw: rule too short\n"); 237098943Sluigi return (EINVAL); 237198943Sluigi } 237298943Sluigi /* first, check for valid size */ 237398943Sluigi l = RULESIZE(rule); 237498943Sluigi if (l != size) { 237599622Sluigi printf("ipfw: size mismatch (have %d want %d)\n", size, l); 237698943Sluigi return (EINVAL); 237798943Sluigi } 237898943Sluigi /* 237998943Sluigi * Now go for the individual checks. Very simple ones, basically only 238098943Sluigi * instruction sizes. 238198943Sluigi */ 238298943Sluigi for (l = rule->cmd_len, cmd = rule->cmd ; 238398943Sluigi l > 0 ; l -= cmdlen, cmd += cmdlen) { 238498943Sluigi cmdlen = F_LEN(cmd); 238598943Sluigi if (cmdlen > l) { 238699622Sluigi printf("ipfw: opcode %d size truncated\n", 238798943Sluigi cmd->opcode); 238898943Sluigi return EINVAL; 238998943Sluigi } 239099622Sluigi DEB(printf("ipfw: opcode %d\n", cmd->opcode);) 239198943Sluigi switch (cmd->opcode) { 239298943Sluigi case O_NOP: 239398943Sluigi case O_PROBE_STATE: 239498943Sluigi case O_KEEP_STATE: 239598943Sluigi case O_PROTO: 239698943Sluigi case O_IP_SRC_ME: 239798943Sluigi case O_IP_DST_ME: 239898943Sluigi case O_LAYER2: 239998943Sluigi case O_IN: 240098943Sluigi case O_FRAG: 240198943Sluigi case O_IPOPT: 240298943Sluigi case O_IPTOS: 240399475Sluigi case O_IPPRECEDENCE: 240498943Sluigi case O_IPVER: 240598943Sluigi case O_TCPWIN: 240698943Sluigi case O_TCPFLAGS: 240798943Sluigi case O_TCPOPTS: 240898943Sluigi case O_ESTAB: 2409112250Scjc case O_VERREVPATH: 2410117241Sluigi case O_IPSEC: 241198943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn)) 241298943Sluigi goto bad_size; 241398943Sluigi break; 241498943Sluigi 241598943Sluigi case O_UID: 241698943Sluigi case O_GID: 241798943Sluigi case O_IP_SRC: 241898943Sluigi case O_IP_DST: 241998943Sluigi case O_TCPSEQ: 242098943Sluigi case O_TCPACK: 242198943Sluigi case O_PROB: 242298943Sluigi case O_ICMPTYPE: 242398943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 242498943Sluigi goto bad_size; 242598943Sluigi break; 242698943Sluigi 242798943Sluigi case O_LIMIT: 242898943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) 242998943Sluigi goto bad_size; 243098943Sluigi break; 243198943Sluigi 243298943Sluigi case O_LOG: 243398943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_log)) 243498943Sluigi goto bad_size; 2435105775Smaxim 243698943Sluigi ((ipfw_insn_log *)cmd)->log_left = 243798943Sluigi ((ipfw_insn_log *)cmd)->max_log; 243898943Sluigi 243998943Sluigi break; 244098943Sluigi 244198943Sluigi case O_IP_SRC_MASK: 244298943Sluigi case O_IP_DST_MASK: 244398943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_ip)) 244498943Sluigi goto bad_size; 244598943Sluigi if (((ipfw_insn_ip *)cmd)->mask.s_addr == 0) { 244699622Sluigi printf("ipfw: opcode %d, useless rule\n", 244798943Sluigi cmd->opcode); 244898943Sluigi return EINVAL; 244998943Sluigi } 245098943Sluigi break; 245198943Sluigi 245298943Sluigi case O_IP_SRC_SET: 245398943Sluigi case O_IP_DST_SET: 245498943Sluigi if (cmd->arg1 == 0 || cmd->arg1 > 256) { 245599622Sluigi printf("ipfw: invalid set size %d\n", 245698943Sluigi cmd->arg1); 245798943Sluigi return EINVAL; 245898943Sluigi } 245998943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 246098943Sluigi (cmd->arg1+31)/32 ) 246198943Sluigi goto bad_size; 246298943Sluigi break; 246398943Sluigi 246498943Sluigi case O_MACADDR2: 246598943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) 246698943Sluigi goto bad_size; 246798943Sluigi break; 246898943Sluigi 2469116690Sluigi case O_IPID: 2470116690Sluigi case O_IPTTL: 2471116690Sluigi case O_IPLEN: 2472116690Sluigi if (cmdlen < 1 || cmdlen > 31) 2473116690Sluigi goto bad_size; 2474116690Sluigi break; 2475116690Sluigi 247698943Sluigi case O_MAC_TYPE: 247798943Sluigi case O_IP_SRCPORT: 2478102086Sluigi case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */ 2479102086Sluigi if (cmdlen < 2 || cmdlen > 31) 248098943Sluigi goto bad_size; 248198943Sluigi break; 248298943Sluigi 248398943Sluigi case O_RECV: 248498943Sluigi case O_XMIT: 248598943Sluigi case O_VIA: 248698943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) 248798943Sluigi goto bad_size; 248898943Sluigi break; 248998943Sluigi 249098943Sluigi case O_PIPE: 249198943Sluigi case O_QUEUE: 249298943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_pipe)) 249398943Sluigi goto bad_size; 249498943Sluigi goto check_action; 249598943Sluigi 249699475Sluigi case O_FORWARD_IP: 249798943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) 249898943Sluigi goto bad_size; 249998943Sluigi goto check_action; 250098943Sluigi 250199475Sluigi case O_FORWARD_MAC: /* XXX not implemented yet */ 250298943Sluigi case O_CHECK_STATE: 250398943Sluigi case O_COUNT: 250498943Sluigi case O_ACCEPT: 250598943Sluigi case O_DENY: 250698943Sluigi case O_REJECT: 250798943Sluigi case O_SKIPTO: 250898943Sluigi case O_DIVERT: 250998943Sluigi case O_TEE: 251098943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn)) 251198943Sluigi goto bad_size; 251298943Sluigicheck_action: 251398943Sluigi if (have_action) { 251499622Sluigi printf("ipfw: opcode %d, multiple actions" 251598943Sluigi " not allowed\n", 251698943Sluigi cmd->opcode); 251798943Sluigi return EINVAL; 251898943Sluigi } 251998943Sluigi have_action = 1; 252098943Sluigi if (l != cmdlen) { 252199622Sluigi printf("ipfw: opcode %d, action must be" 252298943Sluigi " last opcode\n", 252398943Sluigi cmd->opcode); 252498943Sluigi return EINVAL; 252598943Sluigi } 252698943Sluigi break; 252798943Sluigi default: 252899622Sluigi printf("ipfw: opcode %d, unknown opcode\n", 252998943Sluigi cmd->opcode); 253098943Sluigi return EINVAL; 253198943Sluigi } 253298943Sluigi } 253398943Sluigi if (have_action == 0) { 253499622Sluigi printf("ipfw: missing action\n"); 253598943Sluigi return EINVAL; 253698943Sluigi } 253798943Sluigi return 0; 253898943Sluigi 253998943Sluigibad_size: 254099622Sluigi printf("ipfw: opcode %d size %d wrong\n", 254198943Sluigi cmd->opcode, cmdlen); 254298943Sluigi return EINVAL; 254398943Sluigi} 254498943Sluigi 254598943Sluigi 254698943Sluigi/** 254798943Sluigi * {set|get}sockopt parser. 254898943Sluigi */ 254998943Sluigistatic int 255098943Sluigiipfw_ctl(struct sockopt *sopt) 255198943Sluigi{ 255298943Sluigi int error, s, rulenum; 255398943Sluigi size_t size; 255498943Sluigi struct ip_fw *bp , *buf, *rule; 255598943Sluigi 255698943Sluigi static u_int32_t rule_buf[255]; /* we copy the data here */ 255798943Sluigi 255898943Sluigi /* 255998943Sluigi * Disallow modifications in really-really secure mode, but still allow 256098943Sluigi * the logging counters to be reset. 256198943Sluigi */ 256298943Sluigi if (sopt->sopt_name == IP_FW_ADD || 256398943Sluigi (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) { 256498943Sluigi#if __FreeBSD_version >= 500034 256598943Sluigi error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 256698943Sluigi if (error) 256798943Sluigi return (error); 256898943Sluigi#else /* FreeBSD 4.x */ 256998943Sluigi if (securelevel >= 3) 257098943Sluigi return (EPERM); 257198943Sluigi#endif 257298943Sluigi } 257398943Sluigi 257498943Sluigi error = 0; 257598943Sluigi 257698943Sluigi switch (sopt->sopt_name) { 257798943Sluigi case IP_FW_GET: 257898943Sluigi /* 257998943Sluigi * pass up a copy of the current rules. Static rules 258098943Sluigi * come first (the last of which has number IPFW_DEFAULT_RULE), 258198943Sluigi * followed by a possibly empty list of dynamic rule. 258298943Sluigi * The last dynamic rule has NULL in the "next" field. 258398943Sluigi */ 258498943Sluigi s = splimp(); 258598943Sluigi size = static_len; /* size of static rules */ 258698943Sluigi if (ipfw_dyn_v) /* add size of dyn.rules */ 258798943Sluigi size += (dyn_count * sizeof(ipfw_dyn_rule)); 258898943Sluigi 258998943Sluigi /* 259098943Sluigi * XXX todo: if the user passes a short length just to know 259198943Sluigi * how much room is needed, do not bother filling up the 259298943Sluigi * buffer, just jump to the sooptcopyout. 259398943Sluigi */ 2594111119Simp buf = malloc(size, M_TEMP, M_WAITOK); 259598943Sluigi if (buf == 0) { 259698943Sluigi splx(s); 259798943Sluigi error = ENOBUFS; 259898943Sluigi break; 259998943Sluigi } 260098943Sluigi 260198943Sluigi bp = buf; 260298943Sluigi for (rule = layer3_chain; rule ; rule = rule->next) { 260398943Sluigi int i = RULESIZE(rule); 260498943Sluigi bcopy(rule, bp, i); 2605115793Sticso bcopy(&set_disable, &(bp->next_rule), 2606115793Sticso sizeof(set_disable)); 260798943Sluigi bp = (struct ip_fw *)((char *)bp + i); 260898943Sluigi } 260998943Sluigi if (ipfw_dyn_v) { 261098943Sluigi int i; 261198943Sluigi ipfw_dyn_rule *p, *dst, *last = NULL; 261298943Sluigi 261398943Sluigi dst = (ipfw_dyn_rule *)bp; 261498943Sluigi for (i = 0 ; i < curr_dyn_buckets ; i++ ) 261598943Sluigi for ( p = ipfw_dyn_v[i] ; p != NULL ; 261698943Sluigi p = p->next, dst++ ) { 261798943Sluigi bcopy(p, dst, sizeof *p); 2618115793Sticso bcopy(&(p->rule->rulenum), &(dst->rule), 2619115793Sticso sizeof(p->rule->rulenum)); 262098943Sluigi /* 262198943Sluigi * store a non-null value in "next". 262298943Sluigi * The userland code will interpret a 262398943Sluigi * NULL here as a marker 262498943Sluigi * for the last dynamic rule. 262598943Sluigi */ 2626115793Sticso bcopy(&dst, &dst->next, sizeof(dst)); 262798943Sluigi last = dst ; 262898943Sluigi dst->expire = 262998943Sluigi TIME_LEQ(dst->expire, time_second) ? 263098943Sluigi 0 : dst->expire - time_second ; 263198943Sluigi } 263298943Sluigi if (last != NULL) /* mark last dynamic rule */ 2633115793Sticso bzero(&last->next, sizeof(last)); 263498943Sluigi } 263598943Sluigi splx(s); 263698943Sluigi 263798943Sluigi error = sooptcopyout(sopt, buf, size); 263898943Sluigi free(buf, M_TEMP); 263998943Sluigi break; 264098943Sluigi 264198943Sluigi case IP_FW_FLUSH: 264298943Sluigi /* 264398943Sluigi * Normally we cannot release the lock on each iteration. 264498943Sluigi * We could do it here only because we start from the head all 264598943Sluigi * the times so there is no risk of missing some entries. 264698943Sluigi * On the other hand, the risk is that we end up with 264798943Sluigi * a very inconsistent ruleset, so better keep the lock 264898943Sluigi * around the whole cycle. 2649105775Smaxim * 265098943Sluigi * XXX this code can be improved by resetting the head of 265198943Sluigi * the list to point to the default rule, and then freeing 265298943Sluigi * the old list without the need for a lock. 265398943Sluigi */ 265498943Sluigi 265598943Sluigi s = splimp(); 265698943Sluigi free_chain(&layer3_chain, 0 /* keep default rule */); 265798943Sluigi splx(s); 265898943Sluigi break; 265998943Sluigi 266098943Sluigi case IP_FW_ADD: 266198943Sluigi rule = (struct ip_fw *)rule_buf; /* XXX do a malloc */ 266298943Sluigi error = sooptcopyin(sopt, rule, sizeof(rule_buf), 266398943Sluigi sizeof(struct ip_fw) ); 266498943Sluigi size = sopt->sopt_valsize; 266598943Sluigi if (error || (error = check_ipfw_struct(rule, size))) 266698943Sluigi break; 266798943Sluigi 266898943Sluigi error = add_rule(&layer3_chain, rule); 266998943Sluigi size = RULESIZE(rule); 267098943Sluigi if (!error && sopt->sopt_dir == SOPT_GET) 267198943Sluigi error = sooptcopyout(sopt, rule, size); 267298943Sluigi break; 267398943Sluigi 2674101978Sluigi case IP_FW_DEL: 2675101628Sluigi /* 2676101978Sluigi * IP_FW_DEL is used for deleting single rules or sets, 2677101978Sluigi * and (ab)used to atomically manipulate sets. Argument size 2678101978Sluigi * is used to distinguish between the two: 2679101978Sluigi * sizeof(u_int32_t) 2680101978Sluigi * delete single rule or set of rules, 2681101978Sluigi * or reassign rules (or sets) to a different set. 2682101978Sluigi * 2*sizeof(u_int32_t) 2683101978Sluigi * atomic disable/enable sets. 2684101978Sluigi * first u_int32_t contains sets to be disabled, 2685101978Sluigi * second u_int32_t contains sets to be enabled. 2686101628Sluigi */ 2687101978Sluigi error = sooptcopyin(sopt, rule_buf, 2688101978Sluigi 2*sizeof(u_int32_t), sizeof(u_int32_t)); 268998943Sluigi if (error) 269098943Sluigi break; 2691101978Sluigi size = sopt->sopt_valsize; 2692101978Sluigi if (size == sizeof(u_int32_t)) /* delete or reassign */ 2693101978Sluigi error = del_entry(&layer3_chain, rule_buf[0]); 2694101978Sluigi else if (size == 2*sizeof(u_int32_t)) /* set enable/disable */ 2695101978Sluigi set_disable = 2696101978Sluigi (set_disable | rule_buf[0]) & ~rule_buf[1] & 2697101978Sluigi ~(1<<31); /* set 31 always enabled */ 2698101978Sluigi else 269998943Sluigi error = EINVAL; 270098943Sluigi break; 270198943Sluigi 270298943Sluigi case IP_FW_ZERO: 270398943Sluigi case IP_FW_RESETLOG: /* argument is an int, the rule number */ 270498943Sluigi rulenum=0; 270598943Sluigi 270698943Sluigi if (sopt->sopt_val != 0) { 270798943Sluigi error = sooptcopyin(sopt, &rulenum, 270898943Sluigi sizeof(int), sizeof(int)); 270998943Sluigi if (error) 271098943Sluigi break; 271198943Sluigi } 271298943Sluigi error = zero_entry(rulenum, sopt->sopt_name == IP_FW_RESETLOG); 271398943Sluigi break; 271498943Sluigi 271598943Sluigi default: 2716108258Smaxim printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); 271798943Sluigi error = EINVAL; 271898943Sluigi } 271998943Sluigi 272098943Sluigi return (error); 272198943Sluigi} 272298943Sluigi 272398943Sluigi/** 272498943Sluigi * dummynet needs a reference to the default rule, because rules can be 272598943Sluigi * deleted while packets hold a reference to them. When this happens, 272698943Sluigi * dummynet changes the reference to the default rule (it could well be a 272798943Sluigi * NULL pointer, but this way we do not need to check for the special 272898943Sluigi * case, plus here he have info on the default behaviour). 272998943Sluigi */ 273098943Sluigistruct ip_fw *ip_fw_default_rule; 273198943Sluigi 2732101978Sluigi/* 2733101978Sluigi * This procedure is only used to handle keepalives. It is invoked 2734101978Sluigi * every dyn_keepalive_period 2735101978Sluigi */ 273698943Sluigistatic void 2737100004Sluigiipfw_tick(void * __unused unused) 2738100004Sluigi{ 2739100004Sluigi int i; 2740100004Sluigi int s; 2741100004Sluigi ipfw_dyn_rule *q; 2742100004Sluigi 2743100004Sluigi if (dyn_keepalive == 0 || ipfw_dyn_v == NULL || dyn_count == 0) 2744100004Sluigi goto done; 2745100004Sluigi 2746100004Sluigi s = splimp(); 2747100004Sluigi for (i = 0 ; i < curr_dyn_buckets ; i++) { 2748100004Sluigi for (q = ipfw_dyn_v[i] ; q ; q = q->next ) { 2749100004Sluigi if (q->dyn_type == O_LIMIT_PARENT) 2750100004Sluigi continue; 2751100004Sluigi if (q->id.proto != IPPROTO_TCP) 2752100004Sluigi continue; 2753100004Sluigi if ( (q->state & BOTH_SYN) != BOTH_SYN) 2754100004Sluigi continue; 2755101978Sluigi if (TIME_LEQ( time_second+dyn_keepalive_interval, 2756101978Sluigi q->expire)) 2757100004Sluigi continue; /* too early */ 2758100004Sluigi if (TIME_LEQ(q->expire, time_second)) 2759100004Sluigi continue; /* too late, rule expired */ 2760100004Sluigi 2761100004Sluigi send_pkt(&(q->id), q->ack_rev - 1, q->ack_fwd, TH_SYN); 2762100004Sluigi send_pkt(&(q->id), q->ack_fwd - 1, q->ack_rev, 0); 2763100004Sluigi } 2764100004Sluigi } 2765100004Sluigi splx(s); 2766100004Sluigidone: 2767101978Sluigi ipfw_timeout_h = timeout(ipfw_tick, NULL, dyn_keepalive_period*hz); 2768100004Sluigi} 2769100004Sluigi 2770100004Sluigistatic void 277198943Sluigiipfw_init(void) 277298943Sluigi{ 277398943Sluigi struct ip_fw default_rule; 277498943Sluigi 277598943Sluigi ip_fw_chk_ptr = ipfw_chk; 277698943Sluigi ip_fw_ctl_ptr = ipfw_ctl; 277798943Sluigi layer3_chain = NULL; 277898943Sluigi 277998943Sluigi bzero(&default_rule, sizeof default_rule); 278098943Sluigi 278198943Sluigi default_rule.act_ofs = 0; 278298943Sluigi default_rule.rulenum = IPFW_DEFAULT_RULE; 278398943Sluigi default_rule.cmd_len = 1; 2784101628Sluigi default_rule.set = 31; 278598943Sluigi 278698943Sluigi default_rule.cmd[0].len = 1; 278798943Sluigi default_rule.cmd[0].opcode = 278898943Sluigi#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT 278998943Sluigi 1 ? O_ACCEPT : 279098943Sluigi#endif 279198943Sluigi O_DENY; 279298943Sluigi 279398943Sluigi add_rule(&layer3_chain, &default_rule); 279498943Sluigi 279598943Sluigi ip_fw_default_rule = layer3_chain; 2796102086Sluigi printf("ipfw2 initialized, divert %s, " 2797102086Sluigi "rule-based forwarding enabled, default to %s, logging ", 279898943Sluigi#ifdef IPDIVERT 279998943Sluigi "enabled", 280098943Sluigi#else 280198943Sluigi "disabled", 280298943Sluigi#endif 280398943Sluigi default_rule.cmd[0].opcode == O_ACCEPT ? "accept" : "deny"); 280498943Sluigi 280598943Sluigi#ifdef IPFIREWALL_VERBOSE 280698943Sluigi fw_verbose = 1; 280798943Sluigi#endif 280898943Sluigi#ifdef IPFIREWALL_VERBOSE_LIMIT 280998943Sluigi verbose_limit = IPFIREWALL_VERBOSE_LIMIT; 281098943Sluigi#endif 281198943Sluigi if (fw_verbose == 0) 281298943Sluigi printf("disabled\n"); 281398943Sluigi else if (verbose_limit == 0) 281498943Sluigi printf("unlimited\n"); 281598943Sluigi else 281698943Sluigi printf("limited to %d packets/entry by default\n", 281798943Sluigi verbose_limit); 2818100004Sluigi bzero(&ipfw_timeout_h, sizeof(struct callout_handle)); 2819100004Sluigi ipfw_timeout_h = timeout(ipfw_tick, NULL, hz); 282098943Sluigi} 282198943Sluigi 282298943Sluigistatic int 282398943Sluigiipfw_modevent(module_t mod, int type, void *unused) 282498943Sluigi{ 282598943Sluigi int s; 282698943Sluigi int err = 0; 2827105775Smaxim 282898943Sluigi switch (type) { 282998943Sluigi case MOD_LOAD: 283098943Sluigi s = splimp(); 283198943Sluigi if (IPFW_LOADED) { 283298943Sluigi splx(s); 283398943Sluigi printf("IP firewall already loaded\n"); 283498943Sluigi err = EEXIST; 283598943Sluigi } else { 283698943Sluigi ipfw_init(); 283798943Sluigi splx(s); 283898943Sluigi } 283998943Sluigi break; 284098943Sluigi 284198943Sluigi case MOD_UNLOAD: 284298943Sluigi#if !defined(KLD_MODULE) 284398943Sluigi printf("ipfw statically compiled, cannot unload\n"); 284498943Sluigi err = EBUSY; 284598943Sluigi#else 284698943Sluigi s = splimp(); 2847100004Sluigi untimeout(ipfw_tick, NULL, ipfw_timeout_h); 284898943Sluigi ip_fw_chk_ptr = NULL; 284998943Sluigi ip_fw_ctl_ptr = NULL; 285098943Sluigi free_chain(&layer3_chain, 1 /* kill default rule */); 285198943Sluigi splx(s); 285298943Sluigi printf("IP firewall unloaded\n"); 285398943Sluigi#endif 285498943Sluigi break; 285598943Sluigi default: 285698943Sluigi break; 285798943Sluigi } 285898943Sluigi return err; 285998943Sluigi} 286098943Sluigi 286198943Sluigistatic moduledata_t ipfwmod = { 286298943Sluigi "ipfw", 286398943Sluigi ipfw_modevent, 286498943Sluigi 0 286598943Sluigi}; 286698943SluigiDECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY); 286798943SluigiMODULE_VERSION(ipfw, 1); 286899622Sluigi#endif /* IPFW2 */ 2869