GolangはDNS要求の送信を実現する

3433 ワード

DNSプロトコルの具体的な内容についてはRFC 1035を参照してください.英語があまり上手でなければ、次の人の訳文をお勧めします.
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で正しいかどうかをチェックします(1枚切るのが長すぎて見にくいので2段に切りました):


DNSリクエストパケットを構築してみましょう.
Golang实现发送DNS请求_第1张图片
転載する場合は出典を明記してください.http://blog.csdn.net/gophers/article/details/22942457