Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Mathias Peters committed Nov 26, 2024
1 parent 8c20d10 commit d99af93
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 120 deletions.
165 changes: 165 additions & 0 deletions xray/analyze.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import argparse
import csv
import matplotlib.pyplot as plt # type: ignore
import shlex
import subprocess
from enum import Enum
from pathlib import Path

def analyze(csv_name, pcap_name, count):
# analyze_csv(csv_name, count)
# analyze_pcap(pcap_name, count)

# plt.tight_layout()
# plt.show()
analyzer = Analyzer(csv_name, pcap_name, count)


class CsvData:
def __init__(self, csv_name):
self.indices = []
self.timestamps = []
self.min_ts = -1
self.max_ts = -1

with open(csv_name, newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=",", quotechar="|")
next(reader)
for row in reader:
self.indices.append(int(row[0]))
ts = int(row[2]) - int(row[1])
self.timestamps.append(ts)
if self.min_ts < 0 or ts < self.min_ts:
min_timestamp = ts
if self.max_ts < 0 or ts > self.max_ts:
self.max_ts = ts

class PcapData:
def __init__(self, pcap_name):
pass

class Analyzer:
def __init__(self, csv_name, pcap_name, count):
self.count = count
self.csv_data = CsvData(csv_name)
self.pcap_data = PcapData(pcap_name)

csv = [self.ordering_pie_chart, self.packet_ordering]
pcap = [self.packet_latency]

fig, ax = plt.subplots(nrows=max(len(csv), len(pcap)), ncols=2)

for i, fn in enumerate(csv):
fn(ax[i, 0])

fig.tight_layout()
plt.show()


def ordering_pie_chart(self, ax):
in_order = count_ordered(self.csv_data.indices)
reordered = len(self.csv_data.indices) - in_order
dropped = self.count - in_order - reordered
data = []
labels = []
if in_order > 0:
data.append(in_order)
labels.append(f"In order ({round((in_order/self.count) * 100, 2)}%)")
if reordered > 0:
data.append(reordered)
labels.append(f"Reordered ({round((reordered/self.count) * 100, 2)}%)")
if dropped > 0:
data.append(dropped)
labels.append(f"Dropped ({round((dropped/self.count) * 100, 2)}%)")
ax.set_title("In order/reordered/dropped")
ax.pie(data, labels=labels)

def packet_ordering(self, ax):
y_axis = [None]
x_axis = [0]
for i in range(0, self.count):
if i < len(self.csv_data.indices):
y_axis.append(self.csv_data.indices[i])
else:
y_axis.append(None)
x_axis.append(i + 1)
ax.set_title("Packet order")
# ax.xlabel("Received order")
# ax.ylabel("Packet index")
ax.plot(x_axis, y_axis)

def packet_latency(self, ax):
num_buckets = 15
bucket_size = int((self.csv_data.max_ts - self.csv_data.min_ts) / (num_buckets - 1))
buckets = []
for ts in self.csv_data.timestamps:
bucket_index = int((ts - self.csv_data.min_ts) / bucket_size)
buckets.append(self.csv_data.min_ts + (bucket_index * bucket_size))
ax.set_title("Latency")
# ax.xlabel("Latency (nanosecond)")
# ax.ylabel("Count")
ax.hist(buckets, color="blue", bins=num_buckets)


def analyze_csv(file_name, count):
# prepare data
indices = []
timestamps = []
min_timestamp = -1
max_timestamp = -1
with open(file_name, newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=",", quotechar="|")
next(reader)
for row in reader:
indices.append(int(row[0]))
ts = int(row[2]) - int(row[1])
timestamps.append(ts)
if min_timestamp < 0 or ts < min_timestamp:
min_timestamp = ts
if max_timestamp < 0 or ts > max_timestamp:
max_timestamp = ts

plt.subplot(3, 1, 1)

plt.subplot(3, 1, 2)

plt.subplot(3, 1, 3)


# This counts in-order packets by looking at series of successive packets
# the length of the sequence could be considered a number of packest in order
# however, if the first packet of the sequence is not in order, then the length of the sequence - 1 is in order
# this last step also takes care of sequences of length 1 (unless the packet is where it's supposed to be)
def count_ordered(data):
if len(data) == 0:
return 0
ordered = 0
range_good_start = data[0] == 0
range_len = 1
prev = data[0]
for i in range(1, len(data)):
if data[i] == prev + 1:
range_len += 1
else:
ordered += range_len - (0 if range_good_start else 1)
range_good_start = data[i] = i
range_len = 1
prev = data[i]
ordered += range_len - (0 if range_good_start else 1)
return ordered


def analyze_pcap(file_name, count):
# pcaps
# for each packet, show it (with timestamps)
# 1. leaving original socket
# 2. arriving at wg interface
# 3. leaving wg interface
# 4. arriving at destination socket
# with this info
# - draw funnel diagram
# - Show different distribution graphs or maybe a graph with three data points showing the span and normal distribution of those data points (apparently called box plot)
# 1. time from og socket to wg
# 2. time from wg enter to wg exit (how do I know which packet entering is which packet exiting?)
# 3. time from wg to dst socket
pass
135 changes: 16 additions & 119 deletions xray/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import matplotlib.pyplot as plt # type: ignore
import shlex
import subprocess
from analyze import analyze
from enum import Enum
from pathlib import Path

Expand All @@ -29,6 +30,7 @@ class Wireguard(Enum):
NepTUN = 1
WgGo = 2
Native = 3
BoringTun = 4

def from_str(s):
if s is None or s.lower() == "neptun":
Expand All @@ -37,6 +39,8 @@ def from_str(s):
return Wireguard.WgGo
elif s is not None and s.lower() == "native":
return Wireguard.Native
elif s is not None and s.lower() == "boringtun":
return Wireguard.BoringTun
else:
raise Exception(f"{s} is not a valid wireguard type")

Expand All @@ -51,6 +55,8 @@ def setup_wireguard(wg, build_neptun):
.decode("utf-8")
)
run_command(f"sudo {wggo} {WG_IFC_NAME}")
elif wg == Wireguard.BoringTun:
run_command(f"sudo ../target/release/neptun-cli {WG_IFC_NAME}")
else:
if build_neptun:
run_command(f"cargo run --release -p neptun-cli -- {WG_IFC_NAME}")
Expand Down Expand Up @@ -85,115 +91,6 @@ def destroy_wireguard(wg):
run_command(f"sudo ip link delete {WG_IFC_NAME}")


def do_analysis(csv_name, pcap_name, count):
analyze_csv(csv_name, count)
analyze_pcap(pcap_name, count)
plt.tight_layout()
# plt.show()


def analyze_csv(file_name, count):
# prepare data
indices = []
timestamps = []
min_timestamp = -1
max_timestamp = -1
with open(file_name, newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=",", quotechar="|")
next(reader)
for row in reader:
indices.append(int(row[0]))
ts = int(row[2]) - int(row[1])
timestamps.append(ts)
if min_timestamp < 0 or ts < min_timestamp:
min_timestamp = ts
if max_timestamp < 0 or ts > max_timestamp:
max_timestamp = ts

plt.subplot(3, 1, 1)
in_order = count_ordered(indices)
reordered = len(indices) - in_order
dropped = count - in_order - reordered
data = []
labels = []
if in_order > 0:
data.append(in_order)
labels.append(f"In order ({round((in_order/count) * 100, 2)}%)")
if reordered > 0:
data.append(reordered)
labels.append(f"Reordered ({round((reordered/count) * 100, 2)}%)")
if dropped > 0:
data.append(dropped)
labels.append(f"Dropped ({round((dropped/count) * 100, 2)}%)")
plt.title("In order/reordered/dropped")
plt.pie(data, labels=labels)

plt.subplot(3, 1, 2)
y_axis = [None]
x_axis = [0]
for i in range(0, count):
if i < len(indices):
y_axis.append(indices[i])
else:
y_axis.append(None)
x_axis.append(i + 1)
plt.title("Packet order")
plt.xlabel("Received order")
plt.ylabel("Packet index")
plt.plot(x_axis, y_axis)

plt.subplot(3, 1, 3)
num_buckets = 15
bucket_size = int((max_timestamp - min_timestamp) / (num_buckets - 1))
buckets = []
for ts in timestamps:
bucket_index = int((ts - min_timestamp) / bucket_size)
buckets.append(min_timestamp + (bucket_index * bucket_size))
plt.title("Latency")
plt.xlabel("Latency (nanosecond)")
plt.ylabel("Count")
plt.hist(buckets, color="blue", bins=num_buckets)


# This counts in-order packets by looking at series of successive packets
# the length of the sequence could be considered a number of packest in order
# however, if the first packet of the sequence is not in order, then the length of the sequence - 1 is in order
# this last step also takes care of sequences of length 1 (unless the packet is where it's supposed to be)
def count_ordered(data):
if len(data) == 0:
return 0
ordered = 0
range_good_start = data[0] == 0
range_len = 1
prev = data[0]
for i in range(1, len(data)):
if data[i] == prev + 1:
range_len += 1
else:
ordered += range_len - (0 if range_good_start else 1)
range_good_start = data[i] = i
range_len = 1
prev = data[i]
ordered += range_len - (0 if range_good_start else 1)
return ordered


def analyze_pcap(file_name, count):
# pcaps
# for each packet, show it (with timestamps)
# 1. leaving original socket
# 2. arriving at wg interface
# 3. leaving wg interface
# 4. arriving at destination socket
# with this info
# - draw funnel diagram
# - Show different distribution graphs or maybe a graph with three data points showing the span and normal distribution of those data points (apparently called box plot)
# 1. time from og socket to wg
# 2. time from wg enter to wg exit (how do I know which packet entering is which packet exiting?)
# 3. time from wg to dst socket
pass


def main():
Path("results/").mkdir(parents=True, exist_ok=True)

Expand All @@ -214,18 +111,18 @@ def main():
assert count > 0, f"Count must be at least one, but got {count}"
build_neptun = args.nobuild is None

setup_wireguard(wg, build_neptun)
tcpdump = start_tcpdump(get_pcap_name(wg.name, test_type))
# setup_wireguard(wg, build_neptun)
# tcpdump = start_tcpdump(get_pcap_name(wg.name, test_type))

try:
run_xray(wg.name, test_type, count)
finally:
stop_tcpdump(tcpdump)
destroy_wireguard(wg)
# try:
# run_xray(wg.name, test_type, count)
# finally:
# stop_tcpdump(tcpdump)
# destroy_wireguard(wg)

do_analysis(
get_csv_name(wg.name, test_type), get_pcap_name(wg.name, test_type), count
)
analyze(
get_csv_name(wg.name, test_type), get_pcap_name(wg.name, test_type), count
)


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion xray/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ pub async fn configure_wg(
}

match adapter_type {
"native" => configure_native_wg(wg_name, wg_keys, peer_keys, wg_port),
"native" | "boringtun" => configure_native_wg(wg_name, wg_keys, peer_keys, wg_port),
"wggo" | "neptun" => configure_userspace_wg(wg_name, wg_keys, peer_keys, wg_port).await,
_ => panic!("Unknown adapter type {adapter_type}"),
}
Expand Down

0 comments on commit d99af93

Please sign in to comment.