Skip to content

Instantly share code, notes, and snippets.

@brickgao
Created October 21, 2016 11:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brickgao/a74400108bdbdddadeddc3e5666f1824 to your computer and use it in GitHub Desktop.
Save brickgao/a74400108bdbdddadeddc3e5666f1824 to your computer and use it in GitHub Desktop.
Script to implement Cloudflare DDNS
#!/usr/bin/env python3
# The MIT License (MIT)
# Copyright (c) <2016> <brickgao>
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import fcntl
import socket
import struct
import requests
CLOUDFLARE_EMAIL = ""
CLOUDFLARE_API_KEY = ""
CLOUDFLARE_ZONE_NAME = ""
CLOUDFLARE_DNS_RECORD_NAME = ""
CLOUDFLARE_BASE_API_URL = "https://api.cloudflare.com/client/v4"
BASE_HEADERS = {
"X-Auth-Email": CLOUDFLARE_EMAIL,
"X-Auth-Key": CLOUDFLARE_API_KEY,
"Content-Type": "application/json"
}
class CloudFlareException(Exception):
pass
def get_ip_address(ifname):
_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(
fcntl.ioctl(
_socket.fileno(),
0x8915,
struct.pack('256s', ifname[:15].encode("ascii"))
)[20:24]
)
def get_zone_id():
request_url = "{0}/zones".format(CLOUDFLARE_BASE_API_URL)
payload = {
"name": CLOUDFLARE_ZONE_NAME
}
result = requests.get(
request_url, params=payload, headers=BASE_HEADERS
).json()
if result["success"]:
return result["result"][0]["id"]
else:
raise CloudFlareException("Failed to get zone_id",
result["error_chain"])
def get_dns_record_id(zone_id):
request_url = "{0}/zones/{1}/dns_records".format(
CLOUDFLARE_BASE_API_URL, zone_id
)
payload = {
"name": CLOUDFLARE_DNS_RECORD_NAME
}
result = requests.get(
request_url, params=payload, headers=BASE_HEADERS
).json()
if result["success"]:
return result["result"][0]["id"]
else:
raise CloudFlareException("Failed to get dns_record_id",
result["error_chain"])
def update_dns_record(zone_id, dns_record_id, current_ip):
request_url = "{0}/zones/{1}/dns_records/{2}".format(
CLOUDFLARE_BASE_API_URL, zone_id, dns_record_id
)
payload = {
"id": dns_record_id,
"type": "A",
"name": CLOUDFLARE_DNS_RECORD_NAME,
"content": current_ip,
}
result = requests.put(
request_url, json=payload, headers=BASE_HEADERS
).json()
if not result["success"]:
raise CloudFlareException("Failed to update DNS record",
result["error_chain"])
def ddns():
zone_id = get_zone_id()
dns_record_id = get_dns_record_id(zone_id=zone_id)
current_ip = get_ip_address("eth0")
update_dns_record(zone_id=zone_id, dns_record_id=dns_record_id,
current_ip=current_ip)
if __name__ == "__main__":
ddns()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment