1 /* |
1 /* |
2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
27 |
27 |
28 import java.io.IOException; |
28 import java.io.IOException; |
29 import java.net.DatagramSocket; |
29 import java.net.DatagramSocket; |
30 import java.net.DatagramPacket; |
30 import java.net.DatagramPacket; |
31 import java.net.InetAddress; |
31 import java.net.InetAddress; |
|
32 import java.net.InetSocketAddress; |
32 import java.net.Socket; |
33 import java.net.Socket; |
|
34 import java.net.SocketTimeoutException; |
33 import java.security.SecureRandom; |
35 import java.security.SecureRandom; |
34 import javax.naming.*; |
36 import javax.naming.*; |
35 |
37 |
36 import java.util.Collections; |
38 import java.util.Collections; |
37 import java.util.Map; |
39 import java.util.Map; |
80 private static final int DEFAULT_PORT = 53; |
82 private static final int DEFAULT_PORT = 53; |
81 private static final int TRANSACTION_ID_BOUND = 0x10000; |
83 private static final int TRANSACTION_ID_BOUND = 0x10000; |
82 private static final SecureRandom random = JCAUtil.getSecureRandom(); |
84 private static final SecureRandom random = JCAUtil.getSecureRandom(); |
83 private InetAddress[] servers; |
85 private InetAddress[] servers; |
84 private int[] serverPorts; |
86 private int[] serverPorts; |
85 private int timeout; // initial timeout on UDP queries in ms |
87 private int timeout; // initial timeout on UDP and TCP queries in ms |
86 private int retries; // number of UDP retries |
88 private int retries; // number of UDP retries |
87 |
89 |
88 private final Object udpSocketLock = new Object(); |
90 private final Object udpSocketLock = new Object(); |
89 private static final DNSDatagramSocketFactory factory = |
91 private static final DNSDatagramSocketFactory factory = |
90 new DNSDatagramSocketFactory(random); |
92 new DNSDatagramSocketFactory(random); |
98 //------------------------------------------------------------------------- |
100 //------------------------------------------------------------------------- |
99 |
101 |
100 /* |
102 /* |
101 * Each server is of the form "server[:port]". IPv6 literal host names |
103 * Each server is of the form "server[:port]". IPv6 literal host names |
102 * include delimiting brackets. |
104 * include delimiting brackets. |
103 * "timeout" is the initial timeout interval (in ms) for UDP queries, |
105 * "timeout" is the initial timeout interval (in ms) for queries, |
104 * and "retries" gives the number of retries per server. |
106 * and "retries" gives the number of retries per server. |
105 */ |
107 */ |
106 public DnsClient(String[] servers, int timeout, int retries) |
108 public DnsClient(String[] servers, int timeout, int retries) |
107 throws NamingException { |
109 throws NamingException { |
108 this.timeout = timeout; |
110 this.timeout = timeout; |
235 } |
237 } |
236 if (hdr.truncated) { // message is truncated -- try TCP |
238 if (hdr.truncated) { // message is truncated -- try TCP |
237 |
239 |
238 // Try each server, starting with the one that just |
240 // Try each server, starting with the one that just |
239 // provided the truncated message. |
241 // provided the truncated message. |
|
242 int retryTimeout = (timeout * (1 << retry)); |
240 for (int j = 0; j < servers.length; j++) { |
243 for (int j = 0; j < servers.length; j++) { |
241 int ij = (i + j) % servers.length; |
244 int ij = (i + j) % servers.length; |
242 if (doNotRetry[ij]) { |
245 if (doNotRetry[ij]) { |
243 continue; |
246 continue; |
244 } |
247 } |
245 try { |
248 try { |
246 Tcp tcp = |
249 Tcp tcp = |
247 new Tcp(servers[ij], serverPorts[ij]); |
250 new Tcp(servers[ij], serverPorts[ij], retryTimeout); |
248 byte[] msg2; |
251 byte[] msg2; |
249 try { |
252 try { |
250 msg2 = doTcpQuery(tcp, pkt); |
253 msg2 = doTcpQuery(tcp, pkt); |
251 } finally { |
254 } finally { |
252 tcp.close(); |
255 tcp.close(); |
325 Exception caughtException = null; |
328 Exception caughtException = null; |
326 |
329 |
327 // Try each name server. |
330 // Try each name server. |
328 for (int i = 0; i < servers.length; i++) { |
331 for (int i = 0; i < servers.length; i++) { |
329 try { |
332 try { |
330 Tcp tcp = new Tcp(servers[i], serverPorts[i]); |
333 Tcp tcp = new Tcp(servers[i], serverPorts[i], timeout); |
331 byte[] msg; |
334 byte[] msg; |
332 try { |
335 try { |
333 msg = doTcpQuery(tcp, pkt); |
336 msg = doTcpQuery(tcp, pkt); |
334 Header hdr = new Header(msg, msg.length); |
337 Header hdr = new Header(msg, msg.length); |
335 // Check only rcode as per |
338 // Check only rcode as per |
460 /* |
463 /* |
461 * Returns the next DNS message from the TCP socket, or null on EOF. |
464 * Returns the next DNS message from the TCP socket, or null on EOF. |
462 */ |
465 */ |
463 private byte[] continueTcpQuery(Tcp tcp) throws IOException { |
466 private byte[] continueTcpQuery(Tcp tcp) throws IOException { |
464 |
467 |
465 int lenHi = tcp.in.read(); // high-order byte of response length |
468 int lenHi = tcp.read(); // high-order byte of response length |
466 if (lenHi == -1) { |
469 if (lenHi == -1) { |
467 return null; // EOF |
470 return null; // EOF |
468 } |
471 } |
469 int lenLo = tcp.in.read(); // low-order byte of response length |
472 int lenLo = tcp.read(); // low-order byte of response length |
470 if (lenLo == -1) { |
473 if (lenLo == -1) { |
471 throw new IOException("Corrupted DNS response: bad length"); |
474 throw new IOException("Corrupted DNS response: bad length"); |
472 } |
475 } |
473 int len = (lenHi << 8) | lenLo; |
476 int len = (lenHi << 8) | lenLo; |
474 byte[] msg = new byte[len]; |
477 byte[] msg = new byte[len]; |
475 int pos = 0; // next unfilled position in msg |
478 int pos = 0; // next unfilled position in msg |
476 while (len > 0) { |
479 while (len > 0) { |
477 int n = tcp.in.read(msg, pos, len); |
480 int n = tcp.read(msg, pos, len); |
478 if (n == -1) { |
481 if (n == -1) { |
479 throw new IOException( |
482 throw new IOException( |
480 "Corrupted DNS response: too little data"); |
483 "Corrupted DNS response: too little data"); |
481 } |
484 } |
482 len -= n; |
485 len -= n; |
680 |
683 |
681 } |
684 } |
682 |
685 |
683 class Tcp { |
686 class Tcp { |
684 |
687 |
685 private Socket sock; |
688 private final Socket sock; |
686 java.io.InputStream in; |
689 private final java.io.InputStream in; |
687 java.io.OutputStream out; |
690 final java.io.OutputStream out; |
688 |
691 private int timeoutLeft; |
689 Tcp(InetAddress server, int port) throws IOException { |
692 |
690 sock = new Socket(server, port); |
693 Tcp(InetAddress server, int port, int timeout) throws IOException { |
691 sock.setTcpNoDelay(true); |
694 sock = new Socket(); |
692 out = new java.io.BufferedOutputStream(sock.getOutputStream()); |
695 try { |
693 in = new java.io.BufferedInputStream(sock.getInputStream()); |
696 long start = System.currentTimeMillis(); |
|
697 sock.connect(new InetSocketAddress(server, port), timeout); |
|
698 timeoutLeft = (int) (timeout - (System.currentTimeMillis() - start)); |
|
699 if (timeoutLeft <= 0) |
|
700 throw new SocketTimeoutException(); |
|
701 |
|
702 sock.setTcpNoDelay(true); |
|
703 out = new java.io.BufferedOutputStream(sock.getOutputStream()); |
|
704 in = new java.io.BufferedInputStream(sock.getInputStream()); |
|
705 } catch (Exception e) { |
|
706 try { |
|
707 sock.close(); |
|
708 } catch (IOException ex) { |
|
709 e.addSuppressed(ex); |
|
710 } |
|
711 throw e; |
|
712 } |
694 } |
713 } |
695 |
714 |
696 void close() throws IOException { |
715 void close() throws IOException { |
697 sock.close(); |
716 sock.close(); |
|
717 } |
|
718 |
|
719 private interface SocketReadOp { |
|
720 int read() throws IOException; |
|
721 } |
|
722 |
|
723 private int readWithTimeout(SocketReadOp reader) throws IOException { |
|
724 if (timeoutLeft <= 0) |
|
725 throw new SocketTimeoutException(); |
|
726 |
|
727 sock.setSoTimeout(timeoutLeft); |
|
728 long start = System.currentTimeMillis(); |
|
729 try { |
|
730 return reader.read(); |
|
731 } |
|
732 finally { |
|
733 timeoutLeft -= System.currentTimeMillis() - start; |
|
734 } |
|
735 } |
|
736 |
|
737 int read() throws IOException { |
|
738 return readWithTimeout(() -> in.read()); |
|
739 } |
|
740 |
|
741 int read(byte b[], int off, int len) throws IOException { |
|
742 return readWithTimeout(() -> in.read(b, off, len)); |
698 } |
743 } |
699 } |
744 } |
700 |
745 |
701 /* |
746 /* |
702 * javaos emulation -cj |
747 * javaos emulation -cj |