Add URL parameter to enable notification of IP changes
This commit is contained in:
@@ -166,6 +166,7 @@ Without TSIG authentication, the DNS server must allow updates based on IP addre
|
||||
### Endpoints
|
||||
|
||||
Configure one or more HTTP endpoints. If no endpoints are defined, a default endpoint at `/update` is created with standard parameter names.
|
||||
Set an empty list of names to disable a parameter.
|
||||
|
||||
```toml
|
||||
[[endpoints]]
|
||||
@@ -176,6 +177,7 @@ ipv4 = ["myip", "ipv4", "ip4"]
|
||||
ipv6 = ["myip6", "ipv6", "ip6"]
|
||||
username = ["username", "user"]
|
||||
password = ["password", "pass", "token"]
|
||||
notify_change = ["notify_change"]
|
||||
|
||||
[[endpoints]]
|
||||
path = "/nic/update"
|
||||
@@ -185,6 +187,7 @@ ipv4 = ["myip"]
|
||||
ipv6 = ["myip6"]
|
||||
username = ["username"]
|
||||
password = ["password"]
|
||||
notify_change = []
|
||||
```
|
||||
|
||||
**Default accepted parameter names** (first match wins):
|
||||
|
||||
@@ -65,7 +65,10 @@ from_address = "ddns@example.com" # required if email.enabled
|
||||
# ipv6 (IPv6 address): myip6, ipv6, ip6
|
||||
# username: username, user
|
||||
# password: password, pass, token
|
||||
# notify_change: notify_change
|
||||
#
|
||||
# Multiple endpoints can be defined with custom parameter names
|
||||
|
||||
# [[endpoints]]
|
||||
# path = "/update"
|
||||
# [endpoints.params]
|
||||
@@ -74,6 +77,7 @@ from_address = "ddns@example.com" # required if email.enabled
|
||||
# ipv6 = ["myip6", "ipv6", "ip6"]
|
||||
# username = ["username", "user"]
|
||||
# password = ["password", "pass", "token"]
|
||||
# notify_change = ["notify_change"]
|
||||
|
||||
# [[endpoints]]
|
||||
# path = "/nic/update"
|
||||
@@ -83,3 +87,4 @@ from_address = "ddns@example.com" # required if email.enabled
|
||||
# ipv6 = ["myip6"]
|
||||
# username = ["username"]
|
||||
# password = ["password"]
|
||||
# notify_change = []
|
||||
|
||||
@@ -149,7 +149,7 @@ def cmd_hostname_list(args, app):
|
||||
return 0
|
||||
|
||||
print(
|
||||
f"{'Hostname':<35} {'User':<15} {'Zone':<20} "
|
||||
f"\n{'Hostname':<35} {'User':<15} {'Zone':<20} "
|
||||
f"{'DNS-TTL':<8} {'Exp-TTL':<8} {'Last-Update IPv4':<25} {'Last-Update IPv6'}"
|
||||
)
|
||||
print("-" * 140)
|
||||
|
||||
@@ -21,6 +21,7 @@ DEFAULT_ENDPOINT_PARAMS = {
|
||||
"ipv6": ["myip6", "ipv6", "ip6"],
|
||||
"username": ["username", "user"],
|
||||
"password": ["password", "pass", "token"],
|
||||
"notify_change": ["notify_change"],
|
||||
}
|
||||
|
||||
VALID_PARAM_KEYS = frozenset(DEFAULT_ENDPOINT_PARAMS.keys())
|
||||
|
||||
@@ -94,7 +94,7 @@ class EmailService:
|
||||
logging.error(f"Email send failed: to={to} error={e}")
|
||||
return False
|
||||
|
||||
def send_changed_notification(
|
||||
def send_change_notification(
|
||||
self,
|
||||
email,
|
||||
hostname,
|
||||
@@ -135,8 +135,8 @@ class EmailService:
|
||||
"expiry_ttl": hostname.expiry_ttl,
|
||||
}
|
||||
|
||||
subject = f"DDNS hostname expired: {fqdn}"
|
||||
body = self.expiry_template.render(**template_variables)
|
||||
subject = f"DDNS hostname changed: {fqdn}"
|
||||
body = self.change_template.render(**template_variables)
|
||||
|
||||
return self.send(email, subject, body)
|
||||
|
||||
|
||||
@@ -317,7 +317,8 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
||||
|
||||
now = utc_now()
|
||||
|
||||
changed = False
|
||||
ipv4_changed = False
|
||||
ipv6_changed = False
|
||||
if ipv4:
|
||||
hostname.last_ipv4_update = now
|
||||
if ipv4 != hostname.last_ipv4:
|
||||
@@ -330,7 +331,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
||||
hostname.dns_ttl
|
||||
)
|
||||
hostname.last_ipv4 = ipv4
|
||||
changed = True
|
||||
ipv4_changed = True
|
||||
except Exception as e:
|
||||
hostname.save()
|
||||
logging.error(
|
||||
@@ -351,7 +352,7 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
||||
hostname.dns_ttl
|
||||
)
|
||||
hostname.last_ipv6 = ipv6
|
||||
changed = True
|
||||
ipv6_changed = True
|
||||
except Exception as e:
|
||||
hostname.save()
|
||||
logging.error(
|
||||
@@ -364,15 +365,15 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
||||
hostname.save()
|
||||
|
||||
changed_addrs = ""
|
||||
if ipv4:
|
||||
changed_addrs += f"ipv4={ipv4}"
|
||||
if ipv6:
|
||||
if ipv4_changed:
|
||||
changed_addrs += f" ipv4={ipv4}"
|
||||
if ipv6_changed:
|
||||
changed_addrs += f" ipv6={ipv6}"
|
||||
|
||||
if not changed:
|
||||
if not ipv4_changed and not ipv6_changed:
|
||||
logging.info(
|
||||
f"No change: client={client_ip} hostname={hostname.hostname} "
|
||||
f"zone={hostname.zone} {changed_addrs}"
|
||||
f"zone={hostname.zone}{changed_addrs}"
|
||||
)
|
||||
return (
|
||||
200, "nochg",
|
||||
@@ -381,8 +382,21 @@ class DDNSRequestHandler(BaseHTTPRequestHandler):
|
||||
|
||||
logging.info(
|
||||
f"Updated: client={client_ip} hostname={hostname.hostname} "
|
||||
f"zone={hostname.zone} {changed_addrs}"
|
||||
f"zone={hostname.zone}{changed_addrs}"
|
||||
)
|
||||
|
||||
notify_change = extract_param(params, endpoint["params"]["notify_change"])
|
||||
if notify_change and notify_change.lower() not in ["0", "no", "off"]:
|
||||
try:
|
||||
self.app.email_service.send_change_notification(
|
||||
hostname.user.email,
|
||||
hostname,
|
||||
ipv4_changed,
|
||||
ipv6_changed
|
||||
)
|
||||
except Exception as e:
|
||||
logging.error(f"Sending change notification error: {e}")
|
||||
|
||||
return (
|
||||
200, "good",
|
||||
{"ipv4": hostname.last_ipv4, "ipv6": hostname.last_ipv6}
|
||||
|
||||
Reference in New Issue
Block a user