Switched to drop-ins for routes
This commit is contained in:
parent
fc44f65e07
commit
c0e692048a
@ -50,6 +50,7 @@ class Config:
|
||||
# This is well below what systemd-networkd will use by default, so these rules will take precedence.
|
||||
# Access through the non-private property for auto-incrementing!!!
|
||||
_routingpolicyrule_prio = 16000
|
||||
_route_id = 0
|
||||
|
||||
@property
|
||||
def routingpolicyrule_prio(self) -> int:
|
||||
@ -57,6 +58,12 @@ class Config:
|
||||
self._routingpolicyrule_prio += 1
|
||||
return val
|
||||
|
||||
@property
|
||||
def route_id(self) -> int:
|
||||
val = self._route_id
|
||||
self._route_id += 1
|
||||
return val
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.vpnd_connection_name = os.environ.get("VPND_CONNECTION_NAME")
|
||||
@ -113,46 +120,56 @@ class Config:
|
||||
)
|
||||
)
|
||||
|
||||
def write_route(self, stream: TextIOBase, net: ipaddress.IPv4Network):
|
||||
def write_route(self, dir: Path, net: ipaddress.IPv4Network):
|
||||
"""Write a systemd-networkd route config for the given network to the given stream."""
|
||||
route_id = self.route_id
|
||||
if self.vpnd_enforce_split_tunnel:
|
||||
if self.vpn_gateway in net:
|
||||
# Refuse to create a policy rule that would block the uplink.
|
||||
# this is probably a global route, which we will already have.
|
||||
return
|
||||
with (dir / f"inclusion-{route_id}.conf").open("w") as stream:
|
||||
stream.writelines(
|
||||
[
|
||||
"[RoutingPolicyRule]\n",
|
||||
f"To={net}\n",
|
||||
f"Table={self.split_enforcement_table}\n"
|
||||
f"Priority={self.routingpolicyrule_prio}\n",
|
||||
]
|
||||
)
|
||||
else:
|
||||
with (dir / f"route-{route_id}.conf").open("w") as stream:
|
||||
stream.writelines(
|
||||
[
|
||||
"[Route]\n",
|
||||
"Gateway=0.0.0.0\n",
|
||||
f"To={net}\n",
|
||||
# systemd-networkd defaults to a route metric of 1024. We set a very low metric to shadow any routes that aren't meant
|
||||
# to explicitly override this, but still allows explicit overrides if desired.
|
||||
"Metric=64\n",
|
||||
]
|
||||
)
|
||||
|
||||
def write_exclusion(self, dir: Path, net: ipaddress.IPv4Network):
|
||||
"""Write a routing policy rule to exclude the given network from our routing table."""
|
||||
if not self.vpnd_enforce_split_tunnel:
|
||||
return
|
||||
route_id = self.route_id
|
||||
with (dir / f"exclusion-{route_id}.conf").open("w") as stream:
|
||||
stream.writelines(
|
||||
[
|
||||
"[RoutingPolicyRule]\n",
|
||||
f"To={net}\n",
|
||||
f"Table={self.split_enforcement_table}\n"
|
||||
f"Table=main\n",
|
||||
f"Priority={self.routingpolicyrule_prio}\n",
|
||||
]
|
||||
)
|
||||
else:
|
||||
stream.writelines(
|
||||
[
|
||||
"[Route]\n",
|
||||
"Gateway=0.0.0.0\n",
|
||||
f"To={net}\n",
|
||||
# systemd-networkd defaults to a route metric of 1024. We set a very low metric to shadow any routes that aren't meant
|
||||
# to explicitly override this, but still allows explicit overrides if desired.
|
||||
"Metric=64\n",
|
||||
]
|
||||
)
|
||||
|
||||
def write_exclusion(self, stream: TextIOBase, net: ipaddress.IPv4Network):
|
||||
"""Write a routing policy rule to exclude the given network from our routing table."""
|
||||
if not self.vpnd_enforce_split_tunnel:
|
||||
return
|
||||
stream.writelines(
|
||||
[
|
||||
"[RoutingPolicyRule]\n",
|
||||
f"To={net}\n",
|
||||
f"Table=main\n",
|
||||
f"Priority={self.routingpolicyrule_prio}\n",
|
||||
]
|
||||
)
|
||||
|
||||
def write_config(self, stream: TextIOBase):
|
||||
def write_config(self, path: Path):
|
||||
"""Generate a transient systemd-networkd config file."""
|
||||
# This file will not enforce split-tunneling restrictions, and will not shadow existing routes.
|
||||
# Any route _inclusions_ will be added as [Route]s, while _exclusions_ will be ignored.
|
||||
stream = path.open("w")
|
||||
if not stream.writable():
|
||||
raise ValueError("Stream is not writable")
|
||||
stream.writelines(
|
||||
@ -182,10 +199,15 @@ class Config:
|
||||
f"Priority={self.routingpolicyrule_prio}\n",
|
||||
]
|
||||
)
|
||||
dir = path.with_suffix(".d")
|
||||
if not dir.exists():
|
||||
dir.mkdir()
|
||||
for net in self.split_tunnel_inclusions:
|
||||
self.write_route(dir, net)
|
||||
if self.vpnd_enforce_split_tunnel:
|
||||
# configure exclusions after inclusions. inclusions don't make sense without this, since they'd just be captured by the default.
|
||||
for net in self.split_tunnel_exclusions:
|
||||
self.write_exclusion(stream, net)
|
||||
self.write_exclusion(dir, net)
|
||||
# Set a final catch-all rule (which should still have significantly lower priority than any auto-numbered rules) which will redirect
|
||||
# anything not intended for the gateway IP itself to our routing table.
|
||||
stream.writelines(
|
||||
@ -197,6 +219,7 @@ class Config:
|
||||
f"Priority={self.routingpolicyrule_prio}\n",
|
||||
]
|
||||
)
|
||||
stream.close()
|
||||
|
||||
|
||||
async def main():
|
||||
@ -224,8 +247,7 @@ async def configure_with_networkd():
|
||||
|
||||
if config.reason in {Reason.CONNECT, Reason.ATTEMPT_RECONNECT, Reason.RECONNECT}:
|
||||
# only write out the file if the reason indicates a new connection.
|
||||
with open(Path("/run/systemd/network") / filename, "w") as f:
|
||||
config.write_config(f)
|
||||
config.write_config(Path("/run/systemd/network") / filename)
|
||||
elif config.reason == Reason.PRE_INIT:
|
||||
# idk what this does, but the script does it, so we will too.
|
||||
try:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user