1

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...

Jörg
  • 45
  • 6

1 Answers1

1

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.

Gil Hamilton
  • 11,973
  • 28
  • 51
  • working great, thank you! one remark tho - when the port does not matter, than why not use the port from recfrom()? like:[code] buffer, raddr = recfrom(...) test_sock = socket.socket(...) test_sock.connect(raddr) ...[/code] that way one does not need to think of a port thats not used but needed for the call ;) – Jörg Dec 05 '17 at 15:46
  • working great, thank you! one remark tho - when the port does not matter, than why not use the port from recfrom()? like: >>> buffer, raddr = recfrom(...) >>> test_sock = socket.socket(...) >>> test_sock.connect(raddr) >>> ... that way one does not need to think of a port thats not used but needed for the call ;) – Jörg Dec 05 '17 at 15:53
  • Yes. Works fine to just use the remote's IP/port tuple directly. (And yes: very limited formatting is available in comments. You can use asterisks -- *single* and **double** -- and `backticks`.) – Gil Hamilton Dec 05 '17 at 19:35
  • seems that trick isn't always working - I just had the following case: `a local network with three network interfaces: 192.168.1.100, 192.168.1.200 and 192.168.1.112 while the client (.112) was talking to the server (at .100), the return-socket got connected to the third I/F (.200) instead of the requesting client (.112)` I get back with more details as soon as I figure those ... ((I dont get it - how on earth do I preserve linefeeds in the comment??)) – Jörg Dec 06 '17 at 16:48
  • That doesn't make sense. You're *telling* the system what address to connect the socket to, right? If you tell it to connect to .112 it's not going to magically connect to .200 instead. So maybe you're talking about the local address? But that leads me to wonder if you have two interfaces on the server with addresses on the same subnet. That is a bad idea unless you're doing something very special (and you know what you're doing). – Gil Hamilton Dec 06 '17 at 18:12
  • no, no - it did not `connect` to .200 - it was the *local* addr (from `getsockname()`) being .200, i.e. as if the client was talking to .200 and not .100 before -- but it turned out that this was caused by some mess going on when my change was merged into the baseline; now that the merge is ok, this problem doesn't show anymore! I consider this solved now :) – Jörg Dec 08 '17 at 08:26
  • well, well... I just got the remark from my colleague that is using the server that today he needed to deactivate the .200 I/F to make it work... so there still **IS** an issue with this trick; seems it does not always return the correct IP address this way! Is there a better way then? – Jörg Dec 08 '17 at 08:59
  • I did mention that having two interfaces on the same subnet is a bad idea. Is there a reason your server is configured that way? – Gil Hamilton Dec 08 '17 at 22:04
  • are you saying I can only have two peers per one ethernet wire? not really... - there usually are many PCs connected and some of them run servers; all on different IP addresses of course. so, how do I find the address a client was talking to when there are more then only two PCs connected? – Jörg Dec 10 '17 at 13:33
  • That is not what I'm saying. I'm saying that there is simply no way that `getsockname` will report .200 to you as your socket's local address if .200 is not associated with an interface on your local machine. I suspect your code is incorrect in some other respect. – Gil Hamilton Dec 10 '17 at 20:27
  • hehe... well, that .200 belongs to a virtual machine on the same physical PC, maybe sharing the same network hardware, but not sure about it... – Jörg Dec 10 '17 at 22:18