目前需要从不同的地方访问一个域名的CNAME, 比如从国内和海外两个不同的地方访问, 并查看这个CNAME是不是设置正确。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
package main

import (
    "context"
    "flag"
    "fmt"
    "net"
    "time"

    "github.com/miekg/dns"
)

var (
    TIMEOUT = 5 * time.Second
)

type edns struct {
    client *dns.Client
    server string
}

func NewEdns() (*edns, error) {
    server := "223.5.5.5"
    port := "53"

    c := new(dns.Client)
    edns := &edns{
        client: c,
        server: net.JoinHostPort(server, port),
    }
    return edns, nil
}

func (e *edns) ednsMsg(domain string, clientIP net.IP) *dns.Msg {
    m := new(dns.Msg)
    m.SetQuestion(dns.Fqdn(domain), dns.TypeCNAME)
    m.RecursionDesired = true

    o := &dns.OPT{
        Hdr: dns.RR_Header{
            Name:   ".",
            Rrtype: dns.TypeOPT,
        },
    }

    ed := &dns.EDNS0_SUBNET{
        Code:          dns.EDNS0SUBNET,
        Address:       clientIP,
        Family:        1,
        SourceNetmask: net.IPv4len * 8,
    }

    o.Option = append(o.Option, ed)
    m.Extra = append(m.Extra, o)
    return m
}

func (e *edns) Query(domain string, clientIP net.IP) ([]string, error) {
    ctx, cancle := context.WithTimeout(context.Background(), TIMEOUT)
    defer cancle()

    m := e.ednsMsg(domain, clientIP)
    r, _, err := e.client.ExchangeContext(ctx, m, e.server)

    if r == nil {
        return nil, err
    }

    if r.Rcode != dns.RcodeSuccess {
        return nil, fmt.Errorf("invalid answer name")
    }

    var result []string
    for _, a := range r.Answer {
        switch ans := a.(type) {
        case *dns.CNAME:
            result = append(result, ans.Target)
        }
    }
    return result, nil
}

func main() {
    domain := flag.String("d", "www.baidu.com", "domain")
    clientIP := flag.String("c", "38.143.9.29", "client ip")

    flag.Parse()

    ed, err := NewEdns()
    if err != nil {
        panic(err)
    }

    cnames, err := ed.Query(*domain, net.ParseIP(*clientIP))
    if err != nil {
        panic(err)
    }

    fmt.Printf("domain: %s, cnames: %v\n", *domain, cnames)
}

output:

$ ./dns -d  test.ictim2020.com -c 58.22.114.38
domain: test.ictim2020.com, cnames: [www.baidu.com.]
$ ./dns -d  test.ictim2020.com -c 1.1.1.1
domain: test.ictim2020.com, cnames: [www.google.com.]