亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用golang怎么實現一個DNS服務器

發布時間:2021-05-04 19:08:07 來源:億速云 閱讀:467 作者:Leah 欄目:開發技術

使用golang怎么實現一個DNS服務器?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

golang適合做什么

golang可以做服務器端開發,但golang很適合做日志處理、數據打包、虛擬機處理、數據庫代理等工作。在網絡編程方面,它還廣泛應用于web應用、API應用等領域。

簡單的DNS服務器

提供一個簡單的可以查詢域名和反向查詢的DNS服務器。

dig命令主要用來從 DNS 域名服務器查詢主機地址信息。

查找www.baidu.com的ip (A記錄):

命令:dig @127.0.0.1 www.baidu.com

使用golang怎么實現一個DNS服務器

根據ip查找對應域名 (PTR記錄):

命令:dig @127.0.0.1 -x 220.181.38.150

使用golang怎么實現一個DNS服務器

源碼 :

package mainimport (	"fmt"	"net"	"golang.org/x/net/dns/dnsmessage")func main() {	conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: 53})	if err != nil {		panic(err)	}	defer conn.Close()	fmt.Println("Listing ...")	for {		buf := make([]byte, 512)		_, addr, _ := conn.ReadFromUDP(buf)		var msg dnsmessage.Message		if err := msg.Unpack(buf); err != nil {			fmt.Println(err)			continue		}		go ServerDNS(addr, conn, msg)	}}// address booksvar (	addressBookOfA = map[string][4]byte{		"www.baidu.com.": [4]byte{220, 181, 38, 150},	}	addressBookOfPTR = map[string]string{		"150.38.181.220.in-addr.arpa.": "www.baidu.com.",	})// ServerDNS servefunc ServerDNS(addr *net.UDPAddr, conn *net.UDPConn, msg dnsmessage.Message) {	// query info	if len(msg.Questions) < 1 {		return	}	question := msg.Questions[0]	var (		queryTypeStr = question.Type.String()		queryNameStr = question.Name.String()		queryType    = question.Type		queryName, _ = dnsmessage.NewName(queryNameStr)	)	fmt.Printf("[%s] queryName: [%s]\n", queryTypeStr, queryNameStr)	// find record	var resource dnsmessage.Resource	switch queryType {	case dnsmessage.TypeA:		if rst, ok := addressBookOfA[queryNameStr]; ok {			resource = NewAResource(queryName, rst)		} else {			fmt.Printf("not fount A record queryName: [%s] \n", queryNameStr)			Response(addr, conn, msg)			return		}	case dnsmessage.TypePTR:		if rst, ok := addressBookOfPTR[queryName.String()]; ok {			resource = NewPTRResource(queryName, rst)		} else {			fmt.Printf("not fount PTR record queryName: [%s] \n", queryNameStr)			Response(addr, conn, msg)			return		}	default:		fmt.Printf("not support dns queryType: [%s] \n", queryTypeStr)		return	}	// send response	msg.Response = true	msg.Answers = append(msg.Answers, resource)	Response(addr, conn, msg)}// Response returnfunc Response(addr *net.UDPAddr, conn *net.UDPConn, msg dnsmessage.Message) {	packed, err := msg.Pack()	if err != nil {		fmt.Println(err)		return	}	if _, err := conn.WriteToUDP(packed, addr); err != nil {		fmt.Println(err)	}}// NewAResource A recordfunc NewAResource(query dnsmessage.Name, a [4]byte) dnsmessage.Resource {	return dnsmessage.Resource{		Header: dnsmessage.ResourceHeader{			Name:  query,			Class: dnsmessage.ClassINET,			TTL:   600,		},		Body: &dnsmessage.AResource{			A: a,		},	}}// NewPTRResource PTR recordfunc NewPTRResource(query dnsmessage.Name, ptr string) dnsmessage.Resource {	name, _ := dnsmessage.NewName(ptr)	return dnsmessage.Resource{		Header: dnsmessage.ResourceHeader{			Name:  query,			Class: dnsmessage.ClassINET,		},		Body: &dnsmessage.PTRResource{			PTR: name,		},	}}

補充:Golang自定義DNS Nameserver

某些情況下我們希望程序通過自定義Nameserver去查詢域名,而不希望通過操作系統給定的Nameserver,本文介紹如何在Golang中實現自定義Nameserver。

DNS解析過程

Golang中一般通過net.Resolver的LookupHost(ctx context.Context, host string) (addrs []string, err error)去實現域名解析,

解析過程如下:

檢查本地hosts文件是否存在解析記錄,存在即返回解析地址

不存在即根據resolv.conf中讀取的nameserver發起遞歸查詢

nameserver不斷的向上級nameserver發起迭代查詢

nameserver最終返回查詢結果給請求者

用戶可以通過修改/etc/resolv.conf來添加特定的nameserver,但某些場景下我們不希望更改系統配置。比如在kubernetes中,作為sidecar服務需要通過service去訪問其他集群內服務,必須更改dnsPolicy為ClusterFirst,但這可能會影響其他容器的DNS查詢效率。

自定義Nameserver

在Golang中自定義Nameserver,需要我們自己實現一個Resolver,如果是httpClient需要自定義DialContext()

Resolver實現如下:

// 默認dialerdialer := &net.Dialer{  Timeout: 1 * time.Second,}// 定義resolverresolver := &net.Resolver{ Dial: func(ctx context.Context, network, address string) (net.Conn, error) {  return dialer.DialContext(ctx, "tcp", nameserver) // 通過tcp請求nameserver解析域名 },}

自定義Dialer如下:

type Dialer struct { dialer     *net.Dialer resolver   *net.Resolver nameserver string}// NewDialer create a Dialer with user's nameserver.func NewDialer(dialer *net.Dialer, nameserver string) (*Dialer, error) { conn, err := dialer.Dial("tcp", nameserver) if err != nil {  return nil, err } defer conn.Close() return &Dialer{  dialer: dialer,  resolver: &net.Resolver{   Dial: func(ctx context.Context, network, address string) (net.Conn, error) {    return dialer.DialContext(ctx, "tcp", nameserver)   },  },  nameserver: nameserver, // 用戶設置的nameserver }, nil}// DialContext connects to the address on the named network using// the provided context.func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { host, port, err := net.SplitHostPort(address) if err != nil {  return nil, err } ips, err := d.resolver.LookupHost(ctx, host) // 通過自定義nameserver查詢域名 for _, ip := range ips {    // 創建鏈接  conn, err := d.dialer.DialContext(ctx, network, ip+":"+port)  if err == nil {   return conn, nil  } } return d.dialer.DialContext(ctx, network, address)}

httpClient中自定義DialContext()如下:

ndialer, _ := NewDialer(dialer, nameserver)client := &http.Client{  Transport: &http.Transport{    DialContext:         ndialer.DialContext,    TLSHandshakeTimeout: 10 * time.Second,  },  Timeout: timeout,}

關于使用golang怎么實現一個DNS服務器問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

澎湖县| 上犹县| 出国| 龙游县| 静海县| 西平县| 阿坝县| 乡城县| 渭南市| 台中市| 沾益县| 蓝山县| 南安市| 固阳县| 新宾| 福安市| 历史| 安义县| 洛隆县| 靖安县| 丹寨县| 岢岚县| 炎陵县| 柞水县| 清水河县| 大关县| 左贡县| 任丘市| 宁都县| 岑溪市| 资源县| 长沙市| 江西省| 牙克石市| 芦溪县| 武宣县| 遂平县| 会昌县| 鄂尔多斯市| 嵊州市| 衡水市|