caymon 0 Posted April 21, 2021 A system A, which has several IP addresses, sends UDP packets to a system B that also have several addresses: On system A, there is a TIdUPDClient with the code: UDPClient.Host := '2017::7690:5000:0:1'; // one of the addresses of B; UDPClient.Port := 3610; UDPClient.IPVersion := Id_IPv6; UDPClient.BoundIP := 'FD00:CAFE:CAFE::AAAA'; // one of the addresses of A The UDP packets are sent with: Src= FD00:CAFE:CAFE::AAAA and Dst=2017::7690:5000:0:1, which is OK. In the system B, there is an IdUDPServer listening to any addresses of B, i.e: IdUDPServer.Bindings.Add.IP := ''; When B receives a packet, the handler UDPRead is executed, with a ''ABinding'' parameter with the values: ABinding.IP = '0:0:0:0.0:0:0:0' ABinding.Port = 3610 ABinding.PeerIP = 'FD00:CAFE:CAFE::AAAA' // src address of the packet, which is correct ABinding.PeerPort = ...any value From the 'ABinding' parameter, is there a way to know the ''real local address'' that received the packet? In our example, this address should be 2017::7690:5000:0:1? Then, before responding to the received message, could I do UDPServer.Binding.IP := ''the real local address'' and then UDPServer.SendBuffer() so that the sent UDP packet would have Src=2017::7690:5000:0:1 and Dst=FD00:CAFE:CAFE::AAAA? Thank you. Share this post Link to post
Remy Lebeau 1393 Posted April 21, 2021 (edited) 2 hours ago, caymon said: From the 'ABinding' parameter, is there a way to know the ''real local address'' that received the packet? No, when ABinding is bound to a wildcard IP like '::0'. Internally, TIdUDPServer uses recvfrom() to read packets, and the information you want is simply not available from recvfrom(). You would need to use recvmsg()/WSARecvMsg() instead (ie, via Indy's TIdStack.ReceiveMsg() method), which requires the IP_PKTINFO/IPV6_RECVPKINFO option be enabled on the socket for recvmsg() to report the receiving adapter's info on each packet read. TIdUDPServer does not support recvmsg(), though. You would have to alter its source code and recompile. Otherwise, you could use TIdUDPClient instead and run your own reading logic with it (despite their names, TIdUDPClient and TIdUDPServer are not true client/server components since UDP is connectionless, so their roles are a little more blurry than with TCP. You can use TIdUDPClient as a server, and TIdUDPServer as a client). Otherwise, you could simply enumerate the local IPs (ie via Indy's TIdStack.GetLocalAddressList() method) and create a separate Binding for each IP individually, and then ABinding.IP will have a meaningful value in the OnUDPRead event. This does mean that TIdUDPServer would need to allocate multiple sockets, though. Quote Then, before responding to the received message, could I do UDPServer.Binding.IP := ''the real local address'' and then UDPServer.SendBuffer() so that the sent UDP packet would have Src=2017::7690:5000:0:1 and Dst=FD00:CAFE:CAFE::AAAA? No. Sending data out from a bound socket will use the IP of the adapter that the socket is bound to. If the socket is bound to a wildcard IP, then the OS will pick which adapter to use, based on its own routing tables for the destination IP. If you want to send out from a specific adapter, you need to either create and bind a separate socket (ie TIdUDPClient) to that adapter, and then send using that socket. use sendmsg()/WSASendMsg() (which Indy does not have a wrapper for), passing in a msghdr struct containing an IP_PKTINFO/IPV6_PKTINFO control message that specifies the desired source IP and interface index. See Setting the source IP for a UDP socket Edited April 21, 2021 by Remy Lebeau Share this post Link to post