概要
DNS协议属于比较简单的网络协议,最近用golang实现了对于dns协议的解包和打包,暂时只实现了一个查询问题与一个回答问题,代码如下。
本文代码地址
https://github.com/changjixiong/goNotes/tree/master/dnsnotes
DNS报文解包与打包
package dnsKit
import (
"bytes"
"encoding/binary"
"net"
"strings"
)
/*
DNS报文格式,不论是请求报文,还是DNS服务器返回的应答报文,都使用统一的格式。
2个字节(16bit),标识字段,客户端会解析服务器返回的DNS应答报文,获取ID值与请求报文设置的ID值做比较
如果相同,则认为是同一个DNS会话。
QR 标示该消息是请求消息(该位为0)还是应答消息(该位为1)
QR这一段位 Flag 16bit长度
header
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
question
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ... |
| QNAME |
| ... |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QTYPE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QCLASS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*/
// DNSHeader 头
type DNSHeader struct {
ID uint16
//golang 没有bit类型,只能这样处理
QR uint16 //1bit
OperationCode uint16 //4bit
AuthoritativeAnswer uint16 //1bit
Truncation uint16 //1bit
RecursionDesired uint16 //1bit
RecursionAvailable uint16 //1bit
Zero uint16 //3bit
ResponseCode uint16 //4bit
QuestionCount uint16
AnswerRRs uint16
AuthorityRRs uint16
AdditionalRRs uint16
}
func (dh *DNSHeader) ToBytes() []byte {
var buffer bytes.Buffer
binary.Write(&buffer, binary.BigEndian, dh.ID)
bits := dh.QR<<15 + dh.OperationCode<<11 + dh.AuthoritativeAnswer<<10 + dh.Truncation<<9
bits += dh.RecursionDesired<<8 + dh.RecursionAvailable<<7 + dh.ResponseCode
binary.Write(&buffer, binary.BigEndian, bits)
binary.Write(&buffer, binary.BigEndian, dh.QuestionCount)
binary.Write(&buffer, binary.BigEndian, dh.AnswerRRs)
binary.Write(&buffer, binary.BigEndian, dh.AuthorityRRs)
binary.Write(&buffer, binary.BigEndian, dh.AdditionalRRs)
return buffer.Bytes()
}
func NewDNSHeader(buffer *bytes.Buffer) *DNSHeader {
// 读12byte
id := binary.BigEndian.Uint16(buffer.Next(2))
flag := binary.BigEndian.Uint16(buffer.Next(2))
return &DNSHeader{
ID: id,
QR: flag >> 15,
OperationCode: (flag >> 11) % (1 << 4),
AuthoritativeAnswer: (flag >> 10) % (1 << 1),
Truncation: (flag >> 9) % (1 << 1),
RecursionDesired: (flag >> 8) % (1 << 1),
RecursionAvailable: (flag >> 7) % (1 << 1),
Zero: (flag >> 4) % (1 << 3),
ResponseCode: flag % (1 << 4),
QuestionCount: binary.BigEndian.Uint16(buffer.Next(2)),
AnswerRRs: binary.BigEndian.Uint16(buffer.Next(2)),
AuthorityRRs: binary.BigEndian.Uint16(buffer.Next(2)),
AdditionalRRs: binary.BigEndian.Uint16(buffer.