2
votes

I'm implementing a DNS server with DatagramSocket (UDP) in Java and the code looks like:

try (DatagramSocket socket = new DatagramSocket(new InetSocketAddress("0.0.0.0", 53))) {
    DatagramPacket request = ... // Init Packet
    socket.receive(request);
    ... // Parse request, Resolve, then Generate reesponse
    socket.send(response);
}

It works fine on my PC and most servers (including aws, linode, etc), but does not work well on a server with double ethernet adapter.

This server has a network config:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
address 192.168.1.204
netmask 255.255.255.0

auto eth1
iface eth1 inet static
address 192.168.1.207
netmask 255.255.255.0

When I test this DNS, I get:

# nslookup
> server 192.168.1.207
Default server: 192.168.1.207
Address: 192.168.1.207#53
> info.dev.
;; reply from unexpected source: 192.168.1.204#53, expected 192.168.1.207#53
;; reply from unexpected source: 192.168.1.204#53, expected 192.168.1.207#53
;; reply from unexpected source: 192.168.1.204#53, expected 192.168.1.207#53
;; connection timed out; no servers could be reached
>

It seems to receive a packet from eth1 (192.168.1.207) but send to eth0 (192.168.1.204). And my code does not know which interface the packet is received from.

try (DatagramSocket socket = new DatagramSocket(new InetSocketAddress("0.0.0.0", 53))) {
    ...
    socket.receive(request); // local socket address not known :-(
    ...
    socket.send(response); // local socket address not known :-(
}

Socket (TCP) can do this but I do not know whether DatagramSocket (UDP) can do so.

UPDATE-1:

bind one interface instead of 0.0.0.0, it works fine.

UPDATE-2:

Socket (TCP) can get both local and remote address:

try (ServerSocket server = new ServerSocket(23)) {
    try (Socket socket = server.accept()) {
        System.out.println(socket.getLocalSocketAddress());
        System.out.println(socket.getRemoteSocketAddress());
    }
}
1
0.0.0.0 basically means "all interfaces", couldn't you bind the socket to one interface?Anders R. Bystrup
I don't understand the question. The local address of that DatagramSocket is 0.0.0.0:53. The one you specified when you constructed it. Which interface it uses to reply on is determined by the static IP routing tables. Not by this code. Not a programming question: off topic.user207421
@AndersR.Bystrup, bind one (e.g. 192.168.1.207) is ok.auntyellow
The local address of an accepted TCP socket is the target address that was used by the client. UDP doesn't have accepted sockets, so it doesn't have that. If you printed out the local address of the ServerSocket, you would get 0.0.0.0:23, much as you did for the DatagramSocket, and for the same reason. There is an API to get the target address of a datagram, at the C level, but it isn't implemented in Java.user207421

1 Answers

3
votes

The local address of that DatagramSocket is 0.0.0.0:53. The one you specified when you constructed it. Which interface it uses to reply on is determined by the static IP routing tables. Not by this code. And getting the local address of the DatagramSocket, or even the target address of the datagram (which you can get in C but not Java), wouldn't help you to solve this problem, if it is a problem.

my code does not know which interface the packet is received from.

Correct. It doesn't care. It is listening at all IP addresses. You told it to do that. It only cares about the remote address, which you haven't shown but have clearly got correct.

try (DatagramSocket socket = new DatagramSocket(new InetSocketAddress("0.0.0.0", 53))) {

I don't know why you've posted this twice.

What you have here is a static IP routing issue. Not a programming problem.