feat(webnsupdate): allow running in IPv4/6 only mode #81
3 changed files with 279 additions and 29 deletions
|
@ -48,6 +48,16 @@ let
|
|||
type = types.port;
|
||||
default = 5353;
|
||||
};
|
||||
allowedIPVersion = mkOption {
|
||||
description = ''The allowed IP versions to accept updates from.'';
|
||||
type = types.enum [
|
||||
"both"
|
||||
"ipv4-only"
|
||||
"ipv6-only"
|
||||
];
|
||||
default = "both";
|
||||
example = "ipv4-only";
|
||||
};
|
||||
passwordFile = mkOption {
|
||||
description = ''
|
||||
The file where the password is stored.
|
||||
|
@ -126,6 +136,8 @@ let
|
|||
cfg.passwordFile
|
||||
"--address"
|
||||
cfg.bindIp
|
||||
"--ip-type"
|
||||
cfg.allowedIPVersion
|
||||
"--port"
|
||||
(builtins.toString cfg.bindPort)
|
||||
"--ttl"
|
||||
|
|
|
@ -6,25 +6,25 @@
|
|||
checks =
|
||||
let
|
||||
testDomain = "webnstest.example";
|
||||
lastIPPath = "/var/lib/webnsupdate/last-ip.json";
|
||||
|
||||
zoneFile = pkgs.writeText "${testDomain}.zoneinfo" ''
|
||||
$ORIGIN .
|
||||
$TTL 60 ; 1 minute
|
||||
${testDomain} IN SOA ns1.${testDomain}. admin.${testDomain}. (
|
||||
1 ; serial
|
||||
21600 ; refresh (6 hours)
|
||||
3600 ; retry (1 hour)
|
||||
604800 ; expire (1 week)
|
||||
86400) ; negative caching TTL (1 day)
|
||||
|
||||
IN NS ns1.${testDomain}.
|
||||
$ORIGIN ${testDomain}.
|
||||
${testDomain}. IN A 127.0.0.1
|
||||
${testDomain}. IN AAAA ::1
|
||||
ns1 IN A 127.0.0.1
|
||||
ns1 IN AAAA ::1
|
||||
nsupdate IN A 127.0.0.1
|
||||
nsupdate IN AAAA ::1
|
||||
@ IN SOA ns1.${testDomain}. admin.${testDomain}. (
|
||||
1 ; serial
|
||||
6h ; refresh
|
||||
1h ; retry
|
||||
1w ; expire
|
||||
1d) ; negative caching TTL
|
||||
|
||||
IN NS ns1.${testDomain}.
|
||||
@ IN A 127.0.0.1
|
||||
ns1 IN A 127.0.0.1
|
||||
nsupdate IN A 127.0.0.1
|
||||
@ IN AAAA ::1
|
||||
ns1 IN AAAA ::1
|
||||
nsupdate IN AAAA ::1
|
||||
'';
|
||||
|
||||
bindDynamicZone =
|
||||
|
@ -121,6 +121,16 @@
|
|||
};
|
||||
};
|
||||
|
||||
webnsupdate-ipv4-only-machine = {
|
||||
imports = [ webnsupdate-nginx-machine ];
|
||||
config.services.webnsupdate.allowedIPVersion = "ipv4-only";
|
||||
};
|
||||
|
||||
webnsupdate-ipv6-only-machine = {
|
||||
imports = [ webnsupdate-nginx-machine ];
|
||||
config.services.webnsupdate.allowedIPVersion = "ipv6-only";
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.start(allow_reboot=True)
|
||||
machine.wait_for_unit("bind.service")
|
||||
|
@ -128,8 +138,8 @@
|
|||
|
||||
# ensure base DNS records area available
|
||||
with subtest("query base DNS records"):
|
||||
machine.succeed("dig @127.0.0.1 ${testDomain} | grep ^${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 ns1.${testDomain} | grep ^ns1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 ${testDomain} | grep ^${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 ns1.${testDomain} | grep ^ns1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 nsupdate.${testDomain} | grep ^nsupdate.${testDomain}")
|
||||
|
||||
# ensure webnsupdate managed records are missing
|
||||
|
@ -140,7 +150,7 @@
|
|||
|
||||
with subtest("update webnsupdate DNS records (invalid auth)"):
|
||||
machine.fail("curl --fail --silent -u test1:test1 -X GET http://localhost:5353/update")
|
||||
machine.fail("cat /var/lib/webnsupdate/last-ip") # no last-ip set yet
|
||||
machine.fail("cat ${lastIPPath}") # no last-ip set yet
|
||||
|
||||
# ensure webnsupdate managed records are missing
|
||||
with subtest("query webnsupdate DNS records (fail)"):
|
||||
|
@ -150,7 +160,7 @@
|
|||
|
||||
with subtest("update webnsupdate DNS records (valid auth)"):
|
||||
machine.succeed("curl --fail --silent -u test:test -X GET http://localhost:5353/update")
|
||||
machine.succeed("cat /var/lib/webnsupdate/last-ip")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
|
||||
# ensure webnsupdate managed records are available
|
||||
with subtest("query webnsupdate DNS records (succeed)"):
|
||||
|
@ -159,9 +169,9 @@
|
|||
machine.succeed("dig @127.0.0.1 test3.${testDomain} A test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
|
||||
machine.reboot()
|
||||
machine.succeed("cat /var/lib/webnsupdate/last-ip")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
machine.wait_for_unit("webnsupdate.service")
|
||||
machine.succeed("cat /var/lib/webnsupdate/last-ip")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
|
||||
# ensure base DNS records area available after a reboot
|
||||
with subtest("query base DNS records"):
|
||||
|
@ -197,8 +207,8 @@
|
|||
|
||||
# ensure base DNS records area available
|
||||
with subtest("query base DNS records"):
|
||||
machine.succeed("dig @127.0.0.1 ${testDomain} | grep ^${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 ns1.${testDomain} | grep ^ns1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 ${testDomain} | grep ^${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 ns1.${testDomain} | grep ^ns1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 nsupdate.${testDomain} | grep ^nsupdate.${testDomain}")
|
||||
|
||||
# ensure webnsupdate managed records are missing
|
||||
|
@ -212,7 +222,7 @@
|
|||
|
||||
with subtest("update webnsupdate DNS records (invalid auth)"):
|
||||
machine.fail("curl --fail --silent -u test1:test1 -X GET http://127.0.0.1/update")
|
||||
machine.fail("cat /var/lib/webnsupdate/last-ip") # no last-ip set yet
|
||||
machine.fail("cat ${lastIPPath}") # no last-ip set yet
|
||||
|
||||
# ensure webnsupdate managed records are missing
|
||||
with subtest("query webnsupdate DNS records (fail)"):
|
||||
|
@ -225,7 +235,7 @@
|
|||
|
||||
with subtest("update webnsupdate IPv4 DNS records (valid auth)"):
|
||||
machine.succeed("curl --fail --silent -u test:test -X GET http://127.0.0.1/update")
|
||||
machine.succeed("cat /var/lib/webnsupdate/last-ip")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
|
||||
# ensure webnsupdate managed IPv4 records are available
|
||||
with subtest("query webnsupdate IPv4 DNS records (succeed)"):
|
||||
|
@ -241,7 +251,7 @@
|
|||
|
||||
with subtest("update webnsupdate IPv6 DNS records (valid auth)"):
|
||||
machine.succeed("curl --fail --silent -u test:test -X GET http://[::1]/update")
|
||||
machine.succeed("cat /var/lib/webnsupdate/last-ip")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
|
||||
# ensure webnsupdate managed IPv6 records are missing
|
||||
with subtest("query webnsupdate IPv6 DNS records (fail)"):
|
||||
|
@ -250,9 +260,9 @@
|
|||
machine.succeed("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
|
||||
machine.reboot()
|
||||
machine.succeed("cat /var/lib/webnsupdate/last-ip")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
machine.wait_for_unit("webnsupdate.service")
|
||||
machine.succeed("cat /var/lib/webnsupdate/last-ip")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
|
||||
# ensure base DNS records area available after a reboot
|
||||
with subtest("query base DNS records"):
|
||||
|
@ -270,6 +280,172 @@
|
|||
machine.succeed("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
'';
|
||||
};
|
||||
module-ipv4-only-test = pkgs.testers.runNixOSTest {
|
||||
name = "webnsupdate-ipv4-only-module";
|
||||
nodes.machine = webnsupdate-ipv4-only-machine;
|
||||
testScript = ''
|
||||
machine.start(allow_reboot=True)
|
||||
machine.wait_for_unit("bind.service")
|
||||
machine.wait_for_unit("webnsupdate.service")
|
||||
|
||||
# ensure base DNS records area available
|
||||
with subtest("query base DNS records"):
|
||||
machine.succeed("dig @127.0.0.1 ${testDomain} | grep ^${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 ns1.${testDomain} | grep ^ns1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 nsupdate.${testDomain} | grep ^nsupdate.${testDomain}")
|
||||
|
||||
# ensure webnsupdate managed records are missing
|
||||
with subtest("query webnsupdate DNS records (fail)"):
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} A | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} A | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} A | grep ^test3.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} AAAA | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} AAAA | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
|
||||
with subtest("update webnsupdate DNS records (invalid auth)"):
|
||||
machine.fail("curl --fail --silent -u test1:test1 -X GET http://127.0.0.1/update")
|
||||
machine.fail("cat ${lastIPPath}") # no last-ip set yet
|
||||
|
||||
# ensure webnsupdate managed records are missing
|
||||
with subtest("query webnsupdate DNS records (fail)"):
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} A | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} A | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} A | grep ^test3.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} AAAA | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} AAAA | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
|
||||
with subtest("update webnsupdate IPv6 DNS records (valid auth)"):
|
||||
machine.fail("curl --fail --silent -u test:test -X GET http://[::1]/update")
|
||||
machine.fail("cat ${lastIPPath}")
|
||||
|
||||
# ensure webnsupdate managed IPv6 records are missing
|
||||
with subtest("query webnsupdate IPv6 DNS records (fail)"):
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} AAAA | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} AAAA | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
|
||||
with subtest("update webnsupdate IPv4 DNS records (valid auth)"):
|
||||
machine.succeed("curl --fail --silent -u test:test -X GET http://127.0.0.1/update")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
|
||||
# ensure webnsupdate managed IPv4 records are available
|
||||
with subtest("query webnsupdate IPv4 DNS records (succeed)"):
|
||||
machine.succeed("dig @127.0.0.1 test1.${testDomain} A | grep ^test1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 test2.${testDomain} A | grep ^test2.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 test3.${testDomain} A | grep ^test3.${testDomain}")
|
||||
|
||||
# ensure webnsupdate managed IPv6 records are missing
|
||||
with subtest("query webnsupdate IPv6 DNS records (fail)"):
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} AAAA | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} AAAA | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
|
||||
machine.reboot()
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
machine.wait_for_unit("webnsupdate.service")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
|
||||
# ensure base DNS records area available after a reboot
|
||||
with subtest("query base DNS records"):
|
||||
machine.succeed("dig @127.0.0.1 ${testDomain} | grep ^${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 ns1.${testDomain} | grep ^ns1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 nsupdate.${testDomain} | grep ^nsupdate.${testDomain}")
|
||||
|
||||
# ensure webnsupdate managed records are available after a reboot
|
||||
with subtest("query webnsupdate DNS records (succeed)"):
|
||||
machine.succeed("dig @127.0.0.1 test1.${testDomain} A | grep ^test1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 test2.${testDomain} A | grep ^test2.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 test3.${testDomain} A | grep ^test3.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} AAAA | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} AAAA | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
'';
|
||||
};
|
||||
module-ipv6-only-test = pkgs.testers.runNixOSTest {
|
||||
name = "webnsupdate-ipv6-only-module";
|
||||
nodes.machine = webnsupdate-ipv6-only-machine;
|
||||
testScript = ''
|
||||
machine.start(allow_reboot=True)
|
||||
machine.wait_for_unit("bind.service")
|
||||
machine.wait_for_unit("webnsupdate.service")
|
||||
|
||||
# ensure base DNS records area available
|
||||
with subtest("query base DNS records"):
|
||||
machine.succeed("dig @127.0.0.1 ${testDomain} | grep ^${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 ns1.${testDomain} | grep ^ns1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 nsupdate.${testDomain} | grep ^nsupdate.${testDomain}")
|
||||
|
||||
# ensure webnsupdate managed records are missing
|
||||
with subtest("query webnsupdate DNS records (fail)"):
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} A | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} A | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} A | grep ^test3.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} AAAA | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} AAAA | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
|
||||
with subtest("update webnsupdate DNS records (invalid auth)"):
|
||||
machine.fail("curl --fail --silent -u test1:test1 -X GET http://127.0.0.1/update")
|
||||
machine.fail("cat ${lastIPPath}") # no last-ip set yet
|
||||
|
||||
# ensure webnsupdate managed records are missing
|
||||
with subtest("query webnsupdate DNS records (fail)"):
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} A | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} A | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} A | grep ^test3.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} AAAA | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} AAAA | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
|
||||
with subtest("update webnsupdate IPv4 DNS records (valid auth)"):
|
||||
machine.fail("curl --fail --silent -u test:test -X GET http://127.0.0.1/update")
|
||||
machine.fail("cat ${lastIPPath}")
|
||||
|
||||
# ensure webnsupdate managed IPv4 records are missing
|
||||
with subtest("query webnsupdate IPv4 DNS records (fail)"):
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} A | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} A | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} A | grep ^test3.${testDomain}")
|
||||
|
||||
with subtest("update webnsupdate IPv6 DNS records (valid auth)"):
|
||||
machine.succeed("curl --fail --silent -u test:test -X GET http://[::1]/update")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
|
||||
# ensure webnsupdate managed IPv6 records are available
|
||||
with subtest("query webnsupdate IPv6 DNS records (succeed)"):
|
||||
machine.succeed("dig @127.0.0.1 test1.${testDomain} AAAA | grep ^test1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 test2.${testDomain} AAAA | grep ^test2.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
|
||||
# ensure webnsupdate managed IPv4 records are missing
|
||||
with subtest("query webnsupdate IPv4 DNS records (fail)"):
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} A | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} A | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} A | grep ^test3.${testDomain}")
|
||||
|
||||
machine.reboot()
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
machine.wait_for_unit("webnsupdate.service")
|
||||
machine.succeed("cat ${lastIPPath}")
|
||||
|
||||
# ensure base DNS records area available after a reboot
|
||||
with subtest("query base DNS records"):
|
||||
machine.succeed("dig @127.0.0.1 ${testDomain} | grep ^${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 ns1.${testDomain} | grep ^ns1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 nsupdate.${testDomain} | grep ^nsupdate.${testDomain}")
|
||||
|
||||
# ensure webnsupdate managed records are available after a reboot
|
||||
with subtest("query webnsupdate DNS records (succeed)"):
|
||||
machine.succeed("dig @127.0.0.1 test1.${testDomain} AAAA | grep ^test1.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 test2.${testDomain} AAAA | grep ^test2.${testDomain}")
|
||||
machine.succeed("dig @127.0.0.1 test3.${testDomain} AAAA | grep ^test3.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test1.${testDomain} A | grep ^test1.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test2.${testDomain} A | grep ^test2.${testDomain}")
|
||||
machine.fail("dig @127.0.0.1 test3.${testDomain} A | grep ^test3.${testDomain}")
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
64
src/main.rs
64
src/main.rs
|
@ -81,10 +81,55 @@ struct Opts {
|
|||
#[clap(long, default_value = "RightmostXForwardedFor")]
|
||||
ip_source: SecureClientIpSource,
|
||||
|
||||
/// Set which IPs to allow updating
|
||||
#[clap(long, default_value_t = IpType::Both)]
|
||||
ip_type: IpType,
|
||||
|
||||
#[clap(subcommand)]
|
||||
subcommand: Option<Cmd>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
enum IpType {
|
||||
#[default]
|
||||
Both,
|
||||
IPv4Only,
|
||||
IPv6Only,
|
||||
}
|
||||
|
||||
impl IpType {
|
||||
fn valid_for_type(self, ip: IpAddr) -> bool {
|
||||
match self {
|
||||
IpType::Both => true,
|
||||
IpType::IPv4Only => ip.is_ipv4(),
|
||||
IpType::IPv6Only => ip.is_ipv6(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for IpType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
IpType::Both => f.write_str("both"),
|
||||
IpType::IPv4Only => f.write_str("ipv4-only"),
|
||||
IpType::IPv6Only => f.write_str("ipv6-only"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for IpType {
|
||||
type Err = miette::Error;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
match s {
|
||||
"both" => Ok(Self::Both),
|
||||
"ipv4-only" => Ok(Self::IPv4Only),
|
||||
"ipv6-only" => Ok(Self::IPv6Only),
|
||||
_ => bail!("expected one of 'ipv4-only', 'ipv6-only' or 'both', got '{s}'"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Cmd {
|
||||
Mkpasswd(password::Mkpasswd),
|
||||
|
@ -117,6 +162,9 @@ struct AppState<'a> {
|
|||
|
||||
/// Last recorded IPs
|
||||
last_ips: std::sync::Arc<tokio::sync::Mutex<SavedIPs>>,
|
||||
|
||||
/// The IP type for which to allow updates
|
||||
ip_type: IpType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
|
||||
|
@ -173,13 +221,14 @@ impl AppState<'static> {
|
|||
salt: _,
|
||||
ttl,
|
||||
ip_source: _,
|
||||
ip_type,
|
||||
} = args;
|
||||
|
||||
// Set state
|
||||
let ttl = Duration::from_secs(*ttl);
|
||||
|
||||
// Use last registered IP address if available
|
||||
let ip_file = Box::leak(data_dir.join("last-ip").into_boxed_path());
|
||||
let ip_file = Box::leak(data_dir.join("last-ip.json").into_boxed_path());
|
||||
|
||||
let state = AppState {
|
||||
ttl,
|
||||
|
@ -198,6 +247,7 @@ impl AppState<'static> {
|
|||
})
|
||||
.transpose()?,
|
||||
ip_file,
|
||||
ip_type: *ip_type,
|
||||
last_ips: std::sync::Arc::new(tokio::sync::Mutex::new(
|
||||
load_ip(ip_file)?.unwrap_or_default(),
|
||||
)),
|
||||
|
@ -276,6 +326,7 @@ fn main() -> Result<()> {
|
|||
salt,
|
||||
ttl: _,
|
||||
ip_source,
|
||||
ip_type,
|
||||
} = args;
|
||||
|
||||
info!("checking environment");
|
||||
|
@ -312,6 +363,10 @@ fn main() -> Result<()> {
|
|||
// Update DNS record with previous IPs (if available)
|
||||
let ips = state.last_ips.lock().await.clone();
|
||||
for ip in ips.ips() {
|
||||
if !ip_type.valid_for_type(ip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match nsupdate::nsupdate(ip, state.ttl, state.key_file, state.records).await {
|
||||
Ok(status) => {
|
||||
if !status.success() {
|
||||
|
@ -361,6 +416,13 @@ async fn update_records(
|
|||
SecureClientIp(ip): SecureClientIp,
|
||||
) -> axum::response::Result<&'static str> {
|
||||
info!("accepted update from {ip}");
|
||||
|
||||
if !state.ip_type.valid_for_type(ip) {
|
||||
let ip_type = state.ip_type;
|
||||
tracing::warn!("rejecting update from {ip} as we are running a {ip_type} filter");
|
||||
return Err((StatusCode::CONFLICT, format!("running in {ip_type} mode")).into());
|
||||
}
|
||||
|
||||
match nsupdate::nsupdate(ip, state.ttl, state.key_file, state.records).await {
|
||||
Ok(status) if status.success() => {
|
||||
let ips = {
|
||||
|
|
Loading…
Add table
Reference in a new issue