Golang中DNS CNAME记录的创建与配置

Golang中DNS CNAME记录的创建与配置 各位社区极客们好,

我是Go语言的新手,正在尝试用Go编写一个自动化脚本。 我们是一组管理员,在我们的DNS服务器上有一个托管区域。有时我们需要为用户可读性创建CNAME记录。我有手动执行此任务的有效凭据。但尝试用Go来自动化这个过程时,它就是不工作。

package main

import (
	"fmt"
	"github.com/miekg/dns"
	// "golang.org/x/net/context"
	"net"
	//"crypto/tls"
	//"golang.org/x/net/idna"
)

func main() {

	dnsServer := "subdomain.domain.com"
	dnsUsername := "111111-adm"
	dnsPassword := "*******"


	domain := "subdomain.domain.com"
	cnameName := "prettydns-demo.subdomain.domain.com"
	cnameData := "actual-cname.subdomain.domain.com"

	msg := dns.Msg{}
	msg.SetUpdate(domain)

	cnameRecord := &dns.CNAME{
		Hdr: dns.RR_Header{
			Name:   dns.Fqdn(cnameName),
			Rrtype: dns.TypeCNAME,
			Class:  dns.ClassINET,
			Ttl:    300,
		},
		Target: cnameData,
	}

        msg.Insert([]dns.RR{cnameRecord})

	serverAddr := dnsServer + ":53"

        // Open a TCP connection to the DNS server
	conn, err := net.Dial("tcp", serverAddr)
	if err != nil {
		fmt.Printf("Error opening TCP connection: %v\n", err)
		return
	}

	defer conn.Close()

	// Send the update message to the DNS server
	_, err = conn.Write([]byte(fmt.Sprintf("%s:%s", dnsUsername, dnsPassword)))
	if err != nil {
		fmt.Printf("Error sending update request: %v\n", err)
		return
	}

	// Read the response from the DNS server Over tcp
	responseBytes := make([]byte, 1024)
	n, err := conn.Read(responseBytes)
	if err != nil {
		fmt.Printf("Error reading response: %v\n", err)
		return
	}

	response, err := client.ReadMsg(conn)
	if err != nil {
		fmt.Printf("Error reading response: %v\n", err)
		return
	}
	if response != nil && response.Rcode == dns.RcodeSuccess {
		fmt.Println("CNAME record created successfully!")
	} else {
		fmt.Println("Error creating CNAME record.")
	}
}

我之前没有Go语言的经验,所以如果我问了什么愚蠢的问题,我为此道歉。我只是从谷歌搜索中尝试了很多方法,但就是不行。对此的任何帮助对我来说都将是一次很好的学习。


更多关于Golang中DNS CNAME记录的创建与配置的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

感谢您的回答。然而,即使我尝试修正了所有这些,我仍然无法完成这项工作。不确定在身份验证方面我需要做什么。

更多关于Golang中DNS CNAME记录的创建与配置的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你的代码能编译吗?我遇到了两个错误:

n, err := conn.Read(responseBytes)

n 未被使用,并且

response, err := client.ReadMsg(conn)

client 未定义…

使用 miekg/dns 库进行 DNS 更新时,需要正确配置 TSIG 认证和 DNS 客户端。以下是修正后的代码示例:

package main

import (
    "fmt"
    "github.com/miekg/dns"
)

func main() {
    dnsServer := "subdomain.domain.com"
    domain := "subdomain.domain.com"
    cnameName := "prettydns-demo.subdomain.domain.com"
    cnameData := "actual-cname.subdomain.domain.com"

    // 创建 TSIG 密钥(需要与 DNS 服务器配置匹配)
    secret := "your-tsig-secret-key"
    tsigKey := dns.Fqdn("tsig-key-name") + ":" + dns.HmacMD5
    
    // 配置客户端
    client := new(dns.Client)
    client.TsigSecret = map[string]string{tsigKey: secret}
    client.Net = "tcp" // 或 "udp"

    // 创建更新消息
    msg := new(dns.Msg)
    msg.SetUpdate(dns.Fqdn(domain))
    msg.SetTsig(tsigKey, dns.HmacMD5, 300, time.Now().Unix())

    // 创建 CNAME 记录
    rr := &dns.CNAME{
        Hdr: dns.RR_Header{
            Name:   dns.Fqdn(cnameName),
            Rrtype: dns.TypeCNAME,
            Class:  dns.ClassINET,
            Ttl:    300,
        },
        Target: dns.Fqdn(cnameData),
    }

    // 插入记录
    msg.Insert([]dns.RR{rr})

    // 发送更新请求
    resp, _, err := client.Exchange(msg, dnsServer+":53")
    if err != nil {
        fmt.Printf("DNS update failed: %v\n", err)
        return
    }

    if resp.Rcode == dns.RcodeSuccess {
        fmt.Println("CNAME record created successfully!")
    } else {
        fmt.Printf("DNS update failed with Rcode: %d\n", resp.Rcode)
    }
}

对于不需要 TSIG 的简单更新(使用用户名/密码认证),需要实现自定义认证机制:

package main

import (
    "fmt"
    "github.com/miekg/dns"
    "strings"
)

type authConn struct {
    net.Conn
    username string
    password string
}

func (ac *authConn) Write(b []byte) (int, error) {
    // 添加认证头
    authHeader := fmt.Sprintf("%s:%s\n", ac.username, ac.password)
    _, err := ac.Conn.Write([]byte(authHeader))
    if err != nil {
        return 0, err
    }
    return ac.Conn.Write(b)
}

func main() {
    dnsServer := "subdomain.domain.com:53"
    username := "111111-adm"
    password := "*******"
    domain := "subdomain.domain.com"
    cnameName := "prettydns-demo.subdomain.domain.com"
    cnameData := "actual-cname.subdomain.domain.com"

    // 创建原始连接
    conn, err := net.Dial("tcp", dnsServer)
    if err != nil {
        fmt.Printf("Connection failed: %v\n", err)
        return
    }
    defer conn.Close()

    // 包装连接以添加认证
    authConn := &authConn{
        Conn:     conn,
        username: username,
        password: password,
    }

    // 创建客户端
    client := new(dns.Client)
    client.Net = "tcp"
    client.Conn = authConn

    // 创建更新消息
    msg := new(dns.Msg)
    msg.SetUpdate(dns.Fqdn(domain))

    // 创建 CNAME 记录
    rr := &dns.CNAME{
        Hdr: dns.RR_Header{
            Name:   dns.Fqdn(cnameName),
            Rrtype: dns.TypeCNAME,
            Class:  dns.ClassINET,
            Ttl:    300,
        },
        Target: dns.Fqdn(cnameData),
    }

    msg.Insert([]dns.RR{rr})

    // 发送请求
    resp, _, err := client.Exchange(msg, dnsServer)
    if err != nil {
        fmt.Printf("DNS update failed: %v\n", err)
        return
    }

    if resp.Rcode == dns.RcodeSuccess {
        fmt.Println("CNAME record created successfully!")
    } else {
        fmt.Printf("DNS update failed with Rcode: %d\n", resp.Rcode)
    }
}

如果使用 BIND 的 update-policy 认证,可以使用 TSIG 或 IP 认证。对于 IP 认证的简单示例:

package main

import (
    "fmt"
    "github.com/miekg/dns"
)

func main() {
    dnsServer := "subdomain.domain.com:53"
    domain := "subdomain.domain.com"
    cnameName := "prettydns-demo.subdomain.domain.com"
    cnameData := "actual-cname.subdomain.domain.com"

    client := new(dns.Client)
    client.Net = "tcp"

    msg := new(dns.Msg)
    msg.SetUpdate(dns.Fqdn(domain))

    rr := &dns.CNAME{
        Hdr: dns.RR_Header{
            Name:   dns.Fqdn(cnameName),
            Rrtype: dns.TypeCNAME,
            Class:  dns.ClassINET,
            Ttl:    300,
        },
        Target: dns.Fqdn(cnameData),
    }

    msg.Insert([]dns.RR{rr})

    resp, _, err := client.Exchange(msg, dnsServer)
    if err != nil {
        fmt.Printf("DNS update failed: %v\n", err)
        return
    }

    if resp.Rcode == dns.RcodeSuccess {
        fmt.Println("CNAME record created successfully!")
    } else {
        fmt.Printf("DNS update failed: %v\n", resp)
    }
}

确保 DNS 服务器配置允许来自运行脚本的 IP 地址的更新请求。

回到顶部