golang实现请求cloudflare修改域名A记录解析
现在有些DNS解析要收费,国内的几个厂商需要实名制。下面给出golang请求cloudflare修改域名A记录解析的代码。
准备工作:
- 在域名购买服务商处,将dns解析服务器改为cloudflare的dns服务器地址
- 将域名添加到cloudflare后台,非cloudflare购买的域名也可以添加!
- cloudflare后台获取API KEY;获取区域ID,即代码中用到的zone id ; 代码中需要用到
- 在后台先为域名设置一条A记录,设置“仅限DNS”
如果准备工作不知道操作的,搜索其他博客,或者在B站搜索,都有教程。
示例代码实现的功能:从wan口获取公网ip地址,与当前dns记录比较,如果相同则不请求接口修改A记录,不同则请求接口。wan获取ip用正则实现,可以根据实际情况修改代码。
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"os"
"os/exec"
"path/filepath"
"regexp"
)
// 响应体的json中有其他字段,此处只定义需要的字段
type GetDnsRecords struct {
Result []Result `json:"result"`
Success bool `json:"success"`
}
type PutDnsRecordResponse struct {
Result Result `json:"result"`
Errors interface{} `json:"errors"`
Success bool `json:"success"`
}
// 单条dns记录
type Result struct {
// dns 记录后台的ID
Id string `json:"id"`
// 一级域名,例如:fuck.com
ZoneName string `json:"zone_name"`
// 具体被解析的域名, 例如:y.fuck.com
Name string `json:"name"`
// 解析到的内容,可能是IP
Content string `json:"content"`
// 解析类型,例如:A
Type string `json:"type"`
}
type PutDns struct {
Type string `json:"type"`
Name string `json:"name"`
Content string `json:"content"`
Proxied bool `json:"proxied"`
}
func main() {
// 需要解析的域名、cloudflare api key、zone id 写到环境变量
domain := os.Getenv("CLOUDFLARE_DOMAIN")
apiKey := os.Getenv("CLOUDFLARE_API_KEY")
zoneId := os.Getenv("CLOUDFLARE_ZONE_ID")
recordId, lastIp, err := getDnsRecordId(apiKey, zoneId, domain)
if err != nil {
fmt.Println("getDnsRecordId err", err)
return
}
dnsType := "A"
proxied := false
// 从网口获取IP
nowIp := getLocalIP()
if nowIp != lastIp {
_, er := putDnsRecord(zoneId, apiKey, recordId, dnsType, domain, nowIp, proxied)
if er == nil {
fmt.Println("putDnsRecord success ", "lastIp: ", lastIp, "nowIp: ", nowIp)
return
} else {
fmt.Println("putDnsRecord err", er)
return
}
} else {
fmt.Println("ip no change ", "lastIp: ", lastIp, "nowIp: ", nowIp)
return
}
}
// 执行shell,获取wan口信息正则匹配ip
func getLocalIP() (ip string) {
commandStr := "ifconfig pppoe-wan"
cmd := exec.Command("/bin/bash", "-c", commandStr)
stdout, _ := cmd.StdoutPipe()
if err := cmd.Start(); err != nil {
return ""
}
outBytes, _ := ioutil.ReadAll(stdout)
stdout.Close()
if err := cmd.Wait(); err != nil {
fmt.Println("Execute failed when Wait:" + err.Error())
return ""
}
ifconfig := string(outBytes)
pattern := `inet addr:(\d+\.\d+\.\d+\.\d+)`
reg := regexp.MustCompile(pattern)
match := reg.FindString(ifconfig)
if match != "" {
pattern = `\d+\.\d+\.\d+\.\d+`
reg = regexp.MustCompile(pattern)
return reg.FindString(match)
}
return
}
// 获取DNS记录ID
func getDnsRecordId(apiKey string, zoneId string, domain string ) (recordId string, lastContent string, e error) {
api := "https://api.cloudflare.com/client/v4/zones/%s/dns_records"
api = fmt.Sprintf(api, zoneId)
requestHeader := map[string]string{
// Bearer后有1空格
"Authorization" : "Bearer " + apiKey,
}
code, resBody, _, er := JsonCurl("GET", api, nil, requestHeader)
if er != nil {
e = er
return
}
var dnsRecords GetDnsRecords
err := json.Unmarshal(resBody, &dnsRecords)
if code!= 200 || err != nil || dnsRecords.Success != true {
e = err
return
}
for _, value := range dnsRecords.Result {
if value.Name == domain {
recordId = value.Id
lastContent = value.Content
return
}
}
return
}
/*
* @Description: 修改dns
* @param dnsType string A记录传"A"
* @param name string 具体域名
* @param content string 解析到内容例如IP
* @param proxied bool 是否代理传
* @author ""
* @date 2022-05-04 15:30:00
*/
func putDnsRecord(zoneId string, apiKey string, recordId string, dnsType string, name string, content string, proxied bool) (bool,error) {
putDns := PutDns{
Type: dnsType,
Name: name,
Content: content,
Proxied: proxied,
}
api := `https://api.cloudflare.com/client/v4/zones/%s/dns_records/%s`
api = fmt.Sprintf(api, zoneId, recordId)
requestHeader := map[string]string{
// Bearer后有1空格
"Authorization" : "Bearer " + apiKey,
}
_, resBody, _, er := JsonCurl("PUT", api, putDns, requestHeader)
if er != nil {
return false, er
}
var dnsRecords PutDnsRecordResponse
err := json.Unmarshal(resBody, &dnsRecords)
if err != nil {
// 记录日志
return false, err
}
if dnsRecords.Success != true {
return false,errors.New( fmt.Sprintf("resBody: %s, url: %s, apiKey: %s", string(resBody) , api, apiKey))
}
return true, nil
}
func JsonCurl(method, url string, body interface{}, headers map[string]string) (code int, data []byte, respHeader http.Header, error error) {
jsonStr, _ := json.Marshal(body)
buffer := bytes.NewBuffer(jsonStr)
request, err := http.NewRequest(method, url, buffer)
if err != nil {
error = err
return
}
request.Header.Set("Content-Type", "application/json;charset=UTF-8")
for key, val := range headers {
request.Header.Set(key, val)
}
resp, err := http.DefaultClient.Do(request)
defer resp.Body.Close()
if err != nil {
error = err
return
}
code = resp.StatusCode
data, _ = ioutil.ReadAll(resp.Body)
respHeader = resp.Header
return
}
func writeIpToFile(fileName string, content string) error {
f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
if err != nil {
return err
} else {
n, _ := f.Seek(0, os.SEEK_END)
_, e := f.WriteAt([]byte(content), n)
defer f.Close()
if e != nil {
return e
}
}
return nil
}
golang实现请求cloudflare修改域名A记录解析的更多相关文章
- Charles系列三:Charles打断点(包含修改请求,修改返回的内容),模拟慢速网络(弱网测试),域名映射,过滤请求,接口调试,打压测试
一:Charles断点的使用(包含修改请求,修改返回的数据) 设置断点来修改请求和返回的数据,在开发过程中可以模拟多种响应.步骤如下: 1.添加断点方法有两种: 方法1:找到Charles中菜单项Pr ...
- DNS安全浅议、域名A记录(ANAME),MX记录,CNAME记录
相关学习资料 http://baike.baidu.com/link?url=77B3BYIuVsB3MpK1nOQXI-JbS-AP5MvREzSnnedU7F9_G8l_Kvbkt_O2gKqFw ...
- DNS安全浅议、域名A记录(ANAME),MX记录,CNAME记录(转)
http://www.cnblogs.com/LittleHann/p/3828927.html 相关学习资料 http://baike.baidu.com/link?url=77B3BYIuVsB3 ...
- 解释-DNS,A记录,CNAME记录,域名转向,SRV记录,TTL值,泛域名与泛解析,域名绑定
http://www.lihongye.net/post/dns.html DNS DNS,Domain Name System或者Domain Name Service(域名系统或者域名服务).域名 ...
- DNS安全浅议、域名A记录(ANAME),MX记录,CNAME记录 专题
首先要做的就是配置域名的MX 记录啦: 先添加一条A记录: mail.abc.com 指向 你的服务器IP! 然后添加域名的MX 记录,指向mail.abc.com A 记录( 即域名MX 记录的值为 ...
- salesforce 零基础学习(六十九)当新增/修改一条记录以后发生了什么(适合初学者)
salesforce开发中,我们会对object进行很多的操作,比如对object设置字段的必填性唯一性等,设置validation rule实现一下相关的字段的逻辑校验,设置workflow实现某个 ...
- cdnbest获取,删除,增加,修改域名列表,高级设置api示例
<?php $uid = 28; $vhost = 'asdfw'; $token = getToken($uid, $vhost); print_r($token); //获取token fu ...
- 修改window本地hosts文件,修改域名指向
Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Host ...
- SVN如何查看修改的文件记录] 来源:Linux社区 作者:frogoscar
SVN如何查看修改的文件记录 [日期:2014-11-20] 来源:Linux社区 作者:frogoscar [字体:大 中 小] 主要是有四个命令,svn log用来展示svn 的版本作者 ...
- 修改sphinx最大输出记录数
修改sphinx最大输出记录数 归纳如下: Sphinx的查询默认最大记录数是:1000,而我们想更改这个数值.就需要更改三个地方. 1是更改sphinx.conf配置文件的:max_matches ...
随机推荐
- zzul1073_Java
import java.util.Scanner;/** * 限制解是正数,且脚数为偶数即可 */public class zzul1073 { public static void main(Str ...
- CH32F103C8T6调试口Disable后的修复办法
1.问题描述 因为软件编程,将CH32F103的 debug disable了,无法通过仿真器下载程序. 2. 修复 2.1 解决思路 利用厂家给的串口ISP进行下载(HUSB或者COM) 2.2 硬 ...
- 「SOL」Quick Tortoise (Codeforces)
只能说没想到 题面 给出一个 \(n\times m\) 的网格图,每个格子要么是空地要么是障碍. 给出 \(q\) 个询问,每次给出 \((sx, sy),(ex,ey)\),问从 \((sx,sy ...
- 7.26-javascript
折半查找:数据必须有序 //数组定义 let arr1 = [1,2,3,4,5]; //用字面量定义数组 let arr2 = new Array(1,2,3,4,5); //用字面量定义数组 le ...
- c语言container_of 编译报错
求指针ptr所在的结构体实例的首地址, #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define co ...
- Jmeter:随机类函数
一.__Random 功能介绍:计算范围内的随机数 ${__Random(参数 1,参数 2,参数 3)} 参数 1:开始数字,包括在内 参数 2:结束数字,包括在内 参数 3:注册变量名称 二._ ...
- Vue中使用model属性
model属性接收两个参数 类型:{ prop?: string, event?: string } prop 也就是调用该组件的父组件中使用v-model指令绑定的属性 event 对应的是修改pr ...
- django admin 字段设置
来源:http://xieboke.net/article/100/ django admin 后台里有些输入框长度.宽度.提示语等,可能不满足我们的需求,这个时候,我们就需要对 admin 的样式进 ...
- python翻译(二)
百度翻译,通过设置参数可可以实现翻译为指定语种 baidujs1.js var i = "320305.131321201" function n(r, o) { for (var ...
- centos下安装部署nginx
1.在安装Nginx之前,要确保已经安装了需要的软件:gcc.pcre-devel.zlib-devel.openssl-devel.如果没有安装,执行下面命令. yum -y install gcc ...