久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

golang實(shí)現(xiàn)dns域名解析(一)

 vclyin 2018-08-22

  本文將詳細(xì)講解如何用go語言一步一步實(shí)現(xiàn)dns域名解析的過程,并簡單介紹點(diǎn)dns有關(guān)的知識,直接開始正題吧,。

  首先我們要了解dns解析的過程,,沒有了解的請看這里DNS入門(轉(zhuǎn))很詳細(xì),。掃盲結(jié)束后,我們需要了解下dns報文格式,,知道了報文的格式是怎樣的,,才可以寫代碼構(gòu)造dns請求包:    

  dns請求和應(yīng)答都是用相同的報文格式,分成5個段(有的報文段在不同的情況下可能為空),,如下:         

  

  Header段是報文的頭部,,它定義了報文是請求還是應(yīng)答,也定義了其他段是否需要存在,,以及是標(biāo)準(zhǔn)查詢還是其他,。     

  Header包含如下字段:

         

  各字段分別解釋如下:

  ID:請求客戶端設(shè)置的16位標(biāo)示,服務(wù)器給出應(yīng)答的時候會帶相同的標(biāo)示字段回來,,這樣請求客戶端就可以區(qū)分不同的請求應(yīng)答了,。

  QR:1個比特位用來區(qū)分是請求(0)還是應(yīng)答(1)。

  OPCODE:4個比特位用來設(shè)置查詢的種類,,應(yīng)答的時候會帶相同值,,可用的值如下: 0 標(biāo)準(zhǔn)查詢 (QUERY) 1 反向查詢 (IQUERY) 2 服務(wù)器狀態(tài)查詢 (STATUS) 3-15保留值,暫時未使用

  AA:授權(quán)應(yīng)答(Authoritative Answer) - 這個比特位在應(yīng)答的時候才有意義,,指出給出應(yīng)答的服務(wù)器是查詢域名的授權(quán)解析服務(wù)器,。注意因?yàn)閯e名的存在,應(yīng)答可能存在多個主域名,,這個AA位對應(yīng)請求名,,或者應(yīng)答中的第一個主域名。

  TC:截斷(TrunCation) - 用來指出報文比允許的長度還要長,,導(dǎo)致被截斷,。   

  RD:期望遞歸(Recursion Desired) - 這個比特位被請求設(shè)置,應(yīng)答的時候使用的相同的值返回,。如果設(shè)置了RD,,就建議域名服務(wù)器進(jìn)行遞歸解析,遞歸查詢的支持是可選的,。   

  RA:支持遞歸(Recursion Available) - 這個比特位在應(yīng)答中設(shè)置或取消,,用來代表服務(wù)器是否支持遞歸查詢。   

  Z:保留值,,暫時未使用,。在所有的請求和應(yīng)答報文中必須置為0。   

  RCODE:應(yīng)答碼(Response code) - 這4個比特位在應(yīng)答報文中設(shè)置,,代表的含義如下:

    0 沒有錯誤,。

    1 報文格式錯誤(Format error) - 服務(wù)器不能理解請求的報文。

    2 服務(wù)器失敗(Server failure) - 因?yàn)榉?wù)器的原因?qū)е聸]辦法處理這個請求,。

    3 名字錯誤(Name Error) - 只有對授權(quán)域名解析服務(wù)器有意義,,指出解析的域名不存在。

    4 沒有實(shí)現(xiàn)(Not Implemented) - 域名服務(wù)器不支持查詢類型,。

    5 拒絕(Refused) - 服務(wù)器由于設(shè)置的策略拒絕給出應(yīng)答,。比如,服務(wù)器不希望對某些請求者給出應(yīng)答,,或者服務(wù)器不希望進(jìn)行某些操作(比如區(qū)域傳送zone transfer),。

    6-15 保留值,暫時未使用,。

  QDCOUNT 無符號16位整數(shù)表示報文請求段中的問題記錄數(shù),。

  ANCOUNT 無符號16位整數(shù)表示報文回答段中的回答記錄數(shù)。

  NSCOUNT 無符號16位整數(shù)表示報文授權(quán)段中的授權(quán)記錄數(shù),。

  ARCOUNT 無符號16位整數(shù)表示報文附加段中的附加記錄數(shù),。

  根據(jù)這些,dns頭部的數(shù)據(jù)結(jié)構(gòu)可以定義如下:

  type dnsHeader struct {

      Id                                 uint16

      Bits                               uint16

      Qdcount, Ancount, Nscount, Arcount uint16

  }

  構(gòu)造頭部信息我們主要處理Bits,,可以直接根據(jù)需求對相應(yīng)位置值,,也可以定義好每一個字段,通過移位的方式然后相加構(gòu)造請求的頭部各個字段,。推薦后一種方法,,這樣就有:

      header.Bits = QR<<15 + OperationCode<<11 + AuthoritativeAnswer<<10 + Truncation<<9 + RecursionDesired<<8 + RecursionAvailable<<7 + ResponseCode

    其他的頭部信息就比較簡單了:

  requestHeader := dnsHeader{

        Id:      0x0010,

        Qdcount: 1,

        Ancount: 0,

        Nscount: 0,

        Arcount: 0,

  }

  報文頭搞定后,接下來就是查詢問題Question

  Question段描述了查詢的問題,,包括查詢類型(QTYPE),,查詢類(QCLASS),以及查詢的域名(QNAME),。字段含義如下   QNAME域名被編碼為一些labels序列,,每個labels包含一個字節(jié)表示后續(xù)字符串長度,以及這個字符串,,以0長度和空字符串來表示域名結(jié)束,。注意這個字段可能為奇數(shù)字節(jié),不需要進(jìn)行邊界填充對齊,。   QTYPE2個字節(jié)表示查詢類型,,.取值可以為任何可用的類型值,以及通配碼來表示所有的資源記錄,。   QCLASS2個字節(jié)表示查詢的協(xié)議類,,比如,IN代表Internet,。所以我們直接定義查詢的結(jié)構(gòu)體如下:

  type dnsQuery struct {

      QuestionType  uint16

      QuestionClass uint16

  }

查詢的域名不定義在查詢的結(jié)構(gòu)體中,,由函數(shù)接收參數(shù)的方式接收,。

  剩下的3個段包含相同的格式:一系列可能為空的資源記錄(RRs)。Answer段包含回答問題的RRs,;授權(quán)段包含授權(quán)域名服務(wù)器的RRs,;附加段包含和請求相關(guān)的,但是不是必須回答的RRs,。而在發(fā)送請求的時候,,我們是發(fā)起請求方,所以這些字段放空就好,。

完整代碼:

// 002 project main.go
package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
    "net"
    "strings"
    "time"
)

type dnsHeader struct {
    Id                                 uint16
    Bits                               uint16
    Qdcount, Ancount, Nscount, Arcount uint16
}

func (header *dnsHeader) SetFlag(QR uint16, OperationCode uint16, AuthoritativeAnswer uint16, Truncation uint16, RecursionDesired uint16, RecursionAvailable uint16, ResponseCode uint16) {
    header.Bits = 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 {
    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 Send(dnsServer, domain string) ([]byte, int, time.Duration) {
    requestHeader := dnsHeader{
        Id:      0x0010,
        Qdcount: 1,
        Ancount: 0,
        Nscount: 0,
        Arcount: 0,
    }
    requestHeader.SetFlag(0, 0, 0, 0, 1, 0, 0)

    requestQuery := dnsQuery{
        QuestionType:  1,
        QuestionClass: 1,
    }

    var (
        conn   net.Conn
        err    error
        buffer bytes.Buffer
    )

    if conn, err = net.Dial("udp", dnsServer); err != nil {
        fmt.Println(err.Error())
        return make([]byte, 0), 0, 0
    }
    defer conn.Close()

    binary.Write(&buffer, binary.BigEndian, requestHeader)
    binary.Write(&buffer, binary.BigEndian, ParseDomainName(domain))
    binary.Write(&buffer, binary.BigEndian, requestQuery)

    buf := make([]byte, 1024)
    t1 := time.Now()
    if _, err := conn.Write(buffer.Bytes()); err != nil {
        fmt.Println(err.Error())
        return make([]byte, 0), 0, 0
    }
    length, err := conn.Read(buf)
    t := time.Now().Sub(t1)
    return buf, length, t
}
func main() {
    remsg, n, _ := Send("114.114.114.114:53", "www.baidu.com")
    fmt.Println(remsg, n)
}

 

抓個包看看:

 

這是發(fā)出去的,,看看詳細(xì)的Questions信息:

 

我們設(shè)置的請求類型是1,class1,意味著是請求A記錄,,class IN,。下一節(jié)我們在來討論下如何處理服務(wù)器端響應(yīng)的內(nèi)容。

 

 轉(zhuǎn)自:http://www.cnblogs.com/chase-wind/p/6814053.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多