extra:
{ config, lib, pkgs, ... }:
let
chromecastIP = "192.168.86.190";
iptables = "iptables -A nixos-fw";
ipr = "${pkgs.iproute}/bin/ip";
hasVPN = builtins.hasAttr "services" config.services.openvpn && config.services.openvpn.services.pia != null;
writeBash = extra.util.writeBash;
transmission-dir = "/zbig/torrents";
download-dir = "${transmission-dir}/Downloads";
openCloseTCP = op: dev: port: ''
ip46tables -${op} nixos-fw -i ${dev} -p tcp --dport ${toString port} -j nixos-fw-accept ${if op == "D" then "|| true" else ""}
'';
openTCP = dev: port: openCloseTCP "A" dev port;
closeTCP = dev: port: openCloseTCP "D" dev port;
vpn = {
name = "pia";
table = "300";
credfile = pkgs.writeText "vpncreds" ''
${extra.private.vpncred.user}
${extra.private.vpncred.pass}
'';
routeup = writeBash "openvpn-pia-routeup" ''
${pkgs.iproute}/bin/ip route add default via $route_vpn_gateway dev $dev metric 1 table ${vpn.table}
exit 0
'';
# up = writeBash "openvpn-pia-preup" config.services.openvpn.servers.pia.up;
# down = writeBash "openvpn-pia-stop" config.services.openvpn.servers.pia.down;
};
ports = {
synergy = 24800;
lightning = 9735;
lightningt = 9736;
dns = 53;
http = 80;
wireguard = 51820;
inherit (extra.private) notify-port;
};
firewallRules = [
"nixos-fw -s 10.100.0.1/24,192.168.86.1/24 -p tcp --dport 8080 -j nixos-fw-accept" # dev
"nixos-fw -s 192.168.122.218 -p udp --dport 137 -j nixos-fw-accept"
"nixos-fw -s 192.168.122.218 -p udp --dport 138 -j nixos-fw-accept"
"nixos-fw -s 192.168.122.218 -p tcp --dport 139 -j nixos-fw-accept"
"nixos-fw -s 192.168.122.218 -p tcp --dport 445 -j nixos-fw-accept"
]
++ lib.optional hasVPN [
"OUTPUT -t mangle -m cgroup --cgroup 11 -j MARK --set-mark 11"
"POSTROUTING -t nat -m cgroup --cgroup 11 -o tun0 -j MASQUERADE"
];
addRule = rule: "iptables -A ${rule}";
rmRule = rule: "iptables -D ${rule} || true";
extraCommands = lib.concatStringsSep "\n" (map addRule firewallRules);
extraStopCommands = lib.concatStringsSep "\n" (map rmRule firewallRules);
in
{
networking.hostId = extra.machine.hostId;
#networking.firewall.trustedInterfaces = ["wg0"];
networking.firewall.allowedTCPPorts = with ports; [ lightning lightningt synergy http ];
networking.firewall.allowedUDPPorts = [ ports.dns ports.wireguard ];
networking.nat.enable = true;
networking.nat.externalInterface = "eth0";
networking.nat.internalInterfaces = [ "wg0" ];
networking.wireguard.interfaces = {
# "wg0" is the network interface name. You can name the interface arbitrarily.
wg0 = {
# Determines the IP address and subnet of the server's end of the tunnel interface.
ips = [ "10.100.0.1/24" ];
listenPort = ports.wireguard;
postSetup = ''
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o enp30s0 -j MASQUERADE
'';
postShutdown = ''
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o enp30s0 -j MASQUERADE
'';
privateKeyFile = "/home/jb55/.wg/private";
peers = [
{ publicKey = "wcoun9+1GX4awQF2Yd0WbsQ6RKHE9SsOsYv3qR7mbB0="; # quiver
allowedIPs = [ "10.100.0.2/32" ];
}
{ publicKey = "vIh3IQgP92OhHaC9XBiJVDLlrs3GVcR6hlXaapjTiA0="; # phone
allowedIPs = [ "10.100.0.3/32" ];
}
{ publicKey = "Dp8Df75X8Kh9gd33e+CWyyhOvT4mT0X9ToPwBUEBU1k="; # macos
allowedIPs = [ "10.100.0.4/32" ];
}
];
};
rcx0 = {
# Determines the IP address and subnet of the server's end of the tunnel interface.
ips = [ "10.200.0.2/32" ];
privateKeyFile = "/home/jb55/.wg/rcx/private";
peers = [
{ publicKey = "wC+mEE9/PJDuIfr7DFZWnM8HbQz5fSOFHmmzQRxULzM="; # server
allowedIPs = [ "10.200.0.1/32" ];
endpoint = "159.89.143.225:53";
persistentKeepalive = 25;
}
{ publicKey = "vrKDdLPXAXAPP7XuuQl/dsD+z3dV/Z0uhgc+yjJ4Nys="; # winvm
allowedIPs = [ "10.200.0.3/32" ];
endpoint = "192.168.122.218:51820";
persistentKeepalive = 25;
}
];
};
};
services.transmission = {
enable = true;
home = transmission-dir;
settings = {
incomplete-dir-enable = true;
rpc-whitelist = "127.0.0.1";
};
port = 14325;
};
services.plex = {
enable = true;
group = "transmission";
openFirewall = true;
};
services.xinetd.enable = true;
services.xinetd.services =
[
{ name = "gopher";
port = 70;
server = "${pkgs.gophernicus}/bin/in.gophernicus";
serverArgs = "-nf -r /var/gopher";
extraConfig = ''
disable = no
env = PATH=${pkgs.coreutils}/bin:${pkgs.curl}/bin
passenv = PATH
'';
}
];
services.nginx.httpConfig = lib.mkIf config.services.transmission.enable ''
server {
listen 80;
listen ${extra.machine.ztip}:80;
listen 192.168.86.26;
# server names for this server.
# any requests that come in that match any these names will use the proxy.
server_name plex.jb55.com plez.jb55.com media.home plex.home;
# this is where everything cool happens (you probably don't need to change anything here):
location / {
# if a request to / comes in, 301 redirect to the main plex page.
# but only if it doesn't contain the X-Plex-Device-Name header
# this fixes a bug where you get permission issues when accessing the web dashboard
if ($http_x_plex_device_name = \'\') {
rewrite ^/$ http://$http_host/web/index.html;
}
# set some headers and proxy stuff.
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $server_addr;
proxy_set_header Referer $server_addr;
proxy_set_header Origin $server_addr;
# plex headers
proxy_set_header X-Plex-Client-Identifier $http_x_plex_client_identifier;
proxy_set_header X-Plex-Device $http_x_plex_device;
proxy_set_header X-Plex-Device-Name $http_x_plex_device_name;
proxy_set_header X-Plex-Platform $http_x_plex_platform;
proxy_set_header X-Plex-Platform-Version $http_x_plex_platform_version;
proxy_set_header X-Plex-Product $http_x_plex_product;
proxy_set_header X-Plex-Token $http_x_plex_token;
proxy_set_header X-Plex-Version $http_x_plex_version;
proxy_set_header X-Plex-Nocache $http_x_plex_nocache;
proxy_set_header X-Plex-Provides $http_x_plex_provides;
proxy_set_header X-Plex-Device-Vendor $http_x_plex_device_vendor;
proxy_set_header X-Plex-Model $http_x_plex_model;
# Websockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Buffering off send to the client as soon as the data is received from Plex.
proxy_redirect off;
proxy_buffering off;
client_max_body_size 100M;
send_timeout 100m;
# include Host header
proxy_set_header Host $host;
# proxy request to plex server
proxy_pass http://plex.jb55.com:32400/;
}
}
server {
listen 80;
listen ${extra.machine.ztip}:80;
listen 192.168.86.26;
server_name torrents.jb55.com torrentz.jb55.com torrents.home torrent.home;
location = /download {
return 301 " /download/";
}
location /download/ {
alias ${download-dir}/;
autoindex on;
}
location / {
proxy_read_timeout 300;
proxy_pass_header X-Transmission-Session-Id;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:${toString config.services.transmission.port}/transmission/web/;
}
location /rpc {
proxy_pass http://127.0.0.1:${toString config.services.transmission.port}/transmission/rpc;
}
location /upload {
proxy_pass http://127.0.0.1:${toString config.services.transmission.port}/transmission/upload;
}
}
'';
systemd.services.transmission.requires = [ "openvpn-pia.service" ];
systemd.services.transmission.after = [ "openvpn-pia.service" ];
systemd.services.transmission.serviceConfig.User = lib.mkForce "root";
systemd.services.transmission.serviceConfig.ExecStart = lib.mkForce (
writeBash "start-transmission-under-vpn" ''
exec ${pkgs.libcgroup}/bin/cgexec --sticky -g net_cls:pia \
${pkgs.sudo}/bin/sudo -u transmission \
${pkgs.transmission}/bin/transmission-daemon \
-f \
--port ${toString config.services.transmission.port};
''
);
networking.firewall.extraCommands =
# openvpn stuff, we only want to do this once
(if hasVPN then ''
# create separate routing table
${ipr} rule add fwmark 11 table ${vpn.table}
# add fallback route that blocks traffic, should the VPN go down
${ipr} route add blackhole default metric 2 table ${vpn.table}
'' else "") + extraCommands;
networking.firewall.extraStopCommands =
(if hasVPN then ''
# remove separate routing table
${ipr} rule del fwmark 11 table ${vpn.table} || true
${ipr} route del blackhole default metric 2 table ${vpn.table} || true
'' else "") + extraStopCommands;
users.extraGroups.vpn-pia.members = [ "jb55" "transmission" ];
users.extraGroups.tor.members = [ "jb55" ];
systemd.services.openvpn-pia.path = [ pkgs.libcgroup ];
services.openvpn.servers = {
pia = {
autoStart = false;
config = ''
client
dev tun
proto udp
remote 66.115.146.27 1194
resolv-retry infinite
remote-random
nobind
tun-mtu 1500
tun-mtu-extra 32
mssfix 1450
persist-key
persist-tun
ping 15
ping-restart 0
ping-timer-rem
reneg-sec 0
comp-lzo no
remote-cert-tls server
auth-user-pass ${vpn.credfile}
fast-io
cipher AES-256-CBC
auth SHA512
route-noexec
route-up ${vpn.routeup}
-----BEGIN CERTIFICATE-----
MIIFCjCCAvKgAwIBAgIBATANBgkqhkiG9w0BAQ0FADA5MQswCQYDVQQGEwJQQTEQ
MA4GA1UEChMHTm9yZFZQTjEYMBYGA1UEAxMPTm9yZFZQTiBSb290IENBMB4XDTE2
MDEwMTAwMDAwMFoXDTM1MTIzMTIzNTk1OVowOTELMAkGA1UEBhMCUEExEDAOBgNV
BAoTB05vcmRWUE4xGDAWBgNVBAMTD05vcmRWUE4gUm9vdCBDQTCCAiIwDQYJKoZI
hvcNAQEBBQADggIPADCCAgoCggIBAMkr/BYhyo0F2upsIMXwC6QvkZps3NN2/eQF
kfQIS1gql0aejsKsEnmY0Kaon8uZCTXPsRH1gQNgg5D2gixdd1mJUvV3dE3y9FJr
XMoDkXdCGBodvKJyU6lcfEVF6/UxHcbBguZK9UtRHS9eJYm3rpL/5huQMCppX7kU
eQ8dpCwd3iKITqwd1ZudDqsWaU0vqzC2H55IyaZ/5/TnCk31Q1UP6BksbbuRcwOV
skEDsm6YoWDnn/IIzGOYnFJRzQH5jTz3j1QBvRIuQuBuvUkfhx1FEwhwZigrcxXu
MP+QgM54kezgziJUaZcOM2zF3lvrwMvXDMfNeIoJABv9ljw969xQ8czQCU5lMVmA
37ltv5Ec9U5hZuwk/9QO1Z+d/r6Jx0mlurS8gnCAKJgwa3kyZw6e4FZ8mYL4vpRR
hPdvRTWCMJkeB4yBHyhxUmTRgJHm6YR3D6hcFAc9cQcTEl/I60tMdz33G6m0O42s
Qt/+AR3YCY/RusWVBJB/qNS94EtNtj8iaebCQW1jHAhvGmFILVR9lzD0EzWKHkvy
WEjmUVRgCDd6Ne3eFRNS73gdv/C3l5boYySeu4exkEYVxVRn8DhCxs0MnkMHWFK6
MyzXCCn+JnWFDYPfDKHvpff/kLDobtPBf+Lbch5wQy9quY27xaj0XwLyjOltpiST
LWae/Q4vAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqG
SIb3DQEBDQUAA4ICAQC9fUL2sZPxIN2mD32VeNySTgZlCEdVmlq471o/bDMP4B8g
nQesFRtXY2ZCjs50Jm73B2LViL9qlREmI6vE5IC8IsRBJSV4ce1WYxyXro5rmVg/
k6a10rlsbK/eg//GHoJxDdXDOokLUSnxt7gk3QKpX6eCdh67p0PuWm/7WUJQxH2S
DxsT9vB/iZriTIEe/ILoOQF0Aqp7AgNCcLcLAmbxXQkXYCCSB35Vp06u+eTWjG0/
pyS5V14stGtw+fA0DJp5ZJV4eqJ5LqxMlYvEZ/qKTEdoCeaXv2QEmN6dVqjDoTAo
k0t5u4YRXzEVCfXAC3ocplNdtCA72wjFJcSbfif4BSC8bDACTXtnPC7nD0VndZLp
+RiNLeiENhk0oTC+UVdSc+n2nJOzkCK0vYu0Ads4JGIB7g8IB3z2t9ICmsWrgnhd
NdcOe15BincrGA8avQ1cWXsfIKEjbrnEuEk9b5jel6NfHtPKoHc9mDpRdNPISeVa
wDBM1mJChneHt59Nh8Gah74+TM1jBsw4fhJPvoc7Atcg740JErb904mZfkIEmojC
VPhBHVQ9LHBAdM8qFI2kRK0IynOmAZhexlP/aT/kpEsEPyaZQlnBn3An1CRz8h0S
PApL8PytggYKeQmRhl499+6jLxcZ2IegLfqq41dzIjwHwTMplg+1pKIOVojpWA==
-----END CERTIFICATE-----
key-direction 1
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
e685bdaf659a25a200e2b9e39e51ff03
0fc72cf1ce07232bd8b2be5e6c670143
f51e937e670eee09d4f2ea5a6e4e6996
5db852c275351b86fc4ca892d78ae002
d6f70d029bd79c4d1c26cf14e9588033
cf639f8a74809f29f72b9d58f9b8f5fe
fc7938eade40e9fed6cb92184abb2cc1
0eb1a296df243b251df0643d53724cdb
5a92a1d6cb817804c4a9319b57d53be5
80815bcfcb2df55018cc83fc43bc7ff8
2d51f9b88364776ee9d12fc85cc7ea5b
9741c4f598c485316db066d52db4540e
212e1518a9bd4828219e24b20d88f598
a196c9de96012090e333519ae18d3509
9427e7b372d348d352dc4c85e18cd4b9
3f8a56ddb2e64eb67adfc9b337157ff4
-----END OpenVPN Static key V1-----
'';
up = ''
# enable ip forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# create cgroup for 3rd party VPN (can change 'vpn' to your name of choice)
mkdir -p /sys/fs/cgroup/net_cls/${vpn.name}
# give it an arbitrary id
echo 11 > /sys/fs/cgroup/net_cls/${vpn.name}/net_cls.classid
# grant a non-root user access
cgcreate -t jb55:vpn-pia -a jb55:vpn-pia -g net_cls:${vpn.name}
# disable reverse path filtering for all interfaces
for i in /proc/sys/net/ipv4/conf\/*/rp_filter; do echo 0 > $i; done
'';
down = ''
echo 0 > /proc/sys/net/ipv4/ip_forward
cgdelete -g net_cls:${vpn.name}
# not sure if cgdelete does this...
rm -rf /sys/fs/cgroup/net_cls/${vpn.name}
'';
};
};
networking.firewall.checkReversePath = false;
networking.firewall.logReversePathDrops = true;
}