-
Notifications
You must be signed in to change notification settings - Fork 66
/
gdns.go
98 lines (83 loc) · 2.44 KB
/
gdns.go
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
/**
* dingo: a DNS caching proxy written in Go
* This file implements a Google DNS-over-HTTPS client
*
* Copyright (C) 2016 Pawel Foremski <[email protected]>
* Licensed under GNU GPL v3
*/
package main
import "fmt"
import "net/url"
import "time"
import "encoding/json"
import "math/rand"
import "strings"
import "flag"
type Gdns struct {
workers *int
server *string
auto *bool
sni *string
host *string
edns *string
nopad *bool
}
/* command-line arguments */
func (r *Gdns) Init() {
r.workers = flag.Int("gdns:workers", 10,
"Google DNS: number of independent workers")
r.server = flag.String("gdns:server", "216.58.195.78",
"Google DNS: server address")
r.auto = flag.Bool("gdns:auto", false,
"Google DNS: try to lookup the closest IPv4 server")
r.sni = flag.String("gdns:sni", "www.google.com",
"Google DNS: SNI string to send (should match server certificate)")
r.host = flag.String("gdns:host", "dns.google.com",
"Google DNS: HTTP 'Host' header (real FQDN, encrypted in TLS)")
r.edns = flag.String("gdns:edns", "",
"Google DNS: EDNS client subnet (set 0.0.0.0/0 to disable)")
r.nopad = flag.Bool("gdns:nopad", false,
"Google DNS: disable random padding")
}
/**********************************************************************/
func (R *Gdns) Start() {
if *R.workers <= 0 { return }
if *R.auto {
dbg(1, "resolving dns.google.com...")
r4 := R.resolve(NewHttps(*R.sni, false), *R.server, "dns.google.com", 1)
if r4.Status == 0 && len(r4.Answer) > 0 {
R.server = &r4.Answer[0].Data
}
}
dbg(1, "starting %d Google Public DNS client(s) querying server %s",
*R.workers, *R.server)
for i := 0; i < *R.workers; i++ { go R.worker(*R.server) }
}
func (R *Gdns) worker(server string) {
var https = NewHttps(*R.sni, false)
for q := range qchan {
*q.rchan <- *R.resolve(https, server, q.Name, q.Type)
}
}
func (R *Gdns) resolve(https *Https, server string, qname string, qtype int) *Reply {
r := Reply{ Status: -1 }
v := url.Values{}
/* prepare */
v.Set("name", qname)
v.Set("type", fmt.Sprintf("%d", qtype))
if len(*R.edns) > 0 {
v.Set("edns_client_subnet", *R.edns)
}
if !*R.nopad {
v.Set("random_padding", strings.Repeat(string(65+rand.Intn(26)), rand.Intn(500)))
}
/* query */
buf, err := https.Get(server, *R.host, "/resolve?" + v.Encode())
if err != nil { return &r }
/* parse */
r.Now = time.Now()
json.Unmarshal(buf, &r)
return &r
}
/* register module */
var _ = register("gdns", new(Gdns))