mirror of
https://github.com/SamTherapy/dnscrypt.git
synced 2024-12-22 08:50:43 +00:00
5ddb58f703
Graceful shutdown of the DNSCrypt server This PR implements Server.Shutdown(ctx context.Context) method that allows to shut down the DNSCrypt server gracefully. Some additional changes that were inadvertently made while doing that: 1. Added benchmark tests 2. Started using dns.ReadFromSessionUDP / dns.WriteToSessionUDP instead of implementing it by ourselves 3. Generally improved tests 4. Added depguard 5. Improved comments overall in the code
113 lines
3.6 KiB
Go
113 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/AdguardTeam/golibs/log"
|
|
"github.com/ameshkov/dnscrypt/v2"
|
|
"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")
|
|
}
|