199 lines
4.6 KiB
Go
199 lines
4.6 KiB
Go
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.froth.zone/sam/awl/query"
|
|
"git.froth.zone/sam/awl/util"
|
|
"github.com/miekg/dns"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
func doQuery(c *cli.Context) error {
|
|
var (
|
|
err error
|
|
)
|
|
// load cli flags into options struct
|
|
Options := query.Options{
|
|
Logger: util.InitLogger(c.Bool("debug")),
|
|
Port: c.Int("port"),
|
|
IPv4: c.Bool("4"),
|
|
IPv6: c.Bool("6"),
|
|
DNSSEC: c.Bool("dnssec"),
|
|
Short: c.Bool("short"),
|
|
TCP: c.Bool("tcp"),
|
|
TLS: c.Bool("tls"),
|
|
HTTPS: c.Bool("https"),
|
|
QUIC: c.Bool("quic"),
|
|
Truncate: c.Bool("no-truncate"),
|
|
AA: c.Bool("aa"),
|
|
TC: c.Bool("tc"),
|
|
Z: c.Bool("z"),
|
|
CD: c.Bool("cd"),
|
|
NoRD: c.Bool("no-rd"),
|
|
NoRA: c.Bool("no-ra"),
|
|
Reverse: c.Bool("reverse"),
|
|
Debug: c.Bool("debug"),
|
|
}
|
|
Options.Answers, err = parseArgs(c.Args().Slice(), Options)
|
|
if err != nil {
|
|
Options.Logger.Error("Unable to parse args")
|
|
return err
|
|
}
|
|
msg := new(dns.Msg)
|
|
|
|
if Options.Reverse {
|
|
if dns.TypeToString[Options.Answers.Request] == "A" {
|
|
Options.Answers.Request = dns.StringToType["PTR"]
|
|
}
|
|
Options.Answers.Name, err = util.ReverseDNS(Options.Answers.Name, Options.Answers.Request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// if the domain is not canonical, make it canonical
|
|
if !strings.HasSuffix(Options.Answers.Name, ".") {
|
|
Options.Answers.Name = fmt.Sprintf("%s.", Options.Answers.Name)
|
|
}
|
|
msg.SetQuestion(Options.Answers.Name, Options.Answers.Request)
|
|
// If port is not set, set it
|
|
if Options.Port == 0 {
|
|
if Options.TLS || Options.QUIC {
|
|
Options.Port = 853
|
|
} else {
|
|
Options.Port = 53
|
|
}
|
|
}
|
|
Options.Logger.Debug("setting any message flags")
|
|
// Make this authoritative (does this do anything?)
|
|
if Options.AA {
|
|
Options.Logger.Debug("making message authorative")
|
|
msg.Authoritative = true
|
|
}
|
|
// Set truncated flag (why)
|
|
if Options.TC {
|
|
msg.Truncated = true
|
|
}
|
|
// Set the zero flag if requested (does nothing)
|
|
if Options.Z {
|
|
Options.Logger.Debug("setting to zero")
|
|
msg.Zero = true
|
|
}
|
|
// Disable DNSSEC validation
|
|
if Options.CD {
|
|
Options.Logger.Debug("disabling DNSSEC validation")
|
|
msg.CheckingDisabled = true
|
|
}
|
|
// Disable wanting recursion
|
|
if Options.NoRD {
|
|
Options.Logger.Debug("disabling recursion")
|
|
msg.RecursionDesired = false
|
|
}
|
|
// Disable recursion being available (I don't think this does anything)
|
|
if Options.NoRA {
|
|
msg.RecursionAvailable = false
|
|
}
|
|
// Set DNSSEC if requested
|
|
if Options.DNSSEC {
|
|
Options.Logger.Debug("using DNSSEC")
|
|
msg.SetEdns0(1232, true)
|
|
}
|
|
|
|
resolver, err := query.LoadResolver(Options.Answers.Server, Options)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if Options.Debug {
|
|
Options.Logger.SetLevel(3)
|
|
}
|
|
|
|
Options.Logger.Debug("Starting awl")
|
|
|
|
var in = Options.Answers.DNS
|
|
|
|
// Make the DNS request
|
|
if Options.HTTPS {
|
|
in, Options.Answers.RTT, err = resolver.LookUp(msg)
|
|
} else if Options.QUIC {
|
|
in, Options.Answers.RTT, err = resolver.LookUp(msg)
|
|
} else {
|
|
Options.Answers.Server = net.JoinHostPort(Options.Answers.Server, strconv.Itoa(Options.Port))
|
|
d := new(dns.Client)
|
|
|
|
// Set TCP/UDP, depending on flags
|
|
if Options.TCP || Options.TLS {
|
|
d.Net = "tcp"
|
|
} else {
|
|
Options.Logger.Debug("using udp")
|
|
d.Net = "udp"
|
|
}
|
|
|
|
// Set IPv4 or IPv6, depending on flags
|
|
switch {
|
|
case Options.IPv4:
|
|
d.Net += "4"
|
|
case Options.IPv6:
|
|
d.Net += "6"
|
|
}
|
|
|
|
// Add TLS, if requested
|
|
if Options.TLS {
|
|
d.Net += "-tls"
|
|
}
|
|
|
|
in, Options.Answers.RTT, err = d.Exchange(msg, Options.Answers.Server)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// If UDP truncates, use TCP instead (unless truncation is to be ignored)
|
|
if in.MsgHdr.Truncated && !Options.Truncate {
|
|
fmt.Printf(";; Truncated, retrying with TCP\n\n")
|
|
d.Net = "tcp"
|
|
switch {
|
|
case Options.IPv4:
|
|
d.Net += "4"
|
|
case Options.IPv4:
|
|
d.Net += "6"
|
|
}
|
|
in, Options.Answers.RTT, err = d.Exchange(msg, Options.Answers.Server)
|
|
}
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if c.Bool("json") {
|
|
json, err := json.MarshalIndent(in, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Println(string(json))
|
|
} else {
|
|
if !c.Bool("short") {
|
|
// Print everything
|
|
fmt.Println(in)
|
|
fmt.Println(";; Query time:", Options.Answers.RTT)
|
|
fmt.Println(";; SERVER:", Options.Answers.Server)
|
|
fmt.Println(";; WHEN:", time.Now().Format(time.RFC1123Z))
|
|
fmt.Println(";; MSG SIZE rcvd:", in.Len())
|
|
} else {
|
|
// Print just the responses, nothing else
|
|
for _, res := range in.Answer {
|
|
temp := strings.Split(res.String(), "\t")
|
|
fmt.Println(temp[len(temp)-1])
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|