Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 15 Jun 2014 18:12:52 GMT
From:      dpl@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r269594 - soc2014/dpl/netmap-ipfw/sys/netpfil/ipfw
Message-ID:  <201406151812.s5FICq59053275@socsvn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dpl
Date: Sun Jun 15 18:12:52 2014
New Revision: 269594
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=269594

Log:
  Renamed ip_rules, and changed include line at ip_fw2.c
  

Added:
  soc2014/dpl/netmap-ipfw/sys/netpfil/ipfw/ip_fw_rules.h
Deleted:
  soc2014/dpl/netmap-ipfw/sys/netpfil/ipfw/ip_rules.h
Modified:
  soc2014/dpl/netmap-ipfw/sys/netpfil/ipfw/ip_fw2.c

Modified: soc2014/dpl/netmap-ipfw/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- soc2014/dpl/netmap-ipfw/sys/netpfil/ipfw/ip_fw2.c	Sun Jun 15 17:14:52 2014	(r269593)
+++ soc2014/dpl/netmap-ipfw/sys/netpfil/ipfw/ip_fw2.c	Sun Jun 15 18:12:52 2014	(r269594)
@@ -38,7 +38,7 @@
 #endif /* INET */
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
-#include "ip_rules.h"
+#include "ip_fw_rules.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>

Added: soc2014/dpl/netmap-ipfw/sys/netpfil/ipfw/ip_fw_rules.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2014/dpl/netmap-ipfw/sys/netpfil/ipfw/ip_fw_rules.h	Sun Jun 15 18:12:52 2014	(r269594)
@@ -0,0 +1,1242 @@
+/*
+ * Actions executed per-rule.
+ * We'll have to include some of the included files at ip_fw2.c
+ */
+
+inline void
+rule_nop(int *match)
+{
+	*match = 1;
+}
+
+inline void
+rule_forward_mac(int opcode)
+{
+	printf("ipfw: opcode %d unimplemented\n",
+		opcode);
+
+}
+
+inline void
+rule_jail(u_short offset, uint8_t proto, ipfw_insn ipfw_insn_u32 *cmd, struct ip_fw_args *args, int ucred_lookup, void *ucred_cache)
+{
+	/*
+	 * We only check offset == 0 && proto != 0,
+	 * as this ensures that we have a
+	 * packet with the ports info.
+	 */
+	if (offset != 0)
+		return;
+	if (proto == IPPROTO_TCP ||
+		proto == IPPROTO_UDP)
+		*match = check_uidgid(
+				(ipfw_insn_u32 *)cmd,
+				args, &ucred_lookup,
+#ifdef __FreeBSD__
+				&(struct bsd_ucred *)ucred_cache);
+#else
+				(void *)&(struct ucred *)ucred_cache);
+#endif
+}
+
+inline void
+rule_recv(int *match, ipfw_insn *cmd, struct mbuf *m, struct ip_fw_chain *chain, uint32_t *tablearg)
+{
+	*match = iface_match(m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd, chain, tablearg);
+}
+
+inline void
+rule_xmit(int *match, struct ifnet *oif, ipfw_insn *cmd, struct ip_fw_chain *chain, uint32_t *tablearg)
+{
+	*match = iface_match(oif, (ipfw_insn_if *)cmd, chain, tablearg);
+}
+
+inline void
+rule_via(int *match, struct ifnet *oif, struct mbuf *m, ipfw_insn *cmd, struct ip_fw_chain *chain, uint32_t *tablearg)
+{
+	*match = iface_match(oif ? oif : m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd, chain, tablearg);
+}
+
+inline void
+rule_macaddr2(int *match, struct ip_fw_args *args, ipfw_insn *cmd)
+{
+	if (args->eh != NULL) {	/* have MAC header */
+		u_int32_t *want = (u_int32_t *)
+			((ipfw_insn_mac *)cmd)->addr;
+		u_int32_t *mask = (u_int32_t *)
+			((ipfw_insn_mac *)cmd)->mask;
+		u_int32_t *hdr = (u_int32_t *)args->eh;
+
+		*match =
+		    ( want[0] == (hdr[0] & mask[0]) &&
+		      want[1] == (hdr[1] & mask[1]) &&
+		      want[2] == (hdr[2] & mask[2]) );
+	}
+
+}
+
+inline void
+rule_mac_type(int *match, struct ip_fw_args *args, ipfw_insn *cmd, int cmdlen, uint16_t etype);
+{
+	if (args->eh != NULL) {
+		u_int16_t *p =
+		    ((ipfw_insn_u16 *)cmd)->ports;
+		int i;
+
+		for (i = cmdlen - 1; !match && i>0;
+		    i--, p += 2)
+			*match = (etype >= p[0] &&
+			    etype <= p[1]);
+	}
+
+}
+
+inline void
+rule_frag(int *match, u_short offset)
+{
+	*match = (offset != 0);
+}
+
+inline void
+rule_in(int *match, struct ifnet *oif)
+{
+	/* "out" is "not in" */
+	*match = (oif == NULL);
+}
+
+inline void
+rule_layer2(int *match, struct ip_fw_args * args)
+{
+	*match = (args->eh != NULL);
+}
+
+inline void
+rule_diverted(int *match, struct ip_fw_args * args)
+{
+	/* For diverted packets, args->rule.info
+	 * contains the divert port (in host format)
+	 * reason and direction.
+	 */
+	uint32_t i = args->rule.info;
+	*match = (i&IPFW_IS_MASK) == IPFW_IS_DIVERT &&
+	    cmd->arg1 & ((i & IPFW_INFO_IN) ? 1 : 2);
+}
+
+inline void
+rule_proto(int *match, uint8_t proto, ipfs_insn *cmd)
+{
+	/*
+	 * We do not allow an arg of 0 so the
+	 * check of "proto" only suffices.
+	 */
+	*match = (proto == cmd->arg1);
+}
+
+inline void
+rule_ip_src(int *match, int is_ipv4, ipfs_insn *cmd, struct in_addr *src_ip)
+{
+	*match = is_ipv4 &&
+	    (((ipfw_insn_ip *)cmd)->addr.s_addr ==
+	    src_ip->s_addr);
+}
+
+
+inline void
+rule_2_lookup(int *match, ipfw_insn *cmd, int cmdlen, int is_ipv4, int is_ipv6, struct ip *ip, struct in_addr *dst_ip, struct in_addr *src_ip, uint16_t dst_port, uint16_t src_port, u_short offset, uint8_t proto, int ucred_lookup, void *ucred_cache, struct ip_fw_chain *chain)
+{
+	if (is_ipv4) {
+	    uint32_t key =
+		(cmd->opcode == O_IP_DST_LOOKUP) ?
+		    dst_ip.s_addr : src_ip.s_addr;
+	    uint32_t v = 0;
+
+	    if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
+		/* generic lookup. The key must be
+		 * in 32bit big-endian format.
+		 */
+		v = ((ipfw_insn_u32 *)cmd)->d[1];
+		if (v == 0)
+		    key = dst_ip.s_addr;
+		else if (v == 1)
+		    key = src_ip.s_addr;
+		else if (v == 6) /* dscp */
+		    key = (ip->ip_tos >> 2) & 0x3f;
+		else if (offset != 0)
+		    return;
+		else if (proto != IPPROTO_TCP &&
+			proto != IPPROTO_UDP)
+		    return;
+		else if (v == 2)
+		    key = htonl(dst_port);
+		else if (v == 3)
+		    key = htonl(src_port);
+#ifndef USERSPACE
+		else if (v == 4 || v == 5) {
+		    check_uidgid(
+			(ipfw_insn_u32 *)cmd,
+			args, &ucred_lookup,
+#ifdef __FreeBSD__
+			(struct bsd_ucred *)ucred_cache);
+		    if (v == 4 /* O_UID */)
+			key = ucred_cache->cr_uid;
+		    else if (v == 5 /* O_JAIL */)
+			key = ucred_cache->cr_prison->pr_id;
+#else /* !__FreeBSD__ */
+			ucred_cache);
+		    if (v ==4 /* O_UID */)
+			key = ucred_cache.uid;
+		    else if (v == 5 /* O_JAIL */)
+			key = ucred_cache.xid;
+#endif /* !__FreeBSD__ */
+		    key = htonl(key);
+		} else
+#endif /* !USERSPACE */
+		    return;
+	    }
+	    *match = ipfw_lookup_table(chain,
+		cmd->arg1, key, &v);
+	    if (!(*match))
+			return;
+	    if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
+		*match =
+		    ((ipfw_insn_u32 *)cmd)->d[0] == v;
+	    else
+		tablearg = v;
+	} else if (is_ipv6) {
+		uint32_t v = 0;
+		void *pkey = (cmd->opcode == O_IP_DST_LOOKUP) ?
+			&args->f_id.dst_ip6: &args->f_id.src_ip6;
+		*match = ipfw_lookup_table_extended(chain,
+				cmd->arg1, pkey, &v,
+				IPFW_TABLE_CIDR);
+		if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
+			*match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
+		if (*match)
+			tablearg = v;
+	}
+}
+
+
+inline void
+rule_ip_dst_mask(int *match, int is_ipv4, ipfw_insn *cmd, int cmdlen, struct in_addr *dst_ip, struct in_addr *src_ip)
+{
+	if (is_ipv4) {
+	    uint32_t a =
+		(cmd->opcode == O_IP_DST_MASK) ?
+		    dst_ip.s_addr : src_ip.s_addr;
+	    uint32_t *p = ((ipfw_insn_u32 *)cmd)->d;
+	    int i = cmdlen-1;
+
+	    for (; !match && i>0; i-= 2, p+= 2)
+		*match = (p[0] == (a & p[1]));
+	}
+}
+
+inline void
+rule_ip_src_me(int *match, struct in_addr *src_ip, struct ip_fw_args *args)
+{
+	if (is_ipv4) {
+		struct ifnet *tif;
+
+		INADDR_TO_IFP(src_ip, tif);
+		*match = (tif != NULL);
+		return;
+	}
+	/* The next behavior has been also added to the next action */
+	*match= is_ipv6 && search_ip6_addr_net(&args->f_id.src_ip6);
+}
+
+inline void
+rule_ip6_src_me(int *match, int is_ipv6, struct ip_fw_args *args)
+{
+	*match= is_ipv6 && search_ip6_addr_net(&args->f_id.src_ip6);
+}
+
+inline void
+rule_ip_src_set(int *match, int is_ipv4, ipfw_insn *cmd, struct ip_fw_args *args)
+{
+	if (is_ipv4) {
+		u_int32_t *d = (u_int32_t *)(cmd+1);
+		u_int32_t addr =
+		    cmd->opcode == O_IP_DST_SET ?
+			args->f_id.dst_ip :
+			args->f_id.src_ip;
+
+		    if (addr < d[0])
+			    return;
+		    addr -= d[0]; /* subtract base */
+		    *match = (addr < cmd->arg1) &&
+			( d[ 1 + (addr>>5)] &
+			  (1<<(addr & 0x1f)) );
+	}
+}
+
+inline void
+rule_ip_dst(int *match, int is_ipv4, ipfw_insn *cmd, struct in_addr *dst_ip)
+{
+	*match = is_ipv4 &&
+	    (((ipfw_insn_ip *)cmd)->addr.s_addr ==
+	    dst_ip->s_addr);
+}
+
+inline void
+rule_ip_dst_me(int *match, is_ipv4, is_ipv6, struct in_addr *dst_ip, dst_ip6)
+{
+	if (is_ipv4) {
+		struct ifnet *tif;
+
+		INADDR_TO_IFP(dst_ip, tif);
+		*match = (tif != NULL);
+		return;
+	}
+	*match= is_ipv6 && search_ip6_addr_net(&args->f_id.dst_ip6);
+}
+
+inline void
+rule_ip6_dst_me(int *match, struct ip_fw_args *args)
+{
+	*match= is_ipv6 && search_ip6_addr_net(&args->f_id.dst_ip6);
+}
+
+inline void
+rule_ip_dstport(int *match, uint8_t proto, u_short offset, ipfw_insn *cmd, int cmdlen)
+{
+	/*
+	 * offset == 0 && proto != 0 is enough
+	 * to guarantee that we have a
+	 * packet with port info.
+	 */
+	if ((proto==IPPROTO_UDP || proto==IPPROTO_TCP)
+	    && offset == 0) {
+		u_int16_t x =
+		    (cmd->opcode == O_IP_SRCPORT) ?
+			src_port : dst_port ;
+		u_int16_t *p =
+		    ((ipfw_insn_u16 *)cmd)->ports;
+		int i;
+
+		for (i = cmdlen - 1; !match && i>0;
+		    i--, p += 2)
+			*match = (x>=p[0] && x<=p[1]);
+	}
+}
+
+inline void
+rule_icmptype(int *match, u_short offset, uint8_t proto, void *ulp, ipfw_insn *cmd )
+{
+	*match = (offset == 0 && proto==IPPROTO_ICMP &&
+	    icmptype_match(ICMP(ulp), (ipfw_insn_u32 *)cmd) );
+}
+
+inline void
+rule_icmp6type(int *match, u_short offset, uint8_t proto, void *void *ulp, ipfw_insn *cmd)
+{
+	*match = is_ipv6 && offset == 0 &&
+	    proto==IPPROTO_ICMPV6 &&
+	    icmp6type_match(
+		ICMP6(void *ulp)->icmp6_type,
+		(ipfw_insn_u32 *)cmd);
+}
+
+
+inline void
+rule_ipopt(int *match, int is_ipv4, struct ip *ip, ipfw_insn *cmd)
+{
+	*match = (is_ipv4 &&
+    	ipopts_match(ip, cmd) );
+
+}
+
+inline void
+rule_ipver(int *match, int is_ipv4, ipfw_insn *cmd, struct ip *ip)
+{
+	match = (is_ipv4 &&
+		cmd->arg1 == ip->ip_v);
+}
+
+inline void
+rule_ipttl(int *match, int is_ipv4 ipfw_insn *cmd, int cmdlen, struct ip *ip, uint16_t iplen)
+{
+	if (is_ipv4) {	/* only for IP packets */
+	    uint16_t x;
+	    uint16_t *p;
+	    int i;
+
+	    if (cmd->opcode == O_IPLEN)
+			x = iplen;
+	    else if (cmd->opcode == O_IPTTL)
+			x = ip->ip_ttl;
+	    else /* must be IPID */
+			x = ntohs(ip->ip_id);
+	    if (cmdlen == 1) {
+			*match = (cmd->arg1 == x);
+			return;
+	    }
+	    /* otherwise we have ranges */
+	    p = ((ipfw_insn_u16 *)cmd)->ports;
+	    i = cmdlen - 1;
+	    for (; !match && i>0; i--, p += 2)
+			*match = (x >= p[0] && x <= p[1]);
+	}
+}
+
+inline void
+rule_ipprecedence(int *match, int is_ipv4, ipfw_insn *cmd, struct ip *ip)
+{
+	*match = (is_ipv4 &&
+	    (cmd->arg1 == (ip->ip_tos & 0xe0)) );
+}
+
+inline void
+rule_iptos(int *match, int is_ipv4 ipfw_insn *cmd, struct ip *ip)
+{
+	*match = (is_ipv4 &&
+	    flags_match(cmd, ip->ip_tos));
+}
+
+inline void
+rule_dscp(int *match, int is_ipv4, int is_ipv6, ipfw_insn *cmd, struct ip *ip)
+{
+	uint32_t *p;
+	uint16_t x;
+
+	p = ((ipfw_insn_u32 *)cmd)->d;
+
+	if (is_ipv4)
+		x = ip->ip_tos >> 2;
+	else if (is_ipv6) {
+		uint8_t *v;
+		v = &((struct ip6_hdr *)ip)->ip6_vfc;
+		x = (*v & 0x0F) << 2;
+		v++;
+		x |= *v >> 6;
+	} else
+		return;
+
+	/* DSCP bitmask is stored as low_u32 high_u32 */
+	if (x > 32)
+		*match = *(p + 1) & (1 << (x - 32));
+	else
+		*match = *p & (1 << x);
+}
+
+inline void
+rule_tcpdatalen(int *match, uint8_t proto, u_short offset, void *ulp, uint16_t iplen int cmdlen, ipfw_insn *cmd)
+{
+	if (proto == IPPROTO_TCP && offset == 0) {
+	    struct tcphdr *tcp;
+	    uint16_t x;
+	    uint16_t *p;
+	    int i;
+
+	    tcp = TCP(ulp);
+	    x = iplen -
+		    ((ip->ip_hl + tcp->th_off) << 2);
+	    if (cmdlen == 1) {
+			match = (cmd->arg1 == x);
+			return;
+	    }
+	    /* otherwise we have ranges */
+	    p = ((ipfw_insn_u16 *)cmd)->ports;
+	    i = cmdlen - 1;
+	    for (; !match && i>0; i--, p += 2)
+			*match = (x >= p[0] && x <= p[1]);
+	}
+}
+
+inline void
+rule_tcpflags(int *match, uint8_t proto, u_short offset, ipfw_insn *cmd, void *ulp)
+{
+	*match = (proto == IPPROTO_TCP && offset == 0 &&
+	    flags_match(cmd, TCP(ulp)->th_flags));
+}
+
+inline void
+rule_tcpopts(int *match, u_int hlen, void *ulp, uint8_t proto, u_short offset, ipfw_insn *cmd);
+{
+	PULLUP_LEN(hlen, ulp, (TCP(ulp)->th_off << 2));
+	*match = (proto == IPPROTO_TCP && offset == 0 &&
+	    tcpopts_match(TCP(ulp), cmd));
+}
+
+inline void
+rule_tcpseq(int *match, uint8_t proto, u_short offset, ipfw_insn *cmd, void *ulp)
+{
+	match = (proto == IPPROTO_TCP && offset == 0 &&
+	    ((ipfw_insn_u32 *)cmd)->d[0] ==
+		TCP(ulp)->th_seq);
+}
+
+inline void
+rule_tcpack(int *match, uint8_t proto, u_short offset, ipfw_insn *cmd, void *ulp)
+{
+	*match = (proto == IPPROTO_TCP && offset == 0 &&
+	    ((ipfw_insn_u32 *)cmd)->d[0] ==
+		TCP(void *ulp)->th_ack);
+}
+
+inline void
+rule_tcpwin(int *match, uint8_t proto, u_short offset, ipfw_insn *cmd, void *ulp)
+{
+	if (proto == IPPROTO_TCP && offset == 0) {
+	    uint16_t x;
+	    uint16_t *p;
+	    int i;
+
+	    x = ntohs(TCP(ulp)->th_win);
+	    if (cmdlen == 1) {
+			*match = (cmd->arg1 == x);
+			return;
+	    }
+	    /* Otherwise we have ranges. */
+	    p = ((ipfw_insn_u16 *)cmd)->ports;
+	    i = cmdlen - 1;
+	    for (; !(*match) && i > 0; i--, p += 2)
+		*match = (x >= p[0] && x <= p[1]);
+	}
+}
+
+inline void
+rule_estab(int *match, uint8_t proto, u_short offset, void *ulp)
+{
+	/* reject packets which have SYN only */
+	/* XXX should i also check for TH_ACK ? */
+	*match = (proto == IPPROTO_TCP && offset == 0 &&
+	    (TCP(ulp)->th_flags &
+	     (TH_RST | TH_ACK | TH_SYN)) != TH_SYN);
+}
+
+inline void
+rule_altq(int *match, ipfw_insn *cmd, struct mbuf *m)
+{
+	struct pf_mtag *at;
+	struct m_tag *mtag;
+	ipfw_insn_altq *altq = (ipfw_insn_altq *)cmd;
+
+	/*
+	 * ALTQ uses mbuf tags from another
+	 * packet filtering system - pf(4).
+	 * We allocate a tag in its format
+	 * and fill it in, pretending to be pf(4).
+	 */
+	*match = 1;
+	at = pf_find_mtag(m);
+	if (at != NULL && at->qid != 0)
+		return;
+	mtag = m_tag_get(PACKET_TAG_PF,
+		sizeof(struct pf_mtag), M_NOWAIT | M_ZERO);
+	if (mtag == NULL) {
+		/*
+		 * Let the packet fall back to the
+		 * default ALTQ.
+		 */
+		return;
+	}
+	m_tag_prepend(m, mtag);
+	at = (struct pf_mtag *)(mtag + 1);
+	at->qid = altq->qid;
+	at->hdr = ip;
+}
+
+inline void
+rule_log(int *match, struct ip_fw *f, u_int hlen, struct ip_fw_args *args, struct mbuf *m, struct ifnet *oif, u_short offset, u_short ip6f_mf, uint32_t tablearg, struct ip *ip)
+{
+	ipfw_log(f, hlen, args, m,
+		oif, offset | ip6f_mf, tablearg, ip);
+	*match = 1;
+}
+
+inline void
+rule_prob(int *match, ipfw_insn *cmd)
+{
+	*match = (random()<((ipfw_insn_u32 *)cmd)->d[0]);
+	return;
+}
+
+inline void
+rule_verrevpath(int *match, struct ifnet *oif, struct mbuf *m, int is_ipv6, struct ip_fw_args *args, struct in_addr *src_ip)
+{
+	/* Outgoing packets automatically pass/match */
+	*match = ((oif != NULL) ||
+	    (m->m_pkthdr.rcvif == NULL) ||
+	    (
+#ifdef INET6
+	    is_ipv6 ?
+		verify_path6(&(args->f_id.src_ip6),
+		    m->m_pkthdr.rcvif, args->f_id.fib) :
+#endif
+	    verify_path(src_ip, m->m_pkthdr.rcvif,
+	        args->f_id.fib)));
+}
+
+inline void
+rule_versrcreach(int *match, u_int hlen, int is_ipv6 struct ip_fw_args *args, struct in_addr *src_ip)
+{
+	/* Outgoing packets automatically pass/match */
+	match = (hlen > 0 && ((oif != NULL) ||
+#ifdef INET6
+	    is_ipv6 ?
+	        verify_path6(&(args->f_id.src_ip6),
+	            NULL, args->f_id.fib) :
+#endif
+	    verify_path(src_ip, NULL, args->f_id.fib)));
+}
+
+inline void
+rule_antispoof(int *match, struct ifnet *oif, u_int hlen, int is_ipv4, int is_ipv6, struct in_addr *src_ip, struct ip_fw_args *args, struct mbuf *m)
+{
+	/* Outgoing packets automatically pass/match */
+	if (oif == NULL && hlen > 0 &&
+	    (  (is_ipv4 && in_localaddr(src_ip))
+#ifdef INET6
+	    || (is_ipv6 &&
+	        in6_localaddr(&(args->f_id.src_ip6)))
+#endif
+	    ))
+		*match =
+#ifdef INET6
+		    is_ipv6 ? verify_path6(
+		        &(args->f_id.src_ip6),
+		        m->m_pkthdr.rcvif,
+			args->f_id.fib) :
+#endif
+		    verify_path(src_ip,
+		    	m->m_pkthdr.rcvif,
+		        args->f_id.fib);
+	else
+		*match = 1;
+}
+
+#ifdef IPSEC
+inline void
+rule_ipsec(int *match, m)
+{
+	*match = (m_tag_find(m,
+	    PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL);
+}
+#endif
+
+#ifdef INET6
+inline void
+rule_ip6_src(int *match, int is_ipv6, struct ip_fw_args *args, ipfw_insn *cmd)
+{
+	*match = is_ipv6 &&
+	    IN6_ARE_ADDR_EQUAL(&args->f_id.src_ip6,
+	    &((ipfw_insn_ip6 *)cmd)->addr6);
+}
+
+inline void
+rule_ip6_dst(int *match, int is_ipv6, struct ip_fw_args *args, ipfw_insn *cmd)
+{
+	*match = is_ipv6 &&
+	IN6_ARE_ADDR_EQUAL(&args->f_id.dst_ip6,
+	    &((ipfw_insn_ip6 *)cmd)->addr6);
+}
+
+inline void
+rule_ip6_dst_mask(int *match, struct ip_fw_args *args, ipfw_insn *cmd, int cmdlen, int is_ipv6)
+{
+	if (is_ipv6) {
+		int i = cmdlen - 1;
+		struct in6_addr p;
+		struct in6_addr *d =
+		    &((ipfw_insn_ip6 *)cmd)->addr6;
+
+		for (; !(*match) && i > 0; d += 2,
+		    i -= F_INSN_SIZE(struct in6_addr)
+		    * 2) {
+			p = (cmd->opcode ==
+			    O_IP6_SRC_MASK) ?
+			    args->f_id.src_ip6:
+			    args->f_id.dst_ip6;
+			APPLY_MASK(&p, &d[1]);
+			*match =
+			    IN6_ARE_ADDR_EQUAL(&d[0],
+			    &p);
+		}
+	}
+}
+
+inline void
+rule_flow6id(int *match, struct ip_fw_args *args, ipfw_insn *cmd)
+{
+	*match = is_ipv6 &&
+	    flow6id_match(args->f_id.flow_id6,
+	    (ipfw_insn_u32 *) cmd);
+}
+
+inline void
+rule_ext_hdr(int *match, int is_ipv6, uint16_t ext_hd, ipfw_insn *cmd)
+{
+	*match = is_ipv6 &&
+	    (ext_hd & ((ipfw_insn *) cmd)->arg1);
+}
+
+inline void
+rule_ip6(int *match, int is_ipv6)
+{
+	*match = is_ipv6;
+}
+#endif
+
+inline void
+rule_ip4(int *match, int is_ipv4)
+{
+	*match = is_ipv4;
+}
+
+inline void
+rule_tag(int *match, ipfw_insn *cmd, struct mbuf *m)
+{
+	struct m_tag *mtag;
+	uint32_t tag = IP_FW_ARG_TABLEARG(cmd->arg1);
+
+	/* Packet is already tagged with this tag? */
+	mtag = m_tag_locate(m, MTAG_IPFW, tag, NULL);
+
+	/* We have `untag' action when F_NOT flag is
+	 * present. And we must remove this mtag from
+	 * mbuf and reset `match' to zero (`match' will
+	 * be inversed later).
+	 * Otherwise we should allocate new mtag and
+	 * push it into mbuf.
+	 */
+	if (cmd->len & F_NOT) { /* `untag' action */
+		if (mtag != NULL)
+			m_tag_delete(m, mtag);
+		*match = 0;
+	} else {
+		if (mtag == NULL) {
+			mtag = m_tag_alloc( MTAG_IPFW,
+			    tag, 0, M_NOWAIT);
+			if (mtag != NULL)
+				m_tag_prepend(m, mtag);
+		}
+		*match = 1;
+	}
+}
+
+inline void
+rule_fib(int *match, struct ip_fw_args *args, ipfw_insn *cmd)
+{
+	if (args->f_id.fib == cmd->arg1)
+		*match = 1;
+}
+
+inline void
+rule_sockarg(int *match, int is_ipv6 uint8_t proto, struct ip_fw_args *args, struct in_addr *dst_ip, struct in_addr *src_ip, uint16_t dst_port, uint16_t src_port, uint32_t *tablearg)
+{
+#ifndef USERSPACE	/* not supported in userspace */
+	struct inpcb *inp = args->inp;
+	struct inpcbinfo *pi;
+	
+	if (is_ipv6) /* XXX can we remove this ? */
+		return;
+
+	if (proto == IPPROTO_TCP)
+		pi = &V_tcbinfo;
+	else if (proto == IPPROTO_UDP)
+		pi = &V_udbinfo;
+	else
+		return;
+
+	/*
+	 * XXXRW: so_user_cookie should almost
+	 * certainly be inp_user_cookie?
+	 */
+
+	/* For incomming packet, lookup up the 
+	inpcb using the src/dest ip/port tuple */
+	if (inp == NULL) {
+		inp = in_pcblookup(pi, 
+			src_ip, htons(src_port),
+			dst_ip, htons(dst_port),
+			INPLOOKUP_RLOCKPCB, NULL);
+		if (inp != NULL) {
+			tablearg =
+			    inp->inp_socket->so_user_cookie;
+			if (tablearg)
+				*match = 1;
+			INP_RUNLOCK(inp);
+		}
+	} else {
+		if (inp->inp_socket) {
+			tablearg =
+			    inp->inp_socket->so_user_cookie;
+			if (tablearg)
+				*match = 1;
+		}
+	}
+#endif /* !USERSPACE */
+}
+
+inline void
+rule_tagged(int *match, ipfw_insn *cmd, int cmdlen, struct mbuf *m)
+{
+	struct m_tag *mtag;
+	uint32_t tag = IP_FW_ARG_TABLEARG(cmd->arg1);
+
+	if (cmdlen == 1) {
+		*match = m_tag_locate(m, MTAG_IPFW,
+		    tag, NULL) != NULL;
+		return;
+	}
+
+	/* we have ranges */
+	for (mtag = m_tag_first(m);
+	    mtag != NULL && !(*match);
+	    mtag = m_tag_next(m, mtag)) {
+		uint16_t *p;
+		int i;
+
+		if (mtag->m_tag_cookie != MTAG_IPFW)
+			continue;
+
+		p = ((ipfw_insn_u16 *)cmd)->ports;
+		i = cmdlen - 1;
+		for(; !(*match) && i > 0; i--, p += 2)
+			*match =
+			    mtag->m_tag_id >= p[0] &&
+			    mtag->m_tag_id <= p[1];
+	}
+}
+
+/*
+ * The second sets of opcodes. They represent the actions of a rule.
+ */
+inline void
+rule_keep_state(int *match, struct ip_fw *f, ipfw_insn *cmd, struct ip_fw_args *args, uint32_t *tablearg, int *retval, int *l, int *done)
+{
+	if (ipfw_install_state(f,
+	    (ipfw_insn_limit *)cmd, args, tablearg)) {
+		/* error or limit violation */
+		*retval = IP_FW_DENY;
+		*l = 0;	/* exit inner loop */
+		*done = 1; /* exit outer loop */
+	}
+	*match = 1;
+}
+
+inline void
+rule_check_state(int *match, int *dyn_dir, ipfw_dyn_rule *q, struct ip_fw_args *args, uint8_t proto, void *ulp, int pktlen, struct ip_fw *f, int *f_pos, struct ip_fw_chain *chain, ipfw_insn *cmd, int *cmdlen, int *l)
+{
+	/*
+	 * dynamic rules are checked at the first
+	 * keep-state or check-state occurrence,
+	 * with the result being stored in dyn_dir.
+	 * The compiler introduces a PROBE_STATE
+	 * instruction for us when we have a
+	 * KEEP_STATE (because PROBE_STATE needs
+	 * to be run first).
+	 */
+	if (*dyn_dir == MATCH_UNKNOWN &&
+	    (q = ipfw_lookup_dyn_rule(&args->f_id,
+	     dyn_dir, proto == IPPROTO_TCP ?
+		TCP(ulp) : NULL))
+		!= NULL) {
+		/*
+		 * Found dynamic entry, update stats
+		 * and jump to the 'action' part of
+		 * the parent rule by setting
+		 * f, cmd, l and clearing cmdlen.
+		 */
+		IPFW_INC_DYN_COUNTER(q, pktlen);
+		/* XXX we would like to have f_pos
+		 * readily accessible in the dynamic
+	         * rule, instead of having to
+		 * lookup q->rule.
+		 */
+		f = q->rule;
+		*f_pos = ipfw_find_rule(chain,
+			f->rulenum, f->id);
+		cmd = ACTION_PTR(f);
+		*l = f->cmd_len - f->act_ofs;
+		ipfw_dyn_unlock(q);
+		*cmdlen = 0;
+		*match = 1;
+		return;
+	}
+	/*
+	 * Dynamic entry not found. If CHECK_STATE,
+	 * skip to next rule, if PROBE_STATE just
+	 * ignore and continue with next opcode.
+	 */
+	if (cmd->opcode == O_CHECK_STATE)
+		*l = 0;	/* exit inner loop */
+	*match = 1;
+}
+
+inline void
+rule_accept(int *retval, int *l, int *done)
+{
+	*retval = 0;	/* accept */
+	*l = 0;		/* exit inner loop */
+	*done = 1;	/* exit outer loop */
+}
+
+inline void
+rule_queue(struct ip_fw_args *args, int f_pos, struct ip_fw_chain *chain, ipfw_insn *cmd, int *retval, int *l, int *done)
+{
+	set_match(args, f_pos, chain);
+	args->rule.info = IP_FW_ARG_TABLEARG(cmd->arg1);
+	if (cmd->opcode == O_PIPE)
+		args->rule.info |= IPFW_IS_PIPE;
+	if (V_fw_one_pass)
+		args->rule.info |= IPFW_ONEPASS;
+	*retval = IP_FW_DUMMYNET;
+	*l = 0;          /* exit inner loop */
+	*done = 1;       /* exit outer loop */
+}
+
+inline void
+rule_tee(int *l, int *done, int *retval, ipfw_insn *cmd, struct ip_fw_args *args, int f_pos, struct ip_fw_chain *chain)
+{
+	if (args->eh) /* not on layer 2 */
+	    return;
+	/* otherwise this is terminal */
+	*l = 0;		/* exit inner loop */
+	*done = 1;	/* exit outer loop */
+	*retval = (cmd->opcode == O_DIVERT) ?
+		IP_FW_DIVERT : IP_FW_TEE;
+	set_match(args, f_pos, chain);
+	args->rule.info = IP_FW_ARG_TABLEARG(cmd->arg1);
+}
+
+inline void
+rule_count(int *l, struct ip_fw *f, int pktlen)
+{
+	IPFW_INC_RULE_COUNTER(f, pktlen);
+	*l = 0;		/* exit inner loop */
+}
+
+inline void
+rule_skipto(int *match, int *l, ipfw_insn *cmd, int *cmdlen, int *skip_or, int *f_pos, struct ip_fw *f, int pktlen, struct ip_fw_chain *chain, ipfw_insn *cmd, uint32_t tablearg)
+{
+    IPFW_INC_RULE_COUNTER(f, pktlen);
+    *f_pos = jump_fast(chain, f, cmd->arg1, tablearg, 0);
+    /*
+     * Skip disabled rules, and re-enter
+     * the inner loop with the correct
+     * f_pos, f, l and cmd.
+     * Also clear cmdlen and skip_or
+     */
+    for (; (*f_pos) < chain->n_rules - 1 &&
+	    (V_set_disable &
+	     (1 << chain->map[(*f_pos)]->set));
+	    (*f_pos)++)
+	;
+    /* Re-enter the inner loop at the skipto rule. */
+    f = chain->map[(*f_pos)];
+    *l = f->cmd_len;
+    cmd = f->cmd;
+    *match = 1;
+    *cmdlen = 0;
+    *skip_or = 0;
+}
+
+inline void
+rule_callreturn(ipfw_insn *cmd, struct mbuf *m, struct ip_fw *f, struct ip_fw_chain *chain, uint32_t tablearg, int pktlen, int *skip_or, int *cmdlen, int *f_pos, int *l)
+{
+	/*
+	 * Implementation of `subroutine' call/return,
+	 * in the stack carried in an mbuf tag. This
+	 * is different from `skipto' in that any call
+	 * address is possible (`skipto' must prevent
+	 * backward jumps to avoid endless loops).
+	 * We have `return' action when F_NOT flag is
+	 * present. The `m_tag_id' field is used as
+	 * stack pointer.
+	 */
+	struct m_tag *mtag;
+	uint16_t jmpto, *stack;
+
+#define	IS_CALL		((cmd->len & F_NOT) == 0)
+#define	IS_RETURN	((cmd->len & F_NOT) != 0)
+	/*
+	 * Hand-rolled version of m_tag_locate() with
+	 * wildcard `type'.
+	 * If not already tagged, allocate new tag.
+	 */
+	mtag = m_tag_first(m);
+	while (mtag != NULL) {
+		if (mtag->m_tag_cookie ==
+		    MTAG_IPFW_CALL)
+			break;
+		mtag = m_tag_next(m, mtag);
+	}
+	if (mtag == NULL && IS_CALL) {
+		mtag = m_tag_alloc(MTAG_IPFW_CALL, 0,
+		    IPFW_CALLSTACK_SIZE *
+		    sizeof(uint16_t), M_NOWAIT);
+		if (mtag != NULL)
+			m_tag_prepend(m, mtag);
+	}
+
+	/*
+	 * On error both `call' and `return' just
+	 * continue with next rule.
+	 */
+	if (IS_RETURN && (mtag == NULL ||
+	    mtag->m_tag_id == 0)) {
+		l = 0;		/* exit inner loop */
+		break;
+	}
+	if (IS_CALL && (mtag == NULL ||
+	    mtag->m_tag_id >= IPFW_CALLSTACK_SIZE)) {
+		printf("ipfw: call stack error, "

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201406151812.s5FICq59053275>