forked from timothymiller/cloudflare-ddns
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcloudflare-ddns.py
executable file
·151 lines (130 loc) · 4.64 KB
/
cloudflare-ddns.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import requests, json, sys, signal, os
import time
PATH = os.getcwd() + "/"
version = float(str(sys.version_info[0]) + "." + str(sys.version_info[1]))
if(version < 3.5):
raise Exception("This script requires Python 3.5+")
def sigtermHandler(sig_no, stack_frame):
print("Caught SIGTERM, shutting down...")
sys.exit(0)
signal.signal(signal.SIGTERM, sigtermHandler)
with open(PATH + "config.json") as config_file:
config = json.loads(config_file.read())
def getIPs():
a = ""
aaaa = ""
try:
a = requests.get("https://1.1.1.1/cdn-cgi/trace").text.split("\n")
a.pop()
a = dict(s.split("=") for s in a)["ip"]
except Exception:
pass
try:
aaaa = requests.get("https://[2606:4700:4700::1111]/cdn-cgi/trace").text.split("\n")
aaaa.pop()
aaaa = dict(s.split("=") for s in aaaa)["ip"]
except Exception:
pass
ips = []
if(a.find(".") > -1):
ips.append({
"type": "A",
"ip": a
})
else:
print("Warning: IPv4 not detected.")
if(aaaa.find(":") > -1):
ips.append({
"type": "AAAA",
"ip": aaaa
})
else:
print("Warning: IPv6 not detected.")
return ips
def commitRecord(ip):
stale_record_ids = []
for c in config["cloudflare"]:
subdomains = c["subdomains"]
response = cf_api("zones/" + c['zone_id'], "GET", c)
base_domain_name = response["result"]["name"]
ttl = 120
if "ttl" in c:
ttl=c["ttl"]
for subdomain in subdomains:
subdomain = subdomain.lower()
exists = False
record = {
"type": ip["type"],
"name": subdomain,
"content": ip["ip"],
"proxied": c["proxied"],
"ttl": ttl
}
list = cf_api(
"zones/" + c['zone_id'] + "/dns_records?per_page=100&type=" + ip["type"], "GET", c)
full_subdomain = base_domain_name
if subdomain:
full_subdomain = subdomain + "." + full_subdomain
dns_id = ""
for r in list["result"]:
if (r["name"] == full_subdomain):
exists = True
if (r["content"] != ip["ip"]):
if (dns_id == ""):
dns_id = r["id"]
else:
stale_record_ids.append(r["id"])
if(exists == False):
print("Adding new record " + str(record))
response = cf_api(
"zones/" + c['zone_id'] + "/dns_records", "POST", c, {}, record)
elif(dns_id != ""):
# Only update if the record content is different
print("Updating record " + str(record))
response = cf_api(
"zones/" + c['zone_id'] + "/dns_records/" + dns_id, "PUT", c, {}, record)
# Delete duplicate, stale records
for identifier in stale_record_ids:
print("Deleting stale record " + str(identifier))
response = cf_api(
"zones/" + c['zone_id'] + "/dns_records/" + identifier, "DELETE", c)
return True
def cf_api(endpoint, method, config, headers={}, data=False):
api_token = config['authentication']['api_token']
if api_token != '' and api_token != 'api_token_here':
headers = {
"Authorization": "Bearer " + api_token,
**headers
}
else:
headers = {
"X-Auth-Email": config['authentication']['api_key']['account_email'],
"X-Auth-Key": config['authentication']['api_key']['api_key'],
}
if(data == False):
response = requests.request(
method, "https://api.cloudflare.com/client/v4/" + endpoint, headers=headers)
else:
response = requests.request(
method, "https://api.cloudflare.com/client/v4/" + endpoint, headers=headers, json=data)
return response.json()
def updateIPs():
for ip in getIPs():
commitRecord(ip)
try:
if(len(sys.argv) > 1):
if(sys.argv[1] == "--repeat"):
print("Updating A & AAAA records every 10 minutes")
updateIPs()
delay = 10*60 # 10 minutes
next_time = time.time() + delay
while True:
time.sleep(max(0, next_time - time.time()))
updateIPs()
next_time += (time.time() - next_time) // delay * delay + delay
else:
print("Unrecognized parameter '" + sys.argv[1] + "'. Stopping now.")
else:
updateIPs()
except SystemExit:
print("Goodbye!")