golang 写一个dns中转代码 将wwwbaiducom域名请求到119292929
以下是一个简单的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响应。如果不是,则忽略该请求
原文地址: https://www.cveoy.top/t/topic/fnuv 著作权归作者所有。请勿转载和采集!