55 "fmt"
66 "math/rand"
77 "net"
8+ "net/http"
89 "os"
910 "os/signal"
1011 "path/filepath"
@@ -18,6 +19,11 @@ import (
1819 "github.com/fardog/secureoperator/cmd"
1920)
2021
22+ const (
23+ gdnsEndpoint = "https://dns.google.com/resolve"
24+ cloudflareEndpoint = "https://cloudflare-dns.com/dns-query"
25+ )
26+
2127var (
2228 listenAddress = flag .String (
2329 "listen" , ":53" , "listen address, as `[host]:port`" ,
@@ -35,49 +41,72 @@ var (
3541 "Log level, one of: debug, info, warn, error, fatal, panic" ,
3642 )
3743
44+ // one-stop configuration flags; when used, these configure sane defaults
45+ google = flag .Bool (
46+ "google" ,
47+ false ,
48+ fmt .Sprintf (`Use Google defaults. When set, the following options will be used unless
49+ explicitly overridden:
50+ dns-servers: 8.8.8.8,8.8.4.4
51+ endpoint: %v` , gdnsEndpoint ),
52+ )
53+ cloudflare = flag .Bool (
54+ "cloudflare" ,
55+ false ,
56+ fmt .Sprintf (`Use Cloudflare defaults. When set, the following options will be used
57+ unless explicitly overridden:
58+ dns-servers: 1.0.0.1,1.1.1.1
59+ params: ct=application/dns-json
60+ endpoint: %v` , cloudflareEndpoint ),
61+ )
62+
3863 // resolution of the Google DNS endpoint; the interaction of these values is
3964 // somewhat complex, and is further explained in the help message.
4065 endpoint = flag .String (
4166 "endpoint" ,
42- "https://dns.google.com/resolve" ,
43- "Google DNS-over-HTTPS endpoint url" ,
67+ gdnsEndpoint ,
68+ "DNS-over-HTTPS endpoint url" ,
4469 )
4570 endpointIPs = flag .String (
4671 "endpoint-ips" ,
4772 "" ,
48- `IPs of the Google DNS-over-HTTPS endpoint; if provided, endpoint lookup is
49- skipped, and the host value in "endpoint" is sent as the Host header. Comma
50- separated with no spaces; e.g. "74.125.28.139,74.125.28.102". One server is
51- randomly chosen for each request, failed requests are not retried.` ,
73+ `IPs of the DNS-over-HTTPS endpoint; if provided, endpoint lookup is
74+ skipped, and the host value in "endpoint" is sent as the Host header. Comma
75+ separated with no spaces; e.g. "74.125.28.139,74.125.28.102". One server is
76+ randomly chosen for each request, failed requests are not retried.` ,
5277 )
5378 dnsServers = flag .String (
5479 "dns-servers" ,
5580 "" ,
5681 `DNS Servers used to look up the endpoint; system default is used if absent.
57- Ignored if "endpoint-ips" is set. Comma separated, e.g. "8.8.8.8,8.8.4.4:53".
58- The port section is optional, and 53 will be used by default.` ,
82+ Ignored if "endpoint-ips" is set. Comma separated, e.g. "8.8.8.8,8.8.4.4:53".
83+ The port section is optional, and 53 will be used by default.` ,
5984 )
6085 autoEDNS = flag .Bool (
6186 "auto-edns-subnet" ,
6287 false ,
6388 `By default, we use an EDNS subnet of 0.0.0.0/0 which does not reveal your
64- IP address or subnet to authoratative DNS servers. If privacy of your IP
65- address is not a concern and you want to take advantage of an authoratative
66- server determining the best DNS results for you, set this flag. This flag
67- specifies that Google should choose what subnet to send; if you'd like to
68- specify your own subnet, use the -edns-subnet option.` ,
89+ IP address or subnet to authoratative DNS servers. If privacy of your IP
90+ address is not a concern and you want to take advantage of an authoratative
91+ server determining the best DNS results for you, set this flag. This flag
92+ specifies that Google should choose what subnet to send; if you'd like to
93+ specify your own subnet, use the -edns-subnet option.` ,
6994 )
7095 ednsSubnet = flag .String (
7196 "edns-subnet" ,
7297 secop .GoogleEDNSSentinelValue ,
7398 `Specify a subnet to be sent in the edns0-client-subnet option; by default
74- we specify that this option should not be used, for privacy. If
75- -auto-edns-subnet is used, the value specified here is ignored.
99+ we specify that this option should not be used, for privacy. If
100+ -auto-edns-subnet is used, the value specified here is ignored.
76101 ` ,
77102 )
78103
79104 enableTCP = flag .Bool ("tcp" , true , "Listen on TCP" )
80105 enableUDP = flag .Bool ("udp" , true , "Listen on UDP" )
106+
107+ // variables set in main body
108+ headers = make (cmd.KeyValue )
109+ queryParameters = make (cmd.KeyValue )
81110)
82111
83112func serve (net string ) {
@@ -102,6 +131,21 @@ func serve(net string) {
102131}
103132
104133func main () {
134+ // non-standard flag vars
135+ flag .Var (
136+ headers ,
137+ "header" ,
138+ `Additional headers to be sent with http requests, as Key=Value; specify
139+ multiple as:
140+ -header Key-1=Value-1-1 -header Key-1=Value1-2 -header Key-2=Value-2` ,
141+ )
142+ flag .Var (
143+ queryParameters ,
144+ "param" ,
145+ `Additional query parameters to be sent with http requests, as key=value;
146+ specify multiple as:
147+ -param key1=value1-1 -param key1=value1-2 -param key2=value2` ,
148+ )
105149 flag .Usage = func () {
106150 _ , exe := filepath .Split (os .Args [0 ])
107151 fmt .Fprint (os .Stderr , "A DNS-protocol proxy for Google's DNS-over-HTTPS service.\n \n " )
@@ -121,6 +165,10 @@ func main() {
121165 }
122166 log .SetLevel (level )
123167
168+ if * google && * cloudflare {
169+ log .Fatalf ("you may not specify `-google` and `-cloudflare` arguments together" )
170+ }
171+
124172 eips , err := cmd .CSVtoIPs (* endpointIPs )
125173 if err != nil {
126174 log .Fatalf ("error parsing endpoint-ips: %v" , err )
@@ -141,13 +189,43 @@ func main() {
141189 log .Warn ("EDNS will be used; authoritative name servers may be able to determine your location" )
142190 }
143191
144- provider , err := secop .NewGDNSProvider (* endpoint , & secop.GDNSOptions {
192+ ep := * endpoint
193+ opts := & secop.GDNSOptions {
145194 Pad : ! * noPad ,
146195 EndpointIPs : eips ,
147196 DNSServers : dips ,
148197 UseEDNSsubnetOption : true ,
149198 EDNSSubnet : edns ,
150- })
199+ QueryParameters : map [string ][]string (queryParameters ),
200+ Headers : http .Header (headers ),
201+ }
202+
203+ // handle "sane defaults" if requested; only where settings are not explicitly
204+ // provided by the user
205+ if * google {
206+ if len (opts .DNSServers ) == 0 {
207+ opts .DNSServers = []secop.Endpoint {
208+ secop.Endpoint {IP : net .ParseIP ("8.8.8.8" ), Port : 53 },
209+ secop.Endpoint {IP : net .ParseIP ("8.8.4.4" ), Port : 53 },
210+ }
211+ }
212+ } else if * cloudflare {
213+ // override only if it's currently the default
214+ if ep == gdnsEndpoint {
215+ ep = cloudflareEndpoint
216+ }
217+ if len (opts .DNSServers ) == 0 {
218+ opts .DNSServers = []secop.Endpoint {
219+ secop.Endpoint {IP : net .ParseIP ("1.0.0.1" ), Port : 53 },
220+ secop.Endpoint {IP : net .ParseIP ("1.1.1.1" ), Port : 53 },
221+ }
222+ }
223+ if _ , ok := opts .QueryParameters ["ct" ]; ! ok {
224+ opts .QueryParameters ["ct" ] = []string {"application/dns-json" }
225+ }
226+ }
227+
228+ provider , err := secop .NewGDNSProvider (ep , opts )
151229 if err != nil {
152230 log .Fatal (err )
153231 }
0 commit comments