Sitelet https://web.archive.org/web/20201023082350/https://github.com/dnsjava/dnsjava/issues/110
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UDP port stays open when DNS query runs into a timeout or error #110

Closed
teetrenz opened this issue May 22, 2020 · 7 comments
Closed

UDP port stays open when DNS query runs into a timeout or error #110

teetrenz opened this issue May 22, 2020 · 7 comments
Labels
bug
Milestone

Comments

@teetrenz
Copy link

@teetrenz teetrenz commented May 22, 2020

In our application, we have a little piece of code that checks whether a target computer has a DNS service installed. For that purpose, we send a DNS query to the target computer. When the target server hosts a DNS service, then we receive a proper response and everything is fine. However, when there is an error (timeout or IOException), then we get the correct error message, but a UDP port stays open.

When we perform 1000 queries to IP addresses which don't have a DNS server up and running, then we end up with 1000 open UDP ports until the process terminates. After testing even more, the system runs out of ports.

We run our code currently with dnsjava-3.0.2, but we also tested the latest release 3.1.0 with the same result. We are running our project with OpenJDK 13 on Windows. We check the open ports from the command line via 'netstat.exe -a -n -b | find "UDP"'

This here is basically our source code. The parameter "address" corresponds to the IP address where we would like to check whether a valid DNS server is running on that IP address:

public DiscoveryProtocolStatus validateDnsServer(IPAddress address) {
DiscoveryProtocolStatus retval = DiscoveryProtocolStatus.NotTested;

if(address != null) {
  try {
    SimpleResolver resolver = new SimpleResolver();
    resolver.setAddress(address.getInetAddress ());
    
    if(getTimeoutInMillis() / 1000.0 > 0) {
      Duration timeout = Duration.ofMillis (getTimeoutInMillis());
      resolver.setTimeout (timeout);
    }
      
    Record record = Record.newRecord(ReverseMap.fromAddress(address.getInetAddress ()), Type.PTR, DClass.IN);
    Message query = Message.newQuery(record);
    
    resolver.send(query);
    retval = DiscoveryProtocolStatus.getSuccess();
  }
  catch(SocketTimeoutException e) {
    retval = DiscoveryProtocolStatus.Timeout;
  }
  catch (IOException e) {
    retval = DiscoveryProtocolStatus.IOFailure;
  }
  catch(Exception e) {
    retval = DiscoveryProtocolStatus.getFailure();
  }
}

return retval;

}

@teetrenz
Copy link
Author

@teetrenz teetrenz commented May 23, 2020

Hi,
I was debugging a little and the cause might be the method processReadKey (SelectionKey key) in the class NioUdpClient.

When we get an IO exception, then the channel does not get closed.

` public void processReadyKey(SelectionKey key) {
if (!key.isReadable()) {
f.completeExceptionally(new EOFException("channel not readable"));
pendingTransactions.remove(this);
return;
}

  DatagramChannel channel = (DatagramChannel) key.channel();
  ByteBuffer buffer = ByteBuffer.allocate(max);
  int read;
  try {
    read = channel.read(buffer);
    if (read <= 0) {
      throw new EOFException();
    }
  } catch (IOException e) {
    **_// Shouldn't the channel be closed here?_**
    pendingTransactions.remove(this);
    f.completeExceptionally(e);
    return;
  }

  buffer.flip();
  byte[] data = new byte[read];
  System.arraycopy(buffer.array(), 0, data, 0, read);
  verboseLog(
      "UDP read",
      channel.socket().getLocalSocketAddress(),
      channel.socket().getRemoteSocketAddress(),
      data);
  try {
    channel.disconnect();
    channel.close();
  } catch (IOException e) {
    // ignore, we already have everything we need
  }

  f.complete(data);
  pendingTransactions.remove(this);
}

`

@teetrenz
Copy link
Author

@teetrenz teetrenz commented May 23, 2020

I think, the channel should be closed in the catch (IOException e) block.

@ibauersachs
Copy link
Member

@ibauersachs ibauersachs commented May 26, 2020

Yes, you're probably right. I need to verify the behavior, which might take me a while.

@teetrenz
Copy link
Author

@teetrenz teetrenz commented May 26, 2020

I added some code to close the channel in the above situation and it is now working fine for me. However, I am not sure, whether this are all error conditions where you should close the datagram socket...

@ibauersachs ibauersachs added this to the v3.2 milestone May 26, 2020
@teetrenz
Copy link
Author

@teetrenz teetrenz commented May 26, 2020

Verifying is pretty easy. Run in a loop DNS requests against an IP that doesn't have a DNS server installed. You will get an error and after a while, you will have plenty of open UDP datagram sockets.

@ibauersachs
Copy link
Member

@ibauersachs ibauersachs commented May 26, 2020

If you already changed this, would you mind creating a pull request? Ideally including a unit test that verifies your fix is working.

@ibauersachs ibauersachs added the bug label May 26, 2020
@teetrenz
Copy link
Author

@teetrenz teetrenz commented May 26, 2020

Hi,

this is my modified version of the NioUdpClient.java based on 3.1.0 release. I have added a block to close the channels.

I was testing it by checking the list of open UDP ports using the netstat command. Don't know how you might automate that in a unit test....

NioUdpClient.java.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.