go语言中强大的DNS库

github.com/miekg/dns

简介

github.com/miekg/dns 是一个用于 Go 语言的 DNS 库,它提供了丰富的功能来处理 DNS 查询、响应、解析和构建 DNS 消息。

这个库非常灵活和强大,被广泛用于构建 DNS 客户端和服务器应用程序。

主要功能

  1. DNS 查询与响应:
    • 支持各种类型的 DNS 查询(如 A、AAAA、MX、NS、TXT 等)。
    • 支持发送和接收 DNS 消息。
  2. DNS 消息构建与解析:
    • 提供便捷的方法来构建 DNS 消息(如请求和响应)。
    • 能够解析 DNS 消息并提取所需信息。
  3. DNS 服务器:
    • 可以用来构建自定义的 DNS 服务器。
    • 支持处理多种类型的 DNS 请求。
  4. 扩展性:
    • 支持扩展和自定义,允许用户添加自己的功能和处理逻辑。

官网

https://github.com/miekg/dns

安装

go get github.com/miekg/dns

使用

作为客户端

基础使用

获取各种查询记录

package main

import (
	"fmt"

	"github.com/miekg/dns"
)

var (
	msg       = new(dns.Msg)
	dnsServer = "223.6.6.6:53"
	client    = new(dns.Client)
)

// 获取 A 记录
func ResolveARecord(domain string) error {
	// 创建 DNS 消息

	msg.SetQuestion(dns.Fqdn(domain), dns.TypeA)

	// 发送 DNS 查询
	response, _, err := client.Exchange(msg, dnsServer)
	if err != nil {
		fmt.Printf("Failed to query DNS for %s: %v\n", domain, err)
		return err
	}

	// 处理响应
	if response.Rcode != dns.RcodeSuccess {
		fmt.Printf("DNS query failed with Rcode %d\n", response.Rcode)
		return fmt.Errorf("DNS query failed with Rcode %d", response.Rcode)
	}

	// 打印 A 记录
	for _, ans := range response.Answer {
		if aRecord, ok := ans.(*dns.A); ok {
			fmt.Printf("A record for %s: %s\n", domain, aRecord.A.String())
		}
	}
	return nil
}

// 获取 AAAA 记录
func ResolveAAAARecord(domain string) error {
	// 创建 DNS 消息

	msg.SetQuestion(dns.Fqdn(domain), dns.TypeAAAA)

	// 发送 DNS 查询
	response, _, err := client.Exchange(msg, dnsServer)
	if err != nil {
		fmt.Printf("Failed to query DNS for %s: %v\n", domain, err)
		return err
	}

	// 处理响应
	if response.Rcode != dns.RcodeSuccess {
		fmt.Printf("DNS query failed with Rcode %d\n", response.Rcode)
		return fmt.Errorf("DNS query failed with Rcode %d", response.Rcode)
	}

	// 打印 AAAA 记录
	for _, ans := range response.Answer {
		if aRecord, ok := ans.(*dns.AAAA); ok {
			fmt.Printf("AAAA record for %s: %s\n", domain, aRecord.AAAA.String())
		}
	}
	return nil
}

// 获取 TXT 记录
func ResolveTXTRecord(domain string) error {
	// 创建 DNS 消息

	msg.SetQuestion(dns.Fqdn(domain), dns.TypeTXT)

	// 发送 DNS 查询
	response, _, err := client.Exchange(msg, dnsServer)
	if err != nil {
		fmt.Printf("Failed to query DNS for %s: %v\n", domain, err)
		return err
	}

	// 处理响应
	if response.Rcode != dns.RcodeSuccess {
		fmt.Printf("DNS query failed with Rcode %d\n", response.Rcode)
		return fmt.Errorf("DNS query failed with Rcode %d", response.Rcode)
	}

	// 打印 TXT 记录
	for _, ans := range response.Answer {
		if aRecord, ok := ans.(*dns.TXT); ok {
			for _, txt := range aRecord.Txt {
				fmt.Printf("TXT record for %s: %s\n", domain, txt)
			}
		}
	}
	return nil
}

// 获取 NS 记录
func ResolveNSRecord(domain string) error {
	// 创建 DNS 消息

	msg.SetQuestion(dns.Fqdn(domain), dns.TypeNS)

	// 发送 DNS 查询
	response, _, err := client.Exchange(msg, dnsServer)
	if err != nil {
		fmt.Printf("Failed to query DNS for %s: %v\n", domain, err)
		return err
	}

	// 处理响应
	if response.Rcode != dns.RcodeSuccess {
		fmt.Printf("DNS query failed with Rcode %d\n", response.Rcode)
		return fmt.Errorf("DNS query failed with Rcode %d", response.Rcode)
	}

	// 打印 TXT 记录
	for _, ans := range response.Answer {
		if aRecord, ok := ans.(*dns.NS); ok {
			fmt.Printf("NS record for %s: %s\n", domain, aRecord.Ns)
		}
	}
	return nil
}

func main() {
	// 要查询的域名
	domain := "www.baidu.com"
	ResolveARecord(domain)
	ResolveAAAARecord(domain)
	ResolveTXTRecord(domain)
	ResolveNSRecord(domain)
}

设置查询超时和开启递归查询

package main

import (
	"fmt"
	"time"

	"github.com/miekg/dns"
)

var (
	msg       = new(dns.Msg)
	dnsServer = "223.6.6.6:53"
	client    = new(dns.Client)
)

func ResolveARecord(domain string) error {
	// 设置解析超时
	client.Timeout = 5 * time.Second
	// 设置允许递归查询
	msg.RecursionAvailable = true
	// 创建 DNS 查询
	msg.SetQuestion(dns.Fqdn(domain), dns.TypeA)

	// 发送 DNS 查询
	response, _, err := client.Exchange(msg, dnsServer)
	if err != nil {
		fmt.Printf("Failed to query DNS for %s: %v\n", domain, err)
		return err
	}

	// 处理响应
	if response.Rcode != dns.RcodeSuccess {
		fmt.Printf("DNS query failed with Rcode %d\n", response.Rcode)
		return fmt.Errorf("DNS query failed with Rcode %d", response.Rcode)
	}

	// 打印 A 记录
	for _, ans := range response.Answer {
		if aRecord, ok := ans.(*dns.A); ok {
			fmt.Printf("A record for %s: %s\n", domain, aRecord.A.String())
		}
	}
	return nil
}

func main() {
	// 要查询的域名
	domain := "www.baidu.com"
	err := ResolveARecord(domain)
	if err != nil {
		fmt.Println(err)
	}
}

指定源地址

package main

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

var (
	msg       = new(dns.Msg)
	dnsServer = "192.168.140.3:53"
	client    = new(dns.Client)
)

func ResolveARecord(domain string) error {
	// 新建本地源地址和端口
	dialer := &net.Dialer{
		LocalAddr: &net.UDPAddr{
			IP:   net.ParseIP("192.168.140.90"),
			Port: 3333,
		},
	}
	client.Dialer = dialer
	// 设置允许递归查询
	msg.RecursionAvailable = true
	// 创建 DNS 查询
	msg.SetQuestion(dns.Fqdn(domain), dns.TypeA)

	// 发送 DNS 查询
	response, _, err := client.Exchange(msg, dnsServer)
	if err != nil {
		fmt.Printf("Failed to query DNS for %s: %v\n", domain, err)
		return err
	}

	// 处理响应
	if response.Rcode != dns.RcodeSuccess {
		fmt.Printf("DNS query failed with Rcode %d\n", response.Rcode)
		return fmt.Errorf("DNS query failed with Rcode %d", response.Rcode)
	}

	// 打印 A 记录
	for _, ans := range response.Answer {
		if aRecord, ok := ans.(*dns.A); ok {
			fmt.Printf("A record for %s: %s\n", domain, aRecord.A.String())
		}
	}
	return nil
}

func main() {
	// 要查询的域名
	domain := "www.baidu.com"
	err := ResolveARecord(domain)
	if err != nil {
		fmt.Println(err)
	}
}

也可以不指定端口,不指定端口的情况下,端口会随机产生

使用 EDNS0 Client Subnet

什么是 EDNS0 Client Subnet

EDNS0 (Extension Mechanisms for DNS, version 0) 是一种扩展DNS协议的方式,它允许客户端和服务器之间传输超过原始DNS协议限制的数据量(512字节)。这使得DNS能够支持更多的功能和更复杂的数据交换。

其中,“Client Subnet”(CS)是EDNS0的一个选项,它的主要目的是为了提高DNS解析的地理定位准确性。
Client Subnet选项允许递归解析器(客户端)向权威DNS服务器报告发起请求的客户端的部分IP地址信息。
这样,权威服务器可以根据客户端的大致地理位置来选择最佳的IP地址响应,通常是为了提供更快的服务或遵守地理限制政策。

主要特点:

  1. 提高性能:通过提供客户端的位置信息,权威服务器可以更好地选择接近客户端的服务器或内容。
  2. 隐私保护:Client Subnet只发送部分IP地址信息,而不是完整的IP地址,以此减少隐私泄露的风险。
  3. 地理定位服务:对于需要根据用户地理位置提供服务的情况非常有用,例如CDN(内容分发网络)会选择最近的内容节点。

工作原理:

  • 当客户端向递归解析器发送DNS查询时,递归解析器会附加一个包含部分客户端IP地址信息的EDNS0 Client Subnet选项。
  • 权威服务器收到这个带有Client Subnet选项的查询后,会使用这些位置信息来决定返回哪个IP地址给客户端。
  • 返回的结果通常是离客户端最近的服务器的IP地址,以优化响应时间和用户体验。

总的来说,EDNS0 Client Subnet是一种有效提升DNS解析性能和准确性的技术,尤其适用于那些需要根据用户地理位置来提供服务的应用场景。

使用 EDNS0 Client Subnet

准备一个地址,这里是使用了一个广州移动的ip 211.136.192.6

那么解析的ip,就也是广州移动的IP

前提是 DNS服务是支持 EDNS0 Client Subnet,并且被解析的域名是有配置多地域多线路

package main

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

var (
	msg       = new(dns.Msg)
	dnsServer = "223.5.5.5:53"
	client    = new(dns.Client)
)

func ResolveARecord(domain string) error {
	// 开始创建OPT记录
	opt := new(dns.OPT)
	opt.Hdr.Name = "."
	opt.Hdr.Rrtype = dns.TypeOPT
	ip := net.ParseIP("211.136.192.6")
	if ip == nil {
		fmt.Println("Invalid IP address")
		return fmt.Errorf("Invalid IP address")
	}
	ecs := new(dns.EDNS0_SUBNET)
	if ip.To4() != nil {
		ecs = &dns.EDNS0_SUBNET{
			Code:          dns.EDNS0SUBNET,
			Family:        1, // 1 表示 IPv4,2 表示 IPv6
			SourceNetmask: 24,
			SourceScope:   0,
			Address:       ip.To4(),
		}
	} else {
		ecs = &dns.EDNS0_SUBNET{
			Code:          dns.EDNS0SUBNET,
			Family:        2, // 1 表示 IPv4,2 表示 IPv6
			SourceNetmask: 56,
			SourceScope:   0,
			Address:       ip.To16(),
		}
	}

	// 创建EDNS0客户端子网选项
	opt.Option = append(opt.Option, ecs)
	msg.Extra = append(msg.Extra, opt)
	// 设置允许递归查询
	msg.RecursionAvailable = true
	// 创建 DNS 查询
	msg.SetQuestion(dns.Fqdn(domain), dns.TypeA)

	// 发送 DNS 查询
	response, _, err := client.Exchange(msg, dnsServer)
	if err != nil {
		fmt.Printf("Failed to query DNS for %s: %v\n", domain, err)
		return err
	}

	// 处理响应
	if response.Rcode != dns.RcodeSuccess {
		fmt.Printf("DNS query failed with Rcode %d\n", response.Rcode)
		return fmt.Errorf("DNS query failed with Rcode %d", response.Rcode)
	}

	// 打印 A 记录
	for _, ans := range response.Answer {
		if aRecord, ok := ans.(*dns.A); ok {
			fmt.Printf("A record for %s: %s\n", domain, aRecord.A.String())
		}
	}
	return nil
}

func main() {
	// 要查询的域名
	domain := "www.baidu.com"
	err := ResolveARecord(domain)
	if err != nil {
		fmt.Println(err)
	}
}

对响应做一些判断

package main

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

var (
	msg       = new(dns.Msg)
	dnsServer = "223.5.5.5:53"
	client    = new(dns.Client)
)

func ResolveARecord(domain string) error {
	// 设置允许递归查询
	msg.RecursionAvailable = true
	// 创建 DNS 查询
	msg.SetQuestion(dns.Fqdn(domain), dns.TypeA)

	// 发送 DNS 查询
	response, _, err := client.Exchange(msg, dnsServer)
	if err != nil {
		fmt.Printf("Failed to query DNS for %s: %v\n", domain, err)
		return err
	}

	// 处理响应 判断是否解析成功
	if response.Rcode != dns.RcodeSuccess {
		fmt.Printf("DNS query failed with Rcode %d\n", response.Rcode)
		return fmt.Errorf("DNS query failed with Rcode %d", response.Rcode)
	}
	// 判断是否来自权威服务器
	if response.Authoritative {
		fmt.Println("来自权威服务器")
	}
	// 判断是否递归查询
	if response.RecursionAvailable {
		fmt.Println("这是递归查询")
	}

	// 打印 A 记录
	for _, ans := range response.Answer {
		if aRecord, ok := ans.(*dns.A); ok {
			fmt.Printf("A record for %s: %s\n", domain, aRecord.A.String())
		}
	}
	return nil
}

func main() {
	// 要查询的域名
	domain := "www.baidu.com"
	err := ResolveARecord(domain)
	if err != nil {
		fmt.Println(err)
	}
}

作为服务端

package main

import (
	"log"
	"net"

	"github.com/miekg/dns"
)

func main() {
	// 注册 DNS 请求处理函数
	dns.HandleFunc(".", handleDNSRequest)

	// 设置服务器地址和协议
	server := &dns.Server{Addr: ":53", Net: "udp"}
	log.Printf("Starting DNS server on %s\n", server.Addr)
	if err := server.ListenAndServe(); err != nil {
		log.Fatalf("Failed to start DNS server: %v\n", err)
	}
}

// 处理 DNS 请求的函数
func handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
	msg := new(dns.Msg)
	msg.SetReply(r)
    // 将 DNS 响应标记为权威应答
	msg.Authoritative = true
    // 将 DNS 响应标记为递归可用
    // msg.RecursionAvailable = true
    
	// 遍历请求中的问题部分,生成相应的回答
	for _, question := range r.Question {
        fmt.Println("请求解析的域名:", question.Name)
		switch question.Qtype {
		case dns.TypeA:
			handleARecord(question, msg)
		case dns.TypeAAAA:
			handleAAAARecord(question, msg)
			// 你可以在这里添加其他类型的记录处理逻辑
		}
	}

	w.WriteMsg(msg)
}

// 构建 A 记录的函数
func handleARecord(q dns.Question, msg *dns.Msg) {
	ip := net.ParseIP("192.0.2.1")
	rr := &dns.A{
		Hdr: dns.RR_Header{
			Name:   q.Name,
			Rrtype: dns.TypeA,
			Class:  dns.ClassINET,
			Ttl:    600,
		},
		A: ip,
	}
	msg.Answer = append(msg.Answer, rr)
}

func handleAAAARecord(q dns.Question, msg *dns.Msg) {
	ip := net.ParseIP("240c::6666")
	rr := &dns.AAAA{
		Hdr: dns.RR_Header{
			Name:   q.Name,
			Rrtype: dns.TypeAAAA,
			Class:  dns.ClassINET,
			Ttl:    600,
		},
		AAAA: ip,
	}
	msg.Answer = append(msg.Answer, rr)
}

详细说明

  1. 注册 DNS 请求处理函数

    dns.HandleFunc(".", handleDNSRequest)
    

    注册一个处理函数 handleDNSRequest,它将处理所有的 DNS 请求("." 表示所有域名)。

  2. 设置服务器地址和协议

    server := &dns.Server{Addr: ":53", Net: "udp"}
    

    创建一个 DNS 服务器,监听 :53 端口并使用 UDP 协议。

  3. 启动服务器

    log.Printf("Starting DNS server on %s\n", server.Addr)
    if err := server.ListenAndServe(); err != nil {
        log.Fatalf("Failed to start DNS server: %v\n", err)
    }
    

    启动服务器并开始监听传入的 DNS 请求。

  4. 处理 DNS 请求的函数

    func handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
        msg := new(dns.Msg)
        msg.SetReply(r)
        msg.Authoritative = true
    
        for _, question := range r.Question {
            switch question.Qtype {
            case dns.TypeA:
                handleARecord(question, msg)
            }
        }
    
        w.WriteMsg(msg)
    }
    

    这个函数处理传入的 DNS 请求。它会根据请求中的问题(r.Question)生成响应消息,并将其发送回客户端。

  5. 构建 A 记录的函数

    func handleARecord(q dns.Question, msg *dns.Msg) {
        ip := net.ParseIP("192.0.2.1")
        rr := &dns.A{
            Hdr: dns.RR_Header{
                Name:   q.Name,
                Rrtype: dns.TypeA,
                Class:  dns.ClassINET,
                Ttl:    600,
            },
            A: ip,
        }
        msg.Answer = append(msg.Answer, rr)
    }
    

    生成一个 A 记录的响应,其中 IP 地址为 192.0.2.1,并将其添加到响应消息中。

处理其他类型的 DNS 记录

你可以扩展 handleDNSRequest 函数来处理其他类型的 DNS 记录,例如 CNAME、MX、TXT 等。只需在 switch 语句中添加相应的处理函数:

switch question.Qtype {
case dns.TypeA:
    handleARecord(question, msg)
case dns.TypeCNAME:
    handleCNAMERecord(question, msg)
case dns.TypeMX:
    handleMXRecord(question, msg)
case dns.TypeTXT:
    handleTXTRecord(question, msg)
}

然后为每种记录类型编写相应的处理函数,例如:

func handleCNAMERecord(q dns.Question, msg *dns.Msg) {
    rr := &dns.CNAME{
        Hdr: dns.RR_Header{
            Name:   q.Name,
            Rrtype: dns.TypeCNAME,
            Class:  dns.ClassINET,
            Ttl:    600,
        },
        Target: "example.com.",
    }
    msg.Answer = append(msg.Answer, rr)
}

func handleMXRecord(q dns.Question, msg *dns.Msg) {
    rr := &dns.MX{
        Hdr: dns.RR_Header{
            Name:   q.Name,
            Rrtype: dns.TypeMX,
            Class:  dns.ClassINET,
            Ttl:    600,
        },
        Preference: 10,
        Mx:         "mail.example.com.",
    }
    msg.Answer = append(msg.Answer, rr)
}

func handleTXTRecord(q dns.Question, msg *dns.Msg) {
    rr := &dns.TXT{
        Hdr: dns.RR_Header{
            Name:   q.Name,
            Rrtype: dns.TypeTXT,
            Class:  dns.ClassINET,
            Ttl:    600,
        },
        Txt: []string{"v=spf1 include:_spf.example.com ~all"},
    }
    msg.Answer = append(msg.Answer, rr)
}

通过这种方式,你可以构建一个功能全面的自定义 DNS 服务器,能够处理多种类型的 DNS 查询并返回相应的响应。

修改或伪造DNS 响应

package main

import (
	"fmt"
	"log"
	"net"

	"github.com/miekg/dns"
)

func main() {
	// 注册 DNS 请求处理函数
	dns.HandleFunc(".", HandleDNSRequest)

	// 设置服务器地址和协议
	server := &dns.Server{Addr: ":53", Net: "udp"}
	log.Printf("Starting DNS server on %s\n", server.Addr)
	if err := server.ListenAndServe(); err != nil {
		log.Fatalf("Failed to start DNS server: %v\n", err)
	}
}

func HandleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
	c := new(dns.Client)
	c.Net = "udp"

	var upstreamDNS string
	if w.RemoteAddr().(*net.UDPAddr).IP.To4() != nil {
		upstreamDNS = "192.168.140.3:53"
	} else {
		upstreamDNS = "[240c::6666]:53"
	}

	resp, _, err := c.Exchange(r, upstreamDNS)
	if err != nil {
		fmt.Printf("查询上游DNS时出错: %v\n", err)
		return
	}

	for _, question := range resp.Question {
		fmt.Println("查询的域名:", question.Name)
		if question.Name == "www.baidu.com." {
			// 修改响应中的 A 和 AAAA 记录
			for _, answer := range resp.Answer {
				switch rr := answer.(type) {
				case *dns.A:
					fmt.Printf("替换前的A类型地址: %s\n", rr.A.String())
					rr.A = net.ParseIP("1.2.3.4")
					fmt.Printf("替换后的A类型地址: %s\n", rr.A.String())
				case *dns.AAAA:
					fmt.Printf("替换前的AAAA类型地址: %s\n", rr.AAAA.String())
					rr.AAAA = net.ParseIP("::1")
					fmt.Printf("替换后的AAAA类型地址: %s\n", rr.AAAA.String())
				}
			}
		}
	}

	w.WriteMsg(resp)
}

本地监听在53端口接收DNS请求,并将请求转发给上游DNS服务器。
当发现请求解析的域名是www.baidu.com时,会修改响应中的A和AAAA记录,将其替换为指定的IP地址。
然后返回给客户端

当然,也可以完全自定义DNS记录

package main

import (
	"fmt"
	"log"
	"net"
	"strings"

	"github.com/miekg/dns"
)

func main() {
	// 注册 DNS 请求处理函数
	dns.HandleFunc(".", HandleDNSRequest)

	// 设置服务器地址和协议
	server := &dns.Server{Addr: ":53", Net: "udp"}
	log.Printf("Starting DNS server on %s\n", server.Addr)
	if err := server.ListenAndServe(); err != nil {
		log.Fatalf("Failed to start DNS server: %v\n", err)
	}
}

func HandleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
	c := new(dns.Client)
	c.Net = "udp"

	var upstreamDNS string
	if w.RemoteAddr().(*net.UDPAddr).IP.To4() != nil {
		upstreamDNS = "192.168.140.3:53"
	} else {
		upstreamDNS = "[240c::6666]:53"
	}

	resp, _, err := c.Exchange(r, upstreamDNS)
	if err != nil {
		fmt.Printf("查询上游DNS时出错: %v\n", err)
		return
	}

	var (
		newARecords    = []string{} // 替换的 A 记录地址
		newAAAARecords = []string{} // 替换的 AAAA 记录地址
	)
	// 存储去重后的记录
	var newAnswers []dns.RR
	host := strings.TrimSuffix(r.Question[0].Name, ".")
	for _, question := range resp.Question {
		fmt.Println("查询的域名:", question.Name)
		if host == "www.baidu.com" {
			A := false
			AAAA := false
			for _, answer := range resp.Answer {
				switch rr := answer.(type) {
				case *dns.A:
					fmt.Println("解析的v4原地址:", rr.A.String())
					if A {
						continue
					}
					A = true
				case *dns.AAAA:
					fmt.Println("解析的v6原地址:", rr.AAAA.String())
					if AAAA {
						continue
					}
					AAAA = true
				}
			}
			if A {
				newARecords = append(newARecords, "192.168.1.2")
				// 处理 A 记录
				for _, addr := range newARecords {
					newRR := &dns.A{
						Hdr: dns.RR_Header{
							Name:   r.Question[0].Name,
							Rrtype: dns.TypeA,
							Class:  dns.ClassINET,
							Ttl:    300,
						},
						A: net.ParseIP(addr),
					}
					newAnswers = append(newAnswers, newRR)
				}
				// 替换响应中的记录
				resp.Answer = newAnswers
			}
			if AAAA {
				newAAAARecords = append(newAAAARecords, "2001:1:2:3:4::5")
				// 处理 AAAA 记录
				for _, addr := range newAAAARecords {
					newRR := &dns.AAAA{
						Hdr: dns.RR_Header{
							Name:   r.Question[0].Name,
							Rrtype: dns.TypeAAAA,
							Class:  dns.ClassINET,
							Ttl:    300,
						},
						AAAA: net.ParseIP(addr),
					}
					newAnswers = append(newAnswers, newRR)
				}
				// 替换响应中的记录
				resp.Answer = newAnswers
			}
		}
	}

	w.WriteMsg(resp)
}

这里实现了一个 DNS 服务器,通过 HandleDNSRequest 函数处理传入的 DNS 请求,并根据请求的域名和类型替换响应中的记录。
如果查询的是 www.baidu.com,且存在 A 记录或 AAAA 记录,则将这些记录分别替换为伪造的 IP 地址 192.168.1.2 和 2001:1:2:3:4::5。

posted @   厚礼蝎  阅读(853)  评论(0编辑  收藏  举报
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
历史上的今天:
2023-07-17 Go 标准库net-url
2023-07-17 go中http客户端设置当响应码为3xx时禁止自动跳转
2023-07-17 解决go中http客户端请求遇到tls: server selected unsupported protocol version 301错误
2023-07-17 go中http设置忽略证书
2023-07-17 go中http如何解决跳转自动携带cookie的问题
点击右上角即可分享
微信分享提示