Hi,

debugging my setup at home I realized that NAT-T on IPv6 is broken.
I know that NAT in IPv6 sucks, but apparently my dsl modem does not
reliably forward ESP packets, so I use NAT-T instead... *sigh*

Moving that setup from IPv4 to IPv6 I noticed that pf was blocking
outgoing packets and its src/dst addresses were broken.  Digging
in the code I saw that the UDP header injection is written only
for IPv4.

This diff was written for and tested on OpenBSD 5.8, then ported
to -current.  The only difference in the tested diff and this
diff is that m_makespace() was replaced by m_inject().

Patrick

diff --git sys/netinet/ipsec_output.c sys/netinet/ipsec_output.c
index 91c319f..372d8d4 100644
--- sys/netinet/ipsec_output.c
+++ sys/netinet/ipsec_output.c
@@ -375,13 +375,30 @@ ipsp_process_done(struct mbuf *m, struct tdb *tdb)
        if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0) {
                struct mbuf *mi;
                struct udphdr *uh;
+               int iphlen;
 
                if (!udpencap_enable || !udpencap_port) {
                        m_freem(m);
                        return ENXIO;
                }
-               mi = m_inject(m, sizeof(struct ip), sizeof(struct udphdr),
-                   M_DONTWAIT);
+
+               switch (tdb->tdb_dst.sa.sa_family) {
+               case AF_INET:
+                       iphlen = sizeof(struct ip);
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       iphlen = sizeof(struct ip6_hdr);
+                       break;
+#endif /* INET6 */
+               default:
+                       m_freem(m);
+                       DPRINTF(("ipsp_process_done(): unknown protocol family 
(%d)\n",
+                           tdb->tdb_dst.sa.sa_family));
+                       return ENXIO;
+               }
+
+               mi = m_inject(m, iphlen, sizeof(struct udphdr), M_DONTWAIT);
                if (mi == NULL) {
                        m_freem(m);
                        return ENOMEM;
@@ -391,8 +408,11 @@ ipsp_process_done(struct mbuf *m, struct tdb *tdb)
                if (tdb->tdb_udpencap_port)
                        uh->uh_dport = tdb->tdb_udpencap_port;
 
-               uh->uh_ulen = htons(m->m_pkthdr.len - sizeof(struct ip));
+               uh->uh_ulen = htons(m->m_pkthdr.len - iphlen);
                uh->uh_sum = 0;
+               if (tdb->tdb_dst.sa.sa_family == AF_INET6)
+                       uh->uh_sum = in6_cksum(m, IPPROTO_UDP,
+                           iphlen, m->m_pkthdr.len - iphlen);
                espstat.esps_udpencout++;
        }
 

Reply via email to