mirror of
https://github.com/curl/curl.git
synced 2026-07-29 00:03:12 +03:00
tests: fix the FTP check for unexpected RST
- In vsftpd ignore unrelated RST by matching tcpdump RSTs to the data connection port pair. Prior to this change an unrelated RST on a recycled ephemeral port could cause test failure. Closes https://github.com/curl/curl/pull/22305
This commit is contained in:
parent
545cdd4b50
commit
c8860532dd
5 changed files with 27 additions and 13 deletions
|
|
@ -161,7 +161,7 @@ class TestVsFTPD:
|
|||
# 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")
|
||||
|
|
@ -182,7 +182,7 @@ class TestVsFTPD:
|
|||
# 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'
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ class TestVsFTPD:
|
|||
# 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")
|
||||
|
|
@ -197,7 +197,7 @@ class TestVsFTPD:
|
|||
# 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'
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ class TestFtpsVsFTPD:
|
|||
# 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")
|
||||
|
|
@ -207,7 +207,7 @@ class TestFtpsVsFTPD:
|
|||
# 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'
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ from datetime import datetime, timedelta, timezone
|
|||
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
|
||||
|
|
@ -188,9 +188,19 @@ class RunTcpDump:
|
|||
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:
|
||||
|
|
@ -198,7 +208,10 @@ class RunTcpDump:
|
|||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import socket
|
|||
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
|
||||
|
|
@ -226,6 +226,7 @@ class VsFTPD:
|
|||
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))]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue