现在有些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. JS form表单数据校验及失效情况下的解决方案

    如下图,当执行提交操作之前,我们需要对序号,要求完成时间,责任人,措施内容四项进行非空,字符长度及输入内容的类型进行校验. 直接贴样式代码 <div class="wrapper an ...

  2. “const char*“类型的实参与“LPCWSTR-类型的形参不兼容

    const char *类型的实参与LPCWSTR类型的形参不兼容解决 LPCWSTR类型是是一个指向unicode编码字符串的32位指针,所指向字符串是wchar型(4字节,Unicode编码宽字节 ...

  3. shell脚本实战笔录-在PATH中查找程序

    #!/bin/bashin_path(){ cmd=$1        ourpath=$2         result=1 #将默认的IFS(分隔符)为空格,这里先保留原本的给变量oldIFS,然 ...

  4. vue项目跳转外部链接,替换链接地址参数信息

    //修改url某个指定的参数 url 地址. paramName 参数.   repalceValue替换的新值 replaceUrl( url, paramName, repalceValue){ ...

  5. Gitbook部署

    title: Gitbook部署 # 标题 date: 2020-06-14 08:00:00 借助Gitbook,写自己的第一本电子书 Gitbook部署 一.电脑环境 Git 环境,我的电脑上已经 ...

  6. 安装jdk,tomcat,oracle,PL/SQL的一些问题

    仅限于自己学习使用 新进公司,需要安装jdk1.6,tomcat6, oracle和pl/sql 先是jdk1.6,安装后配置环境变量,都在系统变量里,在cmd,分别打出 java -version, ...

  7. [canvas]ncaught TypeError: Cannot read properties of null (reading 'getContext')

    相信你和我一样是直接复制大佬的js代码(笑) ------------ 主要问题在于:js先加载完了,html才加载,导致js获取不了html的对象 解决办法: 把  <head />  ...

  8. [笔记]gdb调试中一个string变量太长,如何将该string变量完全输出在屏幕上?

    来自 https://stackoverflow.com/questions/233328/how-do-i-print-the-full-value-of-a-long-string-in-gdb ...

  9. usb 2.0的状态跳转图

  10. docker的安装和命令

    一. 认识Docker 我们写的代码会接触好几个环境:开发环境,测试环境以及生产环境 开发环境:程序员开发代码的环境 测试环境:开发完的代码部署到测试环境 给测试人员进行测试 生产环境:测试完成后有运 ...