-
-
Notifications
You must be signed in to change notification settings - Fork 84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Fix and enable connection migration tests #410
Changes from all commits
6623b30
538c786
298264d
c5b0ba1
9dc67c2
2324a3d
028d6f1
4ba6e90
86427d1
3432b55
cde2270
1b4e1f5
9b5d2fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,7 @@ | |
get_direction, | ||
get_packet_type, | ||
) | ||
from typing import List | ||
from typing import List, Tuple | ||
|
||
from Crypto.Cipher import AES | ||
|
||
|
@@ -1244,6 +1244,21 @@ def scenario() -> str: | |
"""Scenario for the ns3 simulator""" | ||
return "rebind --delay=15ms --bandwidth=10Mbps --queue=25 --first-rebind=1s --rebind-freq=5s" | ||
|
||
@staticmethod | ||
def _addr(p: List, which: str) -> str: | ||
return ( | ||
getattr(p["ipv6"], which) | ||
if "IPV6" in str(p.layers) | ||
else getattr(p["ip"], which) | ||
) | ||
|
||
@staticmethod | ||
def _path(p: List) -> Tuple[str, int, str, int]: | ||
return ( | ||
(TestCasePortRebinding._addr(p, "src"), int(getattr(p["udp"], "srcport"))), | ||
(TestCasePortRebinding._addr(p, "dst"), int(getattr(p["udp"], "dstport"))), | ||
) | ||
|
||
def check(self) -> TestResult: | ||
super().check() | ||
if not self._keylog_file(): | ||
|
@@ -1258,59 +1273,40 @@ def check(self) -> TestResult: | |
self._server_trace()._get_direction_filter(Direction.FROM_SERVER) + " quic" | ||
) | ||
|
||
ports = list(set(getattr(p["udp"], "dstport") for p in tr_server)) | ||
|
||
logging.info("Server saw these client ports: %s", ports) | ||
if len(ports) <= 1: | ||
logging.info("Server saw only a single client port in use; test broken?") | ||
return TestResult.FAILED | ||
larseggert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
cur = None | ||
last = None | ||
num_migrations = 0 | ||
paths = set() | ||
challenges = set() | ||
for p in tr_server: | ||
cur = ( | ||
( | ||
getattr(p["ipv6"], "dst") | ||
if "IPV6" in str(p.layers) | ||
else getattr(p["ip"], "dst") | ||
), | ||
int(getattr(p["udp"], "dstport")), | ||
) | ||
cur = self._path(p) | ||
if last is None: | ||
last = cur | ||
continue | ||
|
||
if last != cur: | ||
if last != cur and cur not in paths: | ||
paths.add(last) | ||
last = cur | ||
num_migrations += 1 | ||
# packet to different IP/port, should have a PATH_CHALLENGE frame | ||
# Packet on new path, should have a PATH_CHALLENGE frame | ||
if hasattr(p["quic"], "path_challenge.data") is False: | ||
logging.info( | ||
"First server packet to new client destination %s did not contain a PATH_CHALLENGE frame", | ||
"First server packet on new path %s did not contain a PATH_CHALLENGE frame", | ||
cur, | ||
) | ||
logging.info(p["quic"]) | ||
return TestResult.FAILED | ||
else: | ||
challenges.add(getattr(p["quic"], "path_challenge.data")) | ||
paths.add(cur) | ||
|
||
logging.info("Server saw these paths used: %s", paths) | ||
if len(paths) <= 1: | ||
logging.info("Server saw only a single path in use; test broken?") | ||
return TestResult.FAILED | ||
|
||
tr_client = self._client_trace()._get_packets( | ||
self._client_trace()._get_direction_filter(Direction.FROM_CLIENT) + " quic" | ||
) | ||
|
||
challenges = list( | ||
set( | ||
getattr(p["quic"], "path_challenge.data") | ||
for p in tr_server | ||
if hasattr(p["quic"], "path_challenge.data") | ||
) | ||
) | ||
if len(challenges) < num_migrations: | ||
logging.info( | ||
"Saw %d migrations, but only %d unique PATH_CHALLENGE frames", | ||
len(challenges), | ||
num_migrations, | ||
) | ||
return TestResult.FAILED | ||
|
||
responses = list( | ||
set( | ||
getattr(p["quic"], "path_response.data") | ||
|
@@ -1336,6 +1332,10 @@ def name(): | |
def abbreviation(): | ||
return "BA" | ||
|
||
@staticmethod | ||
def testname(p: Perspective): | ||
return "transfer" | ||
|
||
Comment on lines
+1335
to
+1338
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This means that implementation that don't implement path validation yet (like quic-go 🤐) will fail this test. I think this is ok, since this is a mandatory part of the RFC. Might lead to some complaints though if the matrix is getting slightly more red as a result of merging this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No progress without pain. |
||
@staticmethod | ||
def desc(): | ||
return "Transfer completes under frequent IP address and port rebindings on the client side." | ||
|
@@ -1435,7 +1435,8 @@ def abbreviation(): | |
|
||
@staticmethod | ||
def testname(p: Perspective): | ||
if p is Perspective.CLIENT: | ||
if p is Perspective.SERVER: | ||
# Server needs to send preferred addresses | ||
return "connectionmigration" | ||
return "transfer" | ||
|
||
|
@@ -1447,6 +1448,11 @@ def desc(): | |
def scenario() -> str: | ||
return super(TestCaseTransfer, TestCaseTransfer).scenario() | ||
|
||
@staticmethod | ||
def urlprefix() -> str: | ||
"""URL prefix""" | ||
return "https://server46:443/" | ||
|
||
def get_paths(self): | ||
self._files = [ | ||
self._generate_random_file(2 * MB), | ||
|
@@ -1466,22 +1472,17 @@ def check(self) -> TestResult: | |
) | ||
|
||
last = None | ||
paths = set() | ||
dcid = None | ||
for p in tr_client: | ||
cur = ( | ||
( | ||
getattr(p["ipv6"], "src") | ||
if "IPV6" in str(p.layers) | ||
else getattr(p["ip"], "src") | ||
), | ||
int(getattr(p["udp"], "srcport")), | ||
) | ||
cur = self._path(p) | ||
if last is None: | ||
last = cur | ||
dcid = getattr(p["quic"], "dcid") | ||
continue | ||
|
||
if last != cur: | ||
if last != cur and cur not in paths: | ||
paths.add(last) | ||
last = cur | ||
# packet to different IP/port, should have a new DCID | ||
if dcid == getattr(p["quic"], "dcid"): | ||
|
@@ -1699,11 +1700,9 @@ def additional_containers() -> List[str]: | |
TestCaseTransferCorruption, | ||
TestCaseIPv6, | ||
TestCaseV2, | ||
# The next three tests are disabled due to Wireshark not being able | ||
# to decrypt packets sent on the new path. | ||
# TestCasePortRebinding, | ||
# TestCaseAddressRebinding, | ||
# TestCaseConnectionMigration, | ||
TestCasePortRebinding, | ||
TestCaseAddressRebinding, | ||
TestCaseConnectionMigration, | ||
] | ||
|
||
MEASUREMENTS = [ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is? You gotta indent the block if it's supposed to be part of the bullet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, makes sense.