awl/util/options.go
Sam Therapy b9abedfca2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
API work
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-09-13 03:04:45 +02:00

180 lines
4.4 KiB
Go

// SPDX-License-Identifier: BSD-3-Clause
package util
import (
"fmt"
"net"
"git.froth.zone/sam/awl/logawl"
"github.com/miekg/dns"
)
// Options is the grand structure for all query options.
type Options struct {
// The logger
Logger *logawl.Logger
// Host to verify TLS cert with
TLSHost string `json:"tlsHost"`
// EDNS Options
EDNS
// DNS request :)
Request Request
// Verbosity levels, see [logawl.AllLevels]
Verbosity int `json:"-"`
// Display options
Display Display
// Ignore Truncation
Truncate bool `json:"ignoreTruncate"`
// Print only the answer
Short bool `json:"short"`
// When Short is true, display where the query came from
Identify bool `json:"identify"`
// Perform a reverse DNS query when true
Reverse bool `json:"reverse"`
HeaderFlags
// Display resposne as JSON
JSON bool `json:"-" xml:"-" yaml:"-"`
// Display response as XML
XML bool `json:"-" xml:"-" yaml:"-"`
// Display response as YAML
YAML bool `json:"-" xml:"-" yaml:"-"`
// Use TCP instead of UDP to make the query
TCP bool `json:"tcp"`
// Use DNS-over-TLS to make the query
TLS bool `json:"dns_over_tls"`
// When using TLS, ignore certificates
TLSNoVerify bool `json:"tlsNoVerify"`
// Use DNS-over-HTTPS to make the query
HTTPS bool `json:"dns_over_https"`
// Use DNS-over-QUIC to make the query
QUIC bool `json:"dns_over_quic"`
// Use DNSCrypt to make the query
DNSCrypt bool `json:"dnscrpyt"`
// Force IPv4 only
IPv4 bool `json:"force_IPv4"`
// Force IPv6 only
IPv6 bool `json:"force_IPv6"`
}
// HeaderFlags are the flags that are in DNS headers.
type HeaderFlags struct {
// Authoritative Answer DNS query flag
AA bool `json:"authoritative,"`
// Authenticated Data DNS query flag
AD bool `json:"authenticatedData,"`
// Checking Disabled DNS query flag
CD bool `json:"checkingDisabled,"`
// QueRy DNS query flag
QR bool `json:"query"`
// Recursion Desired DNS query flag
RD bool `json:"recursionDesired"`
// Recursion Available DNS query flag
RA bool `json:"recursionAvailable"`
// TrunCated DNS query flag
TC bool `json:"truncated"`
// Zero DNS query flag
Z bool `json:"zero"`
}
// Display contains toggles for what to (and not to) display.
type Display struct {
/* Section displaying */
// Comments?
Comments bool `json:"comments"`
// QUESTION SECTION
Question bool `json:"question"`
// OPT PSEUDOSECTION
Opt bool `json:"opt"`
// ANSWER SECTION
Answer bool `json:"answer"`
// AUTHORITY SECTION
Authority bool `json:"authority"`
// ADDITIONAL SECTION
Additional bool `json:"additional"`
// Query time, message size, etc.
Statistics bool `json:"statistics"`
// Display TTL in response
TTL bool `json:"ttl"`
/* Answer formatting */
// Display Class in response
ShowClass bool `json:"showClass"`
// Display query before it is sent
ShowQuery bool `json:"showQuery"`
// Display TTL as human-readable
HumanTTL bool `json:"HumanTTL"`
// Translate Punycode back to Unicode
UcodeTranslate bool `json:"unicode"`
}
// EDNS contains toggles for various EDNS options.
type EDNS struct {
// Subnet to originate query from.
Subnet dns.EDNS0_SUBNET `json:"subnet"`
// Must Be Zero flag
ZFlag uint16 `json:"zflag"`
// UDP buffer size
BufSize uint16 `json:"bufSize"`
// Enable/Disable EDNS entirely
EnableEDNS bool `json:"edns"`
// Sending EDNS cookie
Cookie bool `json:"cookie"`
// Enabling DNSSEC
DNSSEC bool `json:"dnssec"`
// Sending EDNS Expire
Expire bool `json:"expire"`
// Sending EDNS TCP keepopen
KeepOpen bool `json:"keepOpen"`
// Sending EDNS NSID
Nsid bool `json:"nsid"`
// Send EDNS Padding
Padding bool `json:"padding"`
// Set EDNS version (default: 0)
Version uint8 `json:"version"`
}
// ParseSubnet takes a subnet argument and makes it into one that the DNS library
// understands.
func ParseSubnet(subnet string, opts *Options) error {
ip, inet, err := net.ParseCIDR(subnet)
if err != nil {
// TODO: make not a default?
if subnet == "0" {
opts.EDNS.Subnet = dns.EDNS0_SUBNET{
Code: dns.EDNS0SUBNET,
Family: 1,
SourceNetmask: 0,
SourceScope: 0,
Address: net.IPv4(0, 0, 0, 0),
}
return nil
}
return fmt.Errorf("EDNS subnet parsing: %w", err)
}
sub, _ := inet.Mask.Size()
opts.EDNS.Subnet = dns.EDNS0_SUBNET{}
opts.EDNS.Subnet.Address = ip
opts.EDNS.Subnet.SourceNetmask = uint8(sub)
switch ip.To4() {
case nil:
// Not a valid IPv4 so assume IPv6
opts.EDNS.Subnet.Family = 2
default:
// Valid IPv4
opts.EDNS.Subnet.Family = 1
}
return nil
}