DNS协议解析与DNS模拟服务器-基于golang实现

概要

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.
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值