This commit is contained in:
parent
48be45de26
commit
ba7c9d5fcc
10 changed files with 96 additions and 143 deletions
6
pom.xml
6
pom.xml
|
@ -18,6 +18,7 @@
|
||||||
<surefire-plugin.version>3.5.0</surefire-plugin.version>
|
<surefire-plugin.version>3.5.0</surefire-plugin.version>
|
||||||
<mockito.version>5.14.1</mockito.version>
|
<mockito.version>5.14.1</mockito.version>
|
||||||
<assertj.version>3.26.3</assertj.version>
|
<assertj.version>3.26.3</assertj.version>
|
||||||
|
<dnsjava.version>3.6.2</dnsjava.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
@ -55,6 +56,11 @@
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-arc</artifactId>
|
<artifactId>quarkus-arc</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>dnsjava</groupId>
|
||||||
|
<artifactId>dnsjava</artifactId>
|
||||||
|
<version>${dnsjava.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-junit5</artifactId>
|
<artifactId>quarkus-junit5</artifactId>
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class Updater {
|
||||||
void run() {
|
void run() {
|
||||||
log.trace("Updater running.");
|
log.trace("Updater running.");
|
||||||
|
|
||||||
if(config.isEmpty()) {
|
if (config.isEmpty()) {
|
||||||
throw new IllegalStateException("Missing configuration");
|
throw new IllegalStateException("Missing configuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
46
src/main/java/de/rpr/ddnsclient/lookup/DnsJava.java
Normal file
46
src/main/java/de/rpr/ddnsclient/lookup/DnsJava.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package de.rpr.ddnsclient.lookup;
|
||||||
|
|
||||||
|
import de.rpr.ddnsclient.model.IPs;
|
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||||
|
import org.xbill.DNS.*;
|
||||||
|
import org.xbill.DNS.Record;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class DnsJava implements DnsResolver {
|
||||||
|
|
||||||
|
private final String resolverAddress;
|
||||||
|
|
||||||
|
public DnsJava(@ConfigProperty(name = "", defaultValue = "9.9.9.9") String resolverAddress) {
|
||||||
|
this.resolverAddress = resolverAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IPs resolve(String hostname) {
|
||||||
|
String v4 = getIp(hostname, Type.A).orElseThrow(() -> new RuntimeException("Missing A Record"));
|
||||||
|
String v6 = getIp(hostname, Type.AAAA).orElseThrow(() -> new RuntimeException("Missing AAAA Record"));
|
||||||
|
return new IPs(v4, v6);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<String> getIp(String hostname, int type) {
|
||||||
|
try {
|
||||||
|
SimpleResolver resolver = new SimpleResolver(resolverAddress);
|
||||||
|
|
||||||
|
Lookup lookup = new Lookup(hostname, type);
|
||||||
|
lookup.setResolver(resolver);
|
||||||
|
|
||||||
|
Record[] records = lookup.run();
|
||||||
|
for (Record record : records) {
|
||||||
|
if (record instanceof ARecord) {
|
||||||
|
return Optional.of(((ARecord) record).getAddress().getHostAddress());
|
||||||
|
}
|
||||||
|
if (record instanceof AAAARecord) {
|
||||||
|
return Optional.of(((AAAARecord) record).getAddress().getHostAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,48 +1,7 @@
|
||||||
package de.rpr.ddnsclient.lookup;
|
package de.rpr.ddnsclient.lookup;
|
||||||
|
|
||||||
|
|
||||||
import de.rpr.ddnsclient.model.IPs;
|
import de.rpr.ddnsclient.model.IPs;
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
import javax.naming.NamingException;
|
public interface DnsResolver {
|
||||||
import javax.naming.directory.Attributes;
|
IPs resolve(String hostname);
|
||||||
import javax.naming.directory.DirContext;
|
|
||||||
|
|
||||||
@ApplicationScoped
|
|
||||||
public class DnsResolver {
|
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(DnsResolver.class);
|
|
||||||
|
|
||||||
public static final int MAX_RETRIES = 5;
|
|
||||||
private final DirContext dirContext;
|
|
||||||
|
|
||||||
DnsResolver(DirContext dirContext) {
|
|
||||||
this.dirContext = dirContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IPs resolve(String hostname) {
|
|
||||||
|
|
||||||
log.tracef("Trying to resolve %s", hostname);
|
|
||||||
|
|
||||||
int resolveCounter = 0;
|
|
||||||
try {
|
|
||||||
Attributes result;
|
|
||||||
do {
|
|
||||||
if (resolveCounter == MAX_RETRIES) {
|
|
||||||
throw new IllegalStateException("Couldn't resolve all attributes");
|
|
||||||
}
|
|
||||||
resolveCounter++;
|
|
||||||
log.tracef("Try #%d", resolveCounter);
|
|
||||||
result = dirContext.getAttributes(hostname, new String[]{"A", "AAAA"});
|
|
||||||
} while (result.size() != 2);
|
|
||||||
|
|
||||||
return new IPs(
|
|
||||||
result.get("A").get().toString(),
|
|
||||||
result.get("AAAA").get().toString()
|
|
||||||
);
|
|
||||||
} catch (NamingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package de.rpr.ddnsclient.lookup;
|
package de.rpr.ddnsclient.lookup;
|
||||||
|
|
||||||
import de.rpr.ddnsclient.model.IPs;
|
import de.rpr.ddnsclient.model.IPs;
|
||||||
import io.quarkus.runtime.Quarkus;
|
|
||||||
import io.quarkus.runtime.StartupEvent;
|
import io.quarkus.runtime.StartupEvent;
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
import jakarta.enterprise.event.Observes;
|
import jakarta.enterprise.event.Observes;
|
||||||
|
@ -81,33 +80,24 @@ public class PublicIpLookup {
|
||||||
try {
|
try {
|
||||||
String provider = this.provider.map(it -> it.url).orElseGet(() -> Providers.random().url);
|
String provider = this.provider.map(it -> it.url).orElseGet(() -> Providers.random().url);
|
||||||
|
|
||||||
IPs.Builder ipsBuilder = new IPs.Builder();
|
String v4 = getIp(provider, CurlProcessFactory.IpClass.V4);
|
||||||
|
String v6 = getIp(provider, CurlProcessFactory.IpClass.V6);
|
||||||
|
|
||||||
try {
|
return new IPs(v4, v6);
|
||||||
Process curlProcess = curlProcessFactory.create(provider, CurlProcessFactory.IpClass.V4).start();
|
|
||||||
curlProcess.waitFor();
|
|
||||||
InputStream inputStream = curlProcess.getInputStream();
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
|
||||||
String v4 = reader.readLine();
|
|
||||||
log.tracef("Retrieved ipv4: %s", v4);
|
|
||||||
ipsBuilder.v4(v4);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getIp(String provider, CurlProcessFactory.IpClass ipClass) {
|
||||||
try {
|
try {
|
||||||
Process curlProcess = curlProcessFactory.create(provider, CurlProcessFactory.IpClass.V6).start();
|
Process curlProcess = curlProcessFactory.create(provider, ipClass).start();
|
||||||
curlProcess.waitFor();
|
curlProcess.waitFor();
|
||||||
InputStream inputStream = curlProcess.getInputStream();
|
InputStream inputStream = curlProcess.getInputStream();
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||||
String v6 = reader.readLine();
|
String ip = reader.readLine();
|
||||||
log.tracef("Retrieved ipv6: %s", v6);
|
log.tracef("Retrieved ip: %s", ip);
|
||||||
ipsBuilder.v6(v6);
|
return ip;
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ipsBuilder.build();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package de.rpr.ddnsclient.model;
|
package de.rpr.ddnsclient.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@RegisterForReflection
|
||||||
public class Config extends ArrayList<Config.Value> {
|
public class Config extends ArrayList<Config.Value> {
|
||||||
|
|
||||||
public record Value(
|
public record Value(
|
||||||
|
@ -12,4 +16,9 @@ public class Config extends ArrayList<Config.Value> {
|
||||||
String token) {
|
String token) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public Config() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,23 +2,5 @@ package de.rpr.ddnsclient.model;
|
||||||
|
|
||||||
public record IPs(String v4, String v6) {
|
public record IPs(String v4, String v6) {
|
||||||
|
|
||||||
public static final class Builder {
|
|
||||||
String v4;
|
|
||||||
String v6;
|
|
||||||
|
|
||||||
public Builder v4(String v4) {
|
|
||||||
this.v4 = v4;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder v6(String v6) {
|
|
||||||
this.v6 = v6;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IPs build() {
|
|
||||||
return new IPs(v4, v6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
src/test/java/de/rpr/ddnsclient/lookup/DnsJavaTest.java
Normal file
16
src/test/java/de/rpr/ddnsclient/lookup/DnsJavaTest.java
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package de.rpr.ddnsclient.lookup;
|
||||||
|
|
||||||
|
import de.rpr.ddnsclient.model.IPs;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class DnsJavaTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test() {
|
||||||
|
IPs result = new DnsJava("9.9.9.9").resolve("example.com");
|
||||||
|
assertThat(result.v4()).isNotBlank();
|
||||||
|
assertThat(result.v6()).isNotBlank();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,53 +0,0 @@
|
||||||
package de.rpr.ddnsclient.lookup;
|
|
||||||
|
|
||||||
import de.rpr.ddnsclient.model.IPs;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.naming.directory.BasicAttributes;
|
|
||||||
import javax.naming.directory.DirContext;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
class DnsResolverTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
DirContext dirContext;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void should_throw_exception_if_resolving_failes_repeatedly() throws NamingException {
|
|
||||||
|
|
||||||
when(dirContext.getAttributes(anyString(), any())).thenReturn(new BasicAttributes());
|
|
||||||
|
|
||||||
DnsResolver dnsResolver = new DnsResolver(dirContext);
|
|
||||||
|
|
||||||
assertThatExceptionOfType(IllegalStateException.class)
|
|
||||||
.isThrownBy(() -> dnsResolver.resolve("example.com"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void should_return_ips() throws NamingException {
|
|
||||||
|
|
||||||
BasicAttributes attributes = new BasicAttributes() {{
|
|
||||||
put("A", "ipv4");
|
|
||||||
put("AAAA", "ipv6");
|
|
||||||
}};
|
|
||||||
when(dirContext.getAttributes(anyString(), any())).thenReturn(attributes);
|
|
||||||
|
|
||||||
DnsResolver dnsResolver = new DnsResolver(dirContext);
|
|
||||||
|
|
||||||
IPs result = dnsResolver.resolve("example.com");
|
|
||||||
|
|
||||||
assertThat(result.v4()).isEqualTo("ipv4");
|
|
||||||
assertThat(result.v6()).isEqualTo("ipv6");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,9 +8,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.mockito.stubbing.Answer;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue