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 ...
随机推荐
- go简单写个ini配置文件读取工具
直接上代码: 1 package main 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "reflect" 7 ...
- redis 0: "AUTH <password> called without any password configured for the def
运行项目的时候,报redis 0: "AUTH <password> called without any password configured for the def 原因: ...
- Linux 软件包 管理
rpm.deb包管理操作 yum.apt/apt-get线上管理操作 查找软件包 $ yum search [name|info] $ apt-cache search [name|info] 安装软 ...
- 利用拉格朗日乘子法从最优化问题中推导出KKT条件
优化问题的一般形式 在优化问题中,我们将其一般形式定义为有约束(不等式约束.等式约束)的最小化优化问题,其具体定义如下: \[\begin{array}{ll} \min _{x} & f_{ ...
- Java语言打印空心菱形
打印空心菱形如果一开始觉得比较困难的话,那么不妨分成几个步骤走完成菱形的打印. 1.先打印一个直角三角形(都是由星星组成的) 代码如下: import java.util.Scanner;//导入Sc ...
- 12组-Beta冲刺-2/5
一.基本情况 队名:字节不跳动 组长博客:https://www.cnblogs.com/147258369k/p/15594989.html Github链接:https://github.com/ ...
- NGINX一次电脑自己可以访问其它IP访问不了
配制好NGINX 本地电脑curl http..... 正常访问...其它电脑不可以 第一想法防火墙 查一下 firewall-cmd --state not running 然后查下是不是服务开启 ...
- 在百度云服务器上部署Django网站的经历
前言: 前段时间,利用Django为单位制作了一个小型的内部考勤系统,本想放到单位内部的服务器上,考虑到运行的稳定.安全防护等问题,最终决定把网站部署到百度云服务器上,事先也在网上查找了一些资料,但过 ...
- for in 和 for of 的区别(枚举解释)
一.for....of 1.for-of是作为ES6新增的遍历方式,允许遍历一个含有iterator接口的数据结构(数组.对象等)并且返回各项的值,普通的对象用for-of遍历是会报错的. 2.for ...
- Nginx基础篇
目录 一.nginx基础篇 1.Nginx开源版本安装 2.Nginx的基础配置 3.虚拟主机与域名解析 4.ServerName匹配规则 5.反向代理 6.动静分离 7.location后符号的匹配 ...