Last active
March 15, 2020 15:28
-
-
Save xiaohui-zhangxh/9f15257d915d679cf0ac6a1b818d8da5 to your computer and use it in GitHub Desktop.
通过 QCloud/DnsPod API 动态更新域名解析
This file contains 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
# frozen_string_literal: true | |
require 'json' | |
require 'net/http' | |
class DnspodAPI | |
API_HOST = 'https://dnsapi.cn' | |
# API requires UserAgent contains app name/version and email | |
def initialize(token, app_name:, app_version:, email:) | |
@token = token | |
@app_name = app_name | |
@app_version = app_version | |
@email = email | |
end | |
def domain_records(domain, length: 100, **params) | |
method(__method__).parameters.each do |(type, name)| | |
params[name] = binding.local_variable_get(name) if type != :keyrest | |
end | |
request_api('/Record.List', params)['records'] | |
end | |
def update_record(domain, sub_domain, value:, **params) | |
method(__method__).parameters.each do |(type, name)| | |
params[name] = binding.local_variable_get(name) if type != :keyrest | |
end | |
params[:record_type] ||= 'A' | |
params[:record_line] ||= '默认' | |
unless params[:record_id] | |
record = domain_records(domain, params.slice(:sub_domain, :record_type)).first | |
raise 'record not found' if record.nil? | |
return record if record['value'] == value | |
params[:record_id] = record['id'] | |
end | |
request_api('/Record.Modify', params) | |
end | |
def request_api(path, params) | |
params = params.merge(login_token: @token, format: :json) | |
resp = Net::HTTP.post( | |
URI(API_HOST).merge(path), | |
URI.encode_www_form(params), | |
'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8', | |
'User-Agent' => user_agent | |
) | |
raise resp unless resp.is_a?(Net::HTTPOK) | |
JSON.parse(resp.body) | |
end | |
def user_agent | |
"#{@app_name}/#{@app_version} (#{@email})" | |
end | |
end | |
if $PROGRAM_NAME == __FILE__ | |
require 'socket' | |
def current_ip | |
s = TCPSocket.new 'ns1.dnspod.net', 6666 | |
ip = s.gets | |
s.close | |
ip | |
end | |
token = ARGV[0] | |
client = DnspodAPI.new( | |
token, | |
app_name: 'Ruby Client', | |
app_version: '0.1.0', | |
email: '[email protected]' | |
) | |
pp client.domain_records('tanmer.com', sub_domain: 'debug') | |
pp client.update_record('tanmer.com', 'debug', value: ARGV[2] || current_ip) | |
end |
This file contains 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 | |
require 'active_support/core_ext/string' | |
require 'active_support/core_ext/hash' | |
require 'active_support/core_ext/object/to_query' | |
require 'openssl' | |
require 'base64' | |
require 'open-uri' | |
require 'json' | |
require 'logger' | |
class QCloudAPI | |
attr_reader :secret_id, :secret | |
def initialize(secret_id, secret, logger: Logger.new(STDOUT)) | |
@secret_id = secret_id | |
@secret = secret | |
@logger = logger | |
end | |
def log(method=:puts, message) | |
@logger.send(method, message) | |
end | |
def common_args( | |
action: , | |
timestamp: , | |
nonce: , | |
secret_id: , | |
signature: nil, | |
region: nil, | |
signature_method: 'HmacSHA256', | |
token: nil | |
) | |
%w[action timestamp nonce secret_id signature region signature_method token].reduce({}) { |h, k| | |
v = eval(k) | |
h[k.classify] = v if v | |
h | |
} | |
end | |
# https://cloud.tencent.com/document/product/302/7310 | |
def build_signature(method, host, path, args, secret) | |
args = args.stringify_keys | |
args_str = args.keys.sort.map{ |k| "#{k}=#{args[k]}" }.join('&') | |
str = "#{method.to_s.upcase}#{host}#{path}?#{args_str}" | |
mac = OpenSSL::HMAC.digest("SHA256", secret, str) | |
Base64.encode64(mac).strip | |
end | |
def request_api(host, path, action, args) | |
final_args = common_args(action: action, timestamp: Time.now.to_i, nonce: SecureRandom.hex(4), secret_id: secret_id).merge(args) | |
signature = build_signature('GET', host, path, final_args, secret) | |
params = final_args.merge('Signature' => signature).to_query | |
response = open("https://#{host}#{path}?#{params}") and nil | |
body = JSON.parse(response.read) | |
raise "#{body['code']} - #{body['codeDesc']} - #{body['message']}" unless body['code'] == 0 | |
body | |
end | |
def domain_lists | |
response = request_api('cns.api.qcloud.com', '/v2/index.php', 'DomainList', length: 200) | |
response['data']['domains'].map { |domain| domain.slice('id', 'name') } | |
end | |
def domain_records(domain) | |
response = request_api('cns.api.qcloud.com', '/v2/index.php', 'RecordList', length: 200, domain: domain) | |
response['data']['records'].map { |record| record.slice('id', 'name', 'status', 'line', 'type', 'value') } | |
end | |
# https://cloud.tencent.com/document/product/302/8511 | |
def update_domain_record( | |
domain: , | |
sub_domain: , | |
value: , | |
record_id: nil, | |
record_type: nil, | |
record_line: nil) | |
old_value = nil | |
if record_id.nil? || record_type.nil? | |
record = domain_records(domain).find { |domain| domain['name'] == sub_domain } | |
raise "Domain #{sub_domain}.#{domain} not found" if record.nil? | |
old_value = record['value'] | |
return false if value == old_value | |
record_id = record['id'] | |
record_type = record['type'] | |
record_line = record['line'] | |
end | |
log :print, "Updating DNS #{sub_domain}.#{domain} from #{old_value} to #{value} ... " | |
response = request_api( | |
'cns.api.qcloud.com', | |
'/v2/index.php', | |
'RecordModify', | |
domain: domain, | |
recordId: record_id, | |
subDomain: sub_domain, | |
recordType: record_type, | |
recordLine: record_line, | |
value: value | |
) | |
log :puts, 'Done.' | |
return true | |
end | |
end | |
require 'socket' | |
def current_ip | |
s = TCPSocket.new 'ns1.dnspod.net', 6666 | |
ip = s.gets | |
s.close | |
ip | |
end | |
# ========================= update below ====================== | |
api = QCloudAPI.new('secret key', 'secret') | |
api.update_domain_record( | |
domain: 'c456.com', | |
sub_domain: 'tanmerdev', | |
value: current_ip | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment