diff --git a/hosts/by-name/servo/net.nix b/hosts/by-name/servo/net.nix
index f018b79f..63882b73 100644
--- a/hosts/by-name/servo/net.nix
+++ b/hosts/by-name/servo/net.nix
@@ -3,7 +3,7 @@
let
portOpts = with lib; types.submodule {
options = {
- visibleTo.ovpn = mkOption {
+ visibleTo.ovpns = mkOption {
type = types.bool;
default = false;
description = ''
@@ -12,11 +12,81 @@ let
};
};
};
+
+ bridgedWireguardNamespace = { name, ip4, peers, privateKeyFile, vethSubnet, vpnDns }: let
+ ip = "${pkgs.iproute2}/bin/ip";
+ in-ns = "${ip} netns exec ${name}";
+ iptables = "${pkgs.iptables}/bin/iptables";
+ veth-host-ip = "${vethSubnet}.5"; # "x.y.z.5", "x.y.z.6" is legacy: some things elsewhere assume this for ovpns
+ veth-local-ip = "${vethSubnet}.6";
+ bridgePort = port: proto: ''
+ ${in-ns} ${iptables} -A PREROUTING -t nat -p ${proto} --dport ${port} -m iprange --dst-range ${ip4} \
+ -j DNAT --to-destination ${veth-host-ip}
+ '';
+ bridgeStatements = lib.foldlAttrs
+ (acc: port: portCfg: acc ++ (builtins.map (bridgePort port) portCfg.protocol))
+ []
+ (lib.filterAttrs
+ (port: portCfg: portCfg.visibleTo."${name}")
+ config.sane.ports.ports
+ )
+ ;
+ in {
+ inherit peers privateKeyFile; #< passthrough wireguard config
+ interfaceNamespace = name;
+ ips = [ "${ip4}/32" ];
+
+ preSetup = ''
+ ${ip} netns add ${name} || (test -e /run/netns/${name} && echo "${name} already exists")
+ '';
+
+ postSetup = ''
+ # DOCS:
+ # - some of this approach is described here:
+ # - iptables primer:
+ # create veth pair
+ ${ip} link add ${name}-veth-a type veth peer name ${name}-veth-b
+ ${ip} addr add ${veth-host-ip}/24 dev ${name}-veth-a
+ ${ip} link set ${name}-veth-a up
+
+ # move veth-b into the namespace
+ ${ip} link set ${name}-veth-b netns ${name}
+ ${in-ns} ip addr add ${veth-local-ip}/24 dev ${name}-veth-b
+ ${in-ns} ip link set ${name}-veth-b up
+
+ # make it so traffic originating from the host side of the veth
+ # is sent over the veth no matter its destination.
+ ${ip} rule add from ${veth-host-ip} lookup ${name} pref 50
+
+ # for traffic originating at the host veth to the WAN, use the veth as our gateway
+ # not sure if the metric 1002 matters.
+ ${ip} route add default via ${veth-local-ip} dev ${name}-veth-a proto kernel src ${veth-host-ip} metric 1002 table ${name}
+ # give the default route lower priority
+ ${ip} rule add from all lookup local pref 100
+ ${ip} rule del from all lookup local pref 0
+
+ # in order to access DNS in this netns, we need to route it to the VPN's nameservers
+ # - alternatively, we could fix DNS servers like 1.1.1.1.
+ ${in-ns} ${iptables} -A OUTPUT -t nat -p udp --dport 53 -m iprange --dst-range 127.0.0.53 \
+ -j DNAT --to-destination ${vpnDns}:53
+ '' + (lib.concatStringsSep "\n" bridgeStatements);
+
+ postShutdown = ''
+ ${in-ns} ip link del ${name}-veth-b || echo "couldn't delete ${name}-veth-b"
+ ${ip} link del ${name}-veth-a || echo "couldn't delete ${name}-veth-a"
+ ${ip} netns delete ${name} || echo "couldn't delete ${name}"
+ # restore rules/routes
+ ${ip} rule del from ${veth-host-ip} lookup ${name} pref 50 || echo "couldn't delete init -> ${name} rule"
+ ${ip} route del default via ${veth-local-ip} dev ${name}-veth-a proto kernel src ${veth-host-ip} metric 1002 table ${name} || echo "couldn't delete init -> ${name} route"
+ ${ip} rule add from all lookup local pref 0
+ ${ip} rule del from all lookup local pref 100
+ '';
+ };
in
{
options = with lib; {
sane.ports.ports = mkOption {
- # add the `visibleTo.ovpn` option
+ # add the `visibleTo.ovpns` option
type = types.attrsOf portOpts;
};
};
@@ -79,36 +149,13 @@ in
# if you `systemctl restart wireguard-wg-ovpns`, make sure to also restart any other services in `NetworkNamespacePath = .../ovpns`.
# TODO: why not create the namespace as a seperate operation (nix config for that?)
networking.wireguard.enable = true;
- networking.wireguard.interfaces.wg-ovpns = let
- ip = "${pkgs.iproute2}/bin/ip";
- in-ns = "${ip} netns exec ovpns";
- iptables = "${pkgs.iptables}/bin/iptables";
- veth-host-ip = "10.0.1.5";
- veth-local-ip = "10.0.1.6";
- vpn-ip = "185.157.162.178";
- # DNS = 46.227.67.134, 192.165.9.158, 2a07:a880:4601:10f0:cd45::1, 2001:67c:750:1:cafe:cd45::1
- vpn-dns = "46.227.67.134";
- bridgePort = port: proto: ''
- ${in-ns} ${iptables} -A PREROUTING -t nat -p ${proto} --dport ${port} -m iprange --dst-range ${vpn-ip} \
- -j DNAT --to-destination ${veth-host-ip}
- '';
- bridgeStatements = lib.foldlAttrs
- (acc: port: portCfg: acc ++ (builtins.map (bridgePort port) portCfg.protocol))
- []
- (lib.filterAttrs
- (port: portCfg: portCfg.visibleTo.ovpn)
- config.sane.ports.ports
- )
- ;
- in {
+ networking.wireguard.interfaces.wg-ovpns = bridgedWireguardNamespace {
privateKeyFile = config.sops.secrets.wg_ovpns_privkey.path;
# wg is active only in this namespace.
# run e.g. ip netns exec ovpns
# sudo ip netns exec ovpns ping www.google.com
- interfaceNamespace = "ovpns";
- ips = [
- "185.157.162.178/32"
- ];
+ name = "ovpns";
+ ip4 = "185.157.162.178";
peers = [
{
publicKey = "SkkEZDCBde22KTs/Hc7FWvDBfdOCQA4YtBEuC3n5KGs=";
@@ -126,48 +173,9 @@ in
# dynamicEndpointRefreshRestartSeconds = 5;
}
];
- preSetup = ''
- ${ip} netns add ovpns || (test -e /run/netns/ovpns && echo "ovpns already exists")
- '';
- postShutdown = ''
- ${in-ns} ip link del ovpns-veth-b || echo "couldn't delete ovpns-veth-b"
- ${ip} link del ovpns-veth-a || echo "couldn't delete ovpns-veth-a"
- ${ip} netns delete ovpns || echo "couldn't delete ovpns"
- # restore rules/routes
- ${ip} rule del from ${veth-host-ip} lookup ovpns pref 50 || echo "couldn't delete init -> ovpns rule"
- ${ip} route del default via ${veth-local-ip} dev ovpns-veth-a proto kernel src ${veth-host-ip} metric 1002 table ovpns || echo "couldn't delete init -> ovpns route"
- ${ip} rule add from all lookup local pref 0
- ${ip} rule del from all lookup local pref 100
- '';
- postSetup = ''
- # DOCS:
- # - some of this approach is described here:
- # - iptables primer:
- # create veth pair
- ${ip} link add ovpns-veth-a type veth peer name ovpns-veth-b
- ${ip} addr add ${veth-host-ip}/24 dev ovpns-veth-a
- ${ip} link set ovpns-veth-a up
- # mv veth-b into the ovpns namespace
- ${ip} link set ovpns-veth-b netns ovpns
- ${in-ns} ip addr add ${veth-local-ip}/24 dev ovpns-veth-b
- ${in-ns} ip link set ovpns-veth-b up
-
- # make it so traffic originating from the host side of the veth
- # is sent over the veth no matter its destination.
- ${ip} rule add from ${veth-host-ip} lookup ovpns pref 50
- # for traffic originating at the host veth to the WAN, use the veth as our gateway
- # not sure if the metric 1002 matters.
- ${ip} route add default via ${veth-local-ip} dev ovpns-veth-a proto kernel src ${veth-host-ip} metric 1002 table ovpns
- # give the default route lower priority
- ${ip} rule add from all lookup local pref 100
- ${ip} rule del from all lookup local pref 0
-
- # in order to access DNS in this netns, we need to route it to the VPN's nameservers
- # - alternatively, we could fix DNS servers like 1.1.1.1.
- ${in-ns} ${iptables} -A OUTPUT -t nat -p udp --dport 53 -m iprange --dst-range 127.0.0.53 \
- -j DNAT --to-destination ${vpn-dns}:53
- '' + (lib.concatStringsSep "\n" bridgeStatements);
+ vethSubnet = "10.0.1"; #< 10.0.1.x is used for forwarding traffic between the root namespace and the VPN namespace
+ vpnDns = "46.227.67.134"; #< DNS requests inside the namespace are forwarded here
};
# create a new routing table that we can use to proxy traffic out of the root namespace
diff --git a/hosts/by-name/servo/services/coturn.nix b/hosts/by-name/servo/services/coturn.nix
index 2d1e6afe..ea8d927e 100644
--- a/hosts/by-name/servo/services/coturn.nix
+++ b/hosts/by-name/servo/services/coturn.nix
@@ -55,7 +55,7 @@ in
# protocol = [ "tcp" "udp" ];
# # visibleTo.lan = true;
# # visibleTo.wan = true;
- # visibleTo.ovpn = true; # forward traffic from the VPN to the root NS
+ # visibleTo.ovpns = true; # forward traffic from the VPN to the root NS
# description = "colin-stun-turn";
# };
# "5349" = {
@@ -63,7 +63,7 @@ in
# protocol = [ "tcp" ];
# # visibleTo.lan = true;
# # visibleTo.wan = true;
- # visibleTo.ovpn = true;
+ # visibleTo.ovpns = true;
# description = "colin-stun-turn-over-tls";
# };
# }
@@ -76,7 +76,7 @@ in
# protocol = [ "tcp" "udp" ];
# # visibleTo.lan = true;
# # visibleTo.wan = true;
- # visibleTo.ovpn = true;
+ # visibleTo.ovpns = true;
# description = "colin-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
# };
# })
diff --git a/hosts/by-name/servo/services/nginx.nix b/hosts/by-name/servo/services/nginx.nix
index a61f5d64..11cee4c7 100644
--- a/hosts/by-name/servo/services/nginx.nix
+++ b/hosts/by-name/servo/services/nginx.nix
@@ -18,7 +18,7 @@ in
protocol = [ "tcp" ];
visibleTo.lan = true;
visibleTo.wan = true;
- visibleTo.ovpn = true; # so that letsencrypt can procure a cert for the mx record
+ visibleTo.ovpns = true; # so that letsencrypt can procure a cert for the mx record
description = "colin-http-uninsane.org";
};
sane.ports.ports."443" = {
diff --git a/hosts/by-name/servo/services/slskd.nix b/hosts/by-name/servo/services/slskd.nix
index 6b00995d..29c781aa 100644
--- a/hosts/by-name/servo/services/slskd.nix
+++ b/hosts/by-name/servo/services/slskd.nix
@@ -22,8 +22,7 @@
sane.ports.ports."50300" = {
protocol = [ "tcp" ];
- # not visible to WAN: i run this in a separate netns
- visibleTo.ovpn = true;
+ # visibleTo.ovpns = true; #< not needed: it runs in the ovpns namespace
description = "colin-soulseek";
};
diff --git a/hosts/by-name/servo/services/transmission.nix b/hosts/by-name/servo/services/transmission.nix
index 4672f2a6..078c1252 100644
--- a/hosts/by-name/servo/services/transmission.nix
+++ b/hosts/by-name/servo/services/transmission.nix
@@ -197,7 +197,7 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
sane.dns.zones."uninsane.org".inet.CNAME."bt" = "native";
sane.ports.ports."51413" = {
protocol = [ "tcp" "udp" ];
- visibleTo.ovpn = true;
+ # visibleTo.ovpns = true; #< not needed: it runs in the ovpns namespace
description = "colin-bittorrent";
};
}
diff --git a/hosts/by-name/servo/services/trust-dns.nix b/hosts/by-name/servo/services/trust-dns.nix
index 3c3ee507..e25d7805 100644
--- a/hosts/by-name/servo/services/trust-dns.nix
+++ b/hosts/by-name/servo/services/trust-dns.nix
@@ -11,7 +11,7 @@ in
protocol = [ "udp" "tcp" ];
visibleTo.lan = true;
visibleTo.wan = true;
- visibleTo.ovpn = true;
+ visibleTo.ovpns = true;
description = "colin-dns-hosting";
};