1
0
Fork 0
mirror of https://github.com/SamTherapy/dnscrypt.git synced 2024-12-22 08:50:43 +00:00
dnscrypt/cmd/lookup.go
Sam Therapy 3459b621a6
change import URL
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-03-06 23:26:40 +01:00

113 lines
3.6 KiB
Go

package main
import (
"encoding/json"
"os"
"strings"
"time"
"dns.froth.zone/dnscrypt"
"github.com/AdguardTeam/golibs/log"
"github.com/ameshkov/dnsstamps"
"github.com/miekg/dns"
)
// LookupStampArgs is the "lookup-stamp" command arguments structure
type LookupStampArgs struct {
Network string `short:"n" long:"network" description:"network type (tcp/udp)" default:"udp"`
Stamp string `short:"s" long:"stamp" description:"DNSCrypt resolver stamp. Param is required." required:"true"`
Domain string `short:"d" long:"domain" description:"Domain to resolve. Param is required." required:"true"`
Type string `short:"t" long:"type" description:"DNS query type" default:"A"`
}
// LookupArgs is the "lookup" command arguments structure
type LookupArgs struct {
Network string `short:"n" long:"network" description:"network type (tcp/udp)" default:"udp"`
ProviderName string `short:"p" long:"provider-name" description:"DNSCrypt resolver provider name. Param is required." required:"true"`
PublicKey string `short:"k" long:"public-key" description:"DNSCrypt resolver public key. Param is required." required:"true"`
ServerAddr string `short:"a" long:"addr" description:"Resolver address (IP[:port]). By default, the port is 443. Param is required." required:"true"`
Domain string `short:"d" long:"domain" description:"Domain to resolve. Param is required." required:"true"`
Type string `short:"t" long:"type" description:"DNS query type" default:"A"`
}
// LookupResult is the lookup result that contains the cert info and the query response
type LookupResult struct {
Certificate struct {
Serial uint32 `json:"serial"`
EsVersion string `json:"encryption"`
NotAfter time.Time `json:"not_after"`
NotBefore time.Time `json:"not_before"`
} `json:"certificate"`
Reply *dns.Msg `json:"reply"`
}
// lookup performs a DNS lookup, prints DNSCrypt info and lookup results
func lookup(args LookupArgs) {
serverPk, err := dnscrypt.HexDecodeKey(args.PublicKey)
if err != nil {
log.Fatalf("invalid resolver public key: %v", err)
}
stamp := dnsstamps.ServerStamp{
ProviderName: args.ProviderName,
ServerPk: serverPk,
ServerAddrStr: args.ServerAddr,
Proto: dnsstamps.StampProtoTypeDNSCrypt,
}
lookupStamp(LookupStampArgs{
Network: args.Network,
Stamp: stamp.String(),
Domain: args.Domain,
Type: args.Type,
})
}
// lookupStamp performs a DNS lookup, prints DNSCrypt cert info and lookup results
func lookupStamp(args LookupStampArgs) {
c := &dnscrypt.Client{
Net: args.Network,
Timeout: 10 * time.Second,
}
ri, err := c.Dial(args.Stamp)
if err != nil {
log.Fatalf("failed to establish connection with the server: %v", err)
}
res := LookupResult{}
res.Certificate.Serial = ri.ResolverCert.Serial
res.Certificate.NotAfter = time.Unix(int64(ri.ResolverCert.NotAfter), 0)
res.Certificate.NotBefore = time.Unix(int64(ri.ResolverCert.NotBefore), 0)
res.Certificate.EsVersion = ri.ResolverCert.EsVersion.String()
dnsType, ok := dns.StringToType[strings.ToUpper(args.Type)]
if !ok {
log.Fatalf("invalid type %s", args.Type)
}
req := &dns.Msg{}
req.Id = dns.Id()
req.RecursionDesired = true
req.Question = []dns.Question{
{
Name: dns.Fqdn(args.Domain),
Qtype: dnsType,
Qclass: dns.ClassINET,
},
}
reply, err := c.Exchange(req, ri)
if err != nil {
log.Fatalf("failed to resolve %s %s", args.Type, args.Domain)
}
res.Reply = reply
b, err := json.MarshalIndent(res, "", " ")
if err != nil {
log.Fatalf("failed to marshal result to json: %v", err)
}
_, _ = os.Stdout.WriteString(string(b) + "\n")
}