Skip to content

Commit 9cfe03f

Browse files
tomribbenshoh
authored andcommitted
Fix: Remove hardcoded 172.0.0.0/8 range from use to comply with RFC1918
Previously, 172.0.0.0/8 range was hardcoded to be used as the pool for which to assign IP addresses out of. As this was in violation of RFC1918, this needed to change. As this meant reworking the code anyway, it was changed so the range is configurable.
1 parent 7c742b0 commit 9cfe03f

File tree

6 files changed

+82
-16
lines changed

6 files changed

+82
-16
lines changed

firecracker/microvm.py

+7-9
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class MicroVM:
7171
config_file_path: Optional[Path] = None
7272
drives: List[Drive]
7373
init_timeout: float
74+
guest_ip: Optional[str]
75+
host_ip: Optional[str]
7476

7577
_unix_socket: Server
7678

@@ -97,28 +99,24 @@ def vsock_path(self):
9799
else:
98100
return f"{VSOCK_PATH}"
99101

100-
@property
101-
def guest_ip(self):
102-
return f"172.{self.vm_id // 256}.{self.vm_id % 256}.2"
103-
104-
@property
105-
def host_ip(self):
106-
return f"172.{self.vm_id // 256}.{self.vm_id % 256}.1"
107-
108102
def __init__(
109103
self,
110104
vm_id: int,
111105
firecracker_bin_path: str,
112106
use_jailer: bool = True,
113107
jailer_bin_path: Optional[str] = None,
114108
init_timeout: float = 5.0,
109+
guest_ip: Optional[str] = None,
110+
host_ip: Optional[str] = None,
115111
):
116112
self.vm_id = vm_id
117113
self.use_jailer = use_jailer
118114
self.firecracker_bin_path = firecracker_bin_path
119115
self.jailer_bin_path = jailer_bin_path
120116
self.drives = []
121117
self.init_timeout = init_timeout
118+
self.guest_ip = guest_ip
119+
self.host_ip = host_ip
122120

123121
def to_dict(self):
124122
return {
@@ -316,7 +314,7 @@ async def create_network_interface(self, interface: str = "eth0") -> str:
316314
self.network_tap = host_dev_name
317315

318316
system(f"ip tuntap add {host_dev_name} mode tap")
319-
system(f"ip addr add {self.host_ip}/24 dev {host_dev_name}")
317+
system(f"ip addr add {self.host_ip} dev {host_dev_name}")
320318
system(f"ip link set {host_dev_name} up")
321319
system('sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"')
322320
# TODO: Don't fill iptables with duplicate rules; purge rules on delete

runtimes/aleph-alpine-3.13-python/init1.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,11 @@ def setup_network(
123123
system("ip addr add 127.0.0.1/8 dev lo brd + scope host")
124124
system("ip addr add ::1/128 dev lo")
125125
system("ip link set lo up")
126-
system(f"ip addr add {ip}/24 dev eth0")
126+
system(f"ip addr add {ip} dev eth0")
127127
system("ip link set eth0 up")
128128

129129
if route:
130-
system(f"ip route add default via {route} dev eth0")
130+
system(f"ip route add default via {route.split('/')[0]} dev eth0")
131131
logger.debug("IP and route set")
132132
else:
133133
logger.warning("IP set with no network route")

vm_supervisor/conf.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,22 @@ class Settings(BaseSettings):
7272
REUSE_TIMEOUT: float = 60 * 60.0
7373
WATCH_FOR_MESSAGES = True
7474
WATCH_FOR_UPDATES = True
75-
NETWORK_INTERFACE = "eth0"
76-
DNS_RESOLUTION: Optional[DnsResolver] = DnsResolver.resolv_conf
77-
DNS_NAMESERVERS: Optional[List[str]] = None
7875

7976
API_SERVER = "https://official.aleph.cloud"
8077
USE_JAILER = True
8178
# System logs make boot ~2x slower
8279
PRINT_SYSTEM_LOGS = False
8380
DEBUG_ASYNCIO = False
81+
8482
# Networking does not work inside Docker/Podman
8583
ALLOW_VM_NETWORKING = True
84+
NETWORK_INTERFACE = "eth0"
85+
IPV4_ADDRESS_POOL = "172.16.0.0/12"
86+
IPV4_NETWORK_SIZE = 24
87+
88+
DNS_RESOLUTION: Optional[DnsResolver] = DnsResolver.resolv_conf
89+
DNS_NAMESERVERS: Optional[List[str]] = None
90+
8691
FIRECRACKER_PATH = "/opt/firecracker/firecracker"
8792
JAILER_PATH = "/opt/firecracker/jailer"
8893
LINUX_PATH = "/opt/firecracker/vmlinux.bin"

vm_supervisor/pool.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ def get_unique_vm_id(self) -> int:
4444
This identifier is used to name the network interface and in the IPv4 range
4545
dedicated to the VM.
4646
"""
47+
_, network_range = settings.IPV4_ADDRESS_POOL.split("/")
48+
available_bits = int(network_range) - settings.IPV4_NETWORK_SIZE
4749
self.counter += 1
48-
if self.counter < 255**2:
50+
if self.counter < 2**available_bits:
4951
# In common cases, use the counter itself as the vm_id. This makes it
5052
# easier to debug.
5153
return self.counter

vm_supervisor/utils.py

+51-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import logging
44
from base64 import b32decode, b16encode
55
from dataclasses import is_dataclass, asdict as dataclass_as_dict
6-
from typing import Any, Optional, Coroutine
6+
from typing import Any, Optional, Coroutine, Tuple, Iterable
77

88
import aiodns
99

@@ -51,3 +51,53 @@ async def run_and_log_exception(coro: Coroutine):
5151
def create_task_log_exceptions(coro: Coroutine, *, name=None):
5252
"""Ensure that exceptions running in coroutines are logged."""
5353
return asyncio.create_task(run_and_log_exception(coro), name=name)
54+
55+
56+
def ipstr_to_int(ip_string: str) -> Tuple[int, int]:
57+
"""Convert an IP address string with subnet mask to an integer
58+
representation of the IP and the mask separately.
59+
"""
60+
ip, mask = ip_string.split("/")
61+
ip_int = sum(
62+
int(octet) * 256**idx for idx, octet in enumerate(reversed(ip.split(".")))
63+
)
64+
return ip_int, int(mask)
65+
66+
67+
def int_to_ipstr(ip_int: int, mask: int) -> str:
68+
"""Converts an integer representation of an IP address and a subnetmask
69+
and turns it into a string representation
70+
"""
71+
ip_integers: Iterable[int] = (
72+
(ip_int >> (8 * i)) & 0xFF for i in reversed(range(4))
73+
)
74+
ip_string: str = ".".join(str(i) for i in ip_integers)
75+
return f"{ip_string}/{mask}"
76+
77+
78+
def get_ip_addresses(
79+
vm_id: int, address_pool: str, ip_network_size: int
80+
) -> Tuple[str, str]:
81+
"""Calculates the host and guest ip from vm_id and returns it as their string representations with subnetmask"""
82+
network_pool, pool_size = ipstr_to_int(address_pool)
83+
pool_netmask = 0xFFFFFFFF << 32 - pool_size
84+
network_part = vm_id << 32 - ip_network_size
85+
network_part_mask = 2 ** (ip_network_size - pool_size) - 1 << 32 - ip_network_size
86+
host = 1
87+
guest = 2
88+
hosts_mask = 2 ** (32 - ip_network_size) - 1
89+
90+
host_ip = (
91+
(network_pool & pool_netmask)
92+
| (network_part & network_part_mask)
93+
| (host & hosts_mask)
94+
)
95+
guest_ip = (
96+
(network_pool & pool_netmask)
97+
| (network_part & network_part_mask)
98+
| (guest & hosts_mask)
99+
)
100+
101+
return int_to_ipstr(host_ip, ip_network_size), int_to_ipstr(
102+
guest_ip, ip_network_size
103+
)

vm_supervisor/vm/firecracker_microvm.py

+11
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
import msgpack
1414

15+
from ..utils import get_ip_addresses
16+
1517
try:
1618
import psutil as psutil
1719
except ImportError:
@@ -211,6 +213,8 @@ class AlephFirecrackerVM:
211213
hardware_resources: MachineResources
212214
fvm: Optional[MicroVM] = None
213215
guest_api_process: Optional[Process] = None
216+
host_ip: Optional[str] = None
217+
guest_ip: Optional[str] = None
214218

215219
def __init__(
216220
self,
@@ -260,12 +264,19 @@ def to_dict(self):
260264
async def setup(self):
261265
logger.debug("setup started")
262266
await setfacl()
267+
host_ip, guest_ip = get_ip_addresses(
268+
self.vm_id,
269+
address_pool=settings.IPV4_ADDRESS_POOL,
270+
ip_network_size=settings.IPV4_NETWORK_SIZE,
271+
)
263272
fvm = MicroVM(
264273
vm_id=self.vm_id,
265274
firecracker_bin_path=settings.FIRECRACKER_PATH,
266275
use_jailer=settings.USE_JAILER,
267276
jailer_bin_path=settings.JAILER_PATH,
268277
init_timeout=settings.INIT_TIMEOUT,
278+
host_ip=host_ip,
279+
guest_ip=guest_ip,
269280
)
270281
fvm.prepare_jailer()
271282

0 commit comments

Comments
 (0)