Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Use simple parser instead of regex for parsing resolv.conf #5439

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 91 additions & 31 deletions vertx-core/src/main/java/io/vertx/core/impl/HostnameResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,35 +45,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;
Expand Down Expand Up @@ -129,18 +120,65 @@ public Future<Void> close() {
return provider.close();
}

public static int parseNdotsOptionFromResolvConf(String s) {
// visible for testing
public static ResolverOptions parseLinux(File f) {
try {
if (f.exists() && f.isFile()) {
return parseLinux(new String(Files.readAllBytes(f.toPath())));
}
} catch (Throwable t) {
log.debug("Failed to load options from /etc/resolv.conf", t);
}
return new ResolverOptions(DEFAULT_NDOTS, DEFAULT_ROTATE);
}

// exists mainly to facilitate testing
public static ResolverOptions parseLinux(String input) {
int ndots = -1;
Matcher matcher = NDOTS_OPTIONS_PATTERN.matcher(s);
while (matcher.find()) {
ndots = Integer.parseInt(matcher.group(1));
boolean rotate = false;
try {
int optionsIndex = input.indexOf(OPTIONS_ROW_LABEL);
if (optionsIndex != -1) {
boolean isProperOptionsLabel = false;
if (optionsIndex == 0) {
isProperOptionsLabel = true;
} else if (Character.isWhitespace(input.charAt(optionsIndex - 1))) {
isProperOptionsLabel = true;
}
if (isProperOptionsLabel) {
String afterOptions = input.substring(optionsIndex + OPTIONS_ROW_LABEL.length());
int rotateIndex = afterOptions.indexOf(ROTATE_LABEL);
if (rotateIndex != -1) {
if (!containsNewLine(afterOptions.substring(0, rotateIndex))) {
rotate = true;
}
}
int ndotsIndex = afterOptions.indexOf(NDOTS_LABEL);
if (ndotsIndex != -1) {
if (!containsNewLine(afterOptions.substring(0, ndotsIndex))) {
Matcher matcher = Pattern.compile("ndots:[ \\t\\f]*(\\d)+(?=$|\\s)").matcher(afterOptions.substring(ndotsIndex));
while (matcher.find()) {
ndots = Integer.parseInt(matcher.group(1));
}
}
}
}
}
} catch (NumberFormatException e) {
log.debug("Failed to load options from /etc/resolv.conf", e);
}
return ndots;
return new ResolverOptions(ndots, rotate);
}

public static boolean parseRotateOptionFromResolvConf(String s) {
Matcher matcher = ROTATE_OPTIONS_PATTERN.matcher(s);
return matcher.find();
//TODO: this can easily be parallelized if necessary
private static boolean containsNewLine(String input) {
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c == '\n') {
return true;
}
}
return false;
}

class Impl<L> implements EndpointResolver<SocketAddress, SocketAddress, L, L> {
Expand Down Expand Up @@ -190,4 +228,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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -769,40 +770,40 @@ 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("options").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options ndots: 4").getNdots());
assertEquals(4, HostnameResolver.parseLinux("\noptions ndots: 4").getNdots());
assertEquals(-1, HostnameResolver.parseLinux("boptions ndots: 4").getNdots());
assertEquals(4, HostnameResolver.parseLinux(" options ndots: 4").getNdots());
assertEquals(4, HostnameResolver.parseLinux("\toptions ndots: 4").getNdots());
assertEquals(4, HostnameResolver.parseLinux("\foptions ndots: 4").getNdots());
assertEquals(4, HostnameResolver.parseLinux("\n options ndots: 4").getNdots());

assertEquals(4, HostnameResolver.parseLinux("options\tndots: 4").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options\fndots: 4").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options ndots: 4").getNdots());
assertEquals(-1, HostnameResolver.parseLinux("options\nndots: 4").getNdots());

assertEquals(4, HostnameResolver.parseLinux("options ndots:4").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options ndots:\t4").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options ndots: 4").getNdots());
assertEquals(-1, HostnameResolver.parseLinux("options ndots:\n4").getNdots());

assertEquals(4, HostnameResolver.parseLinux("options ndots:4 ").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options ndots:4\t").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options ndots:4\f").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options ndots:4\n").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options ndots:4\r").getNdots());
assertEquals(-1, HostnameResolver.parseLinux("options ndots:4_").getNdots());

assertEquals(2, HostnameResolver.parseLinux("options ndots:4\noptions ndots:2").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options ndots:4 debug").getNdots());
assertEquals(4, HostnameResolver.parseLinux("options debug ndots:4").getNdots());

assertEquals(false, HostnameResolver.parseLinux("options").isRotate());
assertEquals(true, HostnameResolver.parseLinux("options rotate").isRotate());
assertEquals(true, HostnameResolver.parseLinux("options rotate\n").isRotate());
assertEquals(false, HostnameResolver.parseLinux("options\nrotate").isRotate());
}

@Test
Expand Down
Loading