[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1490742712.24891.25.camel@edumazet-glaptop3.roam.corp.google.com>
Date: Tue, 28 Mar 2017 16:11:52 -0700
From: Eric Dumazet <eric.dumazet@...il.com>
To: Cong Wang <xiyou.wangcong@...il.com>
Cc: Daurnimator <quae@...rnimator.com>,
Linux Kernel Network Developers <netdev@...r.kernel.org>,
William Ahern <william@...handclement.com>,
"Santi T." <santitm99@...il.com>,
Michael Kerrisk-manpages <mtk.manpages@...il.com>
Subject: Re: EINVAL when using connect() for udp sockets
On Mon, 2017-03-27 at 21:22 -0700, Cong Wang wrote:
> On Fri, Mar 24, 2017 at 4:19 PM, Eric Dumazet <eric.dumazet@...il.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.dumazet@...il.com> wrote:
> >> > On Thu, 2017-03-23 at 13:22 +1100, Daurnimator wrote:
> >> >> On 9 March 2017 at 14:10, Daurnimator <quae@...rnimator.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 !
Powered by blists - more mailing lists