pythonsocketsservertftp

(Python/TFTP-Server) how to listen to an non (yet) existing IP-address (RNDIS)?


Hy folks,

my problem: I want to start a (tftp) server for an non-existing IP-address. the server is meant for USB/RNDIS where its IP-address by nature only is existing when there is actual network-traffic going on -- but I want to start the server 'early' (e.g. when Windows starts).

idea was to bind() the socket to 0.0.0.0 - and then to check each request for "valid" addresses.

problem with that approach: recfrom() only returns the source-address (client), but not the destination (server)!

how do I get the IP-address this client has talked to? (I could of course check for the same subnet at least, but I need the real server-address this client was talking to!)

or, are there by chance any options to let bind() use a non-existing IP-address?

cheers.

p.s. this is for the Python tftpy server... -- at the moment I need to ping from client side when starting the server, which is quite meh...


Solution

  • There's no way to get the local address directly but there's a trick that will usually work for you.

    Let's say that you just obtained a buffer and client address from recvfrom. Now you create a new auxiliary UDP socket, connect it to the client's address, and then use getsockname to obtain the local address on this new socket. (With UDP, connect doesn't actually send anything to the peer, it just does address resolution.)

    So in this way, you can discover the IP address that the server system would use as source were it to send a datagram back to the client system. That's usually the same address that the client used to target the server.

    >>> cbytes, caddr = server_sock.recvfrom(2048)
    >>> print(caddr)                           # Client IP and port
    ('192.168.0.11', 38869)
    
    >>> aux_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    >>> aux_socket.connect((caddr[0], 9999))   # Connect back to client (port doesn't matter)
    >>> saddr = aux_socket.getsockname()       # Get local IP and port (ignore port here too)
    >>> print(saddr)
    ('192.168.0.12', 39753)
    

    This works on linux. I'm not 100% sure it would work the same way on Windows but it seems reasonable to expect that it would.