# look only at ports from DATA connection.
data_ports = vsftpd.get_data_ports(r)
assert len(data_ports), f'unable to find FTP data port connected to\n{r.dump_logs()}'
- assert len(r.tcpdump.get_rsts(ports=data_ports)) == 0, 'Unexpected TCP RST packets'
+ assert len(r.tcpdump.get_rsts(port_pairs=data_ports)) == 0, 'Unexpected TCP RST packets'
# check with `tcpdump` if curl causes any TCP RST packets
@pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available")
# look only at ports from DATA connection.
data_ports = vsftpd.get_data_ports(r)
assert len(data_ports), f'unable to find FTP data port connected to\n{r.dump_logs()}'
- assert len(r.tcpdump.get_rsts(ports=data_ports)) == 0, 'Unexpected TCP RST packets'
+ assert len(r.tcpdump.get_rsts(port_pairs=data_ports)) == 0, 'Unexpected TCP RST packets'
def test_30_08_active_download(self, env: Env, vsftpd: VsFTPD):
docname = 'data-10k'
# look only at ports from DATA connection.
data_ports = vsftpds.get_data_ports(r)
assert len(data_ports), f'unable to find FTP data port connected to\n{r.dump_logs()}'
- assert len(r.tcpdump.get_rsts(ports=data_ports)) == 0, 'Unexpected TCP RST packets'
+ assert len(r.tcpdump.get_rsts(port_pairs=data_ports)) == 0, 'Unexpected TCP RST packets'
# check with `tcpdump` if curl causes any TCP RST packets
@pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available")
# look only at ports from DATA connection.
data_ports = vsftpds.get_data_ports(r)
assert len(data_ports), f'unable to find FTP data port connected to\n{r.dump_logs()}'
- assert len(r.tcpdump.get_rsts(ports=data_ports)) == 0, 'Unexpected TCP RST packets'
+ assert len(r.tcpdump.get_rsts(port_pairs=data_ports)) == 0, 'Unexpected TCP RST packets'
def test_31_08_upload_ascii(self, env: Env, vsftpds: VsFTPD):
docname = 'upload-ascii'
# look only at ports from DATA connection.
data_ports = vsftpds.get_data_ports(r)
assert len(data_ports), f'unable to find FTP data port connected to\n{r.dump_logs()}'
- assert len(r.tcpdump.get_rsts(ports=data_ports)) == 0, 'Unexpected TCP RST packets'
+ assert len(r.tcpdump.get_rsts(port_pairs=data_ports)) == 0, 'Unexpected TCP RST packets'
# check with `tcpdump` if curl causes any TCP RST packets
@pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available")
# look only at ports from DATA connection.
data_ports = vsftpds.get_data_ports(r)
assert len(data_ports), f'unable to find FTP data port connected to\n{r.dump_logs()}'
- assert len(r.tcpdump.get_rsts(ports=data_ports)) == 0, 'Unexpected TCP RST packets'
+ assert len(r.tcpdump.get_rsts(port_pairs=data_ports)) == 0, 'Unexpected TCP RST packets'
def test_32_08_upload_ascii(self, env: Env, vsftpds: VsFTPD):
docname = 'upload-ascii'
from functools import cmp_to_key
from statistics import fmean, mean
from threading import Thread
-from typing import Any, Dict, List, Optional, Union
+from typing import Any, Dict, List, Optional, Tuple, Union
from urllib.parse import urlparse
import psutil
self._stdoutfile = os.path.join(self._run_dir, 'tcpdump.out')
self._stderrfile = os.path.join(self._run_dir, 'tcpdump.err')
- def get_rsts(self, ports: Optional[List[int]] = None) -> Optional[List[str]]:
+ def get_rsts(self, ports: Optional[List[int]] = None,
+ port_pairs: Optional[List[Tuple[int, int]]] = None
+ ) -> Optional[List[str]]:
if self._proc:
raise Exception('tcpdump still running')
+ # a pair matches only a RST between exactly these two ports, while
+ # a port in `ports` matches any RST it is involved in
+ pairs = None
+ if port_pairs is not None:
+ pairs = set()
+ for p1, p2 in port_pairs:
+ pairs.add((p1, p2))
+ pairs.add((p2, p1))
lines = []
with open(self._stdoutfile) as fd:
for line in fd:
if m:
sport = int(m.group(1))
dport = int(m.group(2))
- if ports is None or sport in ports or dport in ports:
+ if pairs is not None:
+ if (sport, dport) in pairs:
+ lines.append(line)
+ elif ports is None or sport in ports or dport in ports:
lines.append(line)
return lines
import subprocess
import time
from datetime import datetime, timedelta
-from typing import Dict, List
+from typing import Dict, List, Tuple
from .curl import CurlClient, ExecResult
from .env import Env
with open(self._conf_file, 'w') as fd:
fd.write("\n".join(conf))
- def get_data_ports(self, r: ExecResult) -> List[int]:
- return [int(m.group(1)) for line in r.trace_lines if
- (m := re.match(r'.*Established 2nd connection to .* \(\S+ port (\d+)\)', line))]
+ def get_data_ports(self, r: ExecResult) -> List[Tuple[int, int]]:
+ return [(int(m.group(1)), int(m.group(2))) for line in r.trace_lines if
+ (m := re.match(r'.*Established 2nd connection to .* '
+ r'\(\S+ port (\d+)\) from \S+ port (\d+)', line))]