0

If I send a UDP packet containing 'foo' like this:

socket = UDPSocket.new
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
socket.send('foo', 0, '<broadcast>', 40001)

then wireshark tells me the packet gets sent correctly, but unfortunately its source address is 192.168.0.3. As my server is listening on localhost:40001, that means it doesn't receive the packet. I don't want to let the server listen on 0.0.0.0, as it shouldn't receive similar UDP requests that are sent within another network. I can make the server listen within the 192.168.0.0/24 network, but later on it will be listening from another network, that is neither localhost nor 192.168.0.0/24, so that doesn't solve the problem.

Is there a way to choose the source address from which (and the interface via which) the client socket will send its packet?

Confusion
  • 16,256
  • 8
  • 46
  • 71

3 Answers3

2

I guess you're trying to send it out to the loopback device, so it should be something like (never tried this with ruby):

dev="lo"
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BINDTODEVICE, dev+'\0'))

you also might have to enable multicast loop:

socket.setsockopt(Socket::SOL_SOCKET, Socket::IP_MULTICAST_LOOP, [1].pack('i'))
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
  • Thanks for the suggestion. Unfortunately, I'm not allowed to set that option. According to e.g. http://stackoverflow.com/questions/1207746/problems-with-so-bindtodevice-linux-socket-option, SO_BINDTODEVICE requires root privileges. I'd rather not run the application as root. – Confusion Feb 03 '12 at 11:34
  • uhm.. then listen on 0.0.0.0, and the filter the connections based on ip address. – Karoly Horvath Feb 03 '12 at 11:46
  • That is the fallback plan :). – Confusion Feb 05 '12 at 21:13
1

Have you tried bind() yet? Generally speaking, if you socket.bind() to an address (such as 127.0.0.1) then your packets should originate from that address. The loopback, and broadcasts for that matter, might be treated specially but bind() would be my first choice to try.

Seth Noble
  • 3,233
  • 19
  • 31
  • Using bind works, but it's not my preferred solution. It means I have to choose a free port for my client, which you normally leave to the OS. That introduces additional complexity. – Confusion Feb 05 '12 at 21:00
  • Ah, after reading through some additional C examples, I found I can safely bind to 'dummy' port 0. – Confusion Feb 05 '12 at 21:14
0

Answer appearing two years too late, but this might help future StackOverflow users. It looks like you need to use socket option IP_MULTICAST_IF, which takes a network ordered DWORD version of your interface address. Fortunately the ipaddr library has a utility method for converting human readable addresses:

address = '127.0.0.1'
hton = IPAddr.new(address).hton
socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_IF, hton)
Huw Walters
  • 1,888
  • 20
  • 20