• golang 实现简单DNS服务器


    简单的DNS服务器

    提供一个简单的可以查询域名和反向查询的DNS服务器。

    dig命令主要用来从 DNS 域名服务器查询主机地址信息。

    查找www.baidu.com的ip (A记录):

    命令:dig @127.0.0.1 www.baidu.com
    在这里插入图片描述

    根据ip查找对应域名 (PTR记录):

    命令:dig @127.0.0.1 -x 220.181.38.150
    在这里插入图片描述

    源码 :
    package main
    
    import (
    	"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 books
    var (
    	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 serve
    func 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]
    ", 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] 
    ", 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] 
    ", queryNameStr)
    			Response(addr, conn, msg)
    			return
    		}
    	default:
    		fmt.Printf("not support dns queryType: [%s] 
    ", queryTypeStr)
    		return
    	}
    
    	// send response
    	msg.Response = true
    	msg.Answers = append(msg.Answers, resource)
    	Response(addr, conn, msg)
    }
    
    // Response return
    func 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 record
    func 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 record
    func 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,
    		},
    	}
    }
    

     转载: https://blog.csdn.net/qq_27068845/article/details/104597845

    浪漫家园,没事就来逛逛
  • 相关阅读:
    linux源码阅读笔记 asm函数
    linux源码阅读笔记 #define 语句的妙用
    对于python的内存管理的好文章
    #define x do{......} while(0)的用处
    reverse list
    判断数组是否存在重复元素
    找出数组中出现奇数次的元素
    找出数组中唯一的重复元素
    两个有序数组中的交集
    Java Socket(3): NIO
  • 原文地址:https://www.cnblogs.com/lovezbs/p/13701185.html
Copyright © 2020-2023  润新知