aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--_doc/resolver.1.gzbin1460 -> 1941 bytes
-rw-r--r--_doc/resolver.adoc113
-rw-r--r--client.go60
-rw-r--r--cmd/resolver/main.go68
-rw-r--r--cmd/resolver/resolver.go73
5 files changed, 252 insertions, 62 deletions
diff --git a/_doc/resolver.1.gz b/_doc/resolver.1.gz
index d495fa6..ca2af09 100644
--- a/_doc/resolver.1.gz
+++ b/_doc/resolver.1.gz
Binary files differ
diff --git a/_doc/resolver.adoc b/_doc/resolver.adoc
index 0aa3a70..e71b406 100644
--- a/_doc/resolver.adoc
+++ b/_doc/resolver.adoc
@@ -9,45 +9,72 @@
== NAME
-resolver - a tool to query DNS record, specifically build for *rescached*(1)
-and developer.
+resolver - command line interface for DNS and rescached server.
== SYNOPSIS
-+resolver+ [-ns nameserver] [-t type] [-c class] hostname
+resolver [-insecure] [-ns nameserver] [-server] <command> [args...]
== DESCRIPTION
-+resolver+ is a tool to resolve hostname to address, or to query services
-on hostname by type (MX, SOA, TXT, etc.).
-It will return and print the DNS response.
+resolver is a tool to resolve hostname to IP address or to query services
+on hostname by type (MX, SOA, TXT, etc.) using standard DNS protocol with UDP,
+DNS over TLS (DoT), or DNS over HTTPS (DoH).
== OPTIONS
-[[nameserver]]
-=== +nameserver+
+`-insecure`::
++
+--
+Ignore invalid server certificate when querying DoT, DoH, or rescached server.
+--
+
+`-ns <nameserver>`::
++
+--
+This option define the parent DNS server where the resolver send the query.
+Default to one of "nameserver" in `/etc/resolv.conf`.
+
+The nameserver is defined in the following format,
+
+ ("udp"/"tcp"/"https") "://" (domain / ip-address) [":" port]
+
+Examples,
+
+* udp://194.233.68.184:53 for querying with UDP,
+* tcp://194.233.68.184:53 for querying with TCP,
+* https://194.233.68.184:853 for querying with DNS over TLS (DoT), and
+* https://kilabit.info/dns-query for querying with DNS over HTTPS (DoH).
+--
+
+`-server <rescached-URL>`::
++
+--
+Set the rescached HTTP server where commands will send.
+The rescached-URL use HTTP scheme:
-Value:: Internet address
-Format:: xxx.xxx.xxx.xxx[:port]
-Default:: One of +nameserver+ in +/etc/resolv.conf+
-Description:: This option define the DNS server where the resolver will
-send the query.
+ ("http" / "https") "://" (domain / ip-address) [":" port]
-[[type]]
-=== +type+
+Default to "https://127.0.0.1:5380" if its empty.
+--
-Value:: DNS record type
-Format:: String
-Default:: A
-Description:: List of supported DNS record type,
+== COMMANDS
+
+query <domain / ip-address> [type] [class]::
+
-----
-TYPE (ID) - Description
+--
+Query the domain or IP address with optional type and/or class.
+
+Unless the option "-ns" is given, the query command will use the
+nameserver defined in the system resolv.conf file.
+
+The "type" parameter define DNS record type to be queried.
+List of valid types,
-* A (1) - a host Address
+* A (1) - a host Address (default)
* NS (2) - an authoritative Name Server
* CNAME (5) - the Canonical NAME for an alias
* SOA (6) - marks the Start of a zone of Authority
@@ -63,15 +90,15 @@ TYPE (ID) - Description
* TXT (16) - TeXT strings
* AAAA (28) - a host address in IPv6
* SRV (33) - a SerViCe record
-----
-[[hostname]]
-=== +hostname+
+The "class" parameter is optional, its either IN (default), CS, or HS.
+--
-Value:: Internet hostname
-Format:: [subdomain].[domain][.TLD]
-Default:: -
-Description:: Hostname that will be queried to name server.
+caches::
++
+--
+Fetch and print all caches from rescached server.
+--
== EXIT STATUS
@@ -79,22 +106,34 @@ Description:: Hostname that will be queried to name server.
Upon exit and success +resolver+ will return 0, or 1 otherwise.
-== EXAMPLE
+== EXAMPLES
+
+Query the IPv4 address for kilabit.info,
-Resolve the IPv4 address for kilabit.info using one of nameserver in
-`/etc/resolv.conf`,
+ $ resolver query kilabit.info
- $ resolver kilabit.info
+Query the mail exchange (MX) for domain kilabit.info,
-Resolve the IPv4 address for kilabit.info using 127.0.0.1 at port 54 as
+ $ resolver query kilabit.info MX
+
+Query the IPv4 address for kilabit.info using 127.0.0.1 at port 53 as
name server,
- $ resolver -ns 127.0.0.1:54 kilabit.info
+ $ resolver -ns=udp://127.0.0.1:53 query kilabit.info
+
+Query the IPv4 address of domain name "kilabit.info" using DNS over TLS at
+name server 194.233.68.184,
+
+ $ resolver -insecure -ns=https://194.233.68.184 query kilabit.info
+
+Query the IPv4 records of domain name "kilabit.info" using DNS over HTTPS on
+name server kilabit.info,
-Resolve the mail exchange (MX) for kilabit.info,
+ $ resolver -ns=https://kilabit.info/dns-query query kilabit.info
- $ resolver -t MX kilabit.info
+Inspect the rescached's caches on server at http://127.0.0.1:5380
+ $ resolver -server=http://127.0.0.1:5380 caches
== AUTHOR
diff --git a/client.go b/client.go
new file mode 100644
index 0000000..0d626f1
--- /dev/null
+++ b/client.go
@@ -0,0 +1,60 @@
+// SPDX-FileCopyrightText: 2022 M. Shulhan <ms@kilabit.info>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package rescached
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/shuLhan/share/lib/dns"
+ libhttp "github.com/shuLhan/share/lib/http"
+)
+
+// Client for rescached.
+type Client struct {
+ *libhttp.Client
+}
+
+// NewClient create new HTTP client that connect to rescached HTTP server.
+func NewClient(serverUrl string, insecure bool) (cl *Client) {
+ var (
+ httpcOpts = libhttp.ClientOptions{
+ ServerUrl: serverUrl,
+ AllowInsecure: insecure,
+ }
+ )
+ cl = &Client{
+ Client: libhttp.NewClient(&httpcOpts),
+ }
+ return cl
+}
+
+// Caches fetch all of non-local caches from server.
+func (cl *Client) Caches() (answers []*dns.Answer, err error) {
+ var (
+ logp = "Caches"
+ res = libhttp.EndpointResponse{
+ Data: &answers,
+ }
+
+ resb []byte
+ )
+
+ _, resb, err = cl.Get(apiCaches, nil, nil)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", logp, err)
+ }
+
+ err = json.Unmarshal(resb, &res)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", logp, err)
+ }
+
+ if res.Code != http.StatusOK {
+ return nil, fmt.Errorf("%s: %s", logp, res.Code, res.Message)
+ }
+
+ return answers, nil
+}
diff --git a/cmd/resolver/main.go b/cmd/resolver/main.go
index 49ba6a6..98e448d 100644
--- a/cmd/resolver/main.go
+++ b/cmd/resolver/main.go
@@ -15,7 +15,8 @@ import (
// List of valid commands.
const (
- cmdQuery = "query"
+ cmdCaches = "caches"
+ cmdQuery = "query"
)
func main() {
@@ -28,8 +29,9 @@ func main() {
log.SetFlags(0)
+ flag.BoolVar(&rsol.insecure, "insecure", false, "Ignore invalid server certificate.")
flag.StringVar(&rsol.nameserver, "ns", "", "Parent name server address using scheme based.")
- flag.BoolVar(&rsol.insecure, "insecure", false, "Ignore invalid server certificate")
+ flag.StringVar(&rsol.rescachedUrl, "server", defRescachedUrl, "Set the rescached HTTP server.")
flag.BoolVar(&optHelp, "h", false, "")
flag.Parse()
@@ -49,6 +51,9 @@ func main() {
rsol.cmd = strings.ToLower(args[0])
switch rsol.cmd {
+ case cmdCaches:
+ rsol.doCmdCaches()
+
case cmdQuery:
args = args[1:]
if len(args) == 0 {
@@ -69,25 +74,36 @@ func help() {
== Usage
- resolver [-ns nameserver] [-insecure] <command> <args>
+ resolver [-insecure] [-ns nameserver] [-server] <command> [args...]
== Options
-Accepted command is query.
+The following options affect the commands operation.
+
+-insecure
+
+ Ignore invalid server certificate when querying DoT, DoH, or rescached
+ server.
-ns nameserver
Parent name server address using scheme based.
For example,
- udp://35.240.172.103:53 for querying with UDP,
- tcp://35.240.172.103:53 for querying with TCP,
- https://35.240.172:103:853 for querying with DNS over TLS (DoT), and
- https://kilabit.info/dns-query for querying with DNS over HTTPS (DoH).
--insecure
+ * udp://35.240.172.103:53 for querying with UDP,
+ * tcp://35.240.172.103:53 for querying with TCP,
+ * https://35.240.172:103:853 for querying with DNS over TLS (DoT), and
+ * https://kilabit.info/dns-query for querying with DNS over HTTPS
+ (DoH).
- Ignore invalid server certificate when querying DoT, DoH, or rescached
- server.
+-server <rescached-URL>
+
+ Set the location of rescached HTTP server where commands will send.
+ The rescached-URL use HTTP scheme:
+
+ ("http" / "https") "://" (domain / ip-address) [":" port]
+
+ Default to "https://127.0.0.1:5380" if its empty.
== Commands
@@ -105,19 +121,37 @@ query <domain / ip-address> [type] [class]
Valid class are either IN, CS, HS.
Default value is IN.
+caches
+
+ Fetch and print all caches from rescached server.
+
== Examples
-Query the MX records using UDP on name server 35.240.172.103,
+Query the IPv4 address for kilabit.info,
+
+ $ resolver query kilabit.info
- $ resolver -ns udp://35.240.172.103 query kilabit.info MX
+Query the mail exchange (MX) for domain kilabit.info,
-Query the IPv4 records of domain name "kilabit.info" using DNS over TLS on
-name server 35.240.172.103,
+ $ resolver query kilabit.info MX
- $ resolver -ns https://35.240.172.103 -insecure query kilabit.info
+Query the IPv4 address for kilabit.info using 127.0.0.1 at port 53 as
+name server,
+
+ $ resolver -ns=udp://127.0.0.1:53 query kilabit.info
+
+Query the IPv4 address of domain name "kilabit.info" using DNS over TLS at
+name server 194.233.68.184,
+
+ $ resolver -insecure -ns=https://194.233.68.184 query kilabit.info
Query the IPv4 records of domain name "kilabit.info" using DNS over HTTPS on
name server kilabit.info,
- $ resolver -ns https://kilabit.info/dns-query query kilabit.info`)
+ $ resolver -insecure -ns=https://kilabit.info/dns-query query kilabit.info
+
+Inspect the rescached's caches on server at http://127.0.0.1:5380
+
+ $ resolver -server=http://127.0.0.1:5380 caches
+`)
}
diff --git a/cmd/resolver/resolver.go b/cmd/resolver/resolver.go
index 19cebaf..c9f172e 100644
--- a/cmd/resolver/resolver.go
+++ b/cmd/resolver/resolver.go
@@ -10,16 +10,18 @@ import (
"strings"
"time"
+ "github.com/shuLhan/rescached-go/v4"
"github.com/shuLhan/share/lib/dns"
libnet "github.com/shuLhan/share/lib/net"
)
const (
- defAttempts = 1
- defQueryType = "A"
- defQueryClass = "IN"
- defResolvConf = "/etc/resolv.conf"
- defTimeout = 5 * time.Second
+ defAttempts = 1
+ defQueryType = "A"
+ defQueryClass = "IN"
+ defRescachedUrl = "http://127.0.0.1:5380"
+ defResolvConf = "/etc/resolv.conf"
+ defTimeout = 5 * time.Second
)
type resolver struct {
@@ -31,13 +33,68 @@ type resolver struct {
sqtype string
sqclass string
- nameserver string
- qtype dns.RecordType
- qclass dns.RecordClass
+ nameserver string
+ rescachedUrl string
+
+ qtype dns.RecordType
+ qclass dns.RecordClass
insecure bool
}
+func (rsol *resolver) doCmdCaches() {
+ var (
+ resc *rescached.Client
+ answer *dns.Answer
+ answers []*dns.Answer
+ format string
+ header string
+ line strings.Builder
+ err error
+ x int
+ maxNameLen int
+ )
+
+ if len(rsol.rescachedUrl) == 0 {
+ rsol.rescachedUrl = defRescachedUrl
+ }
+
+ resc = rescached.NewClient(rsol.rescachedUrl, rsol.insecure)
+
+ answers, err = resc.Caches()
+ if err != nil {
+ log.Printf("resolver: caches: %s", err)
+ return
+ }
+
+ fmt.Printf("Total caches: %d\n", len(answers))
+
+ for _, answer = range answers {
+ if len(answer.QName) > maxNameLen {
+ maxNameLen = len(answer.QName)
+ }
+ }
+
+ format = fmt.Sprintf("%%4s | %%%ds | %%4s | %%5s | %%30s | %%30s", maxNameLen)
+ header = fmt.Sprintf(format, "#", "Name", "Type", "Class", "Received at", "Accessed at")
+ for x = 0; x < len(header); x++ {
+ line.WriteString("-")
+ }
+ fmt.Println(line.String())
+ fmt.Println(header)
+ fmt.Println(line.String())
+
+ format = fmt.Sprintf("%%4d | %%%ds | %%4s | %%5s | %%30s | %%30s\n", maxNameLen)
+ for x, answer = range answers {
+ fmt.Printf(format, x, answer.QName,
+ dns.RecordTypeNames[answer.RType],
+ dns.RecordClassName[answer.RClass],
+ time.Unix(answer.ReceivedAt, 0),
+ time.Unix(answer.AccessedAt, 0),
+ )
+ }
+}
+
func (rsol *resolver) doCmdQuery(args []string) {
var (
maxAttempts = defAttempts