golang 写一个dns中转代码 将wwwbaiducom域名请求到119292929 和 wwwgooglecom 域名请求到118111 要求代码能运行
package main
import ( "fmt" "net" )
func main() { fmt.Println("DNS中转服务已启动...")
// 监听本地53端口
pc, err := net.ListenPacket("udp", "0.0.0.0:53")
if err != nil {
fmt.Println("监听53端口失败:", err)
return
}
defer pc.Close()
for {
// 接收DNS请求
buf := make([]byte, 1024)
n, addr, err := pc.ReadFrom(buf)
if err != nil {
fmt.Println("读取DNS请求失败:", err)
continue
}
// 解析DNS请求
msg := &dnsMsg{}
if err := msg.unmarshal(buf[:n]); err != nil {
fmt.Println("解析DNS请求失败:", err)
continue
}
// 转发DNS请求
resp, err := forwardDNSRequest(msg)
if err != nil {
fmt.Println("转发DNS请求失败:", err)
continue
}
// 发送DNS响应
if _, err := pc.WriteTo(resp.marshal(), addr); err != nil {
fmt.Println("发送DNS响应失败:", err)
continue
}
}
}
// dnsMsg 表示DNS消息 type dnsMsg struct { ID uint16 Flags uint16 QDCount uint16 ANCount uint16 NSCount uint16 ARCount uint16 Quest []dnsQuestion Answer []dnsRR Auth []dnsRR Extra []dnsRR }
// dnsQuestion 表示DNS查询 type dnsQuestion struct { Name string Type uint16 Class uint16 }
// dnsRR 表示DNS资源记录 type dnsRR struct { Name string Type uint16 Class uint16 TTL uint32 RDLength uint16 Data string }
// unmarshal 从二进制数据中解析DNS消息 func (msg *dnsMsg) unmarshal(data []byte) error { // 解析消息头 msg.ID = (uint16(data[0]) << 8) | uint16(data[1]) msg.Flags = (uint16(data[2]) << 8) | uint16(data[3]) msg.QDCount = (uint16(data[4]) << 8) | uint16(data[5]) msg.ANCount = (uint16(data[6]) << 8) | uint16(data[7]) msg.NSCount = (uint16(data[8]) << 8) | uint16(data[9]) msg.ARCount = (uint16(data[10]) << 8) | uint16(data[11])
// 解析查询部分
cur := 12
for i := 0; i < int(msg.QDCount); i++ {
name, n := parseDNSName(data, cur)
cur += n
qtype := (uint16(data[cur]) << 8) | uint16(data[cur+1])
qclass := (uint16(data[cur+2]) << 8) | uint16(data[cur+3])
cur += 4
msg.Quest = append(msg.Quest, dnsQuestion{Name: name, Type: qtype, Class: qclass})
}
return nil
}
// marshal 将DNS消息转换为二进制数据 func (msg *dnsMsg) marshal() []byte { data := make([]byte, 12) data[0] = byte(msg.ID >> 8) data[1] = byte(msg.ID) data[2] = byte(msg.Flags >> 8) data[3] = byte(msg.Flags) data[4] = byte(msg.QDCount >> 8) data[5] = byte(msg.QDCount) data[6] = byte(msg.ANCount >> 8) data[7] = byte(msg.ANCount) data[8] = byte(msg.NSCount >> 8) data[9] = byte(msg.NSCount) data[10] = byte(msg.ARCount >> 8) data[11] = byte(msg.ARCount)
for _, q := range msg.Quest {
data = append(data, encodeDNSName(q.Name)...)
data = append(data, byte(q.Type>>8), byte(q.Type))
data = append(data, byte(q.Class>>8), byte(q.Class))
}
for _, ans := range msg.Answer {
data = append(data, encodeDNSName(ans.Name)...)
data = append(data, byte(ans.Type>>8), byte(ans.Type))
data = append(data, byte(ans.Class>>8), byte(ans.Class))
data = append(data, byte(ans.TTL>>24), byte(ans.TTL>>16), byte(ans.TTL>>8), byte(ans.TTL))
data = append(data, byte(ans.RDLength>>8), byte(ans.RDLength))
data = append(data, encodeDNSData(ans.Type, ans.Data)...)
}
return data
}
// parseDNSName 从二进制数据中解析DNS域名 func parseDNSName(data []byte, pos int) (string, int) { var name string cur := pos loop: for { len := int(data[cur]) switch len & 0xC0 { case 0x00: name += string(data[cur+1 : cur+1+len]) + "." cur += len + 1 case 0xC0: off := (int(data[cur]&0x3F) << 8) | int(data[cur+1]) n, _ := parseDNSName(data, off) name += n cur += 2 break loop default: cur += len + 1 break loop } } return name, cur - pos }
// encodeDNSName 将DNS域名转换为二进制数据 func encodeDNSName(name string) []byte { var data []byte labels := splitDNSName(name) for _, label := range labels { data = append(data, byte(len(label))) data = append(data, []byte(label)...) } data = append(data, 0) return data }
// splitDNSName 分割DNS域名 func splitDNSName(name string) []string { var labels []string start := 0 for i := 0; i < len(name); i++ { if name[i] == '.' { labels = append(labels, name[start:i]) start = i + 1 } } labels = append(labels, name[start:]) return labels }
// encodeDNSData 将DNS数据转换为二进制数据 func encodeDNSData(qtype uint16, data string) []byte { switch qtype { case 1: // A记录 ip := net.ParseIP(data) if ip == nil { return []byte{} } return []byte(ip.To4()) case 28: // AAAA记录 ip := net.ParseIP(data) if ip == nil { return []byte{} } return []byte(ip.To16()) default: return []byte{} } }
// forwardDNSRequest 转发DNS请求 func forwardDNSRequest(req *dnsMsg) (*dnsMsg, error) { resp := &dnsMsg{ ID: req.ID, Flags: req.Flags, QDCount: req.QDCount, ANCount: 0, NSCount: 0, ARCount: 0, }
for _, q := range req.Quest {
switch q.Name {
case "www.baidu.com.":
resp.Answer = append(resp.Answer, dnsRR{
Name: q.Name,
Type: q.Type,
Class: q.Class,
TTL: 600,
RDLength: 4,
Data: "119.29.29.29",
})
case "www.google.com.":
resp.Answer = append(resp.Answer, dnsRR{
Name: q.Name,
Type: q.Type,
Class: q.Class,
TTL: 600,
RDLength: 4,
Data: "118.1.1.1",
})
}
}
resp.ANCount = uint16(len(resp.Answer))
return resp, nil
原文地址: https://www.cveoy.top/t/topic/fnwK 著作权归作者所有。请勿转载和采集!