分享
Golang实现发送DNS请求
u011774512 · · 3397 次点击 · · 开始浏览这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
关于DNS协议的具体内容可以查看RFC1035,如果英语不太好我推荐下面这个人的译文:
http://blog.csdn.net/tigerjibo/article/details/6827736 翻译的足够详尽了。
那么来看下Go的实现:
package main
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"strings"
)
type DNSHeader struct {
ID uint16
Flag uint16
QuestionCount uint16
AnswerRRs uint16 //RRs is Resource Records
AuthorityRRs uint16
AdditionalRRs uint16
}
func (header *DNSHeader) SetFlag(QR uint16, OperationCode uint16, AuthoritativeAnswer uint16, Truncation uint16, RecursionDesired uint16, RecursionAvailable uint16, ResponseCode uint16) {
header.Flag = QR<<15 + OperationCode<<11 + AuthoritativeAnswer<<10 + Truncation<<9 + RecursionDesired<<8 + RecursionAvailable<<7 + ResponseCode
}
type DNSQuery struct {
QuestionType uint16
QuestionClass uint16
}
func ParseDomainName(domain string) []byte {
//要将域名解析成相应的格式,例如:
//"www.google.com"会被解析成"0x03www0x06google0x03com0x00"
//就是长度+内容,长度+内容......最后以0x00结尾
var (
buffer bytes.Buffer
segments []string = strings.Split(domain, ".")
)
for _, seg := range segments {
binary.Write(&buffer, binary.BigEndian, byte(len(seg)))
binary.Write(&buffer, binary.BigEndian, []byte(seg))
}
binary.Write(&buffer, binary.BigEndian, byte(0x00))
return buffer.Bytes()
}
func main() {
var (
dns_header DNSHeader
dns_question DNSQuery
)
//填充dns首部
dns_header.ID = 0xFFFF
dns_header.SetFlag(0, 0, 0, 0, 1, 0, 0)
dns_header.QuestionCount = 1
dns_header.AnswerRRs = 0
dns_header.AuthorityRRs = 0
dns_header.AdditionalRRs = 0
//填充dns查询首部
dns_question.QuestionType = 1 //IPv4
dns_question.QuestionClass = 1
var (
conn net.Conn
err error
buffer bytes.Buffer
)
//DNS服务器的端口一般是53,IP你自己ipconfig查一下
//别忘了DNS是基于UDP协议的
if conn, err = net.Dial("udp", "211.137.191.26:53"); err != nil {
fmt.Println(err.Error())
return
}
defer conn.Close()
//buffer中是我们要发送的数据,里面的内容是DNS首部+查询内容+DNS查询首部
binary.Write(&buffer, binary.BigEndian, dns_header)
binary.Write(&buffer, binary.BigEndian, ParseDomainName("www.baidu.com"))
binary.Write(&buffer, binary.BigEndian, dns_question)
fmt.Println(buffer.Bytes())
if _, err := conn.Write(buffer.Bytes()); err != nil {
fmt.Println(err.Error())
return
}
fmt.Println("send success.")
}
用Wireshark来检查一下是否正确(截一张太长了不方便看,所以截成了两段):
看看我们构造的DNS请求数据包:
如果转载请注明出处:http://blog.csdn.net/gophers/article/details/22942457
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信3397 次点击
添加一条新回复
(您需要 后才能回复 没有账号 ?)
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
关于DNS协议的具体内容可以查看RFC1035,如果英语不太好我推荐下面这个人的译文:
http://blog.csdn.net/tigerjibo/article/details/6827736 翻译的足够详尽了。
那么来看下Go的实现:
package main
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"strings"
)
type DNSHeader struct {
ID uint16
Flag uint16
QuestionCount uint16
AnswerRRs uint16 //RRs is Resource Records
AuthorityRRs uint16
AdditionalRRs uint16
}
func (header *DNSHeader) SetFlag(QR uint16, OperationCode uint16, AuthoritativeAnswer uint16, Truncation uint16, RecursionDesired uint16, RecursionAvailable uint16, ResponseCode uint16) {
header.Flag = QR<<15 + OperationCode<<11 + AuthoritativeAnswer<<10 + Truncation<<9 + RecursionDesired<<8 + RecursionAvailable<<7 + ResponseCode
}
type DNSQuery struct {
QuestionType uint16
QuestionClass uint16
}
func ParseDomainName(domain string) []byte {
//要将域名解析成相应的格式,例如:
//"www.google.com"会被解析成"0x03www0x06google0x03com0x00"
//就是长度+内容,长度+内容......最后以0x00结尾
var (
buffer bytes.Buffer
segments []string = strings.Split(domain, ".")
)
for _, seg := range segments {
binary.Write(&buffer, binary.BigEndian, byte(len(seg)))
binary.Write(&buffer, binary.BigEndian, []byte(seg))
}
binary.Write(&buffer, binary.BigEndian, byte(0x00))
return buffer.Bytes()
}
func main() {
var (
dns_header DNSHeader
dns_question DNSQuery
)
//填充dns首部
dns_header.ID = 0xFFFF
dns_header.SetFlag(0, 0, 0, 0, 1, 0, 0)
dns_header.QuestionCount = 1
dns_header.AnswerRRs = 0
dns_header.AuthorityRRs = 0
dns_header.AdditionalRRs = 0
//填充dns查询首部
dns_question.QuestionType = 1 //IPv4
dns_question.QuestionClass = 1
var (
conn net.Conn
err error
buffer bytes.Buffer
)
//DNS服务器的端口一般是53,IP你自己ipconfig查一下
//别忘了DNS是基于UDP协议的
if conn, err = net.Dial("udp", "211.137.191.26:53"); err != nil {
fmt.Println(err.Error())
return
}
defer conn.Close()
//buffer中是我们要发送的数据,里面的内容是DNS首部+查询内容+DNS查询首部
binary.Write(&buffer, binary.BigEndian, dns_header)
binary.Write(&buffer, binary.BigEndian, ParseDomainName("www.baidu.com"))
binary.Write(&buffer, binary.BigEndian, dns_question)
fmt.Println(buffer.Bytes())
if _, err := conn.Write(buffer.Bytes()); err != nil {
fmt.Println(err.Error())
return
}
fmt.Println("send success.")
}
用Wireshark来检查一下是否正确(截一张太长了不方便看,所以截成了两段):
看看我们构造的DNS请求数据包:
如果转载请注明出处:http://blog.csdn.net/gophers/article/details/22942457