mirror of
https://github.com/DNSCrypt/dnscrypt-proxy.git
synced 2025-03-04 02:14:40 +01:00
Revamp dnscrypt-proxy -resolve
This commit is contained in:
parent
a584effbe9
commit
fc82a6c05e
4 changed files with 338 additions and 49 deletions
|
@ -6,6 +6,10 @@
|
|||
* `generate-domains-blacklist.py` has been renamed to
|
||||
`generate-domains-blocklist.py`, and the configuration files
|
||||
have been renamed as well.
|
||||
- `dnscrypt-proxy -resolve` has been completely revamped, and now requires
|
||||
the configuration file to be accessible. It will send a query to an IP address
|
||||
of the `dnscrypt-proxy` server by default. Sending queries to arbitrary
|
||||
servers is also supported with the `-resolve name,address` syntax.
|
||||
- Server lists can't be older than a week any more, even if directory
|
||||
permissions are incorrect and cache files cannot be written.
|
||||
- macOS/arm64 is now officially supported.
|
||||
|
|
|
@ -277,6 +277,7 @@ type CaptivePortalsConfig struct {
|
|||
}
|
||||
|
||||
type ConfigFlags struct {
|
||||
Resolve *string
|
||||
List *bool
|
||||
ListAll *bool
|
||||
JSONOutput *bool
|
||||
|
@ -314,6 +315,16 @@ func ConfigLoad(proxy *Proxy, flags *ConfigFlags) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if flags.Resolve != nil && len(*flags.Resolve) > 0 {
|
||||
addr := "127.0.0.1:53"
|
||||
if len(config.ListenAddresses) > 0 {
|
||||
addr = config.ListenAddresses[0]
|
||||
}
|
||||
Resolve(addr, *flags.Resolve, len(config.ServerNames) == 1)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if err := cdFileDir(foundConfigFile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ func main() {
|
|||
|
||||
svcFlag := flag.String("service", "", fmt.Sprintf("Control the system service: %q", service.ControlAction))
|
||||
version := flag.Bool("version", false, "print current proxy version")
|
||||
resolve := flag.String("resolve", "", "resolve a name using system libraries")
|
||||
flags := ConfigFlags{}
|
||||
flags.Resolve = flag.String("resolve", "", "resolve a DNS name (string can be <name> or <name>,<resolver address>)")
|
||||
flags.List = flag.Bool("list", false, "print the list of available resolvers for the enabled filters")
|
||||
flags.ListAll = flag.Bool("list-all", false, "print the complete list of available resolvers, ignoring filters")
|
||||
flags.JSONOutput = flag.Bool("json", false, "output list as JSON")
|
||||
|
@ -58,10 +58,6 @@ func main() {
|
|||
fmt.Println(AppVersion)
|
||||
os.Exit(0)
|
||||
}
|
||||
if resolve != nil && len(*resolve) > 0 {
|
||||
Resolve(*resolve)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
app := &App{
|
||||
flags: &flags,
|
||||
|
|
|
@ -1,58 +1,336 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const myResolverHost string = "resolver.dnscrypt.info"
|
||||
const myResolverHost string = "resolver.dnscrypt.info."
|
||||
const nonexistentName string = "nonexistent-zone.dnscrypt-test."
|
||||
|
||||
func Resolve(name string) {
|
||||
fmt.Printf("Resolving [%s]\n\n", name)
|
||||
|
||||
fmt.Printf("Canonical name: ")
|
||||
cname, err := net.LookupCNAME(name)
|
||||
if err != nil {
|
||||
fmt.Println("-")
|
||||
} else {
|
||||
fmt.Println(cname)
|
||||
func resolveQuery(server string, qName string, qType uint16) (*dns.Msg, error) {
|
||||
client := new(dns.Client)
|
||||
client.ReadTimeout = 10 * time.Second
|
||||
msg := &dns.Msg{
|
||||
MsgHdr: dns.MsgHdr{
|
||||
RecursionDesired: true,
|
||||
Opcode: dns.OpcodeQuery,
|
||||
},
|
||||
Question: make([]dns.Question, 1),
|
||||
}
|
||||
|
||||
fmt.Printf("IP addresses: ")
|
||||
addrs, err := net.LookupHost(name)
|
||||
if err != nil {
|
||||
fmt.Println("-")
|
||||
} else {
|
||||
fmt.Println(strings.Join(addrs, ", "))
|
||||
options := &dns.OPT{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: ".",
|
||||
Rrtype: dns.TypeOPT,
|
||||
},
|
||||
}
|
||||
|
||||
fmt.Printf("TXT records: ")
|
||||
txt, err := net.LookupTXT(name)
|
||||
if err != nil {
|
||||
fmt.Println("-")
|
||||
} else {
|
||||
fmt.Println(strings.Join(txt, " "))
|
||||
}
|
||||
|
||||
mxs, _ := net.LookupMX(name)
|
||||
if len(mxs) > 0 {
|
||||
fmt.Printf("Mail servers: %d mail servers found\n", len(mxs))
|
||||
}
|
||||
|
||||
ns, _ := net.LookupNS(name)
|
||||
if len(ns) > 0 {
|
||||
fmt.Printf("Name servers: %d name servers found\n", len(ns))
|
||||
}
|
||||
|
||||
resIP, err := net.LookupHost(myResolverHost)
|
||||
if err == nil && len(resIP) > 0 {
|
||||
fmt.Printf("Resolver IP: %s", resIP[0])
|
||||
rev, err := net.LookupAddr(resIP[0])
|
||||
if err == nil && len(rev) > 0 {
|
||||
fmt.Printf(" (%s)", rev[0])
|
||||
msg.Extra = append(msg.Extra, options)
|
||||
options.SetDo()
|
||||
options.SetUDPSize(uint16(MaxDNSPacketSize))
|
||||
msg.Question[0] = dns.Question{Name: qName, Qtype: qType, Qclass: dns.ClassINET}
|
||||
msg.Id = dns.Id()
|
||||
for i := 0; i < 2; i++ {
|
||||
response, rtt, err := client.Exchange(msg, server)
|
||||
if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
|
||||
continue
|
||||
}
|
||||
fmt.Println("")
|
||||
_ = rtt
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
return nil, errors.New("Timeout")
|
||||
}
|
||||
|
||||
func Resolve(server string, name string, singleResolver bool) {
|
||||
parts := strings.SplitN(name, ",", 2)
|
||||
if len(parts) == 2 {
|
||||
name, server = parts[0], parts[1]
|
||||
singleResolver = true
|
||||
}
|
||||
|
||||
host, port := ExtractHostAndPort(server, 53)
|
||||
if host == "0.0.0.0" {
|
||||
host = "127.0.0.1"
|
||||
} else if host == "[::]" {
|
||||
host = "[::1]"
|
||||
}
|
||||
server = fmt.Sprintf("%s:%d", host, port)
|
||||
|
||||
fmt.Printf("Resolving [%s] using %s port %d\n\n", name, host, port)
|
||||
name = dns.Fqdn(name)
|
||||
|
||||
cname := name
|
||||
|
||||
for {
|
||||
response, err := resolveQuery(server, myResolverHost, dns.TypeA)
|
||||
if err != nil {
|
||||
fmt.Printf("Unable to resolve: [%s]\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Resolver : ")
|
||||
res := make([]string, 0)
|
||||
for _, answer := range response.Answer {
|
||||
if answer.Header().Class != dns.ClassINET {
|
||||
continue
|
||||
}
|
||||
var ip string
|
||||
if answer.Header().Rrtype == dns.TypeA {
|
||||
ip = answer.(*dns.A).A.String()
|
||||
} else if answer.Header().Rrtype == dns.TypeAAAA {
|
||||
ip = answer.(*dns.AAAA).AAAA.String()
|
||||
}
|
||||
if rev, err := dns.ReverseAddr(ip); err == nil {
|
||||
response, err = resolveQuery(server, rev, dns.TypePTR)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
for _, answer := range response.Answer {
|
||||
if answer.Header().Rrtype != dns.TypePTR || answer.Header().Class != dns.ClassINET {
|
||||
continue
|
||||
}
|
||||
ip = ip + " (" + answer.(*dns.PTR).Ptr + ")"
|
||||
break
|
||||
}
|
||||
}
|
||||
res = append(res, ip)
|
||||
}
|
||||
if len(res) == 0 {
|
||||
fmt.Println("-")
|
||||
} else {
|
||||
fmt.Println(strings.Join(res, ", "))
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if singleResolver {
|
||||
for {
|
||||
fmt.Printf("Lying : ")
|
||||
response, err := resolveQuery(server, nonexistentName, dns.TypeA)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if response.Rcode == dns.RcodeSuccess {
|
||||
fmt.Println("yes. That resolver returns wrong responses")
|
||||
} else if response.Rcode == dns.RcodeNameError {
|
||||
fmt.Println("no")
|
||||
} else {
|
||||
fmt.Printf("unknown - query returned %s\n", dns.RcodeToString[response.Rcode])
|
||||
}
|
||||
|
||||
if response.Rcode == dns.RcodeNameError {
|
||||
fmt.Printf("DNSSEC : ")
|
||||
if response.AuthenticatedData {
|
||||
fmt.Println("yes, the resolver supports DNSSEC")
|
||||
} else {
|
||||
fmt.Println("no, the resolver doesn't support DNSSEC")
|
||||
fmt.Println(response)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Multiple resolvers have been configured; this is just one one of them.")
|
||||
}
|
||||
|
||||
fmt.Println("")
|
||||
|
||||
cname:
|
||||
for {
|
||||
fmt.Printf("Canonical name: ")
|
||||
for i := 0; i < 100; i++ {
|
||||
response, err := resolveQuery(server, cname, dns.TypeCNAME)
|
||||
if err != nil {
|
||||
break cname
|
||||
}
|
||||
found := false
|
||||
for _, answer := range response.Answer {
|
||||
if answer.Header().Rrtype != dns.TypeCNAME || answer.Header().Class != dns.ClassINET {
|
||||
continue
|
||||
}
|
||||
cname = answer.(*dns.CNAME).Target
|
||||
found = true
|
||||
break
|
||||
}
|
||||
if !found {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println(cname)
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Println("")
|
||||
|
||||
for {
|
||||
fmt.Printf("IPv4 addresses: ")
|
||||
response, err := resolveQuery(server, cname, dns.TypeA)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
ipv4 := make([]string, 0)
|
||||
for _, answer := range response.Answer {
|
||||
if answer.Header().Rrtype != dns.TypeA || answer.Header().Class != dns.ClassINET {
|
||||
continue
|
||||
}
|
||||
ipv4 = append(ipv4, answer.(*dns.A).A.String())
|
||||
}
|
||||
if len(ipv4) == 0 {
|
||||
fmt.Println("-")
|
||||
} else {
|
||||
fmt.Println(strings.Join(ipv4, ", "))
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
for {
|
||||
fmt.Printf("IPv6 addresses: ")
|
||||
response, err := resolveQuery(server, cname, dns.TypeAAAA)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
ipv6 := make([]string, 0)
|
||||
for _, answer := range response.Answer {
|
||||
if answer.Header().Rrtype != dns.TypeAAAA || answer.Header().Class != dns.ClassINET {
|
||||
continue
|
||||
}
|
||||
ipv6 = append(ipv6, answer.(*dns.AAAA).AAAA.String())
|
||||
}
|
||||
if len(ipv6) == 0 {
|
||||
fmt.Println("-")
|
||||
} else {
|
||||
fmt.Println(strings.Join(ipv6, ", "))
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Println("")
|
||||
|
||||
for {
|
||||
fmt.Printf("Name servers : ")
|
||||
response, err := resolveQuery(server, cname, dns.TypeNS)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
nss := make([]string, 0)
|
||||
for _, answer := range response.Answer {
|
||||
if answer.Header().Rrtype != dns.TypeNS || answer.Header().Class != dns.ClassINET {
|
||||
continue
|
||||
}
|
||||
nss = append(nss, answer.(*dns.NS).Ns)
|
||||
}
|
||||
if len(nss) == 0 {
|
||||
fmt.Println("No name servers found")
|
||||
} else {
|
||||
fmt.Println(strings.Join(nss, ", "))
|
||||
}
|
||||
|
||||
fmt.Printf("DNSSEC signed : ")
|
||||
if response.AuthenticatedData {
|
||||
fmt.Println("yes")
|
||||
} else {
|
||||
fmt.Println("no")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
for {
|
||||
fmt.Printf("Mail servers : ")
|
||||
response, err := resolveQuery(server, cname, dns.TypeMX)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
mxs := make([]string, 0)
|
||||
for _, answer := range response.Answer {
|
||||
if answer.Header().Rrtype != dns.TypeMX || answer.Header().Class != dns.ClassINET {
|
||||
continue
|
||||
}
|
||||
mxs = append(mxs, answer.(*dns.MX).Mx)
|
||||
}
|
||||
if len(mxs) == 0 {
|
||||
fmt.Println("no mail servers found")
|
||||
} else if len(mxs) > 1 {
|
||||
fmt.Printf("%d mail servers found\n", len(mxs))
|
||||
} else {
|
||||
fmt.Println("1 mail servers found")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Println("")
|
||||
|
||||
for {
|
||||
fmt.Printf("HTTPS alias : ")
|
||||
response, err := resolveQuery(server, cname, dns.TypeHTTPS)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
aliases := make([]string, 0)
|
||||
for _, answer := range response.Answer {
|
||||
if answer.Header().Rrtype != dns.TypeHTTPS || answer.Header().Class != dns.ClassINET {
|
||||
continue
|
||||
}
|
||||
https := answer.(*dns.HTTPS)
|
||||
if https.Priority != 0 || len(https.Target) < 2 {
|
||||
continue
|
||||
}
|
||||
aliases = append(aliases, https.Target)
|
||||
}
|
||||
if len(aliases) == 0 {
|
||||
fmt.Println("-")
|
||||
} else {
|
||||
fmt.Println(strings.Join(aliases, ", "))
|
||||
}
|
||||
|
||||
fmt.Printf("HTTPS info : ")
|
||||
info := make([]string, 0)
|
||||
for _, answer := range response.Answer {
|
||||
if answer.Header().Rrtype != dns.TypeHTTPS || answer.Header().Class != dns.ClassINET {
|
||||
continue
|
||||
}
|
||||
https := answer.(*dns.HTTPS)
|
||||
if https.Priority == 0 || len(https.Target) > 1 {
|
||||
continue
|
||||
}
|
||||
for _, value := range https.Value {
|
||||
info = append(info, fmt.Sprintf("[%s]=[%s]", value.Key(), value.String()))
|
||||
}
|
||||
}
|
||||
if len(info) == 0 {
|
||||
fmt.Println("-")
|
||||
} else {
|
||||
fmt.Println(strings.Join(info, ", "))
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Println("")
|
||||
|
||||
for {
|
||||
fmt.Printf("TXT records : ")
|
||||
response, err := resolveQuery(server, cname, dns.TypeTXT)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
txt := make([]string, 0)
|
||||
for _, answer := range response.Answer {
|
||||
if answer.Header().Rrtype != dns.TypeTXT || answer.Header().Class != dns.ClassINET {
|
||||
continue
|
||||
}
|
||||
txt = append(txt, strings.Join(answer.(*dns.TXT).Txt, " "))
|
||||
}
|
||||
if len(txt) == 0 {
|
||||
fmt.Println("-")
|
||||
} else {
|
||||
fmt.Println(strings.Join(txt, ", "))
|
||||
}
|
||||
break
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue