From 150a052211f4e62efc371cb9c2075c08e2c6bc57 Mon Sep 17 00:00:00 2001 From: UpYoursMicrosoft Date: Tue, 27 Feb 2024 00:34:28 -0800 Subject: [PATCH] support moving interfaces into default netns Closes #23. --- README.md | 4 ++-- pyproject.toml | 2 +- wgnetns/main.py | 26 ++++++++++++++------------ 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 1abccf9..92ad8e9 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,9 @@ Minimal JSON example: Full YAML example: ~~~ yaml -# name of the network namespace +# name of the network namespace where the interface is moved into, if null the default namespace is used name: ns-example -# namespace where the interface is initialized, defaults to the main/default namespace +# namespace where the interface is initialized, if null the default namespace is used base_netns: null # if false, the netns itself won't be created or deleted, just the interfaces inside it managed: true diff --git a/pyproject.toml b/pyproject.toml index 131dc54..15190c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wgnetns" -version = "2.3.1" +version = "2.3.2" description = "wg-quick for network namespaces" authors = ["dadevel "] license = "MIT" diff --git a/wgnetns/main.py b/wgnetns/main.py index e847112..e31692d 100755 --- a/wgnetns/main.py +++ b/wgnetns/main.py @@ -15,6 +15,7 @@ try: YAML_SUPPORTED = True except ModuleNotFoundError: YAML_SUPPORTED = False + yaml = NotImplemented WIREGUARD_DIR = Path('/etc/wireguard') NETNS_DIR = Path('/etc/netns') @@ -172,17 +173,17 @@ class Interface: if self.private_key: wg('set', self.name, 'private-key', '/dev/stdin', stdin=self.private_key, netns=self.base_netns) - def _assign_namespace(self, namespace: str) -> None: - ip('link', 'set', self.name, 'netns', namespace, netns=self.base_netns) + def _assign_namespace(self, namespace: str|None) -> None: + ip('link', 'set', self.name, 'netns', namespace if namespace else '1', netns=self.base_netns) - def _assign_addresses(self, namespace: str) -> None: + def _assign_addresses(self, namespace: str|None) -> None: for address in self.address: ip('-6' if ':' in address else '-4', 'address', 'add', address, 'dev', self.name, netns=namespace) - def _bring_up(self, namespace: str) -> None: + def _bring_up(self, namespace: str|None) -> None: ip('link', 'set', 'dev', self.name, 'mtu', self.mtu, 'up', netns=namespace) - def _create_routes(self, namespace: str): + def _create_routes(self, namespace: str|None): for peer in self.peers: networks = peer.routes if peer.routes is not None else peer.allowed_ips for network in networks: @@ -217,8 +218,8 @@ class ScriptletItem: host_namespace = bool(data.pop('host_namespace', None)) return cls(**data, host_namespace=host_namespace) - def run(self, netns: str): - if self.host_namespace: + def run(self, netns: str|None): + if self.host_namespace or not netns: host_eval(self.command) else: ip_netns_eval(self.command, netns=netns) @@ -247,14 +248,14 @@ class Scriptlet: item = ScriptletItem.from_str(data) return cls(items=[item]) - def run(self, netns: str): + def run(self, netns: str|None): for item in self.items: item.run(netns=netns) @dataclasses.dataclass class Namespace: - name: str + name: str|None pre_up: Optional[Scriptlet] = None post_up: Optional[Scriptlet] = None pre_down: Optional[Scriptlet] = None @@ -302,7 +303,7 @@ class Namespace: return cls(**data, **scriptlets, interfaces=interfaces) # type: ignore def setup(self) -> Namespace: - if self.managed: + if self.managed and self.name: self._create() self._write_resolvconf() if self.pre_up: @@ -338,6 +339,7 @@ class Namespace: @property def _resolvconf_path(self) -> Path: + assert self.name return NETNS_DIR/self.name/'resolv.conf' def _write_resolvconf(self) -> None: @@ -370,8 +372,8 @@ def ip_netns_exec(*args, netns: str, stdin: str|None = None, check=True, capture return ip('netns', 'exec', netns, *args, stdin=stdin, check=check, capture=capture) -def ip(*args, stdin: str|None = None, netns=None, check=True, capture=False) -> str: - return run('ip', *([] if netns is None else ['-n', netns]), *args, stdin=stdin, check=check, capture=capture) +def ip(*args, stdin: str|None = None, netns: str|None =None, check=True, capture=False) -> str: + return run('ip', *(['-n', netns] if netns else []), *args, stdin=stdin, check=check, capture=capture) def host_eval(*args, stdin: str|None = None, check=True, capture=False) -> str: