Date: Thu, 17 Jul 2014 09:48:34 GMT From: dpl@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r271013 - in soc2014/dpl/netmap-ipfwjit: . sys/netpfil/ipfw Message-ID: <201407170948.s6H9mYes009387@socsvn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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: -@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: -@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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201407170948.s6H9mYes009387>