-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathloopiadns.py
108 lines (90 loc) · 3.38 KB
/
loopiadns.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/usr/bin/env python3
import requests
from re import search
import logging
import configparser
from socket import gethostbyname, gaierror
configfile = "accounts.cfg"
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
logger.addHandler(ch)
def get_my_ip():
'''
Uses Loopia's external IP checker, returns IP address string if it goes well
'''
ipcheck = 'http://dns.loopia.se/checkip/checkip.php'
r = requests.get(ipcheck)
# Simple IP address regexp, matches some invalid addresses too.
m = search('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', r.text)
logger.info("Got IP %s", m.group(0))
return m.group(0)
def update_dns_record(hostname, username, password, ip):
'''
Sends a GET request to Loopia's DynDNS to update IP address.
If address is omitted, tries to map its own public IP to the hostname.
'''
dyndns = 'http://dns.loopia.se/XDynDNSServer/XDynDNS.php'
if not ip:
return False
logger.info("Trying to make %s point to %s", hostname, ip)
payload = {'system': 'custom', 'hostname': hostname, 'myip': ip, 'backmx': 'YES'}
r = requests.get(dyndns, params=payload, auth=(username, password))
logger.debug("Result: %s", r.text)
return r.text
def resolve_host(hostname):
'''
DNS query, resolving IP address
'''
try:
ip = gethostbyname(hostname)
logger.debug("%s points to %s", hostname, ip)
return ip
except gaierror:
logger.debug("Couldn't resolve hostname: %s", hostname)
return None
def read_config(file=configfile):
'''
Read config file, remove from it the DEFAULT section and incomplete records
'''
cleanconfig = {}
config = configparser.ConfigParser()
config.read(file)
for domain in config.keys():
logger.debug("Parsing configuration file section %s", domain)
keys = config[domain].keys()
# We skip the DEFAULT section and make sure username, password and ip values are available
if 'DEFAULT' not in domain and 'ip' in keys and 'username' in keys and 'password' in keys:
logger.debug("Section %s checks out - adding to clean configuration", domain)
cleanconfig[domain] = config[domain]
return cleanconfig
def main():
logger.info("Checking public IP of this machine")
myip = get_my_ip()
config = read_config(configfile)
for domain in config.keys():
logger.info("Working with hostname %s", domain)
futureip = config[domain]['ip']
username = config[domain]['username']
password = config[domain]['password']
if 'check' in futureip:
futureip = myip
currentip = resolve_host(domain)
if futureip in currentip:
logger.info("%s: Already correct IP", domain)
else:
ret = update_dns_record(domain, username, password, futureip)
if 'BADAUTH' in ret:
logger.info("%s: Bad Credentials", domain)
if 'abuse' in ret:
logger.info("%s: Update abuse", domain)
if 'nochg' in ret:
logger.info("%s: No change", domain)
if 'good' in ret:
logger.info("%s: Went well", domain)
else:
logger.info("%s: %s", domain, ret)
if __name__ == '__main__':
main()