Hi all, I've hacked that source code myself months ago, and it works well on my use case (I have 4 dual stack pppoe wan set on my openwrt router, and seted a wireguard sever on it), my hack will pickup the dst_addr from incoming handshake packet in kernel sk_buff, and then use that addr as src_addr to reply. I'm not good at source code, and I know that my hack may be ugly, but it works, hope this patch can help: https://github.com/openwrt/packages/issues/9538#issuecomment-1150592803
Daniel Gröber <[email protected]> 于2023年2月20日周一 06:42写道: > > Hi, > > I though it might be useful to do some quick and dirty code review instead > of speculating wildly to figure out where these source IP selection > problems could be coming from ;) > > From previous code deep dives I know the udp_tunnel_xmit_skb function is > where tunnel packets get handed off to the kernel. So in > net/wireguard/socket.c:send4 we have: > > udp_tunnel_xmit_skb(rt, sock, skb, fl.saddr, fl.daddr, ds, > ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport, > fl.fl4_dport, false, false); > > Where fl.saddr is the source address that's supposedly wrong (sometimes? I > guess?) Where does that come from? > > Let's look at the code (heavily culled): > > struct flowi4 fl = { > .saddr = endpoint->src4.s_addr, > }; > if (cache) > rt = dst_cache_get_ip4(cache, &fl.saddr); > if (!rt) { > if (unlikely(!inet_confirm_addr(sock_net(sock), NULL, 0, > fl.saddr, RT_SCOPE_HOST))) > fl.saddr = 0; > if (unlikely(endpoint->src_if4 && ((IS_ERR(rt) && > PTR_ERR(rt) == -EINVAL) || (!IS_ERR(rt) && > rt->dst.dev->ifindex != endpoint->src_if4)))) > fl.saddr = 0; > > Well it's initialized from endpoint->src4.s_addr, overwritten with zero in > some cases, which I believe lets the kernel do it's regular source addr > selection, and populated from something called dst_cache at some callsites. > > @Nico could it perhaps simply be that you're hitting one of these zero'ing > cases and that's why it's using regular kernel src addr selection instead > of the cached endpoint src4 address? > > The first case !inet_confirm_addr(..., RT_SCOPE_HOST) ought to confirm that > the saddr is actually still a local address. Makes sens if the address we > remembered was removed from the interface we can't use it anymore. > > The second case looks like it's checking if the (sometimes cached) src_if4 > interface index is still what the route we're about to use points to. > > If neither of those seem likely we can keep reading :) > > --Daniel > > >
