On Mon, 2017-03-27 at 21:22 -0700, Cong Wang wrote: > On Fri, Mar 24, 2017 at 4:19 PM, Eric Dumazet <eric.duma...@gmail.com> wrote: > > On Fri, 2017-03-24 at 15:34 -0700, Cong Wang wrote: > >> (Cc'ing Michael Kerrisk) > >> > >> On Wed, Mar 22, 2017 at 10:18 PM, Eric Dumazet <eric.duma...@gmail.com> > >> wrote: > >> > On Thu, 2017-03-23 at 13:22 +1100, Daurnimator wrote: > >> >> On 9 March 2017 at 14:10, Daurnimator <q...@daurnimator.com> wrote: > >> >> > When debugging https://github.com/daurnimator/lua-http/issues/73 which > >> >> > uses https://github.com/wahern/dns we ran into an issue where modern > >> >> > linux kernels return EINVAL if you try and re-use a udp socket. > >> >> > The issue seems to occur if you go from a local destination ip to a > >> >> > non-local one. > >> >> > >> >> Did anyone get a chance to look into this issue? > >> > > >> > I believe man page is not complete. > >> > > >> > A disconnect is needed before another connect() > >> > >> Is it? Making connect() reentrant is reasonable for connection-less > >> protocol like UDP, but I don't dig POSIX for the details. If so we need > >> something like below... > >> > >> --- a/net/ipv4/datagram.c > >> +++ b/net/ipv4/datagram.c > >> @@ -40,7 +40,7 @@ int __ip4_datagram_connect(struct sock *sk, struct > >> sockaddr *uaddr, int addr_len > >> sk_dst_reset(sk); > >> > >> oif = sk->sk_bound_dev_if; > >> - saddr = inet->inet_saddr; > >> + saddr = inet->inet_saddr = 0; > >> if (ipv4_is_multicast(usin->sin_addr.s_addr)) { > >> if (!oif) > >> oif = inet->mc_index; > > > > Wont this break bind() ? > > > > Right. We need to distinguish bind() and connect(), something > like below? > > --- a/net/ipv4/datagram.c > +++ b/net/ipv4/datagram.c > @@ -26,7 +26,7 @@ int __ip4_datagram_connect(struct sock *sk, struct > sockaddr *uaddr, int addr_len > struct sockaddr_in *usin = (struct sockaddr_in *) uaddr; > struct flowi4 *fl4; > struct rtable *rt; > - __be32 saddr; > + __be32 saddr = 0; > int oif; > int err; > > @@ -40,7 +40,8 @@ int __ip4_datagram_connect(struct sock *sk, struct > sockaddr *uaddr, int addr_len > sk_dst_reset(sk); > > oif = sk->sk_bound_dev_if; > - saddr = inet->inet_saddr; > + if (sk->sk_userlocks & SOCK_BINDADDR_LOCK) > + saddr = inet->inet_saddr; > if (ipv4_is_multicast(usin->sin_addr.s_addr)) { > if (!oif) > oif = inet->mc_index;
Yes, this looks better. Although you probably need to change a bit later this part : if (!inet->inet_saddr) inet->inet_saddr = fl4->saddr; /* Update source address */ Should we also fix IPv6 or is this bug only about IPv4 ? Thanks !