Does a UDP service have to respond from the connected IP address?
Question: [Pyzor](http://pyzor.org) uses UDP/IP as the communication protocol. We
recently switched the public server to a new machine, and started getting
reports of many timeouts. I discovered that I could fix the problem if I
changed the IP that was queried from `eth0:1` to `eth0`.

I can reproduce this problem with a simple example:

This is the server code:

    
    
    #! /usr/bin/env python
    
    import SocketServer
    
    class RequestHandler(SocketServer.DatagramRequestHandler):
        def handle(self):
            print self.packet
            self.wfile.write("Pong")
    
    s = SocketServer.UDPServer(("0.0.0.0", 24440), RequestHandler)
    s.serve_forever()
    

This is the client code (`188.40.77.206` is `eth0`. `188.40.77.236` is the
same server, but is `eth0:1`):

    
    
    >>> import socket
    >>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    >>> s.sendto('ping', 0, ("188.40.77.206", 24440))
    4
    >>> s.recvfrom(1024)
    ('Pong', ('188.40.77.206', 24440))
    >>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    >>> s.sendto('ping', 0, ("188.40.77.236", 24440))
    4
    >>> s.recvfrom(1024)
    [never gets anything]
    

The server gets the "ping" packet in both cases (and therefore sends the
"pong" packet in both cases).

Oddly, this **does** work from some places (i.e. I'll get a response from both
IPs). For example, it works from `188.40.37.137` (same network/datacenter,
different server), but also from `89.18.189.160` (different datacenter). In
those cases, the `recvfrom` response does have the `eth0` IP, rather than the
one that was connected to.

Is this just a rule of UDP? Is this a problem/limitation with the
[Python](http://python.org) `UDPServer` class? Is it something I'm doing
incorrectly? Is there any way that I can have this work apart from simply
connecting to the `eth0` IP (or listening on the specific IP rather than
`0.0.0.0`)?


Answer: I came across this with a TFTP server. My server had two IP addresses facing
the same network. Because UDP is connectionless, there can be issues with IP
addresses not being set as expected in that situation. The sequence I had was:

  1. Client sends the initial packet to the server at a particular IP address
  2. Server reads the client's source address from the incoming packet, and sends a response. 
    1. However, in the response, the server's "source address" is set according to the routing tables, and it gets set to the **other** IP address.
    2. It wasn't possible to control the server's "source" IP address because the OS didn't tell us which IP address the request came in through.
  3. The client gets a response from the "other" IP address, and rejects it.

The solution in my case was to specifically bind the TFTP server to the IP
address that I wanted to listen to, rather than binding to all interfaces.

I found some text that may be relevant in a [Linux man page for
**`tftpd`**](http://man.cx/tftpd%288%29) (TFTP server). Here it is:

    
    
     Unfortunately, on multi-homed systems, it is impossible for tftpd to
     determine the address on which a packet was received. As a result, tftpd
     uses two different mechanisms to guess the best source address to use for
     replies. If the socket that inetd(8) passed to tftpd is bound to a par‐
     ticular address, tftpd uses that address for replies. Otherwise, tftpd
     uses ‘‘UDP connect’’ to let the kernel choose the reply address based on
     the destination of the replies and the routing tables. This means that
     most setups will work transparently, while in cases where the reply
     address must be fixed, the virtual hosting feature of inetd(8) can be
     used to ensure that replies go out from the correct address.  These con‐
     siderations are important, because most tftp clients will reject reply
     packets that appear to come from an unexpected address.
    

See [this answer](http://stackoverflow.com/a/3929208/60075) which shows that
on Linux it _is_ possible to read the local address for incoming UDP packets,
and set it for outgoing packets. It's possible in C; I'm not sure about Python
though.

