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)
}
|