Repository: mageddo/dns-proxy-server
Pull request #387 (2023-03-21 01:24:34)

Fixing host.docker
Relates to #384 . Fixing  regression on version `3.14` host.docker wasn't solving host IP when running inside a container.


Patch:
diff --git a/Dockerfile b/Dockerfile
index 7e1fbd4a..135093b5 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,5 +2,6 @@ FROM debian:10-slim
 COPY ./build/artifacts/linux-amd64/dns-proxy-server /app/dns-proxy-server
 WORKDIR /app
 LABEL dps.container=true
+ENV DPS_CONTAINER=1
 VOLUME ["/var/run/docker.sock", "/var/run/docker.sock"]
 ENTRYPOINT ["/app/dns-proxy-server"]
diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64
index d772a4e3..7194b037 100644
--- a/Dockerfile.aarch64
+++ b/Dockerfile.aarch64
@@ -2,5 +2,6 @@ FROM arm64v8/debian:10-slim
 COPY ./build/artifacts/linux-aarch64/dns-proxy-server /app/dns-proxy-server
 WORKDIR /app
 LABEL dps.container=true
+ENV DPS_CONTAINER=1
 VOLUME ["/var/run/docker.sock", "/var/run/docker.sock"]
 ENTRYPOINT ["/app/dns-proxy-server"]
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 049d24ea..033e2538 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -1,4 +1,7 @@
-## 3.14.3-snapshot
+## 3.14.4
+* Fixing regression on version 3.14 host.docker wasn't solving host IP when running inside a container, see #384.
+
+## 3.14.3
 * Support for regex on localdb solver and docker container hostname and HOSTNAMES env
 * Smarter Cache for loading with Docker and LocalDB Solvers see #376
 * Docker host parameter by flag, json config or env
diff --git a/build.gradle b/build.gradle
index ae78fe47..cb95a9f1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -36,7 +36,7 @@ dependencies {
   implementation 'org.graalvm.sdk:graal-sdk:22.3.1'
   implementation('jakarta.enterprise:jakarta.enterprise.cdi-api:2.0.2')
   implementation('jakarta.ws.rs:jakarta.ws.rs-api:2.1.6')
-  implementation('com.mageddo.commons:commons-lang:0.1.11')
+  implementation('com.mageddo.commons:commons-lang:0.1.12')
   implementation('org.apache.commons:commons-exec:1.3')
 
   implementation('ch.qos.logback:logback-classic:1.4.5')
diff --git a/gradle.properties b/gradle.properties
index 19b425e1..f6fc54f8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,1 +1,1 @@
-version=3.14.3
+version=3.14.4
diff --git a/src/main/java/com/mageddo/dnsproxyserver/docker/DpsContainerManager.java b/src/main/java/com/mageddo/dnsproxyserver/docker/DpsContainerManager.java
index 50445790..fd3463a7 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/docker/DpsContainerManager.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/docker/DpsContainerManager.java
@@ -4,8 +4,8 @@ import com.github.dockerjava.api.DockerClient;
 import com.github.dockerjava.api.model.Container;
 import com.github.dockerjava.api.model.Network;
 import com.mageddo.dnsproxyserver.config.Configs;
-import com.mageddo.net.Networks;
 import com.mageddo.dnsproxyserver.server.dns.IP;
+import com.mageddo.net.Networks;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.BooleanUtils;
@@ -28,6 +28,8 @@ import static com.mageddo.dnsproxyserver.docker.ContainerSolvingService.NETWORK_
 @AllArgsConstructor(onConstructor = @__({@Inject}))
 public class DpsContainerManager {
 
+  static final String DPS_INSIDE_CONTAINER = "1";
+
   private final ContainerSolvingService containerSolvingService;
   private final DockerDAO dockerDAO;
   private final DockerClient dockerClient;
@@ -118,7 +120,7 @@ public class DpsContainerManager {
   }
 
   public boolean isDpsRunningInsideContainer() {
-    return this.dockerDAO.isConnected() && this.findDpsContainer() != null;
+    return StringUtils.equals(getDpsContainerEnv(), DPS_INSIDE_CONTAINER);
   }
 
   public static boolean isDpsContainer(Container c) {
@@ -158,4 +160,8 @@ public class DpsContainerManager {
     }
   }
 
+  String getDpsContainerEnv() {
+    return System.getenv("DPS_CONTAINER");
+  }
+
 }
diff --git a/src/main/java/com/mageddo/dnsproxyserver/usecase/HostMachineService.java b/src/main/java/com/mageddo/dnsproxyserver/usecase/HostMachineService.java
index 24afde75..a501d007 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/usecase/HostMachineService.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/usecase/HostMachineService.java
@@ -1,32 +1,33 @@
 package com.mageddo.dnsproxyserver.usecase;
 
 import com.mageddo.dnsproxyserver.docker.DockerDAO;
+import com.mageddo.dnsproxyserver.docker.DpsContainerManager;
 import com.mageddo.dnsproxyserver.server.dns.IP;
 import com.mageddo.net.Networks;
+import lombok.RequiredArgsConstructor;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
-import java.util.Optional;
 
 @Singleton
+@RequiredArgsConstructor(onConstructor = @__({@Inject}))
 public class HostMachineService {
 
   private final DockerDAO dockerDAO;
+  private final DpsContainerManager dpsContainerManager;
 
-  @Inject
-  public HostMachineService(DockerDAO dockerDAO) {
-    this.dockerDAO = dockerDAO;
+  public IP findHostMachineIP() {
+    if (this.isDpsRunningInsideContainer()) {
+      return this.dockerDAO.findHostMachineIp();
+    }
+    return this.findCurrentMachineIp();
   }
 
-  public IP findHostMachineIP() {
-    return Optional
-      .ofNullable(Networks.findCurrentMachineIP())
-      .filter(it -> !it.isLoopback())
-      .orElseGet(() -> {
-        if (this.dockerDAO.isConnected()) {
-          return this.dockerDAO.findHostMachineIp();
-        }
-        return null;
-      });
+  boolean isDpsRunningInsideContainer() {
+    return this.dpsContainerManager.isDpsRunningInsideContainer();
+  }
+
+  IP findCurrentMachineIp() {
+    return Networks.findCurrentMachineIP();
   }
 }
diff --git a/src/main/java/com/mageddo/net/Network.java b/src/main/java/com/mageddo/net/Network.java
index a9dcc3ba..d9a4ac03 100644
--- a/src/main/java/com/mageddo/net/Network.java
+++ b/src/main/java/com/mageddo/net/Network.java
@@ -4,7 +4,11 @@ import com.mageddo.net.osx.NetworkOSX;
 import com.mageddo.net.windows.NetworkWindows;
 import com.mageddo.os.Platform;
 
+import java.io.UncheckedIOException;
+import java.net.NetworkInterface;
+import java.net.SocketException;
 import java.util.List;
+import java.util.stream.Stream;
 
 public interface Network {
 
@@ -25,12 +29,23 @@ public interface Network {
    */
   List<String> findNetworkDnsServers(String network);
 
+  default Stream<NetworkInterface> findNetworkInterfaces(){
+    try {
+      return NetworkInterface.networkInterfaces();
+    } catch (SocketException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
   static Network getInstance() {
     if (Platform.isMac()) {
       return new NetworkOSX();
     } else if (Platform.isWindows()) {
       return new NetworkWindows();
+    } else if(Platform.isLinux()){
+      return new NetworkLinux();
     }
     throw new UnsupportedOperationException("Unsupported platform: " + System.getProperty("os.name"));
   }
+
 }
diff --git a/src/main/java/com/mageddo/net/NetworkLinux.java b/src/main/java/com/mageddo/net/NetworkLinux.java
new file mode 100644
index 00000000..f3825f9f
--- /dev/null
+++ b/src/main/java/com/mageddo/net/NetworkLinux.java
@@ -0,0 +1,21 @@
+package com.mageddo.net;
+
+import java.util.List;
+
+public class NetworkLinux implements Network {
+
+  @Override
+  public List<String> findNetworks() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public boolean updateDnsServers(String network, List<String> servers) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public List<String> findNetworkDnsServers(String network) {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/src/main/java/com/mageddo/net/Networks.java b/src/main/java/com/mageddo/net/Networks.java
index 91c3ac4a..3e8568ca 100644
--- a/src/main/java/com/mageddo/net/Networks.java
+++ b/src/main/java/com/mageddo/net/Networks.java
@@ -5,7 +5,6 @@ import com.github.dockerjava.api.model.ContainerNetwork;
 import com.mageddo.dnsproxyserver.server.dns.IP;
 import lombok.SneakyThrows;
 
-import java.io.UncheckedIOException;
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.util.Comparator;
@@ -14,6 +13,8 @@ import java.util.Optional;
 
 public class Networks {
 
+  volatile static Network network = Network.getInstance();
+
   @SneakyThrows
   public static IP findCurrentMachineIP() {
     return findMachineIps()
@@ -22,6 +23,12 @@ public class Networks {
       .orElse(null);
   }
 
+  /**
+   *  The "relevance" is understood as the IP which have most chances of represent the real hardware network interface,
+   *  we say "most chances" beucase java api haven't deterministic information on that.
+   *
+   * @return Machine ips ordered by relevance.
+   */
   public static List<IP> findMachineIps() {
     return findInterfaces()
       .stream()
@@ -37,20 +44,15 @@ public class Networks {
   }
 
   public static List<NetworkInterface> findInterfaces() {
-    try {
-      return NetworkInterface
-        .networkInterfaces()
-        .filter(it -> {
-          try {
-            return it.isUp();
-          } catch (SocketException e) {
-            return false;
-          }
-        })
-        .toList();
-    } catch (SocketException e) {
-      throw new UncheckedIOException(e);
-    }
+    return network.findNetworkInterfaces()
+      .filter(it -> {
+        try {
+          return it.isUp();
+        } catch (SocketException e) {
+          return false;
+        }
+      })
+      .toList();
   }
 
   public static String findIpv4Address(String networkName, Container container) {


Test patch:
diff --git a/src/test/java/com/mageddo/dnsproxyserver/dnsconfigurator/DnsConfiguratorDefaultLinuxTest.java b/src/test/java/com/mageddo/dnsproxyserver/dnsconfigurator/DnsConfiguratorDefaultLinuxTest.java
deleted file mode 100644
index 42cd93a9..00000000
--- a/src/test/java/com/mageddo/dnsproxyserver/dnsconfigurator/DnsConfiguratorDefaultLinuxTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.mageddo.dnsproxyserver.dnsconfigurator;
-
-import com.mageddo.os.Platform;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assumptions.assumeTrue;
-
-@ExtendWith(MockitoExtension.class)
-class DnsConfiguratorDefaultLinuxTest {
-
-  @InjectMocks
-  DnsConfiguratorDefault configurator;
-
-  @BeforeEach
-  void beforeEach(){
-    assumeTrue(Platform.isLinux());
-  }
-
-  @Test
-  void mustFailAsLinuxIsNotSupported(){
-    // arrange
-
-    // act
-    assertThrows(UnsupportedOperationException.class, () -> {
-      this.configurator.restore();
-    });
-
-    // assert
-
-  }
-}
diff --git a/src/test/java/com/mageddo/dnsproxyserver/docker/DpsContainerManagerTest.java b/src/test/java/com/mageddo/dnsproxyserver/docker/DpsContainerManagerTest.java
new file mode 100644
index 00000000..9cfcd630
--- /dev/null
+++ b/src/test/java/com/mageddo/dnsproxyserver/docker/DpsContainerManagerTest.java
@@ -0,0 +1,34 @@
+package com.mageddo.dnsproxyserver.docker;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static com.mageddo.dnsproxyserver.docker.DpsContainerManager.DPS_INSIDE_CONTAINER;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.doReturn;
+
+@ExtendWith(MockitoExtension.class)
+class DpsContainerManagerTest {
+
+  @Spy
+  @InjectMocks
+  DpsContainerManager dpsContainerManager;
+
+  @Test
+  void mustCheckIsRunningInsideContainer() {
+    // arrange
+    doReturn(DPS_INSIDE_CONTAINER)
+      .when(this.dpsContainerManager)
+      .getDpsContainerEnv()
+    ;
+
+    // act
+    final var insideContainer = this.dpsContainerManager.isDpsRunningInsideContainer();
+
+    // assert
+    assertTrue(insideContainer);
+  }
+}
diff --git a/src/test/java/com/mageddo/dnsproxyserver/usecase/HostMachineServiceTest.java b/src/test/java/com/mageddo/dnsproxyserver/usecase/HostMachineServiceTest.java
new file mode 100644
index 00000000..e9cad3d4
--- /dev/null
+++ b/src/test/java/com/mageddo/dnsproxyserver/usecase/HostMachineServiceTest.java
@@ -0,0 +1,66 @@
+package com.mageddo.dnsproxyserver.usecase;
+
+import com.mageddo.dnsproxyserver.docker.DockerDAO;
+import com.mageddo.dnsproxyserver.templates.IpTemplates;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.doReturn;
+
+@ExtendWith(MockitoExtension.class)
+class HostMachineServiceTest {
+
+  @Mock
+  DockerDAO dockerDAO;
+
+  @Spy
+  @InjectMocks
+  HostMachineService machineService;
+
+  @Test
+  void mustReturnHostIP() {
+    // arrange
+    doReturn(false)
+      .when(this.machineService)
+      .isDpsRunningInsideContainer()
+    ;
+
+    final var expectedIp = IpTemplates.local();
+    doReturn(expectedIp)
+      .when(this.machineService)
+      .findCurrentMachineIp()
+    ;
+
+    // act
+    final var ip = this.machineService.findHostMachineIP();
+
+    // assert
+    assertEquals(expectedIp, ip);
+  }
+
+  @Test
+  void mustReturnHostIPEvenWhenRunningInsideDockerContainer() {
+    // arrange
+    doReturn(true)
+      .when(this.machineService)
+      .isDpsRunningInsideContainer()
+    ;
+
+    final var expectedIp = IpTemplates.local();
+    doReturn(expectedIp)
+      .when(this.dockerDAO)
+      .findHostMachineIp()
+    ;
+
+    // act
+    final var ip = this.machineService.findHostMachineIP();
+
+    // assert
+    assertEquals(expectedIp, ip);
+  }
+}
diff --git a/src/test/java/testing/ContextSupplier.java b/src/test/java/testing/ContextSupplier.java
index e8eea95c..225f7e3d 100644
--- a/src/test/java/testing/ContextSupplier.java
+++ b/src/test/java/testing/ContextSupplier.java
@@ -8,7 +8,9 @@ import java.util.function.Supplier;
 public class ContextSupplier implements Supplier<Context> {
   @Override
   public Context get() {
+    Configs.clear();
     Configs.getInstance(new String[]{"--web-server-port=9944"});
     return Context.create();
   }
+
 }