From: Denis Fondras Subject: Re: IPv4 route with IPv6 gateway To: "Nitsche, Elia" Cc: Denis Fondras , "tech@openbsd.org" Date: Tue, 21 Jul 2026 17:08:31 +0200 Le Tue, Jul 21, 2026 at 02:13:50PM +0000, Nitsche, Elia a écrit : > Hi, > > I started implementing this too, but I am using a route flag (currently set by > > sbin/route). Your approach might be cleaner though. > > > Also my diff, does not set the correct ipv4 address in icmp message send from > > router nodes without an ivp4 address. I dont see any code for this in your diff > > either. > > (currently sends as 0.0.0.0, should be 192.0.0.8; see RFC draft-ietf-intarea-v4-via) > > > elia > Thank you for your diff. Adding a flag is a good idea :) > > Index: route.c > =================================================================== > RCS file: /cvs/src/sbin/route/route.c,v > diff -u -p -u -r1.267 route.c > --- route.c 9 May 2024 08:35:40 -0000 1.267 > +++ route.c 21 Jul 2026 14:05:13 -0000 > @@ -790,6 +790,11 @@ newroute(int argc, char **argv) > flags |= RTF_HOST; > if (iflag == 0) > flags |= RTF_GATEWAY; > + if (so_dst.sin.sin_family == AF_INET && so_gate.sin6.sin6_family == AF_INET6) { > + flags |= RTF_6NHOB; > + fmask |= RTF_6NHOB; > + } > for (attempts = 1; ; attempts++) { > errno = 0; > if ((ret = rtmsg(*cmd, flags, fmask, prio)) == 0) > > Index: net/if.c > =================================================================== > RCS file: /cvs/src/sys/net/if.c,v > diff -u -p -u -r1.763 if.c > --- net/if.c 22 Mar 2026 23:14:00 -0000 1.763 > +++ net/if.c 21 Jul 2026 13:13:55 -0000 > @@ -935,7 +935,10 @@ if_output_tso(struct ifnet *ifp, struct > break; > #ifdef INET6 > case AF_INET6: > - ifcap = IFCAP_TSOv6; > + if (rt == NULL || !(rt->rt_flags & RTF_6NHOP)) > + ifcap = IFCAP_TSOv6; > + else > + ifcap = IFCAP_TSOv4; > break; > #endif > default: > @@ -960,7 +963,13 @@ if_output_tso(struct ifnet *ifp, struct > break; > #ifdef INET6 > case AF_INET6: > - in6_proto_cksum_out(*mp, ifp); > + if (rt == NULL || !(rt->rt_flags & RTF_6NHOP)) { > + in6_proto_cksum_out(*mp, ifp); > + } else { > + in_hdr_cksum_out(*mp, ifp); > + in_proto_cksum_out(*mp, ifp); > + } > break; > #endif > } > Index: net/if_ethersubr.c > =================================================================== > RCS file: /cvs/src/sys/net/if_ethersubr.c,v > diff -u -p -u -r1.308 if_ethersubr.c > --- net/if_ethersubr.c 19 Dec 2025 02:04:13 -0000 1.308 > +++ net/if_ethersubr.c 21 Jul 2026 13:13:55 -0000 > @@ -265,7 +265,11 @@ ether_resolve(struct ifnet *ifp, struct > error = nd6_resolve(ifp, rt, m, dst, eh->ether_dhost); > if (error) > return (error); > - eh->ether_type = htons(ETHERTYPE_IPV6); > + if (rt == NULL || !(rt->rt_flags & RTF_6NHOP)) { > + eh->ether_type = htons(ETHERTYPE_IPV6); > + } else { > + eh->ether_type = htons(ETHERTYPE_IP); > + } > break; > #endif > #ifdef MPLS > Index: net/route.h > =================================================================== > RCS file: /cvs/src/sys/net/route.h,v > diff -u -p -u -r1.218 route.h > --- net/route.h 14 Jul 2025 08:48:51 -0000 1.218 > +++ net/route.h 21 Jul 2026 13:13:55 -0000 > @@ -167,11 +167,12 @@ struct rtentry { > #define RTF_BROADCAST 0x400000 /* route associated to a bcast addr. */ > #define RTF_CONNECTED 0x800000 /* interface route */ > #define RTF_BFD 0x1000000 /* Link state controlled by BFD */ > +#define RTF_6NHOP 0x2000000 /* v4 route with v6 next hop */ > > /* mask of RTF flags that are allowed to be modified by RTM_CHANGE */ > #define RTF_FMASK \ > (RTF_LLINFO | RTF_PROTO1 | RTF_PROTO2 | RTF_PROTO3 | RTF_BLACKHOLE | \ > - RTF_REJECT | RTF_STATIC | RTF_MPLS | RTF_BFD) > + RTF_REJECT | RTF_STATIC | RTF_MPLS | RTF_BFD | RTF_6NHOP) > > /* Routing priorities used by the different routing protocols */ > #define RTP_NONE 0 /* unset priority use sane default */ > > > ________________________________ > From: owner-tech@openbsd.org on behalf of Denis Fondras > Sent: Monday, July 20, 2026 5:39:24 PM > To: tech@openbsd.org > Subject: IPv4 route with IPv6 gateway > > Hello, > > Inspired by https://labs.ripe.net/author/remco-van-mook/a-farewell-to-arps-ipv4-service-on-ipv6-only-networks/ I decided to check how OpenBSD behaves when an IPv4 route uses an IPv6 gateway. > > With the help of a small diff below, I can : > > ``` > $ doas ifconfig iwm0 192.168.21.234/32 up > $ doas ifconfig iwm0 inet6 eui64 > $ doas route add default fe80::764d:28ff:fe83:fbdc%iwm0 > $ route -n get default > route to: 0.0.0.0 > destination: 0.0.0.0 > mask: 0.0.0.0 > gateway: fe80::764d:28ff:fe83:fbdc%iwm0 > interface: iwm0 > if address: 192.168.21.234 > priority: 12 () > flags: > use mtu expire > 665 0 0 > $ ping 8.8.8.8 > PING 8.8.8.8 (8.8.8.8): 56 data bytes > 64 bytes from 8.8.8.8: icmp_seq=0 ttl=116 time=12.392 ms > 64 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=11.987 ms > ^C > --- 8.8.8.8 ping statistics --- > 2 packets transmitted, 2 packets received, 0.0% packet loss > round-trip min/avg/max/std-dev = 11.987/12.190/12.392/0.202 ms > $ arp -an > Host Ethernet Address Netif Expire Flags > 192.168.21.234 fe:e1:ba:d0:c9:9b iwm0 permanent l > $ ndp -an > Neighbor Linklayer Address Netif Expire S Flags > fe80::764d:28ff:fe83:fbdc%iwm0 74:4d:28:83:fb:dc iwm0 23h59m6s S R > fe80::fce1:baff:fed0:c99b%iwm0 fe:e1:ba:d0:c9:9b iwm0 permanent R l > ``` > > Index: net/if.c > =================================================================== > RCS file: /cvs/src/sys/net/if.c,v > diff -u -p -r1.763 if.c > --- net/if.c 22 Mar 2026 23:14:00 -0000 1.763 > +++ net/if.c 20 Jul 2026 15:28:03 -0000 > @@ -928,8 +928,12 @@ if_output_tso(struct ifnet *ifp, struct > { > uint32_t ifcap; > int error; > + int af = dst->sa_family; > > - switch (dst->sa_family) { > + if (*mp != NULL) > + af = (*mp)->m_pkthdr.ph_family; > + > + switch (af) { > case AF_INET: > ifcap = IFCAP_TSOv4; > break; > @@ -939,7 +943,7 @@ if_output_tso(struct ifnet *ifp, struct > break; > #endif > default: > - unhandled_af(dst->sa_family); > + unhandled_af(af); > } > > /* > @@ -953,7 +957,7 @@ if_output_tso(struct ifnet *ifp, struct > return error; > > if ((*mp)->m_pkthdr.len <= mtu) { > - switch (dst->sa_family) { > + switch (af) { > case AF_INET: > in_hdr_cksum_out(*mp, ifp); > in_proto_cksum_out(*mp, ifp); > Index: net/if_ethersubr.c > =================================================================== > RCS file: /cvs/src/sys/net/if_ethersubr.c,v > diff -u -p -r1.308 if_ethersubr.c > --- net/if_ethersubr.c 19 Dec 2025 02:04:13 -0000 1.308 > +++ net/if_ethersubr.c 20 Jul 2026 15:28:03 -0000 > @@ -265,7 +265,10 @@ ether_resolve(struct ifnet *ifp, struct > error = nd6_resolve(ifp, rt, m, dst, eh->ether_dhost); > if (error) > return (error); > - eh->ether_type = htons(ETHERTYPE_IPV6); > + if (rt != NULL && rt->rt_dest->sa_family == AF_INET) > + eh->ether_type = htons(ETHERTYPE_IP); > + else > + eh->ether_type = htons(ETHERTYPE_IPV6); > break; > #endif > #ifdef MPLS > Index: netinet/ip_output.c > =================================================================== > RCS file: /cvs/src/sys/netinet/ip_output.c,v > diff -u -p -r1.417 ip_output.c > --- netinet/ip_output.c 6 May 2026 11:36:13 -0000 1.417 > +++ netinet/ip_output.c 20 Jul 2026 15:28:03 -0000 > @@ -434,6 +434,7 @@ reroute: > /* > * If TSO or small enough for interface, can just send directly. > */ > + m->m_pkthdr.ph_family = AF_INET; > error = if_output_tso(ifp, &m, sintosa(dst), ro->ro_rt, mtu); > if (error || m == NULL) > goto done; > Index: netinet6/ip6_forward.c > =================================================================== > RCS file: /cvs/src/sys/netinet6/ip6_forward.c,v > diff -u -p -r1.130 ip6_forward.c > --- netinet6/ip6_forward.c 23 Jun 2026 15:45:00 -0000 1.130 > +++ netinet6/ip6_forward.c 20 Jul 2026 15:28:03 -0000 > @@ -323,6 +323,7 @@ reroute: > } > #endif > > + m->m_pkthdr.ph_family = AF_INET6; > error = if_output_tso(ifp, &m, dst, rt, ifp->if_mtu); > if (error) > ip6stat_inc(ip6s_cantforward); > Index: netinet6/ip6_output.c > =================================================================== > RCS file: /cvs/src/sys/netinet6/ip6_output.c,v > diff -u -p -r1.306 ip6_output.c > --- netinet6/ip6_output.c 25 Jun 2026 13:16:44 -0000 1.306 > +++ netinet6/ip6_output.c 20 Jul 2026 15:28:03 -0000 > @@ -661,6 +661,7 @@ reroute: > * transmit packet without fragmentation > */ > if (dontfrag || tlen <= mtu) { /* case 1-a and 2-a */ > + m->m_pkthdr.ph_family = AF_INET6; > error = if_output_tso(ifp, &m, sin6tosa(dst), ro->ro_rt, > ifp->if_mtu); > if (error || m == NULL)