pf: redirect a packet's port but not its address?

Andrey V. Elsukov bu7cher at yandex.ru
Tue Jan 23 23:27:11 UTC 2018


On 24.01.2018 00:01, Alan Somers wrote:
> Thanks.  It works now, at least for global addresses.  But the fwd rule
> does not work for link-local addresses.  When I try, the ACK packet gets
> dropped because it violates IPv6 scope rules.  A custom dtrace probe
> shows that ipfw is apparently not setting the embedded scope identifier
> on the forwarded packet.  The address should be
> "fe80:2:0:0:215:17ff:fee9:3079" but it's actually
> "fe80:0:0:0:215:17ff:fee9:3079".  This is similar to the problems I ran
> into with pf.  In fact, I never did get pf working with link-local
> addresses either.

I think it is correct behavior if you try to forward to loopback
address. In case when you listen on the LLA and fwd to this LLA there is
seems the bug.

# ipfw add fwd fe80::e6a7:a0ff:fe8e:16bf%lagg0,5678 tcp from any to any
dst-port 4000
# nc -6 -l fe80::e6a7:a0ff:fe8e:16bf%lagg0 5678

This doesn't work, because ip6_input() doesn't embed scope zone index
into IPv6 header's addresses before TCP segment will be handled by
tcp_input().

I think the bug is in ipfw_check_packet() function. Since it changes
destination address and sets M_FASTFWD_OURS flag, it also should embed
scope zone id into ip6_src/ip6_dst and check for scope violation like
ip6_input() does just after "passin" label.

With this patch I'm able to use above commands and they work.

--- a/sys/netpfil/ipfw/ip_fw_pfil.c
+++ b/sys/netpfil/ipfw/ip_fw_pfil.c
@@ -211,8 +211,20 @@ again:
                                ret = EACCES;
                                break;
                        }
-                       if (in6_localip(&sa6->sin6_addr))
+                       if (in6_localip(&sa6->sin6_addr)) {
+                               struct ip6_hdr *ip6 = mtod(*m0, struct
ip6_hdr *);
+
                                (*m0)->m_flags |= M_FASTFWD_OURS;
+       if (in6_clearscope(&ip6->ip6_src) ||
in6_clearscope(&ip6->ip6_dst)) {
+               ret = EACCES;
+               break;
+       }
+       if (in6_setscope(&ip6->ip6_src, (*m0)->m_pkthdr.rcvif, NULL) ||
+           in6_setscope(&ip6->ip6_dst, (*m0)->m_pkthdr.rcvif, NULL)) {
+               ret = EACCES;
+               break;
+       }
+                       }
                        (*m0)->m_flags |= M_IP6_NEXTHOP;
                }
 #endif

-- 
WBR, Andrey V. Elsukov

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 553 bytes
Desc: OpenPGP digital signature
URL: <http://lists.freebsd.org/pipermail/freebsd-net/attachments/20180124/3cfe4acc/attachment.sig>


More information about the freebsd-net mailing list