以下是一个简单的golang DNS中转代码,它将所有针对"www.baidu.com"的DNS请求转发到"119.29.29.29":

package main

import (
	"log"
	"net"
)

func main() {
	// 设置本地DNS服务器地址
	localDNS := net.UDPAddr{
		IP:   net.ParseIP("0.0.0.0"),
		Port: 53,
	}

	// 创建UDP监听器
	conn, err := net.ListenUDP("udp", &localDNS)
	if err != nil {
		log.Fatalf("ListenUDP failed: %v", err)
	}
	defer conn.Close()

	log.Printf("Listening on %s...\n", conn.LocalAddr())

	// 处理DNS请求
	for {
		buf := make([]byte, 512)
		n, remoteAddr, err := conn.ReadFromUDP(buf)
		if err != nil {
			log.Printf("ReadFromUDP failed: %v", err)
			continue
		}

		// 解析DNS请求
		msg := &dnsMsg{}
		if err := msg.parse(buf[:n]); err != nil {
			log.Printf("Failed to parse DNS message: %v", err)
			continue
		}

		// 判断是否为"www.baidu.com"的DNS请求
		if !msg.isQuery() || !msg.isDomain("www.baidu.com") {
			log.Printf("Ignoring non-www.baidu.com DNS request from %s", remoteAddr)
			continue
		}

		// 修改DNS请求的IP地址为"119.29.29.29"
		msg.setIP(net.ParseIP("119.29.29.29"))

		// 回复修改后的DNS响应
		if _, err := conn.WriteToUDP(msg.bytes(), remoteAddr); err != nil {
			log.Printf("Failed to send DNS response: %v", err)
		} else {
			log.Printf("Forwarded www.baidu.com DNS request from %s to 119.29.29.29", remoteAddr)
		}
	}
}

// DNS消息结构体
type dnsMsg struct {
	ID      uint16
	Flags   uint16
	QDCount uint16
	ANCount uint16
	NSCount uint16
	ARCount uint16
	Quest   []dnsQuestion
	Answer  []dnsResource
}

// DNS问题结构体
type dnsQuestion struct {
	Name  string
	Type  uint16
	Class uint16
}

// DNS资源结构体
type dnsResource struct {
	Name     string
	Type     uint16
	Class    uint16
	TTL      uint32
	RDLength uint16
	RData    []byte
}

// 解析DNS消息
func (msg *dnsMsg) parse(buf []byte) error {
	// 解析DNS头部
	msg.ID = uint16(buf[0])<<8 | uint16(buf[1])
	msg.Flags = uint16(buf[2])<<8 | uint16(buf[3])
	msg.QDCount = uint16(buf[4])<<8 | uint16(buf[5])
	msg.ANCount = uint16(buf[6])<<8 | uint16(buf[7])
	msg.NSCount = uint16(buf[8])<<8 | uint16(buf[9])
	msg.ARCount = uint16(buf[10])<<8 | uint16(buf[11])

	// 解析DNS问题
	offset := 12
	for i := 0; i < int(msg.QDCount); i++ {
		name, n := readName(buf, offset)
		offset += n
		qtype := uint16(buf[offset])<<8 | uint16(buf[offset+1])
		qclass := uint16(buf[offset+2])<<8 | uint16(buf[offset+3])
		offset += 4
		msg.Quest = append(msg.Quest, dnsQuestion{Name: name, Type: qtype, Class: qclass})
	}

	// 解析DNS资源
	for i := 0; i < int(msg.ANCount+msg.NSCount+msg.ARCount); i++ {
		name, n := readName(buf, offset)
		offset += n
		qtype := uint16(buf[offset])<<8 | uint16(buf[offset+1])
		qclass := uint16(buf[offset+2])<<8 | uint16(buf[offset+3])
		ttl := uint32(buf[offset+4])<<24 | uint32(buf[offset+5])<<16 | uint32(buf[offset+6])<<8 | uint32(buf[offset+7])
		rdlength := uint16(buf[offset+8])<<8 | uint16(buf[offset+9])
		offset += 10
		rdata := make([]byte, rdlength)
		copy(rdata, buf[offset:offset+int(rdlength)])
		offset += int(rdlength)
		msg.Answer = append(msg.Answer, dnsResource{Name: name, Type: qtype, Class: qclass, TTL: ttl, RDLength: rdlength, RData: rdata})
	}

	return nil
}

// 将DNS消息转换为字节数组
func (msg *dnsMsg) bytes() []byte {
	buf := make([]byte, 0, 512)

	// DNS头部
	buf = append(buf, byte(msg.ID>>8), byte(msg.ID))
	buf = append(buf, byte(msg.Flags>>8), byte(msg.Flags))
	buf = append(buf, byte(msg.QDCount>>8), byte(msg.QDCount))
	buf = append(buf, byte(msg.ANCount>>8), byte(msg.ANCount))
	buf = append(buf, byte(msg.NSCount>>8), byte(msg.NSCount))
	buf = append(buf, byte(msg.ARCount>>8), byte(msg.ARCount))

	// DNS问题
	for _, q := range msg.Quest {
		buf = append(buf, encodeName(q.Name)...)
		buf = append(buf, byte(q.Type>>8), byte(q.Type))
		buf = append(buf, byte(q.Class>>8), byte(q.Class))
	}

	// DNS资源
	for _, a := range msg.Answer {
		buf = append(buf, encodeName(a.Name)...)
		buf = append(buf, byte(a.Type>>8), byte(a.Type))
		buf = append(buf, byte(a.Class>>8), byte(a.Class))
		buf = append(buf, byte(a.TTL>>24), byte(a.TTL>>16), byte(a.TTL>>8), byte(a.TTL))
		buf = append(buf, byte(a.RDLength>>8), byte(a.RDLength))
		buf = append(buf, a.RData...)
	}

	return buf
}

// 判断DNS消息是否为查询消息
func (msg *dnsMsg) isQuery() bool {
	return (msg.Flags & 0x8000) == 0
}

// 判断DNS消息是否为指定域名
func (msg *dnsMsg) isDomain(domain string) bool {
	for _, q := range msg.Quest {
		if q.Name == domain {
			return true
		}
	}
	return false
}

// 修改DNS消息中的IP地址
func (msg *dnsMsg) setIP(ip net.IP) {
	for i := range msg.Answer {
		if msg.Answer[i].Type == 1 { // A记录
			msg.Answer[i].RData = ip.To4()
		}
	}
}

// 读取DNS消息中的域名
func readName(buf []byte, offset int) (string, int) {
	var name string
	for buf[offset] != 0 {
		if buf[offset]&0xc0 == 0xc0 { // 压缩指针
			ptr := uint16(buf[offset]&0x3f)<<8 | uint16(buf[offset+1])
			off, _ := readName(buf, int(ptr))
			name += off
			offset += 2
			return name, offset
		} else { // 普通标签
			n := int(buf[offset])
			name += string(buf[offset+1 : offset+1+n]) + "."
			offset += n + 1
		}
	}
	return name, offset + 1
}

// 编码域名为DNS消息格式
func encodeName(name string) []byte {
	var buf []byte
	labels := strings.Split(name, ".")
	for _, label := range labels {
		buf = append(buf, byte(len(label)))
		buf = append(buf, []byte(label)...)
	}
	buf = append(buf, 0)
	return buf
}

这个代码使用了UDP监听器来接收DNS请求,并解析请求消息。然后,它检查是否为"www.baidu.com"的DNS请求,如果是,则将IP地址修改为"119.29.29.29",并回复修改后的DNS响应。如果不是,则忽略该请求

golang 写一个dns中转代码 将wwwbaiducom域名请求到119292929

原文地址: https://www.cveoy.top/t/topic/fnuv 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录