2019-10-03 19:41:04 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
# Copyright (C) 2019 Freie Universität Berlin
|
|
|
|
#
|
|
|
|
# This file is subject to the terms and conditions of the GNU Lesser
|
|
|
|
# General Public License v2.1. See the file LICENSE in the top level
|
|
|
|
# directory for more details.
|
|
|
|
|
|
|
|
import base64
|
2020-10-09 11:14:42 +02:00
|
|
|
import pexpect
|
2019-10-03 19:41:04 +02:00
|
|
|
import os
|
|
|
|
import socket
|
|
|
|
import sys
|
|
|
|
|
|
|
|
from scapy.all import Ether, IPv6, TCP, raw, \
|
|
|
|
sendp
|
|
|
|
from testrunner import run
|
|
|
|
|
|
|
|
from shared_func import sudo_guard, get_host_tap_device, get_host_ll_addr, \
|
|
|
|
get_riot_if_id, get_riot_l2_addr, get_riot_ll_addr, \
|
|
|
|
generate_port_number, verify_pktbuf_empty
|
|
|
|
|
|
|
|
|
|
|
|
def testfunc(func):
|
|
|
|
def runner(child):
|
|
|
|
tap = get_host_tap_device()
|
|
|
|
host_ll = get_host_ll_addr(tap)
|
|
|
|
dst_if = get_riot_if_id(child)
|
|
|
|
dst_ll = get_riot_ll_addr(child)
|
|
|
|
dst_l2 = get_riot_l2_addr(child)
|
|
|
|
port = generate_port_number()
|
|
|
|
|
|
|
|
# Setup RIOT Node wait for incoming connections from host system
|
|
|
|
child.sendline('gnrc_tcp_tcb_init')
|
|
|
|
child.expect_exact('gnrc_tcp_tcb_init: argc=1, argv[0] = gnrc_tcp_tcb_init')
|
2021-05-08 08:55:42 +02:00
|
|
|
child.sendline('gnrc_tcp_listen [::]:{}'.format(port))
|
|
|
|
child.expect(r'gnrc_tcp_listen: argc=2, '
|
|
|
|
r'argv\[0\] = gnrc_tcp_listen, '
|
2020-01-02 15:20:20 +01:00
|
|
|
r'argv\[1\] = \[::\]:(\d+)\r\n')
|
2019-10-03 19:41:04 +02:00
|
|
|
assert int(child.match.group(1)) == port
|
|
|
|
|
2021-05-08 08:55:42 +02:00
|
|
|
child.sendline('gnrc_tcp_accept 15000')
|
|
|
|
|
2019-10-03 19:41:04 +02:00
|
|
|
try:
|
|
|
|
print("- {} ".format(func.__name__), end="")
|
|
|
|
if child.logfile == sys.stdout:
|
|
|
|
func(child, tap, host_ll, dst_if, dst_l2, dst_ll, port)
|
|
|
|
print("")
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
func(child, tap, host_ll, dst_if, dst_l2, dst_ll, port)
|
|
|
|
print("SUCCESS")
|
|
|
|
except Exception as e:
|
|
|
|
print("FAILED")
|
|
|
|
raise e
|
|
|
|
finally:
|
|
|
|
child.sendline('gnrc_tcp_close')
|
2021-05-08 08:55:42 +02:00
|
|
|
child.sendline('gnrc_tcp_stop_listen')
|
2019-10-03 19:41:04 +02:00
|
|
|
|
|
|
|
return runner
|
|
|
|
|
|
|
|
|
|
|
|
@testfunc
|
|
|
|
def test_short_payload(child, src_if, src_ll, dst_if, dst_l2, dst_ll, dst_port):
|
|
|
|
# see https://github.com/RIOT-OS/RIOT/issues/11999
|
|
|
|
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock:
|
|
|
|
sock.settimeout(child.timeout)
|
|
|
|
addr_info = socket.getaddrinfo(dst_ll + '%' + src_if, dst_port,
|
|
|
|
type=socket.SOCK_STREAM)
|
|
|
|
sock.connect(addr_info[0][-1])
|
2021-05-08 08:55:42 +02:00
|
|
|
child.expect_exact('gnrc_tcp_accept: returns 0')
|
2019-10-03 19:41:04 +02:00
|
|
|
child.sendline('gnrc_tcp_recv 1000000 1')
|
|
|
|
child.expect_exact('gnrc_tcp_recv: argc=3, '
|
|
|
|
'argv[0] = gnrc_tcp_recv, '
|
|
|
|
'argv[1] = 1000000, argv[2] = 1')
|
|
|
|
assert 1 == sock.send(b"f")
|
|
|
|
child.expect_exact('gnrc_tcp_recv: received 1', timeout=20)
|
|
|
|
verify_pktbuf_empty(child)
|
|
|
|
|
|
|
|
|
|
|
|
@testfunc
|
|
|
|
def test_short_header(child, src_if, src_ll, dst_if, dst_l2, dst_ll, dst_port):
|
|
|
|
# see https://github.com/RIOT-OS/RIOT/issues/12086
|
|
|
|
tcp_hdr = TCP(dport=dst_port, flags="S", sport=2342, seq=1, dataofs=6)
|
|
|
|
# shorten header
|
|
|
|
tcp_hdr = raw(tcp_hdr)[:-2]
|
|
|
|
sendp(Ether(dst=dst_l2) / IPv6(src=src_ll, dst=dst_ll) / tcp_hdr,
|
|
|
|
iface=src_if, verbose=0)
|
|
|
|
|
|
|
|
# let server command return to later check packet buffer
|
|
|
|
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock:
|
|
|
|
sock.settimeout(child.timeout)
|
|
|
|
addr_info = socket.getaddrinfo(dst_ll + '%' + src_if, dst_port,
|
|
|
|
type=socket.SOCK_STREAM)
|
|
|
|
sock.connect(addr_info[0][-1])
|
2021-05-08 08:55:42 +02:00
|
|
|
child.expect_exact('gnrc_tcp_accept: returns 0')
|
2019-10-03 19:41:04 +02:00
|
|
|
verify_pktbuf_empty(child)
|
|
|
|
|
|
|
|
|
|
|
|
@testfunc
|
|
|
|
def test_send_ack_instead_of_syn(child, src_if, src_ll,
|
|
|
|
dst_if, dst_l2, dst_ll, dst_port):
|
2020-10-09 11:14:42 +02:00
|
|
|
# check if any debug output is generated during `@testfunc` decorator
|
|
|
|
# execution. If so, send fewer packets to prevent the target node
|
|
|
|
# from being overwhelmed by packets and output.
|
|
|
|
debug = child.expect([pexpect.TIMEOUT,
|
|
|
|
r'GNRC_TCP: Enter "\S+", File: .+\(\d+\)\s'], timeout=1)
|
|
|
|
if debug:
|
|
|
|
count = 10
|
|
|
|
else:
|
|
|
|
count = 1000
|
|
|
|
|
2019-10-03 19:41:04 +02:00
|
|
|
# see https://github.com/RIOT-OS/RIOT/pull/12001
|
|
|
|
provided_data = base64.b64decode("rwsQf2pekYLaU+exUBBwgPDKAAA=")
|
|
|
|
tcp_hdr = TCP(provided_data)
|
|
|
|
assert provided_data == raw(tcp_hdr)
|
|
|
|
# set destination port to application specific port
|
|
|
|
tcp_hdr.dport = dst_port
|
|
|
|
sendp(Ether(dst=dst_l2) / IPv6(src=src_ll, dst=dst_ll) / tcp_hdr,
|
2020-10-09 11:14:42 +02:00
|
|
|
iface=src_if, verbose=0, count=count)
|
2019-10-03 19:41:04 +02:00
|
|
|
|
|
|
|
# check if server actually still works
|
|
|
|
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock:
|
|
|
|
sock.settimeout(child.timeout)
|
|
|
|
addr_info = socket.getaddrinfo(dst_ll + '%' + src_if, dst_port,
|
|
|
|
type=socket.SOCK_STREAM)
|
|
|
|
sock.connect(addr_info[0][-1])
|
2021-05-08 08:55:42 +02:00
|
|
|
child.expect_exact('gnrc_tcp_accept: returns 0')
|
2019-10-03 19:41:04 +02:00
|
|
|
verify_pktbuf_empty(child)
|
|
|
|
|
|
|
|
|
|
|
|
@testfunc
|
|
|
|
def test_option_parsing_term(child, src_if, src_ll,
|
|
|
|
dst_if, dst_l2, dst_ll, dst_port):
|
|
|
|
# see https://github.com/RIOT-OS/RIOT/issues/12086
|
|
|
|
tcp_hdr = TCP(dport=dst_port, flags="S", sport=2342, seq=1, dataofs=6)
|
|
|
|
sendp(Ether(dst=dst_l2) / IPv6(src=src_ll, dst=dst_ll) / tcp_hdr /
|
|
|
|
b"\x50\x00\x00\x00", iface=src_if, verbose=0)
|
|
|
|
|
|
|
|
# check if server actually still works
|
|
|
|
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock:
|
|
|
|
sock.settimeout(child.timeout)
|
|
|
|
addr_info = socket.getaddrinfo(dst_ll + '%' + src_if, dst_port,
|
|
|
|
type=socket.SOCK_STREAM)
|
|
|
|
sock.connect(addr_info[0][-1])
|
2021-05-08 08:55:42 +02:00
|
|
|
child.expect_exact('gnrc_tcp_accept: returns 0')
|
2019-10-03 19:41:04 +02:00
|
|
|
verify_pktbuf_empty(child)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
sudo_guard(uses_scapy=True)
|
|
|
|
script = sys.modules[__name__]
|
|
|
|
tests = [getattr(script, t) for t in script.__dict__
|
|
|
|
if type(getattr(script, t)).__name__ == "function"
|
|
|
|
and t.startswith("test_")]
|
|
|
|
for test in tests:
|
|
|
|
res = run(test, timeout=10, echo=False)
|
|
|
|
if res != 0:
|
|
|
|
sys.exit(res)
|
|
|
|
print(os.path.basename(sys.argv[0]) + ": success\n")
|