Skip to content

Commit

Permalink
fix(net.admin): dns monitor fixes (#4636)
Browse files Browse the repository at this point in the history
* Fixed resolv file writing

Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>

Implemented dns monitor with unmanaged interfaces logic

Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>

Added test for dns monitor

Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>

Small refactor of the dns monitor

Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>

Fixes build.properties in net.admin test; refactored LinuxDns

Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>

Modified LinuxDns constructor; added tests

Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>

Removed comments

Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>

* Updated linux.net version

Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>

* Updated linux.net version in manifest

Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>

---------

Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>
  • Loading branch information
pierantoniomerlino committed May 10, 2023
1 parent d4151f6 commit 39d8fee
Show file tree
Hide file tree
Showing 7 changed files with 281 additions and 64 deletions.
2 changes: 1 addition & 1 deletion kura/distrib/config/kura.build.properties
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ org.eclipse.kura.ble.provider.version=1.2.0
org.eclipse.kura.ble.ibeacon.provider.version=1.2.0
org.eclipse.kura.ble.eddystone.provider.version=1.2.0
org.eclipse.kura.linux.command.version=1.2.0
org.eclipse.kura.linux.net.version=2.2.0
org.eclipse.kura.linux.net.version=2.2.1
org.eclipse.kura.linux.sysv.provider.version=1.2.0
org.eclipse.kura.linux.systemd.provider.version=1.2.0
org.eclipse.kura.linux.debian.provider.version=1.2.0
Expand Down
2 changes: 1 addition & 1 deletion kura/org.eclipse.kura.linux.net/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: org.eclipse.kura.linux.net
Bundle-SymbolicName: org.eclipse.kura.linux.net;singleton:=true
Bundle-Version: 2.2.1.qualifier
Bundle-Version: 2.2.1
Bundle-Vendor: Eclipse Kura
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Service-Component: OSGI-INF/*.xml
Expand Down
2 changes: 1 addition & 1 deletion kura/org.eclipse.kura.linux.net/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</parent>

<artifactId>org.eclipse.kura.linux.net</artifactId>
<version>2.2.1-SNAPSHOT</version>
<version>2.2.1</version>
<packaging>eclipse-plugin</packaging>

<properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others
* Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -41,13 +41,24 @@ public class LinuxDns {

private static final Logger logger = LoggerFactory.getLogger(LinuxDns.class);

private static final String DNS_FILE_NAME = "/etc/resolv.conf";
private static final String[] PPP_DNS_FILES = { "/var/run/ppp/resolv.conf", "/etc/ppp/resolv.conf" };
private static final String BACKUP_DNS_FILE_NAME = "/etc/resolv.conf.save";
private static final String BACKUP_DNS_FILE_NAME_SUFFIX = ".save";
private static final int COMMAND_TIMEOUT = 60;
private static final String NAMESERVER = "nameserver";

private static LinuxDns linuxDns = null;
private final String dnsFileName;
private final String[] pppDnsFileNames;

LinuxDns(String dnsFile, String[] pppDnsFiles) {
dnsFileName = dnsFile;
pppDnsFileNames = pppDnsFiles;
}

private LinuxDns() {
dnsFileName = "/etc/resolv.conf";
String[] pppFiles = { "/var/run/ppp/resolv.conf", "/etc/ppp/resolv.conf" };
pppDnsFileNames = pppFiles;
}

public static synchronized LinuxDns getInstance() {
if (linuxDns == null) {
Expand Down Expand Up @@ -88,7 +99,7 @@ public synchronized Set<IPAddress> getDnServers() {
public synchronized void setDnServers(Set<IPAddress> servers) {
if (servers == null) {
if (getDnServers() != null) {
writeDnsFile(new HashSet<IPAddress>());
writeDnsFile(new HashSet<>());
}
} else if (!servers.equals(getDnServers())) {
writeDnsFile(servers);
Expand Down Expand Up @@ -192,7 +203,7 @@ public synchronized void unsetPppDns(CommandExecutorService executorService) thr
}

public synchronized boolean isPppDnsSet() throws KuraException {
File file = new File(DNS_FILE_NAME);
File file = new File(dnsFileName);
boolean ret = false;
if (isSymlink(file) && getRealPath(file).equals(getPppDnsFileName())) {
return true;
Expand All @@ -201,17 +212,18 @@ public synchronized boolean isPppDnsSet() throws KuraException {
}

private void backupDnsFile(CommandExecutorService executorService) throws KuraException {
File file = new File(DNS_FILE_NAME);
File file = new File(dnsFileName);
if (file.exists()) {
Command command = new Command(new String[] { "mv", DNS_FILE_NAME, BACKUP_DNS_FILE_NAME });
Command command = new Command(
new String[] { "mv", dnsFileName, dnsFileName + BACKUP_DNS_FILE_NAME_SUFFIX });
command.setTimeout(COMMAND_TIMEOUT);
CommandStatus status = executorService.execute(command);
if (!status.getExitStatus().isSuccessful()) {
logger.error("Failed to move the {} file to {}. The 'mv' command has failed ...", DNS_FILE_NAME,
BACKUP_DNS_FILE_NAME);
throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR, "Failed to backup DNS file " + DNS_FILE_NAME);
logger.error("Failed to move the {} file to {}{}. The 'mv' command has failed ...", dnsFileName,
dnsFileName, BACKUP_DNS_FILE_NAME_SUFFIX);
throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR, "Failed to backup DNS file " + dnsFileName);
} else {
logger.info("successfully backed up {}", DNS_FILE_NAME);
logger.info("successfully backed up {}", dnsFileName);
}
}
}
Expand All @@ -221,11 +233,11 @@ private void setDnsPppLink(String sPppDnsFileName, CommandExecutorService execut
logger.debug("failed to set permissions to {}", sPppDnsFileName);
}

Command command = new Command(new String[] { "ln", "-sf", sPppDnsFileName, DNS_FILE_NAME });
Command command = new Command(new String[] { "ln", "-sf", sPppDnsFileName, dnsFileName });
command.setTimeout(COMMAND_TIMEOUT);
CommandStatus status = executorService.execute(command);
if (!status.getExitStatus().isSuccessful()) {
logger.error("failed to create symbolic link: {} -> {}", DNS_FILE_NAME, sPppDnsFileName);
logger.error("failed to create symbolic link: {} -> {}", dnsFileName, sPppDnsFileName);
throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR,
"failed to create symbolic link to " + sPppDnsFileName);
} else {
Expand All @@ -234,23 +246,23 @@ private void setDnsPppLink(String sPppDnsFileName, CommandExecutorService execut
}

private void unsetDnsPppLink(String pppDnsFilename, CommandExecutorService executorService) throws KuraException {
File file = new File(DNS_FILE_NAME);
File file = new File(dnsFileName);
if (file.exists()) {
Command command = new Command(new String[] { "rm", DNS_FILE_NAME });
Command command = new Command(new String[] { "rm", dnsFileName });
command.setTimeout(COMMAND_TIMEOUT);
CommandStatus status = executorService.execute(command);
if (!status.getExitStatus().isSuccessful()) {
logger.error("failed to delete {} symlink that points to {}", DNS_FILE_NAME, pppDnsFilename);
logger.error("failed to delete {} symlink that points to {}", dnsFileName, pppDnsFilename);
throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR,
"failed to delete " + DNS_FILE_NAME + " symlink that points to " + pppDnsFilename);
"failed to delete " + dnsFileName + " symlink that points to " + pppDnsFilename);
} else {
logger.info("successfully removed symlink that points to {}", pppDnsFilename);
}
}
}

private void restoreDnsFile(CommandExecutorService executorService) throws KuraException {
File file = new File(BACKUP_DNS_FILE_NAME);
File file = new File(dnsFileName + BACKUP_DNS_FILE_NAME_SUFFIX);
if (file.exists()) {
restoreDnsFileFromBackup(executorService);
} else {
Expand All @@ -259,15 +271,15 @@ private void restoreDnsFile(CommandExecutorService executorService) throws KuraE
}

private void restoreDnsFileFromBackup(CommandExecutorService executorService) throws KuraException {
Command command = new Command(new String[] { "mv", BACKUP_DNS_FILE_NAME, DNS_FILE_NAME });
Command command = new Command(new String[] { "mv", dnsFileName + BACKUP_DNS_FILE_NAME_SUFFIX, dnsFileName });
command.setTimeout(COMMAND_TIMEOUT);
CommandStatus status = executorService.execute(command);
if (!status.getExitStatus().isSuccessful()) {
logger.error("failed to restore {} to {}", BACKUP_DNS_FILE_NAME, DNS_FILE_NAME);
logger.error("failed to restore {}{} to {}", dnsFileName, BACKUP_DNS_FILE_NAME_SUFFIX, dnsFileName);
throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR,
"failed to restore " + BACKUP_DNS_FILE_NAME + " to " + DNS_FILE_NAME);
"failed to restore " + dnsFileName + BACKUP_DNS_FILE_NAME_SUFFIX + " to " + dnsFileName);
} else {
logger.info("successfully restored {} from {}", DNS_FILE_NAME, BACKUP_DNS_FILE_NAME);
logger.info("successfully restored {}{} from {}", dnsFileName, dnsFileName, BACKUP_DNS_FILE_NAME_SUFFIX);
}
}

Expand All @@ -289,7 +301,7 @@ private synchronized boolean isSymlink(File file) throws KuraException {
ret = !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
} catch (Exception e) {
logger.error("isSymlink call failed", e);
throw new KuraException(KuraErrorCode.INTERNAL_ERROR);
throw new KuraException(KuraErrorCode.IO_ERROR);
}
return ret;
}
Expand All @@ -308,7 +320,7 @@ private synchronized String getRealPath(File file) throws KuraException {
path = canon.getCanonicalFile().toString();
} catch (Exception e) {
logger.error("getRealPath call failed", e);
throw new KuraException(KuraErrorCode.INTERNAL_ERROR);
throw new KuraException(KuraErrorCode.IO_ERROR);
}
return path;
}
Expand All @@ -320,86 +332,80 @@ private boolean isLinkToPppDnsFile() throws IOException {
return false;
}

return Files.readSymbolicLink(Paths.get(DNS_FILE_NAME)).equals(Paths.get(pppDnsFileName));
return Files.readSymbolicLink(Paths.get(dnsFileName)).equals(Paths.get(pppDnsFileName));
}

private synchronized void writeDnsFile(Set<IPAddress> servers) {
logger.debug("Writing DNS servers to file");
List<String> lines = new ArrayList<>();
try {
if (Files.isSymbolicLink(Paths.get(DNS_FILE_NAME)) && !isLinkToPppDnsFile()) {
Files.delete(Paths.get(DNS_FILE_NAME));
if (Files.isSymbolicLink(Paths.get(dnsFileName)) && !isLinkToPppDnsFile()) {
Files.delete(Paths.get(dnsFileName));
}
lines.addAll(readDnsFileExceptNameservers());
servers.forEach(server -> lines.add("nameserver " + server.getHostAddress()));
writeLinesToDnsFile(lines);
} catch (IOException e) {
logger.error("Cannot read symlink", e);
logger.error("Failed to write dns servers to file {}", dnsFileName, e);
}
}

private void writeLinesToDnsFile(List<String> lines) {
try (FileOutputStream fos = new FileOutputStream(getOrCreateDnsFile());
PrintWriter pw = new PrintWriter(fos);) {
String[] existingFile = getModifiedFile();
for (String element : existingFile) {
pw.write(element + "\n");
}
pw.write("\n");
for (IPAddress server : servers) {
pw.write("nameserver " + server.getHostAddress() + "\n");
}
lines.forEach(line -> pw.write(line + "\n"));
pw.flush();
fos.getFD().sync();
} catch (Exception e1) {
logger.error("writeDnsFile() :: failed to write the {} file ", DNS_FILE_NAME, e1);
} catch (IOException | KuraException e) {
logger.error("writeDnsFile() :: failed to write the {} file ", dnsFileName, e);
}
}

private synchronized String[] getModifiedFile() {
private synchronized List<String> readDnsFileExceptNameservers() {
File dnsFile;
try {
dnsFile = getOrCreateDnsFile();
} catch (final Exception e) {
return new String[0];
return new ArrayList<>();
}

ArrayList<String> linesWithoutServers = new ArrayList<>();
ArrayList<String> lines = new ArrayList<>();
try (FileReader fr = new FileReader(dnsFile); BufferedReader br = new BufferedReader(fr)) {
String line;
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.indexOf(NAMESERVER) != 0) {
linesWithoutServers.add(line);
if (!line.toLowerCase().contains(NAMESERVER)) {
lines.add(line);
}
}
} catch (Exception e) {
logger.error("error parsing the {} file ", DNS_FILE_NAME, e);
}

String[] lines = new String[linesWithoutServers.size()];
for (int i = 0; i < linesWithoutServers.size(); i++) {
lines[i] = linesWithoutServers.get(i);
} catch (IOException e) {
logger.error("error parsing the {} file ", dnsFileName, e);
}
return lines;
}

private File getOrCreateDnsFile() throws KuraException {
File f = new File(DNS_FILE_NAME);
File f = new File(dnsFileName);
if (!f.exists()) {
try {
if (f.createNewFile()) {
logger.debug("The {} doesn't exist, created new empty file ...", DNS_FILE_NAME);
logger.debug("The {} doesn't exist, created new empty file ...", dnsFileName);
}
} catch (Exception e) {
logger.error("Failed to create new empty {} file", DNS_FILE_NAME, e);
} catch (IOException e) {
logger.error("Failed to create new empty {} file", dnsFileName, e);
throw new KuraException(KuraErrorCode.IO_ERROR);
}
}
if (!f.setReadable(true, false)) {
logger.debug("failed to set permissions to {}", DNS_FILE_NAME);
logger.debug("failed to set permissions to {}", dnsFileName);
}
return f;
}

private String getPppDnsFileName() {

String pppDnsFileName = null;
for (String name : PPP_DNS_FILES) {
for (String name : pppDnsFileNames) {
File file = new File(name);
if (file.exists()) {
pppDnsFileName = name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,17 @@ private boolean isEnabledForWan(NetInterfaceConfig<? extends NetInterfaceAddress
.equals(NetInterfaceStatus.netIPv4StatusEnabledWAN);
}

private boolean isNotManaged(NetInterfaceConfig<? extends NetInterfaceAddressConfig> netInterfaceConfig) {
return ((AbstractNetInterface<?>) netInterfaceConfig).getInterfaceStatus()
.equals(NetInterfaceStatus.netIPv4StatusUnmanaged);
}

private void setDnsServers(Set<IPAddress> newServers) {
if (isNotAllowedToManageDnsServers()) {
logger.debug("Don't manage dns servers");
return;
}

LinuxDns linuxDns = this.dnsUtil;
Set<IPAddress> currentServers = linuxDns.getDnServers();

Expand All @@ -308,14 +318,40 @@ private void setDnsServers(Set<IPAddress> newServers) {
}
}

// Kura will not manage the dns servers if no WAN interfaces are configured, but
// there are Unmanaged ones.
private boolean isNotAllowedToManageDnsServers() {
boolean wanInterfaceExist = false;
boolean unmanagedInterfaceExist = false;
if (this.networkConfiguration != null && this.networkConfiguration.getNetInterfaceConfigs() != null) {
List<NetInterfaceConfig<? extends NetInterfaceAddressConfig>> netInterfaceConfigs = this.networkConfiguration
.getNetInterfaceConfigs();
for (NetInterfaceConfig<? extends NetInterfaceAddressConfig> netInterfaceConfig : netInterfaceConfigs) {
if ((netInterfaceConfig.getType() == NetInterfaceType.ETHERNET
|| netInterfaceConfig.getType() == NetInterfaceType.WIFI
|| netInterfaceConfig.getType() == NetInterfaceType.MODEM)
&& isEnabledForWan(netInterfaceConfig)) {
wanInterfaceExist = true;
}
if ((netInterfaceConfig.getType() == NetInterfaceType.ETHERNET
|| netInterfaceConfig.getType() == NetInterfaceType.WIFI
|| netInterfaceConfig.getType() == NetInterfaceType.MODEM)
&& isNotManaged(netInterfaceConfig)) {
unmanagedInterfaceExist = true;
}
}
}
return !wanInterfaceExist && unmanagedInterfaceExist;
}

// Get a list of dns servers for all WAN interfaces
private Set<IPAddress> getConfiguredDnsServers() {
LinkedHashSet<IPAddress> serverList = new LinkedHashSet<>();
if (this.networkConfiguration != null && this.networkConfiguration.getNetInterfaceConfigs() != null) {
List<NetInterfaceConfig<? extends NetInterfaceAddressConfig>> netInterfaceConfigs = this.networkConfiguration
.getNetInterfaceConfigs();
// If there are multiple WAN interfaces, their configured DNS servers are all included in no particular
// order
// If there are multiple WAN interfaces, their configured DNS servers are all
// included in no particular order
for (NetInterfaceConfig<? extends NetInterfaceAddressConfig> netInterfaceConfig : netInterfaceConfigs) {
if ((netInterfaceConfig.getType() == NetInterfaceType.ETHERNET
|| netInterfaceConfig.getType() == NetInterfaceType.WIFI
Expand Down

0 comments on commit 39d8fee

Please sign in to comment.