-
-
Save sixtyfive/6afd5440d7ca2e80d4ad73f307431d7f to your computer and use it in GitHub Desktop.
DIY dDNS service script using Hetzner's DNS API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env ruby | |
| # | |
| # Original, including IsoLinearCHiP's improvements: https://gist.github.com/IsoLinearCHiP/d6bc594143102e6acd131fc65c080f64 | |
| # Current version, adapted to Hetzner phasing out dns.h.d for console.h.d | |
| # now maintained at https://gist.weitnahbei.de/sixtyfive/7b090861f8e44a8ba3b37c9cde93c3af | |
| API="https://api.hetzner.cloud/v1" | |
| require 'json' | |
| require 'socket' | |
| require 'net/http' | |
| require 'fileutils' | |
| require 'pstore' | |
| FileUtils.mkdir_p "#{Dir.home}/.local/share/update-ddns" | |
| @pstore = PStore.new "#{Dir.home}/.local/share/update-ddns/cache.pstore" | |
| def api(path, records=nil) | |
| if records | |
| cmd = "curl -s -X POST -H 'Authorization: Bearer #{@token}' -H 'Content-Type: application/json' -d '{\"records\": #{records.to_json}}' #{API}#{path}" | |
| `#{cmd}` | |
| else | |
| cmd = "curl -s -H 'Authorization: Bearer #{@token}' #{API}#{path}" | |
| JSON.parse `#{cmd}` | |
| end | |
| end | |
| def cache(key, value=nil) | |
| if value | |
| @pstore.transaction{@pstore[key] = value} | |
| end | |
| @pstore.transaction(true){return @pstore[key]} | |
| end | |
| def current_wan_ip | |
| Socket.getifaddrs | |
| .map{|iface| [iface.name, iface.addr.ip_address] if iface.addr.ipv4? if iface.addr} | |
| .compact | |
| .find{|x| x[0]=='ppp0'}[1] | |
| end | |
| def query | |
| @token = cache('api_token') | |
| zone = ARGV[0] | |
| rrset_name = ARGV[1] | |
| zone_id = cache('zone_id') | |
| zone_id ||= cache('zone_id', api('/zones')['zones'].find{|x| x['name'] == @zone}['id']) | |
| wan_ip = cache('current_wan_ip', current_wan_ip) | |
| puts wan_ip | |
| ips_on_record = api("/zones/#{zone_id}/rrsets/#{rrset_name}/A")['rrset']['records'].collect{|x| x['value']} | |
| if ips_on_record.last != wan_ip | |
| api("/zones/#{zone_id}/rrsets/#{rrset_name}/A/actions/set_records", [{value: wan_ip, comment: 'dynamically updated'}]) | |
| puts "record updated" | |
| else | |
| puts "no update necessary" | |
| end | |
| end | |
| case ARGV.size | |
| when 1 | |
| cache('api_token', ARGV[0]) | |
| puts "API token set" | |
| when 2 | |
| (warn "Error: API token not set"; exit!) unless cache('api_token') | |
| query | |
| else | |
| warn "Usage: update-ddns <zone> <record> | update-ddns <api token>" | |
| exit! | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment