现在有些DNS解析要收费,国内的几个厂商需要实名制。下面给出golang请求cloudflare修改域名A记录解析的代码。

准备工作:

  1. 在域名购买服务商处,将dns解析服务器改为cloudflare的dns服务器地址
  2. 将域名添加到cloudflare后台,非cloudflare购买的域名也可以添加!
  3. cloudflare后台获取API KEY;获取区域ID,即代码中用到的zone id ; 代码中需要用到
  4. 在后台先为域名设置一条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记录解析的更多相关文章

  1. Charles系列三:Charles打断点(包含修改请求,修改返回的内容),模拟慢速网络(弱网测试),域名映射,过滤请求,接口调试,打压测试

    一:Charles断点的使用(包含修改请求,修改返回的数据) 设置断点来修改请求和返回的数据,在开发过程中可以模拟多种响应.步骤如下: 1.添加断点方法有两种: 方法1:找到Charles中菜单项Pr ...

  2. DNS安全浅议、域名A记录(ANAME),MX记录,CNAME记录

    相关学习资料 http://baike.baidu.com/link?url=77B3BYIuVsB3MpK1nOQXI-JbS-AP5MvREzSnnedU7F9_G8l_Kvbkt_O2gKqFw ...

  3. DNS安全浅议、域名A记录(ANAME),MX记录,CNAME记录(转)

    http://www.cnblogs.com/LittleHann/p/3828927.html 相关学习资料 http://baike.baidu.com/link?url=77B3BYIuVsB3 ...

  4. 解释-DNS,A记录,CNAME记录,域名转向,SRV记录,TTL值,泛域名与泛解析,域名绑定

    http://www.lihongye.net/post/dns.html DNS DNS,Domain Name System或者Domain Name Service(域名系统或者域名服务).域名 ...

  5. DNS安全浅议、域名A记录(ANAME),MX记录,CNAME记录 专题

    首先要做的就是配置域名的MX 记录啦: 先添加一条A记录: mail.abc.com 指向 你的服务器IP! 然后添加域名的MX 记录,指向mail.abc.com A 记录( 即域名MX 记录的值为 ...

  6. salesforce 零基础学习(六十九)当新增/修改一条记录以后发生了什么(适合初学者)

    salesforce开发中,我们会对object进行很多的操作,比如对object设置字段的必填性唯一性等,设置validation rule实现一下相关的字段的逻辑校验,设置workflow实现某个 ...

  7. cdnbest获取,删除,增加,修改域名列表,高级设置api示例

    <?php $uid = 28; $vhost = 'asdfw'; $token = getToken($uid, $vhost); print_r($token); //获取token fu ...

  8. 修改window本地hosts文件,修改域名指向

    Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Host ...

  9. SVN如何查看修改的文件记录] 来源:Linux社区 作者:frogoscar

    SVN如何查看修改的文件记录 [日期:2014-11-20] 来源:Linux社区  作者:frogoscar [字体:大 中 小]     主要是有四个命令,svn log用来展示svn 的版本作者 ...

  10. 修改sphinx最大输出记录数

    修改sphinx最大输出记录数 归纳如下: Sphinx的查询默认最大记录数是:1000,而我们想更改这个数值.就需要更改三个地方. 1是更改sphinx.conf配置文件的:max_matches ...

随机推荐

  1. vue路由跳转当前路由刷新

    在app.vue里面定义 reload() {         this.isRouterAlive = false         this.$nextTick(function () {      ...

  2. 搭PHP本地环境-windows

    项目中要用php开发,但是本地没环境调试不方便,所以搭一下本期环境. 1.下载php phpstudy工具官网:https://www.xp.cn/.phpstudy和WAMP工具的不同之处在于,ph ...

  3. React.js 修改文本中数字样式

    export function numberToColor(text, color = '#635BFF', size = '12px') { let reg = /(\d+)/g; return t ...

  4. Pytest 插件

    1. 执行标记用例执行次数 首先安装 repeat: pip install pytest-repeat @pytest.mark.repeat(n)执行当前用例 n 次 然后再往下执行其他用例 im ...

  5. spring的aop的粗浅理解

    aop有什么用? 假设你写了一本书,写的是一个平民的日常聊天.现在突然你想让这个平民变成一个书生的口气.于是你想在这个平民的每句话之前加上"之乎",后面加上"者也&quo ...

  6. 星链技术设计(starlink techriage design)

    1.星链  定义:  星链,是美国太空探索技术公司的一个项目,太空探索技术公司计划在2019年至2024年间在太空搭建由约1.2万颗卫星组成的"星链"网络提供互联网服务,其中158 ...

  7. while循环内使用for循环

    一个基础问题,while循环内使用for循环,且当for循环内有控制while循环条件时. 如下所示: bool flag = true; while(flag) { for(i=0;i<10; ...

  8. [转]cfs 调度

    https://www.cnblogs.com/LoyenWang/p/12495319.html 背景 Read the fucking source code! --By 鲁迅 A picture ...

  9. Typora以及Markdown学习

    Typora以及Markdown学习 标题 n级标题 一级标题为#+[空格]+标题或者ctrl+1 二级标题则为``##+[空格]+标题`或者ctrl+2 后续几级标题依此类推... 最多支持6级标题 ...

  10. 第一次写,python爬虫图片,操作excel。

    第一次写博客,其实老早就注册博客园了,有写博客的想法,就是没有行动,总是学了忘,忘了丢,最后啥都没有,电脑里零零散散,东找找,西看看,今天认识到写博客的重要性. 最近闲着看了潭州教育的在线直播课程,颇 ...