From 50d7b9dc2ae6556529ed10981e49b22d053c9d0d Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Tue, 21 Jun 2022 22:54:50 +0200 Subject: [PATCH] Rewrite in Go :^) Signed-off-by: Sam Therapy --- .drone.yml | 13 -- .gitignore | 154 ++--------------- .vscode/settings.json | 5 - LICENSE | 5 - README.md | 37 +++- args.ts | 53 ------ awl.go | 374 +++++++++++++++++++++++++++++++++++++++++ awl.ts | 121 ------------- deps.ts | 7 - docs.go | 9 + go.mod | 20 +++ go.sum | 54 ++++++ lib/query.ts | 65 ------- lib/response.ts | 117 ------------- lib/reverse.ts | 73 -------- lib/utils.ts | 93 ---------- mod.ts | 8 - tests/query_test.ts | 59 ------- tests/response_test.ts | 112 ------------ tests/reverse_test.ts | 43 ----- tests/testDeps.ts | 4 - 21 files changed, 508 insertions(+), 918 deletions(-) delete mode 100644 .drone.yml delete mode 100644 .vscode/settings.json delete mode 100644 LICENSE delete mode 100644 args.ts create mode 100644 awl.go delete mode 100644 awl.ts delete mode 100644 deps.ts create mode 100644 docs.go create mode 100644 go.mod create mode 100644 go.sum delete mode 100644 lib/query.ts delete mode 100644 lib/response.ts delete mode 100644 lib/reverse.ts delete mode 100644 lib/utils.ts delete mode 100644 mod.ts delete mode 100644 tests/query_test.ts delete mode 100644 tests/response_test.ts delete mode 100644 tests/reverse_test.ts delete mode 100644 tests/testDeps.ts diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index f28537ba..00000000 --- a/.drone.yml +++ /dev/null @@ -1,13 +0,0 @@ -kind: pipeline -type: docker -name: default -steps: - - name: lint - image: denoland/deno:debian - commands: - - deno fmt --check - - deno lint - - name: test - image: denoland/deno:debian - commands: - - deno test -A \ No newline at end of file diff --git a/.gitignore b/.gitignore index c640434f..682e852c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,136 +1,18 @@ -# ---> Node -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -.dccache - -result.json -*.vtt \ No newline at end of file +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e40716fd..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "deno.enable": true, - "deno.lint": true, - "deno.unstable": true -} diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 5ed684cf..00000000 --- a/LICENSE +++ /dev/null @@ -1,5 +0,0 @@ -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 3a0bf84c..74328433 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,33 @@ -# awl: drill, writ small (and using deno) - -Install: -`deno install --allow-net https://git.froth.zone/sam/awl/raw/branch/master/awl.ts` +# awl + +`awl` is a command-line DNS client, much like +[`drill`](https://github.com/NLnetLabs/ldns), +[`dig`](https://bind9.readthedocs.io/en/v9_18_3/manpages.html#dig-dns-lookup-utility), +[`dog`](https://github.com/ogham/dog), +[`doggo`](https://github.com/mr-karan/doggo), +or [`q`](https://github.com/natesales/q) + +The excellent [dns](https://github.com/miekg/dns) library for Go does most of the heavy +lifting. + +## What works + +- UDP +- TCP +- TLS +- HTTPS (maybe) + +## What doesn't + +- DNS-over-QUIC (eventually) +- Your sanity after reading my awful code +- A motivation for making this after finding q and doggo + +## What should change + +- Make the CLI less abysmal (migrate to [cobra](https://github.com/spf13/cobra)? + or just use stdlib's flags) +- Optimize everything +- Make the code less spaghetti + - Like not just having one massive unreadable file, this is AWFUL +- Documentation, documentation, documentation \ No newline at end of file diff --git a/args.ts b/args.ts deleted file mode 100644 index 77c0cbf0..00000000 --- a/args.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Args } from "./deps.ts"; -import { isRecordType, ServerOptions } from "./lib/utils.ts"; -/** - * A handler for parsing the arguments passed in - * @param {ServerOptions} server - The DNS server to query - * @param {Deno.RecordType} type - The type of DNS request, see Deno.RecordType for more info - * @param {string} name - Server to look up - */ -export type arguments = { - server?: ServerOptions; - type?: Deno.RecordType; - name?: string; -}; - -/** - * @param {Args} args - The arguments, directly passed in - * @returns {arguments} The arguments, parsed - */ -export function parseArgs(args: Args): arguments { - const parsed: arguments = {} as arguments; - args._.forEach((arg) => { - arg = arg.toString(); - - // if it starts with an @, it's a server - if (arg.includes("@")) { - parsed.server = { - server: arg.split("@").pop() as string, - port: args.port, - }; - return; - } - // if there is a dot, it's a name - if (arg.includes(".")) { - parsed.name = arg; - return; - } - - if (isRecordType(arg)) { - parsed.type = arg.toUpperCase() as Deno.RecordType; - return; - } - - // if all else fails, assume it's a name - parsed.name = arg; - }); - - // Add a . to the end of the name if it's not there - if (parsed.name?.charAt(parsed.name.length - 1) !== ".") { - parsed.name = parsed.name?.concat("."); - } - - return parsed; -} diff --git a/awl.go b/awl.go new file mode 100644 index 00000000..18bd4c08 --- /dev/null +++ b/awl.go @@ -0,0 +1,374 @@ +package main + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "net" + "net/http" + "os" + "runtime" + "strconv" + "strings" + "time" + + "github.com/c-robinson/iplib" + "github.com/miekg/dns" + "github.com/urfave/cli/v2" + "golang.org/x/net/idna" +) + +// The basic structure of a DNS request +type request struct { + server string // The server to make the DNS request from + request uint16 // The type of request + name string // The domain name to make a DNS request for +} + +func main() { + // Custom version string + cli.VersionPrinter = func(c *cli.Context) { + fmt.Printf("%s version %s, built with %s\n", c.App.Name, c.App.Version, runtime.Version()) + } + + cli.VersionFlag = &cli.BoolFlag{ + Name: "v", + Usage: "show version", + } + + cli.HelpFlag = &cli.BoolFlag{ + Name: "h", + Usage: "show this help", + } + + // Hack to get rid of the annoying default on the CLI + oldFlagStringer := cli.FlagStringer + cli.FlagStringer = func(f cli.Flag) string { + return strings.TrimSuffix(oldFlagStringer(f), " (default: false)") + } + + cli.AppHelpTemplate = `{{.Name}} - {{.Usage}} + + Usage: {{.HelpName}} name [@server] [type] + can be a name or an IP address + defaults to A + + arguments can be in any order + {{if .VisibleFlags}} + Options: + {{range .VisibleFlags}}{{.}} + {{end}}{{end}}` + app := &cli.App{ + Name: "awl", + Usage: "drill, writ small", + Version: "v0.2.0", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "port", + Aliases: []string{"p"}, + Usage: "port to make DNS query", + DefaultText: "53 over plain TCP/UDP, 853 over TLS or QUIC, and 443 over HTTPS", + }, + &cli.BoolFlag{ + Name: "4", + Usage: "force IPv4", + }, + &cli.BoolFlag{ + Name: "6", + Usage: "force IPv6", + }, + &cli.BoolFlag{ + Name: "dnssec", + Aliases: []string{"D"}, + Usage: "enable DNSSEC", + }, + &cli.BoolFlag{ + Name: "json", + Aliases: []string{"j"}, + Usage: "return the result(s) as JSON", + }, + &cli.BoolFlag{ + Name: "short", + Aliases: []string{"s"}, + Usage: "print just the results, equivalent to dig +short", + }, + &cli.BoolFlag{ + Name: "tcp", + Aliases: []string{"t"}, + Usage: "use TCP (default: use UDP)", + }, + &cli.BoolFlag{ + Name: "tls", + Aliases: []string{"T"}, + Usage: "use DNS-over-TLS", + }, + &cli.BoolFlag{ + Name: "https", + Aliases: []string{"H"}, + Usage: "use DNS-over-HTTPS (NOT FULLY COMPLETE)", + }, + &cli.BoolFlag{ + Name: "quic", + Aliases: []string{"Q"}, + Usage: "use DNS-over-QUIC (NOT YET IMPLEMENTED)", + }, + &cli.BoolFlag{ + Name: "no-truncate", + Usage: "Ignore truncation if a UDP request truncates (default: retry with TCP)", + }, + &cli.BoolFlag{ + Name: "reverse", + Aliases: []string{"x"}, + Usage: "do a reverse lookup", + }, + }, + Action: func(c *cli.Context) error { + var err error + + req := parseArgs(c.Args().Slice()) + // Set DNS-over-TLS, if enabled + 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") { + req.server = net.JoinHostPort(req.server, strconv.Itoa(port)) + } else { + req.server = "https://" + req.server + } + + // Process the IP/Phone number so a PTR/NAPTR can be done + if c.Bool("reverse") { + if dns.TypeToString[req.request] == "A" { + req.request = dns.StringToType["PTR"] + } + req.name, err = reverseDNS(req.name, dns.TypeToString[req.request]) + if err != nil { + return err + } + } + + // if the domain is not canonical, make it canonical + if !strings.HasSuffix(req.name, ".") { + req.name = fmt.Sprintf("%s.", req.name) + } + + msg := new(dns.Msg) + msg.SetQuestion(req.name, req.request) + + // Set DNSSEC if requested + if c.Bool("dnssec") { + msg.SetEdns0(1232, true) + } + + var ( + in *dns.Msg + rtt time.Duration + ) + + // Make the DNS request + if c.Bool("https") { + in, err = resolveHTTPS(msg, req.server) + } else if c.Bool("quic") { + return fmt.Errorf("quic: not yet implemented") + } else { + + d := new(dns.Client) + + // Set TCP/UDP, depending on flags + if c.Bool("tcp") { + d.Net = "tcp" + if c.Bool("4") { + d.Net = "tcp4" + } + if c.Bool("6") { + d.Net = "tcp6" + } + } else { + d.Net = "udp" + if c.Bool("4") { + d.Net = "udp4" + } + if c.Bool("6") { + d.Net = "udp6" + } + } + + // This is apparently all it takes to enable DoT + // TODO: Is it really? + if c.Bool("tls") { + d.Net = "tcp-tls" + } + in, rtt, err = d.Exchange(msg, req.server) + + // If UDP truncates, use TCP instead + if !c.Bool("no-truncate") { + if in.MsgHdr.Truncated { + fmt.Printf(";; Truncated, retrying with TCP\n\n") + d.Net = "tcp" + if c.Bool("4") { + d.Net = "tcp4" + } + if c.Bool("6") { + d.Net = "tcp6" + } + in, rtt, err = d.Exchange(msg, req.server) + } + } + } + + if err != nil { + return err + } + + if c.Bool("json") { + json, _ := json.Marshal(in) + fmt.Println(string(json)) + } else { + if !c.Bool("short") { + // Print everything + fmt.Println(in) + fmt.Println(";; Query time:", rtt) + fmt.Println(";; SERVER:", req.server) + fmt.Println(";; WHEN:", time.Now().Format(time.RFC1123)) + 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 + }, + } + + err := app.Run(os.Args) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func parseArgs(args []string) request { + var ( + server string + req uint16 + name string + ) + for _, arg := range args { + // If it starts with @, it's a DNS server + if strings.HasPrefix(arg, "@") { + server = strings.Split(arg, "@")[1] + continue + } + // If there's a dot, it's a name + if strings.Contains(arg, ".") { + name, _ = idna.ToUnicode(arg) + continue + } + // If it's a request, it's a request (duh) + if r, ok := dns.StringToType[strings.ToUpper(arg)]; ok { + req = r + continue + } + + //else, assume it's a name + name, _ = idna.ToUnicode(arg) + } + + // If nothing was set, set a default + if name == "" { + name = "." + if req == 0 { + req = dns.StringToType["NS"] + } + } else { + if req == 0 { + req = dns.StringToType["A"] + } + } + if server == "" { + resolv, err := dns.ClientConfigFromFile("/etc/resolv.conf") + if err != nil { // Query Google by default, needed for Windows since the DNS library doesn't support Windows + // TODO: Actually find where windows stuffs its dns resolvers + server = "8.8.4.4" + } else { + server = resolv.Servers[0] + } + } + + return request{server: server, request: req, name: name} +} + +func reverseDNS(dom string, q string) (string, error) { + if q == "PTR" { + if strings.Contains(dom, ".") { + // It's an IPv4 address + ip := net.ParseIP(dom) + if ip != nil { + return iplib.IP4ToARPA(ip), nil + } else { + return "", errors.New("error: Could not parse IPv4 address") + } + + } else if strings.Contains(dom, ":") { + // It's an IPv6 address + ip := net.ParseIP(dom) + if ip != nil { + return iplib.IP6ToARPA(ip), nil + } else { + return "", errors.New("error: Could not parse IPv6 address") + } + } + } + return "", errors.New("error: -x flag given but no IP found") +} + +func resolveHTTPS(msg *dns.Msg, server string) (*dns.Msg, error) { + httpR := &http.Client{} + buf, err := msg.Pack() + if err != nil { + return nil, err + } + query := server + "?dns=" + base64.RawURLEncoding.EncodeToString(buf) + req, err := http.NewRequest("GET", query, nil) + if err != nil { + return nil, err + } + req.Header.Set("Accept", "application/dns-message") + + res, err := httpR.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return nil, fmt.Errorf("bad HTTP Request: %d", res.StatusCode) + } + + fullRes, err := io.ReadAll(res.Body) + if err != nil { + return nil, err + } + response := dns.Msg{} + err = response.Unpack(fullRes) + if err != nil { + return nil, err + } + + return &response, nil + +} diff --git a/awl.ts b/awl.ts deleted file mode 100644 index 9f92ee5a..00000000 --- a/awl.ts +++ /dev/null @@ -1,121 +0,0 @@ -// SPDX-License-Identifier: MIT -import { bold, italic, parse, underline } from "./deps.ts"; -import { QueryResponse, ServerOptions } from "./lib/utils.ts"; -import { doQuery } from "./lib/query.ts"; -import { parseResponse } from "./lib/response.ts"; -import { parseArgs } from "./args.ts"; -import { parseNAPTR, parsePTR } from "./lib/reverse.ts"; - -async function main() { - // Parse args - const args = parse(Deno.args, { - alias: { - h: "help", - p: "port", - s: "short", - x: "ptr", - V: "version", - }, - boolean: ["help", "ptr", "short", "version"], - string: ["port"], - default: { - "port": "53", - }, - }); - if (args.help) args.version = true; - - if (args.version) { - console.log( - `${ - bold("awl") - } version 0.1.0 (running with deno ${Deno.version.deno}, TypeScript ${Deno.version.typescript}, on V8 ${Deno.version.v8}) -Written by (YOUR NAME GOES HERE)`, - ); - } - - if (args.help) { - console.log( - ` ${bold("Usage:")} awl name ${italic("type")} ${italic("@server")} - ${bold("")} domain name - ${bold("")} defaults to A - ${bold("<@server>")} defaults to your local resolver - - Order ${bold("DOES NOT")} matter\n - `, - `${underline("Options")}: - -p use for query, defaults to 53 - -s Equivalent to dig +short, only return addresses - -x do a reverse lookup - -h print this helpful guide - -V get the version - `, - ); - } - - if (args.version) Deno.exit(0); - - const parsedArgs = parseArgs(args); - - let domain = parsedArgs.name || "."; - - let query = parsedArgs.type || "A"; - if (domain === ".") query = "NS"; - - if (query === "PTR") { - // The "server" is an IP address, it needs to become a canonical domain - domain = parsePTR(domain); - } else if (query === "NAPTR") { - // The "server" is a phone number, it needs to become a canonical domain - domain = parseNAPTR(domain); - } - - const server = parsedArgs.server || { server: "", port: 53 }; - - const response: QueryResponse = await doQuery(domain, query, server); - - if (!args.short) { - console.log( - `;; ->>HEADER<<- opcode: QUERY, rcode: ${response.response} -;; QUESTION SECTION: -;; ${domain} IN ${query} - -;; ANSWER SECTION:`, - ); - } - if (response.response === "NOERROR") { - const res = parseResponse(response, domain, query, args.short); - res.forEach((answer) => { - console.log(answer); - }); - } - if (!args.short) { - console.log(` -;; ADDITONAL SECTION: - -;; Query time: ${response.time} msec -;; SERVER: ${displayServer(server)} -;; WHEN: ${new Date().toLocaleString()} - `); - } -} - -/** - * A handler for displaying the server - * @param {ServerOptions} server - The DNS server used - * @returns {string} The string used - */ -function displayServer(server: ServerOptions): string { - let val = ""; - if (server.server) { - val += server.server; - } - if (server.port != 53) { - val += `#${server.port}`; - } - if (!val) val = "System"; - return val; -} - -if (import.meta.main) { - await main(); -} diff --git a/deps.ts b/deps.ts deleted file mode 100644 index 0d7ef6cc..00000000 --- a/deps.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { parse } from "https://deno.land/std@0.144.0/flags/mod.ts"; -export type { Args } from "https://deno.land/std@0.144.0/flags/mod.ts"; -export { - bold, - italic, - underline, -} from "https://deno.land/std@0.139.0/fmt/colors.ts"; diff --git a/docs.go b/docs.go new file mode 100644 index 00000000..edf903bc --- /dev/null +++ b/docs.go @@ -0,0 +1,9 @@ +/* +awl is a DNS lookup tool written in Go, +similar to (and heavily inspired by) drill. + +It runs and displays similar outputs to drill, at the current time. + +Why use this over the alternatives? Good question. +*/ +package main diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..067e6a43 --- /dev/null +++ b/go.mod @@ -0,0 +1,20 @@ +module example.com/awl + +go 1.18 + +require ( + github.com/c-robinson/iplib v1.0.3 + github.com/miekg/dns v1.1.50 + github.com/urfave/cli/v2 v2.10.2 + golang.org/x/net v0.0.0-20220621193019-9d032be2e588 +) + +require ( + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.11 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..22a39b12 --- /dev/null +++ b/go.sum @@ -0,0 +1,54 @@ +github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU= +github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8= +github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y= +github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220621193019-9d032be2e588 h1:9ubFuySsnAJYGyJrZ3koiEv8FyqofCBdz3G9Mbf2YFc= +golang.org/x/net v0.0.0-20220621193019-9d032be2e588/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY= +golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/lib/query.ts b/lib/query.ts deleted file mode 100644 index ef726620..00000000 --- a/lib/query.ts +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT -import { QueryResponse, ServerOptions } from "./utils.ts"; - -/** - * @param domain Domain to query - * @param query - * @param server {@link utils.ts/ServerOptions} - * @returns - */ -export async function doQuery( - domain: string, - query: Deno.RecordType, - server?: ServerOptions, -) { - const response: QueryResponse = {} as QueryResponse; - if (!server?.server) { - const t0 = performance.now(); - await Deno.resolveDns(domain, query) - // If there's no error - .then((value) => { - const t1 = performance.now(); - response.time = t1 - t0; - response.response = "NOERROR"; - response.dnsResponse = value; - }) - // If there is an error - .catch((e: Error) => { - const t1 = performance.now(); - response.time = t1 - t0; - switch (e.name) { - case "NotFound": - response.response = "NXDOMAIN"; - break; - default: - console.dir(e); - response.response = "SERVFAIL"; - } - }); - } else { - const t0 = performance.now(); - await Deno.resolveDns(domain, query, { - nameServer: { "ipAddr": server.server, "port": server.port }, - }) - // If there's no error - .then((value) => { - const t1 = performance.now(); - response.time = t1 - t0; - response.response = "NOERROR"; - response.dnsResponse = value; - }) - // If there is an error - .catch((e: Error) => { - const t1 = performance.now(); - response.time = t1 - t0; - switch (e.name) { - case "NotFound": - response.response = "NXDOMAIN"; - break; - default: - response.response = "SERVFAIL"; - } - }); - } - return response; -} diff --git a/lib/response.ts b/lib/response.ts deleted file mode 100644 index 3ceb3ae9..00000000 --- a/lib/response.ts +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-License-Identifier: MIT -import { - isCAA, - isMX, - isNAPTR, - isSOA, - isSRV, - isTXT, - QueryResponse, -} from "./utils.ts"; - -/** - * @param res A DNS {@link QueryResponse} - * @param domain The domain (or IP, if doing it in reverse) queried - * @param query The DNS query that was queried - * @returns {string} The DNS response, put in canonical form - */ -export function parseResponse( - res: QueryResponse, - domain: string, - query: string, - short: boolean, -): string[] { - const answer: string[] = []; - switch (query) { - case "A": - case "AAAA": - case "CNAME": - case "NS": - case "PTR": - res.dnsResponse.forEach((ip) => { - let dnsQuery = ""; - if (!short) dnsQuery += `${domain} IN ${query} `; - dnsQuery += `${ip}`; - answer.push(dnsQuery); - }); - break; - case "MX": - if (isMX(res.dnsResponse)) { - res.dnsResponse.forEach((record) => { - let dnsQuery = ""; - if (!short) { - dnsQuery += `${domain} IN ${query} `; - } - dnsQuery += `${record.preference} ${record.exchange}`; - answer.push(dnsQuery); - }); - } - break; - case "CAA": - if (isCAA(res.dnsResponse)) { - res.dnsResponse.forEach((record) => { - let dnsQuery = ""; - if (!short) { - dnsQuery += `${domain} IN ${query} `; - } - dnsQuery += `${ - record.critical ? "1" : "0" - } ${record.tag} "${record.value}"`; - answer.push(dnsQuery); - }); - } - break; - case "NAPTR": - if (isNAPTR(res.dnsResponse)) { - res.dnsResponse.forEach((record) => { - let dnsQuery = ""; - if (!short) dnsQuery += `${domain} IN ${query} `; - dnsQuery += - `${record.order} ${record.preference} "${record.flags}" "${record.services}" ${record.regexp} ${record.replacement}`; - answer.push(dnsQuery); - }); - } - break; - case "SOA": - if (isSOA(res.dnsResponse)) { - res.dnsResponse.forEach((record) => { - let dnsQuery = ""; - if (!short) dnsQuery += `${domain} IN ${query} `; - dnsQuery += - `${record.mname} ${record.rname} ${record.serial} ${record.refresh} ${record.retry} ${record.expire} ${record.minimum}`; - answer.push(dnsQuery); - }); - } - break; - case "SRV": - if (isSRV(res.dnsResponse)) { - res.dnsResponse.forEach((record) => { - let dnsQuery = ""; - if (!short) dnsQuery += `${domain} IN ${query} `; - dnsQuery += - `${record.priority} ${record.weight} ${record.port} ${record.target}`; - answer.push(dnsQuery); - }); - } - break; - case "TXT": - if (isTXT(res.dnsResponse)) { - res.dnsResponse.forEach((record) => { - let dnsQuery = ""; - let txt = ""; - record.forEach((value) => { - txt += `"${value}"`; - }); - if (!short) { - dnsQuery += `${domain} IN ${query} `; - } - dnsQuery += `${txt}`; - answer.push(dnsQuery); - }); - } - break; - default: - throw new Error("Not yet implemented"); - } - return answer; -} diff --git a/lib/reverse.ts b/lib/reverse.ts deleted file mode 100644 index 3170f640..00000000 --- a/lib/reverse.ts +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: MIT - -export function parsePTR(ip: string) { - if (ip.includes(".")) { - // It's an IPv4 address - const ptr = ip.split("."); - let pop: string | undefined = "not undefined"; - let domain = ""; - do { - pop = ptr.pop(); - if (pop) { - domain += `${pop}.`; - } - } while (pop !== undefined); - domain += "in-addr.arpa"; - return domain; - } else if (ip.includes(":")) { - const parsedIP = parseIPv6(ip); - const ptr = parsedIP.split(":"); - // It's an IPv6 address - let pop: string[] | undefined = ["e"]; - let domain = ""; - do { - pop = ptr.pop()?.split("").reverse(); - if (pop) { - for (const part of pop) { - domain += `${part}.`; - } - } - } while (pop !== undefined); - domain += "ip6.arpa"; - return domain; - } else { - // It's not an address - return ""; - } -} - -export function parseIPv6(addr: string) { - addr = addr.replace(/^:|:$/g, ""); - - const ipv6 = addr.split(":"); - - for (let i = 0; i < ipv6.length; i++) { - let hex: string | string[] = ipv6[i]; - if (hex != "") { - // normalize leading zeros - // TODO: make this not deprecated - ipv6[i] = ("0000" + hex).substr(-4); - } else { - // normalize grouped zeros :: - hex = []; - for (let j = ipv6.length; j <= 8; j++) { - hex.push("0000"); - } - ipv6[i] = hex.join(":"); - } - } - - return ipv6.join(":"); -} - -export function parseNAPTR(phNum: string) { - phNum = phNum.toString(); - phNum = phNum.replace("+", "").replaceAll(" ", "").replaceAll("-", ""); - const rev = phNum.split("").reverse(); - let ptr = ""; - rev.forEach((n) => { - ptr += `${n}.`; - }); - ptr += "e164.arpa"; - return ptr; -} diff --git a/lib/utils.ts b/lib/utils.ts deleted file mode 100644 index 68ece482..00000000 --- a/lib/utils.ts +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: MIT - -/** - * A DNS response - */ -export type QueryResponse = { - dnsResponse: - | string[] - | Deno.CAARecord[] - | Deno.MXRecord[] - | Deno.NAPTRRecord[] - | Deno.SOARecord[] - | Deno.SRVRecord[] - | string[][]; - response: string; - time: number; -}; -/** - * Options for which DNS server to query - */ -export type ServerOptions = { - server: string; - port?: number; -}; - -export function isRecordType(type: string): type is Deno.RecordType { - return type.toUpperCase() === "A" || type.toUpperCase() === "AAAA" || - type.toUpperCase() === "CNAME" || type.toUpperCase() === "MX" || - type.toUpperCase() === "NS" || type.toUpperCase() === "PTR" || - type.toUpperCase() === "SOA" || type.toUpperCase() === "TXT" || - type.toUpperCase() === "NAPTR" || type.toUpperCase() === "SRV" || - type.toUpperCase() === "CAA"; -} - -/** - * Test if the DNS query is an MX record - * @param {QueryResponse["dnsResponse"]} record - DNS response - * @returns {boolean} - true if the record is an MX record - */ -export function isMX( - record: QueryResponse["dnsResponse"], -): record is Deno.MXRecord[] { - return (record as unknown as Deno.MXRecord[])[0].exchange !== undefined; -} -/** - * Test if the DNS query is a CAA record - * @param {QueryResponse["dnsResponse"]} record - DNS response - * @returns {boolean} - true if the record is a CAA record - */ -export function isCAA( - record: QueryResponse["dnsResponse"], -): record is Deno.CAARecord[] { - return (record as unknown as Deno.CAARecord[])[0].critical !== undefined; -} - -/** - * Test if the DNS query is an NAPTR record - * @param {QueryResponse["dnsResponse"]} record - DNS response - * @returns {boolean} - true if the record is an NAPTR record - */ -export function isNAPTR( - record: QueryResponse["dnsResponse"], -): record is Deno.NAPTRRecord[] { - return (record as unknown as Deno.NAPTRRecord[])[0].regexp !== undefined; -} - -/** - * Test if the DNS query is an SOA record - * @param {QueryResponse["dnsResponse"]} record - DNS response - * @returns {boolean} - true if the record is an SOA record - */ -export function isSOA( - record: QueryResponse["dnsResponse"], -): record is Deno.SOARecord[] { - return (record as unknown as Deno.SOARecord[])[0].rname !== undefined; -} - -/** - * Test if the DNS query is an SRV record - * @param {QueryResponse["dnsResponse"]} record - DNS response - * @returns {boolean} - true if the record is an SRV record - */ -export function isSRV( - record: QueryResponse["dnsResponse"], -): record is Deno.SRVRecord[] { - return (record as unknown as Deno.SRVRecord[])[0].port !== undefined; -} - -export function isTXT( - record: QueryResponse["dnsResponse"], -): record is string[][] { - return Array.isArray(record as unknown as Array); -} diff --git a/mod.ts b/mod.ts deleted file mode 100644 index a4e9c121..00000000 --- a/mod.ts +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT - -// Exports for lawl, the library for awl -export type { QueryResponse, ServerOptions } from "./lib/utils.ts"; -export { isRecordType } from "./lib/utils.ts"; -export { doQuery } from "./lib/query.ts"; -export { parseResponse } from "./lib/response.ts"; -export { parseIPv6, parseNAPTR, parsePTR } from "./lib/reverse.ts"; diff --git a/tests/query_test.ts b/tests/query_test.ts deleted file mode 100644 index 35690c35..00000000 --- a/tests/query_test.ts +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: MIT -import { assertEquals } from "./testDeps.ts"; -import { doQuery } from "../lib/query.ts"; - -Deno.test("Get localhost", async () => { - const res = await doQuery("localhost", "A"); - assertEquals(res.dnsResponse, ["127.0.0.1"]); - assertEquals(res.response, "NOERROR"); -}); - -Deno.test("Get localhost, external NS", async () => { - const res = await doQuery("localhost", "AAAA", { server: "1.1.1.1" }); - assertEquals(res.dnsResponse, ["::1"]); - assertEquals(res.response, "NOERROR"); -}); - -Deno.test("PTR localhost", async () => { - const res = await doQuery("1.0.0.127.in-addr.arpa.", "PTR"); - assertEquals(res.dnsResponse, ["localhost."]); -}); - -// This test will fail if this random Bri ish phone number goes down -// It's also unreliable, so it's disabled -// Deno.test("NAPTR, Remote",async () => { -// const res = await doQuery("4.4.2.2.3.3.5.6.8.1.4.4.e164.arpa.", "NAPTR"); -// assertStrictEquals(res.dnsResponse, [ -// { -// order: 100, -// preference: 10, -// flags: "u", -// services: "E2U+sip", -// regexp: "!^\\+441865332(.*)$!sip:\\1@nominet.org.uk!", -// replacement: "." -// }, -// { -// order: 100, -// preference: 20, -// flags: "u", -// services: "E2U+pstn:tel", -// regexp: "!^(.*)$!tel:\\1!", -// replacement: "." -// } -// ]) -// }) - -Deno.test("Get invalid IP, regular NS", async () => { - const res = await doQuery("l", "A"); - assertEquals(res.dnsResponse, undefined); - assertEquals(res.response, "NXDOMAIN"); -}); - -// This isn't supposed to SERVFAIL -// It also takes forever - -Deno.test("Get invalid IP, external NS", async () => { - const res = await doQuery("b", "AAAA", { server: "1.1.1.1" }); - assertEquals(res.dnsResponse, undefined); - assertEquals(res.response, "SERVFAIL"); -}); diff --git a/tests/response_test.ts b/tests/response_test.ts deleted file mode 100644 index 0313329c..00000000 --- a/tests/response_test.ts +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-License-Identifier: MIT -import { assertEquals, assertThrows } from "./testDeps.ts"; -import { parseResponse } from "../lib/response.ts"; -import { QueryResponse } from "../lib/utils.ts"; - -const mockResponse: QueryResponse = { - dnsResponse: [], - response: "NOERROR", - time: 0, -}; -let domain = "localhost."; - -Deno.test("A query", () => { - mockResponse.dnsResponse = ["127.0.0.1"]; - assertEquals(parseResponse(mockResponse, domain, "A", false), [ - "localhost. IN A 127.0.0.1", - ]); -}); - -Deno.test("AAAA query, short", () => { - mockResponse.dnsResponse = ["::1"]; - assertEquals(parseResponse(mockResponse, domain, "AAAA", true), [ - "::1", - ]); -}); - -Deno.test("MX query", () => { - mockResponse.dnsResponse = [{ - exchange: "mail.localhost", - preference: 10, - }]; - assertEquals(parseResponse(mockResponse, domain, "MX", false), [ - "localhost. IN MX 10 mail.localhost", - ]); -}); - -Deno.test("CAA query", () => { - mockResponse.dnsResponse = [{ - critical: false, - tag: "issue", - value: "pki.goog", - }]; - assertEquals(parseResponse(mockResponse, domain, "CAA", false), [ - 'localhost. IN CAA 0 issue "pki.goog"', - ]); -}); - -Deno.test("NAPTR query", () => { - domain = "4.3.2.1.5.5.5.0.0.8.1.e164.arpa."; - mockResponse.dnsResponse = [{ - flags: "u", - order: 100, - preference: 10, - services: "E2U+sip", - regexp: "!^.*$!sip:customer-service@example.com!", - replacement: ".", - }, { - flags: "u", - order: 102, - preference: 10, - services: "E2U+email", - regexp: "!^.*$!mailto:information@example.com!", - replacement: ".", - }]; - assertEquals(parseResponse(mockResponse, domain, "NAPTR", false), [ - `4.3.2.1.5.5.5.0.0.8.1.e164.arpa. IN NAPTR 100 10 "u" "E2U+sip" !^.*$!sip:customer-service@example.com! .`, - `4.3.2.1.5.5.5.0.0.8.1.e164.arpa. IN NAPTR 102 10 "u" "E2U+email" !^.*$!mailto:information@example.com! .`, - ]); -}); - -Deno.test("SOA query", () => { - domain = "cloudflare.com."; - mockResponse.dnsResponse = [{ - mname: "ns3.cloudflare.com.", - rname: "dns.cloudflare.com.", - serial: 2280958559, - refresh: 10000, - retry: 2400, - expire: 604800, - minimum: 300, - }]; - assertEquals(parseResponse(mockResponse, domain, "SOA", false), [ - "cloudflare.com. IN SOA ns3.cloudflare.com. dns.cloudflare.com. 2280958559 10000 2400 604800 300", - ]); -}); - -Deno.test("SRV query", () => { - domain = "localhost"; - mockResponse.dnsResponse = [{ - port: 22, - priority: 0, - target: "localhost", - weight: 10, - }]; - assertEquals(parseResponse(mockResponse, domain, "SRV", false), [ - "localhost IN SRV 0 10 22 localhost", - ]); -}); - -Deno.test("TXT query", () => { - mockResponse.dnsResponse = [["a"]]; - assertEquals(parseResponse(mockResponse, domain, "TXT", false), [ - 'localhost IN TXT "a"', - ]); -}); - -Deno.test("Invalid query", () => { - mockResponse.dnsResponse = [["a"]]; - assertThrows((): void => { - parseResponse(mockResponse, domain, "E", true); - }); -}); diff --git a/tests/reverse_test.ts b/tests/reverse_test.ts deleted file mode 100644 index b5569724..00000000 --- a/tests/reverse_test.ts +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT -import { parseIPv6, parseNAPTR, parsePTR } from "../lib/reverse.ts"; -import { assertEquals } from "./testDeps.ts"; - -Deno.test("IPv6 Parse, localhost", () => { - assertEquals(parseIPv6("::1"), "0000:0000:0000:0000:0000:0000:0000:0001"); -}); - -Deno.test("IPv6 Parse, :: in middle of address", () => { - assertEquals( - parseIPv6("2001:4860:4860::8844"), - "2001:4860:4860:0000:0000:0000:0000:8844", - ); -}); - -Deno.test("IPv4 PTR, localhost", () => { - assertEquals(parsePTR("127.0.0.1"), "1.0.0.127.in-addr.arpa"); -}); - -Deno.test("IPv6 PTR, actual IP", () => { - assertEquals( - parsePTR("2606:4700:4700::1111"), - "1.1.1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.4.0.0.7.4.6.0.6.2.ip6.arpa", - ); -}); - -Deno.test("PTR, Fallback lel", () => { - assertEquals(parsePTR("1367218g3a1"), ""); -}); - -Deno.test("NAPTR, US number", () => { - assertEquals( - parseNAPTR("+1-800-555-1234"), - "4.3.2.1.5.5.5.0.0.8.1.e164.arpa", - ); -}); - -Deno.test("NAPTR, non-US number", () => { - assertEquals( - parseNAPTR("44 186 533 2244"), - "4.4.2.2.3.3.5.6.8.1.4.4.e164.arpa", - ); -}); diff --git a/tests/testDeps.ts b/tests/testDeps.ts deleted file mode 100644 index 6a92c1ed..00000000 --- a/tests/testDeps.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - assertEquals, - assertThrows, -} from "https://deno.land/std@0.144.0/testing/asserts.ts";