Skip to content

Commit

Permalink
feat: allow ip detector to exclude certain ip addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
junfuchen99 committed Nov 28, 2023
1 parent c9015da commit 94a42a4
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 2 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@
<dependency>
<groupId>com.aws.greengrass</groupId>
<artifactId>nucleus</artifactId>
<version>2.2.0-SNAPSHOT</version>
<version>2.12.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.aws.greengrass</groupId>
<artifactId>nucleus</artifactId>
<version>2.2.0-SNAPSHOT</version>
<version>2.12.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/com/aws/greengrass/detector/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
package com.aws.greengrass.detector.config;

import com.aws.greengrass.componentmanager.KernelConfigResolver;
import com.aws.greengrass.config.Topic;
import com.aws.greengrass.config.Topics;
import com.aws.greengrass.logging.api.Logger;
import com.aws.greengrass.logging.impl.LogManager;
import com.aws.greengrass.util.Coerce;
import lombok.Getter;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

Expand All @@ -19,6 +23,7 @@ public class Config {

static final String INCLUDE_IPV4_LOOPBACK_ADDRESSES_CONFIG_KEY = "includeIPv4LoopbackAddrs";
static final String INCLUDE_IPV4_LINK_LOCAL_ADDRESSES_CONFIG_KEY = "includeIPv4LinkLocalAddrs";
static final String EXCLUDED_IP_ADDRESSES_CONFIG_KEY = "excludedIPAddresses";
static final String DEFAULT_PORT_CONFIG_KEY = "defaultPort";
static final boolean DEFAULT_INCLUDE_IPV4_LOOPBACK_ADDRESSES = false;
static final boolean DEFAULT_INCLUDE_IPV4_LINK_LOCAL_ADDRESSES = false;
Expand All @@ -27,6 +32,8 @@ public class Config {
private AtomicInteger defaultPort = new AtomicInteger(DEFAULT_PORT);
private AtomicBoolean includeIPv4LoopbackAddrs = new AtomicBoolean(DEFAULT_INCLUDE_IPV4_LOOPBACK_ADDRESSES);
private AtomicBoolean includeIPv4LinkLocalAddrs = new AtomicBoolean(DEFAULT_INCLUDE_IPV4_LINK_LOCAL_ADDRESSES);
@Getter
private final List<String> excludedIPAddresses = new ArrayList<>();

/**
* Config constructor.
Expand All @@ -39,6 +46,7 @@ public Config(Topics topics) {
if (configurationTopics.isEmpty()) {
this.includeIPv4LoopbackAddrs = new AtomicBoolean(DEFAULT_INCLUDE_IPV4_LOOPBACK_ADDRESSES);
this.includeIPv4LinkLocalAddrs = new AtomicBoolean(DEFAULT_INCLUDE_IPV4_LINK_LOCAL_ADDRESSES);
this.excludedIPAddresses.clear();
this.defaultPort = new AtomicInteger(DEFAULT_PORT);
return;
}
Expand All @@ -57,9 +65,20 @@ public Config(Topics topics) {
Coerce.toInt(
configurationTopics.findOrDefault(DEFAULT_PORT,
DEFAULT_PORT_CONFIG_KEY)));
Topic excludedIPTopic = configurationTopics.find(EXCLUDED_IP_ADDRESSES_CONFIG_KEY);
if (excludedIPTopic != null) {
if (excludedIPTopic.getOnce() instanceof List) {
this.excludedIPAddresses.clear();
this.excludedIPAddresses.addAll(Coerce.toStringList(excludedIPTopic.getOnce()));
} else {
logger.atWarn().kv("value", excludedIPTopic.getOnce()).log("Invalid config value for"
+ " excludedIPAddresses. The config must be input as a list");
}
}

logger.atInfo().kv("includeIPv4LoopbackAddrs", includeIPv4LoopbackAddrs.get())
.kv("includeIPv4LinkLocalAddrs", includeIPv4LinkLocalAddrs.get())
.kv("excludedIPAddresses", excludedIPAddresses)
.kv("defaultPort", defaultPort.get())
.log("Configuration updated");
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ List<InetAddress> getIpAddresses(Enumeration<NetworkInterface> interfaces, Confi

for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
InetAddress address = interfaceAddress.getAddress();
if (config.getExcludedIPAddresses().contains(address.getHostAddress())) {
continue;
}
if (address instanceof Inet6Address) {
continue;
}
Expand Down
36 changes: 36 additions & 0 deletions src/test/java/com/aws/greengrass/detector/config/ConfigTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@


import com.aws.greengrass.config.ChildChanged;
import com.aws.greengrass.config.Topic;
import com.aws.greengrass.config.Topics;
import com.aws.greengrass.util.Coerce;
import com.aws.greengrass.utils.TestConstants;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;

import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
Expand All @@ -30,8 +36,11 @@ class ConfigTest {
public void GIVEN_config_topics_WHEN_initialize_THEN_configuration_created() {
Topics topics = Mockito.mock(Topics.class);
Topics configTopics = Mockito.mock(Topics.class);
Topic excludedIpTopic = Mockito.mock(Topic.class);
String mockIncludeIPv4LoopbackAddrsConfig = "true";
String mockIncludeIPv4LinkLocalAddrsConfig = "true";
String mockExcludeIPsConfig = String.format("[%s]", TestConstants.IP_1);
List<String> mockList = Collections.singletonList(TestConstants.IP_1);
int mockPortValue = 9000;

// stub subscribe() to call just the callback method without adding watcher
Expand All @@ -49,13 +58,16 @@ public void GIVEN_config_topics_WHEN_initialize_THEN_configuration_created() {
Mockito.doReturn(mockPortValue)
.when(configTopics).findOrDefault(anyInt(), eq(Config.DEFAULT_PORT_CONFIG_KEY));

Mockito.doReturn(excludedIpTopic).when(configTopics).find(Config.EXCLUDED_IP_ADDRESSES_CONFIG_KEY);
Mockito.doReturn(mockList).when(excludedIpTopic).getOnce();
Mockito.doReturn(configTopics).when(topics).lookupTopics(anyString());
config = new Config(topics);

assertNotNull(config);
assertEquals(mockPortValue, config.getDefaultPort());
assertEquals(Coerce.toBoolean(mockIncludeIPv4LoopbackAddrsConfig), config.isIncludeIPv4LoopbackAddrs());
assertEquals(Coerce.toBoolean(mockIncludeIPv4LinkLocalAddrsConfig), config.isIncludeIPv4LinkLocalAddrs());
assertEquals(Coerce.toStringList(mockExcludeIPsConfig), config.getExcludedIPAddresses());
}

@Test
Expand All @@ -78,5 +90,29 @@ public void GIVEN_empty_config_topics_WHEN_initialize_THEN_default_configuration
assertEquals(Config.DEFAULT_INCLUDE_IPV4_LOOPBACK_ADDRESSES, config.isIncludeIPv4LoopbackAddrs());
assertEquals(Config.DEFAULT_INCLUDE_IPV4_LINK_LOCAL_ADDRESSES, config.isIncludeIPv4LinkLocalAddrs());
assertEquals(Config.DEFAULT_PORT, config.getDefaultPort());
assertTrue(config.getExcludedIPAddresses().isEmpty());
}

@Test
public void GIVEN_invalid_excluded_ips_list_WHEN_initialize_THEN_default_configuration_created() {
Topics topics = Mockito.mock(Topics.class);
Topics configTopics = Mockito.mock(Topics.class);

// stub subscribe() to call just the callback method without adding watcher
doAnswer((Answer<Void>) invocation -> {
ChildChanged childChanged = invocation.getArgument(0);
childChanged.childChanged(null, null);
return null;
}).when(configTopics).subscribe(any());

Mockito.doReturn(false).when(configTopics).isEmpty();
Mockito.doReturn(configTopics).when(topics).lookupTopics(anyString());
Topic excludedIpTopic = Mockito.mock(Topic.class);
Mockito.doReturn(excludedIpTopic).when(configTopics).find(Config.EXCLUDED_IP_ADDRESSES_CONFIG_KEY);
Mockito.doReturn("bad-config").when(excludedIpTopic).getOnce();
config = new Config(topics);

assertNotNull(config);
assertTrue(config.getExcludedIPAddresses().isEmpty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

@ExtendWith({MockitoExtension.class})
Expand Down Expand Up @@ -98,6 +100,34 @@ public void GIVEN_network_down_WHEN_get_ipAddresses_THEN_null_returned() throws
assertTrue(ipAddresses.isEmpty());
}

@Test
public void GIVEN_excludeIPAddresses_WHEN_get_ipAddresses_THEN_excludeIPs_filtered() throws SocketException {
// exclude IP_1 (0.61.124.18)
NetworkInterface networkInterface = Mockito.mock(NetworkInterface.class);
Config config = Mockito.mock(Config.class);

List<NetworkInterface> networkInterfaces = new ArrayList<>();
List<InterfaceAddress> interfaceAddresses = getAllAddresses();

Mockito.doReturn(interfaceAddresses).when(networkInterface).getInterfaceAddresses();
Mockito.doReturn(true).when(networkInterface).isUp();
// Exclude IPv4 Loopback addresses and Link-Local addresses
Mockito.doReturn(true).when(config).isIncludeIPv4LoopbackAddrs();
Mockito.doReturn(true).when(config).isIncludeIPv4LinkLocalAddrs();
Mockito.doReturn(Collections.singletonList(TestConstants.IP_1)).when(config).getExcludedIPAddresses();

networkInterfaces.add(networkInterface);
Enumeration<NetworkInterface> enumeration = Collections.enumeration(networkInterfaces);
ipDetector = new IpDetector();
List<InetAddress> ipAddresses = ipDetector.getIpAddresses(enumeration, config);

assertEquals(2, ipAddresses.size());
assertFalse(ipAddresses.stream().map(InetAddress::getHostAddress)
.collect(Collectors.joining()).contains(TestConstants.IP_1));
assertEquals(TestConstants.IPV4_LOOPBACK, ipAddresses.get(0).getHostAddress());
assertEquals(TestConstants.IPV4_LINK_LOCAL, ipAddresses.get(1).getHostAddress());
}

private List<InterfaceAddress> getAllAddresses() {
List<InterfaceAddress> interfaceAddresses = new ArrayList<>();
InterfaceAddress interfaceAddress1 = Mockito.mock(InterfaceAddress.class);
Expand Down

0 comments on commit 94a42a4

Please sign in to comment.