add weekly notif msg; add variable refresh timer

This commit is contained in:
rskntroot
2025-06-16 01:29:25 +00:00
parent 2c7201288a
commit 25a950f758
3 changed files with 74 additions and 47 deletions

View File

@@ -14,20 +14,18 @@ This is intended to be installed on a public-facing loadbalancer.
## Assumptions ## Assumptions
1. Your ISP randomly changes your PublicIP and that pisses you off. 1. Your ISP randomly changes your PublicIP and that upsets you.
1. You just want something that will curl `ipv4.icanhazip.com`, check 3rd-party dns, and update Route53. 1. You just want something that will curl `ipv4.icanhazip.com`, check 3rd-party dns, and update Route53.
1. Your Name records only contain a single IP. (future update maybe). 1. Your Name records only contain a single IP.
If so, this is for you. If so, this is for you.
## Setup ## Setup
1. get
1. setup `Route53AllowRecordUpdate.policy` 1. in [aws console](https://console.aws.amazon.com):
```zsh - create IAM user
DNS_ZONE_ID=YOURZONEIDHERE \ - attach policy `aws.policy` file provided
envsubst < aws.policy > Route53AllowRecordUpdate.policy - generate access keys for automated service
```
1. in aws, create IAM user, attach policy, generate access keys for automated service
1. log into aws cli with the account you created above 1. log into aws cli with the account you created above
``` ```
aws configure aws configure
@@ -36,14 +34,18 @@ If so, this is for you.
``` zsh ``` zsh
ln -sf ~/r53-ddns/target/release/r53-ddns /usr/bin/r53-ddns ln -sf ~/r53-ddns/target/release/r53-ddns /usr/bin/r53-ddns
``` ```
1. get your hosted_zone_id
``` zsh
aws route53 list-hosted-zones
```
1. setup systemd service and then install as normal 1. setup systemd service and then install as normal
```zsh ``` zsh
DNS_ZONE_ID=YOURZONEIDHERE \ DNS_ZONE_ID=YOURZONEIDHERE \
DOMAIN_NAME=your.domain.com. \ DOMAIN_NAME=your.domain.com. \
envsubst < r53-ddns.service | sudo tee -a /etc/systemd/system/r53-ddns.service envsubst < r53-ddns.service | sudo tee /etc/systemd/system/r53-ddns.service
``` ```
## CLI Usage ## Usage
``` ```
$ r53-ddns -h $ r53-ddns -h
@@ -54,6 +56,7 @@ Usage: r53-ddns --dns-zone-id <DNS_ZONE_ID> --domain-name <DOMAIN_NAME>
Options: Options:
-z, --dns-zone-id <DNS_ZONE_ID> DNS ZONE ID (see AWS Console Route53) -z, --dns-zone-id <DNS_ZONE_ID> DNS ZONE ID (see AWS Console Route53)
-d, --domain-name <DOMAIN_NAME> DOMAIN NAME (ex. 'docs.rskio.com.') -d, --domain-name <DOMAIN_NAME> DOMAIN NAME (ex. 'docs.rskio.com.')
-s, --seconds <SECONDS> SECONDS refresh timer in seconds [default: 180]
-h, --help Print help -h, --help Print help
``` ```
@@ -73,7 +76,9 @@ sudo systemctl status r53-ddns.service
``` ```
``` ```
$ systemctl status r53-ddns.service $ envsubst < r53-ddns.service | sudo tee /etc/systemd/system/r53-ddns.service
$ sudo systemctl enable --now r53-ddns.service
$ sudo systemctl status r53-ddns.service
● r53-ddns.service - Route53 Dynamic DNS Service ● r53-ddns.service - Route53 Dynamic DNS Service
Loaded: loaded (/etc/systemd/system/r53-ddns.service; enabled; vendor preset: enabled) Loaded: loaded (/etc/systemd/system/r53-ddns.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2024-07-29 09:03:40 UTC; 7min ago Active: active (running) since Mon 2024-07-29 09:03:40 UTC; 7min ago
@@ -86,18 +91,19 @@ $ systemctl status r53-ddns.service
Jul 29 09:03:40 hostname systemd[1]: Started Route53 Dynamic DNS Service. Jul 29 09:03:40 hostname systemd[1]: Started Route53 Dynamic DNS Service.
Jul 29 09:03:40 hostname r53-ddns[215630]: [2024-07-29T09:03:40Z INFO r53_ddns] starting with options: -z [##TRUNCATED##] -d rskio.com. Jul 29 09:03:40 hostname r53-ddns[215630]: [2024-07-29T09:03:40Z INFO r53_ddns] starting with options: -z [##TRUNCATED##] -d rskio.com.
Jul 29 09:03:40 hostname r53-ddns[215630]: [2024-07-29T09:03:40Z INFO r53_ddns] current public address is: 10.0.0.1
Jul 29 09:09:41 hostname r53-ddns[215630]: [2024-07-29T09:09:41Z INFO r53_ddns::dns] dynamic ip drift detected: 10.0.0.1 -> 71.211.88.219 Jul 29 09:09:41 hostname r53-ddns[215630]: [2024-07-29T09:09:41Z INFO r53_ddns::dns] dynamic ip drift detected: 10.0.0.1 -> 71.211.88.219
Jul 29 09:09:41 hostname r53-ddns[215630]: [2024-07-29T09:09:41Z INFO r53_ddns::route53] requesting update to route53 record for A rskio.com. -> 71.211.88.219 Jul 29 09:09:41 hostname r53-ddns[215630]: [2024-07-29T09:09:41Z INFO r53_ddns::route53] requesting update to route53 record for A rskio.com. -> 71.211.88.219
Jul 29 09:09:41 hostname r53-ddns[215630]: [2024-07-29T09:09:41Z INFO r53_ddns::route53] change_id: /change/C02168177BNS6R50C32Q has status: Pending Jul 29 09:09:41 hostname r53-ddns[215630]: [2024-07-29T09:09:41Z INFO r53_ddns::route53] change_id: /change/C02168177BNS6R50C32Q has status: Pending
Jul 29 09:10:41 hostname r53-ddns[215630]: [2024-07-29T09:09:41Z INFO r53_ddns::route53] change_id: /change/C02168177BNS6R50C32Q has status: Insync Jul 29 09:10:41 hostname r53-ddns[215630]: [2024-07-29T09:09:41Z INFO r53_ddns::route53] change_id: /change/C02168177BNS6R50C32Q has status: Insync
``` ```
## Q&A ## FAQs
> Why did you do create this monster in rust? > Does this handle multiple record updates?
To be able to handle errors in the future. No. The goal here was for a single server to sync its dns record. If you are running multiple services from the same host, then consider using CNAMEs to point at a global A|AAAA record for this to update.
> wen IPv6? > What if I need to update only a single address in the record?
It should work with IPv6. Let me know. I have been considering this use-case, but haven't implemented it yet.

View File

@@ -1,24 +1,27 @@
{ {
"Version": "2012-10-17", "Version": "2012-10-17",
"Statement": [ "Statement": [
{ {
"Sid": "VisualEditor0", "Sid": "VisualEditor0",
"Effect": "Allow", "Effect": "Allow",
"Action": [ "Action": [
"route53:ListResourceRecordSets", "route53:ListResourceRecordSets",
"route53:ChangeResourceRecordSets", "route53:ChangeResourceRecordSets",
"route53:GetChange" "route53:GetChange"
], ],
"Resource": [ "Resource": [
"arn:aws:route53:::hostedzone/${DNS_ZONE_ID}", "arn:aws:route53:::hostedzone/*",
"arn:aws:route53:::change/*" "arn:aws:route53:::change/*"
] ]
}, },
{ {
"Sid": "VisualEditor1", "Sid": "VisualEditor1",
"Effect": "Allow", "Effect": "Allow",
"Action": "route53:TestDNSAnswer", "Action": [
"Resource": "*" "route53:TestDNSAnswer",
} "route53:ListHostedZones"
] ],
"Resource": "*"
}
]
} }

View File

@@ -6,19 +6,28 @@ use env_logger::Builder;
use log::info; use log::info;
use reqwest::get; use reqwest::get;
use std::net::IpAddr; use std::net::IpAddr;
use std::time::SystemTime;
use tokio::time::{sleep, Duration}; use tokio::time::{sleep, Duration};
#[derive(Parser)] #[derive(Parser)]
#[clap( #[clap(
name = "r53-ddns", name = "r53-ddns",
about = "A CLI tool for correcting drift between your PublicIP and Route53 DNS A RECORD" about = "A CLI tool for correcting drift between your PublicIP and a Route53 DNS A|AAAA RECORD"
)] )]
struct Args { struct Args {
#[clap(short = 'z', long, help = "DNS ZONE ID\t(see AWS Console Route53)")] #[clap(short = 'z', long, help = "DNS ZONE ID\t(see AWS Console Route53)")]
dns_zone_id: String, dns_zone_id: String,
#[clap(short, long, help = "DOMAIN NAME\t(ex. 'docs.rskio.com.')")] #[clap(short = 'd', long, help = "DOMAIN NAME\t(ex. 'docs.rskio.com.')")]
domain_name: String, domain_name: String,
#[clap(
short = 's',
long,
help = "SECONDS\trefresh timer in seconds",
default_value = "180"
)]
seconds: u64,
} }
#[tokio::main] #[tokio::main]
@@ -27,18 +36,27 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Builder::new().filter(None, log::LevelFilter::Info).init(); Builder::new().filter(None, log::LevelFilter::Info).init();
info!( info!(
"starting with options: -z {} -d {}", "starting with options: -z {} -d {} -s {}",
&args.dns_zone_id, &args.domain_name, &args.dns_zone_id, &args.domain_name, &args.seconds,
); );
let mut next_status_time = SystemTime::now();
loop { loop {
let public_ip = get_public_ip().await?; let public_ip = get_public_ip().await?;
// print the current public ip each week
if SystemTime::now() > next_status_time {
info!("current public address is: {}", public_ip);
next_status_time += Duration::from_secs(7 * 24 * 60 * 60);
}
// update record if current public ip drifts from dns record
if !dns::is_addr_current(&args.domain_name, public_ip).await? { if !dns::is_addr_current(&args.domain_name, public_ip).await? {
route53::update_record(&args.dns_zone_id, &args.domain_name, public_ip).await?; route53::update_record(&args.dns_zone_id, &args.domain_name, public_ip).await?;
}; }
sleep(Duration::from_secs(60)).await; sleep(Duration::from_secs(args.seconds)).await;
} }
} }