sane-ip-check: also store the upnp gateway

This commit is contained in:
Colin 2023-07-11 00:55:04 +00:00
parent 798f467128
commit f765e3d030
6 changed files with 89 additions and 44 deletions

View File

@ -6,8 +6,8 @@ let
getIp = pkgs.writeShellScript "dyn-dns-query-wan" ''
# preferred method and fallback
# OPNsense router broadcasts its UPnP endpoint every 30s
timeout 60 ${pkgs.sane-scripts.ip-check-upnp}/bin/sane-ip-check-upnp || \
${pkgs.sane-scripts.ip-check}/bin/sane-ip-check
timeout 60 ${pkgs.sane-scripts.ip-check}/bin/sane-ip-check --json || \
${pkgs.sane-scripts.ip-check}/bin/sane-ip-check --json --no-upnp
'';
in
{
@ -24,6 +24,14 @@ in
description = "where to store the latest WAN IPv4 address";
};
upnpPath = mkOption {
default = "/var/lib/uninsane/upnp.txt";
type = types.str;
description = ''
where to store the address of the UPNP device (if any) that can be used to create port forwards.
'';
};
ipCmd = mkOption {
default = "${getIp}";
type = types.path;
@ -54,18 +62,33 @@ in
wantedBy = cfg.restartOnChange;
before = cfg.restartOnChange;
script = ''
script = let
jq = "${pkgs.jq}/bin/jq";
sed = "${pkgs.gnused}/bin/sed";
in ''
mkdir -p "$(dirname '${cfg.ipPath}')"
newIp=$(${cfg.ipCmd})
mkdir -p "$(dirname '${cfg.upnpPath}')"
newIpDetails=$(${cfg.ipCmd})
newIp=$(echo "$newIpDetails" | ${jq} ".wan" | ${sed} 's/^"//' | ${sed} 's/"$//')
newUpnp=$(echo "$newIpDetails" | ${jq} ".upnp" | ${sed} 's/^"//' | ${sed} 's/"$//')
oldIp=$(cat '${cfg.ipPath}' || true)
oldUpnp=$(cat '${cfg.upnpPath}' || true)
# systemd path units are triggered on any file write action,
# regardless of content change. so only update the file if our IP *actually* changed
if [ "$newIp" != "$oldIp" ]
if [ "$newIp" != "$oldIp" -a -n "$newIp" ]
then
echo "$newIp" > '${cfg.ipPath}'
echo "WAN ip changed $oldIp -> $newIp"
fi
exit $(test -f '${cfg.ipPath}')
if [ "$newUpnp" != "$oldUpnp" -a -n "$newUpnp" ]
then
echo "$newUpnp" > '${cfg.upnpPath}'
echo "UPNP changed $oldUpnp -> $newUpnp"
fi
exit $(test -f '${cfg.ipPath}' -a '${cfg.upnpPath}')
'';
};

View File

@ -86,16 +86,11 @@ let
src = ./src;
pkgs = [ "git" ];
};
ip-check = static-nix-shell.mkBash {
ip-check = static-nix-shell.mkPython3Bin {
pname = "sane-ip-check";
src = ./src;
pkgs = [ "curl" "gnugrep" ];
};
ip-check-upnp = static-nix-shell.mkPython3Bin {
pname = "sane-ip-check-upnp";
src = ./src;
pkgs = [ "miniupnpc" ];
pyPkgs = [ "sane-lib.ssdp" ];
pyPkgs = [ "requests" "sane-lib.ssdp" ];
};
ip-port-forward = static-nix-shell.mkPython3Bin {
pname = "sane-ip-port-forward";

View File

@ -0,0 +1 @@
bt/sane_bt.py

View File

@ -0,0 +1 @@
ssdp/sane_ssdp.py

View File

@ -1,5 +1,57 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl -p gnugrep
ip=$(curl --silent https://ipinfo.io/ip)
echo "$ip" | grep -P " *^\d+\.\d+\.\d+\.\d+ *$"
exit $?
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.requests ps.sane-lib.ssdp ])" -p miniupnpc
# best to run this with an external timeout. e.g.
# - `timeout 60 sane-ip-check`
import json
import logging
import requests
import subprocess
import sys
from sane_ssdp import get_any_wan
logger = logging.getLogger(__name__)
def get_wan_fallback():
"untrusted method in which to get the WAN IP"
r = requests.get("https://ipinfo.io/ip")
ip = r.text.strip()
if any(c not in "0123456789." for c in ip):
logging.warn("invalid IP from ipinfo.ip", ip)
return ""
else:
return ip
if __name__ == '__main__':
logging.basicConfig()
format = "plaintext"
try_upnp = True
for arg in sys.argv[1:]:
if arg == "-v":
logging.getLogger().setLevel(logging.INFO)
elif arg == "-vv":
logging.getLogger().setLevel(logging.DEBUG)
elif arg == "--json":
format = "json"
elif arg == "--no-upnp":
try_upnp = False
else:
raise RuntimeError(f"invalid CLI argument {arg!r}")
upnp_details = get_any_wan() if try_upnp else None
if upnp_details:
root_dev, _lan_ip, wan_ip = upnp_details
else:
root_dev, wan_ip = "", get_wan_fallback()
if format == "plaintext":
print(wan_ip)
elif format == "json":
print(json.dumps(dict(
wan=wan_ip,
upnp=root_dev,
)))

View File

@ -1,27 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.sane-lib.ssdp ])" -p miniupnpc
# best to run this with an external timeout. e.g.
# - `timeout 60 sane-ip-check-upnp`
import logging
import os
import sys
d = os.path.dirname(__file__)
sys.path.insert(0, d)
from lib.sane_ssdp import get_any_wan
if __name__ == '__main__':
logging.basicConfig()
for arg in sys.argv[1:]:
if arg == "-v":
logging.getLogger().setLevel(logging.INFO)
elif arg == "-vv":
logging.getLogger().setLevel(logging.DEBUG)
else:
raise RuntimeError(f"invalid CLI argument {arg!r}")
_rootdev, _lan_ip, wan_ip = get_any_wan()
print(wan_ip)