• [转]go(golang) dns 解析源码 go/src/net/dnsclient_unix.go 分析


    转: 原文:https://blog.csdn.net/mumumuwudi/article/details/48722063

    strace 命令不错,非常有用!!

    使用strace命令分析一下, 系统调用过程:

    ________________________________________________________________

    关于go dns解析的一些说明参照另一篇文章http://blog.csdn.net/mumumuwudi/article/details/48200505
    go dns 解析 源码在go/src/net/dnsclient_unix.go, lookupHost()通过向本地dns server发送请求,获得IP和
    域名的对应关系然后返回,函数调用关系如下:

      1.  
        // ---------------------------------------------------
      2.  
        // lookupHost()
      3.  
        //
      4.  
        // ->goLookupHostOrder()
      5.  
        //
      6.  
        // ---->goLookupIPOrder()
      7.  
        //
      8.  
        // -------->tryOneName()
      9.  
        //
      10.  
        // ----------->exchange()

    其中的timeout 是 dns 超时时间 是在dnsconfig_unix.go 文件中读取 /etc/reslove.conf  的配置决定的. 
    net.go中的DialTimeout函数也会走到DNS解析流程中,该函数最终会调用到 lookupIPDeadline 启用
    一个新的协程去解析DNS, 具体调用栈如下:

    1.  
      // ----------------------------------------------------------------
    2.  
      // DialTimeout()
    3.  
      //
    4.  
      // ->resolveAddrList()
    5.  
      //
    6.  
      // --->internetAddrList()
    7.  
      //
    8.  
      // ------>lookupIPDeadline()
    9.  
      //
    10.  
      // --------->lookupGroup.DoChan() 在新的协程中去做 dns解析
    11.  
      //
    12.  
      // ------------->lookupIP()
    13.  
      //
    14.  
      // ------------------>goLookupIPOrder()
    15.  
      // ------------------------------------------------------------------

    总之,纯go语言的 DNS解析流程还是比较完善的~~

    ——————————————————————————————

    之前使用过GO语言写了一个实时图片下载程序,主要考虑到GO语言的DNS解析对协程支持友好, 即
    DNS解析时不会阻塞执行线程,只会阻塞当前协程,顺便研究了一下GO的net.LookupHost/ResolveIPAddr
    实现方式。下面一段描述翻译自go语言的官方文档 https://golang.org/pkg/net/域名解析:
            域名解析函数,Dial函数会间接调用到,而LokupHost和LookupAddr则会直接调用域名解析函数,不同
    的操作系统实现不同,  在Unix系统中有两种方法进行域名解析:
            1) 纯GO语言实现的域名解析,从/etc/resolv.conf中取出本地dns server地址列表, 发送DNS请求(UDP
                  报文)并获得结果
             2)  使用cgo方式, 最终会调用到c标准库的getaddrinfo或getnameinfo函数(不建议使用对GO协程不
                 友好)
            
            关于 cgo dns 解析的坑 参照以下链接:
            https://jira.mongodb.org/browse/MGO-41
            https://github.com/golang/go/issues/8602#issuecomment-66098142
            
             GO语言默认使用纯GO的域名解析,因为这样一个阻塞的DNS请求只会消耗一个协程, 使 用cgo的
    方式则会阻塞一个系统线程, 只有某些特定条件下才会使用系统提供的cgo方式, 例如: 1) 在OS X系统中不
    允许程序直接发送DNS请求;  2) LOCALDOMAINH环境变量存在,即使为空;  3) ES_OPTIONS或
    HOSTALIASES或ASR_CONFIG环境变量非空; 4)/etc/resolv.conf或/etc/nsswitch.conf指定的使用
    方式GO解析器没有实现;5) 当要解析的域名以.local结束, 或者是一个mDNS域名
            可以通过GODEBUG环境变量来设置go语言的默认DNS解析方式 纯go或cgo,
            -----------------------------------------------------------------------
            export GODEBUG=netdns=go    # force pure Go resolver 纯go 方式
            export GODEBUG=netdns=cgo   # force cgo resolver   cgo 方式
            -----------------------------------------------------------------------
            也可以在编译时指定netgo或netcgo的编译tag来设置
            在plan 9中 域名解析只能通过 /net/cs和 /net/dns
            在windows中 域名解析只能通过windows提供的C标准库函数GetAddrInfo或DnsQuery

    OK 官方说明看完了, 我们写一个例子试一下:

    package main
    
    import (
    	"net"
    	"fmt"
    	"os"
    )
    
    
    func main() {
    
    
    	ns, err := net.LookupHost("www.baidu.com")
    	if err != nil {
    		fmt.Fprintf(os.Stderr, "Err: %s", err.Error())
    		return
    	}
    
    	for _, n := range ns {
    		fmt.Fprintf(os.Stdout, "--%s
    ", n) 
    	}
    
    }
    

    1.  编译上述程序:go build -o ss source-dns.go

    2. 执行上述程序,得到进程号: 15097

    root@fly:/home/fly/mm# ./ss &
    [7] 15097

    3. 使用strace命令分析一下, 系统调用过程:   strace -p 15097 -o aaa

    使用strace命令分析一下, 系统调用过程:

    上面得到的aaa 文件内如如下:

    restart_syscall(<... resuming interrupted futex ...>) = -1 ETIMEDOUT (Connection timed out)
    futex(0x60ac70, FUTEX_WAKE_PRIVATE, 1)  = 1
    openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
    epoll_create1(EPOLL_CLOEXEC)            = 4
    epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=716087048, u64=139737477062408}}) = -1 EPERM (Operation not permitted)
    epoll_ctl(4, EPOLL_CTL_DEL, 3, 0xc000045abc) = -1 EPERM (Operation not permitted)
    read(3, "# /etc/nsswitch.conf
    #
    # Example"..., 1024) = 513
    read(3, "", 1024)                       = 0
    close(3)                                = 0
    openat(AT_FDCWD, "/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
    epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=716087048, u64=139737477062408}}) = -1 EPERM (Operation not permitted)
    epoll_ctl(4, EPOLL_CTL_DEL, 3, 0xc00004599c) = -1 EPERM (Operation not permitted)
    fstat(3, {st_mode=S_IFREG|0644, st_size=726, ...}) = 0
    read(3, "# This file is managed by man:sy"..., 65536) = 726
    read(3, "", 64810)                      = 0
    read(3, "", 65536)                      = 0
    close(3)                                = 0
    newfstatat(AT_FDCWD, "/etc/mdns.allow", 0xc000073078, 0) = -1 ENOENT (No such file or directory)
    getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=1024*1024}) = 0
    socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
    connect(3, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
    close(3)                                = 0
    socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
    connect(3, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
    close(3)                                = 0
    openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=513, ...}) = 0
    read(3, "# /etc/nsswitch.conf
    #
    # Example"..., 4096) = 513
    read(3, "", 4096)                       = 0
    close(3)                                = 0
    stat("/etc/resolv.conf", {st_mode=S_IFREG|0644, st_size=726, ...}) = 0
    openat(AT_FDCWD, "/etc/host.conf", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=92, ...}) = 0
    read(3, "# The "order" line is only used "..., 4096) = 92
    read(3, "", 4096)                       = 0
    close(3)                                = 0
    futex(0x7f172a74aba4, FUTEX_WAKE_PRIVATE, 2147483647) = 0
    openat(AT_FDCWD, "/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=726, ...}) = 0
    read(3, "# This file is managed by man:sy"..., 4096) = 726
    read(3, "", 4096)                       = 0
    close(3)                                = 0
    openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=30918, ...}) = 0
    mmap(NULL, 30918, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f172ab8a000
    close(3)                                = 0
    access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
    read(3, "177ELF2113>1P#"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0644, st_size=47568, ...}) = 0
    mmap(NULL, 2168632, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1725f34000
    mprotect(0x7f1725f3f000, 2093056, PROT_NONE) = 0
    mmap(0x7f172613e000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xa000) = 0x7f172613e000
    mmap(0x7f1726140000, 22328, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1726140000
    close(3)                                = 0
    mprotect(0x7f172613e000, 4096, PROT_READ) = 0
    munmap(0x7f172ab8a000, 30918)           = 0
    openat(AT_FDCWD, "/etc/hosts", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=218, ...}) = 0
    read(3, "127.0.0.1 localhost
    127.0.1.1 fl"..., 4096) = 218
    read(3, "", 4096)                       = 0
    close(3)                                = 0
    openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=30918, ...}) = 0
    mmap(NULL, 30918, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f172ab8a000
    close(3)                                = 0
    access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 3
    read(3, "177ELF2113>120017"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0644, st_size=26936, ...}) = 0
    mmap(NULL, 2121952, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1725d2d000
    mprotect(0x7f1725d32000, 2097152, PROT_NONE) = 0
    mmap(0x7f1725f32000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x5000) = 0x7f1725f32000
    close(3)                                = 0
    access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 3
    read(3, "177ELF2113>10008"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0644, st_size=101168, ...}) = 0
    mmap(NULL, 2206336, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1725b12000
    mprotect(0x7f1725b29000, 2097152, PROT_NONE) = 0
    mmap(0x7f1725d29000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17000) = 0x7f1725d29000
    mmap(0x7f1725d2b000, 6784, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1725d2b000
    close(3)                                = 0
    mprotect(0x7f1725d29000, 4096, PROT_READ) = 0
    mprotect(0x7f1725f32000, 4096, PROT_READ) = 0
    munmap(0x7f172ab8a000, 30918)           = 0
    socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 3
    connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, 16) = 0
    poll([{fd=3, events=POLLOUT}], 1, 0)    = 1 ([{fd=3, revents=POLLOUT}])
    sendmmsg(3, [{msg_hdr={msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="3t1113iot10vidagrid3com1"..., iov_len=45}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, msg_len=45}, {msg_hdr={msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="3152021113iot10vidagrid3com34"..., iov_len=45}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_TRUNC|MSG_WAITALL|MSG_NOSIGNAL|MSG_MORE|MSG_WAITFORONE}, msg_len=45}], 2, MSG_NOSIGNAL) = 2
    poll([{fd=3, events=POLLIN}], 1, 5000)  = 1 ([{fd=3, revents=POLLIN}])
    ioctl(3, FIONREAD, [61])                = 0
     recvfrom(3, "3t2012001113iot10vidagrid3com1"..., 2048, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, [28->16]) = 61
     poll([{fd=3, events=POLLIN}], 1, 4999)  = 1 ([{fd=3, revents=POLLIN}])
     ioctl(3, FIONREAD, [45])                = 0
     recvfrom(3, "315202201200113iot10vidagrid3com34"..., 65536, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, [28->16]) = 45
     close(3)                                = 0
     futex(0x60ac70, FUTEX_WAKE_PRIVATE, 1)  = 1
     futex(0x60ab70, FUTEX_WAKE_PRIVATE, 1)  = 1
     write(1, "--120.78.15.160
    ", 16)       = 16
     exit_group(0)                           = ?
     +++ exited with 0 +++
                                                                                                                                                                                                          
                                                                                                                                                                                                          
                                                                                                                                                                                                          
                                                                                                                                                                                                          
                                                                                                                                                                                                          
    

      

    # coding=UTF-8
    import threading
    import socket
    import socketserver
    
    
    class Handler(socketserver.BaseRequestHandler):
        def handle(self):
            request_data = self.request[0]
            # 将请求转发到 114 DNS
            redirect_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            redirect_socket.sendto(request_data, ('114.114.114.114', 53))
            response_data, address = redirect_socket.recvfrom(1024)
    
            # 将114响应响应给客户
            client_socket = self.request[1]
            client_socket.sendto(response_data, self.client_address)
    
    
    class Server(socketserver.ThreadingMixIn, socketserver.UDPServer):
        pass
    
    
    if __name__ == "__main__":
        # 一下ip需换成自己电脑的ip
        server = Server(('0.0.0.0',8088), Handler)
        with server:
            server_thread = threading.Thread(target=server.serve_forever)
            server_thread.daemon = True
            server_thread.start()
            print('The DNS server is running at 172.16.42.254...')
            server_thread.join()
    

      

  • 相关阅读:
    Educational Codeforces Round 86 (Rated for Div. 2)
    第十六届东南大学大学生程序设计竞赛(春、夏季)
    Codeforces Round #643 (Div. 2)
    [P3384] 【模板】轻重链剖分
    [BJOI2012] 连连看
    [CF1349C] Orac and Game of Life
    Codeforces Round #641 (Div. 2)
    [TJOI2018] 数学计算
    [CF1157D] N Problems During K Days
    [CF1163C1] Power Transmission (Easy Edition)
  • 原文地址:https://www.cnblogs.com/oxspirt/p/14154610.html
Copyright © 2020-2023  润新知