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