104 lines
2.9 KiB
Python
104 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import time
|
|
import requests
|
|
import docker
|
|
import tldextract
|
|
from cloudflare import Cloudflare
|
|
|
|
CLOUDFLARE_TOKEN = os.getenv("CLOUDFLARE_TOKEN")
|
|
PUBLIC_IPV4 = os.getenv("PUBLIC_IPV4")
|
|
PUBLIC_IPV6 = os.getenv("PUBLIC_IPV6") # optional
|
|
|
|
if not CLOUDFLARE_TOKEN or not PUBLIC_IPV4:
|
|
raise ValueError("CLOUDFLARE_TOKEN and PUBLIC_IPV4 must be set")
|
|
|
|
cf = Cloudflare(
|
|
api_token = CLOUDFLARE_TOKEN,
|
|
)
|
|
|
|
def get_zone_id(zone):
|
|
zones = cf.zones.list(
|
|
name = zone
|
|
).result
|
|
if zones == []:
|
|
return None
|
|
return zones[0].id
|
|
|
|
def get_record(zone_id, fqdn):
|
|
records = cf.dns.records.list(
|
|
zone_id = zone_id,
|
|
name = fqdn
|
|
).result
|
|
return records
|
|
|
|
def create_record(zone_id, fqdn, ip, record_type, proxied):
|
|
record_response = cf.dns.records.create(
|
|
zone_id = zone_id,
|
|
name = fqdn,
|
|
ttl = 3600,
|
|
type = record_type,
|
|
content = ip,
|
|
proxied = proxied,
|
|
)
|
|
print("Created " + record_type + " " + fqdn)
|
|
|
|
def delete_record(zone_id, fqdn):
|
|
records = get_record(zone_id, fqdn)
|
|
for r in records:
|
|
cf.dns.records.delete(
|
|
dns_record_id = r.id,
|
|
zone_id = zone_id,
|
|
)
|
|
print("Removed " + r.type + " " + r.name)
|
|
|
|
def handle_event(event):
|
|
status = event.get("status")
|
|
attrs = event.get("Actor", {}).get("Attributes", {})
|
|
if attrs.get("cloudflare.enable") == "true":
|
|
|
|
# should we proxy the domain ?
|
|
if attrs.get("cloudflare.proxied") == "true":
|
|
proxied = True
|
|
else:
|
|
proxied = False
|
|
|
|
# check we have a fqdn defined
|
|
if attrs.get("cloudflare.fqdn") == None:
|
|
print(attrs.get("name") + ": No FQDN is given, skipping")
|
|
return
|
|
|
|
# break down domain name and get zone id
|
|
fqdn = attrs.get("cloudflare.fqdn")
|
|
fqdn_extracted = tldextract.extract(fqdn)
|
|
subdomain = fqdn_extracted.subdomain
|
|
domain = fqdn_extracted.top_domain_under_public_suffix
|
|
|
|
# get zone id
|
|
zone_id = get_zone_id(domain)
|
|
if zone_id == None:
|
|
print("Error: zone " + domain + " not found")
|
|
return
|
|
|
|
# run actions
|
|
if status == "start":
|
|
create_record(zone_id, fqdn, PUBLIC_IPV4, "A", proxied)
|
|
create_record(zone_id, fqdn, PUBLIC_IPV6, "AAAA", proxied)
|
|
elif status == "stop":
|
|
delete_record(zone_id, fqdn)
|
|
|
|
def main():
|
|
print(f"Starting cloudflare-dns-docker agent with IPv4: {PUBLIC_IPV4}, IPv6: {PUBLIC_IPV6}")
|
|
client = docker.from_env()
|
|
while True:
|
|
try:
|
|
filters = {"type": "container"}
|
|
for event in client.events(decode=True, filters=filters):
|
|
handle_event(event)
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
time.sleep(5)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|