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>