awl/query.go

179 lines
3.8 KiB
Go

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
resp util.Response
isHTTPS bool
)
resp.Answers, err = parseArgs(c.Args().Slice())
if err != nil {
return err
}
port := c.Int("port")
// If port is not set, set it
if port == 0 {
if c.Bool("tls") || c.Bool("quic") {
port = 853
} else {
port = 53
}
}
if c.Bool("https") || strings.HasPrefix(resp.Answers.Server, "https://") {
// add https:// if it doesn't already exist
if !strings.HasPrefix(resp.Answers.Server, "https://") {
resp.Answers.Server = "https://" + resp.Answers.Server
}
isHTTPS = true
} else {
resp.Answers.Server = net.JoinHostPort(resp.Answers.Server, strconv.Itoa(port))
}
// Process the IP/Phone number so a PTR/NAPTR can be done
if c.Bool("reverse") {
if dns.TypeToString[resp.Answers.Request] == "A" {
resp.Answers.Request = dns.StringToType["PTR"]
}
resp.Answers.Name, err = util.ReverseDNS(resp.Answers.Name, dns.TypeToString[resp.Answers.Request])
if err != nil {
return err
}
}
// if the domain is not canonical, make it canonical
if !strings.HasSuffix(resp.Answers.Name, ".") {
resp.Answers.Name = fmt.Sprintf("%s.", resp.Answers.Name)
}
msg := new(dns.Msg)
msg.SetQuestion(resp.Answers.Name, resp.Answers.Request)
// TODO: maybe not make this a gross chunk of if statements? who knows
// Make this authoritative (does this do anything?)
if c.Bool("aa") {
msg.Authoritative = true
}
// Set truncated flag (why)
if c.Bool("tc") {
msg.Truncated = true
}
// Set the zero flag if requested (does nothing)
if c.Bool("z") {
msg.Zero = true
}
// Disable DNSSEC validation
if c.Bool("cd") {
msg.CheckingDisabled = true
}
// Disable wanting recursion
if c.Bool("no-rd") {
msg.RecursionDesired = false
}
// Disable recursion being available (I don't think this does anything)
if c.Bool("no-ra") {
msg.RecursionAvailable = false
}
// Set DNSSEC if requested
if c.Bool("dnssec") {
msg.SetEdns0(1232, true)
}
var in *dns.Msg
// Make the DNS request
if isHTTPS {
in, resp.Answers.RTT, err = query.ResolveHTTPS(msg, resp.Answers.Server)
} else if c.Bool("quic") {
in, resp.Answers.RTT, err = query.ResolveQUIC(msg, resp.Answers.Server)
} else {
d := new(dns.Client)
// Set TCP/UDP, depending on flags
if c.Bool("tcp") || c.Bool("tls") {
d.Net = "tcp"
} else {
d.Net = "udp"
}
// Set IPv4 or IPv6, depending on flags
switch {
case c.Bool("4"):
d.Net += "4"
case c.Bool("6"):
d.Net += "6"
}
// Add TLS, if requested
if c.Bool("tls") {
d.Net += "-tls"
}
in, resp.Answers.RTT, err = d.Exchange(msg, resp.Answers.Server)
if err != nil {
return err
}
// If UDP truncates, use TCP instead (unless truncation is to be ignored)
if in.MsgHdr.Truncated && !c.Bool("no-truncate") {
fmt.Printf(";; Truncated, retrying with TCP\n\n")
d.Net = "tcp"
switch {
case c.Bool("4"):
d.Net += "4"
case c.Bool("6"):
d.Net += "6"
}
in, resp.Answers.RTT, err = d.Exchange(msg, resp.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:", resp.Answers.RTT)
fmt.Println(";; SERVER:", resp.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
}