mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-28 18:28:23 -05:00
04fd8ea1ba
Instead of accessing the logs list member of the remote host directly, use a function to add logs to the remote host to be collected after the test. This enables us to later have different implementation of remote hosts or logs collection without requiring to have this list as the implementation. Signed-off-by: Jonathan Afek <jonathanx.afek@intel.com>
544 lines
16 KiB
Python
544 lines
16 KiB
Python
# Utils
|
|
# Copyright (c) 2016, Tieto Corporation
|
|
#
|
|
# This software may be distributed under the terms of the BSD license.
|
|
# See README for more details.
|
|
|
|
import time
|
|
from remotehost import Host
|
|
import hostapd
|
|
import config
|
|
|
|
class TestSkip(Exception):
|
|
def __init__(self, reason):
|
|
self.reason = reason
|
|
def __str__(self):
|
|
return self.reason
|
|
|
|
# get host based on name
|
|
def get_host(devices, dev_name):
|
|
dev = config.get_device(devices, dev_name)
|
|
host = Host(host = dev['hostname'],
|
|
ifname = dev['ifname'],
|
|
port = dev['port'],
|
|
name = dev['name'])
|
|
host.dev = dev
|
|
return host
|
|
|
|
# run setup_hw - hw specyfic
|
|
def setup_hw(hosts, setup_params):
|
|
for host in hosts:
|
|
setup_hw_host(host, setup_params)
|
|
|
|
def setup_hw_host(host, setup_params):
|
|
try:
|
|
setup_hw = setup_params['setup_hw']
|
|
restart = ""
|
|
try:
|
|
if setup_params['restart_device'] == True:
|
|
restart = " -R "
|
|
except:
|
|
pass
|
|
host.execute([setup_hw, "-I", host.ifname, restart])
|
|
except:
|
|
pass
|
|
|
|
# get traces - hw specific
|
|
def trace_start(hosts, setup_params):
|
|
for host in hosts:
|
|
trace_start_stop(host, setup_params, start=True)
|
|
|
|
def trace_stop(hosts, setup_params):
|
|
for host in hosts:
|
|
trace_start_stop(host, setup_params, start=False)
|
|
|
|
def trace_start_stop(host, setup_params, start):
|
|
if setup_params['trace'] == False:
|
|
return
|
|
try:
|
|
start_trace = setup_params['trace_start']
|
|
stop_trace = setup_params['trace_stop']
|
|
if start:
|
|
cmd = start_trace
|
|
else:
|
|
cmd = stop_trace
|
|
trace_dir = setup_params['log_dir'] + host.ifname + "/remote_traces"
|
|
host.add_log(trace_dir + "/*")
|
|
host.execute([cmd, "-I", host.ifname, "-D", trace_dir])
|
|
except:
|
|
pass
|
|
|
|
# get perf
|
|
def perf_start(hosts, setup_params):
|
|
for host in hosts:
|
|
perf_start_stop(host, setup_params, start=True)
|
|
|
|
def perf_stop(hosts, setup_params):
|
|
for host in hosts:
|
|
perf_start_stop(host, setup_params, start=False)
|
|
|
|
def perf_start_stop(host, setup_params, start):
|
|
if setup_params['perf'] == False:
|
|
return
|
|
try:
|
|
perf_start = setup_params['perf_start']
|
|
perf_stop = setup_params['perf_stop']
|
|
if start:
|
|
cmd = perf_start
|
|
else:
|
|
cmd = perf_stop
|
|
perf_dir = setup_params['log_dir'] + host.ifname + "/remote_perf"
|
|
host.add_log(perf_dir + "/*")
|
|
host.execute([cmd, "-I", host.ifname, "-D", perf_dir])
|
|
except:
|
|
pass
|
|
|
|
# hostapd/wpa_supplicant helpers
|
|
def run_hostapd(host, setup_params):
|
|
log_file = None
|
|
try:
|
|
tc_name = setup_params['tc_name']
|
|
log_dir = setup_params['log_dir']
|
|
log_file = log_dir + tc_name + "_hostapd_" + host.name + "_" + host.ifname + ".log"
|
|
host.execute(["rm", log_file])
|
|
log = " -f " + log_file
|
|
except:
|
|
log = ""
|
|
|
|
if log_file:
|
|
host.add_log(log_file)
|
|
status, buf = host.execute([setup_params['hostapd'], "-B", "-ddt", "-g", "udp:" + host.port, log])
|
|
if status != 0:
|
|
raise Exception("Could not run hostapd: " + buf)
|
|
|
|
def run_wpasupplicant(host, setup_params):
|
|
log_file = None
|
|
try:
|
|
tc_name = setup_params['tc_name']
|
|
log_dir = setup_params['log_dir']
|
|
log_file = log_dir + tc_name + "_wpa_supplicant_" + host.name + "_" + host.ifname + ".log"
|
|
host.execute(["rm", log_file])
|
|
log = " -f " + log_file
|
|
except:
|
|
log = ""
|
|
|
|
if log_file:
|
|
host.add_log(log_file)
|
|
status, buf = host.execute([setup_params['wpa_supplicant'], "-B", "-ddt", "-g", "udp:" + host.port, log])
|
|
if status != 0:
|
|
raise Exception("Could not run wpa_supplicant: " + buf)
|
|
|
|
def get_ap_params(channel="1", bw="HT20", country="US", security="open", ht_capab=None, vht_capab=None):
|
|
ssid = "test_" + channel + "_" + security + "_" + bw
|
|
|
|
if bw == "b_only":
|
|
params = hostapd.b_only_params(channel, ssid, country)
|
|
elif bw == "g_only":
|
|
params = hostapd.g_only_params(channel, ssid, country)
|
|
elif bw == "g_only_wmm":
|
|
params = hostapd.g_only_params(channel, ssid, country)
|
|
params['wmm_enabled'] = "1"
|
|
elif bw == "a_only":
|
|
params = hostapd.a_only_params(channel, ssid, country)
|
|
elif bw == "a_only_wmm":
|
|
params = hostapd.a_only_params(channel, ssid, country)
|
|
params['wmm_enabled'] = "1"
|
|
elif bw == "HT20":
|
|
params = hostapd.ht20_params(channel, ssid, country)
|
|
if ht_capab:
|
|
try:
|
|
params['ht_capab'] = params['ht_capab'] + ht_capab
|
|
except:
|
|
params['ht_capab'] = ht_capab
|
|
elif bw == "HT40+":
|
|
params = hostapd.ht40_plus_params(channel, ssid, country)
|
|
if ht_capab:
|
|
params['ht_capab'] = params['ht_capab'] + ht_capab
|
|
elif bw == "HT40-":
|
|
params = hostapd.ht40_minus_params(channel, ssid, country)
|
|
if ht_capab:
|
|
params['ht_capab'] = params['ht_capab'] + ht_capab
|
|
elif bw == "VHT80":
|
|
params = hostapd.ht40_plus_params(channel, ssid, country)
|
|
if ht_capab:
|
|
params['ht_capab'] = params['ht_capab'] + ht_capab
|
|
if vht_capab:
|
|
try:
|
|
params['vht_capab'] = params['vht_capab'] + vht_capab
|
|
except:
|
|
params['vht_capab'] = vht_capab
|
|
params['ieee80211ac'] = "1"
|
|
params['vht_oper_chwidth'] = "1"
|
|
params['vht_oper_centr_freq_seg0_idx'] = str(int(channel) + 6)
|
|
else:
|
|
params = {}
|
|
|
|
# now setup security params
|
|
if security == "tkip":
|
|
sec_params = hostapd.wpa_params(passphrase="testtest")
|
|
elif security == "ccmp":
|
|
sec_params = hostapd.wpa2_params(passphrase="testtest")
|
|
elif security == "mixed":
|
|
sec_params = hostapd.wpa_mixed_params(passphrase="testtest")
|
|
elif security == "wep":
|
|
sec_params = { "wep_key0" : "123456789a",
|
|
"wep_default_key" : "0",
|
|
"auth_algs" : "1"}
|
|
elif security == "wep_shared":
|
|
sec_params = { "wep_key0" : "123456789a",
|
|
"wep_default_key" : "0",
|
|
"auth_algs" : "2" }
|
|
else:
|
|
sec_params = {}
|
|
|
|
params.update(sec_params)
|
|
|
|
return params
|
|
|
|
# ip helpers
|
|
def get_ipv4(client, ifname=None):
|
|
if ifname is None:
|
|
ifname = client.ifname
|
|
status, buf = client.execute(["ifconfig", ifname])
|
|
lines = buf.splitlines()
|
|
|
|
for line in lines:
|
|
res = line.find("inet addr:")
|
|
if res != -1:
|
|
break
|
|
|
|
if res != -1:
|
|
words = line.split()
|
|
addr = words[1].split(":")
|
|
return addr[1]
|
|
|
|
return "unknown"
|
|
|
|
def get_ipv6(client, ifname=None):
|
|
res = -1
|
|
if ifname is None:
|
|
ifname = client.ifname
|
|
status, buf = client.execute(["ifconfig", ifname])
|
|
lines = buf.splitlines()
|
|
|
|
for line in lines:
|
|
res = line.find("Scope:Link")
|
|
if res != -1:
|
|
break
|
|
|
|
if res != -1:
|
|
words = line.split()
|
|
if words[0] == "inet6" and words[1] == "addr:":
|
|
addr_mask = words[2]
|
|
addr = addr_mask.split("/")
|
|
return addr[0]
|
|
|
|
return "unknown"
|
|
|
|
def get_ip(client, addr_type="ipv6", iface=None):
|
|
if addr_type == "ipv6":
|
|
return get_ipv6(client, iface)
|
|
elif addr_type == "ipv4":
|
|
return get_ipv4(client, iface)
|
|
else:
|
|
return "unknown addr_type: " + addr_type
|
|
|
|
def get_ipv4_addr(setup_params, number):
|
|
try:
|
|
ipv4_base = setup_params['ipv4_test_net']
|
|
except:
|
|
ipv4_base = "172.16.12.0"
|
|
|
|
parts = ipv4_base.split('.')
|
|
ipv4 = parts[0] + "." + parts[1] + "." + parts[2] + "." + str(number)
|
|
|
|
return ipv4
|
|
|
|
def get_mac_addr(host, iface=None):
|
|
if iface == None:
|
|
iface = host.ifname
|
|
status, buf = host.execute(["ifconfig", iface])
|
|
if status != 0:
|
|
raise Exception("ifconfig " + iface)
|
|
words = buf.split()
|
|
found = 0
|
|
for word in words:
|
|
if found == 1:
|
|
return word
|
|
if word == "HWaddr":
|
|
found = 1
|
|
raise Exception("Could not find HWaddr")
|
|
|
|
# connectivity/ping helpers
|
|
def get_ping_packet_loss(ping_res):
|
|
loss_line = ""
|
|
lines = ping_res.splitlines()
|
|
for line in lines:
|
|
if line.find("packet loss") != -1:
|
|
loss_line = line
|
|
break;
|
|
|
|
if loss_line == "":
|
|
return "100%"
|
|
|
|
sections = loss_line.split(",")
|
|
|
|
for section in sections:
|
|
if section.find("packet loss") != -1:
|
|
words = section.split()
|
|
return words[0]
|
|
|
|
return "100%"
|
|
|
|
def ac_to_ping_ac(qos):
|
|
if qos == "be":
|
|
qos_param = "0x00"
|
|
elif qos == "bk":
|
|
qos_param = "0x20"
|
|
elif qos == "vi":
|
|
qos_param = "0xA0"
|
|
elif qos == "vo":
|
|
qos_param = "0xE0"
|
|
else:
|
|
qos_param = "0x00"
|
|
return qos_param
|
|
|
|
def ping_run(host, ip, result, ifname=None, addr_type="ipv4", deadline="5", qos=None):
|
|
if ifname is None:
|
|
ifname = host.ifname
|
|
if addr_type == "ipv6":
|
|
ping = ["ping6"]
|
|
else:
|
|
ping = ["ping"]
|
|
|
|
ping = ping + ["-w", deadline, "-I", ifname]
|
|
if qos:
|
|
ping = ping + ["-Q", ac_to_ping_ac(qos)]
|
|
ping = ping + [ip]
|
|
|
|
flush_arp_cache(host)
|
|
|
|
thread = host.execute_run(ping, result)
|
|
return thread
|
|
|
|
def ping_wait(host, thread, timeout=None):
|
|
host.wait_execute_complete(thread, timeout)
|
|
if thread.isAlive():
|
|
raise Exception("ping thread still alive")
|
|
|
|
def flush_arp_cache(host):
|
|
host.execute(["ip", "-s", "-s", "neigh", "flush", "all"])
|
|
|
|
def check_connectivity(a, b, addr_type = "ipv4", deadline="5", qos=None):
|
|
addr_a = get_ip(a, addr_type)
|
|
addr_b = get_ip(b, addr_type)
|
|
|
|
if addr_type == "ipv4":
|
|
ping = ["ping"]
|
|
else:
|
|
ping = ["ping6"]
|
|
|
|
ping_a_b = ping + ["-w", deadline, "-I", a.ifname]
|
|
ping_b_a = ping + ["-w", deadline, "-I", b.ifname]
|
|
if qos:
|
|
ping_a_b = ping_a_b + ["-Q", ac_to_ping_ac(qos)]
|
|
ping_b_a = ping_b_a + ["-Q", ac_to_ping_ac(qos)]
|
|
ping_a_b = ping_a_b + [addr_b]
|
|
ping_b_a = ping_b_a + [addr_a]
|
|
|
|
# Clear arp cache
|
|
flush_arp_cache(a)
|
|
flush_arp_cache(b)
|
|
|
|
status, buf = a.execute(ping_a_b)
|
|
if status == 2 and ping == "ping6":
|
|
# tentative possible for a while, try again
|
|
time.sleep(3)
|
|
status, buf = a.execute(ping_a_b)
|
|
if status != 0:
|
|
raise Exception("ping " + a.name + "/" + a.ifname + " >> " + b.name + "/" + b.ifname)
|
|
|
|
a_b = get_ping_packet_loss(buf)
|
|
|
|
# Clear arp cache
|
|
flush_arp_cache(a)
|
|
flush_arp_cache(b)
|
|
|
|
status, buf = b.execute(ping_b_a)
|
|
if status != 0:
|
|
raise Exception("ping " + b.name + "/" + b.ifname + " >> " + a.name + "/" + a.ifname)
|
|
|
|
b_a = get_ping_packet_loss(buf)
|
|
|
|
if int(a_b[:-1]) > 40:
|
|
raise Exception("Too high packet lost: " + a_b)
|
|
|
|
if int(b_a[:-1]) > 40:
|
|
raise Exception("Too high packet lost: " + b_a)
|
|
|
|
return a_b, b_a
|
|
|
|
|
|
# iperf helpers
|
|
def get_iperf_speed(iperf_res, pattern="Mbits/sec"):
|
|
lines = iperf_res.splitlines()
|
|
sum_line = ""
|
|
last_line = ""
|
|
count = 0
|
|
res = -1
|
|
|
|
# first find last SUM line
|
|
for line in lines:
|
|
res = line.find("[SUM]")
|
|
if res != -1:
|
|
sum_line = line
|
|
|
|
# next check SUM status
|
|
if sum_line != "":
|
|
words = sum_line.split()
|
|
for word in words:
|
|
res = word.find(pattern)
|
|
if res != -1:
|
|
return words[count - 1] + " " + pattern
|
|
count = count + 1
|
|
|
|
# no SUM - one thread - find last line
|
|
for line in lines:
|
|
res = line.find(pattern)
|
|
if res != -1:
|
|
last_line = line
|
|
|
|
if last_line == "":
|
|
return "0 " + pattern
|
|
|
|
count = 0
|
|
words = last_line.split()
|
|
for word in words:
|
|
res = word.find(pattern)
|
|
if res != -1:
|
|
return words[count - 1] + " " + pattern
|
|
break;
|
|
count = count + 1
|
|
return "0 " + pattern
|
|
|
|
def ac_to_iperf_ac(qos):
|
|
if qos == "be":
|
|
qos_param = "0x00"
|
|
elif qos == "bk":
|
|
qos_param = "0x20"
|
|
elif qos == "vi":
|
|
qos_param = "0xA0"
|
|
elif qos == "vo":
|
|
qos_param = "0xE0"
|
|
else:
|
|
qos_param = "0x00"
|
|
return qos_param
|
|
|
|
def iperf_run(server, client, server_ip, client_res, server_res,
|
|
l4="udp", bw="30M", test_time="30", parallel="5",
|
|
qos="be", param=" -i 5 ", ifname=None, l3="ipv4",
|
|
port="5001", iperf="iperf"):
|
|
if ifname == None:
|
|
ifname = client.ifname
|
|
|
|
if iperf == "iperf":
|
|
iperf_server = [iperf]
|
|
elif iperf == "iperf3":
|
|
iperf_server = [iperf, "-1"]
|
|
|
|
if l3 == "ipv4":
|
|
iperf_client = [iperf, "-c", server_ip, "-p", port]
|
|
iperf_server = iperf_server + ["-p", port]
|
|
elif l3 == "ipv6":
|
|
iperf_client = [iperf, "-V", "-c", server_ip + "%" + ifname, "-p", port]
|
|
iperf_server = iperf_server + ["-V", "-p", port]
|
|
else:
|
|
return -1, -1
|
|
|
|
iperf_server = iperf_server + ["-s", "-f", "m", param]
|
|
iperf_client = iperf_client + ["-f", "m", "-t", test_time]
|
|
|
|
if parallel != "1":
|
|
iperf_client = iperf_client + ["-P", parallel]
|
|
|
|
if l4 == "udp":
|
|
if iperf != "iperf3":
|
|
iperf_server = iperf_server + ["-u"]
|
|
iperf_client = iperf_client + ["-u", "-b", bw]
|
|
|
|
if qos:
|
|
iperf_client = iperf_client + ["-Q", ac_to_iperf_ac(qos)]
|
|
|
|
flush_arp_cache(server)
|
|
flush_arp_cache(client)
|
|
|
|
server_thread = server.execute_run(iperf_server, server_res)
|
|
time.sleep(1)
|
|
client_thread = client.execute_run(iperf_client, client_res)
|
|
|
|
return server_thread, client_thread
|
|
|
|
def iperf_wait(server, client, server_thread, client_thread, timeout=None, iperf="iperf"):
|
|
client.wait_execute_complete(client_thread, timeout)
|
|
if client_thread.isAlive():
|
|
raise Exception("iperf client thread still alive")
|
|
|
|
server.wait_execute_complete(server_thread, 5)
|
|
if server_thread.isAlive():
|
|
server.execute(["killall", "-s", "INT", iperf])
|
|
time.sleep(1)
|
|
|
|
server.wait_execute_complete(server_thread, 5)
|
|
if server_thread.isAlive():
|
|
raise Execption("iperf server thread still alive")
|
|
|
|
return
|
|
|
|
def run_tp_test(server, client, l3="ipv4", iperf="iperf", l4="tcp", test_time="10", parallel="5",
|
|
qos="be", bw="30M", ifname=None, port="5001"):
|
|
client_res = []
|
|
server_res = []
|
|
|
|
server_ip = get_ip(server, l3)
|
|
time.sleep(1)
|
|
server_thread, client_thread = iperf_run(server, client, server_ip, client_res, server_res,
|
|
l3=l3, iperf=iperf, l4=l4, test_time=test_time,
|
|
parallel=parallel, qos=qos, bw=bw, ifname=ifname,
|
|
port=port)
|
|
iperf_wait(server, client, server_thread, client_thread, iperf=iperf, timeout=int(test_time) + 10)
|
|
|
|
if client_res[0] != 0:
|
|
raise Exception(iperf + " client: " + client_res[1])
|
|
if server_res[0] != 0:
|
|
raise Exception(iperf + " server: " + server_res[1])
|
|
if client_res[1] is None:
|
|
raise Exception(iperf + " client result issue")
|
|
if server_res[1] is None:
|
|
raise Exception(iperf + " server result issue")
|
|
|
|
if iperf == "iperf":
|
|
result = server_res[1]
|
|
if iperf == "iperf3":
|
|
result = client_res[1]
|
|
|
|
speed = get_iperf_speed(result)
|
|
return speed
|
|
|
|
def get_iperf_bw(bw, parallel, spacial_streams=2):
|
|
if bw == "b_only":
|
|
max_tp = 11
|
|
elif bw == "g_only" or bw == "g_only_wmm" or bw == "a_only" or bw == "a_only_wmm":
|
|
max_tp = 54
|
|
elif bw == "HT20":
|
|
max_tp = 72 * spacial_streams
|
|
elif bw == "HT40+" or bw == "HT40-":
|
|
max_tp = 150 * spacial_streams
|
|
elif bw == "VHT80":
|
|
max_tp = 433 * spacial_streams
|
|
else:
|
|
max_tp = 150
|
|
|
|
max_tp = 1.2 * max_tp
|
|
|
|
return str(int(max_tp/int(parallel))) + "M"
|