On Fri, Mar 24, 2017 at 4:19 PM, Eric Dumazet <[email protected]> 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 <[email protected]>
>> wrote:
>> > On Thu, 2017-03-23 at 13:22 +1100, Daurnimator wrote:
>> >> On 9 March 2017 at 14:10, Daurnimator <[email protected]> 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;