From 6536727619ff06f7cef3c29b9923f99101617c47 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Oct 2019 14:49:12 +0100 Subject: [PATCH 001/431] Code cleanup --- src/main/java/org/xbill/DNS/DNSSEC.java | 33 ++++++++++++------- src/main/java/org/xbill/DNS/Lookup.java | 2 +- src/main/java/org/xbill/DNS/TSIG.java | 19 +---------- src/main/java/org/xbill/DNS/tools/jnamed.java | 8 ++--- .../java/org/xbill/DNS/URIRecordTest.java | 2 +- 5 files changed, 29 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/xbill/DNS/DNSSEC.java b/src/main/java/org/xbill/DNS/DNSSEC.java index c84ae2792..eb38d127a 100644 --- a/src/main/java/org/xbill/DNS/DNSSEC.java +++ b/src/main/java/org/xbill/DNS/DNSSEC.java @@ -200,8 +200,16 @@ public static byte[] digestMessage(SIGRecord sig, Message msg, byte[] previous) /** A DNSSEC exception. */ public static class DNSSECException extends Exception { - DNSSECException(String s) { - super(s); + DNSSECException(String message, Throwable cause) { + super(message, cause); + } + + DNSSECException(Throwable cause) { + super(cause); + } + + DNSSECException(String message) { + super(message); } } @@ -217,13 +225,14 @@ public static class MalformedKeyException extends DNSSECException { MalformedKeyException(KEYBase rec) { super("Invalid key data: " + rec.rdataToString()); } + + MalformedKeyException(KEYBase rec, Throwable cause) { + super("Invalid key data: " + rec.rdataToString(), cause); + } } /** A DNSSEC verification failed because fields in the DNSKEY and RRSIG records do not match. */ public static class KeyMismatchException extends DNSSECException { - private KEYBase key; - private SIGBase sig; - KeyMismatchException(KEYBase key, SIGBase sig) { super( "key " @@ -244,7 +253,8 @@ public static class KeyMismatchException extends DNSSECException { /** A DNSSEC verification failed because the signature has expired. */ public static class SignatureExpiredException extends DNSSECException { - private Instant when, now; + private Instant when; + private Instant now; SignatureExpiredException(Instant when, Instant now) { super("signature expired"); @@ -265,7 +275,8 @@ public Instant getVerifyTime() { /** A DNSSEC verification failed because the signature has not yet become valid. */ public static class SignatureNotYetValidException extends DNSSECException { - private Instant when, now; + private Instant when; + private Instant now; SignatureNotYetValidException(Instant when, Instant now) { super("signature is not yet valid"); @@ -519,9 +530,9 @@ static PublicKey toPublicKey(KEYBase r) throws DNSSECException { throw new UnsupportedAlgorithmException(alg); } } catch (IOException e) { - throw new MalformedKeyException(r); + throw new MalformedKeyException(r, e); } catch (GeneralSecurityException e) { - throw new DNSSECException(e.toString()); + throw new DNSSECException(e); } } @@ -926,7 +937,7 @@ private static void verify(PublicKey key, int alg, byte[] data, byte[] signature throw new SignatureVerificationException(); } } catch (GeneralSecurityException e) { - throw new DNSSECException(e.toString()); + throw new DNSSECException(e); } } @@ -1002,7 +1013,7 @@ static byte[] sign(PrivateKey privkey, PublicKey pubkey, int alg, byte[] data, S s.update(data); signature = s.sign(); } catch (GeneralSecurityException e) { - throw new DNSSECException(e.toString()); + throw new DNSSECException(e); } if (pubkey instanceof DSAPublicKey) { diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index 1d6f026b2..1d11822ac 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -222,7 +222,7 @@ public Lookup(Name name, int type, int dclass) { Type.check(type); DClass.check(dclass); if (!Type.isRR(type) && type != Type.ANY) { - throw new IllegalArgumentException("Cannot query for " + "meta-types other than ANY"); + throw new IllegalArgumentException("Cannot query for meta-types other than ANY"); } this.name = name; this.type = type; diff --git a/src/main/java/org/xbill/DNS/TSIG.java b/src/main/java/org/xbill/DNS/TSIG.java index dd661d992..93d138fcf 100644 --- a/src/main/java/org/xbill/DNS/TSIG.java +++ b/src/main/java/org/xbill/DNS/TSIG.java @@ -435,12 +435,11 @@ public void applyStream(Message m, TSIGRecord old, boolean first) { * @param b An array containing the message in unparsed form. This is necessary since TSIG signs * the message in wire format, and we can't recreate the exact wire format (with the same name * compression). - * @param length The length of the message in the array. * @param old If this message is a response, the TSIG from the request * @return The result of the verification (as an Rcode) * @see Rcode */ - public byte verify(Message m, byte[] b, int length, TSIGRecord old) { + public byte verify(Message m, byte[] b, TSIGRecord old) { m.tsigState = Message.TSIG_FAILED; TSIGRecord tsig = m.getTSIG(); hmac.reset(); @@ -517,22 +516,6 @@ public byte verify(Message m, byte[] b, int length, TSIGRecord old) { return Rcode.NOERROR; } - /** - * Verifies a TSIG record on an incoming message. Since this is only called in the context where a - * TSIG is expected to be present, it is an error if one is not present. After calling this - * routine, Message.isVerified() may be called on this message. - * - * @param m The message - * @param b The message in unparsed form. This is necessary since TSIG signs the message in wire - * format, and we can't recreate the exact wire format (with the same name compression). - * @param old If this message is a response, the TSIG from the request - * @return The result of the verification (as an Rcode) - * @see Rcode - */ - public int verify(Message m, byte[] b, TSIGRecord old) { - return verify(m, b, b.length, old); - } - /** * Returns the maximum length of a TSIG record generated by this key. * diff --git a/src/main/java/org/xbill/DNS/tools/jnamed.java b/src/main/java/org/xbill/DNS/tools/jnamed.java index b070c6b66..0fd13ce6e 100644 --- a/src/main/java/org/xbill/DNS/tools/jnamed.java +++ b/src/main/java/org/xbill/DNS/tools/jnamed.java @@ -414,7 +414,7 @@ byte[] doAXFR(Name name, Message query, TSIG tsig, TSIGRecord qtsig, Socket s) { * anything. Currently this only happens if this is an AXFR request over * TCP. */ - byte[] generateReply(Message query, byte[] in, int length, Socket s) { + byte[] generateReply(Message query, byte[] in, Socket s) { Header header; boolean badversion; int maxLength; @@ -437,7 +437,7 @@ byte[] generateReply(Message query, byte[] in, int length, Socket s) { TSIG tsig = null; if (queryTSIG != null) { tsig = TSIGs.get(queryTSIG.getName()); - if (tsig == null || tsig.verify(query, in, length, null) != Rcode.NOERROR) { + if (tsig == null || tsig.verify(query, in, null) != Rcode.NOERROR) { return formerrMessage(in); } } @@ -535,7 +535,7 @@ public void TCPclient(Socket s) { byte[] response; try { query = new Message(in); - response = generateReply(query, in, in.length, s); + response = generateReply(query, in, s); if (response == null) { return; } @@ -595,7 +595,7 @@ public void serveUDP(InetAddress addr, int port) { byte[] response; try { query = new Message(in); - response = generateReply(query, in, indp.getLength(), null); + response = generateReply(query, in, null); if (response == null) { continue; } diff --git a/src/test/java/org/xbill/DNS/URIRecordTest.java b/src/test/java/org/xbill/DNS/URIRecordTest.java index 48384e9e7..4be1d407e 100644 --- a/src/test/java/org/xbill/DNS/URIRecordTest.java +++ b/src/test/java/org/xbill/DNS/URIRecordTest.java @@ -46,7 +46,7 @@ void test_ctor_6arg() throws TextParseException { @Test void test_rdataFromString() throws IOException { - Tokenizer t = new Tokenizer(0xABCD + " " + 0xEF01 + " " + "\"http://foo:1234/bar?baz=bum\""); + Tokenizer t = new Tokenizer(0xABCD + " " + 0xEF01 + " \"http://foo:1234/bar?baz=bum\""); URIRecord r = new URIRecord(); r.rdataFromString(t, null); From 8d79cb339b08295c404cfa32cad200e5db4a4a25 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Oct 2019 14:50:08 +0100 Subject: [PATCH 002/431] Add options to sign and verify DNSSEC messages at a given time --- src/main/java/org/xbill/DNS/DNSSEC.java | 4 +-- src/main/java/org/xbill/DNS/SIG0.java | 39 +++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/xbill/DNS/DNSSEC.java b/src/main/java/org/xbill/DNS/DNSSEC.java index eb38d127a..34509d46d 100644 --- a/src/main/java/org/xbill/DNS/DNSSEC.java +++ b/src/main/java/org/xbill/DNS/DNSSEC.java @@ -1178,7 +1178,7 @@ static SIGRecord signMessage( } static void verifyMessage( - Message message, byte[] bytes, SIGRecord sig, SIGRecord previous, KEYRecord key) + Message message, byte[] bytes, SIGRecord sig, SIGRecord previous, KEYRecord key, Instant now) throws DNSSECException { if (message.sig0start == 0) { throw new NoSignatureException(); @@ -1188,8 +1188,6 @@ static void verifyMessage( throw new KeyMismatchException(key, sig); } - Instant now = Instant.now(); - if (now.compareTo(sig.getExpire()) > 0) { throw new SignatureExpiredException(sig.getExpire(), now); } diff --git a/src/main/java/org/xbill/DNS/SIG0.java b/src/main/java/org/xbill/DNS/SIG0.java index 7a8a68212..260f80c98 100644 --- a/src/main/java/org/xbill/DNS/SIG0.java +++ b/src/main/java/org/xbill/DNS/SIG0.java @@ -5,6 +5,7 @@ import java.security.PrivateKey; import java.time.Duration; import java.time.Instant; +import org.xbill.DNS.DNSSEC.DNSSECException; /** * Creates SIG(0) transaction signatures. @@ -34,6 +35,22 @@ private SIG0() {} public static void signMessage( Message message, KEYRecord key, PrivateKey privkey, SIGRecord previous) throws DNSSEC.DNSSECException { + signMessage(message, key, privkey, previous, Instant.now()); + } + + /** + * Sign a message with SIG(0). The DNS key and private key must refer to the same underlying + * cryptographic key. + * + * @param message The message to be signed + * @param key The DNSKEY record to use as part of signing + * @param privkey The PrivateKey to use when signing + * @param previous If this message is a response, the SIG(0) from the query + * @param timeSigned The time instant when the message has been signed. + */ + public static void signMessage( + Message message, KEYRecord key, PrivateKey privkey, SIGRecord previous, Instant timeSigned) + throws DNSSEC.DNSSECException { int validityOption = Options.intValue("sig0validity"); Duration validity; @@ -43,7 +60,6 @@ public static void signMessage( validity = Duration.ofSeconds(validityOption); } - Instant timeSigned = Instant.now(); Instant timeExpires = timeSigned.plus(validity); SIGRecord sig = DNSSEC.signMessage(message, previous, key, privkey, timeSigned, timeExpires); @@ -52,7 +68,7 @@ public static void signMessage( } /** - * Verify a message using SIG(0). + * Verify a message using SIG(0). Uses the current system clock for the date/time. * * @param message The message to be signed * @param b An array containing the message in unparsed form. This is necessary since SIG(0) signs @@ -62,6 +78,23 @@ public static void signMessage( * @param previous If this message is a response, the SIG(0) from the query */ public static void verifyMessage(Message message, byte[] b, KEYRecord key, SIGRecord previous) + throws DNSSECException { + verifyMessage(message, b, key, previous, Instant.now()); + } + + /** + * Verify a message using SIG(0). + * + * @param message The message to be signed + * @param b An array containing the message in unparsed form. This is necessary since SIG(0) signs + * the message in wire format, and we can't recreate the exact wire format (with the same name + * compression). + * @param key The KEY record to verify the signature with. + * @param previous If this message is a response, the SIG(0) from the query + * @param now the time instant to verify the message. + */ + public static void verifyMessage( + Message message, byte[] b, KEYRecord key, SIGRecord previous, Instant now) throws DNSSEC.DNSSECException { SIGRecord sig = null; Record[] additional = message.getSectionArray(Section.ADDITIONAL); @@ -75,6 +108,6 @@ public static void verifyMessage(Message message, byte[] b, KEYRecord key, SIGRe sig = (SIGRecord) record; break; } - DNSSEC.verifyMessage(message, b, sig, previous, key); + DNSSEC.verifyMessage(message, b, sig, previous, key, now); } } From 4276ad715c2cff76a244b67c02f0035faa1b6220 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Oct 2019 16:04:41 +0100 Subject: [PATCH 003/431] Remove test_ prefix from test methods --- src/test/java/org/xbill/DNS/A6RecordTest.java | 14 +- .../java/org/xbill/DNS/AAAARecordTest.java | 14 +- .../java/org/xbill/DNS/AFSDBRecordTest.java | 4 +- .../java/org/xbill/DNS/APLRecordTest.java | 72 +++--- src/test/java/org/xbill/DNS/ARecordTest.java | 14 +- src/test/java/org/xbill/DNS/AddressTest.java | 32 +-- .../java/org/xbill/DNS/CNAMERecordTest.java | 6 +- src/test/java/org/xbill/DNS/DClassTest.java | 4 +- .../java/org/xbill/DNS/DNAMERecordTest.java | 6 +- src/test/java/org/xbill/DNS/DNSInputTest.java | 48 ++-- .../java/org/xbill/DNS/DNSKEYRecordTest.java | 8 +- .../java/org/xbill/DNS/DNSOutputTest.java | 38 +-- src/test/java/org/xbill/DNS/DSRecordTest.java | 28 +-- .../java/org/xbill/DNS/EmptyRecordTest.java | 12 +- .../java/org/xbill/DNS/ExceptionTest.java | 16 +- .../java/org/xbill/DNS/ExtendedFlagsTest.java | 4 +- src/test/java/org/xbill/DNS/FlagsTest.java | 6 +- .../java/org/xbill/DNS/FormattedTimeTest.java | 6 +- .../java/org/xbill/DNS/GPOSRecordTest.java | 52 ++--- .../java/org/xbill/DNS/HINFORecordTest.java | 22 +- src/test/java/org/xbill/DNS/HeaderTest.java | 34 +-- src/test/java/org/xbill/DNS/KEYBaseTest.java | 10 +- .../java/org/xbill/DNS/KEYRecordTest.java | 14 +- src/test/java/org/xbill/DNS/KXRecordTest.java | 4 +- src/test/java/org/xbill/DNS/MBRecordTest.java | 6 +- src/test/java/org/xbill/DNS/MDRecordTest.java | 6 +- src/test/java/org/xbill/DNS/MFRecordTest.java | 6 +- src/test/java/org/xbill/DNS/MGRecordTest.java | 6 +- src/test/java/org/xbill/DNS/MRRecordTest.java | 6 +- src/test/java/org/xbill/DNS/MXRecordTest.java | 6 +- src/test/java/org/xbill/DNS/MessageTest.java | 8 +- src/test/java/org/xbill/DNS/MnemonicTest.java | 16 +- .../org/xbill/DNS/NSAP_PTRRecordTest.java | 6 +- src/test/java/org/xbill/DNS/NSRecordTest.java | 6 +- src/test/java/org/xbill/DNS/NameTest.java | 216 +++++++++--------- src/test/java/org/xbill/DNS/OpcodeTest.java | 4 +- src/test/java/org/xbill/DNS/OptionsTest.java | 14 +- src/test/java/org/xbill/DNS/RRsetTest.java | 18 +- src/test/java/org/xbill/DNS/RTRecordTest.java | 4 +- src/test/java/org/xbill/DNS/RcodeTest.java | 6 +- src/test/java/org/xbill/DNS/RecordTest.java | 64 +++--- .../java/org/xbill/DNS/ReverseMapTest.java | 6 +- .../java/org/xbill/DNS/SOARecordTest.java | 44 ++-- src/test/java/org/xbill/DNS/SectionTest.java | 8 +- src/test/java/org/xbill/DNS/SerialTest.java | 24 +- .../java/org/xbill/DNS/SetResponseTest.java | 30 +-- .../DNS/SingleCompressedNameBaseTest.java | 4 +- .../org/xbill/DNS/SingleNameBaseTest.java | 10 +- src/test/java/org/xbill/DNS/TSIGTest.java | 6 +- src/test/java/org/xbill/DNS/TTLTest.java | 8 +- .../java/org/xbill/DNS/TokenizerTest.java | 40 ++-- .../java/org/xbill/DNS/TypeBitmapTest.java | 6 +- src/test/java/org/xbill/DNS/TypeTest.java | 8 +- .../java/org/xbill/DNS/U16NameBaseTest.java | 14 +- .../java/org/xbill/DNS/URIRecordTest.java | 20 +- .../java/org/xbill/DNS/utils/base16Test.java | 18 +- .../java/org/xbill/DNS/utils/base64Test.java | 70 +++--- .../java/org/xbill/DNS/utils/hexdumpTest.java | 8 +- 58 files changed, 592 insertions(+), 598 deletions(-) diff --git a/src/test/java/org/xbill/DNS/A6RecordTest.java b/src/test/java/org/xbill/DNS/A6RecordTest.java index 22b60ef89..04c9ade70 100644 --- a/src/test/java/org/xbill/DNS/A6RecordTest.java +++ b/src/test/java/org/xbill/DNS/A6RecordTest.java @@ -72,7 +72,7 @@ void setUp() throws TextParseException, UnknownHostException { } @Test - void test_ctor_0arg() { + void ctor_0arg() { A6Record ar = new A6Record(); assertNull(ar.getName()); assertEquals(0, ar.getType()); @@ -81,14 +81,14 @@ void test_ctor_0arg() { } @Test - void test_getObject() { + void getObject() { A6Record ar = new A6Record(); Record r = ar.getObject(); assertTrue(r instanceof A6Record); } @Test - void test_ctor_6arg() { + void ctor_6arg() { A6Record ar = new A6Record(m_an, DClass.IN, m_ttl, m_prefix_bits, m_addr, null); assertEquals(m_an, ar.getName()); assertEquals(Type.A6, ar.getType()); @@ -135,7 +135,7 @@ void test_ctor_6arg() { } @Test - void test_rrFromWire() throws IOException { + void rrFromWire() throws IOException { // record with no prefix DNSOutput dout = new DNSOutput(); dout.writeU8(0); @@ -167,7 +167,7 @@ void test_rrFromWire() throws IOException { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { // record with no prefix Tokenizer t = new Tokenizer("0 " + m_addr_string); A6Record ar = new A6Record(); @@ -198,7 +198,7 @@ void test_rdataFromString() throws IOException { } @Test - void test_rrToString() { + void rrToString() { A6Record ar = new A6Record(m_an, DClass.IN, m_ttl, m_prefix_bits, m_addr, m_an2); String exp = "" + m_prefix_bits + " " + m_addr_string_canonical + " " + m_an2; String out = ar.rrToString(); @@ -206,7 +206,7 @@ void test_rrToString() { } @Test - void test_rrToWire() { + void rrToWire() { // canonical form A6Record ar = new A6Record(m_an, DClass.IN, m_ttl, m_prefix_bits, m_addr, m_an2); DNSOutput dout = new DNSOutput(); diff --git a/src/test/java/org/xbill/DNS/AAAARecordTest.java b/src/test/java/org/xbill/DNS/AAAARecordTest.java index db0f1b684..086fd0652 100644 --- a/src/test/java/org/xbill/DNS/AAAARecordTest.java +++ b/src/test/java/org/xbill/DNS/AAAARecordTest.java @@ -66,7 +66,7 @@ void setUp() throws TextParseException, UnknownHostException { } @Test - void test_ctor_0arg() { + void ctor_0arg() { AAAARecord ar = new AAAARecord(); assertNull(ar.getName()); assertEquals(0, ar.getType()); @@ -76,14 +76,14 @@ void test_ctor_0arg() { } @Test - void test_getObject() { + void getObject() { AAAARecord ar = new AAAARecord(); Record r = ar.getObject(); assertTrue(r instanceof AAAARecord); } @Test - void test_ctor_4arg() { + void ctor_4arg() { AAAARecord ar = new AAAARecord(m_an, DClass.IN, m_ttl, m_addr); assertEquals(m_an, ar.getName()); assertEquals(Type.AAAA, ar.getType()); @@ -105,7 +105,7 @@ void test_ctor_4arg() { } @Test - void test_rrFromWire() throws IOException { + void rrFromWire() throws IOException { DNSInput di = new DNSInput(m_addr_bytes); AAAARecord ar = new AAAARecord(); @@ -115,7 +115,7 @@ void test_rrFromWire() throws IOException { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { Tokenizer t = new Tokenizer(m_addr_string); AAAARecord ar = new AAAARecord(); @@ -130,13 +130,13 @@ void test_rdataFromString() throws IOException { } @Test - void test_rrToString() { + void rrToString() { AAAARecord ar = new AAAARecord(m_an, DClass.IN, m_ttl, m_addr); assertEquals(m_addr_string, ar.rrToString()); } @Test - void test_rrToWire() { + void rrToWire() { AAAARecord ar = new AAAARecord(m_an, DClass.IN, m_ttl, m_addr); // canonical diff --git a/src/test/java/org/xbill/DNS/AFSDBRecordTest.java b/src/test/java/org/xbill/DNS/AFSDBRecordTest.java index 48d89e117..415c0e762 100644 --- a/src/test/java/org/xbill/DNS/AFSDBRecordTest.java +++ b/src/test/java/org/xbill/DNS/AFSDBRecordTest.java @@ -41,14 +41,14 @@ class AFSDBRecordTest { @Test - void test_getObject() { + void getObject() { AFSDBRecord d = new AFSDBRecord(); Record r = d.getObject(); assertTrue(r instanceof AFSDBRecord); } @Test - void test_ctor_5arg() throws TextParseException { + void ctor_5arg() throws TextParseException { Name n = Name.fromString("My.Name."); Name m = Name.fromString("My.OtherName."); diff --git a/src/test/java/org/xbill/DNS/APLRecordTest.java b/src/test/java/org/xbill/DNS/APLRecordTest.java index 99ea5556c..ccddc41dd 100644 --- a/src/test/java/org/xbill/DNS/APLRecordTest.java +++ b/src/test/java/org/xbill/DNS/APLRecordTest.java @@ -62,7 +62,7 @@ void setUp() throws UnknownHostException { } @Test - void test_valid_IPv4() { + void valid_IPv4() { Element el = new Element(true, m_addr4, 16); assertEquals(Address.IPv4, el.family); assertTrue(el.negative); @@ -71,12 +71,12 @@ void test_valid_IPv4() { } @Test - void test_invalid_IPv4() { + void invalid_IPv4() { assertThrows(IllegalArgumentException.class, () -> new Element(true, m_addr4, 33)); } @Test - void test_valid_IPv6() { + void valid_IPv6() { Element el = new Element(false, m_addr6, 74); assertEquals(Address.IPv6, el.family); assertFalse(el.negative); @@ -85,7 +85,7 @@ void test_valid_IPv6() { } @Test - void test_invalid_IPv6() { + void invalid_IPv6() { assertThrows(IllegalArgumentException.class, () -> new Element(true, m_addr6, 129)); } } @@ -123,7 +123,7 @@ void setUp() throws TextParseException, UnknownHostException { } @Test - void test_0arg() { + void ctor_0arg() { APLRecord ar = new APLRecord(); assertNull(ar.getName()); assertEquals(0, ar.getType()); @@ -133,14 +133,14 @@ void test_0arg() { } @Test - void test_getObject() { + void getObject() { APLRecord ar = new APLRecord(); Record r = ar.getObject(); assertTrue(r instanceof APLRecord); } @Test - void test_4arg_basic() { + void ctor_4arg_basic() { APLRecord ar = new APLRecord(m_an, DClass.IN, m_ttl, m_elements); assertEquals(m_an, ar.getName()); assertEquals(Type.APL, ar.getType()); @@ -150,13 +150,13 @@ void test_4arg_basic() { } @Test - void test_4arg_empty_elements() { + void ctor_4arg_empty_elements() { APLRecord ar = new APLRecord(m_an, DClass.IN, m_ttl, new ArrayList<>()); assertEquals(new ArrayList(), ar.getElements()); } @Test - void test_4arg_relative_name() { + void ctor_4arg_relative_name() { assertThrows( RelativeNameException.class, () -> new APLRecord(m_rn, DClass.IN, m_ttl, m_elements)); } @@ -178,7 +178,7 @@ void setUp() throws UnknownHostException { } @Test - void test_validIPv4() throws IOException { + void validIPv4() throws IOException { byte[] raw = new byte[] { 0, @@ -201,7 +201,7 @@ void test_validIPv4() throws IOException { } @Test - void test_validIPv4_short_address() throws IOException { + void validIPv4_short_address() throws IOException { byte[] raw = new byte[] {0, 1, 20, (byte) 0x83, m_addr4_bytes[0], m_addr4_bytes[1], m_addr4_bytes[2]}; @@ -217,7 +217,7 @@ void test_validIPv4_short_address() throws IOException { } @Test - void test_invalid_IPv4_prefix() throws IOException { + void invalid_IPv4_prefix() throws IOException { byte[] raw = new byte[] { 0, @@ -236,7 +236,7 @@ void test_invalid_IPv4_prefix() throws IOException { } @Test - void test_invalid_IPv4_length() throws IOException { + void invalid_IPv4_length() throws IOException { byte[] raw = new byte[] { 0, @@ -256,7 +256,7 @@ void test_invalid_IPv4_length() throws IOException { } @Test - void test_multiple_validIPv4() throws IOException { + void multiple_validIPv4() throws IOException { byte[] raw = new byte[] { 0, @@ -288,7 +288,7 @@ void test_multiple_validIPv4() throws IOException { } @Test - void test_validIPv6() throws IOException { + void validIPv6() throws IOException { byte[] raw = new byte[] { 0, @@ -323,7 +323,7 @@ void test_validIPv6() throws IOException { } @Test - void test_valid_nonIP() throws IOException { + void valid_nonIP() throws IOException { byte[] raw = new byte[] {0, 3, (byte) 130, (byte) 0x85, 1, 2, 3, 4, 5}; DNSInput di = new DNSInput(raw); @@ -361,7 +361,7 @@ void setUp() throws UnknownHostException { } @Test - void test_validIPv4() throws IOException { + void validIPv4() throws IOException { Tokenizer t = new Tokenizer("1:" + m_addr4_string + "/11\n"); APLRecord ar = new APLRecord(); ar.rdataFromString(t, null); @@ -376,7 +376,7 @@ void test_validIPv4() throws IOException { } @Test - void test_valid_multi() throws IOException { + void valid_multi() throws IOException { Tokenizer t = new Tokenizer("1:" + m_addr4_string + "/11 !2:" + m_addr6_string + "/100"); APLRecord ar = new APLRecord(); ar.rdataFromString(t, null); @@ -389,7 +389,7 @@ void test_valid_multi() throws IOException { } @Test - void test_validIPv6() throws IOException { + void validIPv6() throws IOException { Tokenizer t = new Tokenizer("!2:" + m_addr6_string + "/36\n"); APLRecord ar = new APLRecord(); ar.rdataFromString(t, null); @@ -404,77 +404,77 @@ void test_validIPv6() throws IOException { } @Test - void test_no_colon() throws IOException { + void no_colon() throws IOException { Tokenizer t = new Tokenizer("!1192.68.0.1/20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void test_colon_and_slash_swapped() throws IOException { + void colon_and_slash_swapped() throws IOException { Tokenizer t = new Tokenizer("!1/192.68.0.1:20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void test_no_slash() throws IOException { + void no_slash() throws IOException { Tokenizer t = new Tokenizer("!1:192.68.0.1|20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void test_empty_family() throws IOException { + void empty_family() throws IOException { Tokenizer t = new Tokenizer("!:192.68.0.1/20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void test_malformed_family() throws IOException { + void malformed_family() throws IOException { Tokenizer t = new Tokenizer("family:192.68.0.1/20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void test_invalid_family() throws IOException { + void invalid_family() throws IOException { Tokenizer t = new Tokenizer("3:192.68.0.1/20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void test_empty_prefix() throws IOException { + void empty_prefix() throws IOException { Tokenizer t = new Tokenizer("1:192.68.0.1/"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void test_malformed_prefix() throws IOException { + void malformed_prefix() throws IOException { Tokenizer t = new Tokenizer("1:192.68.0.1/prefix"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void test_invalid_prefix() throws IOException { + void invalid_prefix() throws IOException { Tokenizer t = new Tokenizer("1:192.68.0.1/33"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void test_empty_address() throws IOException { + void empty_address() throws IOException { Tokenizer t = new Tokenizer("1:/33"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void test_malformed_address() throws IOException { + void malformed_address() throws IOException { Tokenizer t = new Tokenizer("1:A.B.C.D/33"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); @@ -553,7 +553,7 @@ void setUp() throws TextParseException, UnknownHostException { } @Test - void test_empty() { + void empty() { APLRecord ar = new APLRecord(m_an, DClass.IN, m_ttl, new ArrayList<>()); DNSOutput dout = new DNSOutput(); @@ -562,7 +562,7 @@ void test_empty() { } @Test - void test_basic() { + void basic() { APLRecord ar = new APLRecord(m_an, DClass.IN, m_ttl, m_elements); byte[] exp = @@ -604,7 +604,7 @@ void test_basic() { } @Test - void test_non_IP() throws IOException { + void non_IP() throws IOException { byte[] exp = new byte[] {0, 3, (byte) 130, (byte) 0x85, 1, 2, 3, 4, 5}; DNSInput di = new DNSInput(exp); @@ -618,7 +618,7 @@ void test_non_IP() throws IOException { } @Test - void test_address_with_embedded_zero() throws UnknownHostException { + void address_with_embedded_zero() throws UnknownHostException { InetAddress a = InetAddress.getByName("232.0.11.1"); ArrayList elements = new ArrayList<>(); elements.add(new Element(true, a, 31)); @@ -634,7 +634,7 @@ void test_address_with_embedded_zero() throws UnknownHostException { } @Test - void test_short_address() throws UnknownHostException { + void short_address() throws UnknownHostException { InetAddress a = InetAddress.getByName("232.0.11.0"); ArrayList elements = new ArrayList<>(); elements.add(new Element(true, a, 31)); @@ -650,7 +650,7 @@ void test_short_address() throws UnknownHostException { } @Test - void test_wildcard_address() throws UnknownHostException { + void wildcard_address() throws UnknownHostException { InetAddress a = InetAddress.getByName("0.0.0.0"); ArrayList elements = new ArrayList<>(); elements.add(new Element(true, a, 31)); diff --git a/src/test/java/org/xbill/DNS/ARecordTest.java b/src/test/java/org/xbill/DNS/ARecordTest.java index c254c2714..a6e4e231b 100644 --- a/src/test/java/org/xbill/DNS/ARecordTest.java +++ b/src/test/java/org/xbill/DNS/ARecordTest.java @@ -66,7 +66,7 @@ void setUp() throws TextParseException, UnknownHostException { } @Test - void test_ctor_0arg() throws UnknownHostException { + void ctor_0arg() throws UnknownHostException { ARecord ar = new ARecord(); assertNull(ar.getName()); assertEquals(0, ar.getType()); @@ -76,14 +76,14 @@ void test_ctor_0arg() throws UnknownHostException { } @Test - void test_getObject() { + void getObject() { ARecord ar = new ARecord(); Record r = ar.getObject(); assertTrue(r instanceof ARecord); } @Test - void test_ctor_4arg() { + void ctor_4arg() { ARecord ar = new ARecord(m_an, DClass.IN, m_ttl, m_addr); assertEquals(m_an, ar.getName()); assertEquals(Type.A, ar.getType()); @@ -106,7 +106,7 @@ void test_ctor_4arg() { } @Test - void test_rrFromWire() throws IOException { + void rrFromWire() throws IOException { DNSInput di = new DNSInput(m_addr_bytes); ARecord ar = new ARecord(); @@ -116,7 +116,7 @@ void test_rrFromWire() throws IOException { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { Tokenizer t = new Tokenizer(m_addr_string); ARecord ar = new ARecord(); @@ -131,13 +131,13 @@ void test_rdataFromString() throws IOException { } @Test - void test_rrToString() { + void rrToString() { ARecord ar = new ARecord(m_an, DClass.IN, m_ttl, m_addr); assertEquals(m_addr_string, ar.rrToString()); } @Test - void test_rrToWire() { + void rrToWire() { ARecord ar = new ARecord(m_an, DClass.IN, m_ttl, m_addr); DNSOutput dout = new DNSOutput(); diff --git a/src/test/java/org/xbill/DNS/AddressTest.java b/src/test/java/org/xbill/DNS/AddressTest.java index e9d7a92ae..43fdc7bd9 100644 --- a/src/test/java/org/xbill/DNS/AddressTest.java +++ b/src/test/java/org/xbill/DNS/AddressTest.java @@ -47,12 +47,12 @@ class AddressTest { @Test - void test_toByteArray_invalid() { + void toByteArray_invalid() { assertThrows(IllegalArgumentException.class, () -> Address.toByteArray("doesn't matter", 3)); } @Test - void test_toByteArray_IPv4() { + void toByteArray_IPv4() { byte[] exp = new byte[] {(byte) 198, (byte) 121, (byte) 10, (byte) 234}; byte[] ret = Address.toByteArray("198.121.10.234", Address.IPv4); assertArrayEquals(exp, ret); @@ -67,7 +67,7 @@ void test_toByteArray_IPv4() { } @Test - void test_toByteArray_IPv4_invalid() { + void toByteArray_IPv4_invalid() { assertNull(Address.toByteArray("A.B.C.D", Address.IPv4)); assertNull(Address.toByteArray("128...", Address.IPv4)); @@ -106,7 +106,7 @@ void test_toByteArray_IPv4_invalid() { } @Test - void test_toByteArray_IPv6() { + void toByteArray_IPv6() { byte[] exp = new byte[] { (byte) 32, (byte) 1, (byte) 13, (byte) 184, (byte) 133, (byte) 163, (byte) 8, (byte) 211, @@ -237,7 +237,7 @@ void test_toByteArray_IPv6() { } @Test - void test_toByteArray_IPv6_invalid() { + void toByteArray_IPv6_invalid() { // not enough groups assertNull(Address.toByteArray("2001:0db8:85a3:08d3:1319:8a2e:0370", Address.IPv6)); // too many groups @@ -257,7 +257,7 @@ void test_toByteArray_IPv6_invalid() { } @Test - void test_toArray() { + void toArray() { int[] exp = new int[] {1, 2, 3, 4}; int[] ret = Address.toArray("1.2.3.4", Address.IPv4); assertArrayEquals(exp, ret); @@ -272,20 +272,20 @@ void test_toArray() { } @Test - void test_toArray_invalid() { + void toArray_invalid() { assertNull(Address.toArray("128.121.1", Address.IPv4)); assertNull(Address.toArray("")); } @Test - void test_isDottedQuad() { + void isDottedQuad() { assertTrue(Address.isDottedQuad("1.2.3.4")); assertFalse(Address.isDottedQuad("256.2.3.4")); } @Test - void test_toDottedQuad() { + void toDottedQuad() { assertEquals( "128.176.201.1", Address.toDottedQuad(new byte[] {(byte) 128, (byte) 176, (byte) 201, (byte) 1})); @@ -294,7 +294,7 @@ void test_toDottedQuad() { } @Test - void test_addressLength() { + void addressLength() { assertEquals(4, Address.addressLength(Address.IPv4)); assertEquals(16, Address.addressLength(Address.IPv6)); @@ -302,7 +302,7 @@ void test_addressLength() { } @Test - void test_getByName() throws UnknownHostException { + void getByName() throws UnknownHostException { InetAddress out = Address.getByName("128.145.198.231"); assertEquals("128.145.198.231", out.getHostAddress()); @@ -311,13 +311,13 @@ void test_getByName() throws UnknownHostException { } @Test - void test_getByName_invalid() { + void getByName_invalid() { assertThrows(UnknownHostException.class, () -> Address.getByName("example.invalid")); assertThrows(UnknownHostException.class, () -> Address.getByName("")); } @Test - void test_getAllByName() throws UnknownHostException { + void getAllByName() throws UnknownHostException { InetAddress[] out = Address.getAllByName("128.145.198.231"); assertEquals(1, out.length); assertEquals("128.145.198.231", out[0].getHostAddress()); @@ -335,20 +335,20 @@ void test_getAllByName() throws UnknownHostException { } @Test - void test_getAllByName_invalid() { + void getAllByName_invalid() { assertThrows(UnknownHostException.class, () -> Address.getAllByName("example.invalid")); assertThrows(UnknownHostException.class, () -> Address.getAllByName("")); } @Test - void test_familyOf() throws UnknownHostException { + void familyOf() throws UnknownHostException { assertEquals(Address.IPv4, Address.familyOf(InetAddress.getByName("192.168.0.1"))); assertEquals(Address.IPv6, Address.familyOf(InetAddress.getByName("1:2:3:4:5:6:7:8"))); assertThrows(IllegalArgumentException.class, () -> Address.familyOf(null)); } @Test - void test_getHostName() throws UnknownHostException { + void getHostName() throws UnknownHostException { String out = Address.getHostName(InetAddress.getByName("198.41.0.4")); assertEquals("a.root-servers.net.", out); diff --git a/src/test/java/org/xbill/DNS/CNAMERecordTest.java b/src/test/java/org/xbill/DNS/CNAMERecordTest.java index 59ccf22db..bedfd8b4d 100644 --- a/src/test/java/org/xbill/DNS/CNAMERecordTest.java +++ b/src/test/java/org/xbill/DNS/CNAMERecordTest.java @@ -42,7 +42,7 @@ class CNAMERecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { CNAMERecord d = new CNAMERecord(); assertNull(d.getName()); assertNull(d.getTarget()); @@ -50,7 +50,7 @@ void test_ctor_0arg() { } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("my.name."); Name a = Name.fromString("my.alias."); @@ -64,7 +64,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_getObject() { + void getObject() { CNAMERecord d = new CNAMERecord(); Record r = d.getObject(); assertTrue(r instanceof CNAMERecord); diff --git a/src/test/java/org/xbill/DNS/DClassTest.java b/src/test/java/org/xbill/DNS/DClassTest.java index 59f6465b8..8aef99afc 100644 --- a/src/test/java/org/xbill/DNS/DClassTest.java +++ b/src/test/java/org/xbill/DNS/DClassTest.java @@ -42,7 +42,7 @@ class DClassTest { @Test - void test_string() { + void string() { // a regular one assertEquals("IN", DClass.string(DClass.IN)); @@ -59,7 +59,7 @@ void test_string() { } @Test - void test_value() { + void value() { // regular one assertEquals(DClass.NONE, DClass.value("NONE")); diff --git a/src/test/java/org/xbill/DNS/DNAMERecordTest.java b/src/test/java/org/xbill/DNS/DNAMERecordTest.java index d1f2177ea..ba7b5613f 100644 --- a/src/test/java/org/xbill/DNS/DNAMERecordTest.java +++ b/src/test/java/org/xbill/DNS/DNAMERecordTest.java @@ -42,7 +42,7 @@ class DNAMERecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { DNAMERecord d = new DNAMERecord(); assertNull(d.getName()); assertNull(d.getTarget()); @@ -50,7 +50,7 @@ void test_ctor_0arg() { } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("my.name."); Name a = Name.fromString("my.alias."); @@ -64,7 +64,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_getObject() { + void getObject() { DNAMERecord d = new DNAMERecord(); Record r = d.getObject(); assertTrue(r instanceof DNAMERecord); diff --git a/src/test/java/org/xbill/DNS/DNSInputTest.java b/src/test/java/org/xbill/DNS/DNSInputTest.java index 6a30dcb6e..f0d324f91 100644 --- a/src/test/java/org/xbill/DNS/DNSInputTest.java +++ b/src/test/java/org/xbill/DNS/DNSInputTest.java @@ -52,58 +52,58 @@ void setUp() { } @Test - void test_initial_state() { + void initial_state() { assertEquals(0, m_di.current()); assertEquals(10, m_di.remaining()); } @Test - void test_jump1() { + void jump1() { m_di.jump(1); assertEquals(1, m_di.current()); assertEquals(9, m_di.remaining()); } @Test - void test_jump2() { + void jump2() { m_di.jump(9); assertEquals(9, m_di.current()); assertEquals(1, m_di.remaining()); } @Test - void test_jump_invalid() { + void jump_invalid() { assertThrows(IllegalArgumentException.class, () -> m_di.jump(10)); } @Test - void test_setActive() { + void setActive() { m_di.setActive(5); assertEquals(0, m_di.current()); assertEquals(5, m_di.remaining()); } @Test - void test_setActive_boundary1() { + void setActive_boundary1() { m_di.setActive(10); assertEquals(0, m_di.current()); assertEquals(10, m_di.remaining()); } @Test - void test_setActive_boundary2() { + void setActive_boundary2() { m_di.setActive(0); assertEquals(0, m_di.current()); assertEquals(0, m_di.remaining()); } @Test - void test_setActive_invalid() { + void setActive_invalid() { assertThrows(IllegalArgumentException.class, () -> m_di.setActive(11)); } @Test - void test_clearActive() { + void clearActive() { // first without setting active: m_di.clearActive(); assertEquals(0, m_di.current()); @@ -116,12 +116,12 @@ void test_clearActive() { } @Test - void test_restore_invalid() { + void restore_invalid() { assertThrows(IllegalStateException.class, () -> m_di.restore()); } @Test - void test_save_restore() { + void save_restore() { m_di.jump(4); assertEquals(4, m_di.current()); assertEquals(6, m_di.remaining()); @@ -137,7 +137,7 @@ void test_save_restore() { } @Test - void test_readU8_basic() throws WireParseException { + void readU8_basic() throws WireParseException { int v1 = m_di.readU8(); assertEquals(1, m_di.current()); assertEquals(9, m_di.remaining()); @@ -145,7 +145,7 @@ void test_readU8_basic() throws WireParseException { } @Test - void test_readU8_maxval() throws WireParseException { + void readU8_maxval() throws WireParseException { m_di.jump(9); final int[] v1 = {m_di.readU8()}; assertEquals(10, m_di.current()); @@ -156,7 +156,7 @@ void test_readU8_maxval() throws WireParseException { } @Test - void test_readU16_basic() throws WireParseException { + void readU16_basic() throws WireParseException { int v1 = m_di.readU16(); assertEquals(2, m_di.current()); assertEquals(8, m_di.remaining()); @@ -168,7 +168,7 @@ void test_readU16_basic() throws WireParseException { } @Test - void test_readU16_maxval() throws WireParseException { + void readU16_maxval() throws WireParseException { m_di.jump(8); int v = m_di.readU16(); assertEquals(10, m_di.current()); @@ -184,7 +184,7 @@ void test_readU16_maxval() throws WireParseException { } @Test - void test_readU32_basic() throws WireParseException { + void readU32_basic() throws WireParseException { long v1 = m_di.readU32(); assertEquals(4, m_di.current()); assertEquals(6, m_di.remaining()); @@ -192,7 +192,7 @@ void test_readU32_basic() throws WireParseException { } @Test - void test_readU32_maxval() throws WireParseException { + void readU32_maxval() throws WireParseException { m_di.jump(6); long v = m_di.readU32(); assertEquals(10, m_di.current()); @@ -208,7 +208,7 @@ void test_readU32_maxval() throws WireParseException { } @Test - void test_readByteArray_0arg() { + void readByteArray_0arg() { m_di.jump(1); byte[] out = m_di.readByteArray(); assertEquals(10, m_di.current()); @@ -220,7 +220,7 @@ void test_readByteArray_0arg() { } @Test - void test_readByteArray_0arg_boundary() throws WireParseException { + void readByteArray_0arg_boundary() throws WireParseException { m_di.jump(9); m_di.readU8(); byte[] out = m_di.readByteArray(); @@ -228,7 +228,7 @@ void test_readByteArray_0arg_boundary() throws WireParseException { } @Test - void test_readByteArray_1arg() throws WireParseException { + void readByteArray_1arg() throws WireParseException { byte[] out = m_di.readByteArray(2); assertEquals(2, m_di.current()); assertEquals(8, m_di.remaining()); @@ -238,7 +238,7 @@ void test_readByteArray_1arg() throws WireParseException { } @Test - void test_readByteArray_1arg_boundary() throws WireParseException { + void readByteArray_1arg_boundary() throws WireParseException { byte[] out = m_di.readByteArray(10); assertEquals(10, m_di.current()); assertEquals(0, m_di.remaining()); @@ -246,12 +246,12 @@ void test_readByteArray_1arg_boundary() throws WireParseException { } @Test - void test_readByteArray_1arg_invalid() { + void readByteArray_1arg_invalid() { assertThrows(WireParseException.class, () -> m_di.readByteArray(11)); } @Test - void test_readByteArray_3arg() throws WireParseException { + void readByteArray_3arg() throws WireParseException { byte[] data = new byte[5]; m_di.jump(4); @@ -264,7 +264,7 @@ void test_readByteArray_3arg() throws WireParseException { } @Test - void test_readCountedSting() throws WireParseException { + void readCountedSting() throws WireParseException { m_di.jump(1); byte[] out = m_di.readCountedString(); assertEquals(1, out.length); diff --git a/src/test/java/org/xbill/DNS/DNSKEYRecordTest.java b/src/test/java/org/xbill/DNS/DNSKEYRecordTest.java index 0b8ae5d04..1a1b134d2 100644 --- a/src/test/java/org/xbill/DNS/DNSKEYRecordTest.java +++ b/src/test/java/org/xbill/DNS/DNSKEYRecordTest.java @@ -45,7 +45,7 @@ class DNSKEYRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { DNSKEYRecord ar = new DNSKEYRecord(); assertNull(ar.getName()); assertEquals(0, ar.getType()); @@ -59,14 +59,14 @@ void test_ctor_0arg() { } @Test - void test_getObject() { + void getObject() { DNSKEYRecord ar = new DNSKEYRecord(); Record r = ar.getObject(); assertTrue(r instanceof DNSKEYRecord); } @Test - void test_ctor_7arg() throws TextParseException { + void ctor_7arg() throws TextParseException { Name n = Name.fromString("My.Absolute.Name."); Name r = Name.fromString("My.Relative.Name"); byte[] key = new byte[] {0, 1, 3, 5, 7, 9}; @@ -88,7 +88,7 @@ void test_ctor_7arg() throws TextParseException { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { // basic DNSKEYRecord kr = new DNSKEYRecord(); Tokenizer st = new Tokenizer(0xABCD + " " + 0x81 + " RSASHA1 AQIDBAUGBwgJ"); diff --git a/src/test/java/org/xbill/DNS/DNSOutputTest.java b/src/test/java/org/xbill/DNS/DNSOutputTest.java index 129f3d7d5..c946688c6 100644 --- a/src/test/java/org/xbill/DNS/DNSOutputTest.java +++ b/src/test/java/org/xbill/DNS/DNSOutputTest.java @@ -50,20 +50,20 @@ void setUp() { } @Test - void test_default_ctor() { + void default_ctor() { m_do = new DNSOutput(); assertEquals(0, m_do.current()); } @Test - void test_initial_state() { + void initial_state() { assertEquals(0, m_do.current()); assertThrows(IllegalStateException.class, () -> m_do.restore()); assertThrows(IllegalArgumentException.class, () -> m_do.jump(1)); } @Test - void test_writeU8_basic() { + void writeU8_basic() { m_do.writeU8(1); assertEquals(1, m_do.current()); @@ -73,7 +73,7 @@ void test_writeU8_basic() { } @Test - void test_writeU8_expand() { + void writeU8_expand() { // starts off at 1; m_do.writeU8(1); m_do.writeU8(2); @@ -87,19 +87,19 @@ void test_writeU8_expand() { } @Test - void test_writeU8_max() { + void writeU8_max() { m_do.writeU8(0xFF); byte[] curr = m_do.toByteArray(); assertEquals((byte) 0xFF, curr[0]); } @Test - void test_writeU8_toobig() { + void writeU8_toobig() { assertThrows(IllegalArgumentException.class, () -> m_do.writeU8(0x1FF)); } @Test - void test_writeU16_basic() { + void writeU16_basic() { m_do.writeU16(0x100); assertEquals(2, m_do.current()); @@ -110,7 +110,7 @@ void test_writeU16_basic() { } @Test - void test_writeU16_max() { + void writeU16_max() { m_do.writeU16(0xFFFF); byte[] curr = m_do.toByteArray(); assertEquals((byte) 0xFF, curr[0]); @@ -118,12 +118,12 @@ void test_writeU16_max() { } @Test - void test_writeU16_toobig() { + void writeU16_toobig() { assertThrows(IllegalArgumentException.class, () -> m_do.writeU16(0x1FFFF)); } @Test - void test_writeU32_basic() { + void writeU32_basic() { m_do.writeU32(0x11001011); assertEquals(4, m_do.current()); @@ -136,7 +136,7 @@ void test_writeU32_basic() { } @Test - void test_writeU32_max() { + void writeU32_max() { m_do.writeU32(0xFFFFFFFFL); byte[] curr = m_do.toByteArray(); assertEquals((byte) 0xFF, curr[0]); @@ -146,12 +146,12 @@ void test_writeU32_max() { } @Test - void test_writeU32_toobig() { + void writeU32_toobig() { assertThrows(IllegalArgumentException.class, () -> m_do.writeU32(0x1FFFFFFFFL)); } @Test - void test_jump_basic() { + void jump_basic() { m_do.writeU32(0x11223344L); assertEquals(4, m_do.current()); m_do.jump(2); @@ -165,7 +165,7 @@ void test_jump_basic() { } @Test - void test_writeByteArray_1arg() { + void writeByteArray_1arg() { byte[] in = new byte[] {(byte) 0xAB, (byte) 0xCD, (byte) 0xEF, (byte) 0x12, (byte) 0x34}; m_do.writeByteArray(in); assertEquals(5, m_do.current()); @@ -174,7 +174,7 @@ void test_writeByteArray_1arg() { } @Test - void test_writeByteArray_3arg() { + void writeByteArray_3arg() { byte[] in = new byte[] {(byte) 0xAB, (byte) 0xCD, (byte) 0xEF, (byte) 0x12, (byte) 0x34}; m_do.writeByteArray(in, 2, 3); assertEquals(3, m_do.current()); @@ -184,7 +184,7 @@ void test_writeByteArray_3arg() { } @Test - void test_writeCountedString_basic() { + void writeCountedString_basic() { byte[] in = new byte[] {'h', 'e', 'l', 'L', '0'}; m_do.writeCountedString(in); assertEquals(in.length + 1, m_do.current()); @@ -194,7 +194,7 @@ void test_writeCountedString_basic() { } @Test - void test_writeCountedString_empty() { + void writeCountedString_empty() { byte[] in = new byte[] {}; m_do.writeCountedString(in); assertEquals(in.length + 1, m_do.current()); @@ -204,13 +204,13 @@ void test_writeCountedString_empty() { } @Test - void test_writeCountedString_toobig() { + void writeCountedString_toobig() { byte[] in = new byte[256]; assertThrows(IllegalArgumentException.class, () -> m_do.writeCountedString(in)); } @Test - void test_save_restore() { + void save_restore() { m_do.writeU32(0x12345678L); assertEquals(4, m_do.current()); m_do.save(); diff --git a/src/test/java/org/xbill/DNS/DSRecordTest.java b/src/test/java/org/xbill/DNS/DSRecordTest.java index 4f530298e..b0802d26c 100644 --- a/src/test/java/org/xbill/DNS/DSRecordTest.java +++ b/src/test/java/org/xbill/DNS/DSRecordTest.java @@ -46,7 +46,7 @@ class DSRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { DSRecord dr = new DSRecord(); assertNull(dr.getName()); assertEquals(0, dr.getType()); @@ -59,7 +59,7 @@ void test_ctor_0arg() { } @Test - void test_getObject() { + void getObject() { DSRecord dr = new DSRecord(); Record r = dr.getObject(); assertTrue(r instanceof DSRecord); @@ -84,7 +84,7 @@ void setUp() throws TextParseException { } @Test - void test_basic() { + void basic() { DSRecord dr = new DSRecord(m_n, DClass.IN, m_ttl, m_footprint, m_algorithm, m_digestid, m_digest); assertEquals(m_n, dr.getName()); @@ -98,49 +98,49 @@ void test_basic() { } @Test - void test_toosmall_footprint() { + void toosmall_footprint() { assertThrows( IllegalArgumentException.class, () -> new DSRecord(m_n, DClass.IN, m_ttl, -1, m_algorithm, m_digestid, m_digest)); } @Test - void test_toobig_footprint() { + void toobig_footprint() { assertThrows( IllegalArgumentException.class, () -> new DSRecord(m_n, DClass.IN, m_ttl, 0x10000, m_algorithm, m_digestid, m_digest)); } @Test - void test_toosmall_algorithm() { + void toosmall_algorithm() { assertThrows( IllegalArgumentException.class, () -> new DSRecord(m_n, DClass.IN, m_ttl, m_footprint, -1, m_digestid, m_digest)); } @Test - void test_toobig_algorithm() { + void toobig_algorithm() { assertThrows( IllegalArgumentException.class, () -> new DSRecord(m_n, DClass.IN, m_ttl, m_footprint, 0x10000, m_digestid, m_digest)); } @Test - void test_toosmall_digestid() { + void toosmall_digestid() { assertThrows( IllegalArgumentException.class, () -> new DSRecord(m_n, DClass.IN, m_ttl, m_footprint, m_algorithm, -1, m_digest)); } @Test - void test_toobig_digestid() { + void toobig_digestid() { assertThrows( IllegalArgumentException.class, () -> new DSRecord(m_n, DClass.IN, m_ttl, m_footprint, m_algorithm, 0x10000, m_digest)); } @Test - void test_null_digest() { + void null_digest() { DSRecord dr = new DSRecord(m_n, DClass.IN, m_ttl, m_footprint, m_algorithm, m_digestid, null); assertEquals(m_n, dr.getName()); assertEquals(DClass.IN, dr.getDClass()); @@ -154,7 +154,7 @@ void test_null_digest() { } @Test - void test_rrFromWire() throws IOException { + void rrFromWire() throws IOException { byte[] raw = new byte[] { (byte) 0xAB, @@ -178,7 +178,7 @@ void test_rrFromWire() throws IOException { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { byte[] raw = new byte[] { (byte) 0xAB, @@ -203,7 +203,7 @@ void test_rdataFromString() throws IOException { } @Test - void test_rrToString() throws TextParseException { + void rrToString() throws TextParseException { String exp = 0xABCD + " " + 0xEF + " " + 0x01 + " 23456789AB"; DSRecord dr = @@ -219,7 +219,7 @@ void test_rrToString() throws TextParseException { } @Test - void test_rrToWire() throws TextParseException { + void rrToWire() throws TextParseException { DSRecord dr = new DSRecord( Name.fromString("The.Name."), diff --git a/src/test/java/org/xbill/DNS/EmptyRecordTest.java b/src/test/java/org/xbill/DNS/EmptyRecordTest.java index f9650e294..887c557e0 100644 --- a/src/test/java/org/xbill/DNS/EmptyRecordTest.java +++ b/src/test/java/org/xbill/DNS/EmptyRecordTest.java @@ -43,7 +43,7 @@ class EmptyRecordTest { @Test - void test_ctor() { + void ctor() { EmptyRecord ar = new EmptyRecord(); assertNull(ar.getName()); assertEquals(0, ar.getType()); @@ -52,14 +52,14 @@ void test_ctor() { } @Test - void test_getObject() { + void getObject() { EmptyRecord ar = new EmptyRecord(); Record r = ar.getObject(); assertTrue(r instanceof EmptyRecord); } @Test - void test_rrFromWire() throws IOException { + void rrFromWire() throws IOException { DNSInput i = new DNSInput(new byte[] {1, 2, 3, 4, 5}); i.jump(3); @@ -73,7 +73,7 @@ void test_rrFromWire() throws IOException { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { Tokenizer t = new Tokenizer("these are the tokens"); EmptyRecord er = new EmptyRecord(); er.rdataFromString(t, null); @@ -86,13 +86,13 @@ void test_rdataFromString() throws IOException { } @Test - void test_rrToString() { + void rrToString() { EmptyRecord er = new EmptyRecord(); assertEquals("", er.rrToString()); } @Test - void test_rrToWire() { + void rrToWire() { EmptyRecord er = new EmptyRecord(); DNSOutput out = new DNSOutput(); er.rrToWire(out, null, true); diff --git a/src/test/java/org/xbill/DNS/ExceptionTest.java b/src/test/java/org/xbill/DNS/ExceptionTest.java index ad1edecde..a2f80a45e 100644 --- a/src/test/java/org/xbill/DNS/ExceptionTest.java +++ b/src/test/java/org/xbill/DNS/ExceptionTest.java @@ -42,25 +42,25 @@ class ExceptionTest { @Test - void test_InvalidDClassException() { + void InvalidDClassException() { IllegalArgumentException e = new InvalidDClassException(10); assertEquals("Invalid DNS class: 10", e.getMessage()); } @Test - void test_InvalidTTLException() { + void InvalidTTLException() { IllegalArgumentException e = new InvalidTTLException(32345); assertEquals("Invalid DNS TTL: 32345", e.getMessage()); } @Test - void test_InvalidTypeException() { + void InvalidTypeException() { IllegalArgumentException e = new InvalidTypeException(32345); assertEquals("Invalid DNS type: 32345", e.getMessage()); } @Test - void test_NameTooLongException() { + void NameTooLongException() { WireParseException e = new NameTooLongException(); assertNull(e.getMessage()); @@ -69,7 +69,7 @@ void test_NameTooLongException() { } @Test - void test_RelativeNameException() throws TextParseException { + void RelativeNameException() throws TextParseException { IllegalArgumentException e = new RelativeNameException("This is my relative name"); assertEquals("This is my relative name", e.getMessage()); @@ -78,7 +78,7 @@ void test_RelativeNameException() throws TextParseException { } @Test - void test_TextParseException() { + void TextParseException() { IOException e = new TextParseException(); assertNull(e.getMessage()); @@ -87,7 +87,7 @@ void test_TextParseException() { } @Test - void test_WireParseException() { + void WireParseException() { IOException e = new WireParseException(); assertNull(e.getMessage()); @@ -96,7 +96,7 @@ void test_WireParseException() { } @Test - void test_ZoneTransferException() { + void ZoneTransferException() { Exception e = new ZoneTransferException(); assertNull(e.getMessage()); diff --git a/src/test/java/org/xbill/DNS/ExtendedFlagsTest.java b/src/test/java/org/xbill/DNS/ExtendedFlagsTest.java index 216cb3e88..2773cecbb 100644 --- a/src/test/java/org/xbill/DNS/ExtendedFlagsTest.java +++ b/src/test/java/org/xbill/DNS/ExtendedFlagsTest.java @@ -42,7 +42,7 @@ class ExtendedFlagsTest { @Test - void test_string() { + void string() { // a regular one assertEquals("do", ExtendedFlags.string(ExtendedFlags.DO)); @@ -56,7 +56,7 @@ void test_string() { } @Test - void test_value() { + void value() { // regular one assertEquals(ExtendedFlags.DO, ExtendedFlags.value("do")); diff --git a/src/test/java/org/xbill/DNS/FlagsTest.java b/src/test/java/org/xbill/DNS/FlagsTest.java index 1ce8207df..5726f40f6 100644 --- a/src/test/java/org/xbill/DNS/FlagsTest.java +++ b/src/test/java/org/xbill/DNS/FlagsTest.java @@ -43,7 +43,7 @@ class FlagsTest { @Test - void test_string() { + void string() { // a regular one assertEquals("aa", Flags.string(Flags.AA)); @@ -57,7 +57,7 @@ void test_string() { } @Test - void test_value() { + void value() { // regular one assertEquals(Flags.CD, Flags.value("cd")); @@ -75,7 +75,7 @@ void test_value() { } @Test - void test_isFlag() { + void isFlag() { assertThrows(IllegalArgumentException.class, () -> Flags.isFlag(-1)); assertTrue(Flags.isFlag(0)); assertFalse(Flags.isFlag(1)); // opcode diff --git a/src/test/java/org/xbill/DNS/FormattedTimeTest.java b/src/test/java/org/xbill/DNS/FormattedTimeTest.java index 243492cf2..e4d1325f1 100644 --- a/src/test/java/org/xbill/DNS/FormattedTimeTest.java +++ b/src/test/java/org/xbill/DNS/FormattedTimeTest.java @@ -46,7 +46,7 @@ class FormattedTimeTest { @Test - void test_format() { + void format() { GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); cal.set(2005, 2, 19, 4, 4, 5); String out = FormattedTime.format(cal.toInstant()); @@ -54,7 +54,7 @@ void test_format() { } @Test - void test_parse() throws DateTimeParseException, TextParseException { + void parse() throws DateTimeParseException, TextParseException { // have to make sure to clear out the milliseconds since there // is occasionally a difference between when cal and cal2 are // instantiated. @@ -70,7 +70,7 @@ void test_parse() throws DateTimeParseException, TextParseException { } @Test - void test_parse_invalid() { + void parse_invalid() { assertThrows(DateTimeParseException.class, () -> FormattedTime.parse("2004010101010")); assertThrows(DateTimeParseException.class, () -> FormattedTime.parse("200401010101010")); assertThrows(DateTimeParseException.class, () -> FormattedTime.parse("2004010101010A")); diff --git a/src/test/java/org/xbill/DNS/GPOSRecordTest.java b/src/test/java/org/xbill/DNS/GPOSRecordTest.java index f8a268b79..234176a14 100644 --- a/src/test/java/org/xbill/DNS/GPOSRecordTest.java +++ b/src/test/java/org/xbill/DNS/GPOSRecordTest.java @@ -45,7 +45,7 @@ class GPOSRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { GPOSRecord gr = new GPOSRecord(); assertNull(gr.getName()); assertEquals(0, gr.getType()); @@ -54,7 +54,7 @@ void test_ctor_0arg() { } @Test - void test_getObject() { + void getObject() { GPOSRecord gr = new GPOSRecord(); Record r = gr.getObject(); assertTrue(r instanceof GPOSRecord); @@ -75,7 +75,7 @@ void setUp() throws TextParseException { } @Test - void test_basic() { + void basic() { GPOSRecord gr = new GPOSRecord(m_n, DClass.IN, m_ttl, m_long, m_lat, m_alt); assertEquals(m_n, gr.getName()); assertEquals(DClass.IN, gr.getDClass()); @@ -90,35 +90,35 @@ void test_basic() { } @Test - void test_toosmall_longitude() { + void toosmall_longitude() { assertThrows( IllegalArgumentException.class, () -> new GPOSRecord(m_n, DClass.IN, m_ttl, -90.001, m_lat, m_alt)); } @Test - void test_toobig_longitude() { + void toobig_longitude() { assertThrows( IllegalArgumentException.class, () -> new GPOSRecord(m_n, DClass.IN, m_ttl, 90.001, m_lat, m_alt)); } @Test - void test_toosmall_latitude() { + void toosmall_latitude() { assertThrows( IllegalArgumentException.class, () -> new GPOSRecord(m_n, DClass.IN, m_ttl, m_long, -180.001, m_alt)); } @Test - void test_toobig_latitude() { + void toobig_latitude() { assertThrows( IllegalArgumentException.class, () -> new GPOSRecord(m_n, DClass.IN, m_ttl, m_long, 180.001, m_alt)); } @Test - void test_invalid_string() { + void invalid_string() { assertThrows( IllegalArgumentException.class, () -> @@ -147,7 +147,7 @@ void setUp() throws TextParseException { } @Test - void test_basic() { + void basic() { GPOSRecord gr = new GPOSRecord( m_n, @@ -169,7 +169,7 @@ void test_basic() { } @Test - void test_toosmall_longitude() { + void toosmall_longitude() { assertThrows( IllegalArgumentException.class, () -> @@ -183,7 +183,7 @@ void test_toosmall_longitude() { } @Test - void test_toobig_longitude() { + void toobig_longitude() { assertThrows( IllegalArgumentException.class, () -> @@ -192,7 +192,7 @@ void test_toobig_longitude() { } @Test - void test_toosmall_latitude() { + void toosmall_latitude() { assertThrows( IllegalArgumentException.class, () -> @@ -206,7 +206,7 @@ void test_toosmall_latitude() { } @Test - void test_toobig_latitude() { + void toobig_latitude() { assertThrows( IllegalArgumentException.class, () -> @@ -222,7 +222,7 @@ void test_toobig_latitude() { static class Test_rrFromWire { @Test - void test_basic() throws IOException { + void basic() throws IOException { byte[] raw = new byte[] { 5, '-', '8', '.', '1', '2', 6, '1', '2', '3', '.', '0', '7', 3, '0', '.', '0' @@ -237,7 +237,7 @@ void test_basic() throws IOException { } @Test - void test_longitude_toosmall() throws IOException { + void longitude_toosmall() throws IOException { byte[] raw = new byte[] { 5, '-', '9', '5', '.', '0', 6, '1', '2', '3', '.', '0', '7', 3, '0', '.', '0' @@ -249,7 +249,7 @@ void test_longitude_toosmall() throws IOException { } @Test - void test_longitude_toobig() throws IOException { + void longitude_toobig() throws IOException { byte[] raw = new byte[] { 5, '1', '8', '5', '.', '0', 6, '1', '2', '3', '.', '0', '7', 3, '0', '.', '0' @@ -261,7 +261,7 @@ void test_longitude_toobig() throws IOException { } @Test - void test_latitude_toosmall() throws IOException { + void latitude_toosmall() throws IOException { byte[] raw = new byte[] { 5, '-', '8', '5', '.', '0', 6, '-', '1', '9', '0', '.', '0', 3, '0', '.', '0' @@ -273,7 +273,7 @@ void test_latitude_toosmall() throws IOException { } @Test - void test_latitude_toobig() throws IOException { + void latitude_toobig() throws IOException { byte[] raw = new byte[] { 5, '-', '8', '5', '.', '0', 6, '2', '1', '9', '0', '.', '0', 3, '0', '.', '0' @@ -287,7 +287,7 @@ void test_latitude_toobig() throws IOException { static class Test_rdataFromString { @Test - void test_basic() throws IOException { + void basic() throws IOException { Tokenizer t = new Tokenizer("10.45 171.121212 1010787"); GPOSRecord gr = new GPOSRecord(); @@ -298,7 +298,7 @@ void test_basic() throws IOException { } @Test - void test_longitude_toosmall() { + void longitude_toosmall() { Tokenizer t = new Tokenizer("-100.390 171.121212 1010787"); GPOSRecord gr = new GPOSRecord(); @@ -306,7 +306,7 @@ void test_longitude_toosmall() { } @Test - void test_longitude_toobig() { + void longitude_toobig() { Tokenizer t = new Tokenizer("90.00001 171.121212 1010787"); GPOSRecord gr = new GPOSRecord(); @@ -314,7 +314,7 @@ void test_longitude_toobig() { } @Test - void test_latitude_toosmall() { + void latitude_toosmall() { Tokenizer t = new Tokenizer("0.0 -180.01 1010787"); GPOSRecord gr = new GPOSRecord(); @@ -322,7 +322,7 @@ void test_latitude_toosmall() { } @Test - void test_latitude_toobig() { + void latitude_toobig() { Tokenizer t = new Tokenizer("0.0 180.01 1010787"); GPOSRecord gr = new GPOSRecord(); @@ -330,7 +330,7 @@ void test_latitude_toobig() { } @Test - void test_invalid_string() throws IOException { + void invalid_string() throws IOException { Tokenizer t = new Tokenizer("1.0 2.0 \\435"); try { GPOSRecord gr = new GPOSRecord(); @@ -341,7 +341,7 @@ void test_invalid_string() throws IOException { } @Test - void test_rrToString() throws TextParseException { + void rrToString() throws TextParseException { String exp = "\"10.45\" \"171.121212\" \"1010787.0\""; GPOSRecord gr = @@ -350,7 +350,7 @@ void test_rrToString() throws TextParseException { } @Test - void test_rrToWire() throws TextParseException { + void rrToWire() throws TextParseException { GPOSRecord gr = new GPOSRecord(Name.fromString("The.Name."), DClass.IN, 0x123, -10.45, 120.0, 111.0); diff --git a/src/test/java/org/xbill/DNS/HINFORecordTest.java b/src/test/java/org/xbill/DNS/HINFORecordTest.java index 3fc156cf6..780fff232 100644 --- a/src/test/java/org/xbill/DNS/HINFORecordTest.java +++ b/src/test/java/org/xbill/DNS/HINFORecordTest.java @@ -45,7 +45,7 @@ class HINFORecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { HINFORecord dr = new HINFORecord(); assertNull(dr.getName()); assertEquals(0, dr.getType()); @@ -54,14 +54,14 @@ void test_ctor_0arg() { } @Test - void test_getObject() { + void getObject() { HINFORecord dr = new HINFORecord(); Record r = dr.getObject(); assertTrue(r instanceof HINFORecord); } @Test - void test_ctor_5arg() throws TextParseException { + void ctor_5arg() throws TextParseException { Name n = Name.fromString("The.Name."); long ttl = 0xABCDL; String cpu = "i686 Intel(R) Pentium(R) M processor 1.70GHz GenuineIntel GNU/Linux"; @@ -77,7 +77,7 @@ void test_ctor_5arg() throws TextParseException { } @Test - void test_ctor_5arg_invalid_CPU() throws TextParseException { + void ctor_5arg_invalid_CPU() throws TextParseException { Name n = Name.fromString("The.Name."); long ttl = 0xABCDL; String cpu = "i686 Intel(R) Pentium(R) M \\256 processor 1.70GHz GenuineIntel GNU/Linux"; @@ -87,7 +87,7 @@ void test_ctor_5arg_invalid_CPU() throws TextParseException { } @Test - void test_ctor_5arg_invalid_OS() throws TextParseException { + void ctor_5arg_invalid_OS() throws TextParseException { Name n = Name.fromString("The.Name."); long ttl = 0xABCDL; String cpu = "i686 Intel(R) Pentium(R) M processor 1.70GHz GenuineIntel GNU/Linux"; @@ -97,7 +97,7 @@ void test_ctor_5arg_invalid_OS() throws TextParseException { } @Test - void test_rrFromWire() throws IOException { + void rrFromWire() throws IOException { String cpu = "Intel(R) Pentium(R) M processor 1.70GHz"; String os = "Linux troy 2.6.10-gentoo-r6"; @@ -118,7 +118,7 @@ void test_rrFromWire() throws IOException { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { String cpu = "Intel(R) Pentium(R) M processor 1.70GHz"; String os = "Linux troy 2.6.10-gentoo-r6"; @@ -131,7 +131,7 @@ void test_rdataFromString() throws IOException { } @Test - void test_rdataFromString_invalid_CPU() throws IOException { + void rdataFromString_invalid_CPU() throws IOException { String cpu = "Intel(R) Pentium(R) \\388 M processor 1.70GHz"; String os = "Linux troy 2.6.10-gentoo-r6"; @@ -142,7 +142,7 @@ void test_rdataFromString_invalid_CPU() throws IOException { } @Test - void test_rdataFromString_invalid_OS() throws IOException { + void rdataFromString_invalid_OS() throws IOException { String cpu = "Intel(R) Pentium(R) M processor 1.70GHz"; Tokenizer t = new Tokenizer("\"" + cpu + "\""); @@ -152,7 +152,7 @@ void test_rdataFromString_invalid_OS() throws IOException { } @Test - void test_rrToString() throws TextParseException { + void rrToString() throws TextParseException { String cpu = "Intel(R) Pentium(R) M processor 1.70GHz"; String os = "Linux troy 2.6.10-gentoo-r6"; @@ -163,7 +163,7 @@ void test_rrToString() throws TextParseException { } @Test - void test_rrToWire() throws TextParseException { + void rrToWire() throws TextParseException { String cpu = "Intel(R) Pentium(R) M processor 1.70GHz"; String os = "Linux troy 2.6.10-gentoo-r6"; byte[] raw = diff --git a/src/test/java/org/xbill/DNS/HeaderTest.java b/src/test/java/org/xbill/DNS/HeaderTest.java index 2d9fcf2e8..8beed8e8f 100644 --- a/src/test/java/org/xbill/DNS/HeaderTest.java +++ b/src/test/java/org/xbill/DNS/HeaderTest.java @@ -53,7 +53,7 @@ void setUp() { } @Test - void test_fixture_state() { + void fixture_state() { assertEquals(0xABCD, m_h.getID()); boolean[] flags = m_h.getFlags(); @@ -69,7 +69,7 @@ void test_fixture_state() { } @Test - void test_ctor_0arg() { + void ctor_0arg() { m_h = new Header(); assertTrue(0 <= m_h.getID() && m_h.getID() < 0xFFFF); @@ -86,7 +86,7 @@ void test_ctor_0arg() { } @Test - void test_ctor_DNSInput() throws IOException { + void ctor_DNSInput() throws IOException { byte[] raw = new byte[] { (byte) 0x12, @@ -134,7 +134,7 @@ void test_ctor_DNSInput() throws IOException { } @Test - void test_toWire() throws IOException { + void toWire() throws IOException { byte[] raw = new byte[] { (byte) 0x12, @@ -181,7 +181,7 @@ void test_toWire() throws IOException { } @Test - void test_flags() { + void flags() { m_h.setFlag(0); m_h.setFlag(5); assertTrue(m_h.getFlag(0)); @@ -211,7 +211,7 @@ void test_flags() { } @Test - void test_flags_invalid() { + void flags_invalid() { assertThrows(IllegalArgumentException.class, () -> m_h.setFlag(-1)); assertThrows(IllegalArgumentException.class, () -> m_h.setFlag(1)); assertThrows(IllegalArgumentException.class, () -> m_h.setFlag(16)); @@ -224,7 +224,7 @@ void test_flags_invalid() { } @Test - void test_ID() { + void ID() { assertEquals(0xABCD, m_h.getID()); m_h = new Header(); @@ -238,13 +238,13 @@ void test_ID() { } @Test - void test_setID_invalid() { + void setID_invalid() { assertThrows(IllegalArgumentException.class, () -> m_h.setID(0x10000)); assertThrows(IllegalArgumentException.class, () -> m_h.setID(-1)); } @Test - void test_Rcode() { + void Rcode() { assertEquals(0, m_h.getRcode()); m_h.setRcode(0xA); // 1010 @@ -258,13 +258,13 @@ void test_Rcode() { } @Test - void test_setRcode_invalid() { + void setRcode_invalid() { assertThrows(IllegalArgumentException.class, () -> m_h.setRcode(-1)); assertThrows(IllegalArgumentException.class, () -> m_h.setRcode(0x100)); } @Test - void test_Opcode() { + void Opcode() { assertEquals(0, m_h.getOpcode()); m_h.setOpcode(0xE); // 1110 @@ -278,13 +278,13 @@ void test_Opcode() { } @Test - void test_setOpcode_invalid() { + void setOpcode_invalid() { assertThrows(IllegalArgumentException.class, () -> m_h.setOpcode(-1)); assertThrows(IllegalArgumentException.class, () -> m_h.setOpcode(0x100)); } @Test - void test_Count() { + void Count() { m_h.setCount(2, 0x1E); assertEquals(0, m_h.getCount(0)); assertEquals(0, m_h.getCount(1)); @@ -299,7 +299,7 @@ void test_Count() { } @Test - void test_setCount_invalid() { + void setCount_invalid() { assertThrows(ArrayIndexOutOfBoundsException.class, () -> m_h.setCount(-1, 0)); assertThrows(ArrayIndexOutOfBoundsException.class, () -> m_h.setCount(4, 0)); @@ -308,19 +308,19 @@ void test_setCount_invalid() { } @Test - void test_getCount_invalid() { + void getCount_invalid() { assertThrows(ArrayIndexOutOfBoundsException.class, () -> m_h.getCount(-1)); assertThrows(ArrayIndexOutOfBoundsException.class, () -> m_h.getCount(4)); } @Test - void test_incCount_invalid() { + void incCount_invalid() { m_h.setCount(1, 0xFFFF); assertThrows(IllegalStateException.class, () -> m_h.incCount(1)); } @Test - void test_decCount_invalid() { + void decCount_invalid() { m_h.setCount(2, 0); assertThrows(IllegalStateException.class, () -> m_h.decCount(2)); } diff --git a/src/test/java/org/xbill/DNS/KEYBaseTest.java b/src/test/java/org/xbill/DNS/KEYBaseTest.java index 0fbbf2a8c..a151c3e9e 100644 --- a/src/test/java/org/xbill/DNS/KEYBaseTest.java +++ b/src/test/java/org/xbill/DNS/KEYBaseTest.java @@ -62,7 +62,7 @@ void rdataFromString(Tokenizer st, Name origin) {} } @Test - void test_ctor() throws TextParseException { + void ctor() throws TextParseException { TestClass tc = new TestClass(); assertEquals(0, tc.getFlags()); assertEquals(0, tc.getProtocol()); @@ -86,7 +86,7 @@ void test_ctor() throws TextParseException { } @Test - void test_rrFromWire() throws IOException { + void rrFromWire() throws IOException { byte[] raw = new byte[] {(byte) 0xAB, (byte) 0xCD, (byte) 0xEF, (byte) 0x19, 1, 2, 3, 4, 5}; DNSInput in = new DNSInput(raw); @@ -111,7 +111,7 @@ void test_rrFromWire() throws IOException { } @Test - void test_rrToString() throws IOException { + void rrToString() throws IOException { Name n = Name.fromString("my.name."); byte[] key = new byte[] {0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}; @@ -135,7 +135,7 @@ void test_rrToString() throws IOException { } @Test - void test_getFootprint() throws TextParseException { + void getFootprint() throws TextParseException { Name n = Name.fromString("my.name."); byte[] key = new byte[] {0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}; @@ -166,7 +166,7 @@ void test_getFootprint() throws TextParseException { } @Test - void test_rrToWire() throws IOException { + void rrToWire() throws IOException { Name n = Name.fromString("my.name."); byte[] key = new byte[] {0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}; diff --git a/src/test/java/org/xbill/DNS/KEYRecordTest.java b/src/test/java/org/xbill/DNS/KEYRecordTest.java index eecea415c..94b4d5fe2 100644 --- a/src/test/java/org/xbill/DNS/KEYRecordTest.java +++ b/src/test/java/org/xbill/DNS/KEYRecordTest.java @@ -45,7 +45,7 @@ class KEYRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { KEYRecord ar = new KEYRecord(); assertNull(ar.getName()); assertEquals(0, ar.getType()); @@ -59,14 +59,14 @@ void test_ctor_0arg() { } @Test - void test_getObject() { + void getObject() { KEYRecord ar = new KEYRecord(); Record r = ar.getObject(); assertTrue(r instanceof KEYRecord); } @Test - void test_ctor_7arg() throws TextParseException { + void ctor_7arg() throws TextParseException { Name n = Name.fromString("My.Absolute.Name."); Name r = Name.fromString("My.Relative.Name"); byte[] key = new byte[] {0, 1, 3, 5, 7, 9}; @@ -88,7 +88,7 @@ void test_ctor_7arg() throws TextParseException { } @Test - void test_Protocol_string() { + void Protocol_string() { // a regular one assertEquals("DNSSEC", KEYRecord.Protocol.string(KEYRecord.Protocol.DNSSEC)); // a unassigned value within range @@ -100,7 +100,7 @@ void test_Protocol_string() { } @Test - void test_Protocol_value() { + void Protocol_value() { // a regular one assertEquals(KEYRecord.Protocol.IPSEC, KEYRecord.Protocol.value("IPSEC")); // a unassigned value within range @@ -112,7 +112,7 @@ void test_Protocol_value() { } @Test - void test_Flags_value() { + void Flags_value() { // numeric // lower bound @@ -141,7 +141,7 @@ void test_Flags_value() { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { // basic KEYRecord kr = new KEYRecord(); Tokenizer st = new Tokenizer("NOAUTH|ZONE|FLAG10 EMAIL RSASHA1 AQIDBAUGBwgJ"); diff --git a/src/test/java/org/xbill/DNS/KXRecordTest.java b/src/test/java/org/xbill/DNS/KXRecordTest.java index 42cbd748f..fd6d2ddf8 100644 --- a/src/test/java/org/xbill/DNS/KXRecordTest.java +++ b/src/test/java/org/xbill/DNS/KXRecordTest.java @@ -41,14 +41,14 @@ class KXRecordTest { @Test - void test_getObject() { + void getObject() { KXRecord d = new KXRecord(); Record r = d.getObject(); assertTrue(r instanceof KXRecord); } @Test - void test_ctor_5arg() throws TextParseException { + void ctor_5arg() throws TextParseException { Name n = Name.fromString("My.Name."); Name m = Name.fromString("My.OtherName."); diff --git a/src/test/java/org/xbill/DNS/MBRecordTest.java b/src/test/java/org/xbill/DNS/MBRecordTest.java index 6e9c6c2dd..b473e8b86 100644 --- a/src/test/java/org/xbill/DNS/MBRecordTest.java +++ b/src/test/java/org/xbill/DNS/MBRecordTest.java @@ -42,7 +42,7 @@ class MBRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { MBRecord d = new MBRecord(); assertNull(d.getName()); assertNull(d.getAdditionalName()); @@ -50,7 +50,7 @@ void test_ctor_0arg() { } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("my.name."); Name a = Name.fromString("my.alias."); @@ -64,7 +64,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_getObject() { + void getObject() { MBRecord d = new MBRecord(); Record r = d.getObject(); assertTrue(r instanceof MBRecord); diff --git a/src/test/java/org/xbill/DNS/MDRecordTest.java b/src/test/java/org/xbill/DNS/MDRecordTest.java index 774ccd1e9..ab5d570de 100644 --- a/src/test/java/org/xbill/DNS/MDRecordTest.java +++ b/src/test/java/org/xbill/DNS/MDRecordTest.java @@ -42,7 +42,7 @@ class MDRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { MDRecord d = new MDRecord(); assertNull(d.getName()); assertNull(d.getAdditionalName()); @@ -50,7 +50,7 @@ void test_ctor_0arg() { } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("my.name."); Name a = Name.fromString("my.alias."); @@ -64,7 +64,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_getObject() { + void getObject() { MDRecord d = new MDRecord(); Record r = d.getObject(); assertTrue(r instanceof MDRecord); diff --git a/src/test/java/org/xbill/DNS/MFRecordTest.java b/src/test/java/org/xbill/DNS/MFRecordTest.java index 56d926e56..a0ee6acb1 100644 --- a/src/test/java/org/xbill/DNS/MFRecordTest.java +++ b/src/test/java/org/xbill/DNS/MFRecordTest.java @@ -42,7 +42,7 @@ class MFRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { MFRecord d = new MFRecord(); assertNull(d.getName()); assertNull(d.getAdditionalName()); @@ -50,7 +50,7 @@ void test_ctor_0arg() { } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("my.name."); Name a = Name.fromString("my.alias."); @@ -64,7 +64,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_getObject() { + void getObject() { MFRecord d = new MFRecord(); Record r = d.getObject(); assertTrue(r instanceof MFRecord); diff --git a/src/test/java/org/xbill/DNS/MGRecordTest.java b/src/test/java/org/xbill/DNS/MGRecordTest.java index 1f9ee3ad8..8fe0c35e6 100644 --- a/src/test/java/org/xbill/DNS/MGRecordTest.java +++ b/src/test/java/org/xbill/DNS/MGRecordTest.java @@ -42,14 +42,14 @@ class MGRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { MGRecord d = new MGRecord(); assertNull(d.getName()); assertNull(d.getMailbox()); } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("my.name."); Name a = Name.fromString("my.alias."); @@ -62,7 +62,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_getObject() { + void getObject() { MGRecord d = new MGRecord(); Record r = d.getObject(); assertTrue(r instanceof MGRecord); diff --git a/src/test/java/org/xbill/DNS/MRRecordTest.java b/src/test/java/org/xbill/DNS/MRRecordTest.java index 086d516e8..535d7e851 100644 --- a/src/test/java/org/xbill/DNS/MRRecordTest.java +++ b/src/test/java/org/xbill/DNS/MRRecordTest.java @@ -42,14 +42,14 @@ class MRRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { MRRecord d = new MRRecord(); assertNull(d.getName()); assertNull(d.getNewName()); } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("my.name."); Name a = Name.fromString("my.alias."); @@ -62,7 +62,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_getObject() { + void getObject() { MRRecord d = new MRRecord(); Record r = d.getObject(); assertTrue(r instanceof MRRecord); diff --git a/src/test/java/org/xbill/DNS/MXRecordTest.java b/src/test/java/org/xbill/DNS/MXRecordTest.java index 1f48a6ae7..e4f4a69c1 100644 --- a/src/test/java/org/xbill/DNS/MXRecordTest.java +++ b/src/test/java/org/xbill/DNS/MXRecordTest.java @@ -43,14 +43,14 @@ class MXRecordTest { @Test - void test_getObject() { + void getObject() { MXRecord d = new MXRecord(); Record r = d.getObject(); assertTrue(r instanceof MXRecord); } @Test - void test_ctor_5arg() throws TextParseException { + void ctor_5arg() throws TextParseException { Name n = Name.fromString("My.Name."); Name m = Name.fromString("My.OtherName."); @@ -65,7 +65,7 @@ void test_ctor_5arg() throws TextParseException { } @Test - void test_rrToWire() throws TextParseException { + void rrToWire() throws TextParseException { Name n = Name.fromString("My.Name."); Name m = Name.fromString("M.O.n."); diff --git a/src/test/java/org/xbill/DNS/MessageTest.java b/src/test/java/org/xbill/DNS/MessageTest.java index fa33b7617..0684eb3fd 100644 --- a/src/test/java/org/xbill/DNS/MessageTest.java +++ b/src/test/java/org/xbill/DNS/MessageTest.java @@ -47,7 +47,7 @@ public class MessageTest { static class Test_init { @Test - void test_0arg() { + void ctor_0arg() { Message m = new Message(); assertArrayEquals(new Record[0], m.getSectionArray(0)); assertArrayEquals(new Record[0], m.getSectionArray(1)); @@ -62,7 +62,7 @@ void test_0arg() { } @Test - void test_1arg() { + void ctor_1arg() { Message m = new Message(10); assertEquals(new Header(10).toString(), m.getHeader().toString()); assertArrayEquals(new Record[0], m.getSectionArray(0)); @@ -78,7 +78,7 @@ void test_1arg() { } @Test - void test_newQuery() throws TextParseException, UnknownHostException { + void newQuery() throws TextParseException, UnknownHostException { Name n = Name.fromString("The.Name."); ARecord ar = new ARecord(n, DClass.IN, 1, InetAddress.getByName("192.168.101.110")); @@ -98,7 +98,7 @@ void test_newQuery() throws TextParseException, UnknownHostException { } @Test - void test_sectionToWire() throws IOException { + void sectionToWire() throws IOException { Message m = new Message(4711); Name n2 = Name.fromConstantString("test2.example."); m.addRecord(new TXTRecord(n2, DClass.IN, 86400, "other record"), Section.ADDITIONAL); diff --git a/src/test/java/org/xbill/DNS/MnemonicTest.java b/src/test/java/org/xbill/DNS/MnemonicTest.java index c58e6e05c..34130b393 100644 --- a/src/test/java/org/xbill/DNS/MnemonicTest.java +++ b/src/test/java/org/xbill/DNS/MnemonicTest.java @@ -52,7 +52,7 @@ void setUp() { } @Test - void test_no_maximum() { + void no_maximum() { assertThrows(IllegalArgumentException.class, () -> m_mn.check(-1)); try { m_mn.check(0); @@ -78,7 +78,7 @@ void test_no_maximum() { } @Test - void test_setMaximum() { + void setMaximum() { m_mn.setMaximum(15); assertThrows(IllegalArgumentException.class, () -> m_mn.check(-1)); try { @@ -110,7 +110,7 @@ void test_setMaximum() { } @Test - void test_setPrefix() { + void setPrefix() { final String prefix = "A mixed CASE Prefix".toUpperCase(); m_mn.setPrefix(prefix); @@ -122,7 +122,7 @@ void test_setPrefix() { } @Test - void test_basic_operation() { + void basic_operation() { // setUp creates Mnemonic with CASE_UPPER m_mn.add(10, "Ten"); m_mn.add(20, "Twenty"); @@ -155,7 +155,7 @@ void test_basic_operation() { } @Test - void test_basic_operation_lower() { + void basic_operation_lower() { m_mn = new Mnemonic(MnemonicTest.class.getName() + " LOWER", Mnemonic.CASE_LOWER); m_mn.add(10, "Ten"); m_mn.add(20, "Twenty"); @@ -188,7 +188,7 @@ void test_basic_operation_lower() { } @Test - void test_basic_operation_sensitive() { + void basic_operation_sensitive() { m_mn = new Mnemonic(MnemonicTest.class.getName() + " SENSITIVE", Mnemonic.CASE_SENSITIVE); m_mn.add(10, "Ten"); m_mn.add(20, "Twenty"); @@ -227,14 +227,14 @@ void test_basic_operation_sensitive() { } @Test - void test_invalid_numeric() { + void invalid_numeric() { m_mn.setNumericAllowed(true); int value = m_mn.getValue("Not-A-Number"); assertEquals(-1, value); } @Test - void test_addAll() { + void addAll() { m_mn.add(10, "Ten"); m_mn.add(20, "Twenty"); diff --git a/src/test/java/org/xbill/DNS/NSAP_PTRRecordTest.java b/src/test/java/org/xbill/DNS/NSAP_PTRRecordTest.java index 8b94f40ab..689a2c7c6 100644 --- a/src/test/java/org/xbill/DNS/NSAP_PTRRecordTest.java +++ b/src/test/java/org/xbill/DNS/NSAP_PTRRecordTest.java @@ -43,14 +43,14 @@ class NSAP_PTRRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { NSAP_PTRRecord d = new NSAP_PTRRecord(); assertNull(d.getName()); assertNull(d.getTarget()); } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("my.name."); Name a = Name.fromString("my.alias."); @@ -63,7 +63,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_getObject() { + void getObject() { NSAP_PTRRecord d = new NSAP_PTRRecord(); Record r = d.getObject(); assertTrue(r instanceof NSAP_PTRRecord); diff --git a/src/test/java/org/xbill/DNS/NSRecordTest.java b/src/test/java/org/xbill/DNS/NSRecordTest.java index d9bcc3027..12c7c0918 100644 --- a/src/test/java/org/xbill/DNS/NSRecordTest.java +++ b/src/test/java/org/xbill/DNS/NSRecordTest.java @@ -42,7 +42,7 @@ class NSRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { NSRecord d = new NSRecord(); assertNull(d.getName()); assertNull(d.getTarget()); @@ -50,7 +50,7 @@ void test_ctor_0arg() { } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("my.name."); Name a = Name.fromString("my.alias."); @@ -64,7 +64,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_getObject() { + void getObject() { NSRecord d = new NSRecord(); Record r = d.getObject(); assertTrue(r instanceof NSRecord); diff --git a/src/test/java/org/xbill/DNS/NameTest.java b/src/test/java/org/xbill/DNS/NameTest.java index 34fe542b0..c9bacddc4 100644 --- a/src/test/java/org/xbill/DNS/NameTest.java +++ b/src/test/java/org/xbill/DNS/NameTest.java @@ -62,12 +62,12 @@ void setUp() throws TextParseException { } @Test - void test_ctor_empty() { + void ctor_empty() { assertThrows(TextParseException.class, () -> new Name("")); } @Test - void test_ctor_at_null_origin() throws TextParseException { + void ctor_at_null_origin() throws TextParseException { Name n = new Name("@"); assertFalse(n.isAbsolute()); assertFalse(n.isWild()); @@ -76,19 +76,19 @@ void test_ctor_at_null_origin() throws TextParseException { } @Test - void test_ctor_at_abs_origin() throws TextParseException { + void ctor_at_abs_origin() throws TextParseException { Name n = new Name("@", m_abs_origin); assertEquals(m_abs_origin, n); } @Test - void test_ctor_at_rel_origin() throws TextParseException { + void ctor_at_rel_origin() throws TextParseException { Name n = new Name("@", m_rel_origin); assertEquals(m_rel_origin, n); } @Test - void test_ctor_dot() throws TextParseException { + void ctor_dot() throws TextParseException { Name n = new Name("."); assertEquals(Name.root, n); assertNotSame(Name.root, n); @@ -97,7 +97,7 @@ void test_ctor_dot() throws TextParseException { } @Test - void test_ctor_wildcard() throws TextParseException { + void ctor_wildcard() throws TextParseException { Name n = new Name("*"); assertFalse(n.isAbsolute()); assertTrue(n.isWild()); @@ -108,7 +108,7 @@ void test_ctor_wildcard() throws TextParseException { } @Test - void test_ctor_abs() throws TextParseException { + void ctor_abs() throws TextParseException { Name n = new Name(m_abs); assertTrue(n.isAbsolute()); assertFalse(n.isWild()); @@ -125,7 +125,7 @@ void test_ctor_abs() throws TextParseException { } @Test - void test_ctor_rel() throws TextParseException { + void ctor_rel() throws TextParseException { Name n = new Name(m_rel); assertFalse(n.isAbsolute()); assertFalse(n.isWild()); @@ -138,7 +138,7 @@ void test_ctor_rel() throws TextParseException { } @Test - void test_ctor_7label() throws TextParseException { + void ctor_7label() throws TextParseException { // 7 is the number of label positions that are cached Name n = new Name("a.b.c.d.e.f."); assertTrue(n.isAbsolute()); @@ -162,7 +162,7 @@ void test_ctor_7label() throws TextParseException { } @Test - void test_ctor_8label() throws TextParseException { + void ctor_8label() throws TextParseException { // 7 is the number of label positions that are cached Name n = new Name("a.b.c.d.e.f.g."); assertTrue(n.isAbsolute()); @@ -188,7 +188,7 @@ void test_ctor_8label() throws TextParseException { } @Test - void test_ctor_removed_label() throws TextParseException, NameTooLongException { + void ctor_removed_label() throws TextParseException, NameTooLongException { String pre = "prepend"; Name stripped = new Name(Name.fromString("sub.domain.example."), 1); Name concat = new Name(pre, stripped); @@ -198,7 +198,7 @@ void test_ctor_removed_label() throws TextParseException, NameTooLongException { } @Test - void test_ctor_abs_abs_origin() throws TextParseException { + void ctor_abs_abs_origin() throws TextParseException { Name n = new Name(m_abs, m_abs_origin); assertTrue(n.isAbsolute()); assertFalse(n.isWild()); @@ -215,7 +215,7 @@ void test_ctor_abs_abs_origin() throws TextParseException { } @Test - void test_ctor_abs_rel_origin() throws TextParseException { + void ctor_abs_rel_origin() throws TextParseException { Name n = new Name(m_abs, m_rel_origin); assertTrue(n.isAbsolute()); assertFalse(n.isWild()); @@ -232,7 +232,7 @@ void test_ctor_abs_rel_origin() throws TextParseException { } @Test - void test_ctor_rel_abs_origin() throws TextParseException { + void ctor_rel_abs_origin() throws TextParseException { Name n = new Name(m_rel, m_abs_origin); assertTrue(n.isAbsolute()); assertFalse(n.isWild()); @@ -249,12 +249,12 @@ void test_ctor_rel_abs_origin() throws TextParseException { } @Test - void test_ctor_invalid_label() { + void ctor_invalid_label() { assertThrows(TextParseException.class, () -> new Name("junk..junk.")); } @Test - void test_ctor_max_label() throws TextParseException { + void ctor_max_label() throws TextParseException { // name with a 63 char label Name n = new Name("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b."); assertTrue(n.isAbsolute()); @@ -278,7 +278,7 @@ void test_ctor_max_label() throws TextParseException { } @Test - void test_ctor_toobig_label() { + void ctor_toobig_label() { // name with a 64 char label assertThrows( TextParseException.class, @@ -286,7 +286,7 @@ void test_ctor_toobig_label() { } @Test - void test_ctor_max_length_rel() throws TextParseException { + void ctor_max_length_rel() throws TextParseException { // relative name with three 63-char labels and a 62-char label Name n = new Name( @@ -298,7 +298,7 @@ void test_ctor_max_length_rel() throws TextParseException { } @Test - void test_ctor_max_length_abs() throws TextParseException { + void ctor_max_length_abs() throws TextParseException { // absolute name with three 63-char labels and a 61-char label Name n = new Name( @@ -310,7 +310,7 @@ void test_ctor_max_length_abs() throws TextParseException { } @Test - void test_ctor_escaped() throws TextParseException { + void ctor_escaped() throws TextParseException { Name n = new Name("ab\\123cd"); assertFalse(n.isAbsolute()); assertFalse(n.isWild()); @@ -320,7 +320,7 @@ void test_ctor_escaped() throws TextParseException { } @Test - void test_ctor_escaped_end() throws TextParseException { + void ctor_escaped_end() throws TextParseException { Name n = new Name("abcd\\123"); assertFalse(n.isAbsolute()); assertFalse(n.isWild()); @@ -330,32 +330,32 @@ void test_ctor_escaped_end() throws TextParseException { } @Test - void test_ctor_short_escaped() { + void ctor_short_escaped() { assertThrows(TextParseException.class, () -> new Name("ab\\12cd")); } @Test - void test_ctor_short_escaped_end() { + void ctor_short_escaped_end() { assertThrows(TextParseException.class, () -> new Name("ab\\12")); } @Test - void test_ctor_empty_escaped_end() { + void ctor_empty_escaped_end() { assertThrows(TextParseException.class, () -> new Name("ab\\")); } @Test - void test_ctor_toobig_escaped() { + void ctor_toobig_escaped() { assertThrows(TextParseException.class, () -> new Name("ab\\256cd")); } @Test - void test_ctor_toobig_escaped_end() { + void ctor_toobig_escaped_end() { assertThrows(TextParseException.class, () -> new Name("ab\\256")); } @Test - void test_ctor_max_label_escaped() throws TextParseException { + void ctor_max_label_escaped() throws TextParseException { // name with a 63 char label containing an escape Name n = new Name("aaaa\\100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b."); assertTrue(n.isAbsolute()); @@ -437,7 +437,7 @@ void test_ctor_max_label_escaped() throws TextParseException { } @Test - void test_ctor_max_labels() throws TextParseException { + void ctor_max_labels() throws TextParseException { StringBuilder sb = new StringBuilder(); for (int i = 0; i < 127; ++i) { sb.append("a."); @@ -456,7 +456,7 @@ void test_ctor_max_labels() throws TextParseException { } @Test - void test_ctor_toobig_label_escaped_end() { + void ctor_toobig_label_escaped_end() { assertThrows( TextParseException.class, () -> @@ -464,7 +464,7 @@ void test_ctor_toobig_label_escaped_end() { } @Test - void test_ctor_toobig_label_escaped() { + void ctor_toobig_label_escaped() { assertThrows( TextParseException.class, () -> @@ -472,40 +472,40 @@ void test_ctor_toobig_label_escaped() { } @Test - void test_fromString() throws TextParseException { + void fromString() throws TextParseException { Name n = new Name(m_rel, m_abs_origin); Name n2 = Name.fromString(m_rel, m_abs_origin); assertEquals(n, n2); } @Test - void test_fromString_at() throws TextParseException { + void fromString_at() throws TextParseException { Name n = Name.fromString("@", m_rel_origin); assertSame(m_rel_origin, n); } @Test - void test_fromString_dot() throws TextParseException { + void fromString_dot() throws TextParseException { Name n = Name.fromString("."); assertSame(Name.root, n); } @Test - void test_fromConstantString() throws TextParseException { + void fromConstantString() throws TextParseException { Name n = new Name(m_abs); Name n2 = Name.fromConstantString(m_abs); assertEquals(n, n2); } @Test - void test_fromConstantString_invalid() { + void fromConstantString_invalid() { assertThrows(IllegalArgumentException.class, () -> Name.fromConstantString("junk..junk")); } } static class Test_DNSInput_init { @Test - void test_basic() throws IOException { + void basic() throws IOException { final byte[] raw = new byte[] {3, 'W', 'w', 'w', 7, 'D', 'n', 's', 'J', 'a', 'v', 'a', 3, 'o', 'r', 'g', 0}; @@ -516,24 +516,24 @@ void test_basic() throws IOException { } @Test - void test_incomplete() throws IOException { + void incomplete() throws IOException { assertThrows(WireParseException.class, () -> new Name(new byte[] {3, 'W', 'w', 'w'})); } @Test - void test_root() throws WireParseException { + void root() throws WireParseException { final byte[] raw = new byte[] {0}; Name n = new Name(new DNSInput(raw)); assertEquals(Name.root, n); } @Test - void test_invalid_length() throws IOException { + void invalid_length() throws IOException { assertThrows(WireParseException.class, () -> new Name(new byte[] {4, 'W', 'w', 'w'})); } @Test - void test_max_label_length() throws TextParseException, WireParseException { + void max_label_length() throws TextParseException, WireParseException { byte[] raw = new byte[] { 63, 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', @@ -548,7 +548,7 @@ void test_max_label_length() throws TextParseException, WireParseException { } @Test - void test_max_name() throws TextParseException, WireParseException { + void max_name() throws TextParseException, WireParseException { // absolute name with three 63-char labels and a 61-char label Name e = new Name( @@ -577,7 +577,7 @@ void test_max_name() throws TextParseException, WireParseException { } @Test - void test_toolong_name() { + void toolong_name() { // absolute name with three 63-char labels and a 62-char label byte[] raw = new byte[] { @@ -602,7 +602,7 @@ void test_toolong_name() { } @Test - void test_max_labels() throws TextParseException, WireParseException { + void max_labels() throws TextParseException, WireParseException { byte[] raw = new byte[] { 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', @@ -627,7 +627,7 @@ void test_max_labels() throws TextParseException, WireParseException { } @Test - void test_toomany_labels() { + void toomany_labels() { byte[] raw = new byte[] { 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', @@ -647,7 +647,7 @@ void test_toomany_labels() { } @Test - void test_basic_compression() throws TextParseException, WireParseException { + void basic_compression() throws TextParseException, WireParseException { byte[] raw = new byte[] {10, 3, 'a', 'b', 'c', 0, (byte) 0xC0, 1}; Name e = Name.fromString("abc."); @@ -659,7 +659,7 @@ void test_basic_compression() throws TextParseException, WireParseException { } @Test - void test_two_pointer_compression() throws TextParseException, WireParseException { + void two_pointer_compression() throws TextParseException, WireParseException { byte[] raw = new byte[] {10, 3, 'a', 'b', 'c', 0, (byte) 0xC0, 1, (byte) 0xC0, 6}; Name e = Name.fromString("abc."); @@ -671,7 +671,7 @@ void test_two_pointer_compression() throws TextParseException, WireParseExceptio } @Test - void test_two_part_compression() throws TextParseException, WireParseException { + void two_part_compression() throws TextParseException, WireParseException { byte[] raw = new byte[] {10, 3, 'a', 'b', 'c', 0, 1, 'B', (byte) 0xC0, 1}; Name e = Name.fromString("B.abc."); @@ -683,7 +683,7 @@ void test_two_part_compression() throws TextParseException, WireParseException { } @Test - void test_long_jump_compression() throws TextParseException, WireParseException { + void long_jump_compression() throws TextParseException, WireParseException { // pointer to name beginning at index 256 byte[] raw = new byte[] { @@ -960,13 +960,13 @@ void test_long_jump_compression() throws TextParseException, WireParseException } @Test - void test_bad_compression() { + void bad_compression() { byte[] raw = new byte[] {(byte) 0xC0, 2, 0}; assertThrows(WireParseException.class, () -> new Name(new DNSInput(raw))); } @Test - void test_basic_compression_state_restore() throws TextParseException, WireParseException { + void basic_compression_state_restore() throws TextParseException, WireParseException { byte[] raw = new byte[] {10, 3, 'a', 'b', 'c', 0, (byte) 0xC0, 1, 3, 'd', 'e', 'f', 0}; Name e = Name.fromString("abc."); Name e2 = Name.fromString("def."); @@ -982,7 +982,7 @@ void test_basic_compression_state_restore() throws TextParseException, WireParse } @Test - void test_two_part_compression_state_restore() throws TextParseException, WireParseException { + void two_part_compression_state_restore() throws TextParseException, WireParseException { byte[] raw = new byte[] {10, 3, 'a', 'b', 'c', 0, 1, 'B', (byte) 0xC0, 1, 3, 'd', 'e', 'f', 0}; Name e = Name.fromString("B.abc."); @@ -1000,7 +1000,7 @@ void test_two_part_compression_state_restore() throws TextParseException, WirePa } @Test - void test_init_from_name() throws TextParseException { + void init_from_name() throws TextParseException { Name n = new Name("A.B.c.d."); Name e = new Name("B.c.d."); Name o = new Name(n, 1); @@ -1008,14 +1008,14 @@ void test_init_from_name() throws TextParseException { } @Test - void test_init_from_name_root() throws TextParseException { + void init_from_name_root() throws TextParseException { Name n = new Name("A.B.c.d."); Name o = new Name(n, 4); assertEquals(Name.root, o); } @Test - void test_init_from_name_empty() throws TextParseException { + void init_from_name_empty() throws TextParseException { Name n = new Name("A.B.c.d."); Name n2 = new Name(n, 5); @@ -1026,7 +1026,7 @@ void test_init_from_name_empty() throws TextParseException { } @Test - void test_concatenate_basic() throws NameTooLongException, TextParseException { + void concatenate_basic() throws NameTooLongException, TextParseException { Name p = Name.fromString("A.B"); Name s = Name.fromString("c.d."); Name e = Name.fromString("A.B.c.d."); @@ -1036,7 +1036,7 @@ void test_concatenate_basic() throws NameTooLongException, TextParseException { } @Test - void test_concatenate_abs_prefix() throws NameTooLongException, TextParseException { + void concatenate_abs_prefix() throws NameTooLongException, TextParseException { Name p = Name.fromString("A.B."); Name s = Name.fromString("c.d."); Name e = Name.fromString("A.B."); @@ -1046,7 +1046,7 @@ void test_concatenate_abs_prefix() throws NameTooLongException, TextParseExcepti } @Test - void test_concatenate_too_long() throws TextParseException { + void concatenate_too_long() throws TextParseException { Name p = Name.fromString( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); @@ -1058,7 +1058,7 @@ void test_concatenate_too_long() throws TextParseException { } @Test - void test_relativize() throws TextParseException { + void relativize() throws TextParseException { Name sub = Name.fromString("a.b.c."); Name dom = Name.fromString("c."); Name exp = Name.fromString("a.b"); @@ -1068,7 +1068,7 @@ void test_relativize() throws TextParseException { } @Test - void test_relativize_null_origin() throws TextParseException { + void relativize_null_origin() throws TextParseException { Name sub = Name.fromString("a.b.c."); Name dom = null; @@ -1077,7 +1077,7 @@ void test_relativize_null_origin() throws TextParseException { } @Test - void test_relativize_disjoint() throws TextParseException { + void relativize_disjoint() throws TextParseException { Name sub = Name.fromString("a.b.c."); Name dom = Name.fromString("e.f."); @@ -1086,7 +1086,7 @@ void test_relativize_disjoint() throws TextParseException { } @Test - void test_relativize_root() throws TextParseException { + void relativize_root() throws TextParseException { Name sub = Name.fromString("a.b.c."); Name dom = Name.fromString("."); Name exp = Name.fromString("a.b.c"); @@ -1096,7 +1096,7 @@ void test_relativize_root() throws TextParseException { } @Test - void test_wild() throws TextParseException { + void wild() throws TextParseException { Name sub = Name.fromString("a.b.c."); Name exp = Name.fromString("*.b.c."); @@ -1105,7 +1105,7 @@ void test_wild() throws TextParseException { } @Test - void test_wild_abs() throws TextParseException { + void wild_abs() throws TextParseException { Name sub = Name.fromString("a.b.c."); Name exp = Name.fromString("*."); @@ -1114,19 +1114,19 @@ void test_wild_abs() throws TextParseException { } @Test - void test_wild_toobig() throws TextParseException { + void wild_toobig() throws TextParseException { Name sub = Name.fromString("a.b.c."); assertThrows(IllegalArgumentException.class, () -> sub.wild(4)); } @Test - void test_wild_toosmall() throws TextParseException { + void wild_toosmall() throws TextParseException { Name sub = Name.fromString("a.b.c."); assertThrows(IllegalArgumentException.class, () -> sub.wild(0)); } @Test - void test_fromDNAME() throws NameTooLongException, TextParseException { + void fromDNAME() throws NameTooLongException, TextParseException { Name own = new Name("the.owner."); Name alias = new Name("the.alias."); DNAMERecord dnr = new DNAMERecord(own, DClass.IN, 0xABCD, alias); @@ -1138,7 +1138,7 @@ void test_fromDNAME() throws NameTooLongException, TextParseException { } @Test - void test_fromDNAME_toobig() throws TextParseException { + void fromDNAME_toobig() throws TextParseException { Name own = new Name("the.owner."); Name alias = new Name( @@ -1151,7 +1151,7 @@ void test_fromDNAME_toobig() throws TextParseException { } @Test - void test_fromDNAME_disjoint() throws NameTooLongException, TextParseException { + void fromDNAME_disjoint() throws NameTooLongException, TextParseException { Name own = new Name("the.owner."); Name alias = new Name("the.alias."); DNAMERecord dnr = new DNAMERecord(own, DClass.IN, 0xABCD, alias); @@ -1162,7 +1162,7 @@ void test_fromDNAME_disjoint() throws NameTooLongException, TextParseException { } @Test - void test_subdomain_abs() throws TextParseException { + void subdomain_abs() throws TextParseException { Name dom = new Name("the.domain."); Name sub = new Name("sub.of.the.domain."); assertTrue(sub.subdomain(dom)); @@ -1170,7 +1170,7 @@ void test_subdomain_abs() throws TextParseException { } @Test - void test_subdomain_rel() throws TextParseException { + void subdomain_rel() throws TextParseException { Name dom = new Name("the.domain"); Name sub = new Name("sub.of.the.domain"); assertTrue(sub.subdomain(dom)); @@ -1178,7 +1178,7 @@ void test_subdomain_rel() throws TextParseException { } @Test - void test_subdomain_equal() throws TextParseException { + void subdomain_equal() throws TextParseException { Name dom = new Name("the.domain"); Name sub = new Name("the.domain"); assertTrue(sub.subdomain(dom)); @@ -1186,7 +1186,7 @@ void test_subdomain_equal() throws TextParseException { } @Test - void test_toString_abs() throws TextParseException { + void toString_abs() throws TextParseException { String in = "This.Is.My.Absolute.Name."; Name n = new Name(in); @@ -1194,7 +1194,7 @@ void test_toString_abs() throws TextParseException { } @Test - void test_toString_rel() throws TextParseException { + void toString_rel() throws TextParseException { String in = "This.Is.My.Relative.Name"; Name n = new Name(in); @@ -1202,32 +1202,32 @@ void test_toString_rel() throws TextParseException { } @Test - void test_toString_at() throws TextParseException { + void toString_at() throws TextParseException { Name n = new Name("@", null); assertEquals("@", n.toString()); } @Test - void test_toString_root() { + void toString_root() { assertEquals(".", Name.root.toString()); } @Test - void test_toString_wild() throws TextParseException { + void toString_wild() throws TextParseException { String in = "*.A.b.c.e"; Name n = new Name(in); assertEquals(in, n.toString()); } @Test - void test_toString_escaped() throws TextParseException { + void toString_escaped() throws TextParseException { String in = "my.escaped.junk\\128.label."; Name n = new Name(in); assertEquals(in, n.toString()); } @Test - void test_toString_special_char() throws WireParseException { + void toString_special_char() throws WireParseException { byte[] raw = new byte[] {1, '"', 1, '(', 1, ')', 1, '.', 1, ';', 1, '\\', 1, '@', 1, '$', 0}; String exp = "\\\".\\(.\\).\\..\\;.\\\\.\\@.\\$."; Name n = new Name(new DNSInput(raw)); @@ -1236,13 +1236,13 @@ void test_toString_special_char() throws WireParseException { static class Test_toWire { @Test - void test_rel() throws TextParseException { + void rel() throws TextParseException { Name n = new Name("A.Relative.Name"); assertThrows(IllegalArgumentException.class, () -> n.toWire(new DNSOutput(), null)); } @Test - void test_null_Compression() throws TextParseException { + void null_Compression() throws TextParseException { byte[] raw = new byte[] {1, 'A', 5, 'B', 'a', 's', 'i', 'c', 4, 'N', 'a', 'm', 'e', 0}; Name n = new Name("A.Basic.Name."); @@ -1253,7 +1253,7 @@ void test_null_Compression() throws TextParseException { } @Test - void test_empty_Compression() throws TextParseException { + void empty_Compression() throws TextParseException { byte[] raw = new byte[] {1, 'A', 5, 'B', 'a', 's', 'i', 'c', 4, 'N', 'a', 'm', 'e', 0}; Name n = new Name("A.Basic.Name."); @@ -1266,7 +1266,7 @@ void test_empty_Compression() throws TextParseException { } @Test - void test_with_exact_Compression() throws TextParseException { + void with_exact_Compression() throws TextParseException { Name n = new Name("A.Basic.Name."); Compression c = new Compression(); @@ -1280,7 +1280,7 @@ void test_with_exact_Compression() throws TextParseException { } @Test - void test_with_partial_Compression() throws TextParseException { + void with_partial_Compression() throws TextParseException { Name d = new Name("Basic.Name."); Name n = new Name("A.Basic.Name."); @@ -1296,13 +1296,13 @@ void test_with_partial_Compression() throws TextParseException { } @Test - void test_0arg_rel() throws TextParseException { + void ctor_0arg_rel() throws TextParseException { Name n = new Name("A.Relative.Name"); assertThrows(IllegalArgumentException.class, () -> n.toWire()); } @Test - void test_0arg() throws TextParseException { + void ctor_0arg() throws TextParseException { byte[] raw = new byte[] {1, 'A', 5, 'B', 'a', 's', 'i', 'c', 4, 'N', 'a', 'm', 'e', 0}; Name n = new Name("A.Basic.Name."); @@ -1312,13 +1312,13 @@ void test_0arg() throws TextParseException { } @Test - void test_root() { + void root() { byte[] out = Name.root.toWire(); assertArrayEquals(new byte[] {0}, out); } @Test - void test_3arg() throws TextParseException { + void ctor_3arg() throws TextParseException { Name d = new Name("Basic.Name."); Name n = new Name("A.Basic.Name."); @@ -1336,7 +1336,7 @@ void test_3arg() throws TextParseException { static class Test_toWireCanonical { @Test - void test_basic() throws TextParseException { + void basic() throws TextParseException { byte[] raw = new byte[] {1, 'a', 5, 'b', 'a', 's', 'i', 'c', 4, 'n', 'a', 'm', 'e', 0}; Name n = new Name("A.Basic.Name."); @@ -1347,7 +1347,7 @@ void test_basic() throws TextParseException { } @Test - void test_0arg() throws TextParseException { + void ctor_0arg() throws TextParseException { byte[] raw = new byte[] {1, 'a', 5, 'b', 'a', 's', 'i', 'c', 4, 'n', 'a', 'm', 'e', 0}; Name n = new Name("A.Basic.Name."); @@ -1357,20 +1357,20 @@ void test_0arg() throws TextParseException { } @Test - void test_root() { + void root() { byte[] out = Name.root.toWireCanonical(); assertArrayEquals(new byte[] {0}, out); } @Test - void test_empty() throws TextParseException { + void empty() throws TextParseException { Name n = new Name("@", null); byte[] out = n.toWireCanonical(); assertArrayEquals(new byte[0], out); } @Test - void test_3arg() throws TextParseException { + void ctor_3arg() throws TextParseException { Name d = new Name("Basic.Name."); Name n = new Name("A.Basic.Name."); @@ -1388,7 +1388,7 @@ void test_3arg() throws TextParseException { static class Test_equals { @Test - void test_same() throws TextParseException { + void same() throws TextParseException { Name n = new Name("A.Name."); assertEquals(n, n); } @@ -1400,13 +1400,13 @@ void test_null() throws TextParseException { } @Test - void test_notName() throws TextParseException { + void notName() throws TextParseException { Name n = new Name("A.Name."); assertNotEquals(n, new Object()); } @Test - void test_abs() throws TextParseException { + void abs() throws TextParseException { Name n = new Name("A.Name."); Name n2 = new Name("a.name."); @@ -1415,7 +1415,7 @@ void test_abs() throws TextParseException { } @Test - void test_rel() throws TextParseException { + void rel() throws TextParseException { Name n1 = new Name("A.Relative.Name"); Name n2 = new Name("a.relative.name"); @@ -1424,7 +1424,7 @@ void test_rel() throws TextParseException { } @Test - void test_mixed() throws TextParseException { + void mixed() throws TextParseException { Name n1 = new Name("A.Name"); Name n2 = new Name("a.name."); @@ -1433,7 +1433,7 @@ void test_mixed() throws TextParseException { } @Test - void test_weird() throws TextParseException { + void weird() throws TextParseException { Name n1 = new Name("ab.c"); Name n2 = new Name("abc."); @@ -1444,19 +1444,19 @@ void test_weird() throws TextParseException { static class Test_compareTo { @Test - void test_notName() throws TextParseException { + void notName() throws TextParseException { Name n = new Name("A.Name"); assertThrows(ClassCastException.class, () -> n.compareTo(new Object())); } @Test - void test_same() throws TextParseException { + void same() throws TextParseException { Name n = new Name("A.Name"); assertEquals(0, n.compareTo(n)); } @Test - void test_equal() throws TextParseException { + void equal() throws TextParseException { Name n1 = new Name("A.Name."); Name n2 = new Name("a.name."); @@ -1465,7 +1465,7 @@ void test_equal() throws TextParseException { } @Test - void test_close() throws TextParseException { + void close() throws TextParseException { Name n1 = new Name("a.name"); Name n2 = new Name("a.name."); @@ -1474,7 +1474,7 @@ void test_close() throws TextParseException { } @Test - void test_disjoint() throws TextParseException { + void disjoint() throws TextParseException { Name n1 = new Name("b"); Name n2 = new Name("c"); @@ -1483,7 +1483,7 @@ void test_disjoint() throws TextParseException { } @Test - void test_label_prefix() throws TextParseException { + void label_prefix() throws TextParseException { Name n1 = new Name("thisIs.a."); Name n2 = new Name("thisIsGreater.a."); @@ -1492,7 +1492,7 @@ void test_label_prefix() throws TextParseException { } @Test - void test_more_labels() throws TextParseException { + void more_labels() throws TextParseException { Name n1 = new Name("c.b.a."); Name n2 = new Name("d.c.b.a."); @@ -1502,7 +1502,7 @@ void test_more_labels() throws TextParseException { } @Test - void test_canonicalize() throws TextParseException { + void canonicalize() throws TextParseException { Name n1 = new Name("ABC.com"); Name n2 = new Name("abc.com"); Name n3 = new Name("\\193.com"); @@ -1521,7 +1521,7 @@ void test_canonicalize() throws TextParseException { } @Test - void test_to_string() throws TextParseException { + void to_string() throws TextParseException { Name n1 = new Name("abc.com"); Name n2 = new Name("abc.com."); @@ -1533,7 +1533,7 @@ void test_to_string() throws TextParseException { } @Test - void test_absolute() throws TextParseException { + void absolute() throws TextParseException { Name n1 = new Name("abc.com"); Name n2 = new Name("abc.com."); Name n3 = new Name("abc.com", Name.root); diff --git a/src/test/java/org/xbill/DNS/OpcodeTest.java b/src/test/java/org/xbill/DNS/OpcodeTest.java index a37ce871b..8955d8d82 100644 --- a/src/test/java/org/xbill/DNS/OpcodeTest.java +++ b/src/test/java/org/xbill/DNS/OpcodeTest.java @@ -42,7 +42,7 @@ class OpcodeTest { @Test - void test_string() { + void string() { // a regular one assertEquals("IQUERY", Opcode.string(Opcode.IQUERY)); @@ -56,7 +56,7 @@ void test_string() { } @Test - void test_value() { + void value() { // regular one assertEquals(Opcode.STATUS, Opcode.value("STATUS")); diff --git a/src/test/java/org/xbill/DNS/OptionsTest.java b/src/test/java/org/xbill/DNS/OptionsTest.java index 2d3626e64..1022f1e22 100644 --- a/src/test/java/org/xbill/DNS/OptionsTest.java +++ b/src/test/java/org/xbill/DNS/OptionsTest.java @@ -50,7 +50,7 @@ void setUp() { } @Test - void test_set_1arg() { + void set_1arg() { Options.set("Option1"); assertEquals("true", Options.value("option1")); @@ -63,7 +63,7 @@ void test_set_1arg() { } @Test - void test_set_2arg() { + void set_2arg() { Options.set("OPTION1", "Value1"); assertEquals("value1", Options.value("Option1")); @@ -77,7 +77,7 @@ void test_set_2arg() { } @Test - void test_check() { + void check() { assertFalse(Options.check("No Options yet")); Options.set("First Option"); @@ -87,7 +87,7 @@ void test_check() { } @Test - void test_unset() { + void unset() { // unset something non-existant Options.unset("Not an option Name"); @@ -106,7 +106,7 @@ void test_unset() { } @Test - void test_value() { + void value() { assertNull(Options.value("Table is Null")); Options.set("Testing Option"); @@ -116,7 +116,7 @@ void test_value() { } @Test - void test_intValue() { + void intValue() { assertEquals(-1, Options.intValue("Table is Null")); Options.set("A Boolean Option"); @@ -132,7 +132,7 @@ void test_intValue() { } @Test - void test_systemProperty() { + void systemProperty() { System.setProperty( "dnsjava.options", "booleanOption,valuedOption1=10,valuedOption2=NotAnInteger"); diff --git a/src/test/java/org/xbill/DNS/RRsetTest.java b/src/test/java/org/xbill/DNS/RRsetTest.java index a8cf3a4dd..ce157286d 100644 --- a/src/test/java/org/xbill/DNS/RRsetTest.java +++ b/src/test/java/org/xbill/DNS/RRsetTest.java @@ -94,7 +94,7 @@ void setUp() throws TextParseException, UnknownHostException { } @Test - void test_ctor_0arg() { + void ctor_0arg() { assertEquals(0, m_rs.size()); assertThrows(IllegalStateException.class, () -> m_rs.getDClass()); assertThrows(IllegalStateException.class, () -> m_rs.getType()); @@ -114,7 +114,7 @@ void test_ctor_0arg() { } @Test - void test_basics() { + void basics() { m_rs.addRR(m_a1); assertEquals(1, m_rs.size()); @@ -195,7 +195,7 @@ void test_basics() { } @Test - void test_ctor_1arg() { + void ctor_1arg() { m_rs.addRR(m_a1); m_rs.addRR(m_a2); m_rs.addRR(m_s1); @@ -233,7 +233,7 @@ void test_toString() { @SuppressWarnings("unchecked") @Test - void test_addRR_invalidType() throws TextParseException { + void addRR_invalidType() throws TextParseException { m_rs.addRR(m_a1); CNAMERecord c = new CNAMERecord(m_name, DClass.IN, m_ttl, Name.fromString("an.alias.")); @@ -242,7 +242,7 @@ void test_addRR_invalidType() throws TextParseException { } @Test - void test_addRR_invalidName() throws UnknownHostException { + void addRR_invalidName() throws UnknownHostException { m_rs.addRR(m_a1); m_a2 = new ARecord(m_name2, DClass.IN, m_ttl, InetAddress.getByName("192.169.232.11")); @@ -251,7 +251,7 @@ void test_addRR_invalidName() throws UnknownHostException { } @Test - void test_addRR_invalidDClass() throws UnknownHostException { + void addRR_invalidDClass() throws UnknownHostException { m_rs.addRR(m_a1); m_a2 = new ARecord(m_name, DClass.CHAOS, m_ttl, InetAddress.getByName("192.169.232.11")); @@ -260,7 +260,7 @@ void test_addRR_invalidDClass() throws UnknownHostException { } @Test - void test_TTLcalculation() { + void TTLcalculation() { m_rs.addRR(m_a2); assertEquals(m_a2.getTTL(), m_rs.getTTL()); m_rs.addRR(m_a1); @@ -272,7 +272,7 @@ void test_TTLcalculation() { } @Test - void test_Record_placement() { + void Record_placement() { m_rs.addRR(m_a1); m_rs.addRR(m_s1); m_rs.addRR(m_a2); @@ -288,7 +288,7 @@ void test_Record_placement() { } @Test - void test_noncycling_iterator() { + void noncycling_iterator() { m_rs.addRR(m_a1); m_rs.addRR(m_a2); diff --git a/src/test/java/org/xbill/DNS/RTRecordTest.java b/src/test/java/org/xbill/DNS/RTRecordTest.java index 2adebe19f..8b5dffe35 100644 --- a/src/test/java/org/xbill/DNS/RTRecordTest.java +++ b/src/test/java/org/xbill/DNS/RTRecordTest.java @@ -41,14 +41,14 @@ class RTRecordTest { @Test - void test_getObject() { + void getObject() { RTRecord d = new RTRecord(); Record r = d.getObject(); assertTrue(r instanceof RTRecord); } @Test - void test_ctor_5arg() throws TextParseException { + void ctor_5arg() throws TextParseException { Name n = Name.fromString("My.Name."); Name m = Name.fromString("My.OtherName."); diff --git a/src/test/java/org/xbill/DNS/RcodeTest.java b/src/test/java/org/xbill/DNS/RcodeTest.java index d98dec550..eac7ea35e 100644 --- a/src/test/java/org/xbill/DNS/RcodeTest.java +++ b/src/test/java/org/xbill/DNS/RcodeTest.java @@ -42,7 +42,7 @@ class RcodeTest { @Test - void test_string() { + void string() { // a regular one assertEquals("NXDOMAIN", Rcode.string(Rcode.NXDOMAIN)); @@ -59,7 +59,7 @@ void test_string() { } @Test - void test_TSIGstring() { + void TSIGstring() { // a regular one assertEquals("BADSIG", Rcode.TSIGstring(Rcode.BADSIG)); @@ -73,7 +73,7 @@ void test_TSIGstring() { } @Test - void test_value() { + void value() { // regular one assertEquals(Rcode.FORMERR, Rcode.value("FORMERR")); diff --git a/src/test/java/org/xbill/DNS/RecordTest.java b/src/test/java/org/xbill/DNS/RecordTest.java index 00ec8c0a9..de7c1c0a5 100644 --- a/src/test/java/org/xbill/DNS/RecordTest.java +++ b/src/test/java/org/xbill/DNS/RecordTest.java @@ -98,7 +98,7 @@ public Object clone() throws CloneNotSupportedException { } @Test - void test_ctor_0arg() { + void ctor_0arg() { SubRecord sr = new SubRecord(); assertNull(sr.getName()); assertEquals(0, sr.getType()); @@ -107,7 +107,7 @@ void test_ctor_0arg() { } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("my.name."); int t = Type.A; int d = DClass.IN; @@ -121,7 +121,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_ctor_4arg_invalid() throws TextParseException { + void ctor_4arg_invalid() throws TextParseException { Name n = Name.fromString("my.name."); Name r = Name.fromString("my.relative.name"); int t = Type.A; @@ -138,7 +138,7 @@ void test_ctor_4arg_invalid() throws TextParseException { } @Test - void test_newRecord_3arg() throws TextParseException { + void newRecord_3arg() throws TextParseException { Name n = Name.fromString("my.name."); Name r = Name.fromString("my.relative.name"); int t = Type.A; @@ -155,7 +155,7 @@ void test_newRecord_3arg() throws TextParseException { } @Test - void test_newRecord_4arg() throws TextParseException { + void newRecord_4arg() throws TextParseException { Name n = Name.fromString("my.name."); Name r = Name.fromString("my.relative.name"); int t = Type.A; @@ -173,7 +173,7 @@ void test_newRecord_4arg() throws TextParseException { } @Test - void test_newRecord_5arg() throws TextParseException, UnknownHostException { + void newRecord_5arg() throws TextParseException, UnknownHostException { Name n = Name.fromString("my.name."); int t = Type.A; int d = DClass.IN; @@ -191,7 +191,7 @@ void test_newRecord_5arg() throws TextParseException, UnknownHostException { } @Test - void test_newRecord_6arg() throws TextParseException, UnknownHostException { + void newRecord_6arg() throws TextParseException, UnknownHostException { Name n = Name.fromString("my.name."); int t = Type.A; int d = DClass.IN; @@ -224,7 +224,7 @@ void test_newRecord_6arg() throws TextParseException, UnknownHostException { } @Test - void test_newRecord_6arg_invalid() throws TextParseException { + void newRecord_6arg_invalid() throws TextParseException { Name n = Name.fromString("my.name."); Name r = Name.fromString("my.relative.name"); int t = Type.A; @@ -241,7 +241,7 @@ void test_newRecord_6arg_invalid() throws TextParseException { } @Test - void test_fromWire() throws IOException { + void fromWire() throws IOException { Name n = Name.fromString("my.name."); int t = Type.A; int d = DClass.IN; @@ -308,7 +308,7 @@ void test_fromWire() throws IOException { } @Test - void test_toWire() throws IOException { + void toWire() throws IOException { Name n = Name.fromString("my.name."); int t = Type.A; int d = DClass.IN; @@ -355,7 +355,7 @@ void test_toWire() throws IOException { } @Test - void test_toWireCanonical() throws IOException { + void toWireCanonical() throws IOException { Name n = Name.fromString("My.Name."); int t = Type.A; int d = DClass.IN; @@ -379,7 +379,7 @@ void test_toWireCanonical() throws IOException { } @Test - void test_rdataToWireCanonical() throws IOException { + void rdataToWireCanonical() throws IOException { Name n = Name.fromString("My.Name."); Name n2 = Name.fromString("My.Second.Name."); int t = Type.NS; @@ -402,7 +402,7 @@ void test_rdataToWireCanonical() throws IOException { } @Test - void test_rdataToString() throws IOException { + void rdataToString() throws IOException { Name n = Name.fromString("My.Name."); Name n2 = Name.fromString("My.Second.Name."); int t = Type.NS; @@ -456,7 +456,7 @@ void test_toString() throws TextParseException { } @Test - void test_byteArrayFromString() throws TextParseException { + void byteArrayFromString() throws TextParseException { String in = "the 98 \" \' quick 0xAB brown"; byte[] out = SubRecord.byteArrayFromString(in); assertArrayEquals(in.getBytes(), out); @@ -468,7 +468,7 @@ void test_byteArrayFromString() throws TextParseException { } @Test - void test_byteArrayFromString_invalid() { + void byteArrayFromString_invalid() { StringBuilder b = new StringBuilder(); for (int i = 0; i < 257; ++i) { b.append('A'); @@ -484,14 +484,14 @@ void test_byteArrayFromString_invalid() { } @Test - void test_byteArrayToString() { + void byteArrayToString() { byte[] in = new byte[] {' ', 0x1F, 'A', 'a', ';', '"', '\\', 0x7E, 0x7F, (byte) 0xFF}; String exp = "\" \\031Aa;\\\"\\\\~\\127\\255\""; assertEquals(exp, SubRecord.byteArrayToString(in, true)); } @Test - void test_unknownToString() { + void unknownToString() { byte[] data = new byte[] { (byte) 0x12, @@ -510,7 +510,7 @@ void test_unknownToString() { } @Test - void test_fromString() throws IOException { + void fromString() throws IOException { Name n = Name.fromString("My.N."); Name n2 = Name.fromString("My.Second.Name."); int t = Type.A; @@ -541,7 +541,7 @@ void test_fromString() throws IOException { } @Test - void test_fromString_invalid() throws IOException { + void fromString_invalid() throws IOException { Name n = Name.fromString("My.N."); Name rel = Name.fromString("My.R"); Name n2 = Name.fromString("My.Second.Name."); @@ -566,7 +566,7 @@ void test_fromString_invalid() throws IOException { } @Test - void test_getRRsetType() throws TextParseException { + void getRRsetType() throws TextParseException { Name n = Name.fromString("My.N."); Record r = Record.newRecord(n, Type.A, DClass.IN, 0); @@ -583,7 +583,7 @@ void test_getRRsetType() throws TextParseException { } @Test - void test_sameRRset() throws TextParseException { + void sameRRset() throws TextParseException { Name n = Name.fromString("My.N."); Name m = Name.fromString("My.M."); @@ -605,7 +605,7 @@ void test_sameRRset() throws TextParseException { } @Test - void test_equals() throws TextParseException { + void equals() throws TextParseException { Name n = Name.fromString("My.N."); Name n2 = Name.fromString("my.n."); Name m = Name.fromString("My.M."); @@ -690,7 +690,7 @@ void test_hashCode() throws TextParseException { } @Test - void test_cloneRecord() throws TextParseException { + void cloneRecord() throws TextParseException { Name n = Name.fromString("My.N."); byte[] d = new byte[] {23, 12, 9, (byte) 129}; Record r = Record.newRecord(n, Type.A, DClass.IN, 0xABCDE9, d); @@ -706,7 +706,7 @@ void test_cloneRecord() throws TextParseException { } @Test - void test_withName() throws TextParseException { + void withName() throws TextParseException { Name n = Name.fromString("My.N."); Name m = Name.fromString("My.M.Name."); Name rel = Name.fromString("My.Relative.Name"); @@ -725,7 +725,7 @@ void test_withName() throws TextParseException { } @Test - void test_withDClass() throws TextParseException { + void withDClass() throws TextParseException { Name n = Name.fromString("My.N."); byte[] d = new byte[] {23, 12, 9, (byte) 129}; Record r = Record.newRecord(n, Type.A, DClass.IN, 0xABCDE9, d); @@ -740,7 +740,7 @@ void test_withDClass() throws TextParseException { } @Test - void test_setTTL() throws TextParseException, UnknownHostException { + void setTTL() throws TextParseException, UnknownHostException { Name n = Name.fromString("My.N."); byte[] d = new byte[] {23, 12, 9, (byte) 129}; InetAddress exp = InetAddress.getByName("23.12.9.129"); @@ -758,7 +758,7 @@ void test_setTTL() throws TextParseException, UnknownHostException { } @Test - void test_compareTo() throws TextParseException { + void compareTo() throws TextParseException { Name n = Name.fromString("My.N."); Name n2 = Name.fromString("my.n."); Name m = Name.fromString("My.M."); @@ -806,7 +806,7 @@ void test_compareTo() throws TextParseException { } @Test - void test_getAdditionalName() throws TextParseException { + void getAdditionalName() throws TextParseException { Name n = Name.fromString("My.N."); Record r = new SubRecord(n, Type.A, DClass.IN, 0xABCDE9); @@ -814,7 +814,7 @@ void test_getAdditionalName() throws TextParseException { } @Test - void test_checkU8() { + void checkU8() { assertThrows(IllegalArgumentException.class, () -> Record.checkU8("field", -1)); assertEquals(0, Record.checkU8("field", 0)); assertEquals(0x9D, Record.checkU8("field", 0x9D)); @@ -823,7 +823,7 @@ void test_checkU8() { } @Test - void test_checkU16() { + void checkU16() { assertThrows(IllegalArgumentException.class, () -> Record.checkU16("field", -1)); assertEquals(0, Record.checkU16("field", 0)); assertEquals(0x9DA1, Record.checkU16("field", 0x9DA1)); @@ -832,7 +832,7 @@ void test_checkU16() { } @Test - void test_checkU32() { + void checkU32() { assertThrows(IllegalArgumentException.class, () -> Record.checkU32("field", -1)); assertEquals(0, Record.checkU32("field", 0)); assertEquals(0x9DA1F02DL, Record.checkU32("field", 0x9DA1F02DL)); @@ -841,7 +841,7 @@ void test_checkU32() { } @Test - void test_checkName() throws TextParseException { + void checkName() throws TextParseException { Name n = Name.fromString("My.N."); Name m = Name.fromString("My.m"); diff --git a/src/test/java/org/xbill/DNS/ReverseMapTest.java b/src/test/java/org/xbill/DNS/ReverseMapTest.java index 2a23c11ec..09d3213ee 100644 --- a/src/test/java/org/xbill/DNS/ReverseMapTest.java +++ b/src/test/java/org/xbill/DNS/ReverseMapTest.java @@ -43,7 +43,7 @@ class ReverseMapTest { @Test - void test_fromAddress_ipv4() throws UnknownHostException, TextParseException { + void fromAddress_ipv4() throws UnknownHostException, TextParseException { Name exp = Name.fromString("1.0.168.192.in-addr.arpa."); String addr = "192.168.0.1"; assertEquals(exp, ReverseMap.fromAddress(addr)); @@ -56,7 +56,7 @@ void test_fromAddress_ipv4() throws UnknownHostException, TextParseException { } @Test - void test_fromAddress_ipv6() throws UnknownHostException, TextParseException { + void fromAddress_ipv6() throws UnknownHostException, TextParseException { Name exp = Name.fromString( "4.3.3.7.0.7.3.0.E.2.A.8.9.1.3.1.3.D.8.0.3.A.5.8.8.B.D.0.1.0.0.2.ip6.arpa."); @@ -75,7 +75,7 @@ void test_fromAddress_ipv6() throws UnknownHostException, TextParseException { } @Test - void test_fromAddress_invalid() { + void fromAddress_invalid() { assertThrows(UnknownHostException.class, () -> ReverseMap.fromAddress("A.B.C.D", Address.IPv4)); assertThrows(IllegalArgumentException.class, () -> ReverseMap.fromAddress(new byte[0])); assertThrows(IllegalArgumentException.class, () -> ReverseMap.fromAddress(new byte[3])); diff --git a/src/test/java/org/xbill/DNS/SOARecordTest.java b/src/test/java/org/xbill/DNS/SOARecordTest.java index d96aa8471..846e71646 100644 --- a/src/test/java/org/xbill/DNS/SOARecordTest.java +++ b/src/test/java/org/xbill/DNS/SOARecordTest.java @@ -75,7 +75,7 @@ void setUp() throws TextParseException { } @Test - void test_0arg() { + void ctor_0arg() { SOARecord ar = new SOARecord(); assertNull(ar.getName()); assertEquals(0, ar.getType()); @@ -91,14 +91,14 @@ void test_0arg() { } @Test - void test_getObject() { + void getObject() { SOARecord ar = new SOARecord(); Record r = ar.getObject(); assertTrue(r instanceof SOARecord); } @Test - void test_10arg() { + void ctor_10arg() { SOARecord ar = new SOARecord( m_an, DClass.IN, m_ttl, m_host, m_admin, m_serial, m_refresh, m_retry, m_expire, @@ -117,7 +117,7 @@ void test_10arg() { } @Test - void test_10arg_relative_name() { + void ctor_10arg_relative_name() { assertThrows( RelativeNameException.class, () -> @@ -127,7 +127,7 @@ void test_10arg_relative_name() { } @Test - void test_10arg_relative_host() { + void ctor_10arg_relative_host() { assertThrows( RelativeNameException.class, () -> @@ -137,7 +137,7 @@ void test_10arg_relative_host() { } @Test - void test_10arg_relative_admin() { + void ctor_10arg_relative_admin() { assertThrows( RelativeNameException.class, () -> @@ -147,7 +147,7 @@ void test_10arg_relative_admin() { } @Test - void test_10arg_negative_serial() { + void ctor_10arg_negative_serial() { assertThrows( IllegalArgumentException.class, () -> @@ -157,7 +157,7 @@ void test_10arg_negative_serial() { } @Test - void test_10arg_toobig_serial() { + void ctor_10arg_toobig_serial() { assertThrows( IllegalArgumentException.class, () -> @@ -175,7 +175,7 @@ void test_10arg_toobig_serial() { } @Test - void test_10arg_negative_refresh() { + void ctor_10arg_negative_refresh() { assertThrows( IllegalArgumentException.class, () -> @@ -185,7 +185,7 @@ void test_10arg_negative_refresh() { } @Test - void test_10arg_toobig_refresh() { + void ctor_10arg_toobig_refresh() { assertThrows( IllegalArgumentException.class, () -> @@ -203,7 +203,7 @@ void test_10arg_toobig_refresh() { } @Test - void test_10arg_negative_retry() { + void ctor_10arg_negative_retry() { assertThrows( IllegalArgumentException.class, () -> @@ -213,7 +213,7 @@ void test_10arg_negative_retry() { } @Test - void test_10arg_toobig_retry() { + void ctor_10arg_toobig_retry() { assertThrows( IllegalArgumentException.class, () -> @@ -231,7 +231,7 @@ void test_10arg_toobig_retry() { } @Test - void test_10arg_negative_expire() { + void ctor_10arg_negative_expire() { assertThrows( IllegalArgumentException.class, () -> @@ -241,7 +241,7 @@ void test_10arg_negative_expire() { } @Test - void test_10arg_toobig_expire() { + void ctor_10arg_toobig_expire() { assertThrows( IllegalArgumentException.class, () -> @@ -259,7 +259,7 @@ void test_10arg_toobig_expire() { } @Test - void test_10arg_negative_minimun() { + void ctor_10arg_negative_minimun() { assertThrows( IllegalArgumentException.class, () -> @@ -269,7 +269,7 @@ void test_10arg_negative_minimun() { } @Test - void test_10arg_toobig_minimum() { + void ctor_10arg_toobig_minimum() { assertThrows( IllegalArgumentException.class, () -> @@ -374,7 +374,7 @@ void setUp() throws TextParseException { } @Test - void test_valid() throws IOException { + void valid() throws IOException { Tokenizer t = new Tokenizer( "M.h " + m_admin + " " + m_serial + " " + m_refresh + " " + m_retry + " " + m_expire @@ -393,7 +393,7 @@ void test_valid() throws IOException { } @Test - void test_relative_name() throws IOException { + void relative_name() { Tokenizer t = new Tokenizer( "M.h " + m_admin + " " + m_serial + " " + m_refresh + " " + m_retry + " " + m_expire @@ -422,7 +422,7 @@ void setUp() throws TextParseException { } @Test - void test_singleLine() { + void singleLine() { SOARecord ar = new SOARecord( m_an, DClass.IN, m_ttl, m_host, m_admin, m_serial, m_refresh, m_retry, m_expire, @@ -437,7 +437,7 @@ void test_singleLine() { } @Test - void test_multiLine() { + void multiLine() { SOARecord ar = new SOARecord( m_an, DClass.IN, m_ttl, m_host, m_admin, m_serial, m_refresh, m_retry, m_expire, @@ -490,7 +490,7 @@ void setUp() throws TextParseException { } @Test - void test_canonical() { + void canonical() { byte[] exp = new byte[] { 1, @@ -540,7 +540,7 @@ void test_canonical() { } @Test - void test_case_sensitive() { + void case_sensitive() { byte[] exp = new byte[] { 1, diff --git a/src/test/java/org/xbill/DNS/SectionTest.java b/src/test/java/org/xbill/DNS/SectionTest.java index 972c58305..9e9258b12 100644 --- a/src/test/java/org/xbill/DNS/SectionTest.java +++ b/src/test/java/org/xbill/DNS/SectionTest.java @@ -41,7 +41,7 @@ class SectionTest { @Test - void test_string() { + void string() { // a regular one assertEquals("au", Section.string(Section.AUTHORITY)); @@ -52,7 +52,7 @@ void test_string() { } @Test - void test_value() { + void value() { // regular one assertEquals(Section.ADDITIONAL, Section.value("ad")); @@ -64,7 +64,7 @@ void test_value() { } @Test - void test_longString() { + void longString() { assertEquals("ADDITIONAL RECORDS", Section.longString(Section.ADDITIONAL)); try { @@ -78,7 +78,7 @@ void test_longString() { } @Test - void test_updString() { + void updString() { assertEquals("ZONE", Section.updString(Section.ZONE)); try { diff --git a/src/test/java/org/xbill/DNS/SerialTest.java b/src/test/java/org/xbill/DNS/SerialTest.java index 81bf87786..428569cda 100644 --- a/src/test/java/org/xbill/DNS/SerialTest.java +++ b/src/test/java/org/xbill/DNS/SerialTest.java @@ -42,35 +42,35 @@ class SerialTest { @Test - void test_compare_NegativeArg1() { + void compare_NegativeArg1() { long arg1 = -1; long arg2 = 1; assertThrows(IllegalArgumentException.class, () -> Serial.compare(arg1, arg2)); } @Test - void test_compare_OOBArg1() { + void compare_OOBArg1() { long arg1 = 0xFFFFFFFFL + 1; long arg2 = 1; assertThrows(IllegalArgumentException.class, () -> Serial.compare(arg1, arg2)); } @Test - void test_compare_NegativeArg2() { + void compare_NegativeArg2() { long arg1 = 1; long arg2 = -1; assertThrows(IllegalArgumentException.class, () -> Serial.compare(arg1, arg2)); } @Test - void test_compare_OOBArg2() { + void compare_OOBArg2() { long arg1 = 1; long arg2 = 0xFFFFFFFFL + 1; assertThrows(IllegalArgumentException.class, () -> Serial.compare(arg1, arg2)); } @Test - void test_compare_Arg1Greater() { + void compare_Arg1Greater() { long arg1 = 10; long arg2 = 9; int ret = Serial.compare(arg1, arg2); @@ -78,7 +78,7 @@ void test_compare_Arg1Greater() { } @Test - void test_compare_Arg2Greater() { + void compare_Arg2Greater() { long arg1 = 9; long arg2 = 10; int ret = Serial.compare(arg1, arg2); @@ -86,7 +86,7 @@ void test_compare_Arg2Greater() { } @Test - void test_compare_ArgsEqual() { + void compare_ArgsEqual() { long arg1 = 10; long arg2 = 10; int ret = Serial.compare(arg1, arg2); @@ -94,7 +94,7 @@ void test_compare_ArgsEqual() { } @Test - void test_compare_boundary() { + void compare_boundary() { long arg1 = 0xFFFFFFFFL; long arg2 = 0; int ret = Serial.compare(arg1, arg2); @@ -104,26 +104,26 @@ void test_compare_boundary() { } @Test - void test_increment_NegativeArg() { + void increment_NegativeArg() { long arg = -1; assertThrows(IllegalArgumentException.class, () -> Serial.increment(arg)); } @Test - void test_increment_OOBArg() { + void increment_OOBArg() { long arg = 0xFFFFFFFFL + 1; assertThrows(IllegalArgumentException.class, () -> Serial.increment(arg)); } @Test - void test_increment_reset() { + void increment_reset() { long arg = 0xFFFFFFFFL; long ret = Serial.increment(arg); assertEquals(0, ret); } @Test - void test_increment_normal() { + void increment_normal() { long arg = 10; long ret = Serial.increment(arg); assertEquals(arg + 1, ret); diff --git a/src/test/java/org/xbill/DNS/SetResponseTest.java b/src/test/java/org/xbill/DNS/SetResponseTest.java index 76d9d89e6..dc3bbf52a 100644 --- a/src/test/java/org/xbill/DNS/SetResponseTest.java +++ b/src/test/java/org/xbill/DNS/SetResponseTest.java @@ -47,7 +47,7 @@ class SetResponseTest { @Test - void test_ctor_1arg() { + void ctor_1arg() { final int[] types = new int[] { SetResponse.UNKNOWN, @@ -73,17 +73,17 @@ void test_ctor_1arg() { } @Test - void test_ctor_1arg_toosmall() { + void ctor_1arg_toosmall() { assertThrows(IllegalArgumentException.class, () -> new SetResponse(-1)); } @Test - void test_ctor_1arg_toobig() { + void ctor_1arg_toobig() { assertThrows(IllegalArgumentException.class, () -> new SetResponse(7)); } @Test - void test_ctor_2arg() { + void ctor_2arg() { final int[] types = new int[] { SetResponse.UNKNOWN, @@ -110,17 +110,17 @@ void test_ctor_2arg() { } @Test - void test_ctor_2arg_toosmall() { + void ctor_2arg_toosmall() { assertThrows(IllegalArgumentException.class, () -> new SetResponse(-1, new RRset())); } @Test - void test_ctor_2arg_toobig() { + void ctor_2arg_toobig() { assertThrows(IllegalArgumentException.class, () -> new SetResponse(7, new RRset())); } @Test - void test_ofType_basic() { + void ofType_basic() { final int[] types = new int[] { SetResponse.DELEGATION, SetResponse.CNAME, SetResponse.DNAME, SetResponse.SUCCESSFUL @@ -143,7 +143,7 @@ void test_ofType_basic() { } @Test - void test_ofType_singleton() { + void ofType_singleton() { final int[] types = new int[] {SetResponse.UNKNOWN, SetResponse.NXDOMAIN, SetResponse.NXRRSET}; for (int type : types) { @@ -163,17 +163,17 @@ void test_ofType_singleton() { } @Test - void test_ofType_toosmall() { + void ofType_toosmall() { assertThrows(IllegalArgumentException.class, () -> SetResponse.ofType(-1)); } @Test - void test_ofType_toobig() { + void ofType_toobig() { assertThrows(IllegalArgumentException.class, () -> SetResponse.ofType(7)); } @Test - void test_addRRset() throws TextParseException, UnknownHostException { + void addRRset() throws TextParseException, UnknownHostException { RRset rrs = new RRset<>(); rrs.addRR( new ARecord( @@ -189,7 +189,7 @@ void test_addRRset() throws TextParseException, UnknownHostException { } @Test - void test_addRRset_multiple() throws TextParseException, UnknownHostException { + void addRRset_multiple() throws TextParseException, UnknownHostException { RRset rrs = new RRset<>(); rrs.addRR( new ARecord( @@ -221,13 +221,13 @@ void test_addRRset_multiple() throws TextParseException, UnknownHostException { } @Test - void test_answers_nonSUCCESSFUL() { + void answers_nonSUCCESSFUL() { SetResponse sr = new SetResponse(SetResponse.UNKNOWN, new RRset()); assertNull(sr.answers()); } @Test - void test_getCNAME() throws TextParseException { + void getCNAME() throws TextParseException { RRset rrs = new RRset<>(); CNAMERecord cr = new CNAMERecord( @@ -238,7 +238,7 @@ void test_getCNAME() throws TextParseException { } @Test - void test_getDNAME() throws TextParseException { + void getDNAME() throws TextParseException { RRset rrs = new RRset<>(); DNAMERecord dr = new DNAMERecord( diff --git a/src/test/java/org/xbill/DNS/SingleCompressedNameBaseTest.java b/src/test/java/org/xbill/DNS/SingleCompressedNameBaseTest.java index 48be23569..c8dcd197d 100644 --- a/src/test/java/org/xbill/DNS/SingleCompressedNameBaseTest.java +++ b/src/test/java/org/xbill/DNS/SingleCompressedNameBaseTest.java @@ -62,7 +62,7 @@ public Record getObject() { } @Test - void test_ctor() throws TextParseException { + void ctor() throws TextParseException { TestClass tc = new TestClass(); assertNull(tc.getSingleName()); @@ -79,7 +79,7 @@ void test_ctor() throws TextParseException { } @Test - void test_rrToWire() throws IOException { + void rrToWire() throws IOException { Name n = Name.fromString("my.name."); Name sn = Name.fromString("My.Single.Name."); diff --git a/src/test/java/org/xbill/DNS/SingleNameBaseTest.java b/src/test/java/org/xbill/DNS/SingleNameBaseTest.java index 38d193eec..9f1e72a28 100644 --- a/src/test/java/org/xbill/DNS/SingleNameBaseTest.java +++ b/src/test/java/org/xbill/DNS/SingleNameBaseTest.java @@ -67,7 +67,7 @@ public Record getObject() { } @Test - void test_ctor() throws TextParseException { + void ctor() throws TextParseException { TestClass tc = new TestClass(); assertNull(tc.getSingleName()); @@ -91,7 +91,7 @@ void test_ctor() throws TextParseException { } @Test - void test_rrFromWire() throws IOException { + void rrFromWire() throws IOException { byte[] raw = new byte[] {2, 'm', 'y', 6, 's', 'i', 'n', 'g', 'l', 'e', 4, 'n', 'a', 'm', 'e', 0}; DNSInput in = new DNSInput(raw); @@ -104,7 +104,7 @@ void test_rrFromWire() throws IOException { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { Name exp = Name.fromString("my.single.name."); Tokenizer t = new Tokenizer("my.single.name."); @@ -118,7 +118,7 @@ void test_rdataFromString() throws IOException { } @Test - void test_rrToString() throws IOException { + void rrToString() throws IOException { Name exp = Name.fromString("my.single.name."); Tokenizer t = new Tokenizer("my.single.name."); @@ -131,7 +131,7 @@ void test_rrToString() throws IOException { } @Test - void test_rrToWire() throws IOException { + void rrToWire() throws IOException { Name n = Name.fromString("my.name."); Name sn = Name.fromString("My.Single.Name."); diff --git a/src/test/java/org/xbill/DNS/TSIGTest.java b/src/test/java/org/xbill/DNS/TSIGTest.java index af63a02af..983b2e84f 100644 --- a/src/test/java/org/xbill/DNS/TSIGTest.java +++ b/src/test/java/org/xbill/DNS/TSIGTest.java @@ -9,7 +9,7 @@ class TSIGTest { @Test - void test_TSIG_query() throws IOException { + void TSIG_query() throws IOException { TSIG key = new TSIG(TSIG.HMAC_SHA256, "example.", "12345678"); Name qname = Name.fromString("www.example."); @@ -26,7 +26,7 @@ void test_TSIG_query() throws IOException { } @Test - void test_TSIG_response() throws IOException { + void TSIG_response() throws IOException { TSIG key = new TSIG(TSIG.HMAC_SHA256, "example.", "12345678"); Name qname = Name.fromString("www.example."); @@ -51,7 +51,7 @@ void test_TSIG_response() throws IOException { } @Test - void test_TSIG_truncated() throws IOException { + void TSIG_truncated() throws IOException { TSIG key = new TSIG(TSIG.HMAC_SHA256, "example.", "12345678"); Name qname = Name.fromString("www.example."); diff --git a/src/test/java/org/xbill/DNS/TTLTest.java b/src/test/java/org/xbill/DNS/TTLTest.java index 393eadd6e..cdba7c54b 100644 --- a/src/test/java/org/xbill/DNS/TTLTest.java +++ b/src/test/java/org/xbill/DNS/TTLTest.java @@ -47,7 +47,7 @@ class TTLTest { private final long W = 7 * D; @Test - void test_parseTTL() { + void parseTTL() { assertEquals(9876, TTL.parseTTL("9876")); assertEquals(0, TTL.parseTTL("0S")); @@ -72,7 +72,7 @@ void test_parseTTL() { } @Test - void test_parseTTL_invalid() { + void parseTTL_invalid() { assertThrows(NumberFormatException.class, () -> TTL.parseTTL(null)); assertThrows(NumberFormatException.class, () -> TTL.parseTTL("")); @@ -87,7 +87,7 @@ void test_parseTTL_invalid() { } @Test - void test_format() { + void format() { assertEquals("0S", TTL.format(0)); assertEquals("1S", TTL.format(1)); assertEquals("59S", TTL.format(59)); @@ -107,7 +107,7 @@ void test_format() { } @Test - void test_format_invalid() { + void format_invalid() { assertThrows(InvalidTTLException.class, () -> TTL.format(-1)); assertThrows(InvalidTTLException.class, () -> TTL.format(0x100000000L)); diff --git a/src/test/java/org/xbill/DNS/TokenizerTest.java b/src/test/java/org/xbill/DNS/TokenizerTest.java index 4d17fbfa2..2fc44b694 100644 --- a/src/test/java/org/xbill/DNS/TokenizerTest.java +++ b/src/test/java/org/xbill/DNS/TokenizerTest.java @@ -59,7 +59,7 @@ void setUp() { } @Test - void test_get() throws IOException { + void get() throws IOException { m_t = new Tokenizer( new BufferedInputStream( @@ -195,7 +195,7 @@ void test_get() throws IOException { } @Test - void test_get_invalid() throws IOException { + void get_invalid() throws IOException { m_t = new Tokenizer("(this ;"); m_t.get(); assertThrows(TextParseException.class, () -> m_t.get()); @@ -214,7 +214,7 @@ void test_get_invalid() throws IOException { } @Test - void test_File_input() throws IOException { + void File_input() throws IOException { File tmp = File.createTempFile("dnsjava", "tmp"); try { FileWriter fw = new FileWriter(tmp); @@ -245,7 +245,7 @@ void test_File_input() throws IOException { } @Test - void test_unwanted_comment() throws IOException { + void unwanted_comment() throws IOException { m_t = new Tokenizer("; this whole thing is a comment\n"); Tokenizer.Token tt = m_t.get(); @@ -253,7 +253,7 @@ void test_unwanted_comment() throws IOException { } @Test - void test_unwanted_ungotten_whitespace() throws IOException { + void unwanted_ungotten_whitespace() throws IOException { m_t = new Tokenizer(" "); Tokenizer.Token tt = m_t.get(true, true); m_t.unget(); @@ -262,7 +262,7 @@ void test_unwanted_ungotten_whitespace() throws IOException { } @Test - void test_unwanted_ungotten_comment() throws IOException { + void unwanted_ungotten_comment() throws IOException { m_t = new Tokenizer("; this whole thing is a comment"); Tokenizer.Token tt = m_t.get(true, true); m_t.unget(); @@ -271,7 +271,7 @@ void test_unwanted_ungotten_comment() throws IOException { } @Test - void test_empty_string() throws IOException { + void empty_string() throws IOException { m_t = new Tokenizer(""); Tokenizer.Token tt = m_t.get(); assertEquals(Tokenizer.EOF, tt.type); @@ -282,7 +282,7 @@ void test_empty_string() throws IOException { } @Test - void test_multiple_ungets() throws IOException { + void multiple_ungets() throws IOException { m_t = new Tokenizer("a simple one"); Tokenizer.Token tt = m_t.get(); @@ -291,7 +291,7 @@ void test_multiple_ungets() throws IOException { } @Test - void test_getString() throws IOException { + void getString() throws IOException { m_t = new Tokenizer("just_an_identifier"); final String[] out = {m_t.getString()}; assertEquals("just_an_identifier", out[0]); @@ -305,7 +305,7 @@ void test_getString() throws IOException { } @Test - void test_getIdentifier() throws IOException { + void getIdentifier() throws IOException { m_t = new Tokenizer("just_an_identifier"); String out = m_t.getIdentifier(); assertEquals("just_an_identifier", out); @@ -315,7 +315,7 @@ void test_getIdentifier() throws IOException { } @Test - void test_getLong() throws IOException { + void getLong() throws IOException { m_t = new Tokenizer((Integer.MAX_VALUE + 1L) + ""); long out = m_t.getLong(); assertEquals((Integer.MAX_VALUE + 1L), out); @@ -328,7 +328,7 @@ void test_getLong() throws IOException { } @Test - void test_getUInt32() throws IOException { + void getUInt32() throws IOException { m_t = new Tokenizer(0xABCDEF12L + ""); long out = m_t.getUInt32(); assertEquals(0xABCDEF12L, out); @@ -341,7 +341,7 @@ void test_getUInt32() throws IOException { } @Test - void test_getUInt16() throws IOException { + void getUInt16() throws IOException { m_t = new Tokenizer(0xABCDL + ""); int out = m_t.getUInt16(); assertEquals(0xABCDL, out); @@ -354,7 +354,7 @@ void test_getUInt16() throws IOException { } @Test - void test_getUInt8() throws IOException { + void getUInt8() throws IOException { m_t = new Tokenizer(0xCDL + ""); int out = m_t.getUInt8(); assertEquals(0xCDL, out); @@ -367,7 +367,7 @@ void test_getUInt8() throws IOException { } @Test - void test_getTTL() throws IOException { + void getTTL() throws IOException { m_t = new Tokenizer("59S"); assertEquals(59, m_t.getTTL()); @@ -382,7 +382,7 @@ void test_getTTL() throws IOException { } @Test - void test_getTTLLike() throws IOException { + void getTTLLike() throws IOException { m_t = new Tokenizer("59S"); assertEquals(59, m_t.getTTLLike()); @@ -397,7 +397,7 @@ void test_getTTLLike() throws IOException { } @Test - void test_getName() throws IOException { + void getName() throws IOException { Name root = Name.fromString("."); m_t = new Tokenizer("junk"); Name exp = Name.fromString("junk."); @@ -413,7 +413,7 @@ void test_getName() throws IOException { } @Test - void test_getEOL() throws IOException { + void getEOL() throws IOException { m_t = new Tokenizer("id"); m_t.getIdentifier(); try { @@ -435,7 +435,7 @@ void test_getEOL() throws IOException { } @Test - void test_getBase64() throws IOException { + void getBase64() throws IOException { byte[] exp = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // basic m_t = new Tokenizer("AQIDBAUGBwgJ"); @@ -468,7 +468,7 @@ void test_getBase64() throws IOException { } @Test - void test_getHex() throws IOException { + void getHex() throws IOException { byte[] exp = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; // basic m_t = new Tokenizer("0102030405060708090A0B0C0D0E0F"); diff --git a/src/test/java/org/xbill/DNS/TypeBitmapTest.java b/src/test/java/org/xbill/DNS/TypeBitmapTest.java index 23b5bd00f..ea0e9a429 100644 --- a/src/test/java/org/xbill/DNS/TypeBitmapTest.java +++ b/src/test/java/org/xbill/DNS/TypeBitmapTest.java @@ -39,19 +39,19 @@ class TypeBitmapTest { @Test - void test_empty() { + void empty() { TypeBitmap typeBitmap = new TypeBitmap(new int[] {}); assertEquals(typeBitmap.toString(), ""); } @Test - void test_typeA() { + void typeA() { TypeBitmap typeBitmap = new TypeBitmap(new int[] {1}); assertEquals(typeBitmap.toString(), "A"); } @Test - void test_typeNSandSOA() { + void typeNSandSOA() { TypeBitmap typeBitmap = new TypeBitmap(new int[] {2, 6}); assertEquals(typeBitmap.toString(), "NS SOA"); } diff --git a/src/test/java/org/xbill/DNS/TypeTest.java b/src/test/java/org/xbill/DNS/TypeTest.java index 394e06810..29c946e75 100644 --- a/src/test/java/org/xbill/DNS/TypeTest.java +++ b/src/test/java/org/xbill/DNS/TypeTest.java @@ -43,7 +43,7 @@ class TypeTest { @Test - void test_string() { + void string() { // a regular one assertEquals("CNAME", Type.string(Type.CNAME)); @@ -54,7 +54,7 @@ void test_string() { } @Test - void test_value() { + void value() { // regular one assertEquals(Type.MAILB, Type.value("MAILB")); @@ -69,12 +69,12 @@ void test_value() { } @Test - void test_value_2arg() { + void value_2arg() { assertEquals(301, Type.value("301", true)); } @Test - void test_isRR() { + void isRR() { assertTrue(Type.isRR(Type.CNAME)); assertFalse(Type.isRR(Type.IXFR)); } diff --git a/src/test/java/org/xbill/DNS/U16NameBaseTest.java b/src/test/java/org/xbill/DNS/U16NameBaseTest.java index 5ef26051a..739058d0a 100644 --- a/src/test/java/org/xbill/DNS/U16NameBaseTest.java +++ b/src/test/java/org/xbill/DNS/U16NameBaseTest.java @@ -80,7 +80,7 @@ public Record getObject() { } @Test - void test_ctor_0arg() { + void ctor_0arg() { TestClass tc = new TestClass(); assertNull(tc.getName()); assertEquals(0, tc.getType()); @@ -91,7 +91,7 @@ void test_ctor_0arg() { } @Test - void test_ctor_4arg() throws TextParseException { + void ctor_4arg() throws TextParseException { Name n = Name.fromString("My.Name."); TestClass tc = new TestClass(n, Type.MX, DClass.IN, 0xBCDA); @@ -105,7 +105,7 @@ void test_ctor_4arg() throws TextParseException { } @Test - void test_ctor_8arg() throws TextParseException { + void ctor_8arg() throws TextParseException { Name n = Name.fromString("My.Name."); Name m = Name.fromString("My.Other.Name."); @@ -144,7 +144,7 @@ void test_ctor_8arg() throws TextParseException { } @Test - void test_rrFromWire() throws IOException { + void rrFromWire() throws IOException { byte[] raw = new byte[] { (byte) 0xBC, @@ -177,7 +177,7 @@ void test_rrFromWire() throws IOException { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { Name exp = Name.fromString("My.Single.Name."); Tokenizer t = new Tokenizer(0x19A2 + " My.Single.Name."); @@ -193,7 +193,7 @@ void test_rdataFromString() throws IOException { } @Test - void test_rrToString() throws IOException { + void rrToString() throws IOException { Name n = Name.fromString("My.Name."); Name m = Name.fromString("My.Other.Name."); @@ -208,7 +208,7 @@ void test_rrToString() throws IOException { } @Test - void test_rrToWire() throws IOException { + void rrToWire() throws IOException { Name n = Name.fromString("My.Name."); Name m = Name.fromString("M.O.n."); diff --git a/src/test/java/org/xbill/DNS/URIRecordTest.java b/src/test/java/org/xbill/DNS/URIRecordTest.java index 4be1d407e..e22489d03 100644 --- a/src/test/java/org/xbill/DNS/URIRecordTest.java +++ b/src/test/java/org/xbill/DNS/URIRecordTest.java @@ -11,7 +11,7 @@ class URIRecordTest { @Test - void test_ctor_0arg() { + void ctor_0arg() { URIRecord r = new URIRecord(); assertNull(r.getName()); assertEquals(0, r.getType()); @@ -23,14 +23,14 @@ void test_ctor_0arg() { } @Test - void test_getObject() { + void getObject() { URIRecord dr = new URIRecord(); Record r = dr.getObject(); assertTrue(r instanceof URIRecord); } @Test - void test_ctor_6arg() throws TextParseException { + void ctor_6arg() throws TextParseException { Name n = Name.fromString("my.name."); String target = ("http://foo"); @@ -45,7 +45,7 @@ void test_ctor_6arg() throws TextParseException { } @Test - void test_rdataFromString() throws IOException { + void rdataFromString() throws IOException { Tokenizer t = new Tokenizer(0xABCD + " " + 0xEF01 + " \"http://foo:1234/bar?baz=bum\""); URIRecord r = new URIRecord(); @@ -56,7 +56,7 @@ void test_rdataFromString() throws IOException { } @Test - void test_rdataToWire() throws TextParseException { + void rdataToWire() throws TextParseException { Name n = Name.fromString("my.name."); String target = ("http://foo"); byte[] exp = @@ -84,7 +84,7 @@ void test_rdataToWire() throws TextParseException { } @Test - void test_rrFromWire() throws IOException { + void rrFromWire() throws IOException { byte[] raw = new byte[] { (byte) 0xbe, @@ -112,7 +112,7 @@ void test_rrFromWire() throws IOException { } @Test - void test_toobig_priority() throws TextParseException { + void toobig_priority() throws TextParseException { assertThrows( IllegalArgumentException.class, () -> @@ -121,14 +121,14 @@ void test_toobig_priority() throws TextParseException { } @Test - void test_toosmall_priority() throws TextParseException { + void toosmall_priority() throws TextParseException { assertThrows( IllegalArgumentException.class, () -> new URIRecord(Name.fromString("the.name"), DClass.IN, 0x1234, -1, 42, "http://foo")); } @Test - void test_toobig_weight() throws TextParseException { + void toobig_weight() throws TextParseException { assertThrows( IllegalArgumentException.class, () -> @@ -137,7 +137,7 @@ void test_toobig_weight() throws TextParseException { } @Test - void test_toosmall_weight() throws TextParseException { + void toosmall_weight() throws TextParseException { assertThrows( IllegalArgumentException.class, () -> new URIRecord(Name.fromString("the.name"), DClass.IN, 0x1234, 42, -1, "http://foo")); diff --git a/src/test/java/org/xbill/DNS/utils/base16Test.java b/src/test/java/org/xbill/DNS/utils/base16Test.java index 7d4409ddb..6f0a18df8 100644 --- a/src/test/java/org/xbill/DNS/utils/base16Test.java +++ b/src/test/java/org/xbill/DNS/utils/base16Test.java @@ -41,55 +41,55 @@ class base16Test { @Test - void test_toString_emptyArray() { + void toString_emptyArray() { String out = base16.toString(new byte[0]); assertEquals("", out); } @Test - void test_toString_singleByte1() { + void toString_singleByte1() { byte[] data = {(byte) 1}; String out = base16.toString(data); assertEquals("01", out); } @Test - void test_toString_singleByte2() { + void toString_singleByte2() { byte[] data = {(byte) 16}; String out = base16.toString(data); assertEquals("10", out); } @Test - void test_toString_singleByte3() { + void toString_singleByte3() { byte[] data = {(byte) 255}; String out = base16.toString(data); assertEquals("FF", out); } @Test - void test_toString_array1() { + void toString_array1() { byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; String out = base16.toString(data); assertEquals("0102030405060708090A0B0C0D0E0F", out); } @Test - void test_fromString_emptyString() { + void fromString_emptyString() { String data = ""; byte[] out = base16.fromString(data); assertEquals(0, out.length); } @Test - void test_fromString_invalidStringLength() { + void fromString_invalidStringLength() { String data = "1"; byte[] out = base16.fromString(data); assertNull(out); } @Test - void test_fromString_nonHexChars() { + void fromString_nonHexChars() { String data = "GG"; byte[] out = base16.fromString(data); /* @@ -99,7 +99,7 @@ void test_fromString_nonHexChars() { } @Test - void test_fromString_normal() { + void fromString_normal() { String data = "0102030405060708090A0B0C0D0E0F"; byte[] out = base16.fromString(data); byte[] exp = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; diff --git a/src/test/java/org/xbill/DNS/utils/base64Test.java b/src/test/java/org/xbill/DNS/utils/base64Test.java index 497096024..796634279 100644 --- a/src/test/java/org/xbill/DNS/utils/base64Test.java +++ b/src/test/java/org/xbill/DNS/utils/base64Test.java @@ -42,240 +42,240 @@ class base64Test { @Test - void test_toString_empty() { + void toString_empty() { byte[] data = new byte[0]; String out = base64.toString(data); assertEquals("", out); } @Test - void test_toString_basic1() { + void toString_basic1() { byte[] data = {0}; String out = base64.toString(data); assertEquals("AA==", out); } @Test - void test_toString_basic2() { + void toString_basic2() { byte[] data = {0, 0}; String out = base64.toString(data); assertEquals("AAA=", out); } @Test - void test_toString_basic3() { + void toString_basic3() { byte[] data = {0, 0, 1}; String out = base64.toString(data); assertEquals("AAAB", out); } @Test - void test_toString_basic4() { + void toString_basic4() { byte[] data = {(byte) 0xFC, 0, 0}; String out = base64.toString(data); assertEquals("/AAA", out); } @Test - void test_toString_basic5() { + void toString_basic5() { byte[] data = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; String out = base64.toString(data); assertEquals("////", out); } @Test - void test_toString_basic6() { + void toString_basic6() { byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9}; String out = base64.toString(data); assertEquals("AQIDBAUGBwgJ", out); } @Test - void test_formatString_empty1() { + void formatString_empty1() { String out = base64.formatString(new byte[0], 5, "", false); assertEquals("", out); } @Test - void test_formatString_shorter() { + void formatString_shorter() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 13, "", false); assertEquals("AQIDBAUGBwgJ", out); } @Test - void test_formatString_sameLength() { + void formatString_sameLength() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 12, "", false); assertEquals("AQIDBAUGBwgJ", out); } @Test - void test_formatString_oneBreak() { + void formatString_oneBreak() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 10, "", false); assertEquals("AQIDBAUGBw\ngJ", out); } @Test - void test_formatString_twoBreaks1() { + void formatString_twoBreaks1() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 5, "", false); assertEquals("AQIDB\nAUGBw\ngJ", out); } @Test - void test_formatString_twoBreaks2() { + void formatString_twoBreaks2() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 4, "", false); assertEquals("AQID\nBAUG\nBwgJ", out); } @Test - void test_formatString_shorterWithPrefix() { + void formatString_shorterWithPrefix() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 13, "!_", false); assertEquals("!_AQIDBAUGBwgJ", out); } @Test - void test_formatString_sameLengthWithPrefix() { + void formatString_sameLengthWithPrefix() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 12, "!_", false); assertEquals("!_AQIDBAUGBwgJ", out); } @Test - void test_formatString_oneBreakWithPrefix() { + void formatString_oneBreakWithPrefix() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 10, "!_", false); assertEquals("!_AQIDBAUGBw\n!_gJ", out); } @Test - void test_formatString_twoBreaks1WithPrefix() { + void formatString_twoBreaks1WithPrefix() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 5, "!_", false); assertEquals("!_AQIDB\n!_AUGBw\n!_gJ", out); } @Test - void test_formatString_twoBreaks2WithPrefix() { + void formatString_twoBreaks2WithPrefix() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 4, "!_", false); assertEquals("!_AQID\n!_BAUG\n!_BwgJ", out); } @Test - void test_formatString_shorterWithPrefixAndClose() { + void formatString_shorterWithPrefixAndClose() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 13, "!_", true); assertEquals("!_AQIDBAUGBwgJ )", out); } @Test - void test_formatString_sameLengthWithPrefixAndClose() { + void formatString_sameLengthWithPrefixAndClose() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 12, "!_", true); assertEquals("!_AQIDBAUGBwgJ )", out); } @Test - void test_formatString_oneBreakWithPrefixAndClose() { + void formatString_oneBreakWithPrefixAndClose() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 10, "!_", true); assertEquals("!_AQIDBAUGBw\n!_gJ )", out); } @Test - void test_formatString_twoBreaks1WithPrefixAndClose() { + void formatString_twoBreaks1WithPrefixAndClose() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 5, "!_", true); assertEquals("!_AQIDB\n!_AUGBw\n!_gJ )", out); } @Test - void test_formatString_twoBreaks2WithPrefixAndClose() { + void formatString_twoBreaks2WithPrefixAndClose() { byte[] in = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // "AQIDBAUGBwgJ" (12 chars) String out = base64.formatString(in, 4, "!_", true); assertEquals("!_AQID\n!_BAUG\n!_BwgJ )", out); } @Test - void test_fromString_empty1() { + void fromString_empty1() { byte[] data = new byte[0]; byte[] out = base64.fromString(""); assertArrayEquals(new byte[0], out); } @Test - void test_fromString_basic1() { + void fromString_basic1() { byte[] exp = {0}; byte[] out = base64.fromString("AA=="); assertArrayEquals(exp, out); } @Test - void test_fromString_basic2() { + void fromString_basic2() { byte[] exp = {0, 0}; byte[] out = base64.fromString("AAA="); assertArrayEquals(exp, out); } @Test - void test_fromString_basic3() { + void fromString_basic3() { byte[] exp = {0, 0, 1}; byte[] out = base64.fromString("AAAB"); assertArrayEquals(exp, out); } @Test - void test_fromString_basic4() { + void fromString_basic4() { byte[] exp = {(byte) 0xFC, 0, 0}; byte[] out = base64.fromString("/AAA"); assertArrayEquals(exp, out); } @Test - void test_fromString_basic5() { + void fromString_basic5() { byte[] exp = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; byte[] out = base64.fromString("////"); assertArrayEquals(exp, out); } @Test - void test_fromString_basic6() { + void fromString_basic6() { byte[] exp = {1, 2, 3, 4, 5, 6, 7, 8, 9}; byte[] out = base64.fromString("AQIDBAUGBwgJ"); assertArrayEquals(exp, out); } @Test - void test_fromString_invalid1() { + void fromString_invalid1() { byte[] out = base64.fromString("AAA"); assertNull(out); } @Test - void test_fromString_invalid2() { + void fromString_invalid2() { byte[] out = base64.fromString("AA"); assertNull(out); } @Test - void test_fromString_invalid3() { + void fromString_invalid3() { byte[] out = base64.fromString("A"); assertNull(out); } @Test - void test_fromString_invalid4() { + void fromString_invalid4() { byte[] out = base64.fromString("BB=="); assertNull(out); } @Test - void test_fromString_invalid5() { + void fromString_invalid5() { byte[] out = base64.fromString("BBB="); assertNull(out); } diff --git a/src/test/java/org/xbill/DNS/utils/hexdumpTest.java b/src/test/java/org/xbill/DNS/utils/hexdumpTest.java index 5d4e246bd..8c3fbf5cb 100644 --- a/src/test/java/org/xbill/DNS/utils/hexdumpTest.java +++ b/src/test/java/org/xbill/DNS/utils/hexdumpTest.java @@ -46,7 +46,7 @@ class hexdumpTest { */ @Test - void test_shortform() { + void shortform() { byte[] data = new byte[] { 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -172,10 +172,4 @@ void test_15() { String out = hexdump.dump(null, data, 1, 1); assertEquals("1b:\t0F \n", out); } - - // strictly for stupid code coverage...a useless test - @Test - void test_default_constructor() { - new hexdump(); - } } From b7f39297e4244cac9ef40ec7fc850c17c21eca00 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Oct 2019 16:07:54 +0100 Subject: [PATCH 004/431] Remove unnecessary exception declarations --- .../java/org/xbill/DNS/ZoneTransferIn.java | 14 +++++----- src/main/java/org/xbill/DNS/tools/update.java | 2 +- .../java/org/xbill/DNS/APLRecordTest.java | 26 +++++++++---------- .../java/org/xbill/DNS/EmptyRecordTest.java | 2 +- .../java/org/xbill/DNS/FormattedTimeTest.java | 2 +- .../java/org/xbill/DNS/GPOSRecordTest.java | 8 +++--- .../java/org/xbill/DNS/HINFORecordTest.java | 4 +-- .../java/org/xbill/DNS/NULLRecordTest.java | 3 +-- src/test/java/org/xbill/DNS/NameTest.java | 4 +-- .../java/org/xbill/DNS/OPTRecordTest.java | 3 +-- .../java/org/xbill/DNS/TKEYRecordTest.java | 3 +-- src/test/java/org/xbill/DNS/TSIGTest.java | 2 +- .../java/org/xbill/DNS/URIRecordTest.java | 8 +++--- 13 files changed, 38 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ZoneTransferIn.java b/src/main/java/org/xbill/DNS/ZoneTransferIn.java index 1ae574710..e9a9959a7 100644 --- a/src/main/java/org/xbill/DNS/ZoneTransferIn.java +++ b/src/main/java/org/xbill/DNS/ZoneTransferIn.java @@ -24,7 +24,6 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import lombok.extern.slf4j.Slf4j; @@ -94,31 +93,31 @@ private Delta() { public interface ZoneTransferHandler { /** Called when an AXFR transfer begins. */ - void startAXFR() throws ZoneTransferException; + void startAXFR(); /** Called when an IXFR transfer begins. */ - void startIXFR() throws ZoneTransferException; + void startIXFR(); /** * Called when a series of IXFR deletions begins. * * @param soa The starting SOA. */ - void startIXFRDeletes(Record soa) throws ZoneTransferException; + void startIXFRDeletes(Record soa); /** * Called when a series of IXFR adds begins. * * @param soa The starting SOA. */ - void startIXFRAdds(Record soa) throws ZoneTransferException; + void startIXFRAdds(Record soa); /** * Called for each content record in an AXFR. * * @param r The DNS record. */ - void handleRecord(Record r) throws ZoneTransferException; + void handleRecord(Record r); } private static class BasicHandler implements ZoneTransferHandler { @@ -270,10 +269,9 @@ public static ZoneTransferIn newIXFR( * @param host The host from which to transfer the zone. * @param key The TSIG key used to authenticate the transfer, or null. * @return The ZoneTransferIn object. - * @throws UnknownHostException The host does not exist. */ public static ZoneTransferIn newIXFR( - Name zone, long serial, boolean fallback, String host, TSIG key) throws UnknownHostException { + Name zone, long serial, boolean fallback, String host, TSIG key) { return newIXFR(zone, serial, fallback, host, 0, key); } diff --git a/src/main/java/org/xbill/DNS/tools/update.java b/src/main/java/org/xbill/DNS/tools/update.java index 2e229476c..1b507d0dc 100644 --- a/src/main/java/org/xbill/DNS/tools/update.java +++ b/src/main/java/org/xbill/DNS/tools/update.java @@ -678,7 +678,7 @@ static void help(String topic) { } } - public static void main(String[] args) throws IOException { + public static void main(String[] args) { InputStream in = null; if (args.length >= 1) { diff --git a/src/test/java/org/xbill/DNS/APLRecordTest.java b/src/test/java/org/xbill/DNS/APLRecordTest.java index ccddc41dd..f6952a67b 100644 --- a/src/test/java/org/xbill/DNS/APLRecordTest.java +++ b/src/test/java/org/xbill/DNS/APLRecordTest.java @@ -217,7 +217,7 @@ void validIPv4_short_address() throws IOException { } @Test - void invalid_IPv4_prefix() throws IOException { + void invalid_IPv4_prefix() { byte[] raw = new byte[] { 0, @@ -236,7 +236,7 @@ void invalid_IPv4_prefix() throws IOException { } @Test - void invalid_IPv4_length() throws IOException { + void invalid_IPv4_length() { byte[] raw = new byte[] { 0, @@ -404,77 +404,77 @@ void validIPv6() throws IOException { } @Test - void no_colon() throws IOException { + void no_colon() { Tokenizer t = new Tokenizer("!1192.68.0.1/20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void colon_and_slash_swapped() throws IOException { + void colon_and_slash_swapped() { Tokenizer t = new Tokenizer("!1/192.68.0.1:20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void no_slash() throws IOException { + void no_slash() { Tokenizer t = new Tokenizer("!1:192.68.0.1|20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void empty_family() throws IOException { + void empty_family() { Tokenizer t = new Tokenizer("!:192.68.0.1/20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void malformed_family() throws IOException { + void malformed_family() { Tokenizer t = new Tokenizer("family:192.68.0.1/20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void invalid_family() throws IOException { + void invalid_family() { Tokenizer t = new Tokenizer("3:192.68.0.1/20"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void empty_prefix() throws IOException { + void empty_prefix() { Tokenizer t = new Tokenizer("1:192.68.0.1/"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void malformed_prefix() throws IOException { + void malformed_prefix() { Tokenizer t = new Tokenizer("1:192.68.0.1/prefix"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void invalid_prefix() throws IOException { + void invalid_prefix() { Tokenizer t = new Tokenizer("1:192.68.0.1/33"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void empty_address() throws IOException { + void empty_address() { Tokenizer t = new Tokenizer("1:/33"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); } @Test - void malformed_address() throws IOException { + void malformed_address() { Tokenizer t = new Tokenizer("1:A.B.C.D/33"); APLRecord ar = new APLRecord(); assertThrows(TextParseException.class, () -> ar.rdataFromString(t, null)); diff --git a/src/test/java/org/xbill/DNS/EmptyRecordTest.java b/src/test/java/org/xbill/DNS/EmptyRecordTest.java index 887c557e0..bbb7d3373 100644 --- a/src/test/java/org/xbill/DNS/EmptyRecordTest.java +++ b/src/test/java/org/xbill/DNS/EmptyRecordTest.java @@ -59,7 +59,7 @@ void getObject() { } @Test - void rrFromWire() throws IOException { + void rrFromWire() { DNSInput i = new DNSInput(new byte[] {1, 2, 3, 4, 5}); i.jump(3); diff --git a/src/test/java/org/xbill/DNS/FormattedTimeTest.java b/src/test/java/org/xbill/DNS/FormattedTimeTest.java index e4d1325f1..8fe2aaf0b 100644 --- a/src/test/java/org/xbill/DNS/FormattedTimeTest.java +++ b/src/test/java/org/xbill/DNS/FormattedTimeTest.java @@ -54,7 +54,7 @@ void format() { } @Test - void parse() throws DateTimeParseException, TextParseException { + void parse() throws DateTimeParseException { // have to make sure to clear out the milliseconds since there // is occasionally a difference between when cal and cal2 are // instantiated. diff --git a/src/test/java/org/xbill/DNS/GPOSRecordTest.java b/src/test/java/org/xbill/DNS/GPOSRecordTest.java index 234176a14..f559dbc2f 100644 --- a/src/test/java/org/xbill/DNS/GPOSRecordTest.java +++ b/src/test/java/org/xbill/DNS/GPOSRecordTest.java @@ -237,7 +237,7 @@ void basic() throws IOException { } @Test - void longitude_toosmall() throws IOException { + void longitude_toosmall() { byte[] raw = new byte[] { 5, '-', '9', '5', '.', '0', 6, '1', '2', '3', '.', '0', '7', 3, '0', '.', '0' @@ -249,7 +249,7 @@ void longitude_toosmall() throws IOException { } @Test - void longitude_toobig() throws IOException { + void longitude_toobig() { byte[] raw = new byte[] { 5, '1', '8', '5', '.', '0', 6, '1', '2', '3', '.', '0', '7', 3, '0', '.', '0' @@ -261,7 +261,7 @@ void longitude_toobig() throws IOException { } @Test - void latitude_toosmall() throws IOException { + void latitude_toosmall() { byte[] raw = new byte[] { 5, '-', '8', '5', '.', '0', 6, '-', '1', '9', '0', '.', '0', 3, '0', '.', '0' @@ -273,7 +273,7 @@ void latitude_toosmall() throws IOException { } @Test - void latitude_toobig() throws IOException { + void latitude_toobig() { byte[] raw = new byte[] { 5, '-', '8', '5', '.', '0', 6, '2', '1', '9', '0', '.', '0', 3, '0', '.', '0' diff --git a/src/test/java/org/xbill/DNS/HINFORecordTest.java b/src/test/java/org/xbill/DNS/HINFORecordTest.java index 780fff232..7cfb71191 100644 --- a/src/test/java/org/xbill/DNS/HINFORecordTest.java +++ b/src/test/java/org/xbill/DNS/HINFORecordTest.java @@ -131,7 +131,7 @@ void rdataFromString() throws IOException { } @Test - void rdataFromString_invalid_CPU() throws IOException { + void rdataFromString_invalid_CPU() { String cpu = "Intel(R) Pentium(R) \\388 M processor 1.70GHz"; String os = "Linux troy 2.6.10-gentoo-r6"; @@ -142,7 +142,7 @@ void rdataFromString_invalid_CPU() throws IOException { } @Test - void rdataFromString_invalid_OS() throws IOException { + void rdataFromString_invalid_OS() { String cpu = "Intel(R) Pentium(R) M processor 1.70GHz"; Tokenizer t = new Tokenizer("\"" + cpu + "\""); diff --git a/src/test/java/org/xbill/DNS/NULLRecordTest.java b/src/test/java/org/xbill/DNS/NULLRecordTest.java index 3e906c3cc..9feb52af4 100644 --- a/src/test/java/org/xbill/DNS/NULLRecordTest.java +++ b/src/test/java/org/xbill/DNS/NULLRecordTest.java @@ -3,13 +3,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.IOException; import org.junit.jupiter.api.Test; class NULLRecordTest { @Test - void rdataFromString() throws IOException { + void rdataFromString() { TextParseException thrown = assertThrows( TextParseException.class, diff --git a/src/test/java/org/xbill/DNS/NameTest.java b/src/test/java/org/xbill/DNS/NameTest.java index c9bacddc4..4215f872e 100644 --- a/src/test/java/org/xbill/DNS/NameTest.java +++ b/src/test/java/org/xbill/DNS/NameTest.java @@ -516,7 +516,7 @@ void basic() throws IOException { } @Test - void incomplete() throws IOException { + void incomplete() { assertThrows(WireParseException.class, () -> new Name(new byte[] {3, 'W', 'w', 'w'})); } @@ -528,7 +528,7 @@ void root() throws WireParseException { } @Test - void invalid_length() throws IOException { + void invalid_length() { assertThrows(WireParseException.class, () -> new Name(new byte[] {4, 'W', 'w', 'w'})); } diff --git a/src/test/java/org/xbill/DNS/OPTRecordTest.java b/src/test/java/org/xbill/DNS/OPTRecordTest.java index 571210ec1..da88edf80 100644 --- a/src/test/java/org/xbill/DNS/OPTRecordTest.java +++ b/src/test/java/org/xbill/DNS/OPTRecordTest.java @@ -5,7 +5,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.IOException; import org.junit.jupiter.api.Test; class OPTRecordTest { @@ -39,7 +38,7 @@ void testForEquality() { } @Test - void rdataFromString() throws IOException { + void rdataFromString() { TextParseException thrown = assertThrows( TextParseException.class, diff --git a/src/test/java/org/xbill/DNS/TKEYRecordTest.java b/src/test/java/org/xbill/DNS/TKEYRecordTest.java index 10636c435..5b321c2cf 100644 --- a/src/test/java/org/xbill/DNS/TKEYRecordTest.java +++ b/src/test/java/org/xbill/DNS/TKEYRecordTest.java @@ -3,13 +3,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.IOException; import org.junit.jupiter.api.Test; class TKEYRecordTest { @Test - void rdataFromString() throws IOException { + void rdataFromString() { TextParseException thrown = assertThrows( TextParseException.class, diff --git a/src/test/java/org/xbill/DNS/TSIGTest.java b/src/test/java/org/xbill/DNS/TSIGTest.java index 983b2e84f..170dfea55 100644 --- a/src/test/java/org/xbill/DNS/TSIGTest.java +++ b/src/test/java/org/xbill/DNS/TSIGTest.java @@ -79,7 +79,7 @@ void TSIG_truncated() throws IOException { } @Test - void rdataFromString() throws IOException { + void rdataFromString() { TextParseException thrown = assertThrows( TextParseException.class, diff --git a/src/test/java/org/xbill/DNS/URIRecordTest.java b/src/test/java/org/xbill/DNS/URIRecordTest.java index e22489d03..52f8fe3bc 100644 --- a/src/test/java/org/xbill/DNS/URIRecordTest.java +++ b/src/test/java/org/xbill/DNS/URIRecordTest.java @@ -112,7 +112,7 @@ void rrFromWire() throws IOException { } @Test - void toobig_priority() throws TextParseException { + void toobig_priority() { assertThrows( IllegalArgumentException.class, () -> @@ -121,14 +121,14 @@ void toobig_priority() throws TextParseException { } @Test - void toosmall_priority() throws TextParseException { + void toosmall_priority() { assertThrows( IllegalArgumentException.class, () -> new URIRecord(Name.fromString("the.name"), DClass.IN, 0x1234, -1, 42, "http://foo")); } @Test - void toobig_weight() throws TextParseException { + void toobig_weight() { assertThrows( IllegalArgumentException.class, () -> @@ -137,7 +137,7 @@ void toobig_weight() throws TextParseException { } @Test - void toosmall_weight() throws TextParseException { + void toosmall_weight() { assertThrows( IllegalArgumentException.class, () -> new URIRecord(Name.fromString("the.name"), DClass.IN, 0x1234, 42, -1, "http://foo")); From 937c54c691359c767d6cb13442bcafcaca03a127 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Oct 2019 16:37:22 +0100 Subject: [PATCH 005/431] Remove lookup to cnn.com to avoid network access --- src/test/java/org/xbill/DNS/AddressTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/test/java/org/xbill/DNS/AddressTest.java b/src/test/java/org/xbill/DNS/AddressTest.java index 43fdc7bd9..fa8a21d41 100644 --- a/src/test/java/org/xbill/DNS/AddressTest.java +++ b/src/test/java/org/xbill/DNS/AddressTest.java @@ -327,11 +327,6 @@ void getAllByName() throws UnknownHostException { assertEquals("198.41.0.4", out[0].getHostAddress()); assertEquals("2001:503:ba3e:0:0:0:2:30", out[1].getHostAddress()); - out = Address.getAllByName("cnn.com"); - assertTrue(out.length > 1); - for (InetAddress inetAddress : out) { - assertTrue(inetAddress.getHostName().endsWith("cnn.com")); - } } @Test From dc897e67f81cdf940a5de135c9a17446998b33d3 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Oct 2019 16:53:12 +0100 Subject: [PATCH 006/431] Use mocks for address lookups to avoid network access Closes #77 --- pom.xml | 6 ++ src/test/java/org/xbill/DNS/AddressTest.java | 107 ++++++++++++++++++- 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 63cfa39b6..dc0ddec1d 100644 --- a/pom.xml +++ b/pom.xml @@ -227,6 +227,12 @@ ${org.junit.version} test + + org.mockito + mockito-core + 3.1.0 + test + diff --git a/src/test/java/org/xbill/DNS/AddressTest.java b/src/test/java/org/xbill/DNS/AddressTest.java index fa8a21d41..f894fcf49 100644 --- a/src/test/java/org/xbill/DNS/AddressTest.java +++ b/src/test/java/org/xbill/DNS/AddressTest.java @@ -40,10 +40,17 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; +import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; class AddressTest { @Test @@ -302,36 +309,105 @@ void addressLength() { } @Test - void getByName() throws UnknownHostException { + void getByName() throws IOException { InetAddress out = Address.getByName("128.145.198.231"); assertEquals("128.145.198.231", out.getHostAddress()); + Name aRootServer = Name.fromString("a.root-servers.net."); + Message aMessage = new Message(); + aMessage.getHeader().setRcode(Rcode.NOERROR); + aMessage.addRecord(Record.newRecord(aRootServer, Type.A, DClass.IN), Section.QUESTION); + aMessage.addRecord( + new ARecord( + aRootServer, + DClass.IN, + 60, + InetAddress.getByAddress(new byte[] {(byte) 198, 41, 0, 4})), + Section.ANSWER); + + Resolver mockResolver = Mockito.mock(Resolver.class); + when(mockResolver.send(ArgumentMatchers.any(Message.class))).thenReturn(aMessage); + Lookup.setDefaultResolver(mockResolver); + out = Address.getByName("a.root-servers.net"); assertEquals("198.41.0.4", out.getHostAddress()); + + // reset resolver + Lookup.refreshDefault(); } @Test - void getByName_invalid() { + void getByName_invalid() throws IOException { + Message m = new Message(); + m.getHeader().setRcode(Rcode.NXDOMAIN); + Resolver mockResolver = Mockito.mock(Resolver.class); + when(mockResolver.send(ArgumentMatchers.any(Message.class))).thenReturn(m); + Lookup.setDefaultResolver(mockResolver); assertThrows(UnknownHostException.class, () -> Address.getByName("example.invalid")); + // reset resolver + Lookup.refreshDefault(); + assertThrows(UnknownHostException.class, () -> Address.getByName("")); } @Test - void getAllByName() throws UnknownHostException { + void getAllByName() throws IOException { InetAddress[] out = Address.getAllByName("128.145.198.231"); assertEquals(1, out.length); assertEquals("128.145.198.231", out[0].getHostAddress()); + Name aRootServer = Name.fromString("a.root-servers.net."); + Message aMessage = new Message(); + aMessage.getHeader().setRcode(Rcode.NOERROR); + aMessage.addRecord(Record.newRecord(aRootServer, Type.A, DClass.IN), Section.QUESTION); + aMessage.addRecord( + new ARecord( + aRootServer, + DClass.IN, + 60, + InetAddress.getByAddress(new byte[] {(byte) 198, 41, 0, 4})), + Section.ANSWER); + Message aaaaMessage = new Message(); + aaaaMessage.getHeader().setRcode(Rcode.NOERROR); + aaaaMessage.addRecord(Record.newRecord(aRootServer, Type.AAAA, DClass.IN), Section.QUESTION); + aaaaMessage.addRecord( + new AAAARecord( + aRootServer, + DClass.IN, + 60, + InetAddress.getByAddress( + new byte[] {0x20, 1, 5, 3, (byte) 0xba, 0x3e, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0x30})), + Section.ANSWER); + Resolver mockResolver = Mockito.mock(Resolver.class); + doReturn(aMessage) + .when(mockResolver) + .send(argThat(message -> message.getQuestion().getType() == Type.A)); + doReturn(aaaaMessage) + .when(mockResolver) + .send(argThat(message -> message.getQuestion().getType() == Type.AAAA)); + Lookup.setDefaultResolver(mockResolver); + out = Address.getAllByName("a.root-servers.net"); assertEquals(2, out.length); assertEquals("198.41.0.4", out[0].getHostAddress()); assertEquals("2001:503:ba3e:0:0:0:2:30", out[1].getHostAddress()); + // reset resolver + Lookup.refreshDefault(); } @Test - void getAllByName_invalid() { + void getAllByName_invalid() throws IOException { + Message m = new Message(); + m.getHeader().setRcode(Rcode.NXDOMAIN); + Resolver mockResolver = Mockito.mock(Resolver.class); + when(mockResolver.send(ArgumentMatchers.any(Message.class))).thenReturn(m); + Lookup.setDefaultResolver(mockResolver); assertThrows(UnknownHostException.class, () -> Address.getAllByName("example.invalid")); + + // reset resolver + Lookup.refreshDefault(); + assertThrows(UnknownHostException.class, () -> Address.getAllByName("")); } @@ -343,12 +419,33 @@ void familyOf() throws UnknownHostException { } @Test - void getHostName() throws UnknownHostException { + void getHostName() throws IOException { + Name aRootServer = Name.fromString("a.root-servers.net."); + Name aRootServerPtr = Name.fromString("4.0.41.198.in-addr.arpa."); + Message ptrMessage = new Message(); + ptrMessage.getHeader().setRcode(Rcode.NOERROR); + ptrMessage.addRecord(Record.newRecord(aRootServerPtr, Type.PTR, DClass.IN), Section.QUESTION); + ptrMessage.addRecord(new PTRRecord(aRootServerPtr, DClass.IN, 60, aRootServer), Section.ANSWER); + Resolver mockResolver = Mockito.mock(Resolver.class); + when(mockResolver.send(any(Message.class))).thenReturn(ptrMessage); + Lookup.setDefaultResolver(mockResolver); + String out = Address.getHostName(InetAddress.getByName("198.41.0.4")); assertEquals("a.root-servers.net.", out); + Message ptrMessage2 = new Message(); + ptrMessage.getHeader().setRcode(Rcode.NXDOMAIN); + ptrMessage.addRecord( + Record.newRecord(Name.fromString("1.1.168.192.in-addr.arpa."), Type.PTR, DClass.IN), + Section.QUESTION); + mockResolver = Mockito.mock(Resolver.class); + when(mockResolver.send(any())).thenReturn(ptrMessage2); + Lookup.setDefaultResolver(mockResolver); assertThrows( UnknownHostException.class, () -> Address.getHostName(InetAddress.getByName("192.168.1.1"))); + + // reset resolver + Lookup.refreshDefault(); } } From 37028fd011c2721b1f24546e52687b8ed6d8ea0a Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Oct 2019 19:52:22 +0100 Subject: [PATCH 007/431] Remove unnecessary string concats after applying Java formatting --- src/main/java/org/xbill/DNS/APLRecord.java | 2 +- .../org/xbill/DNS/ClientSubnetOption.java | 4 +- src/main/java/org/xbill/DNS/DNSInput.java | 6 +-- src/main/java/org/xbill/DNS/DNSOutput.java | 4 +- src/main/java/org/xbill/DNS/Header.java | 4 +- .../java/org/xbill/DNS/IPSECKEYRecord.java | 8 ++-- .../java/org/xbill/DNS/NSEC3PARAMRecord.java | 2 +- src/main/java/org/xbill/DNS/Name.java | 6 +-- src/main/java/org/xbill/DNS/Record.java | 10 ++--- src/main/java/org/xbill/DNS/ReverseMap.java | 4 +- .../java/org/xbill/DNS/SimpleResolver.java | 4 +- src/main/java/org/xbill/DNS/TSIG.java | 4 +- src/main/java/org/xbill/DNS/Tokenizer.java | 4 +- src/main/java/org/xbill/DNS/Zone.java | 2 +- .../java/org/xbill/DNS/ZoneTransferIn.java | 6 +-- src/main/java/org/xbill/DNS/tools/dig.java | 4 +- src/main/java/org/xbill/DNS/tools/update.java | 40 +++++++++---------- src/main/java/org/xbill/DNS/tools/xfrin.java | 2 +- 18 files changed, 57 insertions(+), 59 deletions(-) diff --git a/src/main/java/org/xbill/DNS/APLRecord.java b/src/main/java/org/xbill/DNS/APLRecord.java index ee0486c92..acaf613e4 100644 --- a/src/main/java/org/xbill/DNS/APLRecord.java +++ b/src/main/java/org/xbill/DNS/APLRecord.java @@ -35,7 +35,7 @@ private Element(int family, boolean negative, Object address, int prefixLength) this.address = address; this.prefixLength = prefixLength; if (!validatePrefixLength(family, prefixLength)) { - throw new IllegalArgumentException("invalid prefix " + "length"); + throw new IllegalArgumentException("invalid prefix length"); } } diff --git a/src/main/java/org/xbill/DNS/ClientSubnetOption.java b/src/main/java/org/xbill/DNS/ClientSubnetOption.java index 032b03e77..2bc8dda8a 100644 --- a/src/main/java/org/xbill/DNS/ClientSubnetOption.java +++ b/src/main/java/org/xbill/DNS/ClientSubnetOption.java @@ -42,7 +42,7 @@ private static int checkMaskLength(String field, int family, int val) { int max = Address.addressLength(family) * 8; if (val < 0 || val > max) { throw new IllegalArgumentException( - "\"" + field + "\" " + val + " must be in the range " + "[0.." + max + "]"); + "\"" + field + "\" " + val + " must be in the range [0.." + max + "]"); } return val; } @@ -67,7 +67,7 @@ public ClientSubnetOption(int sourceNetmask, int scopeNetmask, InetAddress addre this.address = Address.truncate(address, sourceNetmask); if (!address.equals(this.address)) { - throw new IllegalArgumentException("source netmask is not " + "valid for address"); + throw new IllegalArgumentException("source netmask is not valid for address"); } } diff --git a/src/main/java/org/xbill/DNS/DNSInput.java b/src/main/java/org/xbill/DNS/DNSInput.java index 42f175fda..7b6295d72 100644 --- a/src/main/java/org/xbill/DNS/DNSInput.java +++ b/src/main/java/org/xbill/DNS/DNSInput.java @@ -62,7 +62,7 @@ private void require(int n) throws WireParseException { */ public void setActive(int len) { if (len > byteBuffer.capacity() - byteBuffer.position()) { - throw new IllegalArgumentException("cannot set active " + "region past end of input"); + throw new IllegalArgumentException("cannot set active region past end of input"); } byteBuffer.limit(byteBuffer.position() + len); } @@ -89,7 +89,7 @@ public int saveActive() { */ public void restoreActive(int pos) { if (pos > byteBuffer.capacity()) { - throw new IllegalArgumentException("cannot set active " + "region past end of input"); + throw new IllegalArgumentException("cannot set active region past end of input"); } byteBuffer.limit(byteBuffer.position()); } @@ -103,7 +103,7 @@ public void restoreActive(int pos) { */ public void jump(int index) { if (index >= byteBuffer.capacity()) { - throw new IllegalArgumentException("cannot jump past " + "end of input"); + throw new IllegalArgumentException("cannot jump past end of input"); } byteBuffer.position(index); byteBuffer.limit(byteBuffer.capacity()); diff --git a/src/main/java/org/xbill/DNS/DNSOutput.java b/src/main/java/org/xbill/DNS/DNSOutput.java index d0974768c..5080237cd 100644 --- a/src/main/java/org/xbill/DNS/DNSOutput.java +++ b/src/main/java/org/xbill/DNS/DNSOutput.java @@ -63,7 +63,7 @@ private void need(int n) { */ public void jump(int index) { if (index > pos) { - throw new IllegalArgumentException("cannot jump past " + "end of data"); + throw new IllegalArgumentException("cannot jump past end of data"); } pos = index; } @@ -118,7 +118,7 @@ public void writeU16(int val) { public void writeU16At(int val, int where) { check(val, 16); if (where > pos - 2) { - throw new IllegalArgumentException("cannot write past " + "end of data"); + throw new IllegalArgumentException("cannot write past end of data"); } array[where++] = (byte) ((val >>> 8) & 0xFF); array[where++] = (byte) (val & 0xFF); diff --git a/src/main/java/org/xbill/DNS/Header.java b/src/main/java/org/xbill/DNS/Header.java index b37a15681..a688b5989 100644 --- a/src/main/java/org/xbill/DNS/Header.java +++ b/src/main/java/org/xbill/DNS/Header.java @@ -211,14 +211,14 @@ void setCount(int field, int value) { void incCount(int field) { if (counts[field] == 0xFFFF) { - throw new IllegalStateException("DNS section count cannot " + "be incremented"); + throw new IllegalStateException("DNS section count cannot be incremented"); } counts[field]++; } void decCount(int field) { if (counts[field] == 0) { - throw new IllegalStateException("DNS section count cannot " + "be decremented"); + throw new IllegalStateException("DNS section count cannot be decremented"); } counts[field]--; } diff --git a/src/main/java/org/xbill/DNS/IPSECKEYRecord.java b/src/main/java/org/xbill/DNS/IPSECKEYRecord.java index 3e1e492cc..bf3f869e9 100644 --- a/src/main/java/org/xbill/DNS/IPSECKEYRecord.java +++ b/src/main/java/org/xbill/DNS/IPSECKEYRecord.java @@ -75,24 +75,24 @@ public IPSECKEYRecord( break; case Gateway.IPv4: if (!(gateway instanceof InetAddress)) { - throw new IllegalArgumentException("\"gateway\" " + "must be an IPv4 " + "address"); + throw new IllegalArgumentException("\"gateway\" must be an IPv4 address"); } this.gateway = gateway; break; case Gateway.IPv6: if (!(gateway instanceof Inet6Address)) { - throw new IllegalArgumentException("\"gateway\" " + "must be an IPv6 " + "address"); + throw new IllegalArgumentException("\"gateway\" must be an IPv6 address"); } this.gateway = gateway; break; case Gateway.Name: if (!(gateway instanceof Name)) { - throw new IllegalArgumentException("\"gateway\" " + "must be a DNS " + "name"); + throw new IllegalArgumentException("\"gateway\" must be a DNS name"); } this.gateway = checkName("gateway", (Name) gateway); break; default: - throw new IllegalArgumentException("\"gatewayType\" " + "must be between 0 and 3"); + throw new IllegalArgumentException("\"gatewayType\" must be between 0 and 3"); } this.key = key; diff --git a/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java b/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java index fe048e2ae..afb6727ed 100644 --- a/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java +++ b/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java @@ -53,7 +53,7 @@ public NSEC3PARAMRecord( if (salt != null) { if (salt.length > 255) { - throw new IllegalArgumentException("Invalid salt " + "length"); + throw new IllegalArgumentException("Invalid salt length"); } if (salt.length > 0) { this.salt = new byte[salt.length]; diff --git a/src/main/java/org/xbill/DNS/Name.java b/src/main/java/org/xbill/DNS/Name.java index 8dc894de5..490362226 100644 --- a/src/main/java/org/xbill/DNS/Name.java +++ b/src/main/java/org/xbill/DNS/Name.java @@ -410,7 +410,7 @@ public Name(byte[] b) throws IOException { public Name(Name src, int n) { int slabels = src.labels(); if (n > slabels) { - throw new IllegalArgumentException("attempted to remove too " + "many labels"); + throw new IllegalArgumentException("attempted to remove too many labels"); } name = src.name; setlabels(slabels - n); @@ -465,7 +465,7 @@ public Name relativize(Name origin) { */ public Name wild(int n) { if (n < 1) { - throw new IllegalArgumentException("must replace 1 or more " + "labels"); + throw new IllegalArgumentException("must replace 1 or more labels"); } try { Name newname = new Name(); @@ -679,7 +679,7 @@ public String getLabelString(int n) { */ public void toWire(DNSOutput out, Compression c) { if (!isAbsolute()) { - throw new IllegalArgumentException("toWire() called on " + "non-absolute name"); + throw new IllegalArgumentException("toWire() called on non-absolute name"); } int labels = labels(); diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index f85a851ed..dd813edf6 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -436,7 +436,7 @@ public static Record fromString( data = new byte[0]; } if (length != data.length) { - throw st.exception("invalid unknown RR encoding: " + "length mismatch"); + throw st.exception("invalid unknown RR encoding: length mismatch"); } DNSInput in = new DNSInput(data); return newRecord(name, type, dclass, ttl, length, in); @@ -643,7 +643,7 @@ public Name getAdditionalName() { static int checkU8(String field, int val) { if (val < 0 || val > 0xFF) { throw new IllegalArgumentException( - "\"" + field + "\" " + val + " must be an unsigned 8 " + "bit value"); + "\"" + field + "\" " + val + " must be an unsigned 8 bit value"); } return val; } @@ -652,7 +652,7 @@ static int checkU8(String field, int val) { static int checkU16(String field, int val) { if (val < 0 || val > 0xFFFF) { throw new IllegalArgumentException( - "\"" + field + "\" " + val + " must be an unsigned 16 " + "bit value"); + "\"" + field + "\" " + val + " must be an unsigned 16 bit value"); } return val; } @@ -661,7 +661,7 @@ static int checkU16(String field, int val) { static long checkU32(String field, long val) { if (val < 0 || val > 0xFFFFFFFFL) { throw new IllegalArgumentException( - "\"" + field + "\" " + val + " must be an unsigned 32 " + "bit value"); + "\"" + field + "\" " + val + " must be an unsigned 32 bit value"); } return val; } @@ -678,7 +678,7 @@ static Name checkName(String field, Name name) { static byte[] checkByteArrayLength(String field, byte[] array, int maxLength) { if (array.length > 0xFFFF) { throw new IllegalArgumentException( - "\"" + field + "\" array " + "must have no more than " + maxLength + " elements"); + "\"" + field + "\" array must have no more than " + maxLength + " elements"); } byte[] out = new byte[array.length]; System.arraycopy(array, 0, out, 0, array.length); diff --git a/src/main/java/org/xbill/DNS/ReverseMap.java b/src/main/java/org/xbill/DNS/ReverseMap.java index 55bf3b80c..7d9b5f8c7 100644 --- a/src/main/java/org/xbill/DNS/ReverseMap.java +++ b/src/main/java/org/xbill/DNS/ReverseMap.java @@ -29,7 +29,7 @@ private ReverseMap() {} */ public static Name fromAddress(byte[] addr) { if (addr.length != 4 && addr.length != 16) { - throw new IllegalArgumentException("array must contain " + "4 or 16 elements"); + throw new IllegalArgumentException("array must contain 4 or 16 elements"); } StringBuilder sb = new StringBuilder(); @@ -76,7 +76,7 @@ public static Name fromAddress(int[] addr) { byte[] bytes = new byte[addr.length]; for (int i = 0; i < addr.length; i++) { if (addr[i] < 0 || addr[i] > 0xFF) { - throw new IllegalArgumentException("array must " + "contain values " + "between 0 and 255"); + throw new IllegalArgumentException("array must contain values between 0 and 255"); } bytes[i] = (byte) addr[i]; } diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index 67e90072c..7bb4cbd6f 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -140,7 +140,7 @@ public void setIgnoreTruncation(boolean flag) { @Override public void setEDNS(int level, int payloadSize, int flags, List options) { if (level != 0 && level != -1) { - throw new IllegalArgumentException("invalid EDNS level - " + "must be 0 or -1"); + throw new IllegalArgumentException("invalid EDNS level - must be 0 or -1"); } if (payloadSize == 0) { payloadSize = DEFAULT_EDNS_PAYLOADSIZE; @@ -256,7 +256,7 @@ public Message send(Message query) throws IOException { * Check that the response is long enough. */ if (in.length < Header.LENGTH) { - throw new WireParseException("invalid DNS header - " + "too short"); + throw new WireParseException("invalid DNS header - too short"); } /* * Check that the response ID matches the query ID. We want diff --git a/src/main/java/org/xbill/DNS/TSIG.java b/src/main/java/org/xbill/DNS/TSIG.java index 93d138fcf..e54bd28db 100644 --- a/src/main/java/org/xbill/DNS/TSIG.java +++ b/src/main/java/org/xbill/DNS/TSIG.java @@ -118,7 +118,7 @@ private void init_hmac(String macAlgorithm, SecretKey key) { hmac = Mac.getInstance(macAlgorithm); hmac.init(key); } catch (GeneralSecurityException ex) { - throw new IllegalArgumentException("Caught security " + "exception setting up " + "HMAC."); + throw new IllegalArgumentException("Caught security exception setting up HMAC."); } } @@ -238,7 +238,7 @@ public TSIG(String name, String key) { public static TSIG fromString(String str) { String[] parts = str.split("[:/]", 3); if (parts.length < 2) { - throw new IllegalArgumentException("Invalid TSIG key " + "specification"); + throw new IllegalArgumentException("Invalid TSIG key specification"); } if (parts.length == 3) { try { diff --git a/src/main/java/org/xbill/DNS/Tokenizer.java b/src/main/java/org/xbill/DNS/Tokenizer.java index 7c7342588..2e2bbbe11 100644 --- a/src/main/java/org/xbill/DNS/Tokenizer.java +++ b/src/main/java/org/xbill/DNS/Tokenizer.java @@ -251,7 +251,7 @@ public Token get(boolean wantWhitespace, boolean wantComment) throws IOException if (c == -1 || delimiters.indexOf(c) != -1) { if (c == -1) { if (quoting) { - throw exception("EOF in " + "quoted string"); + throw exception("EOF in quoted string"); } else if (sb.length() == 0) { return current.set(EOF, null); } else { @@ -265,7 +265,7 @@ public Token get(boolean wantWhitespace, boolean wantComment) throws IOException continue; } else if (c == ')') { if (multiline <= 0) { - throw exception("invalid " + "close " + "parenthesis"); + throw exception("invalid close parenthesis"); } multiline--; skipWhitespace(); diff --git a/src/main/java/org/xbill/DNS/Zone.java b/src/main/java/org/xbill/DNS/Zone.java index 0efaddca2..e0510e35b 100644 --- a/src/main/java/org/xbill/DNS/Zone.java +++ b/src/main/java/org/xbill/DNS/Zone.java @@ -182,7 +182,7 @@ private void fromXFR(ZoneTransferIn xfrin) throws IOException, ZoneTransferExcep maybeAddRecord(record); } if (!xfrin.isAXFR()) { - throw new IllegalArgumentException("zones can only be " + "created from AXFRs"); + throw new IllegalArgumentException("zones can only be created from AXFRs"); } validate(); } diff --git a/src/main/java/org/xbill/DNS/ZoneTransferIn.java b/src/main/java/org/xbill/DNS/ZoneTransferIn.java index e9a9959a7..704f02e29 100644 --- a/src/main/java/org/xbill/DNS/ZoneTransferIn.java +++ b/src/main/java/org/xbill/DNS/ZoneTransferIn.java @@ -176,7 +176,7 @@ private ZoneTransferIn( try { zname = Name.concatenate(zone, Name.root); } catch (NameTooLongException e) { - throw new IllegalArgumentException("ZoneTransferIn: " + "name too long"); + throw new IllegalArgumentException("ZoneTransferIn: name too long"); } } qtype = xfrtype; @@ -292,7 +292,7 @@ public int getType() { */ public void setTimeout(int secs) { if (secs < 0) { - throw new IllegalArgumentException("timeout cannot be " + "negative"); + throw new IllegalArgumentException("timeout cannot be negative"); } timeout = 1000L * secs; } @@ -573,7 +573,7 @@ private BasicHandler getBasicHandler() throws IllegalArgumentException { if (handler instanceof BasicHandler) { return (BasicHandler) handler; } - throw new IllegalArgumentException("ZoneTransferIn used callback " + "interface"); + throw new IllegalArgumentException("ZoneTransferIn used callback interface"); } /** diff --git a/src/main/java/org/xbill/DNS/tools/dig.java b/src/main/java/org/xbill/DNS/tools/dig.java index 45af9ef45..cca5b1b8b 100644 --- a/src/main/java/org/xbill/DNS/tools/dig.java +++ b/src/main/java/org/xbill/DNS/tools/dig.java @@ -22,7 +22,7 @@ public class dig { static int type = Type.A, dclass = DClass.IN; static void usage() { - System.out.println("Usage: dig [@server] name [] [] " + "[options]"); + System.out.println("Usage: dig [@server] name [] [] [options]"); System.exit(0); } @@ -170,7 +170,7 @@ public static void main(String[] argv) throws IOException { } edns = Integer.parseInt(ednsStr); if (edns < 0 || edns > 1) { - System.out.println("Unsupported " + "EDNS level: " + edns); + System.out.println("Unsupported EDNS level: " + edns); return; } res.setEDNS(edns); diff --git a/src/main/java/org/xbill/DNS/tools/update.java b/src/main/java/org/xbill/DNS/tools/update.java index 1b507d0dc..f88ac54be 100644 --- a/src/main/java/org/xbill/DNS/tools/update.java +++ b/src/main/java/org/xbill/DNS/tools/update.java @@ -561,7 +561,7 @@ static void help(String topic) { switch (topic) { case "add": System.out.println( - "add [ttl] [class] \n\n" + "specify a record to be added\n"); + "add [ttl] [class] \n\nspecify a record to be added\n"); break; case "assert": System.out.println( @@ -573,10 +573,10 @@ static void help(String topic) { + ", , , , , or .\n"); break; case "class": - System.out.println("class \n\n" + "class of the zone to be updated (default: IN)\n"); + System.out.println("class \n\nclass of the zone to be updated (default: IN)\n"); break; case "clear": - System.out.println("clear\n\n" + "clears the current update packet\n"); + System.out.println("clear\n\nclears the current update packet\n"); break; case "date": System.out.println( @@ -594,10 +594,10 @@ static void help(String topic) { + "all records at a name should be deleted\n"); break; case "echo": - System.out.println("echo \n\n" + "prints the text\n"); + System.out.println("echo \n\nprints the text\n"); break; case "edns": - System.out.println("edns \n\n" + "EDNS level specified when sending messages\n"); + System.out.println("edns \n\nEDNS level specified when sending messages\n"); break; case "file": System.out.println( @@ -607,7 +607,7 @@ static void help(String topic) { break; case "glue": System.out.println( - "glue [ttl] [class] \n\n" + "specify an additional record\n"); + "glue [ttl] [class] \n\nspecify an additional record\n"); break; case "help": System.out.println( @@ -617,14 +617,13 @@ static void help(String topic) { + "command\n"); break; case "key": - System.out.println("key \n\n" + "TSIG key used to sign messages\n"); + System.out.println("key \n\nTSIG key used to sign messages\n"); break; case "log": - System.out.println( - "log \n\n" + "opens the specified file and uses it to log output\n"); + System.out.println("log \n\nopens the specified file and uses it to log output\n"); break; case "port": - System.out.println("port \n\n" + "UDP/TCP port messages are sent to (default: 53)\n"); + System.out.println("port \n\nUDP/TCP port messages are sent to (default: 53)\n"); break; case "prohibit": System.out.println( @@ -633,11 +632,11 @@ static void help(String topic) { + "require that a set or name is not present\n"); break; case "query": - System.out.println("query [type [class]] \n\n" + "issues a query\n"); + System.out.println("query [type [class]] \n\nissues a query\n"); break; case "q": case "quit": - System.out.println("quit\n\n" + "quits the program\n"); + System.out.println("quit\n\nquits the program\n"); break; case "require": System.out.println( @@ -647,30 +646,29 @@ static void help(String topic) { + "require that a record, set, or name is present\n"); break; case "send": - System.out.println("send\n\n" + "sends and resets the current update packet\n"); + System.out.println("send\n\nsends and resets the current update packet\n"); break; case "server": - System.out.println( - "server [port]\n\n" + "server that receives send updates/queries\n"); + System.out.println("server [port]\n\nserver that receives send updates/queries\n"); break; case "show": - System.out.println("show\n\n" + "shows the current update packet\n"); + System.out.println("show\n\nshows the current update packet\n"); break; case "sleep": - System.out.println("sleep \n\n" + "pause for interval before next command\n"); + System.out.println("sleep \n\npause for interval before next command\n"); break; case "tcp": - System.out.println("tcp\n\n" + "TCP should be used to send all messages\n"); + System.out.println("tcp\n\nTCP should be used to send all messages\n"); break; case "ttl": - System.out.println("ttl \n\n" + "default ttl of added records (default: 0)\n"); + System.out.println("ttl \n\ndefault ttl of added records (default: 0)\n"); break; case "zone": case "origin": - System.out.println("zone \n\n" + "zone to update (default: .\n"); + System.out.println("zone \n\nzone to update (default: .\n"); break; case "#": - System.out.println("# \n\n" + "a comment\n"); + System.out.println("# \n\na comment\n"); break; default: System.out.println("Topic '" + topic + "' unrecognized\n"); diff --git a/src/main/java/org/xbill/DNS/tools/xfrin.java b/src/main/java/org/xbill/DNS/tools/xfrin.java index 042ecb107..8e4392cc2 100644 --- a/src/main/java/org/xbill/DNS/tools/xfrin.java +++ b/src/main/java/org/xbill/DNS/tools/xfrin.java @@ -17,7 +17,7 @@ public class xfrin { private static void usage(String s) { System.out.println("Error: " + s); System.out.println( - "usage: xfrin [-i serial] [-k keyname/secret] " + "[-s server] [-p port] [-f] zone"); + "usage: xfrin [-i serial] [-k keyname/secret] [-s server] [-p port] [-f] zone"); System.exit(1); } From 57b9f26e5c88dd23425dd645e977287643dc84e5 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Oct 2019 20:03:31 +0100 Subject: [PATCH 008/431] Properly implement clone to return the actual object in a hierarchy --- src/main/java/org/xbill/DNS/DNSSEC.java | 2 +- src/main/java/org/xbill/DNS/Header.java | 9 +++++++-- src/main/java/org/xbill/DNS/Message.java | 11 ++++++++--- src/main/java/org/xbill/DNS/SimpleResolver.java | 2 +- src/test/java/org/xbill/DNS/HeaderTest.java | 2 +- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/xbill/DNS/DNSSEC.java b/src/main/java/org/xbill/DNS/DNSSEC.java index 34509d46d..33d29cd97 100644 --- a/src/main/java/org/xbill/DNS/DNSSEC.java +++ b/src/main/java/org/xbill/DNS/DNSSEC.java @@ -1201,7 +1201,7 @@ static void verifyMessage( out.writeByteArray(previous.getSignature()); } - Header header = (Header) message.getHeader().clone(); + Header header = message.getHeader().clone(); header.decCount(Section.ADDITIONAL); out.writeByteArray(header.toWire()); diff --git a/src/main/java/org/xbill/DNS/Header.java b/src/main/java/org/xbill/DNS/Header.java index a688b5989..51c40ad15 100644 --- a/src/main/java/org/xbill/DNS/Header.java +++ b/src/main/java/org/xbill/DNS/Header.java @@ -274,8 +274,13 @@ public String toString() { /* Creates a new Header identical to the current one */ @Override - public Object clone() { - Header h = new Header(); + public Header clone() { + Header h; + try { + h = (Header) super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } h.id = id; h.flags = flags; System.arraycopy(counts, 0, h.counts, 0, counts.length); diff --git a/src/main/java/org/xbill/DNS/Message.java b/src/main/java/org/xbill/DNS/Message.java index 0f626b21e..4495d6676 100644 --- a/src/main/java/org/xbill/DNS/Message.java +++ b/src/main/java/org/xbill/DNS/Message.java @@ -620,14 +620,19 @@ public String toString() { * @see OPTRecord */ @Override - public Object clone() { - Message m = new Message(); + public Message clone() { + Message m; + try { + m = (Message) super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } for (int i = 0; i < sections.length; i++) { if (sections[i] != null) { m.sections[i] = new LinkedList<>(sections[i]); } } - m.header = (Header) header.clone(); + m.header = header.clone(); m.size = size; return m; } diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index 7bb4cbd6f..4a6dea60e 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -230,7 +230,7 @@ public Message send(Message query) throws IOException { } } - query = (Message) query.clone(); + query = query.clone(); applyEDNS(query); if (tsig != null) { tsig.apply(query, null); diff --git a/src/test/java/org/xbill/DNS/HeaderTest.java b/src/test/java/org/xbill/DNS/HeaderTest.java index 8beed8e8f..c0664b2d8 100644 --- a/src/test/java/org/xbill/DNS/HeaderTest.java +++ b/src/test/java/org/xbill/DNS/HeaderTest.java @@ -362,7 +362,7 @@ void test_clone() { m_h.setCount(1, 0xFF); m_h.setCount(2, 0x0A); - Header h2 = (Header) m_h.clone(); + Header h2 = m_h.clone(); assertNotSame(m_h, h2); assertEquals(m_h.getID(), h2.getID()); From 6be282747274131e1f5459e72c4578fd5fe25b4c Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Oct 2019 20:12:05 +0100 Subject: [PATCH 009/431] Fulfill equals matches hashCode contract --- src/main/java/org/xbill/DNS/OPTRecord.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/org/xbill/DNS/OPTRecord.java b/src/main/java/org/xbill/DNS/OPTRecord.java index d1246b2c7..2018f7578 100644 --- a/src/main/java/org/xbill/DNS/OPTRecord.java +++ b/src/main/java/org/xbill/DNS/OPTRecord.java @@ -185,4 +185,14 @@ public List getOptions(int code) { public boolean equals(final Object arg) { return super.equals(arg) && ttl == ((OPTRecord) arg).ttl; } + + @Override + public int hashCode() { + byte[] array = toWireCanonical(); + int code = 0; + for (byte b : array) { + code += ((code << 3) + (b & 0xFF)); + } + return code; + } } From 19e5a124cf7dbeb22837a6a84c6e21f8a96eb354 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Oct 2019 20:24:28 +0100 Subject: [PATCH 010/431] Always access the listener from the same synchronized context --- .../java/org/xbill/DNS/ExtendedResolver.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index c56bde05d..a3cf8739e 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -129,7 +129,9 @@ public Message start() throws IOException { /* Start an asynchronous resolution */ public void startAsync(ResolverListener listener) { - this.listener = listener; + synchronized (this) { + this.listener = listener; + } send(0); } @@ -140,6 +142,7 @@ public void startAsync(ResolverListener listener) { @Override public void receiveMessage(Object id, Message m) { log.debug("received message"); + ResolverListener listenerCopy; synchronized (this) { if (done) { return; @@ -149,9 +152,11 @@ public void receiveMessage(Object id, Message m) { if (listener == null) { notifyAll(); return; + } else { + listenerCopy = listener; } } - listener.receiveMessage(this, response); + listenerCopy.receiveMessage(this, response); } /* @@ -161,6 +166,7 @@ public void receiveMessage(Object id, Message m) { @Override public void handleException(Object id, Exception e) { log.debug("resolving failed", e); + ResolverListener listenerCopy = null; synchronized (this) { outstanding--; if (done) { @@ -225,6 +231,8 @@ public void handleException(Object id, Exception e) { if (listener == null) { notifyAll(); return; + } else { + listenerCopy = listener; } } if (!done) { @@ -233,9 +241,9 @@ public void handleException(Object id, Exception e) { } /* If we're done and this is asynchronous, call the callback. */ if (!(thrown instanceof Exception)) { - thrown = new RuntimeException(thrown.getMessage()); + thrown = new RuntimeException(thrown); } - listener.handleException(this, (Exception) thrown); + listenerCopy.handleException(this, (Exception) thrown); } } From 535300f2a11808f975ad9218fc4b39ea41ad16bf Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 28 Oct 2019 22:11:54 +0100 Subject: [PATCH 011/431] Fix synchronization issues, remove weird/dead code --- src/main/java/org/xbill/DNS/DNSSEC.java | 6 ++--- src/main/java/org/xbill/DNS/Header.java | 23 +++++++------------ src/main/java/org/xbill/DNS/Lookup.java | 2 +- src/main/java/org/xbill/DNS/UDPClient.java | 2 +- src/main/java/org/xbill/DNS/Zone.java | 4 +++- src/main/java/org/xbill/DNS/tools/Tools.java | 3 +++ src/main/java/org/xbill/DNS/tools/jnamed.java | 2 -- src/main/java/org/xbill/DNS/tools/update.java | 2 +- 8 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/xbill/DNS/DNSSEC.java b/src/main/java/org/xbill/DNS/DNSSEC.java index 33d29cd97..e0b64f4a1 100644 --- a/src/main/java/org/xbill/DNS/DNSSEC.java +++ b/src/main/java/org/xbill/DNS/DNSSEC.java @@ -677,7 +677,7 @@ private static byte[] DSASignaturefromDNS(byte[] dns) throws DNSSECException, IO DNSInput in = new DNSInput(dns); DNSOutput out = new DNSOutput(); - int t = in.readU8(); + /*int t =*/ in.readU8(); byte[] r = in.readByteArray(DSA_LEN); int rlen = DSA_LEN; @@ -737,7 +737,7 @@ private static byte[] DSASignaturetoDNS(byte[] signature, int t) throws IOExcept if (tmp != ASN1_SEQ) { throw new IOException("Invalid ASN.1 data, expected " + ASN1_SEQ + " got " + tmp); } - int seqlen = in.readU8(); + /*int seqlen =*/ in.readU8(); tmp = in.readU8(); if (tmp != ASN1_INT) { @@ -859,7 +859,7 @@ private static byte[] ECDSASignaturetoDNS(byte[] signature, ECKeyInfo keyinfo) if (tmp != ASN1_SEQ) { throw new IOException("Invalid ASN.1 data, expected " + ASN1_SEQ + " got " + tmp); } - int seqlen = in.readU8(); + /*int seqlen =*/ in.readU8(); tmp = in.readU8(); if (tmp != ASN1_INT) { diff --git a/src/main/java/org/xbill/DNS/Header.java b/src/main/java/org/xbill/DNS/Header.java index 51c40ad15..43617328b 100644 --- a/src/main/java/org/xbill/DNS/Header.java +++ b/src/main/java/org/xbill/DNS/Header.java @@ -17,30 +17,26 @@ public class Header implements Cloneable { private int flags; private int[] counts; - private static Random random = new Random(); + private static final Random random = new Random(); /** The length of a DNS Header in wire format. */ public static final int LENGTH = 12; - private void init() { - counts = new int[4]; - flags = 0; - id = -1; - } - /** * Create a new empty header. * * @param id The message id */ public Header(int id) { - init(); + this(); setID(id); } /** Create a new empty header with a random message id */ public Header() { - init(); + counts = new int[4]; + flags = 0; + id = -1; } /** Parses a Header from a stream containing DNS wire format. */ @@ -90,9 +86,9 @@ static int setFlag(int flags, int bit, boolean value) { // bits are indexed from left to right if (value) { - return flags |= (1 << (15 - bit)); + return flags | (1 << (15 - bit)); } else { - return flags &= ~(1 << (15 - bit)); + return flags & ~(1 << (15 - bit)); } } @@ -139,10 +135,7 @@ boolean[] getFlags() { /** Retrieves the message ID */ public int getID() { - if (id >= 0) { - return id; - } - synchronized (this) { + synchronized (random) { if (id < 0) { id = random.nextInt(0xffff); } diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index 1d11822ac..defd64c9b 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -355,7 +355,7 @@ public void setCache(Cache cache) { * * @param ndots The ndots value to use, which must be greater than or equal to 0. */ - public void setNdots(int ndots) { + public static void setNdots(int ndots) { if (ndots < 0) { throw new IllegalArgumentException("Illegal ndots value: " + ndots); } diff --git a/src/main/java/org/xbill/DNS/UDPClient.java b/src/main/java/org/xbill/DNS/UDPClient.java index cedbd324b..8391dbe52 100644 --- a/src/main/java/org/xbill/DNS/UDPClient.java +++ b/src/main/java/org/xbill/DNS/UDPClient.java @@ -41,7 +41,7 @@ final class UDPClient extends Client { new Runnable() { @Override public void run() { - int n = prng.nextInt(); + /*int n =*/ prng.nextInt(); prng_initializing = false; } }) diff --git a/src/main/java/org/xbill/DNS/Zone.java b/src/main/java/org/xbill/DNS/Zone.java index e0510e35b..d8022efa9 100644 --- a/src/main/java/org/xbill/DNS/Zone.java +++ b/src/main/java/org/xbill/DNS/Zone.java @@ -173,7 +173,9 @@ public Zone(Name zone, Record[] records) throws IOException { } private void fromXFR(ZoneTransferIn xfrin) throws IOException, ZoneTransferException { - data = new TreeMap<>(); + synchronized (this) { + data = new TreeMap<>(); + } origin = xfrin.getName(); List records = xfrin.run(); diff --git a/src/main/java/org/xbill/DNS/tools/Tools.java b/src/main/java/org/xbill/DNS/tools/Tools.java index 98348ab6b..03baa2244 100644 --- a/src/main/java/org/xbill/DNS/tools/Tools.java +++ b/src/main/java/org/xbill/DNS/tools/Tools.java @@ -38,6 +38,9 @@ public static void main(String[] args) throws Exception { case "xfrin": xfrin.main(programArgs); break; + default: + System.out.println("invalid command"); + break; } } } diff --git a/src/main/java/org/xbill/DNS/tools/jnamed.java b/src/main/java/org/xbill/DNS/tools/jnamed.java index 0fd13ce6e..c2f680101 100644 --- a/src/main/java/org/xbill/DNS/tools/jnamed.java +++ b/src/main/java/org/xbill/DNS/tools/jnamed.java @@ -443,8 +443,6 @@ byte[] generateReply(Message query, byte[] in, Socket s) { } OPTRecord queryOPT = query.getOPT(); - if (queryOPT != null && queryOPT.getVersion() > 0) {} - if (s != null) { maxLength = 65535; } else if (queryOPT != null) { diff --git a/src/main/java/org/xbill/DNS/tools/update.java b/src/main/java/org/xbill/DNS/tools/update.java index f88ac54be..76efcf1b4 100644 --- a/src/main/java/org/xbill/DNS/tools/update.java +++ b/src/main/java/org/xbill/DNS/tools/update.java @@ -689,6 +689,6 @@ public static void main(String[] args) { } else { in = System.in; } - update u = new update(in); + new update(in); } } From 4843805b354e902ba735d8e54cdd66383df1b4ed Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 5 Nov 2019 00:32:56 +0100 Subject: [PATCH 012/431] Refactor nameserver lookup to an SPI interface Closes #6, #8, #55, #57, #80 --- pom.xml | 18 +- .../java/org/xbill/DNS/ExtendedResolver.java | 25 +- src/main/java/org/xbill/DNS/Lookup.java | 33 +- .../java/org/xbill/DNS/ResolverConfig.java | 497 +++--------------- .../java/org/xbill/DNS/SimpleResolver.java | 49 +- .../config/AndroidResolverConfigProvider.java | 115 ++++ .../config/BaseResolverConfigProvider.java | 81 +++ .../java/org/xbill/DNS/config/IPHlpAPI.java | 250 +++++++++ .../DNS/config/InitializationException.java | 12 + .../JndiContextResolverConfigProvider.java | 67 +++ .../PropertyResolverConfigProvider.java | 59 +++ .../ResolvConfResolverConfigProvider.java | 128 +++++ .../DNS/config/ResolverConfigProvider.java | 31 ++ .../config/SunJvmResolverConfigProvider.java | 66 +++ .../config/WindowsResolverConfigProvider.java | 125 +++++ .../xbill/DNS/windows/DNSServer.properties | 4 - .../xbill/DNS/windows/DNSServer_de.properties | 4 - .../xbill/DNS/windows/DNSServer_fr.properties | 4 - .../xbill/DNS/windows/DNSServer_ja.properties | 4 - .../xbill/DNS/windows/DNSServer_pl.properties | 4 - .../org/xbill/DNS/ResolverConfigTest.java | 185 +++++-- 21 files changed, 1225 insertions(+), 536 deletions(-) create mode 100644 src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java create mode 100644 src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java create mode 100644 src/main/java/org/xbill/DNS/config/IPHlpAPI.java create mode 100644 src/main/java/org/xbill/DNS/config/InitializationException.java create mode 100644 src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java create mode 100644 src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java create mode 100644 src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java create mode 100644 src/main/java/org/xbill/DNS/config/ResolverConfigProvider.java create mode 100644 src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java create mode 100644 src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java delete mode 100644 src/main/resources/org/xbill/DNS/windows/DNSServer.properties delete mode 100644 src/main/resources/org/xbill/DNS/windows/DNSServer_de.properties delete mode 100644 src/main/resources/org/xbill/DNS/windows/DNSServer_fr.properties delete mode 100644 src/main/resources/org/xbill/DNS/windows/DNSServer_ja.properties delete mode 100644 src/main/resources/org/xbill/DNS/windows/DNSServer_pl.properties diff --git a/pom.xml b/pom.xml index dc0ddec1d..10059b3c0 100644 --- a/pom.xml +++ b/pom.xml @@ -93,7 +93,11 @@ org.xbill.DNS.* - !org.xbill.DNS*,!sun.*,android.os;resolution:=optional,* + !org.xbill.DNS*, + !sun.*, + android.*;resolution:=optional, + javax.naming.*;resolution:=optional, + com.sun.jna.*;resolution:=optional,* JavaSE-1.8 @@ -209,6 +213,18 @@ 1.18.8 provided + + net.java.dev.jna + jna + 5.5.0 + true + + + net.java.dev.jna + jna-platform + 5.5.0 + true + org.bouncycastle bcprov-jdk15on diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index a3cf8739e..9804d38cb 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -4,9 +4,11 @@ import java.io.IOException; import java.io.InterruptedIOException; +import java.net.InetSocketAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import lombok.extern.slf4j.Slf4j; @@ -264,19 +266,14 @@ private void init() { * * @see SimpleResolver * @see ResolverConfig - * @exception UnknownHostException Failure occured initializing SimpleResolvers */ - public ExtendedResolver() throws UnknownHostException { + public ExtendedResolver() { init(); - String[] servers = ResolverConfig.getCurrentConfig().servers(); - if (servers != null) { - for (String server : servers) { - Resolver r = new SimpleResolver(server); - r.setTimeout(quantum); - resolvers.add(r); - } - } else { - resolvers.add(new SimpleResolver()); + List servers = ResolverConfig.getCurrentConfig().servers(); + for (InetSocketAddress server : servers) { + Resolver r = new SimpleResolver(server); + r.setTimeout(quantum); + resolvers.add(r); } } @@ -286,7 +283,7 @@ public ExtendedResolver() throws UnknownHostException { * @param servers An array of server names for which SimpleResolver contexts should be * initialized. * @see SimpleResolver - * @exception UnknownHostException Failure occured initializing SimpleResolvers + * @exception UnknownHostException Failure occurred initializing SimpleResolvers */ public ExtendedResolver(String[] servers) throws UnknownHostException { init(); @@ -305,9 +302,7 @@ public ExtendedResolver(String[] servers) throws UnknownHostException { */ public ExtendedResolver(Resolver[] res) { init(); - for (Resolver re : res) { - resolvers.add(re); - } + resolvers.addAll(Arrays.asList(res)); } @Override diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index defd64c9b..b08b149f1 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.io.InterruptedIOException; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -30,12 +29,12 @@ public final class Lookup { private static Resolver defaultResolver; - private static Name[] defaultSearchPath; + private static List defaultSearchPath; private static Map defaultCaches; private static int defaultNdots; private Resolver resolver; - private Name[] searchPath; + private List searchPath; private Cache cache; private boolean temporary_cache; private int credibility; @@ -76,12 +75,7 @@ public final class Lookup { public static final int TYPE_NOT_FOUND = 4; public static synchronized void refreshDefault() { - - try { - defaultResolver = new ExtendedResolver(); - } catch (UnknownHostException e) { - throw new RuntimeException("Failed to initialize resolver"); - } + defaultResolver = new ExtendedResolver(); defaultSearchPath = ResolverConfig.getCurrentConfig().searchPath(); defaultCaches = new HashMap<>(); defaultNdots = ResolverConfig.getCurrentConfig().ndots(); @@ -141,7 +135,7 @@ public static synchronized void setDefaultCache(Cache cache, int dclass) { * * @return The default search path. */ - public static synchronized Name[] getDefaultSearchPath() { + public static synchronized List getDefaultSearchPath() { return defaultSearchPath; } @@ -150,7 +144,7 @@ public static synchronized Name[] getDefaultSearchPath() { * * @param domains The default search path. */ - public static synchronized void setDefaultSearchPath(Name[] domains) { + public static synchronized void setDefaultSearchPath(List domains) { defaultSearchPath = domains; } @@ -165,10 +159,12 @@ public static synchronized void setDefaultSearchPath(String[] domains) throws Te defaultSearchPath = null; return; } - Name[] newdomains = new Name[domains.length]; - for (int i = 0; i < domains.length; i++) { - newdomains[i] = Name.fromString(domains[i], Name.root); + + List newdomains = new ArrayList<>(domains.length); + for (String domain : domains) { + newdomains.add(Name.fromString(domain, Name.root)); } + defaultSearchPath = newdomains; } @@ -310,7 +306,7 @@ public void setResolver(Resolver resolver) { * * @param domains An array of names containing the search path. */ - public void setSearchPath(Name[] domains) { + public void setSearchPath(List domains) { this.searchPath = domains; } @@ -325,9 +321,10 @@ public void setSearchPath(String[] domains) throws TextParseException { this.searchPath = null; return; } - Name[] newdomains = new Name[domains.length]; - for (int i = 0; i < domains.length; i++) { - newdomains[i] = Name.fromString(domains[i], Name.root); + + List newdomains = new ArrayList<>(domains.length); + for (String domain : domains) { + newdomains.add(Name.fromString(domain, Name.root)); } this.searchPath = newdomains; } diff --git a/src/main/java/org/xbill/DNS/ResolverConfig.java b/src/main/java/org/xbill/DNS/ResolverConfig.java index 3d21c0fbd..4e398c204 100644 --- a/src/main/java/org/xbill/DNS/ResolverConfig.java +++ b/src/main/java/org/xbill/DNS/ResolverConfig.java @@ -2,483 +2,138 @@ package org.xbill.DNS; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Paths; +import java.net.InetAddress; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; -import java.util.Locale; -import java.util.ResourceBundle; -import java.util.StringTokenizer; import lombok.extern.slf4j.Slf4j; +import org.xbill.DNS.config.AndroidResolverConfigProvider; +import org.xbill.DNS.config.InitializationException; +import org.xbill.DNS.config.JndiContextResolverConfigProvider; +import org.xbill.DNS.config.PropertyResolverConfigProvider; +import org.xbill.DNS.config.ResolvConfResolverConfigProvider; +import org.xbill.DNS.config.ResolverConfigProvider; +import org.xbill.DNS.config.SunJvmResolverConfigProvider; +import org.xbill.DNS.config.WindowsResolverConfigProvider; /** - * A class that tries to locate name servers and the search path to be appended to unqualified - * names. + * Locates name servers and the search path to be appended to unqualified names. * *

The following are attempted, in order, until one succeeds. * *

    - *
  • The properties 'dns.server' and 'dns.search' (comma delimited lists) are checked. The - * servers can either be IP addresses or hostnames (which are resolved using Java's built in - * DNS support). - *
  • The sun.net.dns.ResolverConfiguration class is queried. - *
  • On Unix, /etc/resolv.conf is parsed. - *
  • On Windows, ipconfig is called and its output parsed. This may fail for non-English - * versions on Windows. + *
  • dnsjava properties, see {@link org.xbill.DNS.config.PropertyResolverConfigProvider} + *
  • On Unix, /etc/resolv.conf is parsed, see {@link + * org.xbill.DNS.config.ResolvConfResolverConfigProvider} + *
  • On Windows, GetAdaptersAddresses is called, see {@link + * org.xbill.DNS.config.WindowsResolverConfigProvider} + *
  • On Android, system properties or the ConnectivityManager are read, see {@link + * org.xbill.DNS.config.AndroidResolverConfigProvider} + *
  • The JNDI DNS Service Provider is queried, see {@link + * org.xbill.DNS.config.JndiContextResolverConfigProvider} + *
  • The sun.net.dns.ResolverConfiguration class is queried, see {@link + * org.xbill.DNS.config.SunJvmResolverConfigProvider} *
  • "localhost" is used as the nameserver, and the search path is empty. *
* * These routines will be called internally when creating Resolvers/Lookups without explicitly * specifying server names, and can also be called directly if desired. - * - * @author Brian Wellington - * @author Yannick Meudal - * @author Arnt Gulbrandsen */ @Slf4j -public class ResolverConfig { - - public static final String DNS_SERVER_PROP = "dns.server"; - public static final String DNS_SEARCH_PROP = "dns.search"; - - private String[] servers = null; - private Name[] searchlist = null; - private int ndots = -1; +public final class ResolverConfig { + private List servers = new ArrayList<>(2); + private List searchlist = new ArrayList<>(0); + private int ndots = 1; private static ResolverConfig currentConfig; + private static List configProviders; static { + configProviders = new ArrayList<>(8); + configProviders.add(new PropertyResolverConfigProvider()); + configProviders.add(new ResolvConfResolverConfigProvider()); + configProviders.add(new WindowsResolverConfigProvider()); + configProviders.add(new AndroidResolverConfigProvider()); + configProviders.add(new JndiContextResolverConfigProvider()); + configProviders.add(new SunJvmResolverConfigProvider()); refresh(); } - public ResolverConfig() { - if (findProperty()) { - return; - } - if (findSunJVM()) { - return; - } - if (servers == null || searchlist == null) { - String OS = System.getProperty("os.name"); - String vendor = System.getProperty("java.vendor"); - if (OS.contains("Windows")) { - findWin(); - } else if (OS.contains("NetWare")) { - findNetware(); - } else if (vendor.contains("Android")) { - findAndroid(); - } else { - findUnix(); - } - } - } - - private void addServer(String server, List list) { - if (list.contains(server)) { - return; - } - log.debug("adding server {}", server); - list.add(server); - } - - private void addSearch(String search, List list) { - Name name; - log.debug("adding search {}", search); - try { - name = Name.fromString(search, Name.root); - } catch (TextParseException e) { - return; - } - if (list.contains(name)) { - return; - } - list.add(name); - } - - private int parseNdots(String token) { - token = token.substring(6); - try { - int ndots = Integer.parseInt(token); - if (ndots >= 0) { - log.debug("setting ndots {}", token); - return ndots; - } - } catch (NumberFormatException e) { - } - return -1; - } - - private void configureFromLists(List lserver, List lsearch) { - if (servers == null && lserver.size() > 0) { - servers = lserver.toArray(new String[0]); - } - if (searchlist == null && lsearch.size() > 0) { - searchlist = lsearch.toArray(new Name[0]); - } + /** Gets the current configuration */ + public static synchronized ResolverConfig getCurrentConfig() { + return currentConfig; } - private void configureNdots(int lndots) { - if (ndots < 0 && lndots > 0) { - ndots = lndots; - } + /** Set a new ordered list of resolver config providers. */ + public static synchronized void setConfigProviders(List providers) { + configProviders = new ArrayList<>(providers); } - /** - * Looks in the system properties to find servers and a search path. Servers are defined by - * dns.server=server1,server2... The search path is defined by dns.search=domain1,domain2... - */ - boolean findProperty() { - String prop; - List lserver = new ArrayList<>(0); - List lsearch = new ArrayList<>(0); - StringTokenizer st; - - prop = System.getProperty(DNS_SERVER_PROP); - if (prop != null) { - st = new StringTokenizer(prop, ","); - while (st.hasMoreTokens()) { - addServer(st.nextToken(), lserver); - } - } - - prop = System.getProperty(DNS_SEARCH_PROP); - if (prop != null) { - st = new StringTokenizer(prop, ","); - while (st.hasMoreTokens()) { - addSearch(st.nextToken(), lsearch); - } - } - configureFromLists(lserver, lsearch); - return (servers != null && searchlist != null); - } - - /** - * Uses the undocumented Sun DNS implementation to determine the configuration. This doesn't work - * or even compile with all JVMs (gcj, for example). - */ - @SuppressWarnings("unchecked") - private boolean findSunJVM() { - List lserver = new ArrayList<>(0); - List lserver_tmp; - List lsearch = new ArrayList<>(0); - List lsearch_tmp; - - try { - Class[] noClasses = new Class[0]; - Object[] noObjects = new Object[0]; - String resConfName = "sun.net.dns.ResolverConfiguration"; - Class resConfClass = Class.forName(resConfName); - Object resConf; - - // ResolverConfiguration resConf = ResolverConfiguration.open(); - Method open = resConfClass.getDeclaredMethod("open", noClasses); - resConf = open.invoke(null, noObjects); - - // lserver_tmp = resConf.nameservers(); - Method nameservers = resConfClass.getMethod("nameservers", noClasses); - lserver_tmp = (List) nameservers.invoke(resConf, noObjects); - - // lsearch_tmp = resConf.searchlist(); - Method searchlist = resConfClass.getMethod("searchlist", noClasses); - lsearch_tmp = (List) searchlist.invoke(resConf, noObjects); - } catch (Exception e) { - return false; - } - - if (lserver_tmp.size() == 0) { - return false; - } else { - for (String s : lserver_tmp) { - addServer(s, lserver); - } - } - - if (lsearch_tmp.size() > 0) { - for (String s : lsearch_tmp) { - addSearch(s, lsearch); - } + /** Gets the current configuration */ + public static void refresh() { + ResolverConfig newConfig = new ResolverConfig(); + synchronized (ResolverConfig.class) { + currentConfig = newConfig; } - configureFromLists(lserver, lsearch); - return true; } - /** - * Looks in /etc/resolv.conf to find servers and a search path. "nameserver" lines specify - * servers. "domain" and "search" lines define the search path. - */ - boolean findResolvConf(InputStream in) { - List lserver = new ArrayList<>(0); - List lsearch = new ArrayList<>(0); - int lndots = -1; - try (InputStreamReader isr = new InputStreamReader(in); - BufferedReader br = new BufferedReader(isr)) { - String line; - while ((line = br.readLine()) != null) { - if (line.startsWith("nameserver")) { - StringTokenizer st = new StringTokenizer(line); - st.nextToken(); /* skip nameserver */ - addServer(st.nextToken(), lserver); - } else if (line.startsWith("domain")) { - StringTokenizer st = new StringTokenizer(line); - st.nextToken(); /* skip domain */ - if (!st.hasMoreTokens()) { - continue; - } - if (lsearch.isEmpty()) { - addSearch(st.nextToken(), lsearch); - } - } else if (line.startsWith("search")) { - if (!lsearch.isEmpty()) { - lsearch.clear(); - } - StringTokenizer st = new StringTokenizer(line); - st.nextToken(); /* skip search */ - while (st.hasMoreTokens()) { - addSearch(st.nextToken(), lsearch); + public ResolverConfig() { + for (ResolverConfigProvider provider : configProviders) { + if (provider.isEnabled()) { + try { + provider.initialize(); + if (servers.isEmpty()) { + servers.addAll(provider.servers()); } - } else if (line.startsWith("options")) { - StringTokenizer st = new StringTokenizer(line); - st.nextToken(); /* skip options */ - while (st.hasMoreTokens()) { - String token = st.nextToken(); - if (token.startsWith("ndots:")) { - lndots = parseNdots(token); + + if (searchlist.isEmpty()) { + List lsearchPaths = provider.searchPaths(); + if (!lsearchPaths.isEmpty()) { + searchlist.addAll(lsearchPaths); + ndots = provider.ndots(); } } - } - } - } catch (IOException e) { - return false; - } - - if (lserver.isEmpty()) { - return false; - } - - configureFromLists(lserver, lsearch); - configureNdots(lndots); - return true; - } - - boolean findUnix() { - try (InputStream in = Files.newInputStream(Paths.get("/etc/resolv.conf"))) { - return findResolvConf(in); - } catch (Exception e) { - return false; - } - } - - boolean findNetware() { - try (InputStream in = Files.newInputStream(Paths.get("sys:/etc/resolv.cfg"))) { - return findResolvConf(in); - } catch (Exception e) { - return false; - } - } - /** Parses the output of ipconfig. */ - boolean findWin(InputStream in, Locale locale) { - String packageName = ResolverConfig.class.getPackage().getName(); - String resPackageName = packageName + ".windows.DNSServer"; - ResourceBundle res; - if (locale != null) { - res = ResourceBundle.getBundle(resPackageName, locale); - } else { - res = ResourceBundle.getBundle(resPackageName); - } - - String host_name = res.getString("host_name"); - String primary_dns_suffix = res.getString("primary_dns_suffix"); - String dns_suffix = res.getString("dns_suffix"); - String dns_servers = res.getString("dns_servers"); - - BufferedReader br = new BufferedReader(new InputStreamReader(in)); - try { - List lserver = new ArrayList<>(); - List lsearch = new ArrayList<>(); - String line; - boolean readingServers = false; - boolean readingSearches = false; - while ((line = br.readLine()) != null) { - StringTokenizer st = new StringTokenizer(line); - if (!st.hasMoreTokens()) { - readingServers = false; - readingSearches = false; - continue; - } - String s = st.nextToken(); - if (line.contains(":")) { - readingServers = false; - readingSearches = false; - } - - if (line.contains(host_name)) { - while (st.hasMoreTokens()) { - s = st.nextToken(); - } - Name name; - try { - name = Name.fromString(s, null); - } catch (TextParseException e) { - continue; - } - if (name.labels() == 1) { - continue; - } - addSearch(s, lsearch); - } else if (line.contains(primary_dns_suffix)) { - while (st.hasMoreTokens()) { - s = st.nextToken(); - } - if (s.equals(":")) { - continue; - } - addSearch(s, lsearch); - readingSearches = true; - } else if (readingSearches || line.contains(dns_suffix)) { - while (st.hasMoreTokens()) { - s = st.nextToken(); - } - if (s.equals(":")) { - continue; - } - addSearch(s, lsearch); - readingSearches = true; - } else if (readingServers || line.contains(dns_servers)) { - while (st.hasMoreTokens()) { - s = st.nextToken(); - } - if (s.equals(":")) { - continue; + if (!servers.isEmpty() && !searchlist.isEmpty()) { + // found both servers and search path, we're done + return; } - addServer(s, lserver); - readingServers = true; + } catch (InitializationException e) { + log.warn("Failed to initialize provider", e); } } - if (lserver.isEmpty()) { - return false; - } - configureFromLists(lserver, lsearch); - return true; - } catch (IOException e) { - return false; - } - } - - private boolean findWin(InputStream in) { - boolean found; - String property = "org.xbill.DNS.windows.parse.buffer"; - final int defaultBufSize = 8 * 1024; - int bufSize = Integer.getInteger(property, defaultBufSize); - BufferedInputStream b = new BufferedInputStream(in, bufSize); - b.mark(bufSize); - found = findWin(b, null); - if (servers == null) { - try { - b.reset(); - } catch (IOException e) { - return false; - } - found = findWin(b, new Locale("", "")); } - return found; - } - /** Calls ipconfig and parses the result to find servers and a search path. */ - boolean findWin() { - boolean found; - try { - Process p; - p = Runtime.getRuntime().exec("ipconfig /all"); - found = findWin(p.getInputStream()); - p.destroy(); - } catch (Exception e) { - return false; + if (servers.isEmpty()) { + servers.add( + new InetSocketAddress(InetAddress.getLoopbackAddress(), SimpleResolver.DEFAULT_PORT)); } - return found; - } - - /** - * Parses the output of getprop, which is the only way to get DNS info on Android. getprop might - * disappear in future releases, so this code comes with a use-by date. - */ - boolean findAndroid() { - // This originally looked for all lines containing .dns; but - // http://code.google.com/p/android/issues/detail?id=2207#c73 - // indicates that net.dns* should always be the active nameservers, so - // we use those. - final String re1 = "^\\d+(\\.\\d+){3}$"; - final String re2 = "^[0-9a-f]+(:[0-9a-f]*)+:[0-9a-f]+$"; - ArrayList lserver = new ArrayList<>(); - ArrayList lsearch = new ArrayList<>(); - try { - Class SystemProperties = Class.forName("android.os.SystemProperties"); - Method method = SystemProperties.getMethod("get", String.class); - final String[] netdns = new String[] {"net.dns1", "net.dns2", "net.dns3", "net.dns4"}; - for (String netdn : netdns) { - Object[] args = new Object[] {netdn}; - String v = (String) method.invoke(null, args); - if (v != null && (v.matches(re1) || v.matches(re2)) && !lserver.contains(v)) { - lserver.add(v); - } - } - } catch (Exception e) { - return false; - } - if (lserver.isEmpty()) { - return false; - } - configureFromLists(lserver, lsearch); - return true; } /** Returns all located servers */ - public String[] servers() { + public List servers() { return servers; } /** Returns the first located server */ - public String server() { - if (servers == null) { - return null; - } - return servers[0]; + public InetSocketAddress server() { + return servers.get(0); } /** Returns all entries in the located search path */ - public Name[] searchPath() { + public List searchPath() { return searchlist; } /** - * Returns the located ndots value, or the default (1) if not configured. Note that ndots can only - * be configured in a resolv.conf file, and will only take effect if ResolverConfig uses - * resolv.conf directly (that is, if the JVM does not include the - * sun.net.dns.ResolverConfiguration class). + * Gets the threshold for the number of dots which must appear in a name before it is considered + * absolute. The default is {@code 1}, meaning meaning that if there are any dots in a name, the + * name will be tried first as an absolute name. + * + *

Note that ndots can only be configured in a resolv.conf file or the property {@link + * #DNS_NDOTS_PROP}. */ public int ndots() { - if (ndots < 0) { - return 1; - } return ndots; } - - /** Gets the current configuration */ - public static synchronized ResolverConfig getCurrentConfig() { - return currentConfig; - } - - /** Gets the current configuration */ - public static void refresh() { - ResolverConfig newConfig = new ResolverConfig(); - synchronized (ResolverConfig.class) { - currentConfig = newConfig; - } - } } diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index 4a6dea60e..ee6aa94a0 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -7,6 +7,7 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.List; +import java.util.Objects; import lombok.extern.slf4j.Slf4j; /** @@ -36,9 +37,21 @@ public class SimpleResolver implements Resolver { private static final short DEFAULT_UDPSIZE = 512; - private static String defaultResolver = "localhost"; + private static InetSocketAddress defaultResolver = + new InetSocketAddress(InetAddress.getLoopbackAddress(), DEFAULT_PORT); private static int uniqueID = 0; + /** + * Creates a SimpleResolver. The host to query is either found by using ResolverConfig, or the + * default host is used. + * + * @see ResolverConfig + * @exception UnknownHostException Failure occurred while finding the host + */ + public SimpleResolver() throws UnknownHostException { + this((String) null); + } + /** * Creates a SimpleResolver that will query the specified host * @@ -46,29 +59,25 @@ public class SimpleResolver implements Resolver { */ public SimpleResolver(String hostname) throws UnknownHostException { if (hostname == null) { - hostname = ResolverConfig.getCurrentConfig().server(); - if (hostname == null) { - hostname = defaultResolver; - } + address = ResolverConfig.getCurrentConfig().server(); } - InetAddress addr; - if (hostname.equals("0")) { - addr = InetAddress.getLocalHost(); + + if ("0".equals(hostname)) { + address = defaultResolver; } else { - addr = InetAddress.getByName(hostname); + address = new InetSocketAddress(InetAddress.getByName(hostname), DEFAULT_PORT); } - address = new InetSocketAddress(addr, DEFAULT_PORT); } - /** - * Creates a SimpleResolver. The host to query is either found by using ResolverConfig, or the - * default host is used. - * - * @see ResolverConfig - * @exception UnknownHostException Failure occurred while finding the host - */ - public SimpleResolver() throws UnknownHostException { - this(null); + /** Creates a SimpleResolver that will query the specified host */ + public SimpleResolver(InetSocketAddress host) { + address = Objects.requireNonNull(host, "host must not be null"); + } + + /** Creates a SimpleResolver that will query the specified host */ + public SimpleResolver(InetAddress host) { + Objects.requireNonNull(host, "host must not be null"); + address = new InetSocketAddress(host, DEFAULT_PORT); } /** @@ -82,7 +91,7 @@ public InetSocketAddress getAddress() { } /** Sets the default host (initially localhost) to query */ - public static void setDefaultResolver(String hostname) { + public static void setDefaultResolver(InetSocketAddress hostname) { defaultResolver = hostname; } diff --git a/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java new file mode 100644 index 000000000..dd290f6c0 --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.xbill.DNS.ResolverConfig; +import org.xbill.DNS.SimpleResolver; + +/** + * Resolver config provider for Android. Contrary to all other providers, this provider needs a + * context to operate on which must be set by calling {@link #setContext(Object)}. + * + *

If you are developing for Android, consider implementing your own {@link + * ResolverConfigProvider} that listens to network callbacks and properly refreshes on link changes. + * Something you need to do anyway to call {@link ResolverConfig#refresh()} otherwise it is pretty + * much guaranteed to have outdated servers sooner or later. + */ +@Slf4j +public class AndroidResolverConfigProvider extends BaseResolverConfigProvider { + private static Object context = null; + + /** Gets the current configuration */ + public static void setContext(Object ctx) { + context = ctx; + } + + @Override + public void initialize() throws InitializationException { + // This originally looked for all lines containing .dns; but + // http://code.google.com/p/android/issues/detail?id=2207#c73 indicates + // that net.dns* should always be the active nameservers, so we use those. + // Starting with Android 8 (API 26), the net.dns[1234] properties are no longer available: + // https://developer.android.com/about/versions/oreo/android-8.0-changes.html#o-pri + try { + Class Version = Class.forName("android.os.Build$VERSION"); + Field SDK_INT = Version.getField("SDK_INT"); + + if (SDK_INT.getInt(null) >= 26) { + initializeApi26Nameservers(); + } else { + initializeNameservers(); + } + } catch (NoSuchMethodException + | InvocationTargetException + | NoSuchFieldException + | IllegalAccessException + | ClassNotFoundException e) { + throw new InitializationException(e); + } + } + + private void initializeNameservers() + throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + Class systemPropertiesClass = Class.forName("android.os.SystemProperties"); + Method method = systemPropertiesClass.getMethod("get", String.class); + for (int i = 1; i <= 4; i++) { + String server = (String) method.invoke(null, "net.dns" + i); + if (server != null && !server.isEmpty()) { + nameservers.add(new InetSocketAddress(server, SimpleResolver.DEFAULT_PORT)); + } + } + } + + private void initializeApi26Nameservers() + throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, + InvocationTargetException, InitializationException { + if (context == null) { + throw new InitializationException("Context must be initialized by calling setContext"); + } + + Class contextClass = Class.forName("android.content.Context"); + Method getSystemService = contextClass.getDeclaredMethod("getSystemService", String.class); + Object cm = getSystemService.invoke(context, "connectivity"); + + Class connectivityManagerClass = Class.forName("android.net.ConnectivityManager"); + Method getActiveNetwork = connectivityManagerClass.getDeclaredMethod("getActiveNetwork"); + Object network = getActiveNetwork.invoke(cm); + if (network == null) { + // if the device is offline, there's no active network + return; + } + + Class networkClass = Class.forName("android.net.Network"); + Method getLinkProperties = + connectivityManagerClass.getDeclaredMethod("getLinkProperties", networkClass); + Object lp = getLinkProperties.invoke(cm, network); + if (lp == null) { + // can be null for an unknown network, which may happen if networks change + return; + } + + Class linkPropertiesClass = Class.forName("android.net.LinkProperties"); + Method getDnsServers = linkPropertiesClass.getDeclaredMethod("getDnsServers"); + @SuppressWarnings("unchecked") + List addresses = (List) getDnsServers.invoke(lp); + + for (InetAddress address : addresses) { + addNameserver(new InetSocketAddress(address, SimpleResolver.DEFAULT_PORT)); + } + + Method getDomains = linkPropertiesClass.getDeclaredMethod("getDomains"); + parseSearchPathList((String) getDomains.invoke(lp), ","); + } + + @Override + public boolean isEnabled() { + return System.getProperty("java.vendor").contains("Android"); + } +} diff --git a/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java new file mode 100644 index 000000000..162c4c947 --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.StringTokenizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xbill.DNS.Name; +import org.xbill.DNS.TextParseException; + +/** + * Base class for resolver config providers that provides a default implementation for the lists and + * utility methods to prevent duplicates. + */ +abstract class BaseResolverConfigProvider implements ResolverConfigProvider { + final Logger log = LoggerFactory.getLogger(getClass()); + List nameservers = new ArrayList<>(3); + List searchlist = new ArrayList<>(1); + + void parseSearchPathList(String search, String delimiter) { + if (search != null) { + StringTokenizer st = new StringTokenizer(search, delimiter); + while (st.hasMoreTokens()) { + addSearchPath(st.nextToken()); + } + } + } + + void addSearchPath(String searchPath) { + try { + Name n = Name.fromString(searchPath, Name.root); + if (!searchlist.contains(n)) { + searchlist.add(n); + log.debug("Added {} to search paths", n); + } + } catch (TextParseException e) { + log.warn("Could not parse search path {} as a dns name, ignoring", searchPath); + } + } + + void addNameserver(InetSocketAddress server) { + if (!nameservers.contains(server)) { + nameservers.add(server); + log.debug("Added {} to nameservers", server); + } + } + + int parseNdots(String token) { + if (token != null && !token.isEmpty()) { + try { + int ndots = Integer.parseInt(token); + if (ndots >= 0) { + if (ndots > 15) { + // man resolv.conf: + // The value for this option is silently capped to 15 + ndots = 15; + } + + return ndots; + } + } catch (NumberFormatException e) { + // ignore + } + } + + return 1; + } + + @Override + public final List servers() { + return Collections.unmodifiableList(nameservers); + } + + @Override + public final List searchPaths() { + return Collections.unmodifiableList(searchlist); + } +} diff --git a/src/main/java/org/xbill/DNS/config/IPHlpAPI.java b/src/main/java/org/xbill/DNS/config/IPHlpAPI.java new file mode 100644 index 000000000..d39e54635 --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/IPHlpAPI.java @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; +import com.sun.jna.WString; +import com.sun.jna.platform.win32.Guid; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.win32.W32APIOptions; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +interface IPHlpAPI extends Library { + IPHlpAPI INSTANCE = Native.load("IPHlpAPI", IPHlpAPI.class, W32APIOptions.ASCII_OPTIONS); + + int AF_UNSPEC = 0; + int AF_INET = 2; + int AF_INET6 = 23; + + int GAA_FLAG_SKIP_UNICAST = 0x0001; + int GAA_FLAG_SKIP_ANYCAST = 0x0002; + int GAA_FLAG_SKIP_MULTICAST = 0x0004; + int GAA_FLAG_SKIP_DNS_SERVER = 0x0008; + int GAA_FLAG_INCLUDE_PREFIX = 0x0010; + int GAA_FLAG_SKIP_FRIENDLY_NAME = 0x0020; + int GAA_FLAG_INCLUDE_WINS_INFO = 0x0040; + int GAA_FLAG_INCLUDE_GATEWAYS = 0x0080; + int GAA_FLAG_INCLUDE_ALL_INTERFACES = 0x0100; + int GAA_FLAG_INCLUDE_ALL_COMPARTMENTS = 0x0200; + int GAA_FLAG_INCLUDE_TUNNEL_BINDINGORDER = 0x0400; + + @Structure.FieldOrder({"sin_family", "sin_port", "sin_addr", "sin_zero"}) + class sockaddr_in extends Structure { + public sockaddr_in(Pointer p) { + super(p); + read(); + } + + public short sin_family; + public short sin_port; + public byte[] sin_addr = new byte[4]; + public byte[] sin_zero = new byte[8]; + } + + @Structure.FieldOrder({"sin6_family", "sin6_port", "sin6_flowinfo", "sin6_addr", "sin6_scope_id"}) + class sockaddr_in6 extends Structure { + public sockaddr_in6(Pointer p) { + super(p); + read(); + } + + public short sin6_family; + public short sin6_port; + public int sin6_flowinfo; + public byte[] sin6_addr = new byte[16]; + public int sin6_scope_id; + } + + @Structure.FieldOrder({"lpSockaddr", "iSockaddrLength"}) + class SOCKET_ADDRESS extends Structure { + public Pointer lpSockaddr; + public int iSockaddrLength; + + InetAddress toAddress() throws UnknownHostException { + switch (lpSockaddr.getShort(0)) { + case AF_INET: + sockaddr_in in4 = new sockaddr_in(lpSockaddr); + return InetAddress.getByAddress(in4.sin_addr); + case AF_INET6: + sockaddr_in6 in6 = new sockaddr_in6(lpSockaddr); + return Inet6Address.getByAddress("", in6.sin6_addr, in6.sin6_scope_id); + } + + return null; + } + } + + @Structure.FieldOrder({ + "Length", + "IfIndex", + "Next", + "Address", + "PrefixOrigin", + "SuffixOrigin", + "DadState", + "ValidLifetime", + "PreferredLifetime", + "LeaseLifetime", + "OnLinkPrefixLength" + }) + class IP_ADAPTER_UNICAST_ADDRESS_LH extends Structure { + public static class ByReference extends IP_ADAPTER_UNICAST_ADDRESS_LH + implements Structure.ByReference {} + + public int Length; + public int IfIndex; + + public IP_ADAPTER_UNICAST_ADDRESS_LH.ByReference Next; + public SOCKET_ADDRESS Address; + public int PrefixOrigin; + public int SuffixOrigin; + public int DadState; + public int ValidLifetime; + public int PreferredLifetime; + public int LeaseLifetime; + public byte OnLinkPrefixLength; + } + + @Structure.FieldOrder({"Length", "Reserved", "Next", "Address"}) + class IP_ADAPTER_DNS_SERVER_ADDRESS_XP extends Structure { + public static class ByReference extends IP_ADAPTER_DNS_SERVER_ADDRESS_XP + implements Structure.ByReference {} + + public int Length; + public int Reserved; + public IP_ADAPTER_DNS_SERVER_ADDRESS_XP.ByReference Next; + public SOCKET_ADDRESS Address; + } + + @Structure.FieldOrder({"Length", "Reserved", "Next", "Address"}) + class IP_ADAPTER_ANYCAST_ADDRESS_XP extends Structure { + public static class ByReference extends IP_ADAPTER_ANYCAST_ADDRESS_XP + implements Structure.ByReference {} + + public int Length; + public int Reserved; + public IP_ADAPTER_DNS_SERVER_ADDRESS_XP.ByReference Next; + public SOCKET_ADDRESS Address; + } + + @Structure.FieldOrder({"Length", "Reserved", "Next", "Address"}) + class IP_ADAPTER_MULTICAST_ADDRESS_XP extends Structure { + public static class ByReference extends IP_ADAPTER_MULTICAST_ADDRESS_XP + implements Structure.ByReference {} + + public int Length; + public int Reserved; + public IP_ADAPTER_DNS_SERVER_ADDRESS_XP.ByReference Next; + public SOCKET_ADDRESS Address; + } + + @Structure.FieldOrder({"Next", "_String"}) + class IP_ADAPTER_DNS_SUFFIX extends Structure { + public static class ByReference extends IP_ADAPTER_DNS_SUFFIX + implements Structure.ByReference {} + + public IP_ADAPTER_DNS_SUFFIX.ByReference Next; + public char[] _String = new char[256]; + } + + @Structure.FieldOrder({ + "Length", + "IfIndex", + "Next", + "AdapterName", + "FirstUnicastAddress", + "FirstAnycastAddress", + "FirstMulticastAddress", + "FirstDnsServerAddress", + "DnsSuffix", + "Description", + "FriendlyName", + "PhysicalAddress", + "PhysicalAddressLength", + "Flags", + "Mtu", + "IfType", + "OperStatus", + "Ipv6IfIndex", + "ZoneIndices", + "FirstPrefix", + "TransmitLinkSpeed", + "ReceiveLinkSpeed", + "FirstWinsServerAddress", + "FirstGatewayAddress", + "Ipv4Metric", + "Ipv6Metric", + "Luid", + "Dhcpv4Server", + "CompartmentId", + "NetworkGuid", + "ConnectionType", + "TunnelType", + "Dhcpv6Server", + "Dhcpv6ClientDuid", + "Dhcpv6ClientDuidLength", + "Dhcpv6Iaid", + "FirstDnsSuffix", + }) + class IP_ADAPTER_ADDRESSES_LH extends Structure { + public static class ByReference extends IP_ADAPTER_ADDRESSES_LH + implements Structure.ByReference {} + + public IP_ADAPTER_ADDRESSES_LH(Pointer p) { + super(p); + read(); + } + + public IP_ADAPTER_ADDRESSES_LH() {} + + public int Length; + public int IfIndex; + + public IP_ADAPTER_ADDRESSES_LH.ByReference Next; + public String AdapterName; + public IP_ADAPTER_UNICAST_ADDRESS_LH.ByReference FirstUnicastAddress; + public IP_ADAPTER_ANYCAST_ADDRESS_XP.ByReference FirstAnycastAddress; + public IP_ADAPTER_MULTICAST_ADDRESS_XP.ByReference FirstMulticastAddress; + public IP_ADAPTER_DNS_SERVER_ADDRESS_XP.ByReference FirstDnsServerAddress; + public WString DnsSuffix; + public WString Description; + public WString FriendlyName; + public byte[] PhysicalAddress = new byte[8]; + public int PhysicalAddressLength; + public int Flags; + public int Mtu; + public int IfType; + public int OperStatus; + public int Ipv6IfIndex; + public int[] ZoneIndices = new int[16]; + public Pointer FirstPrefix; + public long TransmitLinkSpeed; + public long ReceiveLinkSpeed; + public Pointer FirstWinsServerAddress; + public Pointer FirstGatewayAddress; + public int Ipv4Metric; + public int Ipv6Metric; + public Pointer Luid; + public SOCKET_ADDRESS Dhcpv4Server; + public int CompartmentId; + public Guid.GUID NetworkGuid; + public int ConnectionType; + public int TunnelType; + public SOCKET_ADDRESS Dhcpv6Server; + public byte[] Dhcpv6ClientDuid = new byte[130]; + public int Dhcpv6ClientDuidLength; + public int Dhcpv6Iaid; + public IP_ADAPTER_DNS_SUFFIX.ByReference FirstDnsSuffix; + } + + int GetAdaptersAddresses( + int family, + int flags, + Pointer reserved, + Pointer adapterAddresses, + IntByReference sizePointer); +} diff --git a/src/main/java/org/xbill/DNS/config/InitializationException.java b/src/main/java/org/xbill/DNS/config/InitializationException.java new file mode 100644 index 000000000..7648e1822 --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/InitializationException.java @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +public class InitializationException extends Exception { + InitializationException(String message) { + super(message); + } + + InitializationException(Exception e) { + super(e); + } +} diff --git a/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java new file mode 100644 index 000000000..a0e12107c --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Hashtable; +import java.util.StringTokenizer; +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import lombok.extern.slf4j.Slf4j; +import org.xbill.DNS.SimpleResolver; + +/** + * Resolver config provider that tries to extract the system's DNS servers from the JNDI DNS Service + * Provider. + */ +@Slf4j +public class JndiContextResolverConfigProvider extends BaseResolverConfigProvider { + public void initialize() { + Hashtable env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); + // http://mail.openjdk.java.net/pipermail/net-dev/2017-March/010695.html + env.put("java.naming.provider.url", "dns://"); + + String servers = null; + try { + DirContext ctx = new InitialDirContext(env); + servers = (String) ctx.getEnvironment().get("java.naming.provider.url"); + ctx.close(); + } catch (NamingException e) { + // ignore + } + + if (servers != null) { + StringTokenizer st = new StringTokenizer(servers, " "); + while (st.hasMoreTokens()) { + String server = st.nextToken(); + try { + URI serverUri = new URI(server); + String host = serverUri.getHost(); + if (host == null || host.isEmpty()) { + // skip the fallback server to localhost + continue; + } + + int port = serverUri.getPort(); + if (port == -1) { + port = SimpleResolver.DEFAULT_PORT; + } + + addNameserver(new InetSocketAddress(host, port)); + } catch (URISyntaxException e) { + log.debug("Could not parse {} as a dns server, ignoring", server, e); + } + } + } + } + + @Override + public boolean isEnabled() { + return !System.getProperty("java.vendor").contains("Android"); + } +} diff --git a/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java new file mode 100644 index 000000000..ea07f6383 --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.StringTokenizer; +import org.xbill.DNS.SimpleResolver; + +/** + * The properties {@link #DNS_SERVER_PROP}, {@link #DNS_SEARCH_PROP} (comma delimited lists) are + * checked. The servers can either be IP addresses or hostnames (which are resolved using Java's + * built in DNS support). + */ +public class PropertyResolverConfigProvider extends BaseResolverConfigProvider { + public static final String DNS_SERVER_PROP = "dns.server"; + public static final String DNS_SEARCH_PROP = "dns.search"; + public static final String DNS_NDOTS_PROP = "dns.ndots"; + + private int ndots; + + @Override + public void initialize() { + String servers = System.getProperty(DNS_SERVER_PROP); + if (servers != null) { + StringTokenizer st = new StringTokenizer(servers, ","); + while (st.hasMoreTokens()) { + String server = st.nextToken(); + try { + URI uri = new URI("dns://" + server); + // assume this is an IPv6 address without brackets + if (uri.getHost() == null) { + addNameserver(new InetSocketAddress(server, SimpleResolver.DEFAULT_PORT)); + } else { + int port = uri.getPort(); + if (port == -1) { + port = SimpleResolver.DEFAULT_PORT; + } + + addNameserver(new InetSocketAddress(uri.getHost(), port)); + } + } catch (URISyntaxException e) { + log.warn("Ignored invalid server {}", server); + } + } + } + + String searchPathProperty = System.getProperty(DNS_SEARCH_PROP); + parseSearchPathList(searchPathProperty, ","); + + String ndotsProperty = System.getProperty(DNS_NDOTS_PROP); + ndots = parseNdots(ndotsProperty); + } + + @Override + public int ndots() { + return ndots; + } +} diff --git a/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java new file mode 100644 index 000000000..9f41d1619 --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.InetSocketAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.StringTokenizer; +import org.xbill.DNS.SimpleResolver; + +public class ResolvConfResolverConfigProvider extends BaseResolverConfigProvider { + private int ndots = 1; + + public void initialize() { + // first try the default unix config path + if (!tryParseResolveConf("/etc/resolv.cfg")) { + // then fallback to netware + tryParseResolveConf("sys:/etc/resolv.cfg"); + } + } + + private boolean tryParseResolveConf(String path) { + Path p = Paths.get(path); + if (Files.exists(p)) { + try (InputStream in = Files.newInputStream(p)) { + parseResolvConf(in); + return true; + } catch (IOException e) { + // ignore + } + } + + return false; + } + + protected void parseResolvConf(InputStream in) throws IOException { + try (InputStreamReader isr = new InputStreamReader(in); + BufferedReader br = new BufferedReader(isr)) { + String line; + while ((line = br.readLine()) != null) { + StringTokenizer st = new StringTokenizer(line); + if (!st.hasMoreTokens()) { + continue; + } + + switch (st.nextToken()) { + case "nameserver": + addServer(st.nextToken()); + break; + + case "domain": + // man resolv.conf: + // The domain and search keywords are mutually exclusive. If more than one instance of + // these keywords is present, the last instance wins. + searchlist.clear(); + if (!st.hasMoreTokens()) { + continue; + } + + addSearchPath(st.nextToken()); + break; + + case "search": + // man resolv.conf: + // The domain and search keywords are mutually exclusive. If more than one instance of + // these keywords is present, the last instance wins. + searchlist.clear(); + while (st.hasMoreTokens()) { + addSearchPath(st.nextToken()); + } + + case "options": + while (st.hasMoreTokens()) { + String token = st.nextToken(); + if (token.startsWith("ndots:")) { + ndots = parseNdots(token.substring(6)); + } + } + break; + } + } + } + + // man resolv.conf: + // The search keyword of a system's resolv.conf file can be overridden on a per-process basis by + // setting the environment variable LOCALDOMAIN to a space-separated list of search domains. + String localdomain = System.getenv("LOCALDOMAIN"); + if (localdomain != null && !localdomain.isEmpty()) { + searchlist.clear(); + parseSearchPathList(localdomain, " "); + } + + // man resolv.conf: + // The options keyword of a system's resolv.conf file can be amended on a per-process basis by + // setting the environment variable RES_OPTIONS to a space-separated list of resolver options as + // explained above under options. + String resOptions = System.getenv("RES_OPTIONS"); + if (resOptions != null && !resOptions.isEmpty()) { + StringTokenizer st = new StringTokenizer(resOptions, " "); + while (st.hasMoreTokens()) { + String token = st.nextToken(); + if (token.startsWith("ndots:")) { + ndots = parseNdots(token.substring(6)); + } + } + } + } + + private void addServer(String server) { + if (nameservers.size() < 3) { + addNameserver(new InetSocketAddress(server, SimpleResolver.DEFAULT_PORT)); + } + } + + @Override + public int ndots() { + return ndots; + } + + @Override + public boolean isEnabled() { + return !System.getProperty("os.name").contains("Windows"); + } +} diff --git a/src/main/java/org/xbill/DNS/config/ResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/ResolverConfigProvider.java new file mode 100644 index 000000000..176bb9b63 --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/ResolverConfigProvider.java @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +import java.net.InetSocketAddress; +import java.util.List; +import org.xbill.DNS.Name; + +public interface ResolverConfigProvider { + /** Initializes the servers, search paths, etc. */ + void initialize() throws InitializationException; + + /** Returns all located servers, which may be empty. */ + List servers(); + + /** Returns all entries in the located search path, which may be empty. */ + List searchPaths(); + + /** + * Gets the threshold for the number of dots which must appear in a name before it is considered + * absolute. The default is {@code -1}, meaning this provider does not supported reading the ndots + * configuration. + */ + default int ndots() { + return -1; + } + + /** Determines if this provider is enabled. */ + default boolean isEnabled() { + return true; + } +} diff --git a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java new file mode 100644 index 000000000..d4adb6933 --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +import static java.util.stream.Collectors.toList; + +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.List; +import org.xbill.DNS.Name; + +/** + * Resolver config provider that queries the traditional class {@code + * sun.net.dns.ResolverConfiguration} via reflection. + * + *

As of Java 9, this generates an illegal reflective access exception and on Windows, this may + * return invalid nameservers of disconnected NICs. + */ +public class SunJvmResolverConfigProvider implements ResolverConfigProvider { + private List nameservers = null; + private List searchlist = null; + + public void initialize() throws InitializationException { + try { + Class resConfClass = Class.forName("sun.net.dns.ResolverConfiguration"); + Method open = resConfClass.getDeclaredMethod("open"); + Object resConf = open.invoke(null); + + Method nameserversMethod = resConfClass.getMethod("nameservers"); + @SuppressWarnings("unchecked") + List jvmNameservers = (List) nameserversMethod.invoke(resConf); + nameservers = + jvmNameservers.stream().map(ns -> new InetSocketAddress(ns, 53)).collect(toList()); + + Method searchlistMethod = resConfClass.getMethod("searchlist"); + @SuppressWarnings("unchecked") + List jvmSearchlist = (List) searchlistMethod.invoke(resConf); + searchlist = jvmSearchlist.stream().map(Name::fromConstantString).collect(toList()); + } catch (Exception e) { + throw new InitializationException(e); + } + } + + @Override + public List servers() { + if (nameservers == null) { + throw new IllegalStateException("not initialized"); + } + + return Collections.unmodifiableList(nameservers); + } + + @Override + public List searchPaths() { + if (searchlist == null) { + throw new IllegalStateException("not initialized"); + } + + return Collections.unmodifiableList(searchlist); + } + + @Override + public boolean isEnabled() { + return !System.getProperty("java.vendor").contains("Android"); + } +} diff --git a/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java new file mode 100644 index 000000000..7c2c69bfe --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +import static org.xbill.DNS.config.IPHlpAPI.AF_UNSPEC; +import static org.xbill.DNS.config.IPHlpAPI.GAA_FLAG_SKIP_ANYCAST; +import static org.xbill.DNS.config.IPHlpAPI.GAA_FLAG_SKIP_FRIENDLY_NAME; +import static org.xbill.DNS.config.IPHlpAPI.GAA_FLAG_SKIP_MULTICAST; +import static org.xbill.DNS.config.IPHlpAPI.GAA_FLAG_SKIP_UNICAST; +import static org.xbill.DNS.config.IPHlpAPI.INSTANCE; +import static org.xbill.DNS.config.IPHlpAPI.IP_ADAPTER_ADDRESSES_LH; +import static org.xbill.DNS.config.IPHlpAPI.IP_ADAPTER_DNS_SERVER_ADDRESS_XP; +import static org.xbill.DNS.config.IPHlpAPI.IP_ADAPTER_DNS_SUFFIX; + +import com.sun.jna.Memory; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.Win32Exception; +import com.sun.jna.platform.win32.WinError; +import com.sun.jna.ptr.IntByReference; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.xbill.DNS.Name; +import org.xbill.DNS.SimpleResolver; + +/** + * Resolver config provider for Windows. It reads the nameservers and search path by calling the API + * GetAdaptersAddresses. + * This class requires the JNA library on + * the classpath. + */ +@Slf4j +public class WindowsResolverConfigProvider implements ResolverConfigProvider { + private InnerWindowsResolverConfigProvider inner; + + public WindowsResolverConfigProvider() { + if (System.getProperty("os.name").contains("Windows")) { + try { + inner = new InnerWindowsResolverConfigProvider(); + } catch (NoClassDefFoundError e) { + log.debug("JNA not available"); + } + } + } + + @Slf4j + private static class InnerWindowsResolverConfigProvider extends BaseResolverConfigProvider { + public void initialize() throws InitializationException { + // The recommended method of calling the GetAdaptersAddresses function is to pre-allocate a + // 15KB working buffer + Memory buffer = new Memory(15 * 1024); + IntByReference size = new IntByReference(0); + int flags = + GAA_FLAG_SKIP_UNICAST + | GAA_FLAG_SKIP_ANYCAST + | GAA_FLAG_SKIP_MULTICAST + | GAA_FLAG_SKIP_FRIENDLY_NAME; + int error = INSTANCE.GetAdaptersAddresses(AF_UNSPEC, flags, Pointer.NULL, buffer, size); + if (error == WinError.ERROR_BUFFER_OVERFLOW) { + buffer = new Memory(size.getValue()); + error = INSTANCE.GetAdaptersAddresses(AF_UNSPEC, flags, Pointer.NULL, buffer, size); + if (error != WinError.ERROR_SUCCESS) { + throw new InitializationException(new Win32Exception(error)); + } + } + + IP_ADAPTER_ADDRESSES_LH result = new IP_ADAPTER_ADDRESSES_LH(buffer); + do { + // only interfaces with IfOperStatusUp + if (result.OperStatus == 1) { + IP_ADAPTER_DNS_SERVER_ADDRESS_XP dns = result.FirstDnsServerAddress; + while (dns != null) { + InetAddress address = null; + try { + address = dns.Address.toAddress(); + if (!address.isSiteLocalAddress()) { + addNameserver(new InetSocketAddress(address, SimpleResolver.DEFAULT_PORT)); + } else { + log.debug( + "Skipped site-local IPv6 server address {} on adapter index {}", + address, + result.IfIndex); + } + } catch (UnknownHostException e) { + log.warn("Invalid nameserver address on adapter index {}", result.IfIndex, e); + } + + dns = dns.Next; + } + + addSearchPath(result.DnsSuffix.toString()); + IP_ADAPTER_DNS_SUFFIX suffix = result.FirstDnsSuffix; + while (suffix != null) { + addSearchPath(String.valueOf(suffix._String)); + suffix = suffix.Next; + } + } + + result = result.Next; + } while (result != null); + } + } + + @Override + public void initialize() throws InitializationException { + inner.initialize(); + } + + @Override + public List servers() { + return inner.servers(); + } + + @Override + public List searchPaths() { + return inner.searchPaths(); + } + + @Override + public boolean isEnabled() { + return inner != null; + } +} diff --git a/src/main/resources/org/xbill/DNS/windows/DNSServer.properties b/src/main/resources/org/xbill/DNS/windows/DNSServer.properties deleted file mode 100644 index 25342f97b..000000000 --- a/src/main/resources/org/xbill/DNS/windows/DNSServer.properties +++ /dev/null @@ -1,4 +0,0 @@ -host_name=Host Name -primary_dns_suffix=Primary Dns Suffix -dns_suffix=DNS Suffix -dns_servers=DNS Servers diff --git a/src/main/resources/org/xbill/DNS/windows/DNSServer_de.properties b/src/main/resources/org/xbill/DNS/windows/DNSServer_de.properties deleted file mode 100644 index aa3f4a690..000000000 --- a/src/main/resources/org/xbill/DNS/windows/DNSServer_de.properties +++ /dev/null @@ -1,4 +0,0 @@ -host_name=Hostname -primary_dns_suffix=Prim\u00E4res DNS-Suffix -dns_suffix=DNS-Suffixsuchliste -dns_servers=DNS-Server diff --git a/src/main/resources/org/xbill/DNS/windows/DNSServer_fr.properties b/src/main/resources/org/xbill/DNS/windows/DNSServer_fr.properties deleted file mode 100644 index 7c87a25b3..000000000 --- a/src/main/resources/org/xbill/DNS/windows/DNSServer_fr.properties +++ /dev/null @@ -1,4 +0,0 @@ -host_name=Nom de l'h\u00F4te -primary_dns_suffix=Suffixe DNS principal -dns_suffix=Suffixe DNS propre \u00E0 la connexion -dns_servers=Serveurs DNS diff --git a/src/main/resources/org/xbill/DNS/windows/DNSServer_ja.properties b/src/main/resources/org/xbill/DNS/windows/DNSServer_ja.properties deleted file mode 100644 index f87316448..000000000 --- a/src/main/resources/org/xbill/DNS/windows/DNSServer_ja.properties +++ /dev/null @@ -1,4 +0,0 @@ -host_name=\u30db\u30b9\u30c8\u540d -primary_dns_suffix=\u30d7\u30e9\u30a4\u30de\u30ea DNS \u30b5\u30d5\u30a3\u30c3\u30af\u30b9 -dns_suffix=DNS \u30b5\u30d5\u30a3\u30c3\u30af\u30b9 -dns_servers=DNS \u30b5\u30fc\u30d0\u30fc diff --git a/src/main/resources/org/xbill/DNS/windows/DNSServer_pl.properties b/src/main/resources/org/xbill/DNS/windows/DNSServer_pl.properties deleted file mode 100644 index eab57743b..000000000 --- a/src/main/resources/org/xbill/DNS/windows/DNSServer_pl.properties +++ /dev/null @@ -1,4 +0,0 @@ -host_name=Nazwa hosta -primary_dns_suffix=Sufiks podstawowej domeny DNS -dns_suffix=Sufiks DNS konkretnego po\u0142\u0105czenia -dns_servers=Serwery DNS diff --git a/src/test/java/org/xbill/DNS/ResolverConfigTest.java b/src/test/java/org/xbill/DNS/ResolverConfigTest.java index 4a5693b08..48cc009da 100644 --- a/src/test/java/org/xbill/DNS/ResolverConfigTest.java +++ b/src/test/java/org/xbill/DNS/ResolverConfigTest.java @@ -2,82 +2,185 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assumptions.assumeFalse; +import static org.xbill.DNS.config.PropertyResolverConfigProvider.DNS_NDOTS_PROP; +import static org.xbill.DNS.config.PropertyResolverConfigProvider.DNS_SEARCH_PROP; +import static org.xbill.DNS.config.PropertyResolverConfigProvider.DNS_SERVER_PROP; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; import java.util.Arrays; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; +import org.xbill.DNS.config.InitializationException; +import org.xbill.DNS.config.JndiContextResolverConfigProvider; +import org.xbill.DNS.config.PropertyResolverConfigProvider; +import org.xbill.DNS.config.ResolvConfResolverConfigProvider; +import org.xbill.DNS.config.SunJvmResolverConfigProvider; +import org.xbill.DNS.config.WindowsResolverConfigProvider; class ResolverConfigTest { - - @AfterEach - void tearDown() { - ResolverConfig.refresh(); - } - @Test - void findProperty_Success() { - String[] dnsServers = {"server1", "server2"}; + void properties() { + String[] dnsServers = {"192.168.1.1", "192.168.1.2", "192.168.1.1"}; // intentionally adding duplicate search entries for testing String[] dnsSearch = {"dnsjava.org", "example.com", "dnsjava.org"}; Name[] searchPath = Arrays.stream(dnsSearch).map(s -> Name.fromConstantString(s + ".")).toArray(Name[]::new); - System.setProperty(ResolverConfig.DNS_SERVER_PROP, String.join(",", dnsServers)); - System.setProperty(ResolverConfig.DNS_SEARCH_PROP, String.join(",", dnsSearch)); + System.setProperty(DNS_SERVER_PROP, String.join(",", dnsServers)); + System.setProperty(DNS_SEARCH_PROP, String.join(",", dnsSearch)); + System.setProperty(DNS_NDOTS_PROP, String.valueOf(5)); try { - ResolverConfig.refresh(); - ResolverConfig rc = ResolverConfig.getCurrentConfig(); - assertTrue(rc.findProperty()); - assertEquals("server1", rc.server()); - assertEquals(2, rc.servers().length); + PropertyResolverConfigProvider rc = new PropertyResolverConfigProvider(); + assertTrue(rc.isEnabled()); + rc.initialize(); + + assertEquals(2, rc.servers().size()); + assertEquals(dnsServers[0], rc.servers().get(0).getAddress().getHostAddress()); + // any duplicate suffixes should be excluded - assertEquals(2, rc.searchPath().length); - assertEquals(searchPath[0], rc.searchPath()[0]); - assertEquals(searchPath[1], rc.searchPath()[1]); + assertEquals(2, rc.searchPaths().size()); + assertEquals(searchPath[0], rc.searchPaths().get(0)); + assertEquals(searchPath[1], rc.searchPaths().get(1)); + + assertEquals(5, rc.ndots()); + } finally { + System.clearProperty(DNS_SERVER_PROP); + System.clearProperty(DNS_SEARCH_PROP); + System.clearProperty(DNS_NDOTS_PROP); + } + } + + @Test + void propertiesWithPort() { + String[] dnsServers = { + "192.168.1.1", "192.168.1.1:54", "::1", "0:0:0:0:0:0:0:1", "[::1]:54", "[::2]" + }; + System.setProperty(DNS_SERVER_PROP, String.join(",", dnsServers)); + try { + PropertyResolverConfigProvider rc = new PropertyResolverConfigProvider(); + rc.initialize(); + + assertEquals(5, rc.servers().size()); + assertEquals("192.168.1.1", rc.servers().get(0).getAddress().getHostAddress()); + assertEquals(SimpleResolver.DEFAULT_PORT, rc.servers().get(0).getPort()); + + assertEquals("192.168.1.1", rc.servers().get(1).getAddress().getHostAddress()); + assertEquals(54, rc.servers().get(1).getPort()); + + assertEquals("0:0:0:0:0:0:0:1", rc.servers().get(2).getAddress().getHostAddress()); + assertEquals(SimpleResolver.DEFAULT_PORT, rc.servers().get(2).getPort()); + + assertEquals("0:0:0:0:0:0:0:1", rc.servers().get(3).getAddress().getHostAddress()); + assertEquals(54, rc.servers().get(3).getPort()); + + assertEquals("0:0:0:0:0:0:0:2", rc.servers().get(4).getAddress().getHostAddress()); + assertEquals(53, rc.servers().get(4).getPort()); } finally { - System.clearProperty(ResolverConfig.DNS_SERVER_PROP); - System.clearProperty(ResolverConfig.DNS_SEARCH_PROP); + System.clearProperty(DNS_SERVER_PROP); } } @Test - @EnabledOnOs({OS.WINDOWS}) - void findNT_Windows() { - assertTrue(ResolverConfig.getCurrentConfig().findWin()); + @EnabledOnOs(OS.WINDOWS) + void resolvConfDisabledOnWindows() { + ResolvConfResolverConfigProvider rc = new ResolvConfResolverConfigProvider(); + assertFalse(rc.isEnabled()); + } + + @Test + @DisabledOnOs(OS.WINDOWS) + void resolvConfEnabledOnUnix() { + ResolvConfResolverConfigProvider rc = new ResolvConfResolverConfigProvider(); + assertTrue(rc.isEnabled()); + } + + @Test + @EnabledOnOs(OS.WINDOWS) + void windowsEnabledOnWindows() { + WindowsResolverConfigProvider rc = new WindowsResolverConfigProvider(); + assertTrue(rc.isEnabled()); + } + + @Test + @DisabledOnOs(OS.WINDOWS) + void windowsDisabledOnUnix() { + WindowsResolverConfigProvider rc = new WindowsResolverConfigProvider(); + assertFalse(rc.isEnabled()); + } + + @Test + void resolvConf() { + ResolvConfResolverConfigProvider rc = + new ResolvConfResolverConfigProvider() { + @Override + public void initialize() { + try { + try (InputStream in = + ResolverConfigTest.class.getResourceAsStream("/test_loaded_resolv.conf")) { + parseResolvConf(in); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }; + + rc.initialize(); + assertEquals(1, rc.servers().size()); + assertEquals(new InetSocketAddress("192.168.1.1", 53), rc.servers().get(0)); + assertEquals(2, rc.searchPaths().size()); + assertFalse(rc.searchPaths().contains(Name.fromConstantString("domain.com."))); + assertEquals(5, rc.ndots()); } @Test - @DisabledOnOs({OS.WINDOWS}) - void findNT_NotWindows() { - assertFalse(ResolverConfig.getCurrentConfig().findWin()); + void jndi() { + JndiContextResolverConfigProvider rc = new JndiContextResolverConfigProvider(); + assertTrue(rc.isEnabled()); + rc.initialize(); } @Test - @DisabledOnOs({OS.WINDOWS}) - void findUnix() { - assertTrue(ResolverConfig.getCurrentConfig().findUnix()); + void sunJvmThrowsIfNotInitialized() { + SunJvmResolverConfigProvider rc = new SunJvmResolverConfigProvider(); + assertThrows(IllegalStateException.class, rc::servers); } @Test - void resolvConfLoaded() { - assertTrue( - ResolverConfig.getCurrentConfig() - .findResolvConf( - ResolverConfigTest.class.getResourceAsStream("/test_loaded_resolv.conf"))); - assertEquals(5, ResolverConfig.getCurrentConfig().ndots()); + void sunJvm() throws InitializationException { + SunJvmResolverConfigProvider rc = new SunJvmResolverConfigProvider(); + assertTrue(rc.isEnabled()); + rc.initialize(); } @Test - void findNetware() { - assumeFalse(ResolverConfig.getCurrentConfig().findNetware()); + void sunJvmServersEqualsJndi() throws InitializationException { + SunJvmResolverConfigProvider sun = new SunJvmResolverConfigProvider(); + sun.initialize(); + JndiContextResolverConfigProvider jndi = new JndiContextResolverConfigProvider(); + jndi.initialize(); + assertEquals(sun.servers(), jndi.servers()); } @Test - void findAndroid() { - assumeFalse(ResolverConfig.getCurrentConfig().findAndroid()); + @EnabledOnOs(OS.WINDOWS) + void windowsServersContainedInJndi() throws InitializationException { + JndiContextResolverConfigProvider jndi = new JndiContextResolverConfigProvider(); + jndi.initialize(); + WindowsResolverConfigProvider win = new WindowsResolverConfigProvider(); + win.initialize(); + + // the servers returned via Windows API must be in the JNDI list, but not necessarily the other + // way round + for (InetSocketAddress winServer : win.servers()) { + assertTrue( + jndi.servers().contains(winServer), + winServer + " not found in JNDI, " + win.servers() + "; " + jndi.servers()); + } } } From be3093fa036bf7ff73b47843189d3c53ddd55dfb Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 9 Nov 2019 00:02:12 +0100 Subject: [PATCH 013/431] Ignore empty search paths --- .../java/org/xbill/DNS/config/BaseResolverConfigProvider.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java index 162c4c947..8f4f1c6d4 100644 --- a/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java @@ -30,6 +30,10 @@ void parseSearchPathList(String search, String delimiter) { } void addSearchPath(String searchPath) { + if (searchPath == null || searchPath.isEmpty()) { + return; + } + try { Name n = Name.fromString(searchPath, Name.root); if (!searchlist.contains(n)) { From 2f95fb76fc67f725591460dbf92745c6081c5fc2 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 9 Nov 2019 00:03:10 +0100 Subject: [PATCH 014/431] Create mock Message answers with question to satisfy validation --- src/test/java/org/xbill/DNS/AddressTest.java | 51 ++++++++++++++++++-- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/xbill/DNS/AddressTest.java b/src/test/java/org/xbill/DNS/AddressTest.java index f894fcf49..8e7e91222 100644 --- a/src/test/java/org/xbill/DNS/AddressTest.java +++ b/src/test/java/org/xbill/DNS/AddressTest.java @@ -51,6 +51,7 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; +import org.mockito.stubbing.Answer; class AddressTest { @Test @@ -326,7 +327,15 @@ void getByName() throws IOException { Section.ANSWER); Resolver mockResolver = Mockito.mock(Resolver.class); - when(mockResolver.send(ArgumentMatchers.any(Message.class))).thenReturn(aMessage); + when(mockResolver.send(ArgumentMatchers.any(Message.class))) + .thenAnswer( + (Answer) + invocation -> { + Message query = invocation.getArgument(0); + Message answer = aMessage.clone(); + answer.addRecord(query.getQuestion(), Section.QUESTION); + return answer; + }); Lookup.setDefaultResolver(mockResolver); out = Address.getByName("a.root-servers.net"); @@ -341,7 +350,15 @@ void getByName_invalid() throws IOException { Message m = new Message(); m.getHeader().setRcode(Rcode.NXDOMAIN); Resolver mockResolver = Mockito.mock(Resolver.class); - when(mockResolver.send(ArgumentMatchers.any(Message.class))).thenReturn(m); + when(mockResolver.send(ArgumentMatchers.any(Message.class))) + .thenAnswer( + (Answer) + invocation -> { + Message query = invocation.getArgument(0); + Message answer = m.clone(); + answer.addRecord(query.getQuestion(), Section.QUESTION); + return answer; + }); Lookup.setDefaultResolver(mockResolver); assertThrows(UnknownHostException.class, () -> Address.getByName("example.invalid")); // reset resolver @@ -401,7 +418,15 @@ void getAllByName_invalid() throws IOException { Message m = new Message(); m.getHeader().setRcode(Rcode.NXDOMAIN); Resolver mockResolver = Mockito.mock(Resolver.class); - when(mockResolver.send(ArgumentMatchers.any(Message.class))).thenReturn(m); + when(mockResolver.send(ArgumentMatchers.any(Message.class))) + .thenAnswer( + (Answer) + invocation -> { + Message query = invocation.getArgument(0); + Message answer = m.clone(); + answer.addRecord(query.getQuestion(), Section.QUESTION); + return answer; + }); Lookup.setDefaultResolver(mockResolver); assertThrows(UnknownHostException.class, () -> Address.getAllByName("example.invalid")); @@ -427,7 +452,15 @@ void getHostName() throws IOException { ptrMessage.addRecord(Record.newRecord(aRootServerPtr, Type.PTR, DClass.IN), Section.QUESTION); ptrMessage.addRecord(new PTRRecord(aRootServerPtr, DClass.IN, 60, aRootServer), Section.ANSWER); Resolver mockResolver = Mockito.mock(Resolver.class); - when(mockResolver.send(any(Message.class))).thenReturn(ptrMessage); + when(mockResolver.send(any(Message.class))) + .thenAnswer( + (Answer) + invocation -> { + Message query = invocation.getArgument(0); + Message answer = ptrMessage.clone(); + answer.addRecord(query.getQuestion(), Section.QUESTION); + return answer; + }); Lookup.setDefaultResolver(mockResolver); String out = Address.getHostName(InetAddress.getByName("198.41.0.4")); @@ -439,7 +472,15 @@ void getHostName() throws IOException { Record.newRecord(Name.fromString("1.1.168.192.in-addr.arpa."), Type.PTR, DClass.IN), Section.QUESTION); mockResolver = Mockito.mock(Resolver.class); - when(mockResolver.send(any())).thenReturn(ptrMessage2); + when(mockResolver.send(any())) + .thenAnswer( + (Answer) + invocation -> { + Message query = invocation.getArgument(0); + Message answer = ptrMessage2.clone(); + answer.addRecord(query.getQuestion(), Section.QUESTION); + return answer; + }); Lookup.setDefaultResolver(mockResolver); assertThrows( UnknownHostException.class, From 9225d353d1720c3ab85cda0dc1444f1e247ab08b Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 9 Nov 2019 00:03:27 +0100 Subject: [PATCH 015/431] Improve logging --- pom.xml | 8 +++++++- src/main/java/org/xbill/DNS/Cache.java | 5 +++-- src/main/java/org/xbill/DNS/ExtendedResolver.java | 5 +++++ src/main/java/org/xbill/DNS/Lookup.java | 14 +++++--------- src/main/java/org/xbill/DNS/SimpleResolver.java | 5 +++++ src/test/resources/simplelogger.properties | 1 + 6 files changed, 26 insertions(+), 12 deletions(-) create mode 100644 src/test/resources/simplelogger.properties diff --git a/pom.xml b/pom.xml index 10059b3c0..b474963d3 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,7 @@ org.slf4j slf4j-api - 1.7.28 + 1.7.29 org.projectlombok @@ -249,6 +249,12 @@ 3.1.0 test + + org.slf4j + slf4j-simple + 1.7.29 + test + diff --git a/src/main/java/org/xbill/DNS/Cache.java b/src/main/java/org/xbill/DNS/Cache.java index 706059dfa..1f833abab 100644 --- a/src/main/java/org/xbill/DNS/Cache.java +++ b/src/main/java/org/xbill/DNS/Cache.java @@ -721,8 +721,9 @@ public SetResponse addMessage(Message in) { cred = getCred(Section.ADDITIONAL, isAuth); addRRset(rRset, cred); } - log.debug("addMessage: {}", response); - return (response); + + log.debug("caching {} for {}", response, in.getQuestion().getName()); + return response; } /** diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index 9804d38cb..99e851e0f 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -428,4 +428,9 @@ public void setLoadBalance(boolean flag) { public void setRetries(int retries) { this.retries = retries; } + + @Override + public String toString() { + return "ExtendedResolver of " + resolvers; + } } diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index b08b149f1..e1bf3444e 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -433,10 +433,8 @@ private void processResponse(Name name, SetResponse response) { private void lookup(Name current) { SetResponse sr = cache.lookupRecords(current, type, credibility); - if (log.isDebugEnabled()) { - log.debug("lookup {} {}", current, Type.string(type)); - log.debug(sr.toString()); - } + log.debug("lookup {} {}, cache answer: {}", current, Type.string(type), sr); + processResponse(current, sr); if (done || doneCurrent) { return; @@ -448,7 +446,7 @@ private void lookup(Name current) { try { response = resolver.send(query); } catch (IOException e) { - log.debug("Lookup failed", e); + log.debug("Lookup failed using resolver {}", resolver, e); // A network error occurred. Press on. if (e instanceof InterruptedIOException) { @@ -478,10 +476,8 @@ private void lookup(Name current) { if (sr == null) { sr = cache.lookupRecords(current, type, credibility); } - if (log.isDebugEnabled()) { - log.debug("queried {} {}", current, Type.string(type)); - log.debug(sr.toString()); - } + + log.debug("Queried {} {}: {}", current, Type.string(type), sr); processResponse(current, sr); } diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index ee6aa94a0..332cd3200 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -344,4 +344,9 @@ private Message sendAXFR(Message query) throws IOException { } return response; } + + @Override + public String toString() { + return "SimpleResolver [" + address + "]"; + } } diff --git a/src/test/resources/simplelogger.properties b/src/test/resources/simplelogger.properties new file mode 100644 index 000000000..beb56b2e1 --- /dev/null +++ b/src/test/resources/simplelogger.properties @@ -0,0 +1 @@ +org.slf4j.simpleLogger.defaultLogLevel=debug From 43e59edb6c21f490ad3f9bcb6de4a9d4630298a6 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 9 Nov 2019 01:00:05 +0100 Subject: [PATCH 016/431] Use absolute search paths in SunJVM provider --- src/main/java/org/xbill/DNS/Name.java | 2 +- .../DNS/config/SunJvmResolverConfigProvider.java | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Name.java b/src/main/java/org/xbill/DNS/Name.java index 490362226..1481ba2db 100644 --- a/src/main/java/org/xbill/DNS/Name.java +++ b/src/main/java/org/xbill/DNS/Name.java @@ -307,7 +307,7 @@ public static Name fromString(String s, Name origin) throws TextParseException { if (s.equals("@") && origin != null) { return origin; } else if (s.equals(".")) { - return (root); + return root; } return new Name(s, origin); diff --git a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java index d4adb6933..cb0a9612e 100644 --- a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java @@ -8,6 +8,7 @@ import java.util.Collections; import java.util.List; import org.xbill.DNS.Name; +import org.xbill.DNS.TextParseException; /** * Resolver config provider that queries the traditional class {@code @@ -35,7 +36,17 @@ public void initialize() throws InitializationException { Method searchlistMethod = resConfClass.getMethod("searchlist"); @SuppressWarnings("unchecked") List jvmSearchlist = (List) searchlistMethod.invoke(resConf); - searchlist = jvmSearchlist.stream().map(Name::fromConstantString).collect(toList()); + searchlist = + jvmSearchlist.stream() + .map( + n -> { + try { + return Name.fromString(n, Name.root); + } catch (TextParseException e) { + throw new IllegalArgumentException(e); + } + }) + .collect(toList()); } catch (Exception e) { throw new InitializationException(e); } From cb30bfa57a55d179526d14d80a0eacbad113e245 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 9 Nov 2019 01:13:19 +0100 Subject: [PATCH 017/431] Use Github actions for cross os builds --- .github/workflows/build.yml | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..49ca4650a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,38 @@ +name: dnsjava CI + +on: [push] + +jobs: + test: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ ubuntu-16.04, ubuntu-latest, windows-latest ] + java: [ '1.8', '11' ] + arch: [ 'x86', 'x64' ] + exclude: + - os: ubuntu-16.04 + arch: x86 + - os: ubuntu-latest + arch: x86 + + name: Java ${{ matrix.java }}/${{ matrix.arch }}/${{ matrix.os }} + + steps: + - uses: actions/checkout@v1 + + - name: Cache Maven dependencies + uses: actions/cache@v1 + with: + path: ~/.m2 + key: m2 + + - name: Set up JDK ${{ matrix.java }} + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + architecture: ${{ matrix.arch }} + + - name: Build with Maven + run: mvn test jacoco:report -B -"Dgpg.skip" From bc58efc71b818cd7f9e1068cb954d591b2ea641c Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 10 Nov 2019 13:01:32 +0100 Subject: [PATCH 018/431] Move JNDI provider to inner class to avoid CNE on Android --- .../JndiContextResolverConfigProvider.java | 95 ++++++++++++------- 1 file changed, 63 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java index a0e12107c..6e15a1a68 100644 --- a/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java @@ -5,12 +5,14 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.Hashtable; +import java.util.List; import java.util.StringTokenizer; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import lombok.extern.slf4j.Slf4j; +import org.xbill.DNS.Name; import org.xbill.DNS.SimpleResolver; /** @@ -19,49 +21,78 @@ * Provider. */ @Slf4j -public class JndiContextResolverConfigProvider extends BaseResolverConfigProvider { - public void initialize() { - Hashtable env = new Hashtable<>(); - env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); - // http://mail.openjdk.java.net/pipermail/net-dev/2017-March/010695.html - env.put("java.naming.provider.url", "dns://"); +public class JndiContextResolverConfigProvider implements ResolverConfigProvider { + private InnerJndiContextResolverConfigProvider inner; - String servers = null; - try { - DirContext ctx = new InitialDirContext(env); - servers = (String) ctx.getEnvironment().get("java.naming.provider.url"); - ctx.close(); - } catch (NamingException e) { - // ignore + public JndiContextResolverConfigProvider() { + if (!System.getProperty("java.vendor").contains("Android")) { + try { + inner = new InnerJndiContextResolverConfigProvider(); + } catch (NoClassDefFoundError e) { + log.debug("JNDI DNS not available"); + } } + } - if (servers != null) { - StringTokenizer st = new StringTokenizer(servers, " "); - while (st.hasMoreTokens()) { - String server = st.nextToken(); - try { - URI serverUri = new URI(server); - String host = serverUri.getHost(); - if (host == null || host.isEmpty()) { - // skip the fallback server to localhost - continue; - } + private static class InnerJndiContextResolverConfigProvider extends BaseResolverConfigProvider { + public void initialize() { + Hashtable env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); + // http://mail.openjdk.java.net/pipermail/net-dev/2017-March/010695.html + env.put("java.naming.provider.url", "dns://"); - int port = serverUri.getPort(); - if (port == -1) { - port = SimpleResolver.DEFAULT_PORT; - } + String servers = null; + try { + DirContext ctx = new InitialDirContext(env); + servers = (String) ctx.getEnvironment().get("java.naming.provider.url"); + ctx.close(); + } catch (NamingException e) { + // ignore + } + + if (servers != null) { + StringTokenizer st = new StringTokenizer(servers, " "); + while (st.hasMoreTokens()) { + String server = st.nextToken(); + try { + URI serverUri = new URI(server); + String host = serverUri.getHost(); + if (host == null || host.isEmpty()) { + // skip the fallback server to localhost + continue; + } + + int port = serverUri.getPort(); + if (port == -1) { + port = SimpleResolver.DEFAULT_PORT; + } - addNameserver(new InetSocketAddress(host, port)); - } catch (URISyntaxException e) { - log.debug("Could not parse {} as a dns server, ignoring", server, e); + addNameserver(new InetSocketAddress(host, port)); + } catch (URISyntaxException e) { + log.debug("Could not parse {} as a dns server, ignoring", server, e); + } } } } } + @Override + public void initialize() { + inner.initialize(); + } + + @Override + public List servers() { + return inner.servers(); + } + + @Override + public List searchPaths() { + return inner.searchPaths(); + } + @Override public boolean isEnabled() { - return !System.getProperty("java.vendor").contains("Android"); + return inner != null; } } From 347811968f1609f79a5144be36337c3f44ee363b Mon Sep 17 00:00:00 2001 From: Giampaolo Date: Fri, 6 Dec 2019 10:56:57 +1300 Subject: [PATCH 019/431] dont use with android --- .../org/xbill/DNS/config/ResolvConfResolverConfigProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java index 9f41d1619..09cbb634f 100644 --- a/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java @@ -123,6 +123,7 @@ public int ndots() { @Override public boolean isEnabled() { - return !System.getProperty("os.name").contains("Windows"); + return !System.getProperty("os.name").contains("Windows") + && !System.getProperty("java.specification.vendor").toLowerCase().contains("android"); } } From 074ffe573561fb645a73485b0fb21a1ae7ddf049 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Thu, 5 Dec 2019 23:45:09 +0100 Subject: [PATCH 020/431] Fix typo: conf, not cfg on Linux --- .../org/xbill/DNS/config/ResolvConfResolverConfigProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java index 09cbb634f..54709893b 100644 --- a/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java @@ -17,7 +17,7 @@ public class ResolvConfResolverConfigProvider extends BaseResolverConfigProvider public void initialize() { // first try the default unix config path - if (!tryParseResolveConf("/etc/resolv.cfg")) { + if (!tryParseResolveConf("/etc/resolv.conf")) { // then fallback to netware tryParseResolveConf("sys:/etc/resolv.cfg"); } From 1639c91f5c67a7b91a0015ccebd42b1d1524b208 Mon Sep 17 00:00:00 2001 From: demonti Date: Sat, 7 Dec 2019 18:48:35 +0100 Subject: [PATCH 021/431] addition of EDNS Cookie and TCP Keepalive Options (#78) * added Cookie and TCP Keepalive EDNS options * fix: TCP_KEEPALIVE was not handled in fromWire * - added BADCOOKIE extended error code - moved TKEY extended error code to regular error codes as this ist IMHO not part of TSIG - added two more TKEY extended error codes listed at IANA - fixed Rcode test as RCODE 20 is no longer reserved, but assigned * ran code autoformatting (which makes the code even uglier, but anyway) * - use Duration and Optional within the new EDNS options - added test cases * ran code formatter --- src/main/java/org/xbill/DNS/CookieOption.java | 116 ++++++++++++++++++ src/main/java/org/xbill/DNS/EDNSOption.java | 14 +++ src/main/java/org/xbill/DNS/Rcode.java | 17 ++- .../org/xbill/DNS/TcpKeepaliveOption.java | 116 ++++++++++++++++++ .../java/org/xbill/DNS/CookieOptionTest.java | 105 ++++++++++++++++ src/test/java/org/xbill/DNS/RcodeTest.java | 4 +- .../org/xbill/DNS/TcpKeepaliveOptionTest.java | 68 ++++++++++ 7 files changed, 437 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/xbill/DNS/CookieOption.java create mode 100644 src/main/java/org/xbill/DNS/TcpKeepaliveOption.java create mode 100644 src/test/java/org/xbill/DNS/CookieOptionTest.java create mode 100644 src/test/java/org/xbill/DNS/TcpKeepaliveOptionTest.java diff --git a/src/main/java/org/xbill/DNS/CookieOption.java b/src/main/java/org/xbill/DNS/CookieOption.java new file mode 100644 index 000000000..2c91db29b --- /dev/null +++ b/src/main/java/org/xbill/DNS/CookieOption.java @@ -0,0 +1,116 @@ +package org.xbill.DNS; + +import java.io.IOException; +import java.util.Optional; +import org.xbill.DNS.utils.base16; + +/** + * Cookie EDNS0 Option, as defined in https://tools.ietf.org/html/rfc7873 + * + * @see OPTRecord + * @author Klaus Malorny + */ +public class CookieOption extends EDNSOption { + + /** client cookie */ + private byte[] clientCookie; + + /** server cookie */ + private Optional serverCookie; + + /** Default constructor for constructing instance from binary representation. */ + CookieOption() { + super(EDNSOption.Code.COOKIE); + } + + /** + * Constructor. + * + * @param clientCookie the client cookie, which must consist of eight bytes + */ + public CookieOption(byte[] clientCookie) { + this(clientCookie, Optional.empty()); + } + + /** + * Constructor. + * + * @param clientCookie the client cookie, which must consist of eight bytes + * @param serverCookie the server cookie, which must consist of 8 to 32 bytes if present + */ + public CookieOption(byte[] clientCookie, Optional serverCookie) { + this(); + if (clientCookie == null) throw new IllegalArgumentException("client cookie must not be null"); + if (clientCookie.length != 8) + throw new IllegalArgumentException("client cookie must consist of eight bytes"); + this.clientCookie = clientCookie; + + if (serverCookie.isPresent()) { + int length = serverCookie.get().length; + if (length < 8 || length > 32) + throw new IllegalArgumentException("server cookie must consist of 8 to 32 bytes"); + } + this.serverCookie = serverCookie; + } + + /** + * Returns the client cookie. + * + * @return the client cookie + */ + public byte[] getClientCookie() { + return clientCookie; + } + + /** + * Returns the server cookie. + * + * @return the server cookie + */ + public Optional getServerCookie() { + return serverCookie; + } + + /** + * Converts the wire format of an EDNS Option (the option data only) into the type-specific + * format. + * + * @param in The input stream. + */ + @Override + void optionFromWire(DNSInput in) throws IOException { + int length = in.remaining(); + if (length < 8) throw new WireParseException("invalid length of client cookie"); + clientCookie = in.readByteArray(8); + if (length > 8) { + if (length < 16 || length > 40) + throw new WireParseException("invalid length of server cookie"); + serverCookie = Optional.of(in.readByteArray()); + } else { + serverCookie = Optional.empty(); + } + } + + /** + * Converts an EDNS Option (the type-specific option data only) into wire format. + * + * @param out The output stream. + */ + @Override + void optionToWire(DNSOutput out) { + out.writeByteArray(clientCookie); + if (serverCookie.isPresent()) out.writeByteArray(serverCookie.get()); + } + + /** + * Returns a string representation of the option parameters + * + * @return the string representation + */ + @Override + String optionToString() { + return serverCookie.isPresent() + ? base16.toString(clientCookie) + " " + base16.toString(serverCookie.get()) + : base16.toString(clientCookie); + } +} diff --git a/src/main/java/org/xbill/DNS/EDNSOption.java b/src/main/java/org/xbill/DNS/EDNSOption.java index e4c110d70..b1ca55936 100644 --- a/src/main/java/org/xbill/DNS/EDNSOption.java +++ b/src/main/java/org/xbill/DNS/EDNSOption.java @@ -22,6 +22,12 @@ private Code() {} /** Client Subnet, defined in draft-vandergaast-edns-client-subnet-02 */ public static final int CLIENT_SUBNET = 8; + /** Cookie, RFC 7873 */ + public static final int COOKIE = 10; + + /** TCP Keepalive, RFC 7828 */ + public static final int TCP_KEEPALIVE = 11; + private static Mnemonic codes = new Mnemonic("EDNS Option Codes", Mnemonic.CASE_UPPER); static { @@ -31,6 +37,8 @@ private Code() {} codes.add(NSID, "NSID"); codes.add(CLIENT_SUBNET, "CLIENT_SUBNET"); + codes.add(COOKIE, "COOKIE"); + codes.add(TCP_KEEPALIVE, "TCP_KEEPALIVE"); } /** Converts an EDNS Option Code into its textual representation */ @@ -121,6 +129,12 @@ static EDNSOption fromWire(DNSInput in) throws IOException { case Code.CLIENT_SUBNET: option = new ClientSubnetOption(); break; + case Code.COOKIE: + option = new CookieOption(); + break; + case Code.TCP_KEEPALIVE: + option = new TcpKeepaliveOption(); + break; default: option = new GenericEDNSOption(code); break; diff --git a/src/main/java/org/xbill/DNS/Rcode.java b/src/main/java/org/xbill/DNS/Rcode.java index f7b2d02b2..fb65ffc4d 100644 --- a/src/main/java/org/xbill/DNS/Rcode.java +++ b/src/main/java/org/xbill/DNS/Rcode.java @@ -66,6 +66,18 @@ public final class Rcode { /** The mode is invalid (TKEY extended error) */ public static final int BADMODE = 19; + /** Duplicate key name (TKEY extended error) */ + public static final int BADNAME = 20; + + /** Algorithm not supported (TKEY extended error) */ + public static final int BADALG = 21; + + /** Bad truncation (RFC 4635) */ + public static final int BADTRUNC = 22; + + /** Bad or missing server cookie (RFC 7873) */ + public static final int BADCOOKIE = 23; + static { rcodes.setMaximum(0xFFF); rcodes.setPrefix("RESERVED"); @@ -84,6 +96,10 @@ public final class Rcode { rcodes.add(NOTAUTH, "NOTAUTH"); rcodes.add(NOTZONE, "NOTZONE"); rcodes.add(BADVERS, "BADVERS"); + rcodes.add(BADMODE, "BADMODE"); + rcodes.add(BADNAME, "BADNAME"); + rcodes.add(BADALG, "BADALG"); + rcodes.add(BADCOOKIE, "BADCOOKIE"); tsigrcodes.setMaximum(0xFFFF); tsigrcodes.setPrefix("RESERVED"); @@ -93,7 +109,6 @@ public final class Rcode { tsigrcodes.add(BADSIG, "BADSIG"); tsigrcodes.add(BADKEY, "BADKEY"); tsigrcodes.add(BADTIME, "BADTIME"); - tsigrcodes.add(BADMODE, "BADMODE"); } private Rcode() {} diff --git a/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java b/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java new file mode 100644 index 000000000..4b5cb07f7 --- /dev/null +++ b/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java @@ -0,0 +1,116 @@ +package org.xbill.DNS; + +import java.io.IOException; +import java.time.Duration; +import java.util.Optional; +import java.util.OptionalInt; + +/** + * TCP Keepalive EDNS0 Option, as defined in https://tools.ietf.org/html/rfc7828 + * + * @see OPTRecord + * @author Klaus Malorny + */ +public class TcpKeepaliveOption extends EDNSOption { + + /** the timeout */ + private OptionalInt timeout; + + /** upper limit of the duration (exclusive) */ + private static final Duration UPPER_LIMIT = Duration.ofMillis(6553600); + + /** Constructor for an option with no timeout */ + public TcpKeepaliveOption() { + super(EDNSOption.Code.TCP_KEEPALIVE); + timeout = OptionalInt.empty(); + } + + /** + * Constructor for an option with a given timeout. + * + * @param t the timeout time in 100ms units, may not be negative or larger than 65535 + */ + public TcpKeepaliveOption(int t) { + super(EDNSOption.Code.TCP_KEEPALIVE); + if (t < 0 || t > 65535) + throw new IllegalArgumentException("timeout must be betwee 0 and 65535"); + timeout = OptionalInt.of(t); + } + + /** + * Constructor for an option with a given timeout. As the timeout has a coarser granularity than + * the {@link Duration} class, values are rounded down. + * + * @param t the timeout time, must not be negative and must be lower than 6553.5 seconds + */ + public TcpKeepaliveOption(Duration t) { + super(EDNSOption.Code.TCP_KEEPALIVE); + if (t.isNegative() || t.compareTo(UPPER_LIMIT) >= 0) + throw new IllegalArgumentException( + "timeout must be between 0 and 6553.6 seconds (exclusively)"); + timeout = OptionalInt.of((int) t.toMillis() / 100); + } + + /** + * Returns the timeout. + * + * @return the timeout in 100ms units + */ + public OptionalInt getTimeout() { + return timeout; + } + + /** + * Returns the timeout as a {@link Duration}. + * + * @reutrn the timeout + */ + public Optional getTimeoutDuration() { + return timeout.isPresent() + ? Optional.of(Duration.ofMillis(timeout.getAsInt() * 100)) + : Optional.empty(); + } + + /** + * Converts the wire format of an EDNS Option (the option data only) into the type-specific + * format. + * + * @param in The input stream. + */ + @Override + void optionFromWire(DNSInput in) throws IOException { + int length = in.remaining(); + + switch (length) { + case 0: + timeout = OptionalInt.empty(); + break; + case 2: + timeout = OptionalInt.of(in.readU16()); + break; + default: + throw new WireParseException( + "invalid length (" + length + ") of the data in the edns_tcp_keepalive option"); + } + } + + /** + * Converts an EDNS Option (the type-specific option data only) into wire format. + * + * @param out The output stream. + */ + @Override + void optionToWire(DNSOutput out) { + if (timeout.isPresent()) out.writeU16(timeout.getAsInt()); + } + + /** + * Returns a string representation of the option parameters. + * + * @return the string representation + */ + @Override + String optionToString() { + return timeout.isPresent() ? String.valueOf(timeout.getAsInt()) : "-"; + } +} diff --git a/src/test/java/org/xbill/DNS/CookieOptionTest.java b/src/test/java/org/xbill/DNS/CookieOptionTest.java new file mode 100644 index 000000000..a774b4306 --- /dev/null +++ b/src/test/java/org/xbill/DNS/CookieOptionTest.java @@ -0,0 +1,105 @@ +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.xbill.DNS.utils.base16; + +class CookieOptionTest { + + @Test + void constructorTests() { + byte[] sevenBytes = base16.fromString("20212223242526"); + byte[] eightBytes = base16.fromString("3031323334353637"); + byte[] eightBytes2 = base16.fromString("A0A1A2A3A4A5A6A7"); + byte[] nineBytes = base16.fromString("404142434445565748"); + byte[] thirtyTwoBytes = + base16.fromString("505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F"); + byte[] thirtyThreeBytes = + base16.fromString("707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90"); + + CookieOption option = new CookieOption(eightBytes); + assertArrayEquals(eightBytes, option.getClientCookie()); + assertFalse(option.getServerCookie().isPresent()); + new CookieOption(eightBytes, Optional.empty()); + + option = new CookieOption(eightBytes, Optional.empty()); + assertArrayEquals(eightBytes, option.getClientCookie()); + assertFalse(option.getServerCookie().isPresent()); + + option = new CookieOption(eightBytes, Optional.of(eightBytes2)); + Optional serverCookie = option.getServerCookie(); + assertTrue(serverCookie.isPresent()); + assertArrayEquals(eightBytes2, serverCookie.get()); + + option = new CookieOption(eightBytes, Optional.of(thirtyTwoBytes)); + serverCookie = option.getServerCookie(); + assertTrue(serverCookie.isPresent()); + assertArrayEquals(thirtyTwoBytes, serverCookie.get()); + + assertThrows(IllegalArgumentException.class, () -> new CookieOption(sevenBytes)); + assertThrows(IllegalArgumentException.class, () -> new CookieOption(nineBytes)); + assertThrows( + IllegalArgumentException.class, + () -> new CookieOption(eightBytes, Optional.of(sevenBytes))); + assertThrows( + IllegalArgumentException.class, + () -> new CookieOption(eightBytes, Optional.of(thirtyThreeBytes))); + } + + @Test + void wireTests() throws IOException { + byte[] clientOnlyCookieOption = base16.fromString("000A00081011121314151617"); + byte[] clientCookie1 = base16.fromString("1011121314151617"); + byte[] clientServerCookieOption = + base16.fromString("000A0012202122232425262730313233343536373839"); + byte[] clientCookie2 = base16.fromString("2021222324252627"); + byte[] serverCookie2 = base16.fromString("30313233343536373839"); + byte[] validLength1 = base16.fromString("000A0010000102030405060708090A0B0C0D0E0F"); + byte[] validLength2 = + base16.fromString( + "000A0028000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627"); + byte[] brokenLength1 = base16.fromString("000A000700010203040506"); + byte[] brokenLength2 = base16.fromString("000A000C000102030405060708090A0B"); + byte[] brokenLength3 = base16.fromString("000A000F000102030405060708090A0B0C0D0E"); + byte[] brokenLength4 = + base16.fromString( + "000A0029000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728"); + + EDNSOption option = EDNSOption.fromWire(clientOnlyCookieOption); + assertNotNull(option); + assertEquals(CookieOption.class, option.getClass()); + CookieOption cookieOption = (CookieOption) option; + assertArrayEquals(clientCookie1, cookieOption.getClientCookie()); + assertFalse(cookieOption.getServerCookie().isPresent()); + + option = EDNSOption.fromWire(clientServerCookieOption); + assertNotNull(option); + assertEquals(CookieOption.class, option.getClass()); + cookieOption = (CookieOption) option; + assertArrayEquals(clientCookie2, cookieOption.getClientCookie()); + assertTrue(cookieOption.getServerCookie().isPresent()); + assertArrayEquals(serverCookie2, cookieOption.getServerCookie().get()); + + EDNSOption.fromWire(validLength1); + EDNSOption.fromWire(validLength2); + + assertThrows(WireParseException.class, () -> EDNSOption.fromWire(brokenLength1)); + assertThrows(WireParseException.class, () -> EDNSOption.fromWire(brokenLength2)); + assertThrows(WireParseException.class, () -> EDNSOption.fromWire(brokenLength3)); + assertThrows(WireParseException.class, () -> EDNSOption.fromWire(brokenLength4)); + + cookieOption = new CookieOption(clientCookie1); + assertArrayEquals(clientOnlyCookieOption, cookieOption.toWire()); + + cookieOption = new CookieOption(clientCookie2, Optional.of(serverCookie2)); + assertArrayEquals(clientServerCookieOption, cookieOption.toWire()); + } +} diff --git a/src/test/java/org/xbill/DNS/RcodeTest.java b/src/test/java/org/xbill/DNS/RcodeTest.java index eac7ea35e..4d95f3b7c 100644 --- a/src/test/java/org/xbill/DNS/RcodeTest.java +++ b/src/test/java/org/xbill/DNS/RcodeTest.java @@ -50,7 +50,7 @@ void string() { assertEquals("NOTIMP", Rcode.string(Rcode.NOTIMP)); // one that doesn't exist - assertTrue(Rcode.string(20).startsWith("RESERVED")); + assertTrue(Rcode.string(30).startsWith("RESERVED")); assertThrows(IllegalArgumentException.class, () -> Rcode.string(-1)); @@ -64,7 +64,7 @@ void TSIGstring() { assertEquals("BADSIG", Rcode.TSIGstring(Rcode.BADSIG)); // one that doesn't exist - assertTrue(Rcode.TSIGstring(20).startsWith("RESERVED")); + assertTrue(Rcode.TSIGstring(30).startsWith("RESERVED")); assertThrows(IllegalArgumentException.class, () -> Rcode.TSIGstring(-1)); diff --git a/src/test/java/org/xbill/DNS/TcpKeepaliveOptionTest.java b/src/test/java/org/xbill/DNS/TcpKeepaliveOptionTest.java new file mode 100644 index 000000000..0821bb50d --- /dev/null +++ b/src/test/java/org/xbill/DNS/TcpKeepaliveOptionTest.java @@ -0,0 +1,68 @@ +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.time.Duration; +import org.junit.jupiter.api.Test; +import org.xbill.DNS.utils.base16; + +class TcpKeepaliveOptionTest { + + @Test + void constructorTests() { + assertFalse(new TcpKeepaliveOption().getTimeout().isPresent()); + assertEquals(100, new TcpKeepaliveOption(100).getTimeout().getAsInt()); + assertThrows(IllegalArgumentException.class, () -> new TcpKeepaliveOption(-1)); + assertThrows(IllegalArgumentException.class, () -> new TcpKeepaliveOption(65536)); + assertEquals(200, new TcpKeepaliveOption(Duration.ofSeconds(20)).getTimeout().getAsInt()); + assertEquals( + Duration.ofSeconds(30), + new TcpKeepaliveOption(Duration.ofSeconds(30)).getTimeoutDuration().get()); + assertEquals( + 15, + new TcpKeepaliveOption(Duration.ofSeconds(1, 599_999_999)) + .getTimeout() + .getAsInt()); // round down test + assertThrows( + IllegalArgumentException.class, () -> new TcpKeepaliveOption(Duration.ofMillis(-1))); + assertThrows( + IllegalArgumentException.class, + () -> new TcpKeepaliveOption(Duration.ofHours(2))); // 2h > 6553.5 seconds + } + + @Test + void wireTests() throws IOException { + byte[] emptyTimeout = base16.fromString("000B0000"); + byte[] thirtySecsTimeout = base16.fromString("000B0002012C"); + byte[] maxTimeout = base16.fromString("000B0002FFFF"); + byte[] brokenLengthTimeout1 = base16.fromString("000B0001AA"); + byte[] brokenLengthTimeout2 = base16.fromString("000B0005AABBCCDDEE"); + + EDNSOption option = EDNSOption.fromWire(emptyTimeout); + assertNotNull(option); + assertEquals(TcpKeepaliveOption.class, option.getClass()); + assertFalse(((TcpKeepaliveOption) option).getTimeout().isPresent()); + + option = EDNSOption.fromWire(thirtySecsTimeout); + assertNotNull(option); + assertEquals(TcpKeepaliveOption.class, option.getClass()); + assertEquals(300, ((TcpKeepaliveOption) option).getTimeout().getAsInt()); + + option = EDNSOption.fromWire(maxTimeout); + assertNotNull(option); + assertEquals(TcpKeepaliveOption.class, option.getClass()); + assertEquals(65535, ((TcpKeepaliveOption) option).getTimeout().getAsInt()); + + assertThrows(WireParseException.class, () -> EDNSOption.fromWire(brokenLengthTimeout1)); + assertThrows(WireParseException.class, () -> EDNSOption.fromWire(brokenLengthTimeout2)); + + assertArrayEquals(emptyTimeout, new TcpKeepaliveOption().toWire()); + assertArrayEquals(thirtySecsTimeout, new TcpKeepaliveOption(300).toWire()); + assertArrayEquals(maxTimeout, new TcpKeepaliveOption(65535).toWire()); + } +} From 01bdcde9c5e636b7bf570cb1d8b198927d1f3268 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 15 Dec 2019 16:04:15 +0100 Subject: [PATCH 022/431] Cleanup nameservice SPI from pre Java 1.6 implementation --- .../org/xbill/DNS/spi/DNSJavaNameService.java | 68 +++++++++++-------- .../DNS/spi/DNSJavaNameServiceDescriptor.java | 17 +---- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/src/main/java/org/xbill/DNS/spi/DNSJavaNameService.java b/src/main/java/org/xbill/DNS/spi/DNSJavaNameService.java index aec70e5ae..d2cb486d3 100644 --- a/src/main/java/org/xbill/DNS/spi/DNSJavaNameService.java +++ b/src/main/java/org/xbill/DNS/spi/DNSJavaNameService.java @@ -2,7 +2,6 @@ package org.xbill.DNS.spi; -import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.net.InetAddress; import java.net.UnknownHostException; @@ -19,6 +18,7 @@ import org.xbill.DNS.ReverseMap; import org.xbill.DNS.TextParseException; import org.xbill.DNS.Type; +import sun.net.spi.nameservice.NameService; /** * This class implements a Name Service Provider, which Java can use (starting with version 1.4), to @@ -33,7 +33,7 @@ * @author Paul Cowan (pwc21@yahoo.com) */ @Slf4j -public class DNSJavaNameService implements InvocationHandler { +public class DNSJavaNameService implements NameService { private static final String nsProperty = "sun.net.spi.nameservice.nameservers"; private static final String domainProperty = "sun.net.spi.nameservice.domain"; @@ -41,6 +41,11 @@ public class DNSJavaNameService implements InvocationHandler { private boolean preferV6 = false; + private Name localhostName = null; + private InetAddress[] localhostNamedAddresses = null; + private InetAddress[] localhostAddresses = null; + private boolean addressesLoaded = false; + /** * Creates a DNSJavaNameService instance. * @@ -78,32 +83,31 @@ protected DNSJavaNameService() { if (v6 != null && v6.equalsIgnoreCase("true")) { preferV6 = true; } - } - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (method.getName().equals("getHostByAddr")) { - return this.getHostByAddr((byte[]) args[0]); - } else if (method.getName().equals("lookupAllHostAddr")) { - InetAddress[] addresses; - addresses = this.lookupAllHostAddr((String) args[0]); - Class returnType = method.getReturnType(); - if (returnType.equals(InetAddress[].class)) { - // method for Java >= 1.6 - return addresses; - } else if (returnType.equals(byte[][].class)) { - // method for Java <= 1.5 - int naddrs = addresses.length; - byte[][] byteAddresses = new byte[naddrs][]; - byte[] addr; - for (int i = 0; i < naddrs; i++) { - addr = addresses[i].getAddress(); - byteAddresses[i] = addr; - } - return byteAddresses; - } + try { + // retrieve the name from the system that is used as localhost + Class inetAddressImplFactoryClass = Class.forName("java.net.InetAddressImplFactory"); + Method createMethod = inetAddressImplFactoryClass.getDeclaredMethod("create"); + createMethod.setAccessible(true); + + Object inetAddressImpl = createMethod.invoke(null); + Class inetAddressImplClass = Class.forName("java.net.InetAddressImpl"); + Method hostnameMethod = inetAddressImplClass.getMethod("getLocalHostName"); + hostnameMethod.setAccessible(true); + + localhostName = Name.fromString((String) hostnameMethod.invoke(inetAddressImpl)); + Method lookupAllHostAddrMethod = + inetAddressImplClass.getMethod("lookupAllHostAddr", String.class); + lookupAllHostAddrMethod.setAccessible(true); + + localhostNamedAddresses = + (InetAddress[]) lookupAllHostAddrMethod.invoke(inetAddressImpl, localhostName.toString()); + localhostAddresses = + (InetAddress[]) lookupAllHostAddrMethod.invoke(inetAddressImpl, "localhost"); + addressesLoaded = true; + } catch (Exception e) { + log.error("Could not obtain localhost", e); } - throw new IllegalArgumentException("Unknown function name or arguments."); } /** @@ -114,13 +118,22 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl */ public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException { Name name; - try { name = new Name(host); } catch (TextParseException e) { throw new UnknownHostException(host); } + // avoid asking a dns server (causing a probable timeout) when host is the name of the local + // host + if (addressesLoaded) { + if (name.equals(localhostName)) { + return localhostNamedAddresses; + } else if ("localhost".equalsIgnoreCase(host)) { + return localhostAddresses; + } + } + Record[] records = null; if (preferV6) { records = new Lookup(name, Type.AAAA).run(); @@ -137,7 +150,6 @@ public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException InetAddress[] array = new InetAddress[records.length]; for (int i = 0; i < records.length; i++) { - Record record = records[i]; if (records[i] instanceof ARecord) { ARecord a = (ARecord) records[i]; array[i] = a.getAddress(); diff --git a/src/main/java/org/xbill/DNS/spi/DNSJavaNameServiceDescriptor.java b/src/main/java/org/xbill/DNS/spi/DNSJavaNameServiceDescriptor.java index c0fb07381..5e8102a0b 100644 --- a/src/main/java/org/xbill/DNS/spi/DNSJavaNameServiceDescriptor.java +++ b/src/main/java/org/xbill/DNS/spi/DNSJavaNameServiceDescriptor.java @@ -2,7 +2,6 @@ package org.xbill.DNS.spi; -import java.lang.reflect.Proxy; import sun.net.spi.nameservice.NameService; import sun.net.spi.nameservice.NameServiceDescriptor; @@ -13,24 +12,10 @@ * @author Paul Cowan (pwc21@yahoo.com) */ public class DNSJavaNameServiceDescriptor implements NameServiceDescriptor { - - private static NameService nameService; - - static { - ClassLoader loader = NameService.class.getClassLoader(); - if (loader == null) { - loader = Thread.currentThread().getContextClassLoader(); - } - nameService = - (NameService) - Proxy.newProxyInstance( - loader, new Class[] {NameService.class}, new DNSJavaNameService()); - } - /** Returns a reference to a dnsjava name server provider. */ @Override public NameService createNameService() { - return nameService; + return new DNSJavaNameService(); } @Override From e79c17b7b559d9d9791b8bb2e191f8cb1d19e0a1 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 15 Dec 2019 16:05:32 +0100 Subject: [PATCH 023/431] Decrease log level for Name parsing --- src/main/java/org/xbill/DNS/Compression.java | 4 ++-- src/main/java/org/xbill/DNS/Name.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Compression.java b/src/main/java/org/xbill/DNS/Compression.java index 8f4f06517..c1c9d00be 100644 --- a/src/main/java/org/xbill/DNS/Compression.java +++ b/src/main/java/org/xbill/DNS/Compression.java @@ -45,7 +45,7 @@ public void add(int pos, Name name) { entry.pos = pos; entry.next = table[row]; table[row] = entry; - log.debug("Adding {} at {}", name, pos); + log.trace("Adding {} at {}", name, pos); } /** @@ -62,7 +62,7 @@ public int get(Name name) { pos = entry.pos; } } - log.debug("Looking for {}, found {}", name, pos); + log.trace("Looking for {}, found {}", name, pos); return pos; } } diff --git a/src/main/java/org/xbill/DNS/Name.java b/src/main/java/org/xbill/DNS/Name.java index 1481ba2db..566f4b33f 100644 --- a/src/main/java/org/xbill/DNS/Name.java +++ b/src/main/java/org/xbill/DNS/Name.java @@ -371,7 +371,7 @@ public Name(DNSInput in) throws WireParseException { case LABEL_COMPRESSION: pos = in.readU8(); pos += ((len & ~LABEL_MASK) << 8); - log.debug("currently {}, pointer to {}", in.current(), pos); + log.trace("currently {}, pointer to {}", in.current(), pos); if (pos >= in.current() - 2) { throw new WireParseException("bad compression"); @@ -381,7 +381,7 @@ public Name(DNSInput in) throws WireParseException { savedState = true; } in.jump(pos); - log.debug("current name '{}', seeking to {}", this, pos); + log.trace("current name '{}', seeking to {}", this, pos); break; default: throw new WireParseException("bad label type"); From 09ff32ffa1e43d8cea5e2a709c2208499b49da36 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 15 Dec 2019 16:15:23 +0100 Subject: [PATCH 024/431] Add hostname to resolving exception Closes #84 --- src/main/java/org/xbill/DNS/Address.java | 6 +++--- src/main/java/org/xbill/DNS/ReverseMap.java | 4 ++-- src/main/java/org/xbill/DNS/spi/DNSJavaNameService.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Address.java b/src/main/java/org/xbill/DNS/Address.java index 4b5b96fac..c03c56f90 100644 --- a/src/main/java/org/xbill/DNS/Address.java +++ b/src/main/java/org/xbill/DNS/Address.java @@ -267,7 +267,7 @@ private static Record[] lookupHostName(String name, boolean all) throws UnknownH return aaaa; } } - throw new UnknownHostException("unknown host"); + throw new UnknownHostException("<" + name + "> could not be resolved"); } if (!all) { return a; @@ -281,7 +281,7 @@ private static Record[] lookupHostName(String name, boolean all) throws UnknownH System.arraycopy(aaaa, 0, merged, a.length, aaaa.length); return merged; } catch (TextParseException e) { - throw new UnknownHostException("invalid name"); + throw new UnknownHostException("<" + name + "> is invalid"); } } @@ -385,7 +385,7 @@ public static String getHostName(InetAddress addr) throws UnknownHostException { Name name = ReverseMap.fromAddress(addr); Record[] records = new Lookup(name, Type.PTR).run(); if (records == null) { - throw new UnknownHostException("unknown address"); + throw new UnknownHostException("unknown address: " + name); } PTRRecord ptr = (PTRRecord) records[0]; return ptr.getTarget().toString(); diff --git a/src/main/java/org/xbill/DNS/ReverseMap.java b/src/main/java/org/xbill/DNS/ReverseMap.java index 7d9b5f8c7..d21d9f27f 100644 --- a/src/main/java/org/xbill/DNS/ReverseMap.java +++ b/src/main/java/org/xbill/DNS/ReverseMap.java @@ -103,7 +103,7 @@ public static Name fromAddress(InetAddress addr) { public static Name fromAddress(String addr, int family) throws UnknownHostException { byte[] array = Address.toByteArray(addr, family); if (array == null) { - throw new UnknownHostException("Invalid IP address"); + throw new UnknownHostException("Invalid IP address: " + addr); } return fromAddress(array); } @@ -121,7 +121,7 @@ public static Name fromAddress(String addr) throws UnknownHostException { array = Address.toByteArray(addr, Address.IPv6); } if (array == null) { - throw new UnknownHostException("Invalid IP address"); + throw new UnknownHostException("Invalid IP address:" + addr); } return fromAddress(array); } diff --git a/src/main/java/org/xbill/DNS/spi/DNSJavaNameService.java b/src/main/java/org/xbill/DNS/spi/DNSJavaNameService.java index d2cb486d3..53df658cd 100644 --- a/src/main/java/org/xbill/DNS/spi/DNSJavaNameService.java +++ b/src/main/java/org/xbill/DNS/spi/DNSJavaNameService.java @@ -171,7 +171,7 @@ public String getHostByAddr(byte[] addr) throws UnknownHostException { Name name = ReverseMap.fromAddress(InetAddress.getByAddress(addr)); Record[] records = new Lookup(name, Type.PTR).run(); if (records == null) { - throw new UnknownHostException(); + throw new UnknownHostException("Unknown address: " + name); } return ((PTRRecord) records[0]).getTarget().toString(); } From 4867139ec751d1bee2a25220dde67f4b1e5becce Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 15 Dec 2019 16:17:42 +0100 Subject: [PATCH 025/431] Improve documentation --- src/main/java/org/xbill/DNS/Lookup.java | 2 +- src/main/java/org/xbill/DNS/PacketLogger.java | 13 ++++++++++++- src/main/java/org/xbill/DNS/TSIG.java | 13 +++++-------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index e1bf3444e..fa12cae8f 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -169,7 +169,7 @@ public static synchronized void setDefaultSearchPath(String[] domains) throws Te } /** - * Sets a custom logger that will be used to log the send and received packets. + * Sets a custom logger that will be used to log the sent and received packets. * * @param logger The logger */ diff --git a/src/main/java/org/xbill/DNS/PacketLogger.java b/src/main/java/org/xbill/DNS/PacketLogger.java index c13dbcc0c..90d365ce7 100644 --- a/src/main/java/org/xbill/DNS/PacketLogger.java +++ b/src/main/java/org/xbill/DNS/PacketLogger.java @@ -3,10 +3,21 @@ import java.net.SocketAddress; /** - * Custom logger that can log all the packets that were send or received. + * Custom logger that can log all packets that were sent or received. * * @author Damian Minkov */ public interface PacketLogger { + /** + * Logs data (usually a DNS message in wire format) that was sent or received within the dnsjava + * library. + * + *

This method can be invoked concurrently from any thread. + * + * @param prefix a note of where the package originated, e.g. {@code TCP read}. + * @param local the local (i.e. this pc) socket address of the communication channel. + * @param remote the remote (i.e. the server) socket address of the communication channel. + * @param data the transferred data, usually a complete DNS message. + */ void log(String prefix, SocketAddress local, SocketAddress remote, byte[] data); } diff --git a/src/main/java/org/xbill/DNS/TSIG.java b/src/main/java/org/xbill/DNS/TSIG.java index e54bd28db..7e05cfdf2 100644 --- a/src/main/java/org/xbill/DNS/TSIG.java +++ b/src/main/java/org/xbill/DNS/TSIG.java @@ -431,7 +431,7 @@ public void applyStream(Message m, TSIGRecord old, boolean first) { * TSIG is expected to be present, it is an error if one is not present. After calling this * routine, Message.isVerified() may be called on this message. * - * @param m The message + * @param m The message to verify * @param b An array containing the message in unparsed form. This is necessary since TSIG signs * the message in wire format, and we can't recreate the exact wire format (with the same name * compression). @@ -525,13 +525,10 @@ public int recordLength() { return (name.length() + 10 + alg.length() - + 8 - + // time signed, fudge - 18 - + // 2 byte MAC length, 16 byte MAC - 4 - + // original id, error - 8); // 2 byte error length, 6 byte max error field. + + 8 // time signed, fudge + + 18 // 2 byte MAC length, 16 byte MAC + + 4 // original id, error + + 8); // 2 byte error length, 6 byte max error field. } public static class StreamVerifier { From 629f2eb3f5c5ff0695f8264dde03ed7666744775 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 15 Dec 2019 16:18:54 +0100 Subject: [PATCH 026/431] Rewrite UDP/TCP clients to use NIO and built-in worker threads Closes #25 Closes #41 Closes #74 --- src/main/java/org/xbill/DNS/Client.java | 100 ++-- .../java/org/xbill/DNS/ExtendedResolver.java | 459 +++++++----------- src/main/java/org/xbill/DNS/Message.java | 13 + src/main/java/org/xbill/DNS/NioTcpClient.java | 287 +++++++++++ src/main/java/org/xbill/DNS/NioUdpClient.java | 224 +++++++++ .../java/org/xbill/DNS/ResolveThread.java | 36 -- src/main/java/org/xbill/DNS/Resolver.java | 129 ++++- .../java/org/xbill/DNS/ResolverListener.java | 2 + .../java/org/xbill/DNS/SimpleResolver.java | 188 ++++--- src/main/java/org/xbill/DNS/TCPClient.java | 63 ++- src/main/java/org/xbill/DNS/UDPClient.java | 167 ------- .../java/org/xbill/DNS/ZoneTransferIn.java | 16 +- src/main/java/org/xbill/DNS/tools/dig.java | 2 +- 13 files changed, 1025 insertions(+), 661 deletions(-) create mode 100644 src/main/java/org/xbill/DNS/NioTcpClient.java create mode 100644 src/main/java/org/xbill/DNS/NioUdpClient.java delete mode 100644 src/main/java/org/xbill/DNS/ResolveThread.java delete mode 100644 src/main/java/org/xbill/DNS/UDPClient.java diff --git a/src/main/java/org/xbill/DNS/Client.java b/src/main/java/org/xbill/DNS/Client.java index c97daaa00..6b9048eba 100644 --- a/src/main/java/org/xbill/DNS/Client.java +++ b/src/main/java/org/xbill/DNS/Client.java @@ -4,69 +4,89 @@ import java.io.IOException; import java.net.SocketAddress; -import java.net.SocketTimeoutException; -import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; import lombok.extern.slf4j.Slf4j; import org.xbill.DNS.utils.hexdump; @Slf4j class Client { - - protected long endTime; - protected SelectionKey key; - /** Packet logger, if available. */ private static PacketLogger packetLogger = null; - protected Client(SelectableChannel channel, long endTime) throws IOException { - boolean done = false; - Selector selector = null; - this.endTime = endTime; - try { - selector = Selector.open(); - channel.configureBlocking(false); - key = channel.register(selector, SelectionKey.OP_READ); - done = true; - } finally { - if (!done && selector != null) { - selector.close(); - } - if (!done) { - channel.close(); - } + private static volatile boolean run; + private static Thread selectorThread; + private static List timeoutTasks = new CopyOnWriteArrayList<>(); + static Selector selector; + + protected interface KeyProcessor { + void processReadyKey(SelectionKey key); + } + + protected static void start() throws IOException { + if (run) { + return; + } + + run = true; + selector = Selector.open(); + selectorThread = new Thread(Client::runSelector); + selectorThread.setDaemon(true); + selectorThread.setName("dnsjava NIO selector"); + selectorThread.start(); + } + + protected static void close() throws Exception { + if (!run) { + return; } + + run = false; + timeoutTasks.clear(); + selector.wakeup(); + selector.close(); + selectorThread.join(); } - protected static void blockUntil(SelectionKey key, long endTime) throws IOException { - long timeout = endTime - System.currentTimeMillis(); - int nkeys = 0; - if (timeout > 0) { - nkeys = key.selector().select(timeout); - } else if (timeout == 0) { - nkeys = key.selector().selectNow(); + private static void runSelector() { + while (run) { + try { + if (selector.select(100) == 0) { + timeoutTasks.forEach(Runnable::run); + continue; + } + + processReadyKeys(); + } catch (IOException e) { + log.error("A selection operation failed", e); + } } - if (nkeys == 0) { - throw new SocketTimeoutException(); + } + + static void addSelectorTimeoutTask(Runnable r) { + timeoutTasks.add(r); + } + + private static void processReadyKeys() { + Set keys = selector.selectedKeys(); + for (SelectionKey key : keys) { + KeyProcessor t = (KeyProcessor) key.attachment(); + t.processReadyKey(key); } } - protected static void verboseLog( - String prefix, SocketAddress local, SocketAddress remote, byte[] data) { - if (log.isDebugEnabled()) { - log.debug(hexdump.dump(prefix, data)); + static void verboseLog(String prefix, SocketAddress local, SocketAddress remote, byte[] data) { + if (log.isTraceEnabled()) { + log.trace(hexdump.dump(prefix, data)); } if (packetLogger != null) { packetLogger.log(prefix, local, remote, data); } } - void cleanup() throws IOException { - key.selector().close(); - key.channel().close(); - } - static void setPacketLogger(PacketLogger logger) { packetLogger = logger; } diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index 99e851e0f..4e6c2c005 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -2,416 +2,297 @@ package org.xbill.DNS; -import java.io.IOException; -import java.io.InterruptedIOException; import java.net.InetSocketAddress; -import java.net.SocketException; import java.net.UnknownHostException; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; /** - * An implementation of Resolver that can send queries to multiple servers, sending the queries - * multiple times if necessary. + * An implementation of {@link Resolver} that can send queries to multiple servers, sending the + * queries multiple times if necessary. * * @see Resolver * @author Brian Wellington */ @Slf4j public class ExtendedResolver implements Resolver { - - private static class Resolution implements ResolverListener { - Resolver[] resolvers; - int[] sent; - Object[] inprogress; - int retries; - int outstanding; - boolean done; - Message query; - Message response; - Throwable thrown; - ResolverListener listener; - - public Resolution(ExtendedResolver eres, Message query) { - List l = eres.resolvers; - resolvers = l.toArray(new Resolver[0]); + private static class Resolution { + private final Message query; + private final int[] attempts; + private final int retriesPerResolver; + private List resolvers; + private int currentResolver; + + Resolution(ExtendedResolver eres, Message query) { + resolvers = new ArrayList<>(eres.resolvers); if (eres.loadBalance) { - int nresolvers = resolvers.length; - /* - * Note: this is not synchronized, since the - * worst thing that can happen is a random - * ordering, which is ok. - */ - int start = eres.lbStart++ % nresolvers; - if (eres.lbStart > nresolvers) { - eres.lbStart %= nresolvers; - } + int start = eres.lbStart.updateAndGet(i -> i++ % resolvers.size()); if (start > 0) { - Resolver[] shuffle = new Resolver[nresolvers]; - for (int i = 0; i < nresolvers; i++) { - int pos = (i + start) % nresolvers; - shuffle[i] = resolvers[pos]; + List shuffle = new ArrayList<>(resolvers.size()); + for (int i = 0; i < resolvers.size(); i++) { + int pos = (i + start) % resolvers.size(); + shuffle.add(resolvers.get(pos)); } + resolvers = shuffle; } + } else { + Collections.shuffle(resolvers); + resolvers = + resolvers.stream() + .sorted(Comparator.comparingInt(re -> re.failures.get())) + .collect(Collectors.toList()); } - sent = new int[resolvers.length]; - inprogress = new Object[resolvers.length]; - retries = eres.retries; + + attempts = new int[resolvers.size()]; + retriesPerResolver = eres.retries; this.query = query; } /* Asynchronously sends a message. */ - public void send(int n) { - sent[n]++; - outstanding++; - try { - inprogress[n] = resolvers[n].sendAsync(query, this); - } catch (Throwable t) { - synchronized (this) { - thrown = t; - done = true; - if (listener == null) { - notifyAll(); - } - } - } + private CompletableFuture send() { + ResolverEntry r = resolvers.get(currentResolver); + log.debug( + "Sending {}/{}, id={} to resolver {} ({}), attempt {} of {}", + query.getQuestion().getName(), + Type.string(query.getQuestion().getType()), + query.getHeader().getID(), + currentResolver, + r.resolver, + attempts[currentResolver] + 1, + retriesPerResolver); + attempts[currentResolver]++; + return r.resolver.sendAsync(query).toCompletableFuture(); } - /* Start a synchronous resolution */ - public Message start() throws IOException { - try { - /* - * First, try sending synchronously. If this works, - * we're done. Otherwise, we'll get an exception - * and continue. It would be easier to call send(0), - * but this avoids a thread creation. If and when - * SimpleResolver.sendAsync() can be made to not - * create a thread, this could be changed. - */ - sent[0]++; - outstanding++; - inprogress[0] = new Object(); - return resolvers[0].send(query); - } catch (Exception e) { - /* - * This will either cause more queries to be sent - * asynchronously or will set the 'done' flag. - */ - handleException(inprogress[0], e); - } - /* - * Wait for a successful response or for each - * subresolver to fail. - */ - synchronized (this) { - while (!done) { - try { - wait(); - } catch (InterruptedException e) { - throw new IOException(e); - } + /* Start an asynchronous resolution */ + private CompletionStage startAsync() { + CompletableFuture f = new CompletableFuture<>(); + send().handleAsync((result, ex) -> handle(result, ex, f)); + return f; + } + + private Void handle(Message result, Throwable ex, CompletableFuture f) { + AtomicInteger failureCounter = resolvers.get(currentResolver).failures; + if (ex != null) { + log.debug( + "Failed to resolve {}/{}, id={} with resolver {} ({}) on attempt {} of {}, reason={}", + query.getQuestion().getName(), + Type.string(query.getQuestion().getType()), + query.getHeader().getID(), + currentResolver, + resolvers.get(currentResolver).resolver, + attempts[currentResolver], + retriesPerResolver, + ex.getMessage()); + + failureCounter.incrementAndGet(); + // go to next resolver, until retries on all resolvers are exhausted + currentResolver = (currentResolver + 1) % resolvers.size(); + if (attempts[currentResolver] < retriesPerResolver) { + send().handleAsync((r, t) -> handle(r, t, f)); + return null; } - } - /* Return the response or throw an exception */ - if (response != null) { - return response; - } else if (thrown instanceof IOException) { - throw (IOException) thrown; - } else if (thrown instanceof RuntimeException) { - throw (RuntimeException) thrown; - } else if (thrown instanceof Error) { - throw (Error) thrown; + + f.completeExceptionally(ex); } else { - throw new IllegalStateException("ExtendedResolver failure"); + failureCounter.updateAndGet(i -> i > 0 ? (int) Math.log(i) : 0); + f.complete(result); } - } - /* Start an asynchronous resolution */ - public void startAsync(ResolverListener listener) { - synchronized (this) { - this.listener = listener; - } - send(0); + return null; } + } - /* - * Receive a response. If the resolution hasn't been completed, - * either wake up the blocking thread or call the callback. - */ - @Override - public void receiveMessage(Object id, Message m) { - log.debug("received message"); - ResolverListener listenerCopy; - synchronized (this) { - if (done) { - return; - } - response = m; - done = true; - if (listener == null) { - notifyAll(); - return; - } else { - listenerCopy = listener; - } - } - listenerCopy.receiveMessage(this, response); + @RequiredArgsConstructor + private static class ResolverEntry { + private final Resolver resolver; + private final AtomicInteger failures; + + ResolverEntry(Resolver r) { + this(r, new AtomicInteger(0)); } - /* - * Receive an exception. If the resolution has been completed, - * do nothing. Otherwise make progress. - */ @Override - public void handleException(Object id, Exception e) { - log.debug("resolving failed", e); - ResolverListener listenerCopy = null; - synchronized (this) { - outstanding--; - if (done) { - return; - } - int n; - for (n = 0; n < inprogress.length; n++) { - if (inprogress[n] == id) { - break; - } - } - /* If we don't know what this is, do nothing. */ - if (n == inprogress.length) { - return; - } - boolean startnext = false; - /* - * If this is the first response from server n, - * we should start sending queries to server n + 1. - */ - if (sent[n] == 1 && n < resolvers.length - 1) { - startnext = true; - } - if (e instanceof InterruptedIOException) { - /* Got a timeout; resend */ - if (sent[n] < retries) { - send(n); - } - if (thrown == null) { - thrown = e; - } - } else if (e instanceof SocketException) { - /* - * Problem with the socket; don't resend - * on it - */ - if (thrown == null || thrown instanceof InterruptedIOException) { - thrown = e; - } - } else { - /* - * Problem with the response; don't resend - * on the same socket. - */ - thrown = e; - } - if (done) { - return; - } - if (startnext) { - send(n + 1); - } - if (done) { - return; - } - if (outstanding == 0) { - /* - * If we're done and this is synchronous, - * wake up the blocking thread. - */ - done = true; - if (listener == null) { - notifyAll(); - return; - } else { - listenerCopy = listener; - } - } - if (!done) { - return; - } - } - /* If we're done and this is asynchronous, call the callback. */ - if (!(thrown instanceof Exception)) { - thrown = new RuntimeException(thrown); - } - listenerCopy.handleException(this, (Exception) thrown); + public String toString() { + return resolver.toString(); } } - private static final int quantum = 5; + private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(5); - private List resolvers; - private boolean loadBalance = false; - private int lbStart = 0; + private List resolvers = new CopyOnWriteArrayList<>(); + private boolean loadBalance; + private AtomicInteger lbStart = new AtomicInteger(); private int retries = 3; - private void init() { - resolvers = new ArrayList<>(); - } - /** - * Creates a new Extended Resolver. The default ResolverConfig is used to determine the servers - * for which SimpleResolver contexts should be initialized. - * - * @see SimpleResolver - * @see ResolverConfig + * Creates a new Extended Resolver. The default {@link ResolverConfig} is used to determine the + * servers for which {@link SimpleResolver}s are initialized. */ public ExtendedResolver() { - init(); List servers = ResolverConfig.getCurrentConfig().servers(); - for (InetSocketAddress server : servers) { - Resolver r = new SimpleResolver(server); - r.setTimeout(quantum); - resolvers.add(r); - } + resolvers.addAll( + servers.stream() + .map( + server -> { + Resolver r = new SimpleResolver(server); + r.setTimeout(DEFAULT_TIMEOUT); + return new ResolverEntry(r); + }) + .collect(Collectors.toSet())); } /** * Creates a new Extended Resolver * - * @param servers An array of server names for which SimpleResolver contexts should be + * @param servers An array of server names or IP addresses for which {@link SimpleResolver}s are * initialized. - * @see SimpleResolver - * @exception UnknownHostException Failure occurred initializing SimpleResolvers + * @exception UnknownHostException A server name could not be resolved */ public ExtendedResolver(String[] servers) throws UnknownHostException { - init(); - for (String server : servers) { - Resolver r = new SimpleResolver(server); - r.setTimeout(quantum); - resolvers.add(r); + try { + resolvers.addAll( + Arrays.stream(servers) + .map( + server -> { + try { + Resolver r = new SimpleResolver(server); + r.setTimeout(DEFAULT_TIMEOUT); + return new ResolverEntry(r); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.toSet())); + } catch (RuntimeException e) { + if (e.getCause() instanceof UnknownHostException) { + throw (UnknownHostException) e.getCause(); + } + throw e; } } /** * Creates a new Extended Resolver * - * @param res An array of pre-initialized Resolvers is provided. - * @see SimpleResolver + * @param resolvers An array of pre-initialized {@link Resolver}s. */ - public ExtendedResolver(Resolver[] res) { - init(); - resolvers.addAll(Arrays.asList(res)); + public ExtendedResolver(Resolver[] resolvers) { + this(Arrays.asList(resolvers)); + } + + /** + * Creates a new Extended Resolver + * + * @param resolvers An iterable of pre-initialized {@link Resolver}s. + */ + public ExtendedResolver(Iterable resolvers) { + this.resolvers.addAll( + StreamSupport.stream(resolvers.spliterator(), false) + .map( + resolver -> { + resolver.setTimeout(DEFAULT_TIMEOUT); + return new ResolverEntry(resolver); + }) + .collect(Collectors.toSet())); } @Override public void setPort(int port) { - for (Resolver resolver : resolvers) { - resolver.setPort(port); + for (ResolverEntry re : resolvers) { + re.resolver.setPort(port); } } @Override public void setTCP(boolean flag) { - for (Resolver resolver : resolvers) { - resolver.setTCP(flag); + for (ResolverEntry re : resolvers) { + re.resolver.setTCP(flag); } } @Override public void setIgnoreTruncation(boolean flag) { - for (Resolver resolver : resolvers) { - resolver.setIgnoreTruncation(flag); + for (ResolverEntry re : resolvers) { + re.resolver.setIgnoreTruncation(flag); } } @Override public void setEDNS(int level) { - for (Resolver resolver : resolvers) { - resolver.setEDNS(level); + for (ResolverEntry re : resolvers) { + re.resolver.setEDNS(level); } } @Override public void setEDNS(int level, int payloadSize, int flags, List options) { - for (Resolver resolver : resolvers) { - resolver.setEDNS(level, payloadSize, flags, options); + for (ResolverEntry re : resolvers) { + re.resolver.setEDNS(level, payloadSize, flags, options); } } @Override public void setTSIGKey(TSIG key) { - for (Resolver resolver : resolvers) { - resolver.setTSIGKey(key); + for (ResolverEntry re : resolvers) { + re.resolver.setTSIGKey(key); } } @Override - public void setTimeout(int secs, int msecs) { - for (Resolver resolver : resolvers) { - resolver.setTimeout(secs, msecs); + public void setTimeout(Duration timeout) { + for (ResolverEntry re : resolvers) { + re.resolver.setTimeout(timeout); } } - @Override - public void setTimeout(int secs) { - setTimeout(secs, 0); - } - /** - * Sends a message and waits for a response. Multiple servers are queried, and queries are sent - * multiple times until either a successful response is received, or it is clear that there is no - * successful response. + * Sends a message to multiple servers, and queries are sent multiple times until either a + * successful response is received, or it is clear that there is no successful response. * * @param query The query to send. - * @return The response. - * @throws IOException An error occurred while sending or receiving. - */ - @Override - public Message send(Message query) throws IOException { - Resolution res = new Resolution(this, query); - return res.start(); - } - - /** - * Asynchronously sends a message to multiple servers, potentially multiple times, registering a - * listener to receive a callback on success or exception. Multiple asynchronous lookups can be - * performed in parallel. Since the callback may be invoked before the function returns, external - * synchronization is necessary. - * - * @param query The query to send - * @param listener The object containing the callbacks. - * @return An identifier, which is also a parameter in the callback + * @return A future that completes when the query is finished. */ @Override - public Resolution sendAsync(final Message query, final ResolverListener listener) { + public CompletionStage sendAsync(Message query) { Resolution res = new Resolution(this, query); - res.startAsync(listener); - return res; + return res.startAsync(); } /** Returns the nth resolver used by this ExtendedResolver */ public Resolver getResolver(int n) { if (n < resolvers.size()) { - return resolvers.get(n); + return resolvers.get(n).resolver; } return null; } /** Returns all resolvers used by this ExtendedResolver */ public Resolver[] getResolvers() { - return resolvers.toArray(new Resolver[0]); + return (Resolver[]) resolvers.stream().map(re -> re.resolver).toArray(); } /** Adds a new resolver to be used by this ExtendedResolver */ public void addResolver(Resolver r) { - resolvers.add(r); + resolvers.add(new ResolverEntry(r)); } /** Deletes a resolver used by this ExtendedResolver */ public void deleteResolver(Resolver r) { - resolvers.remove(r); + resolvers.removeIf(re -> re.resolver == r); } /** diff --git a/src/main/java/org/xbill/DNS/Message.java b/src/main/java/org/xbill/DNS/Message.java index 4495d6676..65cc46312 100644 --- a/src/main/java/org/xbill/DNS/Message.java +++ b/src/main/java/org/xbill/DNS/Message.java @@ -8,6 +8,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Optional; import java.util.Set; /** @@ -30,6 +31,7 @@ public class Message implements Cloneable { private TSIG tsigkey; private TSIGRecord querytsig; private int tsigerror; + private Resolver resolver; int tsigstart; int tsigState; @@ -634,6 +636,17 @@ public Message clone() { } m.header = header.clone(); m.size = size; + m.resolver = this.resolver; return m; } + + /** Sets the resolver that originally received this Message a server. */ + public void setResolver(Resolver resolver) { + this.resolver = resolver; + } + + /** Gets the resolver that originally received this Message from a server. */ + public Optional getResolver() { + return Optional.ofNullable(resolver); + } } diff --git a/src/main/java/org/xbill/DNS/NioTcpClient.java b/src/main/java/org/xbill/DNS/NioTcpClient.java new file mode 100644 index 000000000..31437ce14 --- /dev/null +++ b/src/main/java/org/xbill/DNS/NioTcpClient.java @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import java.io.EOFException; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; +import java.time.Duration; +import java.util.Iterator; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@UtilityClass +final class NioTcpClient extends Client { + private static Queue registrationQueue; + private static Map channelMap; + private static volatile boolean run; + + private static void startTcp() throws IOException { + if (run) { + return; + } + + run = true; + registrationQueue = new ConcurrentLinkedQueue<>(); + channelMap = new ConcurrentHashMap<>(); + addSelectorTimeoutTask(NioTcpClient::processPendingRegistrations); + addSelectorTimeoutTask(NioTcpClient::checkTransactionTimeouts); + start(); + } + + private static void processPendingRegistrations() { + while (!registrationQueue.isEmpty()) { + ChannelState state = registrationQueue.remove(); + try { + state.channel.register( + selector, + state.channel.isConnected() + ? SelectionKey.OP_READ | SelectionKey.OP_WRITE + : SelectionKey.OP_CONNECT, + state); + } catch (ClosedChannelException e) { + state.handleChannelException(e); + } + } + } + + private static void checkTransactionTimeouts() { + for (ChannelState state : channelMap.values()) { + for (Iterator it = state.pendingTransactions.iterator(); it.hasNext(); ) { + Transaction t = it.next(); + if (t.endTime - System.nanoTime() < 0) { + t.f.completeExceptionally(new SocketTimeoutException("Query timed out")); + it.remove(); + } + } + } + } + + static void closeTcp() throws Exception { + if (!run) { + return; + } + + registrationQueue.clear(); + EOFException closing = new EOFException("Client is closing"); + channelMap.forEach((key, state) -> state.handleTransactionException(closing)); + channelMap.clear(); + close(); + } + + @RequiredArgsConstructor + private static class Transaction { + private final Message query; + private final byte[] queryData; + private final long endTime; + private final SocketChannel channel; + private final CompletableFuture f; + private boolean sendDone; + + void send() throws IOException { + if (sendDone) { + return; + } + + verboseLog( + "TCP write", + channel.socket().getLocalSocketAddress(), + channel.socket().getRemoteSocketAddress(), + queryData); + + // combine length+message to avoid multiple TCP packets + // https://tools.ietf.org/html/rfc7766#section-8 + ByteBuffer buffer = ByteBuffer.allocate(queryData.length + 2); + buffer.put((byte) (queryData.length >>> 8)); + buffer.put((byte) (queryData.length & 0xFF)); + buffer.put(queryData); + buffer.flip(); + while (buffer.hasRemaining()) { + long n = channel.write(buffer); + if (n < 0) { + throw new EOFException(); + } + } + + sendDone = true; + } + } + + @RequiredArgsConstructor + private static class ChannelState implements KeyProcessor { + final SocketChannel channel; + final Queue pendingTransactions = new ConcurrentLinkedQueue<>(); + ByteBuffer responseLengthData = ByteBuffer.allocate(2); + ByteBuffer responseData = ByteBuffer.allocate(Message.MAXLENGTH); + int readState = 0; + + public void processReadyKey(SelectionKey key) { + if (key.isConnectable()) { + processConnect(key); + } + if (key.isWritable()) { + processWrite(); + } + if (key.isReadable()) { + processRead(); + } + } + + void handleTransactionException(IOException e) { + for (Iterator it = pendingTransactions.iterator(); it.hasNext(); ) { + Transaction t = it.next(); + t.f.completeExceptionally(e); + it.remove(); + } + } + + private void handleChannelException(IOException e) { + handleTransactionException(e); + for (Map.Entry entry : channelMap.entrySet()) { + if (entry.getValue() == this) { + channelMap.remove(entry.getKey()); + try { + channel.close(); + } catch (IOException ex) { + log.error("failed to close channel", ex); + } + return; + } + } + } + + private void processConnect(SelectionKey key) { + try { + channel.finishConnect(); + key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); + } catch (IOException e) { + handleChannelException(e); + } + } + + private void processRead() { + try { + if (readState == 0) { + int read = channel.read(responseLengthData); + if (read < 0) { + handleChannelException(new EOFException()); + return; + } + + if (responseLengthData.position() == 2) { + int length = + ((responseLengthData.get(0) & 0xFF) << 8) + (responseLengthData.get(1) & 0xFF); + responseLengthData.flip(); + responseData.limit(length); + readState = 1; + } + } + + int read = channel.read(responseData); + if (read < 0) { + handleChannelException(new EOFException()); + return; + } else if (responseData.hasRemaining()) { + return; + } + } catch (IOException e) { + handleChannelException(e); + return; + } + + readState = 0; + responseData.flip(); + byte[] data = new byte[responseData.limit()]; + System.arraycopy( + responseData.array(), responseData.arrayOffset(), data, 0, responseData.limit()); + verboseLog( + "TCP read", + channel.socket().getLocalSocketAddress(), + channel.socket().getRemoteSocketAddress(), + data); + + for (Iterator it = pendingTransactions.iterator(); it.hasNext(); ) { + Transaction t = it.next(); + int id = ((data[0] & 0xFF) << 8) + (data[1] & 0xFF); + int qid = t.query.getHeader().getID(); + if (id == qid) { + t.f.complete(data); + it.remove(); + return; + } + } + } + + private void processWrite() { + for (Iterator it = pendingTransactions.iterator(); it.hasNext(); ) { + Transaction t = it.next(); + try { + t.send(); + } catch (IOException e) { + t.f.completeExceptionally(e); + it.remove(); + } + } + } + } + + @RequiredArgsConstructor + @EqualsAndHashCode + private static class ChannelKey { + final InetSocketAddress local; + final InetSocketAddress remote; + } + + static CompletableFuture sendrecv( + InetSocketAddress local, + InetSocketAddress remote, + Message query, + byte[] data, + Duration timeout) { + CompletableFuture f = new CompletableFuture<>(); + try { + startTcp(); + long endTime = System.nanoTime() + timeout.toNanos(); + ChannelState channel = + channelMap.computeIfAbsent( + new ChannelKey(local, remote), + key -> { + try { + SocketChannel c = SocketChannel.open(); + c.configureBlocking(false); + if (local != null) { + c.bind(local); + } + + c.connect(remote); + return new ChannelState(c); + } catch (IOException e) { + f.completeExceptionally(e); + return null; + } + }); + if (channel != null) { + Transaction t = new Transaction(query, data, endTime, channel.channel, f); + channel.pendingTransactions.add(t); + registrationQueue.add(channel); + selector.wakeup(); + } + } catch (IOException e) { + f.completeExceptionally(e); + } + + return f; + } +} diff --git a/src/main/java/org/xbill/DNS/NioUdpClient.java b/src/main/java/org/xbill/DNS/NioUdpClient.java new file mode 100644 index 000000000..d84717a4f --- /dev/null +++ b/src/main/java/org/xbill/DNS/NioUdpClient.java @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import java.io.EOFException; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; +import java.nio.channels.SelectionKey; +import java.security.SecureRandom; +import java.time.Duration; +import java.util.Iterator; +import java.util.Queue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import lombok.RequiredArgsConstructor; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@UtilityClass +final class NioUdpClient extends Client { + private static final int EPHEMERAL_START; + private static final int EPHEMERAL_RANGE; + + private static final SecureRandom prng; + private static volatile boolean run; + private static Queue registrationQueue; + private static Queue pendingTransactions; + + static { + // https://tools.ietf.org/html/rfc6335#section-6 + int ephemeralStartDefault = 49152; + int ephemeralEndDefault = 65535; + + // Linux usually uses 32768-60999 + if (System.getProperty("os.name").toLowerCase().contains("linux")) { + ephemeralStartDefault = 32768; + ephemeralEndDefault = 60999; + } + + EPHEMERAL_START = Integer.getInteger("dnsjava.udp.ephemeral.start", ephemeralStartDefault); + int ephemeralEnd = Integer.getInteger("dnsjava.udp.ephemeral.end", ephemeralEndDefault); + EPHEMERAL_RANGE = ephemeralEnd - EPHEMERAL_START; + + if (Boolean.parseBoolean("dnsjava.udp.ephemeral.use_ephemeral_port")) { + prng = null; + } else { + prng = new SecureRandom(); + } + } + + private static void startUdp() throws IOException { + if (run) { + return; + } + + run = true; + registrationQueue = new ConcurrentLinkedQueue<>(); + pendingTransactions = new ConcurrentLinkedQueue<>(); + addSelectorTimeoutTask(NioUdpClient::processPendingRegistrations); + addSelectorTimeoutTask(NioUdpClient::checkTransactionTimeouts); + start(); + } + + private static void processPendingRegistrations() { + while (!registrationQueue.isEmpty()) { + Transaction t = registrationQueue.remove(); + try { + t.channel.register(selector, SelectionKey.OP_READ, t); + t.send(); + } catch (IOException e) { + t.f.completeExceptionally(e); + } + } + } + + private static void checkTransactionTimeouts() { + for (Iterator it = pendingTransactions.iterator(); it.hasNext(); ) { + Transaction t = it.next(); + if (t.endTime - System.nanoTime() < 0) { + try { + t.channel.disconnect(); + t.channel.close(); + } catch (IOException e) { + // ignore, we timed out already + } + + t.f.completeExceptionally(new SocketTimeoutException("Query timed out")); + it.remove(); + } + } + } + + @RequiredArgsConstructor + private static class Transaction implements KeyProcessor { + private final byte[] data; + private final int max; + private final long endTime; + private final DatagramChannel channel; + private final CompletableFuture f; + + void send() throws IOException { + ByteBuffer buffer = ByteBuffer.wrap(data); + verboseLog( + "UDP write", + channel.socket().getLocalSocketAddress(), + channel.socket().getRemoteSocketAddress(), + data); + int n = channel.send(buffer, channel.socket().getRemoteSocketAddress()); + if (n <= 0) { + throw new EOFException(); + } + } + + 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) { + 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); + } + } + + static CompletableFuture sendrecv( + InetSocketAddress local, InetSocketAddress remote, byte[] data, int max, Duration timeout) { + CompletableFuture f = new CompletableFuture<>(); + try { + startUdp(); + DatagramChannel channel = DatagramChannel.open(); + channel.configureBlocking(false); + if (local == null || local.getPort() == 0) { + boolean bound = false; + for (int i = 0; i < 1024; i++) { + try { + InetSocketAddress addr = null; + if (local == null) { + if (prng != null) { + addr = new InetSocketAddress(prng.nextInt(EPHEMERAL_RANGE) + EPHEMERAL_START); + } + } else { + int port = local.getPort(); + if (port == 0 && prng != null) { + port = prng.nextInt(EPHEMERAL_RANGE) + EPHEMERAL_START; + } + + addr = new InetSocketAddress(local.getAddress(), port); + } + + channel.bind(addr); + bound = true; + break; + } catch (SocketException e) { + // ignore, we'll try another random port + } + } + + if (!bound) { + channel.close(); + f.completeExceptionally(new IOException("No available source port found")); + return f; + } + } + + channel.connect(remote); + long endTime = System.nanoTime() + timeout.toNanos(); + Transaction t = new Transaction(data, max, endTime, channel, f); + pendingTransactions.add(t); + registrationQueue.add(t); + selector.wakeup(); + } catch (IOException e) { + f.completeExceptionally(e); + } + + return f; + } + + static void closeUdp() throws Exception { + if (!run) { + return; + } + + run = false; + registrationQueue.clear(); + EOFException closing = new EOFException("Client is closing"); + pendingTransactions.forEach(t -> t.f.completeExceptionally(closing)); + pendingTransactions.clear(); + close(); + } +} diff --git a/src/main/java/org/xbill/DNS/ResolveThread.java b/src/main/java/org/xbill/DNS/ResolveThread.java deleted file mode 100644 index cd2897f08..000000000 --- a/src/main/java/org/xbill/DNS/ResolveThread.java +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) - -package org.xbill.DNS; - -/** - * A special-purpose thread used by Resolvers (both SimpleResolver and ExtendedResolver) to perform - * asynchronous queries. - * - * @author Brian Wellington - */ -class ResolveThread extends Thread { - - private Message query; - private Integer id; - private ResolverListener listener; - private Resolver res; - - /** Creates a new ResolveThread */ - public ResolveThread(Resolver res, Message query, Integer id, ResolverListener listener) { - this.res = res; - this.query = query; - this.id = id; - this.listener = listener; - } - - /** Performs the query, and executes the callback. */ - @Override - public void run() { - try { - Message response = res.send(query); - listener.receiveMessage(id, response); - } catch (Exception e) { - listener.handleException(id, e); - } - } -} diff --git a/src/main/java/org/xbill/DNS/Resolver.java b/src/main/java/org/xbill/DNS/Resolver.java index af4eaa069..ae17a427a 100644 --- a/src/main/java/org/xbill/DNS/Resolver.java +++ b/src/main/java/org/xbill/DNS/Resolver.java @@ -3,7 +3,15 @@ package org.xbill.DNS; import java.io.IOException; +import java.net.SocketTimeoutException; +import java.time.Duration; +import java.util.Arrays; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * Interface describing a resolver. @@ -56,6 +64,22 @@ public interface Resolver { */ void setEDNS(int level, int payloadSize, int flags, List options); + /** + * Sets the EDNS information on outgoing messages. + * + * @param level The EDNS level to use. 0 indicates EDNS0 and -1 indicates no EDNS. + * @param payloadSize The maximum DNS packet size that this host is capable of receiving over UDP. + * If 0 is specified, the default (1280) is used. + * @param flags EDNS extended flags to be set in the OPT record. + * @param options EDNS options to be set in the OPT record, specified as a List of + * OPTRecord.Option elements. + * @throws IllegalArgumentException An invalid field was specified. + * @see OPTRecord + */ + default void setEDNS(int level, int payloadSize, int flags, EDNSOption... options) { + setEDNS(level, payloadSize, flags, Arrays.asList(options)); + } + /** * Specifies the TSIG key that messages will be signed with * @@ -68,15 +92,39 @@ public interface Resolver { * * @param secs The number of seconds to wait. * @param msecs The number of milliseconds to wait. + * @deprecated use {@link #setTimeout(Duration)} */ - void setTimeout(int secs, int msecs); + @Deprecated + default void setTimeout(int secs, int msecs) { + setTimeout(Duration.ofMillis(secs * 1000 + msecs)); + } /** * Sets the amount of time to wait for a response before giving up. * * @param secs The number of seconds to wait. + * @deprecated use {@link #setTimeout(Duration)} */ - void setTimeout(int secs); + @Deprecated + default void setTimeout(int secs) { + setTimeout(Duration.ofSeconds(secs)); + } + + /** + * Sets the amount of time to wait for a response before giving up. + * + * @param timeout The amount of time to wait. + */ + void setTimeout(Duration timeout); + + /** + * Gets the amount of time to wait for a response before giving up. + * + * @see #setTimeout(Duration) + */ + default Duration getTimeout() { + return Duration.ofSeconds(10); + } /** * Sends a message and waits for a response. @@ -85,16 +133,85 @@ public interface Resolver { * @return The response * @throws IOException An error occurred while sending or receiving. */ - Message send(Message query) throws IOException; + default Message send(Message query) throws IOException { + try { + CompletableFuture result = sendAsync(query).toCompletableFuture(); + return result.get(getTimeout().toMillis(), TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + throw new IOException(e); + } catch (ExecutionException e) { + if (e.getCause() instanceof IOException) { + throw (IOException) e.getCause(); + } else { + throw new IOException(e.getCause()); + } + } catch (TimeoutException e) { + throw new SocketTimeoutException(e.getMessage()); + } + } + + /** + * Asynchronously sends a message. + * + *

The default implementation calls the deprecated {@link #sendAsync(Message, + * ResolverListener)}. Implementors must override at least one of the {@code sendAsync} methods or + * a stack overflow will occur. + * + * @param query The query to send. + * @return A future that completes when the query is finished. + */ + @SuppressWarnings("deprecation") + default CompletionStage sendAsync(Message query) { + CompletableFuture f = new CompletableFuture<>(); + sendAsync( + query, + new ResolverListener() { + @Override + public void receiveMessage(Object id, Message m) { + f.complete(m); + } + + @Override + public void handleException(Object id, Exception e) { + f.completeExceptionally(e); + } + }); + return f; + } /** * Asynchronously sends a message registering a listener to receive a callback on success or - * exception. Multiple asynchronous lookups can be performed in parallel. Since the callback may - * be invoked before the function returns, external synchronization is necessary. + * exception. Multiple asynchronous lookups can be performed in parallel. The callback may be + * invoked from any thread. + * + *

The default implementation calls {@link #sendAsync(Message)}. Implementors must override at + * least one of the {@code sendAsync} methods or a stack overflow will occur. * * @param query The query to send * @param listener The object containing the callbacks. * @return An identifier, which is also a parameter in the callback + * @deprecated Use {@link #sendAsync(Message)} */ - Object sendAsync(final Message query, final ResolverListener listener); + @Deprecated + default Object sendAsync(Message query, ResolverListener listener) { + final Object id = new Object(); + CompletionStage f = sendAsync(query); + f.handleAsync( + (result, throwable) -> { + if (throwable != null) { + Exception exception; + if (throwable instanceof Exception) { + exception = (Exception) throwable; + } else { + exception = new Exception(throwable); + } + listener.handleException(id, exception); + return null; + } + + listener.receiveMessage(id, result); + return null; + }); + return id; + } } diff --git a/src/main/java/org/xbill/DNS/ResolverListener.java b/src/main/java/org/xbill/DNS/ResolverListener.java index dcc037b4b..ec1fe019c 100644 --- a/src/main/java/org/xbill/DNS/ResolverListener.java +++ b/src/main/java/org/xbill/DNS/ResolverListener.java @@ -9,7 +9,9 @@ * * @see Resolver * @author Brian Wellington + * @deprecated Use {@link Resolver#sendAsync(Message)} */ +@Deprecated public interface ResolverListener extends EventListener { /** diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index 332cd3200..b5df0bc6a 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -6,8 +6,11 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; +import java.time.Duration; import java.util.List; import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import lombok.extern.slf4j.Slf4j; /** @@ -33,13 +36,12 @@ public class SimpleResolver implements Resolver { private boolean useTCP, ignoreTruncation; private OPTRecord queryOPT; private TSIG tsig; - private long timeoutValue = 10 * 1000; + private Duration timeoutValue = Duration.ofSeconds(10); private static final short DEFAULT_UDPSIZE = 512; private static InetSocketAddress defaultResolver = new InetSocketAddress(InetAddress.getLoopbackAddress(), DEFAULT_PORT); - private static int uniqueID = 0; /** * Creates a SimpleResolver. The host to query is either found by using ResolverConfig, or the @@ -159,7 +161,7 @@ public void setEDNS(int level, int payloadSize, int flags, List opti @Override public void setEDNS(int level) { - setEDNS(level, 0, 0, null); + setEDNS(level, 0, 0); } @Override @@ -172,16 +174,12 @@ TSIG getTSIGKey() { } @Override - public void setTimeout(int secs, int msecs) { - timeoutValue = (long) secs * 1000 + msecs; + public void setTimeout(Duration timeout) { + timeoutValue = timeout; } @Override - public void setTimeout(int secs) { - setTimeout(secs, 0); - } - - long getTimeout() { + public Duration getTimeout() { return timeoutValue; } @@ -221,113 +219,109 @@ private int maxUDPSize(Message query) { } /** - * Sends a message to a single server and waits for a response. No checking is done to ensure that - * the response is associated with the query. + * Asynchronously sends a message to a single server, registering a listener to receive a callback + * on success or exception. Multiple asynchronous lookups can be performed in parallel. Since the + * callback may be invoked before the function returns, external synchronization is necessary. * - * @param query The query to send. - * @return The response. - * @throws IOException An error occurred while sending or receiving. + * @param query The query to send + * @return A future that completes when the response has arrived. */ @Override - public Message send(Message query) throws IOException { - log.debug("Sending to {}:{}", address.getAddress().getHostAddress(), address.getPort()); + public CompletionStage sendAsync(Message query) { + Message ednsTsigQuery = query.clone(); + applyEDNS(ednsTsigQuery); + if (tsig != null) { + tsig.apply(ednsTsigQuery, null); + } if (query.getHeader().getOpcode() == Opcode.QUERY) { Record question = query.getQuestion(); if (question != null && question.getType() == Type.AXFR) { - return sendAXFR(query); + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture.runAsync( + () -> { + try { + f.complete(sendAXFR(query)); + } catch (IOException e) { + f.completeExceptionally(e); + } + }); + + return f; } } - query = query.clone(); - applyEDNS(query); - if (tsig != null) { - tsig.apply(query, null); - } + return sendAsync(ednsTsigQuery, useTCP); + } + private CompletableFuture sendAsync(Message query, boolean forceTcp) { + int qid = query.getHeader().getID(); byte[] out = query.toWire(Message.MAXLENGTH); int udpSize = maxUDPSize(query); - boolean tcp = false; - long endTime = System.currentTimeMillis() + timeoutValue; - do { - byte[] in; - - if (useTCP || out.length > udpSize) { - tcp = true; - } - if (tcp) { - in = TCPClient.sendrecv(localAddress, address, out, endTime); - } else { - in = UDPClient.sendrecv(localAddress, address, out, udpSize, endTime); - } - - /* - * Check that the response is long enough. - */ - if (in.length < Header.LENGTH) { - throw new WireParseException("invalid DNS header - too short"); - } - /* - * Check that the response ID matches the query ID. We want - * to check this before actually parsing the message, so that - * if there's a malformed response that's not ours, it - * doesn't confuse us. - */ - int id = ((in[0] & 0xFF) << 8) + (in[1] & 0xFF); - int qid = query.getHeader().getID(); - if (id != qid) { - String error = "invalid message id: expected " + qid + "; got id " + id; - if (tcp) { - throw new WireParseException(error); - } else { - log.debug(error); - continue; - } - } - Message response = parseMessage(in); - verifyTSIG(query, response, in, tsig); - if (!tcp && !ignoreTruncation && response.getHeader().getFlag(Flags.TC)) { - tcp = true; - continue; - } - return response; - } while (true); - } - - /** - * Asynchronously sends a message to a single server, registering a listener to receive a callback - * on success or exception. Multiple asynchronous lookups can be performed in parallel. Since the - * callback may be invoked before the function returns, external synchronization is necessary. - * - * @param query The query to send - * @param listener The object containing the callbacks. - * @return An identifier, which is also a parameter in the callback - */ - @Override - public Integer sendAsync(final Message query, final ResolverListener listener) { - final Integer id; - synchronized (this) { - id = uniqueID++; - } - Record question = query.getQuestion(); - String qname; - if (question != null) { - qname = question.getName().toString(); + boolean tcp = forceTcp || out.length > udpSize; + log.debug( + "Sending {}/{}, id={} to {}/{}:{}", + query.getQuestion().getName(), + Type.string(query.getQuestion().getType()), + qid, + tcp ? "tcp" : "udp", + address.getAddress().getHostAddress(), + address.getPort()); + log.trace("Query:\n{}", query); + + CompletableFuture result; + if (tcp) { + result = NioTcpClient.sendrecv(localAddress, address, query, out, timeoutValue); } else { - qname = "(none)"; + result = NioUdpClient.sendrecv(localAddress, address, out, udpSize, timeoutValue); } - String name = this.getClass() + ": " + qname; - Thread thread = new ResolveThread(this, query, id, listener); - thread.setName(name); - thread.setDaemon(true); - thread.start(); - return id; + + return result.thenComposeAsync( + in -> { + CompletableFuture f = new CompletableFuture<>(); + + // Check that the response is long enough. + if (in.length < Header.LENGTH) { + f.completeExceptionally(new WireParseException("invalid DNS header - too short")); + return f; + } + + // Check that the response ID matches the query ID. We want + // to check this before actually parsing the message, so that + // if there's a malformed response that's not ours, it + // doesn't confuse us. + int id = ((in[0] & 0xFF) << 8) + (in[1] & 0xFF); + if (id != qid) { + f.completeExceptionally( + new WireParseException("invalid message id: expected " + qid + "; got id " + id)); + return f; + } + + Message response; + try { + response = parseMessage(in); + } catch (WireParseException e) { + f.completeExceptionally(e); + return f; + } + + verifyTSIG(query, response, in, tsig); + if (!tcp && !ignoreTruncation && response.getHeader().getFlag(Flags.TC)) { + log.debug("Got truncated response for id {}, retrying via TCP", qid); + log.trace("Truncated response: {}", response); + return sendAsync(query, true); + } + + response.setResolver(this); + f.complete(response); + return f; + }); } private Message sendAXFR(Message query) throws IOException { Name qname = query.getQuestion().getName(); ZoneTransferIn xfrin = ZoneTransferIn.newAXFR(qname, address, tsig); - xfrin.setTimeout((int) (getTimeout() / 1000)); + xfrin.setTimeout(timeoutValue); xfrin.setLocalAddress(localAddress); try { xfrin.run(); diff --git a/src/main/java/org/xbill/DNS/TCPClient.java b/src/main/java/org/xbill/DNS/TCPClient.java index 94f5145c9..0b32ce8f1 100644 --- a/src/main/java/org/xbill/DNS/TCPClient.java +++ b/src/main/java/org/xbill/DNS/TCPClient.java @@ -8,12 +8,32 @@ import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; import java.nio.channels.SocketChannel; +import java.util.concurrent.TimeUnit; final class TCPClient extends Client { + private long endTime; + private SelectionKey key; - public TCPClient(long endTime) throws IOException { - super(SocketChannel.open(), endTime); + TCPClient(long timeout) throws IOException { + endTime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeout); + boolean done = false; + Selector selector = null; + SocketChannel channel = SocketChannel.open(); + try { + selector = Selector.open(); + channel.configureBlocking(false); + key = channel.register(selector, SelectionKey.OP_READ); + done = true; + } finally { + if (!done && selector != null) { + selector.close(); + } + if (!done) { + channel.close(); + } + } } void bind(SocketAddress addr) throws IOException { @@ -63,7 +83,7 @@ void send(byte[] data) throws IOException { throw new EOFException(); } nsent += (int) n; - if (nsent < data.length + 2 && System.currentTimeMillis() > endTime) { + if (nsent < data.length + 2 && endTime - System.nanoTime() < 0) { throw new SocketTimeoutException(); } } else { @@ -106,6 +126,24 @@ private byte[] _recv(int length) throws IOException { return data; } + private static void blockUntil(SelectionKey key, long endTime) throws IOException { + long timeout = TimeUnit.NANOSECONDS.toMillis(endTime - System.nanoTime()); + int nkeys = 0; + if (timeout > 0) { + nkeys = key.selector().select(timeout); + } else if (timeout == 0) { + nkeys = key.selector().selectNow(); + } + if (nkeys == 0) { + throw new SocketTimeoutException(); + } + } + + void cleanup() throws IOException { + key.selector().close(); + key.channel().close(); + } + byte[] recv() throws IOException { byte[] buf = _recv(2); int length = ((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF); @@ -118,23 +156,4 @@ byte[] recv() throws IOException { data); return data; } - - static byte[] sendrecv(SocketAddress local, SocketAddress remote, byte[] data, long endTime) - throws IOException { - TCPClient client = new TCPClient(endTime); - try { - if (local != null) { - client.bind(local); - } - client.connect(remote); - client.send(data); - return client.recv(); - } finally { - client.cleanup(); - } - } - - static byte[] sendrecv(SocketAddress addr, byte[] data, long endTime) throws IOException { - return sendrecv(null, addr, data, endTime); - } } diff --git a/src/main/java/org/xbill/DNS/UDPClient.java b/src/main/java/org/xbill/DNS/UDPClient.java deleted file mode 100644 index 8391dbe52..000000000 --- a/src/main/java/org/xbill/DNS/UDPClient.java +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2005 Brian Wellington (bwelling@xbill.org) - -package org.xbill.DNS; - -import java.io.EOFException; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.nio.channels.DatagramChannel; -import java.nio.channels.SelectionKey; -import java.security.SecureRandom; - -final class UDPClient extends Client { - - private static final int EPHEMERAL_START = 1024; - private static final int EPHEMERAL_STOP = 65535; - private static final int EPHEMERAL_RANGE = EPHEMERAL_STOP - EPHEMERAL_START; - - private static SecureRandom prng = new SecureRandom(); - private static volatile boolean prng_initializing = true; - - /* - * On some platforms (Windows), the SecureRandom module initialization involves - * a call to InetAddress.getLocalHost(), which can end up here if using a - * dnsjava name service provider. - * - * This can cause problems in multiple ways. - * - If the SecureRandom seed generation process calls into here, and this - * module attempts to seed the local SecureRandom object, the thread hangs. - * - If something else calls InetAddress.getLocalHost(), and that causes this - * module to seed the local SecureRandom object, the thread hangs. - * - * To avoid both of these, check at initialization time to see if InetAddress - * is in the call chain. If so, initialize the SecureRandom object in a new - * thread, and disable port randomization until it completes. - */ - static { - new Thread( - new Runnable() { - @Override - public void run() { - /*int n =*/ prng.nextInt(); - prng_initializing = false; - } - }) - .start(); - } - - private boolean bound = false; - - public UDPClient(long endTime) throws IOException { - super(DatagramChannel.open(), endTime); - } - - private void bind_random(InetSocketAddress addr) { - if (prng_initializing) { - try { - Thread.sleep(2); - } catch (InterruptedException e) { - } - if (prng_initializing) { - return; - } - } - - DatagramChannel channel = (DatagramChannel) key.channel(); - InetSocketAddress temp; - - for (int i = 0; i < 1024; i++) { - try { - int port = prng.nextInt(EPHEMERAL_RANGE) + EPHEMERAL_START; - if (addr != null) { - temp = new InetSocketAddress(addr.getAddress(), port); - } else { - temp = new InetSocketAddress(port); - } - channel.socket().bind(temp); - bound = true; - return; - } catch (SocketException e) { - } - } - } - - void bind(SocketAddress addr) throws IOException { - if (addr == null - || (addr instanceof InetSocketAddress && ((InetSocketAddress) addr).getPort() == 0)) { - bind_random((InetSocketAddress) addr); - if (bound) { - return; - } - } - - if (addr != null) { - DatagramChannel channel = (DatagramChannel) key.channel(); - channel.socket().bind(addr); - bound = true; - } - } - - void connect(SocketAddress addr) throws IOException { - if (!bound) { - bind(null); - } - DatagramChannel channel = (DatagramChannel) key.channel(); - channel.connect(addr); - } - - void send(byte[] data) throws IOException { - DatagramChannel channel = (DatagramChannel) key.channel(); - verboseLog( - "UDP write", - channel.socket().getLocalSocketAddress(), - channel.socket().getRemoteSocketAddress(), - data); - channel.write(ByteBuffer.wrap(data)); - } - - byte[] recv(int max) throws IOException { - DatagramChannel channel = (DatagramChannel) key.channel(); - byte[] temp = new byte[max]; - key.interestOps(SelectionKey.OP_READ); - try { - while (!key.isReadable()) { - blockUntil(key, endTime); - } - } finally { - if (key.isValid()) { - key.interestOps(0); - } - } - long ret = channel.read(ByteBuffer.wrap(temp)); - if (ret <= 0) { - throw new EOFException(); - } - int len = (int) ret; - byte[] data = new byte[len]; - System.arraycopy(temp, 0, data, 0, len); - verboseLog( - "UDP read", - channel.socket().getLocalSocketAddress(), - channel.socket().getRemoteSocketAddress(), - data); - return data; - } - - static byte[] sendrecv( - SocketAddress local, SocketAddress remote, byte[] data, int max, long endTime) - throws IOException { - UDPClient client = new UDPClient(endTime); - try { - client.bind(local); - client.connect(remote); - client.send(data); - return client.recv(max); - } finally { - client.cleanup(); - } - } - - static byte[] sendrecv(SocketAddress addr, byte[] data, int max, long endTime) - throws IOException { - return sendrecv(null, addr, data, max, endTime); - } -} diff --git a/src/main/java/org/xbill/DNS/ZoneTransferIn.java b/src/main/java/org/xbill/DNS/ZoneTransferIn.java index 704f02e29..129de8e95 100644 --- a/src/main/java/org/xbill/DNS/ZoneTransferIn.java +++ b/src/main/java/org/xbill/DNS/ZoneTransferIn.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import lombok.extern.slf4j.Slf4j; @@ -289,7 +290,9 @@ public int getType() { * Sets a timeout on this zone transfer. The default is 900 seconds (15 minutes). * * @param secs The maximum amount of time that this zone transfer can take. + * @deprecated use {@link #setTimeout(Duration)} */ + @Deprecated public void setTimeout(int secs) { if (secs < 0) { throw new IllegalArgumentException("timeout cannot be negative"); @@ -297,6 +300,15 @@ public void setTimeout(int secs) { timeout = 1000L * secs; } + /** + * Sets a timeout on this zone transfer. The default is 900 seconds (15 minutes). + * + * @param t The maximum amount of time that this zone transfer can take. + */ + public void setTimeout(Duration t) { + timeout = (int) t.toMillis(); + } + /** * Sets an alternate DNS class for this zone transfer. * @@ -317,8 +329,7 @@ public void setLocalAddress(SocketAddress addr) { } private void openConnection() throws IOException { - long endTime = System.currentTimeMillis() + timeout; - client = new TCPClient(endTime); + client = new TCPClient(timeout); if (localAddress != null) { client.bind(localAddress); } @@ -368,7 +379,6 @@ private void fallback() throws ZoneTransferException { private void parseRR(Record rec) throws ZoneTransferException { int type = rec.getType(); - Delta delta; switch (state) { case INITIALSOA: diff --git a/src/main/java/org/xbill/DNS/tools/dig.java b/src/main/java/org/xbill/DNS/tools/dig.java index cca5b1b8b..5cca9dfb2 100644 --- a/src/main/java/org/xbill/DNS/tools/dig.java +++ b/src/main/java/org/xbill/DNS/tools/dig.java @@ -177,7 +177,7 @@ public static void main(String[] argv) throws IOException { break; case 'd': - res.setEDNS(0, 0, ExtendedFlags.DO, null); + res.setEDNS(0, 0, ExtendedFlags.DO); break; case 'q': From d16f51c6b34bdb9706fecd829cf489d7ef4a06b4 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 15 Dec 2019 16:41:59 +0100 Subject: [PATCH 027/431] Validate responses according to rfc5452, section 9.1 --- .../java/org/xbill/DNS/SimpleResolver.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index b5df0bc6a..51f80af3e 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -305,6 +305,37 @@ private CompletableFuture sendAsync(Message query, boolean forceTcp) { return f; } + // validate name, class and type (rfc5452#section-9.1) + if (!query.getQuestion().getName().equals(response.getQuestion().getName())) { + f.completeExceptionally( + new WireParseException( + "invalid name in message: expected " + + query.getQuestion().getName() + + "; got " + + response.getQuestion().getName())); + return f; + } + + if (query.getQuestion().getDClass() != response.getQuestion().getDClass()) { + f.completeExceptionally( + new WireParseException( + "invalid class in message: expected " + + DClass.string(query.getQuestion().getDClass()) + + "; got " + + DClass.string(response.getQuestion().getDClass()))); + return f; + } + + if (query.getQuestion().getType() != response.getQuestion().getType()) { + f.completeExceptionally( + new WireParseException( + "invalid type in message: expected " + + Type.string(query.getQuestion().getType()) + + "; got " + + Type.string(response.getQuestion().getType()))); + return f; + } + verifyTSIG(query, response, in, tsig); if (!tcp && !ignoreTruncation && response.getHeader().getFlag(Flags.TC)) { log.debug("Got truncated response for id {}, retrying via TCP", qid); From b2055178246238d5f34aa90316641396d9aeeed5 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 17:49:25 +0100 Subject: [PATCH 028/431] Fix cloning of Header and Message --- src/main/java/org/xbill/DNS/Header.java | 10 ++++------ src/main/java/org/xbill/DNS/Message.java | 18 +++++++++--------- src/test/java/org/xbill/DNS/HeaderTest.java | 5 +++++ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Header.java b/src/main/java/org/xbill/DNS/Header.java index 43617328b..c3a3ae242 100644 --- a/src/main/java/org/xbill/DNS/Header.java +++ b/src/main/java/org/xbill/DNS/Header.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.util.Random; +import lombok.SneakyThrows; /** * A DNS message header @@ -267,15 +268,12 @@ public String toString() { /* Creates a new Header identical to the current one */ @Override + @SneakyThrows(CloneNotSupportedException.class) public Header clone() { - Header h; - try { - h = (Header) super.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } + Header h = (Header) super.clone(); h.id = id; h.flags = flags; + h.counts = new int[h.counts.length]; System.arraycopy(counts, 0, h.counts, 0, counts.length); return h; } diff --git a/src/main/java/org/xbill/DNS/Message.java b/src/main/java/org/xbill/DNS/Message.java index 65cc46312..eabfad156 100644 --- a/src/main/java/org/xbill/DNS/Message.java +++ b/src/main/java/org/xbill/DNS/Message.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import lombok.SneakyThrows; /** * A DNS Message. A message is the basic unit of communication between the client and server of a @@ -622,25 +623,24 @@ public String toString() { * @see OPTRecord */ @Override + @SneakyThrows(CloneNotSupportedException.class) + @SuppressWarnings("unchecked") public Message clone() { - Message m; - try { - m = (Message) super.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } + Message m = (Message) super.clone(); + m.sections = (List[]) new List[sections.length]; for (int i = 0; i < sections.length; i++) { if (sections[i] != null) { m.sections[i] = new LinkedList<>(sections[i]); } } m.header = header.clone(); - m.size = size; - m.resolver = this.resolver; + if (querytsig != null) { + m.querytsig = (TSIGRecord) querytsig.cloneRecord(); + } return m; } - /** Sets the resolver that originally received this Message a server. */ + /** Sets the resolver that originally received this Message from a server. */ public void setResolver(Resolver resolver) { this.resolver = resolver; } diff --git a/src/test/java/org/xbill/DNS/HeaderTest.java b/src/test/java/org/xbill/DNS/HeaderTest.java index c0664b2d8..bd882fdef 100644 --- a/src/test/java/org/xbill/DNS/HeaderTest.java +++ b/src/test/java/org/xbill/DNS/HeaderTest.java @@ -375,5 +375,10 @@ void test_clone() { for (int i = 0; i < 4; ++i) { assertEquals(m_h.getCount(i), h2.getCount(i)); } + + h2.setCount(1, 1); + h2.setCount(2, 1); + assertEquals(0xFF, m_h.getCount(1)); + assertEquals(0x0A, m_h.getCount(2)); } } From d52ffecf96066acf089d6ae4fb1b292128a413ea Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 17:53:22 +0100 Subject: [PATCH 029/431] Revert type param for RRset, add backward compatibility methods --- src/main/java/org/xbill/DNS/Cache.java | 76 +++++++++--------- src/main/java/org/xbill/DNS/DNSSEC.java | 78 ++++++++++++++++++- src/main/java/org/xbill/DNS/Lookup.java | 45 +++++++++-- src/main/java/org/xbill/DNS/Message.java | 53 +++++++------ src/main/java/org/xbill/DNS/RRSIGRecord.java | 45 ++++++++++- src/main/java/org/xbill/DNS/RRset.java | 25 +++--- src/main/java/org/xbill/DNS/Record.java | 3 - .../java/org/xbill/DNS/ResolverConfig.java | 2 +- src/main/java/org/xbill/DNS/SIG0.java | 3 +- src/main/java/org/xbill/DNS/SIGBase.java | 6 +- src/main/java/org/xbill/DNS/SIGRecord.java | 45 ++++++++++- src/main/java/org/xbill/DNS/SetResponse.java | 13 ++-- .../java/org/xbill/DNS/SimpleResolver.java | 17 +++- src/main/java/org/xbill/DNS/TKEYRecord.java | 42 +++++++++- src/main/java/org/xbill/DNS/TSIG.java | 43 +++++++--- src/main/java/org/xbill/DNS/TSIGRecord.java | 43 +++++++++- .../org/xbill/DNS/TcpKeepaliveOption.java | 2 +- src/main/java/org/xbill/DNS/Update.java | 6 +- src/main/java/org/xbill/DNS/Zone.java | 43 +++++----- .../java/org/xbill/DNS/ZoneTransferIn.java | 15 ++-- src/main/java/org/xbill/DNS/tools/dig.java | 3 +- src/main/java/org/xbill/DNS/tools/jnamed.java | 33 ++++---- .../java/org/xbill/DNS/tools/primary.java | 4 +- src/main/java/org/xbill/DNS/tools/update.java | 19 ++--- src/test/java/org/xbill/DNS/DNSSECTest.java | 8 +- src/test/java/org/xbill/DNS/MessageTest.java | 39 +++++----- src/test/java/org/xbill/DNS/RRsetTest.java | 17 ++-- .../java/org/xbill/DNS/SetResponseTest.java | 12 +-- 28 files changed, 518 insertions(+), 222 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Cache.java b/src/main/java/org/xbill/DNS/Cache.java index 1f833abab..e309803ef 100644 --- a/src/main/java/org/xbill/DNS/Cache.java +++ b/src/main/java/org/xbill/DNS/Cache.java @@ -43,20 +43,20 @@ private static int limitExpire(long ttl, long maxttl) { return (int) expire; } - private static class CacheRRset extends RRset implements Element { + private static class CacheRRset extends RRset implements Element { private static final long serialVersionUID = 5971755205903597024L; int credibility; int expire; - public CacheRRset(T rec, int cred, long maxttl) { + public CacheRRset(Record rec, int cred, long maxttl) { super(); this.credibility = cred; this.expire = limitExpire(rec.getTTL(), maxttl); addRR(rec); } - public CacheRRset(RRset rrset, int cred, long maxttl) { + public CacheRRset(RRset rrset, int cred, long maxttl) { super(rrset); this.credibility = cred; this.expire = limitExpire(rrset.getTTL(), maxttl); @@ -75,11 +75,7 @@ public final int compareCredibility(int cred) { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(super.toString()); - sb.append(" cl = "); - sb.append(credibility); - return sb.toString(); + return super.toString() + " cl = " + credibility; } } @@ -187,10 +183,11 @@ public Cache() { /** Creates a Cache which initially contains all records in the specified file. */ public Cache(String file) throws IOException { data = new CacheMap(defaultMaxEntries); - Master m = new Master(file); - Record record; - while ((record = m.nextRecord()) != null) { - addRecord(record, Credibility.HINT); + try (Master m = new Master(file)) { + Record record; + while ((record = m.nextRecord()) != null) { + addRecord(record, Credibility.HINT); + } } } @@ -317,6 +314,18 @@ private synchronized void removeElement(Name name, int type) { public synchronized void clearCache() { data.clear(); } + /** + * Adds a record to the Cache. + * + * @param r The record to be added + * @param cred The credibility of the record + * @param o unused + * @deprecated use {@link #addRecord(Record, int)} + */ + @Deprecated + public synchronized void addRecord(Record r, int cred, Object o) { + addRecord(r, cred); + } /** * Adds a record to the Cache. @@ -333,12 +342,11 @@ public synchronized void addRecord(Record r, int cred) { } Element element = findElement(name, type, cred); if (element == null) { - CacheRRset crrset = new CacheRRset<>(r, cred, maxcache); + CacheRRset crrset = new CacheRRset(r, cred, maxcache); addRRset(crrset, cred); } else if (element.compareCredibility(cred) == 0) { if (element instanceof CacheRRset) { - @SuppressWarnings("unchecked") - CacheRRset crrset = (CacheRRset) element; + CacheRRset crrset = (CacheRRset) element; crrset.addRR(r); } } @@ -351,7 +359,7 @@ public synchronized void addRecord(Record r, int cred) { * @param cred The credibility of these records * @see RRset */ - public synchronized void addRRset(RRset rrset, int cred) { + public synchronized void addRRset(RRset rrset, int cred) { long ttl = rrset.getTTL(); Name name = rrset.getName(); int type = rrset.getType(); @@ -365,11 +373,11 @@ public synchronized void addRRset(RRset rrset, int cred) { element = null; } if (element == null) { - CacheRRset crrset; + CacheRRset crrset; if (rrset instanceof CacheRRset) { - crrset = (CacheRRset) rrset; + crrset = (CacheRRset) rrset; } else { - crrset = new CacheRRset<>(rrset, cred, maxcache); + crrset = new CacheRRset(rrset, cred, maxcache); } addElement(name, crrset); } @@ -454,7 +462,7 @@ protected synchronized SetResponse lookup(Name name, int type, int minCred) { if (element.compareCredibility(minCred) < 0) { continue; } - sr.addRRset((CacheRRset) element); + sr.addRRset((CacheRRset) element); added++; } /* There were positive entries */ @@ -514,11 +522,10 @@ public SetResponse lookupRecords(Name name, int type, int minCred) { return lookup(name, type, minCred); } - @SuppressWarnings("unchecked") - private List> findRecords(Name name, int type, int minCred) { + private List findRecords(Name name, int type, int minCred) { SetResponse cr = lookupRecords(name, type, minCred); if (cr.isSuccessful()) { - return (List>) (List) cr.answers(); + return cr.answers(); } else { return null; } @@ -533,7 +540,7 @@ private List> findRecords(Name name, int type, int m * @return An array of RRsets, or null * @see Credibility */ - public List> findRecords(Name name, int type) { + public List findRecords(Name name, int type) { return findRecords(name, type, Credibility.NORMAL); } @@ -546,7 +553,7 @@ public List> findRecords(Name name, int type) { * @return An array of RRsets, or null * @see Credibility */ - public List> findAnyRecords(Name name, int type) { + public List findAnyRecords(Name name, int type) { return findRecords(name, type, Credibility.GLUE); } @@ -570,7 +577,7 @@ private int getCred(int section, boolean isAuth) { } } - private static void markAdditional(RRset rrset, Set names) { + private static void markAdditional(RRset rrset, Set names) { Record first = rrset.first(); if (first.getAdditionalName() == null) { return; @@ -593,7 +600,6 @@ private static void markAdditional(RRset rrset, Set names) { * nothing useful could be cached from the message. * @see Message */ - @SuppressWarnings("unchecked") public SetResponse addMessage(Message in) { boolean isAuth = in.getHeader().getFlag(Flags.AA); Record question = in.getQuestion(); @@ -604,7 +610,7 @@ public SetResponse addMessage(Message in) { int cred; int rcode = in.getHeader().getRcode(); boolean completed = false; - RRset[] answers, auth, addl; + List answers, auth, addl; SetResponse response = null; HashSet additionalNames; @@ -621,7 +627,7 @@ public SetResponse addMessage(Message in) { additionalNames = new HashSet<>(); answers = in.getSectionRRsets(Section.ANSWER); - for (RRset answer : answers) { + for (RRset answer : answers) { if (answer.getDClass() != qclass) { continue; } @@ -662,13 +668,13 @@ public SetResponse addMessage(Message in) { } auth = in.getSectionRRsets(Section.AUTHORITY); - RRset soa = null; - RRset ns = null; - for (RRset rset : auth) { + RRset soa = null; + RRset ns = null; + for (RRset rset : auth) { if (rset.getType() == Type.SOA && curname.subdomain(rset.getName())) { - soa = (RRset) rset; + soa = rset; } else if (rset.getType() == Type.NS && curname.subdomain(rset.getName())) { - ns = (RRset) rset; + ns = rset; } } if (!completed) { @@ -709,7 +715,7 @@ public SetResponse addMessage(Message in) { } addl = in.getSectionRRsets(Section.ADDITIONAL); - for (RRset rRset : addl) { + for (RRset rRset : addl) { int type = rRset.getType(); if (type != Type.A && type != Type.AAAA && type != Type.A6) { continue; diff --git a/src/main/java/org/xbill/DNS/DNSSEC.java b/src/main/java/org/xbill/DNS/DNSSEC.java index e0b64f4a1..9a5665f76 100644 --- a/src/main/java/org/xbill/DNS/DNSSEC.java +++ b/src/main/java/org/xbill/DNS/DNSSEC.java @@ -22,6 +22,7 @@ import java.security.spec.EllipticCurve; import java.security.spec.RSAPublicKeySpec; import java.time.Instant; +import java.util.Date; /** * Constants and methods relating to DNSSEC. @@ -140,7 +141,7 @@ private static void digestSIG(DNSOutput out, SIGBase sig) { * @param rrset The data to be signed/verified. * @return The data to be cryptographically signed or verified. */ - public static byte[] digestRRset(RRSIGRecord rrsig, RRset rrset) { + public static byte[] digestRRset(RRSIGRecord rrsig, RRset rrset) { DNSOutput out = new DNSOutput(); digestSIG(out, rrsig); @@ -980,8 +981,30 @@ public static void verify(RRset rrset, RRSIGRecord rrsig, DNSKEYRecord key) * @throws SignatureNotYetValidException The signature is not yet valid * @throws SignatureVerificationException The signature does not verify. * @throws DNSSECException Some other error occurred. + * @deprecated use {@link #verify(RRset, RRSIGRecord, DNSKEYRecord, Instant)} */ - public static void verify(RRset rrset, RRSIGRecord rrsig, DNSKEYRecord key, Instant date) + @Deprecated + public static void verify(RRset rrset, RRSIGRecord rrsig, DNSKEYRecord key, Date date) + throws DNSSECException { + verify(rrset, rrsig, key, date.toInstant()); + } + + /** + * Verify a DNSSEC signature. + * + * @param rrset The data to be verified. + * @param rrsig The RRSIG record containing the signature. + * @param key The DNSKEY record to verify the signature with. + * @param date The date against which the signature is verified. + * @throws UnsupportedAlgorithmException The algorithm is unknown + * @throws MalformedKeyException The key is malformed + * @throws KeyMismatchException The key and signature do not match + * @throws SignatureExpiredException The signature has expired + * @throws SignatureNotYetValidException The signature is not yet valid + * @throws SignatureVerificationException The signature does not verify. + * @throws DNSSECException Some other error occurred. + */ + public static void verify(RRset rrset, RRSIGRecord rrsig, DNSKEYRecord key, Instant date) throws DNSSECException { if (!matches(rrsig, key)) { throw new KeyMismatchException(key, rrsig); @@ -1077,6 +1100,55 @@ static void checkAlgorithm(PrivateKey key, int alg) throws UnsupportedAlgorithmE } } + /** + * Generate a DNSSEC signature. key and privateKey must refer to the same underlying cryptographic + * key. + * + * @param rrset The data to be signed + * @param key The DNSKEY record to use as part of signing + * @param privkey The PrivateKey to use when signing + * @param inception The time at which the signatures should become valid + * @param expiration The time at which the signatures should expire + * @throws UnsupportedAlgorithmException The algorithm is unknown + * @throws MalformedKeyException The key is malformed + * @throws DNSSECException Some other error occurred. + * @return The generated signature + * @deprecated use {@link #sign(RRset, DNSKEYRecord, PrivateKey, Instant, Instant)} + */ + @Deprecated + public static RRSIGRecord sign( + RRset rrset, DNSKEYRecord key, PrivateKey privkey, Date inception, Date expiration) + throws DNSSECException { + return sign(rrset, key, privkey, inception.toInstant(), expiration.toInstant(), null); + } + + /** + * Generate a DNSSEC signature. key and privateKey must refer to the same underlying cryptographic + * key. + * + * @param rrset The data to be signed + * @param key The DNSKEY record to use as part of signing + * @param privkey The PrivateKey to use when signing + * @param inception The time at which the signatures should become valid + * @param expiration The time at which the signatures should expire + * @throws UnsupportedAlgorithmException The algorithm is unknown + * @throws MalformedKeyException The key is malformed + * @throws DNSSECException Some other error occurred. + * @return The generated signature + * @deprecated use {@link #sign(RRset, DNSKEYRecord, PrivateKey, Instant, Instant, String)} + */ + @Deprecated + public static RRSIGRecord sign( + RRset rrset, + DNSKEYRecord key, + PrivateKey privkey, + Date inception, + Date expiration, + String provider) + throws DNSSECException { + return sign(rrset, key, privkey, inception.toInstant(), expiration.toInstant(), provider); + } + /** * Generate a DNSSEC signature. key and privateKey must refer to the same underlying cryptographic * key. @@ -1114,7 +1186,7 @@ public static RRSIGRecord sign( * @return The generated signature */ public static RRSIGRecord sign( - RRset rrset, + RRset rrset, DNSKEYRecord key, PrivateKey privkey, Instant inception, diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index fa12cae8f..1dd89dcfd 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.io.InterruptedIOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,6 +36,7 @@ public final class Lookup { private Resolver resolver; private List searchPath; + private int ndots; private Cache cache; private boolean temporary_cache; private int credibility; @@ -148,6 +150,15 @@ public static synchronized void setDefaultSearchPath(List domains) { defaultSearchPath = domains; } + /** + * Sets the search path to be used as the default by future Lookups. + * + * @param domains The default search path. + */ + public static synchronized void setDefaultSearchPath(org.xbill.DNS.Name[] domains) { + setDefaultSearchPath(Arrays.asList(domains)); + } + /** * Sets the search path that will be used as the default by future Lookups. * @@ -228,6 +239,7 @@ public Lookup(Name name, int type, int dclass) { this.searchPath = getDefaultSearchPath(); this.cache = getDefaultCache(dclass); } + this.ndots = defaultNdots; this.credibility = Credibility.NORMAL; this.result = -1; } @@ -310,6 +322,15 @@ public void setSearchPath(List domains) { this.searchPath = domains; } + /** + * Sets the search path to use when performing this lookup. This overrides the default value. + * + * @param domains An array of names containing the search path. + */ + public void setSearchPath(Name[] domains) { + setSearchPath(Arrays.asList(domains)); + } + /** * Sets the search path to use when performing this lookup. This overrides the default value. * @@ -345,6 +366,20 @@ public void setCache(Cache cache) { } } + /** + * Sets the default ndots to use when performing a lookup, overriding the default value. + * Specifically, this refers to the number of "dots" which, if present in a name, indicate that a + * lookup for the absolute name should be attempted before appending any search path elements. + * + * @param ndots The ndots value to use, which must be greater than or equal to 0. + */ + public static void setDefaultNdots(int ndots) { + if (ndots < 0) { + throw new IllegalArgumentException("Illegal ndots value: " + ndots); + } + defaultNdots = ndots; + } + /** * Sets ndots to use when performing this lookup, overriding the default value. Specifically, this * refers to the number of "dots" which, if present in a name, indicate that a lookup for the @@ -352,11 +387,11 @@ public void setCache(Cache cache) { * * @param ndots The ndots value to use, which must be greater than or equal to 0. */ - public static void setNdots(int ndots) { + public void setNdots(int ndots) { if (ndots < 0) { throw new IllegalArgumentException("Illegal ndots value: " + ndots); } - defaultNdots = ndots; + this.ndots = ndots; } /** @@ -392,10 +427,10 @@ private void follow(Name name, Name oldname) { private void processResponse(Name name, SetResponse response) { if (response.isSuccessful()) { - List> rrsets = response.answers(); + List rrsets = response.answers(); List l = new ArrayList<>(); - for (RRset set : rrsets) { + for (RRset set : rrsets) { l.addAll(set.rrs()); } @@ -511,7 +546,7 @@ public Record[] run() { } else if (searchPath == null) { resolve(name, Name.root); } else { - if (name.labels() > defaultNdots) { + if (name.labels() > ndots) { resolve(name, Name.root); } if (done) { diff --git a/src/main/java/org/xbill/DNS/Message.java b/src/main/java/org/xbill/DNS/Message.java index eabfad156..ecbab21a2 100644 --- a/src/main/java/org/xbill/DNS/Message.java +++ b/src/main/java/org/xbill/DNS/Message.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -57,7 +58,6 @@ public class Message implements Cloneable { static final int TSIG_FAILED = 4; private static Record[] emptyRecordArray = new Record[0]; - private static RRset[] emptyRRsetArray = new RRset[0]; @SuppressWarnings("unchecked") private Message(Header header) { @@ -272,11 +272,11 @@ public boolean findRRset(Name name, int type) { * @see Section */ public Record getQuestion() { - List l = sections[Section.QUESTION]; + List l = sections[Section.QUESTION]; if (l == null || l.size() == 0) { return null; } - return (Record) l.get(0); + return l.get(0); } /** @@ -291,8 +291,8 @@ public TSIGRecord getTSIG() { if (count == 0) { return null; } - List l = sections[Section.ADDITIONAL]; - Record rec = (Record) l.get(count - 1); + List l = sections[Section.ADDITIONAL]; + Record rec = l.get(count - 1); if (rec.type != Type.TSIG) { return null; } @@ -324,8 +324,7 @@ public boolean isVerified() { * @see Section */ public OPTRecord getOPT() { - Record[] additional = getSectionArray(Section.ADDITIONAL); - for (Record record : additional) { + for (Record record : getSection(Section.ADDITIONAL)) { if (record instanceof OPTRecord) { return (OPTRecord) record; } @@ -349,7 +348,9 @@ public int getRcode() { * * @see Record * @see Section + * @deprecated use {@link #getSection(int)} */ + @Deprecated public Record[] getSectionArray(int section) { if (sections[section] == null) { return emptyRecordArray; @@ -358,6 +359,19 @@ public Record[] getSectionArray(int section) { return l.toArray(new Record[0]); } + /** + * Returns all records in the given section, or an empty list if the section is empty. + * + * @see Record + * @see Section + */ + public List getSection(int section) { + if (sections[section] == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(sections[section]); + } + private static boolean sameSet(Record r1, Record r2) { return (r1.getRRsetType() == r2.getRRsetType() && r1.getDClass() == r2.getDClass() @@ -370,19 +384,18 @@ private static boolean sameSet(Record r1, Record r2) { * @see RRset * @see Section */ - public RRset[] getSectionRRsets(int section) { + public List getSectionRRsets(int section) { if (sections[section] == null) { - return emptyRRsetArray; + return Collections.emptyList(); } - List> sets = new LinkedList<>(); - Record[] recs = getSectionArray(section); + List sets = new LinkedList<>(); Set hash = new HashSet<>(); - for (Record rec : recs) { + for (Record rec : getSection(section)) { Name name = rec.getName(); boolean newset = true; if (hash.contains(name)) { for (int j = sets.size() - 1; j >= 0; j--) { - RRset set = sets.get(j); + RRset set = sets.get(j); if (set.getType() == rec.getRRsetType() && set.getDClass() == rec.getDClass() && set.getName().equals(name)) { @@ -393,12 +406,12 @@ public RRset[] getSectionRRsets(int section) { } } if (newset) { - RRset set = new RRset<>(rec); + RRset set = new RRset(rec); sets.add(set); hash.add(name); } } - return sets.toArray(new RRset[0]); + return sets; } void toWire(DNSOutput out) { @@ -444,9 +457,9 @@ private int sectionToWire(DNSOutput out, int section, Compression c, int maxLeng } /* Returns true if the message could be rendered. */ - private boolean toWire(DNSOutput out, int maxLength) { + private void toWire(DNSOutput out, int maxLength) { if (maxLength < Header.LENGTH) { - return false; + return; } int tempMaxLength = maxLength; @@ -504,8 +517,6 @@ private boolean toWire(DNSOutput out, int maxLength) { tsigrec.toWire(out, Section.ADDITIONAL, c); out.writeU16At(additionalCount + 1, startpos + 10); } - - return true; } /** Returns an array containing the wire format representation of the Message. */ @@ -568,9 +579,7 @@ public String sectionToString(int i) { } StringBuilder sb = new StringBuilder(); - - Record[] records = getSectionArray(i); - for (Record rec : records) { + for (Record rec : getSection(i)) { if (i == Section.QUESTION) { sb.append(";;\t").append(rec.name); sb.append(", type = ").append(Type.string(rec.type)); diff --git a/src/main/java/org/xbill/DNS/RRSIGRecord.java b/src/main/java/org/xbill/DNS/RRSIGRecord.java index 6475b772a..a157c5522 100644 --- a/src/main/java/org/xbill/DNS/RRSIGRecord.java +++ b/src/main/java/org/xbill/DNS/RRSIGRecord.java @@ -3,6 +3,7 @@ package org.xbill.DNS; import java.time.Instant; +import java.util.Date; /** * Resource Record Signature - An RRSIG provides the digital signature of an RRset, so that the data @@ -18,7 +19,7 @@ */ public class RRSIGRecord extends SIGBase { - private static final long serialVersionUID = -2609150673537226317L; + private static final long serialVersionUID = 7453923738152214746L; RRSIGRecord() {} @@ -65,4 +66,46 @@ public RRSIGRecord( signer, signature); } + + /** + * Creates an RRSIG Record from the given data + * + * @param covered The RRset type covered by this signature + * @param alg The cryptographic algorithm of the key that generated the signature + * @param origttl The original TTL of the RRset + * @param expire The time at which the signature expires + * @param timeSigned The time at which this signature was generated + * @param footprint The footprint/key id of the signing key. + * @param signer The owner of the signing key + * @param signature Binary data representing the signature + * @deprecated use {@link #RRSIGRecord(Name, int, long, int, int, long, Instant, Instant, int, + * Name, byte[])} + */ + @Deprecated + public RRSIGRecord( + Name name, + int dclass, + long ttl, + int covered, + int alg, + long origttl, + Date expire, + Date timeSigned, + int footprint, + Name signer, + byte[] signature) { + super( + name, + Type.RRSIG, + dclass, + ttl, + covered, + alg, + origttl, + expire.toInstant(), + timeSigned.toInstant(), + footprint, + signer, + signature); + } } diff --git a/src/main/java/org/xbill/DNS/RRset.java b/src/main/java/org/xbill/DNS/RRset.java index af5696424..70e82a142 100644 --- a/src/main/java/org/xbill/DNS/RRset.java +++ b/src/main/java/org/xbill/DNS/RRset.java @@ -16,15 +16,8 @@ * @see RRSIGRecord * @author Brian Wellington */ -public class RRset implements Serializable { - - private static final long serialVersionUID = -3270249290171239695L; - - /* - * rrs contains both normal and RRSIG records, with the RRSIG records - * at the end. - */ - private final ArrayList rrs; +public class RRset implements Serializable { + private final ArrayList rrs; private final ArrayList sigs; private short position; private long ttl; @@ -36,13 +29,13 @@ public RRset() { } /** Creates an RRset and sets its contents to the specified record */ - public RRset(T record) { + public RRset(Record record) { this(); addRR(record); } /** Creates an RRset with the contents of an existing RRset */ - public RRset(RRset rrset) { + public RRset(RRset rrset) { rrs = new ArrayList<>(rrset.rrs); sigs = new ArrayList<>(rrset.sigs); position = rrset.position; @@ -63,7 +56,7 @@ public void addRR(RRSIGRecord r) { * in the RRset, all records are set to the lowest TTL of either the added record or the existing * records. */ - public void addRR(T r) { + public void addRR(Record r) { if (r instanceof RRSIGRecord) { addRR((RRSIGRecord) r, sigs); return; @@ -126,7 +119,7 @@ public void deleteRR(RRSIGRecord r) { } /** Deletes a record from this RRset */ - public void deleteRR(T r) { + public void deleteRR(Record r) { if (r instanceof RRSIGRecord) { sigs.remove(r); return; @@ -147,12 +140,12 @@ public void clear() { * @param cycle If true, cycle through the records so that each list will start with a different * record. */ - public List rrs(boolean cycle) { + public List rrs(boolean cycle) { if (!cycle || rrs.size() <= 1) { return Collections.unmodifiableList(rrs); } - List l = new ArrayList<>(rrs.size()); + List l = new ArrayList<>(rrs.size()); int start = position++ % rrs.size(); l.addAll(rrs.subList(start, rrs.size())); l.addAll(rrs.subList(0, start)); @@ -163,7 +156,7 @@ public List rrs(boolean cycle) { * Returns a list of all data records. This cycles through the records, so that each returned list * will start with a different record. */ - public List rrs() { + public List rrs() { return rrs(true); } diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index dd813edf6..25efde973 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -16,9 +16,6 @@ * @author Brian Wellington */ public abstract class Record implements Cloneable, Comparable, Serializable { - - private static final long serialVersionUID = 2694906050116005466L; - protected Name name; protected int type, dclass; protected long ttl; diff --git a/src/main/java/org/xbill/DNS/ResolverConfig.java b/src/main/java/org/xbill/DNS/ResolverConfig.java index 4e398c204..c16c75a31 100644 --- a/src/main/java/org/xbill/DNS/ResolverConfig.java +++ b/src/main/java/org/xbill/DNS/ResolverConfig.java @@ -131,7 +131,7 @@ public List searchPath() { * name will be tried first as an absolute name. * *

Note that ndots can only be configured in a resolv.conf file or the property {@link - * #DNS_NDOTS_PROP}. + * PropertyResolverConfigProvider#DNS_NDOTS_PROP}. */ public int ndots() { return ndots; diff --git a/src/main/java/org/xbill/DNS/SIG0.java b/src/main/java/org/xbill/DNS/SIG0.java index 260f80c98..823160ed0 100644 --- a/src/main/java/org/xbill/DNS/SIG0.java +++ b/src/main/java/org/xbill/DNS/SIG0.java @@ -97,8 +97,7 @@ public static void verifyMessage( Message message, byte[] b, KEYRecord key, SIGRecord previous, Instant now) throws DNSSEC.DNSSECException { SIGRecord sig = null; - Record[] additional = message.getSectionArray(Section.ADDITIONAL); - for (Record record : additional) { + for (Record record : message.getSection(Section.ADDITIONAL)) { if (record.getType() != Type.SIG) { continue; } diff --git a/src/main/java/org/xbill/DNS/SIGBase.java b/src/main/java/org/xbill/DNS/SIGBase.java index f2863cb53..4a35195c8 100644 --- a/src/main/java/org/xbill/DNS/SIGBase.java +++ b/src/main/java/org/xbill/DNS/SIGBase.java @@ -12,13 +12,11 @@ * @author Brian Wellington */ abstract class SIGBase extends Record { - - private static final long serialVersionUID = -3738444391533812369L; - protected int covered; protected int alg, labels; protected long origttl; - protected Instant expire, timeSigned; + protected Instant expire; + protected Instant timeSigned; protected int footprint; protected Name signer; protected byte[] signature; diff --git a/src/main/java/org/xbill/DNS/SIGRecord.java b/src/main/java/org/xbill/DNS/SIGRecord.java index 2bcd50aac..49fd98950 100644 --- a/src/main/java/org/xbill/DNS/SIGRecord.java +++ b/src/main/java/org/xbill/DNS/SIGRecord.java @@ -3,6 +3,7 @@ package org.xbill.DNS; import java.time.Instant; +import java.util.Date; /** * Signature - A SIG provides the digital signature of an RRset, so that the data can be @@ -17,7 +18,7 @@ */ public class SIGRecord extends SIGBase { - private static final long serialVersionUID = 4963556060953589058L; + private static final long serialVersionUID = -2121567461284199774L; SIGRecord() {} @@ -64,4 +65,46 @@ public SIGRecord( signer, signature); } + + /** + * Creates an SIG Record from the given data + * + * @param covered The RRset type covered by this signature + * @param alg The cryptographic algorithm of the key that generated the signature + * @param origttl The original TTL of the RRset + * @param expire The time at which the signature expires + * @param timeSigned The time at which this signature was generated + * @param footprint The footprint/key id of the signing key. + * @param signer The owner of the signing key + * @param signature Binary data representing the signature + * @deprecated use {@link #SIGRecord(Name, int, long, int, int, long, Instant, Instant, int, Name, + * byte[])} + */ + @Deprecated + public SIGRecord( + Name name, + int dclass, + long ttl, + int covered, + int alg, + long origttl, + Date expire, + Date timeSigned, + int footprint, + Name signer, + byte[] signature) { + super( + name, + Type.SIG, + dclass, + ttl, + covered, + alg, + origttl, + expire.toInstant(), + timeSigned.toInstant(), + footprint, + signer, + signature); + } } diff --git a/src/main/java/org/xbill/DNS/SetResponse.java b/src/main/java/org/xbill/DNS/SetResponse.java index 202043363..d2e458a25 100644 --- a/src/main/java/org/xbill/DNS/SetResponse.java +++ b/src/main/java/org/xbill/DNS/SetResponse.java @@ -55,11 +55,11 @@ public class SetResponse { private static final SetResponse nxrrset = new SetResponse(NXRRSET); private int type; - private List> data; + private List data; private SetResponse() {} - SetResponse(int type, RRset rrset) { + SetResponse(int type, RRset rrset) { if (type < 0 || type > 6) { throw new IllegalArgumentException("invalid type"); } @@ -97,7 +97,7 @@ static SetResponse ofType(int type) { } } - void addRRset(RRset rrset) { + void addRRset(RRset rrset) { if (data == null) { data = new ArrayList<>(); } @@ -140,7 +140,7 @@ public boolean isSuccessful() { } /** If the query was successful, return the answers */ - public List> answers() { + public List answers() { if (type != SUCCESSFUL) { return null; } @@ -158,9 +158,8 @@ public DNAMERecord getDNAME() { } /** If the query hit a delegation point, return the NS set. */ - @SuppressWarnings("unchecked") - public RRset getNS() { - return (data != null) ? (RRset) data.get(0) : null; + public RRset getNS() { + return (data != null) ? data.get(0) : null; } /** Prints the value of the SetResponse */ diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index 51f80af3e..151b53eba 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -62,13 +62,21 @@ public SimpleResolver() throws UnknownHostException { public SimpleResolver(String hostname) throws UnknownHostException { if (hostname == null) { address = ResolverConfig.getCurrentConfig().server(); + if (address == null) { + address = defaultResolver; + } + + return; } + InetAddress addr; if ("0".equals(hostname)) { - address = defaultResolver; + addr = InetAddress.getLoopbackAddress(); } else { - address = new InetSocketAddress(InetAddress.getByName(hostname), DEFAULT_PORT); + addr = InetAddress.getByName(hostname); } + + address = new InetSocketAddress(addr, DEFAULT_PORT); } /** Creates a SimpleResolver that will query the specified host */ @@ -97,6 +105,11 @@ public static void setDefaultResolver(InetSocketAddress hostname) { defaultResolver = hostname; } + /** Sets the default host (initially localhost) to query */ + public static void setDefaultResolver(String hostname) { + defaultResolver = new InetSocketAddress(hostname, DEFAULT_PORT); + } + @Override public void setPort(int port) { address = new InetSocketAddress(address.getAddress(), port); diff --git a/src/main/java/org/xbill/DNS/TKEYRecord.java b/src/main/java/org/xbill/DNS/TKEYRecord.java index 36dd530b8..6c3b8701f 100644 --- a/src/main/java/org/xbill/DNS/TKEYRecord.java +++ b/src/main/java/org/xbill/DNS/TKEYRecord.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.time.Instant; +import java.util.Date; import org.xbill.DNS.utils.base64; /** @@ -16,7 +17,7 @@ */ public class TKEYRecord extends Record { - private static final long serialVersionUID = 8828458121926391756L; + private static final long serialVersionUID = -7330934927273584334L; private Name alg; private Instant timeInception; @@ -80,6 +81,45 @@ public TKEYRecord( this.other = other; } + /** + * Creates a TKEY Record from the given data. + * + * @param alg The shared key's algorithm + * @param timeInception The beginning of the validity period of the shared secret or keying + * material + * @param timeExpire The end of the validity period of the shared secret or keying material + * @param mode The mode of key agreement + * @param error The extended error field. Should be 0 in queries + * @param key The shared secret + * @param other The other data field. Currently unused responses. + * @deprecated use {@link #TKEYRecord(Name, int, long, Name, Instant, Instant, int, int, byte[], + * byte[])} + */ + @Deprecated + public TKEYRecord( + Name name, + int dclass, + long ttl, + Name alg, + Date timeInception, + Date timeExpire, + int mode, + int error, + byte[] key, + byte[] other) { + this( + name, + dclass, + ttl, + alg, + timeInception.toInstant(), + timeExpire.toInstant(), + mode, + error, + key, + other); + } + @Override void rrFromWire(DNSInput in) throws IOException { alg = new Name(in); diff --git a/src/main/java/org/xbill/DNS/TSIG.java b/src/main/java/org/xbill/DNS/TSIG.java index 7e05cfdf2..1f2dff591 100644 --- a/src/main/java/org/xbill/DNS/TSIG.java +++ b/src/main/java/org/xbill/DNS/TSIG.java @@ -24,12 +24,16 @@ */ @Slf4j public class TSIG { + // https://www.iana.org/assignments/tsig-algorithm-names/tsig-algorithm-names.xml + + /** The domain name representing the gss-tsig algorithm. */ + public static final Name GSS_TSIG = Name.fromConstantString("gss-tsig."); /** The domain name representing the HMAC-MD5 algorithm. */ public static final Name HMAC_MD5 = Name.fromConstantString("HMAC-MD5.SIG-ALG.REG.INT."); /** The domain name representing the HMAC-MD5 algorithm (deprecated). */ - public static final Name HMAC = HMAC_MD5; + @Deprecated public static final Name HMAC = HMAC_MD5; /** The domain name representing the HMAC-SHA1 algorithm. */ public static final Name HMAC_SHA1 = Name.fromConstantString("hmac-sha1."); @@ -46,7 +50,7 @@ public class TSIG { /** The domain name representing the HMAC-SHA512 algorithm. */ public static final Name HMAC_SHA512 = Name.fromConstantString("hmac-sha512."); - private static Map algMap; + private static Map algMap; static { Map out = new HashMap<>(); @@ -60,17 +64,16 @@ public class TSIG { } public static Name algorithmToName(String alg) { - for (Object o : algMap.entrySet()) { - Map.Entry entry = (Map.Entry) o; - if (alg.equalsIgnoreCase((String) entry.getValue())) { - return (Name) entry.getKey(); + for (Map.Entry entry : algMap.entrySet()) { + if (alg.equalsIgnoreCase(entry.getValue())) { + return entry.getKey(); } } throw new IllegalArgumentException("Unknown algorithm"); } public static String nameToAlgorithm(Name name) { - String alg = (String) algMap.get(name); + String alg = algMap.get(name); if (alg != null) { return alg; } @@ -408,8 +411,6 @@ public void applyStream(Message m, TSIGRecord old, boolean first) { hmac.update(out.toByteArray()); byte[] signature = hmac.doFinal(); - byte[] other = null; - Record r = new TSIGRecord( name, @@ -421,11 +422,31 @@ public void applyStream(Message m, TSIGRecord old, boolean first) { signature, m.getHeader().getID(), Rcode.NOERROR, - other); + null); m.addRecord(r, Section.ADDITIONAL); m.tsigState = Message.TSIG_SIGNED; } + /** + * Verifies a TSIG record on an incoming message. Since this is only called in the context where a + * TSIG is expected to be present, it is an error if one is not present. After calling this + * routine, Message.isVerified() may be called on this message. + * + * @param m The message + * @param b An array containing the message in unparsed form. This is necessary since TSIG signs + * the message in wire format, and we can't recreate the exact wire format (with the same name + * compression). + * @param length unused + * @param old If this message is a response, the TSIG from the request + * @return The result of the verification (as an Rcode) + * @see Rcode + * @deprecated use {@link #verify(Message, byte[], TSIGRecord)} + */ + @Deprecated + public byte verify(Message m, byte[] b, int length, TSIGRecord old) { + return (byte) verify(m, b, old); + } + /** * Verifies a TSIG record on an incoming message. Since this is only called in the context where a * TSIG is expected to be present, it is an error if one is not present. After calling this @@ -439,7 +460,7 @@ public void applyStream(Message m, TSIGRecord old, boolean first) { * @return The result of the verification (as an Rcode) * @see Rcode */ - public byte verify(Message m, byte[] b, TSIGRecord old) { + public int verify(Message m, byte[] b, TSIGRecord old) { m.tsigState = Message.TSIG_FAILED; TSIGRecord tsig = m.getTSIG(); hmac.reset(); diff --git a/src/main/java/org/xbill/DNS/TSIGRecord.java b/src/main/java/org/xbill/DNS/TSIGRecord.java index 15da00fe3..f3c822616 100644 --- a/src/main/java/org/xbill/DNS/TSIGRecord.java +++ b/src/main/java/org/xbill/DNS/TSIGRecord.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.time.Duration; import java.time.Instant; +import java.util.Date; import org.xbill.DNS.utils.base64; /** @@ -19,7 +20,7 @@ */ public class TSIGRecord extends Record { - private static final long serialVersionUID = -88820909016649306L; + private static final long serialVersionUID = -2649450085333713717L; private Name alg; private Instant timeSigned; @@ -36,6 +37,46 @@ Record getObject() { return new TSIGRecord(); } + /** + * Creates a TSIG Record from the given data. This is normally called by the TSIG class + * + * @param alg The shared key's algorithm + * @param timeSigned The time that this record was generated + * @param fudge The fudge factor for time - if the time that the message is received is not in the + * range [now - fudge, now + fudge], the signature fails + * @param signature The signature + * @param originalID The message ID at the time of its generation + * @param error The extended error field. Should be 0 in queries. + * @param other The other data field. Currently used only in BADTIME responses. + * @see TSIG + * @deprecated use {@link #TSIGRecord(Name, int, long, Name, Instant, Duration, byte[], int, int, + * byte[])} + */ + @Deprecated + public TSIGRecord( + Name name, + int dclass, + long ttl, + Name alg, + Date timeSigned, + int fudge, + byte[] signature, + int originalID, + int error, + byte[] other) { + this( + name, + dclass, + ttl, + alg, + timeSigned.toInstant(), + Duration.ofSeconds(fudge), + signature, + originalID, + error, + other); + } + /** * Creates a TSIG Record from the given data. This is normally called by the TSIG class * diff --git a/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java b/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java index 4b5cb07f7..ef0139681 100644 --- a/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java +++ b/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java @@ -63,7 +63,7 @@ public OptionalInt getTimeout() { /** * Returns the timeout as a {@link Duration}. * - * @reutrn the timeout + * @return the timeout */ public Optional getTimeoutDuration() { return timeout.isPresent() diff --git a/src/main/java/org/xbill/DNS/Update.java b/src/main/java/org/xbill/DNS/Update.java index 3650becad..b83c24b6a 100644 --- a/src/main/java/org/xbill/DNS/Update.java +++ b/src/main/java/org/xbill/DNS/Update.java @@ -149,7 +149,7 @@ public void add(Record[] records) { } /** Indicates that all of the records in the rrset should be inserted into the zone. */ - public void add(RRset rrset) { + public void add(RRset rrset) { rrset.rrs().forEach(this::add); } @@ -195,7 +195,7 @@ public void delete(Record[] records) { } /** Indicates that all of the records in the rrset should be deleted from the zone. */ - public void delete(RRset rrset) { + public void delete(RRset rrset) { rrset.rrs().forEach(this::delete); } @@ -244,7 +244,7 @@ public void replace(Record[] records) { * Indicates that all of the records in the rrset should be inserted into the zone replacing any * other records with the same name and type. */ - public void replace(RRset rrset) { + public void replace(RRset rrset) { delete(rrset.getName(), rrset.getType()); rrset.rrs().forEach(this::add); } diff --git a/src/main/java/org/xbill/DNS/Zone.java b/src/main/java/org/xbill/DNS/Zone.java index d8022efa9..180ee26db 100644 --- a/src/main/java/org/xbill/DNS/Zone.java +++ b/src/main/java/org/xbill/DNS/Zone.java @@ -30,11 +30,11 @@ public class Zone implements Serializable { private Name origin; private Object originNode; private int dclass = DClass.IN; - private RRset NS; + private RRset NS; private SOARecord SOA; private boolean hasWild; - class ZoneIterator implements Iterator> { + class ZoneIterator implements Iterator { private Iterator zentries; private RRset[] current; private int count; @@ -216,7 +216,7 @@ public Name getOrigin() { } /** Returns the Zone origin's NS records */ - public RRset getNS() { + public RRset getNS() { return NS; } @@ -234,10 +234,10 @@ private synchronized Object exactName(Name name) { return data.get(name); } - private synchronized RRset[] allRRsets(Object types) { + private synchronized RRset[] allRRsets(Object types) { if (types instanceof List) { @SuppressWarnings("unchecked") - List> typelist = (List>) types; + List typelist = (List) types; return typelist.toArray(new RRset[0]); } else { RRset set = (RRset) types; @@ -245,21 +245,20 @@ private synchronized RRset[] allRRsets(Object types) { } } - private synchronized RRset oneRRset(Object types, int type) { + private synchronized RRset oneRRset(Object types, int type) { if (type == Type.ANY) { throw new IllegalArgumentException("oneRRset(ANY)"); } if (types instanceof List) { @SuppressWarnings("unchecked") - List> list = (List>) types; - for (RRset set : list) { + List list = (List) types; + for (RRset set : list) { if (set.getType() == type) { return set; } } } else { - @SuppressWarnings("unchecked") - RRset set = (RRset) types; + RRset set = (RRset) types; if (set.getType() == type) { return set; } @@ -267,7 +266,7 @@ private synchronized RRset oneRRset(Object types, int type return null; } - private synchronized RRset findRRset(Name name, int type) { + private synchronized RRset findRRset(Name name, int type) { Object types = exactName(name); if (types == null) { return null; @@ -370,7 +369,7 @@ private synchronized SetResponse lookup(Name name, int type) { /* If this is a delegation, return that. */ if (!isOrigin) { - RRset ns = oneRRset(types, Type.NS); + RRset ns = oneRRset(types, Type.NS); if (ns != null) { return new SetResponse(SetResponse.DELEGATION, ns); } @@ -379,8 +378,8 @@ private synchronized SetResponse lookup(Name name, int type) { /* If this is an ANY lookup, return everything. */ if (isExact && type == Type.ANY) { sr = new SetResponse(SetResponse.SUCCESSFUL); - RRset[] sets = allRRsets(types); - for (RRset set : sets) { + RRset[] sets = allRRsets(types); + for (RRset set : sets) { sr.addRRset(set); } return sr; @@ -455,7 +454,7 @@ public SetResponse findRecords(Name name, int type) { * @return The matching RRset * @see RRset */ - public RRset findExactMatch(Name name, int type) { + public RRset findExactMatch(Name name, int type) { Object types = exactName(name); if (types == null) { return null; @@ -469,7 +468,7 @@ public RRset findExactMatch(Name name, int type) { * @param rrset The RRset to be added * @see RRset */ - public void addRRset(RRset rrset) { + public void addRRset(RRset rrset) { Name name = rrset.getName(); addRRset(name, rrset); } @@ -484,9 +483,9 @@ public void addRecord(T r) { Name name = r.getName(); int rtype = r.getRRsetType(); synchronized (this) { - RRset rrset = findRRset(name, rtype); + RRset rrset = findRRset(name, rtype); if (rrset == null) { - rrset = new RRset<>(r); + rrset = new RRset(r); addRRset(name, rrset); } else { rrset.addRR(r); @@ -504,7 +503,7 @@ public void removeRecord(T r) { Name name = r.getName(); int rtype = r.getRRsetType(); synchronized (this) { - RRset rrset = findRRset(name, rtype); + RRset rrset = findRRset(name, rtype); if (rrset == null) { return; } @@ -517,7 +516,7 @@ public void removeRecord(T r) { } /** Returns an Iterator over the RRsets in the zone. */ - public Iterator> iterator() { + public Iterator iterator() { return new ZoneIterator(false); } @@ -526,13 +525,13 @@ public Iterator> iterator() { * This is identical to {@link #iterator} except that the SOA is returned at the end as well as * the beginning. */ - public Iterator> AXFR() { + public Iterator AXFR() { return new ZoneIterator(true); } private void nodeToString(StringBuffer sb, Object node) { RRset[] sets = allRRsets(node); - for (RRset rrset : sets) { + for (RRset rrset : sets) { rrset.rrs().forEach(r -> sb.append(r).append('\n')); rrset.sigs().forEach(r -> sb.append(r).append('\n')); } diff --git a/src/main/java/org/xbill/DNS/ZoneTransferIn.java b/src/main/java/org/xbill/DNS/ZoneTransferIn.java index 129de8e95..112c2ead9 100644 --- a/src/main/java/org/xbill/DNS/ZoneTransferIn.java +++ b/src/main/java/org/xbill/DNS/ZoneTransferIn.java @@ -94,31 +94,31 @@ private Delta() { public interface ZoneTransferHandler { /** Called when an AXFR transfer begins. */ - void startAXFR(); + void startAXFR() throws ZoneTransferException; /** Called when an IXFR transfer begins. */ - void startIXFR(); + void startIXFR() throws ZoneTransferException; /** * Called when a series of IXFR deletions begins. * * @param soa The starting SOA. */ - void startIXFRDeletes(Record soa); + void startIXFRDeletes(Record soa) throws ZoneTransferException; /** * Called when a series of IXFR adds begins. * * @param soa The starting SOA. */ - void startIXFRAdds(Record soa); + void startIXFRAdds(Record soa) throws ZoneTransferException; /** * Called for each content record in an AXFR. * * @param r The DNS record. */ - void handleRecord(Record r); + void handleRecord(Record r) throws ZoneTransferException; } private static class BasicHandler implements ZoneTransferHandler { @@ -507,8 +507,7 @@ private void doxfr() throws IOException, ZoneTransferException { } } - Record[] answers = response.getSectionArray(Section.ANSWER); - + List answers = response.getSection(Section.ANSWER); if (state == INITIALSOA) { int rcode = response.getRcode(); if (rcode != Rcode.NOERROR) { @@ -525,7 +524,7 @@ private void doxfr() throws IOException, ZoneTransferException { fail("invalid question section"); } - if (answers.length == 0 && qtype == Type.IXFR) { + if (answers.isEmpty() && qtype == Type.IXFR) { fallback(); doxfr(); return; diff --git a/src/main/java/org/xbill/DNS/tools/dig.java b/src/main/java/org/xbill/DNS/tools/dig.java index 5cca9dfb2..a7fc18766 100644 --- a/src/main/java/org/xbill/DNS/tools/dig.java +++ b/src/main/java/org/xbill/DNS/tools/dig.java @@ -48,8 +48,7 @@ static void doAXFR(Message response) { return; } - Record[] records = response.getSectionArray(Section.ANSWER); - for (Record record : records) { + for (Record record : response.getSection(Section.ANSWER)) { System.out.println(record); } diff --git a/src/main/java/org/xbill/DNS/tools/jnamed.java b/src/main/java/org/xbill/DNS/tools/jnamed.java index c2f680101..b56e68abc 100644 --- a/src/main/java/org/xbill/DNS/tools/jnamed.java +++ b/src/main/java/org/xbill/DNS/tools/jnamed.java @@ -20,7 +20,6 @@ import java.util.List; import java.util.Map; import java.util.StringTokenizer; -import org.xbill.DNS.ARecord; import org.xbill.DNS.Address; import org.xbill.DNS.CNAMERecord; import org.xbill.DNS.Cache; @@ -31,7 +30,6 @@ import org.xbill.DNS.Flags; import org.xbill.DNS.Header; import org.xbill.DNS.Message; -import org.xbill.DNS.NSRecord; import org.xbill.DNS.Name; import org.xbill.DNS.NameTooLongException; import org.xbill.DNS.OPTRecord; @@ -198,12 +196,12 @@ public Zone findBestZone(Name name) { return null; } - public RRset findExactMatch(Name name, int type, int dclass, boolean glue) { + public RRset findExactMatch(Name name, int type, int dclass, boolean glue) { Zone zone = findBestZone(name); if (zone != null) { return zone.findExactMatch(name, type); } else { - List> rrsets; + List rrsets; Cache cache = getCache(dclass); if (glue) { rrsets = cache.findAnyRecords(name, type); @@ -219,7 +217,7 @@ public RRset findExactMatch(Name name, int type, int dclas } void addRRset( - Name name, Message response, RRset rrset, int section, int flags) { + Name name, Message response, RRset rrset, int section, int flags) { for (int s = 1; s <= section; s++) { if (response.findRRset(name, rrset.getType(), s)) { return; @@ -248,7 +246,7 @@ private void addSOA(Message response, Zone zone) { } private void addNS(Message response, Zone zone, int flags) { - RRset nsRecords = zone.getNS(); + RRset nsRecords = zone.getNS(); addRRset(nsRecords.getName(), response, nsRecords, Section.AUTHORITY, flags); } @@ -257,14 +255,14 @@ private void addCacheNS(Message response, Cache cache, Name name) { if (!sr.isDelegation()) { return; } - RRset nsRecords = sr.getNS(); + RRset nsRecords = sr.getNS(); for (Record r : nsRecords.rrs()) { response.addRecord(r, Section.AUTHORITY); } } private void addGlue(Message response, Name name, int flags) { - RRset a = findExactMatch(name, Type.A, DClass.IN, true); + RRset a = findExactMatch(name, Type.A, DClass.IN, true); if (a == null) { return; } @@ -272,8 +270,7 @@ private void addGlue(Message response, Name name, int flags) { } private void addAdditional2(Message response, int section, int flags) { - Record[] records = response.getSectionArray(section); - for (Record r : records) { + for (Record r : response.getSection(section)) { Name glueName = r.getAdditionalName(); if (glueName != null) { addGlue(response, glueName, flags); @@ -327,11 +324,11 @@ byte addAnswer(Message response, Name name, int type, int dclass, int iterations } } } else if (sr.isDelegation()) { - RRset nsRecords = sr.getNS(); + RRset nsRecords = sr.getNS(); addRRset(nsRecords.getName(), response, nsRecords, Section.AUTHORITY, flags); } else if (sr.isCNAME()) { CNAMERecord cname = sr.getCNAME(); - RRset rrset = new RRset<>(cname); + RRset rrset = new RRset(cname); addRRset(name, response, rrset, Section.ANSWER, flags); if (zone != null && iterations == 0) { response.getHeader().setFlag(Flags.AA); @@ -339,7 +336,7 @@ byte addAnswer(Message response, Name name, int type, int dclass, int iterations rcode = addAnswer(response, cname.getTarget(), type, dclass, iterations + 1, flags); } else if (sr.isDNAME()) { DNAMERecord dname = sr.getDNAME(); - RRset rrset = new RRset<>(dname); + RRset rrset = new RRset(dname); addRRset(name, response, rrset, Section.ANSWER, flags); Name newname; try { @@ -349,15 +346,15 @@ byte addAnswer(Message response, Name name, int type, int dclass, int iterations } CNAMERecord cname = new CNAMERecord(name, dclass, 0, newname); - RRset cnamerrset = new RRset<>(cname); + RRset cnamerrset = new RRset(cname); addRRset(name, response, cnamerrset, Section.ANSWER, flags); if (zone != null && iterations == 0) { response.getHeader().setFlag(Flags.AA); } rcode = addAnswer(response, newname, type, dclass, iterations + 1, flags); } else if (sr.isSuccessful()) { - List> rrsets = sr.answers(); - for (RRset rrset : rrsets) { + List rrsets = sr.answers(); + for (RRset rrset : rrsets) { addRRset(name, response, rrset, Section.ANSWER, flags); } if (zone != null) { @@ -382,9 +379,9 @@ byte[] doAXFR(Name name, Message query, TSIG tsig, TSIGRecord qtsig, Socket s) { DataOutputStream dataOut; dataOut = new DataOutputStream(s.getOutputStream()); int id = query.getHeader().getID(); - Iterator> it = zone.AXFR(); + Iterator it = zone.AXFR(); while (it.hasNext()) { - RRset rrset = it.next(); + RRset rrset = it.next(); Message response = new Message(id); Header header = response.getHeader(); header.setFlag(Flags.QR); diff --git a/src/main/java/org/xbill/DNS/tools/primary.java b/src/main/java/org/xbill/DNS/tools/primary.java index ab303e619..87858d33c 100644 --- a/src/main/java/org/xbill/DNS/tools/primary.java +++ b/src/main/java/org/xbill/DNS/tools/primary.java @@ -46,12 +46,12 @@ public static void main(String[] args) throws Exception { Zone zone = new Zone(origin, file); long end = System.currentTimeMillis(); if (axfr) { - Iterator> it = zone.AXFR(); + Iterator it = zone.AXFR(); while (it.hasNext()) { System.out.println(it.next()); } } else if (iterator) { - Iterator> it = zone.iterator(); + Iterator it = zone.iterator(); while (it.hasNext()) { System.out.println(it.next()); } diff --git a/src/main/java/org/xbill/DNS/tools/update.java b/src/main/java/org/xbill/DNS/tools/update.java index 76efcf1b4..3fc51c583 100644 --- a/src/main/java/org/xbill/DNS/tools/update.java +++ b/src/main/java/org/xbill/DNS/tools/update.java @@ -220,7 +220,7 @@ public update(InputStream in) { doLog(st); break; case "assert": - if (doAssert(st) == false) { + if (!doAssert(st)) { return; } break; @@ -267,8 +267,7 @@ void sendUpdate() throws IOException { updzone = zone; int dclass = defaultClass; if (updzone == null) { - Record[] recs = query.getSectionArray(Section.UPDATE); - for (Record rec : recs) { + for (Record rec : query.getSection(Section.UPDATE)) { if (updzone == null) { updzone = new Name(rec.getName(), 1); } @@ -297,7 +296,6 @@ Record parseRR(Tokenizer st, int classValue, long TTLValue) throws IOException { Name name = st.getName(zone); long ttl; int type; - Record record; String s = st.getString(); @@ -317,12 +315,7 @@ Record parseRR(Tokenizer st, int classValue, long TTLValue) throws IOException { throw new IOException("Invalid type: " + s); } - record = Record.fromString(name, type, classValue, ttl, st, zone); - if (record != null) { - return (record); - } else { - throw new IOException("Parse error"); - } + return Record.fromString(name, type, classValue, ttl, st, zone); } void doRequire(Tokenizer st) throws IOException { @@ -496,11 +489,11 @@ boolean doAssert(Tokenizer st) throws IOException { flag = false; } } else if (field.equalsIgnoreCase("serial")) { - Record[] answers = response.getSectionArray(Section.ANSWER); - if (answers.length < 1 || !(answers[0] instanceof SOARecord)) { + List answers = response.getSection(Section.ANSWER); + if (answers.isEmpty() || !(answers.get(0) instanceof SOARecord)) { print("Invalid response (no SOA)"); } else { - SOARecord soa = (SOARecord) answers[0]; + SOARecord soa = (SOARecord) answers.get(0); long serial = soa.getSerial(); if (serial != Long.parseLong(expected)) { value = Long.toString(serial); diff --git a/src/test/java/org/xbill/DNS/DNSSECTest.java b/src/test/java/org/xbill/DNS/DNSSECTest.java index d400a99d1..a79754a06 100644 --- a/src/test/java/org/xbill/DNS/DNSSECTest.java +++ b/src/test/java/org/xbill/DNS/DNSSECTest.java @@ -30,7 +30,7 @@ void testECDSALeadingZeroUndersize() throws IOException, DNSSECException { "TXT 13 0 3600 19700101000003 19700101000000 46271 . dRwMEthIeGiucMcEcDmwixM8/LZcZ+W6lMM0KDSY5rwAGrm1j7tS/VU6xs+rpD5dSRmBYosinkWD6Jk3zRmyBQ==", Name.root); - RRset rrset = new RRset<>(); + RRset rrset = new RRset(); rrset.addRR(txt); rrset.addRR(rrsig); DNSSEC.verify(rrset, rrsig, dnskey, Instant.ofEpochMilli(60)); @@ -57,7 +57,7 @@ void testECDSALeadingZeroOversize() throws IOException, DNSSECException { "TXT 13 0 3600 19700101000003 19700101000000 25719 . m6sD/b0ZbfBXsQruhq5dYTnHGaA+PRTL5Y1W36rMdnGBb7eOJRRzDS5Wk5hZlrS4RUKQ/tKMCn7lsl9fn4U2lw==", Name.root); - RRset rrset = new RRset<>(); + RRset rrset = new RRset(); rrset.addRR(txt); rrset.addRR(rrsig); DNSSEC.verify(rrset, rrsig, dnskey, Instant.ofEpochMilli(60)); @@ -84,7 +84,7 @@ void testDSALeadingZeroUndersize() throws DNSSECException, IOException { "TXT 3 0 3600 19700101000003 19700101000000 36714 . AAAycZeIdBGB7vjlFzd5+ZgV8IxGRLpLierdV1KO4SGIy707hKUXJRc=", Name.root); - RRset set = new RRset<>(); + RRset set = new RRset(); set.addRR(txt); set.addRR(rrsig); DNSSEC.verify(set, rrsig, dnskey, Instant.ofEpochMilli(60)); @@ -111,7 +111,7 @@ void testDSALeadingZeroOversize() throws DNSSECException, IOException { "TXT 3 0 3600 19700101000003 19700101000000 57407 . AIh8Bp0EFNszs3cB0gNatjWy8tBrgUAUe1gTHkVsm1pva1GYWOW/FbA=", Name.root); - RRset set = new RRset<>(); + RRset set = new RRset(); set.addRR(txt); set.addRR(rrsig); DNSSEC.verify(set, rrsig, dnskey, Instant.ofEpochMilli(60)); diff --git a/src/test/java/org/xbill/DNS/MessageTest.java b/src/test/java/org/xbill/DNS/MessageTest.java index 0684eb3fd..71453ea32 100644 --- a/src/test/java/org/xbill/DNS/MessageTest.java +++ b/src/test/java/org/xbill/DNS/MessageTest.java @@ -34,7 +34,6 @@ // package org.xbill.DNS; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -42,6 +41,7 @@ import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.List; import org.junit.jupiter.api.Test; public class MessageTest { @@ -49,11 +49,11 @@ static class Test_init { @Test void ctor_0arg() { Message m = new Message(); - assertArrayEquals(new Record[0], m.getSectionArray(0)); - assertArrayEquals(new Record[0], m.getSectionArray(1)); - assertArrayEquals(new Record[0], m.getSectionArray(3)); - assertArrayEquals(new Record[0], m.getSectionArray(2)); - assertThrows(IndexOutOfBoundsException.class, () -> m.getSectionArray(4)); + assertTrue(m.getSection(0).isEmpty()); + assertTrue(m.getSection(1).isEmpty()); + assertTrue(m.getSection(3).isEmpty()); + assertTrue(m.getSection(2).isEmpty()); + assertThrows(IndexOutOfBoundsException.class, () -> m.getSection(4)); Header h = m.getHeader(); assertEquals(0, h.getCount(0)); assertEquals(0, h.getCount(1)); @@ -65,11 +65,11 @@ void ctor_0arg() { void ctor_1arg() { Message m = new Message(10); assertEquals(new Header(10).toString(), m.getHeader().toString()); - assertArrayEquals(new Record[0], m.getSectionArray(0)); - assertArrayEquals(new Record[0], m.getSectionArray(1)); - assertArrayEquals(new Record[0], m.getSectionArray(2)); - assertArrayEquals(new Record[0], m.getSectionArray(3)); - assertThrows(IndexOutOfBoundsException.class, () -> m.getSectionArray(4)); + assertTrue(m.getSection(0).isEmpty()); + assertTrue(m.getSection(1).isEmpty()); + assertTrue(m.getSection(2).isEmpty()); + assertTrue(m.getSection(3).isEmpty()); + assertThrows(IndexOutOfBoundsException.class, () -> m.getSection(4)); Header h = m.getHeader(); assertEquals(0, h.getCount(0)); assertEquals(0, h.getCount(1)); @@ -83,10 +83,11 @@ void newQuery() throws TextParseException, UnknownHostException { ARecord ar = new ARecord(n, DClass.IN, 1, InetAddress.getByName("192.168.101.110")); Message m = Message.newQuery(ar); - assertArrayEquals(new Record[] {ar}, m.getSectionArray(0)); - assertArrayEquals(new Record[0], m.getSectionArray(1)); - assertArrayEquals(new Record[0], m.getSectionArray(2)); - assertArrayEquals(new Record[0], m.getSectionArray(3)); + assertEquals(1, m.getSection(0).size()); + assertEquals(ar, m.getSection(0).get(0)); + assertTrue(m.getSection(1).isEmpty()); + assertTrue(m.getSection(2).isEmpty()); + assertTrue(m.getSection(3).isEmpty()); Header h = m.getHeader(); assertEquals(1, h.getCount(0)); @@ -117,10 +118,10 @@ void sectionToWire() throws IOException { byte[] binary = m.toWire(512); Message m2 = new Message(binary); assertEquals(2, m2.getHeader().getCount(Section.ADDITIONAL)); - Record[] records = m2.getSectionArray(Section.ADDITIONAL); - assertEquals(2, records.length); - assertEquals(TXTRecord.class, records[0].getClass()); - assertEquals(OPTRecord.class, records[1].getClass()); + List records = m2.getSection(Section.ADDITIONAL); + assertEquals(2, records.size()); + assertEquals(TXTRecord.class, records.get(0).getClass()); + assertEquals(OPTRecord.class, records.get(1).getClass()); } } } diff --git a/src/test/java/org/xbill/DNS/RRsetTest.java b/src/test/java/org/xbill/DNS/RRsetTest.java index ce157286d..9df970e25 100644 --- a/src/test/java/org/xbill/DNS/RRsetTest.java +++ b/src/test/java/org/xbill/DNS/RRsetTest.java @@ -47,7 +47,7 @@ import org.junit.jupiter.api.Test; class RRsetTest { - private RRset m_rs; + private RRset m_rs; private Name m_name; private Name m_name2; private long m_ttl; @@ -58,7 +58,7 @@ class RRsetTest { @BeforeEach void setUp() throws TextParseException, UnknownHostException { - m_rs = new RRset<>(); + m_rs = new RRset(); m_name = Name.fromString("this.is.a.test."); m_name2 = Name.fromString("this.is.another.test."); m_ttl = 0xABCDL; @@ -104,7 +104,7 @@ void ctor_0arg() { assertEquals("{empty}", m_rs.toString()); - List rrs = m_rs.rrs(); + List rrs = m_rs.rrs(); assertNotNull(rrs); assertEquals(0, rrs.size()); @@ -144,7 +144,7 @@ void basics() { assertEquals(m_ttl, m_rs.getTTL()); assertEquals(Type.A, m_rs.getType()); - List itr = m_rs.rrs(); + List itr = m_rs.rrs(); assertEquals(m_a1, itr.get(0)); assertEquals(m_a2, itr.get(1)); @@ -201,11 +201,11 @@ void ctor_1arg() { m_rs.addRR(m_s1); m_rs.addRR(m_s2); - RRset rs2 = new RRset<>(m_rs); + RRset rs2 = new RRset(m_rs); assertEquals(2, rs2.size()); assertEquals(m_a1, rs2.first()); - List itr = rs2.rrs(); + List itr = rs2.rrs(); assertEquals(m_a1, itr.get(0)); assertEquals(m_a2, itr.get(1)); assertEquals(2, itr.size()); @@ -231,7 +231,6 @@ void test_toString() { assertTrue(out.contains("[192.169.232.12]")); } - @SuppressWarnings("unchecked") @Test void addRR_invalidType() throws TextParseException { m_rs.addRR(m_a1); @@ -277,7 +276,7 @@ void Record_placement() { m_rs.addRR(m_s1); m_rs.addRR(m_a2); - List itr = m_rs.rrs(); + List itr = m_rs.rrs(); assertEquals(m_a1, itr.get(0)); assertEquals(m_a2, itr.get(1)); assertEquals(2, itr.size()); @@ -292,7 +291,7 @@ void noncycling_iterator() { m_rs.addRR(m_a1); m_rs.addRR(m_a2); - List itr = m_rs.rrs(false); + List itr = m_rs.rrs(false); assertEquals(m_a1, itr.get(0)); assertEquals(m_a2, itr.get(1)); diff --git a/src/test/java/org/xbill/DNS/SetResponseTest.java b/src/test/java/org/xbill/DNS/SetResponseTest.java index dc3bbf52a..1bb4f9022 100644 --- a/src/test/java/org/xbill/DNS/SetResponseTest.java +++ b/src/test/java/org/xbill/DNS/SetResponseTest.java @@ -174,7 +174,7 @@ void ofType_toobig() { @Test void addRRset() throws TextParseException, UnknownHostException { - RRset rrs = new RRset<>(); + RRset rrs = new RRset(); rrs.addRR( new ARecord( Name.fromString("The.Name."), DClass.IN, 0xABCD, InetAddress.getByName("192.168.0.1"))); @@ -190,7 +190,7 @@ void addRRset() throws TextParseException, UnknownHostException { @Test void addRRset_multiple() throws TextParseException, UnknownHostException { - RRset rrs = new RRset<>(); + RRset rrs = new RRset(); rrs.addRR( new ARecord( Name.fromString("The.Name."), DClass.IN, 0xABCD, InetAddress.getByName("192.168.0.1"))); @@ -198,7 +198,7 @@ void addRRset_multiple() throws TextParseException, UnknownHostException { new ARecord( Name.fromString("The.Name."), DClass.IN, 0xABCD, InetAddress.getByName("192.168.0.2"))); - RRset rrs2 = new RRset<>(); + RRset rrs2 = new RRset(); rrs2.addRR( new ARecord( Name.fromString("The.Other.Name."), @@ -228,7 +228,7 @@ void answers_nonSUCCESSFUL() { @Test void getCNAME() throws TextParseException { - RRset rrs = new RRset<>(); + RRset rrs = new RRset(); CNAMERecord cr = new CNAMERecord( Name.fromString("The.Name."), DClass.IN, 0xABCD, Name.fromString("The.Alias.")); @@ -239,7 +239,7 @@ void getCNAME() throws TextParseException { @Test void getDNAME() throws TextParseException { - RRset rrs = new RRset<>(); + RRset rrs = new RRset(); DNAMERecord dr = new DNAMERecord( Name.fromString("The.Name."), DClass.IN, 0xABCD, Name.fromString("The.Alias.")); @@ -260,7 +260,7 @@ void test_toString() throws TextParseException, UnknownHostException { SetResponse.DNAME, SetResponse.SUCCESSFUL }; - RRset rrs = new RRset<>(); + RRset rrs = new RRset(); rrs.addRR( new ARecord( Name.fromString("The.Name."), DClass.IN, 0xABCD, InetAddress.getByName("192.168.0.1"))); From a0d77d26604efc8a11f6004e969a6e9e77d53a01 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 18:58:52 +0100 Subject: [PATCH 030/431] Update EDNS client subnet option from draft to RFC 7871 --- .../org/xbill/DNS/ClientSubnetOption.java | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ClientSubnetOption.java b/src/main/java/org/xbill/DNS/ClientSubnetOption.java index 2bc8dda8a..2bd0431c8 100644 --- a/src/main/java/org/xbill/DNS/ClientSubnetOption.java +++ b/src/main/java/org/xbill/DNS/ClientSubnetOption.java @@ -6,16 +6,15 @@ import java.net.UnknownHostException; /** - * The Client Subnet EDNS Option, defined in - * http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-00 ("Client subnet in DNS - * requests"). + * The Client Subnet EDNS Option, defined in Address.addressLength(family) * 8) { + sourcePrefixLength = in.readU8(); + if (sourcePrefixLength > Address.addressLength(family) * 8) { throw new WireParseException("invalid source netmask"); } - scopeNetmask = in.readU8(); - if (scopeNetmask > Address.addressLength(family) * 8) { + scopePrefixLength = in.readU8(); + if (scopePrefixLength > Address.addressLength(family) * 8) { throw new WireParseException("invalid scope netmask"); } // Read the truncated address byte[] addr = in.readByteArray(); - if (addr.length != (sourceNetmask + 7) / 8) { + if (addr.length != (sourcePrefixLength + 7) / 8) { throw new WireParseException("invalid address"); } @@ -134,7 +130,7 @@ void optionFromWire(DNSInput in) throws WireParseException { throw new WireParseException("invalid address", e); } - InetAddress tmp = Address.truncate(address, sourceNetmask); + InetAddress tmp = Address.truncate(address, sourcePrefixLength); if (!tmp.equals(address)) { throw new WireParseException("invalid padding"); } @@ -143,9 +139,9 @@ void optionFromWire(DNSInput in) throws WireParseException { @Override void optionToWire(DNSOutput out) { out.writeU16(family); - out.writeU8(sourceNetmask); - out.writeU8(scopeNetmask); - out.writeByteArray(address.getAddress(), 0, (sourceNetmask + 7) / 8); + out.writeU8(sourcePrefixLength); + out.writeU8(scopePrefixLength); + out.writeByteArray(address.getAddress(), 0, (sourcePrefixLength + 7) / 8); } @Override @@ -153,9 +149,9 @@ String optionToString() { StringBuilder sb = new StringBuilder(); sb.append(address.getHostAddress()); sb.append("/"); - sb.append(sourceNetmask); + sb.append(sourcePrefixLength); sb.append(", scope netmask "); - sb.append(scopeNetmask); + sb.append(scopePrefixLength); return sb.toString(); } } From a9b0dee3ebb174358804c83c2b0d40a4747700c2 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 19:09:27 +0100 Subject: [PATCH 031/431] Generify Name.compareTo --- src/main/java/org/xbill/DNS/Name.java | 20 ++++++-------------- src/test/java/org/xbill/DNS/NameTest.java | 12 ------------ 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Name.java b/src/main/java/org/xbill/DNS/Name.java index 566f4b33f..d4220ce8c 100644 --- a/src/main/java/org/xbill/DNS/Name.java +++ b/src/main/java/org/xbill/DNS/Name.java @@ -13,7 +13,7 @@ * @author Brian Wellington */ @Slf4j -public class Name implements Comparable, Serializable { +public class Name implements Comparable, Serializable { private static final long serialVersionUID = -7257019940971525644L; @@ -800,13 +800,7 @@ public boolean equals(Object arg) { return false; } Name d = (Name) arg; - if (d.hashcode == 0) { - d.hashCode(); - } - if (hashcode == 0) { - hashCode(); - } - if (d.hashcode != hashcode) { + if (d.hashCode() != hashCode()) { return false; } if (d.labels() != labels()) { @@ -819,7 +813,7 @@ public boolean equals(Object arg) { @Override public int hashCode() { if (hashcode != 0) { - return (hashcode); + return hashcode; } int code = 0; for (int i = offset(0); i < name.length; i++) { @@ -832,23 +826,21 @@ public int hashCode() { /** * Compares this Name to another Object. * - * @param o The Object to be compared. + * @param arg The name to be compared. * @return The value 0 if the argument is a name equivalent to this name; a value less than 0 if * the argument is less than this name in the canonical ordering, and a value greater than 0 * if the argument is greater than this name in the canonical ordering. * @throws ClassCastException if the argument is not a Name. */ @Override - public int compareTo(Object o) { - Name arg = (Name) o; - + public int compareTo(Name arg) { if (this == arg) { return (0); } int labels = labels(); int alabels = arg.labels(); - int compares = labels > alabels ? alabels : labels; + int compares = Math.min(labels, alabels); for (int i = 1; i <= compares; i++) { int start = offset(labels - i); diff --git a/src/test/java/org/xbill/DNS/NameTest.java b/src/test/java/org/xbill/DNS/NameTest.java index 4215f872e..7aeff8c7c 100644 --- a/src/test/java/org/xbill/DNS/NameTest.java +++ b/src/test/java/org/xbill/DNS/NameTest.java @@ -1443,18 +1443,6 @@ void weird() throws TextParseException { } static class Test_compareTo { - @Test - void notName() throws TextParseException { - Name n = new Name("A.Name"); - assertThrows(ClassCastException.class, () -> n.compareTo(new Object())); - } - - @Test - void same() throws TextParseException { - Name n = new Name("A.Name"); - assertEquals(0, n.compareTo(n)); - } - @Test void equal() throws TextParseException { Name n1 = new Name("A.Name."); From f15086907d1f9fa98beea1a6c97225ef8d0f7d92 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 20:00:50 +0100 Subject: [PATCH 032/431] Remove Optional<> from parameter/field --- src/main/java/org/xbill/DNS/CookieOption.java | 24 +++++++++---------- .../java/org/xbill/DNS/CookieOptionTest.java | 17 ++++++------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/xbill/DNS/CookieOption.java b/src/main/java/org/xbill/DNS/CookieOption.java index 2c91db29b..e062df404 100644 --- a/src/main/java/org/xbill/DNS/CookieOption.java +++ b/src/main/java/org/xbill/DNS/CookieOption.java @@ -16,7 +16,7 @@ public class CookieOption extends EDNSOption { private byte[] clientCookie; /** server cookie */ - private Optional serverCookie; + private byte[] serverCookie; /** Default constructor for constructing instance from binary representation. */ CookieOption() { @@ -29,7 +29,7 @@ public class CookieOption extends EDNSOption { * @param clientCookie the client cookie, which must consist of eight bytes */ public CookieOption(byte[] clientCookie) { - this(clientCookie, Optional.empty()); + this(clientCookie, null); } /** @@ -38,15 +38,15 @@ public CookieOption(byte[] clientCookie) { * @param clientCookie the client cookie, which must consist of eight bytes * @param serverCookie the server cookie, which must consist of 8 to 32 bytes if present */ - public CookieOption(byte[] clientCookie, Optional serverCookie) { + public CookieOption(byte[] clientCookie, byte[] serverCookie) { this(); if (clientCookie == null) throw new IllegalArgumentException("client cookie must not be null"); if (clientCookie.length != 8) throw new IllegalArgumentException("client cookie must consist of eight bytes"); this.clientCookie = clientCookie; - if (serverCookie.isPresent()) { - int length = serverCookie.get().length; + if (serverCookie != null) { + int length = serverCookie.length; if (length < 8 || length > 32) throw new IllegalArgumentException("server cookie must consist of 8 to 32 bytes"); } @@ -68,7 +68,7 @@ public byte[] getClientCookie() { * @return the server cookie */ public Optional getServerCookie() { - return serverCookie; + return Optional.ofNullable(serverCookie); } /** @@ -85,9 +85,7 @@ void optionFromWire(DNSInput in) throws IOException { if (length > 8) { if (length < 16 || length > 40) throw new WireParseException("invalid length of server cookie"); - serverCookie = Optional.of(in.readByteArray()); - } else { - serverCookie = Optional.empty(); + serverCookie = in.readByteArray(); } } @@ -99,7 +97,9 @@ void optionFromWire(DNSInput in) throws IOException { @Override void optionToWire(DNSOutput out) { out.writeByteArray(clientCookie); - if (serverCookie.isPresent()) out.writeByteArray(serverCookie.get()); + if (serverCookie != null) { + out.writeByteArray(serverCookie); + } } /** @@ -109,8 +109,8 @@ void optionToWire(DNSOutput out) { */ @Override String optionToString() { - return serverCookie.isPresent() - ? base16.toString(clientCookie) + " " + base16.toString(serverCookie.get()) + return serverCookie != null + ? base16.toString(clientCookie) + " " + base16.toString(serverCookie) : base16.toString(clientCookie); } } diff --git a/src/test/java/org/xbill/DNS/CookieOptionTest.java b/src/test/java/org/xbill/DNS/CookieOptionTest.java index a774b4306..716471e98 100644 --- a/src/test/java/org/xbill/DNS/CookieOptionTest.java +++ b/src/test/java/org/xbill/DNS/CookieOptionTest.java @@ -28,30 +28,27 @@ void constructorTests() { CookieOption option = new CookieOption(eightBytes); assertArrayEquals(eightBytes, option.getClientCookie()); assertFalse(option.getServerCookie().isPresent()); - new CookieOption(eightBytes, Optional.empty()); + new CookieOption(eightBytes, null); - option = new CookieOption(eightBytes, Optional.empty()); + option = new CookieOption(eightBytes, null); assertArrayEquals(eightBytes, option.getClientCookie()); assertFalse(option.getServerCookie().isPresent()); - option = new CookieOption(eightBytes, Optional.of(eightBytes2)); + option = new CookieOption(eightBytes, eightBytes2); Optional serverCookie = option.getServerCookie(); assertTrue(serverCookie.isPresent()); assertArrayEquals(eightBytes2, serverCookie.get()); - option = new CookieOption(eightBytes, Optional.of(thirtyTwoBytes)); + option = new CookieOption(eightBytes, thirtyTwoBytes); serverCookie = option.getServerCookie(); assertTrue(serverCookie.isPresent()); assertArrayEquals(thirtyTwoBytes, serverCookie.get()); assertThrows(IllegalArgumentException.class, () -> new CookieOption(sevenBytes)); assertThrows(IllegalArgumentException.class, () -> new CookieOption(nineBytes)); + assertThrows(IllegalArgumentException.class, () -> new CookieOption(eightBytes, sevenBytes)); assertThrows( - IllegalArgumentException.class, - () -> new CookieOption(eightBytes, Optional.of(sevenBytes))); - assertThrows( - IllegalArgumentException.class, - () -> new CookieOption(eightBytes, Optional.of(thirtyThreeBytes))); + IllegalArgumentException.class, () -> new CookieOption(eightBytes, thirtyThreeBytes)); } @Test @@ -99,7 +96,7 @@ void wireTests() throws IOException { cookieOption = new CookieOption(clientCookie1); assertArrayEquals(clientOnlyCookieOption, cookieOption.toWire()); - cookieOption = new CookieOption(clientCookie2, Optional.of(serverCookie2)); + cookieOption = new CookieOption(clientCookie2, serverCookie2); assertArrayEquals(clientServerCookieOption, cookieOption.toWire()); } } From d311ac0c09c61c3330b13688644536fa26dfe22f Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 20:04:50 +0100 Subject: [PATCH 033/431] Add all RFC-defined EDNS options registered at IANA --- src/main/java/org/xbill/DNS/EDNSOption.java | 53 +++++++++++++++------ 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/xbill/DNS/EDNSOption.java b/src/main/java/org/xbill/DNS/EDNSOption.java index b1ca55936..f90f3b646 100644 --- a/src/main/java/org/xbill/DNS/EDNSOption.java +++ b/src/main/java/org/xbill/DNS/EDNSOption.java @@ -5,7 +5,7 @@ import java.util.Arrays; /** - * DNS extension options, as described in RFC 2671. The rdata of an OPT record is defined as a list + * DNS extension options, as described in RFC 6891. The rdata of an OPT record is defined as a list * of options; this represents a single option. * * @author Brian Wellington @@ -13,22 +13,48 @@ */ public abstract class EDNSOption { + /** + * @see IANA + * DNS EDNS0 Option Codes (OPT) + */ public static class Code { private Code() {} /** Name Server Identifier, RFC 5001 */ public static final int NSID = 3; - /** Client Subnet, defined in draft-vandergaast-edns-client-subnet-02 */ + /** DNSSEC Algorithm Understood (DAU), RFC 6975 */ + public static final int DAU = 5; + + /** DNSSEC DS Hash Understood (DHU), RFC 6975 */ + public static final int DHU = 6; + + /** DNSSEC NSEC3 Hash Understood (N3U), RFC 6975 */ + public static final int N3U = 7; + + /** Client Subnet, RFC 7871 */ public static final int CLIENT_SUBNET = 8; + /** (EDNS) EXPIRE Option, RFC 7314 */ + public static final int EDNS_EXPIRE = 9; + /** Cookie, RFC 7873 */ public static final int COOKIE = 10; /** TCP Keepalive, RFC 7828 */ public static final int TCP_KEEPALIVE = 11; - private static Mnemonic codes = new Mnemonic("EDNS Option Codes", Mnemonic.CASE_UPPER); + /** EDNS(0) Padding Option, RFC 7830 */ + public static final int PADDING = 12; + + /** CHAIN Query Requests in DNS, RFC 7901 */ + public static final int CHAIN = 13; + + /** Signaling Trust Anchor Knowledge in DNS Security Extensions (DNSSEC), RFC 8145 */ + public static final int EDNS_KEY_TAG = 14; + + private static Mnemonic codes = new Mnemonic("EDNS Option Codes", Mnemonic.CASE_SENSITIVE); static { codes.setMaximum(0xFFFF); @@ -36,9 +62,16 @@ private Code() {} codes.setNumericAllowed(true); codes.add(NSID, "NSID"); - codes.add(CLIENT_SUBNET, "CLIENT_SUBNET"); + codes.add(DAU, "DAU"); + codes.add(DHU, "DHU"); + codes.add(N3U, "N3U"); + codes.add(CLIENT_SUBNET, "edns-client-subnet"); + codes.add(EDNS_EXPIRE, "EDNS_EXPIRE"); codes.add(COOKIE, "COOKIE"); - codes.add(TCP_KEEPALIVE, "TCP_KEEPALIVE"); + codes.add(TCP_KEEPALIVE, "edns-tcp-keepalive"); + codes.add(PADDING, "Padding"); + codes.add(CHAIN, "CHAIN"); + codes.add(EDNS_KEY_TAG, "edns-key-tag"); } /** Converts an EDNS Option Code into its textual representation */ @@ -66,15 +99,7 @@ public EDNSOption(int code) { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - - sb.append("{"); - sb.append(EDNSOption.Code.string(code)); - sb.append(": "); - sb.append(optionToString()); - sb.append("}"); - - return sb.toString(); + return "{" + Code.string(code) + ": " + optionToString() + "}"; } /** From 18280e0ca035da0bd1b31c9dff390650a196eb82 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 20:05:39 +0100 Subject: [PATCH 034/431] Add DNSSEC algorithm understood EDNS codes from RFC 6975 --- .../org/xbill/DNS/DnssecAlgorithmOption.java | 68 +++++++++++++++++ src/main/java/org/xbill/DNS/EDNSOption.java | 5 ++ .../xbill/DNS/DnssecAlgorithmOptionTest.java | 73 +++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 src/main/java/org/xbill/DNS/DnssecAlgorithmOption.java create mode 100644 src/test/java/org/xbill/DNS/DnssecAlgorithmOptionTest.java diff --git a/src/main/java/org/xbill/DNS/DnssecAlgorithmOption.java b/src/main/java/org/xbill/DNS/DnssecAlgorithmOption.java new file mode 100644 index 000000000..6da195c92 --- /dev/null +++ b/src/main/java/org/xbill/DNS/DnssecAlgorithmOption.java @@ -0,0 +1,68 @@ +package org.xbill.DNS; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import org.xbill.DNS.DNSSEC.Algorithm; + +/** + * The EDNS0 Option for Signaling Cryptographic Algorithm Understanding in DNS Security Extensions + * (DNSSEC), RFC 6975. + */ +public class DnssecAlgorithmOption extends EDNSOption { + private List algCodes; + + private DnssecAlgorithmOption(int code) { + super(code); + switch (code) { + case Code.DAU: + case Code.DHU: + case Code.N3U: + break; + default: + throw new IllegalArgumentException("Invalid option code, must be one of DAU, DHU, N3U"); + } + algCodes = new ArrayList<>(); + } + + public DnssecAlgorithmOption(int code, List algCodes) { + this(code); + this.algCodes.addAll(algCodes); + } + + public DnssecAlgorithmOption(int code, int... algCodes) { + this(code); + if (algCodes != null) { + for (int algCode : algCodes) { + this.algCodes.add(algCode); + } + } + } + + public List getAlgorithms() { + return Collections.unmodifiableList(algCodes); + } + + @Override + void optionFromWire(DNSInput in) throws IOException { + algCodes.clear(); + while (in.remaining() > 0) { + algCodes.add(in.readU8()); + } + } + + @Override + void optionToWire(DNSOutput out) { + algCodes.forEach(out::writeU8); + } + + @Override + String optionToString() { + return Code.string(getCode()) + + ": [" + + algCodes.stream().map(Algorithm::string).collect(Collectors.joining(", ")) + + "]"; + } +} diff --git a/src/main/java/org/xbill/DNS/EDNSOption.java b/src/main/java/org/xbill/DNS/EDNSOption.java index f90f3b646..315272cd4 100644 --- a/src/main/java/org/xbill/DNS/EDNSOption.java +++ b/src/main/java/org/xbill/DNS/EDNSOption.java @@ -154,6 +154,11 @@ static EDNSOption fromWire(DNSInput in) throws IOException { case Code.CLIENT_SUBNET: option = new ClientSubnetOption(); break; + case Code.DAU: + case Code.DHU: + case Code.N3U: + option = new DnssecAlgorithmOption(code); + break; case Code.COOKIE: option = new CookieOption(); break; diff --git a/src/test/java/org/xbill/DNS/DnssecAlgorithmOptionTest.java b/src/test/java/org/xbill/DNS/DnssecAlgorithmOptionTest.java new file mode 100644 index 000000000..be8d7ab99 --- /dev/null +++ b/src/test/java/org/xbill/DNS/DnssecAlgorithmOptionTest.java @@ -0,0 +1,73 @@ +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.Collections; +import org.junit.jupiter.api.Test; +import org.xbill.DNS.DNSSEC.Algorithm; +import org.xbill.DNS.EDNSOption.Code; + +public class DnssecAlgorithmOptionTest { + @Test + void ctor() { + new DnssecAlgorithmOption(Code.DAU); + new DnssecAlgorithmOption(Code.DHU); + new DnssecAlgorithmOption(Code.N3U); + + assertThrows(IllegalArgumentException.class, () -> new DnssecAlgorithmOption(4)); + assertThrows(IllegalArgumentException.class, () -> new DnssecAlgorithmOption(8)); + } + + @Test + void ctorOptionsEmpty() { + DnssecAlgorithmOption o = new DnssecAlgorithmOption(Code.DAU); + assertTrue(o.getAlgorithms().isEmpty()); + } + + @Test + void ctorOptionsList() { + DnssecAlgorithmOption o = + new DnssecAlgorithmOption(Code.DAU, Collections.singletonList(Algorithm.RSASHA1)); + assertEquals(1, o.getAlgorithms().size()); + } + + @Test + void ctorOptionsVarargs() { + DnssecAlgorithmOption o = new DnssecAlgorithmOption(Code.DAU, Algorithm.RSASHA1); + assertEquals(1, o.getAlgorithms().size()); + } + + @Test + void ctorOptionsVarargsNull() { + DnssecAlgorithmOption o = new DnssecAlgorithmOption(Code.DAU, (int[]) null); + assertTrue(o.getAlgorithms().isEmpty()); + } + + @Test + void parse() throws IOException { + DNSInput in = new DNSInput(new byte[] {0, 5, 0, 2, 5, 6}); + DnssecAlgorithmOption o = (DnssecAlgorithmOption) EDNSOption.fromWire(in); + assertEquals(Algorithm.RSASHA1, o.getAlgorithms().get(0)); + assertEquals(Algorithm.DSA_NSEC3_SHA1, o.getAlgorithms().get(1)); + } + + @Test + void write() { + DnssecAlgorithmOption o = + new DnssecAlgorithmOption(Code.DAU, Algorithm.RSASHA1, Algorithm.DSA_NSEC3_SHA1); + DNSOutput out = new DNSOutput(); + o.toWire(out); + assertArrayEquals(new byte[] {0, 5, 0, 2, 5, 6}, out.toByteArray()); + } + + @Test + void testToString() { + DnssecAlgorithmOption o = + new DnssecAlgorithmOption(Code.DAU, Algorithm.RSASHA1, Algorithm.DSA_NSEC3_SHA1); + assertEquals("DAU: [RSASHA1, DSA-NSEC3-SHA1]", o.optionToString()); + } +} From 5b75ac8b420314f7fde5fc070b1d1976836fc0a5 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 20:06:36 +0100 Subject: [PATCH 035/431] Rename EDNS level to version to be in line with RFC 6891 --- src/main/java/org/xbill/DNS/ExtendedResolver.java | 4 ++-- src/main/java/org/xbill/DNS/Resolver.java | 10 +++++----- src/main/java/org/xbill/DNS/SimpleResolver.java | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index 4e6c2c005..fce58d0a0 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -239,9 +239,9 @@ public void setEDNS(int level) { } @Override - public void setEDNS(int level, int payloadSize, int flags, List options) { + public void setEDNS(int version, int payloadSize, int flags, List options) { for (ResolverEntry re : resolvers) { - re.resolver.setEDNS(level, payloadSize, flags, options); + re.resolver.setEDNS(version, payloadSize, flags, options); } } diff --git a/src/main/java/org/xbill/DNS/Resolver.java b/src/main/java/org/xbill/DNS/Resolver.java index ae17a427a..191b1beed 100644 --- a/src/main/java/org/xbill/DNS/Resolver.java +++ b/src/main/java/org/xbill/DNS/Resolver.java @@ -53,7 +53,7 @@ public interface Resolver { /** * Sets the EDNS information on outgoing messages. * - * @param level The EDNS level to use. 0 indicates EDNS0 and -1 indicates no EDNS. + * @param version The EDNS version to use. 0 indicates EDNS0 and -1 indicates no EDNS. * @param payloadSize The maximum DNS packet size that this host is capable of receiving over UDP. * If 0 is specified, the default (1280) is used. * @param flags EDNS extended flags to be set in the OPT record. @@ -62,12 +62,12 @@ public interface Resolver { * @throws IllegalArgumentException An invalid field was specified. * @see OPTRecord */ - void setEDNS(int level, int payloadSize, int flags, List options); + void setEDNS(int version, int payloadSize, int flags, List options); /** * Sets the EDNS information on outgoing messages. * - * @param level The EDNS level to use. 0 indicates EDNS0 and -1 indicates no EDNS. + * @param version The EDNS version to use. 0 indicates EDNS0 and -1 indicates no EDNS. * @param payloadSize The maximum DNS packet size that this host is capable of receiving over UDP. * If 0 is specified, the default (1280) is used. * @param flags EDNS extended flags to be set in the OPT record. @@ -76,8 +76,8 @@ public interface Resolver { * @throws IllegalArgumentException An invalid field was specified. * @see OPTRecord */ - default void setEDNS(int level, int payloadSize, int flags, EDNSOption... options) { - setEDNS(level, payloadSize, flags, Arrays.asList(options)); + default void setEDNS(int version, int payloadSize, int flags, EDNSOption... options) { + setEDNS(version, payloadSize, flags, Arrays.asList(options)); } /** diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index 151b53eba..37629d3c5 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -162,14 +162,14 @@ public void setIgnoreTruncation(boolean flag) { } @Override - public void setEDNS(int level, int payloadSize, int flags, List options) { - if (level != 0 && level != -1) { - throw new IllegalArgumentException("invalid EDNS level - must be 0 or -1"); + public void setEDNS(int version, int payloadSize, int flags, List options) { + if (version != 0 && version != -1) { + throw new IllegalArgumentException("invalid EDNS version - must be 0 or -1"); } if (payloadSize == 0) { payloadSize = DEFAULT_EDNS_PAYLOADSIZE; } - queryOPT = new OPTRecord(payloadSize, 0, level, flags, options); + queryOPT = new OPTRecord(payloadSize, 0, version, flags, options); } @Override From a2b3062f979ef13c57d6c6a380525a35ba9cd0c3 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 20:10:18 +0100 Subject: [PATCH 036/431] Enable EDNS by default, disable with version -1 --- .../java/org/xbill/DNS/SimpleResolver.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index 37629d3c5..ddc6175ff 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -34,7 +34,7 @@ public class SimpleResolver implements Resolver { private InetSocketAddress address; private InetSocketAddress localAddress; private boolean useTCP, ignoreTruncation; - private OPTRecord queryOPT; + private OPTRecord queryOPT = new OPTRecord(DEFAULT_EDNS_PAYLOADSIZE, 0, 0, 0); private TSIG tsig; private Duration timeoutValue = Duration.ofSeconds(10); @@ -163,13 +163,21 @@ public void setIgnoreTruncation(boolean flag) { @Override public void setEDNS(int version, int payloadSize, int flags, List options) { - if (version != 0 && version != -1) { - throw new IllegalArgumentException("invalid EDNS version - must be 0 or -1"); + switch (version) { + case -1: + queryOPT = null; + break; + + case 0: + if (payloadSize == 0) { + payloadSize = DEFAULT_EDNS_PAYLOADSIZE; + } + queryOPT = new OPTRecord(payloadSize, 0, version, flags, options); + break; + + default: + throw new IllegalArgumentException("invalid EDNS version - must be 0 or -1 to disable"); } - if (payloadSize == 0) { - payloadSize = DEFAULT_EDNS_PAYLOADSIZE; - } - queryOPT = new OPTRecord(payloadSize, 0, version, flags, options); } @Override From ca26ba58d9558ee1ac372536a816cb0abb186105 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 20:10:34 +0100 Subject: [PATCH 037/431] Migrate iterator to foreach --- src/main/java/org/xbill/DNS/Zone.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Zone.java b/src/main/java/org/xbill/DNS/Zone.java index 180ee26db..8a8875054 100644 --- a/src/main/java/org/xbill/DNS/Zone.java +++ b/src/main/java/org/xbill/DNS/Zone.java @@ -539,11 +539,9 @@ private void nodeToString(StringBuffer sb, Object node) { /** Returns the contents of the Zone in master file format. */ public synchronized String toMasterFile() { - Iterator zentries = data.entrySet().iterator(); StringBuffer sb = new StringBuffer(); nodeToString(sb, originNode); - while (zentries.hasNext()) { - Map.Entry entry = (Map.Entry) zentries.next(); + for (Map.Entry entry : data.entrySet()) { if (!origin.equals(entry.getKey())) { nodeToString(sb, entry.getValue()); } From 1e04b41f0de0d72b03fe30f8f727620473373a62 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 20:27:49 +0100 Subject: [PATCH 038/431] Avoid 0 as serial since it is illegal Closes #44 Closes #46 --- src/main/java/org/xbill/DNS/Serial.java | 8 +++++--- src/test/java/org/xbill/DNS/SerialTest.java | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Serial.java b/src/main/java/org/xbill/DNS/Serial.java index 633297d12..e2d2b1d73 100644 --- a/src/main/java/org/xbill/DNS/Serial.java +++ b/src/main/java/org/xbill/DNS/Serial.java @@ -4,7 +4,8 @@ /** * Helper functions for doing serial arithmetic. These should be used when setting/checking SOA - * serial numbers. SOA serial number arithmetic is defined in RFC 1982. + * serial numbers. SOA serial number arithmetic is defined in RFC 1982 and also referenced in RFC + * 2136. * * @author Brian Wellington */ @@ -42,7 +43,8 @@ public static int compare(long serial1, long serial2) { /** * Increments a serial number. The number is assumed to be a 32 bit unsigned integer stored in a - * long. This basically adds 1 and resets the value to 0 if it is 2^32. + * long. This basically adds 1 and resets the value to 1 if it is 2^32. A zero value is explicitly + * forbidden as per * RFC 2136 section 4.2 & 7.11. * * @param serial The serial number * @return The incremented serial number @@ -53,7 +55,7 @@ public static long increment(long serial) { throw new IllegalArgumentException(serial + " out of range"); } if (serial == MAX32) { - return 0; + return 1; } return serial + 1; } diff --git a/src/test/java/org/xbill/DNS/SerialTest.java b/src/test/java/org/xbill/DNS/SerialTest.java index 428569cda..718065b51 100644 --- a/src/test/java/org/xbill/DNS/SerialTest.java +++ b/src/test/java/org/xbill/DNS/SerialTest.java @@ -119,7 +119,7 @@ void increment_OOBArg() { void increment_reset() { long arg = 0xFFFFFFFFL; long ret = Serial.increment(arg); - assertEquals(0, ret); + assertEquals(1, ret); } @Test From 913e1e00625bbf28d450d70421867dde3a852e51 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 20:39:01 +0100 Subject: [PATCH 039/431] Remove code duplication between TLSA and SMIME records Closes #53 --- .../org/xbill/DNS/DnssecAlgorithmOption.java | 1 + src/main/java/org/xbill/DNS/SMIMEARecord.java | 121 ++---------------- src/main/java/org/xbill/DNS/TLSARecord.java | 34 ++++- .../xbill/DNS/DnssecAlgorithmOptionTest.java | 1 + 4 files changed, 44 insertions(+), 113 deletions(-) diff --git a/src/main/java/org/xbill/DNS/DnssecAlgorithmOption.java b/src/main/java/org/xbill/DNS/DnssecAlgorithmOption.java index 6da195c92..133c7b28c 100644 --- a/src/main/java/org/xbill/DNS/DnssecAlgorithmOption.java +++ b/src/main/java/org/xbill/DNS/DnssecAlgorithmOption.java @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: BSD-2-Clause package org.xbill.DNS; import java.io.IOException; diff --git a/src/main/java/org/xbill/DNS/SMIMEARecord.java b/src/main/java/org/xbill/DNS/SMIMEARecord.java index debd80e82..ed2020640 100644 --- a/src/main/java/org/xbill/DNS/SMIMEARecord.java +++ b/src/main/java/org/xbill/DNS/SMIMEARecord.java @@ -2,9 +2,6 @@ package org.xbill.DNS; -import java.io.IOException; -import org.xbill.DNS.utils.base16; - /** * S/MIME cert association * @@ -12,49 +9,7 @@ * Certificates with Domain Names for S/MIME * @author Brian Wellington */ -public class SMIMEARecord extends Record { - - private static final long serialVersionUID = 1640247915216425235L; - - // Note; these are copied from the TLSA type. - - public static class CertificateUsage { - private CertificateUsage() {} - - public static final int CA_CONSTRAINT = 0; - public static final int SERVICE_CERTIFICATE_CONSTRAINT = 1; - public static final int TRUST_ANCHOR_ASSERTION = 2; - public static final int DOMAIN_ISSUED_CERTIFICATE = 3; - } - - public static class Selector { - private Selector() {} - - /** Full certificate; the Certificate binary structure defined in [RFC5280] */ - public static final int FULL_CERTIFICATE = 0; - - /** SubjectPublicKeyInfo; DER-encoded binary structure defined in [RFC5280] */ - public static final int SUBJECT_PUBLIC_KEY_INFO = 1; - } - - public static class MatchingType { - private MatchingType() {} - - /** Exact match on selected content */ - public static final int EXACT = 0; - - /** SHA-256 hash of selected content [RFC6234] */ - public static final int SHA256 = 1; - - /** SHA-512 hash of selected content [RFC6234] */ - public static final int SHA512 = 2; - } - - private int certificateUsage; - private int selector; - private int matchingType; - private byte[] certificateAssociationData; - +public class SMIMEARecord extends TLSARecord { SMIMEARecord() {} @Override @@ -80,70 +35,14 @@ public SMIMEARecord( int selector, int matchingType, byte[] certificateAssociationData) { - super(name, Type.SMIMEA, dclass, ttl); - this.certificateUsage = checkU8("certificateUsage", certificateUsage); - this.selector = checkU8("selector", selector); - this.matchingType = checkU8("matchingType", matchingType); - this.certificateAssociationData = - checkByteArrayLength("certificateAssociationData", certificateAssociationData, 0xFFFF); - } - - @Override - void rrFromWire(DNSInput in) throws IOException { - certificateUsage = in.readU8(); - selector = in.readU8(); - matchingType = in.readU8(); - certificateAssociationData = in.readByteArray(); - } - - @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { - certificateUsage = st.getUInt8(); - selector = st.getUInt8(); - matchingType = st.getUInt8(); - certificateAssociationData = st.getHex(); - } - - /** Converts rdata to a String */ - @Override - String rrToString() { - StringBuilder sb = new StringBuilder(); - sb.append(certificateUsage); - sb.append(" "); - sb.append(selector); - sb.append(" "); - sb.append(matchingType); - sb.append(" "); - sb.append(base16.toString(certificateAssociationData)); - - return sb.toString(); - } - - @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { - out.writeU8(certificateUsage); - out.writeU8(selector); - out.writeU8(matchingType); - out.writeByteArray(certificateAssociationData); - } - - /** Returns the certificate usage of the SMIMEA record */ - public int getCertificateUsage() { - return certificateUsage; - } - - /** Returns the selector of the SMIMEA record */ - public int getSelector() { - return selector; - } - - /** Returns the matching type of the SMIMEA record */ - public int getMatchingType() { - return matchingType; - } - - /** Returns the certificate associate data of this SMIMEA record */ - public final byte[] getCertificateAssociationData() { - return certificateAssociationData; + super( + name, + Type.SMIMEA, + dclass, + ttl, + certificateUsage, + selector, + matchingType, + certificateAssociationData); } } diff --git a/src/main/java/org/xbill/DNS/TLSARecord.java b/src/main/java/org/xbill/DNS/TLSARecord.java index 5799aa424..fff6cea6d 100644 --- a/src/main/java/org/xbill/DNS/TLSARecord.java +++ b/src/main/java/org/xbill/DNS/TLSARecord.java @@ -70,15 +70,16 @@ Record getObject() { * @param matchingType How the certificate association is presented. * @param certificateAssociationData The "certificate association data" to be matched. */ - public TLSARecord( + protected TLSARecord( Name name, + int type, int dclass, long ttl, int certificateUsage, int selector, int matchingType, byte[] certificateAssociationData) { - super(name, Type.TLSA, dclass, ttl); + super(name, type, dclass, ttl); this.certificateUsage = checkU8("certificateUsage", certificateUsage); this.selector = checkU8("selector", selector); this.matchingType = checkU8("matchingType", matchingType); @@ -86,6 +87,35 @@ public TLSARecord( checkByteArrayLength("certificateAssociationData", certificateAssociationData, 0xFFFF); } + /** + * Creates an TLSA Record from the given data + * + * @param certificateUsage The provided association that will be used to match the certificate + * presented in the TLS handshake. + * @param selector The part of the TLS certificate presented by the server that will be matched + * against the association data. + * @param matchingType How the certificate association is presented. + * @param certificateAssociationData The "certificate association data" to be matched. + */ + public TLSARecord( + Name name, + int dclass, + long ttl, + int certificateUsage, + int selector, + int matchingType, + byte[] certificateAssociationData) { + this( + name, + Type.TLSA, + dclass, + ttl, + certificateUsage, + selector, + matchingType, + certificateAssociationData); + } + @Override void rrFromWire(DNSInput in) throws IOException { certificateUsage = in.readU8(); diff --git a/src/test/java/org/xbill/DNS/DnssecAlgorithmOptionTest.java b/src/test/java/org/xbill/DNS/DnssecAlgorithmOptionTest.java index be8d7ab99..9a1f69893 100644 --- a/src/test/java/org/xbill/DNS/DnssecAlgorithmOptionTest.java +++ b/src/test/java/org/xbill/DNS/DnssecAlgorithmOptionTest.java @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: BSD-2-Clause package org.xbill.DNS; import static org.junit.jupiter.api.Assertions.assertArrayEquals; From 17225fb8647a5076bc65faad059ac234e1132965 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 20:42:58 +0100 Subject: [PATCH 040/431] Use strong crypto for message ID The race condition in #24 is worked around in 01bdcde9c5e by avoiding to query for localhost. And the SPI is gone in Java 9+. Closes #24 --- src/main/java/org/xbill/DNS/Header.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/Header.java b/src/main/java/org/xbill/DNS/Header.java index c3a3ae242..3344e77b7 100644 --- a/src/main/java/org/xbill/DNS/Header.java +++ b/src/main/java/org/xbill/DNS/Header.java @@ -3,6 +3,7 @@ package org.xbill.DNS; import java.io.IOException; +import java.security.SecureRandom; import java.util.Random; import lombok.SneakyThrows; @@ -18,7 +19,7 @@ public class Header implements Cloneable { private int flags; private int[] counts; - private static final Random random = new Random(); + private static final Random random = new SecureRandom(); /** The length of a DNS Header in wire format. */ public static final int LENGTH = 12; From 437b0879828564069d9692a4f18de08b32e1fbcf Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Dec 2019 20:51:24 +0100 Subject: [PATCH 041/431] Expose control over Lookup result ordering Closes #87 --- src/main/java/org/xbill/DNS/Lookup.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index 1dd89dcfd..6385ecfbe 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -58,6 +58,7 @@ public final class Lookup { private boolean timedout; private boolean nametoolong; private boolean referral; + private boolean cycleResults = true; private static final Name[] noAliases = new Name[0]; @@ -404,6 +405,16 @@ public void setCredibility(int credibility) { this.credibility = credibility; } + /** + * Controls the behavior if results being returned from the cache should be cycled in a + * round-robin style (true) or if the raw lookup results should be returned (false). + * + * @param cycleResults The desired behavior of the order of the results + */ + public void setCycleResults(boolean cycleResults) { + this.cycleResults = cycleResults; + } + private void follow(Name name, Name oldname) { foundAlias = true; badresponse = false; @@ -431,7 +442,7 @@ private void processResponse(Name name, SetResponse response) { List l = new ArrayList<>(); for (RRset set : rrsets) { - l.addAll(set.rrs()); + l.addAll(set.rrs(cycleResults)); } result = SUCCESSFUL; From 84ba76a974ff95d541a7f8cad9b4d507caaa375f Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 25 Dec 2019 14:57:39 +0100 Subject: [PATCH 042/431] Continue parsing when includes are silently disabled --- src/main/java/org/xbill/DNS/Master.java | 5 ++- src/test/java/org/xbill/DNS/MasterTest.java | 38 +++++++++++++++++++ .../resources/zonefileIncludeDirectiveComment | 1 + 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/zonefileIncludeDirectiveComment diff --git a/src/main/java/org/xbill/DNS/Master.java b/src/main/java/org/xbill/DNS/Master.java index 7b9095e1f..b5a23f03c 100644 --- a/src/main/java/org/xbill/DNS/Master.java +++ b/src/main/java/org/xbill/DNS/Master.java @@ -324,8 +324,11 @@ private Record _nextRecord() throws IOException { if (includeThrowsException) { throw st.exception("$INCLUDE encountered, but processing disabled in strict mode"); } + st.getString(); + st.getEOL(); continue; } + String filename = st.getString(); File newfile; if (file != null) { @@ -399,7 +402,7 @@ public Record nextRecord() throws IOException { } /** - * Disable processing of $INCLUDE directives. When disabled, $INCUDE statements will not be + * Disable processing of $INCLUDE directives. When disabled, $INCLUDE statements will not be * processed. Depending on the contents of the file that would have been included, this may cause * the zone to be invalid. (e.g. if there is no SOA or NS at the apex) */ diff --git a/src/test/java/org/xbill/DNS/MasterTest.java b/src/test/java/org/xbill/DNS/MasterTest.java index c44335a18..19b720be0 100644 --- a/src/test/java/org/xbill/DNS/MasterTest.java +++ b/src/test/java/org/xbill/DNS/MasterTest.java @@ -62,6 +62,44 @@ void includeDirective() throws IOException, URISyntaxException { } } + @Test + void includeDirectiveComment() throws IOException, URISyntaxException { + try (Master master = + new Master( + Paths.get(MasterTest.class.getResource("/zonefileIncludeDirectiveComment").toURI()) + .toString())) { + Record rr = master.nextRecord(); + assertEquals(Type.SOA, rr.getType()); + } + } + + @Test + void includeDirectiveDisabled() throws IOException { + try (InputStream is = MasterTest.class.getResourceAsStream("/zonefileIncludeDirective"); + Master m = new Master(is)) { + m.disableIncludes(); + assertNull(m.nextRecord()); + } + } + + @Test + void includeDirectiveDisabledStrict() throws IOException { + try (InputStream is = MasterTest.class.getResourceAsStream("/zonefileIncludeDirective"); + Master m = new Master(is)) { + m.disableIncludes(true); + assertThrows(TextParseException.class, m::nextRecord); + } + } + + @Test + void includeDirectiveDisabledComment() throws IOException { + try (InputStream is = MasterTest.class.getResourceAsStream("/zonefileIncludeDirectiveComment"); + Master m = new Master(is)) { + m.disableIncludes(); + assertNull(m.nextRecord()); + } + } + @Test void expandGenerated() throws IOException { try (Master master = new Master(MasterTest.class.getResourceAsStream("/zonefileEx1"))) { diff --git a/src/test/resources/zonefileIncludeDirectiveComment b/src/test/resources/zonefileIncludeDirectiveComment new file mode 100644 index 000000000..b2f78580a --- /dev/null +++ b/src/test/resources/zonefileIncludeDirectiveComment @@ -0,0 +1 @@ +$INCLUDE zonefileEx1 ; include another zone file From 6bce0f7f1ba6d25df7fbb53f64bf3f948c0732ec Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 25 Dec 2019 14:58:17 +0100 Subject: [PATCH 043/431] Allow absolute paths in $INCLUDE directives Closes #75 --- src/main/java/org/xbill/DNS/Master.java | 20 +++++++++++--------- src/test/java/org/xbill/DNS/MasterTest.java | 8 ++++++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Master.java b/src/main/java/org/xbill/DNS/Master.java index b5a23f03c..2d8b01a62 100644 --- a/src/main/java/org/xbill/DNS/Master.java +++ b/src/main/java/org/xbill/DNS/Master.java @@ -330,20 +330,22 @@ private Record _nextRecord() throws IOException { } String filename = st.getString(); - File newfile; - if (file != null) { - String parent = file.getParent(); - newfile = new File(parent, filename); - } else { - newfile = new File(filename); + File includeFile = new File(filename); + if (!includeFile.isAbsolute()) { + if (file != null) { + includeFile = new File(file.getParent(), filename); + } else { + throw st.exception("Cannot $INCLUDE using relative path when parsing from stream"); + } } - Name incorigin = origin; + + Name includeOrigin = origin; token = st.get(); if (token.isString()) { - incorigin = parseName(token.value, Name.root); + includeOrigin = parseName(token.value, Name.root); st.getEOL(); } - included = new Master(newfile, incorigin, defaultTTL); + included = new Master(includeFile, includeOrigin, defaultTTL); /* * If we continued, we wouldn't be looking in * the new file. Recursing works better. diff --git a/src/test/java/org/xbill/DNS/MasterTest.java b/src/test/java/org/xbill/DNS/MasterTest.java index 19b720be0..5790bfc32 100644 --- a/src/test/java/org/xbill/DNS/MasterTest.java +++ b/src/test/java/org/xbill/DNS/MasterTest.java @@ -73,6 +73,14 @@ void includeDirectiveComment() throws IOException, URISyntaxException { } } + @Test + void relativeIncludeDirectiveViaStream() throws IOException { + try (InputStream is = MasterTest.class.getResourceAsStream("/zonefileIncludeDirective"); + Master m = new Master(is)) { + assertThrows(TextParseException.class, m::nextRecord); + } + } + @Test void includeDirectiveDisabled() throws IOException { try (InputStream is = MasterTest.class.getResourceAsStream("/zonefileIncludeDirective"); From 0b83cd05f6e13420322ebbff407ceef3db2caf8f Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 25 Dec 2019 17:50:42 +0100 Subject: [PATCH 044/431] Implement HIP RR (RFC 8005) Closes #47 --- src/main/java/org/xbill/DNS/DNSSEC.java | 41 +++-- src/main/java/org/xbill/DNS/HIPRecord.java | 163 ++++++++++++++++++ .../java/org/xbill/DNS/IPSECKEYRecord.java | 23 +++ src/main/java/org/xbill/DNS/Type.java | 4 + .../java/org/xbill/DNS/HIPRecordTest.java | 146 ++++++++++++++++ 5 files changed, 358 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/xbill/DNS/HIPRecord.java create mode 100644 src/test/java/org/xbill/DNS/HIPRecordTest.java diff --git a/src/main/java/org/xbill/DNS/DNSSEC.java b/src/main/java/org/xbill/DNS/DNSSEC.java index 9a5665f76..68e70c2fc 100644 --- a/src/main/java/org/xbill/DNS/DNSSEC.java +++ b/src/main/java/org/xbill/DNS/DNSSEC.java @@ -223,11 +223,11 @@ public static class UnsupportedAlgorithmException extends DNSSECException { /** The cryptographic data in a DNSSEC key is malformed. */ public static class MalformedKeyException extends DNSSECException { - MalformedKeyException(KEYBase rec) { - super("Invalid key data: " + rec.rdataToString()); + MalformedKeyException(String message) { + super(message); } - MalformedKeyException(KEYBase rec, Throwable cause) { + MalformedKeyException(Record rec, Throwable cause) { super("Invalid key data: " + rec.rdataToString(), cause); } } @@ -392,8 +392,8 @@ private static void writePaddedBigIntegerLittleEndian(DNSOutput out, BigInteger } } - private static PublicKey toRSAPublicKey(KEYBase r) throws IOException, GeneralSecurityException { - DNSInput in = new DNSInput(r.getKey()); + private static PublicKey toRSAPublicKey(byte[] key) throws IOException, GeneralSecurityException { + DNSInput in = new DNSInput(key); int exponentLength = in.readU8(); if (exponentLength == 0) { exponentLength = in.readU16(); @@ -405,13 +405,13 @@ private static PublicKey toRSAPublicKey(KEYBase r) throws IOException, GeneralSe return factory.generatePublic(new RSAPublicKeySpec(modulus, exponent)); } - private static PublicKey toDSAPublicKey(KEYBase r) + private static PublicKey toDSAPublicKey(byte[] key) throws IOException, GeneralSecurityException, MalformedKeyException { - DNSInput in = new DNSInput(r.getKey()); + DNSInput in = new DNSInput(key); int t = in.readU8(); if (t > 8) { - throw new MalformedKeyException(r); + throw new MalformedKeyException("t is too large"); } BigInteger q = readBigInteger(in, 20); @@ -482,9 +482,9 @@ private static class ECKeyInfo { "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"); - private static PublicKey toECGOSTPublicKey(KEYBase r, ECKeyInfo keyinfo) + private static PublicKey toECGOSTPublicKey(byte[] key, ECKeyInfo keyinfo) throws IOException, GeneralSecurityException { - DNSInput in = new DNSInput(r.getKey()); + DNSInput in = new DNSInput(key); BigInteger x = readBigIntegerLittleEndian(in, keyinfo.length); BigInteger y = readBigIntegerLittleEndian(in, keyinfo.length); @@ -494,9 +494,9 @@ private static PublicKey toECGOSTPublicKey(KEYBase r, ECKeyInfo keyinfo) return factory.generatePublic(new ECPublicKeySpec(q, keyinfo.spec)); } - private static PublicKey toECDSAPublicKey(KEYBase r, ECKeyInfo keyinfo) + private static PublicKey toECDSAPublicKey(byte[] key, ECKeyInfo keyinfo) throws IOException, GeneralSecurityException { - DNSInput in = new DNSInput(r.getKey()); + DNSInput in = new DNSInput(key); // RFC 6605 Section 4 BigInteger x = readBigInteger(in, keyinfo.length); @@ -506,10 +506,13 @@ private static PublicKey toECDSAPublicKey(KEYBase r, ECKeyInfo keyinfo) KeyFactory factory = KeyFactory.getInstance("EC"); return factory.generatePublic(new ECPublicKeySpec(q, keyinfo.spec)); } - /** Converts a KEY/DNSKEY record into a PublicKey */ static PublicKey toPublicKey(KEYBase r) throws DNSSECException { - int alg = r.getAlgorithm(); + return toPublicKey(r.getAlgorithm(), r.getKey(), r); + } + + /** Converts a KEY/DNSKEY record into a PublicKey */ + static PublicKey toPublicKey(int alg, byte[] key, Record r) throws DNSSECException { try { switch (alg) { case Algorithm.RSAMD5: @@ -517,16 +520,16 @@ static PublicKey toPublicKey(KEYBase r) throws DNSSECException { case Algorithm.RSA_NSEC3_SHA1: case Algorithm.RSASHA256: case Algorithm.RSASHA512: - return toRSAPublicKey(r); + return toRSAPublicKey(key); case Algorithm.DSA: case Algorithm.DSA_NSEC3_SHA1: - return toDSAPublicKey(r); + return toDSAPublicKey(key); case Algorithm.ECC_GOST: - return toECGOSTPublicKey(r, GOST); + return toECGOSTPublicKey(key, GOST); case Algorithm.ECDSAP256SHA256: - return toECDSAPublicKey(r, ECDSA_P256); + return toECDSAPublicKey(key, ECDSA_P256); case Algorithm.ECDSAP384SHA384: - return toECDSAPublicKey(r, ECDSA_P384); + return toECDSAPublicKey(key, ECDSA_P384); default: throw new UnsupportedAlgorithmException(alg); } diff --git a/src/main/java/org/xbill/DNS/HIPRecord.java b/src/main/java/org/xbill/DNS/HIPRecord.java new file mode 100644 index 000000000..80f032ab0 --- /dev/null +++ b/src/main/java/org/xbill/DNS/HIPRecord.java @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import java.io.IOException; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import org.xbill.DNS.DNSSEC.DNSSECException; +import org.xbill.DNS.DNSSEC.UnsupportedAlgorithmException; +import org.xbill.DNS.IPSECKEYRecord.Algorithm; +import org.xbill.DNS.Tokenizer.Token; +import org.xbill.DNS.utils.base16; +import org.xbill.DNS.utils.base64; + +/** + * Host Identity Protocol (HIP) Record as defined in RFC 8005. + * + * @see IPSECKEYRecord.Algorithm for PK algorithm numbers + */ +public class HIPRecord extends Record { + private byte[] hit; + private int pkAlgorithm; + private byte[] publicKey; + private List rvServers = new ArrayList<>(); + + HIPRecord() {} + + @Override + Record getObject() { + return new HIPRecord(); + } + + public HIPRecord( + Name name, int dclass, long ttl, byte[] hit, int alg, byte[] key, List servers) { + super(name, Type.HIP, dclass, ttl); + this.hit = hit; + this.pkAlgorithm = alg; + this.publicKey = key; + if (servers != null) { + this.rvServers.addAll(servers); + } + } + + public HIPRecord(Name name, int dclass, long ttl, byte[] hit, int alg, byte[] key) { + this(name, dclass, ttl, hit, alg, key, null); + } + + public HIPRecord( + Name name, int dclass, long ttl, byte[] hit, int alg, PublicKey key, List servers) + throws DNSSECException { + this(name, dclass, ttl, hit, alg, DNSSEC.fromPublicKey(key, mapAlgTypeToDnssec(alg)), servers); + } + + public HIPRecord(Name name, int dclass, long ttl, byte[] hit, int alg, PublicKey key) + throws DNSSECException { + this(name, dclass, ttl, hit, alg, key, null); + } + + public byte[] getHit() { + return hit; + } + + /** + * Gets the PK algorithm number as defined in IPSECKEY + * Resource Record Parameters + * + * @see IPSECKEYRecord.Algorithm + */ + public int getAlgorithm() { + return pkAlgorithm; + } + + /** Gets the raw public key bytes. The format is defined by {@link #getAlgorithm()}. */ + public byte[] getKey() { + return publicKey; + } + + /** + * Gets the public key of this RR as a Java {@link PublicKey}. Only supported for RSA/DSA PK + * algorithm (ECDSA lacks the information about which curve is used). + */ + public PublicKey getPublicKey() throws DNSSECException { + return DNSSEC.toPublicKey(mapAlgTypeToDnssec(pkAlgorithm), publicKey, this); + } + + public List getRvServers() { + return Collections.unmodifiableList(rvServers); + } + + private static int mapAlgTypeToDnssec(int alg) throws UnsupportedAlgorithmException { + switch (alg) { + case Algorithm.DSA: + return DNSSEC.Algorithm.DSA; + case Algorithm.RSA: + return DNSSEC.Algorithm.RSASHA1; + case Algorithm.ECDSA: + default: + throw new UnsupportedAlgorithmException(alg); + } + } + + @Override + String rrToString() { + StringBuilder sb = new StringBuilder(); + if (Options.check("multiline")) { + sb.append("( "); + } + + String separator = Options.check("multiline") ? "\n\t" : " "; + sb.append(pkAlgorithm); + sb.append(" "); + sb.append(base16.toString(hit)); + sb.append(separator); + + sb.append(base64.toString(publicKey)); + if (!rvServers.isEmpty()) { + sb.append(separator); + } + + sb.append(rvServers.stream().map(Name::toString).collect(Collectors.joining(separator))); + if (Options.check("multiline")) { + sb.append(" )"); + } + + return sb.toString(); + } + + @Override + void rdataFromString(Tokenizer st, Name origin) throws IOException { + pkAlgorithm = st.getUInt8(); + hit = st.getHexString(); + publicKey = base64.fromString(st.getString()); + Token t; + while ((t = st.get()).isString()) { + rvServers.add(new Name(t.value)); + } + } + + @Override + void rrToWire(DNSOutput out, Compression c, boolean canonical) { + out.writeU8(hit.length); + out.writeU8(pkAlgorithm); + out.writeU16(publicKey.length); + out.writeByteArray(hit); + out.writeByteArray(publicKey); + rvServers.forEach(n -> n.toWire(out, null, canonical)); + } + + @Override + void rrFromWire(DNSInput in) throws IOException { + int hitLength = in.readU8(); + pkAlgorithm = in.readU8(); + int pkLength = in.readU16(); + hit = in.readByteArray(hitLength); + publicKey = in.readByteArray(pkLength); + while (in.remaining() > 0) { + rvServers.add(new Name(in)); + } + } +} diff --git a/src/main/java/org/xbill/DNS/IPSECKEYRecord.java b/src/main/java/org/xbill/DNS/IPSECKEYRecord.java index bf3f869e9..f5cf8b99f 100644 --- a/src/main/java/org/xbill/DNS/IPSECKEYRecord.java +++ b/src/main/java/org/xbill/DNS/IPSECKEYRecord.java @@ -18,19 +18,42 @@ public class IPSECKEYRecord extends Record { private static final long serialVersionUID = 3050449702765909687L; + /** + * Algorithm types for IPSECKEY RRs as defined in IPSECKEY + * Resource Record Parameters. + */ public static class Algorithm { private Algorithm() {} + /** A DSA key is present, in the format defined in [RFC2536] */ public static final int DSA = 1; + + /** A RSA key is present, in the format defined in [RFC3110] */ public static final int RSA = 2; + + /** An ECDSA key is present, in the format defined in [RFC6605] */ + public static final int ECDSA = 3; } + /** + * Gateway types for IPSECKEY RRs as defined in IPSECKEY + * Resource Record Parameters. + */ public static class Gateway { private Gateway() {} + /** No gateway is present */ public static final int None = 0; + + /** A 4-byte IPv4 address is present */ public static final int IPv4 = 1; + + /** A 16-byte IPv6 address is present */ public static final int IPv6 = 2; + + /** A wire-encoded domain name is present */ public static final int Name = 3; } diff --git a/src/main/java/org/xbill/DNS/Type.java b/src/main/java/org/xbill/DNS/Type.java index 25381c97c..3199caa95 100644 --- a/src/main/java/org/xbill/DNS/Type.java +++ b/src/main/java/org/xbill/DNS/Type.java @@ -177,6 +177,9 @@ public final class Type { /** {@link SMIMEARecord S/MIME cert association} */ public static final int SMIMEA = 53; + /** {@link HIPRecord Host Identity Protocol (HIP)} */ + public static final int HIP = 55; + /** {@link CDSRecord Child Delegation Signer} */ public static final int CDS = 59; @@ -299,6 +302,7 @@ public Record getProto(int val) { types.add(NSEC3PARAM, "NSEC3PARAM", new NSEC3PARAMRecord()); types.add(TLSA, "TLSA", new TLSARecord()); types.add(SMIMEA, "SMIMEA", new SMIMEARecord()); + types.add(HIP, "HIP", new HIPRecord()); types.add(CDNSKEY, "CDNSKEY", new CDNSKEYRecord()); types.add(CDS, "CDS", new CDSRecord()); types.add(OPENPGPKEY, "OPENPGPKEY", new OPENPGPKEYRecord()); diff --git a/src/test/java/org/xbill/DNS/HIPRecordTest.java b/src/test/java/org/xbill/DNS/HIPRecordTest.java new file mode 100644 index 000000000..a6a9cfb26 --- /dev/null +++ b/src/test/java/org/xbill/DNS/HIPRecordTest.java @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.xbill.DNS.DNSSEC.DNSSECException; +import org.xbill.DNS.IPSECKEYRecord.Algorithm; + +public class HIPRecordTest { + private Name exampleCom = Name.fromConstantString("www.example.com."); + private Name rvs = Name.fromConstantString("rvs.example.com."); + private Name rvs1 = Name.fromConstantString("rvs1.example.com."); + private Name rvs2 = Name.fromConstantString("rvs2.example.com."); + private List servers = new ArrayList<>(); + + @BeforeEach + void beforeEach() { + servers.add(rvs1); + servers.add(rvs2); + } + + @Test + void testRfcExample1() throws IOException, DNSSECException { + String example = + "www.example.com. IN HIP ( 2 200100107B1A74DF365639CC39F1D578\n" + + " AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D )"; + try (Master m = new Master(new ByteArrayInputStream(example.getBytes()), Name.root, 900)) { + HIPRecord hip = (HIPRecord) m.nextRecord(); + assertEquals(exampleCom, hip.getName()); + assertEquals(2, hip.getAlgorithm()); + PublicKey pk = hip.getPublicKey(); + assertTrue(pk instanceof RSAPublicKey); + assertEquals(0, hip.getRvServers().size()); + + DNSOutput out = new DNSOutput(); + hip.toWire(out, Section.ANSWER, null); + HIPRecord hip2 = (HIPRecord) Record.fromWire(out.toByteArray(), Section.ANSWER); + assertEquals(hip, hip2); + } + } + + @Test + void testRfcExample2() throws IOException, DNSSECException { + String example = + "www.example.com. IN HIP ( 2 200100107B1A74DF365639CC39F1D578\n" + + " AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D\n" + + " rvs.example.com. )"; + try (Master m = new Master(new ByteArrayInputStream(example.getBytes()), Name.root, 900)) { + HIPRecord hip = (HIPRecord) m.nextRecord(); + assertEquals(exampleCom, hip.getName()); + assertEquals(2, hip.getAlgorithm()); + PublicKey pk = hip.getPublicKey(); + assertTrue(pk instanceof RSAPublicKey); + assertEquals(1, hip.getRvServers().size()); + assertEquals(rvs, hip.getRvServers().get(0)); + + DNSOutput out = new DNSOutput(); + hip.toWire(out, Section.ANSWER, null); + HIPRecord hip2 = (HIPRecord) Record.fromWire(out.toByteArray(), Section.ANSWER); + assertEquals(hip, hip2); + } + } + + @Test + void testRfcExample3() throws IOException, DNSSECException { + String example = + "www.example.com. IN HIP ( 2 200100107B1A74DF365639CC39F1D578\n" + + " AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D\n" + + " rvs1.example.com.\n" + + " rvs2.example.com. )"; + try (Master m = new Master(new ByteArrayInputStream(example.getBytes()), Name.root, 900)) { + HIPRecord hip = (HIPRecord) m.nextRecord(); + assertEquals(exampleCom, hip.getName()); + assertEquals(2, hip.getAlgorithm()); + PublicKey pk = hip.getPublicKey(); + assertTrue(pk instanceof RSAPublicKey); + assertEquals(2, hip.getRvServers().size()); + assertEquals(rvs1, hip.getRvServers().get(0)); + assertEquals(rvs2, hip.getRvServers().get(1)); + + DNSOutput out = new DNSOutput(); + hip.toWire(out, Section.ANSWER, null); + HIPRecord hip2 = (HIPRecord) Record.fromWire(out.toByteArray(), Section.ANSWER); + assertEquals(hip, hip2); + } + } + + @Test + void testHipToString() { + Options.unset("multiline"); + HIPRecord hip = + new HIPRecord( + exampleCom, DClass.IN, 900, new byte[] {1, 2, 3}, Algorithm.RSA, new byte[] {1, 2, 3}); + assertEquals("2 010203 AQID", hip.rrToString()); + } + + @Test + void testHipToStringServers() { + Options.unset("multiline"); + HIPRecord hip = + new HIPRecord( + exampleCom, + DClass.IN, + 900, + new byte[] {1, 2, 3}, + Algorithm.RSA, + new byte[] {1, 2, 3}, + servers); + assertEquals("2 010203 AQID " + rvs1.toString() + " " + rvs2.toString(), hip.rrToString()); + } + + @Test + void testHipToStringMultiline() { + Options.set("multiline"); + HIPRecord hip = + new HIPRecord( + exampleCom, DClass.IN, 900, new byte[] {1, 2, 3}, Algorithm.RSA, new byte[] {1, 2, 3}); + assertEquals("( 2 010203\n\tAQID )", hip.rrToString()); + } + + @Test + void testHipToStringServersMultiline() { + Options.set("multiline"); + HIPRecord hip = + new HIPRecord( + exampleCom, + DClass.IN, + 900, + new byte[] {1, 2, 3}, + Algorithm.RSA, + new byte[] {1, 2, 3}, + servers); + assertEquals( + "( 2 010203\n\t" + "AQID\n\t" + rvs1.toString() + "\n\t" + rvs2.toString() + " )", + hip.rrToString()); + } +} From 22422b1e3042133cea5944e3dd36e92c05517c70 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 25 Dec 2019 18:34:56 +0100 Subject: [PATCH 045/431] Rename EDNS level to version to be in line with RFC 6891 Missed in 5b75ac8 --- src/main/java/org/xbill/DNS/ExtendedResolver.java | 4 ++-- src/main/java/org/xbill/DNS/Resolver.java | 4 ++-- src/main/java/org/xbill/DNS/SimpleResolver.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index fce58d0a0..6e186495e 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -232,9 +232,9 @@ public void setIgnoreTruncation(boolean flag) { } @Override - public void setEDNS(int level) { + public void setEDNS(int version) { for (ResolverEntry re : resolvers) { - re.resolver.setEDNS(level); + re.resolver.setEDNS(version); } } diff --git a/src/main/java/org/xbill/DNS/Resolver.java b/src/main/java/org/xbill/DNS/Resolver.java index 191b1beed..5c51660e1 100644 --- a/src/main/java/org/xbill/DNS/Resolver.java +++ b/src/main/java/org/xbill/DNS/Resolver.java @@ -45,10 +45,10 @@ public interface Resolver { /** * Sets the EDNS version used on outgoing messages. * - * @param level The EDNS level to use. 0 indicates EDNS0 and -1 indicates no EDNS. + * @param version The EDNS level to use. 0 indicates EDNS0 and -1 indicates no EDNS. * @throws IllegalArgumentException An invalid level was indicated. */ - void setEDNS(int level); + void setEDNS(int version); /** * Sets the EDNS information on outgoing messages. diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index ddc6175ff..ebd8ef26f 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -181,8 +181,8 @@ public void setEDNS(int version, int payloadSize, int flags, List op } @Override - public void setEDNS(int level) { - setEDNS(level, 0, 0); + public void setEDNS(int version) { + setEDNS(version, 0, 0); } @Override From fd73861b427ceee3745b41d87da589cb86b2017b Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 27 Dec 2019 15:35:03 +0100 Subject: [PATCH 046/431] Update dependencies, remove lombok from OSGi --- pom.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index b474963d3..4547390f9 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ UTF-8 1.8 5.4.2 + 1.7.30 @@ -95,6 +96,7 @@ !org.xbill.DNS*, !sun.*, + !lombok, android.*;resolution:=optional, javax.naming.*;resolution:=optional, com.sun.jna.*;resolution:=optional,* @@ -205,12 +207,12 @@ org.slf4j slf4j-api - 1.7.29 + ${slf4j.version} org.projectlombok lombok - 1.18.8 + 1.18.10 provided @@ -252,7 +254,7 @@ org.slf4j slf4j-simple - 1.7.29 + ${slf4j.version} test From 20f93da656e8dc87937c7418d508c33614fde2df Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 27 Dec 2019 15:36:31 +0100 Subject: [PATCH 047/431] Add default implementation for the basic EDNS version method --- src/main/java/org/xbill/DNS/ExtendedResolver.java | 7 ------- src/main/java/org/xbill/DNS/Resolver.java | 13 ++++++++++--- src/main/java/org/xbill/DNS/SimpleResolver.java | 9 --------- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index 6e186495e..630b016f5 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -231,13 +231,6 @@ public void setIgnoreTruncation(boolean flag) { } } - @Override - public void setEDNS(int version) { - for (ResolverEntry re : resolvers) { - re.resolver.setEDNS(version); - } - } - @Override public void setEDNS(int version, int payloadSize, int flags, List options) { for (ResolverEntry re : resolvers) { diff --git a/src/main/java/org/xbill/DNS/Resolver.java b/src/main/java/org/xbill/DNS/Resolver.java index 5c51660e1..5d0e368f8 100644 --- a/src/main/java/org/xbill/DNS/Resolver.java +++ b/src/main/java/org/xbill/DNS/Resolver.java @@ -6,6 +6,7 @@ import java.net.SocketTimeoutException; import java.time.Duration; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -48,14 +49,16 @@ public interface Resolver { * @param version The EDNS level to use. 0 indicates EDNS0 and -1 indicates no EDNS. * @throws IllegalArgumentException An invalid level was indicated. */ - void setEDNS(int version); + default void setEDNS(int version) { + setEDNS(version, 0, 0, Collections.emptyList()); + } /** * Sets the EDNS information on outgoing messages. * * @param version The EDNS version to use. 0 indicates EDNS0 and -1 indicates no EDNS. * @param payloadSize The maximum DNS packet size that this host is capable of receiving over UDP. - * If 0 is specified, the default (1280) is used. + * If 0 is specified, the default ({@value SimpleResolver#DEFAULT_EDNS_PAYLOADSIZE}) is used. * @param flags EDNS extended flags to be set in the OPT record. * @param options EDNS options to be set in the OPT record, specified as a List of * OPTRecord.Option elements. @@ -77,7 +80,11 @@ public interface Resolver { * @see OPTRecord */ default void setEDNS(int version, int payloadSize, int flags, EDNSOption... options) { - setEDNS(version, payloadSize, flags, Arrays.asList(options)); + setEDNS( + version, + payloadSize, + flags, + options == null ? Collections.emptyList() : Arrays.asList(options)); } /** diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index ebd8ef26f..4b6dc29a7 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -180,20 +180,11 @@ public void setEDNS(int version, int payloadSize, int flags, List op } } - @Override - public void setEDNS(int version) { - setEDNS(version, 0, 0); - } - @Override public void setTSIGKey(TSIG key) { tsig = key; } - TSIG getTSIGKey() { - return tsig; - } - @Override public void setTimeout(Duration timeout) { timeoutValue = timeout; From 4ba644d5a465bc558662a28ad393481593bc8ac5 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 27 Dec 2019 15:37:00 +0100 Subject: [PATCH 048/431] Add base64url/no padding overload --- src/main/java/org/xbill/DNS/utils/base64.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/utils/base64.java b/src/main/java/org/xbill/DNS/utils/base64.java index 1f1cea74c..fd879a386 100644 --- a/src/main/java/org/xbill/DNS/utils/base64.java +++ b/src/main/java/org/xbill/DNS/utils/base64.java @@ -15,6 +15,8 @@ public class base64 { private static final String Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + private static final String Base64Url = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; private base64() {} @@ -25,8 +27,19 @@ private base64() {} * @return A String containing the encoded data */ public static String toString(byte[] b) { - ByteArrayOutputStream os = new ByteArrayOutputStream(); + return toString(b, false); + } + /** + * Convert binary data to a base64-encoded String + * + * @param b An array containing binary data + * @param useUrl True to use Base64URL encoding (i.e. no trailing =, -_ instead of +/) + * @return A String containing the encoded data + */ + public static String toString(byte[] b, boolean useUrl) { + String base = useUrl ? Base64Url : Base64; + ByteArrayOutputStream os = new ByteArrayOutputStream(); for (int i = 0; i < (b.length + 2) / 3; i++) { short[] s = new short[3]; short[] t = new short[4]; @@ -54,7 +67,10 @@ public static String toString(byte[] b) { t[3] = (short) (s[2] & 0x3F); } for (int j = 0; j < 4; j++) { - os.write(Base64.charAt(t[j])); + if (t[j] == 64 && useUrl) { + continue; + } + os.write(base.charAt(t[j])); } } return new String(os.toByteArray()); From 9af9a0f031056608648163e7c9bdc64d3bccbd2a Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 27 Dec 2019 16:00:41 +0100 Subject: [PATCH 049/431] Add a basic DoH resolver Closes #66 --- src/main/java/org/xbill/DNS/DohResolver.java | 361 +++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 src/main/java/org/xbill/DNS/DohResolver.java diff --git a/src/main/java/org/xbill/DNS/DohResolver.java b/src/main/java/org/xbill/DNS/DohResolver.java new file mode 100644 index 000000000..037dbe858 --- /dev/null +++ b/src/main/java/org/xbill/DNS/DohResolver.java @@ -0,0 +1,361 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ForkJoinPool; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.xbill.DNS.utils.base64; + +/** + * Implements a very basic DNS over HTTP (DoH) resolver. On Java 8, it uses HTTP/1.1, which is + * against the recommendation of RFC 8484 to use HTTP/2 and thus horribly slow. On Java 11 or newer, + * HTTP/2 is always used. + */ +@Slf4j +public final class DohResolver implements Resolver { + private static final boolean useHttpClient; + + private static Object defaultHttpRequestBuilder; + private static Method publisherOfByteArrayMethod; + private static Method requestBuilderTimeoutMethod; + private static Method requestBuilderCopyMethod; + private static Method requestBuilderUriMethod; + private static Method requestBuilderBuildMethod; + private static Method requestBuilderPostMethod; + + private static Method httpClientNewBuilderMethod; + private static Method httpClientBuilderTimeoutMethod; + private static Method httpClientBuilderBuildMethod; + private static Method httpClientSendAsyncMethod; + + private static Method byteArrayBodyPublisherMethod; + private static Method httpResponseBodyMethod; + private static Method httpResponseStatusCodeMethod; + + private boolean usePost = false; + private Duration timeout = Duration.ofSeconds(5); + private String uriTemplate; + private OPTRecord queryOPT = new OPTRecord(0, 0, 0); + private TSIG tsig; + private Object httpClient; + + static { + boolean initSuccess = false; + if (!System.getProperty("java.version").startsWith("1.")) { + try { + Class httpClientBuilderClass = Class.forName("java.net.http.HttpClient$Builder"); + Class httpClientClass = Class.forName("java.net.http.HttpClient"); + Class httpVersionEnum = Class.forName("java.net.http.HttpClient$Version"); + Class httpRequestBuilderClass = Class.forName("java.net.http.HttpRequest$Builder"); + Class httpRequestClass = Class.forName("java.net.http.HttpRequest"); + Class bodyPublishersClass = Class.forName("java.net.http.HttpRequest$BodyPublishers"); + Class bodyPublisherClass = Class.forName("java.net.http.HttpRequest$BodyPublisher"); + Class httpResponseClass = Class.forName("java.net.http.HttpResponse"); + Class bodyHandlersClass = Class.forName("java.net.http.HttpResponse$BodyHandlers"); + Class bodyHandlerClass = Class.forName("java.net.http.HttpResponse$BodyHandler"); + + // HttpClient.Builder + httpClientBuilderTimeoutMethod = + httpClientBuilderClass.getDeclaredMethod("connectTimeout", Duration.class); + httpClientBuilderBuildMethod = httpClientBuilderClass.getDeclaredMethod("build"); + + // HttpClient + httpClientNewBuilderMethod = httpClientClass.getDeclaredMethod("newBuilder"); + httpClientSendAsyncMethod = + httpClientClass.getDeclaredMethod("sendAsync", httpRequestClass, bodyHandlerClass); + + // HttpRequestBuilder + Method requestBuilderHeaderMethod = + httpRequestBuilderClass.getDeclaredMethod("header", String.class, String.class); + Method requestBuilderVersionMethod = + httpRequestBuilderClass.getDeclaredMethod("version", httpVersionEnum); + requestBuilderTimeoutMethod = + httpRequestBuilderClass.getDeclaredMethod("timeout", Duration.class); + requestBuilderUriMethod = httpRequestBuilderClass.getDeclaredMethod("uri", URI.class); + requestBuilderCopyMethod = httpRequestBuilderClass.getDeclaredMethod("copy"); + requestBuilderBuildMethod = httpRequestBuilderClass.getDeclaredMethod("build"); + requestBuilderPostMethod = + httpRequestBuilderClass.getDeclaredMethod("POST", bodyPublisherClass); + + // HttpRequest + Method requestBuilderNewBuilderMethod = httpRequestClass.getDeclaredMethod("newBuilder"); + + // BodyPublishers + publisherOfByteArrayMethod = + bodyPublishersClass.getDeclaredMethod("ofByteArray", byte[].class); + + // BodyPublisher + byteArrayBodyPublisherMethod = bodyHandlersClass.getDeclaredMethod("ofByteArray"); + + // HttpResponse + httpResponseBodyMethod = httpResponseClass.getDeclaredMethod("body"); + httpResponseStatusCodeMethod = httpResponseClass.getDeclaredMethod("statusCode"); + + // defaultHttpRequestBuilder = HttpRequest.newBuilder(); + // defaultHttpRequestBuilder.version(Version.HTTP_2); + // defaultHttpRequestBuilder.header("Content-Type", "application/dns-message"); + // defaultHttpRequestBuilder.header("Accept", "application/dns-message"); + defaultHttpRequestBuilder = requestBuilderNewBuilderMethod.invoke(null); + @SuppressWarnings({"unchecked", "rawtypes"}) + Enum http2Version = Enum.valueOf((Class) httpVersionEnum, "HTTP_2"); + requestBuilderVersionMethod.invoke(defaultHttpRequestBuilder, http2Version); + requestBuilderHeaderMethod.invoke( + defaultHttpRequestBuilder, "Content-Type", "application/dns-message"); + requestBuilderHeaderMethod.invoke( + defaultHttpRequestBuilder, "Accept", "application/dns-message"); + initSuccess = true; + } catch (ClassNotFoundException + | NoSuchMethodException + | IllegalAccessException + | InvocationTargetException e) { + // fallback to Java 8 + log.warn("Java >= 11 detected, but HttpRequest not available"); + } + } + + useHttpClient = initSuccess; + } + + /** + * Creates a new DoH resolver that performs lookups with HTTP GET and the default timeout (5s). + * + * @param uriTemplate the URI to use for resolving, e.g. {@code https://dns.google/dns-query} + */ + public DohResolver(String uriTemplate) { + this.uriTemplate = uriTemplate; + buildHttpClient(); + } + + @SneakyThrows + private void buildHttpClient() { + if (useHttpClient) { + Object httpClientBuilder = httpClientNewBuilderMethod.invoke(null); + httpClientBuilderTimeoutMethod.invoke(httpClientBuilder, timeout); + httpClient = httpClientBuilderBuildMethod.invoke(httpClientBuilder); + requestBuilderTimeoutMethod.invoke(defaultHttpRequestBuilder, timeout); + } + } + + /** Not implemented. Specify the port in {@link #setUriTemplate(String)} if required. */ + @Override + public void setPort(int port) {} + + /** Not implemented. */ + @Override + public void setTCP(boolean flag) {} + + /** Not implemented. */ + @Override + public void setIgnoreTruncation(boolean flag) {} + + /** + * Sets the EDNS information on outgoing messages. + * + * @param version The EDNS version to use. 0 indicates EDNS0 and -1 indicates no EDNS. + * @param payloadSize ignored + * @param flags EDNS extended flags to be set in the OPT record. + * @param options EDNS options to be set in the OPT record + */ + @Override + public void setEDNS(int version, int payloadSize, int flags, List options) { + switch (version) { + case -1: + queryOPT = null; + break; + + case 0: + queryOPT = new OPTRecord(0, 0, version, flags, options); + break; + + default: + throw new IllegalArgumentException("invalid EDNS version - must be 0 or -1 to disable"); + } + } + + @Override + public void setTSIGKey(TSIG key) { + this.tsig = key; + } + + @Override + public void setTimeout(Duration timeout) { + this.timeout = timeout; + buildHttpClient(); + } + + @Override + public Duration getTimeout() { + return timeout; + } + + @Override + public CompletionStage sendAsync(Message query) { + if (useHttpClient) { + return sendAsync11(query); + } + + return sendAsync8(query); + } + + private CompletionStage sendAsync8(final Message query) { + CompletableFuture f = new CompletableFuture<>(); + ForkJoinPool.commonPool() + .execute( + () -> { + try { + byte[] queryBytes = prepareQuery(query).toWire(); + String url = getUrl(queryBytes); + + byte[] responseBytes = sendAndGetMessageBytes(url, queryBytes); + Message response = new Message(responseBytes); + verifyTSIG(query, response, responseBytes, tsig); + response.setResolver(this); + f.complete(response); + } catch (IOException e) { + f.completeExceptionally(e); + } + }); + return f; + } + + private byte[] sendAndGetMessageBytes(String url, byte[] queryBytes) throws IOException { + HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); + conn.setConnectTimeout((int) timeout.toMillis()); + conn.setRequestMethod(isUsePost() ? "POST" : "GET"); + conn.setRequestProperty("Content-Type", "application/dns-message"); + conn.setRequestProperty("Accept", "application/dns-message"); + if (usePost) { + conn.setDoOutput(true); + conn.getOutputStream().write(queryBytes); + } + InputStream is = conn.getInputStream(); + byte[] responseBytes = new byte[conn.getContentLength()]; + int r; + int offset = 0; + while ((r = is.read(responseBytes, offset, responseBytes.length)) > 0) { + offset += r; + } + return responseBytes; + } + + private CompletionStage sendAsync11(final Message query) { + byte[] queryBytes = prepareQuery(query).toWire(); + String url = getUrl(queryBytes); + + try { + // var builder = defaultHttpRequestBuilder.copy(); + Object builder = requestBuilderCopyMethod.invoke(defaultHttpRequestBuilder); + // builder.uri(URI.create(url)); + requestBuilderUriMethod.invoke(builder, URI.create(url)); + if (usePost) { + // builder.POST(BodyPublishers.ofByteArray(queryBytes)); + requestBuilderPostMethod.invoke( + builder, publisherOfByteArrayMethod.invoke(null, queryBytes)); + } + + // var request = request.build(); + // var bodyHandler = BodyHandlers.ofByteArray(); + Object httpRequest = requestBuilderBuildMethod.invoke(builder); + Object bodyHandler = byteArrayBodyPublisherMethod.invoke(null); + return ((CompletionStage) + httpClientSendAsyncMethod.invoke(httpClient, httpRequest, bodyHandler)) + .thenComposeAsync( + response -> { + try { + Message responseMessage; + if ((int) httpResponseStatusCodeMethod.invoke(response) == 200) { + byte[] responseBytes = (byte[]) httpResponseBodyMethod.invoke(response); + responseMessage = new Message(responseBytes); + verifyTSIG(query, responseMessage, responseBytes, tsig); + } else { + responseMessage = new Message(); + responseMessage.getHeader().setRcode(Rcode.SERVFAIL); + } + + responseMessage.setResolver(this); + return CompletableFuture.completedFuture(responseMessage); + } catch (IOException | IllegalAccessException | InvocationTargetException e) { + return failedFuture(e); + } + }); + } catch (IllegalAccessException | InvocationTargetException e) { + return failedFuture(e); + } + } + + private CompletionStage failedFuture(Throwable e) { + CompletableFuture f = new CompletableFuture<>(); + f.completeExceptionally(e); + return f; + } + + private String getUrl(byte[] queryBytes) { + String url = uriTemplate; + if (!usePost) { + url += "?dns=" + base64.toString(queryBytes, true); + } + return url; + } + + private Message prepareQuery(Message query) { + Message preparedQuery = query.clone(); + preparedQuery.getHeader().setID(0); + if (queryOPT != null && preparedQuery.getOPT() == null) { + preparedQuery.addRecord(queryOPT, Section.ADDITIONAL); + } + + if (tsig != null) { + tsig.apply(preparedQuery, null); + } + + return preparedQuery; + } + + private void verifyTSIG(Message query, Message response, byte[] b, TSIG tsig) { + if (tsig == null) { + return; + } + int error = tsig.verify(response, b, query.getTSIG()); + log.debug("TSIG verify: {}", Rcode.TSIGstring(error)); + } + + /** Returns {@code true} if the HTTP method POST to resolve, {@code false} if GET is used. */ + public boolean isUsePost() { + return usePost; + } + + /** + * Sets the HTTP method to use for resolving. + * + * @param usePost {@code true} to use POST, {@code false} to use GET (the default). + */ + public void setUsePost(boolean usePost) { + this.usePost = usePost; + } + + /** Gets the current URI used for resolving. */ + public String getUriTemplate() { + return uriTemplate; + } + + /** Sets the URI to use for resolving, e.g. {@code https://dns.google/dns-query} */ + public void setUriTemplate(String uriTemplate) { + this.uriTemplate = uriTemplate; + } + + @Override + public String toString() { + return "DohResolver {" + (usePost ? "POST " : "GET ") + uriTemplate + "}"; + } +} From ecff2a794a0cb5115a290084cbd2d3eaab18c28a Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 5 Jan 2020 13:30:14 +0100 Subject: [PATCH 050/431] Fix timeout/lost events in TCP client --- src/main/java/org/xbill/DNS/Client.java | 8 +- src/main/java/org/xbill/DNS/NioTcpClient.java | 34 +++--- .../java/org/xbill/DNS/NioTcpClientTest.java | 111 ++++++++++++++++++ 3 files changed, 133 insertions(+), 20 deletions(-) create mode 100644 src/test/java/org/xbill/DNS/NioTcpClientTest.java diff --git a/src/main/java/org/xbill/DNS/Client.java b/src/main/java/org/xbill/DNS/Client.java index 6b9048eba..2722ee452 100644 --- a/src/main/java/org/xbill/DNS/Client.java +++ b/src/main/java/org/xbill/DNS/Client.java @@ -7,7 +7,6 @@ import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.List; -import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import lombok.extern.slf4j.Slf4j; import org.xbill.DNS.utils.hexdump; @@ -31,6 +30,7 @@ protected static void start() throws IOException { return; } + log.debug("Starting dnsjava NIO selector thread"); run = true; selector = Selector.open(); selectorThread = new Thread(Client::runSelector); @@ -54,9 +54,8 @@ protected static void close() throws Exception { private static void runSelector() { while (run) { try { - if (selector.select(100) == 0) { + if (selector.select(1000) == 0) { timeoutTasks.forEach(Runnable::run); - continue; } processReadyKeys(); @@ -71,8 +70,7 @@ static void addSelectorTimeoutTask(Runnable r) { } private static void processReadyKeys() { - Set keys = selector.selectedKeys(); - for (SelectionKey key : keys) { + for (SelectionKey key : selector.selectedKeys()) { KeyProcessor t = (KeyProcessor) key.attachment(); t.processReadyKey(key); } diff --git a/src/main/java/org/xbill/DNS/NioTcpClient.java b/src/main/java/org/xbill/DNS/NioTcpClient.java index 31437ce14..24696ac34 100644 --- a/src/main/java/org/xbill/DNS/NioTcpClient.java +++ b/src/main/java/org/xbill/DNS/NioTcpClient.java @@ -45,12 +45,9 @@ private static void processPendingRegistrations() { while (!registrationQueue.isEmpty()) { ChannelState state = registrationQueue.remove(); try { - state.channel.register( - selector, - state.channel.isConnected() - ? SelectionKey.OP_READ | SelectionKey.OP_WRITE - : SelectionKey.OP_CONNECT, - state); + if (!state.channel.isConnected()) { + state.channel.register(selector, SelectionKey.OP_CONNECT, state); + } } catch (ClosedChannelException e) { state.handleChannelException(e); } @@ -128,15 +125,17 @@ private static class ChannelState implements KeyProcessor { int readState = 0; public void processReadyKey(SelectionKey key) { - if (key.isConnectable()) { - processConnect(key); - } - if (key.isWritable()) { - processWrite(); - } - if (key.isReadable()) { - processRead(); - } + if (key.isValid()) + if (key.isConnectable()) { + processConnect(key); + } else { + if (key.isWritable()) { + processWrite(); + } + if (key.isReadable()) { + processRead(); + } + } } void handleTransactionException(IOException e) { @@ -259,6 +258,7 @@ static CompletableFuture sendrecv( new ChannelKey(local, remote), key -> { try { + log.trace("Opening async channel for l={}/r={}", local, remote); SocketChannel c = SocketChannel.open(); c.configureBlocking(false); if (local != null) { @@ -273,6 +273,10 @@ static CompletableFuture sendrecv( } }); if (channel != null) { + log.trace( + "Creating transaction for {}/{}", + query.getQuestion().getName(), + Type.string(query.getQuestion().getType())); Transaction t = new Transaction(query, data, endTime, channel.channel, f); channel.pendingTransactions.add(t); registrationQueue.add(channel); diff --git a/src/test/java/org/xbill/DNS/NioTcpClientTest.java b/src/test/java/org/xbill/DNS/NioTcpClientTest.java new file mode 100644 index 000000000..d9883154f --- /dev/null +++ b/src/test/java/org/xbill/DNS/NioTcpClientTest.java @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; + +public class NioTcpClientTest { + @Test + void testResponseStream() throws InterruptedException, IOException, ExecutionException { + Record qr = Record.newRecord(Name.fromConstantString("example.com."), Type.A, DClass.IN); + Message[] q = new Message[] {Message.newQuery(qr), Message.newQuery(qr)}; + CountDownLatch cdl1 = new CountDownLatch(q.length); + CountDownLatch cdl2 = new CountDownLatch(q.length); + Message[] serverReceivedMessages = new Message[q.length]; + Message[] clientReceivedAnswers = new Message[q.length]; + AtomicInteger i = new AtomicInteger(0); + Socket[] s = new Socket[1]; + ServerSocket ss = new ServerSocket(0); + Thread server = + new Thread( + () -> { + try { + s[0] = ss.accept(); + while (cdl1.getCount() > 0) { + int ii = i.getAndIncrement(); + try { + InputStream is = s[0].getInputStream(); + byte[] lengthData = new byte[2]; + int readLength = is.read(lengthData); + assertEquals(2, readLength); + byte[] messageData = new byte[(lengthData[0] << 8) + lengthData[1]]; + int readMessageLength = is.read(messageData); + assertEquals(messageData.length, readMessageLength); + serverReceivedMessages[ii] = new Message(messageData); + cdl1.countDown(); + } catch (IOException e) { + fail(e); + } + } + } catch (IOException e) { + fail(e); + } + }); + server.start(); + + for (int j = 0; j < q.length; j++) { + int jj = j; + NioTcpClient.sendrecv( + null, + (InetSocketAddress) ss.getLocalSocketAddress(), + q[j], + q[j].toWire(), + Duration.ofSeconds(5)) + .thenAccept( + d -> { + try { + clientReceivedAnswers[jj] = new Message(d); + cdl2.countDown(); + } catch (IOException e) { + fail(e); + } + }); + } + + if (!cdl1.await(5, TimeUnit.SECONDS)) { + fail("timed out waiting for messages"); + } + + for (int j = q.length - 1; j >= 0; j--) { + Message answer = new Message(); + answer.getHeader().setRcode(Rcode.NOERROR); + answer.getHeader().setID(serverReceivedMessages[j].getHeader().getID()); + answer.addRecord(serverReceivedMessages[j].getQuestion(), Section.QUESTION); + answer.addRecord( + new ARecord( + Name.fromConstantString("example.com."), + DClass.IN, + 900, + InetAddress.getLoopbackAddress()), + Section.ANSWER); + byte[] queryData = answer.toWire(); + ByteBuffer buffer = ByteBuffer.allocate(queryData.length + 2); + buffer.put((byte) (queryData.length >>> 8)); + buffer.put((byte) (queryData.length & 0xFF)); + buffer.put(queryData); + s[0].getOutputStream().write(buffer.array()); + } + + if (!cdl2.await(5, TimeUnit.SECONDS)) { + fail("timed out waiting for answers"); + } + + for (int j = 0; j < q.length; j++) { + assertEquals(q[j].getHeader().getID(), clientReceivedAnswers[j].getHeader().getID()); + } + } +} From 6fc49f31fb32ad5329dad733dc1333074c71cbb0 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 12 Jan 2020 13:57:52 +0100 Subject: [PATCH 051/431] Fix usage of the NIO selected keys set "[...] Keys are never removed from the selected-key set in any other way; they are not, in particular, removed as a side effect of selection operations. [...]" --- src/main/java/org/xbill/DNS/Client.java | 6 +++++- src/test/java/org/xbill/DNS/NioTcpClientTest.java | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Client.java b/src/main/java/org/xbill/DNS/Client.java index 2722ee452..362d6b716 100644 --- a/src/main/java/org/xbill/DNS/Client.java +++ b/src/main/java/org/xbill/DNS/Client.java @@ -6,6 +6,7 @@ import java.net.SocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; +import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import lombok.extern.slf4j.Slf4j; @@ -70,7 +71,10 @@ static void addSelectorTimeoutTask(Runnable r) { } private static void processReadyKeys() { - for (SelectionKey key : selector.selectedKeys()) { + Iterator it = selector.selectedKeys().iterator(); + while (it.hasNext()) { + SelectionKey key = it.next(); + it.remove(); KeyProcessor t = (KeyProcessor) key.attachment(); t.processReadyKey(key); } diff --git a/src/test/java/org/xbill/DNS/NioTcpClientTest.java b/src/test/java/org/xbill/DNS/NioTcpClientTest.java index d9883154f..1b2e009ed 100644 --- a/src/test/java/org/xbill/DNS/NioTcpClientTest.java +++ b/src/test/java/org/xbill/DNS/NioTcpClientTest.java @@ -13,14 +13,13 @@ import java.nio.ByteBuffer; import java.time.Duration; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Test; public class NioTcpClientTest { @Test - void testResponseStream() throws InterruptedException, IOException, ExecutionException { + void testResponseStream() throws InterruptedException, IOException { Record qr = Record.newRecord(Name.fromConstantString("example.com."), Type.A, DClass.IN); Message[] q = new Message[] {Message.newQuery(qr), Message.newQuery(qr)}; CountDownLatch cdl1 = new CountDownLatch(q.length); From 4c2b12692d634fcccab50d2ce427713cf76e4b03 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 18 Jan 2020 18:53:21 +0100 Subject: [PATCH 052/431] Use roboelectric as an Android SDK replacement to avoid reflection (#90) Related to #6 --- pom.xml | 6 ++ .../config/AndroidResolverConfigProvider.java | 71 ++++++------------- .../config/WindowsResolverConfigProvider.java | 2 +- 3 files changed, 28 insertions(+), 51 deletions(-) diff --git a/pom.xml b/pom.xml index 4547390f9..bc7520d01 100644 --- a/pom.xml +++ b/pom.xml @@ -215,6 +215,12 @@ 1.18.10 provided + + org.robolectric + android-all + 10-robolectric-5803371 + provided + net.java.dev.jna jna diff --git a/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java index dd290f6c0..1242a29bb 100644 --- a/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java @@ -1,19 +1,21 @@ // SPDX-License-Identifier: BSD-2-Clause package org.xbill.DNS.config; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.Network; +import android.os.Build; +import android.os.SystemProperties; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.util.List; import lombok.extern.slf4j.Slf4j; import org.xbill.DNS.ResolverConfig; import org.xbill.DNS.SimpleResolver; /** * Resolver config provider for Android. Contrary to all other providers, this provider needs a - * context to operate on which must be set by calling {@link #setContext(Object)}. + * context to operate on which must be set by calling {@link #setContext(Context)}. * *

If you are developing for Android, consider implementing your own {@link * ResolverConfigProvider} that listens to network callbacks and properly refreshes on link changes. @@ -22,10 +24,10 @@ */ @Slf4j public class AndroidResolverConfigProvider extends BaseResolverConfigProvider { - private static Object context = null; + private static Context context = null; /** Gets the current configuration */ - public static void setContext(Object ctx) { + public static void setContext(Context ctx) { context = ctx; } @@ -36,76 +38,45 @@ public void initialize() throws InitializationException { // that net.dns* should always be the active nameservers, so we use those. // Starting with Android 8 (API 26), the net.dns[1234] properties are no longer available: // https://developer.android.com/about/versions/oreo/android-8.0-changes.html#o-pri - try { - Class Version = Class.forName("android.os.Build$VERSION"); - Field SDK_INT = Version.getField("SDK_INT"); - - if (SDK_INT.getInt(null) >= 26) { - initializeApi26Nameservers(); - } else { - initializeNameservers(); - } - } catch (NoSuchMethodException - | InvocationTargetException - | NoSuchFieldException - | IllegalAccessException - | ClassNotFoundException e) { - throw new InitializationException(e); + if (Build.VERSION.SDK_INT >= 26) { + initializeApi26Nameservers(); + } else { + initializeNameservers(); } } - private void initializeNameservers() - throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, - InvocationTargetException { - Class systemPropertiesClass = Class.forName("android.os.SystemProperties"); - Method method = systemPropertiesClass.getMethod("get", String.class); + private void initializeNameservers() { for (int i = 1; i <= 4; i++) { - String server = (String) method.invoke(null, "net.dns" + i); + String server = SystemProperties.get("net.dns" + i); if (server != null && !server.isEmpty()) { nameservers.add(new InetSocketAddress(server, SimpleResolver.DEFAULT_PORT)); } } } - private void initializeApi26Nameservers() - throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, - InvocationTargetException, InitializationException { + private void initializeApi26Nameservers() throws InitializationException { if (context == null) { throw new InitializationException("Context must be initialized by calling setContext"); } - Class contextClass = Class.forName("android.content.Context"); - Method getSystemService = contextClass.getDeclaredMethod("getSystemService", String.class); - Object cm = getSystemService.invoke(context, "connectivity"); - - Class connectivityManagerClass = Class.forName("android.net.ConnectivityManager"); - Method getActiveNetwork = connectivityManagerClass.getDeclaredMethod("getActiveNetwork"); - Object network = getActiveNetwork.invoke(cm); + ConnectivityManager cm = context.getSystemService(ConnectivityManager.class); + Network network = cm.getActiveNetwork(); if (network == null) { // if the device is offline, there's no active network return; } - Class networkClass = Class.forName("android.net.Network"); - Method getLinkProperties = - connectivityManagerClass.getDeclaredMethod("getLinkProperties", networkClass); - Object lp = getLinkProperties.invoke(cm, network); + LinkProperties lp = cm.getLinkProperties(network); if (lp == null) { // can be null for an unknown network, which may happen if networks change return; } - Class linkPropertiesClass = Class.forName("android.net.LinkProperties"); - Method getDnsServers = linkPropertiesClass.getDeclaredMethod("getDnsServers"); - @SuppressWarnings("unchecked") - List addresses = (List) getDnsServers.invoke(lp); - - for (InetAddress address : addresses) { + for (InetAddress address : lp.getDnsServers()) { addNameserver(new InetSocketAddress(address, SimpleResolver.DEFAULT_PORT)); } - Method getDomains = linkPropertiesClass.getDeclaredMethod("getDomains"); - parseSearchPathList((String) getDomains.invoke(lp), ","); + parseSearchPathList(lp.getDomains(), ","); } @Override diff --git a/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java index 7c2c69bfe..de835c5d2 100644 --- a/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java @@ -72,7 +72,7 @@ public void initialize() throws InitializationException { if (result.OperStatus == 1) { IP_ADAPTER_DNS_SERVER_ADDRESS_XP dns = result.FirstDnsServerAddress; while (dns != null) { - InetAddress address = null; + InetAddress address; try { address = dns.Address.toAddress(); if (!address.isSiteLocalAddress()) { From 88421bd51081636ee9043b21392bf92abed4fb9b Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 18 Jan 2020 18:55:20 +0100 Subject: [PATCH 053/431] Disable the JVM reflection provider by default All functionality the JVM is now built-in IF JNA is available. Related to #9 --- .../java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java | 2 +- src/test/java/org/xbill/DNS/ResolverConfigTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java index cb0a9612e..9a6dead07 100644 --- a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java @@ -72,6 +72,6 @@ public List searchPaths() { @Override public boolean isEnabled() { - return !System.getProperty("java.vendor").contains("Android"); + return Boolean.getBoolean("dnsjava.configprovider.sunjvm.enabled"); } } diff --git a/src/test/java/org/xbill/DNS/ResolverConfigTest.java b/src/test/java/org/xbill/DNS/ResolverConfigTest.java index 48cc009da..be690613c 100644 --- a/src/test/java/org/xbill/DNS/ResolverConfigTest.java +++ b/src/test/java/org/xbill/DNS/ResolverConfigTest.java @@ -154,7 +154,7 @@ void sunJvmThrowsIfNotInitialized() { @Test void sunJvm() throws InitializationException { SunJvmResolverConfigProvider rc = new SunJvmResolverConfigProvider(); - assertTrue(rc.isEnabled()); + assertFalse(rc.isEnabled()); rc.initialize(); } From 49dd8521aa68b969cf3cfae88dab8b9a24a23239 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 18 Jan 2020 20:03:11 +0100 Subject: [PATCH 054/431] Fix use_ephemeral_port property parsing --- src/main/java/org/xbill/DNS/NioUdpClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/NioUdpClient.java b/src/main/java/org/xbill/DNS/NioUdpClient.java index d84717a4f..49db6ac67 100644 --- a/src/main/java/org/xbill/DNS/NioUdpClient.java +++ b/src/main/java/org/xbill/DNS/NioUdpClient.java @@ -45,7 +45,7 @@ final class NioUdpClient extends Client { int ephemeralEnd = Integer.getInteger("dnsjava.udp.ephemeral.end", ephemeralEndDefault); EPHEMERAL_RANGE = ephemeralEnd - EPHEMERAL_START; - if (Boolean.parseBoolean("dnsjava.udp.ephemeral.use_ephemeral_port")) { + if (Boolean.getBoolean("dnsjava.udp.ephemeral.use_ephemeral_port")) { prng = null; } else { prng = new SecureRandom(); From 8fc771a6a9ca1fad9ffed2ebfb775e369953f9d2 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 18 Jan 2020 21:12:34 +0100 Subject: [PATCH 055/431] Remove Serializable and serialVersionUID from Record Records alreads have two RFC defined serialization formats, there is no need for an unmaintained, proprietary third option. --- src/main/java/org/xbill/DNS/A6Record.java | 3 --- src/main/java/org/xbill/DNS/AAAARecord.java | 3 --- src/main/java/org/xbill/DNS/AFSDBRecord.java | 3 --- src/main/java/org/xbill/DNS/APLRecord.java | 2 -- src/main/java/org/xbill/DNS/ARecord.java | 3 --- src/main/java/org/xbill/DNS/CAARecord.java | 3 --- src/main/java/org/xbill/DNS/CDNSKEYRecord.java | 3 --- src/main/java/org/xbill/DNS/CDSRecord.java | 3 --- src/main/java/org/xbill/DNS/CERTRecord.java | 2 -- src/main/java/org/xbill/DNS/CNAMERecord.java | 3 --- src/main/java/org/xbill/DNS/Client.java | 4 ++-- src/main/java/org/xbill/DNS/DHCIDRecord.java | 3 --- src/main/java/org/xbill/DNS/DLVRecord.java | 2 -- src/main/java/org/xbill/DNS/DNAMERecord.java | 3 --- src/main/java/org/xbill/DNS/DNSKEYRecord.java | 2 -- src/main/java/org/xbill/DNS/DSRecord.java | 2 -- src/main/java/org/xbill/DNS/EmptyRecord.java | 3 --- src/main/java/org/xbill/DNS/GPOSRecord.java | 3 --- src/main/java/org/xbill/DNS/HINFORecord.java | 3 --- src/main/java/org/xbill/DNS/IPSECKEYRecord.java | 3 --- src/main/java/org/xbill/DNS/ISDNRecord.java | 3 --- src/main/java/org/xbill/DNS/KEYBase.java | 3 --- src/main/java/org/xbill/DNS/KEYRecord.java | 3 --- src/main/java/org/xbill/DNS/KXRecord.java | 3 --- src/main/java/org/xbill/DNS/LOCRecord.java | 3 --- src/main/java/org/xbill/DNS/MBRecord.java | 3 --- src/main/java/org/xbill/DNS/MDRecord.java | 3 --- src/main/java/org/xbill/DNS/MFRecord.java | 3 --- src/main/java/org/xbill/DNS/MGRecord.java | 3 --- src/main/java/org/xbill/DNS/MINFORecord.java | 3 --- src/main/java/org/xbill/DNS/MRRecord.java | 3 --- src/main/java/org/xbill/DNS/MXRecord.java | 3 --- src/main/java/org/xbill/DNS/NAPTRRecord.java | 3 --- src/main/java/org/xbill/DNS/NSAPRecord.java | 3 --- src/main/java/org/xbill/DNS/NSAP_PTRRecord.java | 3 --- src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java | 3 --- src/main/java/org/xbill/DNS/NSEC3Record.java | 2 -- src/main/java/org/xbill/DNS/NSECRecord.java | 3 --- src/main/java/org/xbill/DNS/NSIDOption.java | 3 --- src/main/java/org/xbill/DNS/NSRecord.java | 3 --- src/main/java/org/xbill/DNS/NULLRecord.java | 3 --- src/main/java/org/xbill/DNS/NXTRecord.java | 3 --- src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java | 3 --- src/main/java/org/xbill/DNS/OPTRecord.java | 3 --- src/main/java/org/xbill/DNS/PTRRecord.java | 3 --- src/main/java/org/xbill/DNS/PXRecord.java | 3 --- src/main/java/org/xbill/DNS/RPRecord.java | 3 --- src/main/java/org/xbill/DNS/RRSIGRecord.java | 3 --- src/main/java/org/xbill/DNS/RTRecord.java | 3 --- src/main/java/org/xbill/DNS/Record.java | 3 +-- src/main/java/org/xbill/DNS/SIGRecord.java | 3 --- src/main/java/org/xbill/DNS/SOARecord.java | 3 --- src/main/java/org/xbill/DNS/SPFRecord.java | 3 --- src/main/java/org/xbill/DNS/SRVRecord.java | 3 --- src/main/java/org/xbill/DNS/SSHFPRecord.java | 3 --- src/main/java/org/xbill/DNS/SingleCompressedNameBase.java | 3 --- src/main/java/org/xbill/DNS/SingleNameBase.java | 3 --- src/main/java/org/xbill/DNS/TKEYRecord.java | 3 --- src/main/java/org/xbill/DNS/TLSARecord.java | 3 --- src/main/java/org/xbill/DNS/TSIGRecord.java | 3 --- src/main/java/org/xbill/DNS/TXTBase.java | 3 --- src/main/java/org/xbill/DNS/TXTRecord.java | 3 --- src/main/java/org/xbill/DNS/U16NameBase.java | 3 --- src/main/java/org/xbill/DNS/UNKRecord.java | 3 --- src/main/java/org/xbill/DNS/URIRecord.java | 3 --- src/main/java/org/xbill/DNS/WKSRecord.java | 3 --- src/main/java/org/xbill/DNS/X25Record.java | 3 --- 67 files changed, 3 insertions(+), 193 deletions(-) diff --git a/src/main/java/org/xbill/DNS/A6Record.java b/src/main/java/org/xbill/DNS/A6Record.java index de4fe52d2..cfa58f665 100644 --- a/src/main/java/org/xbill/DNS/A6Record.java +++ b/src/main/java/org/xbill/DNS/A6Record.java @@ -13,9 +13,6 @@ * @see RFC 6563: Moving A6 to Historic Status */ public class A6Record extends Record { - - private static final long serialVersionUID = -8815026887337346789L; - private int prefixBits; private InetAddress suffix; private Name prefix; diff --git a/src/main/java/org/xbill/DNS/AAAARecord.java b/src/main/java/org/xbill/DNS/AAAARecord.java index e9b0eea0e..d4ccbf268 100644 --- a/src/main/java/org/xbill/DNS/AAAARecord.java +++ b/src/main/java/org/xbill/DNS/AAAARecord.java @@ -14,9 +14,6 @@ * 6 */ public class AAAARecord extends Record { - - private static final long serialVersionUID = -4588601512069748050L; - private byte[] address; AAAARecord() {} diff --git a/src/main/java/org/xbill/DNS/AFSDBRecord.java b/src/main/java/org/xbill/DNS/AFSDBRecord.java index 02061e50d..eb82e34d2 100644 --- a/src/main/java/org/xbill/DNS/AFSDBRecord.java +++ b/src/main/java/org/xbill/DNS/AFSDBRecord.java @@ -9,9 +9,6 @@ * @see RFC 1183: New DNS RR Definitions */ public class AFSDBRecord extends U16NameBase { - - private static final long serialVersionUID = 3034379930729102437L; - AFSDBRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/APLRecord.java b/src/main/java/org/xbill/DNS/APLRecord.java index acaf613e4..70e4a7407 100644 --- a/src/main/java/org/xbill/DNS/APLRecord.java +++ b/src/main/java/org/xbill/DNS/APLRecord.java @@ -87,8 +87,6 @@ public int hashCode() { } } - private static final long serialVersionUID = -1348173791712935864L; - private List elements; APLRecord() {} diff --git a/src/main/java/org/xbill/DNS/ARecord.java b/src/main/java/org/xbill/DNS/ARecord.java index 934c31d40..f1ee93b5b 100644 --- a/src/main/java/org/xbill/DNS/ARecord.java +++ b/src/main/java/org/xbill/DNS/ARecord.java @@ -14,9 +14,6 @@ * Specification */ public class ARecord extends Record { - - private static final long serialVersionUID = -2172609200849142323L; - private int addr; ARecord() {} diff --git a/src/main/java/org/xbill/DNS/CAARecord.java b/src/main/java/org/xbill/DNS/CAARecord.java index bf3231e37..e480711ed 100644 --- a/src/main/java/org/xbill/DNS/CAARecord.java +++ b/src/main/java/org/xbill/DNS/CAARecord.java @@ -12,9 +12,6 @@ * Authorization (CAA) Resource Record */ public class CAARecord extends Record { - - private static final long serialVersionUID = 8544304287274216443L; - public static class Flags { private Flags() {} diff --git a/src/main/java/org/xbill/DNS/CDNSKEYRecord.java b/src/main/java/org/xbill/DNS/CDNSKEYRecord.java index 0a24208d5..f8c9e9695 100644 --- a/src/main/java/org/xbill/DNS/CDNSKEYRecord.java +++ b/src/main/java/org/xbill/DNS/CDNSKEYRecord.java @@ -11,9 +11,6 @@ * via CDS/CDNSKEY */ public class CDNSKEYRecord extends DNSKEYRecord { - - private static final long serialVersionUID = 1307874430666933615L; - CDNSKEYRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/CDSRecord.java b/src/main/java/org/xbill/DNS/CDSRecord.java index fcacd8e47..a0fa1b1b5 100644 --- a/src/main/java/org/xbill/DNS/CDSRecord.java +++ b/src/main/java/org/xbill/DNS/CDSRecord.java @@ -9,9 +9,6 @@ * via CDS/CDNSKEY */ public class CDSRecord extends DSRecord { - - private static final long serialVersionUID = -3156174257356976006L; - CDSRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/CERTRecord.java b/src/main/java/org/xbill/DNS/CERTRecord.java index 4ac1aaf42..1be222fbe 100644 --- a/src/main/java/org/xbill/DNS/CERTRecord.java +++ b/src/main/java/org/xbill/DNS/CERTRecord.java @@ -101,8 +101,6 @@ public static int value(String s) { /** Certificate format defined by IOD */ public static final int OID = CertificateType.OID; - private static final long serialVersionUID = 4763014646517016835L; - private int certType, keyTag; private int alg; private byte[] cert; diff --git a/src/main/java/org/xbill/DNS/CNAMERecord.java b/src/main/java/org/xbill/DNS/CNAMERecord.java index 8f64e50de..cfea590f9 100644 --- a/src/main/java/org/xbill/DNS/CNAMERecord.java +++ b/src/main/java/org/xbill/DNS/CNAMERecord.java @@ -10,9 +10,6 @@ * Specification */ public class CNAMERecord extends SingleCompressedNameBase { - - private static final long serialVersionUID = -4020373886892538580L; - CNAMERecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/Client.java b/src/main/java/org/xbill/DNS/Client.java index 362d6b716..d9144ffec 100644 --- a/src/main/java/org/xbill/DNS/Client.java +++ b/src/main/java/org/xbill/DNS/Client.java @@ -22,11 +22,11 @@ class Client { private static List timeoutTasks = new CopyOnWriteArrayList<>(); static Selector selector; - protected interface KeyProcessor { + interface KeyProcessor { void processReadyKey(SelectionKey key); } - protected static void start() throws IOException { + static void start() throws IOException { if (run) { return; } diff --git a/src/main/java/org/xbill/DNS/DHCIDRecord.java b/src/main/java/org/xbill/DNS/DHCIDRecord.java index 5cf3c91fc..3ab936705 100644 --- a/src/main/java/org/xbill/DNS/DHCIDRecord.java +++ b/src/main/java/org/xbill/DNS/DHCIDRecord.java @@ -13,9 +13,6 @@ * Encoding Dynamic Host Configuration Protocol (DHCP) Information (DHCID RR) */ public class DHCIDRecord extends Record { - - private static final long serialVersionUID = -8214820200808997707L; - private byte[] data; DHCIDRecord() {} diff --git a/src/main/java/org/xbill/DNS/DLVRecord.java b/src/main/java/org/xbill/DNS/DLVRecord.java index d78c5ca07..70b161501 100644 --- a/src/main/java/org/xbill/DNS/DLVRecord.java +++ b/src/main/java/org/xbill/DNS/DLVRecord.java @@ -21,8 +21,6 @@ public class DLVRecord extends Record { public static final int SHA1_DIGEST_ID = DSRecord.Digest.SHA1; public static final int SHA256_DIGEST_ID = DSRecord.Digest.SHA1; - private static final long serialVersionUID = 1960742375677534148L; - private int footprint; private int alg; private int digestid; diff --git a/src/main/java/org/xbill/DNS/DNAMERecord.java b/src/main/java/org/xbill/DNS/DNAMERecord.java index 8e497c121..e0899e688 100644 --- a/src/main/java/org/xbill/DNS/DNAMERecord.java +++ b/src/main/java/org/xbill/DNS/DNAMERecord.java @@ -9,9 +9,6 @@ * @see RFC 6672: DNAME Redirection in the DNS */ public class DNAMERecord extends SingleNameBase { - - private static final long serialVersionUID = 2670767677200844154L; - DNAMERecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/DNSKEYRecord.java b/src/main/java/org/xbill/DNS/DNSKEYRecord.java index 37ffca0df..b30b3e1b7 100644 --- a/src/main/java/org/xbill/DNS/DNSKEYRecord.java +++ b/src/main/java/org/xbill/DNS/DNSKEYRecord.java @@ -36,8 +36,6 @@ private Flags() {} public static final int REVOKE = 0x80; } - private static final long serialVersionUID = -8679800040426675002L; - DNSKEYRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/DSRecord.java b/src/main/java/org/xbill/DNS/DSRecord.java index b527516e1..80de4b7d2 100644 --- a/src/main/java/org/xbill/DNS/DSRecord.java +++ b/src/main/java/org/xbill/DNS/DSRecord.java @@ -38,8 +38,6 @@ private Digest() {} public static final int GOST3411_DIGEST_ID = Digest.GOST3411; public static final int SHA384_DIGEST_ID = Digest.SHA384; - private static final long serialVersionUID = -9001819329700081493L; - private int footprint; private int alg; private int digestid; diff --git a/src/main/java/org/xbill/DNS/EmptyRecord.java b/src/main/java/org/xbill/DNS/EmptyRecord.java index 91f0cca24..332086571 100644 --- a/src/main/java/org/xbill/DNS/EmptyRecord.java +++ b/src/main/java/org/xbill/DNS/EmptyRecord.java @@ -9,9 +9,6 @@ * @author Brian Wellington */ class EmptyRecord extends Record { - - private static final long serialVersionUID = 3601852050646429582L; - EmptyRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/GPOSRecord.java b/src/main/java/org/xbill/DNS/GPOSRecord.java index 45f5ce729..0a058ee29 100644 --- a/src/main/java/org/xbill/DNS/GPOSRecord.java +++ b/src/main/java/org/xbill/DNS/GPOSRecord.java @@ -13,9 +13,6 @@ * Location */ public class GPOSRecord extends Record { - - private static final long serialVersionUID = -6349714958085750705L; - private byte[] latitude, longitude, altitude; GPOSRecord() {} diff --git a/src/main/java/org/xbill/DNS/HINFORecord.java b/src/main/java/org/xbill/DNS/HINFORecord.java index 0c9124b9a..95c614865 100644 --- a/src/main/java/org/xbill/DNS/HINFORecord.java +++ b/src/main/java/org/xbill/DNS/HINFORecord.java @@ -12,9 +12,6 @@ * Specification */ public class HINFORecord extends Record { - - private static final long serialVersionUID = -4732870630947452112L; - private byte[] cpu, os; HINFORecord() {} diff --git a/src/main/java/org/xbill/DNS/IPSECKEYRecord.java b/src/main/java/org/xbill/DNS/IPSECKEYRecord.java index f5cf8b99f..6e0d54f1e 100644 --- a/src/main/java/org/xbill/DNS/IPSECKEYRecord.java +++ b/src/main/java/org/xbill/DNS/IPSECKEYRecord.java @@ -15,9 +15,6 @@ * Material in DNS */ public class IPSECKEYRecord extends Record { - - private static final long serialVersionUID = 3050449702765909687L; - /** * Algorithm types for IPSECKEY RRs as defined in IPSECKEY diff --git a/src/main/java/org/xbill/DNS/ISDNRecord.java b/src/main/java/org/xbill/DNS/ISDNRecord.java index 155aefd7d..cddf0da36 100644 --- a/src/main/java/org/xbill/DNS/ISDNRecord.java +++ b/src/main/java/org/xbill/DNS/ISDNRecord.java @@ -11,9 +11,6 @@ * @see RFC 1183: New DNS RR Definitions */ public class ISDNRecord extends Record { - - private static final long serialVersionUID = -8730801385178968798L; - private byte[] address; private byte[] subAddress; diff --git a/src/main/java/org/xbill/DNS/KEYBase.java b/src/main/java/org/xbill/DNS/KEYBase.java index 5835d2eac..fb4f58b96 100644 --- a/src/main/java/org/xbill/DNS/KEYBase.java +++ b/src/main/java/org/xbill/DNS/KEYBase.java @@ -12,9 +12,6 @@ * @author Brian Wellington */ abstract class KEYBase extends Record { - - private static final long serialVersionUID = 3469321722693285454L; - protected int flags, proto, alg; protected byte[] key; protected int footprint = -1; diff --git a/src/main/java/org/xbill/DNS/KEYRecord.java b/src/main/java/org/xbill/DNS/KEYRecord.java index 4a9b024f1..c86b9eca7 100644 --- a/src/main/java/org/xbill/DNS/KEYRecord.java +++ b/src/main/java/org/xbill/DNS/KEYRecord.java @@ -19,9 +19,6 @@ * Delegation Signer (DS) */ public class KEYRecord extends KEYBase { - - private static final long serialVersionUID = 6385613447571488906L; - /** KEY protocol identifiers. */ public static class Protocol { diff --git a/src/main/java/org/xbill/DNS/KXRecord.java b/src/main/java/org/xbill/DNS/KXRecord.java index f2e504b93..0d598f483 100644 --- a/src/main/java/org/xbill/DNS/KXRecord.java +++ b/src/main/java/org/xbill/DNS/KXRecord.java @@ -10,9 +10,6 @@ * the DNS */ public class KXRecord extends U16NameBase { - - private static final long serialVersionUID = 7448568832769757809L; - KXRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/LOCRecord.java b/src/main/java/org/xbill/DNS/LOCRecord.java index ec9669e79..ec163b024 100644 --- a/src/main/java/org/xbill/DNS/LOCRecord.java +++ b/src/main/java/org/xbill/DNS/LOCRecord.java @@ -14,9 +14,6 @@ * Information in the Domain Name System */ public class LOCRecord extends Record { - - private static final long serialVersionUID = 9058224788126750409L; - private static NumberFormat w2, w3; private long size, hPrecision, vPrecision; private long latitude, longitude, altitude; diff --git a/src/main/java/org/xbill/DNS/MBRecord.java b/src/main/java/org/xbill/DNS/MBRecord.java index 0646d3861..0fb383bf6 100644 --- a/src/main/java/org/xbill/DNS/MBRecord.java +++ b/src/main/java/org/xbill/DNS/MBRecord.java @@ -10,9 +10,6 @@ * Specification */ public class MBRecord extends SingleNameBase { - - private static final long serialVersionUID = 532349543479150419L; - MBRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/MDRecord.java b/src/main/java/org/xbill/DNS/MDRecord.java index 7a3bf0859..d927ecebc 100644 --- a/src/main/java/org/xbill/DNS/MDRecord.java +++ b/src/main/java/org/xbill/DNS/MDRecord.java @@ -10,9 +10,6 @@ * Observations */ public class MDRecord extends SingleNameBase { - - private static final long serialVersionUID = 5268878603762942202L; - MDRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/MFRecord.java b/src/main/java/org/xbill/DNS/MFRecord.java index c3558c66e..e41cda175 100644 --- a/src/main/java/org/xbill/DNS/MFRecord.java +++ b/src/main/java/org/xbill/DNS/MFRecord.java @@ -10,9 +10,6 @@ * Observations */ public class MFRecord extends SingleNameBase { - - private static final long serialVersionUID = -6670449036843028169L; - MFRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/MGRecord.java b/src/main/java/org/xbill/DNS/MGRecord.java index 3ce52c7ab..0fa4ceaa2 100644 --- a/src/main/java/org/xbill/DNS/MGRecord.java +++ b/src/main/java/org/xbill/DNS/MGRecord.java @@ -10,9 +10,6 @@ * Specification */ public class MGRecord extends SingleNameBase { - - private static final long serialVersionUID = -3980055550863644582L; - MGRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/MINFORecord.java b/src/main/java/org/xbill/DNS/MINFORecord.java index 97340ecc0..35cf078a6 100644 --- a/src/main/java/org/xbill/DNS/MINFORecord.java +++ b/src/main/java/org/xbill/DNS/MINFORecord.java @@ -13,9 +13,6 @@ * Specification */ public class MINFORecord extends Record { - - private static final long serialVersionUID = -3962147172340353796L; - private Name responsibleAddress; private Name errorAddress; diff --git a/src/main/java/org/xbill/DNS/MRRecord.java b/src/main/java/org/xbill/DNS/MRRecord.java index 3458479ed..18f93627e 100644 --- a/src/main/java/org/xbill/DNS/MRRecord.java +++ b/src/main/java/org/xbill/DNS/MRRecord.java @@ -10,9 +10,6 @@ * Specification */ public class MRRecord extends SingleNameBase { - - private static final long serialVersionUID = -5617939094209927533L; - MRRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/MXRecord.java b/src/main/java/org/xbill/DNS/MXRecord.java index 7f148d4d6..d48064fde 100644 --- a/src/main/java/org/xbill/DNS/MXRecord.java +++ b/src/main/java/org/xbill/DNS/MXRecord.java @@ -12,9 +12,6 @@ * Record for Domains That Accept No Mail */ public class MXRecord extends U16NameBase { - - private static final long serialVersionUID = 2914841027584208546L; - MXRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/NAPTRRecord.java b/src/main/java/org/xbill/DNS/NAPTRRecord.java index 6e5a7042a..9de2557b8 100644 --- a/src/main/java/org/xbill/DNS/NAPTRRecord.java +++ b/src/main/java/org/xbill/DNS/NAPTRRecord.java @@ -13,9 +13,6 @@ * (DDDS) Part Three: The Domain Name System (DNS) Database */ public class NAPTRRecord extends Record { - - private static final long serialVersionUID = 5191232392044947002L; - private int order, preference; private byte[] flags, service, regexp; private Name replacement; diff --git a/src/main/java/org/xbill/DNS/NSAPRecord.java b/src/main/java/org/xbill/DNS/NSAPRecord.java index 6af7a921e..993391462 100644 --- a/src/main/java/org/xbill/DNS/NSAPRecord.java +++ b/src/main/java/org/xbill/DNS/NSAPRecord.java @@ -13,9 +13,6 @@ * @see RFC 1706: DNS NSAP Resource Records */ public class NSAPRecord extends Record { - - private static final long serialVersionUID = -1037209403185658593L; - private byte[] address; NSAPRecord() {} diff --git a/src/main/java/org/xbill/DNS/NSAP_PTRRecord.java b/src/main/java/org/xbill/DNS/NSAP_PTRRecord.java index 8d7fbf618..5775ce851 100644 --- a/src/main/java/org/xbill/DNS/NSAP_PTRRecord.java +++ b/src/main/java/org/xbill/DNS/NSAP_PTRRecord.java @@ -9,9 +9,6 @@ * @see RFC 1706: DNS NSAP Resource Records */ public class NSAP_PTRRecord extends SingleNameBase { - - private static final long serialVersionUID = 2386284746382064904L; - NSAP_PTRRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java b/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java index afb6727ed..89030d863 100644 --- a/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java +++ b/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java @@ -18,9 +18,6 @@ * Authenticated Denial of Existence */ public class NSEC3PARAMRecord extends Record { - - private static final long serialVersionUID = -8689038598776316533L; - private int hashAlg; private int flags; private int iterations; diff --git a/src/main/java/org/xbill/DNS/NSEC3Record.java b/src/main/java/org/xbill/DNS/NSEC3Record.java index 6e13538c4..343d21c53 100644 --- a/src/main/java/org/xbill/DNS/NSEC3Record.java +++ b/src/main/java/org/xbill/DNS/NSEC3Record.java @@ -39,8 +39,6 @@ private Digest() {} public static final int SHA1_DIGEST_ID = Digest.SHA1; - private static final long serialVersionUID = -7123504635968932855L; - private int hashAlg; private int flags; private int iterations; diff --git a/src/main/java/org/xbill/DNS/NSECRecord.java b/src/main/java/org/xbill/DNS/NSECRecord.java index 0f0a42106..1dde5a3bd 100644 --- a/src/main/java/org/xbill/DNS/NSECRecord.java +++ b/src/main/java/org/xbill/DNS/NSECRecord.java @@ -17,9 +17,6 @@ * Security Extensions */ public class NSECRecord extends Record { - - private static final long serialVersionUID = -5165065768816265385L; - private Name next; private TypeBitmap types; diff --git a/src/main/java/org/xbill/DNS/NSIDOption.java b/src/main/java/org/xbill/DNS/NSIDOption.java index 11f92fe29..a10b5568a 100644 --- a/src/main/java/org/xbill/DNS/NSIDOption.java +++ b/src/main/java/org/xbill/DNS/NSIDOption.java @@ -11,9 +11,6 @@ * Option */ public class NSIDOption extends GenericEDNSOption { - - private static final long serialVersionUID = 74739759292589056L; - NSIDOption() { super(EDNSOption.Code.NSID); } diff --git a/src/main/java/org/xbill/DNS/NSRecord.java b/src/main/java/org/xbill/DNS/NSRecord.java index 1ed2d7cf3..e7f3a46b7 100644 --- a/src/main/java/org/xbill/DNS/NSRecord.java +++ b/src/main/java/org/xbill/DNS/NSRecord.java @@ -10,9 +10,6 @@ * Specification */ public class NSRecord extends SingleCompressedNameBase { - - private static final long serialVersionUID = 487170758138268838L; - NSRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/NULLRecord.java b/src/main/java/org/xbill/DNS/NULLRecord.java index 4aabed60d..96bd4fee1 100644 --- a/src/main/java/org/xbill/DNS/NULLRecord.java +++ b/src/main/java/org/xbill/DNS/NULLRecord.java @@ -12,9 +12,6 @@ * Specification */ public class NULLRecord extends Record { - - private static final long serialVersionUID = -5796493183235216538L; - private byte[] data; NULLRecord() {} diff --git a/src/main/java/org/xbill/DNS/NXTRecord.java b/src/main/java/org/xbill/DNS/NXTRecord.java index 6a0da4cd8..5f060f5d9 100644 --- a/src/main/java/org/xbill/DNS/NXTRecord.java +++ b/src/main/java/org/xbill/DNS/NXTRecord.java @@ -15,9 +15,6 @@ * Extensions */ public class NXTRecord extends Record { - - private static final long serialVersionUID = -8851454400765507520L; - private Name next; private BitSet bitmap; diff --git a/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java b/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java index e66553e45..9a78b7180 100644 --- a/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java +++ b/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java @@ -12,9 +12,6 @@ * Entities (DANE) Bindings for OpenPGP */ public class OPENPGPKEYRecord extends Record { - - private static final long serialVersionUID = -1277262990243423062L; - private byte[] cert; OPENPGPKEYRecord() {} diff --git a/src/main/java/org/xbill/DNS/OPTRecord.java b/src/main/java/org/xbill/DNS/OPTRecord.java index 2018f7578..89ffea04b 100644 --- a/src/main/java/org/xbill/DNS/OPTRecord.java +++ b/src/main/java/org/xbill/DNS/OPTRecord.java @@ -20,9 +20,6 @@ * @author Brian Wellington */ public class OPTRecord extends Record { - - private static final long serialVersionUID = -6254521894809367938L; - private List options; OPTRecord() {} diff --git a/src/main/java/org/xbill/DNS/PTRRecord.java b/src/main/java/org/xbill/DNS/PTRRecord.java index f0110c40d..b624bb4c7 100644 --- a/src/main/java/org/xbill/DNS/PTRRecord.java +++ b/src/main/java/org/xbill/DNS/PTRRecord.java @@ -10,9 +10,6 @@ * Specification */ public class PTRRecord extends SingleCompressedNameBase { - - private static final long serialVersionUID = -8321636610425434192L; - PTRRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/PXRecord.java b/src/main/java/org/xbill/DNS/PXRecord.java index 34307fa2b..14d65e564 100644 --- a/src/main/java/org/xbill/DNS/PXRecord.java +++ b/src/main/java/org/xbill/DNS/PXRecord.java @@ -12,9 +12,6 @@ * MIXER Conformant Global Address Mapping (MCGAM) */ public class PXRecord extends Record { - - private static final long serialVersionUID = 1811540008806660667L; - private int preference; private Name map822; private Name mapX400; diff --git a/src/main/java/org/xbill/DNS/RPRecord.java b/src/main/java/org/xbill/DNS/RPRecord.java index ea546db55..795979fa2 100644 --- a/src/main/java/org/xbill/DNS/RPRecord.java +++ b/src/main/java/org/xbill/DNS/RPRecord.java @@ -13,9 +13,6 @@ * @see RFC 1183: New DNS RR Definitions */ public class RPRecord extends Record { - - private static final long serialVersionUID = 8124584364211337460L; - private Name mailbox; private Name textDomain; diff --git a/src/main/java/org/xbill/DNS/RRSIGRecord.java b/src/main/java/org/xbill/DNS/RRSIGRecord.java index a157c5522..b8f6b8aca 100644 --- a/src/main/java/org/xbill/DNS/RRSIGRecord.java +++ b/src/main/java/org/xbill/DNS/RRSIGRecord.java @@ -18,9 +18,6 @@ * @author Brian Wellington */ public class RRSIGRecord extends SIGBase { - - private static final long serialVersionUID = 7453923738152214746L; - RRSIGRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/RTRecord.java b/src/main/java/org/xbill/DNS/RTRecord.java index 3738680a9..41f46828f 100644 --- a/src/main/java/org/xbill/DNS/RTRecord.java +++ b/src/main/java/org/xbill/DNS/RTRecord.java @@ -10,9 +10,6 @@ * Specification */ public class RTRecord extends U16NameBase { - - private static final long serialVersionUID = -3206215651648278098L; - RTRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index 25efde973..8b28d4def 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -4,7 +4,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.Serializable; import java.text.DecimalFormat; import java.util.Arrays; import org.xbill.DNS.utils.base16; @@ -15,7 +14,7 @@ * * @author Brian Wellington */ -public abstract class Record implements Cloneable, Comparable, Serializable { +public abstract class Record implements Cloneable, Comparable { protected Name name; protected int type, dclass; protected long ttl; diff --git a/src/main/java/org/xbill/DNS/SIGRecord.java b/src/main/java/org/xbill/DNS/SIGRecord.java index 49fd98950..0053d823e 100644 --- a/src/main/java/org/xbill/DNS/SIGRecord.java +++ b/src/main/java/org/xbill/DNS/SIGRecord.java @@ -17,9 +17,6 @@ * @author Brian Wellington */ public class SIGRecord extends SIGBase { - - private static final long serialVersionUID = -2121567461284199774L; - SIGRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/SOARecord.java b/src/main/java/org/xbill/DNS/SOARecord.java index 3313abdfe..923704364 100644 --- a/src/main/java/org/xbill/DNS/SOARecord.java +++ b/src/main/java/org/xbill/DNS/SOARecord.java @@ -12,9 +12,6 @@ * Specification */ public class SOARecord extends Record { - - private static final long serialVersionUID = 1049740098229303931L; - private Name host, admin; private long serial, refresh, retry, expire, minimum; diff --git a/src/main/java/org/xbill/DNS/SPFRecord.java b/src/main/java/org/xbill/DNS/SPFRecord.java index 6a2f39b18..1c9f2e96a 100644 --- a/src/main/java/org/xbill/DNS/SPFRecord.java +++ b/src/main/java/org/xbill/DNS/SPFRecord.java @@ -12,9 +12,6 @@ * Authorizing Use of Domains in Email, Version 1 */ public class SPFRecord extends TXTBase { - - private static final long serialVersionUID = -2100754352801658722L; - SPFRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/SRVRecord.java b/src/main/java/org/xbill/DNS/SRVRecord.java index 5d14b5e29..09437f80c 100644 --- a/src/main/java/org/xbill/DNS/SRVRecord.java +++ b/src/main/java/org/xbill/DNS/SRVRecord.java @@ -14,9 +14,6 @@ * of services (DNS SRV) */ public class SRVRecord extends Record { - - private static final long serialVersionUID = -3886460132387522052L; - private int priority, weight, port; private Name target; diff --git a/src/main/java/org/xbill/DNS/SSHFPRecord.java b/src/main/java/org/xbill/DNS/SSHFPRecord.java index 265188468..f9e21b026 100644 --- a/src/main/java/org/xbill/DNS/SSHFPRecord.java +++ b/src/main/java/org/xbill/DNS/SSHFPRecord.java @@ -13,9 +13,6 @@ * Shell (SSH) Key Fingerprints */ public class SSHFPRecord extends Record { - - private static final long serialVersionUID = -8104701402654687025L; - public static class Algorithm { private Algorithm() {} diff --git a/src/main/java/org/xbill/DNS/SingleCompressedNameBase.java b/src/main/java/org/xbill/DNS/SingleCompressedNameBase.java index 59a0615bf..c302ca43d 100644 --- a/src/main/java/org/xbill/DNS/SingleCompressedNameBase.java +++ b/src/main/java/org/xbill/DNS/SingleCompressedNameBase.java @@ -9,9 +9,6 @@ * @author Brian Wellington */ abstract class SingleCompressedNameBase extends SingleNameBase { - - private static final long serialVersionUID = -236435396815460677L; - protected SingleCompressedNameBase() {} protected SingleCompressedNameBase( diff --git a/src/main/java/org/xbill/DNS/SingleNameBase.java b/src/main/java/org/xbill/DNS/SingleNameBase.java index 8a8b8ccac..370b29730 100644 --- a/src/main/java/org/xbill/DNS/SingleNameBase.java +++ b/src/main/java/org/xbill/DNS/SingleNameBase.java @@ -10,9 +10,6 @@ * @author Brian Wellington */ abstract class SingleNameBase extends Record { - - private static final long serialVersionUID = -18595042501413L; - protected Name singleName; protected SingleNameBase() {} diff --git a/src/main/java/org/xbill/DNS/TKEYRecord.java b/src/main/java/org/xbill/DNS/TKEYRecord.java index 6c3b8701f..fd2f65297 100644 --- a/src/main/java/org/xbill/DNS/TKEYRecord.java +++ b/src/main/java/org/xbill/DNS/TKEYRecord.java @@ -16,9 +16,6 @@ * (TKEY RR) */ public class TKEYRecord extends Record { - - private static final long serialVersionUID = -7330934927273584334L; - private Name alg; private Instant timeInception; private Instant timeExpire; diff --git a/src/main/java/org/xbill/DNS/TLSARecord.java b/src/main/java/org/xbill/DNS/TLSARecord.java index fff6cea6d..564743144 100644 --- a/src/main/java/org/xbill/DNS/TLSARecord.java +++ b/src/main/java/org/xbill/DNS/TLSARecord.java @@ -13,9 +13,6 @@ * Named Entities (DANE) Transport Layer Security (TLS) Protocol: TLSA */ public class TLSARecord extends Record { - - private static final long serialVersionUID = 356494267028580169L; - public static class CertificateUsage { private CertificateUsage() {} diff --git a/src/main/java/org/xbill/DNS/TSIGRecord.java b/src/main/java/org/xbill/DNS/TSIGRecord.java index f3c822616..1ea8c5f40 100644 --- a/src/main/java/org/xbill/DNS/TSIGRecord.java +++ b/src/main/java/org/xbill/DNS/TSIGRecord.java @@ -19,9 +19,6 @@ * @author Brian Wellington */ public class TSIGRecord extends Record { - - private static final long serialVersionUID = -2649450085333713717L; - private Name alg; private Instant timeSigned; private Duration fudge; diff --git a/src/main/java/org/xbill/DNS/TXTBase.java b/src/main/java/org/xbill/DNS/TXTBase.java index 6dd1b1440..0fbe6a867 100644 --- a/src/main/java/org/xbill/DNS/TXTBase.java +++ b/src/main/java/org/xbill/DNS/TXTBase.java @@ -14,9 +14,6 @@ * @author Brian Wellington */ abstract class TXTBase extends Record { - - private static final long serialVersionUID = -4319510507246305931L; - protected List strings; protected TXTBase() {} diff --git a/src/main/java/org/xbill/DNS/TXTRecord.java b/src/main/java/org/xbill/DNS/TXTRecord.java index d00df7690..0c5d56a61 100644 --- a/src/main/java/org/xbill/DNS/TXTRecord.java +++ b/src/main/java/org/xbill/DNS/TXTRecord.java @@ -12,9 +12,6 @@ * Specification */ public class TXTRecord extends TXTBase { - - private static final long serialVersionUID = -5780785764284221342L; - TXTRecord() {} @Override diff --git a/src/main/java/org/xbill/DNS/U16NameBase.java b/src/main/java/org/xbill/DNS/U16NameBase.java index e92df3dd5..25ee8811a 100644 --- a/src/main/java/org/xbill/DNS/U16NameBase.java +++ b/src/main/java/org/xbill/DNS/U16NameBase.java @@ -11,9 +11,6 @@ * @author Brian Wellington */ abstract class U16NameBase extends Record { - - private static final long serialVersionUID = -8315884183112502995L; - protected int u16Field; protected Name nameField; diff --git a/src/main/java/org/xbill/DNS/UNKRecord.java b/src/main/java/org/xbill/DNS/UNKRecord.java index b409cf96d..fa3c8442b 100644 --- a/src/main/java/org/xbill/DNS/UNKRecord.java +++ b/src/main/java/org/xbill/DNS/UNKRecord.java @@ -11,9 +11,6 @@ * @author Brian Wellington */ public class UNKRecord extends Record { - - private static final long serialVersionUID = -4193583311594626915L; - private byte[] data; UNKRecord() {} diff --git a/src/main/java/org/xbill/DNS/URIRecord.java b/src/main/java/org/xbill/DNS/URIRecord.java index 4256a7a28..84733b9d4 100644 --- a/src/main/java/org/xbill/DNS/URIRecord.java +++ b/src/main/java/org/xbill/DNS/URIRecord.java @@ -13,9 +13,6 @@ * (URI) DNS Resource Record */ public class URIRecord extends Record { - - private static final long serialVersionUID = 7955422413971804232L; - private int priority, weight; private byte[] target; diff --git a/src/main/java/org/xbill/DNS/WKSRecord.java b/src/main/java/org/xbill/DNS/WKSRecord.java index 2d179a4a6..60bab2229 100644 --- a/src/main/java/org/xbill/DNS/WKSRecord.java +++ b/src/main/java/org/xbill/DNS/WKSRecord.java @@ -17,9 +17,6 @@ * Specification */ public class WKSRecord extends Record { - - private static final long serialVersionUID = -9104259763909119805L; - /** * IP protocol identifiers. This is basically copied out of RFC 1010. * diff --git a/src/main/java/org/xbill/DNS/X25Record.java b/src/main/java/org/xbill/DNS/X25Record.java index 438be9911..ea779e0b0 100644 --- a/src/main/java/org/xbill/DNS/X25Record.java +++ b/src/main/java/org/xbill/DNS/X25Record.java @@ -12,9 +12,6 @@ * @see RFC 1183: New DNS RR Definitions */ public class X25Record extends Record { - - private static final long serialVersionUID = 4267576252335579764L; - private byte[] address; X25Record() {} From 02d2816daa54da9965e8bd9066d92b74ebe7f930 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 19 Jan 2020 13:20:46 +0100 Subject: [PATCH 056/431] Cleanup of examples and documentation --- EXAMPLES.md | 19 +++-- README.md | 237 +++++++++++++++++++++++++++++++++++++++++++--------- USAGE | 60 ------------- USAGE.md | 73 ++++++++++++++++ pom.xml | 8 +- 5 files changed, 286 insertions(+), 111 deletions(-) delete mode 100644 USAGE create mode 100644 USAGE.md diff --git a/EXAMPLES.md b/EXAMPLES.md index 629411ce8..f7e7c89d7 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -1,6 +1,6 @@ -# dnsjava examples +# dnsjava Examples -All of these examples are code fragments. Code using these fragments should +All of these examples are code fragments. Code using these fragments should check exceptions when appropriate, and should: ```java @@ -16,8 +16,8 @@ InetAddress addr = Address.getByName("www.dnsjava.org"); ## Get the MX target and preference of a name ```java -Record [] records = new Lookup("gmail.com", Type.MX).run(); -for (int i = 0; i < records.length; i++) { +Record[] records = new Lookup("gmail.com", Type.MX).run(); +for (int i = 0; i < records.length; i++) { MXRecord mx = (MXRecord) records[i]; System.out.println("Host " + mx.getTarget() + " has preference " + mx.getPriority()); } @@ -29,17 +29,19 @@ for (int i = 0; i < records.length; i++) { Lookup l = new Lookup("version.bind.", Type.TXT, DClass.CH); l.setResolver(new SimpleResolver(args[0])); l.run(); -if (l.getResult() == Lookup.SUCCESSFUL) +if (l.getResult() == Lookup.SUCCESSFUL) { System.out.println(l.getAnswers()[0].rdataToString()); +} ``` ## Transfer a zone from a server and print it ```java -ZoneTransferIn xfr = ZoneTransferIn.newAXFR(new Name("."), "192.5.5.241", null); +ZoneTransferIn xfr = ZoneTransferIn.newAXFR(Name.root, "192.5.5.241", null); List records = xfr.run(); -for (Iterator it = records.iterator(); it.hasNext(); ) +for (Iterator it = records.iterator(); it.hasNext();) { System.out.println(it.next()); +} ``` ## Use DNS dynamic update to set the address of a host to a value specified on the command line @@ -73,6 +75,7 @@ System.out.println(n2.equals(n)); // True // www // dnsjava // org -for (int i = 0; i < n.labels(); i++) +for (int i = 0; i < n.labels(); i++) { System.out.println(n.getLabelString(i)); +} ``` diff --git a/README.md b/README.md index aa55b2dab..45d30f7be 100644 --- a/README.md +++ b/README.md @@ -7,18 +7,18 @@ ## Overview -dnsjava is an implementation of DNS in Java. It supports all defined record -types (including the DNSSEC types), and unknown types. It can be used for -queries, zone transfers, and dynamic updates. It includes a cache which can be -used by clients, and an authoritative only server. It supports TSIG -authenticated messages, partial DNSSEC verification, and EDNS0. It is fully -thread safe. It can be used to replace the native DNS support in Java. - -dnsjava was started as an excuse to learn Java. It was useful for testing new -features in BIND without rewriting the C resolver. It was then cleaned up and +dnsjava is an implementation of DNS in Java. It supports almost all defined record +types (including the DNSSEC types), and unknown types. It can be used for +queries, zone transfers, and dynamic updates. It includes a cache which can be +used by clients, and an authoritative only server. It supports TSIG +authenticated messages, partial DNSSEC verification, and EDNS0. It is fully +thread safe. + +dnsjava was started as an excuse to learn Java. It was useful for testing new +features in BIND without rewriting the C resolver. It was then cleaned up and extended in order to be used as a testing framework for DNS interoperability -testing. The high level API and caching resolver were added to make it useful -to a wider audience. The authoritative only server was added as proof of +testing. The high level API and caching resolver were added to make it useful +to a wider audience. The authoritative only server was added as proof of concept. ## dnsjava on Github @@ -30,66 +30,215 @@ As of 2019-05-15, Github is [officially](https://sourceforge.net/p/dnsjava/mailman/message/36666800/) the new home of dnsjava. -Please use the Github [issue tracker](https://github.com/dnsjava/dnsjava/issues) and send - well tested - pull -requests. The +Please use the Github [issue tracker](https://github.com/dnsjava/dnsjava/issues) +and send - well tested - pull requests. The [dnsjava-users@lists.sourceforge.net](mailto:dnsjava-users@lists.sourceforge.net) mailing list still exists. -## Author - -- Brian Wellington (@bwelling), March 12, 2004 -- Various contributors, see [Changelog](Changelog) - ## Getting started -Run `mvn package` from the toplevel directory to build dnsjava. JDK 1.4 -or higher is required. - -### Replacing the standard Java DNS functionality: - -Java versions from 1.4 to 1.8 can load DNS service providers at runtime. The +### Config options +Some settings of dnsjava can be configured via +[system properties](https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDefaultExample
Explanation
dns.serverString-8.8.8.8,[2001:4860:4860::8888]:853,dns.google
DNS server(s) to use for resolving. Comma separated list. Can be IPv4/IPv6 addresses or hostnames (which are resolved using Java's built in DNS support).
dns.searchString-ds.example.com,example.com
Comma separated list of DNS search paths.
dns.ndotsInteger12
Sets a threshold for the number of dots which must appear in a name given to resolve before an initial absolute query will be made.
dnsjava.optionsoption list-BINDTTL,tsigfudge=1
Comma separated key-value pairs, see below.
dnsjava.configprovider.sunjvm.enabledBooleanfalsetrue
Set to true to enable the reflection based DNS server lookup, see limitations below.
dnsjava.udp.ephemeral.startInteger49152 (Linux: 32768)50000
First ephemeral port for UDP-based DNS queries.
dnsjava.udp.ephemeral.endInteger65535 (Linux: 60999)60000
Last ephemeral port for UDP-based DNS queries.
dnsjava.udp.ephemeral.use_ephemeral_portBooleanfalsetrue
Use an OS-assigned ephemeral port for UDP queries. Enabling this option is insecure! Do NOT use it.
+ +#### dnsjava.options pairs +The dnsjava.options configuration options can also be set programmatically +through the `Options` class. Please refer to the Javadoc for details. + +| Key | Type | Default | Explanation | +| --- | ---- | -------| ----------- | +| BINDTTL | Boolean | false | Print TTLs in BIND format | +| multiline | Boolean | false | Print records in multiline format | +| noPrintIN | Boolean | false | Don't print the class of a record if it's IN | +| tsigfudge | Integer | 300 | Sets the default TSIG fudge value (in seconds) | +| sig0validity | Integer | 300 | Sets the default SIG(0) validity period (in seconds) | + +### Resolvers +dnsjava comes with several built-in resolvers: +- `SimpleResolver`: a basic resolver that uses UDP by default and falls back + to TCP if required. +- `ExtendedResolver`: a resolver that uses multiple `SimpleResolver`s to send + the queries. Can be configured to query the servers in a round-robin order. + Blacklists a server if it times out. +- `DohResolver`: a very basic DNS over HTTP resolver, e.g. to use + `https://dns.google/query`. + +The project [dnssecjava](https://github.com/ibauersachs/dnssecjava) has a +resolver that validates responses with DNSSEC. + +### Migrating from version 2.1.x to v3 +dnsjava 3 has significant API changes compared to version 2.1.x and is +neither source nor binary compatible. The most important changes are: +- The minimum supported version is Java 8 +- Uses [slf4j](http://www.slf4j.org/) for logging and thus needs `slf4j-api` + on the classpath +- The [command line tools](USAGE.md) were moved to the `org.xbill.DNS.tools` + package +- On Windows, [JNA](https://github.com/java-native-access/jna) should be + on the classpath for the search path +- The `Resolver` API for custom resolvers has changed to use + `CompletionStage` for asynchronous resolving. The built-in + resolvers are now fully non-blocking and do not start a thread per + query anymore. +- Many methods return a `List` instead of an array. Ideally, use a + for-each loop. If this isn't possible, call `size()` instead of + using `length`: + - Cache#findAnyRecords + - Cache#findRecords + - Lookup#getDefaultSearchPath + - Message#getSectionRRsets + - SetResponse#answers + - ResolverConfig +- RRset returns a List instead of an `Iterator`. Ideally, modify your + code to use a for-each loop. If this is not possible, create an iterator + on the returned list: + - RRset#rrs + - RRset#sigs +- Methods using `java.util.Date` are deprecated. Use the new versions with + `java.time.Instant` or `java.time.Duration` instead +- The type hierarchy of `SMIMEARecord` changed, it now inherits from + `TLSARecord` and constants are shared +- `Record`s are no longer marked as `Serializable`. Use the RFC defined + serialization formats: + - `toString()`, `rrToString()` <-> `fromString()` + - `toWire()` <-> `fromWire()`, `newRecord()` +- `Message` and `Header` properly supported `clone()` + +### Replacing the standard Java DNS functionality + +Java versions from 1.4 to 8 can load DNS service providers at runtime. The functionality was [removed in JDK 9](https://bugs.openjdk.java.net/browse/JDK-8134577), a replacement is [requested](https://bugs.openjdk.java.net/browse/JDK-8192780), but so far has not been implemented. -To load the dnsjava service provider, build dnsjava on a JDK that still -supports the SPI and set the system property: +To load the dnsjava service provider, build dnsjava on JDK 8 and set the system property: sun.net.spi.nameservice.provider.1=dns,dnsjava This instructs the JVM to use the dnsjava service provide for DNS at the highest priority. +### Build -## Testing dnsjava +Run `mvn package` from the toplevel directory to build dnsjava. JDK 8 +or higher is required. -[Matt Rutherford](mailto:rutherfo@cs.colorado.edu) contributed a number of unit -tests, which are in the tests subdirectory. The hierarchy under tests -mirrors the org.xbill.DNS classes. To run the unit tests, execute -`mvn test`. The tests require JUnit. +### Testing dnsjava -Some high-level test programs are in `org/xbill/DNS/tests`. +[Matt Rutherford](mailto:rutherfo@cs.colorado.edu) contributed a number of unit +tests, which are in the tests subdirectory. The hierarchy under tests +mirrors the org.xbill.DNS classes. To run the unit tests, execute +`mvn test`. ## Limitations There's no standard way to determine what the local nameserver or DNS search -path is at runtime from within the JVM. dnsjava attempts several methods +path is at runtime from within the JVM. dnsjava attempts several methods until one succeeds. - The properties `dns.server` and `dns.search` (comma delimited lists) are - checked. The servers can either be IP addresses or hostnames (which are + checked. The servers can either be IP addresses or hostnames (which are resolved using Java's built in DNS support). -- The `sun.net.dns.ResolverConfiguration` class is queried. -- On Unix, `/etc/resolv.conf` is parsed. -- On Windows, `ipconfig`/`winipcfg` is called and its output parsed. This may - fail for non-English versions on Windows. +- On Unix/Solaris, `/etc/resolv.conf` is parsed. +- On Windows, if [JNA](https://github.com/java-native-access/jna) is available + on the classpath, the `GetAdaptersAddresses` API is used. +- On Android, depending on the SDK level, either the properties `net.dns[1234]` + or the `ConnectivityManager` is used (requires initialization). +- The `sun.net.dns.ResolverConfiguration` class is queried if enabled. +- If available and no servers have been found yet, + [JNDI-DNS](https://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-dns.html) is used. - As a last resort, `localhost` is used as the nameserver, and the search path is empty. -The underlying platform must use an ASCII encoding of characters. This means -that dnsjava will not work on OS/390, for example. - ## Additional documentation @@ -103,6 +252,12 @@ at [javadoc.io](http://javadoc.io/doc/dnsjava/dnsjava). See the dnsjava is placed under the [BSD license](LICENSE). Several files are also under additional licenses; see the individual files for details. +## Authors + +- Brian Wellington (@bwelling), March 12, 2004 +- Various contributors, see [Changelog](Changelog) +- Ingo Bauersachs (@ibauersachs), current maintainer + ## Final notes - Thanks to Network Associates, Inc. for sponsoring some of the original dnsjava work in 1999-2000. diff --git a/USAGE b/USAGE deleted file mode 100644 index cb74210f9..000000000 --- a/USAGE +++ /dev/null @@ -1,60 +0,0 @@ -dnsjava v2.0 - -dnsjava provides several command line programs, which are documented here. -For examples of API usage, see examples.html. - -- dig: - A clone of dig (as distributed with BIND) - dig @server [-x] name type [class] [-p port] [-k name/secret] [-t] \ - [-i] [-e n] [-d] - -x : reverse lookup, name must be a dotted quad - -k : use TSIG transaction security - -t : use TCP by default - -i : ignore truncation errors - -e n: Use EDNS level n (only 0 is defined) - -d : Set the DNSSEC OK bit - -- update: - A dynamic update client with some extra functionality. This can be - used either interactively or by specifying a file containing commands - to be executed. Running 'help' lists all other commands. - update [file] - - -- jnamed: - A basic authoritative only (non-caching, non-recursive) server. It's - not very good, but it's also a whole lot better than it used to be. - - The config file (jnamed.conf by default) supports the following - directives: - primary - secondary - cache - key [algorithm] - address - port - - If no addresses are specified, jnamed will listen on all addresses, - using a wildcard socket. If no ports are specified, jnamed will - listen on port 53. - - The following is an example: - primary internal /etc/namedb/internal.db - secondary xbill.org 127.0.0.1 - cache /etc/namedb/cache.db - key xbill.org 1234 - address 127.0.0.1 - port 12345 - - To run: - jnamed [config_file] - - jnamed should not be used for production, and should probably - not be used for testing. If the above documentation is not enough, - please do not ask for more, because it really should not be used. - -- lookup: - A simple program that looks up records associated with names. - If no type is specified, address lookups are done. - - lookup [-t type] name ... diff --git a/USAGE.md b/USAGE.md new file mode 100644 index 000000000..18729d1c0 --- /dev/null +++ b/USAGE.md @@ -0,0 +1,73 @@ +dnsjava Command Line Tools +========================== + +dnsjava provides several command line programs, which are documented here. +For examples of API usage, see the [examples](EXAMPLES.md). To run them, +at least `dnsjava` and `slf4j-api` need to be on the classpath. A basic +invocation could thus look as follows: + + java -cp dnsjava.jar;slf4-api.jar org.xbill.DNS.tools.Tools [tool] + +dig +--- +A basic, incomplete clone of dig (as distributed with BIND) + + dig @server [-x] name type [class] [-p port] [-k name/secret] [-t] \ + [-i] [-e n] [-d] + -x : reverse lookup, name must be a dotted quad + -k : use TSIG transaction security + -t : use TCP by default + -i : ignore truncation errors + -e n: Use EDNS level n (only 0 is defined) + -d : Set the DNSSEC OK bit + +update +------ +A dynamic update client with some extra functionality. This can be +used either interactively or by specifying a file containing commands +to be executed. Running 'help' lists all other commands. + + update [file] + +jnamed +------ +A basic authoritative only (non-caching, non-recursive) server. It's +not very good, but it's also a whole lot better than it used to be. + +The config file (`jnamed.conf` by default) supports the following +directives: + + primary + secondary + cache + key [algorithm] + address + port + +If no addresses are specified, jnamed will listen on all addresses, +using a wildcard socket. If no ports are specified, jnamed will +listen on port 53. + +The following is an example: + + primary internal /etc/namedb/internal.db + secondary xbill.org 127.0.0.1 + cache /etc/namedb/cache.db + key xbill.org 1234 + address 127.0.0.1 + port 12345 + +To run: + + jnamed [config_file] + +jnamed should not be used for production, and should probably +not be used for testing. If the above documentation is not enough, +please do not ask for more, because it really should not be used. + +lookup +------ +A simple program that looks up records associated with names. +If no type is specified, address lookups (A) are done. + + lookup [-t type] name ... diff --git a/pom.xml b/pom.xml index bc7520d01..105b9df46 100644 --- a/pom.xml +++ b/pom.xml @@ -14,10 +14,10 @@ which can be used by clients, and a minimal implementation of a server. It supports TSIG authenticated messages, partial DNSSEC verification, and EDNS0. - http://www.dnsjava.org + https://github.com/dnsjava/dnsjava dnsjava.org - http://www.dnsjava.org + https://github.com/dnsjava/dnsjava @@ -37,6 +37,10 @@ bwelling Brian Wellington + + ibauersachs + Ingo Bauersachs + From 624dc606d21cf36c20ba5c2664c0ca777ed4ffa9 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 19 Jan 2020 13:22:41 +0100 Subject: [PATCH 057/431] Cleanup remaining use of raw types --- EXAMPLES.md | 6 ++-- src/main/java/org/xbill/DNS/Cache.java | 11 +++---- .../java/org/xbill/DNS/SimpleResolver.java | 6 ++-- src/main/java/org/xbill/DNS/Zone.java | 30 +++++++++---------- .../java/org/xbill/DNS/ZoneTransferIn.java | 16 ++++------ src/main/java/org/xbill/DNS/tools/xfrin.java | 12 ++++---- .../java/org/xbill/DNS/APLRecordTest.java | 2 +- 7 files changed, 38 insertions(+), 45 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index f7e7c89d7..6ea8a0c0a 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -38,9 +38,9 @@ if (l.getResult() == Lookup.SUCCESSFUL) { ```java ZoneTransferIn xfr = ZoneTransferIn.newAXFR(Name.root, "192.5.5.241", null); -List records = xfr.run(); -for (Iterator it = records.iterator(); it.hasNext();) { - System.out.println(it.next()); +xfr.run(); +for (Record r : xfr.getAXFR()) { + System.out.println(r); } ``` diff --git a/src/main/java/org/xbill/DNS/Cache.java b/src/main/java/org/xbill/DNS/Cache.java index e309803ef..f16d60321 100644 --- a/src/main/java/org/xbill/DNS/Cache.java +++ b/src/main/java/org/xbill/DNS/Cache.java @@ -218,9 +218,9 @@ private synchronized Element oneElement(Name name, Object types, int type, int m throw new IllegalArgumentException("oneElement(ANY)"); } if (types instanceof List) { - List list = (List) types; - for (Object o : list) { - Element set = (Element) o; + @SuppressWarnings("unchecked") + List list = (List) types; + for (Element set : list) { if (set.getType() == type) { found = set; break; @@ -290,9 +290,10 @@ private synchronized void removeElement(Name name, int type) { return; } if (types instanceof List) { - List list = (List) types; + @SuppressWarnings("unchecked") + List list = (List) types; for (int i = 0; i < list.size(); i++) { - Element elt = (Element) list.get(i); + Element elt = list.get(i); if (elt.getType() == type) { list.remove(i); if (list.size() == 0) { diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index 4b6dc29a7..ab8104db2 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -371,13 +371,13 @@ private Message sendAXFR(Message query) throws IOException { } catch (ZoneTransferException e) { throw new WireParseException(e.getMessage()); } - List records = xfrin.getAXFR(); + List records = xfrin.getAXFR(); Message response = new Message(query.getHeader().getID()); response.getHeader().setFlag(Flags.AA); response.getHeader().setFlag(Flags.QR); response.addRecord(query.getQuestion(), Section.QUESTION); - for (Object record : records) { - response.addRecord((Record) record, Section.ANSWER); + for (Record record : records) { + response.addRecord(record, Section.ANSWER); } return response; } diff --git a/src/main/java/org/xbill/DNS/Zone.java b/src/main/java/org/xbill/DNS/Zone.java index 8a8875054..9d5fda4ef 100644 --- a/src/main/java/org/xbill/DNS/Zone.java +++ b/src/main/java/org/xbill/DNS/Zone.java @@ -29,13 +29,12 @@ public class Zone implements Serializable { private Map data; private Name origin; private Object originNode; - private int dclass = DClass.IN; private RRset NS; private SOARecord SOA; private boolean hasWild; class ZoneIterator implements Iterator { - private Iterator zentries; + private Iterator> zentries; private RRset[] current; private int count; private boolean wantLastSOA; @@ -77,7 +76,7 @@ public RRset next() { if (count == current.length) { current = null; while (zentries.hasNext()) { - Map.Entry entry = (Map.Entry) zentries.next(); + Map.Entry entry = zentries.next(); if (entry.getKey().equals(origin)) { continue; } @@ -178,14 +177,14 @@ private void fromXFR(ZoneTransferIn xfrin) throws IOException, ZoneTransferExcep } origin = xfrin.getName(); - List records = xfrin.run(); - for (Object o : records) { - Record record = (Record) o; - maybeAddRecord(record); - } + xfrin.run(); if (!xfrin.isAXFR()) { throw new IllegalArgumentException("zones can only be created from AXFRs"); } + + for (Record record : xfrin.getAXFR()) { + maybeAddRecord(record); + } validate(); } @@ -227,7 +226,7 @@ public SOARecord getSOA() { /** Returns the Zone's class */ public int getDClass() { - return dclass; + return DClass.IN; } private synchronized Object exactName(Name name) { @@ -245,7 +244,7 @@ private synchronized RRset[] allRRsets(Object types) { } } - private synchronized RRset oneRRset(Object types, int type) { + private synchronized RRset oneRRset(Object types, int type) { if (type == Type.ANY) { throw new IllegalArgumentException("oneRRset(ANY)"); } @@ -266,7 +265,7 @@ private synchronized RRset oneRRset(Object types, int type) { return null; } - private synchronized RRset findRRset(Name name, int type) { + private synchronized RRset findRRset(Name name, int type) { Object types = exactName(name); if (types == null) { return null; @@ -314,9 +313,10 @@ private synchronized void removeRRset(Name name, int type) { return; } if (types instanceof List) { - List list = (List) types; + @SuppressWarnings("unchecked") + List list = (List) types; for (int i = 0; i < list.size(); i++) { - RRset set = (RRset) list.get(i); + RRset set = list.get(i); if (set.getType() == type) { list.remove(i); if (list.size() == 0) { @@ -454,7 +454,7 @@ public SetResponse findRecords(Name name, int type) { * @return The matching RRset * @see RRset */ - public RRset findExactMatch(Name name, int type) { + public RRset findExactMatch(Name name, int type) { Object types = exactName(name); if (types == null) { return null; @@ -499,7 +499,7 @@ public void addRecord(T r) { * @param r The record to be removed * @see Record */ - public void removeRecord(T r) { + public void removeRecord(Record r) { Name name = r.getName(); int rtype = r.getRRsetType(); synchronized (this) { diff --git a/src/main/java/org/xbill/DNS/ZoneTransferIn.java b/src/main/java/org/xbill/DNS/ZoneTransferIn.java index 112c2ead9..fd90823d8 100644 --- a/src/main/java/org/xbill/DNS/ZoneTransferIn.java +++ b/src/main/java/org/xbill/DNS/ZoneTransferIn.java @@ -560,22 +560,16 @@ public void run(ZoneTransferHandler handler) throws IOException, ZoneTransferExc } /** - * Does the zone transfer. + * Does the zone transfer using an internal handler. Results can be obtained by calling {@link + * #getAXFR()} or getIXFR * - * @return A list, which is either an AXFR-style response (List of Records), and IXFR-style - * response (List of Deltas), or null, which indicates that an IXFR was performed and the zone - * is up to date. * @throws IOException The zone transfer failed to due an IO problem. * @throws ZoneTransferException The zone transfer failed to due a problem with the zone transfer * itself. */ - public List run() throws IOException, ZoneTransferException { + public void run() throws IOException, ZoneTransferException { BasicHandler handler = new BasicHandler(); run(handler); - if (handler.axfr != null) { - return handler.axfr; - } - return handler.ixfr; } private BasicHandler getBasicHandler() throws IllegalArgumentException { @@ -600,7 +594,7 @@ public boolean isAXFR() { * @throws IllegalArgumentException The transfer used the callback interface, so the response was * not stored. */ - public List getAXFR() { + public List getAXFR() { BasicHandler handler = getBasicHandler(); return handler.axfr; } @@ -619,7 +613,7 @@ public boolean isIXFR() { * @throws IllegalArgumentException The transfer used the callback interface, so the response was * not stored. */ - public List getIXFR() { + public List getIXFR() { BasicHandler handler = getBasicHandler(); return handler.ixfr; } diff --git a/src/main/java/org/xbill/DNS/tools/xfrin.java b/src/main/java/org/xbill/DNS/tools/xfrin.java index 8e4392cc2..8432d4bce 100644 --- a/src/main/java/org/xbill/DNS/tools/xfrin.java +++ b/src/main/java/org/xbill/DNS/tools/xfrin.java @@ -3,7 +3,6 @@ package org.xbill.DNS.tools; import java.util.Iterator; -import java.util.List; import org.xbill.DNS.Lookup; import org.xbill.DNS.Name; import org.xbill.DNS.Record; @@ -11,6 +10,7 @@ import org.xbill.DNS.TSIG; import org.xbill.DNS.Type; import org.xbill.DNS.ZoneTransferIn; +import org.xbill.DNS.ZoneTransferIn.Delta; public class xfrin { @@ -82,21 +82,19 @@ public static void main(String[] args) throws Exception { xfrin = ZoneTransferIn.newAXFR(zname, server, port, key); } - List response = xfrin.run(); + xfrin.run(); if (xfrin.isAXFR()) { if (ixfr_serial >= 0) { System.out.println("AXFR-like IXFR response"); } else { System.out.println("AXFR response"); } - for (Object o : response) { - System.out.println(o); + for (Record record : xfrin.getAXFR()) { + System.out.println(record); } } else if (xfrin.isIXFR()) { System.out.println("IXFR response"); - for (Object o : response) { - ZoneTransferIn.Delta delta; - delta = (ZoneTransferIn.Delta) o; + for (Delta delta : xfrin.getIXFR()) { System.out.println("delta from " + delta.start + " to " + delta.end); System.out.println("deletes"); Iterator it2 = delta.deletes.iterator(); diff --git a/src/test/java/org/xbill/DNS/APLRecordTest.java b/src/test/java/org/xbill/DNS/APLRecordTest.java index f6952a67b..8b4a47baa 100644 --- a/src/test/java/org/xbill/DNS/APLRecordTest.java +++ b/src/test/java/org/xbill/DNS/APLRecordTest.java @@ -152,7 +152,7 @@ void ctor_4arg_basic() { @Test void ctor_4arg_empty_elements() { APLRecord ar = new APLRecord(m_an, DClass.IN, m_ttl, new ArrayList<>()); - assertEquals(new ArrayList(), ar.getElements()); + assertEquals(new ArrayList<>(), ar.getElements()); } @Test From 0bcf41e404cbb54de7b0b52d32ec335033bd8b61 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 19 Jan 2020 13:30:47 +0100 Subject: [PATCH 058/431] Release v3.0.0-next.1 --- Changelog | 16 ++++++++++++++++ pom.xml | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 72f0610ff..83d6a5b01 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,19 @@ +01/19/2019: + - 3.0.0-next.1 released + - Requires Java 8 and slf4j-api + - Adds support for Java 9+ and Android O+ via a new server config + lookup system (#6, #9, + - Resolving is now fully asynchronous, no new thread per query anymore + - Message provides information about the resolver that produced it (#41) + - Add support for Host Identity Protocol (HIP) records (RFC 8005, #47) + - Adds a DNS over HTTP (DoH) resolver (#66) + - Fixes some issues with the OSGi manifest (#70) + - Add support for the RES_OPTIONS environment variable (#57) + - Add support for relative $INCLUDE paths in master files (#75) + - Add support for custom DNS server port in config properties (#80) + - Adds new EDNS(0) options + - See the README for hints on migrating from v2.1.x to v3 + 05/25/2019: - 2.1.9 released - Fix getRRsetType for empty RRSIG records. diff --git a/pom.xml b/pom.xml index 105b9df46..bc2194cd4 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.0.0-SNAPSHOT + 3.0.0-next.1 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - HEAD + v3.0.0-next.1 From 176fcdc97b06fa42611140eeecb59467182fabea Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 19 Jan 2020 19:22:08 +0100 Subject: [PATCH 059/431] Return to snapshot version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bc2194cd4..9d42dc6d7 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.0.0-next.1 + 3.0.0-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache From dadf7617af5ac74428c1cde7ffe7a0568eba00de Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 19 Jan 2020 21:42:08 +0100 Subject: [PATCH 060/431] Fix parsing of RRSig records with epoch time format --- .../java/org/xbill/DNS/FormattedTime.java | 11 ++++++++-- .../java/org/xbill/DNS/FormattedTimeTest.java | 20 +++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/xbill/DNS/FormattedTime.java b/src/main/java/org/xbill/DNS/FormattedTime.java index a66c5502e..1f7b1f0e5 100644 --- a/src/main/java/org/xbill/DNS/FormattedTime.java +++ b/src/main/java/org/xbill/DNS/FormattedTime.java @@ -31,11 +31,18 @@ public static String format(Instant date) { /** * Parses a formatted time string into an Instant. * - * @param s The string, in the form YYYYMMDDHHMMSS. + * @param s The string, in the form YYYYMMDDHHMMSS or seconds since epoch (1 January 1970 00:00:00 + * UTC). * @return The Instant object. * @throws DateTimeParseException The string was invalid. */ public static Instant parse(String s) throws DateTimeParseException { - return DEFAULT_FORMAT.parse(s, Instant::from); + // rfc4034#section-3.2 + if (s.length() == 14) { + return DEFAULT_FORMAT.parse(s, Instant::from); + } else if (s.length() <= 10) { + return Instant.ofEpochSecond(Long.parseLong(s)); + } + throw new DateTimeParseException("Invalid time encoding: ", s, 0); } } diff --git a/src/test/java/org/xbill/DNS/FormattedTimeTest.java b/src/test/java/org/xbill/DNS/FormattedTimeTest.java index 8fe2aaf0b..5cf7e9fde 100644 --- a/src/test/java/org/xbill/DNS/FormattedTimeTest.java +++ b/src/test/java/org/xbill/DNS/FormattedTimeTest.java @@ -48,7 +48,7 @@ class FormattedTimeTest { @Test void format() { GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - cal.set(2005, 2, 19, 4, 4, 5); + cal.set(2005, Calendar.MARCH, 19, 4, 4, 5); String out = FormattedTime.format(cal.toInstant()); assertEquals("20050319040405", out); } @@ -59,7 +59,7 @@ void parse() throws DateTimeParseException { // is occasionally a difference between when cal and cal2 are // instantiated. GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - cal.set(2005, 2, 19, 4, 4, 5); + cal.set(2005, Calendar.MARCH, 19, 4, 4, 5); cal.set(Calendar.MILLISECOND, 0); Instant out = FormattedTime.parse("20050319040405"); @@ -69,6 +69,22 @@ void parse() throws DateTimeParseException { assertEquals(cal, cal2); } + @Test() + void parseEpoch() throws DateTimeParseException { + // have to make sure to clear out the milliseconds since there + // is occasionally a difference between when cal and cal2 are + // instantiated. + GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + cal.set(2005, Calendar.MARCH, 19, 4, 4, 5); + cal.set(Calendar.MILLISECOND, 0); + + Instant out = FormattedTime.parse("1111205045"); + GregorianCalendar cal2 = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + cal2.setTimeInMillis(out.toEpochMilli()); + cal2.set(Calendar.MILLISECOND, 0); + assertEquals(cal, cal2); + } + @Test void parse_invalid() { assertThrows(DateTimeParseException.class, () -> FormattedTime.parse("2004010101010")); From 500df9890f5db7cde64e7917dea7f0be8664855c Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 19 Jan 2020 21:42:43 +0100 Subject: [PATCH 061/431] Improve error message on rr text parse failure --- src/main/java/org/xbill/DNS/Record.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index 8b28d4def..752544d5f 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -442,7 +442,8 @@ public static Record fromString( rec.rdataFromString(st, origin); t = st.get(); if (t.type != Tokenizer.EOL && t.type != Tokenizer.EOF) { - throw st.exception("unexpected tokens at end of record"); + throw st.exception( + "unexpected tokens at end of record (wanted EOL/EOF, got " + t.toString() + ")"); } return rec; } From afccc50b7803b2d38172440215f817362b741390 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 19 Jan 2020 21:59:46 +0100 Subject: [PATCH 062/431] Add support for EdDSA in DNSSEC (RFC 8080) --- pom.xml | 4 +- src/main/java/org/xbill/DNS/DNSSEC.java | 18 ++++ src/main/java/org/xbill/DNS/DNSSECWithBC.java | 67 ++++++++++++++ .../xbill/DNS/DNSSECWithBCProviderTest.java | 92 +++++++++++++++++++ 4 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/xbill/DNS/DNSSECWithBC.java diff --git a/pom.xml b/pom.xml index 9d42dc6d7..9014c574c 100644 --- a/pom.xml +++ b/pom.xml @@ -240,8 +240,8 @@ org.bouncycastle bcprov-jdk15on - 1.61 - test + 1.64 + true org.junit.jupiter diff --git a/src/main/java/org/xbill/DNS/DNSSEC.java b/src/main/java/org/xbill/DNS/DNSSEC.java index 68e70c2fc..d5a1f4939 100644 --- a/src/main/java/org/xbill/DNS/DNSSEC.java +++ b/src/main/java/org/xbill/DNS/DNSSEC.java @@ -72,6 +72,12 @@ private Algorithm() {} /** ECDSA Curve P-384 with SHA-384 public key * */ public static final int ECDSAP384SHA384 = 14; + /** Edwards-Curve Digital Security Algorithm (EdDSA) for DNSSEC, RFC8080 */ + public static final int ED25519 = 15; + + /** Edwards-Curve Digital Security Algorithm (EdDSA) for DNSSEC, RFC8080 */ + public static final int ED448 = 16; + /** Indirect keys; the actual key is elsewhere. */ public static final int INDIRECT = 252; @@ -98,6 +104,8 @@ private Algorithm() {} algs.add(ECC_GOST, "ECC-GOST"); algs.add(ECDSAP256SHA256, "ECDSAP256SHA256"); algs.add(ECDSAP384SHA384, "ECDSAP384SHA384"); + algs.add(ED25519, "ED25519"); + algs.add(ED448, "ED448"); algs.add(INDIRECT, "INDIRECT"); algs.add(PRIVATEDNS, "PRIVATEDNS"); algs.add(PRIVATEOID, "PRIVATEOID"); @@ -506,6 +514,7 @@ private static PublicKey toECDSAPublicKey(byte[] key, ECKeyInfo keyinfo) KeyFactory factory = KeyFactory.getInstance("EC"); return factory.generatePublic(new ECPublicKeySpec(q, keyinfo.spec)); } + /** Converts a KEY/DNSKEY record into a PublicKey */ static PublicKey toPublicKey(KEYBase r) throws DNSSECException { return toPublicKey(r.getAlgorithm(), r.getKey(), r); @@ -530,6 +539,9 @@ static PublicKey toPublicKey(int alg, byte[] key, Record r) throws DNSSECExcepti return toECDSAPublicKey(key, ECDSA_P256); case Algorithm.ECDSAP384SHA384: return toECDSAPublicKey(key, ECDSA_P384); + case Algorithm.ED25519: + case Algorithm.ED448: + return DNSSECWithBC.toPublicKey(alg, key); default: throw new UnsupportedAlgorithmException(alg); } @@ -632,6 +644,9 @@ static byte[] fromPublicKey(PublicKey key, int alg) throws DNSSECException { throw new IncompatibleKeyException(); } return fromECDSAPublicKey((ECPublicKey) key, ECDSA_P384); + case Algorithm.ED25519: + case Algorithm.ED448: + return DNSSECWithBC.fromPublicKey(key, alg); default: throw new UnsupportedAlgorithmException(alg); } @@ -663,6 +678,9 @@ public static String algString(int alg) throws UnsupportedAlgorithmException { return "SHA256withECDSA"; case Algorithm.ECDSAP384SHA384: return "SHA384withECDSA"; + case Algorithm.ED25519: + case Algorithm.ED448: + return "EdDSA"; default: throw new UnsupportedAlgorithmException(alg); } diff --git a/src/main/java/org/xbill/DNS/DNSSECWithBC.java b/src/main/java/org/xbill/DNS/DNSSECWithBC.java new file mode 100644 index 000000000..4affbc884 --- /dev/null +++ b/src/main/java/org/xbill/DNS/DNSSECWithBC.java @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.edec.EdECObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPublicKey; +import org.xbill.DNS.DNSSEC.Algorithm; +import org.xbill.DNS.DNSSEC.DNSSECException; +import org.xbill.DNS.DNSSEC.IncompatibleKeyException; +import org.xbill.DNS.DNSSEC.UnsupportedAlgorithmException; + +/** + * Utility class for EdDSA signatures. Keep separate from {@link DNSSEC} to keep BouncyCastle + * optional until JEP 339 is available in Java. + */ +class DNSSECWithBC { + static PublicKey toPublicKey(int alg, byte[] key) + throws DNSSECException, GeneralSecurityException, IOException { + switch (alg) { + case Algorithm.ED25519: + return toEdDSAPublicKey(key, EdECObjectIdentifiers.id_Ed25519); + case Algorithm.ED448: + return toEdDSAPublicKey(key, EdECObjectIdentifiers.id_Ed448); + default: + throw new UnsupportedAlgorithmException(alg); + } + } + + static byte[] fromPublicKey(PublicKey key, int alg) throws DNSSECException { + switch (alg) { + case Algorithm.ED25519: + case Algorithm.ED448: + if (!(key instanceof BCEdDSAPublicKey) || !key.getFormat().equalsIgnoreCase("X.509")) { + throw new IncompatibleKeyException(); + } + return fromEdDSAPublicKey(key); + default: + throw new UnsupportedAlgorithmException(alg); + } + } + + private static PublicKey toEdDSAPublicKey(byte[] key, ASN1ObjectIdentifier algId) + throws GeneralSecurityException, IOException { + // Key is encoded as plain octets, rfc8080#section-3 + // wrap it in ASN.1 format so we can use X509EncodedKeySpec to read it as JCA + SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo(new AlgorithmIdentifier(algId), key); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyInfo.getEncoded()); + + KeyFactory keyFactory = KeyFactory.getInstance("EdDSA"); + return keyFactory.generatePublic(keySpec); + } + + private static byte[] fromEdDSAPublicKey(PublicKey key) { + DNSOutput out = new DNSOutput(); + byte[] encoded = key.getEncoded(); + // subtract the X.509 prefix length + out.writeByteArray(encoded, 12, encoded.length - 12); + return out.toByteArray(); + } +} diff --git a/src/test/java/org/xbill/DNS/DNSSECWithBCProviderTest.java b/src/test/java/org/xbill/DNS/DNSSECWithBCProviderTest.java index 8b41c2769..49ea5698f 100644 --- a/src/test/java/org/xbill/DNS/DNSSECWithBCProviderTest.java +++ b/src/test/java/org/xbill/DNS/DNSSECWithBCProviderTest.java @@ -1,16 +1,22 @@ package org.xbill.DNS; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Security; import java.security.Signature; +import java.time.Instant; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.xbill.DNS.DNSSEC.Algorithm; +import org.xbill.DNS.DNSSEC.DNSSECException; public class DNSSECWithBCProviderTest { @@ -18,6 +24,7 @@ public class DNSSECWithBCProviderTest { int algorithm = Algorithm.RSASHA1; String bcJCAProvider = "BC"; byte[] toSign = "The quick brown fox jumped over the lazy dog.".getBytes(); + private Name exampleCom = Name.fromConstantString("example.com."); @BeforeAll static void setUp() { @@ -42,4 +49,89 @@ void testSignWithDNSSECAndBCProvider() throws Exception { boolean verify = verifier.verify(signature); assertTrue(verify); } + + @Test + void testEdDSA25519_DNSKEY() throws IOException, DNSSECException { + String rrString = "257 3 15 l02Woi0iS8Aa25FQkUd9RMzZHJpBoRQwAQEX1SxZJA4="; + DNSKEYRecord dnskey = + (DNSKEYRecord) + Record.fromString(exampleCom, Type.DNSKEY, DClass.IN, 3600, rrString, Name.root); + assertEquals(Algorithm.ED25519, dnskey.getAlgorithm()); + assertEquals("Ed25519", dnskey.getPublicKey().getAlgorithm()); + DNSKEYRecord dnskey2 = + new DNSKEYRecord(exampleCom, DClass.IN, 3600, 257, 3, 15, dnskey.getPublicKey()); + assertEquals(rrString, dnskey2.rrToString()); + } + + @Test + void testEdDSA25519_DS() throws IOException { + DSRecord ds = + (DSRecord) + Record.fromString( + exampleCom, + Type.DS, + DClass.IN, + 3600, + "3613 15 2 3aa5ab37efce57f737fc1627013fee07bdf241bd10f3b1964ab55c78e79a304b", + Name.root); + assertEquals(Algorithm.ED25519, ds.getAlgorithm()); + } + + @Test + void testEdDSA448_DNSKEY() throws IOException, DNSSECException { + String rrString = + "257 3 16 3kgROaDjrh0H2iuixWBrc8g2EpBBLCdGzHmn+G2MpTPhpj/OiBVHHSfPodx1FYYUcJKm1MDpJtIA"; + DNSKEYRecord dnskey = + (DNSKEYRecord) + Record.fromString(exampleCom, Type.DNSKEY, DClass.IN, 3600, rrString, Name.root); + assertEquals(Algorithm.ED448, dnskey.getAlgorithm()); + assertEquals("Ed448", dnskey.getPublicKey().getAlgorithm()); + DNSKEYRecord dnskey2 = + new DNSKEYRecord(exampleCom, DClass.IN, 3600, 257, 3, 16, dnskey.getPublicKey()); + assertEquals(rrString, dnskey2.rrToString()); + } + + @Test + void testEdDSA448_DS() throws IOException { + DSRecord ds = + (DSRecord) + Record.fromString( + exampleCom, + Type.DS, + DClass.IN, + 3600, + "9713 16 2 6ccf18d5bc5d7fc2fceb1d59d17321402f2aa8d368048db93dd811f5cb2b19c7", + Name.root); + assertEquals(Algorithm.ED448, ds.getAlgorithm()); + } + + @Test + void testEdDSA25519_verify() throws IOException, DNSSECException { + DNSKEYRecord dnskey = + (DNSKEYRecord) + Record.fromString( + exampleCom, + Type.DNSKEY, + DClass.IN, + 3600, + "257 3 15 l02Woi0iS8Aa25FQkUd9RMzZHJpBoRQwAQEX1SxZJA4=", + Name.root); + + try (Master m = + new Master( + new ByteArrayInputStream( + ("example.com. 3600 IN MX 10 mail.example.com.\n" + + "example.com. 3600 IN RRSIG MX 15 2 3600 (\n" + + " 1440021600 1438207200 3613 example.com. (\n" + + " oL9krJun7xfBOIWcGHi7mag5/hdZrKWw15jPGrHpjQeRAvTdszaPD+QLs3f\n" + + " x8A4M3e23mRZ9VrbpMngwcrqNAg== )") + .getBytes(StandardCharsets.US_ASCII)))) { + RRset set = new RRset(); + Record r; + while ((r = m.nextRecord()) != null) { + set.addRR(r); + } + DNSSEC.verify(set, set.sigs().get(0), dnskey, Instant.parse("2015-08-19T22:00:00Z")); + } + } } From ec5f0c15d1417ffb87629fb7a71a90035cfda056 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 26 Jan 2020 20:08:03 +0100 Subject: [PATCH 063/431] Remove test class that was only testing the JDK --- .../org/xbill/DNS/DNSSECWithProviderTest.java | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 src/test/java/org/xbill/DNS/DNSSECWithProviderTest.java diff --git a/src/test/java/org/xbill/DNS/DNSSECWithProviderTest.java b/src/test/java/org/xbill/DNS/DNSSECWithProviderTest.java deleted file mode 100644 index 1e497b546..000000000 --- a/src/test/java/org/xbill/DNS/DNSSECWithProviderTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.xbill.DNS; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.Signature; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.xbill.DNS.DNSSEC.Algorithm; - -class DNSSECWithProviderTest { - - private static final String SIGNATURE_ALGORITHM = "SHA1withRSA"; - private static final String KEY_ALGORITHM = "RSA"; - int algorithm = Algorithm.RSASHA1; - private byte[] toSign = "The quick brown fox jumped over the lazy dog.".getBytes(); - - @BeforeEach - void setUp() {} - - @AfterEach - void tearDown() {} - - @Test - void testSignSoftware() throws Exception { - - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM); - keyPairGenerator.initialize(512); - KeyPair keyPair = keyPairGenerator.generateKeyPair(); - - Signature signer = Signature.getInstance(SIGNATURE_ALGORITHM); - signer.initSign(keyPair.getPrivate()); - signer.update(toSign); - byte[] signature = signer.sign(); - assertNotNull(signature); - - // verify the signature - Signature verifier = Signature.getInstance(SIGNATURE_ALGORITHM); - verifier.initVerify(keyPair.getPublic()); - verifier.update(toSign); - boolean verify = verifier.verify(signature); - assertTrue(verify); - } -} From a4cd5074466b98c4461b993d62472c52963f2b51 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 1 Feb 2020 14:36:46 +0100 Subject: [PATCH 064/431] Replace Record.getObject with reflection --- src/main/java/org/xbill/DNS/A6Record.java | 5 - src/main/java/org/xbill/DNS/AAAARecord.java | 5 - src/main/java/org/xbill/DNS/AFSDBRecord.java | 5 - src/main/java/org/xbill/DNS/APLRecord.java | 5 - src/main/java/org/xbill/DNS/ARecord.java | 5 - src/main/java/org/xbill/DNS/CAARecord.java | 5 - .../java/org/xbill/DNS/CDNSKEYRecord.java | 5 - src/main/java/org/xbill/DNS/CDSRecord.java | 5 - src/main/java/org/xbill/DNS/CERTRecord.java | 5 - src/main/java/org/xbill/DNS/CNAMERecord.java | 5 - src/main/java/org/xbill/DNS/DHCIDRecord.java | 5 - src/main/java/org/xbill/DNS/DLVRecord.java | 5 - src/main/java/org/xbill/DNS/DNAMERecord.java | 5 - src/main/java/org/xbill/DNS/DNSKEYRecord.java | 5 - src/main/java/org/xbill/DNS/DSRecord.java | 5 - src/main/java/org/xbill/DNS/EmptyRecord.java | 5 - src/main/java/org/xbill/DNS/GPOSRecord.java | 5 - src/main/java/org/xbill/DNS/HINFORecord.java | 5 - src/main/java/org/xbill/DNS/HIPRecord.java | 5 - .../java/org/xbill/DNS/IPSECKEYRecord.java | 5 - src/main/java/org/xbill/DNS/ISDNRecord.java | 5 - src/main/java/org/xbill/DNS/KEYRecord.java | 5 - src/main/java/org/xbill/DNS/KXRecord.java | 5 - src/main/java/org/xbill/DNS/LOCRecord.java | 5 - src/main/java/org/xbill/DNS/MBRecord.java | 5 - src/main/java/org/xbill/DNS/MDRecord.java | 5 - src/main/java/org/xbill/DNS/MFRecord.java | 5 - src/main/java/org/xbill/DNS/MGRecord.java | 5 - src/main/java/org/xbill/DNS/MINFORecord.java | 5 - src/main/java/org/xbill/DNS/MRRecord.java | 5 - src/main/java/org/xbill/DNS/MXRecord.java | 5 - src/main/java/org/xbill/DNS/NAPTRRecord.java | 5 - src/main/java/org/xbill/DNS/NSAPRecord.java | 5 - .../java/org/xbill/DNS/NSAP_PTRRecord.java | 5 - .../java/org/xbill/DNS/NSEC3PARAMRecord.java | 5 - src/main/java/org/xbill/DNS/NSEC3Record.java | 5 - src/main/java/org/xbill/DNS/NSECRecord.java | 5 - src/main/java/org/xbill/DNS/NSRecord.java | 5 - src/main/java/org/xbill/DNS/NULLRecord.java | 5 - src/main/java/org/xbill/DNS/NXTRecord.java | 5 - .../java/org/xbill/DNS/OPENPGPKEYRecord.java | 5 - src/main/java/org/xbill/DNS/OPTRecord.java | 5 - src/main/java/org/xbill/DNS/PTRRecord.java | 5 - src/main/java/org/xbill/DNS/PXRecord.java | 5 - src/main/java/org/xbill/DNS/RPRecord.java | 5 - src/main/java/org/xbill/DNS/RRSIGRecord.java | 5 - src/main/java/org/xbill/DNS/RTRecord.java | 5 - src/main/java/org/xbill/DNS/Record.java | 18 ++- src/main/java/org/xbill/DNS/SIGRecord.java | 5 - src/main/java/org/xbill/DNS/SMIMEARecord.java | 5 - src/main/java/org/xbill/DNS/SOARecord.java | 5 - src/main/java/org/xbill/DNS/SPFRecord.java | 5 - src/main/java/org/xbill/DNS/SRVRecord.java | 5 - src/main/java/org/xbill/DNS/SSHFPRecord.java | 5 - src/main/java/org/xbill/DNS/TKEYRecord.java | 5 - src/main/java/org/xbill/DNS/TLSARecord.java | 5 - src/main/java/org/xbill/DNS/TSIGRecord.java | 5 - src/main/java/org/xbill/DNS/TXTRecord.java | 5 - src/main/java/org/xbill/DNS/Type.java | 126 +++++++++--------- src/main/java/org/xbill/DNS/UNKRecord.java | 5 - src/main/java/org/xbill/DNS/URIRecord.java | 5 - src/main/java/org/xbill/DNS/WKSRecord.java | 5 - src/main/java/org/xbill/DNS/X25Record.java | 5 - src/test/java/org/xbill/DNS/A6RecordTest.java | 8 -- .../java/org/xbill/DNS/AAAARecordTest.java | 8 -- .../java/org/xbill/DNS/AFSDBRecordTest.java | 8 -- .../java/org/xbill/DNS/APLRecordTest.java | 7 - src/test/java/org/xbill/DNS/ARecordTest.java | 8 -- .../java/org/xbill/DNS/CNAMERecordTest.java | 8 -- .../java/org/xbill/DNS/DNAMERecordTest.java | 8 -- .../java/org/xbill/DNS/DNSKEYRecordTest.java | 8 -- src/test/java/org/xbill/DNS/DSRecordTest.java | 8 -- .../java/org/xbill/DNS/EmptyRecordTest.java | 8 -- .../java/org/xbill/DNS/GPOSRecordTest.java | 8 -- .../java/org/xbill/DNS/HINFORecordTest.java | 8 -- src/test/java/org/xbill/DNS/KEYBaseTest.java | 5 - .../java/org/xbill/DNS/KEYRecordTest.java | 8 -- src/test/java/org/xbill/DNS/KXRecordTest.java | 8 -- src/test/java/org/xbill/DNS/MBRecordTest.java | 8 -- src/test/java/org/xbill/DNS/MDRecordTest.java | 8 -- src/test/java/org/xbill/DNS/MFRecordTest.java | 8 -- src/test/java/org/xbill/DNS/MGRecordTest.java | 8 -- src/test/java/org/xbill/DNS/MRRecordTest.java | 8 -- src/test/java/org/xbill/DNS/MXRecordTest.java | 8 -- .../org/xbill/DNS/NSAP_PTRRecordTest.java | 8 -- src/test/java/org/xbill/DNS/NSRecordTest.java | 8 -- src/test/java/org/xbill/DNS/RTRecordTest.java | 8 -- src/test/java/org/xbill/DNS/RecordTest.java | 35 ++++- .../java/org/xbill/DNS/SOARecordTest.java | 7 - .../DNS/SingleCompressedNameBaseTest.java | 5 - .../org/xbill/DNS/SingleNameBaseTest.java | 5 - .../java/org/xbill/DNS/U16NameBaseTest.java | 5 - .../java/org/xbill/DNS/URIRecordTest.java | 8 -- 93 files changed, 104 insertions(+), 598 deletions(-) diff --git a/src/main/java/org/xbill/DNS/A6Record.java b/src/main/java/org/xbill/DNS/A6Record.java index cfa58f665..edba41f5d 100644 --- a/src/main/java/org/xbill/DNS/A6Record.java +++ b/src/main/java/org/xbill/DNS/A6Record.java @@ -19,11 +19,6 @@ public class A6Record extends Record { A6Record() {} - @Override - Record getObject() { - return new A6Record(); - } - /** * Creates an A6 Record from the given data * diff --git a/src/main/java/org/xbill/DNS/AAAARecord.java b/src/main/java/org/xbill/DNS/AAAARecord.java index d4ccbf268..5bd8f13a8 100644 --- a/src/main/java/org/xbill/DNS/AAAARecord.java +++ b/src/main/java/org/xbill/DNS/AAAARecord.java @@ -18,11 +18,6 @@ public class AAAARecord extends Record { AAAARecord() {} - @Override - Record getObject() { - return new AAAARecord(); - } - /** * Creates an AAAA Record from the given data * diff --git a/src/main/java/org/xbill/DNS/AFSDBRecord.java b/src/main/java/org/xbill/DNS/AFSDBRecord.java index eb82e34d2..b94489c62 100644 --- a/src/main/java/org/xbill/DNS/AFSDBRecord.java +++ b/src/main/java/org/xbill/DNS/AFSDBRecord.java @@ -11,11 +11,6 @@ public class AFSDBRecord extends U16NameBase { AFSDBRecord() {} - @Override - Record getObject() { - return new AFSDBRecord(); - } - /** * Creates an AFSDB Record from the given data. * diff --git a/src/main/java/org/xbill/DNS/APLRecord.java b/src/main/java/org/xbill/DNS/APLRecord.java index 70e4a7407..5ffd80016 100644 --- a/src/main/java/org/xbill/DNS/APLRecord.java +++ b/src/main/java/org/xbill/DNS/APLRecord.java @@ -91,11 +91,6 @@ public int hashCode() { APLRecord() {} - @Override - Record getObject() { - return new APLRecord(); - } - private static boolean validatePrefixLength(int family, int prefixLength) { if (prefixLength < 0 || prefixLength >= 256) { return false; diff --git a/src/main/java/org/xbill/DNS/ARecord.java b/src/main/java/org/xbill/DNS/ARecord.java index f1ee93b5b..df45ee614 100644 --- a/src/main/java/org/xbill/DNS/ARecord.java +++ b/src/main/java/org/xbill/DNS/ARecord.java @@ -18,11 +18,6 @@ public class ARecord extends Record { ARecord() {} - @Override - Record getObject() { - return new ARecord(); - } - private static int fromArray(byte[] array) { return (((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) diff --git a/src/main/java/org/xbill/DNS/CAARecord.java b/src/main/java/org/xbill/DNS/CAARecord.java index e480711ed..83d3a63ca 100644 --- a/src/main/java/org/xbill/DNS/CAARecord.java +++ b/src/main/java/org/xbill/DNS/CAARecord.java @@ -24,11 +24,6 @@ private Flags() {} CAARecord() {} - @Override - Record getObject() { - return new CAARecord(); - } - /** * Creates an CAA Record from the given data. * diff --git a/src/main/java/org/xbill/DNS/CDNSKEYRecord.java b/src/main/java/org/xbill/DNS/CDNSKEYRecord.java index f8c9e9695..053d95843 100644 --- a/src/main/java/org/xbill/DNS/CDNSKEYRecord.java +++ b/src/main/java/org/xbill/DNS/CDNSKEYRecord.java @@ -13,11 +13,6 @@ public class CDNSKEYRecord extends DNSKEYRecord { CDNSKEYRecord() {} - @Override - Record getObject() { - return new CDNSKEYRecord(); - } - /** * Creates a CDNSKEY Record from the given data * diff --git a/src/main/java/org/xbill/DNS/CDSRecord.java b/src/main/java/org/xbill/DNS/CDSRecord.java index a0fa1b1b5..344752487 100644 --- a/src/main/java/org/xbill/DNS/CDSRecord.java +++ b/src/main/java/org/xbill/DNS/CDSRecord.java @@ -11,11 +11,6 @@ public class CDSRecord extends DSRecord { CDSRecord() {} - @Override - Record getObject() { - return new CDSRecord(); - } - /** * Creates a CDS Record from the given data * diff --git a/src/main/java/org/xbill/DNS/CERTRecord.java b/src/main/java/org/xbill/DNS/CERTRecord.java index 1be222fbe..e84a017d8 100644 --- a/src/main/java/org/xbill/DNS/CERTRecord.java +++ b/src/main/java/org/xbill/DNS/CERTRecord.java @@ -107,11 +107,6 @@ public static int value(String s) { CERTRecord() {} - @Override - Record getObject() { - return new CERTRecord(); - } - /** * Creates a CERT Record from the given data * diff --git a/src/main/java/org/xbill/DNS/CNAMERecord.java b/src/main/java/org/xbill/DNS/CNAMERecord.java index cfea590f9..9fcd5c1dd 100644 --- a/src/main/java/org/xbill/DNS/CNAMERecord.java +++ b/src/main/java/org/xbill/DNS/CNAMERecord.java @@ -12,11 +12,6 @@ public class CNAMERecord extends SingleCompressedNameBase { CNAMERecord() {} - @Override - Record getObject() { - return new CNAMERecord(); - } - /** * Creates a new CNAMERecord with the given data * diff --git a/src/main/java/org/xbill/DNS/DHCIDRecord.java b/src/main/java/org/xbill/DNS/DHCIDRecord.java index 3ab936705..f108bf008 100644 --- a/src/main/java/org/xbill/DNS/DHCIDRecord.java +++ b/src/main/java/org/xbill/DNS/DHCIDRecord.java @@ -17,11 +17,6 @@ public class DHCIDRecord extends Record { DHCIDRecord() {} - @Override - Record getObject() { - return new DHCIDRecord(); - } - /** * Creates an DHCID Record from the given data * diff --git a/src/main/java/org/xbill/DNS/DLVRecord.java b/src/main/java/org/xbill/DNS/DLVRecord.java index 70b161501..d0425cd67 100644 --- a/src/main/java/org/xbill/DNS/DLVRecord.java +++ b/src/main/java/org/xbill/DNS/DLVRecord.java @@ -28,11 +28,6 @@ public class DLVRecord extends Record { DLVRecord() {} - @Override - Record getObject() { - return new DLVRecord(); - } - /** * Creates a DLV Record from the given data * diff --git a/src/main/java/org/xbill/DNS/DNAMERecord.java b/src/main/java/org/xbill/DNS/DNAMERecord.java index e0899e688..55fca32d5 100644 --- a/src/main/java/org/xbill/DNS/DNAMERecord.java +++ b/src/main/java/org/xbill/DNS/DNAMERecord.java @@ -11,11 +11,6 @@ public class DNAMERecord extends SingleNameBase { DNAMERecord() {} - @Override - Record getObject() { - return new DNAMERecord(); - } - /** * Creates a new DNAMERecord with the given data * diff --git a/src/main/java/org/xbill/DNS/DNSKEYRecord.java b/src/main/java/org/xbill/DNS/DNSKEYRecord.java index b30b3e1b7..1bd2ba554 100644 --- a/src/main/java/org/xbill/DNS/DNSKEYRecord.java +++ b/src/main/java/org/xbill/DNS/DNSKEYRecord.java @@ -38,11 +38,6 @@ private Flags() {} DNSKEYRecord() {} - @Override - Record getObject() { - return new DNSKEYRecord(); - } - /** * Creates a DNSKEY Record from the given data * diff --git a/src/main/java/org/xbill/DNS/DSRecord.java b/src/main/java/org/xbill/DNS/DSRecord.java index 80de4b7d2..20a0563ed 100644 --- a/src/main/java/org/xbill/DNS/DSRecord.java +++ b/src/main/java/org/xbill/DNS/DSRecord.java @@ -45,11 +45,6 @@ private Digest() {} DSRecord() {} - @Override - Record getObject() { - return new DSRecord(); - } - /** * Creates a DS Record from the given data * diff --git a/src/main/java/org/xbill/DNS/EmptyRecord.java b/src/main/java/org/xbill/DNS/EmptyRecord.java index 332086571..3e2e25320 100644 --- a/src/main/java/org/xbill/DNS/EmptyRecord.java +++ b/src/main/java/org/xbill/DNS/EmptyRecord.java @@ -11,11 +11,6 @@ class EmptyRecord extends Record { EmptyRecord() {} - @Override - Record getObject() { - return new EmptyRecord(); - } - @Override void rrFromWire(DNSInput in) {} diff --git a/src/main/java/org/xbill/DNS/GPOSRecord.java b/src/main/java/org/xbill/DNS/GPOSRecord.java index 0a058ee29..de027b2b8 100644 --- a/src/main/java/org/xbill/DNS/GPOSRecord.java +++ b/src/main/java/org/xbill/DNS/GPOSRecord.java @@ -17,11 +17,6 @@ public class GPOSRecord extends Record { GPOSRecord() {} - @Override - Record getObject() { - return new GPOSRecord(); - } - private void validate(double longitude, double latitude) throws IllegalArgumentException { if (longitude < -90.0 || longitude > 90.0) { throw new IllegalArgumentException("illegal longitude " + longitude); diff --git a/src/main/java/org/xbill/DNS/HINFORecord.java b/src/main/java/org/xbill/DNS/HINFORecord.java index 95c614865..216294966 100644 --- a/src/main/java/org/xbill/DNS/HINFORecord.java +++ b/src/main/java/org/xbill/DNS/HINFORecord.java @@ -16,11 +16,6 @@ public class HINFORecord extends Record { HINFORecord() {} - @Override - Record getObject() { - return new HINFORecord(); - } - /** * Creates an HINFO Record from the given data * diff --git a/src/main/java/org/xbill/DNS/HIPRecord.java b/src/main/java/org/xbill/DNS/HIPRecord.java index 80f032ab0..f14174677 100644 --- a/src/main/java/org/xbill/DNS/HIPRecord.java +++ b/src/main/java/org/xbill/DNS/HIPRecord.java @@ -27,11 +27,6 @@ public class HIPRecord extends Record { HIPRecord() {} - @Override - Record getObject() { - return new HIPRecord(); - } - public HIPRecord( Name name, int dclass, long ttl, byte[] hit, int alg, byte[] key, List servers) { super(name, Type.HIP, dclass, ttl); diff --git a/src/main/java/org/xbill/DNS/IPSECKEYRecord.java b/src/main/java/org/xbill/DNS/IPSECKEYRecord.java index 6e0d54f1e..6543087de 100644 --- a/src/main/java/org/xbill/DNS/IPSECKEYRecord.java +++ b/src/main/java/org/xbill/DNS/IPSECKEYRecord.java @@ -62,11 +62,6 @@ private Gateway() {} IPSECKEYRecord() {} - @Override - Record getObject() { - return new IPSECKEYRecord(); - } - /** * Creates an IPSECKEY Record from the given data. * diff --git a/src/main/java/org/xbill/DNS/ISDNRecord.java b/src/main/java/org/xbill/DNS/ISDNRecord.java index cddf0da36..9ee3e4cf1 100644 --- a/src/main/java/org/xbill/DNS/ISDNRecord.java +++ b/src/main/java/org/xbill/DNS/ISDNRecord.java @@ -16,11 +16,6 @@ public class ISDNRecord extends Record { ISDNRecord() {} - @Override - Record getObject() { - return new ISDNRecord(); - } - /** * Creates an ISDN Record from the given data * diff --git a/src/main/java/org/xbill/DNS/KEYRecord.java b/src/main/java/org/xbill/DNS/KEYRecord.java index c86b9eca7..f57bfd6d5 100644 --- a/src/main/java/org/xbill/DNS/KEYRecord.java +++ b/src/main/java/org/xbill/DNS/KEYRecord.java @@ -283,11 +283,6 @@ public static int value(String s) { KEYRecord() {} - @Override - Record getObject() { - return new KEYRecord(); - } - /** * Creates a KEY Record from the given data * diff --git a/src/main/java/org/xbill/DNS/KXRecord.java b/src/main/java/org/xbill/DNS/KXRecord.java index 0d598f483..a75eb8acc 100644 --- a/src/main/java/org/xbill/DNS/KXRecord.java +++ b/src/main/java/org/xbill/DNS/KXRecord.java @@ -12,11 +12,6 @@ public class KXRecord extends U16NameBase { KXRecord() {} - @Override - Record getObject() { - return new KXRecord(); - } - /** * Creates a KX Record from the given data * diff --git a/src/main/java/org/xbill/DNS/LOCRecord.java b/src/main/java/org/xbill/DNS/LOCRecord.java index ec163b024..8c84f5f54 100644 --- a/src/main/java/org/xbill/DNS/LOCRecord.java +++ b/src/main/java/org/xbill/DNS/LOCRecord.java @@ -28,11 +28,6 @@ public class LOCRecord extends Record { LOCRecord() {} - @Override - Record getObject() { - return new LOCRecord(); - } - /** * Creates an LOC Record from the given data * diff --git a/src/main/java/org/xbill/DNS/MBRecord.java b/src/main/java/org/xbill/DNS/MBRecord.java index 0fb383bf6..8fdd5df90 100644 --- a/src/main/java/org/xbill/DNS/MBRecord.java +++ b/src/main/java/org/xbill/DNS/MBRecord.java @@ -12,11 +12,6 @@ public class MBRecord extends SingleNameBase { MBRecord() {} - @Override - Record getObject() { - return new MBRecord(); - } - /** * Creates a new MB Record with the given data * diff --git a/src/main/java/org/xbill/DNS/MDRecord.java b/src/main/java/org/xbill/DNS/MDRecord.java index d927ecebc..368733361 100644 --- a/src/main/java/org/xbill/DNS/MDRecord.java +++ b/src/main/java/org/xbill/DNS/MDRecord.java @@ -12,11 +12,6 @@ public class MDRecord extends SingleNameBase { MDRecord() {} - @Override - Record getObject() { - return new MDRecord(); - } - /** * Creates a new MD Record with the given data * diff --git a/src/main/java/org/xbill/DNS/MFRecord.java b/src/main/java/org/xbill/DNS/MFRecord.java index e41cda175..c3ee9805f 100644 --- a/src/main/java/org/xbill/DNS/MFRecord.java +++ b/src/main/java/org/xbill/DNS/MFRecord.java @@ -12,11 +12,6 @@ public class MFRecord extends SingleNameBase { MFRecord() {} - @Override - Record getObject() { - return new MFRecord(); - } - /** * Creates a new MF Record with the given data * diff --git a/src/main/java/org/xbill/DNS/MGRecord.java b/src/main/java/org/xbill/DNS/MGRecord.java index 0fa4ceaa2..3039cb5d9 100644 --- a/src/main/java/org/xbill/DNS/MGRecord.java +++ b/src/main/java/org/xbill/DNS/MGRecord.java @@ -12,11 +12,6 @@ public class MGRecord extends SingleNameBase { MGRecord() {} - @Override - Record getObject() { - return new MGRecord(); - } - /** * Creates a new MG Record with the given data * diff --git a/src/main/java/org/xbill/DNS/MINFORecord.java b/src/main/java/org/xbill/DNS/MINFORecord.java index 35cf078a6..ef13c77ae 100644 --- a/src/main/java/org/xbill/DNS/MINFORecord.java +++ b/src/main/java/org/xbill/DNS/MINFORecord.java @@ -18,11 +18,6 @@ public class MINFORecord extends Record { MINFORecord() {} - @Override - Record getObject() { - return new MINFORecord(); - } - /** * Creates an MINFO Record from the given data * diff --git a/src/main/java/org/xbill/DNS/MRRecord.java b/src/main/java/org/xbill/DNS/MRRecord.java index 18f93627e..92294c474 100644 --- a/src/main/java/org/xbill/DNS/MRRecord.java +++ b/src/main/java/org/xbill/DNS/MRRecord.java @@ -12,11 +12,6 @@ public class MRRecord extends SingleNameBase { MRRecord() {} - @Override - Record getObject() { - return new MRRecord(); - } - /** * Creates a new MR Record with the given data * diff --git a/src/main/java/org/xbill/DNS/MXRecord.java b/src/main/java/org/xbill/DNS/MXRecord.java index d48064fde..8cbb04ef6 100644 --- a/src/main/java/org/xbill/DNS/MXRecord.java +++ b/src/main/java/org/xbill/DNS/MXRecord.java @@ -14,11 +14,6 @@ public class MXRecord extends U16NameBase { MXRecord() {} - @Override - Record getObject() { - return new MXRecord(); - } - /** * Creates an MX Record from the given data * diff --git a/src/main/java/org/xbill/DNS/NAPTRRecord.java b/src/main/java/org/xbill/DNS/NAPTRRecord.java index 9de2557b8..0983da7a9 100644 --- a/src/main/java/org/xbill/DNS/NAPTRRecord.java +++ b/src/main/java/org/xbill/DNS/NAPTRRecord.java @@ -19,11 +19,6 @@ public class NAPTRRecord extends Record { NAPTRRecord() {} - @Override - Record getObject() { - return new NAPTRRecord(); - } - /** * Creates an NAPTR Record from the given data * diff --git a/src/main/java/org/xbill/DNS/NSAPRecord.java b/src/main/java/org/xbill/DNS/NSAPRecord.java index 993391462..152aaab21 100644 --- a/src/main/java/org/xbill/DNS/NSAPRecord.java +++ b/src/main/java/org/xbill/DNS/NSAPRecord.java @@ -17,11 +17,6 @@ public class NSAPRecord extends Record { NSAPRecord() {} - @Override - Record getObject() { - return new NSAPRecord(); - } - private static byte[] checkAndConvertAddress(String address) { if (!address.substring(0, 2).equalsIgnoreCase("0x")) { return null; diff --git a/src/main/java/org/xbill/DNS/NSAP_PTRRecord.java b/src/main/java/org/xbill/DNS/NSAP_PTRRecord.java index 5775ce851..94cd37b71 100644 --- a/src/main/java/org/xbill/DNS/NSAP_PTRRecord.java +++ b/src/main/java/org/xbill/DNS/NSAP_PTRRecord.java @@ -11,11 +11,6 @@ public class NSAP_PTRRecord extends SingleNameBase { NSAP_PTRRecord() {} - @Override - Record getObject() { - return new NSAP_PTRRecord(); - } - /** * Creates a new NSAP_PTR Record with the given data * diff --git a/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java b/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java index 89030d863..dc6b4b142 100644 --- a/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java +++ b/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java @@ -25,11 +25,6 @@ public class NSEC3PARAMRecord extends Record { NSEC3PARAMRecord() {} - @Override - Record getObject() { - return new NSEC3PARAMRecord(); - } - /** * Creates an NSEC3PARAM record from the given data. * diff --git a/src/main/java/org/xbill/DNS/NSEC3Record.java b/src/main/java/org/xbill/DNS/NSEC3Record.java index 343d21c53..38007c309 100644 --- a/src/main/java/org/xbill/DNS/NSEC3Record.java +++ b/src/main/java/org/xbill/DNS/NSEC3Record.java @@ -50,11 +50,6 @@ private Digest() {} NSEC3Record() {} - @Override - Record getObject() { - return new NSEC3Record(); - } - /** * Creates an NSEC3 record from the given data. * diff --git a/src/main/java/org/xbill/DNS/NSECRecord.java b/src/main/java/org/xbill/DNS/NSECRecord.java index 1dde5a3bd..c935e0b8c 100644 --- a/src/main/java/org/xbill/DNS/NSECRecord.java +++ b/src/main/java/org/xbill/DNS/NSECRecord.java @@ -22,11 +22,6 @@ public class NSECRecord extends Record { NSECRecord() {} - @Override - Record getObject() { - return new NSECRecord(); - } - /** * Creates an NSEC Record from the given data. * diff --git a/src/main/java/org/xbill/DNS/NSRecord.java b/src/main/java/org/xbill/DNS/NSRecord.java index e7f3a46b7..d6147277a 100644 --- a/src/main/java/org/xbill/DNS/NSRecord.java +++ b/src/main/java/org/xbill/DNS/NSRecord.java @@ -12,11 +12,6 @@ public class NSRecord extends SingleCompressedNameBase { NSRecord() {} - @Override - Record getObject() { - return new NSRecord(); - } - /** * Creates a new NS Record with the given data * diff --git a/src/main/java/org/xbill/DNS/NULLRecord.java b/src/main/java/org/xbill/DNS/NULLRecord.java index 96bd4fee1..af9371112 100644 --- a/src/main/java/org/xbill/DNS/NULLRecord.java +++ b/src/main/java/org/xbill/DNS/NULLRecord.java @@ -16,11 +16,6 @@ public class NULLRecord extends Record { NULLRecord() {} - @Override - Record getObject() { - return new NULLRecord(); - } - /** * Creates a NULL record from the given data. * diff --git a/src/main/java/org/xbill/DNS/NXTRecord.java b/src/main/java/org/xbill/DNS/NXTRecord.java index 5f060f5d9..45569cfd1 100644 --- a/src/main/java/org/xbill/DNS/NXTRecord.java +++ b/src/main/java/org/xbill/DNS/NXTRecord.java @@ -20,11 +20,6 @@ public class NXTRecord extends Record { NXTRecord() {} - @Override - Record getObject() { - return new NXTRecord(); - } - /** * Creates an NXT Record from the given data * diff --git a/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java b/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java index 9a78b7180..fec5ca860 100644 --- a/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java +++ b/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java @@ -16,11 +16,6 @@ public class OPENPGPKEYRecord extends Record { OPENPGPKEYRecord() {} - @Override - Record getObject() { - return new OPENPGPKEYRecord(); - } - /** * Creates an OPENPGPKEY Record from the given data * diff --git a/src/main/java/org/xbill/DNS/OPTRecord.java b/src/main/java/org/xbill/DNS/OPTRecord.java index 89ffea04b..443020a6d 100644 --- a/src/main/java/org/xbill/DNS/OPTRecord.java +++ b/src/main/java/org/xbill/DNS/OPTRecord.java @@ -24,11 +24,6 @@ public class OPTRecord extends Record { OPTRecord() {} - @Override - Record getObject() { - return new OPTRecord(); - } - /** * Creates an OPT Record. This is normally called by SimpleResolver, but can also be called by a * server. diff --git a/src/main/java/org/xbill/DNS/PTRRecord.java b/src/main/java/org/xbill/DNS/PTRRecord.java index b624bb4c7..e03500c5d 100644 --- a/src/main/java/org/xbill/DNS/PTRRecord.java +++ b/src/main/java/org/xbill/DNS/PTRRecord.java @@ -12,11 +12,6 @@ public class PTRRecord extends SingleCompressedNameBase { PTRRecord() {} - @Override - Record getObject() { - return new PTRRecord(); - } - /** * Creates a new PTR Record with the given data * diff --git a/src/main/java/org/xbill/DNS/PXRecord.java b/src/main/java/org/xbill/DNS/PXRecord.java index 14d65e564..68e8494dc 100644 --- a/src/main/java/org/xbill/DNS/PXRecord.java +++ b/src/main/java/org/xbill/DNS/PXRecord.java @@ -18,11 +18,6 @@ public class PXRecord extends Record { PXRecord() {} - @Override - Record getObject() { - return new PXRecord(); - } - /** * Creates an PX Record from the given data * diff --git a/src/main/java/org/xbill/DNS/RPRecord.java b/src/main/java/org/xbill/DNS/RPRecord.java index 795979fa2..c2f553ab6 100644 --- a/src/main/java/org/xbill/DNS/RPRecord.java +++ b/src/main/java/org/xbill/DNS/RPRecord.java @@ -18,11 +18,6 @@ public class RPRecord extends Record { RPRecord() {} - @Override - Record getObject() { - return new RPRecord(); - } - /** * Creates an RP Record from the given data * diff --git a/src/main/java/org/xbill/DNS/RRSIGRecord.java b/src/main/java/org/xbill/DNS/RRSIGRecord.java index b8f6b8aca..39ef1a1e8 100644 --- a/src/main/java/org/xbill/DNS/RRSIGRecord.java +++ b/src/main/java/org/xbill/DNS/RRSIGRecord.java @@ -20,11 +20,6 @@ public class RRSIGRecord extends SIGBase { RRSIGRecord() {} - @Override - Record getObject() { - return new RRSIGRecord(); - } - /** * Creates an RRSIG Record from the given data * diff --git a/src/main/java/org/xbill/DNS/RTRecord.java b/src/main/java/org/xbill/DNS/RTRecord.java index 41f46828f..cbd2021ed 100644 --- a/src/main/java/org/xbill/DNS/RTRecord.java +++ b/src/main/java/org/xbill/DNS/RTRecord.java @@ -12,11 +12,6 @@ public class RTRecord extends U16NameBase { RTRecord() {} - @Override - Record getObject() { - return new RTRecord(); - } - /** * Creates an RT Record from the given data * diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index 752544d5f..bed7bf531 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.text.DecimalFormat; import java.util.Arrays; import org.xbill.DNS.utils.base16; @@ -40,16 +41,19 @@ protected Record() {} this.ttl = ttl; } - /** Creates an empty record of the correct type; must be overriden */ - abstract Record getObject(); - private static Record getEmptyRecord(Name name, int type, int dclass, long ttl, boolean hasData) { - Record proto, rec; - + Record rec; if (hasData) { - proto = Type.getProto(type); + Class proto = Type.getProto(type); if (proto != null) { - rec = proto.getObject(); + try { + rec = proto.getDeclaredConstructor().newInstance(); + } catch (InstantiationException + | IllegalAccessException + | InvocationTargetException + | NoSuchMethodException e) { + rec = new UNKRecord(); + } } else { rec = new UNKRecord(); } diff --git a/src/main/java/org/xbill/DNS/SIGRecord.java b/src/main/java/org/xbill/DNS/SIGRecord.java index 0053d823e..912590e8e 100644 --- a/src/main/java/org/xbill/DNS/SIGRecord.java +++ b/src/main/java/org/xbill/DNS/SIGRecord.java @@ -19,11 +19,6 @@ public class SIGRecord extends SIGBase { SIGRecord() {} - @Override - Record getObject() { - return new SIGRecord(); - } - /** * Creates an SIG Record from the given data * diff --git a/src/main/java/org/xbill/DNS/SMIMEARecord.java b/src/main/java/org/xbill/DNS/SMIMEARecord.java index ed2020640..db8237721 100644 --- a/src/main/java/org/xbill/DNS/SMIMEARecord.java +++ b/src/main/java/org/xbill/DNS/SMIMEARecord.java @@ -12,11 +12,6 @@ public class SMIMEARecord extends TLSARecord { SMIMEARecord() {} - @Override - Record getObject() { - return new SMIMEARecord(); - } - /** * Creates an SMIMEA Record from the given data * diff --git a/src/main/java/org/xbill/DNS/SOARecord.java b/src/main/java/org/xbill/DNS/SOARecord.java index 923704364..666b10fc8 100644 --- a/src/main/java/org/xbill/DNS/SOARecord.java +++ b/src/main/java/org/xbill/DNS/SOARecord.java @@ -17,11 +17,6 @@ public class SOARecord extends Record { SOARecord() {} - @Override - Record getObject() { - return new SOARecord(); - } - /** * Creates an SOA Record from the given data * diff --git a/src/main/java/org/xbill/DNS/SPFRecord.java b/src/main/java/org/xbill/DNS/SPFRecord.java index 1c9f2e96a..1618e05a8 100644 --- a/src/main/java/org/xbill/DNS/SPFRecord.java +++ b/src/main/java/org/xbill/DNS/SPFRecord.java @@ -14,11 +14,6 @@ public class SPFRecord extends TXTBase { SPFRecord() {} - @Override - Record getObject() { - return new SPFRecord(); - } - /** * Creates a SPF Record from the given data * diff --git a/src/main/java/org/xbill/DNS/SRVRecord.java b/src/main/java/org/xbill/DNS/SRVRecord.java index 09437f80c..09eb2ca33 100644 --- a/src/main/java/org/xbill/DNS/SRVRecord.java +++ b/src/main/java/org/xbill/DNS/SRVRecord.java @@ -19,11 +19,6 @@ public class SRVRecord extends Record { SRVRecord() {} - @Override - Record getObject() { - return new SRVRecord(); - } - /** * Creates an SRV Record from the given data * diff --git a/src/main/java/org/xbill/DNS/SSHFPRecord.java b/src/main/java/org/xbill/DNS/SSHFPRecord.java index f9e21b026..815e11d27 100644 --- a/src/main/java/org/xbill/DNS/SSHFPRecord.java +++ b/src/main/java/org/xbill/DNS/SSHFPRecord.java @@ -32,11 +32,6 @@ private Digest() {} SSHFPRecord() {} - @Override - Record getObject() { - return new SSHFPRecord(); - } - /** * Creates an SSHFP Record from the given data. * diff --git a/src/main/java/org/xbill/DNS/TKEYRecord.java b/src/main/java/org/xbill/DNS/TKEYRecord.java index fd2f65297..f171ae7c2 100644 --- a/src/main/java/org/xbill/DNS/TKEYRecord.java +++ b/src/main/java/org/xbill/DNS/TKEYRecord.java @@ -40,11 +40,6 @@ public class TKEYRecord extends Record { TKEYRecord() {} - @Override - Record getObject() { - return new TKEYRecord(); - } - /** * Creates a TKEY Record from the given data. * diff --git a/src/main/java/org/xbill/DNS/TLSARecord.java b/src/main/java/org/xbill/DNS/TLSARecord.java index 564743144..fe58408e9 100644 --- a/src/main/java/org/xbill/DNS/TLSARecord.java +++ b/src/main/java/org/xbill/DNS/TLSARecord.java @@ -52,11 +52,6 @@ private MatchingType() {} TLSARecord() {} - @Override - Record getObject() { - return new TLSARecord(); - } - /** * Creates an TLSA Record from the given data * diff --git a/src/main/java/org/xbill/DNS/TSIGRecord.java b/src/main/java/org/xbill/DNS/TSIGRecord.java index 1ea8c5f40..257cf55e8 100644 --- a/src/main/java/org/xbill/DNS/TSIGRecord.java +++ b/src/main/java/org/xbill/DNS/TSIGRecord.java @@ -29,11 +29,6 @@ public class TSIGRecord extends Record { TSIGRecord() {} - @Override - Record getObject() { - return new TSIGRecord(); - } - /** * Creates a TSIG Record from the given data. This is normally called by the TSIG class * diff --git a/src/main/java/org/xbill/DNS/TXTRecord.java b/src/main/java/org/xbill/DNS/TXTRecord.java index 0c5d56a61..0a7e95ef7 100644 --- a/src/main/java/org/xbill/DNS/TXTRecord.java +++ b/src/main/java/org/xbill/DNS/TXTRecord.java @@ -14,11 +14,6 @@ public class TXTRecord extends TXTBase { TXTRecord() {} - @Override - Record getObject() { - return new TXTRecord(); - } - /** * Creates a TXT Record from the given data * diff --git a/src/main/java/org/xbill/DNS/Type.java b/src/main/java/org/xbill/DNS/Type.java index 3199caa95..8d5140eaa 100644 --- a/src/main/java/org/xbill/DNS/Type.java +++ b/src/main/java/org/xbill/DNS/Type.java @@ -223,7 +223,7 @@ public final class Type { public static final int DLV = 32769; private static class TypeMnemonic extends Mnemonic { - private HashMap objects; + private HashMap> objects; public TypeMnemonic() { super("Type", CASE_UPPER); @@ -231,7 +231,7 @@ public TypeMnemonic() { objects = new HashMap<>(); } - public void add(int val, String str, Record proto) { + public void add(int val, String str, Class proto) { super.add(val, str); objects.put(val, proto); } @@ -241,7 +241,7 @@ public void check(int val) { Type.check(val); } - public Record getProto(int val) { + public Class getProto(int val) { check(val); return objects.get(val); } @@ -250,73 +250,73 @@ public Record getProto(int val) { private static TypeMnemonic types = new TypeMnemonic(); static { - types.add(A, "A", new ARecord()); - types.add(NS, "NS", new NSRecord()); - types.add(MD, "MD", new MDRecord()); - types.add(MF, "MF", new MFRecord()); - types.add(CNAME, "CNAME", new CNAMERecord()); - types.add(SOA, "SOA", new SOARecord()); - types.add(MB, "MB", new MBRecord()); - types.add(MG, "MG", new MGRecord()); - types.add(MR, "MR", new MRRecord()); - types.add(NULL, "NULL", new NULLRecord()); - types.add(WKS, "WKS", new WKSRecord()); - types.add(PTR, "PTR", new PTRRecord()); - types.add(HINFO, "HINFO", new HINFORecord()); - types.add(MINFO, "MINFO", new MINFORecord()); - types.add(MX, "MX", new MXRecord()); - types.add(TXT, "TXT", new TXTRecord()); - types.add(RP, "RP", new RPRecord()); - types.add(AFSDB, "AFSDB", new AFSDBRecord()); - types.add(X25, "X25", new X25Record()); - types.add(ISDN, "ISDN", new ISDNRecord()); - types.add(RT, "RT", new RTRecord()); - types.add(NSAP, "NSAP", new NSAPRecord()); - types.add(NSAP_PTR, "NSAP-PTR", new NSAP_PTRRecord()); - types.add(SIG, "SIG", new SIGRecord()); - types.add(KEY, "KEY", new KEYRecord()); - types.add(PX, "PX", new PXRecord()); - types.add(GPOS, "GPOS", new GPOSRecord()); - types.add(AAAA, "AAAA", new AAAARecord()); - types.add(LOC, "LOC", new LOCRecord()); - types.add(NXT, "NXT", new NXTRecord()); + types.add(A, "A", ARecord.class); + types.add(NS, "NS", NSRecord.class); + types.add(MD, "MD", MDRecord.class); + types.add(MF, "MF", MFRecord.class); + types.add(CNAME, "CNAME", CNAMERecord.class); + types.add(SOA, "SOA", SOARecord.class); + types.add(MB, "MB", MBRecord.class); + types.add(MG, "MG", MGRecord.class); + types.add(MR, "MR", MRRecord.class); + types.add(NULL, "NULL", NULLRecord.class); + types.add(WKS, "WKS", WKSRecord.class); + types.add(PTR, "PTR", PTRRecord.class); + types.add(HINFO, "HINFO", HINFORecord.class); + types.add(MINFO, "MINFO", MINFORecord.class); + types.add(MX, "MX", MXRecord.class); + types.add(TXT, "TXT", TXTRecord.class); + types.add(RP, "RP", RPRecord.class); + types.add(AFSDB, "AFSDB", AFSDBRecord.class); + types.add(X25, "X25", X25Record.class); + types.add(ISDN, "ISDN", ISDNRecord.class); + types.add(RT, "RT", RTRecord.class); + types.add(NSAP, "NSAP", NSAPRecord.class); + types.add(NSAP_PTR, "NSAP-PTR", NSAP_PTRRecord.class); + types.add(SIG, "SIG", SIGRecord.class); + types.add(KEY, "KEY", KEYRecord.class); + types.add(PX, "PX", PXRecord.class); + types.add(GPOS, "GPOS", GPOSRecord.class); + types.add(AAAA, "AAAA", AAAARecord.class); + types.add(LOC, "LOC", LOCRecord.class); + types.add(NXT, "NXT", NXTRecord.class); types.add(EID, "EID"); types.add(NIMLOC, "NIMLOC"); - types.add(SRV, "SRV", new SRVRecord()); + types.add(SRV, "SRV", SRVRecord.class); types.add(ATMA, "ATMA"); - types.add(NAPTR, "NAPTR", new NAPTRRecord()); - types.add(KX, "KX", new KXRecord()); - types.add(CERT, "CERT", new CERTRecord()); - types.add(A6, "A6", new A6Record()); - types.add(DNAME, "DNAME", new DNAMERecord()); - types.add(OPT, "OPT", new OPTRecord()); - types.add(APL, "APL", new APLRecord()); - types.add(DS, "DS", new DSRecord()); - types.add(SSHFP, "SSHFP", new SSHFPRecord()); - types.add(IPSECKEY, "IPSECKEY", new IPSECKEYRecord()); - types.add(RRSIG, "RRSIG", new RRSIGRecord()); - types.add(NSEC, "NSEC", new NSECRecord()); - types.add(DNSKEY, "DNSKEY", new DNSKEYRecord()); - types.add(DHCID, "DHCID", new DHCIDRecord()); - types.add(NSEC3, "NSEC3", new NSEC3Record()); - types.add(NSEC3PARAM, "NSEC3PARAM", new NSEC3PARAMRecord()); - types.add(TLSA, "TLSA", new TLSARecord()); - types.add(SMIMEA, "SMIMEA", new SMIMEARecord()); - types.add(HIP, "HIP", new HIPRecord()); - types.add(CDNSKEY, "CDNSKEY", new CDNSKEYRecord()); - types.add(CDS, "CDS", new CDSRecord()); - types.add(OPENPGPKEY, "OPENPGPKEY", new OPENPGPKEYRecord()); - types.add(SPF, "SPF", new SPFRecord()); - types.add(TKEY, "TKEY", new TKEYRecord()); - types.add(TSIG, "TSIG", new TSIGRecord()); + types.add(NAPTR, "NAPTR", NAPTRRecord.class); + types.add(KX, "KX", KXRecord.class); + types.add(CERT, "CERT", CERTRecord.class); + types.add(A6, "A6", A6Record.class); + types.add(DNAME, "DNAME", DNAMERecord.class); + types.add(OPT, "OPT", OPTRecord.class); + types.add(APL, "APL", APLRecord.class); + types.add(DS, "DS", DSRecord.class); + types.add(SSHFP, "SSHFP", SSHFPRecord.class); + types.add(IPSECKEY, "IPSECKEY", IPSECKEYRecord.class); + types.add(RRSIG, "RRSIG", RRSIGRecord.class); + types.add(NSEC, "NSEC", NSECRecord.class); + types.add(DNSKEY, "DNSKEY", DNSKEYRecord.class); + types.add(DHCID, "DHCID", DHCIDRecord.class); + types.add(NSEC3, "NSEC3", NSEC3Record.class); + types.add(NSEC3PARAM, "NSEC3PARAM", NSEC3PARAMRecord.class); + types.add(TLSA, "TLSA", TLSARecord.class); + types.add(SMIMEA, "SMIMEA", SMIMEARecord.class); + types.add(HIP, "HIP", HIPRecord.class); + types.add(CDNSKEY, "CDNSKEY", CDNSKEYRecord.class); + types.add(CDS, "CDS", CDSRecord.class); + types.add(OPENPGPKEY, "OPENPGPKEY", OPENPGPKEYRecord.class); + types.add(SPF, "SPF", SPFRecord.class); + types.add(TKEY, "TKEY", TKEYRecord.class); + types.add(TSIG, "TSIG", TSIGRecord.class); types.add(IXFR, "IXFR"); types.add(AXFR, "AXFR"); types.add(MAILB, "MAILB"); types.add(MAILA, "MAILA"); types.add(ANY, "ANY"); - types.add(URI, "URI", new URIRecord()); - types.add(CAA, "CAA", new CAARecord()); - types.add(DLV, "DLV", new DLVRecord()); + types.add(URI, "URI", URIRecord.class); + types.add(CAA, "CAA", CAARecord.class); + types.add(DLV, "DLV", DLVRecord.class); } private Type() {} @@ -367,7 +367,7 @@ public static int value(String s) { return value(s, false); } - static Record getProto(int val) { + static Class getProto(int val) { return types.getProto(val); } diff --git a/src/main/java/org/xbill/DNS/UNKRecord.java b/src/main/java/org/xbill/DNS/UNKRecord.java index fa3c8442b..b55d18f96 100644 --- a/src/main/java/org/xbill/DNS/UNKRecord.java +++ b/src/main/java/org/xbill/DNS/UNKRecord.java @@ -15,11 +15,6 @@ public class UNKRecord extends Record { UNKRecord() {} - @Override - Record getObject() { - return new UNKRecord(); - } - @Override void rrFromWire(DNSInput in) { data = in.readByteArray(); diff --git a/src/main/java/org/xbill/DNS/URIRecord.java b/src/main/java/org/xbill/DNS/URIRecord.java index 84733b9d4..a16c50cd2 100644 --- a/src/main/java/org/xbill/DNS/URIRecord.java +++ b/src/main/java/org/xbill/DNS/URIRecord.java @@ -20,11 +20,6 @@ public class URIRecord extends Record { target = new byte[] {}; } - @Override - Record getObject() { - return new URIRecord(); - } - /** * Creates a URI Record from the given data * diff --git a/src/main/java/org/xbill/DNS/WKSRecord.java b/src/main/java/org/xbill/DNS/WKSRecord.java index 60bab2229..5406c8b70 100644 --- a/src/main/java/org/xbill/DNS/WKSRecord.java +++ b/src/main/java/org/xbill/DNS/WKSRecord.java @@ -573,11 +573,6 @@ public static int value(String s) { WKSRecord() {} - @Override - Record getObject() { - return new WKSRecord(); - } - /** * Creates a WKS Record from the given data * diff --git a/src/main/java/org/xbill/DNS/X25Record.java b/src/main/java/org/xbill/DNS/X25Record.java index ea779e0b0..9cfeabd4f 100644 --- a/src/main/java/org/xbill/DNS/X25Record.java +++ b/src/main/java/org/xbill/DNS/X25Record.java @@ -16,11 +16,6 @@ public class X25Record extends Record { X25Record() {} - @Override - Record getObject() { - return new X25Record(); - } - private static byte[] checkAndConvertAddress(String address) { int length = address.length(); byte[] out = new byte[length]; diff --git a/src/test/java/org/xbill/DNS/A6RecordTest.java b/src/test/java/org/xbill/DNS/A6RecordTest.java index 04c9ade70..c0deb193d 100644 --- a/src/test/java/org/xbill/DNS/A6RecordTest.java +++ b/src/test/java/org/xbill/DNS/A6RecordTest.java @@ -38,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; @@ -80,13 +79,6 @@ void ctor_0arg() { assertEquals(0, ar.getTTL()); } - @Test - void getObject() { - A6Record ar = new A6Record(); - Record r = ar.getObject(); - assertTrue(r instanceof A6Record); - } - @Test void ctor_6arg() { A6Record ar = new A6Record(m_an, DClass.IN, m_ttl, m_prefix_bits, m_addr, null); diff --git a/src/test/java/org/xbill/DNS/AAAARecordTest.java b/src/test/java/org/xbill/DNS/AAAARecordTest.java index 086fd0652..f39b9ae4c 100644 --- a/src/test/java/org/xbill/DNS/AAAARecordTest.java +++ b/src/test/java/org/xbill/DNS/AAAARecordTest.java @@ -38,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; @@ -75,13 +74,6 @@ void ctor_0arg() { assertNull(ar.getAddress()); } - @Test - void getObject() { - AAAARecord ar = new AAAARecord(); - Record r = ar.getObject(); - assertTrue(r instanceof AAAARecord); - } - @Test void ctor_4arg() { AAAARecord ar = new AAAARecord(m_an, DClass.IN, m_ttl, m_addr); diff --git a/src/test/java/org/xbill/DNS/AFSDBRecordTest.java b/src/test/java/org/xbill/DNS/AFSDBRecordTest.java index 415c0e762..9c381a2f1 100644 --- a/src/test/java/org/xbill/DNS/AFSDBRecordTest.java +++ b/src/test/java/org/xbill/DNS/AFSDBRecordTest.java @@ -35,18 +35,10 @@ package org.xbill.DNS; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; class AFSDBRecordTest { - @Test - void getObject() { - AFSDBRecord d = new AFSDBRecord(); - Record r = d.getObject(); - assertTrue(r instanceof AFSDBRecord); - } - @Test void ctor_5arg() throws TextParseException { Name n = Name.fromString("My.Name."); diff --git a/src/test/java/org/xbill/DNS/APLRecordTest.java b/src/test/java/org/xbill/DNS/APLRecordTest.java index 8b4a47baa..2430b8cc5 100644 --- a/src/test/java/org/xbill/DNS/APLRecordTest.java +++ b/src/test/java/org/xbill/DNS/APLRecordTest.java @@ -132,13 +132,6 @@ void ctor_0arg() { assertNull(ar.getElements()); } - @Test - void getObject() { - APLRecord ar = new APLRecord(); - Record r = ar.getObject(); - assertTrue(r instanceof APLRecord); - } - @Test void ctor_4arg_basic() { APLRecord ar = new APLRecord(m_an, DClass.IN, m_ttl, m_elements); diff --git a/src/test/java/org/xbill/DNS/ARecordTest.java b/src/test/java/org/xbill/DNS/ARecordTest.java index a6e4e231b..2a5f39185 100644 --- a/src/test/java/org/xbill/DNS/ARecordTest.java +++ b/src/test/java/org/xbill/DNS/ARecordTest.java @@ -38,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; @@ -75,13 +74,6 @@ void ctor_0arg() throws UnknownHostException { assertEquals(InetAddress.getByName("0.0.0.0"), ar.getAddress()); } - @Test - void getObject() { - ARecord ar = new ARecord(); - Record r = ar.getObject(); - assertTrue(r instanceof ARecord); - } - @Test void ctor_4arg() { ARecord ar = new ARecord(m_an, DClass.IN, m_ttl, m_addr); diff --git a/src/test/java/org/xbill/DNS/CNAMERecordTest.java b/src/test/java/org/xbill/DNS/CNAMERecordTest.java index bedfd8b4d..6df26c34f 100644 --- a/src/test/java/org/xbill/DNS/CNAMERecordTest.java +++ b/src/test/java/org/xbill/DNS/CNAMERecordTest.java @@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -62,11 +61,4 @@ void ctor_4arg() throws TextParseException { assertEquals(a, d.getTarget()); assertEquals(a, d.getAlias()); } - - @Test - void getObject() { - CNAMERecord d = new CNAMERecord(); - Record r = d.getObject(); - assertTrue(r instanceof CNAMERecord); - } } diff --git a/src/test/java/org/xbill/DNS/DNAMERecordTest.java b/src/test/java/org/xbill/DNS/DNAMERecordTest.java index ba7b5613f..0c82a9157 100644 --- a/src/test/java/org/xbill/DNS/DNAMERecordTest.java +++ b/src/test/java/org/xbill/DNS/DNAMERecordTest.java @@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -62,11 +61,4 @@ void ctor_4arg() throws TextParseException { assertEquals(a, d.getTarget()); assertEquals(a, d.getAlias()); } - - @Test - void getObject() { - DNAMERecord d = new DNAMERecord(); - Record r = d.getObject(); - assertTrue(r instanceof DNAMERecord); - } } diff --git a/src/test/java/org/xbill/DNS/DNSKEYRecordTest.java b/src/test/java/org/xbill/DNS/DNSKEYRecordTest.java index 1a1b134d2..bd37c1ccb 100644 --- a/src/test/java/org/xbill/DNS/DNSKEYRecordTest.java +++ b/src/test/java/org/xbill/DNS/DNSKEYRecordTest.java @@ -38,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import org.junit.jupiter.api.Test; @@ -58,13 +57,6 @@ void ctor_0arg() { assertNull(ar.getKey()); } - @Test - void getObject() { - DNSKEYRecord ar = new DNSKEYRecord(); - Record r = ar.getObject(); - assertTrue(r instanceof DNSKEYRecord); - } - @Test void ctor_7arg() throws TextParseException { Name n = Name.fromString("My.Absolute.Name."); diff --git a/src/test/java/org/xbill/DNS/DSRecordTest.java b/src/test/java/org/xbill/DNS/DSRecordTest.java index b0802d26c..79dec7d8f 100644 --- a/src/test/java/org/xbill/DNS/DSRecordTest.java +++ b/src/test/java/org/xbill/DNS/DSRecordTest.java @@ -38,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import org.junit.jupiter.api.BeforeEach; @@ -58,13 +57,6 @@ void ctor_0arg() { assertEquals(0, dr.getFootprint()); } - @Test - void getObject() { - DSRecord dr = new DSRecord(); - Record r = dr.getObject(); - assertTrue(r instanceof DSRecord); - } - static class Test_Ctor_7arg { private Name m_n; private long m_ttl; diff --git a/src/test/java/org/xbill/DNS/EmptyRecordTest.java b/src/test/java/org/xbill/DNS/EmptyRecordTest.java index bbb7d3373..c5ed4bf4f 100644 --- a/src/test/java/org/xbill/DNS/EmptyRecordTest.java +++ b/src/test/java/org/xbill/DNS/EmptyRecordTest.java @@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import org.junit.jupiter.api.Test; @@ -51,13 +50,6 @@ void ctor() { assertEquals(0, ar.getTTL()); } - @Test - void getObject() { - EmptyRecord ar = new EmptyRecord(); - Record r = ar.getObject(); - assertTrue(r instanceof EmptyRecord); - } - @Test void rrFromWire() { DNSInput i = new DNSInput(new byte[] {1, 2, 3, 4, 5}); diff --git a/src/test/java/org/xbill/DNS/GPOSRecordTest.java b/src/test/java/org/xbill/DNS/GPOSRecordTest.java index f559dbc2f..1edd421c3 100644 --- a/src/test/java/org/xbill/DNS/GPOSRecordTest.java +++ b/src/test/java/org/xbill/DNS/GPOSRecordTest.java @@ -37,7 +37,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import org.junit.jupiter.api.BeforeEach; @@ -53,13 +52,6 @@ void ctor_0arg() { assertEquals(0, gr.getTTL()); } - @Test - void getObject() { - GPOSRecord gr = new GPOSRecord(); - Record r = gr.getObject(); - assertTrue(r instanceof GPOSRecord); - } - static class Test_Ctor_6arg_doubles { private Name m_n; private long m_ttl; diff --git a/src/test/java/org/xbill/DNS/HINFORecordTest.java b/src/test/java/org/xbill/DNS/HINFORecordTest.java index 7cfb71191..c84022050 100644 --- a/src/test/java/org/xbill/DNS/HINFORecordTest.java +++ b/src/test/java/org/xbill/DNS/HINFORecordTest.java @@ -38,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import org.junit.jupiter.api.Test; @@ -53,13 +52,6 @@ void ctor_0arg() { assertEquals(0, dr.getTTL()); } - @Test - void getObject() { - HINFORecord dr = new HINFORecord(); - Record r = dr.getObject(); - assertTrue(r instanceof HINFORecord); - } - @Test void ctor_5arg() throws TextParseException { Name n = Name.fromString("The.Name."); diff --git a/src/test/java/org/xbill/DNS/KEYBaseTest.java b/src/test/java/org/xbill/DNS/KEYBaseTest.java index a151c3e9e..125a0d5ce 100644 --- a/src/test/java/org/xbill/DNS/KEYBaseTest.java +++ b/src/test/java/org/xbill/DNS/KEYBaseTest.java @@ -52,11 +52,6 @@ private static class TestClass extends KEYBase { super(name, type, dclass, ttl, flags, proto, alg, key); } - @Override - public Record getObject() { - return null; - } - @Override void rdataFromString(Tokenizer st, Name origin) {} } diff --git a/src/test/java/org/xbill/DNS/KEYRecordTest.java b/src/test/java/org/xbill/DNS/KEYRecordTest.java index 94b4d5fe2..c7d869600 100644 --- a/src/test/java/org/xbill/DNS/KEYRecordTest.java +++ b/src/test/java/org/xbill/DNS/KEYRecordTest.java @@ -38,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import org.junit.jupiter.api.Test; @@ -58,13 +57,6 @@ void ctor_0arg() { assertNull(ar.getKey()); } - @Test - void getObject() { - KEYRecord ar = new KEYRecord(); - Record r = ar.getObject(); - assertTrue(r instanceof KEYRecord); - } - @Test void ctor_7arg() throws TextParseException { Name n = Name.fromString("My.Absolute.Name."); diff --git a/src/test/java/org/xbill/DNS/KXRecordTest.java b/src/test/java/org/xbill/DNS/KXRecordTest.java index fd6d2ddf8..0e20c5b58 100644 --- a/src/test/java/org/xbill/DNS/KXRecordTest.java +++ b/src/test/java/org/xbill/DNS/KXRecordTest.java @@ -35,18 +35,10 @@ package org.xbill.DNS; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; class KXRecordTest { - @Test - void getObject() { - KXRecord d = new KXRecord(); - Record r = d.getObject(); - assertTrue(r instanceof KXRecord); - } - @Test void ctor_5arg() throws TextParseException { Name n = Name.fromString("My.Name."); diff --git a/src/test/java/org/xbill/DNS/MBRecordTest.java b/src/test/java/org/xbill/DNS/MBRecordTest.java index b473e8b86..3258b5663 100644 --- a/src/test/java/org/xbill/DNS/MBRecordTest.java +++ b/src/test/java/org/xbill/DNS/MBRecordTest.java @@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -62,11 +61,4 @@ void ctor_4arg() throws TextParseException { assertEquals(a, d.getAdditionalName()); assertEquals(a, d.getMailbox()); } - - @Test - void getObject() { - MBRecord d = new MBRecord(); - Record r = d.getObject(); - assertTrue(r instanceof MBRecord); - } } diff --git a/src/test/java/org/xbill/DNS/MDRecordTest.java b/src/test/java/org/xbill/DNS/MDRecordTest.java index ab5d570de..f0875a6ed 100644 --- a/src/test/java/org/xbill/DNS/MDRecordTest.java +++ b/src/test/java/org/xbill/DNS/MDRecordTest.java @@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -62,11 +61,4 @@ void ctor_4arg() throws TextParseException { assertEquals(a, d.getAdditionalName()); assertEquals(a, d.getMailAgent()); } - - @Test - void getObject() { - MDRecord d = new MDRecord(); - Record r = d.getObject(); - assertTrue(r instanceof MDRecord); - } } diff --git a/src/test/java/org/xbill/DNS/MFRecordTest.java b/src/test/java/org/xbill/DNS/MFRecordTest.java index a0ee6acb1..da74fff6b 100644 --- a/src/test/java/org/xbill/DNS/MFRecordTest.java +++ b/src/test/java/org/xbill/DNS/MFRecordTest.java @@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -62,11 +61,4 @@ void ctor_4arg() throws TextParseException { assertEquals(a, d.getAdditionalName()); assertEquals(a, d.getMailAgent()); } - - @Test - void getObject() { - MFRecord d = new MFRecord(); - Record r = d.getObject(); - assertTrue(r instanceof MFRecord); - } } diff --git a/src/test/java/org/xbill/DNS/MGRecordTest.java b/src/test/java/org/xbill/DNS/MGRecordTest.java index 8fe0c35e6..c35a629e5 100644 --- a/src/test/java/org/xbill/DNS/MGRecordTest.java +++ b/src/test/java/org/xbill/DNS/MGRecordTest.java @@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -60,11 +59,4 @@ void ctor_4arg() throws TextParseException { assertEquals(0xABCDEL, d.getTTL()); assertEquals(a, d.getMailbox()); } - - @Test - void getObject() { - MGRecord d = new MGRecord(); - Record r = d.getObject(); - assertTrue(r instanceof MGRecord); - } } diff --git a/src/test/java/org/xbill/DNS/MRRecordTest.java b/src/test/java/org/xbill/DNS/MRRecordTest.java index 535d7e851..571978965 100644 --- a/src/test/java/org/xbill/DNS/MRRecordTest.java +++ b/src/test/java/org/xbill/DNS/MRRecordTest.java @@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -60,11 +59,4 @@ void ctor_4arg() throws TextParseException { assertEquals(0xABCDEL, d.getTTL()); assertEquals(a, d.getNewName()); } - - @Test - void getObject() { - MRRecord d = new MRRecord(); - Record r = d.getObject(); - assertTrue(r instanceof MRRecord); - } } diff --git a/src/test/java/org/xbill/DNS/MXRecordTest.java b/src/test/java/org/xbill/DNS/MXRecordTest.java index e4f4a69c1..13ac15481 100644 --- a/src/test/java/org/xbill/DNS/MXRecordTest.java +++ b/src/test/java/org/xbill/DNS/MXRecordTest.java @@ -36,19 +36,11 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import org.junit.jupiter.api.Test; class MXRecordTest { - @Test - void getObject() { - MXRecord d = new MXRecord(); - Record r = d.getObject(); - assertTrue(r instanceof MXRecord); - } - @Test void ctor_5arg() throws TextParseException { Name n = Name.fromString("My.Name."); diff --git a/src/test/java/org/xbill/DNS/NSAP_PTRRecordTest.java b/src/test/java/org/xbill/DNS/NSAP_PTRRecordTest.java index 689a2c7c6..54579e2d2 100644 --- a/src/test/java/org/xbill/DNS/NSAP_PTRRecordTest.java +++ b/src/test/java/org/xbill/DNS/NSAP_PTRRecordTest.java @@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import org.junit.jupiter.api.Test; @@ -62,13 +61,6 @@ void ctor_4arg() throws TextParseException { assertEquals(a, d.getTarget()); } - @Test - void getObject() { - NSAP_PTRRecord d = new NSAP_PTRRecord(); - Record r = d.getObject(); - assertTrue(r instanceof NSAP_PTRRecord); - } - @Test void rdataFromString() throws IOException { Tokenizer t = new Tokenizer("foo.bar.com."); diff --git a/src/test/java/org/xbill/DNS/NSRecordTest.java b/src/test/java/org/xbill/DNS/NSRecordTest.java index 12c7c0918..32b86fcba 100644 --- a/src/test/java/org/xbill/DNS/NSRecordTest.java +++ b/src/test/java/org/xbill/DNS/NSRecordTest.java @@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -62,11 +61,4 @@ void ctor_4arg() throws TextParseException { assertEquals(a, d.getTarget()); assertEquals(a, d.getAdditionalName()); } - - @Test - void getObject() { - NSRecord d = new NSRecord(); - Record r = d.getObject(); - assertTrue(r instanceof NSRecord); - } } diff --git a/src/test/java/org/xbill/DNS/RTRecordTest.java b/src/test/java/org/xbill/DNS/RTRecordTest.java index 8b5dffe35..62bf1cbee 100644 --- a/src/test/java/org/xbill/DNS/RTRecordTest.java +++ b/src/test/java/org/xbill/DNS/RTRecordTest.java @@ -35,18 +35,10 @@ package org.xbill.DNS; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; class RTRecordTest { - @Test - void getObject() { - RTRecord d = new RTRecord(); - Record r = d.getObject(); - assertTrue(r instanceof RTRecord); - } - @Test void ctor_5arg() throws TextParseException { Name n = Name.fromString("My.Name."); diff --git a/src/test/java/org/xbill/DNS/RecordTest.java b/src/test/java/org/xbill/DNS/RecordTest.java index de7c1c0a5..c7aee1241 100644 --- a/src/test/java/org/xbill/DNS/RecordTest.java +++ b/src/test/java/org/xbill/DNS/RecordTest.java @@ -38,15 +38,19 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.net.UnknownHostException; import java.time.Instant; +import junit.framework.Assert; import org.junit.jupiter.api.Test; class RecordTest { @@ -57,11 +61,6 @@ private static class SubRecord extends Record { super(name, type, dclass, ttl); } - @Override - public Record getObject() { - return null; - } - @Override public void rrFromWire(DNSInput in) {} @@ -849,4 +848,30 @@ void checkName() throws TextParseException { assertThrows(RelativeNameException.class, () -> Record.checkName("field", m)); } + + @Test + void testAllTypesHaveNoArgConstructor() { + for (int i = 1; i < 65535; i++) { + Class proto = Type.getProto(i); + if (proto != null) { + try { + Constructor noArgCtor = proto.getDeclaredConstructor(); + assertNotNull(noArgCtor.newInstance()); + } catch (NoSuchMethodException + | InstantiationException + | IllegalAccessException + | InvocationTargetException e) { + Assert.fail( + "Record type " + + Type.string(i) + + " (" + + i + + ", " + + proto.getSimpleName() + + ")" + + " seems to have no or invalid 0arg ctor"); + } + } + } + } } diff --git a/src/test/java/org/xbill/DNS/SOARecordTest.java b/src/test/java/org/xbill/DNS/SOARecordTest.java index 846e71646..ba669e5f8 100644 --- a/src/test/java/org/xbill/DNS/SOARecordTest.java +++ b/src/test/java/org/xbill/DNS/SOARecordTest.java @@ -90,13 +90,6 @@ void ctor_0arg() { assertEquals(0, ar.getMinimum()); } - @Test - void getObject() { - SOARecord ar = new SOARecord(); - Record r = ar.getObject(); - assertTrue(r instanceof SOARecord); - } - @Test void ctor_10arg() { SOARecord ar = diff --git a/src/test/java/org/xbill/DNS/SingleCompressedNameBaseTest.java b/src/test/java/org/xbill/DNS/SingleCompressedNameBaseTest.java index c8dcd197d..6e9a4b798 100644 --- a/src/test/java/org/xbill/DNS/SingleCompressedNameBaseTest.java +++ b/src/test/java/org/xbill/DNS/SingleCompressedNameBaseTest.java @@ -54,11 +54,6 @@ private static class TestClass extends SingleCompressedNameBase { public Name getSingleName() { return super.getSingleName(); } - - @Override - public Record getObject() { - return null; - } } @Test diff --git a/src/test/java/org/xbill/DNS/SingleNameBaseTest.java b/src/test/java/org/xbill/DNS/SingleNameBaseTest.java index 9f1e72a28..186a3a139 100644 --- a/src/test/java/org/xbill/DNS/SingleNameBaseTest.java +++ b/src/test/java/org/xbill/DNS/SingleNameBaseTest.java @@ -59,11 +59,6 @@ private static class TestClass extends SingleNameBase { public Name getSingleName() { return super.getSingleName(); } - - @Override - public Record getObject() { - return null; - } } @Test diff --git a/src/test/java/org/xbill/DNS/U16NameBaseTest.java b/src/test/java/org/xbill/DNS/U16NameBaseTest.java index 739058d0a..f22483b65 100644 --- a/src/test/java/org/xbill/DNS/U16NameBaseTest.java +++ b/src/test/java/org/xbill/DNS/U16NameBaseTest.java @@ -72,11 +72,6 @@ public int getU16Field() { public Name getNameField() { return super.getNameField(); } - - @Override - public Record getObject() { - return null; - } } @Test diff --git a/src/test/java/org/xbill/DNS/URIRecordTest.java b/src/test/java/org/xbill/DNS/URIRecordTest.java index 52f8fe3bc..7839b4c29 100644 --- a/src/test/java/org/xbill/DNS/URIRecordTest.java +++ b/src/test/java/org/xbill/DNS/URIRecordTest.java @@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import org.junit.jupiter.api.Test; @@ -22,13 +21,6 @@ void ctor_0arg() { assertEquals("", r.getTarget()); } - @Test - void getObject() { - URIRecord dr = new URIRecord(); - Record r = dr.getObject(); - assertTrue(r instanceof URIRecord); - } - @Test void ctor_6arg() throws TextParseException { Name n = Name.fromString("my.name."); From 868aa617f95a9bf2816550b7397efccbf35fe38c Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 1 Feb 2020 15:04:53 +0100 Subject: [PATCH 065/431] Add missing DNS RR mnemonics --- src/main/java/org/xbill/DNS/Type.java | 102 +++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Type.java b/src/main/java/org/xbill/DNS/Type.java index 8d5140eaa..d410f2b85 100644 --- a/src/main/java/org/xbill/DNS/Type.java +++ b/src/main/java/org/xbill/DNS/Type.java @@ -138,6 +138,9 @@ public final class Type { /** {@link DNAMERecord Non-terminal name redirection} */ public static final int DNAME = 39; + /** Kitchen Sink (April Fools' Day RR) */ + public static final int SINK = 40; + /** {@link OPTRecord Options - contains EDNS metadata} */ public static final int OPT = 41; @@ -180,6 +183,29 @@ public final class Type { /** {@link HIPRecord Host Identity Protocol (HIP)} */ public static final int HIP = 55; + /** + * Zone Status (ZS). + * + * @see draft-reid-dnsext-zs-01 + */ + public static final int NINFO = 56; + + /** + * RKEY DNS Resource Record, used for encryption of NAPTR records. + * + * @see draft-reid-dnsext-rkey-00 + */ + public static final int RKEY = 57; + + /** + * DNSSEC Trust Anchor History Service. + * + * @see draft-wijngaards-dnsop-trust-history-02 + */ + public static final int TALINK = 58; + /** {@link CDSRecord Child Delegation Signer} */ public static final int CDS = 59; @@ -189,9 +215,45 @@ public final class Type { /** {@link OPENPGPKEYRecord OpenPGP Key} */ public static final int OPENPGPKEY = 61; + /** Child-to-Parent Synchronization. */ + public static final int CSYNC = 62; + + /** Message Digest for DNS Zones. */ + public static final int ZONEMD = 63; + /** {@link SPFRecord Sender Policy Framework} */ public static final int SPF = 99; + /** IANA-Reserved */ + public static final int UINFO = 100; + + /** IANA-Reserved */ + public static final int UID = 101; + + /** IANA-Reserved */ + public static final int GID = 102; + + /** IANA-Reserved */ + public static final int UNSPEC = 103; + + /** Node Identifier (NID). */ + public static final int NID = 104; + + /** 32-bit Locator value for ILNPv4-capable node. */ + public static final int L32 = 105; + + /** Unsigned 64-bit Locator value for ILNPv6-capable node. */ + public static final int L64 = 106; + + /** Name of a subnetwork for ILNP. */ + public static final int LP = 107; + + /** EUI-48 Address. */ + public static final int EUI48 = 108; + + /** EUI-64 Address. */ + public static final int EUI64 = 109; + /** {@link TKEYRecord Transaction key} */ public static final int TKEY = 249; @@ -207,7 +269,7 @@ public final class Type { /** Transfer mailbox records */ public static final int MAILB = 253; - /** Transfer mail agent records */ + /** mail agent RRs (obsolete - {@see MX}) */ public static final int MAILA = 254; /** Matches any type */ @@ -219,6 +281,18 @@ public final class Type { /** {@link CAARecord Certification Authority Authorization} */ public static final int CAA = 257; + /** Application Visibility and Control */ + public static final int AVC = 258; + + /** Digital Object Architecture */ + public static final int DOA = 259; + + /** Automatic Multicast Tunneling Relay */ + public static final int AMTRELAY = 260; + + /** DNSSEC Trust Authorities */ + public static final int TA = 32768; + /** {@link DLVRecord DNSSEC Lookaside Validation} */ public static final int DLV = 32769; @@ -289,6 +363,7 @@ public Class getProto(int val) { types.add(CERT, "CERT", CERTRecord.class); types.add(A6, "A6", A6Record.class); types.add(DNAME, "DNAME", DNAMERecord.class); + types.add(SINK, "SINK"); types.add(OPT, "OPT", OPTRecord.class); types.add(APL, "APL", APLRecord.class); types.add(DS, "DS", DSRecord.class); @@ -302,11 +377,29 @@ public Class getProto(int val) { types.add(NSEC3PARAM, "NSEC3PARAM", NSEC3PARAMRecord.class); types.add(TLSA, "TLSA", TLSARecord.class); types.add(SMIMEA, "SMIMEA", SMIMEARecord.class); + types.add(HIP, "HIP", HIPRecord.class); - types.add(CDNSKEY, "CDNSKEY", CDNSKEYRecord.class); + types.add(NINFO, "NINFO"); + types.add(RKEY, "RKEY"); + types.add(TALINK, "TALINK"); types.add(CDS, "CDS", CDSRecord.class); + types.add(CDNSKEY, "CDNSKEY", CDNSKEYRecord.class); types.add(OPENPGPKEY, "OPENPGPKEY", OPENPGPKEYRecord.class); + types.add(CSYNC, "CSYNC"); + types.add(ZONEMD, "ZONEMD"); + types.add(SPF, "SPF", SPFRecord.class); + types.add(UINFO, "UINFO"); + types.add(UID, "UID"); + types.add(GID, "GID"); + types.add(UNSPEC, "UNSPEC"); + types.add(NID, "NID"); + types.add(L32, "L32"); + types.add(L64, "L64"); + types.add(LP, "LP"); + types.add(EUI48, "EUI48"); + types.add(EUI64, "EUI64"); + types.add(TKEY, "TKEY", TKEYRecord.class); types.add(TSIG, "TSIG", TSIGRecord.class); types.add(IXFR, "IXFR"); @@ -316,6 +409,11 @@ public Class getProto(int val) { types.add(ANY, "ANY"); types.add(URI, "URI", URIRecord.class); types.add(CAA, "CAA", CAARecord.class); + types.add(AVC, "AVC"); + types.add(DOA, "DOA"); + types.add(AMTRELAY, "AMTRELAY"); + + types.add(TA, "TA"); types.add(DLV, "DLV", DLVRecord.class); } From d0781c946f1cbf04c9296f70428ec997a9676b4b Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 1 Feb 2020 15:39:35 +0100 Subject: [PATCH 066/431] Add missing MNemonics --- src/main/java/org/xbill/DNS/EDNSOption.java | 18 ++++++++++++++ src/main/java/org/xbill/DNS/Opcode.java | 4 +++ src/main/java/org/xbill/DNS/Rcode.java | 27 ++++++++++----------- src/test/java/org/xbill/DNS/OpcodeTest.java | 2 +- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/xbill/DNS/EDNSOption.java b/src/main/java/org/xbill/DNS/EDNSOption.java index 315272cd4..3031ca407 100644 --- a/src/main/java/org/xbill/DNS/EDNSOption.java +++ b/src/main/java/org/xbill/DNS/EDNSOption.java @@ -21,6 +21,12 @@ public abstract class EDNSOption { public static class Code { private Code() {} + /** Apple's DNS Long-Lived Queries protocol, draft-sekar-dns-llq-06 */ + public static final int LLQ = 1; + + /** Dynamic DNS Update Leases, draft-sekar-dns-ul-02 */ + public static final int UL = 2; + /** Name Server Identifier, RFC 5001 */ public static final int NSID = 3; @@ -54,6 +60,12 @@ private Code() {} /** Signaling Trust Anchor Knowledge in DNS Security Extensions (DNSSEC), RFC 8145 */ public static final int EDNS_KEY_TAG = 14; + /** DNS EDNS Tags, draft-bellis-dnsop-edns-tags-01 */ + public static final int EDNS_CLIENT_TAG = 16; + + /** DNS EDNS Tags, draft-bellis-dnsop-edns-tags-01 */ + public static final int EDNS_SERVER_TAG = 17; + private static Mnemonic codes = new Mnemonic("EDNS Option Codes", Mnemonic.CASE_SENSITIVE); static { @@ -61,7 +73,10 @@ private Code() {} codes.setPrefix("CODE"); codes.setNumericAllowed(true); + codes.add(LLQ, "LLQ"); + codes.add(UL, "UL"); codes.add(NSID, "NSID"); + codes.add(DAU, "DAU"); codes.add(DHU, "DHU"); codes.add(N3U, "N3U"); @@ -72,6 +87,9 @@ private Code() {} codes.add(PADDING, "Padding"); codes.add(CHAIN, "CHAIN"); codes.add(EDNS_KEY_TAG, "edns-key-tag"); + + codes.add(EDNS_CLIENT_TAG, "EDNS-Client-Tag"); + codes.add(EDNS_SERVER_TAG, "EDNS-Server-Tag"); } /** Converts an EDNS Option Code into its textual representation */ diff --git a/src/main/java/org/xbill/DNS/Opcode.java b/src/main/java/org/xbill/DNS/Opcode.java index 869aaa40a..4e72c2b41 100644 --- a/src/main/java/org/xbill/DNS/Opcode.java +++ b/src/main/java/org/xbill/DNS/Opcode.java @@ -24,6 +24,9 @@ public final class Opcode { /** A dynamic update message */ public static final int UPDATE = 5; + /** DNS Stateful Operations (DSO, RFC8490) */ + public static final int DSO = 6; + private static Mnemonic opcodes = new Mnemonic("DNS Opcode", Mnemonic.CASE_UPPER); static { @@ -36,6 +39,7 @@ public final class Opcode { opcodes.add(STATUS, "STATUS"); opcodes.add(NOTIFY, "NOTIFY"); opcodes.add(UPDATE, "UPDATE"); + opcodes.add(DSO, "DSO"); } private Opcode() {} diff --git a/src/main/java/org/xbill/DNS/Rcode.java b/src/main/java/org/xbill/DNS/Rcode.java index fb65ffc4d..0ed277ecc 100644 --- a/src/main/java/org/xbill/DNS/Rcode.java +++ b/src/main/java/org/xbill/DNS/Rcode.java @@ -8,11 +8,8 @@ * @author Brian Wellington */ public final class Rcode { - private static Mnemonic rcodes = new Mnemonic("DNS Rcode", Mnemonic.CASE_UPPER); - private static Mnemonic tsigrcodes = new Mnemonic("TSIG rcode", Mnemonic.CASE_UPPER); - /** No error */ public static final int NOERROR = 0; @@ -29,7 +26,7 @@ public final class Rcode { public static final int NOTIMP = 4; /** Deprecated synonym for NOTIMP. */ - public static final int NOTIMPL = 4; + @Deprecated public static final int NOTIMPL = 4; /** The operation was refused by the server */ public static final int REFUSED = 5; @@ -96,19 +93,13 @@ public final class Rcode { rcodes.add(NOTAUTH, "NOTAUTH"); rcodes.add(NOTZONE, "NOTZONE"); rcodes.add(BADVERS, "BADVERS"); + rcodes.add(BADKEY, "BADKEY"); + rcodes.add(BADTIME, "BADTIME"); rcodes.add(BADMODE, "BADMODE"); rcodes.add(BADNAME, "BADNAME"); rcodes.add(BADALG, "BADALG"); + rcodes.add(BADTRUNC, "BADTRUNC"); rcodes.add(BADCOOKIE, "BADCOOKIE"); - - tsigrcodes.setMaximum(0xFFFF); - tsigrcodes.setPrefix("RESERVED"); - tsigrcodes.setNumericAllowed(true); - tsigrcodes.addAll(rcodes); - - tsigrcodes.add(BADSIG, "BADSIG"); - tsigrcodes.add(BADKEY, "BADKEY"); - tsigrcodes.add(BADTIME, "BADTIME"); } private Rcode() {} @@ -120,11 +111,19 @@ public static String string(int i) { /** Converts a numeric TSIG extended Rcode into a String */ public static String TSIGstring(int i) { - return tsigrcodes.getText(i); + if (i == BADSIG) { + return "BADSIG"; + } + + return string(i); } /** Converts a String representation of an Rcode into its numeric value */ public static int value(String s) { + if ("BADSIG".equalsIgnoreCase(s)) { + return BADSIG; + } + return rcodes.getValue(s); } } diff --git a/src/test/java/org/xbill/DNS/OpcodeTest.java b/src/test/java/org/xbill/DNS/OpcodeTest.java index 8955d8d82..c23325eef 100644 --- a/src/test/java/org/xbill/DNS/OpcodeTest.java +++ b/src/test/java/org/xbill/DNS/OpcodeTest.java @@ -47,7 +47,7 @@ void string() { assertEquals("IQUERY", Opcode.string(Opcode.IQUERY)); // one that doesn't exist - assertTrue(Opcode.string(6).startsWith("RESERVED")); + assertTrue(Opcode.string(7).startsWith("RESERVED")); assertThrows(IllegalArgumentException.class, () -> Opcode.string(-1)); From 4613f17f7c0e0983168f07445d3633a3ea62818c Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 15 Feb 2020 13:22:06 +0100 Subject: [PATCH 067/431] Release v3.0.0 --- Changelog | 9 ++++++++- pom.xml | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index 83d6a5b01..5870cb479 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,11 @@ -01/19/2019: +02/15/2020 + - 3.0.0 released + - Parse RRsig records with epoch time format + - Add support for EdDSA DNSSEC signatures if BouncyCastle is available + (Ed25519 and Ed448, RFC 8080) + - Add missing RCode, OpCode and RR type mnemonics + +01/19/2020: - 3.0.0-next.1 released - Requires Java 8 and slf4j-api - Adds support for Java 9+ and Android O+ via a new server config diff --git a/pom.xml b/pom.xml index 9014c574c..ee1535d11 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.0.0-SNAPSHOT + 3.0.0 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.0.0-next.1 + v3.0.0 From 8b04fbea187c2cba08458aff0dade025cbe0376e Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 15 Feb 2020 17:58:00 +0100 Subject: [PATCH 068/431] Return to -snapshot --- pom.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ee1535d11..7ce118601 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.0.0 + 3.0.1-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -172,6 +172,14 @@ japicmp-maven-plugin 0.14.0 + + + ${project.groupId} + ${project.artifactId} + 3.0.0 + jar + + true true From b3a7410da7673eede8ffc529ae3193ef8f5ba72d Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 15 Feb 2020 17:59:08 +0100 Subject: [PATCH 069/431] Fix toString of RRset containing only signature(s) --- src/main/java/org/xbill/DNS/RRset.java | 2 +- src/test/java/org/xbill/DNS/RRsetTest.java | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/RRset.java b/src/main/java/org/xbill/DNS/RRset.java index 70e82a142..f6ea68944 100644 --- a/src/main/java/org/xbill/DNS/RRset.java +++ b/src/main/java/org/xbill/DNS/RRset.java @@ -233,7 +233,7 @@ private void appendRrList(Iterator it, StringBuilder sb) { /** Converts the RRset to a String */ @Override public String toString() { - if (rrs.size() == 0) { + if (rrs.isEmpty() && sigs.isEmpty()) { return ("{empty}"); } diff --git a/src/test/java/org/xbill/DNS/RRsetTest.java b/src/test/java/org/xbill/DNS/RRsetTest.java index 9df970e25..f37c7c1a5 100644 --- a/src/test/java/org/xbill/DNS/RRsetTest.java +++ b/src/test/java/org/xbill/DNS/RRsetTest.java @@ -35,6 +35,7 @@ package org.xbill.DNS; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -231,13 +232,29 @@ void test_toString() { assertTrue(out.contains("[192.169.232.12]")); } + @Test + void test_toStringOnlySig() { + m_rs.addRR(m_s1); + + String out = m_rs.toString(); + + assertFalse(out.contains("{empty}")); + assertTrue(out.contains(" sigs: ")); + assertTrue(out.contains(m_name.toString())); + } + + @Test + void test_toStringEmpty() { + assertEquals("{empty}", m_rs.toString()); + } + @Test void addRR_invalidType() throws TextParseException { m_rs.addRR(m_a1); CNAMERecord c = new CNAMERecord(m_name, DClass.IN, m_ttl, Name.fromString("an.alias.")); - assertThrows(IllegalArgumentException.class, () -> ((RRset) m_rs).addRR(c)); + assertThrows(IllegalArgumentException.class, () -> m_rs.addRR(c)); } @Test From 60bc8d448b9cc4b94cbcb44075e1d1d6dcf64c1e Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 23 Feb 2020 14:20:43 +0100 Subject: [PATCH 070/431] Fix a potential sorting bug when creating a DNSSEC digest --- src/main/java/org/xbill/DNS/DNSSEC.java | 6 +-- src/test/java/org/xbill/DNS/DNSSECTest.java | 42 +++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/xbill/DNS/DNSSEC.java b/src/main/java/org/xbill/DNS/DNSSEC.java index d5a1f4939..9f6d4b32c 100644 --- a/src/main/java/org/xbill/DNS/DNSSEC.java +++ b/src/main/java/org/xbill/DNS/DNSSEC.java @@ -149,7 +149,7 @@ private static void digestSIG(DNSOutput out, SIGBase sig) { * @param rrset The data to be signed/verified. * @return The data to be cryptographically signed or verified. */ - public static byte[] digestRRset(RRSIGRecord rrsig, RRset rrset) { + public static byte[] digestRRset(RRSIGRecord rrsig, RRset rrset) { DNSOutput out = new DNSOutput(); digestSIG(out, rrsig); @@ -169,9 +169,9 @@ public static byte[] digestRRset(RRSIGRecord rrsig, RRset rrs header.writeU16(rrset.getType()); header.writeU16(rrset.getDClass()); header.writeU32(rrsig.getOrigTTL()); - rrset.rrs().stream() + rrset.rrs(false).stream() .sorted() - .forEach( + .forEachOrdered( record -> { out.writeByteArray(header.toByteArray()); int lengthPosition = out.current(); diff --git a/src/test/java/org/xbill/DNS/DNSSECTest.java b/src/test/java/org/xbill/DNS/DNSSECTest.java index a79754a06..9ca925764 100644 --- a/src/test/java/org/xbill/DNS/DNSSECTest.java +++ b/src/test/java/org/xbill/DNS/DNSSECTest.java @@ -1,6 +1,8 @@ // SPDX-License-Identifier: BSD-2-Clause package org.xbill.DNS; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + import java.io.IOException; import java.time.Instant; import org.junit.jupiter.api.Test; @@ -116,4 +118,44 @@ void testDSALeadingZeroOversize() throws DNSSECException, IOException { set.addRR(rrsig); DNSSEC.verify(set, rrsig, dnskey, Instant.ofEpochMilli(60)); } + + @Test + void testDigestRrsetOrdering() { + Name name = Name.fromConstantString("a."); + Record a1 = new CNAMERecord(name, DClass.IN, 60, Name.fromConstantString("a.b.c.")); + Record a2 = new CNAMERecord(name, DClass.IN, 60, Name.fromConstantString("aa.bb.cc.")); + + RRSIGRecord s1 = + new RRSIGRecord( + name, + DClass.IN, + 60, + Type.CNAME, + 0xF, + 0x60, + Instant.now(), + Instant.now(), + 0xA, + name, + new byte[] {0xa, 0x0}); + RRSIGRecord s2 = + new RRSIGRecord( + name, + DClass.IN, + 60, + Type.CNAME, + 0xF, + 0x60, + Instant.now(), + Instant.now(), + 0xB, + name, + new byte[] {0x0, 0xa}); + RRset rrset = new RRset(); + rrset.addRR(a2); + rrset.addRR(a1); + rrset.addRR(s1); + rrset.addRR(s2); + assertArrayEquals(DNSSEC.digestRRset(s1, rrset), DNSSEC.digestRRset(s1, rrset)); + } } From 145c800e6c1368b353767801daee1ae8de6a781d Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 23 Feb 2020 14:21:35 +0100 Subject: [PATCH 071/431] Fix getting the resolvers of an ExtendedResolver Closes #92 --- src/main/java/org/xbill/DNS/ExtendedResolver.java | 2 +- .../java/org/xbill/DNS/ExtendedResolverTest.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/xbill/DNS/ExtendedResolverTest.java diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index 630b016f5..d33004cd2 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -275,7 +275,7 @@ public Resolver getResolver(int n) { /** Returns all resolvers used by this ExtendedResolver */ public Resolver[] getResolvers() { - return (Resolver[]) resolvers.stream().map(re -> re.resolver).toArray(); + return resolvers.stream().map(re -> re.resolver).toArray(Resolver[]::new); } /** Adds a new resolver to be used by this ExtendedResolver */ diff --git a/src/test/java/org/xbill/DNS/ExtendedResolverTest.java b/src/test/java/org/xbill/DNS/ExtendedResolverTest.java new file mode 100644 index 000000000..93aaa5c4b --- /dev/null +++ b/src/test/java/org/xbill/DNS/ExtendedResolverTest.java @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.net.UnknownHostException; +import org.junit.jupiter.api.Test; + +public class ExtendedResolverTest { + @Test + void testGetExtendedResolver() throws UnknownHostException { + ExtendedResolver r = new ExtendedResolver(new SimpleResolver[] {new SimpleResolver("0.0.0.0")}); + assertEquals(1, r.getResolvers().length); + } +} From 18e37d35959401e581b63b638268e66ca6eb4161 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 23 Feb 2020 14:24:25 +0100 Subject: [PATCH 072/431] Release v3.0.1 --- Changelog | 6 ++++++ pom.xml | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 5870cb479..ef9262809 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +02/23/2020 + - 3.0.1 released + - Fix toString of RRset reporting empty when it contains signatures + - Fix a potential sorting bug when creating a DNSSEC digest + - Fix getting the resolvers of an ExtendedResolver (#92) + 02/15/2020 - 3.0.0 released - Parse RRsig records with epoch time format diff --git a/pom.xml b/pom.xml index 7ce118601..a99294355 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.0.1-SNAPSHOT + 3.0.1 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.0.0 + v3.0.1 From b6451016935213525e29e84a2ea4e5f736f3afa6 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 8 Mar 2020 11:37:15 +0100 Subject: [PATCH 073/431] Revert to snapshot --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a99294355..ab539cf91 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.0.1 + 3.0.2-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.0.1 + HEAD From ebc20c32f24036ae7ef28cb24540c24343842558 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 8 Mar 2020 11:38:20 +0100 Subject: [PATCH 074/431] Refactor type instantiation from reflection to Supplier<> --- src/main/java/org/xbill/DNS/Record.java | 15 +-- src/main/java/org/xbill/DNS/Type.java | 129 ++++++++++---------- src/test/java/org/xbill/DNS/RecordTest.java | 15 +-- 3 files changed, 74 insertions(+), 85 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index bed7bf531..06ba6ce0b 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -4,9 +4,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.text.DecimalFormat; import java.util.Arrays; +import java.util.function.Supplier; import org.xbill.DNS.utils.base16; /** @@ -44,16 +44,9 @@ protected Record() {} private static Record getEmptyRecord(Name name, int type, int dclass, long ttl, boolean hasData) { Record rec; if (hasData) { - Class proto = Type.getProto(type); + Supplier proto = Type.getProto(type); if (proto != null) { - try { - rec = proto.getDeclaredConstructor().newInstance(); - } catch (InstantiationException - | IllegalAccessException - | InvocationTargetException - | NoSuchMethodException e) { - rec = new UNKRecord(); - } + rec = proto.get(); } else { rec = new UNKRecord(); } @@ -67,7 +60,7 @@ private static Record getEmptyRecord(Name name, int type, int dclass, long ttl, return rec; } - /** Converts the type-specific RR to wire format - must be overriden */ + /** Converts the type-specific RR to wire format - must be overridden */ abstract void rrFromWire(DNSInput in) throws IOException; private static Record newRecord( diff --git a/src/main/java/org/xbill/DNS/Type.java b/src/main/java/org/xbill/DNS/Type.java index d410f2b85..6d153a09d 100644 --- a/src/main/java/org/xbill/DNS/Type.java +++ b/src/main/java/org/xbill/DNS/Type.java @@ -3,6 +3,7 @@ package org.xbill.DNS; import java.util.HashMap; +import java.util.function.Supplier; /** * Constants and functions relating to DNS Types @@ -297,7 +298,7 @@ public final class Type { public static final int DLV = 32769; private static class TypeMnemonic extends Mnemonic { - private HashMap> objects; + private HashMap> objects; public TypeMnemonic() { super("Type", CASE_UPPER); @@ -305,7 +306,7 @@ public TypeMnemonic() { objects = new HashMap<>(); } - public void add(int val, String str, Class proto) { + public void add(int val, String str, Supplier proto) { super.add(val, str); objects.put(val, proto); } @@ -315,7 +316,7 @@ public void check(int val) { Type.check(val); } - public Class getProto(int val) { + public Supplier getProto(int val) { check(val); return objects.get(val); } @@ -324,71 +325,71 @@ public Class getProto(int val) { private static TypeMnemonic types = new TypeMnemonic(); static { - types.add(A, "A", ARecord.class); - types.add(NS, "NS", NSRecord.class); - types.add(MD, "MD", MDRecord.class); - types.add(MF, "MF", MFRecord.class); - types.add(CNAME, "CNAME", CNAMERecord.class); - types.add(SOA, "SOA", SOARecord.class); - types.add(MB, "MB", MBRecord.class); - types.add(MG, "MG", MGRecord.class); - types.add(MR, "MR", MRRecord.class); - types.add(NULL, "NULL", NULLRecord.class); - types.add(WKS, "WKS", WKSRecord.class); - types.add(PTR, "PTR", PTRRecord.class); - types.add(HINFO, "HINFO", HINFORecord.class); - types.add(MINFO, "MINFO", MINFORecord.class); - types.add(MX, "MX", MXRecord.class); - types.add(TXT, "TXT", TXTRecord.class); - types.add(RP, "RP", RPRecord.class); - types.add(AFSDB, "AFSDB", AFSDBRecord.class); - types.add(X25, "X25", X25Record.class); - types.add(ISDN, "ISDN", ISDNRecord.class); - types.add(RT, "RT", RTRecord.class); - types.add(NSAP, "NSAP", NSAPRecord.class); - types.add(NSAP_PTR, "NSAP-PTR", NSAP_PTRRecord.class); - types.add(SIG, "SIG", SIGRecord.class); - types.add(KEY, "KEY", KEYRecord.class); - types.add(PX, "PX", PXRecord.class); - types.add(GPOS, "GPOS", GPOSRecord.class); - types.add(AAAA, "AAAA", AAAARecord.class); - types.add(LOC, "LOC", LOCRecord.class); - types.add(NXT, "NXT", NXTRecord.class); + types.add(A, "A", ARecord::new); + types.add(NS, "NS", NSRecord::new); + types.add(MD, "MD", MDRecord::new); + types.add(MF, "MF", MFRecord::new); + types.add(CNAME, "CNAME", CNAMERecord::new); + types.add(SOA, "SOA", SOARecord::new); + types.add(MB, "MB", MBRecord::new); + types.add(MG, "MG", MGRecord::new); + types.add(MR, "MR", MRRecord::new); + types.add(NULL, "NULL", NULLRecord::new); + types.add(WKS, "WKS", WKSRecord::new); + types.add(PTR, "PTR", PTRRecord::new); + types.add(HINFO, "HINFO", HINFORecord::new); + types.add(MINFO, "MINFO", MINFORecord::new); + types.add(MX, "MX", MXRecord::new); + types.add(TXT, "TXT", TXTRecord::new); + types.add(RP, "RP", RPRecord::new); + types.add(AFSDB, "AFSDB", AFSDBRecord::new); + types.add(X25, "X25", X25Record::new); + types.add(ISDN, "ISDN", ISDNRecord::new); + types.add(RT, "RT", RTRecord::new); + types.add(NSAP, "NSAP", NSAPRecord::new); + types.add(NSAP_PTR, "NSAP-PTR", NSAP_PTRRecord::new); + types.add(SIG, "SIG", SIGRecord::new); + types.add(KEY, "KEY", KEYRecord::new); + types.add(PX, "PX", PXRecord::new); + types.add(GPOS, "GPOS", GPOSRecord::new); + types.add(AAAA, "AAAA", AAAARecord::new); + types.add(LOC, "LOC", LOCRecord::new); + types.add(NXT, "NXT", NXTRecord::new); types.add(EID, "EID"); types.add(NIMLOC, "NIMLOC"); - types.add(SRV, "SRV", SRVRecord.class); + types.add(SRV, "SRV", SRVRecord::new); types.add(ATMA, "ATMA"); - types.add(NAPTR, "NAPTR", NAPTRRecord.class); - types.add(KX, "KX", KXRecord.class); - types.add(CERT, "CERT", CERTRecord.class); - types.add(A6, "A6", A6Record.class); - types.add(DNAME, "DNAME", DNAMERecord.class); + types.add(NAPTR, "NAPTR", NAPTRRecord::new); + types.add(KX, "KX", KXRecord::new); + types.add(CERT, "CERT", CERTRecord::new); + types.add(A6, "A6", A6Record::new); + types.add(DNAME, "DNAME", DNAMERecord::new); types.add(SINK, "SINK"); - types.add(OPT, "OPT", OPTRecord.class); - types.add(APL, "APL", APLRecord.class); - types.add(DS, "DS", DSRecord.class); - types.add(SSHFP, "SSHFP", SSHFPRecord.class); - types.add(IPSECKEY, "IPSECKEY", IPSECKEYRecord.class); - types.add(RRSIG, "RRSIG", RRSIGRecord.class); - types.add(NSEC, "NSEC", NSECRecord.class); - types.add(DNSKEY, "DNSKEY", DNSKEYRecord.class); - types.add(DHCID, "DHCID", DHCIDRecord.class); - types.add(NSEC3, "NSEC3", NSEC3Record.class); - types.add(NSEC3PARAM, "NSEC3PARAM", NSEC3PARAMRecord.class); - types.add(TLSA, "TLSA", TLSARecord.class); - types.add(SMIMEA, "SMIMEA", SMIMEARecord.class); - - types.add(HIP, "HIP", HIPRecord.class); + types.add(OPT, "OPT", OPTRecord::new); + types.add(APL, "APL", APLRecord::new); + types.add(DS, "DS", DSRecord::new); + types.add(SSHFP, "SSHFP", SSHFPRecord::new); + types.add(IPSECKEY, "IPSECKEY", IPSECKEYRecord::new); + types.add(RRSIG, "RRSIG", RRSIGRecord::new); + types.add(NSEC, "NSEC", NSECRecord::new); + types.add(DNSKEY, "DNSKEY", DNSKEYRecord::new); + types.add(DHCID, "DHCID", DHCIDRecord::new); + types.add(NSEC3, "NSEC3", NSEC3Record::new); + types.add(NSEC3PARAM, "NSEC3PARAM", NSEC3PARAMRecord::new); + types.add(TLSA, "TLSA", TLSARecord::new); + types.add(SMIMEA, "SMIMEA", SMIMEARecord::new); + + types.add(HIP, "HIP", HIPRecord::new); types.add(NINFO, "NINFO"); types.add(RKEY, "RKEY"); types.add(TALINK, "TALINK"); - types.add(CDS, "CDS", CDSRecord.class); - types.add(CDNSKEY, "CDNSKEY", CDNSKEYRecord.class); - types.add(OPENPGPKEY, "OPENPGPKEY", OPENPGPKEYRecord.class); + types.add(CDS, "CDS", CDSRecord::new); + types.add(CDNSKEY, "CDNSKEY", CDNSKEYRecord::new); + types.add(OPENPGPKEY, "OPENPGPKEY", OPENPGPKEYRecord::new); types.add(CSYNC, "CSYNC"); types.add(ZONEMD, "ZONEMD"); - types.add(SPF, "SPF", SPFRecord.class); + types.add(SPF, "SPF", SPFRecord::new); types.add(UINFO, "UINFO"); types.add(UID, "UID"); types.add(GID, "GID"); @@ -400,21 +401,21 @@ public Class getProto(int val) { types.add(EUI48, "EUI48"); types.add(EUI64, "EUI64"); - types.add(TKEY, "TKEY", TKEYRecord.class); - types.add(TSIG, "TSIG", TSIGRecord.class); + types.add(TKEY, "TKEY", TKEYRecord::new); + types.add(TSIG, "TSIG", TSIGRecord::new); types.add(IXFR, "IXFR"); types.add(AXFR, "AXFR"); types.add(MAILB, "MAILB"); types.add(MAILA, "MAILA"); types.add(ANY, "ANY"); - types.add(URI, "URI", URIRecord.class); - types.add(CAA, "CAA", CAARecord.class); + types.add(URI, "URI", URIRecord::new); + types.add(CAA, "CAA", CAARecord::new); types.add(AVC, "AVC"); types.add(DOA, "DOA"); types.add(AMTRELAY, "AMTRELAY"); types.add(TA, "TA"); - types.add(DLV, "DLV", DLVRecord.class); + types.add(DLV, "DLV", DLVRecord::new); } private Type() {} @@ -465,7 +466,7 @@ public static int value(String s) { return value(s, false); } - static Class getProto(int val) { + static Supplier getProto(int val) { return types.getProto(val); } diff --git a/src/test/java/org/xbill/DNS/RecordTest.java b/src/test/java/org/xbill/DNS/RecordTest.java index c7aee1241..afc78d826 100644 --- a/src/test/java/org/xbill/DNS/RecordTest.java +++ b/src/test/java/org/xbill/DNS/RecordTest.java @@ -45,11 +45,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.net.UnknownHostException; import java.time.Instant; +import java.util.function.Supplier; import junit.framework.Assert; import org.junit.jupiter.api.Test; @@ -852,22 +851,18 @@ void checkName() throws TextParseException { @Test void testAllTypesHaveNoArgConstructor() { for (int i = 1; i < 65535; i++) { - Class proto = Type.getProto(i); + Supplier proto = Type.getProto(i); if (proto != null) { try { - Constructor noArgCtor = proto.getDeclaredConstructor(); - assertNotNull(noArgCtor.newInstance()); - } catch (NoSuchMethodException - | InstantiationException - | IllegalAccessException - | InvocationTargetException e) { + assertNotNull(proto.get()); + } catch (Exception e) { Assert.fail( "Record type " + Type.string(i) + " (" + i + ", " - + proto.getSimpleName() + + proto.getClass().getSimpleName() + ")" + " seems to have no or invalid 0arg ctor"); } From 267118fa63df39bb03969d147749c650ceaa81b5 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 17 Mar 2020 09:36:01 +0100 Subject: [PATCH 075/431] Add method to register private rr types (#93) * Add method to register private rr types * Rename proto and add remove method for Type Mmenomic Closes #94 --- pom.xml | 2 +- src/main/java/org/xbill/DNS/Mnemonic.java | 20 +++++ src/main/java/org/xbill/DNS/Record.java | 6 +- src/main/java/org/xbill/DNS/Type.java | 47 ++++++++++-- src/test/java/org/xbill/DNS/RecordTest.java | 2 +- src/test/java/org/xbill/DNS/TypeTest.java | 85 +++++++++++++++++++++ 6 files changed, 149 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index ab539cf91..d58d64101 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.0.2-SNAPSHOT + 3.1.0-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache diff --git a/src/main/java/org/xbill/DNS/Mnemonic.java b/src/main/java/org/xbill/DNS/Mnemonic.java index 68f8eb30c..140b83cf6 100644 --- a/src/main/java/org/xbill/DNS/Mnemonic.java +++ b/src/main/java/org/xbill/DNS/Mnemonic.java @@ -100,6 +100,16 @@ public void add(int val, String str) { values.put(val, str); } + /** + * Removes both the numeric value and its text representation, including all aliases. + * + * @param val The numeric value + */ + public void remove(int val) { + values.remove(val); + strings.entrySet().removeIf(entry -> entry.getValue() == val); + } + /** * Defines an additional text representation of a numeric value. This will be used by getValue(), * but not getText(). @@ -113,6 +123,16 @@ public void addAlias(int val, String str) { strings.put(str, val); } + /** + * Removes an additional text representation of a numeric value. + * + * @param str The text string + */ + public void removeAlias(String str) { + str = sanitize(str); + strings.remove(str); + } + /** * Copies all mnemonics from one table into another. * diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index 06ba6ce0b..9176548a3 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -44,9 +44,9 @@ protected Record() {} private static Record getEmptyRecord(Name name, int type, int dclass, long ttl, boolean hasData) { Record rec; if (hasData) { - Supplier proto = Type.getProto(type); - if (proto != null) { - rec = proto.get(); + Supplier factory = Type.getFactory(type); + if (factory != null) { + rec = factory.get(); } else { rec = new UNKRecord(); } diff --git a/src/main/java/org/xbill/DNS/Type.java b/src/main/java/org/xbill/DNS/Type.java index 6d153a09d..1eab238f1 100644 --- a/src/main/java/org/xbill/DNS/Type.java +++ b/src/main/java/org/xbill/DNS/Type.java @@ -298,17 +298,32 @@ public final class Type { public static final int DLV = 32769; private static class TypeMnemonic extends Mnemonic { - private HashMap> objects; + private HashMap> factories; public TypeMnemonic() { super("Type", CASE_UPPER); setPrefix("TYPE"); - objects = new HashMap<>(); + factories = new HashMap<>(); } - public void add(int val, String str, Supplier proto) { + public void add(int val, String str, Supplier factory) { super.add(val, str); - objects.put(val, proto); + factories.put(val, factory); + } + + public void replace(int val, String str, Supplier factory) { + int oldVal = getValue(str); + if (oldVal != -1) { + if (oldVal != val) { + throw new IllegalArgumentException( + "mnemnonic \"" + str + "\" already used by type " + oldVal); + } else { + remove(val); + factories.remove(val); + } + } + + add(val, str, factory); } @Override @@ -316,9 +331,9 @@ public void check(int val) { Type.check(val); } - public Supplier getProto(int val) { + public Supplier getFactory(int val) { check(val); - return objects.get(val); + return factories.get(val); } } @@ -431,6 +446,22 @@ public static void check(int val) { } } + /** + * Registers a new record type along with the respective factory. This allows the reimplementation + * of existing types, the implementation of new types not (yet) supported by the library or the + * implementation of "private use" record types. Note that the method is not synchronized and its + * use may interfere with the creation of records in a multi-threaded environment. The method must + * be used with care in order to avoid unexpected behaviour. + * + * @param val the numeric representation of the record type + * @param str the textual representation of the record type + * @param factory the factory; {@code null} may be used if there is no implementation available. + * In this case, records of the type will be represented by the {@link UNKRecord} class + */ + public static void register(int val, String str, Supplier factory) { + types.replace(val, str, factory); + } + /** * Converts a numeric Type into a String * @@ -466,8 +497,8 @@ public static int value(String s) { return value(s, false); } - static Supplier getProto(int val) { - return types.getProto(val); + static Supplier getFactory(int val) { + return types.getFactory(val); } /** Is this type valid for a record (a non-meta type)? */ diff --git a/src/test/java/org/xbill/DNS/RecordTest.java b/src/test/java/org/xbill/DNS/RecordTest.java index afc78d826..11c6bb446 100644 --- a/src/test/java/org/xbill/DNS/RecordTest.java +++ b/src/test/java/org/xbill/DNS/RecordTest.java @@ -851,7 +851,7 @@ void checkName() throws TextParseException { @Test void testAllTypesHaveNoArgConstructor() { for (int i = 1; i < 65535; i++) { - Supplier proto = Type.getProto(i); + Supplier proto = Type.getFactory(i); if (proto != null) { try { assertNotNull(proto.get()); diff --git a/src/test/java/org/xbill/DNS/TypeTest.java b/src/test/java/org/xbill/DNS/TypeTest.java index 29c946e75..100467212 100644 --- a/src/test/java/org/xbill/DNS/TypeTest.java +++ b/src/test/java/org/xbill/DNS/TypeTest.java @@ -36,9 +36,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; import org.junit.jupiter.api.Test; class TypeTest { @@ -78,4 +82,85 @@ void isRR() { assertTrue(Type.isRR(Type.CNAME)); assertFalse(Type.isRR(Type.IXFR)); } + + private static final int MYTXT = 65534; + private static final String MYTXTName = "MYTXT"; + + private static class MYTXTRecord extends TXTBase { + MYTXTRecord() {} + + public MYTXTRecord(Name name, int dclass, long ttl, List strings) { + super(name, MYTXT, dclass, ttl, strings); + } + + public MYTXTRecord(Name name, int dclass, long ttl, String string) { + super(name, MYTXT, dclass, ttl, string); + } + } + + private static class TXTRecordReplacement extends TXTBase { + TXTRecordReplacement() {} + + public TXTRecordReplacement(Name name, int dclass, long ttl, List strings) { + super(name, Type.TXT, dclass, ttl, strings); + } + + public TXTRecordReplacement(Name name, int dclass, long ttl, String string) { + super(name, Type.TXT, dclass, ttl, string); + } + } + + @Test + void checkCustomRecords() throws Exception { + // test "private use" record + + Type.register(MYTXT, MYTXTName, MYTXTRecord::new); + Name testOwner = Name.fromConstantString("example."); + MYTXTRecord testRecord = new MYTXTRecord(testOwner, DClass.IN, 3600, "hello world"); + + byte[] wireData = testRecord.toWire(Section.ANSWER); + Record record = Record.fromWire(new DNSInput(wireData), Section.ANSWER, false); + assertEquals(MYTXTRecord.class, record.getClass()); + assertEquals(MYTXT, record.getType()); + + byte[] textData = testRecord.toString().getBytes(StandardCharsets.US_ASCII); + Master m = new Master(new ByteArrayInputStream(textData)); + record = m.nextRecord(); + assertNotNull(record); + assertEquals(MYTXTRecord.class, record.getClass()); + assertEquals(MYTXT, record.getType()); + m.close(); + + Type.register(MYTXT, MYTXTName, null); + record = Record.fromWire(new DNSInput(wireData), Section.ANSWER, false); + assertEquals(UNKRecord.class, record.getClass()); + assertEquals(MYTXT, record.getType()); + + // test implementation replacement + + try { + assertThrows( + IllegalArgumentException.class, + () -> Type.register(Type.TXT, "SOA", TXTRecordReplacement::new)); + + Type.register(Type.TXT, "TXT", TXTRecordReplacement::new); + TXTRecord testRecord2 = new TXTRecord(testOwner, DClass.IN, 3600, "howdy"); + wireData = testRecord2.toWire(Section.ANSWER); + record = Record.fromWire(new DNSInput(wireData), Section.ANSWER, false); + assertEquals(TXTRecordReplacement.class, record.getClass()); + assertEquals(Type.TXT, record.getType()); + + byte[] textData2 = testRecord2.toString().getBytes(StandardCharsets.US_ASCII); + m = new Master(new ByteArrayInputStream(textData2)); + record = m.nextRecord(); + assertNotNull(record); + assertEquals(TXTRecordReplacement.class, record.getClass()); + assertEquals(Type.TXT, record.getType()); + m.close(); + + } finally { + // restore default implementation as needed by other tests + Type.register(Type.TXT, "TXT", TXTRecord::new); + } + } } From 857980615e1502f51eeb8bc146ddc364cf08f3d4 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Thu, 19 Mar 2020 13:37:28 +0100 Subject: [PATCH 076/431] Only select for tcp write when there is something to write Closes #95 Closes #96 --- src/main/java/org/xbill/DNS/NioTcpClient.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/xbill/DNS/NioTcpClient.java b/src/main/java/org/xbill/DNS/NioTcpClient.java index 24696ac34..f93682f60 100644 --- a/src/main/java/org/xbill/DNS/NioTcpClient.java +++ b/src/main/java/org/xbill/DNS/NioTcpClient.java @@ -47,6 +47,8 @@ private static void processPendingRegistrations() { try { if (!state.channel.isConnected()) { state.channel.register(selector, SelectionKey.OP_CONNECT, state); + } else { + state.channel.keyFor(selector).interestOps(SelectionKey.OP_WRITE); } } catch (ClosedChannelException e) { state.handleChannelException(e); @@ -130,7 +132,7 @@ public void processReadyKey(SelectionKey key) { processConnect(key); } else { if (key.isWritable()) { - processWrite(); + processWrite(key); } if (key.isReadable()) { processRead(); @@ -164,7 +166,7 @@ private void handleChannelException(IOException e) { private void processConnect(SelectionKey key) { try { channel.finishConnect(); - key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); + key.interestOps(SelectionKey.OP_WRITE); } catch (IOException e) { handleChannelException(e); } @@ -223,7 +225,7 @@ private void processRead() { } } - private void processWrite() { + private void processWrite(SelectionKey key) { for (Iterator it = pendingTransactions.iterator(); it.hasNext(); ) { Transaction t = it.next(); try { @@ -233,6 +235,8 @@ private void processWrite() { it.remove(); } } + + key.interestOps(SelectionKey.OP_READ); } } From 2f6edcb36c0af0aa12a9b7e801774c1539008aa3 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Thu, 19 Mar 2020 13:46:55 +0100 Subject: [PATCH 077/431] Release v3.0.2 --- Changelog | 5 +++++ pom.xml | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index ef9262809..9a444781b 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,8 @@ +03/19/2020 + - 3.0.2 released + - Only select for tcp write when there is something to write + (PR#96, Rouzbeh Delavari) + 02/23/2020 - 3.0.1 released - Fix toString of RRset reporting empty when it contains signatures diff --git a/pom.xml b/pom.xml index ab539cf91..f1c42991d 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.0.2-SNAPSHOT + 3.0.2 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - HEAD + v3.0.2 From 1ec2f494fcb73fd5892a4ddcd0c924a04e842972 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Thu, 19 Mar 2020 13:58:24 +0100 Subject: [PATCH 078/431] Return to -snapshot --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f1c42991d..7f7d086c7 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.0.2 + 3.0.3-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.0.2 + HEAD From 0360283b865bd7f2713b2aead1ac75f2669b1f7a Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 21 Mar 2020 17:30:46 +0100 Subject: [PATCH 079/431] Small performance improvements to record comparison --- src/main/java/org/xbill/DNS/Record.java | 28 ++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index 9176548a3..6509dc5f3 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -327,9 +327,9 @@ protected static byte[] byteArrayFromString(String s) throws TextParseException int digits = 0; int intval = 0; for (byte value : array) { - byte b = value; if (escaped) { - if (b >= '0' && b <= '9' && digits < 3) { + byte b = value; + if (b >= '0' && b <= '9') { digits++; intval *= 10; intval += (b - '0'); @@ -340,7 +340,7 @@ protected static byte[] byteArrayFromString(String s) throws TextParseException continue; } b = (byte) intval; - } else if (digits > 0 && digits < 3) { + } else if (digits > 0) { throw new TextParseException("bad escape"); } os.write(b); @@ -596,30 +596,34 @@ void setTTL(long ttl) { @Override public int compareTo(Record arg) { if (this == arg) { - return (0); + return 0; } int n = name.compareTo(arg.name); if (n != 0) { - return (n); + return n; } + n = dclass - arg.dclass; if (n != 0) { - return (n); + return n; } + n = type - arg.type; if (n != 0) { - return (n); + return n; } + byte[] rdata1 = rdataToWireCanonical(); byte[] rdata2 = arg.rdataToWireCanonical(); - for (int i = 0; i < rdata1.length && i < rdata2.length; i++) { - n = (rdata1[i] & 0xFF) - (rdata2[i] & 0xFF); - if (n != 0) { - return (n); + int minLen = Math.min(rdata1.length, rdata2.length); + for (int i = 0; i < minLen; i++) { + if (rdata1[i] != rdata2[i]) { + return (rdata1[i] & 0xFF) - (rdata2[i] & 0xFF); } } - return (rdata1.length - rdata2.length); + + return rdata1.length - rdata2.length; } /** From e35c39bee9f135ef8768e64623eaa8b82d761b20 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 21 Mar 2020 18:38:20 +0100 Subject: [PATCH 080/431] Remove obsessive parenthesis --- src/main/java/org/xbill/DNS/APLRecord.java | 4 +- src/main/java/org/xbill/DNS/ARecord.java | 8 +-- src/main/java/org/xbill/DNS/Address.java | 12 ++--- src/main/java/org/xbill/DNS/Cache.java | 8 +-- src/main/java/org/xbill/DNS/DNSInput.java | 6 +-- src/main/java/org/xbill/DNS/DNSSEC.java | 10 ++-- src/main/java/org/xbill/DNS/EDNSOption.java | 2 +- src/main/java/org/xbill/DNS/Generator.java | 4 +- src/main/java/org/xbill/DNS/Header.java | 4 +- src/main/java/org/xbill/DNS/KEYBase.java | 8 +-- src/main/java/org/xbill/DNS/LOCRecord.java | 16 +++--- src/main/java/org/xbill/DNS/Master.java | 2 +- src/main/java/org/xbill/DNS/Message.java | 18 +++---- src/main/java/org/xbill/DNS/NXTRecord.java | 2 +- src/main/java/org/xbill/DNS/Name.java | 49 +++++++++---------- src/main/java/org/xbill/DNS/OPTRecord.java | 2 +- src/main/java/org/xbill/DNS/Options.java | 8 +-- src/main/java/org/xbill/DNS/RRset.java | 2 +- src/main/java/org/xbill/DNS/Record.java | 6 +-- src/main/java/org/xbill/DNS/ReverseMap.java | 2 +- src/main/java/org/xbill/DNS/Serial.java | 4 +- src/main/java/org/xbill/DNS/SetResponse.java | 18 +++---- .../java/org/xbill/DNS/SimpleResolver.java | 2 +- src/main/java/org/xbill/DNS/TSIG.java | 20 ++++---- src/main/java/org/xbill/DNS/TSIGRecord.java | 4 +- src/main/java/org/xbill/DNS/Tokenizer.java | 4 +- src/main/java/org/xbill/DNS/TypeBitmap.java | 4 +- src/main/java/org/xbill/DNS/WKSRecord.java | 2 +- src/main/java/org/xbill/DNS/Zone.java | 6 +-- .../java/org/xbill/DNS/ZoneTransferIn.java | 6 +-- src/main/java/org/xbill/DNS/utils/base64.java | 8 +-- .../java/org/xbill/DNS/utils/hexdump.java | 6 +-- .../java/org/xbill/DNS/DNSOutputTest.java | 4 +- src/test/java/org/xbill/DNS/RecordTest.java | 2 +- .../java/org/xbill/DNS/TokenizerTest.java | 2 +- .../java/org/xbill/DNS/URIRecordTest.java | 4 +- 36 files changed, 134 insertions(+), 135 deletions(-) diff --git a/src/main/java/org/xbill/DNS/APLRecord.java b/src/main/java/org/xbill/DNS/APLRecord.java index 5ffd80016..49d07985c 100644 --- a/src/main/java/org/xbill/DNS/APLRecord.java +++ b/src/main/java/org/xbill/DNS/APLRecord.java @@ -75,10 +75,10 @@ public boolean equals(Object arg) { return false; } Element elt = (Element) arg; - return (family == elt.family + return family == elt.family && negative == elt.negative && prefixLength == elt.prefixLength - && address.equals(elt.address)); + && address.equals(elt.address); } @Override diff --git a/src/main/java/org/xbill/DNS/ARecord.java b/src/main/java/org/xbill/DNS/ARecord.java index df45ee614..d51dffb9e 100644 --- a/src/main/java/org/xbill/DNS/ARecord.java +++ b/src/main/java/org/xbill/DNS/ARecord.java @@ -19,10 +19,10 @@ public class ARecord extends Record { ARecord() {} private static int fromArray(byte[] array) { - return (((array[0] & 0xFF) << 24) + return ((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) - | (array[3] & 0xFF)); + | (array[3] & 0xFF); } private static byte[] toArray(int addr) { @@ -60,7 +60,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override String rrToString() { - return (Address.toDottedQuad(toArray(addr))); + return Address.toDottedQuad(toArray(addr)); } /** Returns the Internet address */ @@ -78,6 +78,6 @@ public InetAddress getAddress() { @Override void rrToWire(DNSOutput out, Compression c, boolean canonical) { - out.writeU32(((long) addr) & 0xFFFFFFFFL); + out.writeU32((long) addr & 0xFFFFFFFFL); } } diff --git a/src/main/java/org/xbill/DNS/Address.java b/src/main/java/org/xbill/DNS/Address.java index c03c56f90..536feca3a 100644 --- a/src/main/java/org/xbill/DNS/Address.java +++ b/src/main/java/org/xbill/DNS/Address.java @@ -43,7 +43,7 @@ private static byte[] parseV4(String s) { } numDigits++; currentValue *= 10; - currentValue += (c - '0'); + currentValue += c - '0'; /* 255 is the maximum value for an octet. */ if (currentValue > 255) { return null; @@ -227,7 +227,7 @@ public static byte[] toByteArray(String s, int family) { */ public static boolean isDottedQuad(String s) { byte[] address = Address.toByteArray(s, IPv4); - return (address != null); + return address != null; } /** @@ -237,13 +237,13 @@ public static boolean isDottedQuad(String s) { * @return The string representation */ public static String toDottedQuad(byte[] addr) { - return ((addr[0] & 0xFF) + return (addr[0] & 0xFF) + "." + (addr[1] & 0xFF) + "." + (addr[2] & 0xFF) + "." - + (addr[3] & 0xFF)); + + (addr[3] & 0xFF); } /** @@ -253,7 +253,7 @@ public static String toDottedQuad(byte[] addr) { * @return The string representation */ public static String toDottedQuad(int[] addr) { - return (addr[0] + "." + addr[1] + "." + addr[2] + "." + addr[3]); + return addr[0] + "." + addr[1] + "." + addr[2] + "." + addr[3]; } private static Record[] lookupHostName(String name, boolean all) throws UnknownHostException { @@ -446,7 +446,7 @@ public static InetAddress truncate(InetAddress address, int maskLength) { int maskBits = maskLength % 8; int bitmask = 0; for (int i = 0; i < maskBits; i++) { - bitmask |= (1 << (7 - i)); + bitmask |= 1 << (7 - i); } bytes[maskLength / 8] &= bitmask; try { diff --git a/src/main/java/org/xbill/DNS/Cache.java b/src/main/java/org/xbill/DNS/Cache.java index f16d60321..af7c5d38f 100644 --- a/src/main/java/org/xbill/DNS/Cache.java +++ b/src/main/java/org/xbill/DNS/Cache.java @@ -65,7 +65,7 @@ public CacheRRset(RRset rrset, int cred, long maxttl) { @Override public final boolean expired() { int now = (int) (System.currentTimeMillis() / 1000); - return (now >= expire); + return now >= expire; } @Override @@ -104,7 +104,7 @@ public int getType() { @Override public final boolean expired() { int now = (int) (System.currentTimeMillis() / 1000); - return (now >= expire); + return now >= expire; } @Override @@ -426,8 +426,8 @@ protected synchronized SetResponse lookup(Name name, int type, int minCred) { labels = name.labels(); for (tlabels = labels; tlabels >= 1; tlabels--) { - boolean isRoot = (tlabels == 1); - boolean isExact = (tlabels == labels); + boolean isRoot = tlabels == 1; + boolean isExact = tlabels == labels; if (isRoot) { tname = Name.root; diff --git a/src/main/java/org/xbill/DNS/DNSInput.java b/src/main/java/org/xbill/DNS/DNSInput.java index 7b6295d72..8d8f01104 100644 --- a/src/main/java/org/xbill/DNS/DNSInput.java +++ b/src/main/java/org/xbill/DNS/DNSInput.java @@ -139,7 +139,7 @@ public void restore() { */ public int readU8() throws WireParseException { require(1); - return (byteBuffer.get() & 0xFF); + return byteBuffer.get() & 0xFF; } /** @@ -150,7 +150,7 @@ public int readU8() throws WireParseException { */ public int readU16() throws WireParseException { require(2); - return (byteBuffer.getShort() & 0xFFFF); + return byteBuffer.getShort() & 0xFFFF; } /** @@ -161,7 +161,7 @@ public int readU16() throws WireParseException { */ public long readU32() throws WireParseException { require(4); - return (byteBuffer.getInt() & 0xFFFFFFFFL); + return byteBuffer.getInt() & 0xFFFFFFFFL; } /** diff --git a/src/main/java/org/xbill/DNS/DNSSEC.java b/src/main/java/org/xbill/DNS/DNSSEC.java index 9f6d4b32c..785683eee 100644 --- a/src/main/java/org/xbill/DNS/DNSSEC.java +++ b/src/main/java/org/xbill/DNS/DNSSEC.java @@ -964,9 +964,9 @@ private static void verify(PublicKey key, int alg, byte[] data, byte[] signature } private static boolean matches(SIGBase sig, KEYBase key) { - return (key.getAlgorithm() == sig.getAlgorithm() + return key.getAlgorithm() == sig.getAlgorithm() && key.getFootprint() == sig.getFootprint() - && key.getName().equals(sig.getSigner())); + && key.getName().equals(sig.getSigner()); } /** @@ -1099,20 +1099,20 @@ static void checkAlgorithm(PrivateKey key, int alg) throws UnsupportedAlgorithmE case Algorithm.RSA_NSEC3_SHA1: case Algorithm.RSASHA256: case Algorithm.RSASHA512: - if (!("RSA".equals(key.getAlgorithm()))) { + if (!"RSA".equals(key.getAlgorithm())) { throw new IncompatibleKeyException(); } break; case Algorithm.DSA: case Algorithm.DSA_NSEC3_SHA1: - if (!("DSA".equals(key.getAlgorithm()))) { + if (!"DSA".equals(key.getAlgorithm())) { throw new IncompatibleKeyException(); } break; case Algorithm.ECC_GOST: case Algorithm.ECDSAP256SHA256: case Algorithm.ECDSAP384SHA384: - if (!("EC".equals(key.getAlgorithm()))) { + if (!"EC".equals(key.getAlgorithm())) { throw new IncompatibleKeyException(); } break; diff --git a/src/main/java/org/xbill/DNS/EDNSOption.java b/src/main/java/org/xbill/DNS/EDNSOption.java index 3031ca407..c192f9317 100644 --- a/src/main/java/org/xbill/DNS/EDNSOption.java +++ b/src/main/java/org/xbill/DNS/EDNSOption.java @@ -259,7 +259,7 @@ public int hashCode() { byte[] array = getData(); int hashval = 0; for (byte b : array) { - hashval += ((hashval << 3) + (b & 0xFF)); + hashval += (hashval << 3) + (b & 0xFF); } return hashval; } diff --git a/src/main/java/org/xbill/DNS/Generator.java b/src/main/java/org/xbill/DNS/Generator.java index d9ceb1c21..f21c9dfc7 100644 --- a/src/main/java/org/xbill/DNS/Generator.java +++ b/src/main/java/org/xbill/DNS/Generator.java @@ -49,12 +49,12 @@ public class Generator { */ public static boolean supportedType(int type) { Type.check(type); - return (type == Type.PTR + return type == Type.PTR || type == Type.CNAME || type == Type.DNAME || type == Type.A || type == Type.AAAA - || type == Type.NS); + || type == Type.NS; } /** diff --git a/src/main/java/org/xbill/DNS/Header.java b/src/main/java/org/xbill/DNS/Header.java index 3344e77b7..700ab31f9 100644 --- a/src/main/java/org/xbill/DNS/Header.java +++ b/src/main/java/org/xbill/DNS/Header.java @@ -74,7 +74,7 @@ public byte[] toWire() { } private static boolean validFlag(int bit) { - return (bit >= 0 && bit <= 0xF && Flags.isFlag(bit)); + return bit >= 0 && bit <= 0xF && Flags.isFlag(bit); } private static void checkFlag(int bit) { @@ -185,7 +185,7 @@ public void setOpcode(int value) { throw new IllegalArgumentException("DNS Opcode " + value + "is out of range"); } flags &= 0x87FF; - flags |= (value << 11); + flags |= value << 11; } /** diff --git a/src/main/java/org/xbill/DNS/KEYBase.java b/src/main/java/org/xbill/DNS/KEYBase.java index fb4f58b96..0cbdb4cbb 100644 --- a/src/main/java/org/xbill/DNS/KEYBase.java +++ b/src/main/java/org/xbill/DNS/KEYBase.java @@ -102,15 +102,15 @@ public int getFootprint() { for (i = 0; i < rdata.length - 1; i += 2) { int d1 = rdata[i] & 0xFF; int d2 = rdata[i + 1] & 0xFF; - foot += ((d1 << 8) + d2); + foot += (d1 << 8) + d2; } if (i < rdata.length) { int d1 = rdata[i] & 0xFF; - foot += (d1 << 8); + foot += d1 << 8; } - foot += ((foot >> 16) & 0xFFFF); + foot += (foot >> 16) & 0xFFFF; } - footprint = (foot & 0xFFFF); + footprint = foot & 0xFFFF; return footprint; } diff --git a/src/main/java/org/xbill/DNS/LOCRecord.java b/src/main/java/org/xbill/DNS/LOCRecord.java index 8c84f5f54..277aa0675 100644 --- a/src/main/java/org/xbill/DNS/LOCRecord.java +++ b/src/main/java/org/xbill/DNS/LOCRecord.java @@ -131,7 +131,7 @@ private long parsePosition(Tokenizer st, String type) throws IOException { throw st.exception("Invalid LOC " + type); } - value += (1L << 31); + value += 1L << 31; return value; } @@ -243,32 +243,32 @@ String rrToString() { /** Returns the latitude */ public double getLatitude() { - return ((double) (latitude - (1L << 31))) / (3600 * 1000); + return (double) (latitude - (1L << 31)) / (3600 * 1000); } /** Returns the longitude */ public double getLongitude() { - return ((double) (longitude - (1L << 31))) / (3600 * 1000); + return (double) (longitude - (1L << 31)) / (3600 * 1000); } /** Returns the altitude */ public double getAltitude() { - return ((double) (altitude - 10000000)) / 100; + return (double) (altitude - 10000000) / 100; } /** Returns the diameter of the enclosing sphere */ public double getSize() { - return ((double) size) / 100; + return (double) size / 100; } /** Returns the horizontal precision */ public double getHPrecision() { - return ((double) hPrecision) / 100; + return (double) hPrecision / 100; } /** Returns the horizontal precision */ public double getVPrecision() { - return ((double) vPrecision) / 100; + return (double) vPrecision / 100; } @Override @@ -291,7 +291,7 @@ private static long parseLOCformat(int b) throws WireParseException { while (exp-- > 0) { out *= 10; } - return (out); + return out; } private int toLOCformat(long l) { diff --git a/src/main/java/org/xbill/DNS/Master.java b/src/main/java/org/xbill/DNS/Master.java index 2d8b01a62..b8b82a410 100644 --- a/src/main/java/org/xbill/DNS/Master.java +++ b/src/main/java/org/xbill/DNS/Master.java @@ -308,7 +308,7 @@ private Record _nextRecord() throws IOException { continue; } else if (token.type == Tokenizer.EOF) { return null; - } else if ((token.value).charAt(0) == '$') { + } else if (token.value.charAt(0) == '$') { s = token.value; if (s.equalsIgnoreCase("$ORIGIN")) { diff --git a/src/main/java/org/xbill/DNS/Message.java b/src/main/java/org/xbill/DNS/Message.java index ecbab21a2..74631189d 100644 --- a/src/main/java/org/xbill/DNS/Message.java +++ b/src/main/java/org/xbill/DNS/Message.java @@ -100,7 +100,7 @@ public static Message newUpdate(Name zone) { Message(DNSInput in) throws IOException { this(new Header(in)); - boolean isUpdate = (header.getOpcode() == Opcode.UPDATE); + boolean isUpdate = header.getOpcode() == Opcode.UPDATE; boolean truncated = header.getFlag(Flags.TC); try { for (int i = 0; i < 4; i++) { @@ -216,7 +216,7 @@ public void removeAllRecords(int section) { * @see Section */ public boolean findRecord(Record r, int section) { - return (sections[section] != null && sections[section].contains(r)); + return sections[section] != null && sections[section].contains(r); } /** @@ -260,9 +260,9 @@ public boolean findRRset(Name name, int type, int section) { * @see Section */ public boolean findRRset(Name name, int type) { - return (findRRset(name, type, Section.ANSWER) + return findRRset(name, type, Section.ANSWER) || findRRset(name, type, Section.AUTHORITY) - || findRRset(name, type, Section.ADDITIONAL)); + || findRRset(name, type, Section.ADDITIONAL); } /** @@ -305,7 +305,7 @@ public TSIGRecord getTSIG() { * @see TSIG */ public boolean isSigned() { - return (tsigState == TSIG_SIGNED || tsigState == TSIG_VERIFIED || tsigState == TSIG_FAILED); + return tsigState == TSIG_SIGNED || tsigState == TSIG_VERIFIED || tsigState == TSIG_FAILED; } /** @@ -314,7 +314,7 @@ public boolean isSigned() { * @see TSIG */ public boolean isVerified() { - return (tsigState == TSIG_VERIFIED); + return tsigState == TSIG_VERIFIED; } /** @@ -337,7 +337,7 @@ public int getRcode() { int rcode = header.getRcode(); OPTRecord opt = getOPT(); if (opt != null) { - rcode += (opt.getExtendedRcode() << 4); + rcode += opt.getExtendedRcode() << 4; } return rcode; } @@ -373,9 +373,9 @@ public List getSection(int section) { } private static boolean sameSet(Record r1, Record r2) { - return (r1.getRRsetType() == r2.getRRsetType() + return r1.getRRsetType() == r2.getRRsetType() && r1.getDClass() == r2.getDClass() - && r1.getName().equals(r2.getName())); + && r1.getName().equals(r2.getName()); } /** diff --git a/src/main/java/org/xbill/DNS/NXTRecord.java b/src/main/java/org/xbill/DNS/NXTRecord.java index 45569cfd1..a4e088c7d 100644 --- a/src/main/java/org/xbill/DNS/NXTRecord.java +++ b/src/main/java/org/xbill/DNS/NXTRecord.java @@ -95,7 +95,7 @@ void rrToWire(DNSOutput out, Compression c, boolean canonical) { next.toWire(out, null, canonical); int length = bitmap.length(); for (int i = 0, t = 0; i < length; i++) { - t |= (bitmap.get(i) ? (1 << (7 - i % 8)) : 0); + t |= bitmap.get(i) ? (1 << (7 - i % 8)) : 0; if (i % 8 == 7 || i == length - 1) { out.writeU8(t); t = 0; diff --git a/src/main/java/org/xbill/DNS/Name.java b/src/main/java/org/xbill/DNS/Name.java index d4220ce8c..150977376 100644 --- a/src/main/java/org/xbill/DNS/Name.java +++ b/src/main/java/org/xbill/DNS/Name.java @@ -87,8 +87,8 @@ private void setoffset(int n, int offset) { return; } int shift = 8 * (7 - n); - offsets &= (~(0xFFL << shift)); - offsets |= ((long) offset << shift); + offsets &= ~(0xFFL << shift); + offsets |= (long) offset << shift; } private int offset(int n) { @@ -100,18 +100,18 @@ private int offset(int n) { } if (n < MAXOFFSETS) { int shift = 8 * (7 - n); - return ((int) (offsets >>> shift) & 0xFF); + return (int) (offsets >>> shift) & 0xFF; } else { int pos = offset(MAXOFFSETS - 1); for (int i = MAXOFFSETS - 1; i < n; i++) { - pos += (name[pos] + 1); + pos += name[pos] + 1; } - return (pos); + return pos; } } private void setlabels(int labels) { - offsets &= ~(0xFF); + offsets &= ~0xFF; offsets |= labels; } @@ -137,7 +137,7 @@ private static void copy(Name src, Name dst) { } private void append(byte[] array, int start, int n) throws NameTooLongException { - int length = (name == null ? 0 : (name.length - offset(0))); + int length = name == null ? 0 : name.length - offset(0); int alength = 0; for (int i = 0, pos = start; i < n; i++) { int len = array[pos]; @@ -165,7 +165,7 @@ private void append(byte[] array, int start, int n) throws NameTooLongException name = newname; for (int i = 0, pos = length; i < n; i++) { setoffset(labels + i, pos); - pos += (newname[pos] + 1); + pos += newname[pos] + 1; } setlabels(newlabels); } @@ -226,7 +226,7 @@ public Name(String s, Name origin) throws TextParseException { if (b >= '0' && b <= '9' && digits < 3) { digits++; intval *= 10; - intval += (b - '0'); + intval += b - '0'; if (intval > 255) { throw parseException(s, "bad escape"); } @@ -370,7 +370,7 @@ public Name(DNSInput in) throws WireParseException { break; case LABEL_COMPRESSION: pos = in.readU8(); - pos += ((len & ~LABEL_MASK) << 8); + pos += (len & ~LABEL_MASK) << 8; log.trace("currently {}, pointer to {}", in.current(), pos); if (pos >= in.current() - 2) { @@ -429,7 +429,7 @@ public Name(Name src, int n) { */ public static Name concatenate(Name prefix, Name suffix) throws NameTooLongException { if (prefix.isAbsolute()) { - return (prefix); + return prefix; } Name newname = new Name(); copy(prefix, newname); @@ -535,7 +535,7 @@ public Name fromDNAME(DNAMERecord dname) throws NameTooLongException { for (int i = 0, pos = 0; i < MAXOFFSETS && i < plabels + dlabels; i++) { newname.setoffset(i, pos); - pos += (newname.name[pos] + 1); + pos += newname.name[pos] + 1; } return newname; } @@ -545,7 +545,7 @@ public boolean isWild() { if (labels() == 0) { return false; } - return (name[0] == (byte) 1 && name[1] == (byte) '*'); + return name[0] == (byte) 1 && name[1] == (byte) '*'; } /** Is this name absolute? */ @@ -631,7 +631,7 @@ public String toString(boolean omitFinalDot) { sb.append('.'); } sb.append(byteString(name, pos)); - pos += (1 + len); + pos += 1 + len; } return sb.toString(); } @@ -695,7 +695,7 @@ public void toWire(DNSOutput out, Compression c) { pos = c.get(tname); } if (pos >= 0) { - pos |= (LABEL_MASK << 8); + pos |= LABEL_MASK << 8; out.writeU16(pos); return; } else { @@ -738,7 +738,7 @@ public void toWireCanonical(DNSOutput out) { public byte[] toWireCanonical() { int labels = labels(); if (labels == 0) { - return (new byte[0]); + return new byte[0]; } byte[] b = new byte[name.length - offset(0)]; for (int i = 0, spos = offset(0), dpos = 0; i < labels; i++) { @@ -748,7 +748,7 @@ public byte[] toWireCanonical() { } b[dpos++] = name[spos++]; for (int j = 0; j < len; j++) { - b[dpos++] = lowercase[(name[spos++] & 0xFF)]; + b[dpos++] = lowercase[name[spos++] & 0xFF]; } } return b; @@ -782,7 +782,7 @@ private boolean equals(byte[] b, int bpos) { throw new IllegalStateException("invalid label"); } for (int j = 0; j < len; j++) { - if (lowercase[(name[pos++] & 0xFF)] != lowercase[(b[bpos++] & 0xFF)]) { + if (lowercase[name[pos++] & 0xFF] != lowercase[b[bpos++] & 0xFF]) { return false; } } @@ -817,7 +817,7 @@ public int hashCode() { } int code = 0; for (int i = offset(0); i < name.length; i++) { - code += ((code << 3) + lowercase[(name[i] & 0xFF)]); + code += (code << 3) + lowercase[name[i] & 0xFF]; } hashcode = code; return hashcode; @@ -835,7 +835,7 @@ public int hashCode() { @Override public int compareTo(Name arg) { if (this == arg) { - return (0); + return 0; } int labels = labels(); @@ -848,16 +848,15 @@ public int compareTo(Name arg) { int length = name[start]; int alength = arg.name[astart]; for (int j = 0; j < length && j < alength; j++) { - int n = - lowercase[(name[j + start + 1]) & 0xFF] - lowercase[(arg.name[j + astart + 1]) & 0xFF]; + int n = lowercase[name[j + start + 1] & 0xFF] - lowercase[arg.name[j + astart + 1] & 0xFF]; if (n != 0) { - return (n); + return n; } } if (length != alength) { - return (length - alength); + return length - alength; } } - return (labels - alabels); + return labels - alabels; } } diff --git a/src/main/java/org/xbill/DNS/OPTRecord.java b/src/main/java/org/xbill/DNS/OPTRecord.java index 443020a6d..3fd025934 100644 --- a/src/main/java/org/xbill/DNS/OPTRecord.java +++ b/src/main/java/org/xbill/DNS/OPTRecord.java @@ -183,7 +183,7 @@ public int hashCode() { byte[] array = toWireCanonical(); int code = 0; for (byte b : array) { - code += ((code << 3) + (b & 0xFF)); + code += (code << 3) + (b & 0xFF); } return code; } diff --git a/src/main/java/org/xbill/DNS/Options.java b/src/main/java/org/xbill/DNS/Options.java index 275f2e112..f7b86518c 100644 --- a/src/main/java/org/xbill/DNS/Options.java +++ b/src/main/java/org/xbill/DNS/Options.java @@ -83,7 +83,7 @@ public static boolean check(String option) { if (table == null) { return false; } - return (table.get(option.toLowerCase()) != null); + return table.get(option.toLowerCase()) != null; } /** Returns the value of an option */ @@ -91,7 +91,7 @@ public static String value(String option) { if (table == null) { return null; } - return (table.get(option.toLowerCase())); + return table.get(option.toLowerCase()); } /** Returns the value of an option as an integer, or -1 if not defined. */ @@ -101,11 +101,11 @@ public static int intValue(String option) { try { int val = Integer.parseInt(s); if (val > 0) { - return (val); + return val; } } catch (NumberFormatException e) { } } - return (-1); + return -1; } } diff --git a/src/main/java/org/xbill/DNS/RRset.java b/src/main/java/org/xbill/DNS/RRset.java index f6ea68944..9f20640b2 100644 --- a/src/main/java/org/xbill/DNS/RRset.java +++ b/src/main/java/org/xbill/DNS/RRset.java @@ -234,7 +234,7 @@ private void appendRrList(Iterator it, StringBuilder sb) { @Override public String toString() { if (rrs.isEmpty() && sigs.isEmpty()) { - return ("{empty}"); + return "{empty}"; } StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index 6509dc5f3..9c8888fcc 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -332,7 +332,7 @@ protected static byte[] byteArrayFromString(String s) throws TextParseException if (b >= '0' && b <= '9') { digits++; intval *= 10; - intval += (b - '0'); + intval += b - '0'; if (intval > 255) { throw new TextParseException("bad escape"); } @@ -511,7 +511,7 @@ public long getTTL() { * class of the Records; the ttl and rdata are not compared. */ public boolean sameRRset(Record rec) { - return (getRRsetType() == rec.getRRsetType() && dclass == rec.dclass && name.equals(rec.name)); + return getRRsetType() == rec.getRRsetType() && dclass == rec.dclass && name.equals(rec.name); } /** @@ -541,7 +541,7 @@ public int hashCode() { byte[] array = toWireCanonical(true); int code = 0; for (byte b : array) { - code += ((code << 3) + (b & 0xFF)); + code += (code << 3) + (b & 0xFF); } return code; } diff --git a/src/main/java/org/xbill/DNS/ReverseMap.java b/src/main/java/org/xbill/DNS/ReverseMap.java index d21d9f27f..82b22f1df 100644 --- a/src/main/java/org/xbill/DNS/ReverseMap.java +++ b/src/main/java/org/xbill/DNS/ReverseMap.java @@ -44,7 +44,7 @@ public static Name fromAddress(byte[] addr) { int[] nibbles = new int[2]; for (int i = addr.length - 1; i >= 0; i--) { nibbles[0] = (addr[i] & 0xFF) >> 4; - nibbles[1] = (addr[i] & 0xFF) & 0xF; + nibbles[1] = addr[i] & 0xF; for (int j = nibbles.length - 1; j >= 0; j--) { sb.append(Integer.toHexString(nibbles[j])); if (i > 0 || j > 0) { diff --git a/src/main/java/org/xbill/DNS/Serial.java b/src/main/java/org/xbill/DNS/Serial.java index e2d2b1d73..dca754a38 100644 --- a/src/main/java/org/xbill/DNS/Serial.java +++ b/src/main/java/org/xbill/DNS/Serial.java @@ -34,9 +34,9 @@ public static int compare(long serial1, long serial2) { } long diff = serial1 - serial2; if (diff >= MAX32) { - diff -= (MAX32 + 1); + diff -= MAX32 + 1; } else if (diff < -MAX32) { - diff += (MAX32 + 1); + diff += MAX32 + 1; } return (int) diff; } diff --git a/src/main/java/org/xbill/DNS/SetResponse.java b/src/main/java/org/xbill/DNS/SetResponse.java index d2e458a25..ebd86127e 100644 --- a/src/main/java/org/xbill/DNS/SetResponse.java +++ b/src/main/java/org/xbill/DNS/SetResponse.java @@ -106,37 +106,37 @@ void addRRset(RRset rrset) { /** Is the answer to the query unknown? */ public boolean isUnknown() { - return (type == UNKNOWN); + return type == UNKNOWN; } /** Is the answer to the query that the name does not exist? */ public boolean isNXDOMAIN() { - return (type == NXDOMAIN); + return type == NXDOMAIN; } /** Is the answer to the query that the name exists, but the type does not? */ public boolean isNXRRSET() { - return (type == NXRRSET); + return type == NXRRSET; } /** Is the result of the lookup that the name is below a delegation? */ public boolean isDelegation() { - return (type == DELEGATION); + return type == DELEGATION; } /** Is the result of the lookup a CNAME? */ public boolean isCNAME() { - return (type == CNAME); + return type == CNAME; } /** Is the result of the lookup a DNAME? */ public boolean isDNAME() { - return (type == DNAME); + return type == DNAME; } /** Was the query successful? */ public boolean isSuccessful() { - return (type == SUCCESSFUL); + return type == SUCCESSFUL; } /** If the query was successful, return the answers */ @@ -149,12 +149,12 @@ public List answers() { /** If the query encountered a CNAME, return it. */ public CNAMERecord getCNAME() { - return (CNAMERecord) (data.get(0)).first(); + return (CNAMERecord) data.get(0).first(); } /** If the query encountered a DNAME, return it. */ public DNAMERecord getDNAME() { - return (DNAMERecord) (data.get(0)).first(); + return (DNAMERecord) data.get(0).first(); } /** If the query hit a delegation point, return the NS set. */ diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index ab8104db2..ab6af1d86 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -197,7 +197,7 @@ public Duration getTimeout() { private Message parseMessage(byte[] b) throws WireParseException { try { - return (new Message(b)); + return new Message(b); } catch (IOException e) { if (!(e instanceof WireParseException)) { e = new WireParseException("Error parsing message"); diff --git a/src/main/java/org/xbill/DNS/TSIG.java b/src/main/java/org/xbill/DNS/TSIG.java index 1f2dff591..0782aed82 100644 --- a/src/main/java/org/xbill/DNS/TSIG.java +++ b/src/main/java/org/xbill/DNS/TSIG.java @@ -304,7 +304,7 @@ public TSIGRecord generate(Message m, byte[] b, int error, TSIGRecord old) { alg.toWireCanonical(out); long time = timeSigned.getEpochSecond(); int timeHigh = (int) (time >> 32); - long timeLow = (time & 0xFFFFFFFFL); + long timeLow = time & 0xFFFFFFFFL; out.writeU16(timeHigh); out.writeU32(timeLow); out.writeU16((int) fudge.getSeconds()); @@ -328,13 +328,13 @@ public TSIGRecord generate(Message m, byte[] b, int error, TSIGRecord old) { out = new DNSOutput(); time = Instant.now().getEpochSecond(); timeHigh = (int) (time >> 32); - timeLow = (time & 0xFFFFFFFFL); + timeLow = time & 0xFFFFFFFFL; out.writeU16(timeHigh); out.writeU32(timeLow); other = out.toByteArray(); } - return (new TSIGRecord( + return new TSIGRecord( name, DClass.ANY, 0, @@ -344,7 +344,7 @@ public TSIGRecord generate(Message m, byte[] b, int error, TSIGRecord old) { signature, m.getHeader().getID(), error, - other)); + other); } /** @@ -403,7 +403,7 @@ public void applyStream(Message m, TSIGRecord old, boolean first) { out = new DNSOutput(); long time = timeSigned.getEpochSecond(); int timeHigh = (int) (time >> 32); - long timeLow = (time & 0xFFFFFFFFL); + long timeLow = time & 0xFFFFFFFFL; out.writeU16(timeHigh); out.writeU32(timeLow); out.writeU16((int) fudge.getSeconds()); @@ -499,7 +499,7 @@ public int verify(Message m, byte[] b, TSIGRecord old) { tsig.getAlgorithm().toWireCanonical(out); long time = tsig.getTimeSigned().getEpochSecond(); int timeHigh = (int) (time >> 32); - long timeLow = (time & 0xFFFFFFFFL); + long timeLow = time & 0xFFFFFFFFL; out.writeU16(timeHigh); out.writeU32(timeLow); out.writeU16((int) tsig.getFudge().getSeconds()); @@ -543,13 +543,13 @@ public int verify(Message m, byte[] b, TSIGRecord old) { * @see TSIGRecord */ public int recordLength() { - return (name.length() + return name.length() + 10 + alg.length() + 8 // time signed, fudge + 18 // 2 byte MAC length, 16 byte MAC + 4 // original id, error - + 8); // 2 byte error length, 6 byte max error field. + + 8; // 2 byte error length, 6 byte max error field. } public static class StreamVerifier { @@ -618,7 +618,7 @@ public int verify(Message m, byte[] b) { lastsigned = nresponses; lastTSIG = tsig; } else { - boolean required = (nresponses - lastsigned >= 100); + boolean required = nresponses - lastsigned >= 100; if (required) { m.tsigState = Message.TSIG_FAILED; return Rcode.FORMERR; @@ -637,7 +637,7 @@ public int verify(Message m, byte[] b) { DNSOutput out = new DNSOutput(); long time = tsig.getTimeSigned().getEpochSecond(); int timeHigh = (int) (time >> 32); - long timeLow = (time & 0xFFFFFFFFL); + long timeLow = time & 0xFFFFFFFFL; out.writeU16(timeHigh); out.writeU32(timeLow); out.writeU16((int) tsig.getFudge().getSeconds()); diff --git a/src/main/java/org/xbill/DNS/TSIGRecord.java b/src/main/java/org/xbill/DNS/TSIGRecord.java index 257cf55e8..e1a1becd3 100644 --- a/src/main/java/org/xbill/DNS/TSIGRecord.java +++ b/src/main/java/org/xbill/DNS/TSIGRecord.java @@ -177,7 +177,7 @@ String rrToString() { + ((other[2] & 0xFF) << 24) + ((other[3] & 0xFF) << 16) + ((other[4] & 0xFF) << 8) - + ((other[5] & 0xFF)); + + (other[5] & 0xFF); sb.append(""); @@ -235,7 +235,7 @@ void rrToWire(DNSOutput out, Compression c, boolean canonical) { long time = timeSigned.getEpochSecond(); int timeHigh = (int) (time >> 32); - long timeLow = (time & 0xFFFFFFFFL); + long timeLow = time & 0xFFFFFFFFL; out.writeU16(timeHigh); out.writeU32(timeLow); out.writeU16((int) fudge.getSeconds()); diff --git a/src/main/java/org/xbill/DNS/Tokenizer.java b/src/main/java/org/xbill/DNS/Tokenizer.java index 2e2bbbe11..595b0e8f0 100644 --- a/src/main/java/org/xbill/DNS/Tokenizer.java +++ b/src/main/java/org/xbill/DNS/Tokenizer.java @@ -116,12 +116,12 @@ public String toString() { /** Indicates whether this token contains a string. */ public boolean isString() { - return (type == IDENTIFIER || type == QUOTED_STRING); + return type == IDENTIFIER || type == QUOTED_STRING; } /** Indicates whether this token contains an EOL or EOF. */ public boolean isEOL() { - return (type == EOL || type == EOF); + return type == EOL || type == EOF; } } diff --git a/src/main/java/org/xbill/DNS/TypeBitmap.java b/src/main/java/org/xbill/DNS/TypeBitmap.java index c1fdd8a79..817eb54cc 100644 --- a/src/main/java/org/xbill/DNS/TypeBitmap.java +++ b/src/main/java/org/xbill/DNS/TypeBitmap.java @@ -100,14 +100,14 @@ public String toString() { } private static void mapToWire(DNSOutput out, TreeSet map, int mapbase) { - int arraymax = (map.last()) & 0xFF; + int arraymax = map.last() & 0xFF; int arraylength = (arraymax / 8) + 1; int[] array = new int[arraylength]; out.writeU8(mapbase); out.writeU8(arraylength); for (Integer integer : map) { int typecode = integer; - array[(typecode & 0xFF) / 8] |= (1 << (7 - typecode % 8)); + array[(typecode & 0xFF) / 8] |= 1 << (7 - typecode % 8); } for (int j = 0; j < arraylength; j++) { out.writeU8(array[j]); diff --git a/src/main/java/org/xbill/DNS/WKSRecord.java b/src/main/java/org/xbill/DNS/WKSRecord.java index 5406c8b70..ba292cf57 100644 --- a/src/main/java/org/xbill/DNS/WKSRecord.java +++ b/src/main/java/org/xbill/DNS/WKSRecord.java @@ -688,7 +688,7 @@ void rrToWire(DNSOutput out, Compression c, boolean canonical) { int highestPort = services[services.length - 1]; byte[] array = new byte[highestPort / 8 + 1]; for (int port : services) { - array[port / 8] |= (1 << (7 - port % 8)); + array[port / 8] |= 1 << (7 - port % 8); } out.writeByteArray(array); } diff --git a/src/main/java/org/xbill/DNS/Zone.java b/src/main/java/org/xbill/DNS/Zone.java index 9d5fda4ef..58e32edd4 100644 --- a/src/main/java/org/xbill/DNS/Zone.java +++ b/src/main/java/org/xbill/DNS/Zone.java @@ -60,7 +60,7 @@ class ZoneIterator implements Iterator { @Override public boolean hasNext() { - return (current != null || wantLastSOA); + return current != null || wantLastSOA; } @Override @@ -351,8 +351,8 @@ private synchronized SetResponse lookup(Name name, int type) { olabels = origin.labels(); for (tlabels = olabels; tlabels <= labels; tlabels++) { - boolean isOrigin = (tlabels == olabels); - boolean isExact = (tlabels == labels); + boolean isOrigin = tlabels == olabels; + boolean isExact = tlabels == labels; if (isOrigin) { tname = origin; diff --git a/src/main/java/org/xbill/DNS/ZoneTransferIn.java b/src/main/java/org/xbill/DNS/ZoneTransferIn.java index fd90823d8..d2d8d0237 100644 --- a/src/main/java/org/xbill/DNS/ZoneTransferIn.java +++ b/src/main/java/org/xbill/DNS/ZoneTransferIn.java @@ -585,7 +585,7 @@ private BasicHandler getBasicHandler() throws IllegalArgumentException { * transfer, or an IXFR failed and fallback to AXFR occurred. */ public boolean isAXFR() { - return (rtype == Type.AXFR); + return rtype == Type.AXFR; } /** @@ -604,7 +604,7 @@ public List getAXFR() { * if an IXFR was performed and the server provided an incremental zone transfer. */ public boolean isIXFR() { - return (rtype == Type.IXFR); + return rtype == Type.IXFR; } /** @@ -627,6 +627,6 @@ public List getIXFR() { */ public boolean isCurrent() { BasicHandler handler = getBasicHandler(); - return (handler.axfr == null && handler.ixfr == null); + return handler.axfr == null && handler.ixfr == null; } } diff --git a/src/main/java/org/xbill/DNS/utils/base64.java b/src/main/java/org/xbill/DNS/utils/base64.java index fd879a386..5ee8a2470 100644 --- a/src/main/java/org/xbill/DNS/utils/base64.java +++ b/src/main/java/org/xbill/DNS/utils/base64.java @@ -53,14 +53,14 @@ public static String toString(byte[] b, boolean useUrl) { t[0] = (short) (s[0] >> 2); if (s[1] == -1) { - t[1] = (short) (((s[0] & 0x3) << 4)); + t[1] = (short) ((s[0] & 0x3) << 4); } else { t[1] = (short) (((s[0] & 0x3) << 4) + (s[1] >> 4)); } if (s[1] == -1) { t[2] = t[3] = 64; } else if (s[2] == -1) { - t[2] = (short) (((s[1] & 0xF) << 2)); + t[2] = (short) ((s[1] & 0xF) << 2); t[3] = 64; } else { t[2] = (short) (((s[1] & 0xF) << 2) + (s[2] >> 6)); @@ -135,13 +135,13 @@ public static byte[] fromString(String str) { t[0] = (short) ((s[0] << 2) + (s[1] >> 4)); if (s[2] == 64) { - t[1] = t[2] = (short) (-1); + t[1] = t[2] = (short) -1; if ((s[1] & 0xF) != 0) { return null; } } else if (s[3] == 64) { t[1] = (short) (((s[1] << 4) + (s[2] >> 2)) & 0xFF); - t[2] = (short) (-1); + t[2] = (short) -1; if ((s[2] & 0x3) != 0) { return null; } diff --git a/src/main/java/org/xbill/DNS/utils/hexdump.java b/src/main/java/org/xbill/DNS/utils/hexdump.java index 92e8a59f7..ed72091d9 100644 --- a/src/main/java/org/xbill/DNS/utils/hexdump.java +++ b/src/main/java/org/xbill/DNS/utils/hexdump.java @@ -40,9 +40,9 @@ public static String dump(String description, byte[] b, int offset, int length) sb.append('\t'); } } - int value = (int) (b[i + offset]) & 0xFF; - sb.append(hex[(value >> 4)]); - sb.append(hex[(value & 0xF)]); + int value = (int) b[i + offset] & 0xFF; + sb.append(hex[value >> 4]); + sb.append(hex[value & 0xF]); sb.append(' '); } sb.append('\n'); diff --git a/src/test/java/org/xbill/DNS/DNSOutputTest.java b/src/test/java/org/xbill/DNS/DNSOutputTest.java index c946688c6..b760ccf33 100644 --- a/src/test/java/org/xbill/DNS/DNSOutputTest.java +++ b/src/test/java/org/xbill/DNS/DNSOutputTest.java @@ -189,7 +189,7 @@ void writeCountedString_basic() { m_do.writeCountedString(in); assertEquals(in.length + 1, m_do.current()); byte[] curr = m_do.toByteArray(); - byte[] exp = new byte[] {(byte) (in.length), in[0], in[1], in[2], in[3], in[4]}; + byte[] exp = new byte[] {(byte) in.length, in[0], in[1], in[2], in[3], in[4]}; assertArrayEquals(exp, curr); } @@ -199,7 +199,7 @@ void writeCountedString_empty() { m_do.writeCountedString(in); assertEquals(in.length + 1, m_do.current()); byte[] curr = m_do.toByteArray(); - byte[] exp = new byte[] {(byte) (in.length)}; + byte[] exp = new byte[] {(byte) in.length}; assertArrayEquals(exp, curr); } diff --git a/src/test/java/org/xbill/DNS/RecordTest.java b/src/test/java/org/xbill/DNS/RecordTest.java index 11c6bb446..cfd74ad59 100644 --- a/src/test/java/org/xbill/DNS/RecordTest.java +++ b/src/test/java/org/xbill/DNS/RecordTest.java @@ -455,7 +455,7 @@ void test_toString() throws TextParseException { @Test void byteArrayFromString() throws TextParseException { - String in = "the 98 \" \' quick 0xAB brown"; + String in = "the 98 \" ' quick 0xAB brown"; byte[] out = SubRecord.byteArrayFromString(in); assertArrayEquals(in.getBytes(), out); diff --git a/src/test/java/org/xbill/DNS/TokenizerTest.java b/src/test/java/org/xbill/DNS/TokenizerTest.java index 2fc44b694..2848edb32 100644 --- a/src/test/java/org/xbill/DNS/TokenizerTest.java +++ b/src/test/java/org/xbill/DNS/TokenizerTest.java @@ -318,7 +318,7 @@ void getIdentifier() throws IOException { void getLong() throws IOException { m_t = new Tokenizer((Integer.MAX_VALUE + 1L) + ""); long out = m_t.getLong(); - assertEquals((Integer.MAX_VALUE + 1L), out); + assertEquals(Integer.MAX_VALUE + 1L, out); m_t = new Tokenizer("-10"); assertThrows(TextParseException.class, () -> m_t.getLong()); diff --git a/src/test/java/org/xbill/DNS/URIRecordTest.java b/src/test/java/org/xbill/DNS/URIRecordTest.java index 7839b4c29..22f2c6ba2 100644 --- a/src/test/java/org/xbill/DNS/URIRecordTest.java +++ b/src/test/java/org/xbill/DNS/URIRecordTest.java @@ -24,7 +24,7 @@ void ctor_0arg() { @Test void ctor_6arg() throws TextParseException { Name n = Name.fromString("my.name."); - String target = ("http://foo"); + String target = "http://foo"; URIRecord r = new URIRecord(n, DClass.IN, 0xABCDEL, 42, 69, target); assertEquals(n, r.getName()); @@ -50,7 +50,7 @@ void rdataFromString() throws IOException { @Test void rdataToWire() throws TextParseException { Name n = Name.fromString("my.name."); - String target = ("http://foo"); + String target = "http://foo"; byte[] exp = new byte[] { (byte) 0xbe, From 984bb4f9321670a92a2e98278ad7a659eccdac06 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 21 Mar 2020 18:44:07 +0100 Subject: [PATCH 081/431] Remove redundant method --- src/main/java/org/xbill/DNS/Name.java | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Name.java b/src/main/java/org/xbill/DNS/Name.java index 150977376..bc211619b 100644 --- a/src/main/java/org/xbill/DNS/Name.java +++ b/src/main/java/org/xbill/DNS/Name.java @@ -92,10 +92,10 @@ private void setoffset(int n, int offset) { } private int offset(int n) { - if (n == 0 && getlabels() == 0) { + if (n == 0 && labels() == 0) { return 0; } - if (n < 0 || n >= getlabels()) { + if (n < 0 || n >= labels()) { throw new IllegalArgumentException("label out of range"); } if (n < MAXOFFSETS) { @@ -115,10 +115,6 @@ private void setlabels(int labels) { offsets |= labels; } - private int getlabels() { - return (int) (offsets & 0xFF); - } - private static void copy(Name src, Name dst) { if (src.offset(0) == 0) { dst.name = src.name; @@ -152,7 +148,7 @@ private void append(byte[] array, int start, int n) throws NameTooLongException if (newlength > MAXNAME) { throw new NameTooLongException(); } - int labels = getlabels(); + int labels = labels(); int newlabels = labels + n; if (newlabels > MAXLABELS) { throw new IllegalStateException("too many labels"); @@ -279,7 +275,7 @@ public Name(String s, Name origin) throws TextParseException { appendFromString(s, label, 0, 1); } if (origin != null && !absolute) { - appendFromString(s, origin.name, origin.offset(0), origin.getlabels()); + appendFromString(s, origin.name, origin.offset(0), origin.labels()); } } @@ -356,7 +352,7 @@ public Name(DNSInput in) throws WireParseException { len = in.readU8(); switch (len & LABEL_MASK) { case LABEL_NORMAL: - if (getlabels() >= MAXLABELS) { + if (labels() >= MAXLABELS) { throw new WireParseException("too many labels"); } if (len == 0) { @@ -433,7 +429,7 @@ public static Name concatenate(Name prefix, Name suffix) throws NameTooLongExcep } Name newname = new Name(); copy(prefix, newname); - newname.append(suffix.name, suffix.offset(0), suffix.getlabels()); + newname.append(suffix.name, suffix.offset(0), suffix.labels()); return newname; } @@ -470,7 +466,7 @@ public Name wild(int n) { try { Name newname = new Name(); copy(wild, newname); - newname.append(name, offset(n), getlabels() - n); + newname.append(name, offset(n), labels() - n); return newname; } catch (NameTooLongException e) { throw new IllegalStateException("Name.wild: concatenate failed"); @@ -494,7 +490,7 @@ public Name canonicalize() { } Name newname = new Name(); - newname.appendSafe(name, offset(0), getlabels()); + newname.appendSafe(name, offset(0), labels()); for (int i = 0; i < newname.name.length; i++) { newname.name[i] = lowercase[newname.name[i] & 0xFF]; } @@ -559,7 +555,7 @@ public boolean isAbsolute() { /** The length of the name. */ public short length() { - if (getlabels() == 0) { + if (labels() == 0) { return 0; } return (short) (name.length - offset(0)); @@ -567,7 +563,7 @@ public short length() { /** The number of labels in the name. */ public int labels() { - return getlabels(); + return (int) (offsets & 0xFF); } /** Is the current Name a subdomain of the specified name? */ From 4245c05f5d3a36426954d69b97601237aad68a96 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 21 Mar 2020 19:37:28 +0100 Subject: [PATCH 082/431] Move number of labels to dedicated field --- src/main/java/org/xbill/DNS/Name.java | 86 +++++++++++---------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Name.java b/src/main/java/org/xbill/DNS/Name.java index bc211619b..ec74587e4 100644 --- a/src/main/java/org/xbill/DNS/Name.java +++ b/src/main/java/org/xbill/DNS/Name.java @@ -15,7 +15,7 @@ @Slf4j public class Name implements Comparable, Serializable { - private static final long serialVersionUID = -7257019940971525644L; + private static final long serialVersionUID = 5149282554141851880L; private static final int LABEL_NORMAL = 0; private static final int LABEL_COMPRESSION = 0xC0; @@ -24,15 +24,15 @@ public class Name implements Comparable, Serializable { /* The name data */ private byte[] name; - /* - * Effectively an 8 byte array, where the low order byte stores the number - * of labels and the 7 higher order bytes store per-label offsets. - */ + /* Effectively an 8 byte array, where the bytes store per-label offsets. */ private long offsets; /* Precomputed hashcode. */ private int hashcode; + /* The number of labels in this name. */ + private int labels; + private static final byte[] emptyLabel = new byte[] {(byte) 0}; private static final byte[] wildLabel = new byte[] {(byte) 1, (byte) '*'}; @@ -52,7 +52,7 @@ public class Name implements Comparable, Serializable { private static final int MAXLABELS = 128; /** The maximum number of cached offsets */ - private static final int MAXOFFSETS = 7; + private static final int MAXOFFSETS = 8; /* Used for printing non-printable characters */ private static final DecimalFormat byteFormat = new DecimalFormat(); @@ -86,20 +86,20 @@ private void setoffset(int n, int offset) { if (n >= MAXOFFSETS) { return; } - int shift = 8 * (7 - n); + int shift = 8 * n; offsets &= ~(0xFFL << shift); offsets |= (long) offset << shift; } private int offset(int n) { - if (n == 0 && labels() == 0) { + if (n == 0 && labels == 0) { return 0; } - if (n < 0 || n >= labels()) { + if (n < 0 || n >= labels) { throw new IllegalArgumentException("label out of range"); } if (n < MAXOFFSETS) { - int shift = 8 * (7 - n); + int shift = 8 * n; return (int) (offsets >>> shift) & 0xFF; } else { int pos = offset(MAXOFFSETS - 1); @@ -110,25 +110,20 @@ private int offset(int n) { } } - private void setlabels(int labels) { - offsets &= ~0xFF; - offsets |= labels; - } - private static void copy(Name src, Name dst) { if (src.offset(0) == 0) { dst.name = src.name; dst.offsets = src.offsets; + dst.labels = src.labels; } else { int offset0 = src.offset(0); int namelen = src.name.length - offset0; - int labels = src.labels(); dst.name = new byte[namelen]; System.arraycopy(src.name, offset0, dst.name, 0, namelen); - for (int i = 0; i < labels && i < MAXOFFSETS; i++) { + for (int i = 0; i < src.labels && i < MAXOFFSETS; i++) { dst.setoffset(i, src.offset(i) - offset0); } - dst.setlabels(labels); + dst.labels = src.labels; } } @@ -148,7 +143,6 @@ private void append(byte[] array, int start, int n) throws NameTooLongException if (newlength > MAXNAME) { throw new NameTooLongException(); } - int labels = labels(); int newlabels = labels + n; if (newlabels > MAXLABELS) { throw new IllegalStateException("too many labels"); @@ -163,7 +157,7 @@ private void append(byte[] array, int start, int n) throws NameTooLongException setoffset(labels + i, pos); pos += newname[pos] + 1; } - setlabels(newlabels); + labels = newlabels; } private static TextParseException parseException(String str, String message) { @@ -275,7 +269,7 @@ public Name(String s, Name origin) throws TextParseException { appendFromString(s, label, 0, 1); } if (origin != null && !absolute) { - appendFromString(s, origin.name, origin.offset(0), origin.labels()); + appendFromString(s, origin.name, origin.offset(0), origin.labels); } } @@ -352,7 +346,7 @@ public Name(DNSInput in) throws WireParseException { len = in.readU8(); switch (len & LABEL_MASK) { case LABEL_NORMAL: - if (labels() >= MAXLABELS) { + if (labels >= MAXLABELS) { throw new WireParseException("too many labels"); } if (len == 0) { @@ -404,12 +398,12 @@ public Name(byte[] b) throws IOException { * @param n The number of labels to remove from the beginning in the copy */ public Name(Name src, int n) { - int slabels = src.labels(); + int slabels = src.labels; if (n > slabels) { throw new IllegalArgumentException("attempted to remove too many labels"); } name = src.name; - setlabels(slabels - n); + labels = slabels - n; for (int i = 0; i < MAXOFFSETS && i < slabels - n; i++) { setoffset(i, src.offset(i + n)); } @@ -429,7 +423,7 @@ public static Name concatenate(Name prefix, Name suffix) throws NameTooLongExcep } Name newname = new Name(); copy(prefix, newname); - newname.append(suffix.name, suffix.offset(0), suffix.labels()); + newname.append(suffix.name, suffix.offset(0), suffix.labels); return newname; } @@ -447,8 +441,7 @@ public Name relativize(Name origin) { Name newname = new Name(); copy(this, newname); int length = length() - origin.length(); - int labels = newname.labels() - origin.labels(); - newname.setlabels(labels); + newname.labels = newname.labels - origin.labels; newname.name = new byte[length]; System.arraycopy(name, offset(0), newname.name, 0, length); return newname; @@ -466,7 +459,7 @@ public Name wild(int n) { try { Name newname = new Name(); copy(wild, newname); - newname.append(name, offset(n), labels() - n); + newname.append(name, offset(n), labels - n); return newname; } catch (NameTooLongException e) { throw new IllegalStateException("Name.wild: concatenate failed"); @@ -490,7 +483,7 @@ public Name canonicalize() { } Name newname = new Name(); - newname.appendSafe(name, offset(0), labels()); + newname.appendSafe(name, offset(0), labels); for (int i = 0; i < newname.name.length; i++) { newname.name[i] = lowercase[newname.name[i] & 0xFF]; } @@ -512,11 +505,11 @@ public Name fromDNAME(DNAMERecord dname) throws NameTooLongException { return null; } - int plabels = labels() - dnameowner.labels(); + int plabels = labels - dnameowner.labels; int plength = length() - dnameowner.length(); int pstart = offset(0); - int dlabels = dnametarget.labels(); + int dlabels = dnametarget.labels; int dlength = dnametarget.length(); if (plength + dlength > MAXNAME) { @@ -524,7 +517,7 @@ public Name fromDNAME(DNAMERecord dname) throws NameTooLongException { } Name newname = new Name(); - newname.setlabels(plabels + dlabels); + newname.labels = plabels + dlabels; newname.name = new byte[plength + dlength]; System.arraycopy(name, pstart, newname.name, 0, plength); System.arraycopy(dnametarget.name, 0, newname.name, plength, dlength); @@ -538,7 +531,7 @@ public Name fromDNAME(DNAMERecord dname) throws NameTooLongException { /** Is this name a wildcard? */ public boolean isWild() { - if (labels() == 0) { + if (labels == 0) { return false; } return name[0] == (byte) 1 && name[1] == (byte) '*'; @@ -546,16 +539,15 @@ public boolean isWild() { /** Is this name absolute? */ public boolean isAbsolute() { - int nlabels = labels(); - if (nlabels == 0) { + if (labels == 0) { return false; } - return name[offset(nlabels - 1)] == 0; + return name[offset(labels - 1)] == 0; } /** The length of the name. */ public short length() { - if (labels() == 0) { + if (labels == 0) { return 0; } return (short) (name.length - offset(0)); @@ -563,13 +555,12 @@ public short length() { /** The number of labels in the name. */ public int labels() { - return (int) (offsets & 0xFF); + return labels; } /** Is the current Name a subdomain of the specified name? */ public boolean subdomain(Name domain) { - int labels = labels(); - int dlabels = domain.labels(); + int dlabels = domain.labels; if (dlabels > labels) { return false; } @@ -605,7 +596,6 @@ private String byteString(byte[] array, int pos) { * @return The representation of this name as a (printable) String. */ public String toString(boolean omitFinalDot) { - int labels = labels(); if (labels == 0) { return "@"; } else if (labels == 1 && name[offset(0)] == 0) { @@ -678,7 +668,6 @@ public void toWire(DNSOutput out, Compression c) { throw new IllegalArgumentException("toWire() called on non-absolute name"); } - int labels = labels(); for (int i = 0; i < labels - 1; i++) { Name tname; if (i == 0) { @@ -732,7 +721,6 @@ public void toWireCanonical(DNSOutput out) { * @return The canonical form of the name. */ public byte[] toWireCanonical() { - int labels = labels(); if (labels == 0) { return new byte[0]; } @@ -767,7 +755,6 @@ public void toWire(DNSOutput out, Compression c, boolean canonical) { } private boolean equals(byte[] b, int bpos) { - int labels = labels(); for (int i = 0, pos = offset(0); i < labels; i++) { if (name[pos] != b[bpos]) { return false; @@ -795,14 +782,14 @@ public boolean equals(Object arg) { if (!(arg instanceof Name)) { return false; } - Name d = (Name) arg; - if (d.hashCode() != hashCode()) { + Name other = (Name) arg; + if (other.hashCode() != hashCode()) { return false; } - if (d.labels() != labels()) { + if (other.labels != labels) { return false; } - return equals(d.name, d.offset(0)); + return equals(other.name, other.offset(0)); } /** Computes a hashcode based on the value */ @@ -834,8 +821,7 @@ public int compareTo(Name arg) { return 0; } - int labels = labels(); - int alabels = arg.labels(); + int alabels = arg.labels; int compares = Math.min(labels, alabels); for (int i = 1; i <= compares; i++) { From 146a359ca61aff947afab1ed9e56057320d770c5 Mon Sep 17 00:00:00 2001 From: demonti Date: Thu, 26 Mar 2020 13:23:43 +0100 Subject: [PATCH 083/431] "Record" class access fixes (#98) * set methods that need to be overridden by subclasses to "protected", so that the subclasses may reside in different packages * applied code formatter --- src/main/java/org/xbill/DNS/A6Record.java | 8 ++++---- src/main/java/org/xbill/DNS/AAAARecord.java | 8 ++++---- src/main/java/org/xbill/DNS/APLRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/ARecord.java | 8 ++++---- src/main/java/org/xbill/DNS/CAARecord.java | 8 ++++---- src/main/java/org/xbill/DNS/CERTRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/DHCIDRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/DLVRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/DNSKEYRecord.java | 2 +- src/main/java/org/xbill/DNS/DSRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/EmptyRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/GPOSRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/HINFORecord.java | 8 ++++---- src/main/java/org/xbill/DNS/HIPRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/IPSECKEYRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/ISDNRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/KEYBase.java | 6 +++--- src/main/java/org/xbill/DNS/KEYRecord.java | 2 +- src/main/java/org/xbill/DNS/LOCRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/MINFORecord.java | 8 ++++---- src/main/java/org/xbill/DNS/MXRecord.java | 2 +- src/main/java/org/xbill/DNS/NAPTRRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/NSAPRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/NSEC3Record.java | 8 ++++---- src/main/java/org/xbill/DNS/NSECRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/NULLRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/NXTRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/OPTRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/PXRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/RPRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/Record.java | 10 +++++----- src/main/java/org/xbill/DNS/SIGBase.java | 8 ++++---- src/main/java/org/xbill/DNS/SOARecord.java | 8 ++++---- src/main/java/org/xbill/DNS/SRVRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/SSHFPRecord.java | 8 ++++---- .../java/org/xbill/DNS/SingleCompressedNameBase.java | 2 +- src/main/java/org/xbill/DNS/SingleNameBase.java | 8 ++++---- src/main/java/org/xbill/DNS/TKEYRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/TLSARecord.java | 8 ++++---- src/main/java/org/xbill/DNS/TSIGRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/TXTBase.java | 8 ++++---- src/main/java/org/xbill/DNS/U16NameBase.java | 8 ++++---- src/main/java/org/xbill/DNS/UNKRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/URIRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/WKSRecord.java | 8 ++++---- src/main/java/org/xbill/DNS/X25Record.java | 8 ++++---- src/test/java/org/xbill/DNS/KEYBaseTest.java | 2 +- 49 files changed, 181 insertions(+), 181 deletions(-) diff --git a/src/main/java/org/xbill/DNS/A6Record.java b/src/main/java/org/xbill/DNS/A6Record.java index edba41f5d..c98d6610d 100644 --- a/src/main/java/org/xbill/DNS/A6Record.java +++ b/src/main/java/org/xbill/DNS/A6Record.java @@ -40,7 +40,7 @@ public A6Record( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { prefixBits = in.readU8(); int suffixbits = 128 - prefixBits; int suffixbytes = (suffixbits + 7) / 8; @@ -55,7 +55,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { prefixBits = st.getUInt8(); if (prefixBits > 128) { throw st.exception("prefix bits must be [0..128]"); @@ -74,7 +74,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(prefixBits); if (suffix != null) { @@ -104,7 +104,7 @@ public Name getPrefix() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU8(prefixBits); if (suffix != null) { int suffixbits = 128 - prefixBits; diff --git a/src/main/java/org/xbill/DNS/AAAARecord.java b/src/main/java/org/xbill/DNS/AAAARecord.java index 5bd8f13a8..1adb464a1 100644 --- a/src/main/java/org/xbill/DNS/AAAARecord.java +++ b/src/main/java/org/xbill/DNS/AAAARecord.java @@ -32,18 +32,18 @@ public AAAARecord(Name name, int dclass, long ttl, InetAddress address) { } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { address = in.readByteArray(16); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { address = st.getAddressBytes(Address.IPv6); } /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { InetAddress addr; try { addr = InetAddress.getByAddress(null, address); @@ -77,7 +77,7 @@ public InetAddress getAddress() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeByteArray(address); } } diff --git a/src/main/java/org/xbill/DNS/APLRecord.java b/src/main/java/org/xbill/DNS/APLRecord.java index 49d07985c..61715ab20 100644 --- a/src/main/java/org/xbill/DNS/APLRecord.java +++ b/src/main/java/org/xbill/DNS/APLRecord.java @@ -128,7 +128,7 @@ private static byte[] parseAddress(byte[] in, int length) throws WireParseExcept } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { elements = new ArrayList<>(1); while (in.remaining() != 0) { int family = in.readU16(); @@ -155,7 +155,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { elements = new ArrayList<>(1); while (true) { Tokenizer.Token t = st.get(); @@ -217,7 +217,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { } @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); for (Iterator it = elements.iterator(); it.hasNext(); ) { Element element = it.next(); @@ -244,7 +244,7 @@ private static int addressLength(byte[] addr) { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { for (Element element : elements) { int length; byte[] data; diff --git a/src/main/java/org/xbill/DNS/ARecord.java b/src/main/java/org/xbill/DNS/ARecord.java index d51dffb9e..9dd8c40a3 100644 --- a/src/main/java/org/xbill/DNS/ARecord.java +++ b/src/main/java/org/xbill/DNS/ARecord.java @@ -48,18 +48,18 @@ public ARecord(Name name, int dclass, long ttl, InetAddress address) { } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { addr = fromArray(in.readByteArray(4)); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { addr = fromArray(st.getAddressBytes(Address.IPv4)); } /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { return Address.toDottedQuad(toArray(addr)); } @@ -77,7 +77,7 @@ public InetAddress getAddress() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU32((long) addr & 0xFFFFFFFFL); } } diff --git a/src/main/java/org/xbill/DNS/CAARecord.java b/src/main/java/org/xbill/DNS/CAARecord.java index 83d3a63ca..4d820b5ce 100644 --- a/src/main/java/org/xbill/DNS/CAARecord.java +++ b/src/main/java/org/xbill/DNS/CAARecord.java @@ -43,14 +43,14 @@ public CAARecord(Name name, int dclass, long ttl, int flags, String tag, String } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { flags = in.readU8(); tag = in.readCountedString(); value = in.readByteArray(); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { flags = st.getUInt8(); try { tag = byteArrayFromString(st.getString()); @@ -61,7 +61,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { } @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(flags); sb.append(" "); @@ -87,7 +87,7 @@ public String getValue() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU8(flags); out.writeCountedString(tag); out.writeByteArray(value); diff --git a/src/main/java/org/xbill/DNS/CERTRecord.java b/src/main/java/org/xbill/DNS/CERTRecord.java index e84a017d8..07f1fe49c 100644 --- a/src/main/java/org/xbill/DNS/CERTRecord.java +++ b/src/main/java/org/xbill/DNS/CERTRecord.java @@ -125,7 +125,7 @@ public CERTRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { certType = in.readU16(); keyTag = in.readU16(); alg = in.readU8(); @@ -133,7 +133,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { String certTypeString = st.getString(); certType = CertificateType.value(certTypeString); if (certType < 0) { @@ -150,7 +150,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(certType); sb.append(" "); @@ -190,7 +190,7 @@ public byte[] getCert() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(certType); out.writeU16(keyTag); out.writeU8(alg); diff --git a/src/main/java/org/xbill/DNS/DHCIDRecord.java b/src/main/java/org/xbill/DNS/DHCIDRecord.java index f108bf008..ff7e0a68d 100644 --- a/src/main/java/org/xbill/DNS/DHCIDRecord.java +++ b/src/main/java/org/xbill/DNS/DHCIDRecord.java @@ -28,22 +28,22 @@ public DHCIDRecord(Name name, int dclass, long ttl, byte[] data) { } @Override - void rrFromWire(DNSInput in) { + protected void rrFromWire(DNSInput in) { data = in.readByteArray(); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { data = st.getBase64(); } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeByteArray(data); } @Override - String rrToString() { + protected String rrToString() { return base64.toString(data); } diff --git a/src/main/java/org/xbill/DNS/DLVRecord.java b/src/main/java/org/xbill/DNS/DLVRecord.java index d0425cd67..8f1708f7e 100644 --- a/src/main/java/org/xbill/DNS/DLVRecord.java +++ b/src/main/java/org/xbill/DNS/DLVRecord.java @@ -46,7 +46,7 @@ public DLVRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { footprint = in.readU16(); alg = in.readU8(); digestid = in.readU8(); @@ -54,7 +54,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { footprint = st.getUInt16(); alg = st.getUInt8(); digestid = st.getUInt8(); @@ -63,7 +63,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(footprint); sb.append(" "); @@ -99,7 +99,7 @@ public int getFootprint() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(footprint); out.writeU8(alg); out.writeU8(digestid); diff --git a/src/main/java/org/xbill/DNS/DNSKEYRecord.java b/src/main/java/org/xbill/DNS/DNSKEYRecord.java index 1bd2ba554..907e55c31 100644 --- a/src/main/java/org/xbill/DNS/DNSKEYRecord.java +++ b/src/main/java/org/xbill/DNS/DNSKEYRecord.java @@ -79,7 +79,7 @@ public DNSKEYRecord(Name name, int dclass, long ttl, int flags, int proto, int a } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { flags = st.getUInt16(); proto = st.getUInt8(); String algString = st.getString(); diff --git a/src/main/java/org/xbill/DNS/DSRecord.java b/src/main/java/org/xbill/DNS/DSRecord.java index 20a0563ed..7841931a9 100644 --- a/src/main/java/org/xbill/DNS/DSRecord.java +++ b/src/main/java/org/xbill/DNS/DSRecord.java @@ -100,7 +100,7 @@ public DSRecord(Name name, int dclass, long ttl, int digestid, DNSKEYRecord key) } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { footprint = in.readU16(); alg = in.readU8(); digestid = in.readU8(); @@ -108,7 +108,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { footprint = st.getUInt16(); alg = st.getUInt8(); digestid = st.getUInt8(); @@ -117,7 +117,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(footprint); sb.append(" "); @@ -153,7 +153,7 @@ public int getFootprint() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(footprint); out.writeU8(alg); out.writeU8(digestid); diff --git a/src/main/java/org/xbill/DNS/EmptyRecord.java b/src/main/java/org/xbill/DNS/EmptyRecord.java index 3e2e25320..50e24a368 100644 --- a/src/main/java/org/xbill/DNS/EmptyRecord.java +++ b/src/main/java/org/xbill/DNS/EmptyRecord.java @@ -12,16 +12,16 @@ class EmptyRecord extends Record { EmptyRecord() {} @Override - void rrFromWire(DNSInput in) {} + protected void rrFromWire(DNSInput in) {} @Override - void rdataFromString(Tokenizer st, Name origin) {} + protected void rdataFromString(Tokenizer st, Name origin) {} @Override - String rrToString() { + protected String rrToString() { return ""; } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) {} + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) {} } diff --git a/src/main/java/org/xbill/DNS/GPOSRecord.java b/src/main/java/org/xbill/DNS/GPOSRecord.java index de027b2b8..c58ef2160 100644 --- a/src/main/java/org/xbill/DNS/GPOSRecord.java +++ b/src/main/java/org/xbill/DNS/GPOSRecord.java @@ -63,7 +63,7 @@ public GPOSRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { longitude = in.readCountedString(); latitude = in.readCountedString(); altitude = in.readCountedString(); @@ -75,7 +75,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { try { longitude = byteArrayFromString(st.getString()); latitude = byteArrayFromString(st.getString()); @@ -92,7 +92,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Convert to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(byteArrayToString(longitude, true)); sb.append(" "); @@ -145,7 +145,7 @@ public double getAltitude() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeCountedString(longitude); out.writeCountedString(latitude); out.writeCountedString(altitude); diff --git a/src/main/java/org/xbill/DNS/HINFORecord.java b/src/main/java/org/xbill/DNS/HINFORecord.java index 216294966..6ba63147e 100644 --- a/src/main/java/org/xbill/DNS/HINFORecord.java +++ b/src/main/java/org/xbill/DNS/HINFORecord.java @@ -34,13 +34,13 @@ public HINFORecord(Name name, int dclass, long ttl, String cpu, String os) { } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { cpu = in.readCountedString(); os = in.readCountedString(); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { try { cpu = byteArrayFromString(st.getString()); os = byteArrayFromString(st.getString()); @@ -60,14 +60,14 @@ public String getOS() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeCountedString(cpu); out.writeCountedString(os); } /** Converts to a string */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(byteArrayToString(cpu, true)); sb.append(" "); diff --git a/src/main/java/org/xbill/DNS/HIPRecord.java b/src/main/java/org/xbill/DNS/HIPRecord.java index f14174677..a5fd39a46 100644 --- a/src/main/java/org/xbill/DNS/HIPRecord.java +++ b/src/main/java/org/xbill/DNS/HIPRecord.java @@ -98,7 +98,7 @@ private static int mapAlgTypeToDnssec(int alg) throws UnsupportedAlgorithmExcept } @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); if (Options.check("multiline")) { sb.append("( "); @@ -124,7 +124,7 @@ String rrToString() { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { pkAlgorithm = st.getUInt8(); hit = st.getHexString(); publicKey = base64.fromString(st.getString()); @@ -135,7 +135,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU8(hit.length); out.writeU8(pkAlgorithm); out.writeU16(publicKey.length); @@ -145,7 +145,7 @@ void rrToWire(DNSOutput out, Compression c, boolean canonical) { } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { int hitLength = in.readU8(); pkAlgorithm = in.readU8(); int pkLength = in.readU16(); diff --git a/src/main/java/org/xbill/DNS/IPSECKEYRecord.java b/src/main/java/org/xbill/DNS/IPSECKEYRecord.java index 6543087de..3515e9ccd 100644 --- a/src/main/java/org/xbill/DNS/IPSECKEYRecord.java +++ b/src/main/java/org/xbill/DNS/IPSECKEYRecord.java @@ -114,7 +114,7 @@ public IPSECKEYRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { precedence = in.readU8(); gatewayType = in.readU8(); algorithmType = in.readU8(); @@ -140,7 +140,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { precedence = st.getUInt8(); gatewayType = st.getUInt8(); algorithmType = st.getUInt8(); @@ -168,7 +168,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { } @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(precedence); sb.append(" "); @@ -222,7 +222,7 @@ public byte[] getKey() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU8(precedence); out.writeU8(gatewayType); out.writeU8(algorithmType); diff --git a/src/main/java/org/xbill/DNS/ISDNRecord.java b/src/main/java/org/xbill/DNS/ISDNRecord.java index 9ee3e4cf1..bb2e6fe64 100644 --- a/src/main/java/org/xbill/DNS/ISDNRecord.java +++ b/src/main/java/org/xbill/DNS/ISDNRecord.java @@ -36,7 +36,7 @@ public ISDNRecord(Name name, int dclass, long ttl, String address, String subAdd } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { address = in.readCountedString(); if (in.remaining() > 0) { subAddress = in.readCountedString(); @@ -44,7 +44,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { try { address = byteArrayFromString(st.getString()); Tokenizer.Token t = st.get(); @@ -72,7 +72,7 @@ public String getSubAddress() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeCountedString(address); if (subAddress != null) { out.writeCountedString(subAddress); @@ -80,7 +80,7 @@ void rrToWire(DNSOutput out, Compression c, boolean canonical) { } @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(byteArrayToString(address, true)); if (subAddress != null) { diff --git a/src/main/java/org/xbill/DNS/KEYBase.java b/src/main/java/org/xbill/DNS/KEYBase.java index 0cbdb4cbb..470238e95 100644 --- a/src/main/java/org/xbill/DNS/KEYBase.java +++ b/src/main/java/org/xbill/DNS/KEYBase.java @@ -29,7 +29,7 @@ public KEYBase( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { flags = in.readU16(); proto = in.readU8(); alg = in.readU8(); @@ -40,7 +40,7 @@ void rrFromWire(DNSInput in) throws IOException { /** Converts the DNSKEY/KEY Record to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(flags); sb.append(" "); @@ -129,7 +129,7 @@ public PublicKey getPublicKey() throws DNSSEC.DNSSECException { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(flags); out.writeU8(proto); out.writeU8(alg); diff --git a/src/main/java/org/xbill/DNS/KEYRecord.java b/src/main/java/org/xbill/DNS/KEYRecord.java index f57bfd6d5..720c7f6f3 100644 --- a/src/main/java/org/xbill/DNS/KEYRecord.java +++ b/src/main/java/org/xbill/DNS/KEYRecord.java @@ -311,7 +311,7 @@ public KEYRecord(Name name, int dclass, long ttl, int flags, int proto, int alg, } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { String flagString = st.getIdentifier(); flags = Flags.value(flagString); if (flags < 0) { diff --git a/src/main/java/org/xbill/DNS/LOCRecord.java b/src/main/java/org/xbill/DNS/LOCRecord.java index 277aa0675..68879e204 100644 --- a/src/main/java/org/xbill/DNS/LOCRecord.java +++ b/src/main/java/org/xbill/DNS/LOCRecord.java @@ -58,7 +58,7 @@ public LOCRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { int version; version = in.readU8(); @@ -163,7 +163,7 @@ private long parseDouble( } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { latitude = parsePosition(st, "latitude"); longitude = parsePosition(st, "longitude"); altitude = parseDouble(st, "altitude", true, -10000000, 4284967295L, 0) + 10000000; @@ -211,7 +211,7 @@ private String positionToString(long value, char pos, char neg) { /** Convert to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuffer sb = new StringBuffer(); /* Latitude */ @@ -272,7 +272,7 @@ public double getVPrecision() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU8(0); /* version */ out.writeU8(toLOCformat(size)); out.writeU8(toLOCformat(hPrecision)); diff --git a/src/main/java/org/xbill/DNS/MINFORecord.java b/src/main/java/org/xbill/DNS/MINFORecord.java index ef13c77ae..1af08181f 100644 --- a/src/main/java/org/xbill/DNS/MINFORecord.java +++ b/src/main/java/org/xbill/DNS/MINFORecord.java @@ -32,20 +32,20 @@ public MINFORecord(Name name, int dclass, long ttl, Name responsibleAddress, Nam } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { responsibleAddress = new Name(in); errorAddress = new Name(in); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { responsibleAddress = st.getName(origin); errorAddress = st.getName(origin); } /** Converts the MINFO Record to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(responsibleAddress); sb.append(" "); @@ -64,7 +64,7 @@ public Name getErrorAddress() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { responsibleAddress.toWire(out, null, canonical); errorAddress.toWire(out, null, canonical); } diff --git a/src/main/java/org/xbill/DNS/MXRecord.java b/src/main/java/org/xbill/DNS/MXRecord.java index 8cbb04ef6..5929fa2bb 100644 --- a/src/main/java/org/xbill/DNS/MXRecord.java +++ b/src/main/java/org/xbill/DNS/MXRecord.java @@ -35,7 +35,7 @@ public int getPriority() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(u16Field); nameField.toWire(out, c, canonical); } diff --git a/src/main/java/org/xbill/DNS/NAPTRRecord.java b/src/main/java/org/xbill/DNS/NAPTRRecord.java index 0983da7a9..fdb46dc1a 100644 --- a/src/main/java/org/xbill/DNS/NAPTRRecord.java +++ b/src/main/java/org/xbill/DNS/NAPTRRecord.java @@ -55,7 +55,7 @@ public NAPTRRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { order = in.readU16(); preference = in.readU16(); flags = in.readCountedString(); @@ -65,7 +65,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { order = st.getUInt16(); preference = st.getUInt16(); try { @@ -80,7 +80,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(order); sb.append(" "); @@ -127,7 +127,7 @@ public Name getReplacement() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(order); out.writeU16(preference); out.writeCountedString(flags); diff --git a/src/main/java/org/xbill/DNS/NSAPRecord.java b/src/main/java/org/xbill/DNS/NSAPRecord.java index 152aaab21..6b97bdfde 100644 --- a/src/main/java/org/xbill/DNS/NSAPRecord.java +++ b/src/main/java/org/xbill/DNS/NSAPRecord.java @@ -63,12 +63,12 @@ public NSAPRecord(Name name, int dclass, long ttl, String address) { } @Override - void rrFromWire(DNSInput in) { + protected void rrFromWire(DNSInput in) { address = in.readByteArray(); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { String addr = st.getString(); this.address = checkAndConvertAddress(addr); if (this.address == null) { @@ -82,12 +82,12 @@ public String getAddress() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeByteArray(address); } @Override - String rrToString() { + protected String rrToString() { return "0x" + base16.toString(address); } } diff --git a/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java b/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java index dc6b4b142..dd98fa9c4 100644 --- a/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java +++ b/src/main/java/org/xbill/DNS/NSEC3PARAMRecord.java @@ -55,7 +55,7 @@ public NSEC3PARAMRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { hashAlg = in.readU8(); flags = in.readU8(); iterations = in.readU16(); @@ -69,7 +69,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU8(hashAlg); out.writeU8(flags); out.writeU16(iterations); @@ -83,7 +83,7 @@ void rrToWire(DNSOutput out, Compression c, boolean canonical) { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { hashAlg = st.getUInt8(); flags = st.getUInt8(); iterations = st.getUInt16(); @@ -102,7 +102,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(hashAlg); sb.append(' '); diff --git a/src/main/java/org/xbill/DNS/NSEC3Record.java b/src/main/java/org/xbill/DNS/NSEC3Record.java index 38007c309..c3a1c094b 100644 --- a/src/main/java/org/xbill/DNS/NSEC3Record.java +++ b/src/main/java/org/xbill/DNS/NSEC3Record.java @@ -97,7 +97,7 @@ public NSEC3Record( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { hashAlg = in.readU8(); flags = in.readU8(); iterations = in.readU16(); @@ -115,7 +115,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU8(hashAlg); out.writeU8(flags); out.writeU16(iterations); @@ -133,7 +133,7 @@ void rrToWire(DNSOutput out, Compression c, boolean canonical) { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { hashAlg = st.getUInt8(); flags = st.getUInt8(); iterations = st.getUInt16(); @@ -155,7 +155,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(hashAlg); sb.append(' '); diff --git a/src/main/java/org/xbill/DNS/NSECRecord.java b/src/main/java/org/xbill/DNS/NSECRecord.java index c935e0b8c..57ee85508 100644 --- a/src/main/java/org/xbill/DNS/NSECRecord.java +++ b/src/main/java/org/xbill/DNS/NSECRecord.java @@ -38,27 +38,27 @@ public NSECRecord(Name name, int dclass, long ttl, Name next, int[] types) { } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { next = new Name(in); types = new TypeBitmap(in); } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { // Note: The next name is not lowercased. next.toWire(out, null, false); types.toWire(out); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { next = st.getName(origin); types = new TypeBitmap(st); } /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(next); if (!types.empty()) { diff --git a/src/main/java/org/xbill/DNS/NULLRecord.java b/src/main/java/org/xbill/DNS/NULLRecord.java index af9371112..05c684dfe 100644 --- a/src/main/java/org/xbill/DNS/NULLRecord.java +++ b/src/main/java/org/xbill/DNS/NULLRecord.java @@ -31,17 +31,17 @@ public NULLRecord(Name name, int dclass, long ttl, byte[] data) { } @Override - void rrFromWire(DNSInput in) { + protected void rrFromWire(DNSInput in) { data = in.readByteArray(); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { throw st.exception("no defined text format for NULL records"); } @Override - String rrToString() { + protected String rrToString() { return unknownToString(data); } @@ -51,7 +51,7 @@ public byte[] getData() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeByteArray(data); } } diff --git a/src/main/java/org/xbill/DNS/NXTRecord.java b/src/main/java/org/xbill/DNS/NXTRecord.java index a4e088c7d..4e544163f 100644 --- a/src/main/java/org/xbill/DNS/NXTRecord.java +++ b/src/main/java/org/xbill/DNS/NXTRecord.java @@ -33,7 +33,7 @@ public NXTRecord(Name name, int dclass, long ttl, Name next, BitSet bitmap) { } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { next = new Name(in); bitmap = new BitSet(); int bitmapLength = in.remaining(); @@ -48,7 +48,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { next = st.getName(origin); bitmap = new BitSet(); while (true) { @@ -67,7 +67,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(next); int length = bitmap.length(); @@ -91,7 +91,7 @@ public BitSet getBitmap() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { next.toWire(out, null, canonical); int length = bitmap.length(); for (int i = 0, t = 0; i < length; i++) { diff --git a/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java b/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java index fec5ca860..0fa22ec8a 100644 --- a/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java +++ b/src/main/java/org/xbill/DNS/OPENPGPKEYRecord.java @@ -27,18 +27,18 @@ public OPENPGPKEYRecord(Name name, int dclass, long ttl, byte[] cert) { } @Override - void rrFromWire(DNSInput in) { + protected void rrFromWire(DNSInput in) { cert = in.readByteArray(); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { cert = st.getBase64(); } /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); if (cert != null) { if (Options.check("multiline")) { @@ -57,7 +57,7 @@ public byte[] getCert() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeByteArray(cert); } } diff --git a/src/main/java/org/xbill/DNS/OPTRecord.java b/src/main/java/org/xbill/DNS/OPTRecord.java index 3fd025934..547ecdde7 100644 --- a/src/main/java/org/xbill/DNS/OPTRecord.java +++ b/src/main/java/org/xbill/DNS/OPTRecord.java @@ -75,7 +75,7 @@ public OPTRecord(int payloadSize, int xrcode, int version) { } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { if (in.remaining() > 0) { options = new ArrayList<>(); } @@ -86,13 +86,13 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { throw st.exception("no text format defined for OPT"); } /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); if (options != null) { sb.append(options); @@ -134,7 +134,7 @@ public int getFlags() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { if (options == null) { return; } diff --git a/src/main/java/org/xbill/DNS/PXRecord.java b/src/main/java/org/xbill/DNS/PXRecord.java index 68e8494dc..f84adbacc 100644 --- a/src/main/java/org/xbill/DNS/PXRecord.java +++ b/src/main/java/org/xbill/DNS/PXRecord.java @@ -34,14 +34,14 @@ public PXRecord(Name name, int dclass, long ttl, int preference, Name map822, Na } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { preference = in.readU16(); map822 = new Name(in); mapX400 = new Name(in); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { preference = st.getUInt16(); map822 = st.getName(origin); mapX400 = st.getName(origin); @@ -49,7 +49,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts the PX Record to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(preference); sb.append(" "); @@ -60,7 +60,7 @@ String rrToString() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(preference); map822.toWire(out, null, canonical); mapX400.toWire(out, null, canonical); diff --git a/src/main/java/org/xbill/DNS/RPRecord.java b/src/main/java/org/xbill/DNS/RPRecord.java index c2f553ab6..2ca7faeaf 100644 --- a/src/main/java/org/xbill/DNS/RPRecord.java +++ b/src/main/java/org/xbill/DNS/RPRecord.java @@ -32,20 +32,20 @@ public RPRecord(Name name, int dclass, long ttl, Name mailbox, Name textDomain) } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { mailbox = new Name(in); textDomain = new Name(in); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { mailbox = st.getName(origin); textDomain = st.getName(origin); } /** Converts the RP Record to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(mailbox); sb.append(" "); @@ -64,7 +64,7 @@ public Name getTextDomain() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { mailbox.toWire(out, null, canonical); textDomain.toWire(out, null, canonical); } diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index 9c8888fcc..5f9f15dcc 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -28,7 +28,7 @@ public abstract class Record implements Cloneable, Comparable { protected Record() {} - Record(Name name, int type, int dclass, long ttl) { + protected Record(Name name, int type, int dclass, long ttl) { if (!name.isAbsolute()) { throw new RelativeNameException(name); } @@ -61,7 +61,7 @@ private static Record getEmptyRecord(Name name, int type, int dclass, long ttl, } /** Converts the type-specific RR to wire format - must be overridden */ - abstract void rrFromWire(DNSInput in) throws IOException; + protected abstract void rrFromWire(DNSInput in) throws IOException; private static Record newRecord( Name name, int type, int dclass, long ttl, int length, DNSInput in) throws IOException { @@ -262,7 +262,7 @@ public byte[] rdataToWireCanonical() { } /** Converts the type-specific RR to text format - must be overriden */ - abstract String rrToString(); + protected abstract String rrToString(); /** Converts the rdata portion of a Record into a String representation */ public String rdataToString() { @@ -301,7 +301,7 @@ public String toString() { } /** Converts the text format of an RR to the internal format - must be overriden */ - abstract void rdataFromString(Tokenizer st, Name origin) throws IOException; + protected abstract void rdataFromString(Tokenizer st, Name origin) throws IOException; /** Converts a String into a byte array. */ protected static byte[] byteArrayFromString(String s) throws TextParseException { @@ -504,7 +504,7 @@ public long getTTL() { } /** Converts the type-specific RR to wire format - must be overriden */ - abstract void rrToWire(DNSOutput out, Compression c, boolean canonical); + protected abstract void rrToWire(DNSOutput out, Compression c, boolean canonical); /** * Determines if two Records could be part of the same RRset. This compares the name, type, and diff --git a/src/main/java/org/xbill/DNS/SIGBase.java b/src/main/java/org/xbill/DNS/SIGBase.java index 4a35195c8..cb5427db7 100644 --- a/src/main/java/org/xbill/DNS/SIGBase.java +++ b/src/main/java/org/xbill/DNS/SIGBase.java @@ -54,7 +54,7 @@ public SIGBase( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { covered = in.readU16(); alg = in.readU8(); labels = in.readU8(); @@ -67,7 +67,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { String typeString = st.getString(); covered = Type.value(typeString); if (covered < 0) { @@ -89,7 +89,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts the RRSIG/SIG Record to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(Type.string(covered)); sb.append(" "); @@ -186,7 +186,7 @@ void setSignature(byte[] signature) { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(covered); out.writeU8(alg); out.writeU8(labels); diff --git a/src/main/java/org/xbill/DNS/SOARecord.java b/src/main/java/org/xbill/DNS/SOARecord.java index 666b10fc8..e9cea6a3f 100644 --- a/src/main/java/org/xbill/DNS/SOARecord.java +++ b/src/main/java/org/xbill/DNS/SOARecord.java @@ -50,7 +50,7 @@ public SOARecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { host = new Name(in); admin = new Name(in); serial = in.readU32(); @@ -61,7 +61,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { host = st.getName(origin); admin = st.getName(origin); serial = st.getUInt32(); @@ -73,7 +73,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Convert to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(host); sb.append(" "); @@ -141,7 +141,7 @@ public long getMinimum() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { host.toWire(out, c, canonical); admin.toWire(out, c, canonical); out.writeU32(serial); diff --git a/src/main/java/org/xbill/DNS/SRVRecord.java b/src/main/java/org/xbill/DNS/SRVRecord.java index 09eb2ca33..445d9dedc 100644 --- a/src/main/java/org/xbill/DNS/SRVRecord.java +++ b/src/main/java/org/xbill/DNS/SRVRecord.java @@ -37,7 +37,7 @@ public SRVRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { priority = in.readU16(); weight = in.readU16(); port = in.readU16(); @@ -45,7 +45,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { priority = st.getUInt16(); weight = st.getUInt16(); port = st.getUInt16(); @@ -54,7 +54,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(priority).append(" "); sb.append(weight).append(" "); @@ -84,7 +84,7 @@ public Name getTarget() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(priority); out.writeU16(weight); out.writeU16(port); diff --git a/src/main/java/org/xbill/DNS/SSHFPRecord.java b/src/main/java/org/xbill/DNS/SSHFPRecord.java index 815e11d27..ab5851718 100644 --- a/src/main/java/org/xbill/DNS/SSHFPRecord.java +++ b/src/main/java/org/xbill/DNS/SSHFPRecord.java @@ -47,21 +47,21 @@ public SSHFPRecord(Name name, int dclass, long ttl, int alg, int digestType, byt } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { alg = in.readU8(); digestType = in.readU8(); fingerprint = in.readByteArray(); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { alg = st.getUInt8(); digestType = st.getUInt8(); fingerprint = st.getHex(true); } @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(alg); sb.append(" "); @@ -87,7 +87,7 @@ public byte[] getFingerPrint() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU8(alg); out.writeU8(digestType); out.writeByteArray(fingerprint); diff --git a/src/main/java/org/xbill/DNS/SingleCompressedNameBase.java b/src/main/java/org/xbill/DNS/SingleCompressedNameBase.java index c302ca43d..b30253a07 100644 --- a/src/main/java/org/xbill/DNS/SingleCompressedNameBase.java +++ b/src/main/java/org/xbill/DNS/SingleCompressedNameBase.java @@ -17,7 +17,7 @@ protected SingleCompressedNameBase( } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { singleName.toWire(out, c, canonical); } } diff --git a/src/main/java/org/xbill/DNS/SingleNameBase.java b/src/main/java/org/xbill/DNS/SingleNameBase.java index 370b29730..309770343 100644 --- a/src/main/java/org/xbill/DNS/SingleNameBase.java +++ b/src/main/java/org/xbill/DNS/SingleNameBase.java @@ -25,17 +25,17 @@ protected SingleNameBase( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { singleName = new Name(in); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { singleName = st.getName(origin); } @Override - String rrToString() { + protected String rrToString() { return singleName.toString(); } @@ -44,7 +44,7 @@ protected Name getSingleName() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { singleName.toWire(out, null, canonical); } } diff --git a/src/main/java/org/xbill/DNS/TKEYRecord.java b/src/main/java/org/xbill/DNS/TKEYRecord.java index f171ae7c2..723180ea6 100644 --- a/src/main/java/org/xbill/DNS/TKEYRecord.java +++ b/src/main/java/org/xbill/DNS/TKEYRecord.java @@ -113,7 +113,7 @@ public TKEYRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { alg = new Name(in); timeInception = Instant.ofEpochSecond(in.readU32()); timeExpire = Instant.ofEpochSecond(in.readU32()); @@ -136,7 +136,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { throw st.exception("no text format defined for TKEY"); } @@ -159,7 +159,7 @@ protected String modeString() { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(alg); sb.append(" "); @@ -232,7 +232,7 @@ public byte[] getOther() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { alg.toWire(out, null, canonical); out.writeU32(timeInception.getEpochSecond()); diff --git a/src/main/java/org/xbill/DNS/TLSARecord.java b/src/main/java/org/xbill/DNS/TLSARecord.java index fe58408e9..1759a8897 100644 --- a/src/main/java/org/xbill/DNS/TLSARecord.java +++ b/src/main/java/org/xbill/DNS/TLSARecord.java @@ -109,7 +109,7 @@ public TLSARecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { certificateUsage = in.readU8(); selector = in.readU8(); matchingType = in.readU8(); @@ -117,7 +117,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { certificateUsage = st.getUInt8(); selector = st.getUInt8(); matchingType = st.getUInt8(); @@ -126,7 +126,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(certificateUsage); sb.append(" "); @@ -140,7 +140,7 @@ String rrToString() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU8(certificateUsage); out.writeU8(selector); out.writeU8(matchingType); diff --git a/src/main/java/org/xbill/DNS/TSIGRecord.java b/src/main/java/org/xbill/DNS/TSIGRecord.java index e1a1becd3..e91b134ff 100644 --- a/src/main/java/org/xbill/DNS/TSIGRecord.java +++ b/src/main/java/org/xbill/DNS/TSIGRecord.java @@ -105,7 +105,7 @@ public TSIGRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { alg = new Name(in); long timeHigh = in.readU16(); @@ -129,13 +129,13 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { throw st.exception("no text format defined for TSIG"); } /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(alg); sb.append(" "); @@ -230,7 +230,7 @@ public byte[] getOther() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { alg.toWire(out, null, canonical); long time = timeSigned.getEpochSecond(); diff --git a/src/main/java/org/xbill/DNS/TXTBase.java b/src/main/java/org/xbill/DNS/TXTBase.java index 0fbe6a867..8ca7a084c 100644 --- a/src/main/java/org/xbill/DNS/TXTBase.java +++ b/src/main/java/org/xbill/DNS/TXTBase.java @@ -44,7 +44,7 @@ protected TXTBase(Name name, int type, int dclass, long ttl, String string) { } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { strings = new ArrayList<>(2); while (in.remaining() > 0) { byte[] b = in.readCountedString(); @@ -53,7 +53,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { strings = new ArrayList<>(2); while (true) { Tokenizer.Token t = st.get(); @@ -71,7 +71,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** converts to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); Iterator it = strings.iterator(); while (it.hasNext()) { @@ -107,7 +107,7 @@ public List getStringsAsByteArrays() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { for (byte[] b : strings) { out.writeCountedString(b); } diff --git a/src/main/java/org/xbill/DNS/U16NameBase.java b/src/main/java/org/xbill/DNS/U16NameBase.java index 25ee8811a..e1b8292ea 100644 --- a/src/main/java/org/xbill/DNS/U16NameBase.java +++ b/src/main/java/org/xbill/DNS/U16NameBase.java @@ -35,19 +35,19 @@ protected U16NameBase( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { u16Field = in.readU16(); nameField = new Name(in); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { u16Field = st.getUInt16(); nameField = st.getName(origin); } @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(u16Field); sb.append(" "); @@ -64,7 +64,7 @@ protected Name getNameField() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(u16Field); nameField.toWire(out, null, canonical); } diff --git a/src/main/java/org/xbill/DNS/UNKRecord.java b/src/main/java/org/xbill/DNS/UNKRecord.java index b55d18f96..5608647fe 100644 --- a/src/main/java/org/xbill/DNS/UNKRecord.java +++ b/src/main/java/org/xbill/DNS/UNKRecord.java @@ -16,18 +16,18 @@ public class UNKRecord extends Record { UNKRecord() {} @Override - void rrFromWire(DNSInput in) { + protected void rrFromWire(DNSInput in) { data = in.readByteArray(); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { throw st.exception("invalid unknown RR encoding"); } /** Converts this Record to the String "unknown format" */ @Override - String rrToString() { + protected String rrToString() { return unknownToString(data); } @@ -37,7 +37,7 @@ public byte[] getData() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeByteArray(data); } } diff --git a/src/main/java/org/xbill/DNS/URIRecord.java b/src/main/java/org/xbill/DNS/URIRecord.java index a16c50cd2..509f9b2f4 100644 --- a/src/main/java/org/xbill/DNS/URIRecord.java +++ b/src/main/java/org/xbill/DNS/URIRecord.java @@ -39,14 +39,14 @@ public URIRecord(Name name, int dclass, long ttl, int priority, int weight, Stri } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { priority = in.readU16(); weight = in.readU16(); target = in.readByteArray(); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { priority = st.getUInt16(); weight = st.getUInt16(); try { @@ -58,7 +58,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(priority).append(" "); sb.append(weight).append(" "); @@ -82,7 +82,7 @@ public String getTarget() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeU16(priority); out.writeU16(weight); out.writeByteArray(target); diff --git a/src/main/java/org/xbill/DNS/WKSRecord.java b/src/main/java/org/xbill/DNS/WKSRecord.java index ba292cf57..e845a18c6 100644 --- a/src/main/java/org/xbill/DNS/WKSRecord.java +++ b/src/main/java/org/xbill/DNS/WKSRecord.java @@ -597,7 +597,7 @@ public WKSRecord( } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { address = in.readByteArray(4); protocol = in.readU8(); byte[] array = in.readByteArray(); @@ -617,7 +617,7 @@ void rrFromWire(DNSInput in) throws IOException { } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { String s = st.getString(); address = Address.toByteArray(s, Address.IPv4); if (address == null) { @@ -651,7 +651,7 @@ void rdataFromString(Tokenizer st, Name origin) throws IOException { /** Converts rdata to a String */ @Override - String rrToString() { + protected String rrToString() { StringBuilder sb = new StringBuilder(); sb.append(Address.toDottedQuad(address)); sb.append(" "); @@ -682,7 +682,7 @@ public int[] getServices() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeByteArray(address); out.writeU8(protocol); int highestPort = services[services.length - 1]; diff --git a/src/main/java/org/xbill/DNS/X25Record.java b/src/main/java/org/xbill/DNS/X25Record.java index 9cfeabd4f..9f2d8e524 100644 --- a/src/main/java/org/xbill/DNS/X25Record.java +++ b/src/main/java/org/xbill/DNS/X25Record.java @@ -44,12 +44,12 @@ public X25Record(Name name, int dclass, long ttl, String address) { } @Override - void rrFromWire(DNSInput in) throws IOException { + protected void rrFromWire(DNSInput in) throws IOException { address = in.readCountedString(); } @Override - void rdataFromString(Tokenizer st, Name origin) throws IOException { + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { String addr = st.getString(); this.address = checkAndConvertAddress(addr); if (this.address == null) { @@ -63,12 +63,12 @@ public String getAddress() { } @Override - void rrToWire(DNSOutput out, Compression c, boolean canonical) { + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { out.writeCountedString(address); } @Override - String rrToString() { + protected String rrToString() { return byteArrayToString(address, true); } } diff --git a/src/test/java/org/xbill/DNS/KEYBaseTest.java b/src/test/java/org/xbill/DNS/KEYBaseTest.java index 125a0d5ce..01aee143e 100644 --- a/src/test/java/org/xbill/DNS/KEYBaseTest.java +++ b/src/test/java/org/xbill/DNS/KEYBaseTest.java @@ -53,7 +53,7 @@ private static class TestClass extends KEYBase { } @Override - void rdataFromString(Tokenizer st, Name origin) {} + protected void rdataFromString(Tokenizer st, Name origin) {} } @Test From f81d86bf343c7b05e3db985de0efd78df0e29a95 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 6 May 2020 22:20:00 +0200 Subject: [PATCH 084/431] Fix TSIG fudge seconds rr string representation --- src/main/java/org/xbill/DNS/TSIGRecord.java | 2 +- .../java/org/xbill/DNS/TSIGRecordTest.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/xbill/DNS/TSIGRecordTest.java diff --git a/src/main/java/org/xbill/DNS/TSIGRecord.java b/src/main/java/org/xbill/DNS/TSIGRecord.java index 257cf55e8..313d5b160 100644 --- a/src/main/java/org/xbill/DNS/TSIGRecord.java +++ b/src/main/java/org/xbill/DNS/TSIGRecord.java @@ -145,7 +145,7 @@ String rrToString() { sb.append(timeSigned.getEpochSecond()); sb.append(" "); - sb.append(fudge); + sb.append((int) fudge.getSeconds()); sb.append(" "); sb.append(signature.length); if (Options.check("multiline")) { diff --git a/src/test/java/org/xbill/DNS/TSIGRecordTest.java b/src/test/java/org/xbill/DNS/TSIGRecordTest.java new file mode 100644 index 000000000..2306b42fc --- /dev/null +++ b/src/test/java/org/xbill/DNS/TSIGRecordTest.java @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.Duration; +import java.time.Instant; +import org.junit.jupiter.api.Test; + +public class TSIGRecordTest { + @Test + void testTsigToStringFudge() { + TSIGRecord r = + new TSIGRecord( + Name.root, + DClass.IN, + 60, + TSIG.HMAC_MD5, + Instant.ofEpochSecond(1), + Duration.ofSeconds(5), + new byte[16], + 1, + 0, + null); + assertEquals( + "HMAC-MD5.SIG-ALG.REG.INT. 1 5 16 AAAAAAAAAAAAAAAAAAAAAA== NOERROR 0", r.rrToString()); + } +} From 0d58ae2ad88f0ef8ee7d5469974e74ddea62757a Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 6 May 2020 22:23:51 +0200 Subject: [PATCH 085/431] Do not apply EDNS/TSIG for AXFR queries --- src/main/java/org/xbill/DNS/SimpleResolver.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index ab8104db2..08a83150d 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -240,12 +240,6 @@ private int maxUDPSize(Message query) { */ @Override public CompletionStage sendAsync(Message query) { - Message ednsTsigQuery = query.clone(); - applyEDNS(ednsTsigQuery); - if (tsig != null) { - tsig.apply(ednsTsigQuery, null); - } - if (query.getHeader().getOpcode() == Opcode.QUERY) { Record question = query.getQuestion(); if (question != null && question.getType() == Type.AXFR) { @@ -263,6 +257,12 @@ public CompletionStage sendAsync(Message query) { } } + Message ednsTsigQuery = query.clone(); + applyEDNS(ednsTsigQuery); + if (tsig != null) { + tsig.apply(ednsTsigQuery, null); + } + return sendAsync(ednsTsigQuery, useTCP); } From 1c635cc5bb638698c16eea0ec7b5f2f2dcecd232 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 6 May 2020 23:35:55 +0200 Subject: [PATCH 086/431] Fix order of OPT and TSIG records in messages Closes #100 --- src/main/java/org/xbill/DNS/Message.java | 21 ++++-- .../java/org/xbill/DNS/SimpleResolver.java | 4 +- src/test/java/org/xbill/DNS/TSIGTest.java | 73 +++++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Message.java b/src/main/java/org/xbill/DNS/Message.java index ecbab21a2..687efe40e 100644 --- a/src/main/java/org/xbill/DNS/Message.java +++ b/src/main/java/org/xbill/DNS/Message.java @@ -115,6 +115,9 @@ public static Message newUpdate(Name zone) { if (i == Section.ADDITIONAL) { if (rec.getType() == Type.TSIG) { tsigstart = pos; + if (j != count - 1) { + throw new WireParseException("TSIG is not the last record in the message"); + } } if (rec.getType() == Type.SIG) { SIGRecord sig = (SIGRecord) rec; @@ -519,7 +522,12 @@ private void toWire(DNSOutput out, int maxLength) { } } - /** Returns an array containing the wire format representation of the Message. */ + /** + * Returns an array containing the wire format representation of the {@link Message}, but does not + * do any additional processing (e.g. OPT/TSIG records, truncation). + * + *

Do NOT use this to actually transmit a message, use {@link #toWire(int)} instead. + */ public byte[] toWire() { DNSOutput out = new DNSOutput(); toWire(out); @@ -531,12 +539,15 @@ public byte[] toWire() { * Returns an array containing the wire format representation of the Message with the specified * maximum length. This will generate a truncated message (with the TC bit) if the message doesn't * fit, and will also sign the message with the TSIG key set by a call to setTSIG(). This method - * may return null if the message could not be rendered at all; this could happen if maxLength is - * smaller than a DNS header, for example. + * may return an empty byte array if the message could not be rendered at all; this could happen + * if maxLength is smaller than a DNS header, for example. + * + *

Do NOT use this method in conjunction with {@link TSIG#apply(Message, TSIGRecord)}, it + * produces inconsistent results! Use {@link #setTSIG(TSIG, int, TSIGRecord)} instead. * * @param maxLength The maximum length of the message. - * @return The wire format of the message, or null if the message could not be rendered into the - * specified length. + * @return The wire format of the message, or an empty array if the message could not be rendered + * into the specified length. * @see Flags * @see TSIG */ diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index 08a83150d..c34069fe6 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -260,13 +260,13 @@ public CompletionStage sendAsync(Message query) { Message ednsTsigQuery = query.clone(); applyEDNS(ednsTsigQuery); if (tsig != null) { - tsig.apply(ednsTsigQuery, null); + ednsTsigQuery.setTSIG(tsig, Rcode.NOERROR, null); } return sendAsync(ednsTsigQuery, useTCP); } - private CompletableFuture sendAsync(Message query, boolean forceTcp) { + CompletableFuture sendAsync(Message query, boolean forceTcp) { int qid = query.getHeader().getID(); byte[] out = query.toWire(Message.MAXLENGTH); int udpSize = maxUDPSize(query); diff --git a/src/test/java/org/xbill/DNS/TSIGTest.java b/src/test/java/org/xbill/DNS/TSIGTest.java index 170dfea55..76083355e 100644 --- a/src/test/java/org/xbill/DNS/TSIGTest.java +++ b/src/test/java/org/xbill/DNS/TSIGTest.java @@ -1,10 +1,13 @@ package org.xbill.DNS; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.util.List; +import java.util.concurrent.CompletableFuture; import org.junit.jupiter.api.Test; class TSIGTest { @@ -25,6 +28,76 @@ void TSIG_query() throws IOException { assertTrue(parsed.isSigned()); } + @Test + void TSIG_queryIsLastAddMessageRecord() throws IOException { + TSIG key = new TSIG(TSIG.HMAC_SHA256, "example.", "12345678"); + + Name qname = Name.fromString("www.example."); + Record rec = Record.newRecord(qname, Type.A, DClass.IN); + OPTRecord opt = new OPTRecord(SimpleResolver.DEFAULT_EDNS_PAYLOADSIZE, 0, 0, 0); + Message msg = Message.newQuery(rec); + msg.setTSIG(key, Rcode.NOERROR, null); + msg.addRecord(opt, Section.ADDITIONAL); + byte[] bytes = msg.toWire(512); + assertEquals(bytes[11], 2); // additional RR count, lower byte + + Message parsed = new Message(bytes); + List additionalSection = parsed.getSection(Section.ADDITIONAL); + assertEquals(Type.string(Type.OPT), Type.string(additionalSection.get(0).getType())); + assertEquals(Type.string(Type.TSIG), Type.string(additionalSection.get(1).getType())); + int result = key.verify(parsed, bytes, null); + assertEquals(result, Rcode.NOERROR); + assertTrue(parsed.isSigned()); + } + + @Test + void TSIG_queryAndTsigApplyMisbehaves() throws IOException { + Name qname = Name.fromString("www.example.com."); + Record rec = Record.newRecord(qname, Type.A, DClass.IN); + OPTRecord opt = new OPTRecord(SimpleResolver.DEFAULT_EDNS_PAYLOADSIZE, 0, 0, 0); + Message msg = Message.newQuery(rec); + msg.addRecord(opt, Section.ADDITIONAL); + assertFalse(msg.isSigned()); + + TSIG key = new TSIG(TSIG.HMAC_SHA256, "example.", "12345678"); + key.apply(msg, null); // additional RR count, lower byte + byte[] bytes = msg.toWire(Message.MAXLENGTH); + + assertThrows(WireParseException.class, () -> new Message(bytes), "Expected TSIG error"); + } + + @Test + void TSIG_queryIsLastResolver() throws IOException { + Name qname = Name.fromString("www.example.com."); + Record rec = Record.newRecord(qname, Type.A, DClass.IN); + Message msg = Message.newQuery(rec); + + TSIG key = new TSIG(TSIG.HMAC_SHA256, "example.", "12345678"); + SimpleResolver res = + new SimpleResolver("127.0.0.1") { + @Override + CompletableFuture sendAsync(Message query, boolean forceTcp) { + byte[] out = query.toWire(Message.MAXLENGTH); + try { + return CompletableFuture.completedFuture(new Message(out)); + } catch (IOException e) { + CompletableFuture f = new CompletableFuture<>(); + f.completeExceptionally(e); + return f; + } + } + }; + res.setTSIGKey(key); + Message parsed = res.send(msg); + + List additionalSection = parsed.getSection(Section.ADDITIONAL); + assertEquals(Type.string(Type.OPT), Type.string(additionalSection.get(0).getType())); + assertEquals(Type.string(Type.TSIG), Type.string(additionalSection.get(1).getType())); + int result = key.verify(parsed, parsed.toWire(), null); + assertEquals(result, Rcode.NOERROR); + assertTrue(parsed.isSigned()); + } + @Test void TSIG_response() throws IOException { TSIG key = new TSIG(TSIG.HMAC_SHA256, "example.", "12345678"); From a1f949b3c34c215e86b14b25df8e225eee5294dd Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 6 May 2020 23:42:49 +0200 Subject: [PATCH 087/431] Fix short overflow while iterating over RR set (#107) Closes #102 --- src/main/java/org/xbill/DNS/RRset.java | 3 +++ src/test/java/org/xbill/DNS/RRsetTest.java | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/main/java/org/xbill/DNS/RRset.java b/src/main/java/org/xbill/DNS/RRset.java index f6ea68944..9f2547d76 100644 --- a/src/main/java/org/xbill/DNS/RRset.java +++ b/src/main/java/org/xbill/DNS/RRset.java @@ -146,6 +146,9 @@ public List rrs(boolean cycle) { } List l = new ArrayList<>(rrs.size()); + if (position == Short.MAX_VALUE) { + position = 0; + } int start = position++ % rrs.size(); l.addAll(rrs.subList(start, rrs.size())); l.addAll(rrs.subList(0, start)); diff --git a/src/test/java/org/xbill/DNS/RRsetTest.java b/src/test/java/org/xbill/DNS/RRsetTest.java index f37c7c1a5..4fb2c329e 100644 --- a/src/test/java/org/xbill/DNS/RRsetTest.java +++ b/src/test/java/org/xbill/DNS/RRsetTest.java @@ -316,4 +316,24 @@ void noncycling_iterator() { assertEquals(m_a1, itr.get(0)); assertEquals(m_a2, itr.get(1)); } + + @Test + void cycleBelowShort() throws Exception { + runSim(100); + } + + @Test + void cycleAboveShort() throws Exception { + runSim(50_000); + } + + private void runSim(int numOfCalls) throws Exception { + RRset rrset = new RRset(); + rrset.addRR(m_a1); + rrset.addRR(m_a2); + + for (int i = 0; i < numOfCalls; i++) { + rrset.rrs(true); + } + } } From ff6fb9aaa54d601be5ba03a44ade985f205ac266 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 6 May 2020 21:10:30 +0200 Subject: [PATCH 088/431] Make NIO client initialization thread safe Close #104 --- src/main/java/org/xbill/DNS/Client.java | 60 ++++++++++++------- src/main/java/org/xbill/DNS/NioTcpClient.java | 30 +++------- src/main/java/org/xbill/DNS/NioUdpClient.java | 30 +++------- .../org/xbill/DNS/ResolverConfigTest.java | 3 +- 4 files changed, 57 insertions(+), 66 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Client.java b/src/main/java/org/xbill/DNS/Client.java index d9144ffec..cee12def0 100644 --- a/src/main/java/org/xbill/DNS/Client.java +++ b/src/main/java/org/xbill/DNS/Client.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.net.SocketAddress; +import java.nio.channels.ClosedSelectorException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.Iterator; @@ -17,39 +18,47 @@ class Client { /** Packet logger, if available. */ private static PacketLogger packetLogger = null; - private static volatile boolean run; + private static volatile boolean run = true; + private static final List timeoutTasks = new CopyOnWriteArrayList<>(); + private static final List closeTasks = new CopyOnWriteArrayList<>(); private static Thread selectorThread; - private static List timeoutTasks = new CopyOnWriteArrayList<>(); - static Selector selector; + private static volatile Selector selector; interface KeyProcessor { void processReadyKey(SelectionKey key); } - static void start() throws IOException { - if (run) { - return; + static Selector selector() throws IOException { + if (selector == null) { + synchronized (Client.class) { + if (selector == null) { + selector = Selector.open(); + log.debug("Starting dnsjava NIO selector thread"); + selectorThread = new Thread(Client::runSelector); + selectorThread.setDaemon(true); + selectorThread.setName("dnsjava NIO selector"); + selectorThread.start(); + Thread closeThread = new Thread(Client::close); + closeThread.setName("dnsjava NIO shutdown hook"); + Runtime.getRuntime().addShutdownHook(closeThread); + } + } } - log.debug("Starting dnsjava NIO selector thread"); - run = true; - selector = Selector.open(); - selectorThread = new Thread(Client::runSelector); - selectorThread.setDaemon(true); - selectorThread.setName("dnsjava NIO selector"); - selectorThread.start(); + return selector; } - protected static void close() throws Exception { - if (!run) { - return; - } - + private static void close() { run = false; + closeTasks.forEach(Runnable::run); timeoutTasks.clear(); selector.wakeup(); - selector.close(); - selectorThread.join(); + try { + selector.close(); + selectorThread.join(); + } catch (InterruptedException | IOException e) { + log.warn("Failed to properly shutdown", e); + } } private static void runSelector() { @@ -59,17 +68,26 @@ private static void runSelector() { timeoutTasks.forEach(Runnable::run); } - processReadyKeys(); + if (run) { + processReadyKeys(); + } } catch (IOException e) { log.error("A selection operation failed", e); + } catch (ClosedSelectorException e) { + // ignore } } + log.debug("dnsjava NIO selector thread stopped"); } static void addSelectorTimeoutTask(Runnable r) { timeoutTasks.add(r); } + static void addCloseTask(Runnable r) { + closeTasks.add(r); + } + private static void processReadyKeys() { Iterator it = selector.selectedKeys().iterator(); while (it.hasNext()) { diff --git a/src/main/java/org/xbill/DNS/NioTcpClient.java b/src/main/java/org/xbill/DNS/NioTcpClient.java index f93682f60..9eef1bbb3 100644 --- a/src/main/java/org/xbill/DNS/NioTcpClient.java +++ b/src/main/java/org/xbill/DNS/NioTcpClient.java @@ -6,8 +6,8 @@ import java.net.InetSocketAddress; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; -import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.time.Duration; import java.util.Iterator; @@ -24,33 +24,26 @@ @Slf4j @UtilityClass final class NioTcpClient extends Client { - private static Queue registrationQueue; - private static Map channelMap; - private static volatile boolean run; + private static final Queue registrationQueue = new ConcurrentLinkedQueue<>(); + private static final Map channelMap = new ConcurrentHashMap<>(); - private static void startTcp() throws IOException { - if (run) { - return; - } - - run = true; - registrationQueue = new ConcurrentLinkedQueue<>(); - channelMap = new ConcurrentHashMap<>(); + static { addSelectorTimeoutTask(NioTcpClient::processPendingRegistrations); addSelectorTimeoutTask(NioTcpClient::checkTransactionTimeouts); - start(); + addCloseTask(NioTcpClient::closeTcp); } private static void processPendingRegistrations() { while (!registrationQueue.isEmpty()) { ChannelState state = registrationQueue.remove(); try { + final Selector selector = selector(); if (!state.channel.isConnected()) { state.channel.register(selector, SelectionKey.OP_CONNECT, state); } else { state.channel.keyFor(selector).interestOps(SelectionKey.OP_WRITE); } - } catch (ClosedChannelException e) { + } catch (IOException e) { state.handleChannelException(e); } } @@ -68,16 +61,11 @@ private static void checkTransactionTimeouts() { } } - static void closeTcp() throws Exception { - if (!run) { - return; - } - + private static void closeTcp() { registrationQueue.clear(); EOFException closing = new EOFException("Client is closing"); channelMap.forEach((key, state) -> state.handleTransactionException(closing)); channelMap.clear(); - close(); } @RequiredArgsConstructor @@ -255,7 +243,7 @@ static CompletableFuture sendrecv( Duration timeout) { CompletableFuture f = new CompletableFuture<>(); try { - startTcp(); + final Selector selector = selector(); long endTime = System.nanoTime() + timeout.toNanos(); ChannelState channel = channelMap.computeIfAbsent( diff --git a/src/main/java/org/xbill/DNS/NioUdpClient.java b/src/main/java/org/xbill/DNS/NioUdpClient.java index 49db6ac67..128631025 100644 --- a/src/main/java/org/xbill/DNS/NioUdpClient.java +++ b/src/main/java/org/xbill/DNS/NioUdpClient.java @@ -9,6 +9,7 @@ import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; import java.security.SecureRandom; import java.time.Duration; import java.util.Iterator; @@ -26,9 +27,8 @@ final class NioUdpClient extends Client { private static final int EPHEMERAL_RANGE; private static final SecureRandom prng; - private static volatile boolean run; - private static Queue registrationQueue; - private static Queue pendingTransactions; + private static final Queue registrationQueue = new ConcurrentLinkedQueue<>(); + private static final Queue pendingTransactions = new ConcurrentLinkedQueue<>(); static { // https://tools.ietf.org/html/rfc6335#section-6 @@ -50,26 +50,16 @@ final class NioUdpClient extends Client { } else { prng = new SecureRandom(); } - } - - private static void startUdp() throws IOException { - if (run) { - return; - } - - run = true; - registrationQueue = new ConcurrentLinkedQueue<>(); - pendingTransactions = new ConcurrentLinkedQueue<>(); addSelectorTimeoutTask(NioUdpClient::processPendingRegistrations); addSelectorTimeoutTask(NioUdpClient::checkTransactionTimeouts); - start(); + addCloseTask(NioUdpClient::closeUdp); } private static void processPendingRegistrations() { while (!registrationQueue.isEmpty()) { Transaction t = registrationQueue.remove(); try { - t.channel.register(selector, SelectionKey.OP_READ, t); + t.channel.register(selector(), SelectionKey.OP_READ, t); t.send(); } catch (IOException e) { t.f.completeExceptionally(e); @@ -160,7 +150,7 @@ static CompletableFuture sendrecv( InetSocketAddress local, InetSocketAddress remote, byte[] data, int max, Duration timeout) { CompletableFuture f = new CompletableFuture<>(); try { - startUdp(); + final Selector selector = selector(); DatagramChannel channel = DatagramChannel.open(); channel.configureBlocking(false); if (local == null || local.getPort() == 0) { @@ -209,16 +199,10 @@ static CompletableFuture sendrecv( return f; } - static void closeUdp() throws Exception { - if (!run) { - return; - } - - run = false; + private static void closeUdp() { registrationQueue.clear(); EOFException closing = new EOFException("Client is closing"); pendingTransactions.forEach(t -> t.f.completeExceptionally(closing)); pendingTransactions.clear(); - close(); } } diff --git a/src/test/java/org/xbill/DNS/ResolverConfigTest.java b/src/test/java/org/xbill/DNS/ResolverConfigTest.java index be690613c..efc9760f2 100644 --- a/src/test/java/org/xbill/DNS/ResolverConfigTest.java +++ b/src/test/java/org/xbill/DNS/ResolverConfigTest.java @@ -176,7 +176,8 @@ void windowsServersContainedInJndi() throws InitializationException { win.initialize(); // the servers returned via Windows API must be in the JNDI list, but not necessarily the other - // way round + // way round. Unless there IPv6 servers which are not in the registry and Java <= 15 does not + // find. for (InetSocketAddress winServer : win.servers()) { assertTrue( jndi.servers().contains(winServer), From d82fdae93900d9c89c743241cf0cbd91173cfd1f Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 15 May 2020 21:05:26 +0200 Subject: [PATCH 089/431] Add reverse map parsing into IP address Closes #103 --- src/main/java/org/xbill/DNS/ReverseMap.java | 69 +++++++++++++++++-- .../java/org/xbill/DNS/ReverseMapTest.java | 69 ++++++++++++++----- 2 files changed, 117 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ReverseMap.java b/src/main/java/org/xbill/DNS/ReverseMap.java index 82b22f1df..528157bc8 100644 --- a/src/main/java/org/xbill/DNS/ReverseMap.java +++ b/src/main/java/org/xbill/DNS/ReverseMap.java @@ -6,7 +6,7 @@ import java.net.UnknownHostException; /** - * A set functions designed to deal with DNS names used in reverse mappings. For the IPv4 address + * A set of functions designed to deal with DNS names used in reverse mappings. For the IPv4 address * a.b.c.d, the reverse map name is d.c.b.a.in-addr.arpa. For an IPv6 address, the reverse map name * is ...ip6.arpa. * @@ -14,8 +14,8 @@ */ public final class ReverseMap { - private static Name inaddr4 = Name.fromConstantString("in-addr.arpa."); - private static Name inaddr6 = Name.fromConstantString("ip6.arpa."); + private static final Name inaddr4 = Name.fromConstantString("in-addr.arpa."); + private static final Name inaddr6 = Name.fromConstantString("ip6.arpa."); /* Otherwise the class could be instantiated */ private ReverseMap() {} @@ -121,8 +121,69 @@ public static Name fromAddress(String addr) throws UnknownHostException { array = Address.toByteArray(addr, Address.IPv6); } if (array == null) { - throw new UnknownHostException("Invalid IP address:" + addr); + throw new UnknownHostException("Invalid IP address: " + addr); } return fromAddress(array); } + + /** + * Parses the address from a reverse map string. + * + * @param name The string from which to build an address. + * @return The address corresponding to the reverse map string. + * @throws UnknownHostException the passed name is not a valid reverse map. + */ + public static InetAddress fromName(String name) throws UnknownHostException, TextParseException { + return fromName(Name.fromString(name)); + } + + /** + * Parses the address from a reverse map name. + * + * @param name The name from which to build an address. + * @return The address corresponding to the reverse map name. + * @throws UnknownHostException the passed name is not a valid reverse map. + */ + public static InetAddress fromName(Name name) throws UnknownHostException { + if (name.labels() <= 3) { + throw new UnknownHostException("Not an arpa address: " + name.toString()); + } + + byte[] ipBytes; + if (name.subdomain(inaddr4)) { + Name ip = name.relativize(inaddr4); + if (ip.labels() > 4) { + throw new UnknownHostException("Invalid IPv4 arpa address: " + name.toString()); + } + + ipBytes = new byte[4]; + try { + for (int i = 0; i < ip.labels(); i++) { + ipBytes[ip.labels() - i - 1] = (byte) Integer.parseInt(ip.getLabelString(i)); + } + } catch (NumberFormatException e) { + throw new UnknownHostException("Invalid IPv4 arpa address: " + name.toString()); + } + return InetAddress.getByAddress(ipBytes); + } else if (name.subdomain(inaddr6)) { + Name ip = name.relativize(inaddr6); + if (ip.labels() > 32) { + throw new UnknownHostException("Invalid IPv6 arpa address: " + name.toString()); + } + + ipBytes = new byte[16]; + try { + for (int i = 0; i < ip.labels(); i++) { + ipBytes[(ip.labels() - i - 1) / 2] |= + Byte.parseByte(ip.getLabelString(i), 16) << ((ip.labels() - i) % 2 == 0 ? 0 : 4); + } + } catch (NumberFormatException e) { + throw new UnknownHostException("Invalid IPv6 arpa address: " + name.toString()); + } + } else { + throw new UnknownHostException("Not an arpa address: " + name.toString()); + } + + return InetAddress.getByAddress(ipBytes); + } } diff --git a/src/test/java/org/xbill/DNS/ReverseMapTest.java b/src/test/java/org/xbill/DNS/ReverseMapTest.java index 09d3213ee..2a67e8fae 100644 --- a/src/test/java/org/xbill/DNS/ReverseMapTest.java +++ b/src/test/java/org/xbill/DNS/ReverseMapTest.java @@ -42,25 +42,26 @@ import org.junit.jupiter.api.Test; class ReverseMapTest { + private final String ipv4Addr = "192.168.0.1"; + private final Name ipv4arpa = Name.fromConstantString("1.0.168.192.in-addr.arpa."); + private final Name ipv6arpa = + Name.fromConstantString( + "4.3.3.7.0.7.3.0.E.2.A.8.9.1.3.1.3.D.8.0.3.A.5.8.8.B.D.0.1.0.0.2.ip6.arpa."); + private final String ipv6addr = "2001:db8:85a3:8d3:1319:8a2e:370:7334"; + @Test - void fromAddress_ipv4() throws UnknownHostException, TextParseException { - Name exp = Name.fromString("1.0.168.192.in-addr.arpa."); - String addr = "192.168.0.1"; - assertEquals(exp, ReverseMap.fromAddress(addr)); + void fromAddress_ipv4() throws UnknownHostException { + assertEquals(ipv4arpa, ReverseMap.fromAddress(ipv4Addr)); - assertEquals(exp, ReverseMap.fromAddress(addr, Address.IPv4)); - assertEquals(exp, ReverseMap.fromAddress(InetAddress.getByName(addr))); + assertEquals(ipv4arpa, ReverseMap.fromAddress(ipv4Addr, Address.IPv4)); + assertEquals(ipv4arpa, ReverseMap.fromAddress(InetAddress.getByName(ipv4Addr))); assertEquals( - exp, ReverseMap.fromAddress(new byte[] {(byte) 192, (byte) 168, (byte) 0, (byte) 1})); - assertEquals(exp, ReverseMap.fromAddress(new int[] {192, 168, 0, 1})); + ipv4arpa, ReverseMap.fromAddress(new byte[] {(byte) 192, (byte) 168, (byte) 0, (byte) 1})); + assertEquals(ipv4arpa, ReverseMap.fromAddress(new int[] {192, 168, 0, 1})); } @Test - void fromAddress_ipv6() throws UnknownHostException, TextParseException { - Name exp = - Name.fromString( - "4.3.3.7.0.7.3.0.E.2.A.8.9.1.3.1.3.D.8.0.3.A.5.8.8.B.D.0.1.0.0.2.ip6.arpa."); - String addr = "2001:0db8:85a3:08d3:1319:8a2e:0370:7334"; + void fromAddress_ipv6() throws UnknownHostException { byte[] dat = new byte[] { (byte) 32, (byte) 1, (byte) 13, (byte) 184, (byte) 133, (byte) 163, (byte) 8, (byte) 211, @@ -68,10 +69,10 @@ void fromAddress_ipv6() throws UnknownHostException, TextParseException { }; int[] idat = new int[] {32, 1, 13, 184, 133, 163, 8, 211, 19, 25, 138, 46, 3, 112, 115, 52}; - assertEquals(exp, ReverseMap.fromAddress(addr, Address.IPv6)); - assertEquals(exp, ReverseMap.fromAddress(InetAddress.getByName(addr))); - assertEquals(exp, ReverseMap.fromAddress(dat)); - assertEquals(exp, ReverseMap.fromAddress(idat)); + assertEquals(ipv6arpa, ReverseMap.fromAddress(ipv6addr, Address.IPv6)); + assertEquals(ipv6arpa, ReverseMap.fromAddress(InetAddress.getByName(ipv6addr))); + assertEquals(ipv6arpa, ReverseMap.fromAddress(dat)); + assertEquals(ipv6arpa, ReverseMap.fromAddress(idat)); } @Test @@ -90,4 +91,38 @@ void fromAddress_invalid() { ReverseMap.fromAddress(dat); }); } + + @Test + void fromName_ipv4_valid() throws TextParseException, UnknownHostException { + assertEquals(ipv4Addr, ReverseMap.fromName(ipv4arpa).getHostAddress()); + assertEquals("192.168.0.0", ReverseMap.fromName("168.192.in-addr.arpa.").getHostAddress()); + } + + @Test + void fromName_ipv6_valid() throws TextParseException, UnknownHostException { + assertEquals(ipv6addr, ReverseMap.fromName(ipv6arpa).getHostAddress()); + assertEquals( + "2001:db8:0:0:0:0:0:0", ReverseMap.fromName("8.B.D.0.1.0.0.2.ip6.arpa.").getHostAddress()); + assertEquals( + "2001:d00:0:0:0:0:0:0", ReverseMap.fromName("D.0.1.0.0.2.ip6.arpa.").getHostAddress()); + assertEquals( + "2001:db0:0:0:0:0:0:0", ReverseMap.fromName("B.D.0.1.0.0.2.ip6.arpa.").getHostAddress()); + } + + @Test + void fromNameInvalid() { + assertThrows(UnknownHostException.class, () -> ReverseMap.fromName("host.example.com.")); + + assertThrows(UnknownHostException.class, () -> ReverseMap.fromName("ip6.arpa.")); + assertThrows(UnknownHostException.class, () -> ReverseMap.fromName("caffee.ip6.arpa.")); + assertThrows( + UnknownHostException.class, + () -> + ReverseMap.fromName( + "1.4.3.3.7.0.7.3.0.E.2.A.8.9.1.3.1.3.D.8.0.3.A.5.8.8.B.D.0.1.0.0.2.ip6.arpa.")); + + assertThrows(UnknownHostException.class, () -> ReverseMap.fromName("in-addr.arpa.")); + assertThrows(UnknownHostException.class, () -> ReverseMap.fromName("caffee.in-addr.arpa.")); + assertThrows(UnknownHostException.class, () -> ReverseMap.fromName("1.2.3.4.5.in-addr.arpa.")); + } } From 5f452a780727fdf904c33d642a1e0c8f98d4383a Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 15 May 2020 21:10:37 +0200 Subject: [PATCH 090/431] Release v3.1.0 --- Changelog | 8 ++++++++ pom.xml | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 9a444781b..69dc8e085 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,11 @@ +05/15/2020 + - 3.1.0 released + - Fix order of OPT and TSIG records in messages (#108) + - Fix RRset.cycle() short overflows (#102) + - Fix race condition in resolver I/O (#104) + - Add support for custom record types + (#94, Klaus Malorny ) + 03/19/2020 - 3.0.2 released - Only select for tcp write when there is something to write diff --git a/pom.xml b/pom.xml index d58d64101..df8bacaa0 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.1.0-SNAPSHOT + 3.1.0 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - HEAD + v3.1.0 From 5425082485580a87fc4a69ff73614be54638e99f Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 15 May 2020 21:18:07 +0200 Subject: [PATCH 091/431] Return to -snapshot --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index df8bacaa0..3388ff49d 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.1.0 + 3.2.0-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.1.0 + HEAD From 7654e1abda96851b90a486316a20a8fd182496bb Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 27 May 2020 22:03:19 +0200 Subject: [PATCH 092/431] Close udp sockets after I/O exceptions Closes #110 --- src/main/java/org/xbill/DNS/NioUdpClient.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/xbill/DNS/NioUdpClient.java b/src/main/java/org/xbill/DNS/NioUdpClient.java index 128631025..2c7df7264 100644 --- a/src/main/java/org/xbill/DNS/NioUdpClient.java +++ b/src/main/java/org/xbill/DNS/NioUdpClient.java @@ -71,13 +71,7 @@ private static void checkTransactionTimeouts() { for (Iterator it = pendingTransactions.iterator(); it.hasNext(); ) { Transaction t = it.next(); if (t.endTime - System.nanoTime() < 0) { - try { - t.channel.disconnect(); - t.channel.close(); - } catch (IOException e) { - // ignore, we timed out already - } - + t.silentCloseChannel(); t.f.completeExceptionally(new SocketTimeoutException("Query timed out")); it.remove(); } @@ -107,6 +101,7 @@ void send() throws IOException { public void processReadyKey(SelectionKey key) { if (!key.isReadable()) { + silentCloseChannel(); f.completeExceptionally(new EOFException("channel not readable")); pendingTransactions.remove(this); return; @@ -121,8 +116,9 @@ public void processReadyKey(SelectionKey key) { throw new EOFException(); } } catch (IOException e) { - pendingTransactions.remove(this); + silentCloseChannel(); f.completeExceptionally(e); + pendingTransactions.remove(this); return; } @@ -134,15 +130,18 @@ public void processReadyKey(SelectionKey key) { channel.socket().getLocalSocketAddress(), channel.socket().getRemoteSocketAddress(), data); + silentCloseChannel(); + f.complete(data); + pendingTransactions.remove(this); + } + + private void silentCloseChannel() { try { channel.disconnect(); channel.close(); } catch (IOException e) { - // ignore, we already have everything we need + // ignore, we either already have everything we need or can't do anything } - - f.complete(data); - pendingTransactions.remove(this); } } From 437c6729d2144cd0b2695ce7b1816c33447a0fe1 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 27 May 2020 22:52:39 +0200 Subject: [PATCH 093/431] Add option to disable default config providers Closes #112 See also #111 --- README.md | 9 +++++ .../java/org/xbill/DNS/ResolverConfig.java | 39 +++++++++++++------ .../org/xbill/DNS/ResolverConfigTest.java | 15 +++++++ 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 45d30f7be..33925c561 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,15 @@ Some settings of dnsjava can be configured via Comma separated key-value pairs, see below. + + dnsjava.configprovider.skipinit + Boolean + false + true + + + Set to true to disable static ResolverConfig initialization. + dnsjava.configprovider.sunjvm.enabled Boolean diff --git a/src/main/java/org/xbill/DNS/ResolverConfig.java b/src/main/java/org/xbill/DNS/ResolverConfig.java index c16c75a31..ba8363979 100644 --- a/src/main/java/org/xbill/DNS/ResolverConfig.java +++ b/src/main/java/org/xbill/DNS/ResolverConfig.java @@ -5,6 +5,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import lombok.extern.slf4j.Slf4j; import org.xbill.DNS.config.AndroidResolverConfigProvider; @@ -41,29 +42,45 @@ */ @Slf4j public final class ResolverConfig { - private List servers = new ArrayList<>(2); - private List searchlist = new ArrayList<>(0); + public static final String CONFIGPROVIDER_SKIP_INIT = "dnsjava.configprovider.skipinit"; + + private final List servers = new ArrayList<>(2); + private final List searchlist = new ArrayList<>(0); private int ndots = 1; private static ResolverConfig currentConfig; private static List configProviders; - static { - configProviders = new ArrayList<>(8); - configProviders.add(new PropertyResolverConfigProvider()); - configProviders.add(new ResolvConfResolverConfigProvider()); - configProviders.add(new WindowsResolverConfigProvider()); - configProviders.add(new AndroidResolverConfigProvider()); - configProviders.add(new JndiContextResolverConfigProvider()); - configProviders.add(new SunJvmResolverConfigProvider()); - refresh(); + private static void checkInitialized() { + if (configProviders == null) { + configProviders = new ArrayList<>(8); + if (!Boolean.getBoolean(CONFIGPROVIDER_SKIP_INIT)) { + configProviders.add(new PropertyResolverConfigProvider()); + configProviders.add(new ResolvConfResolverConfigProvider()); + configProviders.add(new WindowsResolverConfigProvider()); + configProviders.add(new AndroidResolverConfigProvider()); + configProviders.add(new JndiContextResolverConfigProvider()); + configProviders.add(new SunJvmResolverConfigProvider()); + } + } + + if (currentConfig == null) { + refresh(); + } } /** Gets the current configuration */ public static synchronized ResolverConfig getCurrentConfig() { + checkInitialized(); return currentConfig; } + /** Gets the ordered list of resolver config providers. */ + public static synchronized List getConfigProviders() { + checkInitialized(); + return Collections.unmodifiableList(configProviders); + } + /** Set a new ordered list of resolver config providers. */ public static synchronized void setConfigProviders(List providers) { configProviders = new ArrayList<>(providers); diff --git a/src/test/java/org/xbill/DNS/ResolverConfigTest.java b/src/test/java/org/xbill/DNS/ResolverConfigTest.java index efc9760f2..10f6d0414 100644 --- a/src/test/java/org/xbill/DNS/ResolverConfigTest.java +++ b/src/test/java/org/xbill/DNS/ResolverConfigTest.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Field; import java.net.InetSocketAddress; import java.util.Arrays; import org.junit.jupiter.api.Test; @@ -24,6 +25,20 @@ import org.xbill.DNS.config.WindowsResolverConfigProvider; class ResolverConfigTest { + @Test + void testSkipInit() throws Exception { + Field configProvidersField = ResolverConfig.class.getDeclaredField("configProviders"); + configProvidersField.setAccessible(true); + configProvidersField.set(null, null); + try { + System.setProperty(ResolverConfig.CONFIGPROVIDER_SKIP_INIT, Boolean.TRUE.toString()); + assertTrue(ResolverConfig.getConfigProviders().isEmpty()); + } finally { + System.setProperty(ResolverConfig.CONFIGPROVIDER_SKIP_INIT, Boolean.FALSE.toString()); + configProvidersField.set(null, null); + } + } + @Test void properties() { String[] dnsServers = {"192.168.1.1", "192.168.1.2", "192.168.1.1"}; From f9073d9baa8b4859d64f755b65837f74ee68ff50 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 27 May 2020 22:55:00 +0200 Subject: [PATCH 094/431] Expose default timeout See #111 --- src/main/java/org/xbill/DNS/ExtendedResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index d33004cd2..a6168cbff 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -131,7 +131,7 @@ public String toString() { } } - private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(5); + public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(5); private List resolvers = new CopyOnWriteArrayList<>(); private boolean loadBalance; From 0d41028439333a6d8cfdcc05c4df01682c43a66c Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 27 May 2020 23:01:30 +0200 Subject: [PATCH 095/431] Add getters for extended resolver settings See #111 --- src/main/java/org/xbill/DNS/ExtendedResolver.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index a6168cbff..c22ec05ff 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -288,6 +288,11 @@ public void deleteResolver(Resolver r) { resolvers.removeIf(re -> re.resolver == r); } + /** Gets whether the servers receive queries load balanced. */ + public boolean getLoadBalance() { + return loadBalance; + } + /** * Sets whether the servers should be load balanced. * @@ -298,6 +303,11 @@ public void setLoadBalance(boolean flag) { loadBalance = flag; } + /** Gets the number of retries sent to each server per query */ + public int getRetries() { + return retries; + } + /** Sets the number of retries sent to each server per query */ public void setRetries(int retries) { this.retries = retries; From 2138e69b686570bd6d7ee6aeffcc10fefd1482b9 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 27 May 2020 23:19:35 +0200 Subject: [PATCH 096/431] Add getters for resolver properties See #111 --- src/main/java/org/xbill/DNS/Resolver.java | 2 +- .../java/org/xbill/DNS/SimpleResolver.java | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/Resolver.java b/src/main/java/org/xbill/DNS/Resolver.java index 5d0e368f8..0989674dd 100644 --- a/src/main/java/org/xbill/DNS/Resolver.java +++ b/src/main/java/org/xbill/DNS/Resolver.java @@ -29,7 +29,7 @@ public interface Resolver { void setPort(int port); /** - * Sets whether TCP connections will be sent by default + * Sets whether TCP connections will be used by default * * @param flag Indicates whether TCP connections are made */ diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index d338c6db0..0b665b2bc 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -110,6 +110,11 @@ public static void setDefaultResolver(String hostname) { defaultResolver = new InetSocketAddress(hostname, DEFAULT_PORT); } + /** Gets the port to communicate with on the server */ + public int getPort() { + return address.getPort(); + } + @Override public void setPort(int port) { address = new InetSocketAddress(address.getAddress(), port); @@ -151,16 +156,45 @@ public void setLocalAddress(InetAddress addr) { localAddress = new InetSocketAddress(addr, 0); } + /** Gets whether TCP connections will be used by default */ + public boolean getTCP() { + return useTCP; + } + @Override public void setTCP(boolean flag) { this.useTCP = flag; } + /** Gets whether truncated responses will be ignored. */ + public boolean getIgnoreTruncation() { + return ignoreTruncation; + } + @Override public void setIgnoreTruncation(boolean flag) { this.ignoreTruncation = flag; } + /** + * Gets the EDNS information on outgoing messages. + * + * @return The current {@link OPTRecord} for EDNS or {@code null} if EDNS is disabled. + */ + public OPTRecord getEDNS() { + return queryOPT; + } + + /** + * Sets the EDNS information on outgoing messages. + * + * @param optRecord the {@link OPTRecord} for EDNS options or null to disable EDNS. + * @see #setEDNS(int, int, int, List) + */ + public void setEDNS(OPTRecord optRecord) { + queryOPT = optRecord; + } + @Override public void setEDNS(int version, int payloadSize, int flags, List options) { switch (version) { @@ -180,6 +214,15 @@ public void setEDNS(int version, int payloadSize, int flags, List op } } + /** + * Get the TSIG key that messages will be signed with. + * + * @return the TSIG signature for outgoing messages or {@code null} if not specified. + */ + public TSIG getTSIGKey() { + return tsig; + } + @Override public void setTSIGKey(TSIG key) { tsig = key; From 7e72ce00401a443c4871fb50013e529cec99a656 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 27 May 2020 23:36:10 +0200 Subject: [PATCH 097/431] Add fallback property config provider See #111 --- README.md | 8 +++++--- .../java/org/xbill/DNS/ResolverConfig.java | 2 ++ ...allbackPropertyResolverConfigProvider.java | 20 +++++++++++++++++++ .../PropertyResolverConfigProvider.java | 10 +++++++--- 4 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/xbill/DNS/config/FallbackPropertyResolverConfigProvider.java diff --git a/README.md b/README.md index 33925c561..2b37fd93d 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Some settings of dnsjava can be configured via - dns.server + dns[.fallback].server String - 8.8.8.8,[2001:4860:4860::8888]:853,dns.google @@ -64,7 +64,7 @@ Some settings of dnsjava can be configured via DNS server(s) to use for resolving. Comma separated list. Can be IPv4/IPv6 addresses or hostnames (which are resolved using Java's built in DNS support). - dns.search + dns[.fallback].search String - ds.example.com,example.com @@ -73,7 +73,7 @@ Some settings of dnsjava can be configured via Comma separated list of DNS search paths. - dns.ndots + dns[.fallback].ndots Integer 1 2 @@ -245,6 +245,8 @@ until one succeeds. - The `sun.net.dns.ResolverConfiguration` class is queried if enabled. - If available and no servers have been found yet, [JNDI-DNS](https://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-dns.html) is used. +- If still no servers have been found yet, use the fallback properties. This can be used to query + e.g. a well-known public DNS server instead of localhost. - As a last resort, `localhost` is used as the nameserver, and the search path is empty. diff --git a/src/main/java/org/xbill/DNS/ResolverConfig.java b/src/main/java/org/xbill/DNS/ResolverConfig.java index ba8363979..2d3f96f6f 100644 --- a/src/main/java/org/xbill/DNS/ResolverConfig.java +++ b/src/main/java/org/xbill/DNS/ResolverConfig.java @@ -9,6 +9,7 @@ import java.util.List; import lombok.extern.slf4j.Slf4j; import org.xbill.DNS.config.AndroidResolverConfigProvider; +import org.xbill.DNS.config.FallbackPropertyResolverConfigProvider; import org.xbill.DNS.config.InitializationException; import org.xbill.DNS.config.JndiContextResolverConfigProvider; import org.xbill.DNS.config.PropertyResolverConfigProvider; @@ -61,6 +62,7 @@ private static void checkInitialized() { configProviders.add(new AndroidResolverConfigProvider()); configProviders.add(new JndiContextResolverConfigProvider()); configProviders.add(new SunJvmResolverConfigProvider()); + configProviders.add(new FallbackPropertyResolverConfigProvider()); } } diff --git a/src/main/java/org/xbill/DNS/config/FallbackPropertyResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/FallbackPropertyResolverConfigProvider.java new file mode 100644 index 000000000..d8f3e0842 --- /dev/null +++ b/src/main/java/org/xbill/DNS/config/FallbackPropertyResolverConfigProvider.java @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.config; + +/** + * The properties {@link #DNS_FALLBACK_SERVER_PROP}, {@link #DNS_FALLBACK_SEARCH_PROP} (comma + * delimited lists) are checked. The servers can either be IP addresses or hostnames (which are + * resolved using Java's built in DNS support). + * + * @since 3.2 + */ +public class FallbackPropertyResolverConfigProvider extends PropertyResolverConfigProvider { + public static final String DNS_FALLBACK_SERVER_PROP = "dns.fallback.server"; + public static final String DNS_FALLBACK_SEARCH_PROP = "dns.fallback.search"; + public static final String DNS_FALLBACK_NDOTS_PROP = "dns.fallback.ndots"; + + @Override + public void initialize() { + initialize(DNS_FALLBACK_SERVER_PROP, DNS_FALLBACK_SEARCH_PROP, DNS_FALLBACK_NDOTS_PROP); + } +} diff --git a/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java index ea07f6383..6eec5def7 100644 --- a/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java @@ -21,7 +21,11 @@ public class PropertyResolverConfigProvider extends BaseResolverConfigProvider { @Override public void initialize() { - String servers = System.getProperty(DNS_SERVER_PROP); + initialize(DNS_SERVER_PROP, DNS_SEARCH_PROP, DNS_NDOTS_PROP); + } + + protected void initialize(String serverName, String searchName, String ndotsName) { + String servers = System.getProperty(serverName); if (servers != null) { StringTokenizer st = new StringTokenizer(servers, ","); while (st.hasMoreTokens()) { @@ -45,10 +49,10 @@ public void initialize() { } } - String searchPathProperty = System.getProperty(DNS_SEARCH_PROP); + String searchPathProperty = System.getProperty(searchName); parseSearchPathList(searchPathProperty, ","); - String ndotsProperty = System.getProperty(DNS_NDOTS_PROP); + String ndotsProperty = System.getProperty(ndotsName); ndots = parseNdots(ndotsProperty); } From 754af4f9ee5adfab464b067d093504ce47c32de2 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 27 May 2020 23:40:12 +0200 Subject: [PATCH 098/431] Open utility class for implementors See #111 --- .../xbill/DNS/config/BaseResolverConfigProvider.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java index 8f4f1c6d4..c266302ef 100644 --- a/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java @@ -15,12 +15,12 @@ * Base class for resolver config providers that provides a default implementation for the lists and * utility methods to prevent duplicates. */ -abstract class BaseResolverConfigProvider implements ResolverConfigProvider { +public abstract class BaseResolverConfigProvider implements ResolverConfigProvider { final Logger log = LoggerFactory.getLogger(getClass()); List nameservers = new ArrayList<>(3); List searchlist = new ArrayList<>(1); - void parseSearchPathList(String search, String delimiter) { + protected void parseSearchPathList(String search, String delimiter) { if (search != null) { StringTokenizer st = new StringTokenizer(search, delimiter); while (st.hasMoreTokens()) { @@ -29,7 +29,7 @@ void parseSearchPathList(String search, String delimiter) { } } - void addSearchPath(String searchPath) { + protected void addSearchPath(String searchPath) { if (searchPath == null || searchPath.isEmpty()) { return; } @@ -45,14 +45,14 @@ void addSearchPath(String searchPath) { } } - void addNameserver(InetSocketAddress server) { + protected void addNameserver(InetSocketAddress server) { if (!nameservers.contains(server)) { nameservers.add(server); log.debug("Added {} to nameservers", server); } } - int parseNdots(String token) { + protected int parseNdots(String token) { if (token != null && !token.isEmpty()) { try { int ndots = Integer.parseInt(token); From 7c5400a425de13410b5f321efdb2d786136cfddd Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 27 May 2020 23:58:10 +0200 Subject: [PATCH 099/431] Add javadoc version attributes for changes since v3.0 --- .../java/org/xbill/DNS/ExtendedResolver.java | 13 ++++++++-- src/main/java/org/xbill/DNS/Mnemonic.java | 2 ++ src/main/java/org/xbill/DNS/Record.java | 25 ++++++++++++++++--- .../java/org/xbill/DNS/ResolverConfig.java | 1 + src/main/java/org/xbill/DNS/ReverseMap.java | 2 ++ .../java/org/xbill/DNS/SimpleResolver.java | 21 +++++++++++++--- src/main/java/org/xbill/DNS/Type.java | 1 + .../config/BaseResolverConfigProvider.java | 2 ++ 8 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index c22ec05ff..e587b1b3e 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -131,6 +131,7 @@ public String toString() { } } + /** @since 3.2 */ public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(5); private List resolvers = new CopyOnWriteArrayList<>(); @@ -288,7 +289,11 @@ public void deleteResolver(Resolver r) { resolvers.removeIf(re -> re.resolver == r); } - /** Gets whether the servers receive queries load balanced. */ + /** + * Gets whether the servers receive queries load balanced. + * + * @since 3.2 + */ public boolean getLoadBalance() { return loadBalance; } @@ -303,7 +308,11 @@ public void setLoadBalance(boolean flag) { loadBalance = flag; } - /** Gets the number of retries sent to each server per query */ + /** + * Gets the number of retries sent to each server per query. + * + * @since 3.2 + */ public int getRetries() { return retries; } diff --git a/src/main/java/org/xbill/DNS/Mnemonic.java b/src/main/java/org/xbill/DNS/Mnemonic.java index 140b83cf6..a09bf912d 100644 --- a/src/main/java/org/xbill/DNS/Mnemonic.java +++ b/src/main/java/org/xbill/DNS/Mnemonic.java @@ -104,6 +104,7 @@ public void add(int val, String str) { * Removes both the numeric value and its text representation, including all aliases. * * @param val The numeric value + * @since 3.1 */ public void remove(int val) { values.remove(val); @@ -127,6 +128,7 @@ public void addAlias(int val, String str) { * Removes an additional text representation of a numeric value. * * @param str The text string + * @since 3.1 */ public void removeAlias(String str) { str = sanitize(str); diff --git a/src/main/java/org/xbill/DNS/Record.java b/src/main/java/org/xbill/DNS/Record.java index 5f9f15dcc..888f3b836 100644 --- a/src/main/java/org/xbill/DNS/Record.java +++ b/src/main/java/org/xbill/DNS/Record.java @@ -28,6 +28,7 @@ public abstract class Record implements Cloneable, Comparable { protected Record() {} + /** @since 3.1 */ protected Record(Name name, int type, int dclass, long ttl) { if (!name.isAbsolute()) { throw new RelativeNameException(name); @@ -60,7 +61,11 @@ private static Record getEmptyRecord(Name name, int type, int dclass, long ttl, return rec; } - /** Converts the type-specific RR to wire format - must be overridden */ + /** + * Converts the type-specific RR to wire format - must be overridden + * + * @since 3.1 + */ protected abstract void rrFromWire(DNSInput in) throws IOException; private static Record newRecord( @@ -261,7 +266,11 @@ public byte[] rdataToWireCanonical() { return out.toByteArray(); } - /** Converts the type-specific RR to text format - must be overriden */ + /** + * Converts the type-specific RR to text format - must be overriden. + * + * @since 3.1 + */ protected abstract String rrToString(); /** Converts the rdata portion of a Record into a String representation */ @@ -300,7 +309,11 @@ public String toString() { return sb.toString(); } - /** Converts the text format of an RR to the internal format - must be overriden */ + /** + * Converts the text format of an RR to the internal format - must be overriden + * + * @since 3.1 + */ protected abstract void rdataFromString(Tokenizer st, Name origin) throws IOException; /** Converts a String into a byte array. */ @@ -503,7 +516,11 @@ public long getTTL() { return ttl; } - /** Converts the type-specific RR to wire format - must be overriden */ + /** + * Converts the type-specific RR to wire format - must be overriden + * + * @since 3.1 + */ protected abstract void rrToWire(DNSOutput out, Compression c, boolean canonical); /** diff --git a/src/main/java/org/xbill/DNS/ResolverConfig.java b/src/main/java/org/xbill/DNS/ResolverConfig.java index 2d3f96f6f..fde0f3006 100644 --- a/src/main/java/org/xbill/DNS/ResolverConfig.java +++ b/src/main/java/org/xbill/DNS/ResolverConfig.java @@ -43,6 +43,7 @@ */ @Slf4j public final class ResolverConfig { + /** @since 3.2 */ public static final String CONFIGPROVIDER_SKIP_INIT = "dnsjava.configprovider.skipinit"; private final List servers = new ArrayList<>(2); diff --git a/src/main/java/org/xbill/DNS/ReverseMap.java b/src/main/java/org/xbill/DNS/ReverseMap.java index 528157bc8..a50bb81e5 100644 --- a/src/main/java/org/xbill/DNS/ReverseMap.java +++ b/src/main/java/org/xbill/DNS/ReverseMap.java @@ -132,6 +132,7 @@ public static Name fromAddress(String addr) throws UnknownHostException { * @param name The string from which to build an address. * @return The address corresponding to the reverse map string. * @throws UnknownHostException the passed name is not a valid reverse map. + * @since 3.1 */ public static InetAddress fromName(String name) throws UnknownHostException, TextParseException { return fromName(Name.fromString(name)); @@ -143,6 +144,7 @@ public static InetAddress fromName(String name) throws UnknownHostException, Tex * @param name The name from which to build an address. * @return The address corresponding to the reverse map name. * @throws UnknownHostException the passed name is not a valid reverse map. + * @since 3.1 */ public static InetAddress fromName(Name name) throws UnknownHostException { if (name.labels() <= 3) { diff --git a/src/main/java/org/xbill/DNS/SimpleResolver.java b/src/main/java/org/xbill/DNS/SimpleResolver.java index 0b665b2bc..6a71eef57 100644 --- a/src/main/java/org/xbill/DNS/SimpleResolver.java +++ b/src/main/java/org/xbill/DNS/SimpleResolver.java @@ -110,7 +110,11 @@ public static void setDefaultResolver(String hostname) { defaultResolver = new InetSocketAddress(hostname, DEFAULT_PORT); } - /** Gets the port to communicate with on the server */ + /** + * Gets the port to communicate with on the server + * + * @since 3.2 + */ public int getPort() { return address.getPort(); } @@ -156,7 +160,11 @@ public void setLocalAddress(InetAddress addr) { localAddress = new InetSocketAddress(addr, 0); } - /** Gets whether TCP connections will be used by default */ + /** + * Gets whether TCP connections will be used by default + * + * @since 3.2 + */ public boolean getTCP() { return useTCP; } @@ -166,7 +174,11 @@ public void setTCP(boolean flag) { this.useTCP = flag; } - /** Gets whether truncated responses will be ignored. */ + /** + * Gets whether truncated responses will be ignored. + * + * @since 3.2 + */ public boolean getIgnoreTruncation() { return ignoreTruncation; } @@ -180,6 +192,7 @@ public void setIgnoreTruncation(boolean flag) { * Gets the EDNS information on outgoing messages. * * @return The current {@link OPTRecord} for EDNS or {@code null} if EDNS is disabled. + * @since 3.2 */ public OPTRecord getEDNS() { return queryOPT; @@ -190,6 +203,7 @@ public OPTRecord getEDNS() { * * @param optRecord the {@link OPTRecord} for EDNS options or null to disable EDNS. * @see #setEDNS(int, int, int, List) + * @since 3.2 */ public void setEDNS(OPTRecord optRecord) { queryOPT = optRecord; @@ -218,6 +232,7 @@ public void setEDNS(int version, int payloadSize, int flags, List op * Get the TSIG key that messages will be signed with. * * @return the TSIG signature for outgoing messages or {@code null} if not specified. + * @since 3.2 */ public TSIG getTSIGKey() { return tsig; diff --git a/src/main/java/org/xbill/DNS/Type.java b/src/main/java/org/xbill/DNS/Type.java index 1eab238f1..8c8199086 100644 --- a/src/main/java/org/xbill/DNS/Type.java +++ b/src/main/java/org/xbill/DNS/Type.java @@ -457,6 +457,7 @@ public static void check(int val) { * @param str the textual representation of the record type * @param factory the factory; {@code null} may be used if there is no implementation available. * In this case, records of the type will be represented by the {@link UNKRecord} class + * @since 3.1 */ public static void register(int val, String str, Supplier factory) { types.replace(val, str, factory); diff --git a/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java index c266302ef..b98734efb 100644 --- a/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java @@ -14,6 +14,8 @@ /** * Base class for resolver config providers that provides a default implementation for the lists and * utility methods to prevent duplicates. + * + * @since 3.2 */ public abstract class BaseResolverConfigProvider implements ResolverConfigProvider { final Logger log = LoggerFactory.getLogger(getClass()); From bd3dee20af56ab38bfe761896169264517a8bb91 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 30 May 2020 19:43:30 +0200 Subject: [PATCH 100/431] Improve javadoc --- pom.xml | 8 -------- src/main/java/org/xbill/DNS/ExtendedResolver.java | 10 +++++++--- src/main/java/org/xbill/DNS/Message.java | 15 ++++++--------- src/main/java/org/xbill/DNS/ResolverConfig.java | 6 +++++- src/main/java/org/xbill/DNS/TSIG.java | 2 +- .../config/PropertyResolverConfigProvider.java | 9 +++++++++ 6 files changed, 28 insertions(+), 22 deletions(-) diff --git a/pom.xml b/pom.xml index 3388ff49d..a38f78d37 100644 --- a/pom.xml +++ b/pom.xml @@ -172,14 +172,6 @@ japicmp-maven-plugin 0.14.0 - - - ${project.groupId} - ${project.artifactId} - 3.0.0 - jar - - true true diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index e587b1b3e..90d10c89d 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -131,12 +131,16 @@ public String toString() { } } - /** @since 3.2 */ + /** + * Default timeout until resolving is aborted. + * + * @since 3.2 + */ public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(5); - private List resolvers = new CopyOnWriteArrayList<>(); + private final List resolvers = new CopyOnWriteArrayList<>(); private boolean loadBalance; - private AtomicInteger lbStart = new AtomicInteger(); + private final AtomicInteger lbStart = new AtomicInteger(); private int retries = 3; /** diff --git a/src/main/java/org/xbill/DNS/Message.java b/src/main/java/org/xbill/DNS/Message.java index 2654fd9a0..196e3557b 100644 --- a/src/main/java/org/xbill/DNS/Message.java +++ b/src/main/java/org/xbill/DNS/Message.java @@ -39,25 +39,22 @@ public class Message implements Cloneable { int tsigState; int sig0start; - /* The message was not signed */ + /** The message was not signed */ static final int TSIG_UNSIGNED = 0; - /* The message was signed and verification succeeded */ + /** The message was signed and verification succeeded */ static final int TSIG_VERIFIED = 1; - /* The message was an unsigned message in multiple-message response */ + /** The message was an unsigned message in multiple-message response */ static final int TSIG_INTERMEDIATE = 2; - /* The message was signed and no verification was attempted. */ + /** The message was signed and no verification was attempted. */ static final int TSIG_SIGNED = 3; - /* - * The message was signed and verification failed, or was not signed - * when it should have been. - */ + /** The message was signed and verification failed, or was not signed when it should have been. */ static final int TSIG_FAILED = 4; - private static Record[] emptyRecordArray = new Record[0]; + private static final Record[] emptyRecordArray = new Record[0]; @SuppressWarnings("unchecked") private Message(Header header) { diff --git a/src/main/java/org/xbill/DNS/ResolverConfig.java b/src/main/java/org/xbill/DNS/ResolverConfig.java index fde0f3006..8404b0d31 100644 --- a/src/main/java/org/xbill/DNS/ResolverConfig.java +++ b/src/main/java/org/xbill/DNS/ResolverConfig.java @@ -78,7 +78,11 @@ public static synchronized ResolverConfig getCurrentConfig() { return currentConfig; } - /** Gets the ordered list of resolver config providers. */ + /** + * Gets the ordered list of resolver config providers. + * + * @since 3.2 + */ public static synchronized List getConfigProviders() { checkInitialized(); return Collections.unmodifiableList(configProviders); diff --git a/src/main/java/org/xbill/DNS/TSIG.java b/src/main/java/org/xbill/DNS/TSIG.java index 0782aed82..5099edcca 100644 --- a/src/main/java/org/xbill/DNS/TSIG.java +++ b/src/main/java/org/xbill/DNS/TSIG.java @@ -80,7 +80,7 @@ public static String nameToAlgorithm(Name name) { throw new IllegalArgumentException("Unknown algorithm"); } - /** The default fudge value for outgoing packets. Can be overriden by the tsigfudge option. */ + /** The default fudge value for outgoing packets. Can be overridden by the tsigfudge option. */ public static final Duration FUDGE = Duration.ofSeconds(300); private Name name, alg; diff --git a/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java index 6eec5def7..ab33a6ba8 100644 --- a/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/PropertyResolverConfigProvider.java @@ -24,6 +24,15 @@ public void initialize() { initialize(DNS_SERVER_PROP, DNS_SEARCH_PROP, DNS_NDOTS_PROP); } + /** + * Initializes the servers, search path and ndots setting with from the property names passed as + * the arguments. + * + * @param serverName the property name for the DNS servers + * @param searchName the property name for the search path + * @param ndotsName the property name for the ndots setting + * @since 3.2 + */ protected void initialize(String serverName, String searchName, String ndotsName) { String servers = System.getProperty(serverName); if (servers != null) { From e2259ef8375d9c1abbe70f7fb6ae4ed31a14ebd1 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 30 May 2020 20:49:01 +0200 Subject: [PATCH 101/431] Refactor TSIG handling - Remove duplicate code in generate/verify by adding a parameter for the difference between "full" and "intermediate" signatures. - Handle truncated signatures in streams - Move time validation as per draft-ietf-dnsop-rfc2845bis - Add trace dump of signature input data Closes #109 --- src/main/java/org/xbill/DNS/DNSOutput.java | 4 + src/main/java/org/xbill/DNS/TSIG.java | 509 ++++++++++-------- .../java/org/xbill/DNS/ZoneTransferIn.java | 4 +- src/main/java/org/xbill/DNS/tools/dig.java | 13 +- src/main/java/org/xbill/DNS/tools/jnamed.java | 2 +- src/main/java/org/xbill/DNS/tools/update.java | 2 +- src/main/java/org/xbill/DNS/tools/xfrin.java | 2 +- 7 files changed, 297 insertions(+), 239 deletions(-) diff --git a/src/main/java/org/xbill/DNS/DNSOutput.java b/src/main/java/org/xbill/DNS/DNSOutput.java index 5080237cd..8d37f0eed 100644 --- a/src/main/java/org/xbill/DNS/DNSOutput.java +++ b/src/main/java/org/xbill/DNS/DNSOutput.java @@ -181,4 +181,8 @@ public byte[] toByteArray() { System.arraycopy(array, 0, out, 0, pos); return out; } + + static byte[] toU16(int val) { + return new byte[] {(byte) ((val >>> 8) & 0xFF), (byte) (val & 0xFF)}; + } } diff --git a/src/main/java/org/xbill/DNS/TSIG.java b/src/main/java/org/xbill/DNS/TSIG.java index 5099edcca..85143b36d 100644 --- a/src/main/java/org/xbill/DNS/TSIG.java +++ b/src/main/java/org/xbill/DNS/TSIG.java @@ -3,17 +3,20 @@ package org.xbill.DNS; import java.security.GeneralSecurityException; +import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import lombok.extern.slf4j.Slf4j; import org.xbill.DNS.utils.base64; +import org.xbill.DNS.utils.hexdump; /** * Transaction signature handling. This class generates and verifies TSIG records on messages, which @@ -50,7 +53,7 @@ public class TSIG { /** The domain name representing the HMAC-SHA512 algorithm. */ public static final Name HMAC_SHA512 = Name.fromConstantString("hmac-sha512."); - private static Map algMap; + private static final Map algMap; static { Map out = new HashMap<>(); @@ -69,7 +72,7 @@ public static Name algorithmToName(String alg) { return entry.getKey(); } } - throw new IllegalArgumentException("Unknown algorithm"); + throw new IllegalArgumentException("Unknown algorithm: " + alg); } public static String nameToAlgorithm(Name name) { @@ -77,38 +80,26 @@ public static String nameToAlgorithm(Name name) { if (alg != null) { return alg; } - throw new IllegalArgumentException("Unknown algorithm"); + throw new IllegalArgumentException("Unknown algorithm: " + name); } /** The default fudge value for outgoing packets. Can be overridden by the tsigfudge option. */ public static final Duration FUDGE = Duration.ofSeconds(300); - private Name name, alg; - private Mac hmac; + private final Name alg; + private final Clock clock; + private final Name name; + private final Mac hmac; /** * Verifies the data (computes the secure hash and compares it to the input) * - * @param mac The HMAC generator + * @param expected The expected (locally calculated) signature * @param signature The signature to compare against * @return true if the signature matches, false otherwise */ - private static boolean verify(Mac mac, byte[] signature) { - return verify(mac, signature, false); - } - - /** - * Verifies the data (computes the secure hash and compares it to the input) - * - * @param mac The HMAC generator - * @param signature The signature to compare against - * @param truncation_ok If true, the signature may be truncated; only the number of bytes in the - * provided signature are compared. - * @return true if the signature matches, false otherwise - */ - private static boolean verify(Mac mac, byte[] signature, boolean truncation_ok) { - byte[] expected = mac.doFinal(); - if (truncation_ok && signature.length < expected.length) { + private static boolean verify(byte[] expected, byte[] signature) { + if (signature.length < expected.length) { byte[] truncated = new byte[signature.length]; System.arraycopy(expected, 0, truncated, 0, truncated.length); expected = truncated; @@ -116,15 +107,30 @@ private static boolean verify(Mac mac, byte[] signature, boolean truncation_ok) return Arrays.equals(signature, expected); } - private void init_hmac(String macAlgorithm, SecretKey key) { + private Mac initHmac(String macAlgorithm, SecretKey key) { try { - hmac = Mac.getInstance(macAlgorithm); - hmac.init(key); + Mac mac = Mac.getInstance(macAlgorithm); + mac.init(key); + return mac; } catch (GeneralSecurityException ex) { - throw new IllegalArgumentException("Caught security exception setting up HMAC."); + throw new IllegalArgumentException("Caught security exception setting up HMAC.", ex); } } + /** + * Creates a new TSIG object, which can be used to sign or verify a message. + * + * @param name The name of the shared key. + * @param key The shared key's data represented as a base64 encoded string. + * @throws IllegalArgumentException The key name is an invalid name + * @throws IllegalArgumentException The key data is improperly encoded + * @throws NullPointerException key is null + * @since 3.2 + */ + public TSIG(Name algorithm, Name name, String key) { + this(algorithm, name, Objects.requireNonNull(base64.fromString(key))); + } + /** * Creates a new TSIG key, which can be used to sign or verify a message. * @@ -135,9 +141,10 @@ private void init_hmac(String macAlgorithm, SecretKey key) { public TSIG(Name algorithm, Name name, byte[] keyBytes) { this.name = name; this.alg = algorithm; + this.clock = Clock.systemUTC(); String macAlgorithm = nameToAlgorithm(algorithm); SecretKey key = new SecretKeySpec(keyBytes, macAlgorithm); - init_hmac(macAlgorithm, key); + this.hmac = initHmac(macAlgorithm, key); } /** @@ -148,10 +155,23 @@ public TSIG(Name algorithm, Name name, byte[] keyBytes) { * @param key The shared key. */ public TSIG(Name algorithm, Name name, SecretKey key) { + this(algorithm, name, key, Clock.systemUTC()); + } + + /** + * Creates a new TSIG key, which can be used to sign or verify a message. + * + * @param algorithm The algorithm of the shared key. + * @param name The name of the shared key. + * @param key The shared key. + * @since 3.2 + */ + public TSIG(Name algorithm, Name name, SecretKey key, Clock clock) { this.name = name; this.alg = algorithm; + this.clock = clock; String macAlgorithm = nameToAlgorithm(algorithm); - init_hmac(macAlgorithm, key); + this.hmac = initHmac(macAlgorithm, key); } /** @@ -164,15 +184,17 @@ public TSIG(Name algorithm, Name name, SecretKey key) { public TSIG(Mac mac, Name name) { this.name = name; this.hmac = mac; + this.clock = Clock.systemUTC(); this.alg = algorithmToName(mac.getAlgorithm()); } /** - * Creates a new TSIG key with the hmac-md5 algorithm, which can be used to sign or verify a - * message. + * Creates a new TSIG key with the {@link #HMAC_MD5} algorithm, which can be used to sign or + * verify a message. * * @param name The name of the shared key. * @param key The shared key's data. + * @deprecated Use {@link #TSIG(Name, Name, SecretKey)} to explicitly specify an algorithm. */ public TSIG(Name name, byte[] key) { this(HMAC_MD5, name, key); @@ -197,8 +219,9 @@ public TSIG(Name algorithm, String name, String key) { throw new IllegalArgumentException("Invalid TSIG key name"); } this.alg = algorithm; + this.clock = Clock.systemUTC(); String macAlgorithm = nameToAlgorithm(this.alg); - init_hmac(macAlgorithm, new SecretKeySpec(keyBytes, macAlgorithm)); + this.hmac = initHmac(macAlgorithm, new SecretKeySpec(keyBytes, macAlgorithm)); } /** @@ -216,13 +239,14 @@ public TSIG(String algorithm, String name, String key) { } /** - * Creates a new TSIG object with the hmac-md5 algorithm, which can be used to sign or verify a - * message. + * Creates a new TSIG object with the {@link #HMAC_MD5} algorithm, which can be used to sign or + * verify a message. * * @param name The name of the shared key * @param key The shared key's data, represented as a base64 encoded string. * @throws IllegalArgumentException The key name is an invalid name * @throws IllegalArgumentException The key data is improperly encoded + * @deprecated Use {@link #TSIG(Name, String, String)} to explicitly specify an algorithm. */ public TSIG(String name, String key) { this(HMAC_MD5, name, key); @@ -232,25 +256,22 @@ public TSIG(String name, String key) { * Creates a new TSIG object, which can be used to sign or verify a message. * * @param str The TSIG key, in the form name:secret, name/secret, alg:name:secret, or - * alg/name/secret. If an algorithm is specified, it must be "hmac-md5", "hmac-sha1", or - * "hmac-sha256". + * alg/name/secret. If no algorithm is specified, the default of {@link #HMAC_MD5} is used. * @throws IllegalArgumentException The string does not contain both a name and secret. * @throws IllegalArgumentException The key name is an invalid name * @throws IllegalArgumentException The key data is improperly encoded + * @deprecated Use an explicit constructor */ public static TSIG fromString(String str) { String[] parts = str.split("[:/]", 3); - if (parts.length < 2) { - throw new IllegalArgumentException("Invalid TSIG key specification"); - } - if (parts.length == 3) { - try { + switch (parts.length) { + case 2: + return new TSIG(HMAC_MD5, parts[0], parts[1]); + case 3: return new TSIG(parts[0], parts[1], parts[2]); - } catch (IllegalArgumentException e) { - parts = str.split("[:/]", 2); - } + default: + throw new IllegalArgumentException("Invalid TSIG key specification"); } - return new TSIG(HMAC_MD5, parts[0], parts[1]); } /** @@ -263,19 +284,39 @@ public static TSIG fromString(String str) { * @return The TSIG record to be added to the message */ public TSIGRecord generate(Message m, byte[] b, int error, TSIGRecord old) { + return generate(m, b, error, old, true); + } + + /** + * Generates a TSIG record with a specific error for a message that has been rendered. + * + * @param m The message + * @param b The rendered message + * @param error The error + * @param old If this message is a response, the TSIG from the request + * @param fullSignature {@code true} if this {@link TSIGRecord} is the to be added to the first of + * many messages in a TCP connection and all TSIG variables (rfc2845, 3.4.2.) should be + * included in the signature. {@code false} for subsequent messages with reduced TSIG + * variables set (rfc2845, 4.4.). + * @return The TSIG record to be added to the message + * @since 3.2 + */ + public TSIGRecord generate( + Message m, byte[] b, int error, TSIGRecord old, boolean fullSignature) { Instant timeSigned; - if (error != Rcode.BADTIME) { - timeSigned = Instant.now(); - } else { + if (error == Rcode.BADTIME) { timeSigned = old.getTimeSigned(); + } else { + timeSigned = clock.instant(); } - Duration fudge; + boolean signing = false; - if (error == Rcode.NOERROR || error == Rcode.BADTIME) { + if (error == Rcode.NOERROR || error == Rcode.BADTIME || error == Rcode.BADTRUNC) { signing = true; hmac.reset(); } + Duration fudge; int fudgeOption = Options.intValue("tsigfudge"); if (fudgeOption < 0 || fudgeOption > 0x7FFF) { fudge = FUDGE; @@ -283,54 +324,49 @@ public TSIGRecord generate(Message m, byte[] b, int error, TSIGRecord old) { fudge = Duration.ofSeconds(fudgeOption); } - if (old != null) { - DNSOutput out = new DNSOutput(); - out.writeU16(old.getSignature().length); - if (signing) { - hmac.update(out.toByteArray()); - hmac.update(old.getSignature()); - } + if (old != null && signing) { + hmacAddSignature(hmac, old); } - /* Digest the message */ + // Digest the message if (signing) { + if (log.isTraceEnabled()) { + log.trace(hexdump.dump("TSIG-HMAC rendered message", b)); + } hmac.update(b); } + // rfc2845, 3.4.2 TSIG Variables + // for section 4.4 TSIG on TCP connection: skip name, class, ttl, alg and other DNSOutput out = new DNSOutput(); - name.toWireCanonical(out); - out.writeU16(DClass.ANY); /* class */ - out.writeU32(0); /* ttl */ - alg.toWireCanonical(out); - long time = timeSigned.getEpochSecond(); - int timeHigh = (int) (time >> 32); - long timeLow = time & 0xFFFFFFFFL; - out.writeU16(timeHigh); - out.writeU32(timeLow); - out.writeU16((int) fudge.getSeconds()); - - out.writeU16(error); - out.writeU16(0); /* No other data */ + if (fullSignature) { + name.toWireCanonical(out); + out.writeU16(DClass.ANY); /* class */ + out.writeU32(0); /* ttl */ + alg.toWireCanonical(out); + } - if (signing) { - hmac.update(out.toByteArray()); + writeTsigTimersVariables(timeSigned, fudge, out); + if (fullSignature) { + out.writeU16(error); + out.writeU16(0); /* No other data */ } byte[] signature; if (signing) { - signature = hmac.doFinal(); + byte[] tsigVariables = out.toByteArray(); + if (log.isTraceEnabled()) { + log.trace(hexdump.dump("TSIG-HMAC variables", tsigVariables)); + } + signature = hmac.doFinal(tsigVariables); } else { signature = new byte[0]; } byte[] other = null; if (error == Rcode.BADTIME) { - out = new DNSOutput(); - time = Instant.now().getEpochSecond(); - timeHigh = (int) (time >> 32); - timeLow = time & 0xFFFFFFFFL; - out.writeU16(timeHigh); - out.writeU32(timeLow); + out = new DNSOutput(6); + writeTsigTime(clock.instant(), out); other = out.toByteArray(); } @@ -347,6 +383,16 @@ public TSIGRecord generate(Message m, byte[] b, int error, TSIGRecord old) { other); } + /** + * Generates a TSIG record for a message and adds it to the message + * + * @param m The message + * @param old If this message is a response, the TSIG from the request + */ + public void apply(Message m, TSIGRecord old) { + apply(m, Rcode.NOERROR, old, true); + } + /** * Generates a TSIG record with a specific error for a message and adds it to the message. * @@ -355,78 +401,54 @@ public TSIGRecord generate(Message m, byte[] b, int error, TSIGRecord old) { * @param old If this message is a response, the TSIG from the request */ public void apply(Message m, int error, TSIGRecord old) { - Record r = generate(m, m.toWire(), error, old); - m.addRecord(r, Section.ADDITIONAL); - m.tsigState = Message.TSIG_SIGNED; + apply(m, error, old, true); } /** - * Generates a TSIG record for a message and adds it to the message + * Generates a TSIG record with a specific error for a message and adds it to the message. * * @param m The message * @param old If this message is a response, the TSIG from the request + * @param fullSignature {@code true} if this message is the first of many in a TCP connection and + * all TSIG variables (rfc2845, 3.4.2.) should be included in the signature. {@code false} for + * subsequent messages with reduced TSIG variables set (rfc2845, 4.4.). + * @since 3.2 */ - public void apply(Message m, TSIGRecord old) { - apply(m, Rcode.NOERROR, old); + public void apply(Message m, TSIGRecord old, boolean fullSignature) { + apply(m, Rcode.NOERROR, old, fullSignature); } /** - * Generates a TSIG record for a message and adds it to the message + * Generates a TSIG record with a specific error for a message and adds it to the message. * * @param m The message + * @param error The error * @param old If this message is a response, the TSIG from the request + * @param fullSignature {@code true} if this message is the first of many in a TCP connection and + * all TSIG variables (rfc2845, 3.4.2.) should be included in the signature. {@code false} for + * subsequent messages with reduced TSIG variables set (rfc2845, 4.4.). + * @since 3.2 */ - public void applyStream(Message m, TSIGRecord old, boolean first) { - if (first) { - apply(m, old); - return; - } - Instant timeSigned = Instant.now(); - Duration fudge; - hmac.reset(); - - int fudgeOption = Options.intValue("tsigfudge"); - if (fudgeOption < 0 || fudgeOption > 0x7FFF) { - fudge = FUDGE; - } else { - fudge = Duration.ofSeconds(fudgeOption); - } - - DNSOutput out = new DNSOutput(); - out.writeU16(old.getSignature().length); - hmac.update(out.toByteArray()); - hmac.update(old.getSignature()); - - /* Digest the message */ - hmac.update(m.toWire()); - - out = new DNSOutput(); - long time = timeSigned.getEpochSecond(); - int timeHigh = (int) (time >> 32); - long timeLow = time & 0xFFFFFFFFL; - out.writeU16(timeHigh); - out.writeU32(timeLow); - out.writeU16((int) fudge.getSeconds()); - - hmac.update(out.toByteArray()); - - byte[] signature = hmac.doFinal(); - Record r = - new TSIGRecord( - name, - DClass.ANY, - 0, - alg, - timeSigned, - fudge, - signature, - m.getHeader().getID(), - Rcode.NOERROR, - null); + public void apply(Message m, int error, TSIGRecord old, boolean fullSignature) { + Record r = generate(m, m.toWire(), error, old, fullSignature); m.addRecord(r, Section.ADDITIONAL); m.tsigState = Message.TSIG_SIGNED; } + /** + * Generates a TSIG record for a message and adds it to the message + * + * @param m The message + * @param old If this message is a response, the TSIG from the request + * @param fullSignature {@code true} if this message is the first of many in a TCP connection and + * all TSIG variables (rfc2845, 3.4.2.) should be included in the signature. {@code false} for + * subsequent messages with reduced TSIG variables set (rfc2845, 4.4.). + * @deprecated use {@link #apply(Message, TSIGRecord, boolean)} + */ + public void applyStream(Message m, TSIGRecord old, boolean fullSignature) { + apply(m, Rcode.NOERROR, old, fullSignature); + } + /** * Verifies a TSIG record on an incoming message. Since this is only called in the context where a * TSIG is expected to be present, it is an error if one is not present. After calling this @@ -461,76 +483,128 @@ public byte verify(Message m, byte[] b, int length, TSIGRecord old) { * @see Rcode */ public int verify(Message m, byte[] b, TSIGRecord old) { + return verify(m, b, old, true); + } + + /** + * Verifies a TSIG record on an incoming message. Since this is only called in the context where a + * TSIG is expected to be present, it is an error if one is not present. After calling this + * routine, Message.isVerified() may be called on this message. + * + * @param m The message to verify + * @param b An array containing the message in unparsed form. This is necessary since TSIG signs + * the message in wire format, and we can't recreate the exact wire format (with the same name + * compression). + * @param old If this message is a response, the TSIG from the request + * @param fullSignature {@code true} if this message is the first of many in a TCP connection and + * all TSIG variables (rfc2845, 3.4.2.) should be included in the signature. {@code false} for + * subsequent messages with reduced TSIG variables set (rfc2845, 4.4.). + * @return The result of the verification (as an Rcode) + * @see Rcode + * @since 3.2 + */ + public int verify(Message m, byte[] b, TSIGRecord old, boolean fullSignature) { m.tsigState = Message.TSIG_FAILED; TSIGRecord tsig = m.getTSIG(); - hmac.reset(); if (tsig == null) { return Rcode.FORMERR; } if (!tsig.getName().equals(name) || !tsig.getAlgorithm().equals(alg)) { - log.debug("BADKEY failure"); + log.debug( + "BADKEY failure, expected: {}/{}, actual: {}/{}", + name, + alg, + tsig.getName(), + tsig.getAlgorithm()); return Rcode.BADKEY; } - Duration delta = Duration.between(Instant.now(), tsig.getTimeSigned()).abs(); - if (delta.compareTo(tsig.getFudge()) > 0) { - log.debug("BADTIME failure"); - return Rcode.BADTIME; - } + hmac.reset(); if (old != null && tsig.getError() != Rcode.BADKEY && tsig.getError() != Rcode.BADSIG) { - DNSOutput out = new DNSOutput(); - out.writeU16(old.getSignature().length); - hmac.update(out.toByteArray()); - hmac.update(old.getSignature()); + hmacAddSignature(hmac, old); } + m.getHeader().decCount(Section.ADDITIONAL); byte[] header = m.getHeader().toWire(); m.getHeader().incCount(Section.ADDITIONAL); + if (log.isTraceEnabled()) { + log.trace(hexdump.dump("TSIG-HMAC header", header)); + } hmac.update(header); int len = m.tsigstart - header.length; + if (log.isTraceEnabled()) { + log.trace(hexdump.dump("TSIG-HMAC message after header", b, header.length, len)); + } hmac.update(b, header.length, len); DNSOutput out = new DNSOutput(); - tsig.getName().toWireCanonical(out); - out.writeU16(tsig.dclass); - out.writeU32(tsig.ttl); - tsig.getAlgorithm().toWireCanonical(out); - long time = tsig.getTimeSigned().getEpochSecond(); - int timeHigh = (int) (time >> 32); - long timeLow = time & 0xFFFFFFFFL; - out.writeU16(timeHigh); - out.writeU32(timeLow); - out.writeU16((int) tsig.getFudge().getSeconds()); - out.writeU16(tsig.getError()); - if (tsig.getOther() != null) { - out.writeU16(tsig.getOther().length); - out.writeByteArray(tsig.getOther()); - } else { - out.writeU16(0); + if (fullSignature) { + tsig.getName().toWireCanonical(out); + out.writeU16(tsig.dclass); + out.writeU32(tsig.ttl); + tsig.getAlgorithm().toWireCanonical(out); + } + writeTsigTimersVariables(tsig.getTimeSigned(), tsig.getFudge(), out); + if (fullSignature) { + out.writeU16(tsig.getError()); + if (tsig.getOther() != null) { + out.writeU16(tsig.getOther().length); + out.writeByteArray(tsig.getOther()); + } else { + out.writeU16(0); + } } - hmac.update(out.toByteArray()); + byte[] tsigVariables = out.toByteArray(); + if (log.isTraceEnabled()) { + log.trace(hexdump.dump("TSIG-HMAC variables", tsigVariables)); + } + hmac.update(tsigVariables); byte[] signature = tsig.getSignature(); int digestLength = hmac.getMacLength(); - int minDigestLength; - if (hmac.getAlgorithm().toLowerCase().contains("md5")) { - minDigestLength = 10; - } else { - minDigestLength = digestLength / 2; - } + // rfc4635#section-3.1, 4.: + // "MAC size" field is less than the larger of 10 (octets) and half + // the length of the hash function in use + int minDigestLength = Math.max(10, digestLength / 2); if (signature.length > digestLength) { - log.debug("BADSIG: signature too long"); + log.debug( + "BADSIG: signature too long, expected: {}, actual: {}", digestLength, signature.length); return Rcode.BADSIG; } else if (signature.length < minDigestLength) { - log.debug("BADSIG: signature too short"); - return Rcode.BADSIG; - } else if (!verify(hmac, signature, true)) { - log.debug("BADSIG: signature verification"); + log.debug( + "BADSIG: signature too short, expected: {} of {}, actual: {}", + minDigestLength, + digestLength, + signature.length); return Rcode.BADSIG; + } else { + byte[] expectedSignature = hmac.doFinal(); + if (!verify(expectedSignature, signature)) { + if (log.isDebugEnabled()) { + log.debug( + "BADSIG: signature verification failed, expected: {}, actual: {}", + base64.toString(expectedSignature), + base64.toString(signature)); + } + return Rcode.BADSIG; + } + } + + // validate time after the signature, as per + // https://tools.ietf.org/html/draft-ietf-dnsop-rfc2845bis-08#section-5.4.3 + Instant now = clock.instant(); + Duration delta = Duration.between(now, tsig.getTimeSigned()).abs(); + if (delta.compareTo(tsig.getFudge()) > 0) { + log.debug( + "BADTIME failure, now {} +/- tsig {} > fudge {}", + now, + tsig.getTimeSigned(), + tsig.getFudge()); + return Rcode.BADTIME; } m.tsigState = Message.TSIG_VERIFIED; @@ -552,21 +626,43 @@ public int recordLength() { + 8; // 2 byte error length, 6 byte max error field. } + private static void hmacAddSignature(Mac hmac, TSIGRecord tsig) { + byte[] signatureSize = DNSOutput.toU16(tsig.getSignature().length); + if (log.isTraceEnabled()) { + log.trace(hexdump.dump("TSIG-HMAC signature size", signatureSize)); + log.trace(hexdump.dump("TSIG-HMAC signature", tsig.getSignature())); + } + + hmac.update(signatureSize); + hmac.update(tsig.getSignature()); + } + + private static void writeTsigTimersVariables(Instant instant, Duration fudge, DNSOutput out) { + writeTsigTime(instant, out); + out.writeU16((int) fudge.getSeconds()); + } + + private static void writeTsigTime(Instant instant, DNSOutput out) { + long time = instant.getEpochSecond(); + int timeHigh = (int) (time >> 32); + long timeLow = time & 0xFFFFFFFFL; + out.writeU16(timeHigh); + out.writeU32(timeLow); + } + public static class StreamVerifier { /** A helper class for verifying multiple message responses. */ - private TSIG key; + private final TSIG key; - private Mac verifier; private int nresponses; private int lastsigned; private TSIGRecord lastTSIG; /** Creates an object to verify a multiple message response */ - public StreamVerifier(TSIG tsig, TSIGRecord old) { + public StreamVerifier(TSIG tsig, TSIGRecord queryTsig) { key = tsig; - verifier = tsig.hmac; nresponses = 0; - lastTSIG = old; + lastTSIG = queryTsig; } /** @@ -583,80 +679,29 @@ public int verify(Message m, byte[] b) { TSIGRecord tsig = m.getTSIG(); nresponses++; - if (nresponses == 1) { int result = key.verify(m, b, lastTSIG); - if (result == Rcode.NOERROR) { - byte[] signature = tsig.getSignature(); - DNSOutput out = new DNSOutput(); - out.writeU16(signature.length); - verifier.update(out.toByteArray()); - verifier.update(signature); - } lastTSIG = tsig; return result; } if (tsig != null) { - m.getHeader().decCount(Section.ADDITIONAL); - } - byte[] header = m.getHeader().toWire(); - if (tsig != null) { - m.getHeader().incCount(Section.ADDITIONAL); - } - verifier.update(header); - - int len; - if (tsig == null) { - len = b.length - header.length; - } else { - len = m.tsigstart - header.length; - } - verifier.update(b, header.length, len); - - if (tsig != null) { + int result = key.verify(m, b, lastTSIG, false); lastsigned = nresponses; lastTSIG = tsig; + return result; } else { boolean required = nresponses - lastsigned >= 100; if (required) { + log.debug("FORMERR: missing required signature on {}th message", nresponses); m.tsigState = Message.TSIG_FAILED; return Rcode.FORMERR; } else { + log.trace("Intermediate message {} without signature", nresponses); m.tsigState = Message.TSIG_INTERMEDIATE; return Rcode.NOERROR; } } - - if (!tsig.getName().equals(key.name) || !tsig.getAlgorithm().equals(key.alg)) { - log.debug("BADKEY failure"); - m.tsigState = Message.TSIG_FAILED; - return Rcode.BADKEY; - } - - DNSOutput out = new DNSOutput(); - long time = tsig.getTimeSigned().getEpochSecond(); - int timeHigh = (int) (time >> 32); - long timeLow = time & 0xFFFFFFFFL; - out.writeU16(timeHigh); - out.writeU32(timeLow); - out.writeU16((int) tsig.getFudge().getSeconds()); - verifier.update(out.toByteArray()); - - if (!TSIG.verify(verifier, tsig.getSignature())) { - log.debug("BADSIG failure"); - m.tsigState = Message.TSIG_FAILED; - return Rcode.BADSIG; - } - - verifier.reset(); - out = new DNSOutput(); - out.writeU16(tsig.getSignature().length); - verifier.update(out.toByteArray()); - verifier.update(tsig.getSignature()); - - m.tsigState = Message.TSIG_VERIFIED; - return Rcode.NOERROR; } } } diff --git a/src/main/java/org/xbill/DNS/ZoneTransferIn.java b/src/main/java/org/xbill/DNS/ZoneTransferIn.java index d2d8d0237..26afc92bf 100644 --- a/src/main/java/org/xbill/DNS/ZoneTransferIn.java +++ b/src/main/java/org/xbill/DNS/ZoneTransferIn.java @@ -499,11 +499,9 @@ private void doxfr() throws IOException, ZoneTransferException { byte[] in = client.recv(); Message response = parseMessage(in); if (response.getHeader().getRcode() == Rcode.NOERROR && verifier != null) { - TSIGRecord tsigrec = response.getTSIG(); - int error = verifier.verify(response, in); if (error != Rcode.NOERROR) { - fail("TSIG failure"); + fail("TSIG failure: " + Rcode.TSIGstring(error)); } } diff --git a/src/main/java/org/xbill/DNS/tools/dig.java b/src/main/java/org/xbill/DNS/tools/dig.java index a7fc18766..aecc10b7b 100644 --- a/src/main/java/org/xbill/DNS/tools/dig.java +++ b/src/main/java/org/xbill/DNS/tools/dig.java @@ -148,7 +148,18 @@ public static void main(String[] argv) throws IOException { } else { key = argv[++arg]; } - res.setTSIGKey(TSIG.fromString(key)); + + String[] parts = key.split("[:/]", 3); + switch (parts.length) { + case 2: + res.setTSIGKey(new TSIG(TSIG.HMAC_MD5, parts[0], parts[1])); + break; + case 3: + res.setTSIGKey(new TSIG(parts[0], parts[1], parts[2])); + break; + default: + throw new IllegalArgumentException("Invalid TSIG key specification"); + } break; case 't': diff --git a/src/main/java/org/xbill/DNS/tools/jnamed.java b/src/main/java/org/xbill/DNS/tools/jnamed.java index b56e68abc..1fe49131b 100644 --- a/src/main/java/org/xbill/DNS/tools/jnamed.java +++ b/src/main/java/org/xbill/DNS/tools/jnamed.java @@ -388,7 +388,7 @@ byte[] doAXFR(Name name, Message query, TSIG tsig, TSIGRecord qtsig, Socket s) { header.setFlag(Flags.AA); addRRset(rrset.getName(), response, rrset, Section.ANSWER, FLAG_DNSSECOK); if (tsig != null) { - tsig.applyStream(response, qtsig, first); + tsig.apply(response, qtsig, first); qtsig = response.getTSIG(); } first = false; diff --git a/src/main/java/org/xbill/DNS/tools/update.java b/src/main/java/org/xbill/DNS/tools/update.java index 3fc51c583..34b6fa010 100644 --- a/src/main/java/org/xbill/DNS/tools/update.java +++ b/src/main/java/org/xbill/DNS/tools/update.java @@ -126,7 +126,7 @@ public update(InputStream in) { if (res == null) { res = new SimpleResolver(server); } - res.setTSIGKey(new TSIG(keyname, keydata)); + res.setTSIGKey(new TSIG(TSIG.HMAC_MD5, keyname, keydata)); break; case "edns": if (res == null) { diff --git a/src/main/java/org/xbill/DNS/tools/xfrin.java b/src/main/java/org/xbill/DNS/tools/xfrin.java index 8432d4bce..84df74aa3 100644 --- a/src/main/java/org/xbill/DNS/tools/xfrin.java +++ b/src/main/java/org/xbill/DNS/tools/xfrin.java @@ -43,7 +43,7 @@ public static void main(String[] args) throws Exception { if (index < 0) { usage("invalid key"); } - key = new TSIG(s.substring(0, index), s.substring(index + 1)); + key = new TSIG(TSIG.HMAC_MD5, s.substring(0, index), s.substring(index + 1)); } else if (args[arg].equals("-s")) { server = args[++arg]; } else if (args[arg].equals("-p")) { From 4230f59c0bd3efa10738888511971e664ffe3042 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Thu, 4 Jun 2020 22:04:01 +0200 Subject: [PATCH 102/431] IPv4 site-local addresses are normal, do not ignore them --- .../org/xbill/DNS/config/WindowsResolverConfigProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java index de835c5d2..778a24701 100644 --- a/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java @@ -16,6 +16,7 @@ import com.sun.jna.platform.win32.Win32Exception; import com.sun.jna.platform.win32.WinError; import com.sun.jna.ptr.IntByReference; +import java.net.Inet4Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; @@ -75,7 +76,7 @@ public void initialize() throws InitializationException { InetAddress address; try { address = dns.Address.toAddress(); - if (!address.isSiteLocalAddress()) { + if (address instanceof Inet4Address || !address.isSiteLocalAddress()) { addNameserver(new InetSocketAddress(address, SimpleResolver.DEFAULT_PORT)); } else { log.debug( From eed126653923b249d8b10aec4d4573bd98699a60 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 6 Jun 2020 13:38:45 +0200 Subject: [PATCH 103/431] Explicitly reference required classes in class init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to JLS §12.3, resolution of references in the Constant Pool can be lazy. Some classloaders like Spring Boot make use of this and would pass the NoClassDefFound check during construction, but fail later. See #112 --- .../DNS/config/JndiContextResolverConfigProvider.java | 8 +++++++- .../xbill/DNS/config/WindowsResolverConfigProvider.java | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java index 6e15a1a68..c3b51da1a 100644 --- a/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/JndiContextResolverConfigProvider.java @@ -34,7 +34,13 @@ public JndiContextResolverConfigProvider() { } } - private static class InnerJndiContextResolverConfigProvider extends BaseResolverConfigProvider { + @Slf4j + private static final class InnerJndiContextResolverConfigProvider + extends BaseResolverConfigProvider { + static { + log.debug("JNDI class: {}", DirContext.class.getName()); + } + public void initialize() { Hashtable env = new Hashtable<>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); diff --git a/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java index 778a24701..1bf17ba6a 100644 --- a/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/WindowsResolverConfigProvider.java @@ -47,7 +47,14 @@ public WindowsResolverConfigProvider() { } @Slf4j - private static class InnerWindowsResolverConfigProvider extends BaseResolverConfigProvider { + private static final class InnerWindowsResolverConfigProvider extends BaseResolverConfigProvider { + static { + log.debug( + "Checking for JNA classes: {} and {}", + Memory.class.getName(), + Win32Exception.class.getName()); + } + public void initialize() throws InitializationException { // The recommended method of calling the GetAdaptersAddresses function is to pre-allocate a // 15KB working buffer From 7c526afedc21dbb51198ed1ce8ad9f29fbb4e4e0 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 6 Jun 2020 15:41:50 +0200 Subject: [PATCH 104/431] Make use of BaseResolverConfigProvider in all built-ins This also removes the limitation to 3 nameservers of the resolv.conf reader. We're not bound to the libc limitation, there's no need to restrict the number of server. --- .../config/AndroidResolverConfigProvider.java | 2 +- .../ResolvConfResolverConfigProvider.java | 8 +--- .../config/SunJvmResolverConfigProvider.java | 46 +++---------------- .../org/xbill/DNS/ResolverConfigTest.java | 7 --- 4 files changed, 9 insertions(+), 54 deletions(-) diff --git a/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java index 1242a29bb..e3df40779 100644 --- a/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java @@ -49,7 +49,7 @@ private void initializeNameservers() { for (int i = 1; i <= 4; i++) { String server = SystemProperties.get("net.dns" + i); if (server != null && !server.isEmpty()) { - nameservers.add(new InetSocketAddress(server, SimpleResolver.DEFAULT_PORT)); + addNameserver(new InetSocketAddress(server, SimpleResolver.DEFAULT_PORT)); } } } diff --git a/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java index 54709893b..c63e3ea7d 100644 --- a/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/ResolvConfResolverConfigProvider.java @@ -49,7 +49,7 @@ protected void parseResolvConf(InputStream in) throws IOException { switch (st.nextToken()) { case "nameserver": - addServer(st.nextToken()); + addNameserver(new InetSocketAddress(st.nextToken(), SimpleResolver.DEFAULT_PORT)); break; case "domain": @@ -110,12 +110,6 @@ protected void parseResolvConf(InputStream in) throws IOException { } } - private void addServer(String server) { - if (nameservers.size() < 3) { - addNameserver(new InetSocketAddress(server, SimpleResolver.DEFAULT_PORT)); - } - } - @Override public int ndots() { return ndots; diff --git a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java index 9a6dead07..62ff635ef 100644 --- a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java @@ -1,14 +1,10 @@ // SPDX-License-Identifier: BSD-2-Clause package org.xbill.DNS.config; -import static java.util.stream.Collectors.toList; import java.lang.reflect.Method; import java.net.InetSocketAddress; -import java.util.Collections; import java.util.List; -import org.xbill.DNS.Name; -import org.xbill.DNS.TextParseException; /** * Resolver config provider that queries the traditional class {@code @@ -17,10 +13,7 @@ *

As of Java 9, this generates an illegal reflective access exception and on Windows, this may * return invalid nameservers of disconnected NICs. */ -public class SunJvmResolverConfigProvider implements ResolverConfigProvider { - private List nameservers = null; - private List searchlist = null; - +public class SunJvmResolverConfigProvider extends BaseResolverConfigProvider { public void initialize() throws InitializationException { try { Class resConfClass = Class.forName("sun.net.dns.ResolverConfiguration"); @@ -30,46 +23,21 @@ public void initialize() throws InitializationException { Method nameserversMethod = resConfClass.getMethod("nameservers"); @SuppressWarnings("unchecked") List jvmNameservers = (List) nameserversMethod.invoke(resConf); - nameservers = - jvmNameservers.stream().map(ns -> new InetSocketAddress(ns, 53)).collect(toList()); + for (String ns : jvmNameservers) { + addNameserver(new InetSocketAddress(ns, 53)); + } Method searchlistMethod = resConfClass.getMethod("searchlist"); @SuppressWarnings("unchecked") List jvmSearchlist = (List) searchlistMethod.invoke(resConf); - searchlist = - jvmSearchlist.stream() - .map( - n -> { - try { - return Name.fromString(n, Name.root); - } catch (TextParseException e) { - throw new IllegalArgumentException(e); - } - }) - .collect(toList()); + for (String n : jvmSearchlist) { + addSearchPath(n); + } } catch (Exception e) { throw new InitializationException(e); } } - @Override - public List servers() { - if (nameservers == null) { - throw new IllegalStateException("not initialized"); - } - - return Collections.unmodifiableList(nameservers); - } - - @Override - public List searchPaths() { - if (searchlist == null) { - throw new IllegalStateException("not initialized"); - } - - return Collections.unmodifiableList(searchlist); - } - @Override public boolean isEnabled() { return Boolean.getBoolean("dnsjava.configprovider.sunjvm.enabled"); diff --git a/src/test/java/org/xbill/DNS/ResolverConfigTest.java b/src/test/java/org/xbill/DNS/ResolverConfigTest.java index 10f6d0414..7c5a4025d 100644 --- a/src/test/java/org/xbill/DNS/ResolverConfigTest.java +++ b/src/test/java/org/xbill/DNS/ResolverConfigTest.java @@ -2,7 +2,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.xbill.DNS.config.PropertyResolverConfigProvider.DNS_NDOTS_PROP; import static org.xbill.DNS.config.PropertyResolverConfigProvider.DNS_SEARCH_PROP; @@ -160,12 +159,6 @@ void jndi() { rc.initialize(); } - @Test - void sunJvmThrowsIfNotInitialized() { - SunJvmResolverConfigProvider rc = new SunJvmResolverConfigProvider(); - assertThrows(IllegalStateException.class, rc::servers); - } - @Test void sunJvm() throws InitializationException { SunJvmResolverConfigProvider rc = new SunJvmResolverConfigProvider(); From e8265eb51dee19655974eef919de58efcc9d9c1d Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 6 Jun 2020 15:51:40 +0200 Subject: [PATCH 105/431] Respect IP version preferences in DNS server list order --- .../config/BaseResolverConfigProvider.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java index b98734efb..fb99a3d59 100644 --- a/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/BaseResolverConfigProvider.java @@ -1,11 +1,13 @@ // SPDX-License-Identifier: BSD-2-Clause package org.xbill.DNS.config; +import java.net.Inet4Address; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.StringTokenizer; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xbill.DNS.Name; @@ -18,8 +20,11 @@ * @since 3.2 */ public abstract class BaseResolverConfigProvider implements ResolverConfigProvider { + private static final boolean ipv4only = Boolean.getBoolean("java.net.preferIPv4Stack"); + private static final boolean ipv6first = Boolean.getBoolean("java.net.preferIPv6Addresses"); + + private final List nameservers = new ArrayList<>(3); final Logger log = LoggerFactory.getLogger(getClass()); - List nameservers = new ArrayList<>(3); List searchlist = new ArrayList<>(1); protected void parseSearchPathList(String search, String delimiter) { @@ -77,6 +82,22 @@ protected int parseNdots(String token) { @Override public final List servers() { + if (ipv6first) { + // prefer IPv6: return IPv6 first, then IPv4 (each in the order added) + return nameservers.stream() + .sorted( + (a, b) -> + Integer.compare( + b.getAddress().getAddress().length, a.getAddress().getAddress().length)) + .collect(Collectors.toList()); + } else if (ipv4only) { + // skip IPv6 addresses + return nameservers.stream() + .filter(isa -> isa.getAddress() instanceof Inet4Address) + .collect(Collectors.toList()); + } + + // neither is specified, return in the order added return Collections.unmodifiableList(nameservers); } From d244bf47e99f5ef47cc2dbb75681bfcf026f2c25 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 6 Jun 2020 17:38:29 +0200 Subject: [PATCH 106/431] Improve query/cache log statements by including type and id --- src/main/java/org/xbill/DNS/Cache.java | 6 +++++- src/main/java/org/xbill/DNS/Lookup.java | 13 ++++++++++--- .../DNS/config/SunJvmResolverConfigProvider.java | 1 - 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Cache.java b/src/main/java/org/xbill/DNS/Cache.java index af7c5d38f..916673151 100644 --- a/src/main/java/org/xbill/DNS/Cache.java +++ b/src/main/java/org/xbill/DNS/Cache.java @@ -729,7 +729,11 @@ public SetResponse addMessage(Message in) { addRRset(rRset, cred); } - log.debug("caching {} for {}", response, in.getQuestion().getName()); + log.debug( + "Caching {} for {}/{}", + response, + in.getQuestion().getName(), + Type.string(in.getQuestion().getType())); return response; } diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index 6385ecfbe..ebdac03c6 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -479,7 +479,7 @@ private void processResponse(Name name, SetResponse response) { private void lookup(Name current) { SetResponse sr = cache.lookupRecords(current, type, credibility); - log.debug("lookup {} {}, cache answer: {}", current, Type.string(type), sr); + log.debug("Lookup for {}/{}, cache answer: {}", current, Type.string(type), sr); processResponse(current, sr); if (done || doneCurrent) { @@ -492,7 +492,13 @@ private void lookup(Name current) { try { response = resolver.send(query); } catch (IOException e) { - log.debug("Lookup failed using resolver {}", resolver, e); + log.debug( + "Lookup for {}/{}, id={} failed using resolver {}", + current, + Type.string(query.getQuestion().getType()), + query.getHeader().getID(), + resolver, + e); // A network error occurred. Press on. if (e instanceof InterruptedIOException) { @@ -523,7 +529,8 @@ private void lookup(Name current) { sr = cache.lookupRecords(current, type, credibility); } - log.debug("Queried {} {}: {}", current, Type.string(type), sr); + log.debug( + "Queried {}/{}, id={}: {}", current, Type.string(type), response.getHeader().getID(), sr); processResponse(current, sr); } diff --git a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java index 62ff635ef..40b40e4b8 100644 --- a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-2-Clause package org.xbill.DNS.config; - import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.util.List; From ee7fbdd5301999c8a5e20a440b9c0f6e4b626330 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 6 Jun 2020 17:45:27 +0200 Subject: [PATCH 107/431] Split overall and individual server timeouts in ExtendedResolver --- .../java/org/xbill/DNS/ExtendedResolver.java | 70 +++++++++++++------ 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index 90d10c89d..0fd2212d7 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -2,6 +2,7 @@ package org.xbill.DNS; +import java.io.IOException; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.time.Duration; @@ -34,9 +35,11 @@ private static class Resolution { private final int retriesPerResolver; private List resolvers; private int currentResolver; + private long endTime; Resolution(ExtendedResolver eres, Message query) { resolvers = new ArrayList<>(eres.resolvers); + endTime = System.nanoTime() + eres.timeout.toNanos(); if (eres.loadBalance) { int start = eres.lbStart.updateAndGet(i -> i++ % resolvers.size()); if (start > 0) { @@ -99,14 +102,26 @@ private Void handle(Message result, Throwable ex, CompletableFuture f) ex.getMessage()); failureCounter.incrementAndGet(); - // go to next resolver, until retries on all resolvers are exhausted - currentResolver = (currentResolver + 1) % resolvers.size(); - if (attempts[currentResolver] < retriesPerResolver) { - send().handleAsync((r, t) -> handle(r, t, f)); - return null; - } - f.completeExceptionally(ex); + if (endTime - System.nanoTime() < 0) { + f.completeExceptionally( + new IOException( + "Timed out while trying to resolve " + + query.getQuestion().getName() + + "/" + + Type.string(query.getQuestion().type) + + ", id=" + + query.getHeader().getID())); + } else { + // go to next resolver, until retries on all resolvers are exhausted + currentResolver = (currentResolver + 1) % resolvers.size(); + if (attempts[currentResolver] < retriesPerResolver) { + send().handleAsync((r, t) -> handle(r, t, f)); + return null; + } + + f.completeExceptionally(ex); + } } else { failureCounter.updateAndGet(i -> i > 0 ? (int) Math.log(i) : 0); f.complete(result); @@ -136,16 +151,25 @@ public String toString() { * * @since 3.2 */ - public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(5); + public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(10); + + /** + * Default timeout until resolving with one of the used resolvers fails. + * + * @since 3.2 + */ + public static final Duration DEFAULT_RESOLVER_TIMEOUT = Duration.ofSeconds(5); private final List resolvers = new CopyOnWriteArrayList<>(); - private boolean loadBalance; private final AtomicInteger lbStart = new AtomicInteger(); + private boolean loadBalance; private int retries = 3; + private Duration timeout = DEFAULT_TIMEOUT; /** * Creates a new Extended Resolver. The default {@link ResolverConfig} is used to determine the - * servers for which {@link SimpleResolver}s are initialized. + * servers for which {@link SimpleResolver}s are initialized. The timeout for each server is + * initialized with {@link #DEFAULT_RESOLVER_TIMEOUT}. */ public ExtendedResolver() { List servers = ResolverConfig.getCurrentConfig().servers(); @@ -154,14 +178,15 @@ public ExtendedResolver() { .map( server -> { Resolver r = new SimpleResolver(server); - r.setTimeout(DEFAULT_TIMEOUT); + r.setTimeout(DEFAULT_RESOLVER_TIMEOUT); return new ResolverEntry(r); }) .collect(Collectors.toSet())); } /** - * Creates a new Extended Resolver + * Creates a new instance with {@link SimpleResolver}s. The timeout for each server is initialized + * with {@link #DEFAULT_RESOLVER_TIMEOUT}. * * @param servers An array of server names or IP addresses for which {@link SimpleResolver}s are * initialized. @@ -175,7 +200,7 @@ public ExtendedResolver(String[] servers) throws UnknownHostException { server -> { try { Resolver r = new SimpleResolver(server); - r.setTimeout(DEFAULT_TIMEOUT); + r.setTimeout(DEFAULT_RESOLVER_TIMEOUT); return new ResolverEntry(r); } catch (UnknownHostException e) { throw new RuntimeException(e); @@ -200,18 +225,16 @@ public ExtendedResolver(Resolver[] resolvers) { } /** - * Creates a new Extended Resolver + * Creates a new {@link ExtendedResolver}. No timeout value is applied to the individual + * resolvers, make sure their timeout is smaller than the timeout of this {@link + * ExtendedResolver}. * * @param resolvers An iterable of pre-initialized {@link Resolver}s. */ public ExtendedResolver(Iterable resolvers) { this.resolvers.addAll( StreamSupport.stream(resolvers.spliterator(), false) - .map( - resolver -> { - resolver.setTimeout(DEFAULT_TIMEOUT); - return new ResolverEntry(resolver); - }) + .map(ResolverEntry::new) .collect(Collectors.toSet())); } @@ -250,11 +273,14 @@ public void setTSIGKey(TSIG key) { } } + @Override + public Duration getTimeout() { + return timeout; + } + @Override public void setTimeout(Duration timeout) { - for (ResolverEntry re : resolvers) { - re.resolver.setTimeout(timeout); - } + this.timeout = timeout; } /** From d89e17e32c5c32b65632e92897f9bcb3cf06b550 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 6 Jun 2020 17:46:12 +0200 Subject: [PATCH 108/431] Keep order of servers when not load-balancing --- src/main/java/org/xbill/DNS/ExtendedResolver.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index 0fd2212d7..28e0dd203 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -8,7 +8,6 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -52,7 +51,6 @@ private static class Resolution { resolvers = shuffle; } } else { - Collections.shuffle(resolvers); resolvers = resolvers.stream() .sorted(Comparator.comparingInt(re -> re.failures.get())) @@ -181,7 +179,7 @@ public ExtendedResolver() { r.setTimeout(DEFAULT_RESOLVER_TIMEOUT); return new ResolverEntry(r); }) - .collect(Collectors.toSet())); + .collect(Collectors.toList())); } /** From 75a750449fdf610da8468b29fb5fc3671feb807b Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 22 Jun 2020 16:29:13 +0200 Subject: [PATCH 109/431] Release v3.2.0 Signed-off-by: Ingo Bauersachs --- Changelog | 10 ++++++++++ pom.xml | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 69dc8e085..ef9ac0f76 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,13 @@ +06/22/2020 + - 3.2.0 released + - Add Javadoc @since tags for APIs introduced since 3.0 + - Fix requiring JNA in certain classloaders (#112) + - Add property to skip initializing builtin resolver config (#112) + - Make ResolverConfig and Resolver API public (#111) + - Add properties for a fallback resolver config provider (#111) + - Close UDP socket on failures (#110) + - Refactor TSIG code and add trace logging (#109) + 05/15/2020 - 3.1.0 released - Fix order of OPT and TSIG records in messages (#108) diff --git a/pom.xml b/pom.xml index a38f78d37..baf952af5 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.2.0-SNAPSHOT + 3.2.0 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - HEAD + v3.2.0 From 1d1468feeaed3fbf4ac7f26453bd0132e6604f79 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 22 Jun 2020 16:47:02 +0200 Subject: [PATCH 110/431] Release v3.2.1 --- Changelog | 4 ++++ pom.xml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index ef9ac0f76..1f49576a6 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ +06/22/2020 + - 3.2.1 released + - Include sources and Javadoc + 06/22/2020 - 3.2.0 released - Add Javadoc @since tags for APIs introduced since 3.0 diff --git a/pom.xml b/pom.xml index baf952af5..348a256f1 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.2.0 + 3.2.1 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.2.0 + v3.2.1 From 2f9a61ceeda45a6206bda95190dd50362e10cbc4 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 22 Jun 2020 16:53:16 +0200 Subject: [PATCH 111/431] Return to -snapshot --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 348a256f1..af3531830 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.2.1 + 3.2.2-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.2.1 + HEAD From 2921ef26784da710a69e4576499971709d927171 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 11 Jul 2020 13:16:31 +0200 Subject: [PATCH 112/431] Fix 32bit mapping of IP_ADAPTER_ADDRESSES_LH --- src/main/java/org/xbill/DNS/config/IPHlpAPI.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/config/IPHlpAPI.java b/src/main/java/org/xbill/DNS/config/IPHlpAPI.java index d39e54635..12d8f57a3 100644 --- a/src/main/java/org/xbill/DNS/config/IPHlpAPI.java +++ b/src/main/java/org/xbill/DNS/config/IPHlpAPI.java @@ -151,6 +151,12 @@ public static class ByReference extends IP_ADAPTER_DNS_SUFFIX public char[] _String = new char[256]; } + @Structure.FieldOrder({"LowPart", "HighPart"}) + class LUID extends Structure { + public int LowPart; + public int HighPart; + } + @Structure.FieldOrder({ "Length", "IfIndex", @@ -228,7 +234,7 @@ public IP_ADAPTER_ADDRESSES_LH() {} public Pointer FirstGatewayAddress; public int Ipv4Metric; public int Ipv6Metric; - public Pointer Luid; + public LUID Luid; public SOCKET_ADDRESS Dhcpv4Server; public int CompartmentId; public Guid.GUID NetworkGuid; From b81c05793a6b101f1287b83542d5e9fa993f8d47 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 11 Jul 2020 11:13:04 +0200 Subject: [PATCH 113/431] Get rid of Zulu --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49ca4650a..292448b2b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,13 +9,13 @@ jobs: strategy: matrix: os: [ ubuntu-16.04, ubuntu-latest, windows-latest ] - java: [ '1.8', '11' ] - arch: [ 'x86', 'x64' ] + java: [ '8', '11' ] + arch: [ 'x32', 'x64' ] exclude: - os: ubuntu-16.04 - arch: x86 + arch: x32 - os: ubuntu-latest - arch: x86 + arch: x32 name: Java ${{ matrix.java }}/${{ matrix.arch }}/${{ matrix.os }} @@ -29,7 +29,7 @@ jobs: key: m2 - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v1 + uses: joschi/setup-jdk@2d2c40de6fb6af3db2a3d2bedd57eb02442521c4 with: java-version: ${{ matrix.java }} architecture: ${{ matrix.arch }} From f7923425e734e4fc51172010072466c8bdbdd99c Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 11 Jul 2020 14:14:00 +0200 Subject: [PATCH 114/431] Ignore internal api in api comparison --- .github/workflows/build.yml | 2 +- pom.xml | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 292448b2b..dd0e81520 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,4 +35,4 @@ jobs: architecture: ${{ matrix.arch }} - name: Build with Maven - run: mvn test jacoco:report -B -"Dgpg.skip" + run: mvn verify -B -"Dgpg.skip" diff --git a/pom.xml b/pom.xml index af3531830..7842ffad7 100644 --- a/pom.xml +++ b/pom.xml @@ -170,21 +170,24 @@ com.github.siom79.japicmp japicmp-maven-plugin - 0.14.0 + 0.14.3 true + public true org.xbill.DNS.spi + + org.xbill.DNS.config.IPHlpAPI check-compatibility - package + verify cmp From 1ca08ae991076787606892f4d7b765b07eb263c2 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 11 Jul 2020 13:57:16 +0200 Subject: [PATCH 115/431] Release v3.2.2 --- Changelog | 5 +++++ README.md | 2 +- pom.xml | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index 1f49576a6..f4dd2895a 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,8 @@ +07/11/2020 + - 3.2.1 released + - Fix JNA access violation in WindowsResolverConfigProvider + on 32bit JVMs + 06/22/2020 - 3.2.1 released - Include sources and Javadoc diff --git a/README.md b/README.md index 2b37fd93d..3f67e582f 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,7 @@ neither source nor binary compatible. The most important changes are: serialization formats: - `toString()`, `rrToString()` <-> `fromString()` - `toWire()` <-> `fromWire()`, `newRecord()` -- `Message` and `Header` properly supported `clone()` +- `Message` and `Header` properly support `clone()` ### Replacing the standard Java DNS functionality diff --git a/pom.xml b/pom.xml index 7842ffad7..b6341f940 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.2.2-SNAPSHOT + 3.2.2 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - HEAD + v3.2.2 From 8265733be7ce88fb8bcc1adabb4ad291b7f11ec4 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 11 Jul 2020 14:23:46 +0200 Subject: [PATCH 116/431] Return to -snapshot --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b6341f940..0ee45abcd 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.2.2 + 3.2.3-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.2.2 + HEAD From 5573276a69cfd16e78c6169e95a19d3a0f35d9e1 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 3 Aug 2020 21:53:07 +0200 Subject: [PATCH 117/431] Run workflow on pull requests --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dd0e81520..1c1319178 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,6 @@ name: dnsjava CI -on: [push] +on: [push, pull_request] jobs: test: From 195cde864a565627f7a124fd412b6b7552b13014 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 8 Aug 2020 15:13:53 +0200 Subject: [PATCH 118/431] Switch master to v3.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0ee45abcd..dc39be945 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.2.3-SNAPSHOT + 3.3.0-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache From 376aabed7eb3ab706b52ee018cf2321117c6bafd Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 8 Aug 2020 17:09:55 +0200 Subject: [PATCH 119/431] Use callback for cmdline dig AXFR for large zones Closes #117 --- src/main/java/org/xbill/DNS/tools/dig.java | 69 +++++++++++----------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/xbill/DNS/tools/dig.java b/src/main/java/org/xbill/DNS/tools/dig.java index aecc10b7b..519c6f548 100644 --- a/src/main/java/org/xbill/DNS/tools/dig.java +++ b/src/main/java/org/xbill/DNS/tools/dig.java @@ -7,58 +7,32 @@ import org.xbill.DNS.ExtendedFlags; import org.xbill.DNS.Message; import org.xbill.DNS.Name; -import org.xbill.DNS.Rcode; import org.xbill.DNS.Record; import org.xbill.DNS.ReverseMap; -import org.xbill.DNS.Section; import org.xbill.DNS.SimpleResolver; import org.xbill.DNS.TSIG; import org.xbill.DNS.Type; +import org.xbill.DNS.WireParseException; +import org.xbill.DNS.ZoneTransferException; +import org.xbill.DNS.ZoneTransferIn; /** @author Brian Wellington <bwelling@xbill.org> */ public class dig { - static Name name = null; static int type = Type.A, dclass = DClass.IN; static void usage() { + System.out.println("; dnsjava dig"); System.out.println("Usage: dig [@server] name [] [] [options]"); System.exit(0); } static void doQuery(Message response, long ms) { - System.out.println("; java dig 0.0"); + System.out.println("; dnsjava dig"); System.out.println(response); System.out.println(";; Query time: " + ms + " ms"); } - static void doAXFR(Message response) { - System.out.println("; java dig 0.0 <> " + name + " axfr"); - if (response.isSigned()) { - System.out.print(";; TSIG "); - if (response.isVerified()) { - System.out.println("ok"); - } else { - System.out.println("failed"); - } - } - - if (response.getRcode() != Rcode.NOERROR) { - System.out.println(response); - return; - } - - for (Record record : response.getSection(Section.ANSWER)) { - System.out.println(record); - } - - System.out.print(";; done ("); - System.out.print(response.getHeader().getCount(Section.ANSWER)); - System.out.print(" records, "); - System.out.print(response.getHeader().getCount(Section.ADDITIONAL)); - System.out.println(" additional)"); - } - public static void main(String[] argv) throws IOException { String server = null; int arg; @@ -215,13 +189,38 @@ public static void main(String[] argv) throws IOException { if (printQuery) { System.out.println(query); } - startTime = System.currentTimeMillis(); - response = res.send(query); - endTime = System.currentTimeMillis(); if (type == Type.AXFR) { - doAXFR(response); + System.out.println("; dnsjava dig <> " + name + " axfr"); + ZoneTransferIn xfrin = ZoneTransferIn.newAXFR(name, res.getAddress(), res.getTSIGKey()); + xfrin.setTimeout(res.getTimeout()); + try { + xfrin.run( + new ZoneTransferIn.ZoneTransferHandler() { + @Override + public void startAXFR() {} + + @Override + public void startIXFR() {} + + @Override + public void startIXFRDeletes(Record soa) {} + + @Override + public void startIXFRAdds(Record soa) {} + + @Override + public void handleRecord(Record r) { + System.out.println(r); + } + }); + } catch (ZoneTransferException e) { + throw new WireParseException(e.getMessage()); + } } else { + startTime = System.currentTimeMillis(); + response = res.send(query); + endTime = System.currentTimeMillis(); doQuery(response, endTime - startTime); } } From 6f379668871fe788c8dfe991aa16a8c54b6857e3 Mon Sep 17 00:00:00 2001 From: adam-stoler <68395423+adam-stoler@users.noreply.github.com> Date: Mon, 17 Aug 2020 16:57:15 -0400 Subject: [PATCH 120/431] Add support for SVCB and HTTPS records (#116) * Initial class structure * Work in progress for implementation, basic tests passing * Add mandatory key type and proper implementation for ipv4hint, echconfig, and ipv6hint * Add support for unknown key types * More tests and error handling cases * Improve naming and code cleanup * Minor fixes based on code review comments * Accessors and initializers for parameter class, more tests and validation code * Add better wire format checking and unit tests for this * Minor fixes and checking for duplicate SvcParam keys in constructor * Add license header comment and comments for the records classes * Addressed code review feedback Ran formatter Used final for private field when possible Added more useful constructors and accessors for Parameter subclasses, such as ones that take in and return List instead of List * Specify UTF_8 when converting to and from bytes for ParameterAlpn * Use US_ASCII charset instead for ParameterAlpn Co-authored-by: Adam Stoler --- src/main/java/org/xbill/DNS/HTTPSRecord.java | 19 + src/main/java/org/xbill/DNS/SVCBBase.java | 753 ++++++++++++++++++ src/main/java/org/xbill/DNS/SVCBRecord.java | 19 + src/main/java/org/xbill/DNS/Type.java | 18 + .../java/org/xbill/DNS/HTTPSRecordTest.java | 121 +++ .../java/org/xbill/DNS/SVCBRecordTest.java | 682 ++++++++++++++++ 6 files changed, 1612 insertions(+) create mode 100644 src/main/java/org/xbill/DNS/HTTPSRecord.java create mode 100644 src/main/java/org/xbill/DNS/SVCBBase.java create mode 100644 src/main/java/org/xbill/DNS/SVCBRecord.java create mode 100644 src/test/java/org/xbill/DNS/HTTPSRecordTest.java create mode 100644 src/test/java/org/xbill/DNS/SVCBRecordTest.java diff --git a/src/main/java/org/xbill/DNS/HTTPSRecord.java b/src/main/java/org/xbill/DNS/HTTPSRecord.java new file mode 100644 index 000000000..01d8a0833 --- /dev/null +++ b/src/main/java/org/xbill/DNS/HTTPSRecord.java @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import java.util.List; + +/** + * HTTPS Service Location and Parameter Binding Record + * + * @see draft-ietf-dnsop-svcb-https + */ +public class HTTPSRecord extends SVCBBase { + HTTPSRecord() {} + + public HTTPSRecord( + Name name, int dclass, long ttl, int priority, Name domain, List params) { + super(name, Type.HTTPS, dclass, ttl, priority, domain, params); + } +} diff --git a/src/main/java/org/xbill/DNS/SVCBBase.java b/src/main/java/org/xbill/DNS/SVCBBase.java new file mode 100644 index 000000000..977670b28 --- /dev/null +++ b/src/main/java/org/xbill/DNS/SVCBBase.java @@ -0,0 +1,753 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +/** Implements common functionality for SVCB and HTTPS records */ +abstract class SVCBBase extends Record { + protected int svcPriority; + protected Name targetName; + protected final Map svcParams; + + public static final int MANDATORY = 0; + public static final int ALPN = 1; + public static final int NO_DEFAULT_ALPN = 2; + public static final int PORT = 3; + public static final int IPV4HINT = 4; + public static final int ECHCONFIG = 5; + public static final int IPV6HINT = 6; + + protected SVCBBase() { + svcParams = new TreeMap<>(); + } + + protected SVCBBase(Name name, int type, int dclass, long ttl) { + super(name, type, dclass, ttl); + svcParams = new TreeMap<>(); + } + + protected SVCBBase( + Name name, + int type, + int dclass, + long ttl, + int priority, + Name domain, + List params) { + super(name, type, dclass, ttl); + svcPriority = priority; + targetName = domain; + svcParams = new TreeMap<>(); + for (ParameterBase param : params) { + if (svcParams.containsKey(param.getKey())) { + throw new IllegalArgumentException("Duplicate SvcParam for key " + param.getKey()); + } + svcParams.put(param.getKey(), param); + } + } + + public int getSvcPriority() { + return svcPriority; + } + + public Name getTargetName() { + return targetName; + } + + public Set getSvcParamKeys() { + return svcParams.keySet(); + } + + public ParameterBase getSvcParamValue(int key) { + return svcParams.get(key); + } + + private static class ParameterMnemonic extends Mnemonic { + private HashMap> factories; + + public ParameterMnemonic() { + super("SVCB/HTTPS Parameters", Mnemonic.CASE_LOWER); + setPrefix("key"); + setNumericAllowed(true); + setMaximum(0xFFFF); + factories = new HashMap<>(); + } + + public void add(int val, String str, Supplier factory) { + super.add(val, str); + factories.put(val, factory); + } + + public Supplier getFactory(int val) { + return factories.get(val); + } + } + + private static final ParameterMnemonic parameters = new ParameterMnemonic(); + + static { + parameters.add(MANDATORY, "mandatory", ParameterMandatory::new); + parameters.add(ALPN, "alpn", ParameterAlpn::new); + parameters.add(NO_DEFAULT_ALPN, "no-default-alpn", ParameterNoDefaultAlpn::new); + parameters.add(PORT, "port", ParameterPort::new); + parameters.add(IPV4HINT, "ipv4hint", ParameterIpv4Hint::new); + parameters.add(ECHCONFIG, "echconfig", ParameterEchConfig::new); + parameters.add(IPV6HINT, "ipv6hint", ParameterIpv6Hint::new); + } + + public abstract static class ParameterBase { + public ParameterBase() {} + + public abstract int getKey(); + + public abstract void fromWire(byte[] bytes) throws IOException; + + public abstract void fromString(String string) throws IOException; + + public abstract byte[] toWire(); + + public abstract String toString(); + + // Split string on commas, but not if comma is escaped with a '\' + public static String[] splitStringWithEscapedCommas(String string) { + return string.split("(? values; + + public ParameterMandatory() { + super(); + values = new ArrayList<>(); + } + + public ParameterMandatory(List values) { + super(); + this.values = values; + } + + public List getValues() { + return values; + } + + @Override + public int getKey() { + return MANDATORY; + } + + @Override + public void fromWire(byte[] bytes) throws IOException { + values.clear(); + DNSInput in = new DNSInput(bytes); + while (in.remaining() >= 2) { + int key = in.readU16(); + values.add(key); + } + if (in.remaining() > 0) { + throw new WireParseException("Unexpected number of bytes in mandatory parameter"); + } + } + + @Override + public void fromString(String string) throws TextParseException { + values.clear(); + if (string == null || string.isEmpty()) { + throw new TextParseException("Non-empty list must be specified for mandatory"); + } + for (String str : splitStringWithEscapedCommas(string)) { + int key = parameters.getValue(str); + if (key == MANDATORY) { + throw new TextParseException("Key mandatory must not appear in its own list"); + } + if (values.contains(key)) { + throw new TextParseException("Duplicate key " + str + " not allowed in mandatory list"); + } + values.add(key); + } + } + + @Override + public byte[] toWire() { + DNSOutput out = new DNSOutput(); + for (Integer val : values) { + out.writeU16(val); + } + return out.toByteArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (Integer val : values) { + if (sb.length() > 0) { + sb.append(","); + } + sb.append(parameters.getText(val)); + } + return sb.toString(); + } + } + + public static class ParameterAlpn extends ParameterBase { + private final List values; + + public ParameterAlpn() { + super(); + values = new ArrayList<>(); + } + + public ParameterAlpn(List values) { + super(); + this.values = + values.stream() + .map(s -> s.getBytes(StandardCharsets.US_ASCII)) + .collect(Collectors.toList()); + } + + public List getValues() { + return values.stream() + .map(b -> new String(b, StandardCharsets.US_ASCII)) + .collect(Collectors.toList()); + } + + @Override + public int getKey() { + return ALPN; + } + + @Override + public void fromWire(byte[] bytes) throws IOException { + values.clear(); + DNSInput in = new DNSInput(bytes); + while (in.remaining() > 0) { + byte[] b = in.readCountedString(); + values.add(b); + } + } + + @Override + public void fromString(String string) throws TextParseException { + values.clear(); + if (string == null || string.isEmpty()) { + throw new TextParseException("Non-empty list must be specified for alpn"); + } + for (String str : splitStringWithEscapedCommas(string)) { + values.add(str.getBytes()); + } + } + + @Override + public byte[] toWire() { + DNSOutput out = new DNSOutput(); + for (byte[] b : values) { + out.writeCountedString(b); + } + return out.toByteArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (byte[] b : values) { + if (sb.length() > 0) { + sb.append(","); + } + sb.append(new String(b)); + } + return sb.toString(); + } + } + + public static class ParameterNoDefaultAlpn extends ParameterBase { + public ParameterNoDefaultAlpn() { + super(); + } + + @Override + public int getKey() { + return NO_DEFAULT_ALPN; + } + + @Override + public void fromWire(byte[] bytes) throws WireParseException { + if (bytes.length > 0) { + throw new WireParseException("No value can be specified for no-default-alpn"); + } + } + + @Override + public void fromString(String string) throws TextParseException { + if (string != null && !string.isEmpty()) { + throw new TextParseException("No value can be specified for no-default-alpn"); + } + } + + @Override + public byte[] toWire() { + return new byte[0]; + } + + @Override + public String toString() { + return ""; + } + } + + public static class ParameterPort extends ParameterBase { + private int port; + + public ParameterPort() { + super(); + } + + public ParameterPort(int port) { + super(); + this.port = port; + } + + public int getPort() { + return port; + } + + @Override + public int getKey() { + return PORT; + } + + @Override + public void fromWire(byte[] bytes) throws IOException { + DNSInput in = new DNSInput(bytes); + port = in.readU16(); + if (in.remaining() > 0) { + throw new WireParseException("Unexpected number of bytes in port parameter"); + } + } + + @Override + public void fromString(String string) throws TextParseException { + if (string == null || string.isEmpty()) { + throw new TextParseException("Integer value must be specified for port"); + } + port = Integer.parseInt(string); + } + + @Override + public byte[] toWire() { + DNSOutput out = new DNSOutput(); + out.writeU16(port); + return out.toByteArray(); + } + + @Override + public String toString() { + return Integer.toString(port); + } + } + + public static class ParameterIpv4Hint extends ParameterBase { + private final List addresses; + + public ParameterIpv4Hint() { + super(); + addresses = new ArrayList<>(); + } + + public ParameterIpv4Hint(List addresses) { + super(); + this.addresses = + addresses.stream().map(Inet4Address::getAddress).collect(Collectors.toList()); + } + + public List getAddresses() throws UnknownHostException { + List addresses = new LinkedList<>(); + for (byte[] bytes : this.addresses) { + InetAddress address = InetAddress.getByAddress(bytes); + if (address instanceof Inet4Address) { + addresses.add((Inet4Address) address); + } + } + return addresses; + } + + @Override + public int getKey() { + return IPV4HINT; + } + + @Override + public void fromWire(byte[] bytes) throws IOException { + addresses.clear(); + DNSInput in = new DNSInput(bytes); + while (in.remaining() >= 4) { + addresses.add(in.readByteArray(4)); + } + if (in.remaining() > 0) { + throw new WireParseException("Unexpected number of bytes in ipv4hint parameter"); + } + } + + @Override + public void fromString(String string) throws IOException { + addresses.clear(); + if (string == null || string.isEmpty()) { + throw new TextParseException("Non-empty IPv4 list must be specified for ipv4hint"); + } + for (String str : string.split(",")) { + byte[] address = Address.toByteArray(str, Address.IPv4); + if (address == null) { + throw new TextParseException("Invalid ipv4hint value '" + str + "'"); + } + addresses.add(address); + } + } + + @Override + public byte[] toWire() { + DNSOutput out = new DNSOutput(); + for (byte[] b : addresses) { + out.writeByteArray(b); + } + return out.toByteArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (byte[] b : addresses) { + if (sb.length() > 0) { + sb.append(","); + } + sb.append(Address.toDottedQuad(b)); + } + return sb.toString(); + } + } + + public static class ParameterEchConfig extends ParameterBase { + private byte[] data; + + public ParameterEchConfig() { + super(); + } + + public ParameterEchConfig(byte[] data) { + super(); + this.data = data; + } + + public byte[] getData() { + return data; + } + + @Override + public int getKey() { + return ECHCONFIG; + } + + @Override + public void fromWire(byte[] bytes) { + data = bytes; + } + + @Override + public void fromString(String string) throws TextParseException { + if (string == null || string.isEmpty()) { + throw new TextParseException("Non-empty base64 value must be specified for echconfig"); + } + data = Base64.getDecoder().decode(string); + } + + @Override + public byte[] toWire() { + return data; + } + + @Override + public String toString() { + return Base64.getEncoder().encodeToString(data); + } + } + + public static class ParameterIpv6Hint extends ParameterBase { + private final List addresses; + + public ParameterIpv6Hint() { + super(); + addresses = new ArrayList<>(); + } + + public ParameterIpv6Hint(List addresses) { + super(); + this.addresses = + addresses.stream().map(Inet6Address::getAddress).collect(Collectors.toList()); + } + + public List getAddresses() throws UnknownHostException { + List addresses = new LinkedList<>(); + for (byte[] bytes : this.addresses) { + InetAddress address = InetAddress.getByAddress(bytes); + if (address instanceof Inet6Address) { + addresses.add((Inet6Address) address); + } + } + return addresses; + } + + @Override + public int getKey() { + return IPV6HINT; + } + + @Override + public void fromWire(byte[] bytes) throws IOException { + addresses.clear(); + DNSInput in = new DNSInput(bytes); + while (in.remaining() >= 16) { + addresses.add(in.readByteArray(16)); + } + if (in.remaining() > 0) { + throw new WireParseException("Unexpected number of bytes in ipv6hint parameter"); + } + } + + @Override + public void fromString(String string) throws IOException { + addresses.clear(); + if (string == null || string.isEmpty()) { + throw new TextParseException("Non-empty IPv6 list must be specified for ipv6hint"); + } + for (String str : string.split(",")) { + byte[] address = Address.toByteArray(str, Address.IPv6); + if (address == null) { + throw new TextParseException("Invalid ipv6hint value '" + str + "'"); + } + addresses.add(address); + } + } + + @Override + public byte[] toWire() { + DNSOutput out = new DNSOutput(); + for (byte[] b : addresses) { + out.writeByteArray(b); + } + return out.toByteArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (byte[] b : addresses) { + if (sb.length() > 0) { + sb.append(","); + } + try { + InetAddress addr = InetAddress.getByAddress(null, b); + sb.append(addr.getCanonicalHostName()); + } catch (UnknownHostException e) { + return null; + } + } + return sb.toString(); + } + } + + public static class ParameterUnknown extends ParameterBase { + private int key; + private byte[] value; + + public ParameterUnknown(int key) { + super(); + this.key = key; + this.value = new byte[0]; + } + + public ParameterUnknown(int key, byte[] value) { + super(); + this.key = key; + this.value = value; + } + + public byte[] getValue() { + return value; + } + + @Override + public int getKey() { + return key; + } + + @Override + public void fromWire(byte[] bytes) { + value = bytes; + } + + @Override + public void fromString(String string) throws IOException { + if (string == null || string.isEmpty()) { + value = new byte[0]; + } else { + value = byteArrayFromString(string); + } + } + + @Override + public byte[] toWire() { + return value; + } + + @Override + public String toString() { + return byteArrayToString(value, false); + } + } + + protected boolean checkMandatoryParams() { + ParameterMandatory param = (ParameterMandatory) getSvcParamValue(MANDATORY); + if (param != null) { + for (int key : param.values) { + if (getSvcParamValue(key) == null) { + return false; + } + } + } + return true; + } + + @Override + protected void rrFromWire(DNSInput in) throws IOException { + svcPriority = in.readU16(); + targetName = new Name(in); + svcParams.clear(); + while (in.remaining() >= 4) { + int key = in.readU16(); + int length = in.readU16(); + byte[] value = in.readByteArray(length); + ParameterBase param; + Supplier factory = parameters.getFactory(key); + if (factory != null) { + param = factory.get(); + } else { + param = new ParameterUnknown(key); + } + param.fromWire(value); + svcParams.put(key, param); + } + if (in.remaining() > 0) { + throw new WireParseException("Record had unexpected number of bytes"); + } + if (!checkMandatoryParams()) { + throw new WireParseException("Not all mandatory SvcParams are specified"); + } + } + + @Override + protected String rrToString() { + StringBuilder sb = new StringBuilder(); + sb.append(svcPriority); + sb.append(" "); + sb.append(targetName); + for (Integer key : svcParams.keySet()) { + sb.append(" "); + sb.append(parameters.getText(key)); + ParameterBase param = svcParams.get(key); + String value = param.toString(); + if (value != null && !value.isEmpty()) { + sb.append("="); + sb.append(value); + } + } + return sb.toString(); + } + + @Override + protected void rdataFromString(Tokenizer st, Name origin) throws IOException { + svcPriority = st.getUInt16(); + targetName = st.getName(origin); + svcParams.clear(); + while (true) { + String keyStr = null; + String valueStr = null; + Tokenizer.Token t = st.get(); + if (!t.isString()) { + break; + } + int indexOfEquals = t.value.indexOf('='); + if (indexOfEquals == -1) { + // No "=" is key with no value case, leave value string as null + keyStr = t.value; + } else if (indexOfEquals == t.value.length() - 1) { + // Ends with "=" means the next token is quoted string with the value + keyStr = t.value.substring(0, indexOfEquals); + Tokenizer.Token valueToken = st.get(); + if (!valueToken.isString()) { + throw new TextParseException("Expected value for parameter key '" + keyStr + "'"); + } + valueStr = valueToken.value; + } else if (indexOfEquals > 0) { + // If "=" is in the middle then need to split the key and value from this token + keyStr = t.value.substring(0, indexOfEquals); + valueStr = t.value.substring(indexOfEquals + 1); + } else { + throw new TextParseException("Expected valid parameter key=value for '" + t.value + "'"); + } + + ParameterBase param; + int key = parameters.getValue(keyStr); + if (key == -1) { + throw new TextParseException("Expected a valid parameter key for '" + keyStr + "'"); + } + if (svcParams.containsKey(key)) { + throw new TextParseException("Duplicate parameter key for '" + keyStr + "'"); + } + Supplier factory = parameters.getFactory(key); + if (factory != null) { + param = factory.get(); + } else { + param = new ParameterUnknown(key); + } + param.fromString(valueStr); + svcParams.put(key, param); + } + + if (svcPriority > 0 && svcParams.isEmpty()) { + throw new TextParseException( + "At least one parameter value must be specified for ServiceMode"); + } + if (svcPriority == 0 && !svcParams.isEmpty()) { + throw new TextParseException("No parameter values allowed for AliasMode"); + } + if (!checkMandatoryParams()) { + throw new TextParseException("Not all mandatory SvcParams are specified"); + } + } + + @Override + protected void rrToWire(DNSOutput out, Compression c, boolean canonical) { + out.writeU16(svcPriority); + targetName.toWire(out, null, canonical); + for (Integer key : svcParams.keySet()) { + out.writeU16(key); + ParameterBase param = svcParams.get(key); + byte[] value = param.toWire(); + out.writeU16(value.length); + out.writeByteArray(value); + } + } +} diff --git a/src/main/java/org/xbill/DNS/SVCBRecord.java b/src/main/java/org/xbill/DNS/SVCBRecord.java new file mode 100644 index 000000000..4bc9eb5c0 --- /dev/null +++ b/src/main/java/org/xbill/DNS/SVCBRecord.java @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import java.util.List; + +/** + * Service Location and Parameter Binding Record + * + * @see draft-ietf-dnsop-svcb-https + */ +public class SVCBRecord extends SVCBBase { + SVCBRecord() {} + + public SVCBRecord( + Name name, int dclass, long ttl, int priority, Name domain, List params) { + super(name, Type.SVCB, dclass, ttl, priority, domain, params); + } +} diff --git a/src/main/java/org/xbill/DNS/Type.java b/src/main/java/org/xbill/DNS/Type.java index 8c8199086..0fb0824c7 100644 --- a/src/main/java/org/xbill/DNS/Type.java +++ b/src/main/java/org/xbill/DNS/Type.java @@ -222,6 +222,22 @@ public final class Type { /** Message Digest for DNS Zones. */ public static final int ZONEMD = 63; + /** + * Service Location and Parameter Binding + * + * @see draft-ietf-dnsop-svcb-https + */ + public static final int SVCB = 64; + + /** + * HTTPS Service Location and Parameter Binding + * + * @see draft-ietf-dnsop-svcb-https + */ + public static final int HTTPS = 65; + /** {@link SPFRecord Sender Policy Framework} */ public static final int SPF = 99; @@ -403,6 +419,8 @@ public Supplier getFactory(int val) { types.add(OPENPGPKEY, "OPENPGPKEY", OPENPGPKEYRecord::new); types.add(CSYNC, "CSYNC"); types.add(ZONEMD, "ZONEMD"); + types.add(SVCB, "SVCB", SVCBRecord::new); + types.add(HTTPS, "HTTPS", HTTPSRecord::new); types.add(SPF, "SPF", SPFRecord::new); types.add(UINFO, "UINFO"); diff --git a/src/test/java/org/xbill/DNS/HTTPSRecordTest.java b/src/test/java/org/xbill/DNS/HTTPSRecordTest.java new file mode 100644 index 000000000..dc48b2ae4 --- /dev/null +++ b/src/test/java/org/xbill/DNS/HTTPSRecordTest.java @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class HTTPSRecordTest { + @Test + void createParams() throws UnknownHostException { + List mandatoryList = Arrays.asList(HTTPSRecord.ALPN, HTTPSRecord.IPV4HINT); + HTTPSRecord.ParameterMandatory mandatory = new HTTPSRecord.ParameterMandatory(mandatoryList); + assertEquals(HTTPSRecord.MANDATORY, mandatory.getKey()); + assertEquals(mandatoryList, mandatory.getValues()); + + List alpnList = Arrays.asList("h2", "h3"); + HTTPSRecord.ParameterAlpn alpn = new HTTPSRecord.ParameterAlpn(alpnList); + assertEquals(HTTPSRecord.ALPN, alpn.getKey()); + assertEquals(alpnList, alpn.getValues()); + + HTTPSRecord.ParameterPort port = new HTTPSRecord.ParameterPort(8443); + assertEquals(HTTPSRecord.PORT, port.getKey()); + assertEquals(8443, port.getPort()); + + List ipv4List = Arrays.asList((Inet4Address) InetAddress.getByName("1.2.3.4")); + HTTPSRecord.ParameterIpv4Hint ipv4hint = new HTTPSRecord.ParameterIpv4Hint(ipv4List); + assertEquals(HTTPSRecord.IPV4HINT, ipv4hint.getKey()); + assertEquals(ipv4List, ipv4hint.getAddresses()); + + byte[] data = {'a', 'b', 'c'}; + HTTPSRecord.ParameterEchConfig echconfig = new HTTPSRecord.ParameterEchConfig(data); + assertEquals(HTTPSRecord.ECHCONFIG, echconfig.getKey()); + assertEquals(data, echconfig.getData()); + + List ipv6List = Arrays.asList((Inet6Address) InetAddress.getByName("2001::1")); + HTTPSRecord.ParameterIpv6Hint ipv6hint = new HTTPSRecord.ParameterIpv6Hint(ipv6List); + assertEquals(HTTPSRecord.IPV6HINT, ipv6hint.getKey()); + assertEquals(ipv6List, ipv6hint.getAddresses()); + + byte[] value = {0, 1, 2, 3}; + HTTPSRecord.ParameterUnknown unknown = new HTTPSRecord.ParameterUnknown(33, value); + assertEquals(33, unknown.getKey()); + assertEquals(value, unknown.getValue()); + } + + @Test + void createRecord() throws IOException { + Name label = Name.fromString("test.com."); + int svcPriority = 5; + Name svcDomain = Name.fromString("svc.test.com."); + HTTPSRecord.ParameterMandatory mandatory = new HTTPSRecord.ParameterMandatory(); + mandatory.fromString("alpn"); + HTTPSRecord.ParameterAlpn alpn = new HTTPSRecord.ParameterAlpn(); + alpn.fromString("h1,h2"); + HTTPSRecord.ParameterIpv4Hint ipv4 = new HTTPSRecord.ParameterIpv4Hint(); + ipv4.fromString("1.2.3.4,5.6.7.8"); + List params = Arrays.asList(mandatory, ipv4, alpn); + HTTPSRecord record = new HTTPSRecord(label, DClass.IN, 300, svcPriority, svcDomain, params); + + assertEquals(Type.HTTPS, record.getType()); + assertEquals(label, record.getName()); + assertEquals(svcPriority, record.getSvcPriority()); + assertEquals(svcDomain, record.getTargetName()); + assertEquals( + Arrays.asList(HTTPSRecord.MANDATORY, HTTPSRecord.ALPN, HTTPSRecord.IPV4HINT).toString(), + record.getSvcParamKeys().toString()); + assertEquals("alpn", record.getSvcParamValue(HTTPSRecord.MANDATORY).toString()); + assertEquals("h1,h2", record.getSvcParamValue(HTTPSRecord.ALPN).toString()); + assertEquals("h1,h2", record.getSvcParamValue(HTTPSRecord.ALPN).toString()); + assertNull(record.getSvcParamValue(1234)); + Options.unset("BINDTTL"); + Options.unset("noPrintIN"); + assertEquals( + "test.com.\t\t300\tIN\tHTTPS\t5 svc.test.com. mandatory=alpn alpn=h1,h2 ipv4hint=1.2.3.4,5.6.7.8", + record.toString()); + } + + @Test + void aliasMode() throws IOException { + String str = "0 a.b.c."; + byte[] bytes = SVCBRecordTest.stringToWire(str); + byte[] expected = new byte[] {0, 0, 1, 'a', 1, 'b', 1, 'c', 0}; + assertArrayEquals(expected, bytes); + assertEquals(str, SVCBRecordTest.wireToString(bytes)); + } + + @Test + void serviceModePort() throws IOException { + String str = "1 . port=8443"; + byte[] bytes = SVCBRecordTest.stringToWire(str); + byte[] expected = new byte[] {0, 1, 0, 0, 3, 0, 2, 0x20, (byte) 0xFB}; + assertArrayEquals(expected, bytes); + assertEquals(str, SVCBRecordTest.wireToString(bytes)); + } + + @Test + void serviceModeEchConfigMulti() throws IOException { + String str = "1 h3pool. alpn=h2,h3 echconfig=1234"; + assertEquals(str, SVCBRecordTest.stringToWireToString(str)); + } + + @Test + void unknownKey() { + String str = "1 . sport=8443"; + assertThrows( + TextParseException.class, + () -> { + SVCBRecordTest.stringToWire(str); + }); + } +} diff --git a/src/test/java/org/xbill/DNS/SVCBRecordTest.java b/src/test/java/org/xbill/DNS/SVCBRecordTest.java new file mode 100644 index 000000000..b2da08334 --- /dev/null +++ b/src/test/java/org/xbill/DNS/SVCBRecordTest.java @@ -0,0 +1,682 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class SVCBRecordTest { + @Test + void createParams() throws UnknownHostException { + List mandatoryList = Arrays.asList(SVCBRecord.ALPN, SVCBRecord.IPV4HINT); + SVCBRecord.ParameterMandatory mandatory = new SVCBBase.ParameterMandatory(mandatoryList); + assertEquals(SVCBRecord.MANDATORY, mandatory.getKey()); + assertEquals(mandatoryList, mandatory.getValues()); + + List alpnList = Arrays.asList("h2", "h3"); + SVCBRecord.ParameterAlpn alpn = new SVCBRecord.ParameterAlpn(alpnList); + assertEquals(SVCBRecord.ALPN, alpn.getKey()); + assertEquals(alpnList, alpn.getValues()); + + SVCBRecord.ParameterPort port = new SVCBBase.ParameterPort(8443); + assertEquals(SVCBRecord.PORT, port.getKey()); + assertEquals(8443, port.getPort()); + + List ipv4List = Arrays.asList((Inet4Address) InetAddress.getByName("1.2.3.4")); + SVCBRecord.ParameterIpv4Hint ipv4hint = new SVCBRecord.ParameterIpv4Hint(ipv4List); + assertEquals(SVCBRecord.IPV4HINT, ipv4hint.getKey()); + assertEquals(ipv4List, ipv4hint.getAddresses()); + + byte[] data = {'a', 'b', 'c'}; + SVCBRecord.ParameterEchConfig echconfig = new SVCBRecord.ParameterEchConfig(data); + assertEquals(SVCBRecord.ECHCONFIG, echconfig.getKey()); + assertEquals(data, echconfig.getData()); + + List ipv6List = Arrays.asList((Inet6Address) InetAddress.getByName("2001::1")); + SVCBRecord.ParameterIpv6Hint ipv6hint = new SVCBRecord.ParameterIpv6Hint(ipv6List); + assertEquals(SVCBRecord.IPV6HINT, ipv6hint.getKey()); + assertEquals(ipv6List, ipv6hint.getAddresses()); + + byte[] value = {0, 1, 2, 3}; + SVCBRecord.ParameterUnknown unknown = new SVCBRecord.ParameterUnknown(33, value); + assertEquals(33, unknown.getKey()); + assertEquals(value, unknown.getValue()); + } + + @Test + void createRecord() throws IOException { + Name label = Name.fromString("test.com."); + int svcPriority = 5; + Name svcDomain = Name.fromString("svc.test.com."); + SVCBRecord.ParameterMandatory mandatory = new SVCBRecord.ParameterMandatory(); + mandatory.fromString("alpn"); + SVCBRecord.ParameterAlpn alpn = new SVCBRecord.ParameterAlpn(); + alpn.fromString("h1,h2"); + SVCBRecord.ParameterIpv4Hint ipv4 = new SVCBRecord.ParameterIpv4Hint(); + ipv4.fromString("1.2.3.4,5.6.7.8"); + List params = Arrays.asList(mandatory, ipv4, alpn); + SVCBRecord record = new SVCBRecord(label, DClass.IN, 300, svcPriority, svcDomain, params); + + assertEquals(Type.SVCB, record.getType()); + assertEquals(label, record.getName()); + assertEquals(svcPriority, record.getSvcPriority()); + assertEquals(svcDomain, record.getTargetName()); + assertEquals( + Arrays.asList(SVCBRecord.MANDATORY, SVCBRecord.ALPN, SVCBRecord.IPV4HINT).toString(), + record.getSvcParamKeys().toString()); + assertEquals("alpn", record.getSvcParamValue(SVCBRecord.MANDATORY).toString()); + assertEquals("h1,h2", record.getSvcParamValue(SVCBRecord.ALPN).toString()); + assertEquals("h1,h2", record.getSvcParamValue(SVCBRecord.ALPN).toString()); + assertNull(record.getSvcParamValue(1234)); + Options.unset("BINDTTL"); + Options.unset("noPrintIN"); + assertEquals( + "test.com.\t\t300\tIN\tSVCB\t5 svc.test.com. mandatory=alpn alpn=h1,h2 ipv4hint=1.2.3.4,5.6.7.8", + record.toString()); + } + + @Test + void createRecordDuplicateParam() throws IOException { + Name label = Name.fromString("test.com."); + Name svcDomain = Name.fromString("svc.test.com."); + SVCBRecord.ParameterAlpn alpn = new SVCBRecord.ParameterAlpn(); + alpn.fromString("h1,h2"); + SVCBRecord.ParameterIpv4Hint ipv4 = new SVCBRecord.ParameterIpv4Hint(); + ipv4.fromString("1.2.3.4,5.6.7.8"); + List params = Arrays.asList(alpn, ipv4, alpn); + assertThrows( + IllegalArgumentException.class, + () -> { + new SVCBRecord(label, DClass.IN, 300, 5, svcDomain, params); + }); + } + + @Test + void aliasMode() throws IOException { + String str = "0 a.b.c."; + byte[] bytes = stringToWire(str); + byte[] expected = new byte[] {0, 0, 1, 'a', 1, 'b', 1, 'c', 0}; + assertArrayEquals(expected, bytes); + assertEquals(str, wireToString(bytes)); + } + + @Test + void serviceModePort() throws IOException { + String str = "1 . port=8443"; + byte[] bytes = stringToWire(str); + byte[] expected = new byte[] {0, 1, 0, 0, 3, 0, 2, 0x20, (byte) 0xFB}; + assertArrayEquals(expected, bytes); + assertEquals(str, wireToString(bytes)); + } + + @Test + void serviceModeAlpn() throws IOException { + String str = "1 . alpn=h3"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeNoDefaultAlpn() throws IOException { + String str = "1 . no-default-alpn"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeMultiKey() throws IOException { + String str = "1 . alpn=h3 no-default-alpn"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeIntKey() throws IOException { + String str = "1 . 1=h3"; + assertEquals("1 . alpn=h3", stringToWireToString(str)); + } + + @Test + void serviceModeMultiValue() throws IOException { + String str = "1 . alpn=h2,h3"; + byte[] bytes = stringToWire(str); + byte[] expected = new byte[] {0, 1, 0, 0, 1, 0, 6, 2, 'h', '2', 2, 'h', '3'}; + assertArrayEquals(expected, bytes); + assertEquals(str, wireToString(bytes)); + } + + @Test + void serviceModeQuotedValue() throws IOException { + String str = "1 . alpn=\"h2,h3\""; + assertEquals("1 . alpn=h2,h3", stringToWireToString(str)); + } + + @Test + void serviceModeQuotedEscapedValue() throws IOException { + String str = "1 . alpn=\"h2\\,h3,h4\""; + assertEquals("1 . alpn=h2\\,h3,h4", stringToWireToString(str)); + } + + @Test + void serviceModeMandatoryAndOutOfOrder() throws IOException { + String str = "1 . alpn=h3 no-default-alpn mandatory=alpn"; + assertEquals("1 . mandatory=alpn alpn=h3 no-default-alpn", stringToWireToString(str)); + } + + @Test + void serviceModeEscapedDomain() throws IOException { + String str = "1 dotty\\.lotty.example.com. no-default-alpn"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeEchConfig() throws IOException { + String str = "1 h3pool. echconfig=1234"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeEchConfigMulti() throws IOException { + String str = "1 h3pool. alpn=h2,h3 echconfig=1234"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeEchConfigOutOfOrder() throws IOException { + String str = "1 h3pool. echconfig=1234 alpn=h2,h3"; + assertEquals("1 h3pool. alpn=h2,h3 echconfig=1234", stringToWireToString(str)); + } + + @Test + void serviceModeEchConfigQuoted() throws IOException { + String str = "1 h3pool. alpn=h2,h3 echconfig=\"1234\""; + assertEquals("1 h3pool. alpn=h2,h3 echconfig=1234", stringToWireToString(str)); + } + + @Test + void serviceModeIpv4Hint() throws IOException { + String str = "3 . ipv4hint=4.5.6.7"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeIpv4HintList() throws IOException { + String str = "5 . ipv4hint=4.5.6.7,8.9.1.2"; + byte[] bytes = stringToWire(str); + byte[] expected = new byte[] {0, 5, 0, 0, 4, 0, 8, 4, 5, 6, 7, 8, 9, 1, 2}; + assertArrayEquals(expected, bytes); + assertEquals(str, wireToString(bytes)); + } + + @Test + void serviceModeIpv4HintQuoted() throws IOException { + String str = "5 . ipv4hint=\"4.5.6.7,8.9.1.2\""; + assertEquals("5 . ipv4hint=4.5.6.7,8.9.1.2", stringToWireToString(str)); + } + + @Test + void serviceModeIpv4HintMultiKey() throws IOException { + String str = "7 . alpn=h2 ipv4hint=4.5.6.7"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeIpv6Hint() throws IOException { + String str = "9 . ipv6hint=2001:2002::1"; + assertEquals("9 . ipv6hint=2001:2002:0:0:0:0:0:1", stringToWireToString(str)); + } + + @Test + void serviceModeIpv6HintMulti() throws IOException { + String str = "2 . alpn=h2 ipv6hint=2001:2002::1,2001:2002::2"; + assertEquals( + "2 . alpn=h2 ipv6hint=2001:2002:0:0:0:0:0:1,2001:2002:0:0:0:0:0:2", + stringToWireToString(str)); + } + + @Test + void serviceModeUnknownKey() throws IOException { + String str = "6 . key12345=abcdefg\\012"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeUnknownKeyBytes() throws IOException { + String str = "8 . key23456=\\000\\001\\002\\003"; + byte[] bytes = stringToWire(str); + byte[] expected = new byte[] {0, 8, 0, 0x5B, (byte) 0xA0, 0, 4, 0, 1, 2, 3}; + assertArrayEquals(expected, bytes); + assertEquals(str, wireToString(bytes)); + } + + @Test + void serviceModeUnknownKeyEscapedChars() throws IOException { + String str = "1 . key29=a\\b\\c"; + assertEquals("1 . key29=abc", stringToWireToString(str)); + } + + @Test + void serviceModeUnknownKeyEscapedSlash() throws IOException { + String str = "65535 . key29=a\\\\b\\\\c"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeUnknownHighKey() throws IOException { + String str = "65535 . key65535=abcdefg"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void serviceModeUnknownKeyNoValue() throws IOException { + String str = "65535 . key65535"; + assertEquals(str, stringToWireToString(str)); + } + + @Test + void invalidText() { + String str = "these are all garbage strings that should fail"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void extraQuotesInParamValues() { + String str = "5 . ipv4hint=\"4.5.6.7\",\"8.9.1.2\""; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void serviceModeWithoutParameters() { + String str = "1 aliasmode.example.com."; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void aliasModeWithParameters() { + String str = "0 . alpn=h3"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void zeroLengthMandatory() { + String str = "1 . mandatory"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void zeroLengthAlpnValue() { + String str = "1 . alpn"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void zeroLengthPortValue() { + String str = "1 . port"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void zeroLengthIpv4Hint() { + String str = "1 . ipv4hint"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void zeroLengthEchConfig() { + String str = "1 . echconfig"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void zeroLengthIpv6Hint() { + String str = "1 . ipv6hint"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void emptyKey() { + String str = "1 . =1234"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void emptyValue() { + String str = "1 . alpn="; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void emptyKeyAndValue() { + String str = "1 . ="; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void unknownKey() { + String str = "1 . sport=8443"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void mandatoryListWithSelf() { + String str = "1 . mandatory=alpn,mandatory alpn=h1"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void mandatoryListWithDuplicate() { + String str = "1 . mandatory=alpn,ipv4hint,alpn alpn=h1 ipv4hint=1.2.3.4"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void mandatoryListWithMissingParam() { + String str = "1 . mandatory=alpn,ipv4hint alpn=h1"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void portValueTooLarge() { + String str = "1 . port=84438"; + assertThrows( + IllegalArgumentException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void noDefaultAlpnWithValue() { + String str = "1 . no-default-alpn=true"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void emptyString() { + String str = ""; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void noParamValues() { + String str = "1 ."; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void svcPriorityTooHigh() { + String str = "65536 . port=443"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void invalidPortKey() { + String str = "1 . port<5"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void invalidSvcDomain() { + String str = "1 fred..harvey port=80"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void duplicateParamKey() { + String str = "1 . alpn=h2 alpn=h3"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void invalidIpv4Hint() { + String str = "1 . ipv4hint=2001::1"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void invalidIpv6Hint() { + String str = "1 . ipv6hint=1.2.3.4"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void negativeSvcPriority() { + String str = "-1 . port=80"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void svcParamUnknownKeyTooHigh() { + String str = "65535 . key65536=abcdefg"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void invalidSvcParamKey() { + String str = "65535 . keyBlooie=abcdefg"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + + @Test + void wireFormatTooShort() { + byte[] wire = new byte[] {0, 1, 0, 0, 1, 0, 10}; + assertThrows( + WireParseException.class, + () -> { + wireToString(wire); + }); + } + + @Test + void wireFormatTooLong() { + byte[] wire = new byte[] {0, 0, 0, 1}; + assertThrows( + WireParseException.class, + () -> { + wireToString(wire); + }); + } + + @Test + void wireFormatMandatoryTooLong() { + byte[] wire = new byte[] {0, 1, 0, 0, 0, 0, 3, 0, 1, 55}; + assertThrows( + WireParseException.class, + () -> { + wireToString(wire); + }); + } + + @Test + void wireFormatAlpnTooShort() { + byte[] wire = new byte[] {0, 1, 0, 0, 1, 0, 3, 10, 1, 55}; + assertThrows( + WireParseException.class, + () -> { + wireToString(wire); + }); + } + + @Test + void wireFormatNoDefaultAlpnTooLong() { + byte[] wire = new byte[] {0, 1, 0, 0, 2, 0, 1, 0}; + assertThrows( + WireParseException.class, + () -> { + wireToString(wire); + }); + } + + @Test + void wireFormatPortTooLong() { + byte[] wire = new byte[] {0, 1, 0, 0, 3, 0, 4, 0, 0, 0, 0}; + assertThrows( + WireParseException.class, + () -> { + wireToString(wire); + }); + } + + @Test + void wireFormatIpv4HintTooLong() { + byte[] wire = new byte[] {0, 1, 0, 0, 4, 0, 5, 1, 2, 3, 4, 5}; + assertThrows( + WireParseException.class, + () -> { + wireToString(wire); + }); + } + + @Test + void wireFormatIpv6HintTooShort() { + byte[] wire = new byte[] {0, 1, 0, 0, 6, 0, 2, 1, 2}; + assertThrows( + WireParseException.class, + () -> { + wireToString(wire); + }); + } + + public static byte[] stringToWire(String str) throws IOException { + Tokenizer t = new Tokenizer(str); + SVCBRecord record = new SVCBRecord(); + record.rdataFromString(t, null); + DNSOutput out = new DNSOutput(); + record.rrToWire(out, null, true); + return out.toByteArray(); + } + + public static String wireToString(byte[] bytes) throws IOException { + DNSInput in = new DNSInput(bytes); + SVCBRecord record = new SVCBRecord(); + record.rrFromWire(in); + return record.rdataToString(); + } + + public static String stringToWireToString(String str) throws IOException { + return wireToString(stringToWire(str)); + } +} From c54e27e5829228b6907b052e7ce0be9ec563a410 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 22 Aug 2020 14:04:30 +0200 Subject: [PATCH 121/431] Use varargs for setting the search path --- src/main/java/org/xbill/DNS/Lookup.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index ebdac03c6..edd2354d3 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -156,7 +156,7 @@ public static synchronized void setDefaultSearchPath(List domains) { * * @param domains The default search path. */ - public static synchronized void setDefaultSearchPath(org.xbill.DNS.Name[] domains) { + public static synchronized void setDefaultSearchPath(Name... domains) { setDefaultSearchPath(Arrays.asList(domains)); } @@ -166,7 +166,8 @@ public static synchronized void setDefaultSearchPath(org.xbill.DNS.Name[] domain * @param domains The default search path. * @throws TextParseException A name in the array is not a valid DNS name. */ - public static synchronized void setDefaultSearchPath(String[] domains) throws TextParseException { + public static synchronized void setDefaultSearchPath(String... domains) + throws TextParseException { if (domains == null) { defaultSearchPath = null; return; @@ -328,7 +329,7 @@ public void setSearchPath(List domains) { * * @param domains An array of names containing the search path. */ - public void setSearchPath(Name[] domains) { + public void setSearchPath(Name... domains) { setSearchPath(Arrays.asList(domains)); } @@ -338,7 +339,7 @@ public void setSearchPath(Name[] domains) { * @param domains An array of names containing the search path. * @throws TextParseException A name in the array is not a valid DNS name. */ - public void setSearchPath(String[] domains) throws TextParseException { + public void setSearchPath(String... domains) throws TextParseException { if (domains == null) { this.searchPath = null; return; From c85392aa3030033192a6cad8ee456c2342d9edeb Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 22 Aug 2020 14:04:58 +0200 Subject: [PATCH 122/431] Make sure search paths are absolute --- src/main/java/org/xbill/DNS/Lookup.java | 34 +++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index edd2354d3..607e81978 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -9,6 +9,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; /** @@ -146,15 +147,19 @@ public static synchronized List getDefaultSearchPath() { * Sets the search path to be used as the default by future Lookups. * * @param domains The default search path. + * @throws IllegalArgumentException if a domain in the search path is not absolute and cannot be + * made absolute. */ public static synchronized void setDefaultSearchPath(List domains) { - defaultSearchPath = domains; + defaultSearchPath = convertSearchPathDomainList(domains); } /** * Sets the search path to be used as the default by future Lookups. * * @param domains The default search path. + * @throws IllegalArgumentException if a domain in the search path is not absolute and cannot be + * made absolute. */ public static synchronized void setDefaultSearchPath(Name... domains) { setDefaultSearchPath(Arrays.asList(domains)); @@ -181,6 +186,27 @@ public static synchronized void setDefaultSearchPath(String... domains) defaultSearchPath = newdomains; } + private static List convertSearchPathDomainList(List domains) { + try { + return domains.stream() + .map( + n -> { + try { + return Name.concatenate(n, Name.root); + } catch (NameTooLongException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.toList()); + } catch (RuntimeException e) { + if (e.getCause() instanceof NameTooLongException) { + throw new IllegalArgumentException(e.getCause()); + } else { + throw e; + } + } + } + /** * Sets a custom logger that will be used to log the sent and received packets. * @@ -319,15 +345,19 @@ public void setResolver(Resolver resolver) { * Sets the search path to use when performing this lookup. This overrides the default value. * * @param domains An array of names containing the search path. + * @throws IllegalArgumentException if a domain in the search path is not absolute and cannot be + * made absolute. */ public void setSearchPath(List domains) { - this.searchPath = domains; + this.searchPath = convertSearchPathDomainList(domains); } /** * Sets the search path to use when performing this lookup. This overrides the default value. * * @param domains An array of names containing the search path. + * @throws IllegalArgumentException if a domain in the search path is not absolute and cannot be + * made absolute. */ public void setSearchPath(Name... domains) { setSearchPath(Arrays.asList(domains)); From ad953c4b4eacab806be3c64fa8a42f35d7058228 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 22 Aug 2020 14:06:12 +0200 Subject: [PATCH 123/431] Lookup a name as absolute after all search path are exhausted Closes #118 --- src/main/java/org/xbill/DNS/Lookup.java | 2 + src/test/java/org/xbill/DNS/LookupTest.java | 90 +++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 src/test/java/org/xbill/DNS/LookupTest.java diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index 607e81978..d2338f101 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -610,6 +610,8 @@ public Record[] run() { break; } } + + resolve(name, Name.root); } if (!done) { if (badresponse) { diff --git a/src/test/java/org/xbill/DNS/LookupTest.java b/src/test/java/org/xbill/DNS/LookupTest.java new file mode 100644 index 000000000..e1332d605 --- /dev/null +++ b/src/test/java/org/xbill/DNS/LookupTest.java @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.xbill.DNS.ResolverConfig.CONFIGPROVIDER_SKIP_INIT; + +import java.io.IOException; +import java.net.InetAddress; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; + +public class LookupTest { + @Test + void testNdots1() throws IOException { + try { + System.setProperty(CONFIGPROVIDER_SKIP_INIT, "true"); + Resolver mockResolver = Mockito.mock(Resolver.class); + Name queryName = Name.fromConstantString("example.com"); + when(mockResolver.send(any(Message.class))) + .thenAnswer( + (Answer) + invocation -> { + Message query = invocation.getArgument(0); + Message answer = new Message(query.getHeader().getID()); + answer.addRecord(query.getQuestion(), Section.QUESTION); + answer.addRecord( + new ARecord( + query.getQuestion().getName(), + DClass.IN, + 60, + InetAddress.getByName("127.0.0.1")), + Section.ANSWER); + return answer; + }); + Lookup l = new Lookup(queryName, Type.A); + l.setCache(null); + l.setResolver(mockResolver); + l.setSearchPath("namespace.svc.cluster.local", "svc.cluster.local", "cluster.local"); + Record[] results = l.run(); + verify(mockResolver, times(1)).send(any(Message.class)); + assertEquals(1, results.length); + } finally { + System.clearProperty(CONFIGPROVIDER_SKIP_INIT); + } + } + + @Test + void testNdotsFallbackToAbsolute() throws IOException { + try { + System.setProperty(CONFIGPROVIDER_SKIP_INIT, "true"); + Resolver mockResolver = Mockito.mock(Resolver.class); + Name queryName = Name.fromConstantString("example.com"); + when(mockResolver.send(any(Message.class))) + .thenAnswer( + (Answer) + invocation -> { + Message query = invocation.getArgument(0); + Message answer = new Message(query.getHeader().getID()); + answer.addRecord(query.getQuestion(), Section.QUESTION); + if (query.getQuestion().getName().labels() == 3) { + answer.addRecord( + new ARecord( + query.getQuestion().getName(), + DClass.IN, + 60, + InetAddress.getByName("127.0.0.1")), + Section.ANSWER); + } else { + answer.getHeader().setRcode(Rcode.NXDOMAIN); + } + return answer; + }); + Lookup l = new Lookup(queryName, Type.A); + l.setCache(null); + l.setResolver(mockResolver); + l.setNdots(5); + l.setSearchPath("namespace.svc.cluster.local", "svc.cluster.local", "cluster.local"); + Record[] results = l.run(); + verify(mockResolver, times(4)).send(any(Message.class)); + assertEquals(1, results.length); + } finally { + System.clearProperty(CONFIGPROVIDER_SKIP_INIT); + } + } +} From 7ca1b167273cccd0a6dba8e431cc3a5da9660187 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 22 Aug 2020 18:11:01 +0200 Subject: [PATCH 124/431] Auto-publish master to Maven Central --- .github/workflows/build.yml | 38 ++++++++++++++++++++++++++++++++++++- pom.xml | 24 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1c1319178..e565c219a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,7 @@ jobs: uses: actions/cache@v1 with: path: ~/.m2 - key: m2 + key: m2-cache-${{ matrix.java }}-${{ matrix.arch }}-${{ matrix.os }} - name: Set up JDK ${{ matrix.java }} uses: joschi/setup-jdk@2d2c40de6fb6af3db2a3d2bedd57eb02442521c4 @@ -36,3 +36,39 @@ jobs: - name: Build with Maven run: mvn verify -B -"Dgpg.skip" + + release: + if: github.ref == 'refs/heads/master' + needs: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + + - name: Cache Maven dependencies + uses: actions/cache@v1 + with: + path: ~/.m2 + key: m2-cache-8-x64-ubuntu-latest + + - name: Set up JDK 8 + uses: joschi/setup-jdk@2d2c40de6fb6af3db2a3d2bedd57eb02442521c4 + with: + java-version: '8' + architecture: 'x64' + server-id: ossrh + server-username: SONATYPE_USER + server-password: SONATYPE_PW + + - name: Release to Maven Central + env: + SONATYPE_USER: ${{ secrets.SONATYPE_USER }} + SONATYPE_PW: ${{ secrets.SONATYPE_PW }} + run: | + cat <(echo -e "${{ secrets.GPG_KEY }}") | gpg --batch --import + gpg --list-secret-keys --keyid-format LONG + mvn \ + --no-transfer-progress \ + --batch-mode \ + -Dgpg.passphrase="${{ secrets.GPG_PW }}" \ + -DperformRelease=true \ + deploy diff --git a/pom.xml b/pom.xml index dc39be945..531b5b198 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,12 @@ + + + --pinentry-mode + loopback + + @@ -207,6 +213,24 @@ + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + ossrh + https://oss.sonatype.org/ + false + + From 67f83a43f426a788d21ac996015390f8d7835dfa Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 22 Aug 2020 19:22:40 +0200 Subject: [PATCH 125/431] Fix Javadoc warnings --- src/main/java/org/xbill/DNS/Resolver.java | 3 ++- src/main/java/org/xbill/DNS/Type.java | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Resolver.java b/src/main/java/org/xbill/DNS/Resolver.java index 0989674dd..37e43da64 100644 --- a/src/main/java/org/xbill/DNS/Resolver.java +++ b/src/main/java/org/xbill/DNS/Resolver.java @@ -58,7 +58,8 @@ default void setEDNS(int version) { * * @param version The EDNS version to use. 0 indicates EDNS0 and -1 indicates no EDNS. * @param payloadSize The maximum DNS packet size that this host is capable of receiving over UDP. - * If 0 is specified, the default ({@value SimpleResolver#DEFAULT_EDNS_PAYLOADSIZE}) is used. + * If 0 is specified, the default ({@value + * org.xbill.DNS.SimpleResolver#DEFAULT_EDNS_PAYLOADSIZE}) is used. * @param flags EDNS extended flags to be set in the OPT record. * @param options EDNS options to be set in the OPT record, specified as a List of * OPTRecord.Option elements. diff --git a/src/main/java/org/xbill/DNS/Type.java b/src/main/java/org/xbill/DNS/Type.java index 0fb0824c7..1a3e3b2eb 100644 --- a/src/main/java/org/xbill/DNS/Type.java +++ b/src/main/java/org/xbill/DNS/Type.java @@ -286,7 +286,11 @@ public final class Type { /** Transfer mailbox records */ public static final int MAILB = 253; - /** mail agent RRs (obsolete - {@see MX}) */ + /** + * mail agent RRs (obsolete) + * + * @see #MX + */ public static final int MAILA = 254; /** Matches any type */ From 2c4a51d4f1887394a0589b8e2782124043efe07e Mon Sep 17 00:00:00 2001 From: adam-stoler <68395423+adam-stoler@users.noreply.github.com> Date: Sat, 22 Aug 2020 13:29:04 -0400 Subject: [PATCH 126/431] Svcb https.fixes (#119) * Support escaped byte sequences in alpn values * Add a couple more unit tests * Updates from running formatter Co-authored-by: Adam Stoler --- src/main/java/org/xbill/DNS/SVCBBase.java | 25 ++++++----- .../java/org/xbill/DNS/HTTPSRecordTest.java | 2 +- .../java/org/xbill/DNS/SVCBRecordTest.java | 45 +++++++++++++++++-- 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/xbill/DNS/SVCBBase.java b/src/main/java/org/xbill/DNS/SVCBBase.java index 977670b28..8db7e3344 100644 --- a/src/main/java/org/xbill/DNS/SVCBBase.java +++ b/src/main/java/org/xbill/DNS/SVCBBase.java @@ -6,7 +6,6 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Base64; import java.util.HashMap; @@ -212,18 +211,20 @@ public ParameterAlpn() { values = new ArrayList<>(); } - public ParameterAlpn(List values) { + public ParameterAlpn(List values) throws TextParseException { super(); - this.values = - values.stream() - .map(s -> s.getBytes(StandardCharsets.US_ASCII)) - .collect(Collectors.toList()); + this.values = new ArrayList<>(); + for (String str : values) { + this.values.add(byteArrayFromString(str)); + } } public List getValues() { - return values.stream() - .map(b -> new String(b, StandardCharsets.US_ASCII)) - .collect(Collectors.toList()); + List values = new ArrayList<>(); + for (byte[] b : this.values) { + values.add(byteArrayToString(b, false)); + } + return values; } @Override @@ -248,7 +249,7 @@ public void fromString(String string) throws TextParseException { throw new TextParseException("Non-empty list must be specified for alpn"); } for (String str : splitStringWithEscapedCommas(string)) { - values.add(str.getBytes()); + values.add(byteArrayFromString(str)); } } @@ -268,7 +269,9 @@ public String toString() { if (sb.length() > 0) { sb.append(","); } - sb.append(new String(b)); + String str = byteArrayToString(b, false); + str = str.replaceAll(",", "\\\\,"); + sb.append(str); } return sb.toString(); } diff --git a/src/test/java/org/xbill/DNS/HTTPSRecordTest.java b/src/test/java/org/xbill/DNS/HTTPSRecordTest.java index dc48b2ae4..f3216ee69 100644 --- a/src/test/java/org/xbill/DNS/HTTPSRecordTest.java +++ b/src/test/java/org/xbill/DNS/HTTPSRecordTest.java @@ -17,7 +17,7 @@ public class HTTPSRecordTest { @Test - void createParams() throws UnknownHostException { + void createParams() throws UnknownHostException, TextParseException { List mandatoryList = Arrays.asList(HTTPSRecord.ALPN, HTTPSRecord.IPV4HINT); HTTPSRecord.ParameterMandatory mandatory = new HTTPSRecord.ParameterMandatory(mandatoryList); assertEquals(HTTPSRecord.MANDATORY, mandatory.getKey()); diff --git a/src/test/java/org/xbill/DNS/SVCBRecordTest.java b/src/test/java/org/xbill/DNS/SVCBRecordTest.java index b2da08334..50eb37d9e 100644 --- a/src/test/java/org/xbill/DNS/SVCBRecordTest.java +++ b/src/test/java/org/xbill/DNS/SVCBRecordTest.java @@ -17,7 +17,7 @@ public class SVCBRecordTest { @Test - void createParams() throws UnknownHostException { + void createParams() throws UnknownHostException, TextParseException { List mandatoryList = Arrays.asList(SVCBRecord.ALPN, SVCBRecord.IPV4HINT); SVCBRecord.ParameterMandatory mandatory = new SVCBBase.ParameterMandatory(mandatoryList); assertEquals(SVCBRecord.MANDATORY, mandatory.getKey()); @@ -160,8 +160,27 @@ void serviceModeQuotedValue() throws IOException { @Test void serviceModeQuotedEscapedValue() throws IOException { - String str = "1 . alpn=\"h2\\,h3,h4\""; - assertEquals("1 . alpn=h2\\,h3,h4", stringToWireToString(str)); + String str = "1 . alpn=\"h2\\,h3,h\\\\4\""; + String expectedStr = "1 . alpn=h2\\,h3,h\\\\4"; + byte[] bytes = stringToWire(str); + byte[] expectedBytes = + new byte[] {0, 1, 0, 0, 1, 0, 10, 5, 104, 50, 44, 104, 51, 3, 104, '\\', 52}; + assertArrayEquals(bytes, expectedBytes); + assertEquals(expectedStr, wireToString(bytes)); + } + + @Test + void serviceModeAlpnEscapedBytes() throws IOException { + String str = "1 . alpn=http/1.1,\\001aa\\003\\b,h2"; + String expectedStr = "1 . alpn=http/1.1,\\001aa\\003b,h2"; + byte[] bytes = stringToWire(str); + byte[] expectedBytes = + new byte[] { + 0, 1, 0, 0, 1, 0, 18, 8, 104, 116, 116, 112, 47, 49, 46, 49, 5, 1, 97, 97, 3, 98, 2, 104, + 50 + }; + assertArrayEquals(bytes, expectedBytes); + assertEquals(expectedStr, wireToString(bytes)); } @Test @@ -460,6 +479,16 @@ void portValueTooLarge() { }); } + @Test + void portValueCharAfterInt() { + String str = "1 . port=443a"; + assertThrows( + IllegalArgumentException.class, + () -> { + stringToWire(str); + }); + } + @Test void noDefaultAlpnWithValue() { String str = "1 . no-default-alpn=true"; @@ -570,6 +599,16 @@ void svcParamUnknownKeyTooHigh() { }); } + @Test + void svcParamUnknownKeyCharAfterInt() { + String str = "65535 . key123a=abcdefg"; + assertThrows( + TextParseException.class, + () -> { + stringToWire(str); + }); + } + @Test void invalidSvcParamKey() { String str = "65535 . keyBlooie=abcdefg"; From 791b5d69d3d9acb1e83ab6b5775484978bdf5f52 Mon Sep 17 00:00:00 2001 From: SPWei Date: Sat, 29 Aug 2020 04:40:32 +0800 Subject: [PATCH 127/431] Support IPv4 mapped IPv6 address in AAAA record (#120) --- src/main/java/org/xbill/DNS/AAAARecord.java | 12 +++--------- src/test/java/org/xbill/DNS/AAAARecordTest.java | 14 +++++--------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/xbill/DNS/AAAARecord.java b/src/main/java/org/xbill/DNS/AAAARecord.java index 1adb464a1..bbee69075 100644 --- a/src/main/java/org/xbill/DNS/AAAARecord.java +++ b/src/main/java/org/xbill/DNS/AAAARecord.java @@ -25,8 +25,8 @@ public class AAAARecord extends Record { */ public AAAARecord(Name name, int dclass, long ttl, InetAddress address) { super(name, Type.AAAA, dclass, ttl); - if (Address.familyOf(address) != Address.IPv6) { - throw new IllegalArgumentException("invalid IPv6 address"); + if (Address.familyOf(address) != Address.IPv4 && Address.familyOf(address) != Address.IPv6) { + throw new IllegalArgumentException("invalid IPv4/IPv6 address"); } this.address = address.getAddress(); } @@ -52,13 +52,7 @@ protected String rrToString() { } if (addr.getAddress().length == 4) { // Deal with Java's broken handling of mapped IPv4 addresses. - StringBuilder sb = new StringBuilder("0:0:0:0:0:ffff:"); - int high = ((address[12] & 0xFF) << 8) + (address[13] & 0xFF); - int low = ((address[14] & 0xFF) << 8) + (address[15] & 0xFF); - sb.append(Integer.toHexString(high)); - sb.append(':'); - sb.append(Integer.toHexString(low)); - return sb.toString(); + return "::ffff:" + addr.getHostAddress(); } return addr.getHostAddress(); } diff --git a/src/test/java/org/xbill/DNS/AAAARecordTest.java b/src/test/java/org/xbill/DNS/AAAARecordTest.java index f39b9ae4c..54f708252 100644 --- a/src/test/java/org/xbill/DNS/AAAARecordTest.java +++ b/src/test/java/org/xbill/DNS/AAAARecordTest.java @@ -38,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.net.InetAddress; @@ -85,15 +84,12 @@ void ctor_4arg() { // a relative name assertThrows(RelativeNameException.class, () -> new AAAARecord(m_rn, DClass.IN, m_ttl, m_addr)); + } - // an IPv4 address - try { - new AAAARecord(m_an, DClass.IN, m_ttl, InetAddress.getByName("192.168.0.1")); - fail("IllegalArgumentException not thrown"); - } catch (IllegalArgumentException e) { - } catch (UnknownHostException e) { - fail(e.getMessage()); - } + @Test + void ctor_v4() throws UnknownHostException { + AAAARecord ar = new AAAARecord(m_an, DClass.IN, m_ttl, InetAddress.getByName("192.168.1.1")); + assertEquals("::ffff:192.168.1.1", ar.rrToString()); } @Test From 394b357e849647b5c34bbf08333a01fdd0528cbf Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 6 Sep 2020 20:32:35 +0200 Subject: [PATCH 128/431] Fix maximum range of Type Closes #125 --- src/main/java/org/xbill/DNS/Type.java | 1 + src/test/java/org/xbill/DNS/TypeTest.java | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/main/java/org/xbill/DNS/Type.java b/src/main/java/org/xbill/DNS/Type.java index 1a3e3b2eb..e32349aca 100644 --- a/src/main/java/org/xbill/DNS/Type.java +++ b/src/main/java/org/xbill/DNS/Type.java @@ -323,6 +323,7 @@ private static class TypeMnemonic extends Mnemonic { public TypeMnemonic() { super("Type", CASE_UPPER); setPrefix("TYPE"); + setMaximum(0xFFFF); factories = new HashMap<>(); } diff --git a/src/test/java/org/xbill/DNS/TypeTest.java b/src/test/java/org/xbill/DNS/TypeTest.java index 100467212..5789d1bc4 100644 --- a/src/test/java/org/xbill/DNS/TypeTest.java +++ b/src/test/java/org/xbill/DNS/TypeTest.java @@ -77,6 +77,11 @@ void value_2arg() { assertEquals(301, Type.value("301", true)); } + @Test + void value_2arg_outOfRange() { + assertEquals(-1, Type.value("TYPE65536", true)); + } + @Test void isRR() { assertTrue(Type.isRR(Type.CNAME)); From 62d1222e3088f106f05032cef7697da324d699d0 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 7 Sep 2020 21:11:00 +0200 Subject: [PATCH 129/431] Make TSIG thread safe See also #123 --- src/main/java/org/xbill/DNS/TSIG.java | 45 +++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/xbill/DNS/TSIG.java b/src/main/java/org/xbill/DNS/TSIG.java index 85143b36d..94a893adb 100644 --- a/src/main/java/org/xbill/DNS/TSIG.java +++ b/src/main/java/org/xbill/DNS/TSIG.java @@ -89,7 +89,9 @@ public static String nameToAlgorithm(Name name) { private final Name alg; private final Clock clock; private final Name name; - private final Mac hmac; + private final SecretKey macKey; + private final String macAlgorithm; + private final Mac sharedHmac; /** * Verifies the data (computes the secure hash and compares it to the input) @@ -107,10 +109,19 @@ private static boolean verify(byte[] expected, byte[] signature) { return Arrays.equals(signature, expected); } - private Mac initHmac(String macAlgorithm, SecretKey key) { + private Mac initHmac() { + if (sharedHmac != null) { + try { + return (Mac) sharedHmac.clone(); + } catch (CloneNotSupportedException e) { + sharedHmac.reset(); + return sharedHmac; + } + } + try { Mac mac = Mac.getInstance(macAlgorithm); - mac.init(key); + mac.init(macKey); return mac; } catch (GeneralSecurityException ex) { throw new IllegalArgumentException("Caught security exception setting up HMAC.", ex); @@ -139,12 +150,7 @@ public TSIG(Name algorithm, Name name, String key) { * @param keyBytes The shared key's data. */ public TSIG(Name algorithm, Name name, byte[] keyBytes) { - this.name = name; - this.alg = algorithm; - this.clock = Clock.systemUTC(); - String macAlgorithm = nameToAlgorithm(algorithm); - SecretKey key = new SecretKeySpec(keyBytes, macAlgorithm); - this.hmac = initHmac(macAlgorithm, key); + this(algorithm, name, new SecretKeySpec(keyBytes, nameToAlgorithm(algorithm))); } /** @@ -170,8 +176,9 @@ public TSIG(Name algorithm, Name name, SecretKey key, Clock clock) { this.name = name; this.alg = algorithm; this.clock = clock; - String macAlgorithm = nameToAlgorithm(algorithm); - this.hmac = initHmac(macAlgorithm, key); + this.macAlgorithm = nameToAlgorithm(algorithm); + this.macKey = key; + this.sharedHmac = null; } /** @@ -180,10 +187,14 @@ public TSIG(Name algorithm, Name name, SecretKey key, Clock clock) { * * @param mac The JCE HMAC object * @param name The name of the key + * @deprecated Use one of the constructors that specifies an algorithm and key. */ + @Deprecated public TSIG(Mac mac, Name name) { this.name = name; - this.hmac = mac; + this.sharedHmac = mac; + this.macAlgorithm = null; + this.macKey = null; this.clock = Clock.systemUTC(); this.alg = algorithmToName(mac.getAlgorithm()); } @@ -220,8 +231,9 @@ public TSIG(Name algorithm, String name, String key) { } this.alg = algorithm; this.clock = Clock.systemUTC(); - String macAlgorithm = nameToAlgorithm(this.alg); - this.hmac = initHmac(macAlgorithm, new SecretKeySpec(keyBytes, macAlgorithm)); + this.macAlgorithm = nameToAlgorithm(algorithm); + this.sharedHmac = null; + this.macKey = new SecretKeySpec(keyBytes, macAlgorithm); } /** @@ -311,9 +323,10 @@ public TSIGRecord generate( } boolean signing = false; + Mac hmac = null; if (error == Rcode.NOERROR || error == Rcode.BADTIME || error == Rcode.BADTRUNC) { signing = true; - hmac.reset(); + hmac = initHmac(); } Duration fudge; @@ -520,7 +533,7 @@ public int verify(Message m, byte[] b, TSIGRecord old, boolean fullSignature) { return Rcode.BADKEY; } - hmac.reset(); + Mac hmac = initHmac(); if (old != null && tsig.getError() != Rcode.BADKEY && tsig.getError() != Rcode.BADSIG) { hmacAddSignature(hmac, old); } From 0525017a75a0e499837ade9611a03837ab8cf90b Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 13 Sep 2020 19:14:21 +0200 Subject: [PATCH 130/431] Mark methods as deprecated that were already noted as such in Javadoc --- src/main/java/org/xbill/DNS/TSIG.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/xbill/DNS/TSIG.java b/src/main/java/org/xbill/DNS/TSIG.java index 94a893adb..67c828f25 100644 --- a/src/main/java/org/xbill/DNS/TSIG.java +++ b/src/main/java/org/xbill/DNS/TSIG.java @@ -207,6 +207,7 @@ public TSIG(Mac mac, Name name) { * @param key The shared key's data. * @deprecated Use {@link #TSIG(Name, Name, SecretKey)} to explicitly specify an algorithm. */ + @Deprecated public TSIG(Name name, byte[] key) { this(HMAC_MD5, name, key); } @@ -260,6 +261,7 @@ public TSIG(String algorithm, String name, String key) { * @throws IllegalArgumentException The key data is improperly encoded * @deprecated Use {@link #TSIG(Name, String, String)} to explicitly specify an algorithm. */ + @Deprecated public TSIG(String name, String key) { this(HMAC_MD5, name, key); } @@ -274,6 +276,7 @@ public TSIG(String name, String key) { * @throws IllegalArgumentException The key data is improperly encoded * @deprecated Use an explicit constructor */ + @Deprecated public static TSIG fromString(String str) { String[] parts = str.split("[:/]", 3); switch (parts.length) { @@ -458,6 +461,7 @@ public void apply(Message m, int error, TSIGRecord old, boolean fullSignature) { * subsequent messages with reduced TSIG variables set (rfc2845, 4.4.). * @deprecated use {@link #apply(Message, TSIGRecord, boolean)} */ + @Deprecated public void applyStream(Message m, TSIGRecord old, boolean fullSignature) { apply(m, Rcode.NOERROR, old, fullSignature); } From a5aca46626e2082eaee2ab76c0f5026c2f1a3c5d Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 13 Sep 2020 19:15:59 +0200 Subject: [PATCH 131/431] Concurrency improvements for the DoH resolver Closes #123 --- src/main/java/org/xbill/DNS/DohResolver.java | 246 +++++++++++++++++-- 1 file changed, 221 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/xbill/DNS/DohResolver.java b/src/main/java/org/xbill/DNS/DohResolver.java index 037dbe858..6998d6c33 100644 --- a/src/main/java/org/xbill/DNS/DohResolver.java +++ b/src/main/java/org/xbill/DNS/DohResolver.java @@ -8,23 +8,44 @@ import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; +import java.security.NoSuchAlgorithmException; import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executor; import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.xbill.DNS.utils.base64; /** - * Implements a very basic DNS over HTTP (DoH) resolver. On Java 8, it uses HTTP/1.1, which is - * against the recommendation of RFC 8484 to use HTTP/2 and thus horribly slow. On Java 11 or newer, - * HTTP/2 is always used. + * Proof-of-concept DNS over HTTP (DoH) resolver. + * This class is not suitable for high load scenarios because of the shortcomings of Java's built-in + * HTTP clients. For more control, implement your own {@link Resolver} using e.g. OkHttp. + * + *

On Java 8, it uses HTTP/1.1, which is against the recommendation of RFC 8484 to use HTTP/2 and + * thus slower. On Java 11 or newer, HTTP/2 is always used, but the built-in HttpClient has it's own + * issues with connection handling. + * + *

As of 2020-09-13, the following limits of public resolvers for HTTP/2 were observed: + *

  • https://cloudflare-dns.com/dns-query: max streams=250, idle timeout=400s + *
  • https://dns.google/dns-query: max streams=100, idle timeout=240s + * + * @since 3.0 */ @Slf4j public final class DohResolver implements Resolver { private static final boolean useHttpClient; + private final SSLSocketFactory sslSocketFactory; private static Object defaultHttpRequestBuilder; private static Method publisherOfByteArrayMethod; @@ -36,6 +57,7 @@ public final class DohResolver implements Resolver { private static Method httpClientNewBuilderMethod; private static Method httpClientBuilderTimeoutMethod; + private static Method httpClientBuilderExecutorMethod; private static Method httpClientBuilderBuildMethod; private static Method httpClientSendAsyncMethod; @@ -46,9 +68,21 @@ public final class DohResolver implements Resolver { private boolean usePost = false; private Duration timeout = Duration.ofSeconds(5); private String uriTemplate; + private final Duration idleConnectionTimeout; private OPTRecord queryOPT = new OPTRecord(0, 0, 0); private TSIG tsig; private Object httpClient; + private Executor executor = ForkJoinPool.commonPool(); + + /** + * Maximum concurrent HTTP/2 streams or HTTP/1.1 connections. + * + *

    rfc7540#section-6.5.2 recommends a minimum of 100 streams for HTTP/2. + */ + private final Semaphore maxConcurrentRequests; + + private final AtomicLong lastRequest = new AtomicLong(0); + private final Semaphore initialRequestLock = new Semaphore(1); static { boolean initSuccess = false; @@ -68,6 +102,8 @@ public final class DohResolver implements Resolver { // HttpClient.Builder httpClientBuilderTimeoutMethod = httpClientBuilderClass.getDeclaredMethod("connectTimeout", Duration.class); + httpClientBuilderExecutorMethod = + httpClientBuilderClass.getDeclaredMethod("executor", Executor.class); httpClientBuilderBuildMethod = httpClientBuilderClass.getDeclaredMethod("build"); // HttpClient @@ -103,7 +139,7 @@ public final class DohResolver implements Resolver { httpResponseStatusCodeMethod = httpResponseClass.getDeclaredMethod("statusCode"); // defaultHttpRequestBuilder = HttpRequest.newBuilder(); - // defaultHttpRequestBuilder.version(Version.HTTP_2); + // defaultHttpRequestBuilder.version(HttpClient.Version.HTTP_2); // defaultHttpRequestBuilder.header("Content-Type", "application/dns-message"); // defaultHttpRequestBuilder.header("Accept", "application/dns-message"); defaultHttpRequestBuilder = requestBuilderNewBuilderMethod.invoke(null); @@ -133,15 +169,63 @@ public final class DohResolver implements Resolver { * @param uriTemplate the URI to use for resolving, e.g. {@code https://dns.google/dns-query} */ public DohResolver(String uriTemplate) { + this(uriTemplate, 100, Duration.ofMinutes(2)); + } + + /** + * Creates a new DoH resolver that performs lookups with HTTP GET and the default timeout (5s). + * + * @param uriTemplate the URI to use for resolving, e.g. {@code https://dns.google/dns-query} + * @param maxConcurrentRequests Maximum concurrent HTTP/2 streams for Java 11+ or HTTP/1.1 + * connections for Java 8. On Java 8 this cannot exceed the system property {@code + * http.maxConnections}. + * @param idleConnectionTimeout Max. idle time for HTTP/2 connections until a request is + * serialized. Applies to Java 11+ only. + * @since 3.3 + */ + public DohResolver( + String uriTemplate, int maxConcurrentRequests, Duration idleConnectionTimeout) { this.uriTemplate = uriTemplate; + this.idleConnectionTimeout = idleConnectionTimeout; + if (maxConcurrentRequests <= 0) { + throw new IllegalArgumentException("maxConcurrentRequests must be > 0"); + } + if (!useHttpClient) { + try { + int javaMaxConn = Integer.parseInt(System.getProperty("http.maxConnections", "5")); + if (maxConcurrentRequests > javaMaxConn) { + maxConcurrentRequests = javaMaxConn; + } + } catch (NumberFormatException nfe) { + // well, use what we got + } + } + this.maxConcurrentRequests = new Semaphore(maxConcurrentRequests); + try { + sslSocketFactory = SSLContext.getDefault().getSocketFactory(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } buildHttpClient(); } @SneakyThrows private void buildHttpClient() { if (useHttpClient) { + // var builder = + // HttpClient.newBuilder().connectTimeout(timeout).version(HttpClient.Version.HTTP_2); + // if (executor != null) { + // builder.executor(executor); + // } + // + // httpClient = builder.build(); + // defaultHttpRequestBuilder.timeout(timeout); + Object httpClientBuilder = httpClientNewBuilderMethod.invoke(null); httpClientBuilderTimeoutMethod.invoke(httpClientBuilder, timeout); + if (executor != null) { + httpClientBuilderExecutorMethod.invoke(httpClientBuilder, executor); + } httpClient = httpClientBuilderBuildMethod.invoke(httpClientBuilder); requestBuilderTimeoutMethod.invoke(defaultHttpRequestBuilder, timeout); } @@ -217,12 +301,23 @@ private CompletionStage sendAsync8(final Message query) { byte[] queryBytes = prepareQuery(query).toWire(); String url = getUrl(queryBytes); - byte[] responseBytes = sendAndGetMessageBytes(url, queryBytes); + // limit number of concurrent connections + if (!maxConcurrentRequests.tryAcquire(timeout.toMillis(), TimeUnit.MILLISECONDS)) { + failedFuture(new IOException("Query timed out")); + return; + } + + byte[] responseBytes; + try { + responseBytes = sendAndGetMessageBytes(url, queryBytes); + } finally { + maxConcurrentRequests.release(); + } Message response = new Message(responseBytes); verifyTSIG(query, response, responseBytes, tsig); response.setResolver(this); f.complete(response); - } catch (IOException e) { + } catch (InterruptedException | IOException e) { f.completeExceptionally(e); } }); @@ -231,49 +326,128 @@ private CompletionStage sendAsync8(final Message query) { private byte[] sendAndGetMessageBytes(String url, byte[] queryBytes) throws IOException { HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); - conn.setConnectTimeout((int) timeout.toMillis()); - conn.setRequestMethod(isUsePost() ? "POST" : "GET"); - conn.setRequestProperty("Content-Type", "application/dns-message"); - conn.setRequestProperty("Accept", "application/dns-message"); - if (usePost) { - conn.setDoOutput(true); - conn.getOutputStream().write(queryBytes); - } - InputStream is = conn.getInputStream(); - byte[] responseBytes = new byte[conn.getContentLength()]; - int r; - int offset = 0; - while ((r = is.read(responseBytes, offset, responseBytes.length)) > 0) { - offset += r; + try { + if (conn instanceof HttpsURLConnection) { + ((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory); + } + conn.setConnectTimeout((int) timeout.toMillis()); + conn.setRequestMethod(isUsePost() ? "POST" : "GET"); + conn.setRequestProperty("Content-Type", "application/dns-message"); + conn.setRequestProperty("Accept", "application/dns-message"); + if (usePost) { + conn.setDoOutput(true); + conn.getOutputStream().write(queryBytes); + } + try (InputStream is = conn.getInputStream()) { + byte[] responseBytes = new byte[conn.getContentLength()]; + int r; + int offset = 0; + while ((r = is.read(responseBytes, offset, responseBytes.length)) > 0) { + offset += r; + } + return responseBytes; + } + } catch (IOException ioe) { + try (InputStream es = conn.getErrorStream()) { + byte[] buf = new byte[4096]; + while (es.read(buf) > 0) { + // discard + } + } + throw ioe; } - return responseBytes; } private CompletionStage sendAsync11(final Message query) { + long startTime = System.nanoTime(); byte[] queryBytes = prepareQuery(query).toWire(); String url = getUrl(queryBytes); try { // var builder = defaultHttpRequestBuilder.copy(); - Object builder = requestBuilderCopyMethod.invoke(defaultHttpRequestBuilder); // builder.uri(URI.create(url)); + Object builder = requestBuilderCopyMethod.invoke(defaultHttpRequestBuilder); requestBuilderUriMethod.invoke(builder, URI.create(url)); if (usePost) { - // builder.POST(BodyPublishers.ofByteArray(queryBytes)); + // builder.POST(HttpRequest.BodyPublishers.ofByteArray(queryBytes)); requestBuilderPostMethod.invoke( builder, publisherOfByteArrayMethod.invoke(null, queryBytes)); } - // var request = request.build(); - // var bodyHandler = BodyHandlers.ofByteArray(); + try { + // check if this request needs to be done synchronously because of HttpClient's stupidity to + // not use the connection pool for HTTP/2 until one connection is successfully established, + // which could lead to hundreds of connections (and threads with the default executor) + if (!initialRequestLock.tryAcquire(timeout.toMillis(), TimeUnit.MILLISECONDS)) { + return failedFuture(new IOException("Query timed out")); + } + } catch (InterruptedException iex) { + return failedFuture(iex); + } + + long lastRequestTime = lastRequest.get(); + long now = System.nanoTime(); + boolean isInitialRequest = (lastRequestTime < now - idleConnectionTimeout.toNanos()); + if (!isInitialRequest) { + initialRequestLock.release(); + } + + // check if we already exceeded the query timeout while checking the initial connection + Duration remainingTimeout = timeout.minus(System.nanoTime() - startTime, ChronoUnit.NANOS); + if (remainingTimeout.isNegative()) { + if (isInitialRequest) { + initialRequestLock.release(); + } + return failedFuture(new IOException("Query timed out")); + } + + try { + // Lock a HTTP/2 stream. Another stupidity of HttpClient to not simply queue the request, + // but fail with an IOException which also CLOSES the connection... *facepalm* + if (!maxConcurrentRequests.tryAcquire(timeout.toMillis(), TimeUnit.MILLISECONDS)) { + if (isInitialRequest) { + initialRequestLock.release(); + } + return failedFuture(new IOException("Query timed out")); + } + } catch (InterruptedException iex) { + if (isInitialRequest) { + initialRequestLock.release(); + } + return failedFuture(iex); + } + + // check if the stream lock acquisition took too long + remainingTimeout = timeout.minus(System.nanoTime() - startTime, ChronoUnit.NANOS); + if (remainingTimeout.isNegative()) { + if (isInitialRequest) { + initialRequestLock.release(); + } + return failedFuture(new IOException("Query timed out")); + } + + // var httpRequest = builder.build(); + // var bodyHandler = HttpResponse.BodyHandlers.ofByteArray(); + // return httpClient + // .sendAsync(httpRequest, bodyHandler) Object httpRequest = requestBuilderBuildMethod.invoke(builder); Object bodyHandler = byteArrayBodyPublisherMethod.invoke(null); return ((CompletionStage) httpClientSendAsyncMethod.invoke(httpClient, httpRequest, bodyHandler)) + .whenComplete( + (result, ex) -> { + maxConcurrentRequests.release(); + if (isInitialRequest && ex == null) { + lastRequest.set(now); + initialRequestLock.release(); + } + }) .thenComposeAsync( response -> { try { Message responseMessage; + // if (response.statusCode() == 200) { + // byte[] responseBytes = response.body(); if ((int) httpResponseStatusCodeMethod.invoke(response) == 200) { byte[] responseBytes = (byte[]) httpResponseBodyMethod.invoke(response); responseMessage = new Message(responseBytes); @@ -354,6 +528,28 @@ public void setUriTemplate(String uriTemplate) { this.uriTemplate = uriTemplate; } + /** + * Gets the {@link Executor} for HTTP/2 requests. Only applicable on Java 11+ and default to + * {@link ForkJoinPool#commonPool()}. + * + * @since 3.3 + */ + public Executor getExecutor() { + return executor; + } + + /** + * Gets the {@link Executor} for HTTP/2 requests. Only applicable on Java 11+ + * + * @param executor The new {@link Executor}, can be null to restore the HttpClient default + * behavior. + * @since 3.3 + */ + public void setExecutor(Executor executor) { + this.executor = executor; + buildHttpClient(); + } + @Override public String toString() { return "DohResolver {" + (usePost ? "POST " : "GET ") + uriTemplate + "}"; From ab0d07907e6fefe7eb8002db18964c1da6a97c38 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 13 Sep 2020 19:51:31 +0200 Subject: [PATCH 132/431] Support DoH with unknown content length Closes #127 --- src/main/java/org/xbill/DNS/DohResolver.java | 29 ++++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/xbill/DNS/DohResolver.java b/src/main/java/org/xbill/DNS/DohResolver.java index 6998d6c33..09ae8d74b 100644 --- a/src/main/java/org/xbill/DNS/DohResolver.java +++ b/src/main/java/org/xbill/DNS/DohResolver.java @@ -1,6 +1,8 @@ // SPDX-License-Identifier: BSD-2-Clause package org.xbill.DNS; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; @@ -339,13 +341,28 @@ private byte[] sendAndGetMessageBytes(String url, byte[] queryBytes) throws IOEx conn.getOutputStream().write(queryBytes); } try (InputStream is = conn.getInputStream()) { - byte[] responseBytes = new byte[conn.getContentLength()]; - int r; - int offset = 0; - while ((r = is.read(responseBytes, offset, responseBytes.length)) > 0) { - offset += r; + int length = conn.getContentLength(); + if (length > -1) { + byte[] responseBytes = new byte[conn.getContentLength()]; + int r; + int offset = 0; + while ((r = is.read(responseBytes, offset, responseBytes.length - offset)) > 0) { + offset += r; + } + if (offset < responseBytes.length) { + throw new EOFException("Could not read expected content length"); + } + return responseBytes; + } else { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + byte[] buffer = new byte[4096]; + int r; + while ((r = is.read(buffer, 0, buffer.length)) > 0) { + bos.write(buffer, 0, r); + } + return bos.toByteArray(); + } } - return responseBytes; } } catch (IOException ioe) { try (InputStream es = conn.getErrorStream()) { From 6c6180fbd7b5110962032169ee7af15f18c39b57 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Sep 2020 12:21:31 +0200 Subject: [PATCH 133/431] Release v3.3.0 --- Changelog | 14 +++++++++++++- README.md | 2 +- pom.xml | 4 ++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Changelog b/Changelog index f4dd2895a..7d602be24 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,17 @@ +09/27/2020 + - 3.3.0 released + - Add support for SVCB and HTTPS records + (PR#116, @adam-stoler) + - Fix an issue with ndots in Lookup (#118) + - Support IPv4 mapped IPv6 address in AAAA record + (PR#120, @spwei) + - Validate range in Type + - Improve DOH Resolver (#123, #127) + Note that this resolver is more a proof of concept and not + production ready. See Javadoc and issue #123. + 07/11/2020 - - 3.2.1 released + - 3.2.2 released - Fix JNA access violation in WindowsResolverConfigProvider on 32bit JVMs diff --git a/README.md b/README.md index 3f67e582f..dcb740250 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ dnsjava comes with several built-in resolvers: - `ExtendedResolver`: a resolver that uses multiple `SimpleResolver`s to send the queries. Can be configured to query the servers in a round-robin order. Blacklists a server if it times out. -- `DohResolver`: a very basic DNS over HTTP resolver, e.g. to use +- `DohResolver`: a proof-of-concept DNS over HTTP resolver, e.g. to use `https://dns.google/query`. The project [dnssecjava](https://github.com/ibauersachs/dnssecjava) has a diff --git a/pom.xml b/pom.xml index 531b5b198..6f90b0bb5 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.3.0-SNAPSHOT + 3.3.0 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - HEAD + v3.3.0 From 6f83acc9af85f3028ae117309fb2114714275035 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 27 Sep 2020 12:42:29 +0200 Subject: [PATCH 134/431] Return to -snapshot --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6f90b0bb5..bcd230d28 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.3.0 + 3.4.0-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.3.0 + HEAD From f3451f0c667585b30252e9ddd0f1392a81ca1e27 Mon Sep 17 00:00:00 2001 From: Adam Stoler Date: Fri, 9 Oct 2020 13:50:46 -0400 Subject: [PATCH 135/431] Fix bug with SVCB/HTTPS record parsing where tokenizer is not properly reset at the end of parsing the record from text. Master format parsing requires this. Added a unit test to verify the behavior --- src/main/java/org/xbill/DNS/SVCBBase.java | 1 + .../java/org/xbill/DNS/SVCBRecordTest.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/main/java/org/xbill/DNS/SVCBBase.java b/src/main/java/org/xbill/DNS/SVCBBase.java index 8db7e3344..d111bbf72 100644 --- a/src/main/java/org/xbill/DNS/SVCBBase.java +++ b/src/main/java/org/xbill/DNS/SVCBBase.java @@ -728,6 +728,7 @@ protected void rdataFromString(Tokenizer st, Name origin) throws IOException { param.fromString(valueStr); svcParams.put(key, param); } + st.unget(); if (svcPriority > 0 && svcParams.isEmpty()) { throw new TextParseException( diff --git a/src/test/java/org/xbill/DNS/SVCBRecordTest.java b/src/test/java/org/xbill/DNS/SVCBRecordTest.java index 50eb37d9e..51147b5dc 100644 --- a/src/test/java/org/xbill/DNS/SVCBRecordTest.java +++ b/src/test/java/org/xbill/DNS/SVCBRecordTest.java @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; @@ -299,6 +300,33 @@ void serviceModeUnknownKeyNoValue() throws IOException { assertEquals(str, stringToWireToString(str)); } + @Test + void masterFormatParsing() throws IOException { + String str = + "test.net. 86400 IN SOA test.net. test.net. 2020100900 3600 600 604800 300\n" + + "test.net. 86400 IN NS ns1.test.net.\n" + + "test.net. 300 IN HTTPS 0 www.test.net.\n" + + "test.net. 300 IN SVCB 1 . alpn=h2\n" + + "www.test.net. 300 IN A 1.2.3.4\n"; + Master m = new Master(new ByteArrayInputStream(str.getBytes())); + + Record r = m.nextRecord(); + assertEquals(Type.SOA, r.getType()); + r = m.nextRecord(); + assertEquals(Type.NS, r.getType()); + r = m.nextRecord(); + assertEquals(Type.HTTPS, r.getType()); + assertEquals("0 www.test.net.", r.rdataToString()); + r = m.nextRecord(); + assertEquals(Type.SVCB, r.getType()); + assertEquals("1 . alpn=h2", r.rdataToString()); + r = m.nextRecord(); + assertEquals(Type.A, r.getType()); + assertEquals("1.2.3.4", r.rdataToString()); + r = m.nextRecord(); + assertNull(r); + } + @Test void invalidText() { String str = "these are all garbage strings that should fail"; From a8f5f7d4f57ab2311ba2fdffd41f27982f7d689e Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 28 Oct 2020 21:20:17 +0100 Subject: [PATCH 136/431] Return the name of the record for C/DNAME See https://tools.ietf.org/html/rfc2181#section-10.1.1 for a detailed explanation Closes #136 --- src/main/java/org/xbill/DNS/CNAMERecord.java | 10 ++++++++-- src/main/java/org/xbill/DNS/DNAMERecord.java | 10 ++++++++-- src/test/java/org/xbill/DNS/CNAMERecordTest.java | 3 ++- src/test/java/org/xbill/DNS/DNAMERecordTest.java | 3 ++- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/xbill/DNS/CNAMERecord.java b/src/main/java/org/xbill/DNS/CNAMERecord.java index 9fcd5c1dd..2951055ac 100644 --- a/src/main/java/org/xbill/DNS/CNAMERecord.java +++ b/src/main/java/org/xbill/DNS/CNAMERecord.java @@ -26,8 +26,14 @@ public Name getTarget() { return getSingleName(); } - /** Gets the alias specified by the CNAME Record */ + /** + * Gets the name of this record, aka the alias or label to the canonical name + * specified in {@link #getTarget()}. + * + * @deprecated use {@link #getName()} + */ + @Deprecated public Name getAlias() { - return getSingleName(); + return getName(); } } diff --git a/src/main/java/org/xbill/DNS/DNAMERecord.java b/src/main/java/org/xbill/DNS/DNAMERecord.java index 55fca32d5..88e93523c 100644 --- a/src/main/java/org/xbill/DNS/DNAMERecord.java +++ b/src/main/java/org/xbill/DNS/DNAMERecord.java @@ -25,8 +25,14 @@ public Name getTarget() { return getSingleName(); } - /** Gets the alias specified by the DNAME Record */ + /** + * Gets the name of this record, aka the alias or label to the delegation + * name specified in {@link #getTarget()}. + * + * @deprecated use {@link #getName()} + */ + @Deprecated public Name getAlias() { - return getSingleName(); + return getName(); } } diff --git a/src/test/java/org/xbill/DNS/CNAMERecordTest.java b/src/test/java/org/xbill/DNS/CNAMERecordTest.java index 6df26c34f..d85f1f0a3 100644 --- a/src/test/java/org/xbill/DNS/CNAMERecordTest.java +++ b/src/test/java/org/xbill/DNS/CNAMERecordTest.java @@ -39,6 +39,7 @@ import org.junit.jupiter.api.Test; +@SuppressWarnings("deprecation") class CNAMERecordTest { @Test void ctor_0arg() { @@ -59,6 +60,6 @@ void ctor_4arg() throws TextParseException { assertEquals(DClass.IN, d.getDClass()); assertEquals(0xABCDEL, d.getTTL()); assertEquals(a, d.getTarget()); - assertEquals(a, d.getAlias()); + assertEquals(n, d.getAlias()); } } diff --git a/src/test/java/org/xbill/DNS/DNAMERecordTest.java b/src/test/java/org/xbill/DNS/DNAMERecordTest.java index 0c82a9157..1e44a145a 100644 --- a/src/test/java/org/xbill/DNS/DNAMERecordTest.java +++ b/src/test/java/org/xbill/DNS/DNAMERecordTest.java @@ -39,6 +39,7 @@ import org.junit.jupiter.api.Test; +@SuppressWarnings("deprecation") class DNAMERecordTest { @Test void ctor_0arg() { @@ -59,6 +60,6 @@ void ctor_4arg() throws TextParseException { assertEquals(DClass.IN, d.getDClass()); assertEquals(0xABCDEL, d.getTTL()); assertEquals(a, d.getTarget()); - assertEquals(a, d.getAlias()); + assertEquals(n, d.getAlias()); } } From 93255c4021a02ec339e8e94c5d0b1e6cc567769f Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 28 Oct 2020 22:05:22 +0100 Subject: [PATCH 137/431] Update dependencies --- pom.xml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index bcd230d28..5e744f62d 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ UTF-8 1.8 - 5.4.2 + 5.7.0 1.7.30 @@ -87,19 +87,20 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 + 3.2.1 org.apache.felix maven-bundle-plugin - 4.2.0 + 5.1.1 true dnsjava is an implementation of DNS in Java org.xbill.dns org.dnsjava + <_noclassforname>true org.xbill.DNS.* @@ -128,7 +129,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.1 + 3.2.0 true dnsjava documentation @@ -156,7 +157,7 @@ org.jacoco jacoco-maven-plugin - 0.8.4 + 0.8.6 prepare-agent @@ -176,7 +177,7 @@ com.github.siom79.japicmp japicmp-maven-plugin - 0.14.3 + 0.14.4 true @@ -204,7 +205,7 @@ com.coveo fmt-maven-plugin - 2.9 + 2.9.1 @@ -255,19 +256,19 @@ net.java.dev.jna jna - 5.5.0 + 5.6.0 true net.java.dev.jna jna-platform - 5.5.0 + 5.6.0 true org.bouncycastle bcprov-jdk15on - 1.64 + 1.66 true @@ -285,7 +286,7 @@ org.mockito mockito-core - 3.1.0 + 3.6.0 test From 976b2fb63deca92d71a4036c240d2fae35e72730 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 28 Oct 2020 22:08:49 +0100 Subject: [PATCH 138/431] Make BouncyCastle optional in OSGi imports --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 5e744f62d..b4edfb89b 100644 --- a/pom.xml +++ b/pom.xml @@ -111,6 +111,7 @@ android.*;resolution:=optional, javax.naming.*;resolution:=optional, com.sun.jna.*;resolution:=optional,* + org.bouncycastle.*;resolution:=optional,* JavaSE-1.8 From b672aa7b5aa1a74cc0e4e76862d34421bb7c1458 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 28 Oct 2020 22:19:01 +0100 Subject: [PATCH 139/431] Release v3.3.1 Closes #138 --- Changelog | 6 ++++++ pom.xml | 10 ++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 7d602be24..9dc751b58 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +10/28/2020 + - 3.3.1 released + - Fix value of getAlias in C/DNameRecord (#136) + - Fix bug with SVCB/HTTPS parsing of master file format + (PR#135, @adam-stoler) + 09/27/2020 - 3.3.0 released - Add support for SVCB and HTTPS records diff --git a/pom.xml b/pom.xml index b4edfb89b..bd3bdcbac 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.4.0-SNAPSHOT + 3.3.1 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - HEAD + v3.3.1 @@ -190,6 +190,12 @@ org.xbill.DNS.config.IPHlpAPI + + + ANNOTATION_DEPRECATED_ADDED + PATCH + + From 8f3b9f076891bb125435eeb9c9c1a6c64fd53a8d Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 28 Oct 2020 22:25:54 +0100 Subject: [PATCH 140/431] Return to -snapshot --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bd3bdcbac..6148b7344 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.3.1 + 3.4.0-SNAPSOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.3.1 + HEAD From 558f73e499a06c5295be95294c3f1acf0d3b9d23 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Nov 2020 23:35:43 +0100 Subject: [PATCH 141/431] Try analyzing with sonarcloud --- .github/workflows/build.yml | 5 +++++ pom.xml | 3 +++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e565c219a..f15c567b6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,8 +35,13 @@ jobs: architecture: ${{ matrix.arch }} - name: Build with Maven + if: matrix.arch != 'x64' && matrix.os != 'ubuntu-latest' && matrix.java != '8' run: mvn verify -B -"Dgpg.skip" + - name: Build with Maven + if: matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '8' + run: mvn verify -B -"Dgpg.skip" org.sonarsource.scanner.maven:sonar-maven-plugin:sonar + release: if: github.ref == 'refs/heads/master' needs: test diff --git a/pom.xml b/pom.xml index 6148b7344..43f81af66 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,9 @@ 1.8 5.7.0 1.7.30 + dnsjava_dnsjava + dnsjava + https://sonarcloud.io From 1ca416d1be29b11104e7635d802cddce21d3cc16 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 24 Nov 2020 23:52:56 +0100 Subject: [PATCH 142/431] Update java install --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f15c567b6..3bcc6c476 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,7 +29,7 @@ jobs: key: m2-cache-${{ matrix.java }}-${{ matrix.arch }}-${{ matrix.os }} - name: Set up JDK ${{ matrix.java }} - uses: joschi/setup-jdk@2d2c40de6fb6af3db2a3d2bedd57eb02442521c4 + uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 with: java-version: ${{ matrix.java }} architecture: ${{ matrix.arch }} @@ -56,7 +56,7 @@ jobs: key: m2-cache-8-x64-ubuntu-latest - name: Set up JDK 8 - uses: joschi/setup-jdk@2d2c40de6fb6af3db2a3d2bedd57eb02442521c4 + uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 with: java-version: '8' architecture: 'x64' From 3a7fedb14c1dd3a356f117f567a725d594462941 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 25 Nov 2020 00:01:49 +0100 Subject: [PATCH 143/431] Run Sonar with Java 11 --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3bcc6c476..d6659b8c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,11 +35,11 @@ jobs: architecture: ${{ matrix.arch }} - name: Build with Maven - if: matrix.arch != 'x64' && matrix.os != 'ubuntu-latest' && matrix.java != '8' + if: matrix.arch != 'x64' && matrix.os != 'ubuntu-latest' && matrix.java != '11' run: mvn verify -B -"Dgpg.skip" - name: Build with Maven - if: matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '8' + if: matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11' run: mvn verify -B -"Dgpg.skip" org.sonarsource.scanner.maven:sonar-maven-plugin:sonar release: From a04cc4fea5b93440be9ebbafe81d5642e1587ed3 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 25 Nov 2020 00:12:59 +0100 Subject: [PATCH 144/431] Pass tokens around. I don't like this. --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6659b8c9..69741afe5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,6 +40,9 @@ jobs: - name: Build with Maven if: matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: mvn verify -B -"Dgpg.skip" org.sonarsource.scanner.maven:sonar-maven-plugin:sonar release: From e706f7348672eebfa441254319c01f9b853bebf8 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 25 Nov 2020 00:33:00 +0100 Subject: [PATCH 145/431] Try setting dnsjava version --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 43f81af66..2c0636cc4 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,7 @@ dnsjava_dnsjava dnsjava https://sonarcloud.io + 8 From f6a45767413b88b579c991d954c01526ec775ff6 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 25 Nov 2020 00:40:43 +0100 Subject: [PATCH 146/431] Create JaCoCo report --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 2c0636cc4..9187f379a 100644 --- a/pom.xml +++ b/pom.xml @@ -170,6 +170,13 @@ prepare-agent + + report + verify + + report + + From a7dc0eb8b988e709b224a445acf0c3154bb834c9 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 6 Jan 2021 22:50:10 +0100 Subject: [PATCH 147/431] Fix condition for Sonar --- .github/workflows/build.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69741afe5..b76278ca3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,16 +34,17 @@ jobs: java-version: ${{ matrix.java }} architecture: ${{ matrix.arch }} - - name: Build with Maven - if: matrix.arch != 'x64' && matrix.os != 'ubuntu-latest' && matrix.java != '11' - run: mvn verify -B -"Dgpg.skip" - - name: Build with Maven if: matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn verify -B -"Dgpg.skip" org.sonarsource.scanner.maven:sonar-maven-plugin:sonar + run: | + if [[ "{{ matrix.arch }}" == "x64" && "{{ matrix.os }}" == "ubuntu-latest" && "{{ matrix.java }}" == "11" ]]; then + mvn verify -B -"Dgpg.skip" org.sonarsource.scanner.maven:sonar-maven-plugin:sonar + else + mvn verify -B -"Dgpg.skip" + fi; release: if: github.ref == 'refs/heads/master' From 3192b526b12319f68e86c512ccea715e62226bb8 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 6 Jan 2021 22:51:19 +0100 Subject: [PATCH 148/431] Remove condition on GH action step --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b76278ca3..f34cbd261 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,6 @@ jobs: architecture: ${{ matrix.arch }} - name: Build with Maven - if: matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From eea575612633fc449ca356fe66c3d20e8fe1e5bd Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 6 Jan 2021 22:53:23 +0100 Subject: [PATCH 149/431] Set shell to use bash on Windows too --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f34cbd261..920d36540 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,6 +38,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + shell: bash run: | if [[ "{{ matrix.arch }}" == "x64" && "{{ matrix.os }}" == "ubuntu-latest" && "{{ matrix.java }}" == "11" ]]; then mvn verify -B -"Dgpg.skip" org.sonarsource.scanner.maven:sonar-maven-plugin:sonar From fd35211c49c892854ff9a30beba9c81ec11a3104 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 31 Jan 2021 20:58:41 +0100 Subject: [PATCH 150/431] Raise max. CNAME chain length to 16 and make it configurable There is RFC specified max length, only that chains are discouraged. 16 is what BIND uses, so we'll do the same. Closes #150 --- README.md | 9 +++++++++ pom.xml | 2 +- src/main/java/org/xbill/DNS/Lookup.java | 5 ++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dcb740250..3df2d19a2 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,15 @@ Some settings of dnsjava can be configured via Use an OS-assigned ephemeral port for UDP queries. Enabling this option is insecure! Do NOT use it. + + dnsjava.lookup.max_iterations + Integer + 16 + 20 + + + Maximum number of CNAMEs to follow in a chain. + diff --git a/pom.xml b/pom.xml index 9187f379a..2a2e69442 100644 --- a/pom.xml +++ b/pom.xml @@ -324,7 +324,7 @@ - 9 + 11 ${target.jdk} diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index d2338f101..2c5fa480a 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -60,6 +60,7 @@ public final class Lookup { private boolean nametoolong; private boolean referral; private boolean cycleResults = true; + private int maxIterations; private static final Name[] noAliases = new Name[0]; @@ -270,6 +271,8 @@ public Lookup(Name name, int type, int dclass) { this.ndots = defaultNdots; this.credibility = Credibility.NORMAL; this.result = -1; + this.maxIterations = + Integer.parseInt(System.getProperty("dnsjava.lookup.max_iterations", "16")); } /** @@ -454,7 +457,7 @@ private void follow(Name name, Name oldname) { nxdomain = false; referral = false; iterations++; - if (iterations >= 10 || name.equals(oldname)) { + if (iterations >= maxIterations || name.equals(oldname)) { result = UNRECOVERABLE; error = "CNAME loop"; done = true; From e4908dca5dcac397471b8f7c9c3ef38a79a99865 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 1 Feb 2021 23:31:18 +0100 Subject: [PATCH 151/431] Prevent a potential PTR lookup --- src/main/java/org/xbill/DNS/SVCBBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/SVCBBase.java b/src/main/java/org/xbill/DNS/SVCBBase.java index d111bbf72..993e79c17 100644 --- a/src/main/java/org/xbill/DNS/SVCBBase.java +++ b/src/main/java/org/xbill/DNS/SVCBBase.java @@ -562,7 +562,7 @@ public String toString() { } try { InetAddress addr = InetAddress.getByAddress(null, b); - sb.append(addr.getCanonicalHostName()); + sb.append(addr.getHostAddress()); } catch (UnknownHostException e) { return null; } From c96667ecba396f151b89bbe78511fab395adb0be Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 1 Feb 2021 23:31:59 +0100 Subject: [PATCH 152/431] Fix contract violation on code that never executes --- src/main/java/org/xbill/DNS/SVCBBase.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/SVCBBase.java b/src/main/java/org/xbill/DNS/SVCBBase.java index 993e79c17..26bdb2916 100644 --- a/src/main/java/org/xbill/DNS/SVCBBase.java +++ b/src/main/java/org/xbill/DNS/SVCBBase.java @@ -564,7 +564,8 @@ public String toString() { InetAddress addr = InetAddress.getByAddress(null, b); sb.append(addr.getHostAddress()); } catch (UnknownHostException e) { - return null; + // should not happen, but returning null and throwing is bad + return e.getMessage(); } } return sb.toString(); From 346acf3e25d3473e5c75264ce082e83ebf0bd7b8 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 1 Feb 2021 23:32:23 +0100 Subject: [PATCH 153/431] Cleanup of example IPv6 addresses and redundant parentheses --- .../java/org/xbill/DNS/HTTPSRecordTest.java | 13 +- .../java/org/xbill/DNS/SVCBRecordTest.java | 261 ++++-------------- 2 files changed, 57 insertions(+), 217 deletions(-) diff --git a/src/test/java/org/xbill/DNS/HTTPSRecordTest.java b/src/test/java/org/xbill/DNS/HTTPSRecordTest.java index f3216ee69..5bdda5770 100644 --- a/src/test/java/org/xbill/DNS/HTTPSRecordTest.java +++ b/src/test/java/org/xbill/DNS/HTTPSRecordTest.java @@ -12,6 +12,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.jupiter.api.Test; @@ -32,7 +33,8 @@ void createParams() throws UnknownHostException, TextParseException { assertEquals(HTTPSRecord.PORT, port.getKey()); assertEquals(8443, port.getPort()); - List ipv4List = Arrays.asList((Inet4Address) InetAddress.getByName("1.2.3.4")); + List ipv4List = + Collections.singletonList((Inet4Address) InetAddress.getByName("1.2.3.4")); HTTPSRecord.ParameterIpv4Hint ipv4hint = new HTTPSRecord.ParameterIpv4Hint(ipv4List); assertEquals(HTTPSRecord.IPV4HINT, ipv4hint.getKey()); assertEquals(ipv4List, ipv4hint.getAddresses()); @@ -42,7 +44,8 @@ void createParams() throws UnknownHostException, TextParseException { assertEquals(HTTPSRecord.ECHCONFIG, echconfig.getKey()); assertEquals(data, echconfig.getData()); - List ipv6List = Arrays.asList((Inet6Address) InetAddress.getByName("2001::1")); + List ipv6List = + Collections.singletonList((Inet6Address) InetAddress.getByName("2001:db8::1")); HTTPSRecord.ParameterIpv6Hint ipv6hint = new HTTPSRecord.ParameterIpv6Hint(ipv6List); assertEquals(HTTPSRecord.IPV6HINT, ipv6hint.getKey()); assertEquals(ipv6List, ipv6hint.getAddresses()); @@ -112,10 +115,6 @@ void serviceModeEchConfigMulti() throws IOException { @Test void unknownKey() { String str = "1 . sport=8443"; - assertThrows( - TextParseException.class, - () -> { - SVCBRecordTest.stringToWire(str); - }); + assertThrows(TextParseException.class, () -> SVCBRecordTest.stringToWire(str)); } } diff --git a/src/test/java/org/xbill/DNS/SVCBRecordTest.java b/src/test/java/org/xbill/DNS/SVCBRecordTest.java index 51147b5dc..b1edf55da 100644 --- a/src/test/java/org/xbill/DNS/SVCBRecordTest.java +++ b/src/test/java/org/xbill/DNS/SVCBRecordTest.java @@ -13,6 +13,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.jupiter.api.Test; @@ -33,7 +34,8 @@ void createParams() throws UnknownHostException, TextParseException { assertEquals(SVCBRecord.PORT, port.getKey()); assertEquals(8443, port.getPort()); - List ipv4List = Arrays.asList((Inet4Address) InetAddress.getByName("1.2.3.4")); + List ipv4List = + Collections.singletonList((Inet4Address) InetAddress.getByName("1.2.3.4")); SVCBRecord.ParameterIpv4Hint ipv4hint = new SVCBRecord.ParameterIpv4Hint(ipv4List); assertEquals(SVCBRecord.IPV4HINT, ipv4hint.getKey()); assertEquals(ipv4List, ipv4hint.getAddresses()); @@ -43,7 +45,8 @@ void createParams() throws UnknownHostException, TextParseException { assertEquals(SVCBRecord.ECHCONFIG, echconfig.getKey()); assertEquals(data, echconfig.getData()); - List ipv6List = Arrays.asList((Inet6Address) InetAddress.getByName("2001::1")); + List ipv6List = + Collections.singletonList((Inet6Address) InetAddress.getByName("2001:db8::1")); SVCBRecord.ParameterIpv6Hint ipv6hint = new SVCBRecord.ParameterIpv6Hint(ipv6List); assertEquals(SVCBRecord.IPV6HINT, ipv6hint.getKey()); assertEquals(ipv6List, ipv6hint.getAddresses()); @@ -97,9 +100,7 @@ void createRecordDuplicateParam() throws IOException { List params = Arrays.asList(alpn, ipv4, alpn); assertThrows( IllegalArgumentException.class, - () -> { - new SVCBRecord(label, DClass.IN, 300, 5, svcDomain, params); - }); + () -> new SVCBRecord(label, DClass.IN, 300, 5, svcDomain, params)); } @Test @@ -249,15 +250,15 @@ void serviceModeIpv4HintMultiKey() throws IOException { @Test void serviceModeIpv6Hint() throws IOException { - String str = "9 . ipv6hint=2001:2002::1"; - assertEquals("9 . ipv6hint=2001:2002:0:0:0:0:0:1", stringToWireToString(str)); + String str = "9 . ipv6hint=2001:db8::1"; + assertEquals("9 . ipv6hint=2001:db8:0:0:0:0:0:1", stringToWireToString(str)); } @Test void serviceModeIpv6HintMulti() throws IOException { - String str = "2 . alpn=h2 ipv6hint=2001:2002::1,2001:2002::2"; + String str = "2 . alpn=h2 ipv6hint=2001:db8::1,2001:db8::2"; assertEquals( - "2 . alpn=h2 ipv6hint=2001:2002:0:0:0:0:0:1,2001:2002:0:0:0:0:0:2", + "2 . alpn=h2 ipv6hint=2001:db8:0:0:0:0:0:1,2001:db8:0:0:0:0:0:2", stringToWireToString(str)); } @@ -330,401 +331,241 @@ void masterFormatParsing() throws IOException { @Test void invalidText() { String str = "these are all garbage strings that should fail"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void extraQuotesInParamValues() { String str = "5 . ipv4hint=\"4.5.6.7\",\"8.9.1.2\""; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void serviceModeWithoutParameters() { String str = "1 aliasmode.example.com."; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void aliasModeWithParameters() { String str = "0 . alpn=h3"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void zeroLengthMandatory() { String str = "1 . mandatory"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void zeroLengthAlpnValue() { String str = "1 . alpn"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void zeroLengthPortValue() { String str = "1 . port"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void zeroLengthIpv4Hint() { String str = "1 . ipv4hint"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void zeroLengthEchConfig() { String str = "1 . echconfig"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void zeroLengthIpv6Hint() { String str = "1 . ipv6hint"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void emptyKey() { String str = "1 . =1234"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void emptyValue() { String str = "1 . alpn="; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void emptyKeyAndValue() { String str = "1 . ="; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void unknownKey() { String str = "1 . sport=8443"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void mandatoryListWithSelf() { String str = "1 . mandatory=alpn,mandatory alpn=h1"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void mandatoryListWithDuplicate() { String str = "1 . mandatory=alpn,ipv4hint,alpn alpn=h1 ipv4hint=1.2.3.4"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void mandatoryListWithMissingParam() { String str = "1 . mandatory=alpn,ipv4hint alpn=h1"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void portValueTooLarge() { String str = "1 . port=84438"; - assertThrows( - IllegalArgumentException.class, - () -> { - stringToWire(str); - }); + assertThrows(IllegalArgumentException.class, () -> stringToWire(str)); } @Test void portValueCharAfterInt() { String str = "1 . port=443a"; - assertThrows( - IllegalArgumentException.class, - () -> { - stringToWire(str); - }); + assertThrows(IllegalArgumentException.class, () -> stringToWire(str)); } @Test void noDefaultAlpnWithValue() { String str = "1 . no-default-alpn=true"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void emptyString() { String str = ""; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void noParamValues() { String str = "1 ."; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void svcPriorityTooHigh() { String str = "65536 . port=443"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void invalidPortKey() { String str = "1 . port<5"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void invalidSvcDomain() { String str = "1 fred..harvey port=80"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void duplicateParamKey() { String str = "1 . alpn=h2 alpn=h3"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void invalidIpv4Hint() { - String str = "1 . ipv4hint=2001::1"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + String str = "1 . ipv4hint=2001:db8::1"; + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void invalidIpv6Hint() { String str = "1 . ipv6hint=1.2.3.4"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void negativeSvcPriority() { String str = "-1 . port=80"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void svcParamUnknownKeyTooHigh() { String str = "65535 . key65536=abcdefg"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void svcParamUnknownKeyCharAfterInt() { String str = "65535 . key123a=abcdefg"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void invalidSvcParamKey() { String str = "65535 . keyBlooie=abcdefg"; - assertThrows( - TextParseException.class, - () -> { - stringToWire(str); - }); + assertThrows(TextParseException.class, () -> stringToWire(str)); } @Test void wireFormatTooShort() { byte[] wire = new byte[] {0, 1, 0, 0, 1, 0, 10}; - assertThrows( - WireParseException.class, - () -> { - wireToString(wire); - }); + assertThrows(WireParseException.class, () -> wireToString(wire)); } @Test void wireFormatTooLong() { byte[] wire = new byte[] {0, 0, 0, 1}; - assertThrows( - WireParseException.class, - () -> { - wireToString(wire); - }); + assertThrows(WireParseException.class, () -> wireToString(wire)); } @Test void wireFormatMandatoryTooLong() { byte[] wire = new byte[] {0, 1, 0, 0, 0, 0, 3, 0, 1, 55}; - assertThrows( - WireParseException.class, - () -> { - wireToString(wire); - }); + assertThrows(WireParseException.class, () -> wireToString(wire)); } @Test void wireFormatAlpnTooShort() { byte[] wire = new byte[] {0, 1, 0, 0, 1, 0, 3, 10, 1, 55}; - assertThrows( - WireParseException.class, - () -> { - wireToString(wire); - }); + assertThrows(WireParseException.class, () -> wireToString(wire)); } @Test void wireFormatNoDefaultAlpnTooLong() { byte[] wire = new byte[] {0, 1, 0, 0, 2, 0, 1, 0}; - assertThrows( - WireParseException.class, - () -> { - wireToString(wire); - }); + assertThrows(WireParseException.class, () -> wireToString(wire)); } @Test void wireFormatPortTooLong() { byte[] wire = new byte[] {0, 1, 0, 0, 3, 0, 4, 0, 0, 0, 0}; - assertThrows( - WireParseException.class, - () -> { - wireToString(wire); - }); + assertThrows(WireParseException.class, () -> wireToString(wire)); } @Test void wireFormatIpv4HintTooLong() { byte[] wire = new byte[] {0, 1, 0, 0, 4, 0, 5, 1, 2, 3, 4, 5}; - assertThrows( - WireParseException.class, - () -> { - wireToString(wire); - }); + assertThrows(WireParseException.class, () -> wireToString(wire)); } @Test void wireFormatIpv6HintTooShort() { byte[] wire = new byte[] {0, 1, 0, 0, 6, 0, 2, 1, 2}; - assertThrows( - WireParseException.class, - () -> { - wireToString(wire); - }); + assertThrows(WireParseException.class, () -> wireToString(wire)); } public static byte[] stringToWire(String str) throws IOException { From 5c0209cd1c99787a2dc464c440e2840281d67347 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 2 Feb 2021 00:04:22 +0100 Subject: [PATCH 154/431] Fix code smells found by Sonar --- src/main/java/org/xbill/DNS/Client.java | 1 + src/main/java/org/xbill/DNS/DohResolver.java | 3 ++ src/main/java/org/xbill/DNS/Resolver.java | 1 + src/main/java/org/xbill/DNS/Zone.java | 11 +++--- src/main/java/org/xbill/DNS/tools/jnamed.java | 37 +++---------------- src/main/java/org/xbill/DNS/tools/update.java | 1 + src/test/java/org/xbill/DNS/AddressTest.java | 5 +-- 7 files changed, 20 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Client.java b/src/main/java/org/xbill/DNS/Client.java index cee12def0..7590326a0 100644 --- a/src/main/java/org/xbill/DNS/Client.java +++ b/src/main/java/org/xbill/DNS/Client.java @@ -58,6 +58,7 @@ private static void close() { selectorThread.join(); } catch (InterruptedException | IOException e) { log.warn("Failed to properly shutdown", e); + Thread.currentThread().interrupt(); } } diff --git a/src/main/java/org/xbill/DNS/DohResolver.java b/src/main/java/org/xbill/DNS/DohResolver.java index 09ae8d74b..a4585f4e9 100644 --- a/src/main/java/org/xbill/DNS/DohResolver.java +++ b/src/main/java/org/xbill/DNS/DohResolver.java @@ -321,6 +321,7 @@ private CompletionStage sendAsync8(final Message query) { f.complete(response); } catch (InterruptedException | IOException e) { f.completeExceptionally(e); + Thread.currentThread().interrupt(); } }); return f; @@ -399,6 +400,7 @@ private CompletionStage sendAsync11(final Message query) { return failedFuture(new IOException("Query timed out")); } } catch (InterruptedException iex) { + Thread.currentThread().interrupt(); return failedFuture(iex); } @@ -431,6 +433,7 @@ private CompletionStage sendAsync11(final Message query) { if (isInitialRequest) { initialRequestLock.release(); } + Thread.currentThread().interrupt(); return failedFuture(iex); } diff --git a/src/main/java/org/xbill/DNS/Resolver.java b/src/main/java/org/xbill/DNS/Resolver.java index 37e43da64..1f0d1c97f 100644 --- a/src/main/java/org/xbill/DNS/Resolver.java +++ b/src/main/java/org/xbill/DNS/Resolver.java @@ -146,6 +146,7 @@ default Message send(Message query) throws IOException { CompletableFuture result = sendAsync(query).toCompletableFuture(); return result.get(getTimeout().toMillis(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); throw new IOException(e); } catch (ExecutionException e) { if (e.getCause() instanceof IOException) { diff --git a/src/main/java/org/xbill/DNS/Zone.java b/src/main/java/org/xbill/DNS/Zone.java index 58e32edd4..1c85694b5 100644 --- a/src/main/java/org/xbill/DNS/Zone.java +++ b/src/main/java/org/xbill/DNS/Zone.java @@ -141,12 +141,13 @@ public Zone(Name zone, String file) throws IOException { if (zone == null) { throw new IllegalArgumentException("no zone name specified"); } - Master m = new Master(file, zone); - Record record; + try (Master m = new Master(file, zone)) { + Record record; - origin = zone; - while ((record = m.nextRecord()) != null) { - maybeAddRecord(record); + origin = zone; + while ((record = m.nextRecord()) != null) { + maybeAddRecord(record); + } } validate(); } diff --git a/src/main/java/org/xbill/DNS/tools/jnamed.java b/src/main/java/org/xbill/DNS/tools/jnamed.java index 1fe49131b..462fdfab9 100644 --- a/src/main/java/org/xbill/DNS/tools/jnamed.java +++ b/src/main/java/org/xbill/DNS/tools/jnamed.java @@ -145,7 +145,7 @@ public jnamed(String conffile) throws IOException, ZoneTransferException { } System.out.println("jnamed: running"); } finally { - fs.close(); + br.close(); } } @@ -552,19 +552,11 @@ public void TCPclient(Socket s) { } public void serveTCP(InetAddress addr, int port) { - try { - ServerSocket sock = new ServerSocket(port, 128, addr); + try (ServerSocket sock = new ServerSocket(port, 128, addr)) { while (true) { final Socket s = sock.accept(); Thread t; - t = - new Thread( - new Runnable() { - @Override - public void run() { - TCPclient(s); - } - }); + t = new Thread(() -> TCPclient(s)); t.start(); } } catch (IOException e) { @@ -573,8 +565,7 @@ public void run() { } public void serveUDP(InetAddress addr, int port) { - try { - DatagramSocket sock = new DatagramSocket(port, addr); + try (DatagramSocket sock = new DatagramSocket(port, addr)) { final short udpLength = 512; byte[] in = new byte[udpLength]; DatagramPacket indp = new DatagramPacket(in, in.length); @@ -613,28 +604,12 @@ public void serveUDP(InetAddress addr, int port) { } public void addTCP(final InetAddress addr, final int port) { - Thread t; - t = - new Thread( - new Runnable() { - @Override - public void run() { - serveTCP(addr, port); - } - }); + Thread t = new Thread(() -> serveTCP(addr, port)); t.start(); } public void addUDP(final InetAddress addr, final int port) { - Thread t; - t = - new Thread( - new Runnable() { - @Override - public void run() { - serveUDP(addr, port); - } - }); + Thread t = new Thread(() -> serveUDP(addr, port)); t.start(); } diff --git a/src/main/java/org/xbill/DNS/tools/update.java b/src/main/java/org/xbill/DNS/tools/update.java index 34b6fa010..976bf73c3 100644 --- a/src/main/java/org/xbill/DNS/tools/update.java +++ b/src/main/java/org/xbill/DNS/tools/update.java @@ -229,6 +229,7 @@ public update(InputStream in) { try { Thread.sleep(interval); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); throw new IOException(e); } break; diff --git a/src/test/java/org/xbill/DNS/AddressTest.java b/src/test/java/org/xbill/DNS/AddressTest.java index 8e7e91222..a49ce695e 100644 --- a/src/test/java/org/xbill/DNS/AddressTest.java +++ b/src/test/java/org/xbill/DNS/AddressTest.java @@ -482,9 +482,8 @@ void getHostName() throws IOException { return answer; }); Lookup.setDefaultResolver(mockResolver); - assertThrows( - UnknownHostException.class, - () -> Address.getHostName(InetAddress.getByName("192.168.1.1"))); + InetAddress address = InetAddress.getByName("192.168.1.1"); + assertThrows(UnknownHostException.class, () -> Address.getHostName(address)); // reset resolver Lookup.refreshDefault(); From 2d69532e6e56b3254d4a2d970826f7f3d75e26de Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 3 Feb 2021 10:08:39 +0100 Subject: [PATCH 155/431] Add available error information to UnknownHostException (#154) * Add available error information to UnknownHostException Closes #149 --- src/main/java/org/xbill/DNS/Address.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Address.java b/src/main/java/org/xbill/DNS/Address.java index 536feca3a..954f7f25c 100644 --- a/src/main/java/org/xbill/DNS/Address.java +++ b/src/main/java/org/xbill/DNS/Address.java @@ -267,7 +267,8 @@ private static Record[] lookupHostName(String name, boolean all) throws UnknownH return aaaa; } } - throw new UnknownHostException("<" + name + "> could not be resolved"); + throw new UnknownHostException( + "<" + name + "> could not be resolved: " + lookup.getErrorString()); } if (!all) { return a; @@ -281,7 +282,7 @@ private static Record[] lookupHostName(String name, boolean all) throws UnknownH System.arraycopy(aaaa, 0, merged, a.length, aaaa.length); return merged; } catch (TextParseException e) { - throw new UnknownHostException("<" + name + "> is invalid"); + throw new UnknownHostException("<" + name + "> is invalid: " + e.getMessage()); } } From 9bc9f66b0dd8ab8b2f66943e0417b51eee8a114d Mon Sep 17 00:00:00 2001 From: Noa Resare Date: Tue, 2 Feb 2021 19:53:17 +0000 Subject: [PATCH 156/431] Use fail() from junit --- src/test/java/org/xbill/DNS/RecordTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/xbill/DNS/RecordTest.java b/src/test/java/org/xbill/DNS/RecordTest.java index cfd74ad59..5e06796dc 100644 --- a/src/test/java/org/xbill/DNS/RecordTest.java +++ b/src/test/java/org/xbill/DNS/RecordTest.java @@ -43,13 +43,13 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.time.Instant; import java.util.function.Supplier; -import junit.framework.Assert; import org.junit.jupiter.api.Test; class RecordTest { @@ -856,7 +856,7 @@ void testAllTypesHaveNoArgConstructor() { try { assertNotNull(proto.get()); } catch (Exception e) { - Assert.fail( + fail( "Record type " + Type.string(i) + " (" From 4e2d8a00c28fca073afbc725db451bd8ce19804e Mon Sep 17 00:00:00 2001 From: Noa Resare Date: Wed, 3 Feb 2021 09:52:16 +0000 Subject: [PATCH 157/431] Increase test coverage in LookupTest --- .../DNS/config/ResolverConfigProvider.java | 6 +- src/test/java/org/xbill/DNS/LookupTest.java | 392 +++++++++++++++--- 2 files changed, 332 insertions(+), 66 deletions(-) diff --git a/src/main/java/org/xbill/DNS/config/ResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/ResolverConfigProvider.java index 176bb9b63..5da215ae0 100644 --- a/src/main/java/org/xbill/DNS/config/ResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/ResolverConfigProvider.java @@ -17,11 +17,11 @@ public interface ResolverConfigProvider { /** * Gets the threshold for the number of dots which must appear in a name before it is considered - * absolute. The default is {@code -1}, meaning this provider does not supported reading the ndots - * configuration. + * absolute. If the interface implementation does not override this, the default implementation + * returns 1. */ default int ndots() { - return -1; + return 1; } /** Determines if this provider is enabled. */ diff --git a/src/test/java/org/xbill/DNS/LookupTest.java b/src/test/java/org/xbill/DNS/LookupTest.java index e1332d605..80029a1d8 100644 --- a/src/test/java/org/xbill/DNS/LookupTest.java +++ b/src/test/java/org/xbill/DNS/LookupTest.java @@ -2,6 +2,8 @@ package org.xbill.DNS; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -9,82 +11,346 @@ import static org.xbill.DNS.ResolverConfig.CONFIGPROVIDER_SKIP_INIT; import java.io.IOException; +import java.io.InterruptedIOException; import java.net.InetAddress; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; -import org.mockito.stubbing.Answer; public class LookupTest { + public static final Name DUMMY_NAME = Name.fromConstantString("ignored."); + private Resolver mockResolver; + + @BeforeEach + void before() { + System.setProperty(CONFIGPROVIDER_SKIP_INIT, "true"); + mockResolver = Mockito.mock(Resolver.class); + } + + @AfterEach + void after() { + System.clearProperty(CONFIGPROVIDER_SKIP_INIT); + } + + @Test + void testRun_absoluteQuery() throws Exception { + wireUpMockResolver(mockResolver, this::simpleAnswer); + + Record[] results = makeLookupWithResolver(mockResolver, "example.com.").run(); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mockResolver).send(messageCaptor.capture()); + + assertEquals( + Record.newRecord(Name.fromConstantString("example.com."), Type.A, DClass.IN, 0L), + messageCaptor.getValue().getSection(Section.QUESTION).get(0)); + + assertEquals(1, results.length); + } + + @Test + void testRun_relativeQueryIsMadeAbsolute() throws Exception { + wireUpMockResolver(mockResolver, this::simpleAnswer); + + Record[] results = makeLookupWithResolver(mockResolver, "example.com").run(); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mockResolver).send(messageCaptor.capture()); + + assertEquals( + Record.newRecord(Name.fromConstantString("example.com."), Type.A, DClass.IN, 0L), + messageCaptor.getValue().getSection(Section.QUESTION).get(0)); + + assertEquals(1, results.length); + } + + @Test + void testRun_searchAppended() throws Exception { + wireUpMockResolver(mockResolver, this::simpleAnswer); + + Lookup lookup = makeLookupWithResolver(mockResolver, "host"); + lookup.setSearchPath("example.com"); + Record[] results = lookup.run(); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mockResolver).send(messageCaptor.capture()); + + assertEquals( + Record.newRecord(Name.fromConstantString("host.example.com."), Type.A, DClass.IN, 0L), + messageCaptor.getValue().getSection(Section.QUESTION).get(0)); + + assertEquals(1, results.length); + } + + @Test + void testRun_searchPathAndTooManyDots() throws Exception { + wireUpMockResolver(mockResolver, this::simpleAnswer); + + Lookup lookup = makeLookupWithResolver(mockResolver, "host.subdomain"); + lookup.setSearchPath("example.com"); + Record[] results = lookup.run(); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mockResolver).send(messageCaptor.capture()); + + assertEquals( + Record.newRecord(Name.fromConstantString("host.subdomain."), Type.A, DClass.IN, 0L), + messageCaptor.getValue().getSection(Section.QUESTION).get(0)); + + assertEquals(1, results.length); + } + @Test - void testNdots1() throws IOException { + void testRun_firstSearchPathAppendedHitsCNAME() throws Exception { + wireUpMockResolver(mockResolver, this::maybeCnameAnswer); + + Lookup lookup = makeLookupWithResolver(mockResolver, "hostX"); + lookup.setSearchPath("first.example.com", "second.example.com"); + Record[] results = lookup.run(); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mockResolver, times(2)).send(messageCaptor.capture()); + + List queries = messageCaptor.getAllValues(); + + assertEquals( + Record.newRecord( + Name.fromConstantString("hostX.first.example.com."), Type.A, DClass.IN, 0L), + queries.get(0).getQuestion()); + assertEquals( + Record.newRecord(Name.fromConstantString("target.example.com."), Type.A, DClass.IN, 0L), + queries.get(1).getQuestion()); + + assertEquals(1, results.length); + } + + Message maybeCnameAnswer(Message query) { + return answer( + query, + name -> { + if (name.toString().equals("hostX.first.example.com.")) { + return new CNAMERecord( + DUMMY_NAME, DClass.IN, 0, Name.fromConstantString("target.example.com.")); + } + return new ARecord(DUMMY_NAME, DClass.IN, 0, InetAddress.getLoopbackAddress()); + }); + } + + @Test + void testRun_CNAMELoop() throws Exception { + wireUpMockResolver(mockResolver, this::cnameLoopAnswer); + + Lookup lookup = makeLookupWithResolver(mockResolver, "host"); + lookup.setSearchPath("first.example.com", "second.example.com"); + Record[] results = lookup.run(); + + assertNull(results); + assertEquals(Lookup.UNRECOVERABLE, lookup.getResult()); + assertEquals("CNAME loop", lookup.getErrorString()); + } + + Message cnameLoopAnswer(Message query) { + return answer( + query, + name -> { + if (name.toString().equals("first.example.com.")) { + return new CNAMERecord( + DUMMY_NAME, DClass.IN, 0, Name.fromConstantString("second.example.com.")); + } + return new CNAMERecord( + DUMMY_NAME, DClass.IN, 0, Name.fromConstantString("first.example.com.")); + }); + } + + @Test + void testRun_reuseLookup() throws Exception { + wireUpMockResolver(mockResolver, this::simpleAnswer); + + Lookup lookup = makeLookupWithResolver(mockResolver, "host"); + lookup.setSearchPath("first.example.com", "second.example.com"); + Record[] results = lookup.run(); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mockResolver, times(1)).send(messageCaptor.capture()); + + List queries = messageCaptor.getAllValues(); + + assertEquals( + Record.newRecord(Name.fromConstantString("host.first.example.com."), Type.A, DClass.IN, 0L), + queries.get(0).getQuestion()); + + assertEquals(1, results.length); + + results = lookup.run(); + assertEquals(1, results.length); + } + + @Test + void testRun_networkError() throws Exception { + when(mockResolver.send(any())).thenThrow(IOException.class); + + Lookup lookup = makeLookupWithResolver(mockResolver, "host"); + Record[] results = lookup.run(); + + assertNull(results); + assertEquals(Lookup.TRY_AGAIN, lookup.getResult()); + assertEquals("network error", lookup.getErrorString()); + } + + @Test + void testRun_timeoutError() throws Exception { + when(mockResolver.send(any())).thenThrow(InterruptedIOException.class); + + Lookup lookup = makeLookupWithResolver(mockResolver, "host"); + Record[] results = lookup.run(); + + assertNull(results); + assertEquals(Lookup.TRY_AGAIN, lookup.getResult()); + assertEquals("timed out", lookup.getErrorString()); + } + + @Test + void testRun_servFail() { + wireUpMockResolver(mockResolver, query -> fail(query, Rcode.SERVFAIL)); + + Lookup lookup = makeLookupWithResolver(mockResolver, "host"); + Record[] results = lookup.run(); + + assertNull(results); + assertEquals(Lookup.TRY_AGAIN, lookup.getResult()); + assertEquals("SERVFAIL", lookup.getErrorString()); + } + + @Test + void testRun_notFound() { + wireUpMockResolver(mockResolver, query -> fail(query, Rcode.NXDOMAIN)); + + Lookup lookup = makeLookupWithResolver(mockResolver, "host"); + Record[] results = lookup.run(); + + assertNull(results); + assertEquals(Lookup.HOST_NOT_FOUND, lookup.getResult()); + assertEquals("host not found", lookup.getErrorString()); + } + + @Test + void testRun_concatenatedNameTooLong() throws Exception { + wireUpMockResolver(mockResolver, this::simpleAnswer); + + String longName = IntStream.range(0, 63).mapToObj(i -> "a").collect(Collectors.joining()); + + Lookup lookup = makeLookupWithResolver(mockResolver, longName); + // search path has a suffix that will make the combined name too long + lookup.setSearchPath(String.format("%s.%s.%s", longName, longName, longName)); + Record[] results = lookup.run(); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mockResolver).send(messageCaptor.capture()); + + // The current (somewhat surprising) behaviour is that the NameTooLongException is silently + // ignored, and resolution falls back to converting longName to an absolute name and querying + // that + assertEquals( + Record.newRecord(Name.fromConstantString(longName + "."), Type.A, DClass.IN, 0L), + messageCaptor.getValue().getSection(Section.QUESTION).get(0)); + + assertEquals(1, results.length); + } + + @Test + void testNdots1() throws Exception { + Resolver mockResolver = Mockito.mock(Resolver.class); + wireUpMockResolver(mockResolver, this::simpleAnswer); + Lookup l = makeLookupWithResolver(mockResolver, "example.com"); + l.setSearchPath("namespace.svc.cluster.local", "svc.cluster.local", "cluster.local"); + Record[] results = l.run(); + verify(mockResolver).send(any(Message.class)); + assertEquals(1, results.length); + } + + @Test + void testNdotsFallbackToAbsolute() throws Exception { + Resolver mockResolver = Mockito.mock(Resolver.class); + wireUpMockResolver(mockResolver, this::goodAnswerWhenThreeLabels); + Lookup l = makeLookupWithResolver(mockResolver, "example.com"); + l.setSearchPath("namespace.svc.cluster.local", "svc.cluster.local", "cluster.local"); + l.setNdots(5); + Record[] results = l.run(); + verify(mockResolver, times(4)).send(any(Message.class)); + assertEquals(1, results.length); + } + + @Test + void testLookup_constructorFailsWithMetaTypes() throws TextParseException { + assertThrows(IllegalArgumentException.class, () -> new Lookup("example.com.", Type.OPT)); + } + + private Message goodAnswerWhenThreeLabels(Message query) { + return answer( + query, + name -> { + if (name.labels() == 3) { + return new ARecord(DUMMY_NAME, DClass.IN, 60, InetAddress.getLoopbackAddress()); + } else { + return null; + } + }); + } + + private Lookup makeLookupWithResolver(Resolver resolver, String name) { + Name queryName = Name.fromConstantString(name); + Lookup lookup = new Lookup(queryName, Type.A); try { - System.setProperty(CONFIGPROVIDER_SKIP_INIT, "true"); - Resolver mockResolver = Mockito.mock(Resolver.class); - Name queryName = Name.fromConstantString("example.com"); - when(mockResolver.send(any(Message.class))) - .thenAnswer( - (Answer) - invocation -> { - Message query = invocation.getArgument(0); - Message answer = new Message(query.getHeader().getID()); - answer.addRecord(query.getQuestion(), Section.QUESTION); - answer.addRecord( - new ARecord( - query.getQuestion().getName(), - DClass.IN, - 60, - InetAddress.getByName("127.0.0.1")), - Section.ANSWER); - return answer; - }); - Lookup l = new Lookup(queryName, Type.A); - l.setCache(null); - l.setResolver(mockResolver); - l.setSearchPath("namespace.svc.cluster.local", "svc.cluster.local", "cluster.local"); - Record[] results = l.run(); - verify(mockResolver, times(1)).send(any(Message.class)); - assertEquals(1, results.length); - } finally { - System.clearProperty(CONFIGPROVIDER_SKIP_INIT); + lookup.setSearchPath((String[]) null); + } catch (TextParseException e) { + throw new RuntimeException(e); } + lookup.setCache(null); + lookup.setResolver(resolver); + return lookup; } - @Test - void testNdotsFallbackToAbsolute() throws IOException { + private void wireUpMockResolver(Resolver mockResolver, Function handler) { try { - System.setProperty(CONFIGPROVIDER_SKIP_INIT, "true"); - Resolver mockResolver = Mockito.mock(Resolver.class); - Name queryName = Name.fromConstantString("example.com"); when(mockResolver.send(any(Message.class))) .thenAnswer( - (Answer) - invocation -> { - Message query = invocation.getArgument(0); - Message answer = new Message(query.getHeader().getID()); - answer.addRecord(query.getQuestion(), Section.QUESTION); - if (query.getQuestion().getName().labels() == 3) { - answer.addRecord( - new ARecord( - query.getQuestion().getName(), - DClass.IN, - 60, - InetAddress.getByName("127.0.0.1")), - Section.ANSWER); - } else { - answer.getHeader().setRcode(Rcode.NXDOMAIN); - } - return answer; - }); - Lookup l = new Lookup(queryName, Type.A); - l.setCache(null); - l.setResolver(mockResolver); - l.setNdots(5); - l.setSearchPath("namespace.svc.cluster.local", "svc.cluster.local", "cluster.local"); - Record[] results = l.run(); - verify(mockResolver, times(4)).send(any(Message.class)); - assertEquals(1, results.length); - } finally { - System.clearProperty(CONFIGPROVIDER_SKIP_INIT); + invocation -> { + Message query = invocation.getArgument(0); + return handler.apply(query); + }); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Message fail(Message query, int code) { + Message answer = new Message(query.getHeader().getID()); + answer.addRecord(query.getQuestion(), Section.QUESTION); + answer.getHeader().setRcode(code); + return answer; + } + + private Message simpleAnswer(Message query) { + Record r = new ARecord(DUMMY_NAME, DClass.IN, 60, InetAddress.getLoopbackAddress()); + return answer(query, name -> r); + } + + private Message answer(Message query, Function recordMaker) { + Message answer = new Message(query.getHeader().getID()); + answer.addRecord(query.getQuestion(), Section.QUESTION); + Name questionName = query.getQuestion().getName(); + Record response = recordMaker.apply(questionName); + if (response == null) { + answer.getHeader().setRcode(Rcode.NXDOMAIN); + } else { + answer.addRecord(response.withName(query.getQuestion().getName()), Section.ANSWER); } + return answer; } } From ada443b2211c871f3319287be56cbb3283f5c2ee Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 2 Feb 2021 23:36:27 +0100 Subject: [PATCH 158/431] Run only on master and PRs, and Sonar only on Ubuntu/x64/Java11 --- .github/workflows/build.yml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 920d36540..4f7cd0bf4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,12 @@ name: dnsjava CI -on: [push, pull_request] +on: + push: + branches: + - master + pull_request: + branches: + - master jobs: test: @@ -35,16 +41,15 @@ jobs: architecture: ${{ matrix.arch }} - name: Build with Maven + if: "${{ !(matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11') }}" + run: mvn verify -B -"Dgpg.skip" + + - name: Build with Maven and run Sonar + if: "${{ matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11' }}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - shell: bash - run: | - if [[ "{{ matrix.arch }}" == "x64" && "{{ matrix.os }}" == "ubuntu-latest" && "{{ matrix.java }}" == "11" ]]; then - mvn verify -B -"Dgpg.skip" org.sonarsource.scanner.maven:sonar-maven-plugin:sonar - else - mvn verify -B -"Dgpg.skip" - fi; + run: mvn verify -B -"Dgpg.skip" org.sonarsource.scanner.maven:sonar-maven-plugin:sonar release: if: github.ref == 'refs/heads/master' From 3be152aaa7d5bf9a7a54fe620b799fbdaeaaebb1 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 2 Feb 2021 23:59:46 +0100 Subject: [PATCH 159/431] Run JaCoCo for Sonar, remove Travis and Coveralls --- .github/workflows/build.yml | 2 +- .travis.yml | 10 ---------- pom.xml | 7 +------ 3 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4f7cd0bf4..abd16b9e9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,7 +49,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn verify -B -"Dgpg.skip" org.sonarsource.scanner.maven:sonar-maven-plugin:sonar + run: mvn -X -B -"Dgpg.skip" verify jacoco:report org.sonarsource.scanner.maven:sonar-maven-plugin:sonar release: if: github.ref == 'refs/heads/master' diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f7d6f2e3a..000000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -branches: - only: - - master - -language: java -jdk: - - openjdk8 - -install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -Dgpg.skip -B -V -script: mvn test jacoco:report coveralls:report -Dgpg.skip -B diff --git a/pom.xml b/pom.xml index 2a2e69442..4067dfb57 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,7 @@ dnsjava https://sonarcloud.io 8 + ${project.build.directory}/site/jacoco/jacoco.xml @@ -180,12 +181,6 @@ - - org.eluder.coveralls - coveralls-maven-plugin - 4.3.0 - - com.github.siom79.japicmp japicmp-maven-plugin From 3d415a529f986f3917001ffd9081e648589b8bdb Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 3 Feb 2021 22:51:27 +0100 Subject: [PATCH 160/431] Add checkstyle to address some of the worst g-j-f issues --- .gitattributes | 1 + pom.xml | 30 +++++++++++++++++++ src/main/java/org/xbill/DNS/CookieOption.java | 17 +++++++---- src/main/java/org/xbill/DNS/NioTcpClient.java | 3 +- .../org/xbill/DNS/TcpKeepaliveOption.java | 10 +++++-- 5 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..fcadb2cf9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text eol=lf diff --git a/pom.xml b/pom.xml index 4067dfb57..605235754 100644 --- a/pom.xml +++ b/pom.xml @@ -228,6 +228,36 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.1.2 + + + false + true + true + + + + + + + + + + + + com.puppycrawl.tools + checkstyle + 8.40 + + + + org.apache.maven.plugins maven-deploy-plugin diff --git a/src/main/java/org/xbill/DNS/CookieOption.java b/src/main/java/org/xbill/DNS/CookieOption.java index e062df404..9e4108af7 100644 --- a/src/main/java/org/xbill/DNS/CookieOption.java +++ b/src/main/java/org/xbill/DNS/CookieOption.java @@ -40,15 +40,19 @@ public CookieOption(byte[] clientCookie) { */ public CookieOption(byte[] clientCookie, byte[] serverCookie) { this(); - if (clientCookie == null) throw new IllegalArgumentException("client cookie must not be null"); - if (clientCookie.length != 8) + if (clientCookie == null) { + throw new IllegalArgumentException("client cookie must not be null"); + } + if (clientCookie.length != 8) { throw new IllegalArgumentException("client cookie must consist of eight bytes"); + } this.clientCookie = clientCookie; if (serverCookie != null) { int length = serverCookie.length; - if (length < 8 || length > 32) + if (length < 8 || length > 32) { throw new IllegalArgumentException("server cookie must consist of 8 to 32 bytes"); + } } this.serverCookie = serverCookie; } @@ -80,11 +84,14 @@ public Optional getServerCookie() { @Override void optionFromWire(DNSInput in) throws IOException { int length = in.remaining(); - if (length < 8) throw new WireParseException("invalid length of client cookie"); + if (length < 8) { + throw new WireParseException("invalid length of client cookie"); + } clientCookie = in.readByteArray(8); if (length > 8) { - if (length < 16 || length > 40) + if (length < 16 || length > 40) { throw new WireParseException("invalid length of server cookie"); + } serverCookie = in.readByteArray(); } } diff --git a/src/main/java/org/xbill/DNS/NioTcpClient.java b/src/main/java/org/xbill/DNS/NioTcpClient.java index 9eef1bbb3..d4061e583 100644 --- a/src/main/java/org/xbill/DNS/NioTcpClient.java +++ b/src/main/java/org/xbill/DNS/NioTcpClient.java @@ -115,7 +115,7 @@ private static class ChannelState implements KeyProcessor { int readState = 0; public void processReadyKey(SelectionKey key) { - if (key.isValid()) + if (key.isValid()) { if (key.isConnectable()) { processConnect(key); } else { @@ -126,6 +126,7 @@ public void processReadyKey(SelectionKey key) { processRead(); } } + } } void handleTransactionException(IOException e) { diff --git a/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java b/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java index ef0139681..37e3eb35a 100644 --- a/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java +++ b/src/main/java/org/xbill/DNS/TcpKeepaliveOption.java @@ -32,8 +32,9 @@ public TcpKeepaliveOption() { */ public TcpKeepaliveOption(int t) { super(EDNSOption.Code.TCP_KEEPALIVE); - if (t < 0 || t > 65535) + if (t < 0 || t > 65535) { throw new IllegalArgumentException("timeout must be betwee 0 and 65535"); + } timeout = OptionalInt.of(t); } @@ -45,9 +46,10 @@ public TcpKeepaliveOption(int t) { */ public TcpKeepaliveOption(Duration t) { super(EDNSOption.Code.TCP_KEEPALIVE); - if (t.isNegative() || t.compareTo(UPPER_LIMIT) >= 0) + if (t.isNegative() || t.compareTo(UPPER_LIMIT) >= 0) { throw new IllegalArgumentException( "timeout must be between 0 and 6553.6 seconds (exclusively)"); + } timeout = OptionalInt.of((int) t.toMillis() / 100); } @@ -101,7 +103,9 @@ void optionFromWire(DNSInput in) throws IOException { */ @Override void optionToWire(DNSOutput out) { - if (timeout.isPresent()) out.writeU16(timeout.getAsInt()); + if (timeout.isPresent()) { + out.writeU16(timeout.getAsInt()); + } } /** From 015a963b59428163ed3a47c5dab118a501e37a53 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 3 Feb 2021 23:13:29 +0100 Subject: [PATCH 161/431] Update checkout action --- .github/workflows/build.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index abd16b9e9..2e7006db4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,11 @@ jobs: name: Java ${{ matrix.java }}/${{ matrix.arch }}/${{ matrix.os }} steps: - - uses: actions/checkout@v1 + - name: Checkout + uses: actions/checkout@v2 + with: + # for Sonar + fetch-depth: 0 - name: Cache Maven dependencies uses: actions/cache@v1 From cc07807d8793ec7d2fe33ae4739d215a6938fca1 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 6 Feb 2021 15:03:03 +0100 Subject: [PATCH 162/431] Add codecov to have coverage for PRs from forks --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2e7006db4..d9ba7fdfb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,6 +48,7 @@ jobs: if: "${{ !(matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11') }}" run: mvn verify -B -"Dgpg.skip" + # doesn't work with PRs from forks, see https://jira.sonarsource.com/browse/MMF-1371 - name: Build with Maven and run Sonar if: "${{ matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11' }}" env: @@ -55,6 +56,10 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: mvn -X -B -"Dgpg.skip" verify jacoco:report org.sonarsource.scanner.maven:sonar-maven-plugin:sonar + - name: Run codecovc + if: "${{ matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11' }}" + uses: codecov/codecov-action@v1 + release: if: github.ref == 'refs/heads/master' needs: test From 96ac540db6af8e7ea644b17fb3a8db1f8ad4f32c Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 13 Feb 2021 18:51:12 +0100 Subject: [PATCH 163/431] Ensure Android API 26 compatibility using Animal Sniffer (#163) --- pom.xml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pom.xml b/pom.xml index 605235754..0ee136a5b 100644 --- a/pom.xml +++ b/pom.xml @@ -275,6 +275,33 @@ false + + + org.codehaus.mojo + animal-sniffer-maven-plugin + 1.20 + + + net.sf.androidscents.signature + android-api-level-26 + 8.0.0_r2 + + + javax.naming.NamingException + javax.naming.directory.* + sun.net.spi.nameservice.* + + + + + animal-sniffer + test + + check + + + + From 630224c9909e081d8dfdfc5c449ed415480ba355 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 14 Feb 2021 19:35:51 +0100 Subject: [PATCH 164/431] Remove pre Android API 26 code Java 8 features CompletableFuture and java.time require this anyway, there's no point keeping stuff for older versions. --- README.md | 4 ++-- .../config/AndroidResolverConfigProvider.java | 24 ------------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 3df2d19a2..b4ce920be 100644 --- a/README.md +++ b/README.md @@ -249,8 +249,8 @@ until one succeeds. - On Unix/Solaris, `/etc/resolv.conf` is parsed. - On Windows, if [JNA](https://github.com/java-native-access/jna) is available on the classpath, the `GetAdaptersAddresses` API is used. -- On Android, depending on the SDK level, either the properties `net.dns[1234]` - or the `ConnectivityManager` is used (requires initialization). +- On Android the `ConnectivityManager` is used (requires initialization using + `org.xbill.DNS.config.AndroidResolverConfigProvider.setContext`). - The `sun.net.dns.ResolverConfiguration` class is queried if enabled. - If available and no servers have been found yet, [JNDI-DNS](https://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-dns.html) is used. diff --git a/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java index e3df40779..85c97f4c2 100644 --- a/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/AndroidResolverConfigProvider.java @@ -5,8 +5,6 @@ import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.Network; -import android.os.Build; -import android.os.SystemProperties; import java.net.InetAddress; import java.net.InetSocketAddress; import lombok.extern.slf4j.Slf4j; @@ -33,28 +31,6 @@ public static void setContext(Context ctx) { @Override public void initialize() throws InitializationException { - // This originally looked for all lines containing .dns; but - // http://code.google.com/p/android/issues/detail?id=2207#c73 indicates - // that net.dns* should always be the active nameservers, so we use those. - // Starting with Android 8 (API 26), the net.dns[1234] properties are no longer available: - // https://developer.android.com/about/versions/oreo/android-8.0-changes.html#o-pri - if (Build.VERSION.SDK_INT >= 26) { - initializeApi26Nameservers(); - } else { - initializeNameservers(); - } - } - - private void initializeNameservers() { - for (int i = 1; i <= 4; i++) { - String server = SystemProperties.get("net.dns" + i); - if (server != null && !server.isEmpty()) { - addNameserver(new InetSocketAddress(server, SimpleResolver.DEFAULT_PORT)); - } - } - } - - private void initializeApi26Nameservers() throws InitializationException { if (context == null) { throw new InitializationException("Context must be initialized by calling setContext"); } From 2d19080b8c537dd7566440a2aa54d06d37bb5d5e Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 14 Feb 2021 19:39:57 +0100 Subject: [PATCH 165/431] Run on Ubuntu 18 and 20, forget about the soon unsupported 16 Do not use -latest anymore as GitHubs migration process takes a long time and it's unpredictable if a job runs on 18 or 20. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d9ba7fdfb..bc561c15b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - os: [ ubuntu-16.04, ubuntu-latest, windows-latest ] + os: [ ubuntu-18.04, ubuntu-20.04, windows-latest ] java: [ '8', '11' ] arch: [ 'x32', 'x64' ] exclude: From 6f63bf28bc136e5088b3972cd63983ddb3deda61 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 14 Feb 2021 19:41:08 +0100 Subject: [PATCH 166/431] Run Sonar on pushes, not pull requests --- .github/workflows/build.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc561c15b..6f5152a46 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,9 +18,9 @@ jobs: java: [ '8', '11' ] arch: [ 'x32', 'x64' ] exclude: - - os: ubuntu-16.04 + - os: ubuntu-18.04 arch: x32 - - os: ubuntu-latest + - os: ubuntu-20.04 arch: x32 name: Java ${{ matrix.java }}/${{ matrix.arch }}/${{ matrix.os }} @@ -45,25 +45,25 @@ jobs: architecture: ${{ matrix.arch }} - name: Build with Maven - if: "${{ !(matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11') }}" + if: "${{ !(matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11') || github.event.pull_request.head.repo.full_name != 'dnsjava/dnsjava' }}" run: mvn verify -B -"Dgpg.skip" # doesn't work with PRs from forks, see https://jira.sonarsource.com/browse/MMF-1371 - name: Build with Maven and run Sonar - if: "${{ matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11' }}" + if: "${{ github.event.pull_request.head.repo.full_name == 'dnsjava/dnsjava' && matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11' }}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: mvn -X -B -"Dgpg.skip" verify jacoco:report org.sonarsource.scanner.maven:sonar-maven-plugin:sonar - name: Run codecovc - if: "${{ matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' && matrix.java == '11' }}" + if: "${{ matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11' }}" uses: codecov/codecov-action@v1 release: if: github.ref == 'refs/heads/master' needs: test - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v1 @@ -71,7 +71,7 @@ jobs: uses: actions/cache@v1 with: path: ~/.m2 - key: m2-cache-8-x64-ubuntu-latest + key: m2-cache-8-x64-ubuntu-20.04 - name: Set up JDK 8 uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 From 5722f1db7a5b967608ef68e196d26d3d1ee7135e Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 14 Feb 2021 19:49:41 +0100 Subject: [PATCH 167/431] Revert to using Zulu via the standard action The joschi action resulted in a 404 --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f5152a46..192529e49 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,12 +16,12 @@ jobs: matrix: os: [ ubuntu-18.04, ubuntu-20.04, windows-latest ] java: [ '8', '11' ] - arch: [ 'x32', 'x64' ] + arch: [ 'x86', 'x64' ] exclude: - os: ubuntu-18.04 - arch: x32 + arch: x86 - os: ubuntu-20.04 - arch: x32 + arch: x86 name: Java ${{ matrix.java }}/${{ matrix.arch }}/${{ matrix.os }} @@ -39,7 +39,7 @@ jobs: key: m2-cache-${{ matrix.java }}-${{ matrix.arch }}-${{ matrix.os }} - name: Set up JDK ${{ matrix.java }} - uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 + uses: actions/setup-java@v1 with: java-version: ${{ matrix.java }} architecture: ${{ matrix.arch }} From 3e1497447e9b9626cf339ac9b595cc98d90983ea Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 16 Feb 2021 00:09:46 +0100 Subject: [PATCH 168/431] Replace the coverage badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b4ce920be..e751915d0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![Build Status](https://travis-ci.org/dnsjava/dnsjava.svg?branch=master)](https://travis-ci.org/dnsjava/dnsjava) -[![Coverage Status](https://coveralls.io/repos/dnsjava/dnsjava/badge.svg)](https://coveralls.io/r/dnsjava/dnsjava) +[![codecov](https://codecov.io/gh/dnsjava/dnsjava/branch/master/graph/badge.svg?token=FKmcwl1Oys)](https://codecov.io/gh/dnsjava/dnsjava) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dnsjava/dnsjava/badge.svg)](https://search.maven.org/artifact/dnsjava/dnsjava) [![Javadocs](http://javadoc.io/badge/dnsjava/dnsjava.svg)](http://javadoc.io/doc/dnsjava/dnsjava) From 8535a5b81adc0bc6f5ff8cba14bac60dc6bd99c2 Mon Sep 17 00:00:00 2001 From: Noa Resare Date: Mon, 15 Feb 2021 22:03:02 +0000 Subject: [PATCH 169/431] Have the 3.4.0-SNAPSHOT version be named that and nothing else --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0ee136a5b..d58e7996e 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.4.0-SNAPSOT + 3.4.0-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache From 0697e5b9482ab081e74fd3609f91399227a25a22 Mon Sep 17 00:00:00 2001 From: Noa Resare Date: Mon, 15 Feb 2021 20:52:52 +0000 Subject: [PATCH 170/431] Have constructing relative Name with length() == MAXNAME fail The Name() constructor will currently fail if it's length() would end up being longer than MAXNAME (255). However, there is an edge case where a relative name can be exactly MAXNAME long. This is legal but the lookup mechanism will then fail to make the name absolute by appending an empty label to be able to use it for lookups. --- src/main/java/org/xbill/DNS/Name.java | 8 ++++++++ src/test/java/org/xbill/DNS/NameTest.java | 22 ++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Name.java b/src/main/java/org/xbill/DNS/Name.java index ec74587e4..9e9737e58 100644 --- a/src/main/java/org/xbill/DNS/Name.java +++ b/src/main/java/org/xbill/DNS/Name.java @@ -271,6 +271,14 @@ public Name(String s, Name origin) throws TextParseException { if (origin != null && !absolute) { appendFromString(s, origin.name, origin.offset(0), origin.labels); } + // A relative name that is MAXNAME octets long is a strange and wonderful thing. + // Not technically in violation, but it can not be used for queries as it needs + // to be made absolute by appending at the very least the an empty label at the + // end, which there is no room for. To make life easier for everyone, let's only + // allow Names that are MAXNAME long if they are absolute. + if (!absolute && length() == MAXNAME) { + throw parseException(s, "Name too long"); + } } /** diff --git a/src/test/java/org/xbill/DNS/NameTest.java b/src/test/java/org/xbill/DNS/NameTest.java index 7aeff8c7c..ed05dcacf 100644 --- a/src/test/java/org/xbill/DNS/NameTest.java +++ b/src/test/java/org/xbill/DNS/NameTest.java @@ -34,6 +34,7 @@ // package org.xbill.DNS; +import static java.lang.String.format; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -45,6 +46,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -286,15 +289,26 @@ void ctor_toobig_label() { } @Test - void ctor_max_length_rel() throws TextParseException { - // relative name with three 63-char labels and a 62-char label + void ctor_length_too_long_rel() { + // We want to fail to crate this as there is no way to make a Name that long absolute, + // which means that it can not be used for lookups or updates. + String label63 = IntStream.range(0, 63).mapToObj(i -> "a").collect(Collectors.joining()); + String label62 = IntStream.range(0, 62).mapToObj(i -> "a").collect(Collectors.joining()); + assertThrows( + TextParseException.class, + () -> new Name(format("%s.%s.%s.%s", label63, label63, label63, label62))); + } + + @Test + void ctor_longest_allowed_rel() throws TextParseException { + // relative name with three 63-char labels and a 61-char label Name n = new Name( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"); + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"); assertFalse(n.isAbsolute()); assertFalse(n.isWild()); assertEquals(4, n.labels()); - assertEquals(255, n.length()); + assertEquals(254, n.length()); } @Test From 89ee0d62fa77cbfe886d5036283618c93ab1a26e Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 19 Feb 2021 21:55:17 +0100 Subject: [PATCH 171/431] Bind checkstyle:check to verifiy phase --- pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pom.xml b/pom.xml index d58e7996e..73379e74c 100644 --- a/pom.xml +++ b/pom.xml @@ -232,6 +232,15 @@ org.apache.maven.plugins maven-checkstyle-plugin 3.1.2 + + + check + + check + + verify + + + checkstyle/checkstyle-config.xml false true true - - - - - - - - diff --git a/lombok.config b/src/main/java/lombok.config similarity index 100% rename from lombok.config rename to src/main/java/lombok.config From 48785dd5d9b51e8c65338c37a97b65c8b23e2bb8 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 26 Feb 2021 00:05:32 +0100 Subject: [PATCH 177/431] Expand wildcard names in Zone lookups Closes #169 --- src/main/java/org/xbill/DNS/RRset.java | 22 ++++ src/main/java/org/xbill/DNS/Zone.java | 60 ++++++----- src/test/java/org/xbill/DNS/RRsetTest.java | 28 +++++ src/test/java/org/xbill/DNS/ZoneTest.java | 120 +++++++++++++++++++++ 4 files changed, 203 insertions(+), 27 deletions(-) create mode 100644 src/test/java/org/xbill/DNS/ZoneTest.java diff --git a/src/main/java/org/xbill/DNS/RRset.java b/src/main/java/org/xbill/DNS/RRset.java index 8233a7cb6..4a338f16e 100644 --- a/src/main/java/org/xbill/DNS/RRset.java +++ b/src/main/java/org/xbill/DNS/RRset.java @@ -8,6 +8,8 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Objects; +import lombok.EqualsAndHashCode; /** * A set of Records with the same name, type, and class. Also included are all RRSIG records signing @@ -17,6 +19,7 @@ * @see RRSIGRecord * @author Brian Wellington */ +@EqualsAndHashCode(of = {"rrs", "sigs"}) public class RRset implements Serializable { private final ArrayList rrs; private final ArrayList sigs; @@ -35,6 +38,19 @@ public RRset(Record record) { addRR(record); } + /** + * Creates an RRset and sets its contents to the specified record(s) + * + * @param records The records to add to the set. See {@link #addRR(Record)} for restrictions. + */ + public RRset(Record... records) { + this(); + Objects.requireNonNull(records); + for (Record r : records) { + addRR(r); + } + } + /** Creates an RRset with the contents of an existing RRset */ public RRset(RRset rrset) { rrs = new ArrayList<>(rrset.rrs); @@ -47,6 +63,9 @@ public RRset(RRset rrset) { * Adds a signature to this RRset. If the TTL of the added signature is not the same as existing * records in the RRset, all records are set to the lowest TTL of either the added record or the * existing records. + * + * @throws IllegalArgumentException if the RRset already contains records and the signature to add + * does not match. */ public void addRR(RRSIGRecord r) { addRR(r, sigs); @@ -56,6 +75,9 @@ public void addRR(RRSIGRecord r) { * Adds a Record to this RRset. If the TTL of the added record is not the same as existing records * in the RRset, all records are set to the lowest TTL of either the added record or the existing * records. + * + * @throws IllegalArgumentException if the RRset already contains records and the record to add + * does not match. */ public void addRR(Record r) { if (r instanceof RRSIGRecord) { diff --git a/src/main/java/org/xbill/DNS/Zone.java b/src/main/java/org/xbill/DNS/Zone.java index 84a987661..87a1f35d9 100644 --- a/src/main/java/org/xbill/DNS/Zone.java +++ b/src/main/java/org/xbill/DNS/Zone.java @@ -337,25 +337,18 @@ private synchronized void removeRRset(Name name, int type) { } private synchronized SetResponse lookup(Name name, int type) { - int labels; - int olabels; - int tlabels; - RRset rrset; - Name tname; - Object types; - SetResponse sr; - if (!name.subdomain(origin)) { return SetResponse.ofType(SetResponse.NXDOMAIN); } - labels = name.labels(); - olabels = origin.labels(); + int labels = name.labels(); + int olabels = origin.labels(); - for (tlabels = olabels; tlabels <= labels; tlabels++) { + for (int tlabels = olabels; tlabels <= labels; tlabels++) { boolean isOrigin = tlabels == olabels; boolean isExact = tlabels == labels; + Name tname; if (isOrigin) { tname = origin; } else if (isExact) { @@ -364,7 +357,7 @@ private synchronized SetResponse lookup(Name name, int type) { tname = new Name(name, labels - tlabels); } - types = exactName(tname); + Object types = exactName(tname); if (types == null) { continue; } @@ -379,9 +372,8 @@ private synchronized SetResponse lookup(Name name, int type) { /* If this is an ANY lookup, return everything. */ if (isExact && type == Type.ANY) { - sr = new SetResponse(SetResponse.SUCCESSFUL); - RRset[] sets = allRRsets(types); - for (RRset set : sets) { + SetResponse sr = new SetResponse(SetResponse.SUCCESSFUL); + for (RRset set : allRRsets(types)) { sr.addRRset(set); } return sr; @@ -392,18 +384,16 @@ private synchronized SetResponse lookup(Name name, int type) { * Otherwise, look for a DNAME. */ if (isExact) { - rrset = oneRRset(types, type); + RRset rrset = oneRRset(types, type); if (rrset != null) { - sr = new SetResponse(SetResponse.SUCCESSFUL); - sr.addRRset(rrset); - return sr; + return new SetResponse(SetResponse.SUCCESSFUL, rrset); } rrset = oneRRset(types, Type.CNAME); if (rrset != null) { return new SetResponse(SetResponse.CNAME, rrset); } } else { - rrset = oneRRset(types, Type.DNAME); + RRset rrset = oneRRset(types, Type.DNAME); if (rrset != null) { return new SetResponse(SetResponse.DNAME, rrset); } @@ -417,18 +407,23 @@ private synchronized SetResponse lookup(Name name, int type) { if (hasWild) { for (int i = 0; i < labels - olabels; i++) { - tname = name.wild(i + 1); - - types = exactName(tname); + Name tname = name.wild(i + 1); + Object types = exactName(tname); if (types == null) { continue; } - rrset = oneRRset(types, type); - if (rrset != null) { - sr = new SetResponse(SetResponse.SUCCESSFUL); - sr.addRRset(rrset); + if (type == Type.ANY) { + SetResponse sr = new SetResponse(SetResponse.SUCCESSFUL); + for (RRset set : allRRsets(types)) { + sr.addRRset(expandSet(set, name)); + } return sr; + } else { + RRset rrset = oneRRset(types, type); + if (rrset != null) { + return new SetResponse(SetResponse.SUCCESSFUL, expandSet(rrset, name)); + } } } } @@ -436,6 +431,17 @@ private synchronized SetResponse lookup(Name name, int type) { return SetResponse.ofType(SetResponse.NXDOMAIN); } + private RRset expandSet(RRset set, Name tname) { + RRset expandedSet = new RRset(); + for (Record r : set.rrs()) { + expandedSet.addRR(r.withName(tname)); + } + for (RRSIGRecord r : set.sigs()) { + expandedSet.addRR(r.withName(tname)); + } + return expandedSet; + } + /** * Looks up Records in the Zone. This follows CNAMEs and wildcards. * diff --git a/src/test/java/org/xbill/DNS/RRsetTest.java b/src/test/java/org/xbill/DNS/RRsetTest.java index 0131391fe..b176dad7d 100644 --- a/src/test/java/org/xbill/DNS/RRsetTest.java +++ b/src/test/java/org/xbill/DNS/RRsetTest.java @@ -44,7 +44,10 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.time.Instant; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -218,6 +221,31 @@ void ctor_1arg() { assertEquals(2, sigs.size()); } + @Test + void ctor_vararg() { + RRset set = new RRset(m_a1, m_a2); + assertEquals(Stream.of(m_a1, m_a2).collect(Collectors.toList()), set.rrs()); + assertEquals(Collections.emptyList(), set.sigs()); + } + + @Test + void ctor_vararg_sig() { + RRset set = new RRset(m_a1, m_a2, m_s1); + assertEquals(Stream.of(m_a1, m_a2).collect(Collectors.toList()), set.rrs()); + assertEquals(Collections.singletonList(m_s1), set.sigs()); + } + + @Test + void ctor_vararg_mismatch() { + TXTRecord txt = new TXTRecord(m_name, DClass.IN, 3600, "test"); + assertThrows(IllegalArgumentException.class, () -> new RRset(m_a1, m_a2, txt)); + } + + @Test + void ctor_vararg_null() { + assertThrows(NullPointerException.class, () -> new RRset((Record[]) null)); + } + @Test void test_toString() { m_rs.addRR(m_a1); diff --git a/src/test/java/org/xbill/DNS/ZoneTest.java b/src/test/java/org/xbill/DNS/ZoneTest.java new file mode 100644 index 000000000..c1ab149d0 --- /dev/null +++ b/src/test/java/org/xbill/DNS/ZoneTest.java @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; + +class ZoneTest { + private static final ARecord A_TEST; + private static final AAAARecord AAAA_1_TEST; + private static final AAAARecord AAAA_2_TEST; + private static final ARecord A_WILD; + private static final TXTRecord TXT_WILD; + private static final Zone ZONE; + + static { + try { + Name nameZone = new Name("example."); + InetAddress localhost4 = InetAddress.getByName("127.0.0.1"); + InetAddress localhost6a = InetAddress.getByName("::1"); + InetAddress localhost6b = InetAddress.getByName("::2"); + A_TEST = new ARecord(new Name("test", nameZone), DClass.IN, 3600, localhost4); + AAAA_1_TEST = new AAAARecord(new Name("test", nameZone), DClass.IN, 3600, localhost6a); + AAAA_2_TEST = new AAAARecord(new Name("test", nameZone), DClass.IN, 3600, localhost6b); + A_WILD = new ARecord(new Name("*", nameZone), DClass.IN, 3600, localhost4); + TXT_WILD = new TXTRecord(new Name("*", nameZone), DClass.IN, 3600, "sometext"); + + Record[] zoneRecords = + new Record[] { + new SOARecord( + nameZone, + DClass.IN, + 3600L, + Name.fromConstantString("nameserver."), + new Name("hostmaster", nameZone), + 1, + 21600L, + 7200L, + 2160000L, + 3600L), + new NSRecord(nameZone, DClass.IN, 300L, Name.fromConstantString("nameserver.")), + A_TEST, + AAAA_1_TEST, + AAAA_2_TEST, + A_WILD, + TXT_WILD, + }; + ZONE = new Zone(nameZone, zoneRecords); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Test + void exactNameExistingALookup() { + Name testName = Name.fromConstantString("test.example."); + SetResponse resp = ZONE.findRecords(testName, Type.A); + assertEquals(oneRRset(A_TEST), resp.answers()); + } + + @Test + void exactNameTwoAaaaLookup() { + Name testName = Name.fromConstantString("test.example."); + SetResponse resp = ZONE.findRecords(testName, Type.AAAA); + assertEquals(oneRRset(AAAA_1_TEST, AAAA_2_TEST), resp.answers()); + } + + @Test + void exactNameAnyLookup() { + Name testName = Name.fromConstantString("test.example."); + SetResponse resp = ZONE.findRecords(testName, Type.ANY); + assertTrue(resp.isSuccessful()); + assertEquals(listOf(new RRset(A_TEST), new RRset(AAAA_1_TEST, AAAA_2_TEST)), resp.answers()); + } + + @Test + void wildNameExistingALookup() { + Name testName = Name.fromConstantString("undefined.example."); + SetResponse resp = ZONE.findRecords(testName, Type.A); + assertEquals(oneRRset(A_WILD.withName(testName)), resp.answers()); + } + + @Test + void wildNameExistingTxtLookup() { + Name testName = Name.fromConstantString("undefined.example."); + SetResponse resp = ZONE.findRecords(testName, Type.TXT); + assertEquals(oneRRset(TXT_WILD.withName(testName)), resp.answers()); + } + + @Test + void wildNameNonExistingMxLookup() { + SetResponse resp = ZONE.findRecords(Name.fromConstantString("undefined.example."), Type.MX); + assertTrue(resp.isNXDOMAIN()); + } + + @Test + void wildNameAnyLookup() { + Name testName = Name.fromConstantString("undefined.example."); + SetResponse resp = ZONE.findRecords(testName, Type.ANY); + assertTrue(resp.isSuccessful()); + assertEquals( + listOf(new RRset(A_WILD.withName(testName)), new RRset(TXT_WILD.withName(testName))), + resp.answers()); + } + + private static List listOf(RRset... rrsets) { + return Stream.of(rrsets).collect(Collectors.toList()); + } + + private static List oneRRset(Record... r) { + return Collections.singletonList(new RRset(r)); + } +} From 054b5077711966ad7a81a4b1313e9a007f09ad5b Mon Sep 17 00:00:00 2001 From: Walter Johnson Date: Fri, 12 Mar 2021 13:05:43 -0500 Subject: [PATCH 178/431] Properly close UDP channel upon error --- src/main/java/org/xbill/DNS/NioUdpClient.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/NioUdpClient.java b/src/main/java/org/xbill/DNS/NioUdpClient.java index 2c7df7264..cd39d474b 100644 --- a/src/main/java/org/xbill/DNS/NioUdpClient.java +++ b/src/main/java/org/xbill/DNS/NioUdpClient.java @@ -138,9 +138,14 @@ public void processReadyKey(SelectionKey key) { private void silentCloseChannel() { try { channel.disconnect(); - channel.close(); } catch (IOException e) { // ignore, we either already have everything we need or can't do anything + } finally { + try { + channel.close(); + } catch (IOException e) { + // ignore + } } } } From d010ef7eb03ab33a6adbb05f72f5d5ad92ec0c0c Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 21 Mar 2021 19:14:08 +0100 Subject: [PATCH 179/431] Run Sonar on master again --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 192529e49..31b3c78a8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,7 @@ jobs: # doesn't work with PRs from forks, see https://jira.sonarsource.com/browse/MMF-1371 - name: Build with Maven and run Sonar - if: "${{ github.event.pull_request.head.repo.full_name == 'dnsjava/dnsjava' && matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11' }}" + if: "${{ (github.ref == 'refs/heads/master' || github.event.pull_request.head.repo.full_name == 'dnsjava/dnsjava') && matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11' }}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From fe85c1cfed748a90254cc357912173df24656b63 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 21 Mar 2021 19:37:37 +0100 Subject: [PATCH 180/431] Do not build twice on master --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 31b3c78a8..5c220c40b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,7 +45,7 @@ jobs: architecture: ${{ matrix.arch }} - name: Build with Maven - if: "${{ !(matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11') || github.event.pull_request.head.repo.full_name != 'dnsjava/dnsjava' }}" + if: "${{ !(matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11') || (github.event.type == 'PullRequestEvent' && github.event.pull_request.head.repo.full_name != 'dnsjava/dnsjava') }}" run: mvn verify -B -"Dgpg.skip" # doesn't work with PRs from forks, see https://jira.sonarsource.com/browse/MMF-1371 @@ -54,7 +54,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn -X -B -"Dgpg.skip" verify jacoco:report org.sonarsource.scanner.maven:sonar-maven-plugin:sonar + run: mvn -B -"Dgpg.skip" verify jacoco:report org.sonarsource.scanner.maven:sonar-maven-plugin:sonar - name: Run codecovc if: "${{ matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11' }}" From 505b4ce94744408aa70cb9e8908ddf3a1aa1919c Mon Sep 17 00:00:00 2001 From: Paulo Costa Date: Mon, 22 Mar 2021 17:42:11 -0300 Subject: [PATCH 181/431] Fix load balancing (#179) * Fix load balancing `lbStart.updateAndGet(i -> i++ % resolvers.size())` is a no-op: `i++` increments the local variable, which is lost, and the returned value is simply `i % resolvers.size()` * Fix precedence * Update ExtendedResolver.java --- src/main/java/org/xbill/DNS/ExtendedResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index 55a64716a..9286880e5 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -41,7 +41,7 @@ private static class Resolution { resolvers = new ArrayList<>(eres.resolvers); endTime = System.nanoTime() + eres.timeout.toNanos(); if (eres.loadBalance) { - int start = eres.lbStart.updateAndGet(i -> i++ % resolvers.size()); + int start = eres.lbStart.updateAndGet(i -> (i + 1) % resolvers.size()); if (start > 0) { List shuffle = new ArrayList<>(resolvers.size()); for (int i = 0; i < resolvers.size(); i++) { From bd37aeab7bc54831985147a67a4d9e41b637adbf Mon Sep 17 00:00:00 2001 From: Pascal K Date: Mon, 5 Apr 2021 21:13:09 +0200 Subject: [PATCH 182/431] Fix restoring active position on byte buffers (#184) Wrong restored position lead to incomplete EDNS0 options parsing. --- src/main/java/org/xbill/DNS/DNSInput.java | 2 +- src/test/java/org/xbill/DNS/DNSInputTest.java | 17 ++ .../java/org/xbill/DNS/EDNS0Messages.java | 177 ++++++++++++++++++ 3 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/xbill/DNS/EDNS0Messages.java diff --git a/src/main/java/org/xbill/DNS/DNSInput.java b/src/main/java/org/xbill/DNS/DNSInput.java index 51a84531c..ce8b9bd80 100644 --- a/src/main/java/org/xbill/DNS/DNSInput.java +++ b/src/main/java/org/xbill/DNS/DNSInput.java @@ -92,7 +92,7 @@ public void restoreActive(int pos) { if (pos > byteBuffer.capacity()) { throw new IllegalArgumentException("cannot set active region past end of input"); } - byteBuffer.limit(byteBuffer.position()); + byteBuffer.limit(pos); } /** diff --git a/src/test/java/org/xbill/DNS/DNSInputTest.java b/src/test/java/org/xbill/DNS/DNSInputTest.java index 0a304c034..1c2294f0b 100644 --- a/src/test/java/org/xbill/DNS/DNSInputTest.java +++ b/src/test/java/org/xbill/DNS/DNSInputTest.java @@ -137,6 +137,23 @@ void save_restore() { assertEquals(6, m_di.remaining()); } + @Test + void save_set_restore() { + m_di.jump(4); + assertEquals(4, m_di.current()); + assertEquals(6, m_di.remaining()); + + int save = m_di.saveActive(); + assertEquals(10, save); + assertEquals(6, m_di.remaining()); + + m_di.setActive(4); + assertEquals(4, m_di.remaining()); + + m_di.restoreActive(save); + assertEquals(6, m_di.remaining()); + } + @Test void readU8_basic() throws WireParseException { int v1 = m_di.readU8(); diff --git a/src/test/java/org/xbill/DNS/EDNS0Messages.java b/src/test/java/org/xbill/DNS/EDNS0Messages.java new file mode 100644 index 000000000..c46ad9cf7 --- /dev/null +++ b/src/test/java/org/xbill/DNS/EDNS0Messages.java @@ -0,0 +1,177 @@ +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import java.io.IOException; +import org.junit.jupiter.api.Test; + +public class EDNS0Messages { + + /* dig +nocookie foo.dns.addere.ch */ + private static final byte[] EDNS0_EMPTY = { + 0x7d, 0x59, 0x01, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x66, 0x6f, 0x6f, + 0x03, 0x64, 0x6e, 0x73, 0x06, 0x61, 0x64, 0x64, 0x65, 0x72, 0x65, 0x02, 0x63, 0x68, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + /* dig foo.dns.addere.ch */ + private static final byte[] EDNS0_COOKIE = { + (byte) 0x95, + (byte) 0xa6, + 0x01, + 0x20, + 0x00, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0x03, + 0x66, + 0x6f, + 0x6f, + 0x03, + 0x64, + 0x6e, + 0x73, + 0x06, + 0x61, + 0x64, + 0x64, + 0x65, + 0x72, + 0x65, + 0x02, + 0x63, + 0x68, + 0x00, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x00, + 0x29, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0c, + 0x00, + 0x0a, + 0x00, + 0x08, + 0x28, + 0x75, + (byte) 0x83, + 0x7f, + 0x00, + 0x32, + (byte) 0xe5, + 0x6f + }; + + /* dig +keepalive foo.dns.addere.ch */ + private static final byte[] EDNS0_COOKIE_KEEPALIVE = { + (byte) 0x8e, + (byte) 0xdd, + 0x01, + 0x20, + 0x00, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0x03, + 0x66, + 0x6f, + 0x6f, + 0x03, + 0x64, + 0x6e, + 0x73, + 0x06, + 0x61, + 0x64, + 0x64, + 0x65, + 0x72, + 0x65, + 0x02, + 0x63, + 0x68, + 0x00, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x00, + 0x29, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0x0a, + 0x00, + 0x08, + (byte) 0xeb, + (byte) 0xed, + (byte) 0xfc, + 0x4c, + 0x1c, + 0x45, + 0x20, + 0x01, + 0x00, + 0x0b, + 0x00, + 0x00 + }; + + /* dig +keepalive +subnet=1.2.3.4 foo.dns.addere.ch */ + private static final byte[] EDNS0_SUBNET_COOKIE_KEEPALIVE = { + 0x42, 0x3a, 0x01, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x66, 0x6f, 0x6f, + 0x03, 0x64, 0x6e, 0x73, 0x06, 0x61, 0x64, 0x64, 0x65, 0x72, 0x65, 0x02, 0x63, 0x68, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x08, + 0x00, 0x08, 0x00, 0x01, 0x20, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x0a, 0x00, 0x08, 0x7c, 0x2e, + 0x0d, 0x0e, (byte) 0x95, (byte) 0xf3, 0x4d, (byte) 0xff, 0x00, 0x0b, 0x00, 0x00 + }; + + @Test + void testParseEdns0Empty() throws IOException { + Message msg = new Message(EDNS0_EMPTY); + assertArrayEquals(EDNS0_EMPTY, msg.toWire()); + } + + @Test + void testParseEdns0Cookie() throws IOException { + Message msg = new Message(EDNS0_COOKIE); + assertArrayEquals(EDNS0_COOKIE, msg.toWire()); + } + + @Test + void testParseEdns0CookieKeepalive() throws IOException { + Message msg = new Message(EDNS0_COOKIE_KEEPALIVE); + assertArrayEquals(EDNS0_COOKIE_KEEPALIVE, msg.toWire()); + } + + @Test + void testParseEdns0SubnetCookieKeepalive() throws IOException { + Message msg = new Message(EDNS0_SUBNET_COOKIE_KEEPALIVE); + assertArrayEquals(EDNS0_SUBNET_COOKIE_KEEPALIVE, msg.toWire()); + } +} From ba97e03ede0a7fbd4fc26c3a39d316187c97c8ef Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 21 Mar 2021 21:13:30 +0100 Subject: [PATCH 183/431] Replace wildcard imports with explicit imports to avoid conflicts Record would otherwise conflict with java.lang.Record as of Java 14 --- .../org/xbill/DNS/lookup/LookupSessionTest.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/xbill/DNS/lookup/LookupSessionTest.java b/src/test/java/org/xbill/DNS/lookup/LookupSessionTest.java index b1d9620fa..3c9af7d05 100644 --- a/src/test/java/org/xbill/DNS/lookup/LookupSessionTest.java +++ b/src/test/java/org/xbill/DNS/lookup/LookupSessionTest.java @@ -38,7 +38,21 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.xbill.DNS.*; +import org.xbill.DNS.ARecord; +import org.xbill.DNS.CNAMERecord; +import org.xbill.DNS.Cache; +import org.xbill.DNS.Credibility; +import org.xbill.DNS.DClass; +import org.xbill.DNS.DNAMERecord; +import org.xbill.DNS.Message; +import org.xbill.DNS.Name; +import org.xbill.DNS.RRset; +import org.xbill.DNS.Rcode; +import org.xbill.DNS.Record; +import org.xbill.DNS.Resolver; +import org.xbill.DNS.Section; +import org.xbill.DNS.SetResponse; +import org.xbill.DNS.Type; @ExtendWith(MockitoExtension.class) class LookupSessionTest { From 159576a4e37bcb17be7100828a5e4b15f192a82f Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 5 Apr 2021 21:31:10 +0200 Subject: [PATCH 184/431] Revert fe85c1cfed748a90254cc357912173df24656b63 The or condition doesn't work resulting in no Java 11 build from forks at all. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5c220c40b..e6e3fe502 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,7 +45,7 @@ jobs: architecture: ${{ matrix.arch }} - name: Build with Maven - if: "${{ !(matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11') || (github.event.type == 'PullRequestEvent' && github.event.pull_request.head.repo.full_name != 'dnsjava/dnsjava') }}" + if: "${{ !(matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11') || github.event.pull_request.head.repo.full_name != 'dnsjava/dnsjava' }}" run: mvn verify -B -"Dgpg.skip" # doesn't work with PRs from forks, see https://jira.sonarsource.com/browse/MMF-1371 From fb4889ee7a73f391f43bf6dc78b019d87ae15f15 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 5 Apr 2021 21:32:30 +0200 Subject: [PATCH 185/431] Remove BC after tests for consistency (#178) --- src/test/java/org/xbill/DNS/DNSSECWithBCProviderTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/org/xbill/DNS/DNSSECWithBCProviderTest.java b/src/test/java/org/xbill/DNS/DNSSECWithBCProviderTest.java index f5f44cd69..7d133d666 100644 --- a/src/test/java/org/xbill/DNS/DNSSECWithBCProviderTest.java +++ b/src/test/java/org/xbill/DNS/DNSSECWithBCProviderTest.java @@ -14,6 +14,7 @@ import java.security.Signature; import java.time.Instant; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.xbill.DNS.DNSSEC.Algorithm; @@ -32,6 +33,11 @@ static void setUp() { Security.addProvider(new BouncyCastleProvider()); } + @AfterAll + static void afterAll() { + Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME); + } + @Test void testSignWithDNSSECAndBCProvider() throws Exception { From ea51f46ca3dd49c3f1d60d5b945ff10a9559d9d1 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 13 Apr 2021 23:02:54 +0200 Subject: [PATCH 186/431] Update actions and early start selector thread for test --- .github/workflows/build.yml | 17 ++++++++++------- .../java/org/xbill/DNS/NioTcpClientTest.java | 9 +++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e6e3fe502..3688b7630 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,16 +33,18 @@ jobs: fetch-depth: 0 - name: Cache Maven dependencies - uses: actions/cache@v1 + uses: actions/cache@v2 with: - path: ~/.m2 + path: ~/.m2/repository key: m2-cache-${{ matrix.java }}-${{ matrix.arch }}-${{ matrix.os }} - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: java-version: ${{ matrix.java }} architecture: ${{ matrix.arch }} + distribution: zulu + check-latest: true - name: Build with Maven if: "${{ !(matrix.arch == 'x64' && matrix.os == 'ubuntu-20.04' && matrix.java == '11') || github.event.pull_request.head.repo.full_name != 'dnsjava/dnsjava' }}" @@ -65,19 +67,20 @@ jobs: needs: test runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Cache Maven dependencies - uses: actions/cache@v1 + uses: actions/cache@v2 with: - path: ~/.m2 + path: ~/.m2/repository key: m2-cache-8-x64-ubuntu-20.04 - name: Set up JDK 8 - uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 + uses: actions/setup-java@v2 with: java-version: '8' architecture: 'x64' + distribution: zulu server-id: ossrh server-username: SONATYPE_USER server-password: SONATYPE_PW diff --git a/src/test/java/org/xbill/DNS/NioTcpClientTest.java b/src/test/java/org/xbill/DNS/NioTcpClientTest.java index 1b2e009ed..8296294e4 100644 --- a/src/test/java/org/xbill/DNS/NioTcpClientTest.java +++ b/src/test/java/org/xbill/DNS/NioTcpClientTest.java @@ -20,8 +20,12 @@ public class NioTcpClientTest { @Test void testResponseStream() throws InterruptedException, IOException { + // start the selector thread early + Client.selector(); + Record qr = Record.newRecord(Name.fromConstantString("example.com."), Type.A, DClass.IN); Message[] q = new Message[] {Message.newQuery(qr), Message.newQuery(qr)}; + CountDownLatch cdlServerThreadStart = new CountDownLatch(1); CountDownLatch cdl1 = new CountDownLatch(q.length); CountDownLatch cdl2 = new CountDownLatch(q.length); Message[] serverReceivedMessages = new Message[q.length]; @@ -33,6 +37,7 @@ void testResponseStream() throws InterruptedException, IOException { new Thread( () -> { try { + cdlServerThreadStart.countDown(); s[0] = ss.accept(); while (cdl1.getCount() > 0) { int ii = i.getAndIncrement(); @@ -56,6 +61,10 @@ void testResponseStream() throws InterruptedException, IOException { }); server.start(); + if (!cdlServerThreadStart.await(5, TimeUnit.SECONDS)) { + fail("timed out waiting for server thread to start"); + } + for (int j = 0; j < q.length; j++) { int jj = j; NioTcpClient.sendrecv( From 892fab2d826e6561c7c28b69461f3a965f2b397c Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Tue, 13 Apr 2021 23:54:05 +0200 Subject: [PATCH 187/431] Inline dummy server replies and only listen on localhost Sending the answers outside the thread can cause races and is more complicated to read. Explicitly listening on localhost seems to be required on GitHub. --- .../java/org/xbill/DNS/NioTcpClientTest.java | 79 ++++++++----------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/src/test/java/org/xbill/DNS/NioTcpClientTest.java b/src/test/java/org/xbill/DNS/NioTcpClientTest.java index 8296294e4..96efd017b 100644 --- a/src/test/java/org/xbill/DNS/NioTcpClientTest.java +++ b/src/test/java/org/xbill/DNS/NioTcpClientTest.java @@ -10,11 +10,11 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.time.Duration; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Test; public class NioTcpClientTest { @@ -26,35 +26,52 @@ void testResponseStream() throws InterruptedException, IOException { Record qr = Record.newRecord(Name.fromConstantString("example.com."), Type.A, DClass.IN); Message[] q = new Message[] {Message.newQuery(qr), Message.newQuery(qr)}; CountDownLatch cdlServerThreadStart = new CountDownLatch(1); - CountDownLatch cdl1 = new CountDownLatch(q.length); - CountDownLatch cdl2 = new CountDownLatch(q.length); - Message[] serverReceivedMessages = new Message[q.length]; - Message[] clientReceivedAnswers = new Message[q.length]; - AtomicInteger i = new AtomicInteger(0); - Socket[] s = new Socket[1]; - ServerSocket ss = new ServerSocket(0); + CountDownLatch cdlQueryRepliesReceived = new CountDownLatch(q.length); + ServerSocket ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); + ss.setSoTimeout(5000); Thread server = new Thread( () -> { try { cdlServerThreadStart.countDown(); - s[0] = ss.accept(); - while (cdl1.getCount() > 0) { - int ii = i.getAndIncrement(); + Socket s = ss.accept(); + for (int i = 0; i < q.length; i++) { try { - InputStream is = s[0].getInputStream(); + InputStream is = s.getInputStream(); byte[] lengthData = new byte[2]; int readLength = is.read(lengthData); assertEquals(2, readLength); byte[] messageData = new byte[(lengthData[0] << 8) + lengthData[1]]; int readMessageLength = is.read(messageData); assertEquals(messageData.length, readMessageLength); - serverReceivedMessages[ii] = new Message(messageData); - cdl1.countDown(); + Message serverReceivedMessages = new Message(messageData); + + for (int j = q.length - 1; j >= 0; j--) { + Message answer = new Message(); + answer.getHeader().setRcode(Rcode.NOERROR); + answer.getHeader().setID(serverReceivedMessages.getHeader().getID()); + answer.addRecord(serverReceivedMessages.getQuestion(), Section.QUESTION); + answer.addRecord( + new ARecord( + Name.fromConstantString("example.com."), + DClass.IN, + 900, + InetAddress.getLoopbackAddress()), + Section.ANSWER); + byte[] queryData = answer.toWire(); + ByteBuffer buffer = ByteBuffer.allocate(queryData.length + 2); + buffer.put((byte) (queryData.length >>> 8)); + buffer.put((byte) (queryData.length & 0xFF)); + buffer.put(queryData); + s.getOutputStream().write(buffer.array()); + } + } catch (IOException e) { fail(e); } } + } catch (SocketTimeoutException ste) { + fail("Timeout waiting for a client connection", ste); } catch (IOException e) { fail(e); } @@ -76,44 +93,16 @@ void testResponseStream() throws InterruptedException, IOException { .thenAccept( d -> { try { - clientReceivedAnswers[jj] = new Message(d); - cdl2.countDown(); + assertEquals(q[jj].getHeader().getID(), new Message(d).getHeader().getID()); + cdlQueryRepliesReceived.countDown(); } catch (IOException e) { fail(e); } }); } - if (!cdl1.await(5, TimeUnit.SECONDS)) { - fail("timed out waiting for messages"); - } - - for (int j = q.length - 1; j >= 0; j--) { - Message answer = new Message(); - answer.getHeader().setRcode(Rcode.NOERROR); - answer.getHeader().setID(serverReceivedMessages[j].getHeader().getID()); - answer.addRecord(serverReceivedMessages[j].getQuestion(), Section.QUESTION); - answer.addRecord( - new ARecord( - Name.fromConstantString("example.com."), - DClass.IN, - 900, - InetAddress.getLoopbackAddress()), - Section.ANSWER); - byte[] queryData = answer.toWire(); - ByteBuffer buffer = ByteBuffer.allocate(queryData.length + 2); - buffer.put((byte) (queryData.length >>> 8)); - buffer.put((byte) (queryData.length & 0xFF)); - buffer.put(queryData); - s[0].getOutputStream().write(buffer.array()); - } - - if (!cdl2.await(5, TimeUnit.SECONDS)) { + if (!cdlQueryRepliesReceived.await(5, TimeUnit.SECONDS)) { fail("timed out waiting for answers"); } - - for (int j = 0; j < q.length; j++) { - assertEquals(q[j].getHeader().getID(), clientReceivedAnswers[j].getHeader().getID()); - } } } From f3ac761cc1e962751d9718d9696b15fbaeaef0fa Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 18 Apr 2021 12:32:22 +0200 Subject: [PATCH 188/431] Add support for EDNS Extended Error Codes, RFC 8914 (#188) --- src/main/java/org/xbill/DNS/EDNSOption.java | 8 +- .../xbill/DNS/ExtendedErrorCodeOption.java | 133 ++++++++++++++++++ .../DNS/ExtendedErrorCodeOptionTest.java | 106 ++++++++++++++ 3 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/xbill/DNS/ExtendedErrorCodeOption.java create mode 100644 src/test/java/org/xbill/DNS/ExtendedErrorCodeOptionTest.java diff --git a/src/main/java/org/xbill/DNS/EDNSOption.java b/src/main/java/org/xbill/DNS/EDNSOption.java index 57ad0820f..a40b866b3 100644 --- a/src/main/java/org/xbill/DNS/EDNSOption.java +++ b/src/main/java/org/xbill/DNS/EDNSOption.java @@ -61,6 +61,9 @@ private Code() {} /** Signaling Trust Anchor Knowledge in DNS Security Extensions (DNSSEC), RFC 8145 */ public static final int EDNS_KEY_TAG = 14; + /** Extended DNS Errors, RFC 8914. */ + public static final int EDNS_EXTENDED_ERROR = 15; + /** DNS EDNS Tags, draft-bellis-dnsop-edns-tags-01 */ public static final int EDNS_CLIENT_TAG = 16; @@ -88,7 +91,7 @@ private Code() {} codes.add(PADDING, "Padding"); codes.add(CHAIN, "CHAIN"); codes.add(EDNS_KEY_TAG, "edns-key-tag"); - + codes.add(EDNS_EXTENDED_ERROR, "Extended_DNS_Error"); codes.add(EDNS_CLIENT_TAG, "EDNS-Client-Tag"); codes.add(EDNS_SERVER_TAG, "EDNS-Server-Tag"); } @@ -184,6 +187,9 @@ static EDNSOption fromWire(DNSInput in) throws IOException { case Code.TCP_KEEPALIVE: option = new TcpKeepaliveOption(); break; + case Code.EDNS_EXTENDED_ERROR: + option = new ExtendedErrorCodeOption(); + break; default: option = new GenericEDNSOption(code); break; diff --git a/src/main/java/org/xbill/DNS/ExtendedErrorCodeOption.java b/src/main/java/org/xbill/DNS/ExtendedErrorCodeOption.java new file mode 100644 index 000000000..f1ac9cbec --- /dev/null +++ b/src/main/java/org/xbill/DNS/ExtendedErrorCodeOption.java @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import lombok.Getter; + +/** + * EDNS option to provide additional information about the cause of DNS errors (RFC 8914). + * + * @since 3.4 + */ +public class ExtendedErrorCodeOption extends EDNSOption { + public static final int OTHER = 0; + public static final int UNSUPPORTED_DNSKEY_ALGORITHM = 1; + public static final int UNSUPPORTED_DS_DIGEST_TYPE = 2; + public static final int STALE_ANSWER = 3; + public static final int FORGED_ANSWER = 4; + public static final int DNSSEC_INDETERMINATE = 5; + public static final int DNSSEC_BOGUS = 6; + public static final int SIGNATURE_EXPIRED = 7; + public static final int SIGNATURE_NOT_YET_VALID = 8; + public static final int DNSKEY_MISSING = 9; + public static final int RRSIGS_MISSING = 10; + public static final int NO_ZONE_KEY_BIT_SET = 11; + public static final int NSEC_MISSING = 12; + public static final int CACHED_ERROR = 13; + public static final int NOT_READY = 14; + public static final int BLOCKED = 15; + public static final int CENSORED = 16; + public static final int FILTERED = 17; + public static final int PROHIBITED = 18; + public static final int STALE_NXDOMAIN_ANSWER = 19; + public static final int NOT_AUTHORITATIVE = 20; + public static final int NOT_SUPPORTED = 21; + public static final int NO_REACHABLE_AUTHORITY = 22; + public static final int NETWORK_ERROR = 23; + public static final int INVALID_DATA = 24; + + @Getter private int errorCode; + @Getter private String text; + + private static final Mnemonic codes = + new Mnemonic("EDNS Extended Error Codes", Mnemonic.CASE_SENSITIVE); + + static { + codes.setMaximum(0xFFFF); + codes.setPrefix("EDE"); + codes.add(OTHER, "Other"); + codes.add(UNSUPPORTED_DNSKEY_ALGORITHM, "Unsupported DNSKEY Algorithm"); + codes.add(UNSUPPORTED_DS_DIGEST_TYPE, "Unsupported DS Digest Type"); + codes.add(STALE_ANSWER, "Stale Answer"); + codes.add(FORGED_ANSWER, "Forged Answer"); + codes.add(DNSSEC_INDETERMINATE, "DNSSEC Indeterminate"); + codes.add(DNSSEC_BOGUS, "DNSSEC Bogus"); + codes.add(SIGNATURE_EXPIRED, "Signature Expired"); + codes.add(SIGNATURE_NOT_YET_VALID, "Signature Not Yet Valid"); + codes.add(DNSKEY_MISSING, "DNSKEY Missing"); + codes.add(RRSIGS_MISSING, "RRSIGs Missing"); + codes.add(NO_ZONE_KEY_BIT_SET, "No Zone Key Bit Set"); + codes.add(NSEC_MISSING, "NSEC Missing"); + codes.add(CACHED_ERROR, "Cached Error"); + codes.add(NOT_READY, "Not Ready"); + codes.add(BLOCKED, "Blocked"); + codes.add(CENSORED, "Censored"); + codes.add(FILTERED, "Filtered"); + codes.add(PROHIBITED, "Prohibited"); + codes.add(STALE_NXDOMAIN_ANSWER, "Stale NXDOMAIN Answer"); + codes.add(NOT_AUTHORITATIVE, "Not Authoritative"); + codes.add(NOT_SUPPORTED, "Not Supported"); + codes.add(NO_REACHABLE_AUTHORITY, "No Reachable Authority"); + codes.add(NETWORK_ERROR, "Network Error"); + codes.add(INVALID_DATA, "Invalid Data"); + } + + /** Creates an extended error code EDNS option. */ + ExtendedErrorCodeOption() { + super(Code.EDNS_EXTENDED_ERROR); + } + + /** + * Creates an extended error code EDNS option. + * + * @param errorCode the extended error. + * @param text optional error message intended for human readers. + */ + public ExtendedErrorCodeOption(int errorCode, String text) { + super(Code.EDNS_EXTENDED_ERROR); + this.errorCode = errorCode; + this.text = text; + } + + /** + * Creates an extended error code EDNS option. + * + * @param errorCode the extended error. + */ + public ExtendedErrorCodeOption(int errorCode) { + this(errorCode, null); + } + + @Override + void optionFromWire(DNSInput in) throws IOException { + errorCode = in.readU16(); + if (in.remaining() > 0) { + byte[] data = in.readByteArray(); + int len = data.length; + + // EDE text may be null terminated but MUST NOT be assumed to be + if (data[data.length - 1] == 0) { + len--; + } + + text = new String(data, 0, len, StandardCharsets.UTF_8); + } + } + + @Override + void optionToWire(DNSOutput out) { + out.writeU16(errorCode); + if (text != null && text.length() > 0) { + out.writeByteArray(text.getBytes(StandardCharsets.UTF_8)); + } + } + + @Override + String optionToString() { + if (text == null) { + return codes.getText(errorCode); + } + return codes.getText(errorCode) + ": " + text; + } +} diff --git a/src/test/java/org/xbill/DNS/ExtendedErrorCodeOptionTest.java b/src/test/java/org/xbill/DNS/ExtendedErrorCodeOptionTest.java new file mode 100644 index 000000000..2de5271d3 --- /dev/null +++ b/src/test/java/org/xbill/DNS/ExtendedErrorCodeOptionTest.java @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import org.junit.jupiter.api.Test; + +class ExtendedErrorCodeOptionTest { + @Test + void testCodeOnly() throws IOException { + byte[] data = + new byte[] { + 0, + 15, // EDNS option code + 0, + 2, // option data length + 0, + 1 // extended error code + }; + EDNSOption option = EDNSOption.fromWire(data); + assertTrue(option instanceof ExtendedErrorCodeOption, "Expected ExtendedErrorCodeOption"); + ExtendedErrorCodeOption ede = (ExtendedErrorCodeOption) option; + assertEquals(1, ede.getErrorCode()); + assertNull(ede.getText()); + assertArrayEquals(data, ede.toWire()); + assertArrayEquals(data, new ExtendedErrorCodeOption(1).toWire()); + } + + @Test + void testCodeAndText() throws IOException { + byte[] data = + new byte[] { + 0, + 15, // EDNS option code + 0, + 4, // option data length + 0, + 1, // extended error code + (byte) 'a', + (byte) 'b' + }; + EDNSOption option = EDNSOption.fromWire(data); + assertTrue(option instanceof ExtendedErrorCodeOption, "Expected ExtendedErrorCodeOption"); + ExtendedErrorCodeOption ede = (ExtendedErrorCodeOption) option; + assertEquals(1, ede.getErrorCode()); + assertEquals("ab", ede.getText()); + assertArrayEquals(data, ede.toWire()); + assertArrayEquals(data, new ExtendedErrorCodeOption(1, "ab").toWire()); + } + + @Test + void testCodeAndTextNullTerminated() throws IOException { + byte[] inputData = + new byte[] { + 0, + 15, // EDNS option code + 0, + 5, // option data length + 0, + 1, // extended error code + (byte) 'a', + (byte) 'b', + 0 + }; + EDNSOption option = EDNSOption.fromWire(inputData); + assertTrue(option instanceof ExtendedErrorCodeOption, "Expected ExtendedErrorCodeOption"); + ExtendedErrorCodeOption ede = (ExtendedErrorCodeOption) option; + assertEquals(1, ede.getErrorCode()); + assertEquals("ab", ede.getText()); + + byte[] outputDataNonNullTerminated = + new byte[] { + 0, + 15, // EDNS option code + 0, + 4, // option data length + 0, + 1, // extended error code + (byte) 'a', + (byte) 'b', + }; + assertArrayEquals(outputDataNonNullTerminated, ede.toWire()); + } + + @Test + void testToStringCodeOnly() { + ExtendedErrorCodeOption option = new ExtendedErrorCodeOption(1); + assertEquals("Unsupported DNSKEY Algorithm", option.optionToString()); + } + + @Test + void testToStringUnknownCode() { + ExtendedErrorCodeOption option = new ExtendedErrorCodeOption(49152); + assertEquals("EDE49152", option.optionToString()); + } + + @Test + void testToStringCodeAndText() { + ExtendedErrorCodeOption option = new ExtendedErrorCodeOption(1, "ab"); + assertEquals("Unsupported DNSKEY Algorithm: ab", option.optionToString()); + } +} From 4a2df35c6a4516ce46f2623ea1480e19398f1ddc Mon Sep 17 00:00:00 2001 From: amitknx <82438262+amitknx@users.noreply.github.com> Date: Sun, 18 Apr 2021 19:01:51 +0530 Subject: [PATCH 189/431] Fix cache timeout based on SOA record to minimum of ttl and minimum field (#191) --- src/main/java/org/xbill/DNS/Cache.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Cache.java b/src/main/java/org/xbill/DNS/Cache.java index d24a2cc58..8f7a1ae8e 100644 --- a/src/main/java/org/xbill/DNS/Cache.java +++ b/src/main/java/org/xbill/DNS/Cache.java @@ -91,7 +91,7 @@ public NegativeElement(Name name, int type, SOARecord soa, int cred, long maxttl this.type = type; long cttl = 0; if (soa != null) { - cttl = soa.getMinimum(); + cttl = Math.min(soa.getMinimum(), soa.getTTL()); } this.credibility = cred; this.expire = limitExpire(cttl, maxttl); @@ -398,7 +398,7 @@ public synchronized void addRRset(RRset rrset, int cred) { public synchronized void addNegative(Name name, int type, SOARecord soa, int cred) { long ttl = 0; if (soa != null) { - ttl = soa.getTTL(); + ttl = Math.min(soa.getMinimum(), soa.getTTL()); } Element element = findElement(name, type, 0); if (ttl == 0) { From 48eae36fd96a76d1845a80c58f7b29112ded155b Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 1 May 2021 16:23:47 +0200 Subject: [PATCH 190/431] Update BouncyCastle Closes #193 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bf64add03..db87c5f16 100644 --- a/pom.xml +++ b/pom.xml @@ -361,7 +361,7 @@ org.bouncycastle bcprov-jdk15on - 1.66 + 1.68 true From 91015e23d8e17ad9243382d143b172c5868526fb Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 29 May 2021 14:09:14 +0200 Subject: [PATCH 191/431] Add a method to shutdown the network I/O (#192) Closes #180 --- src/main/java/org/xbill/DNS/Lookup.java | 2 +- .../xbill/DNS/{Client.java => NioClient.java} | 64 ++++++-- src/main/java/org/xbill/DNS/NioTcpClient.java | 2 +- src/main/java/org/xbill/DNS/NioUdpClient.java | 2 +- src/main/java/org/xbill/DNS/TCPClient.java | 6 +- .../java/org/xbill/DNS/NioTcpClientTest.java | 152 +++++++++--------- 6 files changed, 138 insertions(+), 90 deletions(-) rename src/main/java/org/xbill/DNS/{Client.java => NioClient.java} (62%) diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index bea3cdf4f..32e7ecea9 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -215,7 +215,7 @@ private static List convertSearchPathDomainList(List domains) { * @param logger The logger */ public static synchronized void setPacketLogger(PacketLogger logger) { - Client.setPacketLogger(logger); + NioClient.setPacketLogger(logger); } private void reset() { diff --git a/src/main/java/org/xbill/DNS/Client.java b/src/main/java/org/xbill/DNS/NioClient.java similarity index 62% rename from src/main/java/org/xbill/DNS/Client.java rename to src/main/java/org/xbill/DNS/NioClient.java index 00c31c17e..5fe217f11 100644 --- a/src/main/java/org/xbill/DNS/Client.java +++ b/src/main/java/org/xbill/DNS/NioClient.java @@ -11,19 +11,31 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.xbill.DNS.utils.hexdump; +/** + * Manages the network I/O for the {@link SimpleResolver}. It is mostly an implementation detail of + * {@code dnsjava} and the only method intended to be called is {@link #close()} - and only if + * {@code dnsjava} is used in an application container like Tomcat. In a normal JVM setup {@link + * #close()} is called by a shutdown hook. + * + * @since 3.4 + */ @Slf4j -class Client { +@NoArgsConstructor(access = AccessLevel.NONE) +public abstract class NioClient { /** Packet logger, if available. */ private static PacketLogger packetLogger = null; - private static volatile boolean run = true; private static final List timeoutTasks = new CopyOnWriteArrayList<>(); private static final List closeTasks = new CopyOnWriteArrayList<>(); private static Thread selectorThread; + private static Thread closeThread; private static volatile Selector selector; + private static volatile boolean run; interface KeyProcessor { void processReadyKey(SelectionKey key); @@ -31,15 +43,16 @@ interface KeyProcessor { static Selector selector() throws IOException { if (selector == null) { - synchronized (Client.class) { + synchronized (NioClient.class) { if (selector == null) { selector = Selector.open(); log.debug("Starting dnsjava NIO selector thread"); - selectorThread = new Thread(Client::runSelector); + run = true; + selectorThread = new Thread(NioClient::runSelector); selectorThread.setDaemon(true); selectorThread.setName("dnsjava NIO selector"); selectorThread.start(); - Thread closeThread = new Thread(Client::close); + closeThread = new Thread(() -> close(true)); closeThread.setName("dnsjava NIO shutdown hook"); Runtime.getRuntime().addShutdownHook(closeThread); } @@ -49,17 +62,48 @@ static Selector selector() throws IOException { return selector; } - private static void close() { + /** Shutdown the network I/O used by the {@link SimpleResolver}. */ + public static void close() { + close(false); + } + + private static void close(boolean fromHook) { run = false; - closeTasks.forEach(Runnable::run); - timeoutTasks.clear(); + + if (!fromHook) { + try { + Runtime.getRuntime().removeShutdownHook(closeThread); + } catch (Exception ex) { + log.warn("Failed to remove shutdown hoook, ignoring and continuing close"); + } + } + + for (Runnable closeTask : closeTasks) { + try { + closeTask.run(); + } catch (Exception e) { + log.warn("Failed to execute a shutdown task, ignoring and continuing close", e); + } + } + selector.wakeup(); + try { selector.close(); + } catch (IOException e) { + log.warn("Failed to properly close selector, ignoring and continuing close", e); + } + + try { selectorThread.join(); - } catch (InterruptedException | IOException e) { - log.warn("Failed to properly shutdown", e); + } catch (InterruptedException e) { Thread.currentThread().interrupt(); + } finally { + synchronized (NioClient.class) { + selector = null; + selectorThread = null; + closeThread = null; + } } } diff --git a/src/main/java/org/xbill/DNS/NioTcpClient.java b/src/main/java/org/xbill/DNS/NioTcpClient.java index d4061e583..1153f62db 100644 --- a/src/main/java/org/xbill/DNS/NioTcpClient.java +++ b/src/main/java/org/xbill/DNS/NioTcpClient.java @@ -23,7 +23,7 @@ @Slf4j @UtilityClass -final class NioTcpClient extends Client { +final class NioTcpClient extends NioClient { private static final Queue registrationQueue = new ConcurrentLinkedQueue<>(); private static final Map channelMap = new ConcurrentHashMap<>(); diff --git a/src/main/java/org/xbill/DNS/NioUdpClient.java b/src/main/java/org/xbill/DNS/NioUdpClient.java index cd39d474b..5dba9891d 100644 --- a/src/main/java/org/xbill/DNS/NioUdpClient.java +++ b/src/main/java/org/xbill/DNS/NioUdpClient.java @@ -22,7 +22,7 @@ @Slf4j @UtilityClass -final class NioUdpClient extends Client { +final class NioUdpClient extends NioClient { private static final int EPHEMERAL_START; private static final int EPHEMERAL_RANGE; diff --git a/src/main/java/org/xbill/DNS/TCPClient.java b/src/main/java/org/xbill/DNS/TCPClient.java index 520cc890e..aea727c81 100644 --- a/src/main/java/org/xbill/DNS/TCPClient.java +++ b/src/main/java/org/xbill/DNS/TCPClient.java @@ -13,7 +13,7 @@ import java.nio.channels.SocketChannel; import java.util.concurrent.TimeUnit; -final class TCPClient extends Client { +final class TCPClient { private long endTime; private SelectionKey key; @@ -63,7 +63,7 @@ void connect(SocketAddress addr) throws IOException { void send(byte[] data) throws IOException { SocketChannel channel = (SocketChannel) key.channel(); - verboseLog( + NioClient.verboseLog( "TCP write", channel.socket().getLocalSocketAddress(), channel.socket().getRemoteSocketAddress(), @@ -150,7 +150,7 @@ byte[] recv() throws IOException { int length = ((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF); byte[] data = _recv(length); SocketChannel channel = (SocketChannel) key.channel(); - verboseLog( + NioClient.verboseLog( "TCP read", channel.socket().getLocalSocketAddress(), channel.socket().getRemoteSocketAddress(), diff --git a/src/test/java/org/xbill/DNS/NioTcpClientTest.java b/src/test/java/org/xbill/DNS/NioTcpClientTest.java index 96efd017b..bbb15ba1c 100644 --- a/src/test/java/org/xbill/DNS/NioTcpClientTest.java +++ b/src/test/java/org/xbill/DNS/NioTcpClientTest.java @@ -20,89 +20,93 @@ public class NioTcpClientTest { @Test void testResponseStream() throws InterruptedException, IOException { - // start the selector thread early - Client.selector(); + try { + // start the selector thread early + NioClient.selector(); - Record qr = Record.newRecord(Name.fromConstantString("example.com."), Type.A, DClass.IN); - Message[] q = new Message[] {Message.newQuery(qr), Message.newQuery(qr)}; - CountDownLatch cdlServerThreadStart = new CountDownLatch(1); - CountDownLatch cdlQueryRepliesReceived = new CountDownLatch(q.length); - ServerSocket ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); - ss.setSoTimeout(5000); - Thread server = - new Thread( - () -> { - try { - cdlServerThreadStart.countDown(); - Socket s = ss.accept(); - for (int i = 0; i < q.length; i++) { - try { - InputStream is = s.getInputStream(); - byte[] lengthData = new byte[2]; - int readLength = is.read(lengthData); - assertEquals(2, readLength); - byte[] messageData = new byte[(lengthData[0] << 8) + lengthData[1]]; - int readMessageLength = is.read(messageData); - assertEquals(messageData.length, readMessageLength); - Message serverReceivedMessages = new Message(messageData); + Record qr = Record.newRecord(Name.fromConstantString("example.com."), Type.A, DClass.IN); + Message[] q = new Message[] {Message.newQuery(qr), Message.newQuery(qr)}; + CountDownLatch cdlServerThreadStart = new CountDownLatch(1); + CountDownLatch cdlQueryRepliesReceived = new CountDownLatch(q.length); + ServerSocket ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); + ss.setSoTimeout(5000); + Thread server = + new Thread( + () -> { + try { + cdlServerThreadStart.countDown(); + Socket s = ss.accept(); + for (int i = 0; i < q.length; i++) { + try { + InputStream is = s.getInputStream(); + byte[] lengthData = new byte[2]; + int readLength = is.read(lengthData); + assertEquals(2, readLength); + byte[] messageData = new byte[(lengthData[0] << 8) + lengthData[1]]; + int readMessageLength = is.read(messageData); + assertEquals(messageData.length, readMessageLength); + Message serverReceivedMessages = new Message(messageData); - for (int j = q.length - 1; j >= 0; j--) { - Message answer = new Message(); - answer.getHeader().setRcode(Rcode.NOERROR); - answer.getHeader().setID(serverReceivedMessages.getHeader().getID()); - answer.addRecord(serverReceivedMessages.getQuestion(), Section.QUESTION); - answer.addRecord( - new ARecord( - Name.fromConstantString("example.com."), - DClass.IN, - 900, - InetAddress.getLoopbackAddress()), - Section.ANSWER); - byte[] queryData = answer.toWire(); - ByteBuffer buffer = ByteBuffer.allocate(queryData.length + 2); - buffer.put((byte) (queryData.length >>> 8)); - buffer.put((byte) (queryData.length & 0xFF)); - buffer.put(queryData); - s.getOutputStream().write(buffer.array()); - } + for (int j = q.length - 1; j >= 0; j--) { + Message answer = new Message(); + answer.getHeader().setRcode(Rcode.NOERROR); + answer.getHeader().setID(serverReceivedMessages.getHeader().getID()); + answer.addRecord(serverReceivedMessages.getQuestion(), Section.QUESTION); + answer.addRecord( + new ARecord( + Name.fromConstantString("example.com."), + DClass.IN, + 900, + InetAddress.getLoopbackAddress()), + Section.ANSWER); + byte[] queryData = answer.toWire(); + ByteBuffer buffer = ByteBuffer.allocate(queryData.length + 2); + buffer.put((byte) (queryData.length >>> 8)); + buffer.put((byte) (queryData.length & 0xFF)); + buffer.put(queryData); + s.getOutputStream().write(buffer.array()); + } - } catch (IOException e) { - fail(e); + } catch (IOException e) { + fail(e); + } } - } - } catch (SocketTimeoutException ste) { - fail("Timeout waiting for a client connection", ste); - } catch (IOException e) { - fail(e); - } - }); - server.start(); - - if (!cdlServerThreadStart.await(5, TimeUnit.SECONDS)) { - fail("timed out waiting for server thread to start"); - } - - for (int j = 0; j < q.length; j++) { - int jj = j; - NioTcpClient.sendrecv( - null, - (InetSocketAddress) ss.getLocalSocketAddress(), - q[j], - q[j].toWire(), - Duration.ofSeconds(5)) - .thenAccept( - d -> { - try { - assertEquals(q[jj].getHeader().getID(), new Message(d).getHeader().getID()); - cdlQueryRepliesReceived.countDown(); + } catch (SocketTimeoutException ste) { + fail("Timeout waiting for a client connection", ste); } catch (IOException e) { fail(e); } }); - } + server.start(); + + if (!cdlServerThreadStart.await(5, TimeUnit.SECONDS)) { + fail("timed out waiting for server thread to start"); + } + + for (int j = 0; j < q.length; j++) { + int jj = j; + NioTcpClient.sendrecv( + null, + (InetSocketAddress) ss.getLocalSocketAddress(), + q[j], + q[j].toWire(), + Duration.ofSeconds(5)) + .thenAccept( + d -> { + try { + assertEquals(q[jj].getHeader().getID(), new Message(d).getHeader().getID()); + cdlQueryRepliesReceived.countDown(); + } catch (IOException e) { + fail(e); + } + }); + } - if (!cdlQueryRepliesReceived.await(5, TimeUnit.SECONDS)) { - fail("timed out waiting for answers"); + if (!cdlQueryRepliesReceived.await(5, TimeUnit.SECONDS)) { + fail("timed out waiting for answers"); + } + } finally { + NioClient.close(); } } } From ca9d3815eca92d2caf00a60ffd02d84030f20dfc Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Mon, 31 May 2021 19:30:00 +0200 Subject: [PATCH 192/431] Keep order of resolvers during construction --- .../java/org/xbill/DNS/ExtendedResolver.java | 31 +++++-------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/xbill/DNS/ExtendedResolver.java b/src/main/java/org/xbill/DNS/ExtendedResolver.java index 9286880e5..fe86c8394 100644 --- a/src/main/java/org/xbill/DNS/ExtendedResolver.java +++ b/src/main/java/org/xbill/DNS/ExtendedResolver.java @@ -16,7 +16,6 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -import java.util.stream.StreamSupport; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -192,25 +191,10 @@ public ExtendedResolver() { * @exception UnknownHostException A server name could not be resolved */ public ExtendedResolver(String[] servers) throws UnknownHostException { - try { - resolvers.addAll( - Arrays.stream(servers) - .map( - server -> { - try { - Resolver r = new SimpleResolver(server); - r.setTimeout(DEFAULT_RESOLVER_TIMEOUT); - return new ResolverEntry(r); - } catch (UnknownHostException e) { - throw new RuntimeException(e); - } - }) - .collect(Collectors.toSet())); - } catch (RuntimeException e) { - if (e.getCause() instanceof UnknownHostException) { - throw (UnknownHostException) e.getCause(); - } - throw e; + for (String server : servers) { + Resolver r = new SimpleResolver(server); + r.setTimeout(DEFAULT_RESOLVER_TIMEOUT); + resolvers.add(new ResolverEntry(r)); } } @@ -231,10 +215,9 @@ public ExtendedResolver(Resolver[] resolvers) { * @param resolvers An iterable of pre-initialized {@link Resolver}s. */ public ExtendedResolver(Iterable resolvers) { - this.resolvers.addAll( - StreamSupport.stream(resolvers.spliterator(), false) - .map(ResolverEntry::new) - .collect(Collectors.toSet())); + for (Resolver r : resolvers) { + this.resolvers.add(new ResolverEntry(r)); + } } @Override From b78a29ae9163d36df32768336a656e20fa2d1802 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 9 Jun 2021 19:11:15 +0200 Subject: [PATCH 193/431] Enable parsing the local hosts database in lookups (#195) --- README.md | 9 + src/main/java/org/xbill/DNS/Lookup.java | 62 ++++ .../org/xbill/DNS/hosts/HostsFileParser.java | 235 +++++++++++++++ .../org/xbill/DNS/lookup/LookupSession.java | 76 ++++- src/test/java/org/xbill/DNS/LookupTest.java | 47 +++ .../xbill/DNS/hosts/HostsFileParserTest.java | 277 ++++++++++++++++++ .../xbill/DNS/lookup/LookupSessionTest.java | 172 +++++++++-- src/test/resources/hosts_invalid | 13 + src/test/resources/hosts_windows | 28 ++ 9 files changed, 887 insertions(+), 32 deletions(-) create mode 100644 src/main/java/org/xbill/DNS/hosts/HostsFileParser.java create mode 100644 src/test/java/org/xbill/DNS/hosts/HostsFileParserTest.java create mode 100644 src/test/resources/hosts_invalid create mode 100644 src/test/resources/hosts_windows diff --git a/README.md b/README.md index e751915d0..536c59f0b 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,15 @@ Some settings of dnsjava can be configured via Maximum number of CNAMEs to follow in a chain. + + dnsjava.lookup.use_hosts_file + Boolean + true + false + + + Use the system's hosts file for lookups before resorting to a resolver. + diff --git a/src/main/java/org/xbill/DNS/Lookup.java b/src/main/java/org/xbill/DNS/Lookup.java index 32e7ecea9..073697aae 100644 --- a/src/main/java/org/xbill/DNS/Lookup.java +++ b/src/main/java/org/xbill/DNS/Lookup.java @@ -5,13 +5,18 @@ import java.io.IOException; import java.io.InterruptedIOException; +import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; +import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.xbill.DNS.hosts.HostsFileParser; /** * The Lookup object issues queries to caching DNS servers. The input consists of a name, an @@ -35,6 +40,7 @@ public final class Lookup { private static List defaultSearchPath; private static Map defaultCaches; private static int defaultNdots; + private static HostsFileParser defaultHostsFileParser; private Resolver resolver; private List searchPath; @@ -63,6 +69,13 @@ public final class Lookup { private boolean cycleResults = true; private int maxIterations; + /** + * Gets or sets the local hosts database parser to use for lookup before using a {@link Resolver}. + * + * @since 3.4 + */ + @Getter @Setter private HostsFileParser hostsFileParser; + private static final Name[] noAliases = new Name[0]; /** The lookup was successful. */ @@ -85,6 +98,7 @@ public static synchronized void refreshDefault() { defaultSearchPath = ResolverConfig.getCurrentConfig().searchPath(); defaultCaches = new HashMap<>(); defaultNdots = ResolverConfig.getCurrentConfig().ndots(); + defaultHostsFileParser = new HostsFileParser(); } static { @@ -188,6 +202,24 @@ public static synchronized void setDefaultSearchPath(String... domains) defaultSearchPath = newdomains; } + /** + * Gets the default {@link HostsFileParser} to use for new Lookup instances. + * + * @since 3.4 + */ + public static synchronized HostsFileParser getDefaultHostsFileParser() { + return defaultHostsFileParser; + } + + /** + * Sets the default {@link HostsFileParser} to use for new Lookup instances. + * + * @since 3.4 + */ + public static synchronized void setDefaultHostsFileParser(HostsFileParser hostsFileParser) { + defaultHostsFileParser = hostsFileParser; + } + private static List convertSearchPathDomainList(List domains) { try { return domains.stream() @@ -274,6 +306,9 @@ public Lookup(Name name, int type, int dclass) { this.result = -1; this.maxIterations = Integer.parseInt(System.getProperty("dnsjava.lookup.max_iterations", "16")); + if (Boolean.parseBoolean(System.getProperty("dnsjava.lookup.use_hosts_file", "true"))) { + this.hostsFileParser = getDefaultHostsFileParser(); + } } /** @@ -513,6 +548,10 @@ private void processResponse(Name name, SetResponse response) { } private void lookup(Name current) { + if (lookupFromHostsFile(current)) { + return; + } + SetResponse sr = cache.lookupRecords(current, type, credibility); log.debug("Lookup for {}/{}, cache answer: {}", current, Type.string(type), sr); @@ -569,6 +608,29 @@ private void lookup(Name current) { processResponse(current, sr); } + private boolean lookupFromHostsFile(Name current) { + if (hostsFileParser != null && (type == Type.A || type == Type.AAAA)) { + try { + Optional localLookup = hostsFileParser.getAddressForHost(current, type); + if (localLookup.isPresent()) { + result = SUCCESSFUL; + done = true; + if (type == Type.A) { + answers = new ARecord[] {new ARecord(current, dclass, 0L, localLookup.get())}; + } else { + answers = new AAAARecord[] {new AAAARecord(current, dclass, 0L, localLookup.get())}; + } + + return true; + } + } catch (IOException e) { + log.debug("Local hosts database parsing failed, ignoring and using resolver", e); + } + } + + return false; + } + private void resolve(Name current, Name suffix) { doneCurrent = false; Name tname; diff --git a/src/main/java/org/xbill/DNS/hosts/HostsFileParser.java b/src/main/java/org/xbill/DNS/hosts/HostsFileParser.java new file mode 100644 index 000000000..9dca2ccbb --- /dev/null +++ b/src/main/java/org/xbill/DNS/hosts/HostsFileParser.java @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.hosts; + +import java.io.BufferedReader; +import java.io.IOException; +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Instant; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.xbill.DNS.Address; +import org.xbill.DNS.Name; +import org.xbill.DNS.TextParseException; +import org.xbill.DNS.Type; + +/** + * Parses and caches the systems local hosts database, otherwise known as {@code /etc/hosts}. The + * cache is cleared when the file is modified. + * + * @since 3.4 + */ +@Slf4j +public final class HostsFileParser { + private static final int MAX_FULL_CACHE_FILE_SIZE_BYTES = 16384; + + private final Map hostsCache = new HashMap<>(); + private final Path path; + private final boolean clearCacheOnChange; + private Instant lastFileReadTime = Instant.MIN; + private boolean isEntireFileParsed; + + /** + * Creates a new instance based on the current OS's default. Unix and alike (or rather everything + * else than Windows) use {@code /etc/hosts}, while on Windows {@code + * %SystemRoot%\System32\drivers\etc\hosts} is used. The cache is cleared when the file has + * changed. + */ + public HostsFileParser() { + this( + System.getProperty("os.name").contains("Windows") + ? Paths.get(System.getenv("SystemRoot"), "\\System32\\drivers\\etc\\hosts") + : Paths.get("/etc/hosts"), + true); + } + + /** + * Creates an instance with a custom hosts database path. The cache is cleared when the file has + * changed. + * + * @param path The path to the hosts database. + */ + public HostsFileParser(Path path) { + this(path, true); + } + + /** + * Creates an instance with a custom hosts database path. + * + * @param path The path to the hosts database. + * @param clearCacheOnChange set to true to clear the cache when the hosts file changes. + */ + public HostsFileParser(Path path, boolean clearCacheOnChange) { + this.path = Objects.requireNonNull(path, "path is required"); + this.clearCacheOnChange = clearCacheOnChange; + if (Files.isDirectory(path)) { + throw new IllegalArgumentException("path must be a file"); + } + } + + /** + * Performs on-demand parsing and caching of the local hosts database. + * + * @param name the hostname to search for. + * @param type Record type to search for, see {@link org.xbill.DNS.Type}. + * @return The first address found for the requested hostname. + * @throws IOException When the parsing fails. + * @throws IllegalArgumentException when {@code type} is not {@link org.xbill.DNS.Type#A} or{@link + * org.xbill.DNS.Type#AAAA}. + */ + public synchronized Optional getAddressForHost(Name name, int type) + throws IOException { + Objects.requireNonNull(name, "name is required"); + if (type != Type.A && type != Type.AAAA) { + throw new IllegalArgumentException("type can only be A or AAAA"); + } + + validateCache(); + + InetAddress cachedAddress = hostsCache.get(key(name, type)); + if (cachedAddress != null) { + return Optional.of(cachedAddress); + } + + if (isEntireFileParsed || !Files.exists(path)) { + return Optional.empty(); + } + + if (Files.size(path) <= MAX_FULL_CACHE_FILE_SIZE_BYTES) { + parseEntireHostsFile(); + } else { + searchHostsFileForEntry(name, type); + } + + return Optional.ofNullable(hostsCache.get(key(name, type))); + } + + private void parseEntireHostsFile() throws IOException { + String line; + int lineNumber = 0; + try (BufferedReader hostsReader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { + while ((line = hostsReader.readLine()) != null) { + LineData lineData = parseLine(++lineNumber, line); + if (lineData != null) { + for (Name lineName : lineData.names) { + InetAddress lineAddress = + InetAddress.getByAddress(lineName.toString(true), lineData.address); + hostsCache.putIfAbsent(key(lineName, lineData.type), lineAddress); + } + } + } + } + + isEntireFileParsed = true; + } + + private void searchHostsFileForEntry(Name name, int type) throws IOException { + String line; + int lineNumber = 0; + try (BufferedReader hostsReader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { + while ((line = hostsReader.readLine()) != null) { + LineData lineData = parseLine(++lineNumber, line); + if (lineData != null) { + for (Name lineName : lineData.names) { + boolean isSearchedEntry = lineName.equals(name); + if (isSearchedEntry && type == lineData.type) { + InetAddress lineAddress = + InetAddress.getByAddress(lineName.toString(true), lineData.address); + hostsCache.putIfAbsent(key(lineName, lineData.type), lineAddress); + return; + } + } + } + } + } + } + + @RequiredArgsConstructor + private static final class LineData { + final int type; + final byte[] address; + final Iterable names; + } + + private LineData parseLine(int lineNumber, String line) { + String[] lineTokens = getLineTokens(line); + if (lineTokens.length < 2) { + return null; + } + + int lineAddressType = Type.A; + byte[] lineAddressBytes = Address.toByteArray(lineTokens[0], Address.IPv4); + if (lineAddressBytes == null) { + lineAddressBytes = Address.toByteArray(lineTokens[0], Address.IPv6); + lineAddressType = Type.AAAA; + } + + if (lineAddressBytes == null) { + log.warn("Could not decode address {}, {}#L{}", lineTokens[0], path, lineNumber); + return null; + } + + Iterable lineNames = + Arrays.stream(lineTokens) + .skip(1) + .map(lineTokenName -> safeName(lineTokenName, lineNumber)) + .filter(Objects::nonNull) + ::iterator; + return new LineData(lineAddressType, lineAddressBytes, lineNames); + } + + private Name safeName(String name, int lineNumber) { + try { + return Name.fromString(name, Name.root); + } catch (TextParseException e) { + log.warn("Could not decode name {}, {}#L{}, skipping", name, path, lineNumber); + return null; + } + } + + private String[] getLineTokens(String line) { + // everything after a # until the end of the line is a comment + int commentStart = line.indexOf('#'); + if (commentStart == -1) { + commentStart = line.length(); + } + + return line.substring(0, commentStart).trim().split("\\s+"); + } + + private void validateCache() throws IOException { + if (clearCacheOnChange) { + // A filewatcher / inotify etc. would be nicer, but doesn't work. c.f. the write up at + // https://blog.arkey.fr/2019/09/13/watchservice-and-bind-mount/ + Instant fileTime = + Files.exists(path) ? Files.getLastModifiedTime(path).toInstant() : Instant.MAX; + if (fileTime.isAfter(lastFileReadTime)) { + // skip logging noise when the cache is empty anyway + if (!hostsCache.isEmpty()) { + log.info("Local hosts database has changed at {}, clearing cache", fileTime); + hostsCache.clear(); + } + + isEntireFileParsed = false; + lastFileReadTime = fileTime; + } + } + } + + private String key(Name name, int type) { + return name.toString() + '\t' + type; + } + + // for unit testing only + int cacheSize() { + return hostsCache.size(); + } +} diff --git a/src/main/java/org/xbill/DNS/lookup/LookupSession.java b/src/main/java/org/xbill/DNS/lookup/LookupSession.java index 6e4ccc0c1..f30ae79cd 100644 --- a/src/main/java/org/xbill/DNS/lookup/LookupSession.java +++ b/src/main/java/org/xbill/DNS/lookup/LookupSession.java @@ -1,6 +1,8 @@ // SPDX-License-Identifier: BSD-2-Clause package org.xbill.DNS.lookup; +import java.io.IOException; +import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -11,15 +13,18 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.stream.Collectors; -import java.util.stream.Stream; import lombok.Builder; import lombok.NonNull; import lombok.Singular; +import lombok.extern.slf4j.Slf4j; +import org.xbill.DNS.AAAARecord; +import org.xbill.DNS.ARecord; import org.xbill.DNS.CNAMERecord; import org.xbill.DNS.Cache; import org.xbill.DNS.Credibility; import org.xbill.DNS.DClass; import org.xbill.DNS.DNAMERecord; +import org.xbill.DNS.Lookup; import org.xbill.DNS.Message; import org.xbill.DNS.Name; import org.xbill.DNS.NameTooLongException; @@ -29,6 +34,7 @@ import org.xbill.DNS.Section; import org.xbill.DNS.SetResponse; import org.xbill.DNS.Type; +import org.xbill.DNS.hosts.HostsFileParser; /** * LookupSession provides facilities to make DNS Queries. A LookupSession is intended to be long @@ -36,6 +42,7 @@ * instance returned by the builder() method. */ @Builder +@Slf4j public class LookupSession { public static final int DEFAULT_MAX_ITERATIONS = 16; public static final int DEFAULT_NDOTS = 1; @@ -70,6 +77,9 @@ public class LookupSession { @Singular("cache") private final Map caches; + /** Configures the local hosts database file parser to use within this session. */ + private final HostsFileParser hostsFileParser; + /** * A builder for {@link LookupSession} instances where functionality is mostly generated as * described in the Lombok Builder @@ -79,6 +89,16 @@ public class LookupSession { * LookupSessionBuilder#build()} on the builder instance. */ public static class LookupSessionBuilder { + /** + * Enable querying the local hosts database using the system defaults. + * + * @see HostsFileParser + */ + public LookupSessionBuilder defaultHostsFileParser() { + hostsFileParser = new HostsFileParser(); + return this; + } + void preBuild() { // note that this transform is idempotent, as concatenating an already absolute Name with root // is a noop. @@ -118,30 +138,39 @@ public LookupSession build() { * @return A {@link CompletionStage} what will yield the eventual lookup result. */ public CompletionStage lookupAsync(Name name, int type, int dclass) { + List searchNames = expandName(name); + LookupResult localHostsLookupResult = lookupWithHosts(searchNames, type); + if (localHostsLookupResult != null) { + return CompletableFuture.completedFuture(localHostsLookupResult); + } + CompletableFuture future = new CompletableFuture<>(); - lookupUntilSuccess(expandName(name).iterator(), type, dclass, future); + lookupUntilSuccess(searchNames.iterator(), type, dclass, future); return future; } /** * Generate a stream of names according to the search path application semantics. The semantics of - * this is a bit odd, but they are inherited from Lookup.java. Note that the stream returned is + * this is a bit odd, but they are inherited from {@link Lookup}. Note that the stream returned is * never empty, as it will at the very least always contain {@code name}. */ - Stream expandName(Name name) { + List expandName(Name name) { if (name.isAbsolute()) { - return Stream.of(name); + return Collections.singletonList(name); } - Stream fromSearchPath = - Stream.concat( - searchPath.stream() - .map(searchSuffix -> safeConcat(name, searchSuffix)) - .filter(Objects::nonNull), - Stream.of(safeConcat(name, Name.root))); + + List fromSearchPath = + searchPath.stream() + .map(searchSuffix -> safeConcat(name, searchSuffix)) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(ArrayList::new)); if (name.labels() > ndots) { - return Stream.concat(Stream.of(safeConcat(name, Name.root)), fromSearchPath); + fromSearchPath.add(0, safeConcat(name, Name.root)); + } else { + fromSearchPath.add(safeConcat(name, Name.root)); } + return fromSearchPath; } @@ -153,6 +182,29 @@ private static Name safeConcat(Name name, Name suffix) { } } + private LookupResult lookupWithHosts(List names, int type) { + if (hostsFileParser != null && (type == Type.A || type == Type.AAAA)) { + try { + for (Name name : names) { + Optional result = hostsFileParser.getAddressForHost(name, type); + if (result.isPresent()) { + Record r; + if (type == Type.A) { + r = new ARecord(name, DClass.IN, 0, result.get()); + } else { + r = new AAAARecord(name, DClass.IN, 0, result.get()); + } + return new LookupResult(Collections.singletonList(r), Collections.emptyList()); + } + } + } catch (IOException e) { + log.debug("Local hosts database parsing failed, ignoring and using resolver", e); + } + } + + return null; + } + private void lookupUntilSuccess( Iterator names, int type, int dclass, CompletableFuture future) { diff --git a/src/test/java/org/xbill/DNS/LookupTest.java b/src/test/java/org/xbill/DNS/LookupTest.java index 404b24179..7adedf50f 100644 --- a/src/test/java/org/xbill/DNS/LookupTest.java +++ b/src/test/java/org/xbill/DNS/LookupTest.java @@ -5,6 +5,7 @@ import static java.util.Collections.singletonList; import static java.util.stream.Collectors.joining; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -16,6 +17,9 @@ import java.io.IOException; import java.io.InterruptedIOException; import java.net.InetAddress; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.nio.file.Paths; import java.util.List; import java.util.function.Function; import java.util.stream.IntStream; @@ -24,6 +28,7 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import org.xbill.DNS.hosts.HostsFileParser; public class LookupTest { public static final Name DUMMY_NAME = Name.fromConstantString("to.be.replaced."); @@ -337,6 +342,48 @@ void testLookup_constructorFailsWithMetaTypes() { assertThrows(IllegalArgumentException.class, () -> new Lookup("example.com.", Type.OPT)); } + @Test + void testLookupFromHosts() throws TextParseException, URISyntaxException, UnknownHostException { + Lookup lookup = new Lookup("host.docker.internal", Type.A); + wireUpMockResolver( + mockResolver, + q -> { + throw new RuntimeException("The resolver should not be invoked"); + }); + lookup.setResolver(mockResolver); + lookup.setHostsFileParser( + new HostsFileParser(Paths.get(LookupTest.class.getResource("/hosts_windows").toURI()))); + Record[] run = lookup.run(); + assertNotNull(run); + assertEquals(1, run.length); + assertEquals( + InetAddress.getByAddress( + "host.docker.internal", new byte[] {(byte) 192, (byte) 168, 10, 96}), + ((ARecord) run[0]).getAddress()); + } + + @Test + void testLookupFromHostsWithSearchDomain() + throws TextParseException, URISyntaxException, UnknownHostException { + Lookup lookup = new Lookup("host", Type.A); + lookup.setSearchPath("docker.internal"); + wireUpMockResolver( + mockResolver, + q -> { + throw new RuntimeException("The resolver should not be invoked"); + }); + lookup.setResolver(mockResolver); + lookup.setHostsFileParser( + new HostsFileParser(Paths.get(LookupTest.class.getResource("/hosts_windows").toURI()))); + Record[] run = lookup.run(); + assertNotNull(run); + assertEquals(1, run.length); + assertEquals( + InetAddress.getByAddress( + "host.docker.internal", new byte[] {(byte) 192, (byte) 168, 10, 96}), + ((ARecord) run[0]).getAddress()); + } + private Message goodAnswerWhenThreeLabels(Message query) { return answer( query, diff --git a/src/test/java/org/xbill/DNS/hosts/HostsFileParserTest.java b/src/test/java/org/xbill/DNS/hosts/HostsFileParserTest.java new file mode 100644 index 000000000..24560d5c1 --- /dev/null +++ b/src/test/java/org/xbill/DNS/hosts/HostsFileParserTest.java @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: BSD-2-Clause +package org.xbill.DNS.hosts; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.net.InetAddress; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.FileTime; +import java.util.Optional; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.xbill.DNS.Name; +import org.xbill.DNS.Type; + +class HostsFileParserTest { + private static final Name kubernetesName = Name.fromConstantString("kubernetes.docker.internal."); + private static final byte[] localhostBytes = new byte[] {127, 0, 0, 1}; + private static Path hostsFileWindows; + private static Path hostsFileInvalid; + private static InetAddress kubernetesAddress; + + @TempDir Path tempDir; + + @BeforeAll + static void beforeAll() throws URISyntaxException, UnknownHostException { + hostsFileWindows = Paths.get(HostsFileParserTest.class.getResource("/hosts_windows").toURI()); + hostsFileInvalid = Paths.get(HostsFileParserTest.class.getResource("/hosts_invalid").toURI()); + kubernetesAddress = InetAddress.getByAddress(kubernetesName.toString(), localhostBytes); + } + + @Test + void testArguments() { + assertThrows(NullPointerException.class, () -> new HostsFileParser(null)); + assertThrows(IllegalArgumentException.class, () -> new HostsFileParser(tempDir)); + } + + @Test + void testLookupType() { + HostsFileParser hostsFileParser = new HostsFileParser(hostsFileWindows); + assertThrows( + IllegalArgumentException.class, + () -> hostsFileParser.getAddressForHost(kubernetesName, Type.MX)); + } + + @Test + void testEntireFileParsing() throws IOException { + HostsFileParser hostsFileParser = new HostsFileParser(hostsFileWindows); + assertEquals( + kubernetesAddress, + hostsFileParser + .getAddressForHost(kubernetesName, Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + } + + @Test + void testMissingFileIsEmptyResult() throws IOException { + HostsFileParser hostsFileParser = new HostsFileParser(tempDir.resolve("missing")); + assertEquals(Optional.empty(), hostsFileParser.getAddressForHost(kubernetesName, Type.A)); + } + + @Test + void testCacheLookup() throws IOException { + Path tempHosts = Files.copy(hostsFileWindows, tempDir, StandardCopyOption.REPLACE_EXISTING); + HostsFileParser hostsFileParser = new HostsFileParser(tempHosts, false); + assertEquals(0, hostsFileParser.cacheSize()); + assertEquals( + kubernetesAddress, + hostsFileParser + .getAddressForHost(kubernetesName, Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + assertTrue(hostsFileParser.cacheSize() > 1, "Cache must not be empty"); + Files.delete(tempHosts); + assertEquals( + kubernetesAddress, + hostsFileParser + .getAddressForHost(kubernetesName, Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + } + + @Test + void testFileDeletionClearsCache() throws IOException { + Path tempHosts = + Files.copy( + hostsFileWindows, + tempDir.resolve("testFileWatcherClearsCache"), + StandardCopyOption.REPLACE_EXISTING); + HostsFileParser hostsFileParser = new HostsFileParser(tempHosts); + assertEquals(0, hostsFileParser.cacheSize()); + assertEquals( + kubernetesAddress, + hostsFileParser + .getAddressForHost(kubernetesName, Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + assertTrue(hostsFileParser.cacheSize() > 1, "Cache must not be empty"); + Files.delete(tempHosts); + assertEquals(Optional.empty(), hostsFileParser.getAddressForHost(kubernetesName, Type.A)); + assertEquals(0, hostsFileParser.cacheSize()); + } + + @Test + void testFileChangeClearsCache() throws IOException { + Path tempHosts = + Files.copy( + hostsFileWindows, + tempDir.resolve("testFileWatcherClearsCache"), + StandardCopyOption.REPLACE_EXISTING); + Files.setLastModifiedTime(tempHosts, FileTime.fromMillis(0)); + HostsFileParser hostsFileParser = new HostsFileParser(tempHosts); + assertEquals(0, hostsFileParser.cacheSize()); + assertEquals( + kubernetesAddress, + hostsFileParser + .getAddressForHost(kubernetesName, Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + assertTrue(hostsFileParser.cacheSize() > 1, "Cache must not be empty"); + Name testName = Name.fromConstantString("testFileChangeClearsCache."); + try (BufferedWriter w = + Files.newBufferedWriter(tempHosts, StandardCharsets.UTF_8, StandardOpenOption.APPEND)) { + w.append("127.0.0.1 ").append(testName.toString()); + w.newLine(); + } + + Files.setLastModifiedTime(tempHosts, FileTime.fromMillis(10_0000)); + assertEquals( + InetAddress.getByAddress(testName.toString(), localhostBytes), + hostsFileParser + .getAddressForHost(testName, Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + } + + @Test + void testInvalidContentIsIgnored() throws IOException { + HostsFileParser hostsFileParser = new HostsFileParser(hostsFileInvalid); + assertEquals( + InetAddress.getByAddress("localhost", localhostBytes), + hostsFileParser + .getAddressForHost(Name.fromConstantString("localhost."), Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + assertEquals( + InetAddress.getByAddress("localalias", localhostBytes), + hostsFileParser + .getAddressForHost(Name.fromConstantString("localalias."), Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + assertEquals( + Optional.empty(), + hostsFileParser.getAddressForHost(Name.fromConstantString("some-junk."), Type.A)); + assertNotEquals( + Optional.empty(), + hostsFileParser.getAddressForHost(Name.fromConstantString("example.org."), Type.A)); + } + + @Test + void testBigFileIsNotCompletelyCachedA() throws IOException { + HostsFileParser hostsFileParser = generateLargeHostsFile("testBigFileIsNotCompletelyCachedA"); + hostsFileParser + .getAddressForHost(Name.fromConstantString("localhost-10."), Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found")); + assertEquals(1, hostsFileParser.cacheSize()); + } + + @Test + void testBigFileIsNotCompletelyCachedAAAA() throws IOException { + HostsFileParser hostsFileParser = + generateLargeHostsFile("testBigFileIsNotCompletelyCachedAAAA"); + hostsFileParser + .getAddressForHost(Name.fromConstantString("localhost-10."), Type.AAAA) + .orElseThrow(() -> new IllegalStateException("Host entry not found")); + assertEquals(1, hostsFileParser.cacheSize()); + } + + private HostsFileParser generateLargeHostsFile(String name) throws IOException { + Path generatedLargeFile = tempDir.resolve(name); + try (BufferedWriter w = Files.newBufferedWriter(generatedLargeFile)) { + for (int i = 0; i < 1024; i++) { + w.append("127.0.0.") + .append(String.valueOf(i)) + .append(" localhost-") + .append(String.valueOf(i)); + w.newLine(); + w.append("::") + .append(Integer.toHexString(i)) + .append(" localhost-") + .append(String.valueOf(i)); + w.newLine(); + } + } + return new HostsFileParser(generatedLargeFile); + } + + @Test + void testBigFileNotFoundA() throws IOException { + HostsFileParser hostsFileParser = generateLargeHostsFile("testBigFileNotFoundA"); + hostsFileParser + .getAddressForHost(Name.fromConstantString("localhost-1024."), Type.A) + .ifPresent( + entry -> { + throw new IllegalStateException("Host entry not found"); + }); + assertEquals(0, hostsFileParser.cacheSize()); + } + + @Test + void testBigFileNotFoundAAAA() throws IOException { + HostsFileParser hostsFileParser = generateLargeHostsFile("testBigFileNotFoundAAAA"); + hostsFileParser + .getAddressForHost(Name.fromConstantString("localhost-1024."), Type.AAAA) + .ifPresent( + entry -> { + throw new IllegalStateException("Host entry not found"); + }); + assertEquals(0, hostsFileParser.cacheSize()); + } + + @Test + void testDualStackLookup() throws IOException { + HostsFileParser hostsFileParser = new HostsFileParser(hostsFileInvalid); + assertEquals( + InetAddress.getByAddress("localhost", localhostBytes), + hostsFileParser + .getAddressForHost(Name.fromConstantString("localhost."), Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + byte[] ipv6Localhost = new byte[16]; + ipv6Localhost[15] = 1; + assertEquals( + InetAddress.getByAddress("localhost", ipv6Localhost), + hostsFileParser + .getAddressForHost(Name.fromConstantString("localhost."), Type.AAAA) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + } + + @Test + void testDuplicateItemReturnsFirst() throws IOException { + HostsFileParser hostsFileParser = new HostsFileParser(hostsFileInvalid); + assertEquals( + InetAddress.getByAddress("example.com", new byte[] {127, 0, 0, 5}), + hostsFileParser + .getAddressForHost(Name.fromConstantString("example.com."), Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + + // lookup a second time to validate the cache entry + assertEquals( + InetAddress.getByAddress("example.com", new byte[] {127, 0, 0, 5}), + hostsFileParser + .getAddressForHost(Name.fromConstantString("example.com."), Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + } + + @Test + void testDuplicateItemReturnsFirstOnLargeFile() throws IOException { + Path generatedLargeFile = tempDir.resolve("testDuplicateItemReturnsFirstOnLargeFile"); + try (BufferedWriter w = Files.newBufferedWriter(generatedLargeFile)) { + for (int i = 1; i < 1024; i++) { + w.append("127.0.0.").append(String.valueOf(i)).append(" localhost"); + w.newLine(); + } + } + HostsFileParser hostsFileParser = new HostsFileParser(generatedLargeFile); + assertEquals( + InetAddress.getByAddress("localhost", new byte[] {127, 0, 0, 1}), + hostsFileParser + .getAddressForHost(Name.fromConstantString("localhost."), Type.A) + .orElseThrow(() -> new IllegalStateException("Host entry not found"))); + } +} diff --git a/src/test/java/org/xbill/DNS/lookup/LookupSessionTest.java b/src/test/java/org/xbill/DNS/lookup/LookupSessionTest.java index 3c9af7d05..46fe2cab2 100644 --- a/src/test/java/org/xbill/DNS/lookup/LookupSessionTest.java +++ b/src/test/java/org/xbill/DNS/lookup/LookupSessionTest.java @@ -4,7 +4,6 @@ import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static java.util.stream.Collectors.toList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -20,25 +19,33 @@ import static org.xbill.DNS.LookupTest.answer; import static org.xbill.DNS.LookupTest.fail; import static org.xbill.DNS.Type.A; +import static org.xbill.DNS.Type.AAAA; import static org.xbill.DNS.Type.CNAME; +import static org.xbill.DNS.Type.MX; import java.net.InetAddress; +import java.net.URISyntaxException; import java.net.UnknownHostException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.ExecutionException; import java.util.function.Function; -import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.api.io.TempDir; import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.xbill.DNS.AAAARecord; import org.xbill.DNS.ARecord; +import org.xbill.DNS.Address; import org.xbill.DNS.CNAMERecord; import org.xbill.DNS.Cache; import org.xbill.DNS.Credibility; @@ -53,14 +60,44 @@ import org.xbill.DNS.Section; import org.xbill.DNS.SetResponse; import org.xbill.DNS.Type; +import org.xbill.DNS.hosts.HostsFileParser; @ExtendWith(MockitoExtension.class) class LookupSessionTest { - @Mock Resolver mockResolver; + @TempDir Path tempDir; + + private static final ARecord LOOPBACK_A = + new ARecord(DUMMY_NAME, IN, 3600, InetAddress.getLoopbackAddress()); + private static final AAAARecord LOOPBACK_AAAA; + private HostsFileParser lookupSessionTestHostsFileParser; + + static { + AAAARecord record = null; + try { + record = + new AAAARecord( + DUMMY_NAME, + IN, + 3600, + InetAddress.getByAddress(Address.toByteArray("::1", Address.IPv6))); + } catch (UnknownHostException e) { + // cannot happen + } + + LOOPBACK_AAAA = record; + } + + @BeforeEach + void beforeEach() throws URISyntaxException { + lookupSessionTestHostsFileParser = + new HostsFileParser( + Paths.get(LookupSessionTest.class.getResource("/hosts_windows").toURI())); + } + @AfterEach - void after() { + void afterEach() { verifyNoMoreInteractions(mockResolver); } @@ -78,6 +115,105 @@ void lookupAsync_absoluteQuery() throws InterruptedException, ExecutionException verify(mockResolver).sendAsync(any()); } + @Test + void lookupAsync_absoluteQueryWithHosts() throws InterruptedException, ExecutionException { + LookupSession lookupSession = + LookupSession.builder() + .resolver(mockResolver) + .hostsFileParser(lookupSessionTestHostsFileParser) + .build(); + CompletionStage resultFuture = + lookupSession.lookupAsync(Name.fromConstantString("kubernetes.docker.internal."), A, IN); + + LookupResult result = resultFuture.toCompletableFuture().get(); + assertEquals( + singletonList(LOOPBACK_A.withName(name("kubernetes.docker.internal."))), + result.getRecords()); + } + + @Test + void lookupAsync_absoluteQueryWithHostsInvalidType() { + wireUpMockResolver(mockResolver, query -> fail(query, Rcode.NXDOMAIN)); + LookupSession lookupSession = + LookupSession.builder() + .resolver(mockResolver) + .hostsFileParser(lookupSessionTestHostsFileParser) + .build(); + CompletionStage resultFuture = + lookupSession.lookupAsync(Name.fromConstantString("kubernetes.docker.internal."), MX, IN); + + assertThrowsCause(NoSuchDomainException.class, () -> resultFuture.toCompletableFuture().get()); + verify(mockResolver).sendAsync(any()); + } + + @Test + void lookupAsync_absoluteAaaaQueryWithHosts() throws InterruptedException, ExecutionException { + LookupSession lookupSession = + LookupSession.builder() + .resolver(mockResolver) + .hostsFileParser(lookupSessionTestHostsFileParser) + .build(); + CompletionStage resultFuture = + lookupSession.lookupAsync(Name.fromConstantString("kubernetes.docker.internal."), AAAA, IN); + + LookupResult result = resultFuture.toCompletableFuture().get(); + assertEquals( + singletonList(LOOPBACK_AAAA.withName(name("kubernetes.docker.internal."))), + result.getRecords()); + } + + @Test + void lookupAsync_relativeQueryWithHosts() throws InterruptedException, ExecutionException { + LookupSession lookupSession = + LookupSession.builder() + .resolver(mockResolver) + .hostsFileParser(lookupSessionTestHostsFileParser) + .build(); + CompletionStage resultFuture = + lookupSession.lookupAsync(Name.fromConstantString("kubernetes.docker.internal"), A, IN); + + LookupResult result = resultFuture.toCompletableFuture().get(); + assertEquals( + singletonList(LOOPBACK_A.withName(name("kubernetes.docker.internal."))), + result.getRecords()); + } + + @Test + void lookupAsync_relativeQueryWithHostsNdots3() throws InterruptedException, ExecutionException { + LookupSession lookupSession = + LookupSession.builder() + .resolver(mockResolver) + .ndots(3) + .hostsFileParser(lookupSessionTestHostsFileParser) + .build(); + CompletionStage resultFuture = + lookupSession.lookupAsync(Name.fromConstantString("kubernetes.docker.internal"), A, IN); + + LookupResult result = resultFuture.toCompletableFuture().get(); + assertEquals( + singletonList(LOOPBACK_A.withName(name("kubernetes.docker.internal."))), + result.getRecords()); + } + + @Test + void lookupAsync_relativeQueryWithInvalidHosts() throws InterruptedException, ExecutionException { + wireUpMockResolver(mockResolver, query -> answer(query, name -> LOOPBACK_A)); + LookupSession lookupSession = + LookupSession.builder() + .resolver(mockResolver) + .hostsFileParser( + new HostsFileParser(tempDir.resolve("lookupAsync_relativeQueryWithInvalidHosts"))) + .build(); + CompletionStage resultFuture = + lookupSession.lookupAsync(Name.fromConstantString("kubernetes.docker.internal"), A, IN); + + LookupResult result = resultFuture.toCompletableFuture().get(); + assertEquals( + singletonList(LOOPBACK_A.withName(name("kubernetes.docker.internal."))), + result.getRecords()); + verify(mockResolver).sendAsync(any()); + } + @Test void lookupAsync_absoluteQueryWithCacheMiss() throws InterruptedException, ExecutionException { wireUpMockResolver(mockResolver, query -> answer(query, name -> LOOPBACK_A)); @@ -474,40 +610,39 @@ void lookupAsync_absoluteQueryWithCacheCycleResults() @Test void expandName_absolute() { LookupSession session = LookupSession.builder().resolver(mockResolver).build(); - Stream nameStream = session.expandName(name("a.")); - assertEquals(singletonList(name("a.")), nameStream.collect(toList())); + List nameStream = session.expandName(name("a.")); + assertEquals(singletonList(name("a.")), nameStream); } @Test void expandName_singleSearchPath() { LookupSession session = LookupSession.builder().resolver(mockResolver).searchPath(name("example.com.")).build(); - Stream nameStream = session.expandName(name("host")); - assertEquals(asList(name("host.example.com."), name("host.")), nameStream.collect(toList())); + List nameStream = session.expandName(name("host")); + assertEquals(asList(name("host.example.com."), name("host.")), nameStream); } @Test void expandName_notSetSearchPath() { LookupSession session = LookupSession.builder().resolver(mockResolver).build(); - Stream nameStream = session.expandName(name("host")); - assertEquals(singletonList(name("host.")), nameStream.collect(toList())); + List nameStream = session.expandName(name("host")); + assertEquals(singletonList(name("host.")), nameStream); } @Test void expandName_searchPathIsMadeAbsolute() { LookupSession session = LookupSession.builder().resolver(mockResolver).searchPath(name("example.com")).build(); - Stream nameStream = session.expandName(name("host")); - assertEquals(asList(name("host.example.com."), name("host.")), nameStream.collect(toList())); + List nameStream = session.expandName(name("host")); + assertEquals(asList(name("host.example.com."), name("host.")), nameStream); } @Test void expandName_defaultNdots() { LookupSession session = LookupSession.builder().resolver(mockResolver).searchPath(name("example.com")).build(); - Stream nameStream = session.expandName(name("a.b")); - assertEquals( - asList(name("a.b."), name("a.b.example.com."), name("a.b.")), nameStream.collect(toList())); + List nameStream = session.expandName(name("a.b")); + assertEquals(asList(name("a.b."), name("a.b.example.com.")), nameStream); } @Test @@ -518,13 +653,10 @@ void expandName_ndotsMoreThanOne() { .resolver(mockResolver) .ndots(2) .build(); - Stream nameStream = session.expandName(name("a.b")); - assertEquals(asList(name("a.b.example.com."), name("a.b.")), nameStream.collect(toList())); + List nameStream = session.expandName(name("a.b")); + assertEquals(asList(name("a.b.example.com."), name("a.b.")), nameStream); } - private static final ARecord LOOPBACK_A = - new ARecord(DUMMY_NAME, IN, 3600, InetAddress.getLoopbackAddress()); - private static CNAMERecord cname(String name, String target) { return new CNAMERecord(name(name), IN, 0, name(target)); } diff --git a/src/test/resources/hosts_invalid b/src/test/resources/hosts_invalid new file mode 100644 index 000000000..2cf1e51b7 --- /dev/null +++ b/src/test/resources/hosts_invalid @@ -0,0 +1,13 @@ +127.0.0.5 example.com +127.0.0.7 example.com +127.0.0.2 .. + +127.0.0.3 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd +127.0.0.4 #bla + +::/0 example.net +:::1 invalid-ipv6 +127.0.0.256 invalid-ipv4 +127.0.0.1 localhost localalias +127.0.0.6 example.org #localalias some-junk +::1 localhost diff --git a/src/test/resources/hosts_windows b/src/test/resources/hosts_windows new file mode 100644 index 000000000..c922c1975 --- /dev/null +++ b/src/test/resources/hosts_windows @@ -0,0 +1,28 @@ +# Copyright (c) 1993-2009 Microsoft Corp. +# +# This is a sample HOSTS file used by Microsoft TCP/IP for Windows. +# +# This file contains the mappings of IP addresses to host names. Each +# entry should be kept on an individual line. The IP address should +# be placed in the first column followed by the corresponding host name. +# The IP address and the host name should be separated by at least one +# space. +# +# Additionally, comments (such as these) may be inserted on individual +# lines or following the machine name denoted by a '#' symbol. +# +# For example: +# +# 102.54.94.97 rhino.acme.com # source server +# 38.25.63.10 x.acme.com # x client host + +# localhost name resolution is handled within DNS itself. +# 127.0.0.1 localhost +# ::1 localhost +# Added by Docker Desktop +192.168.10.96 host.docker.internal +192.168.10.96 gateway.docker.internal +# To allow the same kube context to work on the host and the container: +127.0.0.1 kubernetes.docker.internal +::1 kubernetes.docker.internal +# End of section From 87a81d2051787117512bd98257eca0c3076927bc Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 9 Jun 2021 19:15:39 +0200 Subject: [PATCH 194/431] Clarify documentation about CNAME and wildcards #196 --- src/main/java/org/xbill/DNS/Zone.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/Zone.java b/src/main/java/org/xbill/DNS/Zone.java index 87a1f35d9..c8cda55fb 100644 --- a/src/main/java/org/xbill/DNS/Zone.java +++ b/src/main/java/org/xbill/DNS/Zone.java @@ -443,7 +443,8 @@ private RRset expandSet(RRset set, Name tname) { } /** - * Looks up Records in the Zone. This follows CNAMEs and wildcards. + * Looks up Records in the Zone. The answer can be a {@code CNAME} instead of the actual requested + * type and wildcards are expanded. * * @param name The name to look up * @param type The type to look up From 11ae6ce6c8d8763d4258c3782a607d626f217656 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 9 Jun 2021 19:58:16 +0200 Subject: [PATCH 195/431] Release v3.4.0 --- Changelog | 17 +++++++++++++++++ pom.xml | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 9dc751b58..fbce9f4ca 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,20 @@ +06/09/2021 + - 3.4.0 released + - UnknownHostException provides details in message (#154) + - Limit length of relative Name to 254 (#165) + - Fix wildcard lookups in Zone (#169) + - Properly close UDP channel upon error + (#177, Walter Scott Johnson) + - Fix load balancing in ExtendedResolver + (#179, Paulo Costa) + - Add method to shutdown NIO threads (#180) + - Fix restoring active position on byte buffers + (#184, @ryru) + - Add support for extended DNS errors (RFC8914, #187) + - Fix TTL for SOA record to minimum of TTL and minimum field + (#191, @amitknx) + - Add support for hosts file in lookups (#195) + 10/28/2020 - 3.3.1 released - Fix value of getAlias in C/DNameRecord (#136) diff --git a/pom.xml b/pom.xml index db87c5f16..8a3316b6e 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.4.0-SNAPSHOT + 3.4.0 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - HEAD + v3.4.0 From 769a813dea6c1df85e24bb159a4e6dc14eb60fdd Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 9 Jun 2021 20:14:15 +0200 Subject: [PATCH 196/431] Return to -snapshot --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8a3316b6e..ca218363e 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.4.0 + 3.4.1-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.4.0 + HEAD From 67809fa7d1ed4a06a4deac9d1c5aca5269501e11 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Wed, 9 Jun 2021 20:16:56 +0200 Subject: [PATCH 197/431] Replace Travis build badge with GitHub --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 536c59f0b..f3926811e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/dnsjava/dnsjava.svg?branch=master)](https://travis-ci.org/dnsjava/dnsjava) +[![dnsjava CI](https://github.com/dnsjava/dnsjava/actions/workflows/build.yml/badge.svg)](https://github.com/dnsjava/dnsjava/actions/workflows/build.yml) [![codecov](https://codecov.io/gh/dnsjava/dnsjava/branch/master/graph/badge.svg?token=FKmcwl1Oys)](https://codecov.io/gh/dnsjava/dnsjava) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dnsjava/dnsjava/badge.svg)](https://search.maven.org/artifact/dnsjava/dnsjava) [![Javadocs](http://javadoc.io/badge/dnsjava/dnsjava.svg)](http://javadoc.io/doc/dnsjava/dnsjava) From 170c5c6db5567e24e57561dfd4a4456a2102b269 Mon Sep 17 00:00:00 2001 From: Klaus Malorny Date: Thu, 24 Jun 2021 23:11:39 +0200 Subject: [PATCH 198/431] fixes to allow signing with ED25519 and ED448 algorithms (#200) * fixes to allow signing with ED25519 and ED448 algorithms * allow keys with "EdDSA", too * added lost parenthesis --- src/main/java/org/xbill/DNS/DNSSEC.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/xbill/DNS/DNSSEC.java b/src/main/java/org/xbill/DNS/DNSSEC.java index b7e446005..100b8668b 100644 --- a/src/main/java/org/xbill/DNS/DNSSEC.java +++ b/src/main/java/org/xbill/DNS/DNSSEC.java @@ -680,8 +680,9 @@ public static String algString(int alg) throws UnsupportedAlgorithmException { case Algorithm.ECDSAP384SHA384: return "SHA384withECDSA"; case Algorithm.ED25519: + return "Ed25519"; case Algorithm.ED448: - return "EdDSA"; + return "Ed448"; default: throw new UnsupportedAlgorithmException(alg); } @@ -1117,6 +1118,16 @@ static void checkAlgorithm(PrivateKey key, int alg) throws UnsupportedAlgorithmE throw new IncompatibleKeyException(); } break; + case Algorithm.ED25519: + if (!"Ed25519".equals(key.getAlgorithm()) && !"EdDSA".equals(key.getAlgorithm())) { + throw new IncompatibleKeyException(); + } + break; + case Algorithm.ED448: + if (!"Ed448".equals(key.getAlgorithm()) && !"EdDSA".equals(key.getAlgorithm())) { + throw new IncompatibleKeyException(); + } + break; default: throw new UnsupportedAlgorithmException(alg); } From 259ea0d6816e0b54151bb20888ad9540a15734f9 Mon Sep 17 00:00:00 2001 From: adam-stoler <68395423+adam-stoler@users.noreply.github.com> Date: Wed, 7 Jul 2021 17:02:06 -0400 Subject: [PATCH 199/431] Rename echconfig to ech in SVCB/HTTPS records (#202) * Rename echconfig to ech * Add test for obsolete echconfig name being rejected * Add duplicate ECHCONFIG value and ParameterEchConfig class for backwards compatibility * Make ParameterEchConfig a deprecated duplicate class instead of inheriting for full compatibility * Updates for javadoc * Add backwards compatibility support for parsing echconfig name as an alias of ech Co-authored-by: Adam Stoler --- src/main/java/org/xbill/DNS/HTTPSRecord.java | 3 +- src/main/java/org/xbill/DNS/SVCBBase.java | 65 +++++++++++++++++-- src/main/java/org/xbill/DNS/SVCBRecord.java | 3 +- src/main/java/org/xbill/DNS/Type.java | 4 +- .../java/org/xbill/DNS/HTTPSRecordTest.java | 8 ++- .../java/org/xbill/DNS/SVCBRecordTest.java | 34 ++++++---- 6 files changed, 95 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/xbill/DNS/HTTPSRecord.java b/src/main/java/org/xbill/DNS/HTTPSRecord.java index 01d8a0833..bce0182e6 100644 --- a/src/main/java/org/xbill/DNS/HTTPSRecord.java +++ b/src/main/java/org/xbill/DNS/HTTPSRecord.java @@ -7,7 +7,8 @@ * HTTPS Service Location and Parameter Binding Record * * @see draft-ietf-dnsop-svcb-https + * href="https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-06">draft-ietf-dnsop-svcb-https + * @since 3.3 */ public class HTTPSRecord extends SVCBBase { HTTPSRecord() {} diff --git a/src/main/java/org/xbill/DNS/SVCBBase.java b/src/main/java/org/xbill/DNS/SVCBBase.java index 26bdb2916..6ae9d11f2 100644 --- a/src/main/java/org/xbill/DNS/SVCBBase.java +++ b/src/main/java/org/xbill/DNS/SVCBBase.java @@ -17,8 +17,14 @@ import java.util.function.Supplier; import java.util.stream.Collectors; -/** Implements common functionality for SVCB and HTTPS records */ -abstract class SVCBBase extends Record { +/** + * Implements common functionality for SVCB and HTTPS records + * + * @see draft-ietf-dnsop-svcb-https + * @since 3.3 + */ +public abstract class SVCBBase extends Record { protected int svcPriority; protected Name targetName; protected final Map svcParams; @@ -28,8 +34,10 @@ abstract class SVCBBase extends Record { public static final int NO_DEFAULT_ALPN = 2; public static final int PORT = 3; public static final int IPV4HINT = 4; - public static final int ECHCONFIG = 5; + public static final int ECH = 5; public static final int IPV6HINT = 6; + /** @deprecated use {@link #ECH} */ + @Deprecated public static final int ECHCONFIG = 5; protected SVCBBase() { svcParams = new TreeMap<>(); @@ -105,8 +113,10 @@ public Supplier getFactory(int val) { parameters.add(NO_DEFAULT_ALPN, "no-default-alpn", ParameterNoDefaultAlpn::new); parameters.add(PORT, "port", ParameterPort::new); parameters.add(IPV4HINT, "ipv4hint", ParameterIpv4Hint::new); - parameters.add(ECHCONFIG, "echconfig", ParameterEchConfig::new); + parameters.add(ECH, "ech", ParameterEch::new); parameters.add(IPV6HINT, "ipv6hint", ParameterIpv6Hint::new); + /* Support obsolete echconfig name as an alias for ech */ + parameters.addAlias(ECH, "echconfig"); } public abstract static class ParameterBase { @@ -442,6 +452,53 @@ public String toString() { } } + public static class ParameterEch extends ParameterBase { + private byte[] data; + + public ParameterEch() { + super(); + } + + public ParameterEch(byte[] data) { + super(); + this.data = data; + } + + public byte[] getData() { + return data; + } + + @Override + public int getKey() { + return ECH; + } + + @Override + public void fromWire(byte[] bytes) { + data = bytes; + } + + @Override + public void fromString(String string) throws TextParseException { + if (string == null || string.isEmpty()) { + throw new TextParseException("Non-empty base64 value must be specified for ech"); + } + data = Base64.getDecoder().decode(string); + } + + @Override + public byte[] toWire() { + return data; + } + + @Override + public String toString() { + return Base64.getEncoder().encodeToString(data); + } + } + + /** @deprecated use {@link ParameterEch} */ + @Deprecated public static class ParameterEchConfig extends ParameterBase { private byte[] data; diff --git a/src/main/java/org/xbill/DNS/SVCBRecord.java b/src/main/java/org/xbill/DNS/SVCBRecord.java index 4bc9eb5c0..d78292ccd 100644 --- a/src/main/java/org/xbill/DNS/SVCBRecord.java +++ b/src/main/java/org/xbill/DNS/SVCBRecord.java @@ -7,7 +7,8 @@ * Service Location and Parameter Binding Record * * @see draft-ietf-dnsop-svcb-https + * href="https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-06">draft-ietf-dnsop-svcb-https + * @since 3.3 */ public class SVCBRecord extends SVCBBase { SVCBRecord() {} diff --git a/src/main/java/org/xbill/DNS/Type.java b/src/main/java/org/xbill/DNS/Type.java index 2b48ca745..f4348b8a1 100644 --- a/src/main/java/org/xbill/DNS/Type.java +++ b/src/main/java/org/xbill/DNS/Type.java @@ -227,7 +227,7 @@ public final class Type { * Service Location and Parameter Binding * * @see draft-ietf-dnsop-svcb-https + * href="https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-06">draft-ietf-dnsop-svcb-https */ public static final int SVCB = 64; @@ -235,7 +235,7 @@ public final class Type { * HTTPS Service Location and Parameter Binding * * @see draft-ietf-dnsop-svcb-https + * href="https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-06">draft-ietf-dnsop-svcb-https */ public static final int HTTPS = 65; diff --git a/src/test/java/org/xbill/DNS/HTTPSRecordTest.java b/src/test/java/org/xbill/DNS/HTTPSRecordTest.java index 5bdda5770..a8ee3a8f1 100644 --- a/src/test/java/org/xbill/DNS/HTTPSRecordTest.java +++ b/src/test/java/org/xbill/DNS/HTTPSRecordTest.java @@ -40,6 +40,10 @@ void createParams() throws UnknownHostException, TextParseException { assertEquals(ipv4List, ipv4hint.getAddresses()); byte[] data = {'a', 'b', 'c'}; + SVCBBase.ParameterEch ech = new SVCBBase.ParameterEch(data); + assertEquals(HTTPSRecord.ECH, ech.getKey()); + assertEquals(data, ech.getData()); + HTTPSRecord.ParameterEchConfig echconfig = new HTTPSRecord.ParameterEchConfig(data); assertEquals(HTTPSRecord.ECHCONFIG, echconfig.getKey()); assertEquals(data, echconfig.getData()); @@ -107,8 +111,8 @@ void serviceModePort() throws IOException { } @Test - void serviceModeEchConfigMulti() throws IOException { - String str = "1 h3pool. alpn=h2,h3 echconfig=1234"; + void serviceModeEchMulti() throws IOException { + String str = "1 h3pool. alpn=h2,h3 ech=1234"; assertEquals(str, SVCBRecordTest.stringToWireToString(str)); } diff --git a/src/test/java/org/xbill/DNS/SVCBRecordTest.java b/src/test/java/org/xbill/DNS/SVCBRecordTest.java index b1edf55da..fa6d8ec04 100644 --- a/src/test/java/org/xbill/DNS/SVCBRecordTest.java +++ b/src/test/java/org/xbill/DNS/SVCBRecordTest.java @@ -41,6 +41,10 @@ void createParams() throws UnknownHostException, TextParseException { assertEquals(ipv4List, ipv4hint.getAddresses()); byte[] data = {'a', 'b', 'c'}; + SVCBBase.ParameterEch ech = new SVCBBase.ParameterEch(data); + assertEquals(SVCBRecord.ECH, ech.getKey()); + assertEquals(data, ech.getData()); + SVCBRecord.ParameterEchConfig echconfig = new SVCBRecord.ParameterEchConfig(data); assertEquals(SVCBRecord.ECHCONFIG, echconfig.getKey()); assertEquals(data, echconfig.getData()); @@ -198,27 +202,33 @@ void serviceModeEscapedDomain() throws IOException { } @Test - void serviceModeEchConfig() throws IOException { - String str = "1 h3pool. echconfig=1234"; + void serviceModeEch() throws IOException { + String str = "1 h3pool. ech=1234"; assertEquals(str, stringToWireToString(str)); } @Test - void serviceModeEchConfigMulti() throws IOException { - String str = "1 h3pool. alpn=h2,h3 echconfig=1234"; + void serviceModeEchMulti() throws IOException { + String str = "1 h3pool. alpn=h2,h3 ech=1234"; assertEquals(str, stringToWireToString(str)); } @Test - void serviceModeEchConfigOutOfOrder() throws IOException { - String str = "1 h3pool. echconfig=1234 alpn=h2,h3"; - assertEquals("1 h3pool. alpn=h2,h3 echconfig=1234", stringToWireToString(str)); + void serviceModeEchOutOfOrder() throws IOException { + String str = "1 h3pool. ech=1234 alpn=h2,h3"; + assertEquals("1 h3pool. alpn=h2,h3 ech=1234", stringToWireToString(str)); + } + + @Test + void serviceModeEchQuoted() throws IOException { + String str = "1 h3pool. alpn=h2,h3 ech=\"1234\""; + assertEquals("1 h3pool. alpn=h2,h3 ech=1234", stringToWireToString(str)); } @Test - void serviceModeEchConfigQuoted() throws IOException { - String str = "1 h3pool. alpn=h2,h3 echconfig=\"1234\""; - assertEquals("1 h3pool. alpn=h2,h3 echconfig=1234", stringToWireToString(str)); + void serviceModeObsoleteEchConfigName() throws IOException { + String str = "1 . echconfig=1234"; + assertEquals("1 . ech=1234", stringToWireToString(str)); } @Test @@ -377,8 +387,8 @@ void zeroLengthIpv4Hint() { } @Test - void zeroLengthEchConfig() { - String str = "1 . echconfig"; + void zeroLengthEch() { + String str = "1 . ech"; assertThrows(TextParseException.class, () -> stringToWire(str)); } From 403ce32982fdc8fde772cbd74d2eec9c2c7d336f Mon Sep 17 00:00:00 2001 From: adam-stoler <68395423+adam-stoler@users.noreply.github.com> Date: Sun, 18 Jul 2021 15:22:15 -0400 Subject: [PATCH 200/431] Fix issue with Name compareTo and the handling of octal digit byte values (#205) * Fix signed integer issue with octal digits in Name.compareTo() * Also properly handle signed byte in Name.hashCode() Co-authored-by: Adam Stoler --- src/main/java/org/xbill/DNS/Name.java | 6 ++++-- src/test/java/org/xbill/DNS/NameTest.java | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/xbill/DNS/Name.java b/src/main/java/org/xbill/DNS/Name.java index 31c965a91..9f3d4998a 100644 --- a/src/main/java/org/xbill/DNS/Name.java +++ b/src/main/java/org/xbill/DNS/Name.java @@ -809,7 +809,7 @@ public int hashCode() { } int code = 0; for (int i = offset(0); i < name.length; i++) { - code += (code << 3) + lowercase[name[i] & 0xFF]; + code += (code << 3) + (lowercase[name[i] & 0xFF] & 0xFF); } hashcode = code; return hashcode; @@ -839,7 +839,9 @@ public int compareTo(Name arg) { int length = name[start]; int alength = arg.name[astart]; for (int j = 0; j < length && j < alength; j++) { - int n = lowercase[name[j + start + 1] & 0xFF] - lowercase[arg.name[j + astart + 1] & 0xFF]; + int n = + (lowercase[name[j + start + 1] & 0xFF] & 0xFF) + - (lowercase[arg.name[j + astart + 1] & 0xFF] & 0xFF); if (n != 0) { return n; } diff --git a/src/test/java/org/xbill/DNS/NameTest.java b/src/test/java/org/xbill/DNS/NameTest.java index 15769065b..589e08188 100644 --- a/src/test/java/org/xbill/DNS/NameTest.java +++ b/src/test/java/org/xbill/DNS/NameTest.java @@ -1502,6 +1502,24 @@ void more_labels() throws TextParseException { assertTrue(n1.compareTo(n2) < 0); assertTrue(n2.compareTo(n1) > 0); } + + @Test + void octal_digits_low() throws TextParseException { + Name n1 = new Name("\004.b.a."); + Name n2 = new Name("c.b.a."); + + assertTrue(n1.compareTo(n2) < 0); + assertTrue(n2.compareTo(n1) > 0); + } + + @Test + void octal_digits_high() throws TextParseException { + Name n1 = new Name("c.b.a."); + Name n2 = new Name("\237.b.a."); + + assertTrue(n1.compareTo(n2) < 0); + assertTrue(n2.compareTo(n1) > 0); + } } @Test From 018b45f5b2d49612c607e46d64f5744ca28e6a91 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 30 Jul 2021 11:33:32 +0200 Subject: [PATCH 201/431] Release v3.4.1 --- Changelog | 9 +++++++++ pom.xml | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index fbce9f4ca..94a196c1b 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,12 @@ +07/30/2021 + - 3.4.1 released + - Allow signing with ED25519 and ED448 algorithms + (#200, Klaus Malorny) + - Rename echconfig to ech in SVCB/HTTPS records + (#202, @adam-stoler) + - Fix bug in Name.compareTo with byte-values >= 128 + (#205, @adam-stoler) + 06/09/2021 - 3.4.0 released - UnknownHostException provides details in message (#154) diff --git a/pom.xml b/pom.xml index ca218363e..b2ecd4917 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.4.1-SNAPSHOT + 3.4.1 dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - HEAD + v3.4.1 From b52f4b882538d1f29c22cbe2ae28862d24ab2662 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 30 Jul 2021 12:01:43 +0200 Subject: [PATCH 202/431] Return to -snapshot --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b2ecd4917..a76c62d43 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ dnsjava dnsjava bundle - 3.4.1 + 3.5.0-SNAPSHOT dnsjava dnsjava is an implementation of DNS in Java. It supports all defined record types (including the DNSSEC types), and unknown types. It can be used for queries, zone transfers, and dynamic updates. It includes a cache @@ -30,7 +30,7 @@ scm:git:https://github.com/dnsjava/dnsjava scm:git:https://github.com/dnsjava/dnsjava https://github.com/dnsjava/dnsjava - v3.4.1 + HEAD From f639a4701d9c5482a216b62362fb57e5ea64cce2 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 30 Jul 2021 12:19:29 +0200 Subject: [PATCH 203/431] Test with Java 17ea and switch to AdoptOpenJDK --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3688b7630..60c172c57 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: os: [ ubuntu-18.04, ubuntu-20.04, windows-latest ] - java: [ '8', '11' ] + java: [ '8', '11', '17-ea' ] arch: [ 'x86', 'x64' ] exclude: - os: ubuntu-18.04 @@ -43,7 +43,7 @@ jobs: with: java-version: ${{ matrix.java }} architecture: ${{ matrix.arch }} - distribution: zulu + distribution: adopt check-latest: true - name: Build with Maven From f9b8c08a426aa42776ceaaf0d5de5e9f1b727586 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 30 Jul 2021 13:57:03 +0200 Subject: [PATCH 204/431] Update dependencies --- pom.xml | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index a76c62d43..fc309854d 100644 --- a/pom.xml +++ b/pom.xml @@ -46,14 +46,16 @@ UTF-8 1.8 - 5.7.0 - 1.7.30 + 5.7.2 + 1.7.32 dnsjava_dnsjava dnsjava https://sonarcloud.io 8 - ${project.build.directory}/site/jacoco/jacoco.xml + ${project.build.directory}/site/jacoco/jacoco.xml + ${project.build.directory}/generated-sources/delombok + 1.18.20 @@ -61,7 +63,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + 3.0.1 sign-artifacts @@ -99,7 +101,7 @@ org.apache.felix maven-bundle-plugin - 5.1.1 + 5.1.2 true @@ -165,7 +167,7 @@ org.jacoco jacoco-maven-plugin - 0.8.6 + 0.8.7 prepare-agent @@ -257,7 +259,7 @@ com.puppycrawl.tools checkstyle - 8.40 + 8.44 @@ -276,7 +278,7 @@ ossrh https://oss.sonatype.org/ - false + true @@ -310,7 +312,7 @@ org.projectlombok lombok-maven-plugin - 1.18.18.0 + ${lombok.version}.0 ${project.build.sourceDirectory} false @@ -325,6 +327,17 @@ + + org.apache.maven.plugins + maven-resources-plugin + 3.2.0 + + + + org.apache.maven.plugins + maven-install-plugin + 2.5.2 + @@ -337,7 +350,7 @@ org.projectlombok lombok - 1.18.10 + ${lombok.version} provided From 9a317695ac52efeead68d4e3d6d9d3fd9c83c87e Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Fri, 30 Jul 2021 14:25:20 +0200 Subject: [PATCH 205/431] Fix usage of cache action and disable Java 17 due to Lombok --- .github/workflows/build.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 60c172c57..1d746b9ca 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,9 +13,10 @@ jobs: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [ ubuntu-18.04, ubuntu-20.04, windows-latest ] - java: [ '8', '11', '17-ea' ] + java: [ '8', '11' ] arch: [ 'x86', 'x64' ] exclude: - os: ubuntu-18.04 @@ -36,7 +37,9 @@ jobs: uses: actions/cache@v2 with: path: ~/.m2/repository - key: m2-cache-${{ matrix.java }}-${{ matrix.arch }}-${{ matrix.os }} + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Set up JDK ${{ matrix.java }} uses: actions/setup-java@v2 From a118e796158cdad222e3a80d73d94884b6f02cb2 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sun, 1 Aug 2021 14:54:43 +0200 Subject: [PATCH 206/431] Fix a bunch of Javadoc errors --- pom.xml | 7 +++--- .../org/xbill/DNS/ClientSubnetOption.java | 2 +- src/main/java/org/xbill/DNS/Options.java | 24 ++++++++++++------- src/main/java/org/xbill/DNS/Rcode.java | 6 ++++- src/main/java/org/xbill/DNS/Serial.java | 2 +- src/main/java/org/xbill/DNS/TSIG.java | 6 ++++- .../DNS/lookup/LookupFailedException.java | 8 ++----- 7 files changed, 34 insertions(+), 21 deletions(-) diff --git a/pom.xml b/pom.xml index fc309854d..81e5e28d0 100644 --- a/pom.xml +++ b/pom.xml @@ -45,13 +45,14 @@ UTF-8 - 1.8 + 8 + 5.7.2 1.7.32 dnsjava_dnsjava dnsjava https://sonarcloud.io - 8 + ${target.jdk} ${project.build.directory}/site/jacoco/jacoco.xml ${project.build.directory}/generated-sources/delombok @@ -140,6 +141,7 @@ maven-javadoc-plugin 3.2.0 + ${target.jdk} true dnsjava documentation