Skip to content

Instantly share code, notes, and snippets.

@thiagokokada
Last active October 31, 2017 02:09
Show Gist options
  • Save thiagokokada/cd982a4dcf8924d5e18edd38580b9f07 to your computer and use it in GitHub Desktop.
Save thiagokokada/cd982a4dcf8924d5e18edd38580b9f07 to your computer and use it in GitHub Desktop.
Script to update now-dns.com IPv4/v6 address
#!/usr/bin/env python3
# Script to update now-dns.com IPv4/v6 address
# Based on https://now-dns.com/client/dynupdate.pl
# Depends on python3 and python3-requests installed in the system
import os
import re
import requests
from requests.auth import HTTPBasicAuth
# https://gist.github.com/dfee/6ed3a4b05cfe7a6faf40a2102408d5d8
IPV4SEG = r'(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])'
IPV4ADDR = r'(?:(?:' + IPV4SEG + r'\.){3,3}' + IPV4SEG + r')'
IPV6SEG = r'(?:(?:[0-9a-fA-F]){1,4})'
IPV6GROUPS = (
r'(?:' + IPV6SEG + r':){7,7}' + IPV6SEG, # 1:2:3:4:5:6:7:8
r'(?:' + IPV6SEG + r':){1,7}:', # 1:: 1:2:3:4:5:6:7::
r'(?:' + IPV6SEG + r':){1,6}:' + IPV6SEG, # 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8
r'(?:' + IPV6SEG + r':){1,5}(?::' + IPV6SEG + r'){1,2}', # 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8
r'(?:' + IPV6SEG + r':){1,4}(?::' + IPV6SEG + r'){1,3}', # 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8
r'(?:' + IPV6SEG + r':){1,3}(?::' + IPV6SEG + r'){1,4}', # 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8
r'(?:' + IPV6SEG + r':){1,2}(?::' + IPV6SEG + r'){1,5}', # 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8
IPV6SEG + r':(?:(?::' + IPV6SEG + r'){1,6})', # 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8
r':(?:(?::' + IPV6SEG + r'){1,7}|:)', # ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::
r'fe80:(?::' + IPV6SEG + r'){0,4}%[0-9a-zA-Z]{1,}', # fe80::7:8%eth0 fe80::7:8%1 (link-local IPv6 addresses with zone index)
r'::(?:ffff(?::0{1,4}){0,1}:){0,1}[^\s:]' + IPV4ADDR, # ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
r'(?:' + IPV6SEG + r':){1,4}:[^\s:]' + IPV4ADDR, # 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address)
)
IPV6ADDR = '|'.join(['(?:{})'.format(g) for g in IPV6GROUPS[::-1]]) # Reverse rows for greedy match
# Configuration
USERNAME = os.environ.get("NOW_DNS_USERNAME")
PASSWORD = os.environ.get("NOW_DNS_PASSWORD")
HOSTNAME = os.environ.get("NOW_DNS_HOSTNAME")
UPDATE_URL = os.environ.get("NOW_DNS_UPDATE_URL", "https://now-dns.com/update")
TEST_IPV4 = os.environ.get("TEST_IPV4_URL", "http://checkip.dyndns.org/")
TEST_IPV6 = os.environ.get("TEST_IPV6_URL", "http://checkipv6.dyndns.org/")
IP_VERSION = os.environ.get("IP_VERSION", "4")
TIMEOUT = int(os.environ.get("REQUEST_TIMEOUT", "10"))
# Now-DNS response codes
RESPONSE_CODES = {
"good": "OK",
"nochg": "OK",
"nohost": "ERROR",
"notfqdn": "ERROR",
"badauth": "ERROR",
}
# Get IP
if IP_VERSION == "4":
ip_regex = IPV4ADDR
test_url = TEST_IPV4
else:
ip_regex = IPV6ADDR
test_url = TEST_IPV6
response = requests.get(test_url)
ip = re.findall(ip_regex, response.text)[0]
# Create request
auth = HTTPBasicAuth(USERNAME, PASSWORD)
request = "{url}?hostname={hostname}&myip={ip}".format(
url=UPDATE_URL, hostname=HOSTNAME, ip=ip)
# Run request
response = requests.get(request, auth=auth, timeout=TIMEOUT)
body = response.text
print("[{status}] Server returned message '{body}' for URL: {url}".format(
status=RESPONSE_CODES.get(body, "UNKNOWN"), body=body, url=request))
[Unit]
Description=Run dynupdate.py script
After=network.target
[Service]
User=nobody
Type=oneshot
[email protected]
Environment=NOW_DNS_PASSWORD=password
Environment=NOW_DNS_HOSTNAME=mydns.now-dns.org
Environment=IP_VERSION=4
ExecStart=/usr/bin/python3 /opt/scripts/dynupdate.py
[Install]
WantedBy=multi-user.target
[Unit]
Description=Run dynupdate.service each 10 minutes
[Timer]
OnCalendar=*:0/10
Persistent=true
[Install]
WantedBy=timers.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment