最近网络环境趋紧,流行的几个DDNS要么要实名认证,要么直接就不能免费使用,很烦。一个很简单的东西,天朝居然都要搞得这么复杂,最近无聊顺手些了一个,用GoLang实现动态域名解析。
大概的流程
1,通过调用一个远程网站,获得本地的公网IP
2,确认域名的指向与1获得的IP是否一致,如果一致就不继续,如果不一致前进到3
3,通过调用GoDaddy的API重置特定域名的IP指向。
每隔30分钟,循环上述流程,实现DDNS
废话不多说,直接上代码
package main
import (
"fmt"
"net/http"
"net"
"time"
"os"
"io/ioutil"
"strings"
)
func main() {
const TIME_INTERVAL int = 30*60
const DOMAIN_NAME string = "DomainName"
const DOMAIN_SUBNAME string = "subDomain"
const DOMAIN_TYPE string = "A"
const DOMAIN_TTL int = 900
const GoDaddy_Key string = "KEY"
const GoDaddy_Sec string = "SEC"
fmt.Println("Starting the application...")
for true {
ip1 := getPublicIP()
ip2 := getDNSRecordIP(DOMAIN_SUBNAME + "." + DOMAIN_NAME)
// ip2 = "0.0.0.0"
fmt.Println("PublicIP : " + ip1)
fmt.Println("DNSRecord : " + DOMAIN_SUBNAME + "." + DOMAIN_NAME + ":" + ip2)
if ip1 == ip2 {
fmt.Println("No Need For Update Domian Record ")
time.Sleep(time.Duration(TIME_INTERVAL) * time.Second)
continue
}else{
fmt.Print("Ready To Update Domian Record ...")
}
setDNSRecordIP(ip1,DOMAIN_TTL,DOMAIN_NAME,DOMAIN_TYPE,DOMAIN_SUBNAME,GoDaddy_Key,GoDaddy_Sec)
time.Sleep(time.Duration(TIME_INTERVAL) * time.Second)
}
}
func getPublicIP() string {
var ip = "0.0.0.0"
response, err := http.Get("http://ipv4.icanhazip.com/")
if err != nil {
fmt.Printf("The HTTP request failed with error %s\n", err)
} else {
data, _ := ioutil.ReadAll(response.Body)
ip = string(data)
}
return strings.TrimSpace(ip)
}
func getDNSRecordIP(domainName string) string {
var ip = "0.0.0.0" domain := domainName ipAddr, err := net.ResolveIPAddr("ip", domain) if err != nil { fmt.Fprintf(os.Stderr, "Err: %s", err.Error()) return ip } ip = ipAddr.IP.String()
// fmt.Println(ip)
return strings.TrimSpace(ip)
}
func setDNSRecordIP(ip string, ttl int, domain string, domainType string, name string, key string, sec string) {
url := fmt.Sprintf("https://api.godaddy.com/v1/domains/%s/records/%s/%s",domain,domainType,name)
data :=fmt.Sprintf("[{ \"data\": \"%s\", \"ttl\": %v, \"priority\": 0, \"weight\": 1 }]",ip,ttl)
//生成client 参数为默认
client := &http.Client{}
//提交请求
reqest, err := http.NewRequest("PUT", url, strings.NewReader(data))
if err != nil {
panic(err)
}
reqest.Header.Add("content-type", "application/json")
reqest.Header.Add("Accept", "application/json")
ssokey :=fmt.Sprintf("sso-key %s:%s",key,sec)
reqest.Header.Add("Authorization", ssokey)
//处理返回结果
response, _ := client.Do(reqest)
//返回的状态码
status := response.StatusCode
if status == 200 {
fmt.Println("Done!")
}else{
fmt.Print(status)
fmt.Println(" Error Hapened!")
}
}
因为无聊,所以上述代码又通过Python实现了一个遍,熟悉下Go和Python的语法,作为Java和微软系的程序猿。。。嘿嘿
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 本地动态获得公网IP并且重置Godaddy域名设定的例子
import os, socket
# pip install requests
import requests
args = {
"DomainName":"DomainName",
"DomainType":"A",
"DomainApikey":"KEY",
"DomainApiSec":"SEC",
"TTL":3600
}
# 处理主函数
def main():
# 获取当前域名指向IP
# default_ip = socket.gethostbyname('sz-ming.com')
default_ip = socket.gethostbyname(args["DomainName"])
print "当前指向IP : " + default_ip
# 测试用
default_ip = "127.0.0.1"
ip = "127.0.0.1"
# 获取本地的IP地址
try:
f = requests.get('http://ipv4.icanhazip.com/')
ip = f.text.strip()
print "获得公网IP : " + ip.encode('utf-8')
# args.ip = resp.strip()
except Exception,err:
print 1,err
# 区分处理
if default_ip == ip:
print "无需处理,直接退出"
# 直接退出
os._exit(0)
else:
print "正在重新设定域名指向"
hostnames = args["DomainName"].split('.')
# 通过API重新设定
url = 'https://api.godaddy.com/v1/domains/{}/records/{}/{}'.format('.'.join(hostnames[1:]),args["DomainType"],hostnames[0])
print url
data ='[{ "data": "' + ip + '", "ttl": 3600, "priority": 0, "weight": 1 }]'
print data
headers = {
'content-type': 'application/json',
"Accept":"application/json",
"Authorization": "sso-key {}:{}".format(args["DomainApikey"],args["DomainApiSec"])
}
try:
req = requests.put(url, data=data,headers=headers)
print "动态设定完成!"
print req.text
except Exception,err:
print 1,err
# 主函数调用
if __name__ == '__main__':
main()