dissertation-3-evaluation/structure/structure.py

322 lines
9.8 KiB
Python
Raw Normal View History

2020-11-04 22:53:36 +00:00
import ipaddress
2020-11-05 17:25:23 +00:00
import json
2020-11-04 22:53:36 +00:00
import textwrap
from enum import Enum
2020-11-04 22:53:36 +00:00
import random
from typing import List, Optional, Union, Dict
class IpMethod(Enum):
Manual = 0
Management = 1
Auto4 = 2
Auto6 = 3
Dhcp4 = 4
Dhcp6 = 5
class Interface:
2020-11-05 17:25:23 +00:00
def __init__(self, method: IpMethod, rate: Optional[int] = None):
self._method: IpMethod
self._node: Optional[Node] = None
2020-11-05 17:25:23 +00:00
self._rate: Optional[int] = None
self._bridge: Optional[Bridge] = None
self._method = method
2020-11-05 17:25:23 +00:00
self._rate = rate
2020-11-04 22:53:36 +00:00
self._address: ipaddress.ip_address = None
def get_method(self):
return self._method
def set_node(self, node):
self._node = node
def get_node(self):
return self._node
def set_bridge(self, bridge):
self._bridge = bridge
def get_bridge(self):
return self._bridge
2020-11-04 22:53:36 +00:00
def set_address(self, addr: ipaddress.ip_address):
self._address = addr
def get_address(self) -> ipaddress.ip_address:
return self._address
2020-11-05 17:25:23 +00:00
def get_rate(self) -> Optional[int]:
return self._rate
def set_rate(self, rate: Optional[int]):
self._rate = rate
class Bridge:
def __init__(self, *interfaces: Interface):
self._interfaces: List[Interface] = []
self._name: str = ''
for interface in interfaces:
self._interfaces.append(interface)
interface.set_bridge(self)
2020-11-04 22:53:36 +00:00
# Generate a random class c private range by default (10.0.0.0)
self.netmask = 24
self._addr: ipaddress.ip_address = ipaddress.ip_address('10.0.0.0') + random.randint(0, 16777216)
self._network_iterator = ipaddress.ip_network('{}/{}'.format(self._addr, self.netmask), False).hosts()
def get_interfaces(self) -> List[Interface]:
return self._interfaces
def set_name(self, name: str):
self._name = name
def get_name(self) -> str:
return self._name
2020-11-04 22:53:36 +00:00
def set_netmask(self, mask: int):
self.netmask = mask
self._network_iterator = ipaddress.ip_network('{}/{}'.format(self._addr, self.netmask), False).hosts()
def get_ip_address(self) -> ipaddress.ip_address:
return next(self._network_iterator)
2020-11-05 17:25:23 +00:00
def get_network(self) -> str:
return str(ipaddress.ip_network('{}/{}'.format(self._addr, self.netmask), False))
class Node:
2020-11-04 22:53:36 +00:00
def __init__(self, interfaces: List[Interface], setup_params: Dict = None):
self._id: Union[int, None] = None
self._interfaces: List[Interface] = interfaces
self._interfaces.append(Interface(IpMethod.Management))
for interface in self._interfaces:
interface.set_node(self)
2020-11-04 22:53:36 +00:00
self.setup_params = {} if setup_params is None else setup_params
def get_interfaces(self):
return self._interfaces
def set_id(self, new_id):
self._id = new_id
def get_id(self):
return self._id
2020-11-04 22:53:36 +00:00
def get_core_count(self) -> int:
return 2
2020-11-04 22:53:36 +00:00
def get_memory_mb(self) -> int:
return 2048
2020-11-04 22:53:36 +00:00
def get_internet_setup(self) -> Optional[str]:
return None
def get_setup(self) -> Optional[str]:
return None
2020-11-05 17:25:23 +00:00
def ssh(self, *args, **kwargs):
raise RuntimeError('ssh not implemented')
2020-11-04 22:53:36 +00:00
class SpeedTestServer(Node):
2020-11-09 10:54:40 +00:00
def get_internet_setup(self) -> Optional[str]:
return textwrap.dedent('''
cloud-init status --wait || cloud-init status --long
sudo apt-get install -y iperf3
''')
2020-11-09 10:54:40 +00:00
def server(self):
self.ssh('iperf3 -s -1 -D', error_stdout=True, error_stderr=True)
2020-11-09 10:54:40 +00:00
def client(self, target, time=30):
command = 'iperf3 -c {target} -t {time} -O 5 -J'.format(target=target, time=time)
out = self.ssh(command, error_stdout=True, error_stderr=True, return_stdout=True)
return json.loads(out)
2020-11-04 22:53:36 +00:00
class RemotePortal(Node):
def __init__(self, interfaces, **kwargs):
super(RemotePortal, self).__init__(interfaces, **kwargs)
self.local_portal = None
def set_local_portal(self, local_portal):
self.local_portal = local_portal
def get_internet_setup(self) -> Optional[str]:
return textwrap.dedent('''
set -e
wget -q http://10.20.0.11/minio-client
chmod +x minio-client
./minio-client alias set s3 http://10.20.0.25:3900 {access_key} {secret_key} || \
./minio-client alias set s3 s3.us-west-001.backblazeb2.com {access_key} {secret_key}
./minio-client cp s3/dissertation/binaries/debian/{branch} mpbl3p
chmod +x mpbl3p
2020-11-05 17:25:23 +00:00
cloud-init status --wait || cloud-init status --long
sudo apt-get install -y iperf3
2020-11-04 22:53:36 +00:00
''').format(**self.setup_params)
def get_setup(self) -> Optional[str]:
return textwrap.dedent('''
set -e
2020-11-09 10:54:40 +00:00
2020-11-04 22:53:36 +00:00
cat << EOF > config.ini
[Host]
PrivateKey = INVALID
2020-11-09 10:54:40 +00:00
2020-11-04 22:53:36 +00:00
[Peer]
PublicKey = INVALID
Method = TCP
2020-11-09 10:54:40 +00:00
2020-11-04 22:53:36 +00:00
LocalHost = {local_host}
LocalPort = 1234
EOF
2020-11-09 10:54:40 +00:00
2020-11-05 17:25:23 +00:00
(nohup sudo ./mpbl3p > mpbl3p.log 2>&1 & echo $! > mpbl3p.pid)
2020-11-09 10:54:40 +00:00
2020-11-05 17:25:23 +00:00
sleep 1
sudo ip link set up nc0
sudo ip addr add 172.19.152.2/31 dev nc0
2020-11-09 10:54:40 +00:00
ip rule add from all table local priority 20
ip rule del 0
ip rule add to {local_host} dport 1234 table local priority 9
ip route flush 10
ip route add table 10 to {local_host} via 172.19.152.3 dev nc0
ip rule add to {local_host} table 10 priority 10
2020-11-05 17:25:23 +00:00
ps $(cat mpbl3p.pid)
2020-11-04 22:53:36 +00:00
''').format(
local_host=self.get_interfaces()[0].get_address(),
**self.setup_params,
)
2020-11-05 17:25:23 +00:00
def speedtest_server(self):
self.ssh('iperf3 -s -1 -D', error_stdout=True, error_stderr=True)
def speedtest_client(self, target, time=30):
command = 'iperf3 -c {target} -t {time} -O 5 -J'.format(target=target, time=time)
out = self.ssh(command, error_stdout=True, error_stderr=True, return_stdout=True)
return json.loads(out)
2020-11-04 22:53:36 +00:00
class LocalPortal(Node):
def __init__(self, wan_interfaces: List[Interface], child: Optional[Node], **kwargs):
if child is not None:
lan_interface = Interface(IpMethod.Manual)
Bridge(lan_interface, child.get_interfaces()[0])
super().__init__([*wan_interfaces, lan_interface], **kwargs)
else:
super().__init__(wan_interfaces, **kwargs)
self.remote_portal = None
def set_remote_portal(self, remote_portal):
self.remote_portal = remote_portal
def get_internet_setup(self) -> Optional[str]:
return textwrap.dedent('''
set -e
wget -q http://10.20.0.11/minio-client
chmod +x minio-client
./minio-client alias set s3 http://10.20.0.25:3900 {access_key} {secret_key} || \
./minio-client alias set s3 s3.us-west-001.backblazeb2.com {access_key} {secret_key}
./minio-client cp s3/dissertation/binaries/debian/{branch} mpbl3p
2020-11-05 17:25:23 +00:00
2020-11-04 22:53:36 +00:00
chmod +x mpbl3p
2020-11-05 17:25:23 +00:00
cloud-init status --wait || cloud-init status --long
sudo apt-get install -y iperf3
2020-11-04 22:53:36 +00:00
''').format(**self.setup_params)
def get_setup(self) -> str:
peer_string = textwrap.dedent('''
[Peer]
PublicKey = INVALID
Method = TCP
2020-11-09 10:54:40 +00:00
2020-11-04 22:53:36 +00:00
LocalHost = {local_host}
2020-11-09 10:54:40 +00:00
2020-11-04 22:53:36 +00:00
RemoteHost = {remote_host}
RemotePort = 1234
''')
peers = '\n\n'.join([peer_string.format(
local_host=x.get_address(),
remote_host=self.remote_portal.get_interfaces()[0].get_address(),
) for x in self.get_interfaces()[:-1]])
2020-11-05 17:25:23 +00:00
policy_routing_string = textwrap.dedent('''
sudo ip route flush {table_number}
sudo ip route add table {table_number} to {network} dev {device}
sudo ip rule add from {local_address} table {table_number} priority {table_number}
''')
policy_routing = '\n\n'.join([policy_routing_string.format(
table_number=i+10,
device='eth{}'.format(i),
network=iface.get_bridge().get_network(),
local_address=iface.get_address(),
) for i, iface in enumerate(self.get_interfaces()[:-1])])
2020-11-04 22:53:36 +00:00
return textwrap.dedent('''
set -e
2020-11-09 10:54:40 +00:00
2020-11-05 17:25:23 +00:00
sudo sysctl -w net.ipv4.conf.all.arp_announce=1
2020-11-09 10:54:40 +00:00
sudo sysctl -w net.ipv4.conf.all.arp_ignore=1
2020-11-05 17:25:23 +00:00
{policy_routing}
2020-11-04 22:53:36 +00:00
cat << EOF > config.ini
[Host]
PrivateKey = INVALID
{peers}
EOF
2020-11-09 10:54:40 +00:00
2020-11-05 17:25:23 +00:00
(nohup sudo ./mpbl3p > mpbl3p.log 2>&1 & echo $! > mpbl3p.pid)
2020-11-09 10:54:40 +00:00
2020-11-05 17:25:23 +00:00
sleep 1
sudo ip link set up nc0
sudo ip addr add 172.19.152.3/31 dev nc0
2020-11-09 10:54:40 +00:00
ip route flush 8
ip route add table 8 default via 172.19.152.2 dev nc0
ip rule add from {remote_host} iif {local_interface} table 8 priority 8
ip route flush 9
ip route add table 9 to {remote_host} dev {local_interface}
ip rule add to {remote_host} table 9 priority 9
2020-11-05 17:25:23 +00:00
ps $(cat mpbl3p.pid)
2020-11-09 10:54:40 +00:00
''').format(
**self.setup_params,
peers=peers,
policy_routing=policy_routing,
remote_host=self.remote_portal.get_interfaces()[0].get_address(),
local_interface='eth{}'.format(len(self.get_interfaces())-2),
)
2020-11-05 17:25:23 +00:00
def speedtest_server(self):
self.ssh('iperf3 -s -1 -D', error_stdout=True, error_stderr=True)
def speedtest_client(self, target, time=30):
command = 'iperf3 -c {target} -t {time} -O 5 -J'.format(target=target, time=time)
out = self.ssh(command, error_stdout=True, error_stderr=True, return_stdout=True)
return json.loads(out)