Skip to content

Commit

Permalink
Detect and configure systemd-resolved when available (#323)
Browse files Browse the repository at this point in the history
* moving code to the right place

* created a minimal parser for resolved

* generic config parser

* refactoring to generify

* basic resolved parser is working

* adjustments and tests

* process is tested

* fixing tests

* refactoring

* refactoring

* fixing

* imports

* integrating with configurator

* creating more tests

* restart service stuff

* not able to test

* fixed system restart

* unused files

* fixing permissiosn

* Changed default dns server configs

* won't restart service while testing

* Fixing test

* release notes
  • Loading branch information
mageddo authored Feb 26, 2023
1 parent d688e9b commit 9c9ed92
Show file tree
Hide file tree
Showing 34 changed files with 874 additions and 255 deletions.
9 changes: 9 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
### 3.4.0-beta

* DPS will detect and configure systemd-resolved when available
* The default value of MG_RESOLVCONF was changed to
```
/host/etc/systemd/resolved.conf,/host/etc/resolv.conf,/etc/systemd/resolved.conf,/etc/resolv.conf
```
See issue [#321](https://github.com/mageddo/dns-proxy-server/issues/321) for more details.

### 3.3.0-beta
#### MG_RESOLVCONF will now accept more than one value
They will separate by comma , DPS will look for each value, try to use it and stops when finds a valid value, some path which is able to configure (an existing path, with the right read and write permissions and parseable by DPS)
Expand Down
6 changes: 3 additions & 3 deletions docker-compose-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ services:
environment:
- MG_LOG_LEVEL=DEBUG
- MG_REGISTER_CONTAINER_NAMES=1
- MG_RESOLVCONF=/host/etc/resolv.conf
# - MG_RESOLVCONF=/host/etc/systemd/resolved.conf
labels:
- dps.container=true
volumes:
- ./build:/app
- /var/run/docker.sock:/var/run/docker.sock
- /run/systemd/resolve/:/host/etc/
- /etc/systemd/:/host/etc/systemd/
working_dir: /app
command: java -jar dns-proxy-server.jar --default-dns=false
command: java -jar dns-proxy-server.jar
# ports:
# - "172.17.0.1:53:53/udp"
# - "192.168.0.128:53:53/udp"
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=3.3.0-beta
version=3.4.0-beta
quarkusPluginId=io.quarkus
quarkusPluginVersion=2.16.0.Final
quarkusPlatformGroupId=io.quarkus.platform
Expand Down
87 changes: 87 additions & 0 deletions src/main/java/com/mageddo/commons/exec/CommandLines.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.mageddo.commons.exec;

import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
import lombok.ToString;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DaemonExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.PumpStreamHandler;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;

public class CommandLines {

public static Result exec(String commandLine, Object... args) {
return exec(CommandLine.parse(String.format(commandLine, args)),
ExecuteWatchdog.INFINITE_TIMEOUT
);
}

public static Result exec(long timeout, String commandLine, Object... args) {
return exec(CommandLine.parse(String.format(commandLine, args)), timeout);
}

public static Result exec(CommandLine commandLine) {
return exec(commandLine, ExecuteWatchdog.INFINITE_TIMEOUT);
}

public static Result exec(CommandLine commandLine, long timeout) {
final var out = new ByteArrayOutputStream();
final var executor = new DaemonExecutor();
final var streamHandler = new PumpStreamHandler(out);
executor.setStreamHandler(streamHandler);
int exitCode;
try {
executor.setWatchdog(new ExecuteWatchdog(timeout));
exitCode = executor.execute(commandLine);
} catch (ExecuteException e) {
exitCode = e.getExitValue();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return Result
.builder()
.executor(executor)
.out(out)
.exitCode(exitCode)
.build();
}

@Getter
@Builder
@ToString(of = {"exitCode"})
public static class Result {

@NonNull
private Executor executor;

@NonNull
private ByteArrayOutputStream out;

private int exitCode;

public String getOutAsString() {
return this.out.toString();
}

public Result checkExecution() {
if (this.executor.isFailure(this.getExitCode())) {
throw new ExecutionValidationFailedException(this);
}
return this;
}

public String toString(boolean printOut) {
return String.format(
"code=%d, out=%s",
this.exitCode, printOut ? this.getOutAsString() : null
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.mageddo.commons.exec;

public class ExecutionValidationFailedException extends RuntimeException {
private final CommandLines.Result result;

public ExecutionValidationFailedException(CommandLines.Result result) {
super(String.format("error, code=%d, error=%s", result.getExitCode(), result.getOutAsString()));
this.result = result;
}

public CommandLines.Result result() {
return this.result;
}
}
91 changes: 91 additions & 0 deletions src/main/java/com/mageddo/conf/parser/ConfParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.mageddo.conf.parser;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.StringReader;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.mageddo.utils.Files.copyContent;


public class ConfParser {

public static List<Entry> parse(String in, Function<String, EntryType> parser) {
return parse(new BufferedReader(new StringReader(in)), parser);
}

public static List<Entry> parse(BufferedReader r, Function<String, EntryType> parser) {
try {
final var entries = new ArrayList<Entry>();
String line;
while ((line = r.readLine()) != null) {
entries.add(Entry
.builder()
.type(parser.apply(line))
.line(line)
.build()
);
}
return entries;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

public static void process(Path conf, Function<String, EntryType> parser, Transformer h) {
process(conf, conf, parser, h);
}

public static void process(Path source, Path target, Function<String, EntryType> parser, Transformer t) {
try {
final var tmpFile = Files.createTempFile("dps", ".conf");
try (
var reader = Files.newBufferedReader(source);
var writer = Files.newBufferedWriter(tmpFile)
) {
writeToOut(reader, writer, parser, t);
}
copyContent(tmpFile, target);
Files.delete(tmpFile);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

static void writeToOut(
BufferedReader reader, BufferedWriter writer,
Function<String, EntryType> parser, Transformer t
) {
final var lines = parse(reader, parser);
lines
.stream()
.map(t::handle)
.filter(Objects::nonNull)
.forEach(line -> writeLine(writer, line));
final var foundTokens = lines
.stream()
.map(it -> it.getType().name())
.collect(Collectors.toSet());
writeLine(writer, t.after(!lines.isEmpty(), foundTokens));
}

static void writeLine(BufferedWriter writer, String line) {
try {
if (line != null) {
writer.write(line);
writer.write('\n');
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

}
17 changes: 17 additions & 0 deletions src/main/java/com/mageddo/conf/parser/Entry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.mageddo.conf.parser;

import lombok.Builder;
import lombok.NonNull;
import lombok.Value;

@Value
@Builder
public class Entry {

@NonNull
EntryType type;

@NonNull
String line;

}
10 changes: 10 additions & 0 deletions src/main/java/com/mageddo/conf/parser/EntryType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.mageddo.conf.parser;

public interface EntryType {

String name();

static EntryType of(String name) {
return new EntryTypeDefault(name);
}
}
15 changes: 15 additions & 0 deletions src/main/java/com/mageddo/conf/parser/EntryTypeDefault.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.mageddo.conf.parser;

public class EntryTypeDefault implements EntryType {

private final String name;

public EntryTypeDefault(String name) {
this.name = name;
}

@Override
public String name() {
return this.name;
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/mageddo/conf/parser/Transformer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mageddo.conf.parser;

import java.util.Set;

public interface Transformer {

String handle(Entry entry);

default String after(boolean fileHasContent, Set<String> foundEntryTypes) {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ static Config build(ConfigFlag configFlag) {
}

static boolean runningInTestsAndNoCustomConfigPath(ConfigFlag configFlag) {
return !Arrays.toString(configFlag.getArgs()).contains("--conf-path") && Tests.runningOnJunit();
return !Arrays.toString(configFlag.getArgs()).contains("--conf-path") && Tests.inTest();
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public class ConfigEnv {
public static final String MG_DOMAIN = "MG_DOMAIN";
public static final String MG_DPS_NETWORK = "MG_DPS_NETWORK";
public static final String MG_DPS_NETWORK_AUTO_CONNECT = "MG_DPS_NETWORK_AUTO_CONNECT";
public static final String DEFAULT_RESOLV_CONF_PATH = "/host/etc/resolv.conf,/etc/resolv.conf";
public static final String DEFAULT_RESOLV_CONF_PATH =
"/host/etc/systemd/resolved.conf,/host/etc/resolv.conf,/etc/systemd/resolved.conf,/etc/resolv.conf";

private Path currentPath;
private String resolvConfPath;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.mageddo.dnsproxyserver.dnsconfigurator.linux;

import com.mageddo.conf.parser.Entry;
import com.mageddo.conf.parser.Transformer;
import com.mageddo.dnsproxyserver.dnsconfigurator.linux.DpsTokens;
import com.mageddo.dnsproxyserver.dnsconfigurator.linux.EntryTypes;

public class CleanerHandler implements Transformer {

@Override
public String handle(Entry entry) {
return switch (entry.getType().name()) {
case EntryTypes.DPS_SERVER -> null;
case EntryTypes.COMMENTED_SERVER -> DpsTokens.uncomment(entry.getLine());
default -> entry.getLine();
};
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.mageddo.dnsproxyserver.dnsconfigurator.linux;

import com.mageddo.conf.parser.Entry;
import com.mageddo.conf.parser.Transformer;
import com.mageddo.dnsproxyserver.dnsconfigurator.linux.DpsTokens;
import com.mageddo.dnsproxyserver.dnsconfigurator.linux.EntryTypes;

import java.util.Set;
import java.util.function.Supplier;

public class ConfigureDPSHandler implements Transformer {

private final Supplier<String> dpsDnsLineBuilder;

public ConfigureDPSHandler(Supplier<String> dpsDnsLineBuilder) {
this.dpsDnsLineBuilder = dpsDnsLineBuilder;
}

@Override
public String handle(Entry entry) {
return switch (entry.getType().name()) {
case EntryTypes.DPS_SERVER -> this.dpsDnsLineBuilder.get();
case EntryTypes.SERVER -> DpsTokens.comment(entry.getLine());
default -> entry.getLine();
};
}

@Override
public String after(boolean fileHasContent, Set<String> foundEntryTypes) {
if (!fileHasContent || !foundEntryTypes.contains(EntryTypes.DPS_SERVER)) {
return this.dpsDnsLineBuilder.get();
}
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.mageddo.dnsproxyserver.dnsconfigurator.linux;

public class DpsTokens {
public static final String COMMENT_END = "# dps-comment";
public static final String DPS_ENTRY_COMMENT = "# dps-entry";
public static final String COMMENT = "#";

public static String comment(String line) {
return String.format("# %s # dps-comment", line);
}

public static String uncomment(final String line) {
return line
.substring(
2,
line
.indexOf(" " + COMMENT_END)
);
}
}
Loading

0 comments on commit 9c9ed92

Please sign in to comment.