diff options
author | Luiz Otavio O Souza <luiz@netgate.com> | 2016-10-26 18:37:14 -0500 |
---|---|---|
committer | Luiz Souza <luiz@netgate.com> | 2017-07-17 15:18:29 -0500 |
commit | 143eb5e93fc882f6bfe7be8d04839c70d76bdb69 (patch) | |
tree | a5c57574f4eabca41e4dea0929af63de4fdd2bdf | |
parent | 86337e914d8efd35e892fc09af473bc8bd0418cf (diff) | |
download | FreeBSD-src-143eb5e93fc882f6bfe7be8d04839c70d76bdb69.zip FreeBSD-src-143eb5e93fc882f6bfe7be8d04839c70d76bdb69.tar.gz |
Add l2 support to ipfw fwd.
(cherry picked from commit e384dd50b923cdb01b401f4ab943cec5d61fbd7d)
-rw-r--r-- | sys/net/if_ethersubr.c | 7 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw2.c | 4 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_pfil.c | 139 |
3 files changed, 79 insertions, 71 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index e2e65b3..bb79eec 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -775,6 +775,7 @@ ether_demux(struct ifnet *ifp, struct mbuf *m) { struct ether_header *eh; int i, isr; + uint32_t ours; u_short ether_type; KASSERT(ifp != NULL, ("%s: NULL interface pointer", __func__)); @@ -785,7 +786,9 @@ ether_demux(struct ifnet *ifp, struct mbuf *m) if (i != 0 || m == NULL) return; - } + ours = m->m_flags & (M_FASTFWD_OURS | M_IP_NEXTHOP); + } else + ours = 0; eh = mtod(m, struct ether_header *); ether_type = ntohs(eh->ether_type); @@ -824,6 +827,8 @@ ether_demux(struct ifnet *ifp, struct mbuf *m) */ m->m_flags &= ~M_VLANTAG; m_clrprotoflags(m); + if (ours) + m->m_flags |= ours; m_adj(m, ETHER_HDR_LEN); /* diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index 70bc664..1d37643 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -2472,8 +2472,6 @@ do { \ break; case O_FORWARD_IP: - if (args->eh) /* not valid on layer2 pkts */ - break; if (q == NULL || q->rule != f || dyn_dir == MATCH_FORWARD) { struct sockaddr_in *sa; @@ -2530,8 +2528,6 @@ do { \ #ifdef INET6 case O_FORWARD_IP6: - if (args->eh) /* not valid on layer2 pkts */ - break; if (q == NULL || q->rule != f || dyn_dir == MATCH_FORWARD) { struct sockaddr_in6 *sin6; diff --git a/sys/netpfil/ipfw/ip_fw_pfil.c b/sys/netpfil/ipfw/ip_fw_pfil.c index efdc1f5..f014dfb 100644 --- a/sys/netpfil/ipfw/ip_fw_pfil.c +++ b/sys/netpfil/ipfw/ip_fw_pfil.c @@ -113,6 +113,74 @@ SYSEND #endif /* SYSCTL_NODE */ +static int +ipfw_check_next_hop(struct ip_fw_args *args, int dir, struct mbuf *m) +{ + struct m_tag *fwd_tag; + size_t len; + +#if (!defined(INET6) && !defined(INET)) + return (EACCES); +#else + + KASSERT(args->next_hop == NULL || args->next_hop6 == NULL, + ("%s: both next_hop=%p and next_hop6=%p not NULL", __func__, + args->next_hop, args->next_hop6)); +#ifdef INET6 + if (args->next_hop6 != NULL) + len = sizeof(struct sockaddr_in6); +#endif +#ifdef INET + if (args->next_hop != NULL) + len = sizeof(struct sockaddr_in); +#endif + + /* Incoming packets should not be tagged so we do not + * m_tag_find. Outgoing packets may be tagged, so we + * reuse the tag if present. + */ + fwd_tag = (dir == DIR_IN) ? NULL : + m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + m_tag_unlink(m, fwd_tag); + } else { + fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, len, + M_NOWAIT); + if (fwd_tag == NULL) + return (EACCES); + } +#ifdef INET6 + if (args->next_hop6 != NULL) { + struct sockaddr_in6 *sa6; + + sa6 = (struct sockaddr_in6 *)(fwd_tag + 1); + bcopy(args->next_hop6, sa6, len); + /* + * If nh6 address is link-local we should convert + * it to kernel internal form before doing any + * comparisons. + */ + if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) + return (EACCES); + if (in6_localip(&sa6->sin6_addr)) + m->m_flags |= M_FASTFWD_OURS; + m->m_flags |= M_IP6_NEXTHOP; + } +#endif +#ifdef INET + if (args->next_hop != NULL) { + bcopy(args->next_hop, (fwd_tag+1), len); + if (in_localip(args->next_hop->sin_addr)) + m->m_flags |= M_FASTFWD_OURS; + m->m_flags |= M_IP_NEXTHOP; + } +#endif + m_tag_prepend(m, fwd_tag); +#endif /* INET || INET6 */ + + return (IP_FW_PASS); +} + /* * The pfilter hook to pass packets to ipfw_chk and then to * dummynet, divert, netgraph or other modules. @@ -161,72 +229,7 @@ again: /* next_hop may be set by ipfw_chk */ if (args.next_hop == NULL && args.next_hop6 == NULL) break; /* pass */ -#if (!defined(INET6) && !defined(INET)) - ret = EACCES; -#else - { - struct m_tag *fwd_tag; - size_t len; - - KASSERT(args.next_hop == NULL || args.next_hop6 == NULL, - ("%s: both next_hop=%p and next_hop6=%p not NULL", __func__, - args.next_hop, args.next_hop6)); -#ifdef INET6 - if (args.next_hop6 != NULL) - len = sizeof(struct sockaddr_in6); -#endif -#ifdef INET - if (args.next_hop != NULL) - len = sizeof(struct sockaddr_in); -#endif - - /* Incoming packets should not be tagged so we do not - * m_tag_find. Outgoing packets may be tagged, so we - * reuse the tag if present. - */ - fwd_tag = (dir == DIR_IN) ? NULL : - m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL); - if (fwd_tag != NULL) { - m_tag_unlink(*m0, fwd_tag); - } else { - fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, len, - M_NOWAIT); - if (fwd_tag == NULL) { - ret = EACCES; - break; /* i.e. drop */ - } - } -#ifdef INET6 - if (args.next_hop6 != NULL) { - struct sockaddr_in6 *sa6; - - sa6 = (struct sockaddr_in6 *)(fwd_tag + 1); - bcopy(args.next_hop6, sa6, len); - /* - * If nh6 address is link-local we should convert - * it to kernel internal form before doing any - * comparisons. - */ - if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) { - ret = EACCES; - break; - } - if (in6_localip(&sa6->sin6_addr)) - (*m0)->m_flags |= M_FASTFWD_OURS; - (*m0)->m_flags |= M_IP6_NEXTHOP; - } -#endif -#ifdef INET - if (args.next_hop != NULL) { - bcopy(args.next_hop, (fwd_tag+1), len); - if (in_localip(args.next_hop->sin_addr)) - (*m0)->m_flags |= M_FASTFWD_OURS; - (*m0)->m_flags |= M_IP_NEXTHOP; - } -#endif - m_tag_prepend(*m0, fwd_tag); - } -#endif /* INET || INET6 */ + ret = ipfw_check_next_hop(&args, dir, *m0); break; case IP_FW_DENY: @@ -368,6 +371,10 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, /* Check result of ipfw_chk() */ switch (i) { case IP_FW_PASS: + /* next_hop may be set by ipfw_chk */ + if (args.next_hop == NULL && args.next_hop6 == NULL) + break; /* pass */ + ret = ipfw_check_next_hop(&args, dir, *m0); break; case IP_FW_DENY: |