strange behavior when the client bind its UDP socket to a local address

Discussion in 'Linux Networking' started by Christophe Lohr, Jan 16, 2009.

  1. Hi,
    I do a simple test with netcat and tshark.

    Server part:
    $ nc -u -l -p 5555

    Client part:
    $ nc -u -s 192.168.75.62 localhost 5555

    Sniffing lo:
    # tshark -i lo
    192.168.75.62 -> 127.0.0.1 UDP Source port: 39293 Destination
    port: 5555
    192.168.75.62 -> 192.168.75.62 UDP Source port: 5555 Destination
    port: 39293
    192.168.75.62 -> 192.168.75.62 ICMP Destination unreachable (Port
    unreachable)


    So, why is the second packet from 192.168.75.62 to 192.168.75.62 ???
    (and not from 127.0.0.1 to 192.168.75.62)
    I do not see this strange behavior in TCP.

    Regards,
    Christophe.
     
    Christophe Lohr, Jan 16, 2009
    #1
    1. Advertisements

  2. Because 192.168.75.62 is "closer" to 192.168.75.62 than 127.0.0.1 is.
    Normally, the networking stack will try to pick the closest source
    interface address it can.
    Why would it deliberately pick a worse address?
    Because in TCP there's only one connection, and you force it to use
    the worse address, so it has no choice.

    DS
     
    David Schwartz, Jan 16, 2009
    #2
    1. Advertisements

  3. David Schwartz a écrit :
    Fine, thank you!

    Christophe
     
    Christophe Lohr, Jan 19, 2009
    #3
  4. Hello,

    David Schwartz a écrit :
    Probably because the server used the default source address selected by
    the stack instead of using the destination address in the received packet.
    From my observations of the behaviour of the Linux IPv4 stack, I did
    not see any evidence that the default source adresse selection is based
    on "closeness" to the destination address. AFAICS, the default source
    address selection works as follows :

    - If the destination is local (on the host), then use the same address
    as source. This is what is happening here.
    - If the route covering the destination specifies an explicit source
    address, use that source address. This is usually what happens for
    directly attached subnets.
    - Otherwise, use the primary address of the output interface specified
    in the route covering the destination, if it exists.
    - Otherwise, when the output interface has no address, use the primary
    address of the first non-loopback interface.
    Because the client sent a datagram to 127.0.0.1 and expects datagrams
    from the same address, not 192.168.75.62.

    Although UDP is connectionless, it is rather common that bidirectional
    UDP communications use source and destination adresses in the same way
    as TCP does. At least it is common enough so that this is what the UDP
    connection tracking in netfilter expects.

    Now a last comment. As a client, when nc sends a UDP datagram to address
    A it expects to receive datagrams from the same address A. However as a
    server, when nc receives a UDP datagram on address A it may send
    datagrams from a different address. This looks like a bug to me.
     
    Pascal Hambourg, Jan 20, 2009
    #4
  5. David Schwartz a écrit :
    I am not conviced: the third message is an ICMP Error...
    Replying from the contacted address would really be a worse idea?

    Christophe
     
    Christophe Lohr, Jan 21, 2009
    #5
  6. Pascal Hambourg a écrit :
    You mean a bug in Linux?
     
    Christophe Lohr, Jan 21, 2009
    #6
  7. No platform I know of "remembers" that a UDP datagram was received
    with a particular destination address and uses that as the source
    address for subsequent datagrams. In fact, that's a crazy thing to do.
    Sure, that's why many *applications* do this. But this question is
    about an application that doesn't.
    Yes, a bug in whoever invoked the server. If the person invoking the
    server knows the client requires UDP datagrams to have a particular
    source address, they must inform 'nc' of this, by using the '-s'
    option.

    DS
     
    David Schwartz, Jan 21, 2009
    #7
  8. No, a bug in the person who invoked the 'nc' server without telling it
    what source address to use in a context where the client cares what
    source address is used. See my other post.

    DS
     
    David Schwartz, Jan 21, 2009
    #8
  9. Christophe Lohr a écrit :
    No, in nc.
     
    Pascal Hambourg, Jan 21, 2009
    #9
  10. David Schwartz a écrit :
    If by "platform" you mean "OS", I didn't mean that.
    Not only because of stateful filtering, but also because IMO it just
    makes sense to do so, so that the client can identify the reply more easily.
    Yup, and I claim that this application, namely nc, is broken.
    By doing so you limit the nc server to accept communications only on one
    address instead of any local address.
     
    Pascal Hambourg, Jan 21, 2009
    #10
  11. I think you're right, but I would argue that the problem is on the
    other side. There is no reason 'nc' should reject an otherwise valid
    received datagram just because the source address isn't what 'nc'
    thinks is right. The application has no way to test the equivalence of
    the endpoints and shouldn't assume they aren't equivalent.

    DS
     
    David Schwartz, Jan 22, 2009
    #11
  12. David Schwartz a écrit :
    nc does not reject datagrams, the UDP layer does because there is no
    matching UDP socket. Here is what netstat prints when the nc client is
    invoked with the following command line :

    $ nc -u -s 127.7.8.9 localhost 5555

    Active Internet connections (w/o servers)
    Proto Recv-Q Send-Q Local Address Foreign Address State
    udp 0 0 127.7.8.9:1105 127.0.0.1:5555 ESTABLISHED

    So the socket will accept datagrams only from 127.0.0.1. Maybe the nc
    client could/should set the foreign address to 0.0.0.0 and put the
    destination address in each individual datagram it sends ?

    But there's more about the nc server. Let's see what happens.
    I start a nc server in UDP mode with the following command line :

    $ nc -u -l -p 5555

    Proto Recv-Q Send-Q Local Address Foreign Address State
    udp 0 0 0.0.0.0:5555 0.0.0.0:*

    So far so good. Now I send a datagram from the client nc, and see what
    has become of the nc server socket :

    Proto Recv-Q Send-Q Local Address Foreign Address State
    udp 0 0 127.7.8.9:5555 127.7.8.9:1105 ESTABLISHED

    The nc server socket has the local addresse 127.7.8.9 instead of
    127.0.0.1 to which the datagram was sent. What does this mean ? First,
    as we have already seen, the nc server will send datagrams to the client
    with the source address 127.7.8.9 instead of 127.0.0.1. If the client
    socket accepted them as you said, that would be no problem.

    Second, and worse, the nc server socket will now only accept subsequent
    incoming datagrams sent to 127.7.8.9 instead of the original destination
    address 127.0.0.1. Isn't this REALLY broken ? Shouldn't the local
    address of the nc server socket instead be left to 0.0.0.0 or be set to
    the destination address of the first received datagram ?
     
    Pascal Hambourg, Jan 22, 2009
    #12
  13. Ack! Why did 'nc' call 'connect'?! You are right, 'nc' is broken.
    Absolutely. It *must* do that unless it knows for a fact that it will
    only talk to servers that guarantee to send replies with a source
    address that matches the received destination address.
    You are correct. The 'nc' program is badly broken.

    You cannot assume that the source address of datagrams you receive
    will match the destination you sent those datagrams to unless you are
    implementing a protocol that specifically requires this. Since 'nc' is
    not, calling 'connect' is broken.

    DS
     
    David Schwartz, Jan 22, 2009
    #13
  14. David Schwartz a écrit :
    I can just guess. Maybe nc/netcat was primarily designed as a TCP tool
    (the "TCP/IP swiss army knife", says its manpage), and the UDP mode uses
    the same system calls despite the fundamental differences between TCP
    and UDP.
     
    Pascal Hambourg, Jan 22, 2009
    #14
  15. Pascal Hambourg a écrit :
    Ok.. So, may I suggest to replace 'nc' by 'socat'?

    Client:
    socat - UDP:localhost:5555,bind=192.168.75.62
    or:
    socat - UDP-SENDTO:localhost:5555,bind=192.168.75.62
    or:
    socat - UDP-CONNECT:localhost:5555,bind=192.168.75.62

    Server:
    socat UDP-LISTEN:5555 -
    or:
    socat UDP-RECVFROM:5555 -


    Each time, the answer is like that:
    192.168.75.62 -> 192.168.75.62 UDP Source port: 5555 Destination port:
    39293


    Also a bug in "socat"?
    (or in the person invoking the server?)

    Regards,
    Christophe
     
    Christophe Lohr, Jan 23, 2009
    #15
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.