diff --git a/.editorconfig b/.editorconfig index 6e1b7d5ab..0c95aa667 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,6 +6,7 @@ indent_size = 2 insert_final_newline = true charset = utf-8 end_of_line = lf +trim_trailing_whitespace = true [{pom.xml,*.md}] indent_style = space diff --git a/.github/actions/prepare-analysis/action.yml b/.github/actions/prepare-analysis/action.yml index 179564e10..73c2b8624 100644 --- a/.github/actions/prepare-analysis/action.yml +++ b/.github/actions/prepare-analysis/action.yml @@ -38,7 +38,7 @@ runs: echo "check_name<> $GITHUB_OUTPUT - name: Publish Test Report - uses: mikepenz/action-junit-report@v3 + uses: mikepenz/action-junit-report@v4 with: commit: ${{ github.event.workflow_run.head_sha }} report_paths: ${{ steps.junit_paths.outputs.report_paths }} diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 0a545af1c..f9c4a1fd9 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -13,7 +13,7 @@ permissions: checks: write env: - BUILD_JAVA_VERSION: '20' + BUILD_JAVA_VERSION: '21' jobs: analyze: @@ -48,7 +48,7 @@ jobs: number: ${{ steps.pr_number.outputs.pr_number }} - name: Checkout PR - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ${{ github.event.workflow_run.head_repository.full_name }} ref: ${{ github.event.workflow_run.head_sha }} @@ -60,7 +60,7 @@ jobs: run: rm -rf base - name: Checkout base - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ${{ github.event.repository.full_name }} ref: ${{ fromJson(steps.get_pr_data.outputs.data).base.ref }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ad3e5c1ce..f197d55de 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,7 +32,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK ${{ matrix.java }} uses: actions/setup-java@v3 @@ -56,6 +56,16 @@ jobs: mv jacoco.exec jacoco-${{ matrix.java }}-${{ matrix.arch }}-${{ matrix.os }}.exec mv surefire-reports surefire-reports-${{ matrix.java }}-${{ matrix.arch }}-${{ matrix.os }} + - name: Verify that the main classes are really compiled for Java 8 + if: matrix.os == 'ubuntu-latest' + run: | + class_file_version=$(javap -v target/classes/org/xbill/DNS/SimpleResolver.class | grep -oP "major version: \K\d+") + echo "::notice file=SimpleResolver.class::Class file version ${class_file_version}" + if [ "${class_file_version}" != "52" ]; then + echo "::error file=SimpleResolver.class::Class file version is not Java 8" + exit 1 + fi + - name: Upload classes uses: ./.github/actions/upload-artifact if: always() && matrix.java == env.BUILD_JAVA_VERSION && matrix.arch == 'x64' && matrix.os == 'ubuntu-latest' @@ -85,7 +95,7 @@ jobs: needs: test steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK uses: actions/setup-java@v3 @@ -133,7 +143,7 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.owner.login == 'dnsjava' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # for Sonar fetch-depth: 0 @@ -160,12 +170,12 @@ jobs: needs: test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: Set up JDK 8 + - name: Set up JDK ${env.BUILD_JAVA_VERSION} uses: actions/setup-java@v3 with: - java-version: '8' + java-version: env.BUILD_JAVA_VERSION architecture: 'x64' distribution: temurin cache: maven @@ -183,6 +193,23 @@ jobs: mvn \ --no-transfer-progress \ --batch-mode \ - -Dgpg.passphrase="${{ secrets.GPG_PW }}" \ - -DperformRelease=true \ - deploy + compile + # Verify that the main classes are really compiled for Java 8 + class_file_version=$(javap -v target/classes/org/xbill/DNS/SimpleResolver.class | grep -oP "major version: \K\d+") + echo "::notice file=SimpleResolver.class::Class file version ${class_file_version}" + if [ "${class_file_version}" == "52" ]; then + mvn \ + --no-transfer-progress \ + --batch-mode \ + -Dgpg.passphrase="${{ secrets.GPG_PW }}" \ + -DperformRelease=true \ + -DskipTests \ + -Dmaven.test.skip.exec \ + -Dcheckstyle.skip \ + -Dspotless.check.skip=true \ + -Danimal.sniffer.skip=true + deploy + else + echo "::error file=SimpleResolver.class::Class file version is not Java 8" + exit 1 + fi diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0f0d88d97..e58aaeb27 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL @@ -33,16 +33,28 @@ jobs: with: languages: java - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: - java-version: 11 + java-version: 21 distribution: temurin check-latest: true cache: maven - name: Build with Maven - run: mvn verify -B -"Dgpg.skip" + # Skip tests, code style, etc. This is handled in the regular CI workflows. + run: | + mvn clean package -B -V \ + -DskipTests \ + -Dmaven.test.skip.exec \ + -Dgpg.skip \ + -Dcheckstyle.skip \ + -Denforcer.skip \ + -Dmaven.javadoc.skip \ + -Dspotless.check.skip=true \ + -Danimal.sniffer.skip=true \ + compile \ + test-compile - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml new file mode 100644 index 000000000..5674d88a9 --- /dev/null +++ b/.github/workflows/report.yml @@ -0,0 +1,24 @@ +name: report +on: + workflow_run: + workflows: [ build ] + types: [ completed ] + +permissions: + checks: write + +jobs: + checks: + runs-on: ubuntu-latest + steps: + - name: Download Test Report + uses: dawidd6/action-download-artifact@v2 + with: + name: junit-test-results + workflow: ${{ github.event.workflow.id }} + run_id: ${{ github.event.workflow_run.id }} + - name: Publish Test Report + uses: mikepenz/action-junit-report@v3 + with: + commit: ${{ github.event.workflow_run.head_sha }} + report_paths: 'target/surefire-reports/TEST-*.xml' diff --git a/LICENSE b/LICENSE index 3f092bc74..60bca5d90 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ Copyright (c) 1998-2019, Brian Wellington Copyright (c) 2005 VeriSign. All rights reserved. -Copyright (c) 2019-2021, dnsjava authors +Copyright (c) 2019-2023, dnsjava authors All rights reserved. diff --git a/README.adoc b/README.adoc index d4b44e1b1..55646fdf7 100644 --- a/README.adoc +++ b/README.adoc @@ -317,7 +317,7 @@ The servers can either be IP addresses or hostnames (which are resolved using Ja - On Windows, if https://github.com/java-native-access/jna[JNA] is available on the classpath, the `GetAdaptersAddresses` API is used. - 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. -As of Java 16 the JVM flag `--add-opens java.base/sun.net.dns=ALL-UNNAMED` is also required. +As of Java 16 the JVM flag `--add-opens java.base/sun.net.dns=ALL-UNNAMED` (classpath) or `--add-opens java.base/sun.net.dns=org.dnsjava` (modules) is also required. - If available and no servers have been found yet, https://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-dns.html[JNDI-DNS] 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. diff --git a/checkstyle/checkstyle-config.xml b/checkstyle/checkstyle-config.xml index 0d6704580..2b91d226d 100644 --- a/checkstyle/checkstyle-config.xml +++ b/checkstyle/checkstyle-config.xml @@ -9,4 +9,8 @@ + + + + diff --git a/pom.xml b/pom.xml index 1bb04de4c..6b871873f 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,8 @@ UTF-8 8 + true + false 5.10.0 @@ -54,7 +56,7 @@ 1.18.30 5.13.0 1.76 - 4.4.4 + 4.4.6 dnsjava_dnsjava dnsjava @@ -92,7 +94,10 @@ maven-compiler-plugin 3.11.0 - -Xlint:unchecked + + -Xlint:all,-serial,-processing + -Xpkginfo:always + org.projectlombok @@ -118,35 +123,40 @@ true lombok - dnsjava is an implementation of DNS in Java + dnsjava + dnsjava is an implementation of DNS in Java org.xbill.dns - org.dnsjava + https://javadoc.io/doc/dnsjava/dnsjava <_noclassforname>true <_donotcopy>android|sun <_nouses>true + <_noee>true org.xbill.DNS.* - !sun.*,. + !android.*,!sun.*,. !org.xbill.DNS*, !sun.*, !lombok, - android.*;resolution:=optional, + !android.*, javax.naming.*;resolution:=optional, - com.sun.jna.*;resolution:=optional, + org.slf4j;version="[1.7,3)", + com.sun.jna.*;resolution:=optional;version="[5,6)", * - JavaSE-1.8 BSD-3-Clause;link="https://raw.githubusercontent.com/dnsjava/dnsjava/master/LICENSE" - <_removeheaders>Bnd-*, Tool, Require-Capability, Include-Resource + <_removeheaders>Bnd-*, Tool, Require-Capability, Include-Resource, Private-Package + <_snapshot>SNAPSHOT {maven-resources}, META-INF/LICENSE=LICENSE org.xbill.DNS.tools.Tools + <_fixupmessages>"Classes found in the wrong directory";is:=ignore + true @@ -154,7 +164,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.5.0 + 3.6.0 ${target.jdk} true @@ -184,7 +194,7 @@ org.jacoco jacoco-maven-plugin - 0.8.10 + 0.8.11 prepare-agent @@ -222,7 +232,7 @@ com.github.siom79.japicmp japicmp-maven-plugin - 0.17.2 + 0.18.3 @@ -241,6 +251,9 @@ sun org.xbill.DNS.config.IPHlpAPI + org.xbill.DNS.spi.DnsjavaInetAddressResolver + org.xbill.DNS.spi.DNSJavaNameService + org.xbill.DNS.spi.DNSJavaNameServiceDescriptor org.xbill.DNS.dnssec.TrustAnchorStore @@ -269,22 +282,38 @@ - com.coveo - fmt-maven-plugin - 2.9.1 - - - - check - - - + com.diffplug.spotless + spotless-maven-plugin + 2.40.0 + + + + + *.* + + + + + + + + + src/main/java/**/*.java + src/main/java11/**/*.java + src/main/java21/**/*.java + src/test/java/**/*.java + + + 1.7 + + + org.apache.maven.plugins maven-checkstyle-plugin - 3.3.0 + 3.3.1 check @@ -345,8 +374,16 @@ javax.naming.NamingException javax.naming.directory.* sun.net.spi.nameservice.* + java.net.spi.* + + + org.ow2.asm + asm + 9.6 + + animal-sniffer @@ -369,6 +406,12 @@ maven-install-plugin 3.1.1 + + + org.codehaus.mojo + build-helper-maven-plugin + 3.4.0 + @@ -450,6 +493,13 @@ ${vertx.version} test + + + io.vertx + vertx-codegen + ${vertx.version} + test + commons-io commons-io @@ -479,19 +529,79 @@ - java9 + java11 - [9,) + [11,) + + 5.7.0 + + + + org.apache.felix + maven-bundle-plugin + + + + {maven-resources}, + META-INF/versions=-target/classes/META-INF/versions, + META-INF/LICENSE=LICENSE + + + + + org.apache.maven.plugins maven-compiler-plugin ${target.jdk} + + -Xlint:all,-serial,-processing,-requires-automatic + -Xpkginfo:always + + + + + + default-compile + + compile + + + ${target.jdk} + + ${project.basedir}/src/main/java + + + + + + + compile-java11 + + compile + + + 11 + true + + ${project.basedir}/src/main/java11 + + + + + + default-testCompile + + ${target.jdk} + + + @@ -501,20 +611,146 @@ ${argLine} --add-opens java.base/sun.net.dns=ALL-UNNAMED + + ${project.build.outputDirectory}/META-INF/versions/11 + + - java-11 + + java11-not-idea + false [11,) + + !idea.version + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-java11-source + generate-sources + + add-source + + + + src/main/java11 + + + + + + + + - - 5.7.0 - + + + java11-idea + + false + [11,21) + + idea.version + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-java11-source + generate-sources + + add-source + + + + src/main/java11 + + + + + + + + + + + java21 + + [21,) + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + compile-java21 + + compile + + + 21 + true + + ${project.basedir}/src/main/java21 + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${argLine} --add-opens java.base/sun.net.dns=ALL-UNNAMED + + + ${project.build.outputDirectory}/META-INF/versions/11 + ${project.build.outputDirectory}/META-INF/versions/21 + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-java21-source + generate-sources + + add-source + + + + src/main/java21 + + + + + + + diff --git a/src/main/java/org/xbill/DNS/TTL.java b/src/main/java/org/xbill/DNS/TTL.java index 76197d79a..960992e4e 100644 --- a/src/main/java/org/xbill/DNS/TTL.java +++ b/src/main/java/org/xbill/DNS/TTL.java @@ -31,8 +31,9 @@ static void check(long i) { * @return The value as a number of seconds * @throws NumberFormatException The string was not in a valid TTL format. */ + @SuppressWarnings("fallthrough") public static long parse(String s, boolean clamp) { - if (s == null || s.length() == 0 || !Character.isDigit(s.charAt(0))) { + if (s == null || s.isEmpty() || !Character.isDigit(s.charAt(0))) { throw new NumberFormatException(); } long value = 0; diff --git a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java index ae6fe4662..66baeac01 100644 --- a/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java +++ b/src/main/java/org/xbill/DNS/config/SunJvmResolverConfigProvider.java @@ -13,6 +13,8 @@ *
  • Java 9: generates an illegal reflective access exception. *
  • Java 16 (classpath): requires adding the JVM flag {@code --add-opens * java.base/sun.net.dns=ALL-UNNAMED}. + *
  • Java 16 (module path): requires adding the JVM flag {@code --add-opens + * java.base/sun.net.dns=org.dnsjava}. *
  • On Windows, may return invalid nameservers of disconnected NICs before Java 15, JDK-7006496. * diff --git a/src/main/java11/module-info.java b/src/main/java11/module-info.java new file mode 100644 index 000000000..8ed168871 --- /dev/null +++ b/src/main/java11/module-info.java @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: BSD-3-Clause + +module org.dnsjava { + requires static lombok; + requires static java.naming; + requires static com.sun.jna; + requires static com.sun.jna.platform; + requires static java.net.http; + requires org.slf4j; + + exports org.xbill.DNS; + exports org.xbill.DNS.config; + exports org.xbill.DNS.dnssec; + exports org.xbill.DNS.hosts; + exports org.xbill.DNS.lookup; + exports org.xbill.DNS.tools; + exports org.xbill.DNS.utils; +} diff --git a/src/main/java21/module-info.java b/src/main/java21/module-info.java new file mode 100644 index 000000000..73a90f811 --- /dev/null +++ b/src/main/java21/module-info.java @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause + +import java.net.spi.InetAddressResolverProvider; +import org.xbill.DNS.spi.DnsjavaInetAddressResolverProvider; + +module org.dnsjava { + requires static lombok; + requires static java.naming; + requires static com.sun.jna; + requires static com.sun.jna.platform; + requires static java.net.http; + requires org.slf4j; + + exports org.xbill.DNS; + exports org.xbill.DNS.config; + exports org.xbill.DNS.dnssec; + exports org.xbill.DNS.hosts; + exports org.xbill.DNS.lookup; + exports org.xbill.DNS.tools; + exports org.xbill.DNS.utils; + + provides InetAddressResolverProvider with + DnsjavaInetAddressResolverProvider; +} diff --git a/src/main/java21/org/xbill/DNS/spi/DnsjavaInetAddressResolver.java b/src/main/java21/org/xbill/DNS/spi/DnsjavaInetAddressResolver.java new file mode 100644 index 000000000..d92be358e --- /dev/null +++ b/src/main/java21/org/xbill/DNS/spi/DnsjavaInetAddressResolver.java @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: BSD-3-Clause +package org.xbill.DNS.spi; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.net.spi.InetAddressResolver; +import java.net.spi.InetAddressResolverProvider.Configuration; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import lombok.extern.slf4j.Slf4j; +import org.xbill.DNS.AAAARecord; +import org.xbill.DNS.ARecord; +import org.xbill.DNS.Lookup; +import org.xbill.DNS.Name; +import org.xbill.DNS.PTRRecord; +import org.xbill.DNS.Record; +import org.xbill.DNS.ReverseMap; +import org.xbill.DNS.TextParseException; +import org.xbill.DNS.Type; + +@Slf4j +class DnsjavaInetAddressResolver implements InetAddressResolver { + private static final String PREFER_V6_PROPERTY = "java.net.preferIPv6Addresses"; + + private final boolean preferV6; + private final Configuration configuration; + + DnsjavaInetAddressResolver(Configuration configuration) { + log.info("Enabling dnsjava SPI"); + this.configuration = configuration; + preferV6 = Boolean.getBoolean(PREFER_V6_PROPERTY); + } + + @Override + public Stream lookupByName(String host, LookupPolicy lookupPolicy) + throws UnknownHostException { + // delegate local hostnames to the default resolver - we don't know them any better + // and this shouldn't leak anything either + if (host.equalsIgnoreCase(configuration.lookupLocalHostName()) + || "localhost".equalsIgnoreCase(host)) { + return configuration.builtinResolver().lookupByName(host, lookupPolicy); + } + + Name name; + try { + name = new Name(host); + } catch (TextParseException e) { + throw new UnknownHostException(host); + } + + List results = new ArrayList<>(8); + boolean ranIpV4 = false; + boolean ranIpV6 = false; + + int characteristics = lookupPolicy.characteristics(); + // fallback to default policy if no specific preference has been set + if ((characteristics & (LookupPolicy.IPV6_FIRST | LookupPolicy.IPV4_FIRST)) == 0) { + if (preferV6) { + characteristics |= LookupPolicy.IPV6_FIRST; + } else { + characteristics |= LookupPolicy.IPV4_FIRST; + } + } + if ((characteristics & LookupPolicy.IPV6) == LookupPolicy.IPV6 + && (characteristics & LookupPolicy.IPV6_FIRST) == LookupPolicy.IPV6_FIRST) { + Record[] records = new Lookup(name, Type.AAAA).run(); + if (records != null) { + for (Record r : records) { + results.add(((AAAARecord) r).getAddress()); + } + } + ranIpV6 = true; + } + if ((characteristics & LookupPolicy.IPV4) == LookupPolicy.IPV4 + && (characteristics & LookupPolicy.IPV4_FIRST) == LookupPolicy.IPV4_FIRST) { + Record[] records = new Lookup(name, Type.A).run(); + if (records != null) { + for (Record r : records) { + results.add(((ARecord) r).getAddress()); + } + } + ranIpV4 = true; + } + if ((characteristics & LookupPolicy.IPV4) == LookupPolicy.IPV4 && !ranIpV4) { + Record[] records = new Lookup(name, Type.A).run(); + if (records != null) { + for (Record r : records) { + results.add(((ARecord) r).getAddress()); + } + } + } + if ((characteristics & LookupPolicy.IPV6) == LookupPolicy.IPV6 && !ranIpV6) { + Record[] records = new Lookup(name, Type.AAAA).run(); + if (records != null) { + for (Record r : records) { + results.add(((AAAARecord) r).getAddress()); + } + } + } + if (results.isEmpty()) { + throw new UnknownHostException(host); + } + + return results.stream(); + } + + @Override + public String lookupByAddress(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("Unknown address: " + name); + } + return ((PTRRecord) records[0]).getTarget().toString(); + } +} diff --git a/src/main/java21/org/xbill/DNS/spi/DnsjavaInetAddressResolverProvider.java b/src/main/java21/org/xbill/DNS/spi/DnsjavaInetAddressResolverProvider.java new file mode 100644 index 000000000..f146c399a --- /dev/null +++ b/src/main/java21/org/xbill/DNS/spi/DnsjavaInetAddressResolverProvider.java @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +package org.xbill.DNS.spi; + +import java.net.spi.InetAddressResolver; +import java.net.spi.InetAddressResolverProvider; + +public class DnsjavaInetAddressResolverProvider extends InetAddressResolverProvider { + public static final String ENABLE_SPI = "org.dnsjava.spi.enable"; + + @Override + public InetAddressResolver get(Configuration configuration) { + // The provider is opt-in only. Simply placing dnsjava on the classpath should not + // modify default resolution behavior. + if (Boolean.getBoolean(ENABLE_SPI)) { + return new DnsjavaInetAddressResolver(configuration); + } + return configuration.builtinResolver(); + } + + @Override + public String name() { + return "dnsjava"; + } +} diff --git a/src/main/resources/META-INF/services/java.net.spi.InetAddressResolverProvider b/src/main/resources/META-INF/services/java.net.spi.InetAddressResolverProvider new file mode 100644 index 000000000..e477fd238 --- /dev/null +++ b/src/main/resources/META-INF/services/java.net.spi.InetAddressResolverProvider @@ -0,0 +1 @@ +org.xbill.DNS.spi.DnsjavaInetAddressResolverProvider diff --git a/src/test/java/org/xbill/DNS/DNSInputBase.java b/src/test/java/org/xbill/DNS/DNSInputTest.java similarity index 100% rename from src/test/java/org/xbill/DNS/DNSInputBase.java rename to src/test/java/org/xbill/DNS/DNSInputTest.java