diff --git a/config/modules/host.conf b/config/modules/host.conf index deda32bdd6..cd9e9421b4 100644 --- a/config/modules/host.conf +++ b/config/modules/host.conf @@ -7,7 +7,6 @@ build docker/modules add pass add fail add ping -add ipaddr add bacnet add mudgee @@ -15,5 +14,8 @@ add mudgee include subset/pentests/build.conf include usi/build.conf +# Extended dhcp tests +add ipaddr + # Example of how to remove something. remove unused diff --git a/daq/gateway.py b/daq/gateway.py index 9984dc7a6e..4ee9bc2fd1 100644 --- a/daq/gateway.py +++ b/daq/gateway.py @@ -131,9 +131,13 @@ def change_dhcp_response_time(self, mac, time): self.execute_script('change_dhcp_response_time', mac, time) def stop_dhcp_response(self, mac): - """Stops DHCP respopnse for the device""" + """Stops DHCP response for the device""" self.change_dhcp_response_time(mac, -1) + def change_dhcp_range(self, start, end, prefix_length): + """Change dhcp range for devices""" + self.execute_script('change_dhcp_range', start, end, prefix_length) + def allocate_test_port(self): """Get the test port to use for this gateway setup""" test_port = self._switch_port(self.TEST_OFFSET_START) diff --git a/daq/host.py b/daq/host.py index 5de826f8c9..50d8fe224e 100644 --- a/daq/host.py +++ b/daq/host.py @@ -211,10 +211,6 @@ def _get_static_ip(self): def _get_dhcp_mode(self): return self._loaded_config['modules'].get('ipaddr', {}).get('dhcp_mode', 'normal') - def _get_dhcp_tests(self): - tests = self._loaded_config['modules'].get('ipaddr', {}).get('dhcp_tests', {}).keys() - return list(filter(self._test_enabled, tests)) - def _get_unique_upload_path(self, file_name): base = os.path.basename(file_name) partial = os.path.join('tests', self.test_name, base) if self.test_name else base @@ -448,6 +444,9 @@ def ip_notify(self, target_ip, state=MODE.DONE, delta_sec=-1): self._all_ips.append({"ip": target_ip, "timestamp": time.time()}) if self._get_dhcp_mode() == "ip_change" and len(self._all_ips) == 1: self.gateway.request_new_ip(self.target_mac) + # Update ip directly if it's already triggered. + if self.target_ip: + self.target_ip = target_ip if self.test_host: self.test_host.ip_listener(target_ip) diff --git a/daq/ipaddr_test.py b/daq/ipaddr_test.py index 6bf29fafe2..b56948d9e8 100644 --- a/daq/ipaddr_test.py +++ b/daq/ipaddr_test.py @@ -3,6 +3,7 @@ from __future__ import absolute_import import time import os +import copy import logger LOGGER = logger.get_logger('ipaddr') @@ -11,22 +12,23 @@ class IpAddrTest: """Module for inline ipaddr tests""" - DEFAULT_WAIT_SEC = 10 - # pylint: disable=too-many-arguments def __init__(self, host, target_port, tmpdir, test_name, module_config): self.host = host self.target_port = target_port self.tmpdir = tmpdir self.test_config = module_config.get('modules').get('ipaddr') + self.test_dhcp_ranges = copy.copy(self.test_config.get('dhcp_ranges', [])) self.test_name = test_name self.host_name = '%s%02d' % (test_name, self.target_port) self.log_path = os.path.join(self.tmpdir, 'nodes', self.host_name, 'activate.log') self.log_file = None self.callback = None + self._ip_callback = None self.tests = [ - self._dhcp_port_toggle_test, - self._finalize + ('dhcp port_toggle test', self._dhcp_port_toggle_test), + ('dhcp multi subnet test', self._multi_subnet_test), + ('finalize', self._finalize) ] def start(self, port, params, callback, finish_hook): @@ -38,21 +40,34 @@ def start(self, port, params, callback, finish_hook): def _next_test(self): try: - self.tests.pop(0)() + name, func = self.tests.pop(0) + self.log('Running ' + name) + func() except Exception as e: + self.log(str(e)) self._finalize(exception=e) - def activate_log(self, message): + def log(self, message): """Log an activation message""" + LOGGER.info(message) self.log_file.write(message + '\n') def _dhcp_port_toggle_test(self): - self.activate_log('dhcp_port_toggle_test') if not self.host.connect_port(False): - self.activate_log('disconnect port not enabled') + self.log('disconnect port not enabled') return time.sleep(self.host.config.get("port_debounce_sec", 0) + 1) self.host.connect_port(True) + self._ip_callback = self._next_test + + def _multi_subnet_test(self): + if not self.test_dhcp_ranges: + self._next_test() + return + dhcp_range = self.test_dhcp_ranges.pop(0) + self.log('Testing dhcp range: ' + ",".join([str(arg) for arg in dhcp_range])) + self.host.gateway.change_dhcp_range(*dhcp_range) + self._ip_callback = self._multi_subnet_test if self.test_dhcp_ranges else self._next_test def _finalize(self, exception=None): self.terminate() @@ -60,11 +75,12 @@ def _finalize(self, exception=None): def terminate(self): """Terminate this set of tests""" + self.log('Module terminating') self.log_file.close() self.log_file = None def ip_listener(self, target_ip): """Respond to a ip notification event""" - self.activate_log('ip notification %s' % target_ip) - LOGGER.info("%s received ip %s" % (self.test_name, target_ip)) - self._next_test() + self.log('ip notification %s' % target_ip) + if self._ip_callback: + self._ip_callback() diff --git a/docker/include/networking_scripts/change_dhcp_range b/docker/include/networking_scripts/change_dhcp_range new file mode 100755 index 0000000000..0c45cd6bae --- /dev/null +++ b/docker/include/networking_scripts/change_dhcp_range @@ -0,0 +1,24 @@ +#!/bin/bash -e +# +# Dynamically change DHCP lease range, requires killing and restarting +# dnsmasq as per documentation (SIGHUP does not reload configuration file). +LOCAL_IF=${LOCAL_IF:-$HOSTNAME-eth0} + +range_start=$1 +range_end=$2 +prefix_len=$3 +if [ -z $range_start -o -z $range_end -o -z $prefix_len ]; then + echo "Usage: change_dhcp_range range_start range_end prefix_len" + exit 1 +fi +while [ $(cat /etc/dnsmasq.conf | egrep "^dhcp-range=" | wc -l) == 0 ]; do + sleep 1 +done +ip addr add $range_start/$prefix_len dev $LOCAL_IF || true +original=$(cat /etc/dnsmasq.conf | egrep "^dhcp-range=" | head -1) +lease=$(echo $original | cut -d',' -f 3) +if [ -n "lease" ]; then + lease=",$lease" +fi +new="dhcp-range=$range_start,$range_end$lease" +flock /etc/dnsmasq.conf sed -i s/$original/$new/ /etc/dnsmasq.conf \ No newline at end of file diff --git a/docker/include/networking_scripts/change_lease_time b/docker/include/networking_scripts/change_lease_time index 306e985604..0cb8986c8a 100755 --- a/docker/include/networking_scripts/change_lease_time +++ b/docker/include/networking_scripts/change_lease_time @@ -7,10 +7,10 @@ if [ -z $lease ]; then echo "Lease time not defined." exit 1 fi -while [ $(cat /etc/dnsmasq.conf | grep dhcp-range=10.20 | wc -l) == 0 ]; do +while [ $(cat /etc/dnsmasq.conf | grep "^dhcp-range=" | wc -l) == 0 ]; do sleep 1 done -original=$(cat /etc/dnsmasq.conf | grep dhcp-range=10.20 | head -1) +original=$(cat /etc/dnsmasq.conf | grep "^dhcp-range=" | head -1) new="$(echo $original | cut -d',' -f 1,2),$lease" flock /etc/dnsmasq.conf sed -i s/$original/$new/ /etc/dnsmasq.conf diff --git a/docs/device_report.md b/docs/device_report.md index 3cc2ac6675..4a5be26839 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -144,17 +144,6 @@ RESULT pass base.target.ping target reached ``` -## Module ipaddr - - -#### Module Config - -|Attribute|Value| -|---|---| -|enabled|True| -|timeout_sec|300| -|port_flap_timeout_sec|20| - ## Module nmap diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index 83eaa9a3b5..144c249ce2 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -1,9 +1,10 @@ { "modules": { "ipaddr": { - "enabled": true, - "timeout_sec": 300, - "port_flap_timeout_sec": 20 + "enabled": false, + "timeout_sec": 900, + "port_flap_timeout_sec": 20, + "dhcp_ranges": [["192.168.0.1", "192.168.255.254", 16]] }, "pass": { "enabled": true diff --git a/testing/test_aux.out b/testing/test_aux.out index cf65e1a828..b46c806282 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -94,9 +94,16 @@ port-01 module_config modules "enabled": false }, "ipaddr": { - "enabled": true, + "dhcp_ranges": [ + [ + "192.168.0.1", + "192.168.255.254", + 16 + ] + ], + "enabled": false, "port_flap_timeout_sec": 20, - "timeout_sec": 300 + "timeout_sec": 900 }, "macoui": { "enabled": true @@ -147,9 +154,16 @@ port-02 module_config modules "enabled": true }, "ipaddr": { - "enabled": true, + "dhcp_ranges": [ + [ + "192.168.0.1", + "192.168.255.254", + 16 + ] + ], + "enabled": false, "port_flap_timeout_sec": 20, - "timeout_sec": 300 + "timeout_sec": 900 }, "macoui": { "enabled": true, @@ -206,19 +220,16 @@ inst/gw01/nodes/gw01/activate.log inst/gw02/nodes/gw02/activate.log inst/gw03/nodes/gw03/activate.log inst/run-port-01/nodes/fail01/activate.log -inst/run-port-01/nodes/ipaddr01/activate.log inst/run-port-01/nodes/nmap01/activate.log inst/run-port-01/nodes/pass01/activate.log inst/run-port-01/nodes/ping01/activate.log inst/run-port-02/nodes/fail02/activate.log inst/run-port-02/nodes/hold02/activate.log -inst/run-port-02/nodes/ipaddr02/activate.log inst/run-port-02/nodes/nmap02/activate.log inst/run-port-02/nodes/pass02/activate.log inst/run-port-02/nodes/ping02/activate.log inst/run-port-03/nodes/fail03/activate.log inst/run-port-03/nodes/hold03/activate.log -inst/run-port-03/nodes/ipaddr03/activate.log inst/run-port-03/nodes/nmap03/activate.log inst/run-port-03/nodes/pass03/activate.log inst/run-port-03/nodes/ping03/activate.log diff --git a/testing/test_aux.sh b/testing/test_aux.sh index f78d30f506..23861b04b1 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -121,7 +121,7 @@ more inst/run-port-*/scans/ip_triggers.txt | cat dhcp_done=$(fgrep done inst/run-port-01/scans/ip_triggers.txt | wc -l) dhcp_long=$(fgrep long inst/run-port-01/scans/ip_triggers.txt | wc -l) echo dhcp requests $((dhcp_done > 1)) $((dhcp_done < 3)) \ - $((dhcp_long > 1)) $((dhcp_long < 4)) | tee -a $TEST_RESULTS + $((dhcp_long >= 1)) $((dhcp_long < 4)) | tee -a $TEST_RESULTS sort inst/result.log | tee -a $TEST_RESULTS # Show partial logs from each test diff --git a/testing/test_base.out b/testing/test_base.out index d0181c88d0..7ad42c6cce 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -87,17 +87,6 @@ RESULT pass base.target.ping target reached ``` -## Module ipaddr - - -#### Module Config - -|Attribute|Value| -|---|---| -|enabled|True| -|timeout_sec|300| -|port_flap_timeout_sec|20| - ## Module nmap diff --git a/testing/test_many.out b/testing/test_many.out index 3e8525aa5e..29cc0367df 100644 --- a/testing/test_many.out +++ b/testing/test_many.out @@ -5,6 +5,7 @@ Enough results: 1 Enough DHCP timeouts: 1 Enough static ips: 1 Enough ipaddr tests: 1 +Enough alternate subnet ips: 1 Enough ipaddr timeouts: 1 Redacted soak diff No soak report diff diff --git a/testing/test_many.sh b/testing/test_many.sh index 7befe66a76..c63c99a182 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -20,6 +20,7 @@ echo source config/system/default.yaml > local/system.conf echo monitor_scan_sec=5 >> local/system.conf echo switch_setup.uplink_port=$((NUM_DEVICES+1)) >> local/system.conf echo gcp_cred=$gcp_cred >> local/system.conf +echo dhcp_lease_time=120s >> local/system.conf for iface in $(seq 1 $NUM_DEVICES); do xdhcp="" @@ -86,6 +87,7 @@ results=$(fgrep [] inst/result.log | wc -l) timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) ipaddr_timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) ip_notifications=$(fgrep "ip notification" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) +alternate_subnet_ip=$(fgrep "ip notification 192.168" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) cat inst/run-port-*/scans/ip_triggers.txt static_ips=$(fgrep nope inst/run-port-*/scans/ip_triggers.txt | wc -l) @@ -103,7 +105,8 @@ echo Enough results: $((results >= 5*RUN_LIMIT/10)) | tee -a $TEST_RESULTS echo Enough DHCP timeouts: $((timeouts >= NUM_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS echo Enough static ips: $((static_ips >= (NUM_NO_DHCP_DEVICES - NUM_TIMEOUT_DEVICES))) | tee -a $TEST_RESULTS -echo Enough ipaddr tests: $((ip_notifications >= (NUM_IPADDR_TEST_DEVICES - NUM_IPADDR_TEST_TIMEOUT_DEVICES) )) | tee -a $TEST_RESULTS +echo Enough ipaddr tests: $((ip_notifications >= (NUM_IPADDR_TEST_DEVICES - NUM_IPADDR_TEST_TIMEOUT_DEVICES) * 2 )) | tee -a $TEST_RESULTS +echo Enough alternate subnet ips: $((alternate_subnet_ip >= (NUM_IPADDR_TEST_DEVICES - NUM_IPADDR_TEST_TIMEOUT_DEVICES) )) | tee -a $TEST_RESULTS echo Enough ipaddr timeouts: $((ipaddr_timeouts >= NUM_IPADDR_TEST_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS echo bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time count=2