ip_fw2.c revision 101843
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. 998943Sluigi * 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. 1298943Sluigi * 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 101843 2002-08-13 19:13:23Z phk $ 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 7698943Sluigi#include <netinet/if_ether.h> /* XXX for ETHERTYPE_IP */ 7798943Sluigi 7899475Sluigi#include <machine/in_cksum.h> /* XXX for in_cksum */ 7999475Sluigi 80101628Sluigi/* 81101628Sluigi * set_disable contains one bit per set value (0..31). 82101628Sluigi * If the bit is set, all rules with the corresponding set 83101628Sluigi * are disabled. Set 31 is reserved for the default rule 84101628Sluigi * and CANNOT be disabled. 85101628Sluigi */ 86101628Sluigistatic u_int32_t set_disable; 87101628Sluigi 8899622Sluigistatic int fw_verbose; 8999622Sluigistatic int verbose_limit; 9098943Sluigi 91100004Sluigistatic struct callout_handle ipfw_timeout_h; 9298943Sluigi#define IPFW_DEFAULT_RULE 65535 9398943Sluigi 9498943Sluigi/* 9598943Sluigi * list of rules for layer 3 9698943Sluigi */ 9798943Sluigistatic struct ip_fw *layer3_chain; 9898943Sluigi 9998943SluigiMALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); 10098943Sluigi 10198943Sluigistatic int fw_debug = 1; 10298943Sluigiint fw_one_pass = 1; 10398943Sluigistatic int autoinc_step = 100; /* bounded to 1..1000 in add_rule() */ 10498943Sluigi 10598943Sluigi#ifdef SYSCTL_NODE 10698943SluigiSYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); 10798943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, enable, CTLFLAG_RW, 10898943Sluigi &fw_enable, 0, "Enable ipfw"); 10998943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, CTLFLAG_RW, 11098943Sluigi &autoinc_step, 0, "Rule number autincrement step"); 11198943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO,one_pass,CTLFLAG_RW, 11298943Sluigi &fw_one_pass, 0, 11398943Sluigi "Only do a single pass through ipfw when using dummynet(4)"); 11498943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, 11598943Sluigi &fw_debug, 0, "Enable printing of debug ip_fw statements"); 11698943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, 11798943Sluigi &fw_verbose, 0, "Log matches to ipfw rules"); 11898943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, 11998943Sluigi &verbose_limit, 0, "Set upper limit of matches of ipfw rules logged"); 12098943Sluigi 12198943Sluigi/* 12298943Sluigi * Description of dynamic rules. 12398943Sluigi * 12498943Sluigi * Dynamic rules are stored in lists accessed through a hash table 12598943Sluigi * (ipfw_dyn_v) whose size is curr_dyn_buckets. This value can 12698943Sluigi * be modified through the sysctl variable dyn_buckets which is 12798943Sluigi * updated when the table becomes empty. 12898943Sluigi * 12998943Sluigi * XXX currently there is only one list, ipfw_dyn. 13098943Sluigi * 13198943Sluigi * When a packet is received, its address fields are first masked 13298943Sluigi * with the mask defined for the rule, then hashed, then matched 13398943Sluigi * against the entries in the corresponding list. 13498943Sluigi * Dynamic rules can be used for different purposes: 13598943Sluigi * + stateful rules; 13698943Sluigi * + enforcing limits on the number of sessions; 13798943Sluigi * + in-kernel NAT (not implemented yet) 13898943Sluigi * 13998943Sluigi * The lifetime of dynamic rules is regulated by dyn_*_lifetime, 14098943Sluigi * measured in seconds and depending on the flags. 14198943Sluigi * 14298943Sluigi * The total number of dynamic rules is stored in dyn_count. 14398943Sluigi * The max number of dynamic rules is dyn_max. When we reach 14498943Sluigi * the maximum number of rules we do not create anymore. This is 14598943Sluigi * done to avoid consuming too much memory, but also too much 14698943Sluigi * time when searching on each packet (ideally, we should try instead 14798943Sluigi * to put a limit on the length of the list on each bucket...). 14898943Sluigi * 14998943Sluigi * Each dynamic rule holds a pointer to the parent ipfw rule so 15098943Sluigi * we know what action to perform. Dynamic rules are removed when 15198943Sluigi * the parent rule is deleted. XXX we should make them survive. 15298943Sluigi * 15398943Sluigi * There are some limitations with dynamic rules -- we do not 15498943Sluigi * obey the 'randomized match', and we do not do multiple 15598943Sluigi * passes through the firewall. XXX check the latter!!! 15698943Sluigi */ 15798943Sluigistatic ipfw_dyn_rule **ipfw_dyn_v = NULL; 15898943Sluigistatic u_int32_t dyn_buckets = 256; /* must be power of 2 */ 15998943Sluigistatic u_int32_t curr_dyn_buckets = 256; /* must be power of 2 */ 16098943Sluigi 16198943Sluigi/* 16298943Sluigi * Timeouts for various events in handing dynamic rules. 16398943Sluigi */ 16498943Sluigistatic u_int32_t dyn_ack_lifetime = 300; 16598943Sluigistatic u_int32_t dyn_syn_lifetime = 20; 16698943Sluigistatic u_int32_t dyn_fin_lifetime = 1; 16798943Sluigistatic u_int32_t dyn_rst_lifetime = 1; 16898943Sluigistatic u_int32_t dyn_udp_lifetime = 10; 16998943Sluigistatic u_int32_t dyn_short_lifetime = 5; 17098943Sluigi 171100004Sluigistatic u_int32_t dyn_keepalive = 1; /* do send keepalives */ 17298943Sluigi 17399622Sluigistatic u_int32_t static_count; /* # of static rules */ 17499622Sluigistatic u_int32_t static_len; /* size in bytes of static rules */ 17599622Sluigistatic u_int32_t dyn_count; /* # of dynamic rules */ 17698943Sluigistatic u_int32_t dyn_max = 1000; /* max # of dynamic rules */ 17798943Sluigi 17898943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_buckets, CTLFLAG_RW, 17998943Sluigi &dyn_buckets, 0, "Number of dyn. buckets"); 18098943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, curr_dyn_buckets, CTLFLAG_RD, 18198943Sluigi &curr_dyn_buckets, 0, "Current Number of dyn. buckets"); 18298943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_count, CTLFLAG_RD, 18398943Sluigi &dyn_count, 0, "Number of dyn. rules"); 18498943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_max, CTLFLAG_RW, 18598943Sluigi &dyn_max, 0, "Max number of dyn. rules"); 18698943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, static_count, CTLFLAG_RD, 18798943Sluigi &static_count, 0, "Number of static rules"); 18898943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_ack_lifetime, CTLFLAG_RW, 18998943Sluigi &dyn_ack_lifetime, 0, "Lifetime of dyn. rules for acks"); 19098943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_syn_lifetime, CTLFLAG_RW, 19198943Sluigi &dyn_syn_lifetime, 0, "Lifetime of dyn. rules for syn"); 19298943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_fin_lifetime, CTLFLAG_RW, 19398943Sluigi &dyn_fin_lifetime, 0, "Lifetime of dyn. rules for fin"); 19498943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_rst_lifetime, CTLFLAG_RW, 19598943Sluigi &dyn_rst_lifetime, 0, "Lifetime of dyn. rules for rst"); 19698943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_udp_lifetime, CTLFLAG_RW, 19798943Sluigi &dyn_udp_lifetime, 0, "Lifetime of dyn. rules for UDP"); 19898943SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime, CTLFLAG_RW, 19998943Sluigi &dyn_short_lifetime, 0, "Lifetime of dyn. rules for other situations"); 200100004SluigiSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive, CTLFLAG_RW, 201100004Sluigi &dyn_keepalive, 0, "Enable keepalives for dyn. rules"); 20298943Sluigi 20398943Sluigi#endif /* SYSCTL_NODE */ 20498943Sluigi 20598943Sluigi 20698943Sluigistatic ip_fw_chk_t ipfw_chk; 20798943Sluigi 20898943Sluigiip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL; /* hook into dummynet */ 20998943Sluigi 21098943Sluigi/* 21198943Sluigi * This macro maps an ip pointer into a layer3 header pointer of type T 21298943Sluigi */ 21398943Sluigi#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl)) 21498943Sluigi 21599622Sluigistatic __inline int 21698943Sluigiicmptype_match(struct ip *ip, ipfw_insn_u32 *cmd) 21798943Sluigi{ 21898943Sluigi int type = L3HDR(struct icmp,ip)->icmp_type; 21998943Sluigi 22098943Sluigi return (type <= ICMP_MAXTYPE && (cmd->d[0] & (1<<type)) ); 22198943Sluigi} 22298943Sluigi 22398943Sluigi#define TT ( (1 << ICMP_ECHO) | (1 << ICMP_ROUTERSOLICIT) | \ 22498943Sluigi (1 << ICMP_TSTAMP) | (1 << ICMP_IREQ) | (1 << ICMP_MASKREQ) ) 22598943Sluigi 22698943Sluigistatic int 22798943Sluigiis_icmp_query(struct ip *ip) 22898943Sluigi{ 22998943Sluigi int type = L3HDR(struct icmp, ip)->icmp_type; 23098943Sluigi return (type <= ICMP_MAXTYPE && (TT & (1<<type)) ); 23198943Sluigi} 23298943Sluigi#undef TT 23398943Sluigi 23498943Sluigi/* 23598943Sluigi * The following checks use two arrays of 8 or 16 bits to store the 23698943Sluigi * bits that we want set or clear, respectively. They are in the 23798943Sluigi * low and high half of cmd->arg1 or cmd->d[0]. 23898943Sluigi * 23998943Sluigi * We scan options and store the bits we find set. We succeed if 24098943Sluigi * 24198943Sluigi * (want_set & ~bits) == 0 && (want_clear & ~bits) == want_clear 24298943Sluigi * 24398943Sluigi * The code is sometimes optimized not to store additional variables. 24498943Sluigi */ 24598943Sluigi 24698943Sluigistatic int 24798943Sluigiflags_match(ipfw_insn *cmd, u_int8_t bits) 24898943Sluigi{ 24998943Sluigi u_char want_clear; 25098943Sluigi bits = ~bits; 25198943Sluigi 25298943Sluigi if ( ((cmd->arg1 & 0xff) & bits) != 0) 25398943Sluigi return 0; /* some bits we want set were clear */ 25498943Sluigi want_clear = (cmd->arg1 >> 8) & 0xff; 25598943Sluigi if ( (want_clear & bits) != want_clear) 25698943Sluigi return 0; /* some bits we want clear were set */ 25798943Sluigi return 1; 25898943Sluigi} 25998943Sluigi 26098943Sluigistatic int 26198943Sluigiipopts_match(struct ip *ip, ipfw_insn *cmd) 26298943Sluigi{ 26398943Sluigi int optlen, bits = 0; 26498943Sluigi u_char *cp = (u_char *)(ip + 1); 26598943Sluigi int x = (ip->ip_hl << 2) - sizeof (struct ip); 26698943Sluigi 26798943Sluigi for (; x > 0; x -= optlen, cp += optlen) { 26898943Sluigi int opt = cp[IPOPT_OPTVAL]; 26998943Sluigi 27098943Sluigi if (opt == IPOPT_EOL) 27198943Sluigi break; 27298943Sluigi if (opt == IPOPT_NOP) 27398943Sluigi optlen = 1; 27498943Sluigi else { 27598943Sluigi optlen = cp[IPOPT_OLEN]; 27698943Sluigi if (optlen <= 0 || optlen > x) 27798943Sluigi return 0; /* invalid or truncated */ 27898943Sluigi } 27998943Sluigi switch (opt) { 28098943Sluigi 28198943Sluigi default: 28298943Sluigi break; 28398943Sluigi 28498943Sluigi case IPOPT_LSRR: 28598943Sluigi bits |= IP_FW_IPOPT_LSRR; 28698943Sluigi break; 28798943Sluigi 28898943Sluigi case IPOPT_SSRR: 28998943Sluigi bits |= IP_FW_IPOPT_SSRR; 29098943Sluigi break; 29198943Sluigi 29298943Sluigi case IPOPT_RR: 29398943Sluigi bits |= IP_FW_IPOPT_RR; 29498943Sluigi break; 29598943Sluigi 29698943Sluigi case IPOPT_TS: 29798943Sluigi bits |= IP_FW_IPOPT_TS; 29898943Sluigi break; 29998943Sluigi } 30098943Sluigi } 30198943Sluigi return (flags_match(cmd, bits)); 30298943Sluigi} 30398943Sluigi 30498943Sluigistatic int 30598943Sluigitcpopts_match(struct ip *ip, ipfw_insn *cmd) 30698943Sluigi{ 30798943Sluigi int optlen, bits = 0; 30898943Sluigi struct tcphdr *tcp = L3HDR(struct tcphdr,ip); 30998943Sluigi u_char *cp = (u_char *)(tcp + 1); 31098943Sluigi int x = (tcp->th_off << 2) - sizeof(struct tcphdr); 31198943Sluigi 31298943Sluigi for (; x > 0; x -= optlen, cp += optlen) { 31398943Sluigi int opt = cp[0]; 31498943Sluigi if (opt == TCPOPT_EOL) 31598943Sluigi break; 31698943Sluigi if (opt == TCPOPT_NOP) 31798943Sluigi optlen = 1; 31898943Sluigi else { 31998943Sluigi optlen = cp[1]; 32098943Sluigi if (optlen <= 0) 32198943Sluigi break; 32298943Sluigi } 32398943Sluigi 32498943Sluigi switch (opt) { 32598943Sluigi 32698943Sluigi default: 32798943Sluigi break; 32898943Sluigi 32998943Sluigi case TCPOPT_MAXSEG: 33098943Sluigi bits |= IP_FW_TCPOPT_MSS; 33198943Sluigi break; 33298943Sluigi 33398943Sluigi case TCPOPT_WINDOW: 33498943Sluigi bits |= IP_FW_TCPOPT_WINDOW; 33598943Sluigi break; 33698943Sluigi 33798943Sluigi case TCPOPT_SACK_PERMITTED: 33898943Sluigi case TCPOPT_SACK: 33998943Sluigi bits |= IP_FW_TCPOPT_SACK; 34098943Sluigi break; 34198943Sluigi 34298943Sluigi case TCPOPT_TIMESTAMP: 34398943Sluigi bits |= IP_FW_TCPOPT_TS; 34498943Sluigi break; 34598943Sluigi 34698943Sluigi case TCPOPT_CC: 34798943Sluigi case TCPOPT_CCNEW: 34898943Sluigi case TCPOPT_CCECHO: 34998943Sluigi bits |= IP_FW_TCPOPT_CC; 35098943Sluigi break; 35198943Sluigi } 35298943Sluigi } 35398943Sluigi return (flags_match(cmd, bits)); 35498943Sluigi} 35598943Sluigi 35698943Sluigistatic int 35798943Sluigiiface_match(struct ifnet *ifp, ipfw_insn_if *cmd) 35898943Sluigi{ 35998943Sluigi if (ifp == NULL) /* no iface with this packet, match fails */ 36098943Sluigi return 0; 36198943Sluigi /* Check by name or by IP address */ 36299475Sluigi if (cmd->name[0] != '\0') { /* match by name */ 36398943Sluigi /* Check unit number (-1 is wildcard) */ 36498943Sluigi if (cmd->p.unit != -1 && cmd->p.unit != ifp->if_unit) 36598943Sluigi return(0); 36698943Sluigi /* Check name */ 36798943Sluigi if (!strncmp(ifp->if_name, cmd->name, IFNAMSIZ)) 36898943Sluigi return(1); 36998943Sluigi } else { 37098943Sluigi struct ifaddr *ia; 37198943Sluigi 37298943Sluigi TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { 37398943Sluigi if (ia->ifa_addr == NULL) 37498943Sluigi continue; 37598943Sluigi if (ia->ifa_addr->sa_family != AF_INET) 37698943Sluigi continue; 37798943Sluigi if (cmd->p.ip.s_addr == ((struct sockaddr_in *) 37898943Sluigi (ia->ifa_addr))->sin_addr.s_addr) 37998943Sluigi return(1); /* match */ 38098943Sluigi } 38198943Sluigi } 38298943Sluigi return(0); /* no match, fail ... */ 38398943Sluigi} 38498943Sluigi 38598943Sluigistatic u_int64_t norule_counter; /* counter for ipfw_log(NULL...) */ 38698943Sluigi 38798943Sluigi#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0 38899622Sluigi#define SNP(buf) buf, sizeof(buf) 389100004Sluigi 39098943Sluigi/* 39198943Sluigi * We enter here when we have a rule with O_LOG. 39299622Sluigi * XXX this function alone takes about 2Kbytes of code! 39398943Sluigi */ 39498943Sluigistatic void 39598943Sluigiipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh, 39698943Sluigi struct mbuf *m, struct ifnet *oif) 39798943Sluigi{ 39898943Sluigi char *action; 39998943Sluigi int limit_reached = 0; 40099622Sluigi char action2[40], proto[48], fragment[28]; 40198943Sluigi 40298943Sluigi fragment[0] = '\0'; 40398943Sluigi proto[0] = '\0'; 40498943Sluigi 40598943Sluigi if (f == NULL) { /* bogus pkt */ 40698943Sluigi if (verbose_limit != 0 && norule_counter >= verbose_limit) 40798943Sluigi return; 40898943Sluigi norule_counter++; 40998943Sluigi if (norule_counter == verbose_limit) 41098943Sluigi limit_reached = verbose_limit; 41198943Sluigi action = "Refuse"; 41298943Sluigi } else { /* O_LOG is the first action, find the real one */ 41398943Sluigi ipfw_insn *cmd = ACTION_PTR(f); 41498943Sluigi ipfw_insn_log *l = (ipfw_insn_log *)cmd; 41598943Sluigi 41698943Sluigi if (l->max_log != 0 && l->log_left == 0) 41798943Sluigi return; 41898943Sluigi l->log_left--; 41998943Sluigi if (l->log_left == 0) 42098943Sluigi limit_reached = l->max_log; 42198943Sluigi cmd += F_LEN(cmd); /* point to first action */ 42298943Sluigi if (cmd->opcode == O_PROB) 42398943Sluigi cmd += F_LEN(cmd); 42498943Sluigi 42598943Sluigi action = action2; 42698943Sluigi switch (cmd->opcode) { 42798943Sluigi case O_DENY: 42898943Sluigi action = "Deny"; 42998943Sluigi break; 43099475Sluigi 43198943Sluigi case O_REJECT: 43299475Sluigi if (cmd->arg1==ICMP_REJECT_RST) 43399475Sluigi action = "Reset"; 43499475Sluigi else if (cmd->arg1==ICMP_UNREACH_HOST) 43599475Sluigi action = "Reject"; 43699475Sluigi else 43799475Sluigi snprintf(SNPARGS(action2, 0), "Unreach %d", 43899475Sluigi cmd->arg1); 43998943Sluigi break; 44099475Sluigi 44198943Sluigi case O_ACCEPT: 44298943Sluigi action = "Accept"; 44398943Sluigi break; 44498943Sluigi case O_COUNT: 44598943Sluigi action = "Count"; 44698943Sluigi break; 44798943Sluigi case O_DIVERT: 44898943Sluigi snprintf(SNPARGS(action2, 0), "Divert %d", 44998943Sluigi cmd->arg1); 45098943Sluigi break; 45198943Sluigi case O_TEE: 45298943Sluigi snprintf(SNPARGS(action2, 0), "Tee %d", 45398943Sluigi cmd->arg1); 45498943Sluigi break; 45598943Sluigi case O_SKIPTO: 45698943Sluigi snprintf(SNPARGS(action2, 0), "SkipTo %d", 45798943Sluigi cmd->arg1); 45898943Sluigi break; 45998943Sluigi case O_PIPE: 46098943Sluigi snprintf(SNPARGS(action2, 0), "Pipe %d", 46198943Sluigi cmd->arg1); 46298943Sluigi break; 46398943Sluigi case O_QUEUE: 46498943Sluigi snprintf(SNPARGS(action2, 0), "Queue %d", 46598943Sluigi cmd->arg1); 46698943Sluigi break; 46798943Sluigi case O_FORWARD_IP: { 46898943Sluigi ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd; 469100004Sluigi int len; 47098943Sluigi 471100004Sluigi len = snprintf(SNPARGS(action2, 0), "Forward to %s", 472100004Sluigi inet_ntoa(sa->sa.sin_addr)); 47398943Sluigi if (sa->sa.sin_port) 474100004Sluigi snprintf(SNPARGS(action2, len), ":%d", 475100004Sluigi ntohs(sa->sa.sin_port)); 47698943Sluigi } 47798943Sluigi break; 47898943Sluigi default: 47998943Sluigi action = "UNKNOWN"; 48098943Sluigi break; 48198943Sluigi } 48298943Sluigi } 48398943Sluigi 48498943Sluigi if (hlen == 0) { /* non-ip */ 48598943Sluigi snprintf(SNPARGS(proto, 0), "MAC"); 48698943Sluigi } else { 48798943Sluigi struct ip *ip = mtod(m, struct ip *); 48898943Sluigi /* these three are all aliases to the same thing */ 48998943Sluigi struct icmp *const icmp = L3HDR(struct icmp, ip); 49098943Sluigi struct tcphdr *const tcp = (struct tcphdr *)icmp; 49198943Sluigi struct udphdr *const udp = (struct udphdr *)icmp; 49298943Sluigi 49398943Sluigi int ip_off, offset, ip_len; 49498943Sluigi 49598943Sluigi int len; 49698943Sluigi 49798943Sluigi if (eh != NULL) { /* layer 2 packets are as on the wire */ 49898943Sluigi ip_off = ntohs(ip->ip_off); 49998943Sluigi ip_len = ntohs(ip->ip_len); 50098943Sluigi } else { 50198943Sluigi ip_off = ip->ip_off; 50298943Sluigi ip_len = ip->ip_len; 50398943Sluigi } 50498943Sluigi offset = ip_off & IP_OFFMASK; 50598943Sluigi switch (ip->ip_p) { 50698943Sluigi case IPPROTO_TCP: 50798943Sluigi len = snprintf(SNPARGS(proto, 0), "TCP %s", 50898943Sluigi inet_ntoa(ip->ip_src)); 50998943Sluigi if (offset == 0) 510100004Sluigi snprintf(SNPARGS(proto, len), ":%d %s:%d", 511100004Sluigi ntohs(tcp->th_sport), 512100004Sluigi inet_ntoa(ip->ip_dst), 513100004Sluigi ntohs(tcp->th_dport)); 51498943Sluigi else 515100004Sluigi snprintf(SNPARGS(proto, len), " %s", 516100004Sluigi inet_ntoa(ip->ip_dst)); 51798943Sluigi break; 51898943Sluigi 51998943Sluigi case IPPROTO_UDP: 52098943Sluigi len = snprintf(SNPARGS(proto, 0), "UDP %s", 52198943Sluigi inet_ntoa(ip->ip_src)); 52298943Sluigi if (offset == 0) 523100004Sluigi snprintf(SNPARGS(proto, len), ":%d %s:%d", 524100004Sluigi ntohs(udp->uh_sport), 525100004Sluigi inet_ntoa(ip->ip_dst), 526100004Sluigi ntohs(udp->uh_dport)); 52798943Sluigi else 528100004Sluigi snprintf(SNPARGS(proto, len), " %s", 529100004Sluigi inet_ntoa(ip->ip_dst)); 53098943Sluigi break; 53198943Sluigi 53298943Sluigi case IPPROTO_ICMP: 53398943Sluigi if (offset == 0) 53498943Sluigi len = snprintf(SNPARGS(proto, 0), 53598943Sluigi "ICMP:%u.%u ", 53698943Sluigi icmp->icmp_type, icmp->icmp_code); 53798943Sluigi else 53898943Sluigi len = snprintf(SNPARGS(proto, 0), "ICMP "); 53998943Sluigi len += snprintf(SNPARGS(proto, len), "%s", 54098943Sluigi inet_ntoa(ip->ip_src)); 54198943Sluigi snprintf(SNPARGS(proto, len), " %s", 54298943Sluigi inet_ntoa(ip->ip_dst)); 54398943Sluigi break; 54498943Sluigi 54598943Sluigi default: 54698943Sluigi len = snprintf(SNPARGS(proto, 0), "P:%d %s", ip->ip_p, 54798943Sluigi inet_ntoa(ip->ip_src)); 54898943Sluigi snprintf(SNPARGS(proto, len), " %s", 54998943Sluigi inet_ntoa(ip->ip_dst)); 55098943Sluigi break; 55198943Sluigi } 55298943Sluigi 55398943Sluigi if (ip_off & (IP_MF | IP_OFFMASK)) 55498943Sluigi snprintf(SNPARGS(fragment, 0), " (frag %d:%d@%d%s)", 55598943Sluigi ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2), 55698943Sluigi offset << 3, 55798943Sluigi (ip_off & IP_MF) ? "+" : ""); 55898943Sluigi } 55998943Sluigi if (oif || m->m_pkthdr.rcvif) 56098943Sluigi log(LOG_SECURITY | LOG_INFO, 56198943Sluigi "ipfw: %d %s %s %s via %s%d%s\n", 56298943Sluigi f ? f->rulenum : -1, 56398943Sluigi action, proto, oif ? "out" : "in", 56498943Sluigi oif ? oif->if_name : m->m_pkthdr.rcvif->if_name, 56598943Sluigi oif ? oif->if_unit : m->m_pkthdr.rcvif->if_unit, 56698943Sluigi fragment); 56798943Sluigi else 56898943Sluigi log(LOG_SECURITY | LOG_INFO, 56998943Sluigi "ipfw: %d %s %s [no if info]%s\n", 57098943Sluigi f ? f->rulenum : -1, 57198943Sluigi action, proto, fragment); 57298943Sluigi if (limit_reached) 57398943Sluigi log(LOG_SECURITY | LOG_NOTICE, 57498943Sluigi "ipfw: limit %d reached on entry %d\n", 57598943Sluigi limit_reached, f ? f->rulenum : -1); 57698943Sluigi} 57798943Sluigi 57898943Sluigi/* 57998943Sluigi * IMPORTANT: the hash function for dynamic rules must be commutative 58099475Sluigi * in source and destination (ip,port), because rules are bidirectional 58198943Sluigi * and we want to find both in the same bucket. 58298943Sluigi */ 58398943Sluigistatic __inline int 58498943Sluigihash_packet(struct ipfw_flow_id *id) 58598943Sluigi{ 58698943Sluigi u_int32_t i; 58798943Sluigi 58898943Sluigi i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port); 58998943Sluigi i &= (curr_dyn_buckets - 1); 59098943Sluigi return i; 59198943Sluigi} 59298943Sluigi 59398943Sluigi/** 59498943Sluigi * unlink a dynamic rule from a chain. prev is a pointer to 59598943Sluigi * the previous one, q is a pointer to the rule to delete, 59698943Sluigi * head is a pointer to the head of the queue. 59798943Sluigi * Modifies q and potentially also head. 59898943Sluigi */ 59998943Sluigi#define UNLINK_DYN_RULE(prev, head, q) { \ 60098943Sluigi ipfw_dyn_rule *old_q = q; \ 60198943Sluigi \ 60298943Sluigi /* remove a refcount to the parent */ \ 60398943Sluigi if (q->dyn_type == O_LIMIT) \ 60498943Sluigi q->parent->count--; \ 60598943Sluigi DEB(printf("-- unlink entry 0x%08x %d -> 0x%08x %d, %d left\n", \ 60698943Sluigi (q->id.src_ip), (q->id.src_port), \ 60798943Sluigi (q->id.dst_ip), (q->id.dst_port), dyn_count-1 ); ) \ 60898943Sluigi if (prev != NULL) \ 60998943Sluigi prev->next = q = q->next; \ 61098943Sluigi else \ 61198943Sluigi head = q = q->next; \ 61298943Sluigi dyn_count--; \ 61398943Sluigi free(old_q, M_IPFW); } 61498943Sluigi 61598943Sluigi#define TIME_LEQ(a,b) ((int)((a)-(b)) <= 0) 61698943Sluigi 61798943Sluigi/** 61898943Sluigi * Remove dynamic rules pointing to "rule", or all of them if rule == NULL. 61998943Sluigi * 62098943Sluigi * If keep_me == NULL, rules are deleted even if not expired, 62198943Sluigi * otherwise only expired rules are removed. 62298943Sluigi * 62398943Sluigi * The value of the second parameter is also used to point to identify 62498943Sluigi * a rule we absolutely do not want to remove (e.g. because we are 62598943Sluigi * holding a reference to it -- this is the case with O_LIMIT_PARENT 62698943Sluigi * rules). The pointer is only used for comparison, so any non-null 62798943Sluigi * value will do. 62898943Sluigi */ 62998943Sluigistatic void 63098943Sluigiremove_dyn_rule(struct ip_fw *rule, ipfw_dyn_rule *keep_me) 63198943Sluigi{ 63298943Sluigi static u_int32_t last_remove = 0; 63398943Sluigi 63498943Sluigi#define FORCE (keep_me == NULL) 63598943Sluigi 63698943Sluigi ipfw_dyn_rule *prev, *q; 63798943Sluigi int i, pass = 0, max_pass = 0; 63898943Sluigi 63998943Sluigi if (ipfw_dyn_v == NULL || dyn_count == 0) 64098943Sluigi return; 64198943Sluigi /* do not expire more than once per second, it is useless */ 64298943Sluigi if (!FORCE && last_remove == time_second) 64398943Sluigi return; 64498943Sluigi last_remove = time_second; 64598943Sluigi 64698943Sluigi /* 64798943Sluigi * because O_LIMIT refer to parent rules, during the first pass only 64898943Sluigi * remove child and mark any pending LIMIT_PARENT, and remove 64998943Sluigi * them in a second pass. 65098943Sluigi */ 65198943Sluiginext_pass: 65298943Sluigi for (i = 0 ; i < curr_dyn_buckets ; i++) { 65398943Sluigi for (prev=NULL, q = ipfw_dyn_v[i] ; q ; ) { 65498943Sluigi /* 65598943Sluigi * Logic can become complex here, so we split tests. 65698943Sluigi */ 65798943Sluigi if (q == keep_me) 65898943Sluigi goto next; 65998943Sluigi if (rule != NULL && rule != q->rule) 66098943Sluigi goto next; /* not the one we are looking for */ 66198943Sluigi if (q->dyn_type == O_LIMIT_PARENT) { 66298943Sluigi /* 66398943Sluigi * handle parent in the second pass, 66498943Sluigi * record we need one. 66598943Sluigi */ 66698943Sluigi max_pass = 1; 66798943Sluigi if (pass == 0) 66898943Sluigi goto next; 66998943Sluigi if (FORCE && q->count != 0 ) { 67098943Sluigi /* XXX should not happen! */ 67198943Sluigi printf( "OUCH! cannot remove rule," 67298943Sluigi " count %d\n", q->count); 67398943Sluigi } 67498943Sluigi } else { 67598943Sluigi if (!FORCE && 67698943Sluigi !TIME_LEQ( q->expire, time_second )) 67798943Sluigi goto next; 67898943Sluigi } 67998943Sluigi UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q); 68098943Sluigi continue; 68198943Sluiginext: 68298943Sluigi prev=q; 68398943Sluigi q=q->next; 68498943Sluigi } 68598943Sluigi } 68698943Sluigi if (pass++ < max_pass) 68798943Sluigi goto next_pass; 68898943Sluigi} 68998943Sluigi 69098943Sluigi 69198943Sluigi/** 69298943Sluigi * lookup a dynamic rule. 69398943Sluigi */ 69498943Sluigistatic ipfw_dyn_rule * 695100004Sluigilookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction, 696100004Sluigi struct tcphdr *tcp) 69798943Sluigi{ 69898943Sluigi /* 69998943Sluigi * stateful ipfw extensions. 70098943Sluigi * Lookup into dynamic session queue 70198943Sluigi */ 70298943Sluigi#define MATCH_REVERSE 0 70398943Sluigi#define MATCH_FORWARD 1 70498943Sluigi#define MATCH_NONE 2 70598943Sluigi#define MATCH_UNKNOWN 3 70698943Sluigi int i, dir = MATCH_NONE; 70798943Sluigi ipfw_dyn_rule *prev, *q=NULL; 70898943Sluigi 70998943Sluigi if (ipfw_dyn_v == NULL) 71098943Sluigi goto done; /* not found */ 71198943Sluigi i = hash_packet( pkt ); 71298943Sluigi for (prev=NULL, q = ipfw_dyn_v[i] ; q != NULL ; ) { 71398943Sluigi if (q->dyn_type == O_LIMIT_PARENT) 71498943Sluigi goto next; 71598943Sluigi if (TIME_LEQ( q->expire, time_second)) { /* expire entry */ 71698943Sluigi UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q); 71798943Sluigi continue; 71898943Sluigi } 71998943Sluigi if ( pkt->proto == q->id.proto) { 72098943Sluigi if (pkt->src_ip == q->id.src_ip && 72198943Sluigi pkt->dst_ip == q->id.dst_ip && 72298943Sluigi pkt->src_port == q->id.src_port && 72398943Sluigi pkt->dst_port == q->id.dst_port ) { 72498943Sluigi dir = MATCH_FORWARD; 72598943Sluigi break; 72698943Sluigi } 72798943Sluigi if (pkt->src_ip == q->id.dst_ip && 72898943Sluigi pkt->dst_ip == q->id.src_ip && 72998943Sluigi pkt->src_port == q->id.dst_port && 73098943Sluigi pkt->dst_port == q->id.src_port ) { 73198943Sluigi dir = MATCH_REVERSE; 73298943Sluigi break; 73398943Sluigi } 73498943Sluigi } 73598943Sluiginext: 73698943Sluigi prev = q; 73798943Sluigi q = q->next; 73898943Sluigi } 73998943Sluigi if (q == NULL) 74098943Sluigi goto done; /* q = NULL, not found */ 74198943Sluigi 74298943Sluigi if ( prev != NULL) { /* found and not in front */ 74398943Sluigi prev->next = q->next; 74498943Sluigi q->next = ipfw_dyn_v[i]; 74598943Sluigi ipfw_dyn_v[i] = q; 74698943Sluigi } 74798943Sluigi if (pkt->proto == IPPROTO_TCP) { /* update state according to flags */ 74898943Sluigi u_char flags = pkt->flags & (TH_FIN|TH_SYN|TH_RST); 74998943Sluigi 75098943Sluigi#define BOTH_SYN (TH_SYN | (TH_SYN << 8)) 75198943Sluigi#define BOTH_FIN (TH_FIN | (TH_FIN << 8)) 75298943Sluigi q->state |= (dir == MATCH_FORWARD ) ? flags : (flags << 8); 75398943Sluigi switch (q->state) { 75498943Sluigi case TH_SYN: /* opening */ 75598943Sluigi q->expire = time_second + dyn_syn_lifetime; 75698943Sluigi break; 75798943Sluigi case BOTH_SYN: /* move to established */ 75898943Sluigi case BOTH_SYN | TH_FIN : /* one side tries to close */ 75998943Sluigi case BOTH_SYN | (TH_FIN << 8) : 760100004Sluigi if (tcp) { 761100004Sluigi#define _SEQ_GE(a,b) ((int)(a) - (int)(b) >= 0) 762100004Sluigi u_int32_t ack = ntohl(tcp->th_ack); 763100004Sluigi if (dir == MATCH_FORWARD) { 764100004Sluigi if (q->ack_fwd == 0 || _SEQ_GE(ack, q->ack_fwd)) 765100004Sluigi q->ack_fwd = ack; 766100004Sluigi else { /* ignore out-of-sequence */ 767100004Sluigi break; 768100004Sluigi } 769100004Sluigi } else { 770100004Sluigi if (q->ack_rev == 0 || _SEQ_GE(ack, q->ack_rev)) 771100004Sluigi q->ack_rev = ack; 772100004Sluigi else { /* ignore out-of-sequence */ 773100004Sluigi break; 774100004Sluigi } 775100004Sluigi } 776100004Sluigi } 77798943Sluigi q->expire = time_second + dyn_ack_lifetime; 77898943Sluigi break; 77998943Sluigi case BOTH_SYN | BOTH_FIN: /* both sides closed */ 78098943Sluigi q->expire = time_second + dyn_fin_lifetime; 78198943Sluigi break; 78298943Sluigi default: 78398943Sluigi#if 0 78498943Sluigi /* 78598943Sluigi * reset or some invalid combination, but can also 78698943Sluigi * occur if we use keep-state the wrong way. 78798943Sluigi */ 78898943Sluigi if ( (q->state & ((TH_RST << 8)|TH_RST)) == 0) 78998943Sluigi printf("invalid state: 0x%x\n", q->state); 79098943Sluigi#endif 79198943Sluigi q->expire = time_second + dyn_rst_lifetime; 79298943Sluigi break; 79398943Sluigi } 79498943Sluigi } else if (pkt->proto == IPPROTO_UDP) { 79598943Sluigi q->expire = time_second + dyn_udp_lifetime; 79698943Sluigi } else { 79798943Sluigi /* other protocols */ 79898943Sluigi q->expire = time_second + dyn_short_lifetime; 79998943Sluigi } 80098943Sluigidone: 80198943Sluigi if (match_direction) 80298943Sluigi *match_direction = dir; 80398943Sluigi return q; 80498943Sluigi} 80598943Sluigi 80698943Sluigistatic void 80798943Sluigirealloc_dynamic_table(void) 80898943Sluigi{ 80998943Sluigi /* try reallocation, make sure we have a power of 2 */ 81098943Sluigi 81198943Sluigi if ((dyn_buckets & (dyn_buckets-1)) != 0) { /* not a power of 2 */ 81298943Sluigi dyn_buckets = curr_dyn_buckets; /* reset */ 81398943Sluigi return; 81498943Sluigi } 81598943Sluigi curr_dyn_buckets = dyn_buckets; 81698943Sluigi if (ipfw_dyn_v != NULL) 81798943Sluigi free(ipfw_dyn_v, M_IPFW); 81898943Sluigi ipfw_dyn_v = malloc(curr_dyn_buckets * sizeof(ipfw_dyn_rule *), 81998943Sluigi M_IPFW, M_DONTWAIT | M_ZERO); 82098943Sluigi} 82198943Sluigi 82298943Sluigi/** 82398943Sluigi * Install state of type 'type' for a dynamic session. 82498943Sluigi * The hash table contains two type of rules: 82598943Sluigi * - regular rules (O_KEEP_STATE) 82698943Sluigi * - rules for sessions with limited number of sess per user 82798943Sluigi * (O_LIMIT). When they are created, the parent is 82898943Sluigi * increased by 1, and decreased on delete. In this case, 82998943Sluigi * the third parameter is the parent rule and not the chain. 83098943Sluigi * - "parent" rules for the above (O_LIMIT_PARENT). 83198943Sluigi */ 83298943Sluigistatic ipfw_dyn_rule * 83398943Sluigiadd_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule) 83498943Sluigi{ 83598943Sluigi ipfw_dyn_rule *r; 83698943Sluigi int i; 83798943Sluigi 83898943Sluigi if (ipfw_dyn_v == NULL || 83998943Sluigi (dyn_count == 0 && dyn_buckets != curr_dyn_buckets)) { 84098943Sluigi realloc_dynamic_table(); 84198943Sluigi if (ipfw_dyn_v == NULL) 84298943Sluigi return NULL; /* failed ! */ 84398943Sluigi } 84498943Sluigi i = hash_packet(id); 84598943Sluigi 84698943Sluigi r = malloc(sizeof *r, M_IPFW, M_DONTWAIT | M_ZERO); 84798943Sluigi if (r == NULL) { 84898943Sluigi printf ("sorry cannot allocate state\n"); 84998943Sluigi return NULL; 85098943Sluigi } 85198943Sluigi 85298943Sluigi /* increase refcount on parent, and set pointer */ 85398943Sluigi if (dyn_type == O_LIMIT) { 85498943Sluigi ipfw_dyn_rule *parent = (ipfw_dyn_rule *)rule; 85598943Sluigi if ( parent->dyn_type != O_LIMIT_PARENT) 85698943Sluigi panic("invalid parent"); 85798943Sluigi parent->count++; 85898943Sluigi r->parent = parent; 85998943Sluigi rule = parent->rule; 86098943Sluigi } 86198943Sluigi 86298943Sluigi r->id = *id; 86398943Sluigi r->expire = time_second + dyn_syn_lifetime; 86498943Sluigi r->rule = rule; 86598943Sluigi r->dyn_type = dyn_type; 86698943Sluigi r->pcnt = r->bcnt = 0; 86798943Sluigi r->count = 0; 86898943Sluigi 86998943Sluigi r->bucket = i; 87098943Sluigi r->next = ipfw_dyn_v[i]; 87198943Sluigi ipfw_dyn_v[i] = r; 87298943Sluigi dyn_count++; 87398943Sluigi DEB(printf("-- add dyn entry ty %d 0x%08x %d -> 0x%08x %d, total %d\n", 87498943Sluigi dyn_type, 87598943Sluigi (r->id.src_ip), (r->id.src_port), 87698943Sluigi (r->id.dst_ip), (r->id.dst_port), 87798943Sluigi dyn_count ); ) 87898943Sluigi return r; 87998943Sluigi} 88098943Sluigi 88198943Sluigi/** 88298943Sluigi * lookup dynamic parent rule using pkt and rule as search keys. 88398943Sluigi * If the lookup fails, then install one. 88498943Sluigi */ 88598943Sluigistatic ipfw_dyn_rule * 88698943Sluigilookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule) 88798943Sluigi{ 88898943Sluigi ipfw_dyn_rule *q; 88998943Sluigi int i; 89098943Sluigi 89198943Sluigi if (ipfw_dyn_v) { 89298943Sluigi i = hash_packet( pkt ); 89398943Sluigi for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next) 89498943Sluigi if (q->dyn_type == O_LIMIT_PARENT && 89598943Sluigi rule== q->rule && 89698943Sluigi pkt->proto == q->id.proto && 89798943Sluigi pkt->src_ip == q->id.src_ip && 89898943Sluigi pkt->dst_ip == q->id.dst_ip && 89998943Sluigi pkt->src_port == q->id.src_port && 90098943Sluigi pkt->dst_port == q->id.dst_port) { 90198943Sluigi q->expire = time_second + dyn_short_lifetime; 90298943Sluigi DEB(printf("lookup_dyn_parent found 0x%p\n",q);) 90398943Sluigi return q; 90498943Sluigi } 90598943Sluigi } 90698943Sluigi return add_dyn_rule(pkt, O_LIMIT_PARENT, rule); 90798943Sluigi} 90898943Sluigi 90998943Sluigi/** 91098943Sluigi * Install dynamic state for rule type cmd->o.opcode 91198943Sluigi * 91298943Sluigi * Returns 1 (failure) if state is not installed because of errors or because 91398943Sluigi * session limitations are enforced. 91498943Sluigi */ 91598943Sluigistatic int 91698943Sluigiinstall_state(struct ip_fw *rule, ipfw_insn_limit *cmd, 91798943Sluigi struct ip_fw_args *args) 91898943Sluigi{ 91998943Sluigi static int last_log; 92098943Sluigi 92198943Sluigi ipfw_dyn_rule *q; 92298943Sluigi 92398943Sluigi DEB(printf("-- install state type %d 0x%08x %u -> 0x%08x %u\n", 92498943Sluigi cmd->o.opcode, 92598943Sluigi (args->f_id.src_ip), (args->f_id.src_port), 92698943Sluigi (args->f_id.dst_ip), (args->f_id.dst_port) );) 92798943Sluigi 928100004Sluigi q = lookup_dyn_rule(&args->f_id, NULL, NULL); 92998943Sluigi 93098943Sluigi if (q != NULL) { /* should never occur */ 93198943Sluigi if (last_log != time_second) { 93298943Sluigi last_log = time_second; 93398943Sluigi printf(" install_state: entry already present, done\n"); 93498943Sluigi } 93598943Sluigi return 0; 93698943Sluigi } 93798943Sluigi 93898943Sluigi if (dyn_count >= dyn_max) 93998943Sluigi /* 94098943Sluigi * Run out of slots, try to remove any expired rule. 94198943Sluigi */ 94298943Sluigi remove_dyn_rule(NULL, (ipfw_dyn_rule *)1); 94398943Sluigi 94498943Sluigi if (dyn_count >= dyn_max) { 94598943Sluigi if (last_log != time_second) { 94698943Sluigi last_log = time_second; 94798943Sluigi printf("install_state: Too many dynamic rules\n"); 94898943Sluigi } 94998943Sluigi return 1; /* cannot install, notify caller */ 95098943Sluigi } 95198943Sluigi 95298943Sluigi switch (cmd->o.opcode) { 95398943Sluigi case O_KEEP_STATE: /* bidir rule */ 95498943Sluigi add_dyn_rule(&args->f_id, O_KEEP_STATE, rule); 95598943Sluigi break; 95698943Sluigi 95798943Sluigi case O_LIMIT: /* limit number of sessions */ 95898943Sluigi { 95998943Sluigi u_int16_t limit_mask = cmd->limit_mask; 96098943Sluigi struct ipfw_flow_id id; 96198943Sluigi ipfw_dyn_rule *parent; 96298943Sluigi 96398943Sluigi DEB(printf("installing dyn-limit rule %d\n", cmd->conn_limit);) 96498943Sluigi 96598943Sluigi id.dst_ip = id.src_ip = 0; 96698943Sluigi id.dst_port = id.src_port = 0; 96798943Sluigi id.proto = args->f_id.proto; 96898943Sluigi 96998943Sluigi if (limit_mask & DYN_SRC_ADDR) 97098943Sluigi id.src_ip = args->f_id.src_ip; 97198943Sluigi if (limit_mask & DYN_DST_ADDR) 97298943Sluigi id.dst_ip = args->f_id.dst_ip; 97398943Sluigi if (limit_mask & DYN_SRC_PORT) 97498943Sluigi id.src_port = args->f_id.src_port; 97598943Sluigi if (limit_mask & DYN_DST_PORT) 97698943Sluigi id.dst_port = args->f_id.dst_port; 97798943Sluigi parent = lookup_dyn_parent(&id, rule); 97898943Sluigi if (parent == NULL) { 97998943Sluigi printf("add parent failed\n"); 98098943Sluigi return 1; 98198943Sluigi } 98298943Sluigi if (parent->count >= cmd->conn_limit) { 98398943Sluigi /* 98498943Sluigi * See if we can remove some expired rule. 98598943Sluigi */ 98698943Sluigi remove_dyn_rule(rule, parent); 98798943Sluigi if (parent->count >= cmd->conn_limit) { 98898943Sluigi if (fw_verbose && last_log != time_second) { 98998943Sluigi last_log = time_second; 99098943Sluigi printf( 99198943Sluigi "drop session, too many entries\n"); 99298943Sluigi } 99398943Sluigi return 1; 99498943Sluigi } 99598943Sluigi } 99698943Sluigi add_dyn_rule(&args->f_id, O_LIMIT, (struct ip_fw *)parent); 99798943Sluigi } 99898943Sluigi break; 99998943Sluigi default: 100098943Sluigi printf("unknown dynamic rule type %u\n", cmd->o.opcode); 100198943Sluigi return 1; 100298943Sluigi } 1003100004Sluigi lookup_dyn_rule(&args->f_id, NULL, NULL); /* XXX just set lifetime */ 100498943Sluigi return 0; 100598943Sluigi} 100698943Sluigi 1007100004Sluigi/* 1008100004Sluigi * Transmit a TCP packet, containing either a RST or a keepalive. 1009100004Sluigi * When flags & TH_RST, we are sending a RST packet, because of a 1010100004Sluigi * "reset" action matched the packet. 1011100004Sluigi * Otherwise we are sending a keepalive, and flags & TH_ 1012100004Sluigi */ 101399475Sluigistatic void 1014100004Sluigisend_pkt(struct ipfw_flow_id *id, u_int32_t seq, u_int32_t ack, int flags) 101599475Sluigi{ 101699475Sluigi struct mbuf *m; 1017100004Sluigi struct ip *ip; 101899475Sluigi struct tcphdr *tcp; 101999475Sluigi struct route sro; /* fake route */ 102099475Sluigi 102199475Sluigi MGETHDR(m, M_DONTWAIT, MT_HEADER); 102299475Sluigi if (m == 0) 102399475Sluigi return; 102499475Sluigi m->m_pkthdr.rcvif = (struct ifnet *)0; 102599475Sluigi m->m_pkthdr.len = m->m_len = sizeof(struct ip) + sizeof(struct tcphdr); 102699475Sluigi m->m_data += max_linkhdr; 102799475Sluigi 1028100004Sluigi ip = mtod(m, struct ip *); 1029100004Sluigi bzero(ip, m->m_len); 1030100004Sluigi tcp = (struct tcphdr *)(ip + 1); /* no IP options */ 103199475Sluigi ip->ip_p = IPPROTO_TCP; 1032100004Sluigi tcp->th_off = 5; 1033100004Sluigi /* 1034100004Sluigi * Assume we are sending a RST (or a keepalive in the reverse 1035100004Sluigi * direction), swap src and destination addresses and ports. 1036100004Sluigi */ 1037100004Sluigi ip->ip_src.s_addr = htonl(id->dst_ip); 1038100004Sluigi ip->ip_dst.s_addr = htonl(id->src_ip); 1039100004Sluigi tcp->th_sport = htons(id->dst_port); 1040100004Sluigi tcp->th_dport = htons(id->src_port); 1041100004Sluigi if (flags & TH_RST) { /* we are sending a RST */ 1042100004Sluigi if (flags & TH_ACK) { 1043100004Sluigi tcp->th_seq = htonl(ack); 1044100004Sluigi tcp->th_ack = htonl(0); 1045100004Sluigi tcp->th_flags = TH_RST; 1046100004Sluigi } else { 1047100004Sluigi if (flags & TH_SYN) 1048100004Sluigi seq++; 1049100004Sluigi tcp->th_seq = htonl(0); 1050100004Sluigi tcp->th_ack = htonl(seq); 1051100004Sluigi tcp->th_flags = TH_RST | TH_ACK; 1052100004Sluigi } 105399475Sluigi } else { 1054100004Sluigi /* 1055100004Sluigi * We are sending a keepalive. flags & TH_SYN determines 1056100004Sluigi * the direction, forward if set, reverse if clear. 1057100004Sluigi * NOTE: seq and ack are always assumed to be correct 1058100004Sluigi * as set by the caller. This may be confusing... 1059100004Sluigi */ 1060100004Sluigi if (flags & TH_SYN) { 1061100004Sluigi /* 1062100004Sluigi * we have to rewrite the correct addresses! 1063100004Sluigi */ 1064100004Sluigi ip->ip_dst.s_addr = htonl(id->dst_ip); 1065100004Sluigi ip->ip_src.s_addr = htonl(id->src_ip); 1066100004Sluigi tcp->th_dport = htons(id->dst_port); 1067100004Sluigi tcp->th_sport = htons(id->src_port); 1068100004Sluigi } 1069100004Sluigi tcp->th_seq = htonl(seq); 1070100004Sluigi tcp->th_ack = htonl(ack); 1071100004Sluigi tcp->th_flags = TH_ACK; 107299475Sluigi } 1073100004Sluigi /* 1074100004Sluigi * set ip_len to the payload size so we can compute 1075100004Sluigi * the tcp checksum on the pseudoheader 1076100004Sluigi * XXX check this, could save a couple of words ? 1077100004Sluigi */ 1078100004Sluigi ip->ip_len = htons(sizeof(struct tcphdr)); 107999475Sluigi tcp->th_sum = in_cksum(m, m->m_pkthdr.len); 1080100004Sluigi /* 1081100004Sluigi * now fill fields left out earlier 1082100004Sluigi */ 108399475Sluigi ip->ip_ttl = ip_defttl; 108499475Sluigi ip->ip_len = m->m_pkthdr.len; 108599475Sluigi bzero (&sro, sizeof (sro)); 108699475Sluigi ip_rtaddr(ip->ip_dst, &sro); 108799475Sluigi ip_output(m, NULL, &sro, 0, NULL); 108899475Sluigi if (sro.ro_rt) 108999475Sluigi RTFREE(sro.ro_rt); 109099475Sluigi} 109199475Sluigi 109298943Sluigi/* 109398943Sluigi * sends a reject message, consuming the mbuf passed as an argument. 109498943Sluigi */ 109598943Sluigistatic void 109699475Sluigisend_reject(struct ip_fw_args *args, int code, int offset, int ip_len) 109798943Sluigi{ 1098101843Sphk 109998943Sluigi if (code != ICMP_REJECT_RST) /* Send an ICMP unreach */ 110099475Sluigi icmp_error(args->m, ICMP_UNREACH, code, 0L, 0); 110199475Sluigi else if (offset == 0 && args->f_id.proto == IPPROTO_TCP) { 110299475Sluigi struct tcphdr *const tcp = 110399475Sluigi L3HDR(struct tcphdr, mtod(args->m, struct ip *)); 110499475Sluigi if ( (tcp->th_flags & TH_RST) == 0) 1105100004Sluigi send_pkt(&(args->f_id), ntohl(tcp->th_seq), 1106100004Sluigi ntohl(tcp->th_ack), 1107100004Sluigi tcp->th_flags | TH_RST); 110899475Sluigi m_freem(args->m); 110999475Sluigi } else 111099475Sluigi m_freem(args->m); 111199475Sluigi args->m = NULL; 111298943Sluigi} 111398943Sluigi 111498943Sluigi/** 111598943Sluigi * 111698943Sluigi * Given an ip_fw *, lookup_next_rule will return a pointer 111798943Sluigi * to the next rule, which can be either the jump 111898943Sluigi * target (for skipto instructions) or the next one in the list (in 111998943Sluigi * all other cases including a missing jump target). 112098943Sluigi * The result is also written in the "next_rule" field of the rule. 112198943Sluigi * Backward jumps are not allowed, so start looking from the next 112298943Sluigi * rule... 112398943Sluigi * 112498943Sluigi * This never returns NULL -- in case we do not have an exact match, 112598943Sluigi * the next rule is returned. When the ruleset is changed, 112698943Sluigi * pointers are flushed so we are always correct. 112798943Sluigi */ 112898943Sluigi 112998943Sluigistatic struct ip_fw * 113098943Sluigilookup_next_rule(struct ip_fw *me) 113198943Sluigi{ 113298943Sluigi struct ip_fw *rule = NULL; 113398943Sluigi ipfw_insn *cmd; 113498943Sluigi 113598943Sluigi /* look for action, in case it is a skipto */ 113698943Sluigi cmd = ACTION_PTR(me); 113798943Sluigi if ( cmd->opcode == O_SKIPTO ) 113898943Sluigi for (rule = me->next; rule ; rule = rule->next) 113998943Sluigi if (rule->rulenum >= cmd->arg1) 114098943Sluigi break; 114198943Sluigi if (rule == NULL) /* failure or not a skipto */ 114298943Sluigi rule = me->next; 114398943Sluigi me->next_rule = rule; 114498943Sluigi return rule; 114598943Sluigi} 114698943Sluigi 114798943Sluigi/* 114898943Sluigi * The main check routine for the firewall. 114998943Sluigi * 115098943Sluigi * All arguments are in args so we can modify them and return them 115198943Sluigi * back to the caller. 115298943Sluigi * 115398943Sluigi * Parameters: 115498943Sluigi * 115598943Sluigi * args->m (in/out) The packet; we set to NULL when/if we nuke it. 115698943Sluigi * Starts with the IP header. 115798943Sluigi * args->eh (in) Mac header if present, or NULL for layer3 packet. 115898943Sluigi * args->oif Outgoing interface, or NULL if packet is incoming. 115998943Sluigi * The incoming interface is in the mbuf. (in) 116098943Sluigi * args->divert_rule (in/out) 116198943Sluigi * Skip up to the first rule past this rule number; 116298943Sluigi * upon return, non-zero port number for divert or tee. 116398943Sluigi * 116498943Sluigi * args->rule Pointer to the last matching rule (in/out) 116598943Sluigi * args->next_hop Socket we are forwarding to (out). 116698943Sluigi * args->f_id Addresses grabbed from the packet (out) 116798943Sluigi * 116898943Sluigi * Return value: 116998943Sluigi * 117098943Sluigi * IP_FW_PORT_DENY_FLAG the packet must be dropped. 117198943Sluigi * 0 The packet is to be accepted and routed normally OR 117298943Sluigi * the packet was denied/rejected and has been dropped; 117398943Sluigi * in the latter case, *m is equal to NULL upon return. 117498943Sluigi * port Divert the packet to port, with these caveats: 117598943Sluigi * 117698943Sluigi * - If IP_FW_PORT_TEE_FLAG is set, tee the packet instead 117798943Sluigi * of diverting it (ie, 'ipfw tee'). 117898943Sluigi * 117998943Sluigi * - If IP_FW_PORT_DYNT_FLAG is set, interpret the lower 118098943Sluigi * 16 bits as a dummynet pipe number instead of diverting 118198943Sluigi */ 118298943Sluigi 118398943Sluigistatic int 118498943Sluigiipfw_chk(struct ip_fw_args *args) 118598943Sluigi{ 118698943Sluigi /* 118798943Sluigi * Local variables hold state during the processing of a packet. 118898943Sluigi * 118998943Sluigi * IMPORTANT NOTE: to speed up the processing of rules, there 119098943Sluigi * are some assumption on the values of the variables, which 119198943Sluigi * are documented here. Should you change them, please check 119298943Sluigi * the implementation of the various instructions to make sure 119398943Sluigi * that they still work. 119498943Sluigi */ 119598943Sluigi /* 119698943Sluigi * args->eh The MAC header. It is non-null for a layer2 119798943Sluigi * packet, it is NULL for a layer-3 packet. 119898943Sluigi * 119998943Sluigi * m | args->m Pointer to the mbuf, as received from the caller. 120098943Sluigi * It may change if ipfw_chk() does an m_pullup, or if it 120198943Sluigi * consumes the packet because it calls send_reject(). 120298943Sluigi * XXX This has to change, so that ipfw_chk() never modifies 120398943Sluigi * or consumes the buffer. 120498943Sluigi * ip is simply an alias of the value of m, and it is kept 120598943Sluigi * in sync with it (the packet is supposed to start with 120698943Sluigi * the ip header). 120798943Sluigi */ 120898943Sluigi struct mbuf *m = args->m; 120998943Sluigi struct ip *ip = mtod(m, struct ip *); 121098943Sluigi 121198943Sluigi /* 121298943Sluigi * oif | args->oif If NULL, ipfw_chk has been called on the 121398943Sluigi * inbound path (ether_input, bdg_forward, ip_input). 121498943Sluigi * If non-NULL, ipfw_chk has been called on the outbound path 121598943Sluigi * (ether_output, ip_output). 121698943Sluigi */ 121798943Sluigi struct ifnet *oif = args->oif; 121898943Sluigi 121998943Sluigi struct ip_fw *f = NULL; /* matching rule */ 122098943Sluigi int retval = 0; 122198943Sluigi 122298943Sluigi /* 122398943Sluigi * hlen The length of the IPv4 header. 122498943Sluigi * hlen >0 means we have an IPv4 packet. 122598943Sluigi */ 122698943Sluigi u_int hlen = 0; /* hlen >0 means we have an IP pkt */ 122798943Sluigi 122898943Sluigi /* 122998943Sluigi * offset The offset of a fragment. offset != 0 means that 123098943Sluigi * we have a fragment at this offset of an IPv4 packet. 123198943Sluigi * offset == 0 means that (if this is an IPv4 packet) 123298943Sluigi * this is the first or only fragment. 123398943Sluigi */ 123498943Sluigi u_short offset = 0; 123598943Sluigi 123698943Sluigi /* 123798943Sluigi * Local copies of addresses. They are only valid if we have 123898943Sluigi * an IP packet. 123998943Sluigi * 124098943Sluigi * proto The protocol. Set to 0 for non-ip packets, 124198943Sluigi * or to the protocol read from the packet otherwise. 124298943Sluigi * proto != 0 means that we have an IPv4 packet. 124398943Sluigi * 124498943Sluigi * src_port, dst_port port numbers, in HOST format. Only 124598943Sluigi * valid for TCP and UDP packets. 124698943Sluigi * 124798943Sluigi * src_ip, dst_ip ip addresses, in NETWORK format. 124898943Sluigi * Only valid for IPv4 packets. 124998943Sluigi */ 125098943Sluigi u_int8_t proto; 125198943Sluigi u_int16_t src_port = 0, dst_port = 0; /* NOTE: host format */ 125298943Sluigi struct in_addr src_ip, dst_ip; /* NOTE: network format */ 125398943Sluigi u_int16_t ip_len=0; 125498943Sluigi int dyn_dir = MATCH_UNKNOWN; 125598943Sluigi ipfw_dyn_rule *q = NULL; 125698943Sluigi 125798943Sluigi /* 125898943Sluigi * dyn_dir = MATCH_UNKNOWN when rules unchecked, 125998943Sluigi * MATCH_NONE when checked and not matched (q = NULL), 126098943Sluigi * MATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL) 126198943Sluigi */ 126298943Sluigi 126398943Sluigi if (args->eh == NULL || /* layer 3 packet */ 126498943Sluigi ( m->m_pkthdr.len >= sizeof(struct ip) && 126598943Sluigi ntohs(args->eh->ether_type) == ETHERTYPE_IP)) 126698943Sluigi hlen = ip->ip_hl << 2; 126798943Sluigi 126898943Sluigi /* 126998943Sluigi * Collect parameters into local variables for faster matching. 127098943Sluigi */ 127198943Sluigi if (hlen == 0) { /* do not grab addresses for non-ip pkts */ 127298943Sluigi proto = args->f_id.proto = 0; /* mark f_id invalid */ 127398943Sluigi goto after_ip_checks; 127498943Sluigi } 127598943Sluigi 127698943Sluigi proto = args->f_id.proto = ip->ip_p; 127798943Sluigi src_ip = ip->ip_src; 127898943Sluigi dst_ip = ip->ip_dst; 127998943Sluigi if (args->eh != NULL) { /* layer 2 packets are as on the wire */ 128098943Sluigi offset = ntohs(ip->ip_off) & IP_OFFMASK; 128198943Sluigi ip_len = ntohs(ip->ip_len); 128298943Sluigi } else { 128398943Sluigi offset = ip->ip_off & IP_OFFMASK; 128498943Sluigi ip_len = ip->ip_len; 128598943Sluigi } 128698943Sluigi 128798943Sluigi#define PULLUP_TO(len) \ 128898943Sluigi do { \ 128998943Sluigi if ((m)->m_len < (len)) { \ 129098943Sluigi args->m = m = m_pullup(m, (len)); \ 129198943Sluigi if (m == 0) \ 129298943Sluigi goto pullup_failed; \ 129398943Sluigi ip = mtod(m, struct ip *); \ 129498943Sluigi } \ 129598943Sluigi } while (0) 129698943Sluigi 129798943Sluigi if (offset == 0) { 129898943Sluigi switch (proto) { 129998943Sluigi case IPPROTO_TCP: 130098943Sluigi { 130198943Sluigi struct tcphdr *tcp; 130298943Sluigi 130398943Sluigi PULLUP_TO(hlen + sizeof(struct tcphdr)); 130498943Sluigi tcp = L3HDR(struct tcphdr, ip); 130598943Sluigi dst_port = tcp->th_dport; 130698943Sluigi src_port = tcp->th_sport; 130798943Sluigi args->f_id.flags = tcp->th_flags; 130898943Sluigi } 130998943Sluigi break; 131098943Sluigi 131198943Sluigi case IPPROTO_UDP: 131298943Sluigi { 131398943Sluigi struct udphdr *udp; 131498943Sluigi 131598943Sluigi PULLUP_TO(hlen + sizeof(struct udphdr)); 131698943Sluigi udp = L3HDR(struct udphdr, ip); 131798943Sluigi dst_port = udp->uh_dport; 131898943Sluigi src_port = udp->uh_sport; 131998943Sluigi } 132098943Sluigi break; 132198943Sluigi 132298943Sluigi case IPPROTO_ICMP: 132398943Sluigi PULLUP_TO(hlen + 4); /* type, code and checksum. */ 132498943Sluigi args->f_id.flags = L3HDR(struct icmp, ip)->icmp_type; 132598943Sluigi break; 132698943Sluigi 132798943Sluigi default: 132898943Sluigi break; 132998943Sluigi } 133098943Sluigi#undef PULLUP_TO 133198943Sluigi } 133298943Sluigi 133398943Sluigi args->f_id.src_ip = ntohl(src_ip.s_addr); 133498943Sluigi args->f_id.dst_ip = ntohl(dst_ip.s_addr); 133598943Sluigi args->f_id.src_port = src_port = ntohs(src_port); 133698943Sluigi args->f_id.dst_port = dst_port = ntohs(dst_port); 133798943Sluigi 133898943Sluigiafter_ip_checks: 133998943Sluigi if (args->rule) { 134098943Sluigi /* 134198943Sluigi * Packet has already been tagged. Look for the next rule 134298943Sluigi * to restart processing. 134398943Sluigi * 134498943Sluigi * If fw_one_pass != 0 then just accept it. 134598943Sluigi * XXX should not happen here, but optimized out in 134698943Sluigi * the caller. 134798943Sluigi */ 134898943Sluigi if (fw_one_pass) 134998943Sluigi return 0; 135098943Sluigi 135198943Sluigi f = args->rule->next_rule; 135298943Sluigi if (f == NULL) 135398943Sluigi f = lookup_next_rule(args->rule); 135498943Sluigi } else { 135598943Sluigi /* 135698943Sluigi * Find the starting rule. It can be either the first 135798943Sluigi * one, or the one after divert_rule if asked so. 135898943Sluigi */ 135998943Sluigi int skipto = args->divert_rule; 136098943Sluigi 136198943Sluigi f = layer3_chain; 136298943Sluigi if (args->eh == NULL && skipto != 0) { 136398943Sluigi if (skipto >= IPFW_DEFAULT_RULE) 136498943Sluigi return(IP_FW_PORT_DENY_FLAG); /* invalid */ 136598943Sluigi while (f && f->rulenum <= skipto) 136698943Sluigi f = f->next; 136798943Sluigi if (f == NULL) /* drop packet */ 136898943Sluigi return(IP_FW_PORT_DENY_FLAG); 136998943Sluigi } 137098943Sluigi } 137198943Sluigi args->divert_rule = 0; /* reset to avoid confusion later */ 137298943Sluigi 137398943Sluigi /* 137498943Sluigi * Now scan the rules, and parse microinstructions for each rule. 137598943Sluigi */ 137698943Sluigi for (; f; f = f->next) { 137798943Sluigi int l, cmdlen; 137898943Sluigi ipfw_insn *cmd; 137998943Sluigi int skip_or; /* skip rest of OR block */ 138098943Sluigi 138198943Sluigiagain: 1382101628Sluigi if (set_disable & (1 << f->set) ) 1383101628Sluigi continue; 1384101628Sluigi 138598943Sluigi skip_or = 0; 138698943Sluigi for (l = f->cmd_len, cmd = f->cmd ; l > 0 ; 138798943Sluigi l -= cmdlen, cmd += cmdlen) { 138899622Sluigi int match; 138998943Sluigi 139098943Sluigi /* 139198943Sluigi * check_body is a jump target used when we find a 139298943Sluigi * CHECK_STATE, and need to jump to the body of 139398943Sluigi * the target rule. 139498943Sluigi */ 139598943Sluigi 139698943Sluigicheck_body: 139798943Sluigi cmdlen = F_LEN(cmd); 139898943Sluigi /* 139998943Sluigi * An OR block (insn_1 || .. || insn_n) has the 140098943Sluigi * F_OR bit set in all but the last instruction. 140198943Sluigi * The first match will set "skip_or", and cause 140298943Sluigi * the following instructions to be skipped until 140398943Sluigi * past the one with the F_OR bit clear. 140498943Sluigi */ 140598943Sluigi if (skip_or) { /* skip this instruction */ 140698943Sluigi if ((cmd->len & F_OR) == 0) 140798943Sluigi skip_or = 0; /* next one is good */ 140898943Sluigi continue; 140998943Sluigi } 141099622Sluigi match = 0; /* set to 1 if we succeed */ 141199622Sluigi 141298943Sluigi switch (cmd->opcode) { 141399622Sluigi /* 141499622Sluigi * The first set of opcodes compares the packet's 141599622Sluigi * fields with some pattern, setting 'match' if a 141699622Sluigi * match is found. At the end of the loop there is 141799622Sluigi * logic to deal with F_NOT and F_OR flags associated 141899622Sluigi * with the opcode. 141999622Sluigi */ 142098943Sluigi case O_NOP: 142199622Sluigi match = 1; 142299622Sluigi break; 142398943Sluigi 142498943Sluigi case O_FORWARD_MAC: 142598943Sluigi printf("ipfw: opcode %d unimplemented\n", 142698943Sluigi cmd->opcode); 142799622Sluigi break; 142898943Sluigi 142998943Sluigi case O_GID: 143098943Sluigi case O_UID: 143198943Sluigi /* 143298943Sluigi * We only check offset == 0 && proto != 0, 143398943Sluigi * as this ensures that we have an IPv4 143498943Sluigi * packet with the ports info. 143598943Sluigi */ 143698943Sluigi if (offset!=0) 143799622Sluigi break; 143898943Sluigi { 143998943Sluigi struct inpcbinfo *pi; 144098943Sluigi int wildcard; 144198943Sluigi struct inpcb *pcb; 144298943Sluigi 144398943Sluigi if (proto == IPPROTO_TCP) { 144498943Sluigi wildcard = 0; 144598943Sluigi pi = &tcbinfo; 144698943Sluigi } else if (proto == IPPROTO_UDP) { 144798943Sluigi wildcard = 1; 144898943Sluigi pi = &udbinfo; 144998943Sluigi } else 145099622Sluigi break; 145198943Sluigi 145298943Sluigi pcb = (oif) ? 145398943Sluigi in_pcblookup_hash(pi, 145498943Sluigi dst_ip, htons(dst_port), 145598943Sluigi src_ip, htons(src_port), 145698943Sluigi wildcard, oif) : 145798943Sluigi in_pcblookup_hash(pi, 145898943Sluigi src_ip, htons(src_port), 145998943Sluigi dst_ip, htons(dst_port), 146098943Sluigi wildcard, NULL); 146198943Sluigi 146298943Sluigi if (pcb == NULL || pcb->inp_socket == NULL) 146399622Sluigi break; 146499622Sluigi#if __FreeBSD_version < 500034 146599622Sluigi#define socheckuid(a,b) ((a)->so_cred->cr_uid == (b)) 146699622Sluigi#endif 146798943Sluigi if (cmd->opcode == O_UID) { 146899622Sluigi match = 146999622Sluigi socheckuid(pcb->inp_socket, 147099622Sluigi (uid_t)((ipfw_insn_u32 *)cmd)->d[0]); 147198943Sluigi } else { 147299622Sluigi match = groupmember( 147398943Sluigi (uid_t)((ipfw_insn_u32 *)cmd)->d[0], 147499622Sluigi pcb->inp_socket->so_cred); 147598943Sluigi } 147698943Sluigi } 147799622Sluigi break; 147898943Sluigi 147998943Sluigi case O_RECV: 148099622Sluigi match = iface_match(m->m_pkthdr.rcvif, 148199622Sluigi (ipfw_insn_if *)cmd); 148299622Sluigi break; 148398943Sluigi 148498943Sluigi case O_XMIT: 148599622Sluigi match = iface_match(oif, (ipfw_insn_if *)cmd); 148699622Sluigi break; 148798943Sluigi 148898943Sluigi case O_VIA: 148999622Sluigi match = iface_match(oif ? oif : 149099622Sluigi m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd); 149199622Sluigi break; 149298943Sluigi 149398943Sluigi case O_MACADDR2: 149498943Sluigi if (args->eh != NULL) { /* have MAC header */ 149598943Sluigi u_int32_t *want = (u_int32_t *) 149698943Sluigi ((ipfw_insn_mac *)cmd)->addr; 149798943Sluigi u_int32_t *mask = (u_int32_t *) 149898943Sluigi ((ipfw_insn_mac *)cmd)->mask; 149998943Sluigi u_int32_t *hdr = (u_int32_t *)args->eh; 150098943Sluigi 150199622Sluigi match = 150299622Sluigi ( want[0] == (hdr[0] & mask[0]) && 150399622Sluigi want[1] == (hdr[1] & mask[1]) && 150499622Sluigi want[2] == (hdr[2] & mask[2]) ); 150598943Sluigi } 150699622Sluigi break; 150798943Sluigi 150898943Sluigi case O_MAC_TYPE: 150998943Sluigi if (args->eh != NULL) { 151099622Sluigi u_int16_t t = 151198943Sluigi ntohs(args->eh->ether_type); 151298943Sluigi u_int16_t *p = 151398943Sluigi ((ipfw_insn_u16 *)cmd)->ports; 151498943Sluigi int i; 151598943Sluigi 151699622Sluigi for (i = cmdlen - 1; !match && i>0; 151799622Sluigi i--, p += 2) 151899622Sluigi match = (t>=p[0] && t<=p[1]); 151998943Sluigi } 152099622Sluigi break; 152198943Sluigi 152298943Sluigi case O_FRAG: 152399622Sluigi match = (hlen > 0 && offset != 0); 152499622Sluigi break; 152598943Sluigi 152698943Sluigi case O_IN: /* "out" is "not in" */ 152799622Sluigi match = (oif == NULL); 152899622Sluigi break; 152998943Sluigi 153098943Sluigi case O_LAYER2: 153199622Sluigi match = (args->eh != NULL); 153299622Sluigi break; 153398943Sluigi 153498943Sluigi case O_PROTO: 153598943Sluigi /* 153698943Sluigi * We do not allow an arg of 0 so the 153798943Sluigi * check of "proto" only suffices. 153898943Sluigi */ 153999622Sluigi match = (proto == cmd->arg1); 154099622Sluigi break; 154198943Sluigi 154298943Sluigi case O_IP_SRC: 154399622Sluigi match = (hlen > 0 && 154498943Sluigi ((ipfw_insn_ip *)cmd)->addr.s_addr == 154599622Sluigi src_ip.s_addr); 154699622Sluigi break; 154798943Sluigi 154898943Sluigi case O_IP_SRC_MASK: 154999622Sluigi match = (hlen > 0 && 155098943Sluigi ((ipfw_insn_ip *)cmd)->addr.s_addr == 155199622Sluigi (src_ip.s_addr & 155299622Sluigi ((ipfw_insn_ip *)cmd)->mask.s_addr)); 155399622Sluigi break; 155498943Sluigi 155598943Sluigi case O_IP_SRC_ME: 155699622Sluigi if (hlen > 0) { 155799622Sluigi struct ifnet *tif; 155898943Sluigi 155999622Sluigi INADDR_TO_IFP(src_ip, tif); 156099622Sluigi match = (tif != NULL); 156199622Sluigi } 156299622Sluigi break; 156398943Sluigi 156498943Sluigi case O_IP_DST_SET: 156598943Sluigi case O_IP_SRC_SET: 156699622Sluigi if (hlen > 0) { 156799622Sluigi u_int32_t *d = (u_int32_t *)(cmd+1); 156899622Sluigi u_int32_t addr = 156999622Sluigi cmd->opcode == O_IP_DST_SET ? 157099622Sluigi args->f_id.src_ip : 157199622Sluigi args->f_id.dst_ip; 157298943Sluigi 157399622Sluigi if (addr < d[0]) 157499622Sluigi break; 157599622Sluigi addr -= d[0]; /* subtract base */ 157699622Sluigi match = (addr < cmd->arg1) && 157799622Sluigi ( d[ 1 + (addr>>5)] & 157899622Sluigi (1<<(addr & 0x1f)) ); 157999622Sluigi } 158099622Sluigi break; 158198943Sluigi 158298943Sluigi case O_IP_DST: 158399622Sluigi match = (hlen > 0 && 158498943Sluigi ((ipfw_insn_ip *)cmd)->addr.s_addr == 158599622Sluigi dst_ip.s_addr); 158699622Sluigi break; 158798943Sluigi 158898943Sluigi case O_IP_DST_MASK: 158999622Sluigi match = (hlen > 0) && 159099622Sluigi (((ipfw_insn_ip *)cmd)->addr.s_addr == 159199622Sluigi (dst_ip.s_addr & 159299622Sluigi ((ipfw_insn_ip *)cmd)->mask.s_addr)); 159399622Sluigi break; 159498943Sluigi 159598943Sluigi case O_IP_DST_ME: 159699622Sluigi if (hlen > 0) { 159799622Sluigi struct ifnet *tif; 159899622Sluigi 159999622Sluigi INADDR_TO_IFP(dst_ip, tif); 160099622Sluigi match = (tif != NULL); 160199622Sluigi } 160299622Sluigi break; 160398943Sluigi 160498943Sluigi case O_IP_SRCPORT: 160598943Sluigi case O_IP_DSTPORT: 160698943Sluigi /* 160798943Sluigi * offset == 0 && proto != 0 is enough 160898943Sluigi * to guarantee that we have an IPv4 160998943Sluigi * packet with port info. 161098943Sluigi */ 161199622Sluigi if ((proto==IPPROTO_UDP || proto==IPPROTO_TCP) 161299622Sluigi && offset == 0) { 161399622Sluigi u_int16_t x = 161498943Sluigi (cmd->opcode == O_IP_SRCPORT) ? 161599622Sluigi src_port : dst_port ; 161698943Sluigi u_int16_t *p = 161798943Sluigi ((ipfw_insn_u16 *)cmd)->ports; 161898943Sluigi int i; 161998943Sluigi 162099622Sluigi for (i = cmdlen - 1; !match && i>0; 162199622Sluigi i--, p += 2) 162299622Sluigi match = (x>=p[0] && x<=p[1]); 162398943Sluigi } 162499622Sluigi break; 162598943Sluigi 162698943Sluigi case O_ICMPTYPE: 162799622Sluigi match = (offset == 0 && proto==IPPROTO_ICMP && 162899622Sluigi icmptype_match(ip, (ipfw_insn_u32 *)cmd) ); 162999622Sluigi break; 163098943Sluigi 163198943Sluigi case O_IPOPT: 163299622Sluigi match = (hlen > 0 && ipopts_match(ip, cmd) ); 163399622Sluigi break; 163498943Sluigi 163598943Sluigi case O_IPVER: 163699622Sluigi match = (hlen > 0 && cmd->arg1 == ip->ip_v); 163799622Sluigi break; 163898943Sluigi 163998943Sluigi case O_IPTTL: 164099622Sluigi match = (hlen > 0 && cmd->arg1 == ip->ip_ttl); 164199622Sluigi break; 164298943Sluigi 164398943Sluigi case O_IPID: 164499622Sluigi match = (hlen > 0 && 164599622Sluigi cmd->arg1 == ntohs(ip->ip_id)); 164699622Sluigi break; 164798943Sluigi 164898943Sluigi case O_IPLEN: 164999622Sluigi match = (hlen > 0 && cmd->arg1 == ip_len); 165099622Sluigi break; 165198943Sluigi 165299475Sluigi case O_IPPRECEDENCE: 165399622Sluigi match = (hlen > 0 && 165499622Sluigi (cmd->arg1 == (ip->ip_tos & 0xe0)) ); 165599622Sluigi break; 165699475Sluigi 165798943Sluigi case O_IPTOS: 165899622Sluigi match = (hlen > 0 && 165999622Sluigi flags_match(cmd, ip->ip_tos)); 166099622Sluigi break; 166198943Sluigi 166298943Sluigi case O_TCPFLAGS: 166399622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 166499622Sluigi flags_match(cmd, 166599622Sluigi L3HDR(struct tcphdr,ip)->th_flags)); 166699622Sluigi break; 166798943Sluigi 166898943Sluigi case O_TCPOPTS: 166999622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 167099622Sluigi tcpopts_match(ip, cmd)); 167199622Sluigi break; 167298943Sluigi 167398943Sluigi case O_TCPSEQ: 167499622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 167599622Sluigi ((ipfw_insn_u32 *)cmd)->d[0] == 167699622Sluigi L3HDR(struct tcphdr,ip)->th_seq); 167799622Sluigi break; 167898943Sluigi 167998943Sluigi case O_TCPACK: 168099622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 168199622Sluigi ((ipfw_insn_u32 *)cmd)->d[0] == 168299622Sluigi L3HDR(struct tcphdr,ip)->th_ack); 168399622Sluigi break; 168498943Sluigi 168598943Sluigi case O_TCPWIN: 168699622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 168799622Sluigi cmd->arg1 == 168899622Sluigi L3HDR(struct tcphdr,ip)->th_win); 168999622Sluigi break; 169098943Sluigi 169198943Sluigi case O_ESTAB: 169298943Sluigi /* reject packets which have SYN only */ 169399622Sluigi /* XXX should i also check for TH_ACK ? */ 169499622Sluigi match = (proto == IPPROTO_TCP && offset == 0 && 169599622Sluigi (L3HDR(struct tcphdr,ip)->th_flags & 169699622Sluigi (TH_RST | TH_ACK | TH_SYN)) != TH_SYN); 169799622Sluigi break; 169898943Sluigi 169998943Sluigi case O_LOG: 1700100589Sluigi if (fw_verbose) 1701100589Sluigi ipfw_log(f, hlen, args->eh, m, oif); 170299622Sluigi match = 1; 170399622Sluigi break; 170498943Sluigi 170599475Sluigi case O_PROB: 170699622Sluigi match = (random()<((ipfw_insn_u32 *)cmd)->d[0]); 170799622Sluigi break; 170898943Sluigi 170999622Sluigi /* 171099622Sluigi * The second set of opcodes represents 'actions', 171199622Sluigi * i.e. the terminal part of a rule once the packet 171299622Sluigi * matches all previous patterns. 171399622Sluigi * Typically there is only one action for each rule, 171499622Sluigi * and the opcode is stored at the end of the rule 171599622Sluigi * (but there are exceptions -- see below). 171699622Sluigi * 171799622Sluigi * In general, here we set retval and terminate the 171899622Sluigi * outer loop (would be a 'break 3' in some language, 171999622Sluigi * but we need to do a 'goto done'). 172099622Sluigi * 172199622Sluigi * Exceptions: 172299622Sluigi * O_COUNT and O_SKIPTO actions: 172399622Sluigi * instead of terminating, we jump to the next rule 172499622Sluigi * ('goto next_rule', equivalent to a 'break 2'), 172599622Sluigi * or to the SKIPTO target ('goto again' after 172699622Sluigi * having set f, cmd and l), respectively. 172799622Sluigi * 172899622Sluigi * O_LIMIT and O_KEEP_STATE: these opcodes are 172999622Sluigi * not real 'actions', and are stored right 173099622Sluigi * before the 'action' part of the rule. 173199622Sluigi * These opcodes try to install an entry in the 173299622Sluigi * state tables; if successful, we continue with 173399622Sluigi * the next opcode (match=1; break;), otherwise 173499622Sluigi * the packet * must be dropped 173599622Sluigi * ('goto done' after setting retval); 173699622Sluigi * 173799622Sluigi * O_PROBE_STATE and O_CHECK_STATE: these opcodes 173899622Sluigi * cause a lookup of the state table, and a jump 173999622Sluigi * to the 'action' part of the parent rule 174099622Sluigi * ('goto check_body') if an entry is found, or 174199622Sluigi * (CHECK_STATE only) a jump to the next rule if 174299622Sluigi * the entry is not found ('goto next_rule'). 174399622Sluigi * The result of the lookup is cached to make 174499622Sluigi * further instances of these opcodes are 174599622Sluigi * effectively NOPs. 174699622Sluigi */ 174798943Sluigi case O_LIMIT: 174898943Sluigi case O_KEEP_STATE: 174998943Sluigi if (install_state(f, 175099622Sluigi (ipfw_insn_limit *)cmd, args)) { 175199622Sluigi retval = IP_FW_PORT_DENY_FLAG; 175299622Sluigi goto done; /* error/limit violation */ 175399622Sluigi } 175499622Sluigi match = 1; 175599622Sluigi break; 175698943Sluigi 175798943Sluigi case O_PROBE_STATE: 175898943Sluigi case O_CHECK_STATE: 175998943Sluigi /* 176098943Sluigi * dynamic rules are checked at the first 176199622Sluigi * keep-state or check-state occurrence, 176299622Sluigi * with the result being stored in dyn_dir. 176399622Sluigi * The compiler introduces a PROBE_STATE 176498943Sluigi * instruction for us when we have a 176599622Sluigi * KEEP_STATE (because PROBE_STATE needs 176698943Sluigi * to be run first). 176798943Sluigi */ 176899622Sluigi if (dyn_dir == MATCH_UNKNOWN && 176999622Sluigi (q = lookup_dyn_rule(&args->f_id, 1770100004Sluigi &dyn_dir, proto == IPPROTO_TCP ? 1771100004Sluigi L3HDR(struct tcphdr, ip) : NULL)) 1772100004Sluigi != NULL) { 177399622Sluigi /* 177499622Sluigi * Found dynamic entry, update stats 177599622Sluigi * and jump to the 'action' part of 177699622Sluigi * the parent rule. 177799622Sluigi */ 177899622Sluigi q->pcnt++; 177999622Sluigi q->bcnt += ip_len; 178099622Sluigi f = q->rule; 178199622Sluigi cmd = ACTION_PTR(f); 178299622Sluigi l = f->cmd_len - f->act_ofs; 178399622Sluigi goto check_body; 178498943Sluigi } 178599622Sluigi /* 178699622Sluigi * Dynamic entry not found. If CHECK_STATE, 178799622Sluigi * skip to next rule, if PROBE_STATE just 178899622Sluigi * ignore and continue with next opcode. 178999622Sluigi */ 179098943Sluigi if (cmd->opcode == O_CHECK_STATE) 179198943Sluigi goto next_rule; 179299622Sluigi match = 1; 179399622Sluigi break; 179498943Sluigi 179598943Sluigi case O_ACCEPT: 179698943Sluigi retval = 0; /* accept */ 179799622Sluigi goto done; 179898943Sluigi 179998943Sluigi case O_PIPE: 180098943Sluigi case O_QUEUE: 180198943Sluigi args->rule = f; /* report matching rule */ 180298943Sluigi retval = cmd->arg1 | IP_FW_PORT_DYNT_FLAG; 180399622Sluigi goto done; 180498943Sluigi 180598943Sluigi case O_DIVERT: 180698943Sluigi case O_TEE: 180798943Sluigi if (args->eh) /* not on layer 2 */ 180899622Sluigi break; 180998943Sluigi args->divert_rule = f->rulenum; 181099622Sluigi retval = (cmd->opcode == O_DIVERT) ? 181199622Sluigi cmd->arg1 : 181299622Sluigi cmd->arg1 | IP_FW_PORT_TEE_FLAG; 181399622Sluigi goto done; 181498943Sluigi 181598943Sluigi case O_COUNT: 181698943Sluigi case O_SKIPTO: 181798943Sluigi f->pcnt++; /* update stats */ 181898943Sluigi f->bcnt += ip_len; 181998943Sluigi f->timestamp = time_second; 182098943Sluigi if (cmd->opcode == O_COUNT) 182198943Sluigi goto next_rule; 182298943Sluigi /* handle skipto */ 182398943Sluigi if (f->next_rule == NULL) 182498943Sluigi lookup_next_rule(f); 182598943Sluigi f = f->next_rule; 182698943Sluigi goto again; 182798943Sluigi 182898943Sluigi case O_REJECT: 182998943Sluigi /* 183098943Sluigi * Drop the packet and send a reject notice 183198943Sluigi * if the packet is not ICMP (or is an ICMP 183298943Sluigi * query), and it is not multicast/broadcast. 183398943Sluigi */ 183498943Sluigi if (hlen > 0 && 183598943Sluigi (proto != IPPROTO_ICMP || 183699475Sluigi is_icmp_query(ip)) && 183798943Sluigi !(m->m_flags & (M_BCAST|M_MCAST)) && 183898943Sluigi !IN_MULTICAST(dst_ip.s_addr)) { 183999475Sluigi send_reject(args, cmd->arg1, 184099475Sluigi offset,ip_len); 184199475Sluigi m = args->m; 184298943Sluigi } 184399622Sluigi /* FALLTHROUGH */ 184499622Sluigi case O_DENY: 184599622Sluigi retval = IP_FW_PORT_DENY_FLAG; 184699622Sluigi goto done; 184798943Sluigi 184898943Sluigi case O_FORWARD_IP: 184998943Sluigi if (args->eh) /* not valid on layer2 pkts */ 185099622Sluigi break; 185198943Sluigi if (!q || dyn_dir == MATCH_FORWARD) 185298943Sluigi args->next_hop = 185398943Sluigi &((ipfw_insn_sa *)cmd)->sa; 185498943Sluigi retval = 0; 185599622Sluigi goto done; 185698943Sluigi 185798943Sluigi default: 185898943Sluigi panic("-- unknown opcode %d\n", cmd->opcode); 185999622Sluigi } /* end of switch() on opcodes */ 186098943Sluigi 186199622Sluigi if (cmd->len & F_NOT) 186299622Sluigi match = !match; 186398943Sluigi 186499622Sluigi if (match) { 186599622Sluigi if (cmd->len & F_OR) 186699622Sluigi skip_or = 1; 186799622Sluigi } else { 186899622Sluigi if (!(cmd->len & F_OR)) /* not an OR block, */ 186999622Sluigi break; /* try next rule */ 187098943Sluigi } 187198943Sluigi 187298943Sluigi } /* end of inner for, scan opcodes */ 187398943Sluigi 187498965Sdfrnext_rule:; /* try next rule */ 187598943Sluigi 187698943Sluigi } /* end of outer for, scan rules */ 1877101628Sluigi printf("+++ ipfw: ouch!, skip past end of rules, denying packet\n"); 1878101628Sluigi return(IP_FW_PORT_DENY_FLAG); 187998943Sluigi 188099622Sluigidone: 188198943Sluigi /* Update statistics */ 188298943Sluigi f->pcnt++; 188398943Sluigi f->bcnt += ip_len; 188498943Sluigi f->timestamp = time_second; 188598943Sluigi return retval; 188698943Sluigi 188798943Sluigipullup_failed: 188898943Sluigi if (fw_verbose) 188998943Sluigi printf("pullup failed\n"); 189098943Sluigi return(IP_FW_PORT_DENY_FLAG); 189198943Sluigi} 189298943Sluigi 189398943Sluigi/* 189498943Sluigi * When a rule is added/deleted, clear the next_rule pointers in all rules. 189598943Sluigi * These will be reconstructed on the fly as packets are matched. 189698943Sluigi * Must be called at splimp(). 189798943Sluigi */ 189898943Sluigistatic void 189998943Sluigiflush_rule_ptrs(void) 190098943Sluigi{ 190198943Sluigi struct ip_fw *rule; 190298943Sluigi 190398943Sluigi for (rule = layer3_chain; rule; rule = rule->next) 190498943Sluigi rule->next_rule = NULL; 190598943Sluigi} 190698943Sluigi 190798943Sluigi/* 190898943Sluigi * When pipes/queues are deleted, clear the "pipe_ptr" pointer to a given 190998943Sluigi * pipe/queue, or to all of them (match == NULL). 191098943Sluigi * Must be called at splimp(). 191198943Sluigi */ 191298943Sluigivoid 191398943Sluigiflush_pipe_ptrs(struct dn_flow_set *match) 191498943Sluigi{ 191598943Sluigi struct ip_fw *rule; 191698943Sluigi 191798943Sluigi for (rule = layer3_chain; rule; rule = rule->next) { 191898943Sluigi ipfw_insn_pipe *cmd = (ipfw_insn_pipe *)ACTION_PTR(rule); 191998943Sluigi 192098943Sluigi if (cmd->o.opcode != O_PIPE && cmd->o.opcode != O_QUEUE) 192198943Sluigi continue; 192298943Sluigi 192398943Sluigi if (match == NULL || cmd->pipe_ptr == match) 192498943Sluigi cmd->pipe_ptr = NULL; 192598943Sluigi } 192698943Sluigi} 192798943Sluigi 192898943Sluigi/* 192998943Sluigi * Add a new rule to the list. Copy the rule into a malloc'ed area, then 193098943Sluigi * possibly create a rule number and add the rule to the list. 193198943Sluigi * Update the rule_number in the input struct so the caller knows it as well. 193298943Sluigi */ 193398943Sluigistatic int 193498943Sluigiadd_rule(struct ip_fw **head, struct ip_fw *input_rule) 193598943Sluigi{ 193698943Sluigi struct ip_fw *rule, *f, *prev; 193798943Sluigi int s; 193898943Sluigi int l = RULESIZE(input_rule); 193998943Sluigi 194098943Sluigi if (*head == NULL && input_rule->rulenum != IPFW_DEFAULT_RULE) 194198943Sluigi return (EINVAL); 194298943Sluigi 194398943Sluigi rule = malloc(l, M_IPFW, M_DONTWAIT | M_ZERO); 194498943Sluigi if (rule == NULL) 194598943Sluigi return (ENOSPC); 194698943Sluigi 194798943Sluigi bcopy(input_rule, rule, l); 194898943Sluigi 194998943Sluigi rule->next = NULL; 195098943Sluigi rule->next_rule = NULL; 195198943Sluigi 195298943Sluigi rule->pcnt = 0; 195398943Sluigi rule->bcnt = 0; 195498943Sluigi rule->timestamp = 0; 195598943Sluigi 195698943Sluigi s = splimp(); 195798943Sluigi 195898943Sluigi if (*head == NULL) { /* default rule */ 195998943Sluigi *head = rule; 196098943Sluigi goto done; 196198943Sluigi } 196298943Sluigi 196398943Sluigi /* 196498943Sluigi * If rulenum is 0, find highest numbered rule before the 196598943Sluigi * default rule, and add autoinc_step 196698943Sluigi */ 196798943Sluigi if (autoinc_step < 1) 196898943Sluigi autoinc_step = 1; 196998943Sluigi else if (autoinc_step > 1000) 197098943Sluigi autoinc_step = 1000; 197198943Sluigi if (rule->rulenum == 0) { 197298943Sluigi /* 197398943Sluigi * locate the highest numbered rule before default 197498943Sluigi */ 197598943Sluigi for (f = *head; f; f = f->next) { 197698943Sluigi if (f->rulenum == IPFW_DEFAULT_RULE) 197798943Sluigi break; 197898943Sluigi rule->rulenum = f->rulenum; 197998943Sluigi } 198098943Sluigi if (rule->rulenum < IPFW_DEFAULT_RULE - autoinc_step) 198198943Sluigi rule->rulenum += autoinc_step; 198298943Sluigi input_rule->rulenum = rule->rulenum; 198398943Sluigi } 198498943Sluigi 198598943Sluigi /* 198698943Sluigi * Now insert the new rule in the right place in the sorted list. 198798943Sluigi */ 198898943Sluigi for (prev = NULL, f = *head; f; prev = f, f = f->next) { 198998943Sluigi if (f->rulenum > rule->rulenum) { /* found the location */ 199098943Sluigi if (prev) { 199198943Sluigi rule->next = f; 199298943Sluigi prev->next = rule; 199398943Sluigi } else { /* head insert */ 199498943Sluigi rule->next = *head; 199598943Sluigi *head = rule; 199698943Sluigi } 199798943Sluigi break; 199898943Sluigi } 199998943Sluigi } 200098943Sluigi flush_rule_ptrs(); 200198943Sluigidone: 200298943Sluigi static_count++; 200398943Sluigi static_len += l; 200498943Sluigi splx(s); 200598943Sluigi DEB(printf("++ installed rule %d, static count now %d\n", 200698943Sluigi rule->rulenum, static_count);) 200798943Sluigi return (0); 200898943Sluigi} 200998943Sluigi 201098943Sluigi/** 201198943Sluigi * Free storage associated with a static rule (including derived 201298943Sluigi * dynamic rules). 201398943Sluigi * The caller is in charge of clearing rule pointers to avoid 201498943Sluigi * dangling pointers. 201598943Sluigi * @return a pointer to the next entry. 201698943Sluigi * Arguments are not checked, so they better be correct. 201798943Sluigi * Must be called at splimp(). 201898943Sluigi */ 201998943Sluigistatic struct ip_fw * 202098943Sluigidelete_rule(struct ip_fw **head, struct ip_fw *prev, struct ip_fw *rule) 202198943Sluigi{ 202298943Sluigi struct ip_fw *n; 202398943Sluigi int l = RULESIZE(rule); 202498943Sluigi 202598943Sluigi n = rule->next; 202698943Sluigi remove_dyn_rule(rule, NULL /* force removal */); 202798943Sluigi if (prev == NULL) 202898943Sluigi *head = n; 202998943Sluigi else 203098943Sluigi prev->next = n; 203198943Sluigi static_count--; 203298943Sluigi static_len -= l; 203398943Sluigi 203498943Sluigi if (DUMMYNET_LOADED) 203598943Sluigi ip_dn_ruledel_ptr(rule); 203698943Sluigi free(rule, M_IPFW); 203798943Sluigi return n; 203898943Sluigi} 203998943Sluigi 204098943Sluigi/* 204198943Sluigi * Deletes all rules from a chain (including the default rule 204298943Sluigi * if the second argument is set). 204398943Sluigi * Must be called at splimp(). 204498943Sluigi */ 204598943Sluigistatic void 204698943Sluigifree_chain(struct ip_fw **chain, int kill_default) 204798943Sluigi{ 204898943Sluigi struct ip_fw *rule; 204998943Sluigi 205098943Sluigi flush_rule_ptrs(); /* more efficient to do outside the loop */ 205198943Sluigi 205298943Sluigi while ( (rule = *chain) != NULL && 205398943Sluigi (kill_default || rule->rulenum != IPFW_DEFAULT_RULE) ) 205498943Sluigi delete_rule(chain, NULL, rule); 205598943Sluigi} 205698943Sluigi 205798943Sluigi/** 2058101628Sluigi * Remove all rules with given number, and also do set manipulation. 2059101628Sluigi * 2060101628Sluigi * The argument is an int. The low 16 bit are the 2061101628Sluigi * rule or set number, the upper 16 bits are the 2062101628Sluigi * function, namely: 2063101628Sluigi * 2064101628Sluigi * 0 DEL_SINGLE_RULE 2065101628Sluigi * 1 DELETE_RULESET 2066101628Sluigi * 2 DISABLE_SET 2067101628Sluigi * 3 ENABLE_SET 206898943Sluigi */ 206998943Sluigistatic int 2070101628Sluigidel_entry(struct ip_fw **chain, u_int32_t arg) 207198943Sluigi{ 207298943Sluigi struct ip_fw *prev, *rule; 207398943Sluigi int s; 2074101628Sluigi 2075101628Sluigi u_int16_t rulenum, cmd; 207698943Sluigi 2077101628Sluigi rulenum = arg & 0xffff; 2078101628Sluigi cmd = (arg >> 16) & 0xffff; 2079101628Sluigi 2080101628Sluigi if (cmd > 3) 208198943Sluigi return EINVAL; 2082101628Sluigi if (cmd == 0 && rulenum == IPFW_DEFAULT_RULE) 2083101628Sluigi return EINVAL; 208498943Sluigi 2085101628Sluigi if (cmd != 0 && rulenum > 30) { 2086101628Sluigi printf("ipfw: del_entry: invalid set number %d\n", 2087101628Sluigi rulenum); 208898943Sluigi return EINVAL; 2089101628Sluigi } 209098943Sluigi 2091101628Sluigi switch (cmd) { 2092101628Sluigi case 0: /* DEL_SINGLE_RULE */ 2093101628Sluigi /* 2094101628Sluigi * locate first rule to delete 2095101628Sluigi */ 2096101628Sluigi for (prev = NULL, rule = *chain; 2097101628Sluigi rule && rule->rulenum < rulenum; 2098101628Sluigi prev = rule, rule = rule->next) 2099101628Sluigi ; 2100101628Sluigi if (rule->rulenum != rulenum) 2101101628Sluigi return EINVAL; 2102101628Sluigi 2103101628Sluigi s = splimp(); /* no access to rules while removing */ 2104101628Sluigi flush_rule_ptrs(); /* more efficient to do outside the loop */ 2105101628Sluigi /* 2106101628Sluigi * prev remains the same throughout the cycle 2107101628Sluigi */ 2108101628Sluigi while (rule && rule->rulenum == rulenum) 2109101628Sluigi rule = delete_rule(chain, prev, rule); 2110101628Sluigi splx(s); 2111101628Sluigi break; 2112101628Sluigi 2113101628Sluigi case 1: /* DELETE_RULESET */ 2114101628Sluigi s = splimp(); /* no access to rules while removing */ 2115101628Sluigi flush_rule_ptrs(); /* more efficient to do outside the loop */ 2116101628Sluigi for (prev = NULL, rule = *chain; rule ; ) 2117101628Sluigi if (rule->set == rulenum) 2118101628Sluigi rule = delete_rule(chain, prev, rule); 2119101628Sluigi else { 2120101628Sluigi prev = rule; 2121101628Sluigi rule = rule->next; 2122101628Sluigi } 2123101628Sluigi splx(s); 2124101628Sluigi break; 2125101628Sluigi 2126101628Sluigi case 2: /* DISABLE SET */ 2127101628Sluigi s = splimp(); 2128101628Sluigi set_disable |= 1 << rulenum; 2129101628Sluigi splx(s); 2130101628Sluigi break; 2131101628Sluigi 2132101628Sluigi case 3: /* ENABLE SET */ 2133101628Sluigi s = splimp(); 2134101628Sluigi set_disable &= ~(1 << rulenum); 2135101628Sluigi splx(s); 2136101628Sluigi break; 2137101628Sluigi } 213898943Sluigi return 0; 213998943Sluigi} 214098943Sluigi 214198943Sluigi/* 214298943Sluigi * Clear counters for a specific rule. 214398943Sluigi */ 214498943Sluigistatic void 214598943Sluigiclear_counters(struct ip_fw *rule, int log_only) 214698943Sluigi{ 214798943Sluigi ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule); 214898943Sluigi 214998943Sluigi if (log_only == 0) { 215098943Sluigi rule->bcnt = rule->pcnt = 0; 215198943Sluigi rule->timestamp = 0; 215298943Sluigi } 215398943Sluigi if (l->o.opcode == O_LOG) 215498943Sluigi l->log_left = l->max_log; 215598943Sluigi} 215698943Sluigi 215798943Sluigi/** 215898943Sluigi * Reset some or all counters on firewall rules. 215998943Sluigi * @arg frwl is null to clear all entries, or contains a specific 216098943Sluigi * rule number. 216198943Sluigi * @arg log_only is 1 if we only want to reset logs, zero otherwise. 216298943Sluigi */ 216398943Sluigistatic int 216498943Sluigizero_entry(int rulenum, int log_only) 216598943Sluigi{ 216698943Sluigi struct ip_fw *rule; 216798943Sluigi int s; 216898943Sluigi char *msg; 216998943Sluigi 217098943Sluigi if (rulenum == 0) { 217198943Sluigi s = splimp(); 217298943Sluigi norule_counter = 0; 217398943Sluigi for (rule = layer3_chain; rule; rule = rule->next) 217498943Sluigi clear_counters(rule, log_only); 217598943Sluigi splx(s); 217698943Sluigi msg = log_only ? "ipfw: All logging counts reset.\n" : 217798943Sluigi "ipfw: Accounting cleared.\n"; 217898943Sluigi } else { 217998943Sluigi int cleared = 0; 218098943Sluigi /* 218198943Sluigi * We can have multiple rules with the same number, so we 218298943Sluigi * need to clear them all. 218398943Sluigi */ 218498943Sluigi for (rule = layer3_chain; rule; rule = rule->next) 218598943Sluigi if (rule->rulenum == rulenum) { 218698943Sluigi s = splimp(); 218798943Sluigi while (rule && rule->rulenum == rulenum) { 218898943Sluigi clear_counters(rule, log_only); 218998943Sluigi rule = rule->next; 219098943Sluigi } 219198943Sluigi splx(s); 219298943Sluigi cleared = 1; 219398943Sluigi break; 219498943Sluigi } 219598943Sluigi if (!cleared) /* we did not find any matching rules */ 219698943Sluigi return (EINVAL); 219798943Sluigi msg = log_only ? "ipfw: Entry %d logging count reset.\n" : 219898943Sluigi "ipfw: Entry %d cleared.\n"; 219998943Sluigi } 220098943Sluigi if (fw_verbose) 220198943Sluigi log(LOG_SECURITY | LOG_NOTICE, msg, rulenum); 220298943Sluigi return (0); 220398943Sluigi} 220498943Sluigi 220598943Sluigi/* 220698943Sluigi * Check validity of the structure before insert. 220798943Sluigi * Fortunately rules are simple, so this mostly need to check rule sizes. 220898943Sluigi */ 220998943Sluigistatic int 221098943Sluigicheck_ipfw_struct(struct ip_fw *rule, int size) 221198943Sluigi{ 221298943Sluigi int l, cmdlen = 0; 221398943Sluigi int have_action=0; 221498943Sluigi ipfw_insn *cmd; 221598943Sluigi 221698943Sluigi if (size < sizeof(*rule)) { 221799622Sluigi printf("ipfw: rule too short\n"); 221898943Sluigi return (EINVAL); 221998943Sluigi } 222098943Sluigi /* first, check for valid size */ 222198943Sluigi l = RULESIZE(rule); 222298943Sluigi if (l != size) { 222399622Sluigi printf("ipfw: size mismatch (have %d want %d)\n", size, l); 222498943Sluigi return (EINVAL); 222598943Sluigi } 222698943Sluigi /* 222798943Sluigi * Now go for the individual checks. Very simple ones, basically only 222898943Sluigi * instruction sizes. 222998943Sluigi */ 223098943Sluigi for (l = rule->cmd_len, cmd = rule->cmd ; 223198943Sluigi l > 0 ; l -= cmdlen, cmd += cmdlen) { 223298943Sluigi cmdlen = F_LEN(cmd); 223398943Sluigi if (cmdlen > l) { 223499622Sluigi printf("ipfw: opcode %d size truncated\n", 223598943Sluigi cmd->opcode); 223698943Sluigi return EINVAL; 223798943Sluigi } 223899622Sluigi DEB(printf("ipfw: opcode %d\n", cmd->opcode);) 223998943Sluigi switch (cmd->opcode) { 224098943Sluigi case O_NOP: 224198943Sluigi case O_PROBE_STATE: 224298943Sluigi case O_KEEP_STATE: 224398943Sluigi case O_PROTO: 224498943Sluigi case O_IP_SRC_ME: 224598943Sluigi case O_IP_DST_ME: 224698943Sluigi case O_LAYER2: 224798943Sluigi case O_IN: 224898943Sluigi case O_FRAG: 224998943Sluigi case O_IPOPT: 225098943Sluigi case O_IPLEN: 225198943Sluigi case O_IPID: 225298943Sluigi case O_IPTOS: 225399475Sluigi case O_IPPRECEDENCE: 225498943Sluigi case O_IPTTL: 225598943Sluigi case O_IPVER: 225698943Sluigi case O_TCPWIN: 225798943Sluigi case O_TCPFLAGS: 225898943Sluigi case O_TCPOPTS: 225998943Sluigi case O_ESTAB: 226098943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn)) 226198943Sluigi goto bad_size; 226298943Sluigi break; 226398943Sluigi 226498943Sluigi case O_UID: 226598943Sluigi case O_GID: 226698943Sluigi case O_IP_SRC: 226798943Sluigi case O_IP_DST: 226898943Sluigi case O_TCPSEQ: 226998943Sluigi case O_TCPACK: 227098943Sluigi case O_PROB: 227198943Sluigi case O_ICMPTYPE: 227298943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 227398943Sluigi goto bad_size; 227498943Sluigi break; 227598943Sluigi 227698943Sluigi case O_LIMIT: 227798943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) 227898943Sluigi goto bad_size; 227998943Sluigi break; 228098943Sluigi 228198943Sluigi case O_LOG: 228298943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_log)) 228398943Sluigi goto bad_size; 228498943Sluigi 228598943Sluigi ((ipfw_insn_log *)cmd)->log_left = 228698943Sluigi ((ipfw_insn_log *)cmd)->max_log; 228798943Sluigi 228898943Sluigi break; 228998943Sluigi 229098943Sluigi case O_IP_SRC_MASK: 229198943Sluigi case O_IP_DST_MASK: 229298943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_ip)) 229398943Sluigi goto bad_size; 229498943Sluigi if (((ipfw_insn_ip *)cmd)->mask.s_addr == 0) { 229599622Sluigi printf("ipfw: opcode %d, useless rule\n", 229698943Sluigi cmd->opcode); 229798943Sluigi return EINVAL; 229898943Sluigi } 229998943Sluigi break; 230098943Sluigi 230198943Sluigi case O_IP_SRC_SET: 230298943Sluigi case O_IP_DST_SET: 230398943Sluigi if (cmd->arg1 == 0 || cmd->arg1 > 256) { 230499622Sluigi printf("ipfw: invalid set size %d\n", 230598943Sluigi cmd->arg1); 230698943Sluigi return EINVAL; 230798943Sluigi } 230898943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 230998943Sluigi (cmd->arg1+31)/32 ) 231098943Sluigi goto bad_size; 231198943Sluigi break; 231298943Sluigi 231398943Sluigi case O_MACADDR2: 231498943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) 231598943Sluigi goto bad_size; 231698943Sluigi break; 231798943Sluigi 231898943Sluigi case O_MAC_TYPE: 231998943Sluigi case O_IP_SRCPORT: 232098943Sluigi case O_IP_DSTPORT: /* XXX artificial limit, 15 port pairs */ 232198943Sluigi if (cmdlen < 2 || cmdlen > 15) 232298943Sluigi goto bad_size; 232398943Sluigi break; 232498943Sluigi 232598943Sluigi case O_RECV: 232698943Sluigi case O_XMIT: 232798943Sluigi case O_VIA: 232898943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) 232998943Sluigi goto bad_size; 233098943Sluigi break; 233198943Sluigi 233298943Sluigi case O_PIPE: 233398943Sluigi case O_QUEUE: 233498943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_pipe)) 233598943Sluigi goto bad_size; 233698943Sluigi goto check_action; 233798943Sluigi 233899475Sluigi case O_FORWARD_IP: 233998943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) 234098943Sluigi goto bad_size; 234198943Sluigi goto check_action; 234298943Sluigi 234399475Sluigi case O_FORWARD_MAC: /* XXX not implemented yet */ 234498943Sluigi case O_CHECK_STATE: 234598943Sluigi case O_COUNT: 234698943Sluigi case O_ACCEPT: 234798943Sluigi case O_DENY: 234898943Sluigi case O_REJECT: 234998943Sluigi case O_SKIPTO: 235098943Sluigi case O_DIVERT: 235198943Sluigi case O_TEE: 235298943Sluigi if (cmdlen != F_INSN_SIZE(ipfw_insn)) 235398943Sluigi goto bad_size; 235498943Sluigicheck_action: 235598943Sluigi if (have_action) { 235699622Sluigi printf("ipfw: opcode %d, multiple actions" 235798943Sluigi " not allowed\n", 235898943Sluigi cmd->opcode); 235998943Sluigi return EINVAL; 236098943Sluigi } 236198943Sluigi have_action = 1; 236298943Sluigi if (l != cmdlen) { 236399622Sluigi printf("ipfw: opcode %d, action must be" 236498943Sluigi " last opcode\n", 236598943Sluigi cmd->opcode); 236698943Sluigi return EINVAL; 236798943Sluigi } 236898943Sluigi break; 236998943Sluigi default: 237099622Sluigi printf("ipfw: opcode %d, unknown opcode\n", 237198943Sluigi cmd->opcode); 237298943Sluigi return EINVAL; 237398943Sluigi } 237498943Sluigi } 237598943Sluigi if (have_action == 0) { 237699622Sluigi printf("ipfw: missing action\n"); 237798943Sluigi return EINVAL; 237898943Sluigi } 237998943Sluigi return 0; 238098943Sluigi 238198943Sluigibad_size: 238299622Sluigi printf("ipfw: opcode %d size %d wrong\n", 238398943Sluigi cmd->opcode, cmdlen); 238498943Sluigi return EINVAL; 238598943Sluigi} 238698943Sluigi 238798943Sluigi 238898943Sluigi/** 238998943Sluigi * {set|get}sockopt parser. 239098943Sluigi */ 239198943Sluigistatic int 239298943Sluigiipfw_ctl(struct sockopt *sopt) 239398943Sluigi{ 239498943Sluigi int error, s, rulenum; 239598943Sluigi size_t size; 239698943Sluigi struct ip_fw *bp , *buf, *rule; 239798943Sluigi 239898943Sluigi static u_int32_t rule_buf[255]; /* we copy the data here */ 239998943Sluigi 240098943Sluigi /* 240198943Sluigi * Disallow modifications in really-really secure mode, but still allow 240298943Sluigi * the logging counters to be reset. 240398943Sluigi */ 240498943Sluigi if (sopt->sopt_name == IP_FW_ADD || 240598943Sluigi (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) { 240698943Sluigi#if __FreeBSD_version >= 500034 240798943Sluigi error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 240898943Sluigi if (error) 240998943Sluigi return (error); 241098943Sluigi#else /* FreeBSD 4.x */ 241198943Sluigi if (securelevel >= 3) 241298943Sluigi return (EPERM); 241398943Sluigi#endif 241498943Sluigi } 241598943Sluigi 241698943Sluigi error = 0; 241798943Sluigi 241898943Sluigi switch (sopt->sopt_name) { 241998943Sluigi case IP_FW_GET: 242098943Sluigi /* 242198943Sluigi * pass up a copy of the current rules. Static rules 242298943Sluigi * come first (the last of which has number IPFW_DEFAULT_RULE), 242398943Sluigi * followed by a possibly empty list of dynamic rule. 242498943Sluigi * The last dynamic rule has NULL in the "next" field. 242598943Sluigi */ 242698943Sluigi s = splimp(); 242798943Sluigi size = static_len; /* size of static rules */ 242898943Sluigi if (ipfw_dyn_v) /* add size of dyn.rules */ 242998943Sluigi size += (dyn_count * sizeof(ipfw_dyn_rule)); 243098943Sluigi 243198943Sluigi /* 243298943Sluigi * XXX todo: if the user passes a short length just to know 243398943Sluigi * how much room is needed, do not bother filling up the 243498943Sluigi * buffer, just jump to the sooptcopyout. 243598943Sluigi */ 243698943Sluigi buf = malloc(size, M_TEMP, M_WAITOK); 243798943Sluigi if (buf == 0) { 243898943Sluigi splx(s); 243998943Sluigi error = ENOBUFS; 244098943Sluigi break; 244198943Sluigi } 244298943Sluigi 244398943Sluigi bp = buf; 244498943Sluigi for (rule = layer3_chain; rule ; rule = rule->next) { 244598943Sluigi int i = RULESIZE(rule); 244698943Sluigi bcopy(rule, bp, i); 2447101628Sluigi /* 2448101628Sluigi * abuse 'next_rule' to store the set_disable word 2449101628Sluigi */ 2450101628Sluigi (u_int32_t)(((struct ip_fw *)bp)->next_rule) = 2451101628Sluigi set_disable; 245298943Sluigi bp = (struct ip_fw *)((char *)bp + i); 245398943Sluigi } 245498943Sluigi if (ipfw_dyn_v) { 245598943Sluigi int i; 245698943Sluigi ipfw_dyn_rule *p, *dst, *last = NULL; 245798943Sluigi 245898943Sluigi dst = (ipfw_dyn_rule *)bp; 245998943Sluigi for (i = 0 ; i < curr_dyn_buckets ; i++ ) 246098943Sluigi for ( p = ipfw_dyn_v[i] ; p != NULL ; 246198943Sluigi p = p->next, dst++ ) { 246298943Sluigi bcopy(p, dst, sizeof *p); 246398943Sluigi (int)dst->rule = p->rule->rulenum ; 246498943Sluigi /* 246598943Sluigi * store a non-null value in "next". 246698943Sluigi * The userland code will interpret a 246798943Sluigi * NULL here as a marker 246898943Sluigi * for the last dynamic rule. 246998943Sluigi */ 247098943Sluigi dst->next = dst ; 247198943Sluigi last = dst ; 247298943Sluigi dst->expire = 247398943Sluigi TIME_LEQ(dst->expire, time_second) ? 247498943Sluigi 0 : dst->expire - time_second ; 247598943Sluigi } 247698943Sluigi if (last != NULL) /* mark last dynamic rule */ 247798943Sluigi last->next = NULL; 247898943Sluigi } 247998943Sluigi splx(s); 248098943Sluigi 248198943Sluigi error = sooptcopyout(sopt, buf, size); 248298943Sluigi free(buf, M_TEMP); 248398943Sluigi break; 248498943Sluigi 248598943Sluigi case IP_FW_FLUSH: 248698943Sluigi /* 248798943Sluigi * Normally we cannot release the lock on each iteration. 248898943Sluigi * We could do it here only because we start from the head all 248998943Sluigi * the times so there is no risk of missing some entries. 249098943Sluigi * On the other hand, the risk is that we end up with 249198943Sluigi * a very inconsistent ruleset, so better keep the lock 249298943Sluigi * around the whole cycle. 249398943Sluigi * 249498943Sluigi * XXX this code can be improved by resetting the head of 249598943Sluigi * the list to point to the default rule, and then freeing 249698943Sluigi * the old list without the need for a lock. 249798943Sluigi */ 249898943Sluigi 249998943Sluigi s = splimp(); 250098943Sluigi free_chain(&layer3_chain, 0 /* keep default rule */); 250198943Sluigi splx(s); 250298943Sluigi break; 250398943Sluigi 250498943Sluigi case IP_FW_ADD: 250598943Sluigi rule = (struct ip_fw *)rule_buf; /* XXX do a malloc */ 250698943Sluigi error = sooptcopyin(sopt, rule, sizeof(rule_buf), 250798943Sluigi sizeof(struct ip_fw) ); 250898943Sluigi size = sopt->sopt_valsize; 250998943Sluigi if (error || (error = check_ipfw_struct(rule, size))) 251098943Sluigi break; 251198943Sluigi 251298943Sluigi error = add_rule(&layer3_chain, rule); 251398943Sluigi size = RULESIZE(rule); 251498943Sluigi if (!error && sopt->sopt_dir == SOPT_GET) 251598943Sluigi error = sooptcopyout(sopt, rule, size); 251698943Sluigi break; 251798943Sluigi 251898943Sluigi case IP_FW_DEL: /* argument is an int, the rule number */ 2519101628Sluigi /* 2520101628Sluigi * IP_FW_DEL is used for deleting single rules, 2521101628Sluigi * set of rules, and manipulating set_disable. 2522101628Sluigi * 2523101628Sluigi * Everything is managed in del_entry(); 2524101628Sluigi */ 252598943Sluigi error = sooptcopyin(sopt, &rulenum, sizeof(int), sizeof(int)); 252698943Sluigi if (error) 252798943Sluigi break; 252898943Sluigi if (rulenum == IPFW_DEFAULT_RULE) { 252998943Sluigi if (fw_debug) 253098943Sluigi printf("ipfw: can't delete rule %u\n", 253198943Sluigi (unsigned)IPFW_DEFAULT_RULE); 253298943Sluigi error = EINVAL; 253398943Sluigi } else 253498943Sluigi error = del_entry(&layer3_chain, rulenum); 253598943Sluigi break; 253698943Sluigi 253798943Sluigi case IP_FW_ZERO: 253898943Sluigi case IP_FW_RESETLOG: /* argument is an int, the rule number */ 253998943Sluigi rulenum=0; 254098943Sluigi 254198943Sluigi if (sopt->sopt_val != 0) { 254298943Sluigi error = sooptcopyin(sopt, &rulenum, 254398943Sluigi sizeof(int), sizeof(int)); 254498943Sluigi if (error) 254598943Sluigi break; 254698943Sluigi } 254798943Sluigi error = zero_entry(rulenum, sopt->sopt_name == IP_FW_RESETLOG); 254898943Sluigi break; 254998943Sluigi 255098943Sluigi default: 255198943Sluigi printf("ipfw_ctl invalid option %d\n", sopt->sopt_name); 255298943Sluigi error = EINVAL; 255398943Sluigi } 255498943Sluigi 255598943Sluigi return (error); 255698943Sluigi} 255798943Sluigi 255898943Sluigi/** 255998943Sluigi * dummynet needs a reference to the default rule, because rules can be 256098943Sluigi * deleted while packets hold a reference to them. When this happens, 256198943Sluigi * dummynet changes the reference to the default rule (it could well be a 256298943Sluigi * NULL pointer, but this way we do not need to check for the special 256398943Sluigi * case, plus here he have info on the default behaviour). 256498943Sluigi */ 256598943Sluigistruct ip_fw *ip_fw_default_rule; 256698943Sluigi 256798943Sluigistatic void 2568100004Sluigiipfw_tick(void * __unused unused) 2569100004Sluigi{ 2570100004Sluigi int i; 2571100004Sluigi int s; 2572100004Sluigi ipfw_dyn_rule *q; 2573100004Sluigi 2574100004Sluigi if (dyn_keepalive == 0 || ipfw_dyn_v == NULL || dyn_count == 0) 2575100004Sluigi goto done; 2576100004Sluigi 2577100004Sluigi s = splimp(); 2578100004Sluigi for (i = 0 ; i < curr_dyn_buckets ; i++) { 2579100004Sluigi for (q = ipfw_dyn_v[i] ; q ; q = q->next ) { 2580100004Sluigi if (q->dyn_type == O_LIMIT_PARENT) 2581100004Sluigi continue; 2582100004Sluigi if (q->id.proto != IPPROTO_TCP) 2583100004Sluigi continue; 2584100004Sluigi if ( (q->state & BOTH_SYN) != BOTH_SYN) 2585100004Sluigi continue; 2586100004Sluigi if (TIME_LEQ( time_second+20, q->expire)) 2587100004Sluigi continue; /* too early */ 2588100004Sluigi if (TIME_LEQ(q->expire, time_second)) 2589100004Sluigi continue; /* too late, rule expired */ 2590100004Sluigi 2591100004Sluigi send_pkt(&(q->id), q->ack_rev - 1, q->ack_fwd, TH_SYN); 2592100004Sluigi send_pkt(&(q->id), q->ack_fwd - 1, q->ack_rev, 0); 2593100004Sluigi } 2594100004Sluigi } 2595100004Sluigi splx(s); 2596100004Sluigidone: 2597100004Sluigi ipfw_timeout_h = timeout(ipfw_tick, NULL, 5*hz); 2598100004Sluigi} 2599100004Sluigi 2600100004Sluigistatic void 260198943Sluigiipfw_init(void) 260298943Sluigi{ 260398943Sluigi struct ip_fw default_rule; 260498943Sluigi 260598943Sluigi ip_fw_chk_ptr = ipfw_chk; 260698943Sluigi ip_fw_ctl_ptr = ipfw_ctl; 260798943Sluigi layer3_chain = NULL; 260898943Sluigi 260998943Sluigi bzero(&default_rule, sizeof default_rule); 261098943Sluigi 261198943Sluigi default_rule.act_ofs = 0; 261298943Sluigi default_rule.rulenum = IPFW_DEFAULT_RULE; 261398943Sluigi default_rule.cmd_len = 1; 2614101628Sluigi default_rule.set = 31; 261598943Sluigi 261698943Sluigi default_rule.cmd[0].len = 1; 261798943Sluigi default_rule.cmd[0].opcode = 261898943Sluigi#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT 261998943Sluigi 1 ? O_ACCEPT : 262098943Sluigi#endif 262198943Sluigi O_DENY; 262298943Sluigi 262398943Sluigi add_rule(&layer3_chain, &default_rule); 262498943Sluigi 262598943Sluigi ip_fw_default_rule = layer3_chain; 262698943Sluigi printf("IP packet filtering initialized, divert %s, " 262798943Sluigi "rule-based forwarding %s, default to %s, logging ", 262898943Sluigi#ifdef IPDIVERT 262998943Sluigi "enabled", 263098943Sluigi#else 263198943Sluigi "disabled", 263298943Sluigi#endif 263398943Sluigi "enabled", 263498943Sluigi default_rule.cmd[0].opcode == O_ACCEPT ? "accept" : "deny"); 263598943Sluigi 263698943Sluigi#ifdef IPFIREWALL_VERBOSE 263798943Sluigi fw_verbose = 1; 263898943Sluigi#endif 263998943Sluigi#ifdef IPFIREWALL_VERBOSE_LIMIT 264098943Sluigi verbose_limit = IPFIREWALL_VERBOSE_LIMIT; 264198943Sluigi#endif 264298943Sluigi printf("logging "); 264398943Sluigi if (fw_verbose == 0) 264498943Sluigi printf("disabled\n"); 264598943Sluigi else if (verbose_limit == 0) 264698943Sluigi printf("unlimited\n"); 264798943Sluigi else 264898943Sluigi printf("limited to %d packets/entry by default\n", 264998943Sluigi verbose_limit); 2650100004Sluigi bzero(&ipfw_timeout_h, sizeof(struct callout_handle)); 2651100004Sluigi ipfw_timeout_h = timeout(ipfw_tick, NULL, hz); 265298943Sluigi} 265398943Sluigi 265498943Sluigistatic int 265598943Sluigiipfw_modevent(module_t mod, int type, void *unused) 265698943Sluigi{ 265798943Sluigi int s; 265898943Sluigi int err = 0; 265998943Sluigi 266098943Sluigi switch (type) { 266198943Sluigi case MOD_LOAD: 266298943Sluigi s = splimp(); 266398943Sluigi if (IPFW_LOADED) { 266498943Sluigi splx(s); 266598943Sluigi printf("IP firewall already loaded\n"); 266698943Sluigi err = EEXIST; 266798943Sluigi } else { 266898943Sluigi ipfw_init(); 266998943Sluigi splx(s); 267098943Sluigi } 267198943Sluigi break; 267298943Sluigi 267398943Sluigi case MOD_UNLOAD: 267498943Sluigi#if !defined(KLD_MODULE) 267598943Sluigi printf("ipfw statically compiled, cannot unload\n"); 267698943Sluigi err = EBUSY; 267798943Sluigi#else 267898943Sluigi s = splimp(); 2679100004Sluigi untimeout(ipfw_tick, NULL, ipfw_timeout_h); 268098943Sluigi ip_fw_chk_ptr = NULL; 268198943Sluigi ip_fw_ctl_ptr = NULL; 268298943Sluigi free_chain(&layer3_chain, 1 /* kill default rule */); 268398943Sluigi splx(s); 268498943Sluigi printf("IP firewall unloaded\n"); 268598943Sluigi#endif 268698943Sluigi break; 268798943Sluigi default: 268898943Sluigi break; 268998943Sluigi } 269098943Sluigi return err; 269198943Sluigi} 269298943Sluigi 269398943Sluigistatic moduledata_t ipfwmod = { 269498943Sluigi "ipfw", 269598943Sluigi ipfw_modevent, 269698943Sluigi 0 269798943Sluigi}; 269898943SluigiDECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY); 269998943SluigiMODULE_VERSION(ipfw, 1); 270099622Sluigi#endif /* IPFW2 */ 2701