require "net/https"
require "optparse"
require "json"
require "uri"
options = {:ttl => "3600", :records => {}}
req_headers = {"Content-Type" => "application/json"}
OptionParser.new do |opts|
opts.banner = "Usage: ddns.rb -a -p -f file/path -t 3600 -r example.com"
opts.on("-f", "--token TOKEN_PATH", "Absolute path of file containing a Cloudflare API token.") do |path|
if File.file?(path) then
if File.readable?(path) then
cf_token = File.read(path)
cf_token = cf_token.gsub("\s", "")
req_headers["Authorization"] = "Bearer " + cf_token
else
warn "Token file not readable."
exit 11
end
else
warn "Failed to find token file."
exit 10
end
end
opts.on("-t", "--ttl TTL", "TTL") do |ttl|
options[:ttl] = ttl
end
opts.on("-a", "--aaaa", "Update AAAA records as well as A records.") do |aaaa|
options[:update_aaaa] = aaaa
end
opts.on("-p", "--proxy", "Enable proxy on updated DNS records.") do |proxy|
options[:enable_proxy] = proxy
end
opts.on("-r", "--record RECORD", "Add record name to update.") do |record|
options[:records][record] = true
end
end.parse!
print "Fetching external IP... "
ip_res, external_ip = Net::HTTP.get_response("checkip.amazonaws.com", "/")
if ip_res.code == "200" then
external_ip = ip_res.body.tr("\n", "")
puts "#{external_ip}."
else
puts "Failed."
puts "#{ip_res.code}: #{ip_res.body}"
exit 20
end
puts "Updating DDNS records."
zone_uri = URI.parse("https://api.cloudflare.com/client/v4/zones")
https = Net::HTTP.new(zone_uri.host, zone_uri.port)
https.use_ssl = true
zone_req = Net::HTTP::Get.new(zone_uri, req_headers)
zone_res = JSON.parse(https.request(zone_req).body)
if zone_res["success"] == true then
puts "Found #{zone_res["result"].count()} zone(s) to update."
zone_res["result"].each do |zone|
puts "Fetching records from zone '#{zone["name"]}'."
zone_id = zone["id"]
record_uri = URI.parse("https://api.cloudflare.com/client/v4/zones/#{zone_id}/dns_records")
https = Net::HTTP.new(record_uri.host, record_uri.port)
https.use_ssl = true
record_req = Net::HTTP::Get.new(record_uri, req_headers)
record_res = JSON.parse(https.request(record_req).body)
if record_res["success"] == true then
record_res["result"].each do |record|
record_name = record["name"]
record_type = record["type"]
if options[:records][record_name] && (record_type == "A" or (options[:update_aaaa] && record_type == "AAAA")) then
print "Updating record '#{record_name}'... "
if record["content"] == external_ip then
puts "Content doesn't need updating, skipping record."
else
update = {
"type" => record_type,
"name" => record_name,
"content" => external_ip,
"ttl" => options[:ttl],
"proxied" => options[:enable_proxy]
}
update_uri = URI.parse("https://api.cloudflare.com/client/v4/zones/#{zone_id}/dns_records/#{record["id"]}")
https = Net::HTTP.new(update_uri.host, update_uri.port)
https.use_ssl = true
update_req = Net::HTTP::Put.new(update_uri, req_headers)
update_req.body = update.to_json
update_res = JSON.parse(https.request(update_req).body)
if update_res["success"] == true then
puts "Updated successfully!"
else
puts "Update failed!"
pp update_res
end
end
end
end
else
puts record_res
exit 22
end
end
else
puts zone_res
exit 21
end
puts "Updated DDNS records successfully."
Comments
0 B
|👍
/👎
0 B
|👍
/👎