socsvn commit: r271013 - in soc2014/dpl/netmap-ipfwjit: . sys/netpfil/ipfw
dpl at FreeBSD.org
dpl at FreeBSD.org
Thu Jul 17 09:48:36 UTC 2014
Author: dpl
Date: Thu Jul 17 09:48:34 2014
New Revision: 271013
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=271013
Log:
Modified Makefiles so that we can make everything now. Also added the most basic boilerplate to use llvm.
Added:
soc2014/dpl/netmap-ipfwjit/sys/netpfil/ipfw/ip_fw2.cc
Deleted:
soc2014/dpl/netmap-ipfwjit/sys/netpfil/ipfw/ip_fw2.c
soc2014/dpl/netmap-ipfwjit/sys/netpfil/ipfw/ip_fw_rules.bc
Modified:
soc2014/dpl/netmap-ipfwjit/Makefile
soc2014/dpl/netmap-ipfwjit/Makefile.kipfw
Modified: soc2014/dpl/netmap-ipfwjit/Makefile
==============================================================================
--- soc2014/dpl/netmap-ipfwjit/Makefile Thu Jul 17 07:12:12 2014 (r271012)
+++ soc2014/dpl/netmap-ipfwjit/Makefile Thu Jul 17 09:48:34 2014 (r271013)
@@ -26,6 +26,7 @@
clean:
- at rm -rf $(OBJDIR) kipfw
@(cd ipfw && $(MAKE) clean )
+ @rm ./ip_fw_rules.bc
tgz:
@$(MAKE) clean
Modified: soc2014/dpl/netmap-ipfwjit/Makefile.kipfw
==============================================================================
--- soc2014/dpl/netmap-ipfwjit/Makefile.kipfw Thu Jul 17 07:12:12 2014 (r271012)
+++ soc2014/dpl/netmap-ipfwjit/Makefile.kipfw Thu Jul 17 09:48:34 2014 (r271013)
@@ -124,7 +124,6 @@
#EFILES += sys/proc.h sys/rwlock.h sys/socket.h sys/socketvar.h
#EFILES += sys/sysctl.h sys/time.h sys/ucred.h
-
#EFILES += vm/uma_int.h vm/vm_int.h vm/uma_dbg.h
#EFILES += vm/vm_dbg.h vm/vm_page.h vm/vm.h
#EFILES += sys/rwlock.h sys/sysctl.h
@@ -136,6 +135,10 @@
# and the ": = " substitution packs spaces into one.
EFILES = $(foreach i,$(EDIRS),$(subst $(empty) , $(i)/, $(EFILES_$(i): = )))
+BCFLAGS=-emit-llvm -c
+CXX=clang++
+CXXFLAGS= $(CFLAGS) `llvm-config-devel --cxxflags --libs jit support`
+
include_e:
- at echo "Building $(OBJPATH)/include_e ..."
-$(HIDE) rm -rf $(OBJPATH)/include_e opt_*
@@ -152,10 +155,18 @@
# session.o: CFLAGS = -O2
nm_util.o: CFLAGS = -O2 -Wall -Werror $(NETMAP_FLAGS)
-$(MOD): $(IPFW_OBJS)
+$(MOD): $(IPFW_OBJS) ../ip_fw_rules.bc
$(MSG) " LD $@"
$(HIDE)$(CC) -o $@ $^ $(LIBS)
+#Generate the actual bytecode to be used
+../ip_fw_rules.bc:
+ @$(CC) $(CFLAGS) $(BCFLAGS) -o ../ip_fw_rules.bc ../sys/netpfil/ipfw/ip_fw_rules.h
+
+ip_fw2.o: ip_fw2.cc
+ @echo "Building ip_fw2.cc"
+ clang++ $(CXXFLAGS) ../sys/netpfil/ipfw/ip_fw2.cc -o ./ip_fw2.o
+
clean:
-rm -f *.o $(DN) $(MOD)
-rm -rf include_e
Added: soc2014/dpl/netmap-ipfwjit/sys/netpfil/ipfw/ip_fw2.cc
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ soc2014/dpl/netmap-ipfwjit/sys/netpfil/ipfw/ip_fw2.cc Thu Jul 17 09:48:34 2014 (r271013)
@@ -0,0 +1,1543 @@
+/*-
+ * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/netpfil/ipfw/ip_fw2.c 243711 2012-11-30 19:36:55Z melifaro $");
+
+/*
+ * The FreeBSD IP packet firewall, main file
+ */
+
+#include "opt_ipfw.h"
+#include "opt_ipdivert.h"
+#include "opt_inet.h"
+#ifndef INET
+#error "IPFIREWALL requires INET"
+#endif /* INET */
+#include "opt_inet6.h"
+#include "opt_ipsec.h"
+#include "ip_fw_rules.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/condvar.h>
+#include <sys/eventhandler.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/jail.h>
+#include <sys/module.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/rwlock.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/ucred.h>
+#include <net/ethernet.h> /* for ETHERTYPE_IP */
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <net/pfil.h>
+#include <net/vnet.h>
+
+#include <netpfil/pf/pf_mtag.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_fw.h>
+#include <netinet/ip_carp.h>
+#include <netinet/pim.h>
+#include <netinet/tcp_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/sctp.h>
+
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#ifdef INET6
+#include <netinet6/in6_pcb.h>
+#include <netinet6/scope6_var.h>
+#include <netinet6/ip6_var.h>
+#endif
+
+#include <netpfil/ipfw/ip_fw_private.h>
+
+#include <machine/in_cksum.h> /* XXX for in_cksum */
+
+#ifdef MAC
+#include <security/mac/mac_framework.h>
+#endif
+
+/*
+ * static variables followed by global ones.
+ * All ipfw global variables are here.
+ */
+
+/* ipfw_vnet_ready controls when we are open for business */
+static VNET_DEFINE(int, ipfw_vnet_ready) = 0;
+#define V_ipfw_vnet_ready VNET(ipfw_vnet_ready)
+
+static VNET_DEFINE(int, fw_deny_unknown_exthdrs);
+#define V_fw_deny_unknown_exthdrs VNET(fw_deny_unknown_exthdrs)
+
+static VNET_DEFINE(int, fw_permit_single_frag6) = 1;
+#define V_fw_permit_single_frag6 VNET(fw_permit_single_frag6)
+
+#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
+static int default_to_accept = 1;
+#else
+static int default_to_accept;
+#endif
+
+VNET_DEFINE(int, autoinc_step);
+VNET_DEFINE(int, fw_one_pass) = 1;
+
+VNET_DEFINE(unsigned int, fw_tables_max);
+/* Use 128 tables by default */
+static unsigned int default_fw_tables = IPFW_TABLES_DEFAULT;
+
+/* Rule functions, ordered by appereance in the code */
+static inline void rule_nop(int *);
+static inline void rule_forward_mac(int);
+static inline void rule_jail(int *, u_short, uint8_t, ipfw_insn *, struct ip_fw_args *, int, void *);
+static inline void rule_recv(int *, ipfw_insn *, struct mbuf *, struct ip_fw_chain *, uint32_t *);
+static inline void rule_xmit(int *, struct ifnet *, ipfw_insn *, struct ip_fw_chain *, uint32_t *);
+static inline void rule_via(int *, struct ifnet *, struct mbuf *, ipfw_insn *, struct ip_fw_chain *, uint32_t *);
+static inline void rule_macaddr2(int *, struct ip_fw_args *, ipfw_insn *);
+static inline void rule_mac_type(int *, struct ip_fw_args *, ipfw_insn *, int, uint16_t);
+static inline void rule_frag(int *, u_short);
+static inline void rule_in(int *, struct ifnet *);
+static inline void rule_layer2(int *, struct ip_fw_args *);
+static inline void rule_diverted(int *, struct ip_fw_args *, ipfw_insn *);
+static inline void rule_proto(int *, uint8_t, ipfw_insn *);
+static inline void rule_ip_src(int *, int, ipfw_insn *, struct in_addr *);
+static inline void rule_ip_dst_lookup(int *, ipfw_insn *, int, struct ip_fw_args *, uint32_t *, int, int, struct ip *, struct in_addr *, struct in_addr *, uint16_t, uint16_t, u_short, uint8_t, int, void *, struct ip_fw_chain *);
+static inline void rule_ip_dst_mask(int *, int, ipfw_insn *, int, struct in_addr *, struct in_addr *);
+static inline void rule_ip_src_me(int *, int, int, struct in_addr *, struct ip_fw_args *);
+
+#ifdef INET6
+static inline void rule_ip6_src_me(int *, int, struct ip_fw_args *);
+#endif /* INET6 */
+
+static inline void rule_ip_src_set(int *, int, ipfw_insn *, struct ip_fw_args *);
+static inline void rule_ip_dst(int *, int, ipfw_insn *, struct in_addr *);
+static inline void rule_ip_dst_me(int *, struct ip_fw_args *, int, int, struct in_addr *);
+
+#ifdef INET6
+static inline void rule_ip6_dst_me(int *, struct ip_fw_args *args, int is_ipv6);
+#endif /* INET6 */
+
+static inline void rule_ip_dstport(int *, uint8_t, u_short , ipfw_insn *, int , uint16_t , uint16_t);
+static inline void rule_icmptype(int *, u_short, uint8_t , void *, ipfw_insn *);
+
+#ifdef INET6
+static inline void rule_icmp6type(int *, u_short, int, uint8_t, void *, ipfw_insn *);
+#endif /* INET6 */
+
+static inline void rule_ipopt(int *, int, struct ip *, ipfw_insn *);
+static inline void rule_ipver(int *, int, ipfw_insn *, struct ip *);
+static inline void rule_ipttl(int *, int, ipfw_insn *, int, struct ip *, uint16_t);
+static inline void rule_ipprecedence(int *, int, ipfw_insn *, struct ip *);
+static inline void rule_iptos(int *, int, ipfw_insn *, struct ip *);
+static inline void rule_dscp(int *, int, int, ipfw_insn *, struct ip *);
+static inline void rule_tcpdatalen(int *, uint8_t, u_short, void *, uint16_t, int, ipfw_insn *, struct ip *);
+static inline void rule_tcpflags(int *, uint8_t, u_short, ipfw_insn *, void *);
+static inline int rule_tcpopts(int *, u_int, void *, uint8_t, u_short, ipfw_insn *, struct mbuf *, struct ip_fw_args *);
+static inline void rule_tcpseq(int *, uint8_t, u_short, ipfw_insn *, void *);
+static inline void rule_tcpack(int *, uint8_t, u_short, ipfw_insn *, void *);
+static inline void rule_tcpwin(int *, uint8_t, u_short, ipfw_insn *, int, void *);
+static inline void rule_estab(int *, uint8_t, u_short, void *);
+static inline void rule_altq(int *, ipfw_insn *, struct mbuf *, struct ip *);
+static inline void rule_log(int *, struct ip_fw *, u_int, struct ip_fw_args *, struct mbuf *, struct ifnet *, u_short, u_short, uint32_t, struct ip *);
+static inline void rule_prob(int *, ipfw_insn *);
+static inline void rule_verrevpath(int *, struct ifnet *, struct mbuf *, int, struct ip_fw_args *, struct in_addr *);
+static inline void rule_versrcreach(int *, u_int, struct ifnet *, int, struct ip_fw_args *, struct in_addr *);
+static inline void rule_antispoof(int *, struct ifnet *, u_int, int, int, struct in_addr *, struct ip_fw_args *, struct mbuf *);
+
+#ifdef IPSEC
+static inline void rule_ipsec(int *match, struct mbuf *);
+#endif /* IPSEC */
+
+#ifdef INET6
+static inline void rule_ip6_src(int *, int, struct ip_fw_args *, ipfw_insn *);
+static inline void rule_ip6_dst(int *, int, struct ip_fw_args *, ipfw_insn *);
+static inline void rule_ip6_dst_mask(int *, struct ip_fw_args *, ipfw_insn *, int, int);
+static inline void rule_flow6id(int *, int, struct ip_fw_args *, ipfw_insn *);
+static inline void rule_ext_hdr(int *, int, uint16_t, ipfw_insn *);
+static inline void rule_ip6(int *, int);
+#endif /* INET6 */
+
+static inline void rule_ip4(int *, int);
+static inline void rule_tag(int *, ipfw_insn *, struct mbuf *, uint32_t);
+static inline void rule_fib(int *, struct ip_fw_args *, ipfw_insn *);
+static inline void rule_sockarg(int *, int, uint8_t, struct in_addr *, struct in_addr *, uint16_t, uint16_t, struct ip_fw_args *, uint32_t *);
+static inline void rule_tagged(int *, ipfw_insn *, int, struct mbuf *, uint32_t);
+
+/* The second sets of opcodes. They represent the actions of a rule. */
+static inline void rule_keep_state(int *, struct ip_fw *f, ipfw_insn *, struct ip_fw_args *, uint32_t, int *, int *, int *);
+static inline void rule_check_state(int *, int *, ipfw_dyn_rule *, struct ip_fw_args *, uint8_t, void *, int, struct ip_fw *, int *, struct ip_fw_chain *, ipfw_insn *, int *, int *);
+static inline void rule_accept(int *, int *, int *);
+static inline void rule_queue(struct ip_fw_args *, int, struct ip_fw_chain *, ipfw_insn *, uint32_t, int *, int *, int *);
+static inline void rule_tee(int *, int *, int *, ipfw_insn *, struct ip_fw_args *, int, uint32_t, struct ip_fw_chain *);
+static inline void rule_count(int *, struct ip_fw *, int);
+static inline void rule_skipto(int *, int *, ipfw_insn *, int *, int *, int *, struct ip_fw *, int, struct ip_fw_chain *, uint32_t);
+static inline void rule_callreturn(ipfw_insn *, struct mbuf *, struct ip_fw *, struct ip_fw_chain *, uint32_t, int, int *, int *, int *, int *);
+static inline void rule_reject(u_int, int, u_short, uint8_t, void *, struct mbuf *, struct in_addr *, struct ip_fw_args *, ipfw_insn *, uint16_t, struct ip *);
+
+#ifdef INET6
+static inline void rule_unreach6(u_int, int, u_short, uint8_t, uint8_t, struct mbuf *, struct ip_fw_args *, ipfw_insn *, struct ip *);
+#endif /* INET6 */
+
+static inline void rule_deny(int *, int *, int *);
+static inline void rule_forward_ip(struct ip_fw_args *, ipfw_dyn_rule *, struct ip_fw *, int, ipfw_insn *, uint32_t, int *, int *, int *);
+
+#ifdef INET6
+static inline void rule_forward_ip6(struct ip_fw_args *, ipfw_dyn_rule *, struct ip_fw *, int, ipfw_insn *, int *, int *, int *);
+#endif /* INET6 */
+
+static inline void rule_ngtee(struct ip_fw_args *, int, struct ip_fw_chain *, ipfw_insn *, uint32_t, int *, int *, int *);
+static inline void rule_setfib(struct ip_fw *, int, uint32_t, ipfw_insn *, struct mbuf *, struct ip_fw_args *, int *);
+static inline void rule_setdscp(ipfw_insn *, struct ip *, int, int, uint32_t, struct ip_fw *, int, int *);
+static inline void rule_nat(struct ip_fw_args *, int, struct ip_fw_chain *, ipfw_insn *, struct mbuf *, uint32_t, int *, int *, int *);
+static inline void rule_reass(struct ip_fw *, int, struct ip_fw_chain *, int, struct ip *, struct ip_fw_args *, struct mbuf *, int *, int *, int *);
+
+/*
+ * Each rule belongs to one of 32 different sets (0..31).
+ * The variable set_disable contains one bit per set.
+ * If the bit is set, all rules in the corresponding set
+ * are disabled. Set RESVD_SET(31) is reserved for the default rule
+ * and rules that are not deleted by the flush command,
+ * and CANNOT be disabled.
+ * Rules in set RESVD_SET can only be deleted individually.
+ */
+VNET_DEFINE(u_int32_t, set_disable);
+#define V_set_disable VNET(set_disable)
+
+VNET_DEFINE(int, fw_verbose);
+/* counter for ipfw_log(NULL...) */
+VNET_DEFINE(u_int64_t, norule_counter);
+VNET_DEFINE(int, verbose_limit);
+
+/* layer3_chain contains the list of rules for layer 3 */
+VNET_DEFINE(struct ip_fw_chain, layer3_chain);
+
+VNET_DEFINE(int, ipfw_nat_ready) = 0;
+
+ipfw_nat_t *ipfw_nat_ptr = NULL;
+struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);
+ipfw_nat_cfg_t *ipfw_nat_cfg_ptr;
+ipfw_nat_cfg_t *ipfw_nat_del_ptr;
+ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
+ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
+
+#ifdef SYSCTL_NODE
+uint32_t dummy_def = IPFW_DEFAULT_RULE;
+static int sysctl_ipfw_table_num(SYSCTL_HANDLER_ARGS);
+
+SYSBEGIN(f3)
+
+SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, one_pass,
+ CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_one_pass), 0,
+ "Only do a single pass through ipfw when using dummynet(4)");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step,
+ CTLFLAG_RW, &VNET_NAME(autoinc_step), 0,
+ "Rule number auto-increment step");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose,
+ CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_verbose), 0,
+ "Log matches to ipfw rules");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit,
+ CTLFLAG_RW, &VNET_NAME(verbose_limit), 0,
+ "Set upper limit of matches of ipfw rules logged");
+SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD,
+ &dummy_def, 0,
+ "The default/max possible rule number.");
+SYSCTL_VNET_PROC(_net_inet_ip_fw, OID_AUTO, tables_max,
+ CTLTYPE_UINT|CTLFLAG_RW, 0, 0, sysctl_ipfw_table_num, "IU",
+ "Maximum number of tables");
+SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
+ &default_to_accept, 0,
+ "Make the default rule accept all packets.");
+TUNABLE_INT("net.inet.ip.fw.default_to_accept", &default_to_accept);
+TUNABLE_INT("net.inet.ip.fw.tables_max", (int *)&default_fw_tables);
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count,
+ CTLFLAG_RD, &VNET_NAME(layer3_chain.n_rules), 0,
+ "Number of static rules");
+
+#ifdef INET6
+SYSCTL_DECL(_net_inet6_ip6);
+SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
+SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,
+ CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_deny_unknown_exthdrs), 0,
+ "Deny packets with unknown IPv6 Extension Headers");
+SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, permit_single_frag6,
+ CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_permit_single_frag6), 0,
+ "Permit single packet IPv6 fragments");
+#endif /* INET6 */
+
+SYSEND
+
+#endif /* SYSCTL_NODE */
+
+
+/*
+ * Some macros used in the various matching options.
+ * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T
+ * Other macros just cast void * into the appropriate type
+ */
+#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl))
+#define TCP(p) ((struct tcphdr *)(p))
+#define SCTP(p) ((struct sctphdr *)(p))
+#define UDP(p) ((struct udphdr *)(p))
+#define ICMP(p) ((struct icmphdr *)(p))
+#define ICMP6(p) ((struct icmp6_hdr *)(p))
+
+/*
+ * The main check routine for the firewall.
+ *
+ * All arguments are in args so we can modify them and return them
+ * back to the caller.
+ *
+ * Parameters:
+ *
+ * args->m (in/out) The packet; we set to NULL when/if we nuke it.
+ * Starts with the IP header.
+ * args->eh (in) Mac header if present, NULL for layer3 packet.
+ * args->L3offset Number of bytes bypassed if we came from L2.
+ * e.g. often sizeof(eh) ** NOTYET **
+ * args->oif Outgoing interface, NULL if packet is incoming.
+ * The incoming interface is in the mbuf. (in)
+ * args->divert_rule (in/out)
+ * Skip up to the first rule past this rule number;
+ * upon return, non-zero port number for divert or tee.
+ *
+ * args->rule Pointer to the last matching rule (in/out)
+ * args->next_hop Socket we are forwarding to (out).
+ * args->next_hop6 IPv6 next hop we are forwarding to (out).
+ * args->f_id Addresses grabbed from the packet (out)
+ * args->rule.info a cookie depending on rule action
+ *
+ * Return value:
+ *
+ * IP_FW_PASS the packet must be accepted
+ * IP_FW_DENY the packet must be dropped
+ * IP_FW_DIVERT divert packet, port in m_tag
+ * IP_FW_TEE tee packet, port in m_tag
+ * IP_FW_DUMMYNET to dummynet, pipe in args->cookie
+ * IP_FW_NETGRAPH into netgraph, cookie args->cookie
+ * args->rule contains the matching rule,
+ * args->rule.info has additional information.
+ *
+ */
+int
+ipfw_chk(struct ip_fw_args *args)
+{
+
+ /*
+ * Local variables holding state while processing a packet:
+ *
+ * IMPORTANT NOTE: to speed up the processing of rules, there
+ * are some assumption on the values of the variables, which
+ * are documented here. Should you change them, please check
+ * the implementation of the various instructions to make sure
+ * that they still work.
+ *
+ * args->eh The MAC header. It is non-null for a layer2
+ * packet, it is NULL for a layer-3 packet.
+ * **notyet**
+ * args->L3offset Offset in the packet to the L3 (IP or equiv.) header.
+ *
+ * m | args->m Pointer to the mbuf, as received from the caller.
+ * It may change if ipfw_chk() does an m_pullup, or if it
+ * consumes the packet because it calls send_reject().
+ * XXX This has to change, so that ipfw_chk() never modifies
+ * or consumes the buffer.
+ * ip is the beginning of the ip(4 or 6) header.
+ * Calculated by adding the L3offset to the start of data.
+ * (Until we start using L3offset, the packet is
+ * supposed to start with the ip header).
+ */
+ struct mbuf *m = args->m;
+ struct ip *ip = mtod(m, struct ip *);
+
+ /*
+ * For rules which contain uid/gid or jail constraints, cache
+ * a copy of the users credentials after the pcb lookup has been
+ * executed. This will speed up the processing of rules with
+ * these types of constraints, as well as decrease contention
+ * on pcb related locks.
+ */
+#ifndef __FreeBSD__
+ struct bsd_ucred ucred_cache;
+#else
+ struct ucred *ucred_cache = NULL;
+#endif
+ int ucred_lookup = 0;
+
+ /*
+ * oif | args->oif If NULL, ipfw_chk has been called on the
+ * inbound path (ether_input, ip_input).
+ * If non-NULL, ipfw_chk has been called on the outbound path
+ * (ether_output, ip_output).
+ */
+ struct ifnet *oif = args->oif;
+
+ int f_pos = 0; /* index of current rule in the array */
+ int retval = 0;
+
+ /*
+ * hlen The length of the IP header.
+ */
+ u_int hlen = 0; /* hlen >0 means we have an IP pkt */
+
+ /*
+ * offset The offset of a fragment. offset != 0 means that
+ * we have a fragment at this offset of an IPv4 packet.
+ * offset == 0 means that (if this is an IPv4 packet)
+ * this is the first or only fragment.
+ * For IPv6 offset|ip6f_mf == 0 means there is no Fragment Header
+ * or there is a single packet fragement (fragement header added
+ * without needed). We will treat a single packet fragment as if
+ * there was no fragment header (or log/block depending on the
+ * V_fw_permit_single_frag6 sysctl setting).
+ */
+ u_short offset = 0;
+ u_short ip6f_mf = 0;
+
+ /*
+ * Local copies of addresses. They are only valid if we have
+ * an IP packet.
+ *
+ * proto The protocol. Set to 0 for non-ip packets,
+ * or to the protocol read from the packet otherwise.
+ * proto != 0 means that we have an IPv4 packet.
+ *
+ * src_port, dst_port port numbers, in HOST format. Only
+ * valid for TCP and UDP packets.
+ *
+ * src_ip, dst_ip ip addresses, in NETWORK format.
+ * Only valid for IPv4 packets.
+ */
+ uint8_t proto;
+ uint16_t src_port = 0, dst_port = 0; /* NOTE: host format */
+ struct in_addr src_ip, dst_ip; /* NOTE: network format */
+ uint16_t iplen=0;
+ int pktlen;
+ uint16_t etype = 0; /* Host order stored ether type */
+
+ /*
+ * dyn_dir = MATCH_UNKNOWN when rules unchecked,
+ * MATCH_NONE when checked and not matched (q = NULL),
+ * MATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL)
+ */
+ int dyn_dir = MATCH_UNKNOWN;
+ ipfw_dyn_rule *q = NULL;
+ struct ip_fw_chain *chain = &V_layer3_chain;
+
+ /*
+ * We store in ulp a pointer to the upper layer protocol header.
+ * In the ipv4 case this is easy to determine from the header,
+ * but for ipv6 we might have some additional headers in the middle.
+ * ulp is NULL if not found.
+ */
+ void *ulp = NULL; /* upper layer protocol pointer. */
+
+ /* XXX ipv6 variables */
+ int is_ipv6 = 0;
+ uint8_t icmp6_type = 0;
+ uint16_t ext_hd = 0; /* bits vector for extension header filtering */
+ /* end of ipv6 variables */
+
+ int is_ipv4 = 0;
+
+ int done = 0; /* flag to exit the outer loop */
+
+ if (m->m_flags & M_SKIP_FIREWALL || (! V_ipfw_vnet_ready))
+ return (IP_FW_PASS); /* accept */
+
+ dst_ip.s_addr = 0; /* make sure it is initialized */
+ src_ip.s_addr = 0; /* make sure it is initialized */
+ pktlen = m->m_pkthdr.len;
+ args->f_id.fib = M_GETFIB(m); /* note mbuf not altered) */
+ proto = args->f_id.proto = 0; /* mark f_id invalid */
+ /* XXX 0 is a valid proto: IP/IPv6 Hop-by-Hop Option */
+
+/*
+ * PULLUP_TO(len, p, T) makes sure that len + sizeof(T) is contiguous,
+ * then it sets p to point at the offset "len" in the mbuf. WARNING: the
+ * pointer might become stale after other pullups (but we never use it
+ * this way).
+ */
+#define PULLUP_TO(_len, p, T) PULLUP_LEN(_len, p, sizeof(T))
+#define PULLUP_LEN(_len, p, T) \
+do { \
+ int x = (_len) + T; \
+ if ((m)->m_len < x) { \
+ args->m = m = m_pullup(m, x); \
+ if (m == NULL) \
+ goto pullup_failed; \
+ } \
+ p = (mtod(m, char *) + (_len)); \
+} while (0)
+
+ /*
+ * if we have an ether header,
+ */
+ if (args->eh)
+ etype = ntohs(args->eh->ether_type);
+
+ /* Identify IP packets and fill up variables. */
+ if (pktlen >= sizeof(struct ip6_hdr) &&
+ (args->eh == NULL || etype == ETHERTYPE_IPV6) && ip->ip_v == 6) {
+ struct ip6_hdr *ip6 = (struct ip6_hdr *)ip;
+ is_ipv6 = 1;
+ args->f_id.addr_type = 6;
+ hlen = sizeof(struct ip6_hdr);
+ proto = ip6->ip6_nxt;
+
+ /* Search extension headers to find upper layer protocols */
+ while (ulp == NULL && offset == 0) {
+ switch (proto) {
+ case IPPROTO_ICMPV6:
+ PULLUP_TO(hlen, ulp, struct icmp6_hdr);
+ icmp6_type = ICMP6(ulp)->icmp6_type;
+ break;
+
+ case IPPROTO_TCP:
+ PULLUP_TO(hlen, ulp, struct tcphdr);
+ dst_port = TCP(ulp)->th_dport;
+ src_port = TCP(ulp)->th_sport;
+ /* save flags for dynamic rules */
+ args->f_id._flags = TCP(ulp)->th_flags;
+ break;
+
+ case IPPROTO_SCTP:
+ PULLUP_TO(hlen, ulp, struct sctphdr);
+ src_port = SCTP(ulp)->src_port;
+ dst_port = SCTP(ulp)->dest_port;
+ break;
+
+ case IPPROTO_UDP:
+ PULLUP_TO(hlen, ulp, struct udphdr);
+ dst_port = UDP(ulp)->uh_dport;
+ src_port = UDP(ulp)->uh_sport;
+ break;
+
+ case IPPROTO_HOPOPTS: /* RFC 2460 */
+ PULLUP_TO(hlen, ulp, struct ip6_hbh);
+ ext_hd |= EXT_HOPOPTS;
+ hlen += (((struct ip6_hbh *)ulp)->ip6h_len + 1) << 3;
+ proto = ((struct ip6_hbh *)ulp)->ip6h_nxt;
+ ulp = NULL;
+ break;
+
+ case IPPROTO_ROUTING: /* RFC 2460 */
+ PULLUP_TO(hlen, ulp, struct ip6_rthdr);
+ switch (((struct ip6_rthdr *)ulp)->ip6r_type) {
+ case 0:
+ ext_hd |= EXT_RTHDR0;
+ break;
+ case 2:
+ ext_hd |= EXT_RTHDR2;
+ break;
+ default:
+ if (V_fw_verbose)
+ printf("IPFW2: IPV6 - Unknown "
+ "Routing Header type(%d)\n",
+ ((struct ip6_rthdr *)
+ ulp)->ip6r_type);
+ if (V_fw_deny_unknown_exthdrs)
+ return (IP_FW_DENY);
+ break;
+ }
+ ext_hd |= EXT_ROUTING;
+ hlen += (((struct ip6_rthdr *)ulp)->ip6r_len + 1) << 3;
+ proto = ((struct ip6_rthdr *)ulp)->ip6r_nxt;
+ ulp = NULL;
+ break;
+
+ case IPPROTO_FRAGMENT: /* RFC 2460 */
+ PULLUP_TO(hlen, ulp, struct ip6_frag);
+ ext_hd |= EXT_FRAGMENT;
+ hlen += sizeof (struct ip6_frag);
+ proto = ((struct ip6_frag *)ulp)->ip6f_nxt;
+ offset = ((struct ip6_frag *)ulp)->ip6f_offlg &
+ IP6F_OFF_MASK;
+ ip6f_mf = ((struct ip6_frag *)ulp)->ip6f_offlg &
+ IP6F_MORE_FRAG;
+ if (V_fw_permit_single_frag6 == 0 &&
+ offset == 0 && ip6f_mf == 0) {
+ if (V_fw_verbose)
+ printf("IPFW2: IPV6 - Invalid "
+ "Fragment Header\n");
+ if (V_fw_deny_unknown_exthdrs)
+ return (IP_FW_DENY);
+ break;
+ }
+ args->f_id.extra =
+ ntohl(((struct ip6_frag *)ulp)->ip6f_ident);
+ ulp = NULL;
+ break;
+
+ case IPPROTO_DSTOPTS: /* RFC 2460 */
+ PULLUP_TO(hlen, ulp, struct ip6_hbh);
+ ext_hd |= EXT_DSTOPTS;
+ hlen += (((struct ip6_hbh *)ulp)->ip6h_len + 1) << 3;
+ proto = ((struct ip6_hbh *)ulp)->ip6h_nxt;
+ ulp = NULL;
+ break;
+
+ case IPPROTO_AH: /* RFC 2402 */
+ PULLUP_TO(hlen, ulp, struct ip6_ext);
+ ext_hd |= EXT_AH;
+ hlen += (((struct ip6_ext *)ulp)->ip6e_len + 2) << 2;
+ proto = ((struct ip6_ext *)ulp)->ip6e_nxt;
+ ulp = NULL;
+ break;
+
+ case IPPROTO_ESP: /* RFC 2406 */
+ PULLUP_TO(hlen, ulp, uint32_t); /* SPI, Seq# */
+ /* Anything past Seq# is variable length and
+ * data past this ext. header is encrypted. */
+ ext_hd |= EXT_ESP;
+ break;
+
+ case IPPROTO_NONE: /* RFC 2460 */
+ /*
+ * Packet ends here, and IPv6 header has
+ * already been pulled up. If ip6e_len!=0
+ * then octets must be ignored.
+ */
+ ulp = ip; /* non-NULL to get out of loop. */
+ break;
+
+ case IPPROTO_OSPFIGP:
+ /* XXX OSPF header check? */
+ PULLUP_TO(hlen, ulp, struct ip6_ext);
+ break;
+
+ case IPPROTO_PIM:
+ /* XXX PIM header check? */
+ PULLUP_TO(hlen, ulp, struct pim);
+ break;
+
+ case IPPROTO_CARP:
+ PULLUP_TO(hlen, ulp, struct carp_header);
+ if (((struct carp_header *)ulp)->carp_version !=
+ CARP_VERSION)
+ return (IP_FW_DENY);
+ if (((struct carp_header *)ulp)->carp_type !=
+ CARP_ADVERTISEMENT)
+ return (IP_FW_DENY);
+ break;
+
+ case IPPROTO_IPV6: /* RFC 2893 */
+ PULLUP_TO(hlen, ulp, struct ip6_hdr);
+ break;
+
+ case IPPROTO_IPV4: /* RFC 2893 */
+ PULLUP_TO(hlen, ulp, struct ip);
+ break;
+
+ default:
+ if (V_fw_verbose)
+ printf("IPFW2: IPV6 - Unknown "
+ "Extension Header(%d), ext_hd=%x\n",
+ proto, ext_hd);
+ if (V_fw_deny_unknown_exthdrs)
+ return (IP_FW_DENY);
+ PULLUP_TO(hlen, ulp, struct ip6_ext);
+ break;
+ } /*switch */
+ }
+ ip = mtod(m, struct ip *);
+ ip6 = (struct ip6_hdr *)ip;
+ args->f_id.src_ip6 = ip6->ip6_src;
+ args->f_id.dst_ip6 = ip6->ip6_dst;
+ args->f_id.src_ip = 0;
+ args->f_id.dst_ip = 0;
+ args->f_id.flow_id6 = ntohl(ip6->ip6_flow);
+ } else if (pktlen >= sizeof(struct ip) &&
+ (args->eh == NULL || etype == ETHERTYPE_IP) && ip->ip_v == 4) {
+ is_ipv4 = 1;
+ hlen = ip->ip_hl << 2;
+ args->f_id.addr_type = 4;
+
+ /*
+ * Collect parameters into local variables for faster matching.
+ */
+ proto = ip->ip_p;
+ src_ip = ip->ip_src;
+ dst_ip = ip->ip_dst;
+ offset = ntohs(ip->ip_off) & IP_OFFMASK;
+ iplen = ntohs(ip->ip_len);
+ pktlen = iplen < pktlen ? iplen : pktlen;
+
+ if (offset == 0) {
+ switch (proto) {
+ case IPPROTO_TCP:
+ PULLUP_TO(hlen, ulp, struct tcphdr);
+ dst_port = TCP(ulp)->th_dport;
+ src_port = TCP(ulp)->th_sport;
+ /* save flags for dynamic rules */
+ args->f_id._flags = TCP(ulp)->th_flags;
+ break;
+
+ case IPPROTO_SCTP:
+ PULLUP_TO(hlen, ulp, struct sctphdr);
+ src_port = SCTP(ulp)->src_port;
+ dst_port = SCTP(ulp)->dest_port;
+ break;
+
+ case IPPROTO_UDP:
+ PULLUP_TO(hlen, ulp, struct udphdr);
+ dst_port = UDP(ulp)->uh_dport;
+ src_port = UDP(ulp)->uh_sport;
+ break;
+
+ case IPPROTO_ICMP:
+ PULLUP_TO(hlen, ulp, struct icmphdr);
+ //args->f_id.flags = ICMP(ulp)->icmp_type;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ args->f_id.src_ip = ntohl(src_ip.s_addr);
+ args->f_id.dst_ip = ntohl(dst_ip.s_addr);
+ }
+#undef PULLUP_TO
+ if (proto) { /* we may have port numbers, store them */
+ args->f_id.proto = proto;
+ args->f_id.src_port = src_port = ntohs(src_port);
+ args->f_id.dst_port = dst_port = ntohs(dst_port);
+ }
+
+ IPFW_PF_RLOCK(chain);
+ if (! V_ipfw_vnet_ready) { /* shutting down, leave NOW. */
+ IPFW_PF_RUNLOCK(chain);
+ return (IP_FW_PASS); /* accept */
+ }
+ if (args->rule.slot) {
+ /*
+ * Packet has already been tagged as a result of a previous
+ * match on rule args->rule aka args->rule_id (PIPE, QUEUE,
+ * REASS, NETGRAPH, DIVERT/TEE...)
+ * Validate the slot and continue from the next one
+ * if still present, otherwise do a lookup.
+ */
+ f_pos = (args->rule.chain_id == chain->id) ?
+ args->rule.slot :
+ ipfw_find_rule(chain, args->rule.rulenum,
+ args->rule.rule_id);
+ } else {
+ f_pos = 0;
+ }
+
+ /*
+ * Now scan the rules, and parse microinstructions for each rule.
+ * We have two nested loops and an inner switch. Sometimes we
+ * need to break out of one or both loops, or re-enter one of
+ * the loops with updated variables. Loop variables are:
+ *
+ * f_pos (outer loop) points to the current rule.
+ * On output it points to the matching rule.
+ * done (outer loop) is used as a flag to break the loop.
+ * l (inner loop) residual length of current rule.
+ * cmd points to the current microinstruction.
+ *
+ * We break the inner loop by setting l=0 and possibly
+ * cmdlen=0 if we don't want to advance cmd.
+ * We break the outer loop by setting done=1
+ * We can restart the inner loop by setting l>0 and f_pos, f, cmd
+ * as needed.
+ */
+ for (; f_pos < chain->n_rules; f_pos++) {
+ ipfw_insn *cmd;
+ uint32_t tablearg = 0;
+ int l, cmdlen, skip_or; /* skip rest of OR block */
+ struct ip_fw *f;
+
+ f = chain->map[f_pos];
+ if (V_set_disable & (1 << f->set) )
+ continue;
+
+ skip_or = 0;
+ for (l = f->cmd_len, cmd = f->cmd ; l > 0 ;
+ l -= cmdlen, cmd += cmdlen) {
+ int match;
+
+ /*
+ * check_body is a jump target used when we find a
+ * CHECK_STATE, and need to jump to the body of
+ * the target rule.
+ */
+
+/* check_body: */
+ cmdlen = F_LEN(cmd);
+ /*
+ * An OR block (insn_1 || .. || insn_n) has the
+ * F_OR bit set in all but the last instruction.
+ * The first match will set "skip_or", and cause
+ * the following instructions to be skipped until
+ * past the one with the F_OR bit clear.
+ */
+ if (skip_or) { /* skip this instruction */
+ if ((cmd->len & F_OR) == 0)
+ skip_or = 0; /* next one is good */
+ continue;
+ }
+ match = 0; /* set to 1 if we succeed */
+
+ switch (cmd->opcode) {
+ /*
+ * The first set of opcodes compares the packet's
+ * fields with some pattern, setting 'match' if a
+ * match is found. At the end of the loop there is
+ * logic to deal with F_NOT and F_OR flags associated
+ * with the opcode.
+ */
+ case O_NOP:
+ rule_nop(&match);
+ break;
+
+ case O_FORWARD_MAC:
+ rule_forward_mac(cmd->opcode);
+ break;
+
+ case O_GID:
+ case O_UID:
+ case O_JAIL:
+ rule_jail(&match, offset, proto, cmd, args, ucred_lookup, ucred_cache);
+ break;
+
+ case O_RECV:
+ rule_recv(&match, cmd, m, chain, &tablearg);
+ break;
+
+ case O_XMIT:
+ rule_xmit(&match, oif, cmd, chain, &tablearg);
+ break;
+
+ case O_VIA:
+ rule_via(&match, oif, m, cmd, chain, &tablearg);
+ break;
+
+ case O_MACADDR2:
+ rule_macaddr2(&match, args, cmd);
+ break;
+
+ case O_MAC_TYPE:
+ rule_mac_type(&match, args, cmd, cmdlen, etype);
+ break;
+
+ case O_FRAG:
+ rule_frag(&match, offset);
+ break;
+
+ case O_IN:
+ rule_in(&match, oif);
+ break;
+
+ case O_LAYER2:
+ rule_layer2(&match, args);
+ break;
+
+ case O_DIVERTED:
+ rule_diverted(&match, args, cmd);
+ break;
+
+ case O_PROTO:
+ rule_proto(&match, proto, cmd);
+ break;
+
+ case O_IP_SRC:
+ rule_ip_src(&match, is_ipv4, cmd, &src_ip);
+ break;
+
+ case O_IP_SRC_LOOKUP:
+ case O_IP_DST_LOOKUP:
+ rule_ip_dst_lookup(&match, cmd, cmdlen, args, &tablearg, is_ipv4, is_ipv6, ip, &dst_ip, &src_ip, dst_port, src_port, offset, proto, ucred_lookup, ucred_cache, chain);
+ break;
+
+ case O_IP_SRC_MASK:
+ case O_IP_DST_MASK:
+ rule_ip_dst_mask(&match, is_ipv4, cmd, cmdlen, &dst_ip, &src_ip);
+ break;
+
+ case O_IP_SRC_ME:
+ rule_ip_src_me(&match, is_ipv4, is_ipv6, &src_ip, args);
+#ifdef INET6
+ /* FALLTHROUGH */
+ case O_IP6_SRC_ME:
+ rule_ip6_src_me(&match, is_ipv6, args);
+#endif
+ break;
+
+ case O_IP_DST_SET:
+ case O_IP_SRC_SET:
+ rule_ip_src_set(&match, is_ipv4, cmd, args);
+ break;
+
+ case O_IP_DST:
+ rule_ip_dst(&match, is_ipv4, cmd, &dst_ip);
+ break;
+
+ case O_IP_DST_ME:
+ rule_ip_dst_me(&match, args, is_ipv4, is_ipv6, &dst_ip);
+
+#ifdef INET6
+ /* FALLTHROUGH */
+ case O_IP6_DST_ME:
+ rule_ip6_dst_me(&match, args, is_ipv6);
+#endif
+ break;
+
+
+ case O_IP_SRCPORT:
+ case O_IP_DSTPORT:
+ rule_ip_dstport(&match, proto, offset, cmd, cmdlen, dst_port, src_port);
+ break;
+
+ case O_ICMPTYPE:
+ rule_icmptype(&match, offset, proto, ulp, cmd);
+ break;
+
+#ifdef INET6
+ case O_ICMP6TYPE:
+ rule_icmp6type(&match, offset, is_ipv6, proto, ulp, cmd);
+ break;
+#endif /* INET6 */
+
+ case O_IPOPT:
+ rule_ipopt(&match, is_ipv4, ip, cmd);
+ break;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-soc-all
mailing list