Skip to content

Commit

Permalink
Packet capturing automation
Browse files Browse the repository at this point in the history
  • Loading branch information
ggediminass committed Aug 8, 2023
1 parent 6e4a0e6 commit 9ff332f
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 10 deletions.
5 changes: 5 additions & 0 deletions ci/docker/tester/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@ RUN apt-get update \
&& apt-get install -y python3 python3-pip \
# install python packages for tests
&& python3 -m pip install -r /tmp/requirements.txt \
# install thsark
DEBIAN_FRONTEND=noninteractive apt-get install -y tshark \
# make sure, that Docker does not hang during installation, when we get TUI screen
yes yes | DEBIAN_FRONTEND=teletype dpkg-reconfigure wireshark-common \
# cleanup
&& apt-get clean

ARG USER_ID=1000
ARG GROUP_ID=1000

RUN groupadd --system nordvpn && groupadd -g ${GROUP_ID} qa && useradd -l -m -u ${USER_ID} -g qa -G nordvpn qa && echo "qa ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
RUN usermod -a -G wireshark qa

USER qa

Expand Down
10 changes: 5 additions & 5 deletions ci/jobs/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ include: /ci/jobs/.cond.yml
- linux
- infra-docker
stage: test
image: ghcr.io/nordsecurity/nordvpn-linux/tester:1.0.4
image: ghcr.io/nordsecurity/nordvpn-linux/tester:1.1.0
rules:
- !reference [.cond/on-main, rules]
- !reference [.cond/on-version-tag, rules]
Expand Down Expand Up @@ -61,10 +61,10 @@ test/deb:
- TEST: [connect6, dns, dns6, killswitch, login, misc, routing, settings, allowlist]
test/deb-connect1:
extends: .test_job_template
script: $CI_PROJECT_DIR/ci/test_deb.sh connect 'test_quick_connect or test_double_quick_connect_only or test_connect_to_absent_server or test_mistype_connect or test_connect_to_invalid_group or test_connect_to_group_flag_standard or test_connect_to_group_flag_additional or test_connect_without_internet_access'
script: $CI_PROJECT_DIR/ci/test_deb.sh connect 'test_quick_connect or test_double_quick_connect_only or test_connect_to_absent_server or test_mistype_connect or test_connect_to_invalid_group or test_connect_to_group_flag_standard or test_connect_to_group_flag_additional or test_connect_without_internet_access or test_connect_to_city or test_connect_to_code_country'
test/deb-connect2:
extends: .test_job_template
script: $CI_PROJECT_DIR/ci/test_deb.sh connect 'test_connect_to_random_server_by_name or test_connection_recovers_from_network_restart or test_double_quick_connect_disconnect or test_connect_to_city or test_connect_to_country or test_connect_to_code_country or test_connect_to_group_standard or test_connect_to_group_additional'
script: $CI_PROJECT_DIR/ci/test_deb.sh connect 'test_connect_to_random_server_by_name or test_connection_recovers_from_network_restart or test_double_quick_connect_disconnect or test_connect_to_country or test_connect_to_group_standard or test_connect_to_group_additional'
test/deb-combinations:
extends: .test_job_template
script: $CI_PROJECT_DIR/ci/test_deb.sh combinations $PATTERN
Expand All @@ -90,7 +90,7 @@ test/deb-firewall6:
- $CI_PROJECT_DIR/ci/test_deb.sh firewall6
test/deb-manual:
stage: test
image: ghcr.io/nordsecurity/nordvpn-linux/tester:1.0.4
image: ghcr.io/nordsecurity/nordvpn-linux/tester:1.1.0
rules:
# TODO: run automatically after meshnet release
- !reference [.cond/on-click, rules]
Expand All @@ -115,7 +115,7 @@ test/deb-meshnet:
script: $CI_PROJECT_DIR/ci/test_deb.sh meshnet
test/deb-fileshare:
stage: test
image: ghcr.io/nordsecurity/nordvpn-linux/tester:1.0.4
image: ghcr.io/nordsecurity/nordvpn-linux/tester:1.1.0
rules:
- !reference [.cond/on-main, rules]
- !reference [.cond/on-version-tag, rules]
Expand Down
2 changes: 1 addition & 1 deletion magefiles/mage.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const (
imagePackager = registryPrefix + "packager:1.0.1"
imageProtobufGenerator = registryPrefix + "generator:1.0.1"
imageScanner = registryPrefix + "scanner:1.0.0"
imageTester = registryPrefix + "tester:1.0.4"
imageTester = registryPrefix + "tester:1.1.0"
imageQAPeer = registryPrefix + "qa-peer:1.0.2"
imageLinter = registryPrefix + "linter:1.0.0"
imageRuster = registryPrefix + "ruster:1.0.1"
Expand Down
18 changes: 18 additions & 0 deletions test/qa/lib/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,21 @@ def is_peer_running(ssh_client: ssh.Ssh) -> bool:
return False
else:
return True


def get_server_ip():
return sh.nordvpn.status().split('\n')[2].replace('IP: ', '')


def get_current_connection_protocol():
current_protocol = sh.nordvpn("settings").split('\n')[1]

if "UDP" in current_protocol:
return "udp"
elif "TCP" in current_protocol:
return "tcp"
else:
return "nordlynx"

def get_is_obfuscated():
return "enabled" in sh.nordvpn("settings").split('\n')[8]
4 changes: 3 additions & 1 deletion test/qa/lib/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ def collect():
rounting_info = sh.sudo.ip.route()
firewall_info = sh.sudo.iptables("-S")
nameserver_info = sh.sudo.cat("/etc/resolv.conf")
processes = sh.ps("-ef")

# without `ww` we cannot see full process lines, as it is cut off early
processes = sh.ps("-ef", "ww")

return "\n".join(
[
Expand Down
63 changes: 60 additions & 3 deletions test/qa/test_connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
)
import lib
import pytest
import queue
import sh
import socket
import threading
import time
import timeout_decorator


Expand All @@ -32,12 +35,66 @@ def teardown_function(function):
logging.log()


def capture_traffic() -> int:
"""
Captures traffic that goes to VPN server
:return: int - returns count of captured packets
"""

# Collect information needed for tshark filter
server_ip = daemon.get_server_ip()
protocol = daemon.get_current_connection_protocol()
obfuscated = daemon.get_is_obfuscated()

# Choose traffic filter according to information collected above
if protocol == "nordlynx":
traffic_filter = "(udp port 51820) and (ip dst {})".format(server_ip)
elif protocol == "udp" and not obfuscated:
traffic_filter = "(udp port 1194) and (ip dst {})".format(server_ip)
elif protocol == "tcp" and not obfuscated:
traffic_filter = "(tcp port 443) and (ip dst {})".format(server_ip)
elif protocol == "udp" and obfuscated:
traffic_filter = "udp and (port not 1194) and (ip dst {})".format(server_ip)
elif protocol == "tcp" and obfuscated:
traffic_filter = "tcp and (port not 443) and (ip dst {})".format(server_ip)

# Actual capture
# If 2 packets were already captured, do not wait for 3 seconds
# Show compact output about packets
tshark_result = sh.tshark("-i", "any", "-T", "fields", "-e", "ip.src", "-e", "ip.dst", "-a", "duration:3", "-a", "packets:2", "-f", traffic_filter)

packets = tshark_result.replace("\t", " -> ")
packets = tshark_result.split("\n")

logging.log("PACKETS_CAPTURED: " + str(packets))

# If no packets were captured, `packets` value should be 0
return len(packets) - 1


def connect_base_test(group=[], name="", hostname=""):
output = sh.nordvpn.connect(group)
print(output)

# Start capturing packets
packet_capture_thread_queue = queue.Queue()
packet_capture_thread_lambda = lambda: packet_capture_thread_queue.put(capture_traffic())
packet_capture_thread = threading.Thread(target=packet_capture_thread_lambda)
packet_capture_thread.start()

# We need to make sure, that packets are being sent out only after
# tshark starts, and not earlier, so we wait for one second.
time.sleep(1)
assert lib.is_connect_successful(output, name, hostname)

# Following function creates atleast two ICMP packets
assert network.is_connected()

packet_capture_thread.join()
packet_capture_thread_result = packet_capture_thread_queue.get()

assert packet_capture_thread_result >= 2


def disconnect_base_test():
output = sh.nordvpn.disconnect()
Expand Down Expand Up @@ -225,14 +282,14 @@ def test_connect_to_country(tech, proto, obfuscated, country):
disconnect_base_test()


@pytest.mark.parametrize("country", lib.COUNTRY_CODES)
@pytest.mark.parametrize("country_code", lib.COUNTRY_CODES)
@pytest.mark.parametrize("tech,proto,obfuscated", lib.TECHNOLOGIES)
@pytest.mark.flaky(reruns=2, reruns_delay=90)
@timeout_decorator.timeout(40)
def test_connect_to_code_country(tech, proto, obfuscated, country):
def test_connect_to_code_country(tech, proto, obfuscated, country_code):
lib.set_technology_and_protocol(tech, proto, obfuscated)

connect_base_test(country)
connect_base_test(country_code)
disconnect_base_test()


Expand Down

0 comments on commit 9ff332f

Please sign in to comment.