diff --git a/vertx-core/src/main/java/io/vertx/core/impl/HostnameResolver.java b/vertx-core/src/main/java/io/vertx/core/impl/HostnameResolver.java index 9074c010c00..e21ad85a264 100644 --- a/vertx-core/src/main/java/io/vertx/core/impl/HostnameResolver.java +++ b/vertx-core/src/main/java/io/vertx/core/impl/HostnameResolver.java @@ -26,10 +26,13 @@ import io.vertx.core.spi.dns.AddressResolverProvider; import io.vertx.core.spi.endpoint.EndpointResolver; +import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.nio.file.Files; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -45,35 +48,26 @@ public class HostnameResolver implements AddressResolver { private static final Logger log = LoggerFactory.getLogger(HostnameResolver.class); - private static Pattern resolvOption(String regex) { - return Pattern.compile("^[ \\t\\f]*options[^\n]+" + regex + "(?=$|\\s)", Pattern.MULTILINE); - } - - private static final Pattern NDOTS_OPTIONS_PATTERN = resolvOption("ndots:[ \\t\\f]*(\\d)+"); - private static final Pattern ROTATE_OPTIONS_PATTERN = resolvOption("rotate"); + private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\s+"); + private static final String NDOTS_LABEL = "ndots:"; + private static final String ROTATE_LABEL = "rotate"; + private static final String OPTIONS_ROW_LABEL = "options"; public static final int DEFAULT_NDOTS_RESOLV_OPTION; public static final boolean DEFAULT_ROTATE_RESOLV_OPTION; + + private static final int DEFAULT_NDOTS = 1; + private static final boolean DEFAULT_ROTATE = false; + static { - int ndots = 1; - boolean rotate = false; if (isLinux()) { - File f = new File("/etc/resolv.conf"); - try { - if (f.exists() && f.isFile()) { - String conf = Files.readString(f.toPath()); - int ndotsOption = parseNdotsOptionFromResolvConf(conf); - if (ndotsOption != -1) { - ndots = ndotsOption; - } - rotate = parseRotateOptionFromResolvConf(conf); - } - } catch (Throwable t) { - log.debug("Failed to load options from /etc/resolv/.conf", t); - } + ResolverOptions options = parseLinux(new File("/etc/resolv.conf")); + DEFAULT_NDOTS_RESOLV_OPTION = options.getEffectiveNdots(); + DEFAULT_ROTATE_RESOLV_OPTION = options.isRotate(); + } else { + DEFAULT_NDOTS_RESOLV_OPTION = DEFAULT_NDOTS; + DEFAULT_ROTATE_RESOLV_OPTION = DEFAULT_ROTATE; } - DEFAULT_NDOTS_RESOLV_OPTION = ndots; - DEFAULT_ROTATE_RESOLV_OPTION = rotate; } private final Vertx vertx; @@ -129,18 +123,49 @@ public Future close() { return provider.close(); } - public static int parseNdotsOptionFromResolvConf(String s) { - int ndots = -1; - Matcher matcher = NDOTS_OPTIONS_PATTERN.matcher(s); - while (matcher.find()) { - ndots = Integer.parseInt(matcher.group(1)); + // visible for testing + public static ResolverOptions parseLinux(File f) { + try { + if (f.exists() && f.isFile()) { + try (BufferedReader br = new BufferedReader(new FileReader(f))) { + return parseLinux(br); + } + } + } catch (Throwable t) { + log.debug("Failed to load options from /etc/resolv.conf", t); } - return ndots; + return new ResolverOptions(DEFAULT_NDOTS, DEFAULT_ROTATE); } - public static boolean parseRotateOptionFromResolvConf(String s) { - Matcher matcher = ROTATE_OPTIONS_PATTERN.matcher(s); - return matcher.find(); + // exists mainly to facilitate testing + public static ResolverOptions parseLinux(BufferedReader br) { + String line; + int ndots = -1; + boolean rotate = false; + try { + while ((line = br.readLine()) != null) { + if (line.trim().startsWith(OPTIONS_ROW_LABEL)) { + String[] parts = WHITESPACE_PATTERN.split(line.substring(OPTIONS_ROW_LABEL.length())); + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (part.startsWith(NDOTS_LABEL)) { + String value; + if (i < parts.length - 1 && part.equals(NDOTS_LABEL)) { + value = parts[i + 1]; + } else { + value = part.substring(NDOTS_LABEL.length()); + } + ndots = Integer.parseInt(value); + } else if (part.contains(ROTATE_LABEL)) { + rotate = true; + } + } + } + } + } catch (IOException | NumberFormatException e) { + log.debug("Failed to load options from /etc/resolv.conf", e); + } + return new ResolverOptions(ndots, rotate); } class Impl implements EndpointResolver { @@ -190,4 +215,26 @@ public void dispose(L data) { public void close() { } } + + public static class ResolverOptions { + private final int ndots; + private final boolean rotate; + + public ResolverOptions(int ndots, boolean rotate) { + this.ndots = ndots; + this.rotate = rotate; + } + + public int getNdots() { + return ndots; + } + + public int getEffectiveNdots() { + return ndots != -1 ? ndots : 1; + } + + public boolean isRotate() { + return rotate; + } + } } diff --git a/vertx-core/src/test/java/io/vertx/tests/dns/HostnameResolutionTest.java b/vertx-core/src/test/java/io/vertx/tests/dns/HostnameResolutionTest.java index dab3b97d3cd..804c7695e78 100644 --- a/vertx-core/src/test/java/io/vertx/tests/dns/HostnameResolutionTest.java +++ b/vertx-core/src/test/java/io/vertx/tests/dns/HostnameResolutionTest.java @@ -34,8 +34,9 @@ import io.vertx.test.core.TestUtils; import io.vertx.test.core.VertxTestBase; import io.vertx.test.fakedns.FakeDNSServer; +import java.io.BufferedReader; +import java.io.StringReader; import org.junit.Assume; -import org.junit.Ignore; import org.junit.Test; import java.io.File; @@ -769,40 +770,44 @@ public void testNetSearchDomain() throws Exception { @Test public void testParseResolvConf() { - assertEquals(-1, HostnameResolver.parseNdotsOptionFromResolvConf("options")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots: 4")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("\noptions ndots: 4")); - assertEquals(-1, HostnameResolver.parseNdotsOptionFromResolvConf("boptions ndots: 4")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf(" options ndots: 4")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("\toptions ndots: 4")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("\foptions ndots: 4")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("\n options ndots: 4")); - - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options\tndots: 4")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options\fndots: 4")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots: 4")); - assertEquals(-1, HostnameResolver.parseNdotsOptionFromResolvConf("options\nndots: 4")); - - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:4")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:\t4")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots: 4")); - assertEquals(-1, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:\n4")); - - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:4 ")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:4\t")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:4\f")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:4\n")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:4\r")); - assertEquals(-1, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:4_")); - - assertEquals(2, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:4\noptions ndots:2")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options ndots:4 debug")); - assertEquals(4, HostnameResolver.parseNdotsOptionFromResolvConf("options debug ndots:4")); - - assertEquals(false, HostnameResolver.parseRotateOptionFromResolvConf("options")); - assertEquals(true, HostnameResolver.parseRotateOptionFromResolvConf("options rotate")); - assertEquals(true, HostnameResolver.parseRotateOptionFromResolvConf("options rotate\n")); - assertEquals(false, HostnameResolver.parseRotateOptionFromResolvConf("options\nrotate")); + assertEquals(-1, HostnameResolver.parseLinux(toBufferedReader("options")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots: 4")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("\noptions ndots: 4")).getNdots()); + assertEquals(-1, HostnameResolver.parseLinux(toBufferedReader("boptions ndots: 4")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader(" options ndots: 4")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("\toptions ndots: 4")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("\foptions ndots: 4")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("\n options ndots: 4")).getNdots()); + + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options\tndots: 4")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options\fndots: 4")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots: 4")).getNdots()); + assertEquals(-1, HostnameResolver.parseLinux(toBufferedReader("options\nndots: 4")).getNdots()); + + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots:4")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots:\t4")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots: 4")).getNdots()); + assertEquals(-1, HostnameResolver.parseLinux(toBufferedReader("options ndots:\n4")).getNdots()); + + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots:4 ")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots:4\t")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots:4\f")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots:4\n")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots:4\r")).getNdots()); + assertEquals(-1, HostnameResolver.parseLinux(toBufferedReader("options ndots:4_")).getNdots()); + + assertEquals(2, HostnameResolver.parseLinux(toBufferedReader("options ndots:4\noptions ndots:2")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options ndots:4 debug")).getNdots()); + assertEquals(4, HostnameResolver.parseLinux(toBufferedReader("options debug ndots:4")).getNdots()); + + assertEquals(false, HostnameResolver.parseLinux(toBufferedReader("options")).isRotate()); + assertEquals(true, HostnameResolver.parseLinux(toBufferedReader("options rotate")).isRotate()); + assertEquals(true, HostnameResolver.parseLinux(toBufferedReader("options rotate\n")).isRotate()); + assertEquals(false, HostnameResolver.parseLinux(toBufferedReader("options\nrotate")).isRotate()); + } + + private static BufferedReader toBufferedReader(String s) { + return new BufferedReader(new StringReader(s)); } @Test