Compare commits

...

289 Commits

Author SHA1 Message Date
Renovate Bot c88958f5df chore(deps): update dependency go to v1.22.3
Mirror Push / mirror (push) Successful in 5s Details
Test / test (oldstable) (push) Successful in 42s Details
Test / test (stable) (push) Successful in 43s Details
2024-05-07 17:00:26 +00:00
Renovate Bot e91ab27f13 fix(deps): update module golang.org/x/net to v0.25.0
Mirror Push / mirror (push) Successful in 6s Details
Test / test (oldstable) (push) Successful in 42s Details
Test / test (stable) (push) Successful in 38s Details
2024-05-06 17:00:24 +00:00
Renovate Bot 6677c6b5e5 fix(deps): update module github.com/quic-go/quic-go to v0.43.1
Mirror Push / mirror (push) Successful in 5s Details
Test / test (oldstable) (push) Successful in 41s Details
Test / test (stable) (push) Successful in 37s Details
2024-05-04 23:00:35 +00:00
Renovate Bot 7126c753e9 fix(deps): update module golang.org/x/sys to v0.20.0
Mirror Push / mirror (push) Successful in 6s Details
Test / test (oldstable) (push) Successful in 41s Details
Test / test (stable) (push) Successful in 38s Details
2024-05-04 16:00:25 +00:00
Renovate Bot c1a4a7f93a fix(deps): update module github.com/quic-go/quic-go to v0.43.0
Mirror Push / mirror (push) Successful in 6s Details
Test / test (oldstable) (push) Successful in 43s Details
Test / test (stable) (push) Successful in 40s Details
2024-04-27 15:00:46 +00:00
Sam Therapy 9aebf89f57
docs: make the README a little nicer
Mirror Push / mirror (push) Successful in 6s Details
Test / test (oldstable) (push) Successful in 44s Details
Test / test (stable) (push) Successful in 37s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2024-04-19 23:01:11 +02:00
Renovate Bot 37e0c1e9b5 fix(deps): update module github.com/miekg/dns to v1.1.59
Mirror Push / mirror (push) Successful in 7s Details
Test / test (oldstable) (push) Successful in 43s Details
Test / test (stable) (push) Successful in 39s Details
2024-04-17 21:00:38 +00:00
Sam Therapy 40278ed22f
chore: Add Snap and Docker with Goreleaser
Forgejo Release / release (push) Failing after 1m6s Details
Mirror Push / mirror (push) Successful in 6s Details
Test / test (oldstable) (push) Successful in 45s Details
Test / test (stable) (push) Successful in 38s Details
Why not though snap sucks and docker seems kind of pointless since this is just a static file

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2024-04-17 19:00:51 +02:00
Renovate Bot 7631dd7a7b fix(deps): update module golang.org/x/net to v0.24.0
Mirror Push / mirror (push) Successful in 5s Details
Test / test (oldstable) (push) Successful in 44s Details
Test / test (stable) (push) Successful in 39s Details
2024-04-04 20:01:14 +00:00
Renovate Bot 2140c1582f fix(deps): update module golang.org/x/sys to v0.19.0
Mirror Push / mirror (push) Successful in 6s Details
Test / test (oldstable) (push) Successful in 45s Details
Test / test (stable) (push) Successful in 38s Details
2024-04-04 16:01:12 +00:00
Renovate Bot 8c00f85636 fix(deps): update module golang.org/x/net to v0.23.0
Mirror Push / mirror (push) Successful in 5s Details
Test / test (oldstable) (push) Successful in 45s Details
Test / test (stable) (push) Successful in 45s Details
2024-04-03 19:01:10 +00:00
Renovate Bot 8e54337787 chore(deps): update dependency go to v1.22.2
Mirror Push / mirror (push) Successful in 6s Details
Test / test (oldstable) (push) Successful in 43s Details
Test / test (stable) (push) Successful in 44s Details
2024-04-03 16:01:11 +00:00
Sam Therapy a5980be3cc
docs: Use the docs folder more
Mirror Push / mirror (push) Successful in 7s Details
Test / test (stable) (push) Successful in 36s Details
Test / test (oldstable) (push) Successful in 56s Details
Also rename it from doc to docs

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2024-03-23 22:05:57 +01:00
Sam Therapy 58cee5b3c9
docs: Add more documentation
Mirror Push / mirror (push) Successful in 6s Details
Test / test (stable) (push) Successful in 39s Details
Test / test (oldstable) (push) Successful in 56s Details
Add the "official" logo.
Also run golangci-lint

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2024-03-23 22:00:01 +01:00
Renovate Bot 3881caff0d fix(deps): update module github.com/quic-go/quic-go to v0.42.0
Mirror Push / mirror (push) Successful in 6s Details
Test / test (oldstable) (push) Successful in 57s Details
Test / test (stable) (push) Successful in 29s Details
2024-03-18 02:01:09 +00:00
Sam Therapy d8c40abf5a
misc(deps): Re-enable automerge
Mirror Push / mirror (push) Successful in 5s Details
Test / test (stable) (push) Successful in 34s Details
Test / test (oldstable) (push) Successful in 55s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2024-03-16 23:47:30 +01:00
Sam Therapy 92cf0b465b
ci: Improve all actions
Mirror Push / mirror (push) Successful in 6s Details
Test / test (stable) (push) Successful in 50s Details
Test / test (oldstable) (push) Successful in 1m12s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2024-03-16 23:26:02 +01:00
Sam Therapy b5f4ea9c42
ci: Get rid of dedicated submodules step
Mirror Push / mirror (push) Successful in 9s Details
Test / test (stable) (push) Successful in 46s Details
Test / test (oldstable) (push) Successful in 53s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2024-03-16 21:28:49 +01:00
Sam Therapy 8434739516
fix(AAAA): AAAAA
Mirror Push / mirror (push) Successful in 8s Details
Test / test (oldstable) (push) Successful in 1m9s Details
Test / test (stable) (push) Successful in 41s Details
Gitea Release / release (push) Failing after 1m14s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2024-03-15 18:42:29 +01:00
Sam Therapy 556b7a48af
[SKIP CI] fix(readme): correct the manpage URL
Mirror Push / mirror (push) Successful in 7s Details
Test / test (oldstable) (push) Successful in 1m9s Details
Gitea Release / release (push) Failing after 1m19s Details
Test / test (stable) (push) Successful in 40s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2024-03-15 18:32:09 +01:00
Sam Therapy 21047275bf
fix(quic): A workaround for adguard not working over QUIC
Mirror Push / mirror (push) Successful in 6s Details
Test / test (stable) (push) Successful in 41s Details
Test / test (oldstable) (push) Successful in 52s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2024-03-15 18:20:03 +01:00
Sam Therapy 835cb8c950
fix(docs): Totally redesign the readme
Also, use the American spelling of LICENSE instead of LICENCE since that is what everyone else already does
2024-03-15 18:16:58 +01:00
Sam Therapy 20f5b21be1
fix(deps): go get -u 2024-03-15 15:35:02 +01:00
Renovate Bot b975dd8c00 fix(deps): update module golang.org/x/net to v0.22.0
Mirror Push / mirror (push) Successful in 9s Details
Test / test (oldstable) (push) Failing after 43s Details
Test / test (stable) (push) Failing after 41s Details
2024-03-04 21:00:28 +00:00
Renovate Bot 42e50d3e93 fix(deps): update module github.com/miekg/dns to v1.1.58
Mirror Push / mirror (push) Successful in 7s Details
Test / test (oldstable) (push) Successful in 37s Details
Test / test (stable) (push) Successful in 40s Details
2024-01-18 12:00:21 +00:00
Sam Therapy 7030e68100
fix(deps): go get -u
Mirror Push / mirror (push) Successful in 7s Details
Test / test (oldstable) (push) Successful in 34s Details
Test / test (stable) (push) Successful in 39s Details
2024-01-09 21:10:07 +01:00
Renovate Bot c4a267cec9 fix(deps): update module golang.org/x/net to v0.20.0
Mirror Push / mirror (push) Successful in 8s Details
Test / test (oldstable) (push) Successful in 35s Details
Test / test (stable) (push) Successful in 40s Details
2024-01-08 19:00:21 +00:00
Renovate Bot 434de0e5b4 fix(deps): update module golang.org/x/sys to v0.16.0
Mirror Push / mirror (push) Successful in 6s Details
Test / test (stable) (push) Successful in 38s Details
Test / test (oldstable) (push) Successful in 44s Details
2024-01-04 16:00:25 +00:00
Renovate Bot 52cef2e3a3 fix(deps): update module github.com/quic-go/quic-go to v0.40.1
Mirror Push / mirror (push) Successful in 6s Details
Test / test (stable) (push) Successful in 34s Details
Test / test (oldstable) (push) Successful in 41s Details
2023-12-13 05:00:25 +00:00
Renovate Bot e0b14b8b00 chore(deps): update actions/setup-go action to v5
Mirror Push / mirror (push) Successful in 8s Details
Test / test (stable) (push) Successful in 32s Details
Test / test (oldstable) (push) Successful in 40s Details
2023-12-06 16:00:23 +00:00
Renovate Bot c580ac78d4 fix(deps): update module golang.org/x/net to v0.19.0
Mirror Push / mirror (push) Successful in 7s Details
Test / test (stable) (push) Successful in 35s Details
Test / test (oldstable) (push) Successful in 41s Details
2023-11-27 18:00:40 +00:00
Renovate Bot 99e75afcd3 fix(deps): update module golang.org/x/sys to v0.15.0
Mirror Push / mirror (push) Successful in 8s Details
Test / test (oldstable) (push) Successful in 34s Details
Test / test (stable) (push) Successful in 40s Details
2023-11-27 17:00:24 +00:00
Renovate Bot 6ddbf854d8 fix(deps): update module github.com/miekg/dns to v1.1.57
Mirror Push / mirror (push) Successful in 9s Details
Test / test (stable) (push) Successful in 35s Details
Test / test (oldstable) (push) Successful in 39s Details
2023-11-15 10:00:52 +00:00
Sam Therapy 16ef3de591
docs(readme): Use a better file name for deb
Mirror Push / mirror (push) Successful in 8s Details
Test / test (stable) (push) Successful in 33s Details
Test / test (oldstable) (push) Successful in 41s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-11-13 18:44:48 +01:00
Renovate Bot f9263300c7 fix(deps): update module golang.org/x/net to v0.18.0
Mirror Push / mirror (push) Successful in 8s Details
Test / test (oldstable) (push) Successful in 36s Details
Test / test (stable) (push) Successful in 39s Details
2023-11-08 23:00:24 +00:00
Sam Therapy d43543e48a
fix(deps): Go sum update from goreleaser
Mirror Push / mirror (push) Successful in 8s Details
Test / test (oldstable) (push) Successful in 34s Details
Test / test (stable) (push) Successful in 39s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-11-09 00:38:52 +01:00
Sam Therapy 0a6d6b432c
fix(ci): Force goreleaser to use gitea
Mirror Push / mirror (push) Successful in 11s Details
Test / test (oldstable) (push) Successful in 43s Details
Test / test (stable) (push) Successful in 38s Details
Gitea Release / release (push) Failing after 1m10s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-11-08 22:04:09 +01:00
Sam Therapy ffb16ff7fa
fix)ci): make apt update first
Mirror Push / mirror (push) Successful in 7s Details
Gitea Release / release (push) Failing after 31s Details
Test / test (stable) (push) Successful in 39s Details
Test / test (oldstable) (push) Successful in 41s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-11-08 21:57:50 +01:00
Sam Therapy efb4cd6c4a
[SKIP CI] fix(ci): remove sudo
Mirror Push / mirror (push) Successful in 7s Details
Gitea Release / release (push) Failing after 29s Details
Test / test (stable) (push) Successful in 31s Details
Test / test (oldstable) (push) Successful in 37s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-11-08 21:54:57 +01:00
Sam Therapy 59fa146d7f
feat!(quic): Remove gccgo support
Mirror Push / mirror (push) Successful in 7s Details
Gitea Release / release (push) Failing after 22s Details
Test / test (stable) (push) Successful in 38s Details
Test / test (oldstable) (push) Successful in 1m23s Details
Since gccgo is stuck at 1.18 without generics, drop support
sadge

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-11-08 21:51:44 +01:00
Sam Therapy c5c90b97af
fix(deps): go get -u
Mirror Push / mirror (push) Successful in 10s Details
Test / test (stable) (push) Successful in 33s Details
Test / test (oldstable) (push) Successful in 41s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-11-08 21:47:19 +01:00
Sam Therapy e1122a9de7
misc: Cleanup before a release
Mirror Push / mirror (push) Successful in 8s Details
Test / test (stable) (push) Successful in 33s Details
Test / test (oldstable) (push) Successful in 42s Details
Kept a lot waiting, haven't I?

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-11-08 21:45:39 +01:00
Sam Therapy 26ef04b969 feat(goreleaser): Vastly simplify upload process (#229)
Mirror Push / mirror (push) Successful in 8s Details
Test / test (stable) (push) Successful in 38s Details
Test / test (oldstable) (push) Successful in 1m1s Details
Make the upload process to Gitea packages much less of a clusterbomb

Reviewed-on: #229
2023-11-08 18:02:34 +00:00
Sam Therapy 2565d34ade
docs(readme): Update mailing list
Mirror Push / mirror (push) Successful in 10s Details
Test / test (oldstable) (push) Successful in 35s Details
Test / test (stable) (push) Successful in 38s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-11-08 01:04:30 +01:00
Sam Therapy 7dd9b138a3
ci: Add sr.ht mirror
Mirror Push / mirror (push) Successful in 9s Details
Test / test (oldstable) (push) Successful in 34s Details
Test / test (stable) (push) Successful in 39s Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-11-08 00:54:53 +01:00
Sam Therapy b8a2407169 ci: Add Gitea Actions (#228)
Test / test (oldstable) (push) Successful in 1m0s Details
Test / test (stable) (push) Successful in 39s Details
Use Gitea Actions instead of Drone.

Reviewed-on: #228
2023-11-07 20:27:18 +00:00
Renovate Bot 9ef46d33e8 fix(deps): update module golang.org/x/sys to v0.14.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-11-04 16:00:24 +00:00
Renovate Bot 939a09da5b fix(deps): update module github.com/quic-go/quic-go to v0.40.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-10-31 05:00:30 +00:00
Renovate Bot 87c59551ec fix(deps): update module github.com/quic-go/quic-go to v0.39.3
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-10-27 07:00:24 +00:00
Renovate Bot 7efc9523bf fix(deps): update module github.com/quic-go/quic-go to v0.39.2
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-10-25 05:00:39 +00:00
Renovate Bot 2084ae69f6 fix(deps): update module github.com/quic-go/quic-go to v0.39.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-10-17 07:00:22 +00:00
Renovate Bot 5130b6c3cd fix(deps): update module golang.org/x/net to v0.17.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-10-10 17:00:24 +00:00
Renovate Bot 8c949ce4ca fix(deps): update module golang.org/x/net to v0.16.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-10-06 00:00:19 +00:00
Renovate Bot b3fad7abcf fix(deps): update module golang.org/x/sys to v0.13.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-10-05 13:00:22 +00:00
Renovate Bot b713aeb7d4 fix(deps): update module github.com/quic-go/quic-go to v0.39.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-09-24 12:00:23 +00:00
Renovate Bot 260eb979b3 fix(deps): update module gotest.tools/v3 to v3.5.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-09-16 20:00:23 +00:00
Renovate Bot 83ecfbaea1 fix(deps): update module github.com/miekg/dns to v1.1.56
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-09-12 11:00:22 +00:00
Renovate Bot 10faea804b chore(deps): update goreleaser/goreleaser-action action to v5
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-09-11 19:00:21 +00:00
Renovate Bot 0f80004790 fix(deps): update module golang.org/x/net to v0.15.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-09-05 17:00:24 +00:00
Renovate Bot 12863559c5 chore(deps): update actions/checkout action to v4
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-09-04 13:00:20 +00:00
Renovate Bot 8e9574f870 fix(deps): update module golang.org/x/sys to v0.12.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-09-02 13:00:21 +00:00
Renovate Bot fadb04f49f fix(deps): update module github.com/quic-go/quic-go to v0.38.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-08-25 01:00:23 +00:00
Renovate Bot 5704c6a0dd fix(deps): update module github.com/quic-go/quic-go to v0.38.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-08-21 04:00:25 +00:00
Renovate Bot 9c8e5349bf fix(deps): update module github.com/quic-go/quic-go to v0.37.6
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-08-20 00:00:25 +00:00
Sam Therapy dcd932c42e
[SKIP CI] docs: Bump go version in README
Maybe with the removal of the quic TLS fork go version can be supported
longer

gccgo generic support soon (tm) :(
2023-08-11 20:37:07 +02:00
Sam Therapy f4c3283954
[SKIP CI] fix(goreleaser): Unbreak termux?
Hopefully this unbreaks termux packages because they try going into
/usr/bin which makes termux very sad
2023-08-11 20:23:31 +02:00
Sam Therapy 824a60aef1
fix(mk): Add version number in -V
awk(1) magic saves the day
2023-08-11 20:22:16 +02:00
Sam Therapy 43e53a4055
fix(ci): Update GitHub Actions to Go 1.21
continuous-integration/drone/push Build is passing Details
2023-08-10 19:43:43 +02:00
Sam Therapy 60b0300eec
fix(goreleaser): Remove deprecation warnings
continuous-integration/drone/push Build is passing Details
2023-08-10 19:37:54 +02:00
Sam Therapy 9740e6b348
fix(deps): Update indirect dependencies
continuous-integration/drone/push Build is passing Details
2023-08-10 19:35:03 +02:00
Renovate Bot 8c888a90f1 fix(deps): update module gotest.tools/v3 to v3.5.0 (#202)
continuous-integration/drone/push Build is passing Details
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Co-committed-by: Renovate Bot <renovate@whitesourcesoftware.com>
2023-08-10 15:07:46 +00:00
Renovate Bot 71477684d9 fix(deps): update module github.com/quic-go/quic-go to v0.37.4 (#206)
continuous-integration/drone/push Build is running Details
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Co-committed-by: Renovate Bot <renovate@whitesourcesoftware.com>
2023-08-10 15:07:32 +00:00
Renovate Bot e3951db486 fix(deps): update module golang.org/x/net to v0.14.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-08-04 23:00:28 +00:00
Renovate Bot dfe4cca176 fix(deps): update module golang.org/x/sys to v0.11.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-08-04 16:00:23 +00:00
Renovate Bot b5102c91e6 fix(deps): update module golang.org/x/net to v0.13.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-08-01 22:00:24 +00:00
Renovate Bot 03e8f6be61 Merge pull request 'fix(deps): update module golang.org/x/net to v0.12.0' (#205) from renovate/golang.org-x-net-0.x into master
continuous-integration/drone/push Build is passing Details
2023-07-15 17:00:20 +00:00
Renovate Bot f60cd1c315 Merge pull request 'fix(deps): update module golang.org/x/sys to v0.10.0' (#204) from renovate/golang.org-x-sys-0.x into master
continuous-integration/drone/push Build is passing Details
2023-07-15 15:35:47 +00:00
Renovate Bot 00b116abf4 Merge pull request 'fix(deps): update module github.com/quic-go/quic-go to v0.36.2' (#203) from renovate/github.com-quic-go-quic-go-0.x into master
continuous-integration/drone/push Build was killed Details
2023-07-15 15:35:40 +00:00
Renovate Bot 821149b463 Merge pull request 'fix(deps): update module golang.org/x/net to v0.11.0' (#199) from renovate/golang.org-x-net-0.x into master
continuous-integration/drone/push Build is passing Details
2023-06-21 19:07:12 +00:00
Renovate Bot f2f53795ef Merge pull request 'fix(deps): update module github.com/miekg/dns to v1.1.55' (#200) from renovate/github.com-miekg-dns-1.x into master
continuous-integration/drone/push Build is running Details
2023-06-21 19:06:39 +00:00
Renovate Bot 322345a758 Merge pull request 'fix(deps): update module github.com/quic-go/quic-go to v0.36.0' (#201) from renovate/github.com-quic-go-quic-go-0.x into master
continuous-integration/drone/push Build is passing Details
2023-06-21 18:58:40 +00:00
Renovate Bot b4de2ba89e Merge pull request 'fix(deps): update module golang.org/x/sys to v0.9.0' (#198) from renovate/golang.org-x-sys-0.x into master
continuous-integration/drone/push Build is running Details
2023-06-21 18:58:15 +00:00
Sam Therapy 3421066420
[SKIP CI] docs(readme): I hate RPM
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-06-09 01:32:26 +02:00
Sam Therapy aef8a73a28
[SKIP CI] packaging: Correct RPM documentation
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-06-09 01:07:02 +02:00
Sam Therapy ba93384f9b
misc: lint
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-06-02 23:21:56 +02:00
Sam Therapy 66855b5542 make test happy for some reason
continuous-integration/drone/push Build is failing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-06-02 21:10:05 +00:00
Sam Therapy ccc9df39b6 update QUIC code to work with new quic-go version
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-06-02 21:10:05 +00:00
Renovate Bot c6bbda17b2 fix(deps): update module github.com/quic-go/quic-go to v0.35.1 2023-06-02 21:10:05 +00:00
Sam Therapy db77f2315c
fix(https): Small HTTPS annoyance fixes
continuous-integration/drone/push Build is failing Details
Fixes /dns-query being appended on failure
Fixes /dns-query from being appended when it should not be

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-06-02 22:54:02 +02:00
Sam Therapy a157dcb7fb
[SKIP CI] feat(goreleaser): Target termux too 2023-05-15 17:02:00 +02:00
Sam Therapy 428c218405
[SKIP CI] docs(readme): Update packaging location
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-05-14 23:21:39 +02:00
Sam Therapy 8df4863cf4
feat(ci): use my new package utility instead of pages
continuous-integration/drone/push Build is passing Details
2023-05-14 22:45:54 +02:00
Sam Therapy c0cd4d7771
feat(goreleaser): Enable APK and RPM
Gitea supports them now so add them!
2023-05-12 23:19:24 +02:00
Renovate Bot 5f1b81a2be fix(deps): update module golang.org/x/net to v0.10.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-08 17:00:21 +00:00
Renovate Bot 45d1aaf535 fix(deps): update module golang.org/x/sys to v0.8.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-04 16:00:24 +00:00
Renovate Bot 4f42657294 fix(deps): update module github.com/quic-go/quic-go to v0.34.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-30 00:00:27 +00:00
Renovate Bot b6bd22a8fe fix(deps): update module github.com/miekg/dns to v1.1.54
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-29 23:00:27 +00:00
Sam Therapy b0d8e325d6
fix(gomod): Explicitly require 1.19
continuous-integration/drone/push Build is passing Details
2023-04-30 00:42:09 +02:00
Sam Therapy fb9fd7689f
fix(trace): Remove wrong error message
continuous-integration/drone/push Build is passing Details
Reverse queries *are* actually supported, so the error message was wrong
Even dig supports it naturally.
2023-04-27 22:04:28 +02:00
Sam Therapy 329d81c001
fix(deps): go get -u
continuous-integration/drone/push Build is passing Details
2023-04-12 14:46:46 +02:00
Renovate Bot 5329a6f2e0 fix(deps): update module golang.org/x/net to v0.9.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-10 20:00:30 +00:00
Renovate Bot 95ff6f554c fix(deps): update module golang.org/x/sys to v0.7.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-04 17:00:43 +00:00
Sam Therapy 928123edbd
fix(deps): go get -u
continuous-integration/drone/push Build is passing Details
2023-03-28 22:21:18 +02:00
Renovate Bot fd3ceeb066 chore(deps): update actions/setup-go action to v4
continuous-integration/drone/push Build is passing Details
2023-03-28 20:18:02 +00:00
Renovate Bot 1acd48b16d fix(deps): update module github.com/miekg/dns to v1.1.53
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is running Details
2023-03-28 19:00:34 +00:00
Sam Therapy 27ece358c6
fix(resolvers): QUIC: close as soon as the writing is done
continuous-integration/drone/push Build is passing Details
This is required by RFC 9250, and would break some requests when done wrong

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-03-09 23:39:00 +01:00
Sam Therapy 58fa7af2ea
fix(release): Correct scoop bucket location
continuous-integration/drone/push Build is passing Details
Use the scoop bucket template
2023-03-07 18:45:45 +01:00
Sam Therapy 75fb8f2fc6
fix(docs): We're so back
continuous-integration/drone/push Build is passing Details
Using my fork of the DNSCrypt library brings back go install

This reverts commit daff2b7687.
2023-03-07 00:13:26 +01:00
Sam Therapy 3423958809
fix(deps): Use my fork of the dnscrypt lib (#185)
continuous-integration/drone/push Build is passing Details
- Uses newer versions of libraries
- Nicer URL (subjective)
- it is mine :)

Reviewed-on: #185
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2023-03-06 22:41:12 +00:00
Renovate Bot 60491c39c1 fix(deps): update module golang.org/x/net to v0.8.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-03-05 04:00:19 +00:00
Renovate Bot 39f605740a fix(deps): update module golang.org/x/sys to v0.6.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-03-04 16:00:22 +00:00
Sam Therapy 171f5d0d11
fix(doc): fix literally unusable typo in manpage
continuous-integration/drone/push Build is passing Details
2023-03-01 16:16:21 +01:00
Renovate Bot 1e4ff59631 fix(deps): update module github.com/miekg/dns to v1.1.51
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-02-26 12:00:19 +00:00
Renovate Bot f1583fef52 fix(deps): update module github.com/quic-go/quic-go to v0.33.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-02-22 06:00:28 +00:00
Sam Therapy fa709ca327
fix(ci): :(
continuous-integration/drone/push Build was killed Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-20 20:44:59 +01:00
Sam Therapy 30277b5028
fix(goreleaser): add capitalize FreeBSD
continuous-integration/drone/push Build is passing Details
I give up.

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-20 20:39:43 +01:00
Sam Therapy 028c423d89
fix(goreleaser): stop using universal binaries
continuous-integration/drone/push Build is passing Details
Fixes an extremely annoying goreleaser problem that I cannot replicate at all

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-20 20:35:52 +01:00
Renovate Bot 641b003381 chore(deps): update goreleaser/goreleaser-action action to v4
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-02-17 22:00:14 +00:00
Sam Therapy b15584f436
fix(ci): I hate you, GHA
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-17 22:44:21 +01:00
Sam Therapy 9c8f30f432
fix(ci): target 1.20, drop 1.19
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-17 22:40:16 +01:00
Sam Therapy da172f9de5
Revert "ci: Purge GHA"
This reverts commit 0bcc63de8a.
2023-02-17 22:36:18 +01:00
Sam Therapy feb0617ce2
fix(deps): go get -u
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-17 20:40:50 +01:00
Sam Therapy daff2b7687
fix(README): go install does not like replace
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-17 19:34:31 +01:00
Sam Therapy e782c9cb23
feat: change import URL
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-17 19:18:58 +01:00
Sam Therapy 00ec4ef893
fix(Make): stop compressing the manpages
continuous-integration/drone/push Build is passing Details
Let whatever installs them do it themselves

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-16 23:23:10 +01:00
Sam Therapy bf04f59468
fix(goreleaser): add vendor dependency tarball
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-16 18:53:36 +01:00
Renovate Bot db66371420 fix(deps): update module golang.org/x/net to v0.7.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-02-14 18:00:21 +00:00
Renovate Bot 42b17a7912 fix(deps): update module golang.org/x/net to v0.6.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-02-08 22:00:20 +00:00
Renovate Bot 4286c16ae2 fix(deps): update module golang.org/x/sys to v0.5.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-02-07 01:00:31 +00:00
Sam Therapy 6d9690c44f
fix: lint
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-04 15:37:06 -06:00
Sam Therapy bc6e7cd759
fix(deps): Use new quic-go location + update
continuous-integration/drone/push Build is failing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-02-04 14:27:47 +01:00
Sam Therapy 2312fecfc8 fix(trace): Ensure traces stop when request fails (#175)
continuous-integration/drone/push Build is passing Details
Closes #174

Reviewed-on: #175
2023-01-31 16:08:07 +00:00
Sam Therapy 75479f5060
fix(deps): update external dependencies
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2023-01-31 17:06:29 +01:00
Renovate Bot 0c8000d598 fix(deps): update module golang.org/x/net to v0.5.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-01-04 17:00:18 +00:00
Sam Therapy 30be18b474
[SKIP CI] update wiki
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-12-27 21:52:41 +01:00
grumbulon d93eccc064
feat: RFC-8427 (#171)
continuous-integration/drone/push Build is passing Details
This PR will make the JSON response body be based off [RFC-8427](https://www.rfc-editor.org/rfc/rfc8427.html) which will be similar to [kdig's](https://www.knot-dns.cz/docs/2.6/html/man_kdig.html) JSON output.

Co-authored-by: Sam Therapy <sam@samtherapy.net>
Reviewed-on: #171
Reviewed-by: Sam Therapy <sam@samtherapy.net>
Co-authored-by: grumbulon <grumbulon@grumbulon.xyz>
Co-committed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-12-27 20:07:09 +00:00
Sam Therapy fdba9a0a41
refactor: Add named returns (#168)
continuous-integration/drone/push Build is passing Details
Add some named returns

Co-authored-by: grumbulon <grumbulon@grumbulon.xyz>
Reviewed-on: #168
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-12-17 16:52:50 +00:00
Sam Therapy a7f7498d8b
docs(man): overhaul the manpage [SKIP CI] (#170)
Make everything alphabetical, make it look more like dig and kdig

Reviewed-on: #170
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-12-15 19:30:22 +00:00
Sam Therapy 792ddecf6c
fix(print): use any on TTL (#169)
continuous-integration/drone/push Build is passing Details
This allows JSON to use either an int or string depending on output

Reviewed-on: #169
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-12-15 19:30:01 +00:00
Sam Therapy 10d1c4cd2b fix(trace): Only trace when tracing (#167)
continuous-integration/drone/push Build is passing Details
AAAAAAAAAAAAAAAAAAAA

Reviewed-on: #167
2022-12-10 18:19:30 +00:00
Sam Therapy 530ef06ee1
feat: Trace (#162)
continuous-integration/drone/push Build is passing Details
This PR should add the trace option, used by +trace and --trace

TODO
- [x] Making the trace work properly
- [x] Documentation adding
- [x] Completion adding

Co-authored-by: grumbulon <grumbulon@grumbulon.xyz>
Reviewed-on: #162
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-12-10 17:51:49 +00:00
Sam Therapy 0b042af3e2
fix(win): Fix occasional buffer overflows (#166)
continuous-integration/drone/push Build is running Details
This fixes a problem I have had where I get the following message sometimes:
Error: config, windows: The file name is too long.

Delv says it is a buffer overflow so this fixes it at the cost of just allocating more memory.

TODO: Make actually good

Reviewed-on: #166
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-12-10 17:51:00 +00:00
Renovate Bot 4349aec1f2 fix(deps): update module github.com/lucas-clemente/quic-go to v0.31.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-12-08 21:00:15 +00:00
Sam Therapy 185a79e1c2
fix(printable): actually hide sections if requested (#164)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #164
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-12-08 15:21:10 +00:00
Renovate Bot 11ebd2c69f fix(deps): update module golang.org/x/net to v0.4.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-12-07 10:00:15 +00:00
Sam Therapy 64768f0956
fix(errors): put exported errors in util (#161)
continuous-integration/drone/push Build is passing Details
Centralize them in one place

Reviewed-on: #161
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-12-06 21:39:28 +00:00
Renovate Bot 45acd03dff fix(deps): update module golang.org/x/net to v0.3.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-12-06 05:00:16 +00:00
Sam Therapy 78bbb8f23d
fix(make): use correct tag when version is greater than 10
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-12-05 15:25:24 +01:00
Renovate Bot 7e7c88ddd5 fix(deps): update module golang.org/x/sys to v0.3.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-12-04 16:00:20 +00:00
Sam Therapy a2e7b262ea
fix(misc): minor changes (#158)
continuous-integration/drone/push Build is passing Details
1. update indirect dependencies
2. Set timeout to 5 seconds instead of 1
- this helps with slow queries
3. Put class back in the default query output
- this fixes a problem with using awl to make a root file

Reviewed-on: #158
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-12-03 20:36:23 +00:00
Sam Therapy 90f5b92ffd
[SKIP CI] fix(ci): fix typo in downstream plugin
Grafana changed the name of the container

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-11-21 23:12:11 +01:00
grumbulon 5d67ffaad3
fix(log): log levels were wrong for two format statements (#157)
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build encountered an error Details
Reviewed-on: #157
Reviewed-by: Sam Therapy <sam@samtherapy.net>
Co-authored-by: grumbulon <grumbulon@grumbulon.xyz>
Co-committed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-11-20 00:25:35 +00:00
Sam Therapy 303eb974c8
fix(readme): [SKIP CI] add / dev/null to debian
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-11-19 22:52:53 +01:00
Sam Therapy dfa14cbcdf
feat(gccgo): allow compilation with gccgo (#156)
continuous-integration/drone/push Build is passing Details
This PR disables quic-go when compiling with gccgo since gccgo does not support generics

Reviewed-on: #156
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-11-19 18:25:04 +00:00
Sam Therapy 216431f591
fix(make): default file should be static linked [CI SKIP]
Follow the go way
2022-11-17 20:25:34 +01:00
Renovate Bot 07260fb593 fix(deps): update module github.com/lucas-clemente/quic-go to v0.31.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-11-16 23:00:19 +00:00
Renovate Bot 9a9658c6f8 fix(deps): update module golang.org/x/net to v0.2.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-11-08 19:00:16 +00:00
Renovate Bot e456d409ef fix(deps): update module golang.org/x/sys to v0.2.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-11-07 20:00:20 +00:00
Sam Therapy ea3943dd63
fix(ci): use Grafana's downstream trigger
continuous-integration/drone/push Build is passing Details
Newer and includes PRs that should fix the problems I've had
2022-11-07 16:41:21 +01:00
Sam Therapy feef2cddaf
fix(https): add default endpoint (#152)
continuous-integration/drone/push Build is passing Details
say you do -H @dns.froth.zone/sodd
It should send a request to dns.froth.zone/sodd
but if you do -H @dns.froth.zone
it should send a request to dns.froth.zone/dns-query

This does that

Reviewed-on: #152
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-11-07 15:07:44 +00:00
Sam Therapy 2836633c62
fix(make): Make makefile more like the arch default.
continuous-integration/drone/push Build is passing Details
This also fixes the AUR problem I had and forces an upgrade.
2022-11-07 15:50:42 +01:00
Sam Therapy a64a260c55
fix(test): typo fix
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-31 13:56:10 +01:00
Sam Therapy dd542b9f18
ci: replace concat with format strings
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-27 17:56:00 +02:00
Sam Therapy c658b6b796
fix(deps): go get -u
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-27 15:05:33 +02:00
Renovate Bot da7ce61152 Update module github.com/lucas-clemente/quic-go to v0.30.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-22 12:00:15 +00:00
Sam Therapy 852c87c3ab
[SKIP CI] fix(goreleaser): remove broken brew HEAD
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-21 17:10:12 +02:00
Sam Therapy ec6e723eaf
fix(goreleaser) correct URL
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-21 16:16:01 +02:00
Sam Therapy 698b0d3ad1
fix(goreleaser) correct URL
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-21 15:19:21 +02:00
Sam Therapy 8c3a5cb369
[SKIP CI] docs(readme): add more packages
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-21 03:40:19 +02:00
Sam Therapy 60e22e6d33
[SKIP CI] chore(goreleaser): add completions and manpage
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-21 03:30:07 +02:00
Sam Therapy 7feaab7103
[SKIP CI] docs(readme): update apt instructions
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-20 23:15:13 +00:00
Sam Therapy b1fa25a9a0
feat(dig): Dig +https (#147)
continuous-integration/drone/push Build is passing Details
BREAKING CHANGE: DNS-over-HTTPS requests are now dealt with differently

Using +https or -H now implies adding /dns-query (like dig)
Using the implied https:// prefix follows the old behaviour (nothing added or implied)

Reviewed-on: #147
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-10-20 21:34:24 +00:00
Sam Therapy 59212798f7
[SKIP CI] fix(make): Real actual macOS support (#148)
Tested again on the lone Apple device I have.

This time it does not break make on Linux 🌝

Reviewed-on: #148
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-10-20 21:34:16 +00:00
Sam Therapy a386960076
[SKIP CI] chore(goreleaser): Add scoop/brew support (#149)
Reviewed-on: #149
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-10-20 21:34:07 +00:00
Sam Therapy 6144c7219a
[SKIP CI] ci: put token secret in right place
hehe

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-20 23:32:44 +02:00
Renovate Bot 967363f34b fix(deps): update module golang.org/x/net to v0.1.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-19 16:00:15 +00:00
Sam Therapy 2db6ee3935
[SKIP CI] fix(main): Remove webasm restriction
https://www.arp242.net/wasm-cli.html
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-19 14:51:19 +02:00
Renovate Bot 3a1ebaafe1 fix(deps): update golang.org/x/net digest to cb67ada
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-19 03:00:14 +00:00
Renovate Bot 354128d449 fix(deps): update module golang.org/x/sys to v0.1.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-17 19:00:14 +00:00
Sam Therapy def649de4f [SKIP CI] docs: fix HTTPS
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-17 17:38:42 +00:00
Renovate Bot d6a9bd9b0b fix(deps): update golang.org/x/net digest to f25eb7e
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-17 16:00:15 +00:00
Sam Therapy 0bcc63de8a
ci: Purge GHA
continuous-integration/drone/push Build is passing Details
I would rather dedicate to only Gitea (and maybe SRHT)

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-17 15:07:55 +02:00
Sam Therapy 39639c0f7f
fix(deps): go get -u
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-16 16:27:05 +02:00
Sam Therapy b80219019e
Add check for port at the end (#142)
continuous-integration/drone/push Build is passing Details
Fixes #141

Before, a failure would add on the port, eg.
```
127.0.0.1:53
127.0.0.1:53:53
127.0.0.1:53:53:53 // Go actually thinks this is now an IPv6 address, interesting
```

Now a check is added so this doesn't happen

Reviewed-on: #142
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-10-16 14:25:13 +00:00
Sam Therapy bf0e44e80c
ci: Remove server header that was broken
continuous-integration/drone/push Build is failing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-14 20:15:32 +02:00
Sam Therapy 9ec28f9b1a
[SKIP CI] docs: add apt repo to README
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-14 18:59:23 +02:00
Sam Therapy dc4edd55bb
fix(query): fix printing irregularities (#140)
continuous-integration/drone/push Build is passing Details
1. Before, the port printed was duplicated, eg.
`;; SERVER: [::1]:53:53 (UDP)` when making query. This has been fixed (not sure what caused it)
2. JSON/XML/YAML date formatting to be compliant with RFC3339 (thanks, std/time!)

Co-authored-by: Sam Therapy <sam@samtherapy.net>
Reviewed-on: #140
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-10-14 16:51:27 +00:00
Sam Therapy add1ef61a2
feat(packaging): Prepare for apt packaging (#139)
continuous-integration/drone/push Build is passing Details
This needs to be tested (preferably extensively), which I will do now

Reviewed-on: #139
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-10-14 14:11:01 +00:00
Sam Therapy 2d94ea6838 revert e6a3d6040a
continuous-integration/drone/push Build is passing Details
This broke every other operating system (and the AUR)
2022-10-14 12:47:44 +00:00
Renovate Bot 216a4b6dd7 fix(deps): update golang.org/x/net digest to f15817d
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-14 09:00:14 +00:00
Renovate Bot 66422e1512 fix(deps): update golang.org/x/sys digest to 95e765b
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-13 18:00:14 +00:00
Sam Therapy 81da49093d
refactor: Make all calls to options pointers (#132)
continuous-integration/drone/push Build is passing Details
Instead of copying the opts struct every time it gets passed around, it should be created once and passed through reference.

This should reduce memory utilization, unfortunately I cannot test it since this program runs so fast pprof won't report anything useful.

I think I found all of them 🙂

Co-authored-by: Sam Therapy <sam@samtherapy.net>
Reviewed-on: #132
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-10-13 12:49:36 +00:00
Sam Therapy e6a3d6040a [SKIP CI] fix: Make makefiles portable
-D isn't supported on MacOS (sample size: 1)

Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-13 12:49:15 +00:00
Renovate Bot c1b5961717 fix(deps): update module github.com/lucas-clemente/quic-go to v0.29.2
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-12 15:00:22 +00:00
Renovate Bot 3d97359070 fix(deps): update golang.org/x/net digest to 0b7e1fb
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-12 14:00:14 +00:00
Renovate Bot 561958c1b0 fix(deps): update golang.org/x/sys digest to 090e330
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-10 18:00:14 +00:00
Renovate Bot d2c6ed317e fix(deps): update module gotest.tools/v3 to v3.4.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-07 17:00:13 +00:00
Renovate Bot 9734f8ddad fix(deps): update module github.com/dchest/uniuri to v1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-07 13:00:13 +00:00
Renovate Bot 296f5f0a0b fix(deps): update golang.org/x/sys digest to 84dc82d
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-06 22:00:17 +00:00
Sam Therapy 4d0605bd1e
fix(deps): go get -u
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-10-06 16:49:48 +02:00
Renovate Bot a74fbf525b fix(deps): update golang.org/x/net digest to 8021a29
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-04 17:03:36 +00:00
Renovate Bot cf095313a4 fix(deps): update golang.org/x/net digest to bcab684
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-10-02 03:00:20 +00:00
Renovate Bot 6749361395 fix(deps): update golang.org/x/net digest to 107f3e3
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2022-09-30 22:00:19 +00:00
Sam Therapy 4495da2f3e
[SKIP CI] correct README
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-09-30 19:38:26 +02:00
Renovate Bot 11c06f9662 fix(deps): update github.com/dchest/uniuri digest to 3027df4
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-29 11:00:18 +00:00
Sam Therapy d701059b5f [SKIP CI] docs(readme): add links
Signed-off-by: Sam <sam@samtherapy.net>
2022-09-28 21:09:11 +00:00
Sam Therapy 56baff4e18 test: forgot one
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-28 19:07:46 +00:00
Sam Therapy 6a839ba8e5 [SKIP CI] Update wiki
continuous-integration/drone/tag Build is passing Details
2022-09-28 18:36:38 +00:00
Sam Therapy f2cf35ca31 misc: Snapcraft support (#87)
continuous-integration/drone/push Build is passing Details
Preliminary shell for supporting a snap

Reviewed-on: #87
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-28 18:32:20 +00:00
Sam Therapy 607c321de3
feat: fish completions (#122)
continuous-integration/drone/push Build is passing Details
These are basically thrown together but more is always good

Reviewed-on: #122
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-28 18:11:05 +00:00
Sam Therapy f01f2bc15a
feat(resolvers/HTTPS): add HTTP proxy support (#119)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #119
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-28 18:08:56 +00:00
Sam Therapy c053c077c8
test: Add retries to all tests (#121)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #121
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-28 17:51:35 +00:00
Renovate Bot 0a371cd335 fix(deps): update golang.org/x/sys digest to f11e5e4
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-28 15:00:18 +00:00
Sam Therapy f2218481ee
feat(completions): add bash (#118)
continuous-integration/drone/push Build is passing Details
well, at least the same Dig and drill do

Reviewed-on: #118
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-28 12:40:27 +00:00
Renovate Bot 14416d5aec fix(deps): update golang.org/x/net digest to f486391
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-27 19:00:18 +00:00
Renovate Bot 7b11583d6e fix(deps): update golang.org/x/sys digest to d9d178b
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-27 18:00:21 +00:00
Renovate Bot 7bd481cd7a fix(deps): update golang.org/x/net digest to aa73b25
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-27 16:00:20 +00:00
Sam Therapy 60643e2b3e
Remove AUR submodule
continuous-integration/drone/push Build was killed Details
2022-09-27 15:36:34 +00:00
Sam Therapy 434632884c
chore(test): Add more retires (#115)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #115
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-27 13:54:17 +00:00
Renovate Bot 284c0646f2 fix(deps): update golang.org/x/net digest to 02166a9
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2022-09-26 20:00:19 +00:00
grumbulon 3a0a8f015a chore(Refactor) (#110)
continuous-integration/drone/push Build is passing Details
refactor

Co-authored-by: Sam Therapy <sam@samtherapy.net>
Reviewed-on: #110
Reviewed-by: Sam <sam@samtherapy.net>
2022-09-24 23:11:09 +00:00
Sam Therapy ac55b21b25
[SKIP CI] go mod tidy
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-09-24 18:49:02 +02:00
Renovate Bot 840397a85a fix(deps): update golang.org/x/net digest to 8be6392
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-23 21:00:16 +00:00
Renovate Bot f24608667a fix(deps): update module github.com/lucas-clemente/quic-go to v0.29.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2022-09-23 12:00:18 +00:00
Sam Therapy 0845ae2a82
refactor: Make tests less ugly (#102)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #102
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-21 23:08:31 +00:00
Renovate Bot 94b7f523b7 fix(deps): update golang.org/x/net digest to d300de1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2022-09-21 21:00:15 +00:00
Renovate Bot c75db286dc fix(deps): update golang.org/x/net digest to db77216
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-21 16:00:16 +00:00
Renovate Bot 261e5fd6c1 fix(deps): update golang.org/x/net digest to d0c6ba3
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-20 21:00:16 +00:00
Renovate Bot 75ca107e55 fix(deps): update golang.org/x/net digest to f2f64eb
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-20 00:00:20 +00:00
Renovate Bot 98c641848e fix(deps): update golang.org/x/net digest to f8f703f
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-19 18:00:14 +00:00
Renovate Bot 86f115f361 fix(deps): update golang.org/x/sys digest to fb04ddd
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-19 10:00:14 +00:00
Sam Therapy ef87175190
fix: remove race conditions with flags (#101)
continuous-integration/drone/push Build is passing Details
Mainly for testing but a nice to have.

Proceeds a larger testing refactor

Reviewed-on: #101
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-17 10:42:49 +00:00
Sam Therapy 933967016f [SKIP CI] misc: makefile refactoring (#100)
Mainly making it so that it doesn't always run tests when making coverage

Also, making it more cross platform and less splintered is nice.

Co-authored-by: Sam Therapy <sam@samtherapy.net>
Reviewed-on: #100
2022-09-16 23:38:46 +00:00
Sam Therapy 8df0347891 fix: EDNS cookies work properly (#98)
continuous-integration/drone/push Build is passing Details
also slight refactors :)

closes #96

Co-authored-by: Sam Therapy <sam@samtherapy.net>
Reviewed-on: #98
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-16 23:26:10 +00:00
Sam Therapy ddd0277de9 [SKIP CI] ci: add caching (#99)
Reviewed-on: #99
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-16 23:25:56 +00:00
Renovate Bot 55b965d084 fix(deps): update golang.org/x/sys digest to 7b5979e
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-15 21:00:17 +00:00
Sam Therapy 9746ae0a6f feat: more API work
continuous-integration/drone/push Build was killed Details
Reviewed-on: #94
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-15 11:02:43 +00:00
Renovate Bot 0d011bb097 fix(deps): update golang.org/x/sys digest to 63ea559
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-13 18:00:18 +00:00
Sam Therapy 6fa6b2d1f6 feat: Allow opt pseudosection to be printed (#91)
continuous-integration/drone/push Build is passing Details
...when not using the standard print
(JSON/XML/YAML)

This should make making an API for this even easier :)

Reviewed-on: #91
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-10 18:41:25 +00:00
Renovate Bot 4f743f861d fix(deps): update golang.org/x/sys digest to aba9fc2
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-10 00:00:32 +00:00
Renovate Bot 90d2fed6ab fix(deps): update golang.org/x/net digest to bea034e
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-09 17:00:16 +00:00
Sam Therapy c8282e8030 fix: make retries actually work properly (#88)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #88
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-09 12:59:49 +00:00
Sam Therapy 1d0ccbef44 [SKIP CI] chore: update goreleaser syntax (#86)
Reviewed-on: #86
2022-09-08 23:51:30 +00:00
Sam Therapy ae7209c334 ci: reduce fuzz count
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-09-08 23:44:12 +00:00
Sam Therapy dd2a7122c2 ci: enable missing tests
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-09-08 23:44:12 +00:00
Renovate Bot 48b0ba8f63 fix(deps): update golang.org/x/sys digest to 2771309 (#84)
continuous-integration/drone/push Build is passing Details
Co-authored-by: Renovate Bot <renovate-bot@noreply.git.froth.zone>
Co-committed-by: Renovate Bot <renovate-bot@noreply.git.froth.zone>
2022-09-08 23:23:15 +00:00
Renovate Bot 062008b4dc fix(deps): update golang.org/x/net digest to 1e95f45
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-07 14:00:15 +00:00
Renovate Bot 88d090c04a fix(deps): update golang.org/x/sys digest to 87db552
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-07 07:00:15 +00:00
Renovate Bot 74a7ba3c32 fix(deps): update golang.org/x/sys digest to d0df966
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-06 18:00:27 +00:00
Renovate Bot f83453c1ee fix(deps): update golang.org/x/net digest to f3363e0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-09-06 17:00:15 +00:00
Sam Therapy 789710cbeb
[SKIP CI] Update man
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-09-05 17:27:37 +02:00
Sam Therapy 7edd983175 feat: add preliminary message tinkering (#79)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #79
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-09-05 00:05:06 +00:00
Sam Therapy 068706ae9a (feat)Completions and documentation (#78)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #78
2022-09-04 23:28:47 +00:00
Sam Therapy 59a7fe6d7d Modularity(?)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #77
2022-08-31 01:05:17 +00:00
Renovate Bot 61ddbb3693 fix(deps): update golang.org/x/sys digest to d48e67d
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-29 21:00:15 +00:00
Renovate Bot c98be03879 fix(deps): update module github.com/ameshkov/dnscrypt/v2 to v2.2.5
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-29 08:00:17 +00:00
Renovate Bot 2824ce18e1 fix(deps): update module github.com/lucas-clemente/quic-go to v0.29.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-27 12:00:17 +00:00
Renovate Bot 8cf65cf4b7 fix(deps): update golang.org/x/net digest to 83b083e
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-26 16:00:16 +00:00
Renovate Bot a090b30071 fix(deps): update golang.org/x/sys digest to c680a09
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-25 21:00:14 +00:00
Renovate Bot 29bac7ad6b fix(deps): update golang.org/x/sys digest to 20c2bfd
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-23 23:00:15 +00:00
Renovate Bot 8645e9bf46 fix(deps): update golang.org/x/net digest to b0a4917
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-23 00:00:23 +00:00
Renovate Bot db683ca203 fix(deps): update golang.org/x/sys digest to 2296e01
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-18 17:00:13 +00:00
Renovate Bot d051b74c49 fix(deps): update golang.org/x/sys digest to 5a39038
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2022-08-17 08:00:21 +00:00
Renovate Bot fd052f1c6c fix(deps): update golang.org/x/net digest to 3211cb9
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-12 18:00:15 +00:00
Renovate Bot 1743dc564d fix(deps): update golang.org/x/net digest to 13a9a73
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-11 19:00:27 +00:00
Renovate Bot 486961fcbe fix(deps): update golang.org/x/sys digest to fbc7d0a
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-11 18:00:16 +00:00
Sam Therapy bdaefe815d
change spell
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-08-11 19:17:51 +02:00
Sam Therapy 3540770b3d
tinker with GHA more
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-08-11 16:12:25 +02:00
Sam Therapy 3dc4115350
add ,
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-08-11 14:04:22 +02:00
Sam Therapy 0a9e76e6bf
hehe
continuous-integration/drone/push Build is passing Details
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-08-11 14:02:18 +02:00
Renovate Bot 0ce11b36c0 chore(deps): update actions/checkout action to v3
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-11 09:00:21 +00:00
Renovate Bot a77009e32d fix(deps): update golang.org/x/net digest to 07c6da5
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-11 08:00:19 +00:00
Sam Therapy 4cf19ebf78 Another "minor refactor" (#61)
continuous-integration/drone/push Build is passing Details
I need to make fewer of these :)
Reviewed-on: #61
2022-08-11 07:25:36 +00:00
Renovate Bot c70ae88a38 fix(deps): update golang.org/x/sys digest to 1c4a2a7
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-08 16:03:36 +00:00
Renovate Bot 80475e6c3d fix(deps): update golang.org/x/net digest to a33c5aa
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-05 02:00:19 +00:00
Renovate Bot 547383d842 fix(deps): update golang.org/x/sys digest to 8e32c04
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-04 22:00:22 +00:00
Sam Therapy 07728cffdb (feat)EDNS (#55)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #55
2022-08-04 01:09:49 +00:00
Renovate Bot b7a563a989 fix(deps): update golang.org/x/sys digest to 6e608f9
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-03 20:00:22 +00:00
Renovate Bot 5d9d2af959 fix(deps): update golang.org/x/net digest to 0bcc04d
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-02 23:00:19 +00:00
Renovate Bot 2ccfea5de5 fix(deps): update golang.org/x/sys digest to a90be44
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-07-31 18:00:22 +00:00
Renovate Bot abccb5b5cc fix(deps): update golang.org/x/sys digest to 1609e55
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-07-30 11:00:17 +00:00
Renovate Bot 24c8294c36 fix(deps): update golang.org/x/net digest to c7608f3
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-07-28 22:00:17 +00:00
Renovate Bot 7eaba30ca3 fix(deps): update golang.org/x/net digest to f92ba40
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-07-28 19:00:18 +00:00
Renovate Bot 6147e39f7a fix(deps): update golang.org/x/net digest to 1f511ac
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-07-28 16:00:17 +00:00
Renovate Bot b4b2cc4834 fix(deps): update golang.org/x/net digest to 41545e8
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-07-28 04:00:17 +00:00
Renovate Bot 2d7acad6c6 fix(deps): update golang.org/x/net digest to 993b7b1
continuous-integration/drone/push Build is passing Details
2022-07-28 03:00:18 +00:00
Renovate Bot 54f1e31d8a fix(deps): update golang.org/x/sys digest to 3c1f352
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-07-28 01:00:23 +00:00
Renovate Bot d773a86c0e fix(deps): update golang.org/x/sys digest to e65921a
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-07-27 06:00:23 +00:00
Renovate Bot 5989a678e4 fix(deps): update golang.org/x/net digest to 0699458
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-07-27 00:00:23 +00:00
110 changed files with 5509 additions and 2665 deletions

View File

@ -1,81 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
local testing(version, arch) = {
kind: "pipeline",
name: version + "-" + arch ,
platform: {
arch: arch
},
steps: [
{
name: "submodules",
image: "alpine/git",
commands: [
"git submodule update --init --recursive"
]
},
{
name: "lint",
image: "rancher/drone-golangci-lint:latest"
},
{
name: "test",
image: "golang:" + version,
commands: [
"go test -race ./... -cover"
]
},
],
trigger: {
event: {
exclude: "tag",
}
},
};
// "Inspired by" https://goreleaser.com/ci/drone/
local release() = {
kind: "pipeline",
name: "release",
trigger: {
event: "tag"
},
steps: [
{
name: "fetch",
image: "docker:git",
commands : [
"git fetch --tags",
"git submodule update --init --recursive"
]
},
{
name: "test",
image: "golang",
commands: [
"go test -race ./... -cover"
]
},
{
name: "release",
image: "goreleaser/goreleaser",
environment: {
"GITEA_TOKEN": {
from_secret: "GITEA_TOKEN"
}
},
commands: [
"goreleaser release"
],
// when: {
// event: "tag"
// }
}
]
};
[
testing("1.18", "amd64"),
testing("1.18", "arm64"),
release()
]

10
.editorconfig Normal file
View File

@ -0,0 +1,10 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

View File

@ -0,0 +1,35 @@
name: Forgejo Release
on:
push:
tags:
- "*"
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: stable
- name: Install scdoc
run: apt-get update && apt-get install -y scdoc
- name: Release with GoReleaser
uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser
version: latest
args: release --clean --skip docker,snapcraft
env:
GORELEASER_FORCE_TOKEN: gitea
GITEA_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
UPLOAD_PACKAGES_SECRET: ${{ secrets.PUBLISH_TOKEN }}

View File

@ -0,0 +1,14 @@
name: Mirror Push
on: push
jobs:
mirror:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pixta-dev/repository-mirroring-action@v1
with:
target_repo_url: git@git.sr.ht:~sammefishe/awl
ssh_private_key: ${{ secrets.SRHT_SSH_KEY }}

View File

@ -0,0 +1,24 @@
name: Test
on: push
jobs:
test:
strategy:
fail-fast: true
matrix:
goVer: ["oldstable", "stable"]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.goVer }}
- name: Test
run: make test-ci

30
.github/ISSUE_TEMPLATE/bug.md vendored Normal file
View File

@ -0,0 +1,30 @@
---
name: Bug report
about: Report a bug
---
**Describe the bug**
A clear and concise description of what the bug is.
**Reproduction steps**
Steps to reproduce the behavior:
1. 1
2. 2
3. Bug
**Expected behaviour**
A clear and concise description of what you expected to happen.
**Screenshots / Logs**
```
Add `-v=4` and add the debug logs to the report here:
```
**System information (please complete the following information):**
- OS: [e.g. Ubuntu 22.04, OpenBSD, Windows 11]
- Version: [run `awl -V` and print the output]
**Additional context**
Add any other context about the problem here.

17
.github/ISSUE_TEMPLATE/feature.md vendored Normal file
View File

@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest a feature
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
Links to implementations in dig, drill, etc. should go here.
**Additional context**
Add any other context or screenshots about the feature request here.

9
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,9 @@
<!--
Please check the following:
1. Make sure you are targeting the `master` branch.
2. Make sure that you test and format your contributions: `make full_test && make lint`
3. Describe what your pull request does and which issue you're targeting (if any)
-->

56
.github/workflows/ghrelease.yaml vendored Normal file
View File

@ -0,0 +1,56 @@
name: GitHub Release
on:
push:
tags:
- "*"
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
release:
runs-on: ubuntu-latest
env:
SNAPCRAFT_STORE_CREDENTIALS : ${{ secrets.SNAPCRAFT_TOKEN }}
steps:
# Workaround a dumb docker problem where everything has to be lowercase
- id: lowercase
run: |
echo IMAGE_NAME=$(echo $IMAGE_NAME | tr '[:upper:]' '[:lower:]') >> "${GITHUB_ENV}"
- name: Login to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: Install Snapcraft
uses: samuelmeuli/action-snapcraft@v2
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable
- name: Install scdoc
run: sudo apt-get install -y scdoc
- name: Workaround a dumb Snap bug
run: mkdir -p $HOME/.cache/snapcraft/download && mkdir -p $HOME/.cache/snapcraft/stage-packages
- name: Release with GoReleaser
uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser
version: latest
args: release --clean --skip=aur,homebrew,nix,scoop
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

24
.github/workflows/test.yaml vendored Normal file
View File

@ -0,0 +1,24 @@
name: Test
on: push
jobs:
test:
strategy:
fail-fast: true
matrix:
platform: [macos, windows]
goVer: ["oldstable", "stable"]
runs-on: ${{ matrix.platform }}-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.goVer }}
- name: Test
run: make test-ci

52
.gitignore vendored
View File

@ -1,23 +1,29 @@
# 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
dist/
# Test coverage
coverage/*
!coverage/.gitkeep
# 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
dist/
# Test coverage
coverage/*
!coverage/.gitkeep
awl
docs/awl.1
docs/awl.1.gz
.dccache

4
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "doc/wiki"]
path = doc/wiki
[submodule "docs/wiki"]
path = docs/wiki
url = ../awl.wiki

88
.golangci.yaml Normal file
View File

@ -0,0 +1,88 @@
# Refer to golangci-lint's example config file for more options and information:
# https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml
run:
timeout: 5m
modules-download-mode: readonly
skip-dirs:
- "coverage"
- ".github"
linters:
enable:
- errcheck
- errorlint
- gci
- gocritic
- goconst
- godot
- goimports
- govet
- gocritic
- goerr113
- gofmt
- gofumpt
- gosec
- maintidx
- makezero
- misspell
- nlreturn
- nolintlint
- prealloc
- predeclared
- revive
- staticcheck
- tagliatelle
- whitespace
- wrapcheck
- wsl
disable:
- structcheck
linters-settings:
govet:
check-shadowing: true
enable-all: true
disable-all: false
revive:
ignore-generated-header: false
severity: warning
confidence: 0.8
errorCode: 1
warningCode: 1
rules:
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: duplicated-imports
- name: error-return
- name: error-strings
- name: error-naming
- name: errorf
- name: exported
- name: if-return
- name: increment-decrement
- name: modifies-value-receiver
- name: package-comments
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: var-declaration
- name: var-naming
linters-settings:
tagliatelle:
case:
use-field-name: false
rules:
# Any struct tag type can be used.
# Support string case: `camel`, `pascal`, `kebab`, `snake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower`
json: goCamel
yaml: goCamel
xml: goCamel
issues:
exclude-use-default: false
max-issues-per-linter: 0
max-same-issues: 0

View File

@ -2,40 +2,235 @@
# Make sure to check the documentation at https://goreleaser.com
before:
hooks:
# You may remove this if you don't use go modules.
- make clean
- go mod tidy
# you may remove this if you don't need go generate
# - go generate ./...
# Make manpages
- docs/makeman.sh
# Vendor dependencies
- go mod vendor
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
targets:
- go_first_class
- plan9_amd64
- freebsd_amd64
universal_binaries:
- replace: true
- replace: true
archives:
- replacements:
darwin: macOS
linux: Linux
windows: Windows
amd64: x86_64
- files:
- LICENSE
- completions/**
- docs/awl.1.gz
name_template: >-
{{ .ProjectName }}_
{{- if eq .Os "darwin" }}MacOS_
{{- else if eq .Os "freebsd" }}FreeBSD_
{{- else }}{{- title .Os }}_{{ end }}
{{- if eq .Arch "386" }}i386
{{- else if eq .Arch "mips64" }}mips64_hardfloat
{{- else if eq .Arch "mips64le" }}mips64le_hardfloat
{{- else }}{{ .Arch }}{{ end -}}
format_overrides:
- goos: windows
format: zip
- files:
- vendor/**
id: vendor
format: tar.xz
name_template: "{{ .ProjectName }}-{{ .Version }}-deps"
meta: true
wrap_in_directory: "{{ .ProjectName }}"
nfpms:
- id: packages
package_name: awl-dns
vendor: Sam Therapy <sam@samtherapy.net>
maintainer: Sam Therapy <sam@samtherapy.net>
homepage: https://dns.froth.zone/awl
description: |-
Command-line DNS query tool.
Awl supports DNS-over-[UDP,TCP,HTTPS,QUIC] and DNSCrypt.
license: BSD-3-Clause
section: utils
bindir: /usr/bin
formats:
- apk
- archlinux
- deb
- rpm
contents:
- src: completions/bash.bash
dst: /usr/share/bash-completion/completions/awl
- src: docs/awl.1.gz
dst: /usr/share/man/man1/awl.1.gz
- src: LICENSE
dst: /usr/share/docs/awl/copyright
- src: completions/fish.fish
dst: /usr/share/fish/vendor_completions.d/awl.fish
# DEB only
- src: completions/zsh.zsh
dst: /usr/share/zsh/vendor-completions/_awl
packager: deb
# Alpine .apk only
- src: completions/zsh.zsh
dst: /usr/share/zsh/site-functions/_awl
packager: apk
# RPM only
- src: completions/zsh.zsh
dst: /usr/share/zsh/site-functions/_awl
packager: rpm
deb:
lintian_overrides:
- statically-linked-binary
- changelog-file-missing-in-native-package
overrides:
deb:
file_name_template: >-
{{- .PackageName }}_
{{- .Version }}_
{{- if eq .Arch "386" }}i386
{{- else if eq .Arch "arm" }}armel
{{- else }}{{ .Arch }}{{ end -}}
rpm:
file_name_template: >-
{{- .PackageName }}-
{{- .Version }}-
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i686
{{- else if eq .Arch "arm" }}armhfp
{{- else if eq .Arch "arm64" }}aarch64
{{- else }}{{ .Arch }}{{ end -}}
- id: termux
package_name: awl-dns
vendor: Sam Therapy <sam@samtherapy.net>
maintainer: Sam Therapy <sam@samtherapy.net>
homepage: https://dns.froth.zone/awl
description: |-
Command-line DNS query tool.
Awl supports DNS-over-[UDP,TCP,HTTPS,QUIC] and DNSCrypt.
license: BSD-3-Clause
section: utils
formats:
- termux.deb
file_name_template: >-
{{- .PackageName }}_
{{- .Version }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i686
{{- else if eq .Arch "arm" }}arm
{{- else if eq .Arch "arm64" }}aarch64
{{- else }}{{ .Arch }}{{ end -}}
snapcrafts:
-
name: awl-dns
grade: stable
publish: true
summary: A command-line DNS query tool
description: |-
Awl is a command-line DNS query tool.
Awl supports DNS-over-[UDP,TCP,HTTPS,QUIC] and DNSCrypt.
confinement: strict
license: BSD-3-Clause
base: bare
apps:
awl-dns:
command: awl
plugs:
- network
completer: completions/bash.bash
dockers:
-
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}:latest"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}:{{ .Tag }}"
checksum:
name_template: 'checksums.txt'
name_template: "checksums.txt"
snapshot:
name_template: "{{ incpatch .Version }}-next"
brews:
- repository:
owner: packaging
name: homebrew
homepage: https://dns.froth.zone/awl
description: A DNS query tool
license: BSD-3-Clause
# custom_block: |
# head "https://git.froth.zone/sam/awl.git"
install: |-
bin.install "awl"
bash_completion.install "completions/bash.bash" => "awl"
zsh_completion.install "completions/zsh.zsh" => "_awl"
fish_completion.install "completions/fish.fish" => "awl.fish"
man1.install "docs/awl.1.gz"
nix:
- repository:
owner: packaging
name: nur
homepage: https://dns.froth.zone/awl
description: A DNS query client
license: bsd3
extra_install: |-
installManPage ./docs/awl.1.gz
installShellCompletion ./completions/*
scoops:
- repository:
owner: packaging
name: scoop
folder: bucket
homepage: https://dns.froth.zone/awl
description: A DNS query client
license: BSD-3-Clause
changelog:
sort: asc
groups:
- title: "Dependency Updates"
regexp: "^.*fix\\(deps\\)*:+.*$"
order: 2
- title: "Features"
regexp: "^.*feat[(\\w)]*:+.*$"
order: 0
- title: "Bug fixes"
regexp: "^.*fix[(\\w)]*:+.*$"
order: 1
- title: "Other"
order: 999
filters:
exclude:
- '^docs:'
- '^test:'
- "^test:"
- "^docs?:"
- "typo"
- "^ci:"
uploads:
- name: packages
method: PUT
mode: archive
exts:
- deb
- rpm
- apk
- termux.deb
username: sam
target: >-
https://git.froth.zone/api/packages/sam/
{{- if eq .ArtifactExt "deb" }}debian/pool/sid/main/upload
{{- else if eq .ArtifactExt "termux.deb" }}debian/pool/termux/main/upload
{{- else if eq .ArtifactExt "rpm" }}rpm/upload
{{- else if eq .ArtifactExt "apk" }}alpine/edge/main{{ end -}}
custom_artifact_name: true # Truncate the artifact name from the upload URL
gitea_urls:
api: https://git.froth.zone/api/v1/
api: https://git.froth.zone/api/v1
download: https://git.froth.zone

3
Dockerfile Normal file
View File

@ -0,0 +1,3 @@
FROM scratch
ENTRYPOINT ["/awl"]
COPY awl /

View File

@ -1,4 +1,5 @@
# SPDX-License-Identifier: BSD-3-Clause
# GNU Makefile allowing for building on Windows (with GNU Make)
include template.mk
@ -6,19 +7,24 @@ ifeq ($(OS),Windows_NT)
EXE := $(PROG).exe
else
EXE := $(PROG)
ifeq ($(shell uname), Darwin)
INSTALLFLAGS :=
else
INSTALLFLAGS := D
endif
endif
$(PROG):
$(GO) build -o $(EXE) $(GOFLAGS) .
## install: installs awl
install: all
.PHONY: install
ifeq ($(OS),Windows_NT)
install:
$(GO) install $(GOFLAGS) .
else
install -m755 $(PROG) $(PREFIX)/$(BIN)
install -m644 doc/$(PROG).1 $(MAN)/man1
install: all
install -$(INSTALLFLAGS)m755 $(PROG) $(DESTDIR)$(PREFIX)/$(BIN)/$(PROG)
install -$(INSTALLFLAGS)m644 docs/$(PROG).1 $(DESTDIR)$(MAN)/man1/$(PROG).1
# completions need to go in one specific place :)
install -$(INSTALLFLAGS)m644 completions/bash.bash $(DESTDIR)$(PREFIX)/$(SHARE)/bash-completion/completions/$(PROG)
install -$(INSTALLFLAGS)m644 completions/fish.fish $(DESTDIR)$(PREFIX)/$(SHARE)/fish/vendor_completions.d/$(PROG).fish
install -$(INSTALLFLAGS)m644 completions/zsh.zsh $(DESTDIR)$(PREFIX)/$(SHARE)/zsh/site-functions/_$(PROG)
endif
.PHONY: install

20
LICENSE
View File

@ -1,11 +1,11 @@
Copyright 2022 Sam Therapy, Gregward Bulon
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
Copyright 2022 Sam Therapy, Gregward Bulon
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -3,12 +3,14 @@
include template.mk
$(PROG):
$(GO) build -o $(PROG) $(GOFLAGS) .
EXE := $(PROG)
## install: installs awl
.PHONY: install
install: all
install -m755 $(PROG) $(PREFIX)/$(BIN)
install -m644 doc/$(PROG).1 $(MAN)/man1
.PHONY: install
install -Dm755 $(PROG) $(DESTDIR)$(PREFIX)/$(BIN)/$(PROG)
install -Dm644 docs/$(PROG).1 $(DESTDIR)$(MAN)/man1/$(PROG).1
# completions need to go in one specific place :)
install -Dm644 completions/bash.bash $(DESTDIR)$(PREFIX)$(SHARE)/bash-completion/completions/$(PROG)
install -Dm644 completions/fish.fish $(DESTDIR)$(PREFIX)$(SHARE)/fish/vendor_completions.d/$(PROG).fish
install -Dm644 completions/zsh.zsh $(DESTDIR)$(PREFIX)$(SHARE)/zsh/site-functions/_$(PROG)

217
README.md
View File

@ -1,66 +1,195 @@
# awl
<!-- markdownlint-disable MD033 -->
# <img src="./docs/img/awl-text.png" width="50%" title="awl logo" alt="awl">
[![Build Status](https://ci.git.froth.zone/api/badges/sam/awl/status.svg)](https://ci.git.froth.zone/sam/awl)
> awl *(noun)*: A pointed tool for making small holes in wood or leather
`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).
A command-line DNS lookup tool that supports DNS queries over UDP, TCP, TLS, HTTPS, DNSCrypt, and QUIC.
`awl` is designed to be a drop-in replacement for the venerable dig, but support
newer RFC query types, such as DNS-over-HTTPS and DNS-over-QUIC.
## Usage
- [Feature wiki](https://git.froth.zone/sam/awl/wiki/Supported)
- [Manpage](https://git.froth.zone/sam/awl/wiki/awl.1)
[![Gitea Release](https://img.shields.io/gitea/v/release/sam/awl?gitea_url=https%3A%2F%2Fgit.froth.zone&display_name=release&style=for-the-badge)](https://git.froth.zone/sam/awl)
[![Last Commit](https://img.shields.io/gitea/last-commit/sam/awl?gitea_url=https%3A%2F%2Fgit.froth.zone&style=for-the-badge)](https://git.froth.zone/sam/awl/commits/branch/master)
[![License](https://img.shields.io/github/license/samtherapy/awl?style=for-the-badge)](https://spdx.org/licenses/BSD-3-Clause.html)
[![Go Report](https://goreportcard.com/badge/dns.froth.zone/awl?style=for-the-badge)](https://goreportcard.com/report/dns.froth.zone/awl)
## Building and installing
Awl is designed to be a drop-in replacement for [dig](https://bind9.readthedocs.io/en/v9_18_3/manpages.html#dig-dns-lookup-utility).
### From releases
## Examples
Grab a prebuilt binary from the
[release](https://git.froth.zone/sam/awl/releases) section.
```shell
# Query a domain over UDP
awl example.com
### From source
# Query a domain over HTTPS, print only the results
awl example.com +https --short
Dependencies:
- Go >= 1.18
- GNU/BSD make or Plan 9 mk
- [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (optional, for manpage)
Make sure to recursively clone the repo:
```sh
git clone --recursive https://git.froth.zone/sam/awl
# Query a domain over TLS, print as JSON
awl example.com +tls +json
```
Using the makefile:
For more and the usage, see the [manpage](https://git.froth.zone/sam/awl/wiki/awl.1).
```sh
make
sudo make install
## Installing
On any platform, with [Go](https://go.dev) installed, run the following command to install:
```shell
go install dns.froth.zone/awl@latest
```
Alternatively, using `go install`:
### Packaging
```sh
go install git.froth.zone/sam/awl@latest
Alternatively, many package managers are supported:
<details>
<summary>Linux</summary>
#### Distro-specific
<details>
<summary>Alpine Linux</summary>
Provided by [Gitea packages](https://git.froth.zone/sam/-/packages/alpine/awl-dns) \
***Any distro that uses apk should also work***
```shell
# Add the repository
echo "https://git.froth.zone/api/packages/sam/alpine/edge/main" | tee -a /etc/apk/repositories
# Get the signing key
curl -JO https://git.froth.zone/api/packages/sam/alpine/key --output-dir /etc/apk/keys
# Install
apk add awl-dns
```
</details>
<details>
<summary>Arch</summary>
AUR package available as [awl-dns-git](https://aur.archlinux.org/packages/awl-dns-git/)
```shell
yay -S awl-dns-git ||
paru -S awl-dns-git
```
</details>
<details>
<summary>Debian / Ubuntu</summary>
Provided by [Gitea packages](https://git.froth.zone/sam/-/packages/debian/awl-dns/) \
***Any distro that uses deb/dpkg should also work***
```shell
# Add PGP key
sudo curl https://git.froth.zone/api/packages/sam/debian/repository.key -o /usr/share/keyrings/git-froth-zone-sam.asc
# Add repo
echo "deb [signed-by=/usr/share/keyrings/git-froth-zone-sam.asc] https://git.froth.zone/api/packages/sam/debian sid main" | sudo tee /etc/apt/sources.list.d/git-froth-zone-sam.list
# Update and install
sudo apt update
sudo apt install awl-dns
```
</details>
<details>
<summary>Fedora / RHEL / SUSE</summary>
Provided by [Gitea packages](https://git.froth.zone/sam/-/packages/rpm/awl-dns/) \
***Any distro that uses rpm/dnf might also work, I've never tried it***
```shell
# Add the repository
dnf config-manager --add-repo https://git.froth.zone/api/packages/sam/rpm.repo ||
zypper addrepo https://git.froth.zone/api/packages/sam/rpm.repo
# Install
dnf install awl-dns ||
zypper install awl-dns
```
</details>
<details>
<summary>Gentoo</summary>
```shell
# Add the ebuild repository
eselect repository add froth-zone git https://git.froth.zone/packaging/portage.git
emaint sync -r froth-zone
# Install
emerge -av net-dns/awl
```
</details>
#### Distro-agnostic
<details>
<summary><a href="https://brew.sh" nofollow>Homebrew</a></summary>
```shell
brew install SamTherapy/tap/awl
```
</details>
<details>
<summary>Snap</summary>
Snap package available as [awl-dns](https://snapcraft.io/awl-dns)
```shell
snap install awl-dns ||
sudo snap install awl-dns
```
</details>
</details>
<hr />
<details>
<summary>macOS</summary>
<details open>
<summary><a href="https://brew.sh" nofollow>Homebrew</a></summary>
```shell
brew install SamTherapy/tap/awl
```
</details>
</details>
<hr />
<details>
<summary>Windows</summary>
<details open>
<summary><a href="https://scoop.sh" nofollow>Scoop</a></summary>
```pwsh
scoop bucket add froth https://git.froth.zone/packages/scoop.git
scoop install awl
```
</details>
</details>
## Contributing
Send a [pull request](https://git.froth.zone/sam/awl/pulls) our way. Prefer
emails? Send a patch to the
[mailing list](https://lists.sr.ht/~sammefishe/awl-dev).
Please see the [CONTRIBUTING.md](./docs/CONTRIBUTING.md) file for more information.
Found a bug or want a new feature? Create an issue
[here](https://git.froth.zone/sam/awl/issues).
TL;DR: If you like the project, spread the word! If you want to contribute, [use the issue tracker](https://git.froth.zone/sam/awl/issues) or [open a pull request](https://git.froth.zone/sam/awl/pulls).
Want to use email instead? Use our [mailing list](https://lists.sr.ht/~sammefishe/awl-devel)!
### License
### Mirrors
See [LICENSE](./LICENSE)
The canonical repository is located on [my personal Forgejo instance](https://git.froth.zone/sam/awl). \
Official mirrors are located on [GitHub](https://github.com/SamTherapy/awl) and [SourceHut](https://git.sr.ht/~sammefishe/awl/).
Contributions are accepted on all mirrors, but the Forgejo instance is preferred.
## License
[BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html)
### Credits
- Awl image taken from [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Awl.tif), imaged is licensed CC0.

View File

@ -1,170 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package cli
import (
"fmt"
"os"
"runtime"
"strings"
"time"
"git.froth.zone/sam/awl/internal/helpers"
"git.froth.zone/sam/awl/util"
"github.com/miekg/dns"
flag "github.com/stefansundin/go-zflag"
)
// Parse the arguments passed into awl.
func ParseCLI(version string) (Options, error) {
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
flag.Usage = func() {
fmt.Println(`awl - drill, writ small
Usage: awl name [@server] [record]
<name> domain, IP address, phone number
<record> defaults to A
Arguments may be in any order, including flags.
Dig-like +[no]commands are also supported, see dig(1) or dig -h
Options:`)
flag.PrintDefaults()
}
// CLI flag
var (
port = flag.Int("port", 0, "`port` to make DNS query (default: 53 for UDP/TCP, 853 for TLS/QUIC)", flag.OptShorthand('p'), flag.OptDisablePrintDefault(true))
query = flag.String("query", "", "domain name to `query` (default: .)", flag.OptShorthand('q'))
class = flag.String("class", "IN", "DNS `class` to query", flag.OptShorthand('c'))
qType = flag.String("qType", "", "`type` to query (default: A)", flag.OptShorthand('t'))
ipv4 = flag.Bool("4", false, "force IPv4", flag.OptShorthandStr("4"))
ipv6 = flag.Bool("6", false, "force IPv6", flag.OptShorthand('6'))
reverse = flag.Bool("reverse", false, "do a reverse lookup", flag.OptShorthand('x'))
timeout = flag.Float32("timeout", 1, "Timeout, in `seconds`")
retry = flag.Int("retries", 2, "number of `times` to retry")
dnssec = flag.Bool("dnssec", false, "enable DNSSEC", flag.OptShorthand('D'))
truncate = flag.Bool("no-truncate", false, "ignore truncation if a UDP request truncates (default= retry with TCP)")
tcp = flag.Bool("tcp", false, "use TCP")
dnscrypt = flag.Bool("dnscrypt", false, "use DNSCrypt")
tls = flag.Bool("tls", false, "use DNS-over-TLS", flag.OptShorthand('T'))
https = flag.Bool("https", false, "use DNS-over-HTTPS", flag.OptShorthand('H'))
quic = flag.Bool("quic", false, "use DNS-over-QUIC", flag.OptShorthand('Q'))
aa = flag.Bool("aa", false, "set/unset AA (Authoratative Answer) flag (default: not set)")
ad = flag.Bool("ad", false, "set/unset AD (Authenticated Data) flag (default: not set)")
cd = flag.Bool("cd", false, "set/unset CD (Checking Disabled) flag (default: not set)")
qr = flag.Bool("qr", false, "set/unset QR (QueRy) flag (default: not set)")
rd = flag.Bool("rd", true, "set/unset RD (Recursion Desired) flag (default: set)", flag.OptDisablePrintDefault(true))
ra = flag.Bool("ra", false, "set/unset RA (Recursion Available) flag (default: not set)")
tc = flag.Bool("tc", false, "set/unset TC (TrunCated) flag (default: not set)")
z = flag.Bool("z", false, "set/unset Z (Zero) flag (default: not set)", flag.OptShorthand('z'))
short = flag.Bool("short", false, "print just the results, equivalent to dig +short", flag.OptShorthand('s'))
json = flag.Bool("json", false, "print the result(s) as JSON", flag.OptShorthand('j'))
xml = flag.Bool("xml", false, "print the result(s) as XML", flag.OptShorthand('X'))
yaml = flag.Bool("yaml", false, "print the result(s) as yaml", flag.OptShorthand('y'))
noQ = flag.Bool("no-question", false, "disable printing the question section")
noAns = flag.Bool("no-answer", false, "disable printing the answer section")
noAuth = flag.Bool("no-authority", false, "disable printing the authority section")
noAdd = flag.Bool("no-additional", false, "disable printing the additonal section")
noStats = flag.Bool("no-statistics", false, "disable printing the statistics section")
verbosity = flag.Int("verbosity", 0, "sets verbosity `level`", flag.OptShorthand('v'), flag.OptNoOptDefVal("2"))
versionFlag = flag.Bool("version", false, "print version information", flag.OptShorthand('V'))
)
// Don't sort the flags when -h is given
flag.CommandLine.SortFlags = false
// Parse the flags
err := flag.CommandLine.Parse(os.Args[1:])
if err != nil {
return Options{Logger: util.InitLogger(*verbosity)}, err
}
opts := Options{
Logger: util.InitLogger(*verbosity),
Port: *port,
IPv4: *ipv4,
IPv6: *ipv6,
DNSSEC: *dnssec,
Short: *short,
TCP: *tcp,
DNSCrypt: *dnscrypt,
TLS: *tls,
HTTPS: *https,
QUIC: *quic,
Truncate: *truncate,
AA: *aa,
AD: *ad,
TC: *tc,
Z: *z,
CD: *cd,
QR: *qr,
RD: *rd,
RA: *ra,
Reverse: *reverse,
JSON: *json,
XML: *xml,
YAML: *yaml,
Request: helpers.Request{
Type: dns.StringToType[strings.ToUpper(*qType)],
Class: dns.StringToClass[strings.ToUpper(*class)],
Name: *query,
Timeout: time.Duration(*timeout * float32(time.Second)),
Retries: *retry,
},
Display: Displays{
Question: !*noQ,
Answer: !*noAns,
Authority: !*noAuth,
Additional: !*noAdd,
Statistics: !*noStats,
},
}
opts.Logger.Info("POSIX flags parsed")
opts.Logger.Debug(fmt.Sprintf("%+v", opts))
if *versionFlag {
fmt.Printf("awl version %s, built with %s\n", version, runtime.Version())
return opts, ErrNotError
}
// Parse all the arguments that don't start with - or --
// This includes the dig-style (+) options
err = ParseMiscArgs(flag.Args(), &opts)
if err != nil {
opts.Logger.Warn(err)
return opts, err
}
opts.Logger.Info("Dig/Drill flags parsed")
opts.Logger.Debug(fmt.Sprintf("%+v", opts))
if opts.Port == 0 {
if opts.TLS || opts.QUIC {
opts.Port = 853
} else {
opts.Port = 53
}
}
opts.Logger.Info("Port set to", opts.Port)
// Set timeout to 0.5 seconds if set below 0.5
if opts.Request.Timeout < (time.Second / 2) {
opts.Request.Timeout = (time.Second / 2)
}
if opts.Request.Retries < 0 {
opts.Request.Retries = 0
}
return opts, nil
}

View File

@ -1,99 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package cli_test
import (
"os"
"testing"
"time"
"git.froth.zone/sam/awl/cli"
"gotest.tools/v3/assert"
)
func TestEmpty(t *testing.T) {
old := os.Args
os.Args = []string{"awl", "-4"}
opts, err := cli.ParseCLI("TEST")
assert.NilError(t, err)
assert.Assert(t, (opts.Port == 53))
assert.Assert(t, opts.IPv4)
os.Args = old
}
func TestTLSPort(t *testing.T) {
old := os.Args
os.Args = []string{"awl", "-T"}
opts, err := cli.ParseCLI("TEST")
assert.NilError(t, err)
assert.Assert(t, (opts.Port == 853))
os.Args = old
}
func TestInvalidFlag(t *testing.T) {
old := os.Args
os.Args = []string{"awl", "--treebug"}
_, err := cli.ParseCLI("TEST")
assert.ErrorContains(t, err, "unknown flag")
os.Args = old
}
func TestInvalidDig(t *testing.T) {
old := os.Args
os.Args = []string{"awl", "+a"}
_, err := cli.ParseCLI("TEST")
assert.ErrorContains(t, err, "dig: unknown flag")
os.Args = old
}
func TestVersion(t *testing.T) {
old := os.Args
os.Args = []string{"awl", "--version"}
_, err := cli.ParseCLI("TEST")
assert.ErrorType(t, err, cli.ErrNotError)
os.Args = old
}
func TestTimeout(t *testing.T) {
args := [][]string{
{"awl", "+timeout=0"},
{"awl", "--timeout", "0"},
}
for _, test := range args {
old := os.Args
os.Args = test
opt, err := cli.ParseCLI("TEST")
assert.NilError(t, err)
assert.Equal(t, opt.Request.Timeout, time.Second/2)
os.Args = old
}
}
func TestRetries(t *testing.T) {
args := [][]string{
{"awl", "+retry=-2"},
{"awl", "+tries=-2"},
{"awl", "--retries", "-2"},
}
for _, test := range args {
old := os.Args
os.Args = test
opt, err := cli.ParseCLI("TEST")
assert.NilError(t, err)
assert.Equal(t, opt.Request.Retries, 0)
os.Args = old
}
}
func FuzzFlags(f *testing.F) {
testcases := []string{"git.froth.zone", "", "!12345", "google.com.edu.org.fr"}
for _, tc := range testcases {
f.Add(tc)
}
f.Fuzz(func(t *testing.T, orig string) {
os.Args = []string{orig}
//nolint:errcheck // Only make sure the program does not crash
cli.ParseCLI("TEST")
})
}

View File

@ -1,117 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package cli
import (
"fmt"
"strconv"
"strings"
"time"
)
// Parse dig-like commands and set the options as such.
func ParseDig(arg string, opts *Options) error {
// returns true if the flag starts with a no
isNo := !strings.HasPrefix(arg, "no")
opts.Logger.Info("Setting", arg)
switch arg {
// Set DNS query flags
case "aa", "aaflag", "aaonly", "noaa", "noaaflag", "noaaonly":
opts.AA = isNo
case "ad", "adflag", "noad", "noadflag":
opts.AD = isNo
case "cd", "cdflag", "nocd", "nocdflag":
opts.CD = isNo
case "qr", "qrflag", "noqr", "noqrflag":
opts.QR = isNo
case "ra", "raflag", "nora", "noraflag":
opts.RA = isNo
case "rd", "rdflag", "recurse", "nord", "nordflag", "norecurse":
opts.RD = isNo
case "tc", "tcflag", "notc", "notcflag":
opts.TC = isNo
case "z", "zflag", "noz", "nozflag":
opts.Z = isNo
// End DNS query flags
// DNS-over-X
case "dnssec", "nodnssec":
opts.DNSSEC = isNo
case "tcp", "vc", "notcp", "novc":
opts.TCP = isNo
case "ignore", "noignore":
opts.Truncate = isNo
case "tls", "notls":
opts.TLS = isNo
case "dnscrypt", "nodnscrypt":
opts.DNSCrypt = isNo
case "https", "nohttps":
opts.HTTPS = isNo
case "quic", "noquic":
opts.QUIC = isNo
// End DNS-over-X
// Formatting
case "short", "noshort":
opts.Short = isNo
case "json", "nojson":
opts.JSON = isNo
case "xml", "noxml":
opts.XML = isNo
case "yaml", "noyaml":
opts.YAML = isNo
// End formatting
// Output
// TODO: get this to work
// case "comments", "nocomments":
// opts.Display.Comments = isNo
case "question", "noquestion":
opts.Display.Question = isNo
case "answer", "noanswer":
opts.Display.Answer = isNo
case "authority", "noauthority":
opts.Display.Authority = isNo
case "additional", "noadditional":
opts.Display.Additional = isNo
case "stats", "nostats":
opts.Display.Statistics = isNo
case "all", "noall":
opts.Display.Question = isNo
opts.Display.Answer = isNo
opts.Display.Authority = isNo
opts.Display.Additional = isNo
opts.Display.Statistics = isNo
default:
// Recursive switch statements WOO
switch {
case strings.HasPrefix(arg, "timeout"):
timeout, err := strconv.Atoi(strings.Split(arg, "=")[1])
if err != nil {
return fmt.Errorf("dig: Invalid timeout value")
}
opts.Request.Timeout = time.Duration(timeout)
case strings.HasPrefix(arg, "retry"), strings.HasPrefix(arg, "tries"):
tries, err := strconv.Atoi(strings.Split(arg, "=")[1])
if err != nil {
return fmt.Errorf("dig: Invalid retry value")
}
if strings.HasPrefix(arg, "tries") {
tries++
}
opts.Request.Retries = tries
default:
return fmt.Errorf("dig: unknown flag %s given", arg)
}
}
return nil
}

View File

@ -1,55 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package cli_test
import (
"testing"
"git.froth.zone/sam/awl/cli"
"git.froth.zone/sam/awl/util"
"gotest.tools/v3/assert"
)
func FuzzDig(f *testing.F) {
f.Log("ParseDig Fuzzing")
seeds := []string{
"aaflag", "aaonly", "noaaflag", "noaaonly",
"adflag", "noadflag",
"cdflag", "nocdflag",
"qrflag", "noqrflag",
"raflag", "noraflag",
"rdflag", "recurse", "nordflag", "norecurse",
"tcflag", "notcflag",
"zflag", "nozflag",
"dnssec", "nodnssec",
"tcp", "vc", "notcp", "novc",
"ignore", "noignore",
"tls", "notls",
"dnscrypt", "nodnscrypt",
"https", "nohttps",
"quic", "noquic",
"short", "noshort",
"json", "nojson",
"xml", "noxml",
"yaml", "noyaml",
"question", "noquestion",
"answer", "noanswer",
"authority", "noauthority",
"additional", "noadditional",
"stats", "nostats",
"all", "noall",
"invalid",
}
for _, tc := range seeds {
f.Add(tc)
}
f.Fuzz(func(t *testing.T, orig string) {
opts := new(cli.Options)
opts.Logger = util.InitLogger(0)
err := cli.ParseDig(orig, opts)
if err != nil {
assert.ErrorContains(t, err, "unknown flag")
}
})
}

View File

@ -1,5 +0,0 @@
/*
The CLI part of the package, including both POSIX
flag parsing and dig-like flag parsing.
*/
package cli

View File

@ -1,55 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package cli
import (
"errors"
"git.froth.zone/sam/awl/internal/helpers"
"git.froth.zone/sam/awl/logawl"
)
// CLI options structure.
type Options struct {
Logger *logawl.Logger // Logger
Port int // DNS port
IPv4 bool // Force IPv4
IPv6 bool // Force IPv6
DNSSEC bool // Enable DNSSEC
TCP bool // Query with TCP
DNSCrypt bool // Query over DNSCrypt
TLS bool // Query over TLS
HTTPS bool // Query over HTTPS
QUIC bool // Query over QUIC
Truncate bool // Ignore truncation
AA bool // Set Authoratative Answer
AD bool // Set Authenticated Data
CD bool // Set CD
QR bool // Set QueRy
RD bool // Set Recursion Desired
RA bool // Set Recursion Available
TC bool // Set TC (TrunCated)
Z bool // Set Z (Zero)
Reverse bool // Make reverse query
Verbosity int // Set logawl verbosity
// HumanTTL bool // Make TTL human readable
Short bool // Short output
JSON bool // Outout as JSON
XML bool // Output as XML
YAML bool // Output at YAML
Display Displays // Display options
Request helpers.Request // DNS reuqest
}
// What to (and not to) display
type Displays struct {
// Comments bool
Question bool // QUESTION SECTION
Answer bool // ANSWER SECTION
Authority bool // AUTHORITY SECTION
Additional bool // ADDITIONAL SECTION
Statistics bool // Query time, message size, etc.
}
var ErrNotError = errors.New("not an error")

269
cmd/cli.go Normal file
View File

@ -0,0 +1,269 @@
// SPDX-License-Identifier: BSD-3-Clause
package cli
import (
"errors"
"fmt"
"runtime"
"strconv"
"strings"
"time"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
flag "github.com/stefansundin/go-zflag"
)
// ParseCLI parses arguments given from the CLI and passes them into an `Options`
// struct.
func ParseCLI(args []string, version string) (opts *util.Options, err error) {
// Parse the standard flags
opts, misc, err := parseFlags(args, version)
if err != nil {
return opts, err
}
// Parse all the arguments that don't start with - or --
// This includes the dig-style (+) options
err = ParseMiscArgs(misc, opts)
if err != nil {
return opts, err
}
opts.Logger.Info("Dig/Drill flags parsed")
opts.Logger.Debug(fmt.Sprintf("%+v", opts))
// Special options and exceptions time
if opts.Request.Port == 0 {
if opts.TLS || opts.QUIC {
opts.Request.Port = 853
} else {
opts.Request.Port = 53
}
}
opts.Logger.Info("Port set to", opts.Request.Port)
// Set timeout to 0.5 seconds if set below 0.5
if opts.Request.Timeout < (time.Second / 2) {
opts.Request.Timeout = (time.Second / 2)
}
if opts.Request.Retries < 0 {
opts.Request.Retries = 0
}
if opts.Trace {
if opts.TLS || opts.HTTPS || opts.QUIC {
opts.Logger.Warn("Every query after the root query will only use UDP/TCP")
}
opts.RD = true
}
opts.Logger.Info("Options fully populated")
opts.Logger.Debug(fmt.Sprintf("%+v", opts))
return
}
// Everything that has to do with CLI flags goes here (the posix style, eg. -a and --bbbb).
func parseFlags(args []string, version string) (opts *util.Options, flags []string, err error) {
flagSet := flag.NewFlagSet(args[0], flag.ContinueOnError)
flagSet.Usage = func() {
fmt.Println(`awl - drill, writ small
Usage: awl name [@server] [record]
<name> domain, IP address, phone number
<record> defaults to A
Arguments may be in any order, including flags.
Dig-like +[no]commands are also supported, see dig(1) or dig -h
Options:`)
flagSet.PrintDefaults()
}
// CLI flags
//
// Remember, when adding a flag edit the manpage and the completions :)
var (
port = flagSet.Int("port", 0, "`port` to make DNS query (default: 53 for UDP/TCP, 853 for TLS/QUIC)", flag.OptShorthand('p'), flag.OptDisablePrintDefault(true))
query = flagSet.String("query", "", "domain name to `query` (default: .)", flag.OptShorthand('q'))
class = flagSet.String("class", "IN", "DNS `class` to query", flag.OptShorthand('c'))
qType = flagSet.String("qType", "", "`type` to query (default: A)", flag.OptShorthand('t'))
ipv4 = flagSet.Bool("4", false, "force IPv4", flag.OptShorthand('4'))
ipv6 = flagSet.Bool("6", false, "force IPv6", flag.OptShorthand('6'))
reverse = flagSet.Bool("reverse", false, "do a reverse lookup", flag.OptShorthand('x'))
trace = flagSet.Bool("trace", false, "trace from the root")
timeout = flagSet.Float32("timeout", 5, "Timeout, in `seconds`")
retry = flagSet.Int("retries", 2, "number of `times` to retry")
edns = flagSet.Bool("no-edns", false, "disable EDNS entirely")
ednsVer = flagSet.Uint8("edns-ver", 0, "set EDNS version")
dnssec = flagSet.Bool("dnssec", false, "enable DNSSEC", flag.OptShorthand('D'))
expire = flagSet.Bool("expire", false, "set EDNS expire")
nsid = flagSet.Bool("nsid", false, "set EDNS NSID", flag.OptShorthand('n'))
cookie = flagSet.Bool("no-cookie", false, "disable sending EDNS cookie (default: cookie sent)")
tcpKeepAlive = flagSet.Bool("keep-alive", false, "send EDNS TCP keep-alive")
udpBufSize = flagSet.Uint16("buffer-size", 1232, "set EDNS UDP buffer size", flag.OptShorthand('b'))
mbzflag = flagSet.String("zflag", "0", "set EDNS z-flag `value`")
subnet = flagSet.String("subnet", "", "set EDNS client subnet")
padding = flagSet.Bool("pad", false, "set EDNS padding")
badCookie = flagSet.Bool("no-bad-cookie", false, "ignore BADCOOKIE EDNS responses (default: retry with correct cookie")
truncate = flagSet.Bool("no-truncate", false, "ignore truncation if a UDP request truncates (default: retry with TCP)")
tcp = flagSet.Bool("tcp", false, "use TCP")
dnscrypt = flagSet.Bool("dnscrypt", false, "use DNSCrypt")
tls = flagSet.Bool("tls", false, "use DNS-over-TLS", flag.OptShorthand('T'))
https = flagSet.Bool("https", false, "use DNS-over-HTTPS", flag.OptShorthand('H'))
quic = flagSet.Bool("quic", false, "use DNS-over-QUIC", flag.OptShorthand('Q'))
tlsHost = flagSet.String("tls-host", "", "Server name to use for TLS verification")
noVerify = flagSet.Bool("tls-no-verify", false, "Disable TLS cert verification")
aaflag = flagSet.Bool("aa", false, "set/unset AA (Authoratative Answer) flag (default: not set)")
adflag = flagSet.Bool("ad", false, "set/unset AD (Authenticated Data) flag (default: not set)")
cdflag = flagSet.Bool("cd", false, "set/unset CD (Checking Disabled) flag (default: not set)")
qrflag = flagSet.Bool("qr", false, "set/unset QR (QueRy) flag (default: not set)")
rdflag = flagSet.Bool("rd", true, "set/unset RD (Recursion Desired) flag (default: set)", flag.OptDisablePrintDefault(true))
raflag = flagSet.Bool("ra", false, "set/unset RA (Recursion Available) flag (default: not set)")
tcflag = flagSet.Bool("tc", false, "set/unset TC (TrunCated) flag (default: not set)")
zflag = flagSet.Bool("z", false, "set/unset Z (Zero) flag (default: not set)", flag.OptShorthand('z'))
short = flagSet.Bool("short", false, "print just the results", flag.OptShorthand('s'))
json = flagSet.Bool("json", false, "print the result(s) as JSON", flag.OptShorthand('j'))
xml = flagSet.Bool("xml", false, "print the result(s) as XML", flag.OptShorthand('X'))
yaml = flagSet.Bool("yaml", false, "print the result(s) as yaml", flag.OptShorthand('y'))
noC = flagSet.Bool("no-comments", false, "disable printing the comments")
noQ = flagSet.Bool("no-question", false, "disable printing the question section")
noOpt = flagSet.Bool("no-opt", false, "disable printing the OPT pseudosection")
noAns = flagSet.Bool("no-answer", false, "disable printing the answer section")
noAuth = flagSet.Bool("no-authority", false, "disable printing the authority section")
noAdd = flagSet.Bool("no-additional", false, "disable printing the additional section")
noStats = flagSet.Bool("no-statistics", false, "disable printing the statistics section")
verbosity = flagSet.Int("verbosity", 1, "sets verbosity `level`", flag.OptShorthand('v'), flag.OptNoOptDefVal("2"))
versionFlag = flagSet.Bool("version", false, "print version information", flag.OptShorthand('V'))
)
// Don't sort the flags when -h is given
flagSet.SortFlags = true
// Parse the flags
if err = flagSet.Parse(args[1:]); err != nil {
return &util.Options{Logger: util.InitLogger(*verbosity)}, nil, fmt.Errorf("flag: %w", err)
}
// TODO: DRY, dumb dumb.
mbz, err := strconv.ParseInt(*mbzflag, 0, 16)
if err != nil {
return &util.Options{Logger: util.InitLogger(*verbosity)}, nil, fmt.Errorf("EDNS MBZ: %w", err)
}
opts = &util.Options{
Logger: util.InitLogger(*verbosity),
IPv4: *ipv4,
IPv6: *ipv6,
Trace: *trace,
Short: *short,
TCP: *tcp,
DNSCrypt: *dnscrypt,
TLS: *tls,
TLSHost: *tlsHost,
TLSNoVerify: *noVerify,
HTTPS: *https,
QUIC: *quic,
Truncate: *truncate,
BadCookie: *badCookie,
Reverse: *reverse,
JSON: *json,
XML: *xml,
YAML: *yaml,
HeaderFlags: util.HeaderFlags{
AA: *aaflag,
AD: *adflag,
TC: *tcflag,
Z: *zflag,
CD: *cdflag,
QR: *qrflag,
RD: *rdflag,
RA: *raflag,
},
Request: util.Request{
Type: dns.StringToType[strings.ToUpper(*qType)],
Class: dns.StringToClass[strings.ToUpper(*class)],
Name: *query,
Timeout: time.Duration(*timeout * float32(time.Second)),
Retries: *retry,
Port: *port,
},
Display: util.Display{
Comments: !*noC,
Question: !*noQ,
Opt: !*noOpt,
Answer: !*noAns,
Authority: !*noAuth,
Additional: !*noAdd,
Statistics: !*noStats,
TTL: true,
ShowClass: true,
ShowQuery: false,
HumanTTL: false,
UcodeTranslate: true,
},
EDNS: util.EDNS{
EnableEDNS: !*edns,
Cookie: !*cookie,
DNSSEC: *dnssec,
BufSize: *udpBufSize,
Version: *ednsVer,
Expire: *expire,
KeepOpen: *tcpKeepAlive,
Nsid: *nsid,
ZFlag: uint16(mbz & 0x7FFF),
Padding: *padding,
},
HTTPSOptions: util.HTTPSOptions{
Endpoint: "/dns-query",
Get: false,
},
}
// TODO: DRY
if *subnet != "" {
if err = util.ParseSubnet(*subnet, opts); err != nil {
return opts, nil, fmt.Errorf("%w", err)
}
}
opts.Logger.Info("POSIX flags parsed")
opts.Logger.Debug(fmt.Sprintf("%+v", opts))
if *versionFlag {
fmt.Printf("awl version %s, built with %s\n", version, runtime.Version())
return opts, nil, util.ErrNotError
}
flags = flagSet.Args()
return
}
var errNoArg = errors.New("no argument given")
type errInvalidArg struct {
arg string
}
func (e *errInvalidArg) Error() string {
return fmt.Sprintf("digflags: invalid argument %s", e.arg)
}

189
cmd/cli_test.go Normal file
View File

@ -0,0 +1,189 @@
// SPDX-License-Identifier: BSD-3-Clause
package cli_test
import (
"testing"
"time"
cli "dns.froth.zone/awl/cmd"
"dns.froth.zone/awl/pkg/util"
"gotest.tools/v3/assert"
)
func TestEmpty(t *testing.T) {
t.Parallel()
args := []string{"awl", "-4"}
opts, err := cli.ParseCLI(args, "TEST")
assert.NilError(t, err)
assert.Assert(t, opts.IPv4)
assert.Equal(t, opts.Request.Port, 53)
}
func TestTLSPort(t *testing.T) {
t.Parallel()
args := []string{"awl", "-T"}
opts, err := cli.ParseCLI(args, "TEST")
assert.NilError(t, err)
assert.Equal(t, opts.Request.Port, 853)
}
func TestValidSubnet(t *testing.T) {
t.Parallel()
tests := []struct {
args []string
want uint16
}{
{[]string{"awl", "--subnet", "127.0.0.1/32"}, uint16(1)},
{[]string{"awl", "--subnet", "0"}, uint16(1)},
{[]string{"awl", "--subnet", "::/0"}, uint16(2)},
}
for _, test := range tests {
test := test
t.Run(test.args[2], func(t *testing.T) {
t.Parallel()
opts, err := cli.ParseCLI(test.args, "TEST")
assert.NilError(t, err)
assert.Equal(t, opts.EDNS.Subnet.Family, test.want)
})
}
}
func TestInvalidSubnet(t *testing.T) {
t.Parallel()
args := []string{"awl", "--subnet", "/"}
_, err := cli.ParseCLI(args, "TEST")
assert.ErrorContains(t, err, "EDNS subnet")
}
func TestMBZ(t *testing.T) {
t.Parallel()
args := []string{"awl", "--zflag", "G"}
_, err := cli.ParseCLI(args, "TEST")
assert.ErrorContains(t, err, "EDNS MBZ")
}
func TestInvalidFlag(t *testing.T) {
t.Parallel()
args := []string{"awl", "--treebug"}
_, err := cli.ParseCLI(args, "TEST")
assert.ErrorContains(t, err, "unknown flag")
}
func TestInvalidDig(t *testing.T) {
t.Parallel()
args := []string{"awl", "+a"}
_, err := cli.ParseCLI(args, "TEST")
assert.ErrorContains(t, err, "digflags: invalid argument")
}
func TestVersion(t *testing.T) {
t.Parallel()
args := []string{"awl", "--version"}
_, err := cli.ParseCLI(args, "test")
assert.ErrorIs(t, err, util.ErrNotError)
}
func TestTimeout(t *testing.T) {
t.Parallel()
args := [][]string{
{"awl", "+timeout=0"},
{"awl", "--timeout", "0"},
}
for _, test := range args {
test := test
t.Run(test[1], func(t *testing.T) {
t.Parallel()
opt, err := cli.ParseCLI(test, "TEST")
assert.NilError(t, err)
assert.Equal(t, opt.Request.Timeout, time.Second/2)
})
}
}
func TestRetries(t *testing.T) {
t.Parallel()
args := [][]string{
{"awl", "+retry=-2"},
{"awl", "+tries=-2"},
{"awl", "--retries", "-2"},
}
for _, test := range args {
test := test
t.Run(test[1], func(t *testing.T) {
t.Parallel()
opt, err := cli.ParseCLI(test, "TEST")
assert.NilError(t, err)
assert.Equal(t, opt.Request.Retries, 0)
})
}
}
func TestSetHTTPS(t *testing.T) {
t.Parallel()
args := [][]string{
{"awl", "-H", "@dns.froth.zone/dns-query"},
{"awl", "+https", "@dns.froth.zone"},
}
for _, test := range args {
test := test
t.Run(test[1], func(t *testing.T) {
t.Parallel()
opt, err := cli.ParseCLI(test, "TEST")
assert.NilError(t, err)
assert.Equal(t, opt.Request.Server, "dns.froth.zone")
assert.Equal(t, opt.HTTPSOptions.Endpoint, "/dns-query")
})
}
}
func FuzzFlags(f *testing.F) {
testcases := []string{"git.froth.zone", "", "!12345", "google.com.edu.org.fr"}
for _, tc := range testcases {
f.Add(tc)
}
f.Fuzz(func(t *testing.T, orig string) {
// Get rid of outputs
args := []string{"awl", orig}
//nolint:errcheck,gosec // Only make sure the program does not crash
cli.ParseCLI(args, "TEST")
})
}

246
cmd/dig.go Normal file
View File

@ -0,0 +1,246 @@
// SPDX-License-Identifier: BSD-3-Clause
package cli
import (
"fmt"
"strconv"
"strings"
"time"
"dns.froth.zone/awl/pkg/util"
)
// ParseDig parses commands from the popular DNS tool dig.
// All dig commands are taken from https://man.openbsd.org/dig.1 as the source of their functionality.
//
// [no]flags are supported just as flag are and are disabled as such.
func ParseDig(arg string, opts *util.Options) error {
// returns true if the flag starts with a no
isNo := !strings.HasPrefix(arg, "no")
if !isNo {
arg = strings.TrimPrefix(arg, "no")
}
opts.Logger.Info("Setting", arg)
switch arg {
case "trace", "notrace":
opts.Trace = isNo
if isNo {
opts.DNSSEC = true
opts.Display.Comments = false
opts.Display.Question = false
opts.Display.Opt = false
opts.Display.Answer = true
opts.Display.Authority = true
opts.Display.Additional = false
opts.Display.Statistics = false
}
// Set DNS query flags
case "aa", "aaflag", "aaonly":
opts.AA = isNo
case "ad", "adflag":
opts.AD = isNo
case "cd", "cdflag":
opts.CD = isNo
case "qrflag":
opts.QR = isNo
case "ra", "raflag":
opts.RA = isNo
case "rd", "rdflag", "recurse":
opts.RD = isNo
case "tc", "tcflag":
opts.TC = isNo
case "z", "zflag":
opts.Z = isNo
// End DNS query flags
case "qr":
opts.Display.ShowQuery = isNo
case "ttlunits":
opts.Display.HumanTTL = isNo
case "ttl", "ttlid":
opts.Display.TTL = isNo
case "class":
opts.Display.ShowClass = isNo
// EDNS queries
case "do", "dnssec":
opts.EDNS.DNSSEC = isNo
case "expire":
opts.EDNS.Expire = isNo
case "cookie":
opts.EDNS.Cookie = isNo
case "keepopen", "keepalive":
opts.EDNS.KeepOpen = isNo
case "nsid":
opts.EDNS.Nsid = isNo
case "padding":
opts.EDNS.Padding = isNo
// End EDNS queries
// DNS-over-X
case "tcp", "vc":
opts.TCP = isNo
case "ignore":
opts.Truncate = isNo
case "badcookie":
opts.BadCookie = !isNo
case "tls":
opts.TLS = isNo
case "dnscrypt":
opts.DNSCrypt = isNo
case "quic":
opts.QUIC = isNo
// End DNS-over-X
// Formatting
case "short":
opts.Short = isNo
case "identify":
opts.Identify = isNo
case "json":
opts.JSON = isNo
case "xml":
opts.XML = isNo
case "yaml":
opts.YAML = isNo
// End formatting
// Output
case "comments":
opts.Display.Comments = isNo
case "question":
opts.Display.Question = isNo
case "opt":
opts.Display.Opt = isNo
case "answer":
opts.Display.Answer = isNo
case "authority":
opts.Display.Authority = isNo
case "additional":
opts.Display.Additional = isNo
case "stats":
opts.Display.Statistics = isNo
case "all":
opts.Display.Comments = isNo
opts.Display.Question = isNo
opts.Display.Opt = isNo
opts.Display.Answer = isNo
opts.Display.Authority = isNo
opts.Display.Additional = isNo
opts.Display.Statistics = isNo
case "idnin", "idnout":
opts.Display.UcodeTranslate = isNo
default:
if err := parseDigEq(isNo, arg, opts); err != nil {
return err
}
}
return nil
}
// For flags that contain "=".
func parseDigEq(startNo bool, arg string, opts *util.Options) error {
// Recursive switch statements WOO
arg, val, isSplit := strings.Cut(arg, "=")
switch arg {
case "time", "timeout":
if isSplit && val != "" {
timeout, err := strconv.Atoi(val)
if err != nil {
return fmt.Errorf("digflags: timeout : %w", err)
}
opts.Request.Timeout = time.Duration(timeout)
} else {
return fmt.Errorf("digflags: timeout: %w", errNoArg)
}
case "retry", "tries":
if isSplit && val != "" {
tries, err := strconv.Atoi(val)
if err != nil {
return fmt.Errorf("digflags: retry: %w", err)
}
opts.Request.Retries = tries
// TODO: Is there a better way to do this?
if arg == "tries" {
opts.Request.Retries--
}
} else {
return fmt.Errorf("digflags: retry: %w", errNoArg)
}
case "bufsize":
if isSplit && val != "" {
size, err := strconv.Atoi(val)
if err != nil {
return fmt.Errorf("digflags: EDNS UDP: %w", err)
}
opts.EDNS.BufSize = uint16(size)
} else {
return fmt.Errorf("digflags: EDNS UDP: %w", errNoArg)
}
case "ednsflags":
if isSplit && val != "" {
ver, err := strconv.ParseInt(val, 0, 16)
if err != nil {
return fmt.Errorf("digflags: EDNS flag: %w", err)
}
// Ignore setting DO bit
opts.EDNS.ZFlag = uint16(ver & 0x7FFF)
} else {
opts.EDNS.ZFlag = 0
}
case "edns":
opts.EDNS.EnableEDNS = startNo
if isSplit && val != "" {
ver, err := strconv.Atoi(val)
if err != nil {
return fmt.Errorf("digflags: EDNS version: %w", err)
}
opts.EDNS.Version = uint8(ver)
} else {
opts.EDNS.Version = 0
}
case "https", "https-get", "https-post":
opts.HTTPS = startNo
if isSplit && val != "" {
opts.HTTPSOptions.Endpoint = val
} else {
opts.HTTPSOptions.Endpoint = "/dns-query"
}
if strings.HasSuffix(arg, "get") {
opts.HTTPSOptions.Get = true
}
case "subnet":
if isSplit && val != "" {
err := util.ParseSubnet(val, opts)
if err != nil {
return fmt.Errorf("digflags: EDNS Subnet: %w", err)
}
} else {
return fmt.Errorf("digflags: EDNS Subnet: %w", errNoArg)
}
default:
return &errInvalidArg{arg}
}
return nil
}

82
cmd/dig_test.go Normal file
View File

@ -0,0 +1,82 @@
// SPDX-License-Identifier: BSD-3-Clause
package cli_test
import (
"testing"
cli "dns.froth.zone/awl/cmd"
"dns.froth.zone/awl/pkg/util"
"gotest.tools/v3/assert"
)
func FuzzDig(f *testing.F) {
f.Log("ParseDig Fuzzing")
seeds := []string{
"aaflag", "aaonly", "noaaflag", "noaaonly",
"adflag", "noadflag",
"cdflag", "nocdflag",
"qrflag", "noqrflag",
"raflag", "noraflag",
"rdflag", "recurse", "nordflag", "norecurse",
"tcflag", "notcflag",
"zflag", "nozflag",
"qr", "noqr",
"ttlunits", "nottlunits",
"ttlid", "nottlid",
"do", "dnssec", "nodo", "nodnssec",
"edns", "edns=a", "edns=0", "noedns",
"expire", "noexpire",
"ednsflags", "ednsflags=\"", "ednsflags=1", "noednsflags",
"subnet=0.0.0.0/0", "subnet=::0/0", "subnet=b", "subnet=0", "subnet",
"cookie", "nocookie",
"keepopen", "keepalive", "nokeepopen", "nokeepalive",
"nsid", "nonsid",
"padding", "nopadding",
"bufsize=512", "bufsize=a", "bufsize",
"time=5", "timeout=a", "timeout",
"retry=a", "retry=3", "retry",
"tries=2", "tries=b", "tries",
"tcp", "vc", "notcp", "novc",
"ignore", "noignore",
"badcookie", "nobadcookie",
"tls", "notls",
"dnscrypt", "nodnscrypt",
"https", "https=/dns", "https-get", "https-get=/", "nohttps",
"quic", "noquic",
"short", "noshort",
"identify", "noidentify",
"json", "nojson",
"xml", "noxml",
"yaml", "noyaml",
"comments", "nocomments",
"question", "noquestion",
"opt", "noopt",
"answer", "noanswer",
"authority", "noauthority",
"additional", "noadditional",
"stats", "nostats",
"all", "noall",
"idnout", "noidnout",
"class", "noclass",
"trace", "notrace",
"invalid",
}
for _, tc := range seeds {
f.Add(tc)
}
f.Fuzz(func(t *testing.T, orig string) {
// Get rid of outputs
// os.Stdout = os.NewFile(0, os.DevNull)
// os.Stderr = os.NewFile(0, os.DevNull)
opts := new(util.Options)
opts.Logger = util.InitLogger(0)
if err := cli.ParseDig(orig, opts); err != nil {
assert.ErrorContains(t, err, "digflags:")
}
})
}

7
cmd/docs.go Normal file
View File

@ -0,0 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
Package cli is the CLI part of the package, including both POSIX
flag parsing and dig-like flag parsing.
*/
package cli

View File

@ -7,67 +7,99 @@ import (
"math/rand"
"strings"
"git.froth.zone/sam/awl/conf"
"git.froth.zone/sam/awl/util"
"dns.froth.zone/awl/conf"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
"golang.org/x/net/idna"
)
// Parse the wildcard arguments, drill style.
func ParseMiscArgs(args []string, opts *Options) error {
var err error
// ParseMiscArgs parses the wildcard arguments, dig style.
// Only one command is supported at a time, so any extra information overrides previous.
func ParseMiscArgs(args []string, opts *util.Options) error {
for _, arg := range args {
r, ok := dns.StringToType[strings.ToUpper(arg)]
switch {
// If it starts with @, it's a DNS server
case strings.HasPrefix(arg, "@"):
arg = arg[1:]
// Automatically set flags based on URI header
opts.Logger.Info(arg, "detected as a server")
switch {
case strings.HasPrefix(arg, "tls://"):
opts.TLS = true
opts.Request.Server = arg[6:]
opts.Request.Server = strings.TrimPrefix(arg, "tls://")
opts.Logger.Info("DNS-over-TLS implicitly set")
case strings.HasPrefix(arg, "https://"):
opts.HTTPS = true
opts.Request.Server = arg
opts.Logger.Info("DNS-over-HTTPS implicitly set")
_, endpoint, isSplit := strings.Cut(arg, "/")
if isSplit {
opts.HTTPSOptions.Endpoint = "/" + endpoint
}
case strings.HasPrefix(arg, "quic://"):
opts.QUIC = true
opts.Request.Server = arg[7:]
opts.Request.Server = strings.TrimPrefix(arg, "quic://")
opts.Logger.Info("DNS-over-QUIC implicitly set.")
case strings.HasPrefix(arg, "sdns://"):
opts.DNSCrypt = true
opts.Request.Server = arg
opts.Logger.Info("DNSCrypt implicitly set")
case strings.HasPrefix(arg, "tcp://"):
opts.TCP = true
opts.Request.Server = strings.TrimPrefix(arg, "tcp://")
opts.Logger.Info("TCP implicitly set")
case strings.HasPrefix(arg, "udp://"):
opts.Request.Server = strings.TrimPrefix(arg, "udp://")
default:
opts.Request.Server = arg
// Allow HTTPS queries to have a fallback default
if opts.HTTPS {
server, endpoint, isSplit := strings.Cut(arg, "/")
if isSplit {
opts.HTTPSOptions.Endpoint = "/" + endpoint
opts.Request.Server = server
} else {
opts.Request.Server = server
}
} else {
opts.Request.Server = arg
}
}
// Dig-style +queries
case strings.HasPrefix(arg, "+"):
opts.Logger.Info(arg, "detected as a dig query")
if err := ParseDig(strings.ToLower(arg[1:]), opts); err != nil {
return err
}
// Domain names
case strings.Contains(arg, "."):
var err error
opts.Logger.Info(arg, "detected as a domain name")
opts.Request.Name, err = idna.ToASCII(arg)
if err != nil {
return err
return fmt.Errorf("unicode to punycode: %w", err)
}
// DNS query type
case ok:
opts.Logger.Info(arg, "detected as a type")
// If it's a DNS request, it's a DNS request (obviously)
opts.Request.Type = r
case strings.HasPrefix(arg, "+"):
opts.Logger.Info(arg, "detected as a dig query")
// Dig-style +queries
err = ParseDig(strings.ToLower(arg[1:]), opts)
if err != nil {
return err
}
// Domain?
default:
var err error
opts.Logger.Info(arg, "is unknown. Assuming domain")
opts.Request.Name, err = idna.ToASCII(arg)
if err != nil {
return err
return fmt.Errorf("unicode to punycode: %w", err)
}
}
}
@ -76,16 +108,16 @@ func ParseMiscArgs(args []string, opts *Options) error {
if opts.Request.Name == "" {
opts.Logger.Info("Domain not specified, making a default")
opts.Request.Name = "."
if opts.Request.Type == 0 {
opts.Logger.Info("Query not specified, making an \"NS\" query")
opts.Request.Type = dns.StringToType["NS"]
}
} else {
} else if opts.Request.Type == 0 {
opts.Logger.Info("Query not specified, making an \"A\" query")
if opts.Request.Type == 0 {
opts.Request.Type = dns.StringToType["A"]
}
opts.Request.Type = dns.StringToType["A"]
}
//
if opts.Request.Server == "" {
opts.Logger.Info("Server not specified, selecting a default")
// Set "defaults" for each if there is no input
@ -96,55 +128,69 @@ func ParseMiscArgs(args []string, opts *Options) error {
case opts.TLS:
opts.Request.Server = "dns.google"
case opts.HTTPS:
opts.Request.Server = "https://dns.cloudflare.com/dns-query"
opts.Request.Server = "https://dns.cloudflare.com"
case opts.QUIC:
opts.Request.Server = "dns.adguard.com"
opts.Request.Server = "dns.froth.zone"
default:
var err error
resolv, err := conf.GetDNSConfig()
if err != nil {
// :^)
opts.Logger.Warn("Could not query system for server. Using default")
opts.Request.Server = "95.216.99.249"
opts.Logger.Warn("Could not query system for server. Using localhost\n", "Error:", err)
opts.Request.Server = "127.0.0.1"
} else {
// Make sure that if IPv4 or IPv6 is asked for it actually uses it
harmful:
for _, srv := range resolv.Servers {
if opts.IPv4 {
switch {
case opts.IPv4:
if strings.Contains(srv, ".") {
opts.Request.Server = srv
break
break harmful
}
} else if opts.IPv6 {
case opts.IPv6:
if strings.Contains(srv, ":") {
opts.Request.Server = srv
break
break harmful
}
} else {
default:
//#nosec -- This isn't used for anything secure
opts.Request.Server = resolv.Servers[rand.Intn(len(resolv.Servers))]
break
break harmful
}
}
}
}
}
opts.Logger.Info("DNS server set to", opts.Request.Server)
// Make reverse adresses proper addresses
// Make reverse addresses proper addresses
if opts.Reverse {
var err error
opts.Logger.Info("Making reverse DNS query proper *.arpa domain")
if dns.TypeToString[opts.Request.Type] == "A" {
opts.Request.Type = dns.StringToType["PTR"]
}
opts.Request.Name, err = util.ReverseDNS(opts.Request.Name, opts.Request.Type)
if err != nil {
return err
return fmt.Errorf("reverse DNS: %w", err)
}
}
// if the domain is not canonical, make it canonical
if !strings.HasSuffix(opts.Request.Name, ".") {
opts.Request.Name = fmt.Sprintf("%s.", opts.Request.Name)
opts.Logger.Debug("Domain made canonical")
opts.Logger.Info("Domain made canonical")
}
return nil
}

View File

@ -3,25 +3,25 @@
package cli_test
import (
"strconv"
"strings"
"testing"
"git.froth.zone/sam/awl/cli"
"git.froth.zone/sam/awl/util"
cli "dns.froth.zone/awl/cmd"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestParseArgs(t *testing.T) {
t.Parallel()
args := []string{
"go.dev",
"AAAA",
"@1.1.1.1",
"+ignore",
}
opts := new(cli.Options)
opts := new(util.Options)
opts.Logger = util.InitLogger(0)
err := cli.ParseMiscArgs(args, opts)
assert.NilError(t, err)
@ -33,8 +33,9 @@ func TestParseArgs(t *testing.T) {
func TestParseNoInput(t *testing.T) {
t.Parallel()
args := []string{}
opts := new(cli.Options)
opts := new(util.Options)
opts.Logger = util.InitLogger(0)
err := cli.ParseMiscArgs(args, opts)
assert.NilError(t, err)
@ -44,10 +45,11 @@ func TestParseNoInput(t *testing.T) {
func TestParseA(t *testing.T) {
t.Parallel()
args := []string{
"golang.org.",
}
opts := new(cli.Options)
opts := new(util.Options)
opts.Logger = util.InitLogger(0)
err := cli.ParseMiscArgs(args, opts)
assert.NilError(t, err)
@ -57,8 +59,9 @@ func TestParseA(t *testing.T) {
func TestParsePTR(t *testing.T) {
t.Parallel()
args := []string{"8.8.8.8"}
opts := new(cli.Options)
opts := new(util.Options)
opts.Logger = util.InitLogger(0)
opts.Reverse = true
err := cli.ParseMiscArgs(args, opts)
@ -68,8 +71,9 @@ func TestParsePTR(t *testing.T) {
func TestParseInvalidPTR(t *testing.T) {
t.Parallel()
args := []string{"8.88.8"}
opts := new(cli.Options)
opts := new(util.Options)
opts.Logger = util.InitLogger(0)
opts.Reverse = true
err := cli.ParseMiscArgs(args, opts)
@ -78,24 +82,27 @@ func TestParseInvalidPTR(t *testing.T) {
func TestDefaultServer(t *testing.T) {
t.Parallel()
tests := []struct {
in string
want string
}{
{"DNSCRYPT", "sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20"},
{"DNSCrypt", "sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20"},
{"TLS", "dns.google"},
{"HTTPS", "https://dns.cloudflare.com/dns-query"},
{"QUIC", "dns.adguard.com"},
{"HTTPS", "https://dns.cloudflare.com"},
{"QUIC", "dns.froth.zone"},
}
for _, test := range tests {
test := test
t.Run(test.in, func(t *testing.T) {
t.Parallel()
args := []string{}
opts := new(cli.Options)
opts := new(util.Options)
opts.Logger = util.InitLogger(0)
switch test.in {
case "DNSCRYPT":
case "DNSCrypt":
opts.DNSCrypt = true
case "TLS":
opts.TLS = true
@ -113,33 +120,51 @@ func TestDefaultServer(t *testing.T) {
func TestFlagSetting(t *testing.T) {
t.Parallel()
tests := []struct {
in []string
}{
{[]string{"@sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20"}},
{[]string{"@tls://dns.google"}},
{[]string{"@https://dns.cloudflare.com/dns-query"}},
{[]string{"@quic://dns.adguard.com"}},
}
for i, test := range tests {
test := test
i := i
t.Run(strconv.Itoa(i), func(t *testing.T) {
opts := new(cli.Options)
opts.Logger = util.InitLogger(0)
t.Parallel()
err := cli.ParseMiscArgs(test.in, opts)
assert.NilError(t, err)
switch i {
case 0:
assert.Assert(t, opts.DNSCrypt)
case 1:
assert.Assert(t, opts.TLS)
case 2:
assert.Assert(t, opts.HTTPS)
case 3:
assert.Assert(t, opts.QUIC)
tests := []struct {
in string
expected string
over string
}{
{"@sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20", "sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20", "DNSCrypt"},
{"@tls://dns.google", "dns.google", "TLS"},
{"@https://dns.cloudflare.com/dns-query", "https://dns.cloudflare.com/dns-query", "HTTPS"},
{"@https://dns.example.net/a", "https://dns.example.net/a", "HTTPS with a set path"},
{"@quic://dns.adguard.com", "dns.adguard.com", "QUIC"},
{"@tcp://dns.froth.zone", "dns.froth.zone", "TCP"},
{"@udp://dns.example.com", "dns.example.com", "UDP"},
}
for _, test := range tests {
test := test
t.Run(test.over, func(t *testing.T) {
t.Parallel()
opts := new(util.Options)
opts.Logger = util.InitLogger(0)
err := cli.ParseMiscArgs([]string{test.in}, opts)
assert.NilError(t, err)
switch {
case strings.HasPrefix(test.over, "DNSCrypt"):
assert.Assert(t, opts.DNSCrypt)
assert.Equal(t, opts.Request.Server, test.expected)
case strings.HasPrefix(test.over, "TLS"):
assert.Assert(t, opts.TLS)
assert.Equal(t, opts.Request.Server, test.expected)
case strings.HasPrefix(test.over, "HTTPS"):
assert.Assert(t, opts.HTTPS)
assert.Equal(t, opts.Request.Server, test.expected)
case strings.HasPrefix(test.over, "QUIC"):
assert.Assert(t, opts.QUIC)
assert.Equal(t, opts.Request.Server, test.expected)
case strings.HasPrefix(test.over, "TCP"):
assert.Assert(t, opts.TCP)
assert.Equal(t, opts.Request.Server, test.expected)
case strings.HasPrefix(test.over, "UDP"):
assert.Assert(t, true)
assert.Equal(t, opts.Request.Server, test.expected)
}
})
}
@ -153,14 +178,18 @@ func FuzzParseArgs(f *testing.F) {
"+ignore",
"e",
}
for _, tc := range cases {
f.Add(tc)
}
f.Fuzz(func(t *testing.T, arg string) {
// Get rid of outputs
args := []string{arg}
opts := new(cli.Options)
opts := new(util.Options)
opts.Logger = util.InitLogger(0)
//nolint:errcheck // Only make sure the program does not crash
//nolint:errcheck,gosec // Only make sure the program does not crash
cli.ParseMiscArgs(args, opts)
})
}

6
completions/bash.bash Normal file
View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: BSD-3-Clause
# bash completion for awl -*- shell-script -*-
# TODO: MAKE THIS A REAL THING
complete -F _known_hosts awl

75
completions/fish.fish Normal file
View File

@ -0,0 +1,75 @@
# SPDX-License-Identifier: BSD-3-Clause
function __fish_complete_awl
set -l token (commandline -ct)
switch $token
case '+tries=*' '+retry=*' '+time=*' '+bufsize=*' '+edns=*'
printf '%s\n' $token(seq 0 255)
case '-v=*'
printf '%s\n' $token(seq -1 3)
end
end
complete -c awl -x -a "(__fish_print_hostnames) A AAAA AFSDB APL CAA CDNSKEY CDS CERT CNAME DHCID DLV DNAME DNSKEY DS HIP IPSECKEY KEY KX LOC MX NAPTR NS NSEC NSEC3 NSEC3PARAM PTR RRSIG RP SIG SOA SRV SSHFP TA TKEY TLSA TSIG TXT URI"
complete -c awl -x -a "@(__fish_print_hostnames)"
complete -f -c awl -s 4 -d 'Use IPv4 query transport only'
complete -f -c awl -s 6 -d 'Use IPv6 query transport only'
complete -c awl -s c -l class -x -a 'IN CH HS QCLASS' -d 'Specify query class'
complete -c awl -s p -l port -x -d 'Specify port number'
complete -c awl -s q -l query -x -a "(__fish_print_hostnames)" -d 'Query domain'
complete -c awl -s t -l qType -x -a 'A AAAA AFSDB APL CAA CDNSKEY CDS CERT CNAME DHCID DLV DNAME DNSKEY DS HIP IPSECKEY KEY KX LOC MX NAPTR NS NSEC NSEC3 NSEC3PARAM PTR RRSIG RP SIG SOA SRV SSHFP TA TKEY TLSA TSIG TXT URI' -d 'Specify query type'
complete -c awl -l timeout -x -d 'Set timeout'
complete -c awl -l retries -x -d 'Set number of query retries'
complete -c awl -l no-edns -x -d 'Disable EDNS'
complete -f -c awl -l tcp -a '+vc +novc +tcp +notcp' -d 'TCP mode'
complete -f -c awl -l dnscrypt -a '+dnscrypt +nodnscrypt' -d 'Use DNSCrypt'
complete -c awl -s T -l tls -a '+tls +notls' -d 'Use DNS-over-TLS'
complete -c awl -s H -l https -a '+https +nohttps' -d 'Use DNS-over-HTTPS'
complete -c awl -s Q -l quic -a '+quic +noquic' -d 'Use DNS-over-QUIC'
complete -c awl -s j -l json -a '+json +nojson' -d 'Print as JSON'
complete -c awl -s j -l xml -a '+xml +noxml' -d 'Print as XML'
complete -c awl -s j -l yaml -a '+yaml +noyaml' -d 'Print as YAML'
complete -c awl -s x -l reverse -x -d 'Reverse lookup'
complete -f -c awl -s h -l help -d 'Print help and exit'
complete -f -c awl -s V -l version -d 'Print version and exit'
# complete -f -c awl -a '+search +nosearch' -d 'Set whether to use searchlist'
# complete -f -c awl -a '+showsearch +noshowsearch' -d 'Search with intermediate results'
complete -f -c awl -a '+recurse +norecurse' -d 'Recursive mode'
complete -f -c awl -l no-truncate -a '+ignore +noignore' -d 'Dont revert to TCP for TC responses.'
# complete -f -c awl -a '+fail +nofail' -d 'Dont try next server on SERVFAIL'
# complete -f -c awl -a '+besteffort +nobesteffort' -d 'Try to parse even illegal messages'
complete -f -c awl -a '+aaonly +noaaonly' -d 'Set AA flag in query (+[no]aaflag)'
complete -f -c awl -a '+adflag +noadflag' -d 'Set AD flag in query'
complete -f -c awl -a '+cdflag +nocdflag' -d 'Set CD flag in query'
complete -f -c awl -a '+cl +nocl' -d 'Control display of class in records'
# complete -f -c awl -a '+cmd +nocmd' -d 'Control display of command line'
complete -f -c awl -a '+comments +nocomments' -d 'Control display of comment lines'
complete -f -c awl -a '+question +noquestion' -d 'Control display of question'
complete -f -c awl -a '+answer +noanswer' -d 'Control display of answer'
complete -f -c awl -a '+authority +noauthority' -d 'Control display of authority'
complete -f -c awl -a '+additional +noadditional' -d 'Control display of additional'
complete -f -c awl -a '+stats +nostats' -d 'Control display of statistics'
complete -f -c awl -s s -l short -a '+short +noshort' -d 'Disable everything except short form of answer'
complete -f -c awl -a '+ttlid +nottlid' -d 'Control display of ttls in records'
complete -f -c awl -a '+all +noall' -d 'Set or clear all display flags'
complete -f -c awl -a '+qr +noqr' -d 'Print question before sending'
# complete -f -c awl -a '+nssearch +nonssearch' -d 'Search all authoritative nameservers'
complete -f -c awl -a '+identify +noidentify' -d 'ID responders in short answers'
complete -f -c awl -a '+trace +notrace' -d 'Trace delegation down from root'
complete -f -c awl -l dnssec -a '+dnssec +nodnssec +do +nodo' -d 'Request DNSSEC records'
complete -f -c awl -a '+nsid +nonsid' -d 'Request Name Server ID'
# complete -f -c awl -a '+multiline +nomultiline' -d 'Print records in an expanded format'
# complete -f -c awl -a '+onesoa +noonesoa' -d 'AXFR prints only one soa record'
complete -f -c awl -a '+tries=' -d 'Set number of UDP attempts'
complete -f -c awl -a '+retry=' -d 'Set number of UDP retries'
complete -f -c awl -a '+time=' -d 'Set query timeout'
complete -f -c awl -a '+bufsize=' -d 'Set EDNS0 Max UDP packet size'
complete -f -c awl -a '+ndots=' -d 'Set NDOTS value'
complete -f -c awl -a '+edns=' -d 'Set EDNS version'
complete -c awl -a '(__fish_complete_awl)'

112
completions/zsh.zsh Normal file
View File

@ -0,0 +1,112 @@
#compdef awl
# SPDX-License-Identifier: BSD-3-Clause
local curcontext="$curcontext" state line expl
local -a alts args
[[ -prefix + ]] && args=(
'*+'{no,}'tcp[use TCP instead of UDP for queries]'
'*+'{no,}'ignore[ignore truncation in UDP responses]'
'*+'{no,}'tls[use DNS-over-TLS for queries]'
'*+'{no,}'dnscrypt[use DNSCrypt for queries]'
'*+'{no,}'https=[use DNS-over-HTTPS for queries]:endpoint [/dns-query]'
'*+'{no,}'quic[use DNS-over-QUIC for queries]'
'*+'{no,}'aaonly[set aa flag in the query]'
'*+'{no,}'additional[print additional section of a reply]'
'*+'{no,}'adflag[set the AD (authentic data) bit in the query]'
'*+'{no,}'badcookie[retry BADCOOKIE responses]'
'*+'{no,}'cdflag[set the CD (checking disabled) bit in the query]'
'*+'{no,}'cookie[add a COOKIE option to the request]'
'*+edns=[specify EDNS version for query]:version (0-255)'
'*+noedns[clear EDNS version to be sent]'
'*+ednsflags=[set EDNS flags bits]:flags'
# '*+ednsopt=[specify EDNS option]:code point'
'*+noedns[clear EDNS options to be sent]'
'*+'{no,}'expire[send an EDNS Expire option]'
# '*+'{no,}'idnin[set processing of IDN domain names on input]'
'*+'{no,}'idnout[set conversion of IDN puny code on output]'
'*+'{no,}'keepalive[request EDNS TCP keepalive]'
'*+'{no,}'keepopen[keep TCP socket open between queries]'
'*+'{no,}'recurse[set the RD (recursion desired) bit in the query]'
# '*+'{no,}'nssearch[search all authoritative nameservers]'
'*+'{no,}'trace[trace delegation down from root]'
# '*+'{no,}'cmd[print initial comment in output]'
'*+'{no,}'short[print terse output]'
'*+'{no,}'identify[print IP and port of responder]'
'*+'{no,}'comments[print comment lines in output]'
'*+'{no,}'stats[print statistics]'
'*+padding[set padding block size]'
'*+'{no,}'qr[print query as it was sent]'
'*+'{no,}'question[print question section of a query]'
'*+'{no,}'raflag[set RA flag in the query]'
'*+'{no,}'answer[print answer section of a reply]'
'*+'{no,}'authority[print authority section of a reply]'
'*+'{no,}'all[set all print/display flags]'
'*+'{no,}'subnet=[send EDNS client subnet option]:addr/prefix-length'
'*+'{no,}'tcflag[set TC flag in the query]'
'*+time=[set query timeout]:timeout (seconds) [1]'
'*+timeout=[set query timeout]:timeout (seconds) [1]'
'*+tries=[specify number of UDP query attempts]:tries [3]'
'*+retry=[specify number of UDP query retries]:retries [2]'
# '*+'{no,}'rrcomments[set display of per-record comments]'
# '*+ndots=[specify number of dots to be considered absolute]:dots'
'*+bufsize=[specify UDP buffer size]:size (bytes)'
'*+'{no,}''{dnssec,do}'[enable DNSSEC]'
'*+'{no,}'nsid[include EDNS name server ID request in query]'
'*+'{no,}'class[display the class whening printing the answer]'
'*+'{no,}'ttlid[display the TTL whening printing the record]'
'*+'{no,}'ttlunits[display the TTL in human-readable units]'
# '*+'{no,}'unknownformat[print RDATA in RFC 3597 "unknown" format]'
'*+'{no,}'json[present the results as JSON]'
'*+'{no,}'xml[present the results as XML]'
'*+'{no,}'yaml[present the results as YAML]'
'*+'{no,}'zflag[set Z flag in query]'
)
# TODO: Add the regular (POSIX/GNU) flags
_arguments -s -C $args \
'(- *)-'{h,-help}'[display help information]' \
'(- *)-'{V,-version}'[display version information]' \
'-'{v,-verbosity}'=+[set verbosity to custom level]:verbosity:compadd -M "m\:{\-1-3}={\-1-3}" - \-1 0 1 2 3' \
'-'{v,-verbosity}'+[set verbosity to info]' \
'*-'{p,-port}'+[specify port number]:port:_ports' \
'*-'{q,-query}'+[specify host name to query]:host:_hosts' \
'*-'{c,-class}'+[specify class]:class:compadd -M "m\:{a-z}={A-Z}" - IN CS CH HS' \
'*-'{t,-qType}'+[specify type]:type:_dns_types' \
'*-4+[force IPv4 only]' \
'*-6+[force IPv6 only]' \
'*-'{x,-reverse}'+[reverse lookup]' \
'*--timeout+[timeout in seconds]:number [1]' \
'*--retries+[specify number of query retries]:number [2]' \
'*--no-edns+[disable EDNS]' \
'*--edns-ver+[specify EDNS version for query]:version (0-255) [0]' \
'*-'{D,-dnssec}'+[enable DNSSEC]' \
'*--expire+[send EDNS expire]' \
'*-'{n,-nsid}'+[include EDNS name server ID request in query]' \
'*--no-cookie+[disable sending EDNS cookie]' \
'*--keep-alive+[request EDNS TCP keepalive]' \
'*-'{b,-buffer-size}'+[specify UDP buffer size]:size (bytes) [1232]' \
'*--zflag+[set EDNS z-flag]:decimal, hex or octal [0]' \
'*--subnet+[set EDNS client subnet]:addr/prefix-length' \
'*--no-truncate+[ignore truncation in UDP responses]' \
'*--tcp+[use TCP instead of UDP for queries]' \
'*--dnscrypt+[use DNSCrypt for queries]' \
'*-'{T,-tls}'+[use DNS-over-TLS for queries]' \
'*-'{H,-https}'+[use DNS-over-HTTPS for queries]' \
'*-'{Q,-quic}'+[use DNS-over-QUIC for queries]' \
'*--tls-no-verify+[disable TLS verification]' \
'*--tls-host+[set TLS lookup hostname]:host:_hosts' \
'*-'{s,-short}'+[print terse output]' \
'*-'{j,-json}'+[present the results as JSON]' \
'*-'{X,-xml}'+[present the results as XML]' \
'*-'{y,-yaml}'+[present the results as YAML]' \
'*--trace+[trace from the root]' \
'*: :->args' && ret=0
if [[ -n $state ]]; then
if compset -P @; then
_wanted hosts expl 'DNS server' _hosts && ret=0;
else
_alternative 'hosts:host:_hosts' 'types:query type:_dns_types' && ret=0
fi
fi
return ret

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
Helper functions for getting local nameservers
Package conf contains helper functions for getting local nameservers
Currently supported: Unix, Windows, Plan 9 (tested on 9front)
*/

View File

@ -1,29 +1,44 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build plan9
package conf
import (
"errors"
"fmt"
"os"
"strings"
"github.com/miekg/dns"
)
// GetDNSConfig gets DNS information from Plan 9, because it's different from UNIX and Windows.
//
// Plan 9 stores its network data in /net/ndb, which seems to be formatted a specific way
// Yoink it and use it.
//
// See ndb(7).
func GetPlan9Config(str string) (*dns.ClientConfig, error) {
func GetDNSConfig() (*dns.ClientConfig, error) {
dat, err := os.ReadFile("/net/ndb")
if err != nil {
return nil, fmt.Errorf("read ndb: %w", err)
}
str := string(dat)
str = strings.ReplaceAll(str, "\n", "")
spl := strings.FieldsFunc(str, splitChars)
var servers []string
for _, option := range spl {
if strings.HasPrefix(option, "dns=") {
servers = append(servers, strings.TrimPrefix(option, "dns="))
}
}
if len(servers) == 0 {
return nil, fmt.Errorf("plan9: no DNS servers found")
return nil, errPlan9
}
// TODO: read more about how customizable Plan 9 is
@ -38,3 +53,5 @@ func GetPlan9Config(str string) (*dns.ClientConfig, error) {
func splitChars(r rune) bool {
return r == ' ' || r == '\t'
}
var errPlan9 = errors.New("plan9Config: no DNS servers found")

View File

@ -1,52 +1,25 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build plan9
package conf_test
import (
"runtime"
"testing"
"git.froth.zone/sam/awl/conf"
"dns.froth.zone/awl/conf"
"gotest.tools/v3/assert"
)
func TestGetPlan9Config(t *testing.T) {
func TestPlan9Config(t *testing.T) {
t.Parallel()
ndbs := []struct {
in string
want string
}{
{`ip=192.168.122.45 ipmask=255.255.255.0 ipgw=192.168.122.1
sys=chog9
dns=192.168.122.1`, "192.168.122.1"},
{`ipnet=murray-hill ip=135.104.0.0 ipmask=255.255.0.0
dns=135.104.10.1
ntp=ntp.cs.bell-labs.com
ipnet=plan9 ip=135.104.9.0 ipmask=255.255.255.0
ntp=oncore.cs.bell-labs.com
smtp=smtp1.cs.bell-labs.com
ip=135.104.9.6 sys=anna dom=anna.cs.bell-labs.com
smtp=smtp2.cs.bell-labs.com`, "135.104.10.1"},
if runtime.GOOS != "plan9" {
t.Skip("Not running Plan 9, skipping")
}
for _, ndb := range ndbs {
// Go is a little quirky
ndb := ndb
t.Run(ndb.want, func(t *testing.T) {
t.Parallel()
act, err := conf.GetPlan9Config(ndb.in)
assert.NilError(t, err)
assert.Equal(t, ndb.want, act.Servers[0])
})
}
conf, err := conf.GetDNSConfig()
invalid := `sys = spindle
dom=spindle.research.bell-labs.com
bootf=/mips/9powerboot
ip=135.104.117.32 ether=080069020677
proto=il`
act, err := conf.GetPlan9Config(invalid)
assert.ErrorContains(t, err, "no DNS servers found")
assert.Assert(t, act == nil)
assert.NilError(t, err)
assert.Assert(t, len(conf.Servers) != 0)
}

View File

@ -1,24 +1,22 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build !windows
//go:build unix || (!windows && !plan9 && !js && !zos)
// FIXME: Can remove the or on the preprocessor when Go 1.18 becomes obsolete
package conf
import (
"os"
"runtime"
"fmt"
"github.com/miekg/dns"
)
// Get the DNS configuration, either from /etc/resolv.conf or somewhere else
// GetDNSConfig gets the DNS configuration, either from /etc/resolv.conf or somewhere else.
func GetDNSConfig() (*dns.ClientConfig, error) {
if runtime.GOOS == "plan9" {
dat, err := os.ReadFile("/net/ndb")
if err != nil {
return nil, err
}
return GetPlan9Config(string(dat))
} else {
return dns.ClientConfigFromFile("/etc/resolv.conf")
conf, err := dns.ClientConfigFromFile("/etc/resolv.conf")
if err != nil {
return nil, fmt.Errorf("unix config: %w", err)
}
return conf, nil
}

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build !windows
//go:build unix || (!windows && !plan9 && !js && !zos)
// FIXME: Can remove the or on the preprocessor when Go 1.18 becomes obsolete
package conf_test
@ -7,14 +9,17 @@ import (
"runtime"
"testing"
"git.froth.zone/sam/awl/conf"
"dns.froth.zone/awl/conf"
"gotest.tools/v3/assert"
)
func TestNonWinConfig(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Not running Windows, skipping")
func TestUnixConfig(t *testing.T) {
t.Parallel()
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" || runtime.GOOS == "js" || runtime.GOOS == "zos" {
t.Skip("Not running Unix-like, skipping")
}
conf, err := conf.GetDNSConfig()
assert.NilError(t, err)
assert.Assert(t, len(conf.Servers) != 0)

18
conf/wasm.go Normal file
View File

@ -0,0 +1,18 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build js
package conf
import (
"errors"
"github.com/miekg/dns"
)
// GetDNSConfig doesn't do anything, because it is impossible (and bad security)
// if it could, as that is the definition of a DNS leak.
func GetDNSConfig() (*dns.ClientConfig, error) {
return nil, errNotImplemented
}
var errNotImplemented = errors.New("not implemented")

View File

@ -4,6 +4,7 @@
package conf
import (
"fmt"
"strings"
"unsafe"
@ -16,37 +17,48 @@ import (
https://gist.github.com/moloch--/9fb1c8497b09b45c840fe93dd23b1e98
*/
// WindowsDnsClientConfig - returns all DNS server addresses using windows fuckery.
// GetDNSConfig (Windows version) returns all DNS server addresses using windows fuckery.
//
// Here be dragons.
func GetDNSConfig() (*dns.ClientConfig, error) {
l := uint32(20000)
b := make([]byte, l)
length := uint32(100000)
byt := make([]byte, length)
// Windows is an utter fucking trash fire of an operating system.
if err := windows.GetAdaptersAddresses(windows.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l); err != nil {
return nil, err
//nolint:gosec // This is necessary unless we want to drop 1.18
if err := windows.GetAdaptersAddresses(windows.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&byt[0])), &length); err != nil {
return nil, fmt.Errorf("config, windows: %w", err)
}
var addresses []*windows.IpAdapterAddresses
for addr := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); addr != nil; addr = addr.Next {
//nolint:gosec // This is necessary unless we want to drop 1.18
for addr := (*windows.IpAdapterAddresses)(unsafe.Pointer(&byt[0])); addr != nil; addr = addr.Next {
addresses = append(addresses, addr)
}
resolvers := map[string]bool{}
for _, addr := range addresses {
for next := addr.FirstUnicastAddress; next != nil; next = next.Next {
if addr.OperStatus != windows.IfOperStatusUp {
continue
}
if next.Address.IP() != nil {
for dnsServer := addr.FirstDnsServerAddress; dnsServer != nil; dnsServer = dnsServer.Next {
ip := dnsServer.Address.IP()
if ip.IsMulticast() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() || ip.IsUnspecified() {
continue
}
if ip.To16() != nil && strings.HasPrefix(ip.To16().String(), "fec0:") {
continue
}
resolvers[ip.String()] = true
}
break
}
}

View File

@ -7,15 +7,19 @@ import (
"runtime"
"testing"
"git.froth.zone/sam/awl/conf"
"dns.froth.zone/awl/conf"
"gotest.tools/v3/assert"
)
func TestWinConfig(t *testing.T) {
t.Parallel()
if runtime.GOOS != "windows" {
t.Skip("Not running Windows, skipping")
}
conf, err := conf.GetDNSConfig()
assert.NilError(t, err)
assert.Assert(t, len(conf.Servers) != 0)
}

244
doc/awl.1
View File

@ -1,244 +0,0 @@
.\" Generated by scdoc 1.11.2
.\" Complete documentation for this program is not available as a GNU info page
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.nh
.ad l
.\" Begin generated content:
.TH "awl" "1" "2022-07-25"
.PP
.SH NAME
awl - DNS lookup tool
.PP
.SH SYNOPSIS
\fBawl\fR [ \fIOPTIONS\fR ] \fIname\fR [ \fI@server\fR ] [ \fItype\fR ]
.br
where
.PP
\fIname\fR is the query to make (\fBexample: froth.\&zone\fR)
.br
\fI@server\fR is the server to query (\fBexample: dns.\&froth.\&zone\fR)
.br
\fItype\fR is the DNS resource type (\fBexample: AAAA\fR)
.PP
.SH DESCRIPTION
.PP
\fBawl\fR (\fBa\fRwls \fBw\fRant \fBl\fRicorice) is a simple tool designed to make DNS queries,
much like the venerable \fIdig\fR(1).\& An awl is a tool used to make small holes,
typically used in leatherworking.\&
.PP
\fBawl\fR is designed to be a more "modern" version of \fIdrill\fR(1) by including
some more recent RFCs and output options.\& \fBawl\fR is still heavily
Work-In-Progress so some features may get added or removed.\&
.PP
.SH OPTIONS
.RS 4
Dig-like +[no]flags are supported, see dig(1)
.PP
\fB-D\fR, \fB--dnssec\fR, \fB+dnssec\fR
.br
Enable DNSSEC.\& This needs to be manually enabled.\&
.PP
\fB-v\fR \fIvalue\fR
.br
Set verbosity (currently WIP)
.PP
\fB-V\fR
.br
Print the version and exit.\&
.PP
\fB-h\fR
.br
Show a "short" help message.\&
.PP
.RE
.SS Query Options
.RS 4
\fB-4\fR
.br
Only make query over IPv4
.PP
\fB-6\fR
.br
Only make query over IPv6
.PP
\fB-p\fR, \fB--port\fR \fIport\fR
.br
Sets the port to query.\&
.br
.br
\fIDefault Ports\fR:
.RS 4
.PD 0
.IP \(bu 4
\fI53\fR for \fBUDP\fR and \fBTCP\fR
.IP \(bu 4
\fI853\fR for \fBTLS\fR and \fBQUIC\fR
.IP \(bu 4
\fI443\fR for \fBHTTPS\fR
.PD
.PP
.RE
\fB-q\fR, \fB--query\fR \fIdomain\fR
.br
Domain to query (eg.\& example.\&com)
.PP
\fB-c\fR, \fB--class\fR \fIclass\fR
.br
DNS class to query (eg.\& IN, CH)
.PP
\fB-t\fR, \fB--qType\fR \fItype\fR
.br
DNS type to query (eg.\& A, NS)
.PP
\fB--no-truncate\fR, \fB+ignore\fR
.br
Ignore UDP truncation (by default, awl \fIretries with TCP\fR)
.PP
\fB--tcp\fR, \fB+tcp\fR, \fB+vc\fR
.br
Use TCP for the query (see \fIRFC 7766\fR)
.PP
\fB--dnscrypt\fR, \fB+dnscrypt\fR
.br
Use DNSCrypt
.PP
\fB-T\fR, \fB--tls\fR, \fB+tls\fR
.br
Use DNS-over-TLS, implies \fB--tcp\fR (see \fIRFC 7858\fR)
.PP
\fB-H\fR.\& \fB--https\fR, \fB+https\fR
.br
Use DNS-over-HTTPS (see \fIRFC 8484\fR)
.PP
\fB-Q\fR.\& \fB--quic\fR, \fB+quic\fR
.br
Use DNS-over-QUIC (see \fIRFC 9250\fR)
.PP
\fB-x\fR, \fB--reverse\fR
.br
Do a reverse lookup.\& Sets default \fItype\fR to PTR.\&
.br
\fBawl\fR automatically makes an IP or phone number canonical.\&
.PP
\fB--timeout\fR \fIseconds\fR, \fB+timeout=\fR\fIseconds\fR
.br
Set the timeout period.\& Floating point numbers are accepted.\&
.br
0.\&5 seconds is the minimum.\&
.PP
\fB--retries\fR \fIint\fR, \fB+tries\fR=\fIint\fR, \fB+ retry\fR=\fIint\fR
.br
Set the number of retries.\&
.br
Retry is one more than tries, dig style
.PP
.RE
.SS DNS Flags
.PP
.RS 4
\fB--aa=[false]\fR, \fB+[no]aaflag\fR
.br
(Set, Unset) AA (Authoritative Answer) flag
.PP
\fB--ad=[false]\fR, \fB+[no]adflag\fR
.br
(Set, Unset) AD (Authenticated Data) flag
.PP
\fB--tc=[false]\fR, \fB+[no]tcflag\fR
.br
(Set, Unset) TC (TrunCated) flag
.PP
\fB-z=[false]\fR, \fB+[no]zflag\fR
.br
(Set, Unset) Z (Zero) flag
.PP
\fB--cd=[false]\fR, \fB+[no]cdflag\fR
.br
(Set, Unset) CD (Checking Disabled) flag
.PP
\fB--qr=[false]\fR, \fB+[no]qrflag\fR
.br
(Set, Unset) QR (QueRy) flag
.PP
\fB--rd=[true]\fR, \fB+[no]rdflag\fR
.br
(Set, Unset) RD (Recursion Desired) flag
.PP
\fB--ra=[false]\fR, \fB+[no]raflag\fR
.br
(Set, Unset) RA (Recursion Available) flag
.PP
.RE
.SS Output Display
.RS 4
\fB--no-question\fR, \fB+noquestion\fR
.br
Do not display the Question section
.PP
\fB--no-answer\fR, \fB+noanswer\fR
.br
Do not display the Answer section
.PP
\fB--no-answer\fR, \fB+noanswer\fR
.br
Do not display the Answer section
.PP
\fB--no-authority\fR, \fB+noauthority\fR
.br
Do not display the Authority section
.PP
\fB--no-additional\fR, \fB+noadditional\fR
.br
Do not display the Additional section
.PP
\fB--no-statistics\fR, \fB+nostats\fR
.br
Do not display the Statistics (additional comments) section
.PP
.RE
.SS Output Formats
.RS 4
\fB-j\fR, \fB--json\fR, \fB+json\fR
.br
Print the query results as JSON.\&
.PP
\fB-X\fR, \fB--xml\fR, \fB+xml\fR
.br
Print the query results as XML.\&
.PP
\fB-y\fR, \fB--yaml\fR, \fB+yaml\fR
.br
Print the query results as YAML.\&
.PP
\fB-s\fR, \fB--short\fR, \fB+short\fR
.br
Print just the address of the answer.\&
.PP
.RE
.SH EXAMPLES
.nf
.RS 4
awl grumbulon\&.xyz -j +cd
.fi
.RE
Run a query of your local resolver for the A records of grumbulon.\&xyz, print
them as JSON and disable DNSSEC verification.\&
.PP
.nf
.RS 4
awl +short example\&.com AAAA @1\&.1\&.1\&.1
.fi
.RE
Query 1.\&1.\&1.\&1 for the AAAA records of example.\&com, print just the answers
.PP
.nf
.RS 4
awl -xT PTR 8\&.8\&.4\&.4 @dns\&.google
.fi
.RE
Query dns.\&google over TLS for the PTR record to the IP address 8.\&8.\&4.\&4
.PP
.SH SEE ALSO
\fIdrill\fR(1), \fIdig\fR(1), the many DNS RFCs

@ -1 +0,0 @@
Subproject commit 0fba1fbe4b12e8c88514b3f7d98be3e75a5a034d

View File

@ -1,9 +1,10 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
awl is a DNS lookup tool written in Go,
similar to (and heavily inspired by) drill.
awl is a DNS lookup tool written in Go, similar to (and heavily inspired by) drill.
It runs and displays similar outputs to drill, without any frills.
Options are given to print with JSON
Options are given to print with JSON, XML and YAML.
Supports results from DNS-over-[UDP, TCP, TLS, HTTPS, QUIC] servers

1
docs/CODE_OF_CONDUCT.md Symbolic link
View File

@ -0,0 +1 @@
/dev/null

57
docs/CONTRIBUTING.md Normal file
View File

@ -0,0 +1,57 @@
# Contributing to awl
First off, thank you! We appreciate your interest in wanting to contribute to awl.
> If you like the project, spread the word! Help us grow by sharing the project with anyone you thing might be interested. Here are some ways you can help:
>
> - Star the project on GitHub
> - Share the project on social media
> - Tell your friends about the project
## How to contribute
If you want to contribute to awl, you can do so by:
- [Reporting a bug](#reporting-a-bug)
- [Requesting a feature](#requesting-a-feature)
- [Submitting a pull request](#submitting-a-pull-request)
### Reporting a bug
If you find a bug in awl, please [open an issue](https://git.froth.zone/sam/awl/issues) on the project's issue tracker. When reporting a bug, please include as much information as possible, such as:
- The version of awl you are using
- The operating system you are using
- The steps to reproduce the bug
- Any error messages you received
### Requesting a feature
If you have an idea for a feature you would like to see in awl, please [open an issue](https://git.froth.zone/sam/awl/issues) on the project's issue tracker. When requesting a feature, please include as much information as possible, such as:
- A description of the feature
- Why you think the feature would be useful
- Any other relevant information
### Submitting a pull request
If you would like to contribute code to awl, you can do so by submitting a pull request. To submit a pull request, follow these steps:
1. Fork the project on Git
2. Create a new branch for your changes
3. Make your changes
4. Push your changes to your fork
5. [Open a pull request](https://git.froth.zone/sam/awl/pulls) on the project's Git repository
When submitting a pull request, please include as much information as possible, such as:
- A description of the changes you made
- Why you made the changes
- Any other relevant information
Alternatively, you can also contribute by sending an email to the project's [mailing list](https://lists.sr.ht/~sammefishe/awl-devel). For more information about using Git over email, refer to [git-send-email.io](https://git-send-email.io/)
#### Code Style
Before submitting a pull request, please run `make lint` to ensure your code adheres to the project's code style.
Make sure that you have `golangci-lint` installed, that is our linter of choice.

262
docs/awl.1.scd Normal file
View File

@ -0,0 +1,262 @@
awl(1)
; SPDX-License-Identifier: BSD-3-Clause
# NAME
awl - DNS lookup tool
# SYNOPSIS
*awl* [ _OPTIONS_ ] _name_ [ _@server_ ] [ _type_ ], where
_name_ is the query to make (example: froth.zone)++
_@server_ is the server to query (example: dns.froth.zone)++
_type_ is the DNS resource type (example: AAAA)
# DESCRIPTION
*awl* (*a*wls *w*ant *l*icorice) is a simple tool designed to make DNS queries,
much like the venerable *dig*(1). An awl is a tool used to make small holes,
typically used in leatherworking.
*awl* is designed to be a more "modern" version of *drill*(1) by including
some more recent RFCs and output options.
When no arguments are given, *awl* will perform an _NS_ query on the root ('_._').
When a nameserver is not given, *awl* will query a random system nameserver.
If one cannot be found, *awl* will query the localhost.
# OPTIONS
*-4*
Force only IPv4
*-6*
Force only IPv6
*-c*, *--class* _class_
DNS class to query (eg. IN, CH)
The default is IN.
*-h*
Show a "short" help message.
*-p*, *--port* _port_
Sets the port to query. Default ports listed below.
- _53_ for *UDP* and *TCP*
- _853_ for *TLS* and *QUIC*
- _443_ for *HTTPS*
*-q*, *--query* _domain_
Explicitly set a domain to query (eg. example.com)
*-t*, *--qType* _type_
Explicitly set a DNS type to query (eg. A, AAAA, NS)
The default is A.
*-v*[=_int_]
Set verbosity of output
Accepted values are as follows:
- _0_: Only log errors.
- _1_: Log warnings. *This is the default.*
- _2_: Log information *Default when specifying just* _-v_.
- _3_: Log information useful for debugging.
Setting a value lower than 0 disables logging entirely.
By default, specifying just *-v* sets the verbosity to 2 (info).
*-x*, *--reverse*
Do a reverse lookup. Sets default *type* to PTR.
*awl* automatically makes an IP or phone number canonical.
*-V*
Print the version and exit.
# QUERY OPTIONS
Anything in [brackets] is optional.
Many options are inherited from *dig*(1).
*--aa*[=_bool_], *+*[no]*aaflag*, *+*[no]*aaonly*
Sets the AA (Authoritative Answer) flag.
*--ad*[=_bool_], *+*[no]*adflag*
Sets the AD (Authenticated Data) flag.
*--no-additional*, *+*[no]*additional*
Toggle the display of the Additional section.
*--no-answer*, *+*[no]*answer*
Toggle the display of the Answer section.
*--no-authority*, *+*[no]*authority*
Toggle the display of the Authority section.
*--no-bad-cookie*, *+*[no]*badcookie*
\[Do not\] ignore BADCOOKIE responses
*--buffer-size* _int_, *+bufize*=_int_
Set the UDP message buffer size, using EDNS.
Max is 65535, minimum is zero.
The default value is 1232.
*--cd*[=_bool_], *+*[no]*cdflag*
(Set, Unset) CD (Checking Disabled) flag.
*--no-cookie*, *+*[no]*cookie*[=_string_]
Send an EDNS cookie.
This is enabled by default with a random string.
*-D*, *--dnssec*, *+dnssec*, *+do*
Request DNSSEC records as well.
This sets the DNSSEC OK bit (DO)
*--dnscrypt*, *+*[no]*dnscrypt*
Use DNSCrypt.
*--expire*. *+*[no]*expire*
Send an EDNS Expire.
*--edns-ver*, *+edns*[=_int_]
Enable EDNS and set EDNS version.
The maximum value is 255, and the minimum (default) value is 0.
*--no-edns*, *+noedns*
Disable EDNS.
*-H*, *--https*, *+*[no]*https*[=_endpoint_], *+*[no]*https-post*[=_endpoint_]
Use DNS-over-HTTPS (see RFC 8484).
The default endpoint is _/dns-query_
*+*[no]*https-get*[=_endpoint_]
Use an HTTP GET instead of an HTTP POST when making a DNS-over-HTTPS query.
*+*[no]*idnout*
Converts [or leaves] punycode on output.
Input is automatically translated to punycode.
*--no-truncate*, *+ignore*
Ignore UDP truncation (by default, awl *retries with TCP*).
*-j*, *--json*, *+*[no]*json*
Print the query results as JSON.
The result is *not* in compliance with RFC 8427.
*--keep-alive*, *+*[no]*keepalive*, *+*[no]*keepopen*
Send an EDNS keep-alive.
This does nothing unless using TCP.
*--nsid*, *+*[no]*nsid*
Send an EDNS name server ID request.
*--qr*[=_bool_], *+*[no]*qrflag*
Sets the QR (QueRy) flag.
*--no-question*, *+*[no]*question*
Toggle the display of the Question section.
*-Q*. *--quic*, *+*[no]*quic*
Use DNS-over-QUIC (see RFC 9250).
*-s*, *--short*, *+*[no]*short*
Print just the address of the answer.
*--no-statistics*, *+*[no]*stats*
Toggle the display of the Statistics (additional comments) section.
*--subnet* _ip_[_/prefix_], *+*[no]*subnet*[=_ip_[_/prefix_]]
Send an EDNS Client Subnet option with the specified address.
Like *dig*(1), setting the IP to _0.0.0.0/0_, _::/0_ or _0_ will signal the resolver to not use any client information when returning the query.
*--tc*[=_bool_], *+*[no]*tcflag*
Sets the TC (TrunCated) flag
*--tcp*, *+*[no]*tcp*, *+*[no]*vc*
Use TCP for the query (see RFC 7766).
*--timeout* _seconds_, *+timeout*=_seconds_
Set the timeout period. Floating point numbers are accepted.
0.5 seconds is the minimum.
*-T*, *--tls*, *+*[no]*tls*
Use DNS-over-TLS, implies *--tcp* (see RFC 7858)
*--tls-host* _string_
Set hostname to use for TLS certificate validation.
Default is the name of the domain when querying over TLS, and empty for IPs.
*--tls-no-verify*
Ignore TLS validation when performing a DNS query.
*--trace*, *+trace*
Trace the path of the query from the root, acting like its own resolver.
This option enables DNSSEC.
When *@server* is specified, this will only affect the initial query.
*--retries* _int_, *+tries*=_int_, *+retry*=_int_
Set the number of retries.
Retry is one more than tries, dig style.
*-X*, *--xml*, *+*[no]*xml*
Print the query results as XML.
*-y*, *--yaml*, *+*[no]*yaml*
Print the query results as YAML.
*-z*[=_bool_], *+*[no]*zflag*
Sets the Z (Zero) flag.
*--zflag* _int_, *+ednsflags*=_int_
Set the must-be-zero EDNS flags.
Decimal, hexadecimal and octal are supported.
Trying to set DO will be ignored.
# EXIT STATUS
The exit code is 0 when a query is successfully made and received.
This includes SERVFAILs, NOTIMPL among others.
# EXAMPLES
```
awl grumbulon.xyz -j +cd
```
Run a query of your local resolver for the A records of grumbulon.xyz, print
them as JSON and disable DNSSEC verification.
```
awl +short example.com AAAA @1.1.1.1
```
Query 1.1.1.1 for the AAAA records of example.com, print just the answers
```
awl -xT PTR 8.8.4.4 @dns.google
```
Query dns.google over TLS for the PTR record to the IP address 8.8.4.4
# SEE ALSO
*drill*(1), *dig*(1)
# STANDARDS
RFC 1034,1035 (UDP), 7766 (TCP), 7858 (TLS), 8484 (HTTPS), 9230 (QUIC)
Probably more, _https://www.statdns.com/rfc_
# BUGS
Full parity with *dig*(1) is not complete.
This man page is probably not complete.
Likely numerous more, report them either to the tracker
_https://git.froth.zone/sam/awl/issues_ or via email
_~sammefishe/awl-develop@lists.sr.ht_

BIN
docs/img/awl-text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

1
docs/img/awl.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 505 KiB

7
docs/makeman.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
set -e
rm -f docs/awl.1.gz
scdoc <docs/awl.1.scd >docs/awl.1
gzip -9 -n docs/awl.1

1
docs/wiki Submodule

@ -0,0 +1 @@
Subproject commit ab0ac7e0bd1b92339cc97ba026f148478df5a860

55
go.mod
View File

@ -1,40 +1,33 @@
module git.froth.zone/sam/awl
module dns.froth.zone/awl
go 1.18
go 1.21.9
toolchain go1.22.3
require (
github.com/ameshkov/dnscrypt/v2 v2.2.3
github.com/lucas-clemente/quic-go v0.28.1
github.com/miekg/dns v1.1.50
dns.froth.zone/dnscrypt v0.0.2
github.com/dchest/uniuri v1.2.0
github.com/miekg/dns v1.1.59
github.com/quic-go/quic-go v0.43.1
github.com/stefansundin/go-zflag v1.1.1
golang.org/x/net v0.0.0-20220725212005-46097bf591d3
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.3.0
golang.org/x/net v0.25.0
golang.org/x/sys v0.20.0
gopkg.in/yaml.v3 v3.0.1
gotest.tools/v3 v3.5.1
)
require (
github.com/AdguardTeam/golibs v0.10.9 // indirect
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
github.com/AdguardTeam/golibs v0.20.3 // indirect
github.com/ameshkov/dnsstamps v1.0.3 // indirect
github.com/google/go-cmp v0.5.5 // indirect
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 // indirect
)
require (
github.com/cheekybits/genny v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/stretchr/testify v1.8.0 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.11 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/onsi/ginkgo/v2 v2.16.0 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f // indirect
golang.org/x/mod v0.16.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/tools v0.19.0 // indirect
)

384
go.sum
View File

@ -1,343 +1,75 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/golibs v0.10.9 h1:F9oP2da0dQ9RQDM1lGR7LxUTfUWu8hEFOs4icwAkKM0=
github.com/AdguardTeam/golibs v0.10.9/go.mod h1:W+5rznZa1cSNSFt+gPS7f4Wytnr9fOrd5ZYqwadPw14=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us=
github.com/ameshkov/dnscrypt/v2 v2.2.3 h1:X9UP5AHtwp46Ji+sGFfF/1Is6OPI/SjxLqhKpx0P5UI=
github.com/ameshkov/dnscrypt/v2 v2.2.3/go.mod h1:xJB9cE1/GF+NB6EEQqRlkoa4bjcV2w7VYn1G+zVq7Bs=
github.com/ameshkov/dnsstamps v1.0.1/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
dns.froth.zone/dnscrypt v0.0.2 h1:ytqjic/Qway4OuLw8ee0ubxdNzy+F3igUGDrEVwyLls=
dns.froth.zone/dnscrypt v0.0.2/go.mod h1:QZ0HAm7mWe8wz1dTqbKmTZhlr06x5qpe6ZCTPJ7uY30=
github.com/AdguardTeam/golibs v0.20.3 h1:5RiDypxBebd4Y2eftwm6JJla18oBqRHwanR7q0rnrxw=
github.com/AdguardTeam/golibs v0.20.3/go.mod h1:/votX6WK1PdcZ3T2kBOPjPCGmfhlKixhI6ljYrFRPvI=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU=
github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 h1:7m/WlWcSROrcK5NxuXaxYD32BZqe/LEEnBrWcH/cOqQ=
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
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/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g=
github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
github.com/onsi/ginkgo/v2 v2.16.0 h1:7q1w9frJDzninhXxjZd+Y/x54XNjG/UlRLIYPZafsPM=
github.com/onsi/ginkgo/v2 v2.16.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/quic-go/quic-go v0.43.1 h1:fLiMNfQVe9q2JvSsiXo4fXOEguXHGGl9+6gLp4RPeZQ=
github.com/quic-go/quic-go v0.43.1/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stefansundin/go-zflag v1.1.1 h1:XabhzWS588bVvV1z1UctSa6i8zHkXc5W9otqtnDSHw8=
github.com/stefansundin/go-zflag v1.1.1/go.mod h1:HXX5rABl1AoTcZ2jw+CqJ7R8irczaLquGNZlFabZooc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220725212005-46097bf591d3 h1:2yWTtPWWRcISTw3/o+s/Y4UOMnQL71DWyToOANFusCg=
golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/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-20210615035016-665e8c7367d1/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-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
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/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f h1:3CW0unweImhOzd5FmYuRsD4Y4oQFKZIjAnKbjV4WIrw=
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=

View File

@ -1,4 +0,0 @@
/*
Useful structs used everywhere I couldn't find a better place to shove
*/
package helpers

View File

@ -1,25 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package helpers
import (
"time"
"github.com/miekg/dns"
)
// The DNS response.
type Response struct {
DNS *dns.Msg // The full DNS response
RTT time.Duration `json:"rtt"` // The time it took to make the DNS query
}
// A structure for a DNS query.
type Request struct {
Server string `json:"server"` // The server to make the DNS request from
Type uint16 `json:"request"` // The type of request
Class uint16 `json:"class"` // DNS Class
Name string `json:"name"` // The domain name to make a DNS request for
Timeout time.Duration // The maximum timeout
Retries int // Number of queries to retry
}

View File

@ -1,13 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package helpers_test
import (
"testing"
"gotest.tools/v3/assert"
)
func TestNothing(t *testing.T) {
assert.Equal(t, 0, 0)
}

View File

@ -1,76 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package logawl
import (
"fmt"
"io"
"sync"
"sync/atomic"
)
type (
Level int32
Logger struct {
Mu sync.Mutex
Level Level
Prefix string
Out io.Writer
buf []byte
isDiscard int32
}
)
// Stores whatever input value is in mem address of l.level.
func (l *Logger) SetLevel(level Level) {
atomic.StoreInt32((*int32)(&l.Level), int32(level))
}
// Mostly nothing.
func (l *Logger) GetLevel() Level {
return l.level()
}
// Retrieves whatever was stored in mem address of l.level.
func (l *Logger) level() Level {
return Level(atomic.LoadInt32((*int32)(&l.Level)))
}
// Unmarshalls the int value of level for writing the header.
func (l *Logger) UnMarshalLevel(lv Level) (string, error) {
switch lv {
case 0:
return "ERROR ", nil
case 1:
return "WARN ", nil
case 2:
return "INFO ", nil
case 3:
return "DEBUG ", nil
}
return "", fmt.Errorf("invalid log level")
}
func (l *Logger) IsLevel(level Level) bool {
return l.level() >= level
}
var AllLevels = []Level{
ErrLevel,
WarnLevel,
InfoLevel,
DebugLevel,
}
const (
// Fatal logs (will call exit(1)).
ErrLevel Level = iota
// Error logs.
WarnLevel
// What is going on level.
InfoLevel
// Verbose log level.
DebugLevel
)

View File

@ -1,144 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package logawl
import (
"fmt"
"os"
"sync/atomic"
"time"
)
// Calling New instantiates Logger
//
// Level can be changed to one of the other log levels (FatalLevel, ErrorLevel, InfoLevel, DebugLevel)
func New() *Logger {
return &Logger{
Out: os.Stderr,
Level: InfoLevel, //Default value is InfoLevel
}
}
// Takes any and prints it out to Logger -> Out (io.Writer (default is std.Err))
func (l *Logger) Println(level Level, v ...any) {
if atomic.LoadInt32(&l.isDiscard) != 0 {
return
}
//If verbose is not set --debug etc print _nothing_
if l.IsLevel(level) {
switch level { //Goes through log levels and does stuff based on them (Fatal os.Exit...etc)
case 0:
err := l.Printer(0, fmt.Sprintln(v...)) //Fatal level
if err != nil {
fmt.Fprintln(os.Stderr, "FATAL: Logger failed: ", err)
}
case 1:
err := l.Printer(1, fmt.Sprintln(v...)) //Error level
if err != nil {
fmt.Fprintln(os.Stderr, "FATAL: Logger failed: ", err)
}
case 2:
err := l.Printer(2, fmt.Sprintln(v...)) //Info level
if err != nil {
fmt.Fprintln(os.Stderr, "FATAL: Logger failed: ", err)
}
case 3:
err := l.Printer(3, fmt.Sprintln(v...)) //Debug level
if err != nil {
fmt.Fprintln(os.Stderr, "FATAL: Logger failed: ", err)
}
default:
break
}
}
}
// Formats the log header as such <LogLevel> YYYY/MM/DD HH:MM:SS (local time) <the message to log>
func (l *Logger) FormatHeader(buf *[]byte, t time.Time, line int, level Level) error {
if lvl, err := l.UnMarshalLevel(level); err == nil {
// This is ugly but functional
// maybe there can be an append func or something in the future
*buf = append(*buf, lvl...)
year, month, day := t.Date()
*buf = append(*buf, '[')
formatter(buf, year, 4)
*buf = append(*buf, '/')
formatter(buf, int(month), 2)
*buf = append(*buf, '/')
formatter(buf, day, 2)
*buf = append(*buf, ' ')
hour, min, sec := t.Clock()
formatter(buf, hour, 2)
*buf = append(*buf, ':')
formatter(buf, min, 2)
*buf = append(*buf, ':')
formatter(buf, sec, 2)
*buf = append(*buf, ']')
*buf = append(*buf, ':')
*buf = append(*buf, ' ')
} else {
return fmt.Errorf("invalid log level choice")
}
return nil
}
// Printer prints the formatted message directly to stdErr
func (l *Logger) Printer(level Level, s string) error {
now := time.Now()
var line int
l.Mu.Lock()
defer l.Mu.Unlock()
l.buf = l.buf[:0]
err := l.FormatHeader(&l.buf, now, line, level)
if err != nil {
return err
}
l.buf = append(l.buf, s...)
if len(s) == 0 || s[len(s)-1] != '\n' {
l.buf = append(l.buf, '\n')
}
_, err = l.Out.Write(l.buf)
return err
}
// Some line formatting stuff from Golang log stdlib file
//
// Please view https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/log/log.go;drc=41e1d9075e428c2fc32d966b3752a3029b620e2c;l=96
//
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
func formatter(buf *[]byte, i int, wid int) {
// Assemble decimal in reverse order.
var b [20]byte
bp := len(b) - 1
for i >= 10 || wid > 1 {
wid--
q := i / 10
b[bp] = byte('0' + i - q*10)
bp--
i = q
}
// i < 10
b[bp] = byte('0' + i)
*buf = append(*buf, b[bp:]...)
}
// Call print directly with Debug level
func (l *Logger) Debug(v ...any) {
l.Println(DebugLevel, v...)
}
// Call print directly with Info level
func (l *Logger) Info(v ...any) {
l.Println(InfoLevel, v...)
}
// Call print directly with Warn level
func (l *Logger) Warn(v ...any) {
l.Println(WarnLevel, v...)
}
// Call print directly with Error level
func (l *Logger) Error(v ...any) {
l.Println(ErrLevel, v...)
}

219
main.go
View File

@ -3,128 +3,133 @@
package main
import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
"git.froth.zone/sam/awl/cli"
"git.froth.zone/sam/awl/internal/helpers"
"git.froth.zone/sam/awl/query"
"gopkg.in/yaml.v2"
cli "dns.froth.zone/awl/cmd"
"dns.froth.zone/awl/pkg/query"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
)
var version = "DEV"
func main() {
opts, err := cli.ParseCLI(version)
if err != nil {
if opts, code, err := run(os.Args); err != nil {
// TODO: Make not ew
if errors.Is(err, cli.ErrNotError) || strings.Contains(err.Error(), "help requested") {
if errors.Is(err, util.ErrNotError) || strings.Contains(err.Error(), "help requested") {
os.Exit(0)
}
opts.Logger.Error(err)
os.Exit(1)
}
var resp helpers.Response
// Retry queries if a query fails
for i := 0; i < opts.Request.Retries; i++ {
resp, err = query.CreateQuery(opts)
if err == nil {
break
} else {
opts.Logger.Warn("Retrying request, error", err)
}
}
// Query failed, make it fail
if err != nil {
opts.Logger.Error(err)
os.Exit(9)
}
switch {
case opts.JSON:
opts.Logger.Info("Printing as JSON")
json, err := json.MarshalIndent(resp.DNS, "", " ")
if err != nil {
opts.Logger.Error(err)
os.Exit(10)
}
fmt.Println(string(json))
case opts.XML:
opts.Logger.Info("Printing as XML")
xml, err := xml.MarshalIndent(resp.DNS, "", " ")
if err != nil {
opts.Logger.Error(err)
os.Exit(10)
}
fmt.Println(string(xml))
case opts.YAML:
opts.Logger.Info("Printing as YAML")
yaml, err := yaml.Marshal(resp.DNS)
if err != nil {
opts.Logger.Error(err)
os.Exit(10)
}
fmt.Println(string(yaml))
default:
if !opts.Short {
// Print everything
if !opts.Display.Question {
resp.DNS.Question = nil
opts.Logger.Info("Disabled question display")
}
if !opts.Display.Answer {
resp.DNS.Answer = nil
opts.Logger.Info("Disabled answer display")
}
if !opts.Display.Authority {
resp.DNS.Ns = nil
opts.Logger.Info("Disabled authority display")
}
if !opts.Display.Additional {
resp.DNS.Extra = nil
opts.Logger.Info("Disabled additional display")
}
fmt.Println(resp.DNS)
if opts.Display.Statistics {
fmt.Println(";; Query time:", resp.RTT)
// Add extra information to server string
var extra string
switch {
case opts.TCP:
extra = ":" + strconv.Itoa(opts.Port) + " (TCP)"
case opts.TLS:
extra = ":" + strconv.Itoa(opts.Port) + " (TLS)"
case opts.HTTPS, opts.DNSCrypt:
extra = ""
case opts.QUIC:
extra = ":" + strconv.Itoa(opts.Port) + " (QUIC)"
default:
extra = ":" + strconv.Itoa(opts.Port) + " (UDP)"
}
fmt.Println(";; SERVER:", opts.Request.Server+extra)
fmt.Println(";; WHEN:", time.Now().Format(time.RFC1123Z))
fmt.Println(";; MSG SIZE rcvd:", resp.DNS.Len())
}
} else {
// Print just the responses, nothing else
for _, res := range resp.DNS.Answer {
temp := strings.Split(res.String(), "\t")
fmt.Println(temp[len(temp)-1])
}
os.Exit(code)
}
}
}
func run(args []string) (opts *util.Options, code int, err error) {
//nolint:gosec //Secure source not needed
r := rand.New(rand.NewSource(time.Now().Unix()))
opts, err = cli.ParseCLI(args, version)
if err != nil {
return opts, 1, fmt.Errorf("parse: %w", err)
}
var (
resp util.Response
keepTracing bool
tempDomain string
tempQueryType uint16
)
for ok := true; ok; ok = keepTracing {
if opts.Trace {
if keepTracing {
opts.Request.Name = tempDomain
opts.Request.Type = tempQueryType
} else {
tempDomain = opts.Request.Name
tempQueryType = opts.Request.Type
// Override the query because it needs to be done
opts.Request.Name = "."
opts.Request.Type = dns.TypeNS
}
}
// Retry queries if a query fails
for i := 0; i <= opts.Request.Retries; i++ {
resp, err = query.CreateQuery(opts)
if err == nil {
keepTracing = opts.Trace && (!resp.DNS.Authoritative || (opts.Request.Name == "." && tempDomain != ".")) && resp.DNS.MsgHdr.Rcode == 0
break
} else if i != opts.Request.Retries {
opts.Logger.Warn("Retrying request, error:", err)
}
}
// Query failed, make it fail
if err != nil {
return opts, 9, fmt.Errorf("query: %w", err)
}
var str string
if opts.JSON || opts.XML || opts.YAML {
str, err = query.PrintSpecial(resp, opts)
if err != nil {
return opts, 10, fmt.Errorf("format print: %w", err)
}
} else {
str, err = query.ToString(resp, opts)
if err != nil {
return opts, 15, fmt.Errorf("standard print: %w", err)
}
}
fmt.Println(str)
if keepTracing {
var records []dns.RR
if opts.Request.Name == "." {
records = resp.DNS.Answer
} else {
records = resp.DNS.Ns
}
want := func(rr dns.RR) bool {
temp := strings.Split(rr.String(), "\t")
return temp[len(temp)-2] == "NS"
}
i := 0
for _, x := range records {
if want(x) {
records[i] = x
i++
}
}
records = records[:i]
randomRR := records[r.Intn(len(records))]
v := strings.Split(randomRR.String(), "\t")
opts.Request.Server = strings.TrimSuffix(v[len(v)-1], ".")
opts.TLS = false
opts.HTTPS = false
opts.QUIC = false
opts.RD = false
opts.Request.Port = 53
}
}
return opts, 0, nil
}

48
main_test.go Normal file
View File

@ -0,0 +1,48 @@
// SPDX-License-Identifier: BSD-3-Clause
package main
import (
"testing"
"github.com/stefansundin/go-zflag"
"gotest.tools/v3/assert"
)
func TestRun(t *testing.T) {
// t.Parallel()
args := [][]string{
{"awl", "+yaml", "@1.1.1.1"},
{"awl", "+short", "@1.1.1.1"},
}
for _, test := range args {
test := test
t.Run("", func(t *testing.T) {
_, code, err := run(test)
assert.NilError(t, err)
assert.Equal(t, code, 0)
})
}
}
func TestTrace(t *testing.T) {
domains := []string{"git.froth.zone", "google.com", "amazon.com", "freecumextremist.com", "dns.froth.zone", "sleepy.cafe", "pkg.go.dev"}
for i := range domains {
args := []string{"awl", "+trace", domains[i], "@1.1.1.1"}
_, code, err := run(args)
assert.NilError(t, err)
assert.Equal(t, code, 0)
}
}
func TestHelp(t *testing.T) {
// t.Parallel()
args := []string{"awl", "-h"}
_, code, err := run(args)
assert.ErrorIs(t, err, zflag.ErrHelp)
assert.Equal(t, code, 1)
}

32
mkfile
View File

@ -1,30 +1,36 @@
# SPDX-License-Identifier: BSD-3-Clause
# Plan 9 mkfile
</$objtype/mkfile
GO = go
PROG = awl
LDFLAGS = '-s -w'
GOFLAGS = -ldflags=$LDFLAGS
VERSION = `{awk '{print substr($0,0,8)}' .git/refs/heads/master}
GOFLAGS = -ldflags=-s -ldflags=-w -ldflags=-X=main.version=$VERSION -trimpath
CGO_ENABLED = 0
$PROG:
$GO build $GOFLAGS -o $PROG '-buildvcs=false' .
all:V: $PROG
install: $PROG
$GO install $GOFLAGS .
cp doc/$PROG.1 /sys/man/1/$PROG
$PROG:
$GO build $GOFLAGS -o $target .
test:
$GO test -v -cover -coverprofile=coverage/coverage.out ./...
install:V:
$GO install $GOFLAGS .
# cp docs/$PROG.1 /sys/man/1/$PROG
fmt:
test:V:
$GO test -v -cover ./...
fmt:V:
gofmt -w -s .
vet:
vet:V:
$GO vet ./...
lint: fmt vet
lint:V: fmt vet
clean:
clean:V:
$GO clean
nuke:V: clean

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
LogAwl is a package for custom logging needs
Package logawl is a package for custom logging needs
LogAwl extends the standard log library with support for log levels
This is _different_ from the syslog package in the standard library because you do not define a file
@ -12,14 +14,15 @@ because awl is a cli utility it writes directly to std err.
// You can call specific logging levels from your new logger using
//
// logger.Debug("Message to log")
// logger.Fatal("Message to log")
// logger.Warning("Message to log")
// logger.Info("Message to log")
// logger.Error("Message to log")
//
// You may also set the log level on the fly with
//
// Logger.SetLevel(3)
// This allows you to change the default level (Info) and prevent log messages from being posted at higher verbosity levels
// This allows you to change the default level (Info)
// and prevent log messages from being posted at higher verbosity levels
// for example if
// Logger.SetLevel(3)
// is not called and you call

90
pkg/logawl/logawl.go Normal file
View File

@ -0,0 +1,90 @@
// SPDX-License-Identifier: BSD-3-Clause
package logawl
import (
"errors"
"io"
"sync"
"sync/atomic"
)
type (
// Level is the logging level.
Level int32
// Logger is the overall logger.
Logger struct {
Out io.Writer
Prefix string
buf []byte
Mu sync.Mutex
Level Level
isDiscard int32
}
)
// SetLevel stores whatever input value is in mem address of l.level.
func (logger *Logger) SetLevel(level Level) {
atomic.StoreInt32((*int32)(&logger.Level), int32(level))
}
// GetLevel gets the logger level.
func (logger *Logger) GetLevel() Level {
return logger.level()
}
// Retrieves whatever was stored in mem address of l.level.
func (logger *Logger) level() Level {
return Level(atomic.LoadInt32((*int32)(&logger.Level)))
}
// UnMarshalLevel unmarshalls the int value of level for writing the header.
func (logger *Logger) UnMarshalLevel(lv Level) (string, error) {
switch lv {
case ErrLevel:
return "ERROR ", nil
case WarnLevel:
return "WARN ", nil
case InfoLevel:
return "INFO ", nil
case DebugLevel:
return "DEBUG ", nil
}
return "", errInvalidLevel
}
// IsLevel returns true if the logger level is above the level given.
func (logger *Logger) IsLevel(level Level) bool {
return logger.level() >= level
}
// AllLevels is an array of all valid log levels.
var AllLevels = []Level{
ErrLevel,
WarnLevel,
InfoLevel,
DebugLevel,
}
const (
// ErrLevel is the fatal (error) log level.
ErrLevel Level = iota
// WarnLevel is for warning logs.
//
// Example: when one setting implies another, when a request fails but is retried.
WarnLevel
// InfoLevel is for saying what is going on when.
// This is essentially the "verbose" option.
//
// When in doubt, use info.
InfoLevel
// DebugLevel is for spewing debug structs/interfaces.
DebugLevel
)
var errInvalidLevel = errors.New("invalid log level")

175
pkg/logawl/logger.go Normal file
View File

@ -0,0 +1,175 @@
// SPDX-License-Identifier: BSD-3-Clause
package logawl
import (
"fmt"
"os"
"sync/atomic"
"time"
)
// New instantiates Logger
//
// Level can be changed to one of the other log levels (ErrorLevel, WarnLevel, InfoLevel, DebugLevel).
func New() *Logger {
return &Logger{
Out: os.Stderr,
Level: WarnLevel, // Default value is WarnLevel
}
}
// Println takes any and prints it out to Logger -> Out (io.Writer (default is std.Err)).
func (logger *Logger) Println(level Level, in ...any) {
if atomic.LoadInt32(&logger.isDiscard) != 0 {
return
}
// If verbose is not set --debug etc print _nothing_
if logger.IsLevel(level) {
switch level { // Goes through log levels and does stuff based on them (currently nothing)
case ErrLevel:
if err := logger.Printer(ErrLevel, fmt.Sprintln(in...)); err != nil {
fmt.Fprintln(logger.Out, "Logger failed: ", err)
}
case WarnLevel:
if err := logger.Printer(WarnLevel, fmt.Sprintln(in...)); err != nil {
fmt.Fprintln(logger.Out, "Logger failed: ", err)
}
case InfoLevel:
if err := logger.Printer(InfoLevel, fmt.Sprintln(in...)); err != nil {
fmt.Fprintln(logger.Out, "Logger failed: ", err)
}
case DebugLevel:
if err := logger.Printer(DebugLevel, fmt.Sprintln(in...)); err != nil {
fmt.Fprintln(logger.Out, "Logger failed: ", err)
}
default:
break
}
}
}
// FormatHeader formats the log header as such <LogLevel> YYYY/MM/DD HH:MM:SS (local time) <the message to log>.
func (logger *Logger) FormatHeader(buf *[]byte, t time.Time, line int, level Level) error {
if lvl, err := logger.UnMarshalLevel(level); err == nil {
// This is ugly but functional
// maybe there can be an append func or something in the future
*buf = append(*buf, lvl...)
year, month, day := t.Date()
*buf = append(*buf, '[')
formatter(buf, year, 4)
*buf = append(*buf, '/')
formatter(buf, int(month), 2)
*buf = append(*buf, '/')
formatter(buf, day, 2)
*buf = append(*buf, ' ')
hour, min, sec := t.Clock()
formatter(buf, hour, 2)
*buf = append(*buf, ':')
formatter(buf, min, 2)
*buf = append(*buf, ':')
formatter(buf, sec, 2)
*buf = append(*buf, ']')
*buf = append(*buf, ':')
*buf = append(*buf, ' ')
} else {
return errInvalidLevel
}
return nil
}
// Printer prints the formatted message directly to stdErr.
func (logger *Logger) Printer(level Level, s string) error {
now := time.Now()
var line int
logger.Mu.Lock()
defer logger.Mu.Unlock()
logger.buf = logger.buf[:0]
if err := logger.FormatHeader(&logger.buf, now, line, level); err != nil {
return err
}
logger.buf = append(logger.buf, s...)
if len(s) == 0 || s[len(s)-1] != '\n' {
logger.buf = append(logger.buf, '\n')
}
_, err := logger.Out.Write(logger.buf)
if err != nil {
return fmt.Errorf("logger printing: %w", err)
}
return nil
}
// Some line formatting stuff from Golang log stdlib file
//
// Please view
// https://cs.opensource.google/go/go/+/refs/tags/go1.19:src/log/log.go;drc=41e1d9075e428c2fc32d966b3752a3029b620e2c;l=96
//
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
func formatter(buf *[]byte, i int, wid int) {
// Assemble decimal in reverse order.
var b [20]byte
bp := len(b) - 1
for i >= 10 || wid > 1 {
wid--
q := i / 10
b[bp] = byte('0' + i - q*10)
bp--
i = q
}
// i < 10
b[bp] = byte('0' + i)
*buf = append(*buf, b[bp:]...)
}
// Debug calls print directly with Debug level.
func (logger *Logger) Debug(in ...any) {
logger.Println(DebugLevel, in...)
}
// Debugf calls print after formatting the string with Debug level.
func (logger *Logger) Debugf(format string, in ...any) {
logger.Println(DebugLevel, fmt.Sprintf(format, in...))
}
// Info calls print directly with Info level.
func (logger *Logger) Info(in ...any) {
logger.Println(InfoLevel, in...)
}
// Infof calls print after formatting the string with Info level.
func (logger *Logger) Infof(format string, in ...any) {
logger.Println(InfoLevel, fmt.Sprintf(format, in...))
}
// Warn calls print directly with Warn level.
func (logger *Logger) Warn(in ...any) {
logger.Println(WarnLevel, in...)
}
// Warnf calls print after formatting the string with Warn level.
func (logger *Logger) Warnf(format string, in ...any) {
logger.Println(WarnLevel, fmt.Sprintf(format, in...))
}
// Error calls print directly with Error level.
func (logger *Logger) Error(in ...any) {
logger.Println(ErrLevel, in...)
}
// Errorf calls print after formatting the string with Error level.
func (logger *Logger) Errorf(format string, in ...any) {
logger.Println(ErrLevel, fmt.Sprintf(format, in...))
}

View File

@ -7,8 +7,7 @@ import (
"testing"
"time"
"git.froth.zone/sam/awl/logawl"
"dns.froth.zone/awl/pkg/logawl"
"gotest.tools/v3/assert"
)
@ -25,10 +24,11 @@ func TestLogawl(t *testing.T) {
func TestUnmarshalLevels(t *testing.T) {
t.Parallel()
m := make(map[int]string)
var err error
for i := range logawl.AllLevels {
var err error
m[i], err = logger.UnMarshalLevel(logawl.Level(i))
assert.NilError(t, err)
}
@ -48,28 +48,52 @@ func TestLogger(t *testing.T) {
t.Parallel()
for i := range logawl.AllLevels {
// only test non-exiting log levels
switch i {
case 0:
fn := func() {
logger.Error("Test", "E")
logger.Errorf("%s", "Test")
}
var buffer bytes.Buffer
logger.Out = &buffer
fn()
case 1:
fn := func() {
logger.Info("")
logger.Warn("Test")
logger.Warnf("%s", "Test")
}
var buffer bytes.Buffer
logger.Out = &buffer
fn()
case 2:
fn := func() {
logger.Info("Test")
logger.Infof("%s", "Test")
}
var buffer bytes.Buffer
logger.Out = &buffer
fn()
case 3:
fn := func() {
logger.Debug("Test")
logger.Debug("Test 2")
logger.Debugf("%s", "Test")
logger.Debugf("%s %d", "Test", 2)
}
var buffer bytes.Buffer
logger.Out = &buffer
fn()
}
}
@ -77,8 +101,9 @@ func TestLogger(t *testing.T) {
func TestFmt(t *testing.T) {
t.Parallel()
ti := time.Now()
test := []byte("test")
assert.ErrorContains(t, logger.FormatHeader(&test, ti, 0, 9001), "invalid log level") //make sure error is error
// make sure error is error
assert.ErrorContains(t, logger.FormatHeader(&test, ti, 0, 9001), "invalid log level")
}

4
pkg/query/docs.go Normal file
View File

@ -0,0 +1,4 @@
// SPDX-License-Identifier: BSD-3-Clause
// Package query is for the various query types.
package query

313
pkg/query/print.go Normal file
View File

@ -0,0 +1,313 @@
// SPDX-License-Identifier: BSD-3-Clause
package query
import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"strconv"
"strings"
"time"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
"golang.org/x/net/idna"
"gopkg.in/yaml.v3"
)
// ToString turns the response into something that looks a lot like dig
//
// Much of this is taken from https://github.com/miekg/dns/blob/master/msg.go#L900
func ToString(res util.Response, opts *util.Options) (s string, err error) {
if res.DNS == nil {
return "<nil> MsgHdr", errNoMessage
}
var opt *dns.OPT
if !opts.Short {
if opts.Display.Comments {
s += res.DNS.MsgHdr.String() + " "
s += "QUERY: " + strconv.Itoa(len(res.DNS.Question)) + ", "
s += "ANSWER: " + strconv.Itoa(len(res.DNS.Answer)) + ", "
s += "AUTHORITY: " + strconv.Itoa(len(res.DNS.Ns)) + ", "
s += "ADDITIONAL: " + strconv.Itoa(len(res.DNS.Extra)) + "\n"
opt = res.DNS.IsEdns0()
if opt != nil && opts.Display.Opt {
// OPT PSEUDOSECTION
s += opt.String() + "\n"
}
}
if opts.Display.Question {
if len(res.DNS.Question) > 0 {
if opts.Display.Comments {
s += "\n;; QUESTION SECTION:\n"
}
for _, r := range res.DNS.Question {
str, err := stringParse(r.String(), false, opts)
if err != nil {
return "", fmt.Errorf("%w", err)
}
s += str + "\n"
}
}
}
if opts.Display.Answer {
if len(res.DNS.Answer) > 0 {
if opts.Display.Comments {
s += "\n;; ANSWER SECTION:\n"
}
for _, r := range res.DNS.Answer {
if r != nil {
str, err := stringParse(r.String(), true, opts)
if err != nil {
return "", fmt.Errorf("%w", err)
}
s += str + "\n"
}
}
}
}
if opts.Display.Authority {
if len(res.DNS.Ns) > 0 {
if opts.Display.Comments {
s += "\n;; AUTHORITY SECTION:\n"
}
for _, r := range res.DNS.Ns {
if r != nil {
str, err := stringParse(r.String(), true, opts)
if err != nil {
return "", fmt.Errorf("%w", err)
}
s += str + "\n"
}
}
}
}
if opts.Display.Additional {
if len(res.DNS.Extra) > 0 && (opt == nil || len(res.DNS.Extra) > 1) {
if opts.Display.Comments {
s += "\n;; ADDITIONAL SECTION:\n"
}
for _, r := range res.DNS.Extra {
if r != nil && r.Header().Rrtype != dns.TypeOPT {
str, err := stringParse(r.String(), true, opts)
if err != nil {
return "", fmt.Errorf("%w", err)
}
s += str + "\n"
}
}
}
}
if opts.Display.Statistics {
s += "\n;; Query time: " + res.RTT.String()
s += "\n;; SERVER: " + opts.Request.Server + serverExtra(opts)
s += "\n;; WHEN: " + time.Now().Format(time.RFC1123Z)
s += "\n;; MSG SIZE rcvd: " + strconv.Itoa(res.DNS.Len()) + "\n"
}
} else {
// Print just the responses, nothing else
for i, resp := range res.DNS.Answer {
temp := strings.Split(resp.String(), "\t")
s += temp[len(temp)-1]
if opts.Identify {
s += " from server " + opts.Request.Server + " in " + res.RTT.String()
}
// Don't print newline on last line
if i != len(res.DNS.Answer)-1 {
s += "\n"
}
}
}
return
}
func serverExtra(opts *util.Options) string {
switch {
case opts.TCP:
return " (TCP)"
case opts.TLS:
return " (TLS)"
case opts.HTTPS, opts.DNSCrypt:
return ""
case opts.QUIC:
return " (QUIC)"
default:
return " (UDP)"
}
}
// stringParse edits the raw responses to user requests.
func stringParse(str string, isAns bool, opts *util.Options) (string, error) {
split := strings.Split(str, "\t")
// Make edits if so requested
// TODO: make less ew?
// This exists because the question section should be left alone EXCEPT for punycode.
if isAns {
if !opts.Display.TTL {
// Remove from existence
split = append(split[:1], split[2:]...)
}
if !opts.Display.ShowClass {
// Position depends on if the TTL is there or not.
if opts.Display.TTL {
split = append(split[:2], split[3:]...)
} else {
split = append(split[:1], split[2:]...)
}
}
if opts.Display.TTL && opts.Display.HumanTTL {
ttl, _ := strconv.Atoi(split[1])
split[1] = (time.Duration(ttl) * time.Second).String()
}
}
if opts.Display.UcodeTranslate {
var (
err error
semi string
)
if strings.HasPrefix(split[0], ";") {
split[0] = strings.TrimPrefix(split[0], ";")
semi = ";"
}
split[0], err = idna.ToUnicode(split[0])
if err != nil {
return "", fmt.Errorf("punycode: %w", err)
}
split[0] = semi + split[0]
}
return strings.Join(split, "\t"), nil
}
// PrintSpecial is for printing as JSON, XML or YAML.
// As of now JSON and XML use the stdlib version.
func PrintSpecial(res util.Response, opts *util.Options) (string, error) {
formatted, err := MakePrintable(res, opts)
if err != nil {
return "", err
}
switch {
case opts.JSON:
opts.Logger.Info("Printing as JSON")
json, err := json.MarshalIndent(formatted, " ", " ")
return string(json), err
case opts.XML:
opts.Logger.Info("Printing as XML")
xml, err := xml.MarshalIndent(formatted, " ", " ")
return string(xml), err
case opts.YAML:
opts.Logger.Info("Printing as YAML")
yaml, err := yaml.Marshal(formatted)
return string(yaml), err
default:
return "", errInvalidFormat
}
}
// MakePrintable takes a DNS message and makes it nicer to be printed as JSON,YAML,
// and XML. Little is changed beyond naming.
func MakePrintable(res util.Response, opts *util.Options) (*Message, error) {
var (
err error
msg = res.DNS
)
// The things I do for compatibility
ret := &Message{
DateString: time.Now().Format(time.RFC3339),
DateSeconds: time.Now().Unix(),
MsgSize: res.DNS.Len(),
ID: msg.Id,
Opcode: msg.Opcode,
Response: msg.Response,
Authoritative: msg.Authoritative,
Truncated: msg.Truncated,
RecursionDesired: msg.RecursionDesired,
RecursionAvailable: msg.RecursionAvailable,
AuthenticatedData: msg.AuthenticatedData,
CheckingDisabled: msg.CheckingDisabled,
Zero: msg.Zero,
QdCount: len(msg.Question),
AnCount: len(msg.Answer),
NsCount: len(msg.Ns),
ArCount: len(msg.Extra),
}
opt := msg.IsEdns0()
if opt != nil && opts.Display.Opt {
ret.EDNS0, err = ret.ParseOpt(msg.Rcode, *opt)
if err != nil {
return nil, fmt.Errorf("edns print: %w", err)
}
}
if opts.Display.Question {
err = ret.displayQuestion(msg, opts, opt)
if err != nil {
return nil, fmt.Errorf("unable to display questions: %w", err)
}
}
if opts.Display.Answer {
err = ret.displayAnswers(msg, opts, opt)
if err != nil {
return nil, fmt.Errorf("unable to display answers: %w", err)
}
}
if opts.Display.Authority {
err = ret.displayAuthority(msg, opts, opt)
if err != nil {
return nil, fmt.Errorf("unable to display authority: %w", err)
}
}
if opts.Display.Additional {
err = ret.displayAdditional(msg, opts, opt)
if err != nil {
return nil, fmt.Errorf("unable to display additional: %w", err)
}
}
return ret, nil
}
var errInvalidFormat = errors.New("this should never happen")

230
pkg/query/print_test.go Normal file
View File

@ -0,0 +1,230 @@
// SPDX-License-Identifier: BSD-3-Clause
package query_test
import (
"testing"
"dns.froth.zone/awl/pkg/query"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestRealPrint(t *testing.T) {
t.Parallel()
opts := []*util.Options{
{
Logger: util.InitLogger(0),
TCP: true,
HeaderFlags: util.HeaderFlags{
RD: true,
},
JSON: true,
Display: util.Display{
Comments: true,
Question: true,
Answer: true,
Authority: true,
Additional: true,
Statistics: true,
UcodeTranslate: true,
TTL: true,
HumanTTL: true,
ShowQuery: true,
},
Request: util.Request{
Server: "a.gtld-servers.net",
Port: 53,
Type: dns.StringToType["NS"],
Class: 1,
Name: "google.com.",
Retries: 3,
},
EDNS: util.EDNS{
EnableEDNS: false,
},
},
{
Logger: util.InitLogger(0),
TCP: true,
HeaderFlags: util.HeaderFlags{
RD: true,
},
Verbosity: 0,
Short: true,
Identify: true,
YAML: false,
Display: util.Display{
Comments: true,
Question: true,
Answer: true,
Authority: true,
Additional: true,
Statistics: true,
UcodeTranslate: true,
TTL: true,
ShowQuery: true,
},
Request: util.Request{
Server: "ns1.google.com",
Port: 53,
Type: dns.StringToType["NS"],
Class: 1,
Name: "google.com.",
Retries: 3,
},
EDNS: util.EDNS{
EnableEDNS: false,
},
},
{
Logger: util.InitLogger(0),
HTTPS: true,
HeaderFlags: util.HeaderFlags{
RD: true,
},
Identify: true,
XML: true,
Display: util.Display{
Comments: true,
Question: true,
Answer: true,
Authority: true,
Additional: true,
Statistics: true,
UcodeTranslate: true,
TTL: true,
HumanTTL: true,
ShowQuery: true,
},
Request: util.Request{
Server: "https://dns.froth.zone/dns-query",
Port: 443,
Type: dns.StringToType["NS"],
Class: 1,
Name: "freecumextremist.com.",
Retries: 3,
},
EDNS: util.EDNS{
EnableEDNS: false,
DNSSEC: true,
},
},
{
Logger: util.InitLogger(0),
TLS: true,
HeaderFlags: util.HeaderFlags{
RD: true,
},
Verbosity: 0,
Display: util.Display{
Comments: true,
Question: true,
Answer: true,
Authority: true,
Additional: true,
Statistics: true,
UcodeTranslate: true,
TTL: false,
ShowQuery: true,
},
Request: util.Request{
Server: "dns.google",
Port: 853,
Type: dns.StringToType["NS"],
Class: 1,
Name: "freecumextremist.com.",
Retries: 3,
},
},
{
Logger: util.InitLogger(0),
TCP: true,
HeaderFlags: util.HeaderFlags{
AA: true,
RD: true,
},
Verbosity: 0,
YAML: true,
Display: util.Display{
Comments: true,
Question: true,
Answer: true,
Authority: true,
Additional: true,
Statistics: true,
UcodeTranslate: false,
TTL: true,
ShowQuery: true,
},
Request: util.Request{
Server: "rin.froth.zone",
Port: 53,
Type: dns.StringToType["A"],
Class: 1,
Name: "froth.zone.",
Retries: 3,
},
EDNS: util.EDNS{
EnableEDNS: true,
Cookie: true,
Padding: true,
},
},
}
for _, test := range opts {
test := test
t.Run("", func(t *testing.T) {
t.Parallel()
var (
res util.Response
err error
)
for i := 0; i <= test.Request.Retries; i++ {
res, err = query.CreateQuery(test)
if err == nil {
break
}
}
assert.NilError(t, err)
if test.JSON || test.XML || test.YAML {
str := ""
str, err = query.PrintSpecial(res, test)
assert.NilError(t, err)
assert.Assert(t, str != "")
}
str, err := query.ToString(res, test)
assert.NilError(t, err)
assert.Assert(t, str != "")
})
}
}
func TestBadFormat(t *testing.T) {
t.Parallel()
_, err := query.PrintSpecial(util.Response{DNS: new(dns.Msg)}, new(util.Options))
assert.ErrorContains(t, err, "never happen")
}
func TestEmpty(t *testing.T) {
t.Parallel()
str, err := query.ToString(util.Response{}, new(util.Options))
assert.Error(t, err, "no message")
assert.Assert(t, str == "<nil> MsgHdr")
}

145
pkg/query/query.go Normal file
View File

@ -0,0 +1,145 @@
// SPDX-License-Identifier: BSD-3-Clause
package query
import (
"fmt"
"strconv"
"dns.froth.zone/awl/pkg/resolvers"
"dns.froth.zone/awl/pkg/util"
"github.com/dchest/uniuri"
"github.com/miekg/dns"
)
// CreateQuery creates a DNS query from the options given.
// It sets query flags and EDNS flags from the respective options.
func CreateQuery(opts *util.Options) (util.Response, error) {
req := new(dns.Msg)
req.SetQuestion(opts.Request.Name, opts.Request.Type)
req.Question[0].Qclass = opts.Request.Class
// Set standard flags
req.MsgHdr.Response = opts.QR
req.MsgHdr.Authoritative = opts.AA
req.MsgHdr.Truncated = opts.TC
req.MsgHdr.RecursionDesired = opts.RD
req.MsgHdr.RecursionAvailable = opts.RA
req.MsgHdr.Zero = opts.Z
req.MsgHdr.AuthenticatedData = opts.AD
req.MsgHdr.CheckingDisabled = opts.CD
// EDNS time :)
if opts.EDNS.EnableEDNS {
edns := new(dns.OPT)
edns.Hdr.Name = "."
edns.Hdr.Rrtype = dns.TypeOPT
edns.SetVersion(opts.EDNS.Version)
if opts.EDNS.Cookie {
cookie := new(dns.EDNS0_COOKIE)
cookie.Code = dns.EDNS0COOKIE
cookie.Cookie = uniuri.NewLenChars(16, []byte("1234567890abcdef"))
edns.Option = append(edns.Option, cookie)
opts.Logger.Info("Setting EDNS cookie to", cookie.Cookie)
}
if opts.EDNS.Expire {
edns.Option = append(edns.Option, new(dns.EDNS0_EXPIRE))
opts.Logger.Info("Setting EDNS Expire option")
}
if opts.EDNS.KeepOpen {
edns.Option = append(edns.Option, new(dns.EDNS0_TCP_KEEPALIVE))
opts.Logger.Info("Setting EDNS TCP Keepalive option")
}
if opts.EDNS.Nsid {
edns.Option = append(edns.Option, new(dns.EDNS0_NSID))
opts.Logger.Info("Setting EDNS NSID option")
}
if opts.EDNS.Padding {
edns.Option = append(edns.Option, new(dns.EDNS0_PADDING))
opts.Logger.Info("Setting EDNS padding")
}
edns.SetUDPSize(opts.EDNS.BufSize)
opts.Logger.Info("EDNS UDP buffer set to", opts.EDNS.BufSize)
edns.SetZ(opts.EDNS.ZFlag)
opts.Logger.Info("EDNS Z flag set to", opts.EDNS.ZFlag)
if opts.EDNS.DNSSEC {
edns.SetDo()
opts.Logger.Info("EDNS DNSSEC OK set")
}
if opts.EDNS.Subnet.Address != nil {
edns.Option = append(edns.Option, &opts.EDNS.Subnet)
}
req.Extra = append(req.Extra, edns)
} else if opts.EDNS.DNSSEC {
req.SetEdns0(1232, true)
opts.Logger.Warn("DNSSEC implies EDNS, EDNS enabled")
opts.Logger.Info("DNSSEC enabled, UDP buffer set to 1232")
}
opts.Logger.Debug(req)
if !opts.Short {
if opts.Display.ShowQuery {
opts.Logger.Info("Printing constructed query")
var (
str string
err error
)
if opts.JSON || opts.XML || opts.YAML {
str, err = PrintSpecial(util.Response{DNS: req}, opts)
if err != nil {
return util.Response{}, err
}
} else {
temp := opts.Display.Statistics
opts.Display.Statistics = false
str, err = ToString(
util.Response{
DNS: req,
RTT: 0,
}, opts)
if err != nil {
return util.Response{}, err
}
opts.Display.Statistics = temp
str += "\n;; QUERY SIZE: " + strconv.Itoa(req.Len()) + "\n"
}
fmt.Println(str)
opts.Display.ShowQuery = false
}
}
resolver, err := resolvers.LoadResolver(opts)
if err != nil {
return util.Response{}, fmt.Errorf("unable to load resolvers: %w", err)
}
opts.Logger.Info("Query successfully loaded")
//nolint:wrapcheck // Error wrapping not needed here
return resolver.LookUp(req)
}

157
pkg/query/query_test.go Normal file
View File

@ -0,0 +1,157 @@
// SPDX-License-Identifier: BSD-3-Clause
package query_test
import (
"testing"
"time"
"dns.froth.zone/awl/pkg/query"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestCreateQ(t *testing.T) {
t.Parallel()
//nolint:govet // I could not be assed to refactor this, and it is only for tests
tests := []struct {
name string
opts *util.Options
}{
{
"1",
&util.Options{
Logger: util.InitLogger(0),
HeaderFlags: util.HeaderFlags{
Z: true,
},
YAML: true,
Request: util.Request{
Server: "8.8.4.4",
Port: 53,
Type: dns.TypeA,
Name: "example.com.",
Retries: 3,
},
Display: util.Display{
Comments: true,
Question: true,
Opt: true,
Answer: true,
Authority: true,
Additional: true,
Statistics: true,
ShowQuery: true,
},
EDNS: util.EDNS{
ZFlag: 1,
BufSize: 1500,
EnableEDNS: true,
Cookie: true,
DNSSEC: true,
Expire: true,
KeepOpen: true,
Nsid: true,
Padding: true,
Version: 0,
},
},
},
{
"2",
&util.Options{
Logger: util.InitLogger(0),
HeaderFlags: util.HeaderFlags{
Z: true,
},
XML: true,
Request: util.Request{
Server: "8.8.4.4",
Port: 53,
Type: dns.TypeA,
Name: "example.com.",
Retries: 3,
},
Display: util.Display{
Comments: true,
Question: true,
Opt: true,
Answer: true,
Authority: true,
Additional: true,
Statistics: true,
UcodeTranslate: true,
ShowQuery: true,
},
},
},
{
"3",
&util.Options{
Logger: util.InitLogger(0),
JSON: true,
QUIC: true,
Request: util.Request{
Server: "dns.froth.zone",
Port: 853,
Type: dns.TypeA,
Name: "example.com.",
Retries: 3,
Timeout: time.Second,
},
Display: util.Display{
Comments: true,
Question: true,
Opt: true,
Answer: true,
Authority: true,
Additional: true,
Statistics: true,
ShowQuery: true,
},
EDNS: util.EDNS{
EnableEDNS: true,
DNSSEC: true,
Cookie: true,
Expire: true,
Nsid: true,
},
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
var (
res util.Response
err error
)
for i := 0; i <= test.opts.Request.Retries; i++ {
res, err = query.CreateQuery(test.opts)
if err == nil {
break
}
}
assert.NilError(t, err)
assert.Assert(t, res != util.Response{})
str, err := query.PrintSpecial(res, test.opts)
assert.NilError(t, err)
assert.Assert(t, str != "")
str, err = query.ToString(res, test.opts)
assert.NilError(t, err)
assert.Assert(t, str != "")
})
}
}

116
pkg/query/struct.go Normal file
View File

@ -0,0 +1,116 @@
// SPDX-License-Identifier: BSD-3-Clause
package query
import (
"errors"
)
// Message is for overall DNS responses.
//
//nolint:govet,tagliatelle // Better looking output is worth a few bytes.
type Message struct {
DateString string `json:"dateString,omitempty" xml:"dateString,omitempty" yaml:"dateString,omitempty"`
DateSeconds int64 `json:"dateSeconds,omitempty" xml:"dateSeconds,omitempty" yaml:"dateSeconds,omitempty"`
MsgSize int `json:"msgLength,omitempty" xml:"msgSize,omitempty" yaml:"msgSize,omitempty"`
ID uint16 `json:"ID" xml:"ID" yaml:"ID" example:"12"`
Opcode int `json:"opcode" xml:"opcode" yaml:"opcode" example:"QUERY"`
Response bool `json:"QR" xml:"QR" yaml:"QR" example:"true"`
Authoritative bool `json:"AA" xml:"AA" yaml:"AA" example:"false"`
Truncated bool `json:"TC" xml:"TC" yaml:"TC" example:"false"`
RecursionDesired bool `json:"RD" xml:"RD" yaml:"RD" example:"true"`
RecursionAvailable bool `json:"RA" xml:"RA" yaml:"RA" example:"true"`
AuthenticatedData bool `json:"AD" xml:"AD" yaml:"AD" example:"false"`
CheckingDisabled bool `json:"CD" xml:"CD" yaml:"CD" example:"false"`
Zero bool `json:"Z" xml:"Z" yaml:"Z" example:"false"`
QdCount int `json:"QDCOUNT" xml:"QDCOUNT" yaml:"QDCOUNT" example:"0"`
AnCount int `json:"ANCOUNT" xml:"ANCOUNT" yaml:"ANCOUNT" example:"0"`
NsCount int `json:"NSCOUNT" xml:"NSCOUNT" yaml:"NSCOUNT" example:"0"`
ArCount int `json:"ARCOUNT" xml:"ARCOUNT" yaml:"ARCOUNT" example:"0"`
Name string `json:"QNAME,omitempty" xml:"QNAME,omitempty" yaml:"QNAME,omitempty" example:"localhost"`
Type uint16 `json:"QTYPE,omitempty" xml:"QTYPE,omitempty" yaml:"QTYPE,omitempty" example:"IN"`
TypeName string `json:"QTYPEname,omitempty" xml:"QTYPEname,omitempty" yaml:"QTYPEname,omitempty" example:"IN"`
Class uint16 `json:"QCLASS,omitempty" xml:"QCLASS,omitempty" yaml:"QCLASS,omitempty" example:"A"`
ClassName string `json:"QCLASSname,omitempty" xml:"QCLASSname,omitempty" yaml:"QCLASSname,omitempty" example:"1"`
EDNS0 EDNS0 `json:",omitempty" xml:",omitempty" yaml:",omitempty"`
// Answer Section
AnswerRRs []Answer `json:"answersRRs,omitempty" xml:"answersRRs,omitempty" yaml:"answersRRs,omitempty" example:"false"`
AuthoritativeRRs []Answer `json:"authorityRRs,omitempty" xml:"authorityRRs,omitempty" yaml:"authorityRRs,omitempty" example:"false"`
AdditionalRRs []Answer `json:"additionalRRs,omitempty" xml:"additionalRRs,omitempty" yaml:"additionalRRs,omitempty" example:"false"`
}
// Answer is for DNS Resource Headers.
//
//nolint:govet,tagliatelle
type Answer struct {
Name string `json:"NAME,omitempty" xml:"NAME,omitempty" yaml:"NAME,omitempty" example:"127.0.0.1"`
Type uint16 `json:"TYPE,omitempty" xml:"TYPE,omitempty" yaml:"TYPE,omitempty" example:"1"`
TypeName string `json:"TYPEname,omitempty" xml:"TYPEname,omitempty" yaml:"TYPEname,omitempty" example:"A"`
Class uint16 `json:"CLASS,omitempty" xml:"CLASS,omitempty" yaml:"CLASS,omitempty" example:"1"`
ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"IN"`
TTL any `json:"TTL,omitempty" xml:"TTL,omitempty" yaml:"TTL,omitempty" example:"0ms"`
Value string `json:"rdata,omitempty" xml:"rdata,omitempty" yaml:"rdata,omitempty"`
Rdlength uint16 `json:"RDLENGTH,omitempty" xml:"RDLENGTH,omitempty" yaml:"RDLENGTH,omitempty"`
Rdhex string `json:"RDATAHEX,omitempty" xml:"RDATAHEX,omitempty" yaml:"RDATAHEX,omitempty"`
}
// EDNS0 is for all EDNS options.
//
// RFC: https://datatracker.ietf.org/docs/draft-peltan-edns-presentation-format/
//
//nolint:govet,tagliatelle
type EDNS0 struct {
Flags []string `json:"FLAGS" xml:"FLAGS" yaml:"FLAGS"`
Rcode string `json:"RCODE" xml:"RCODE" yaml:"RCODE"`
PayloadSize uint16 `json:"UDPSIZE" xml:"UDPSIZE" yaml:"UDPSIZE"`
LLQ *EdnsLLQ `json:"LLQ,omitempty" xml:"LLQ,omitempty" yaml:"LLQ,omitempty"`
NsidHex string `json:"NSIDHEX,omitempty" xml:"NSIDHEX,omitempty" yaml:"NSIDHEX,omitempty"`
Nsid string `json:"NSID,omitempty" xml:"NSID,omitempty" yaml:"NSID,omitempty"`
Dau []uint8 `json:"DAU,omitempty" xml:"DAU,omitempty" yaml:"DAU,omitempty"`
Dhu []uint8 `json:"DHU,omitempty" xml:"DHU,omitempty" yaml:"DHU,omitempty"`
N3u []uint8 `json:"N3U,omitempty" xml:"N3U,omitempty" yaml:"N3U,omitempty"`
Subnet *EDNSSubnet `json:"ECS,omitempty" xml:"ECS,omitempty" yaml:"ECS,omitempty"`
Expire uint32 `json:"EXPIRE,omitempty" xml:"EXPIRE,omitempty" yaml:"EXPIRE,omitempty"`
Cookie []string `json:"COOKIE,omitempty" xml:"COOKIE,omitempty" yaml:"COOKIE,omitempty"`
KeepAlive uint16 `json:"KEEPALIVE,omitempty" xml:"KEEPALIVE,omitempty" yaml:"KEEPALIVE,omitempty"`
Padding string `json:"PADDING,omitempty" xml:"PADDING,omitempty" yaml:"PADDING,omitempty"`
Chain string `json:"CHAIN,omitempty" xml:"CHAIN,omitempty" yaml:"CHAIN,omitempty"`
EDE *EDNSErr `json:"EDE,omitempty" xml:"EDE,omitempty" yaml:"EDE,omitempty"`
}
// EdnsLLQ is for Long-lived queries.
//
//nolint:tagliatelle
type EdnsLLQ struct {
Version uint16 `json:"LLQ-VERSION" xml:"LLQ-VERSION" yaml:"LLQ-VERSION"`
Opcode uint16 `json:"LLQ-OPCODE" xml:"LLQ-OPCODE" yaml:"LLQ-OPCODE"`
Error uint16 `json:"LLQ-ERROR" xml:"LLQ-ERROR" yaml:"LLQ-ERROR"`
ID uint64 `json:"LLQ-ID" xml:"LLQ-ID" yaml:"LLQ-ID"`
Lease uint32 `json:"LLQ-LEASE" xml:"LLQ-LEASE" yaml:"LLQ-LEASE"`
}
// EDNSSubnet is for EDNS subnet options,
//
//nolint:govet,tagliatelle
type EDNSSubnet struct {
Family uint16 `json:"FAMILY" xml:"FAMILY" yaml:"FAMILY"`
IP string
Source uint8 `json:"SOURCE" xml:"SOURCE" yaml:"SOURCE"`
Scope uint8 `json:"SCOPE,omitempty" xml:"SCOPE,omitempty" yaml:"SCOPE,omitempty"`
}
// EDNSErr is for EDE codes
//
//nolint:govet,tagliatelle
type EDNSErr struct {
Code uint16 `json:"INFO-CODE" xml:"INFO-CODE" yaml:"INFO-CODE"`
Purpose string
Text string `json:"EXTRA-TEXT,omitempty" xml:"EXTRA-TEXT,omitempty" yaml:"EXTRA-TEXT,omitempty"`
}
var errNoMessage = errors.New("no message")

258
pkg/query/util.go Normal file
View File

@ -0,0 +1,258 @@
package query
import (
"encoding/hex"
"fmt"
"strings"
"time"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
"golang.org/x/net/idna"
)
func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error {
var (
name string
err error
)
for _, question := range msg.Question {
if opts.Display.UcodeTranslate {
name, err = idna.ToUnicode(question.Name)
if err != nil {
return fmt.Errorf("punycode to unicode: %w", err)
}
} else {
name = question.Name
}
message.Name = name
message.Type = question.Qtype
message.TypeName = dns.TypeToString[question.Qtype]
message.Class = question.Qclass
message.ClassName = dns.ClassToString[question.Qclass]
}
return nil
}
func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error {
var (
ttl any
name string
err error
)
for _, answer := range msg.Answer {
temp := strings.Split(answer.String(), "\t")
if opts.Display.TTL {
if opts.Display.HumanTTL {
ttl = (time.Duration(answer.Header().Ttl) * time.Second).String()
} else {
ttl = answer.Header().Ttl
}
}
if opts.Display.UcodeTranslate {
name, err = idna.ToUnicode(answer.Header().Name)
if err != nil {
return fmt.Errorf("punycode to unicode: %w", err)
}
} else {
name = answer.Header().Name
}
message.AnswerRRs = append(message.AnswerRRs, Answer{
Name: name,
ClassName: dns.ClassToString[answer.Header().Class],
Class: answer.Header().Class,
TypeName: dns.TypeToString[answer.Header().Rrtype],
Type: answer.Header().Rrtype,
Rdlength: answer.Header().Rdlength,
TTL: ttl,
Value: temp[len(temp)-1],
})
}
return nil
}
func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error {
var (
ttl any
name string
err error
)
for _, ns := range msg.Ns {
temp := strings.Split(ns.String(), "\t")
if opts.Display.TTL {
if opts.Display.HumanTTL {
ttl = (time.Duration(ns.Header().Ttl) * time.Second).String()
} else {
ttl = ns.Header().Ttl
}
}
if opts.Display.UcodeTranslate {
name, err = idna.ToUnicode(ns.Header().Name)
if err != nil {
return fmt.Errorf("punycode to unicode: %w", err)
}
} else {
name = ns.Header().Name
}
message.AuthoritativeRRs = append(message.AuthoritativeRRs, Answer{
Name: name,
TypeName: dns.TypeToString[ns.Header().Rrtype],
Type: ns.Header().Rrtype,
Class: ns.Header().Class,
ClassName: dns.ClassToString[ns.Header().Class],
Rdlength: ns.Header().Rdlength,
TTL: ttl,
Value: temp[len(temp)-1],
})
}
return nil
}
func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error {
var (
ttl any
name string
err error
)
for _, additional := range msg.Extra {
if additional.Header().Rrtype == dns.StringToType["OPT"] {
continue
} else {
temp := strings.Split(additional.String(), "\t")
if opts.Display.TTL {
if opts.Display.HumanTTL {
ttl = (time.Duration(additional.Header().Ttl) * time.Second).String()
} else {
ttl = additional.Header().Ttl
}
}
if opts.Display.UcodeTranslate {
name, err = idna.ToUnicode(additional.Header().Name)
if err != nil {
return fmt.Errorf("punycode to unicode: %w", err)
}
} else {
name = additional.Header().Name
}
message.AdditionalRRs = append(message.AdditionalRRs, Answer{
Name: name,
TypeName: dns.TypeToString[additional.Header().Rrtype],
Type: additional.Header().Rrtype,
Class: additional.Header().Class,
ClassName: dns.ClassToString[additional.Header().Class],
Rdlength: additional.Header().Rdlength,
TTL: ttl,
Value: temp[len(temp)-1],
})
}
}
return nil
}
// ParseOpt parses opts.
func (message *Message) ParseOpt(rcode int, rr dns.OPT) (ret EDNS0, err error) {
ret.Rcode = dns.RcodeToString[rcode]
// Most of this is taken from https://github.com/miekg/dns/blob/master/edns.go#L76
if rr.Do() {
ret.Flags = append(ret.Flags, "DO")
}
for i := uint32(1); i <= 0x7FFF; i <<= 1 {
if rr.Hdr.Ttl&i != 0 {
ret.Flags = append(ret.Flags, fmt.Sprintf("BIT%d", i))
}
}
ret.PayloadSize = rr.UDPSize()
for _, opt := range rr.Option {
switch opt := opt.(type) {
case *dns.EDNS0_NSID:
str := opt.String()
hex, err := hex.DecodeString(str)
if err != nil {
return ret, fmt.Errorf("%w", err)
}
ret.NsidHex = string(hex)
ret.Nsid = str
case *dns.EDNS0_SUBNET:
ret.Subnet = &EDNSSubnet{
Source: opt.SourceNetmask,
Family: opt.Family,
}
// 1: IPv4 2: IPv6
if ret.Subnet.Family <= 2 {
ret.Subnet.IP = opt.Address.String()
} else {
ret.Subnet.IP = hex.EncodeToString([]byte(opt.Address))
}
if opt.SourceScope != 0 {
ret.Subnet.Scope = opt.SourceScope
}
case *dns.EDNS0_COOKIE:
ret.Cookie = append(ret.Cookie, opt.String())
case *dns.EDNS0_EXPIRE:
ret.Expire = opt.Expire
case *dns.EDNS0_TCP_KEEPALIVE:
ret.KeepAlive = opt.Timeout
case *dns.EDNS0_LLQ:
ret.LLQ = &EdnsLLQ{
Version: opt.Version,
Opcode: opt.Opcode,
Error: opt.Error,
ID: opt.Id,
Lease: opt.LeaseLife,
}
case *dns.EDNS0_DAU:
ret.Dau = opt.AlgCode
case *dns.EDNS0_DHU:
ret.Dhu = opt.AlgCode
case *dns.EDNS0_N3U:
ret.N3u = opt.AlgCode
case *dns.EDNS0_PADDING:
ret.Padding = string(opt.Padding)
case *dns.EDNS0_EDE:
ret.EDE = &EDNSErr{
Code: opt.InfoCode,
Purpose: dns.ExtendedErrorCodeToString[opt.InfoCode],
Text: opt.ExtraText,
}
}
}
return ret, nil
}

64
pkg/resolvers/DNSCrypt.go Normal file
View File

@ -0,0 +1,64 @@
// SPDX-License-Identifier: BSD-3-Clause
package resolvers
import (
"fmt"
"time"
"dns.froth.zone/awl/pkg/util"
"dns.froth.zone/dnscrypt"
"github.com/miekg/dns"
)
// DNSCryptResolver is for making DNSCrypt queries.
type DNSCryptResolver struct {
opts *util.Options
}
var _ Resolver = (*DNSCryptResolver)(nil)
// LookUp performs a DNS query.
func (resolver *DNSCryptResolver) LookUp(msg *dns.Msg) (resp util.Response, err error) {
client := dnscrypt.Client{
Timeout: resolver.opts.Request.Timeout,
UDPSize: 1232,
}
if resolver.opts.TCP || resolver.opts.TLS {
client.Net = tcp
} else {
client.Net = udp
}
switch {
case resolver.opts.IPv4:
client.Net += "4"
case resolver.opts.IPv6:
client.Net += "6"
}
resolver.opts.Logger.Debug("Using", client.Net, "for making the request")
resolverInf, err := client.Dial(resolver.opts.Request.Server)
if err != nil {
return resp, fmt.Errorf("dnscrypt: dial: %w", err)
}
now := time.Now()
res, err := client.Exchange(msg, resolverInf)
rtt := time.Since(now)
if err != nil {
return resp, fmt.Errorf("dnscrypt: exchange: %w", err)
}
resp = util.Response{
DNS: res,
RTT: rtt,
}
resolver.opts.Logger.Info("Request successful")
return
}

View File

@ -0,0 +1,93 @@
// SPDX-License-Identifier: BSD-3-Clause
package resolvers_test
import (
"errors"
"testing"
"dns.froth.zone/awl/pkg/query"
"dns.froth.zone/awl/pkg/util"
"dns.froth.zone/dnscrypt"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestDNSCrypt(t *testing.T) {
t.Parallel()
//nolint:govet // I could not be assed to refactor this, and it is only for tests
tests := []struct {
name string
opts *util.Options
}{
{
"Valid",
&util.Options{
Logger: util.InitLogger(0),
DNSCrypt: true,
Request: util.Request{
Server: "sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20",
Type: dns.TypeA,
Name: "example.com.",
Retries: 3,
},
},
},
{
"Valid (TCP)",
&util.Options{
Logger: util.InitLogger(0),
DNSCrypt: true,
TCP: true,
IPv4: true,
Request: util.Request{
Server: "sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20",
Type: dns.TypeAAAA,
Name: "example.com.",
Retries: 3,
},
},
},
{
"Invalid",
&util.Options{
Logger: util.InitLogger(0),
DNSCrypt: true,
TCP: true,
IPv4: true,
Request: util.Request{
Server: "QMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20",
Type: dns.TypeAAAA,
Name: "example.com.",
Retries: 0,
},
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
var (
res util.Response
err error
)
for i := 0; i <= test.opts.Request.Retries; i++ {
res, err = query.CreateQuery(test.opts)
if err == nil || errors.Is(err, dnscrypt.ErrInvalidDNSStamp) {
break
}
}
if err == nil {
assert.Assert(t, res != util.Response{})
} else {
assert.ErrorContains(t, err, "unsupported stamp")
}
})
}
}

104
pkg/resolvers/HTTPS.go Normal file
View File

@ -0,0 +1,104 @@
// SPDX-License-Identifier: BSD-3-Clause
package resolvers
import (
"bytes"
"crypto/tls"
"fmt"
"io"
"net/http"
"time"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
)
// HTTPSResolver is for DNS-over-HTTPS queries.
type HTTPSResolver struct {
opts *util.Options
client http.Client
}
var _ Resolver = (*HTTPSResolver)(nil)
// LookUp performs a DNS query.
func (resolver *HTTPSResolver) LookUp(msg *dns.Msg) (resp util.Response, err error) {
resolver.client = http.Client{
Timeout: resolver.opts.Request.Timeout,
Transport: &http.Transport{
MaxConnsPerHost: 1,
MaxIdleConns: 1,
MaxIdleConnsPerHost: 1,
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
//nolint:gosec // This is intentional if the user requests it
InsecureSkipVerify: resolver.opts.TLSNoVerify,
ServerName: resolver.opts.TLSHost,
},
},
}
buf, err := msg.Pack()
if err != nil {
return resp, fmt.Errorf("doh: packing: %w", err)
}
resolver.opts.Logger.Debug("https: sending HTTPS request")
var method string
if resolver.opts.HTTPSOptions.Get {
method = "GET"
} else {
method = "POST"
}
req, err := http.NewRequest(method, resolver.opts.Request.Server, bytes.NewBuffer(buf))
if err != nil {
return resp, fmt.Errorf("doh: request creation: %w", err)
}
req.Header.Set("Content-Type", "application/dns-message")
req.Header.Set("Accept", "application/dns-message")
now := time.Now()
res, err := resolver.client.Do(req)
resp.RTT = time.Since(now)
if err != nil {
// overwrite RTT or else tests will fail
resp.RTT = 0
return resp, fmt.Errorf("doh: HTTP request: %w", err)
}
if res.StatusCode != http.StatusOK {
// overwrite RTT or else tests will fail
resp.RTT = 0
return resp, &util.ErrHTTPStatus{Code: res.StatusCode}
}
resolver.opts.Logger.Debug("https: reading response")
fullRes, err := io.ReadAll(res.Body)
if err != nil {
return resp, fmt.Errorf("doh: body read: %w", err)
}
err = res.Body.Close()
if err != nil {
return resp, fmt.Errorf("doh: body close: %w", err)
}
resolver.opts.Logger.Debug("https: unpacking response")
resp.DNS = &dns.Msg{}
err = resp.DNS.Unpack(fullRes)
if err != nil {
return resp, fmt.Errorf("doh: dns message unpack: %w", err)
}
return resp, nil
}

102
pkg/resolvers/HTTPS_test.go Normal file
View File

@ -0,0 +1,102 @@
// SPDX-License-Identifier: BSD-3-Clause
package resolvers_test
import (
"errors"
"testing"
"dns.froth.zone/awl/pkg/query"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestHTTPS(t *testing.T) {
t.Parallel()
//nolint:govet // I could not be assed to refactor this, and it is only for tests
tests := []struct {
name string
opts *util.Options
}{
{
"Good",
&util.Options{
HTTPS: true,
Logger: util.InitLogger(0),
Request: util.Request{
Server: "https://dns9.quad9.net/dns-query",
Type: dns.TypeA,
Name: "git.froth.zone.",
Retries: 3,
},
},
},
{
"404",
&util.Options{
HTTPS: true,
Logger: util.InitLogger(0),
Request: util.Request{
Server: "https://dns9.quad9.net/dns",
Type: dns.TypeA,
Name: "git.froth.zone.",
},
},
},
{
"Bad request domain",
&util.Options{
HTTPS: true,
Logger: util.InitLogger(0),
Request: util.Request{
Server: "dns9.quad9.net/dns-query",
Type: dns.TypeA,
Name: "git.froth.zone",
},
},
},
{
"Bad server domain",
&util.Options{
HTTPS: true,
Logger: util.InitLogger(0),
Request: util.Request{
Server: "dns9..quad9.net/dns-query",
Type: dns.TypeA,
Name: "git.froth.zone.",
},
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
var (
res util.Response
err error
)
for i := 0; i <= test.opts.Request.Retries; i++ {
res, err = query.CreateQuery(test.opts)
if err == nil || errors.Is(err, &util.ErrHTTPStatus{}) {
break
}
}
if err == nil {
assert.NilError(t, err)
assert.Assert(t, res != util.Response{})
} else {
if errors.Is(err, &util.ErrHTTPStatus{}) {
assert.ErrorContains(t, err, "404")
}
assert.Equal(t, res, util.Response{})
}
})
}
}

110
pkg/resolvers/QUIC.go Normal file
View File

@ -0,0 +1,110 @@
// SPDX-License-Identifier: BSD-3-Clause
package resolvers
import (
"context"
"crypto/tls"
"fmt"
"io"
"strings"
"time"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
"github.com/quic-go/quic-go"
)
// QUICResolver is for DNS-over-QUIC queries.
type QUICResolver struct {
opts *util.Options
}
var _ Resolver = (*QUICResolver)(nil)
// LookUp performs a DNS query.
func (resolver *QUICResolver) LookUp(msg *dns.Msg) (resp util.Response, err error) {
tls := &tls.Config{
//nolint:gosec // This is intentional if the user requests it
InsecureSkipVerify: resolver.opts.TLSNoVerify,
ServerName: resolver.opts.TLSHost,
MinVersion: tls.VersionTLS12,
NextProtos: []string{"doq"},
}
// Make sure that TLSHost is ALWAYS set
if resolver.opts.TLSHost == "" {
tls.ServerName = strings.Split(resolver.opts.Request.Server, ":")[0]
}
conf := new(quic.Config)
conf.HandshakeIdleTimeout = resolver.opts.Request.Timeout
resolver.opts.Logger.Debug("quic: making query")
ctx, cancel := context.WithTimeout(context.Background(), resolver.opts.Request.Timeout)
defer cancel()
connection, err := quic.DialAddr(ctx, resolver.opts.Request.Server, tls, conf)
if err != nil {
return resp, fmt.Errorf("doq: dial: %w", err)
}
resolver.opts.Logger.Debug("quic: packing query")
// Compress request to over-the-wire
buf, err := msg.Pack()
if err != nil {
return resp, fmt.Errorf("doq: pack: %w", err)
}
t := time.Now()
resolver.opts.Logger.Debug("quic: creating stream")
stream, err := connection.OpenStream()
if err != nil {
return resp, fmt.Errorf("doq: quic stream creation: %w", err)
}
resolver.opts.Logger.Debug("quic: writing to stream")
_, err = stream.Write(buf)
if err != nil {
return resp, fmt.Errorf("doq: quic stream write: %w", err)
}
err = stream.Close()
if err != nil {
return resp, fmt.Errorf("doq: quic stream close: %w", err)
}
resolver.opts.Logger.Debug("quic: reading stream")
fullRes, err := io.ReadAll(stream)
if err != nil {
return resp, fmt.Errorf("doq: quic stream read: %w", err)
}
resp.RTT = time.Since(t)
resolver.opts.Logger.Debug("quic: closing connection")
// Close with error: no error
err = connection.CloseWithError(0, "")
if err != nil {
return resp, fmt.Errorf("doq: quic connection close: %w", err)
}
resolver.opts.Logger.Debug("quic: closing stream")
resp.DNS = &dns.Msg{}
resolver.opts.Logger.Debug("quic: unpacking response")
err = resp.DNS.Unpack(fullRes)
if err != nil {
return resp, fmt.Errorf("doq: unpack: %w", err)
}
return
}

125
pkg/resolvers/QUIC_test.go Normal file
View File

@ -0,0 +1,125 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build !gccgo
package resolvers_test
import (
"testing"
"time"
"dns.froth.zone/awl/pkg/query"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestQuic(t *testing.T) {
t.Parallel()
//nolint:govet // I could not be assed to refactor this, and it is only for tests
tests := []struct {
name string
opts *util.Options
}{
{
"Valid, AdGuard",
&util.Options{
QUIC: true,
Logger: util.InitLogger(0),
Request: util.Request{
Server: "dns.adguard.com",
Type: dns.TypeNS,
Port: 853,
Timeout: 750 * time.Millisecond,
Retries: 3,
},
},
},
{
"Valid, Froth",
&util.Options{
QUIC: true,
Logger: util.InitLogger(0),
Request: util.Request{
Server: "dns.froth.zone",
Type: dns.TypeA,
Name: "git.freecumextremist.com",
Port: 853,
Timeout: 750 * time.Millisecond,
Retries: 3,
},
},
},
{
"Bad domain",
&util.Options{
QUIC: true,
Logger: util.InitLogger(0),
Request: util.Request{
Server: "dns.//./,,adguard\a.com",
Port: 853,
Type: dns.TypeA,
Name: "git.froth.zone",
Timeout: 100 * time.Millisecond,
Retries: 0,
},
},
},
{
"Not canonical",
&util.Options{
QUIC: true,
Logger: util.InitLogger(0),
Request: util.Request{
Server: "dns.adguard.com",
Port: 853,
Type: dns.TypeA,
Name: "git.froth.zone",
Timeout: 100 * time.Millisecond,
Retries: 0,
},
},
},
{
"Invalid query domain",
&util.Options{
QUIC: true,
Logger: util.InitLogger(0),
Request: util.Request{
Server: "example.com",
Port: 853,
Type: dns.TypeA,
Name: "git.froth.zone",
Timeout: 10 * time.Millisecond,
Retries: 0,
},
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
var (
res util.Response
err error
)
for i := 0; i <= test.opts.Request.Retries; i++ {
res, err = query.CreateQuery(test.opts)
if err == nil {
break
}
}
if err == nil {
assert.NilError(t, err)
assert.Assert(t, res != util.Response{})
} else {
assert.Assert(t, res == util.Response{})
}
})
}
}

4
pkg/resolvers/docs.go Normal file
View File

@ -0,0 +1,4 @@
/*
Package resolvers contain the various DNS resolvers to use.
*/
package resolvers

96
pkg/resolvers/general.go Normal file
View File

@ -0,0 +1,96 @@
// SPDX-License-Identifier: BSD-3-Clause
package resolvers
import (
"crypto/tls"
"fmt"
"net"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
)
// StandardResolver is for UDP/TCP resolvers.
type StandardResolver struct {
opts *util.Options
}
var _ Resolver = (*StandardResolver)(nil)
// LookUp performs a DNS query.
func (resolver *StandardResolver) LookUp(msg *dns.Msg) (resp util.Response, err error) {
dnsClient := new(dns.Client)
dnsClient.Dialer = &net.Dialer{
Timeout: resolver.opts.Request.Timeout,
}
if resolver.opts.TCP || resolver.opts.TLS {
dnsClient.Net = tcp
} else {
dnsClient.Net = udp
}
switch {
case resolver.opts.IPv4:
dnsClient.Net += "4"
case resolver.opts.IPv6:
dnsClient.Net += "6"
}
if resolver.opts.TLS {
dnsClient.Net += "-tls"
dnsClient.TLSConfig = &tls.Config{
//nolint:gosec // This is intentional if the user requests it
InsecureSkipVerify: resolver.opts.TLSNoVerify,
ServerName: resolver.opts.TLSHost,
}
}
resolver.opts.Logger.Info("Using", dnsClient.Net, "for making the request")
resp.DNS, resp.RTT, err = dnsClient.Exchange(msg, resolver.opts.Request.Server)
if err != nil {
return resp, fmt.Errorf("standard: DNS exchange: %w", err)
}
switch dns.RcodeToString[resp.DNS.MsgHdr.Rcode] {
case "BADCOOKIE":
if !resolver.opts.BadCookie {
fmt.Printf(";; BADCOOKIE, retrying.\n\n")
msg.Extra = resp.DNS.Extra
resp.DNS, resp.RTT, err = dnsClient.Exchange(msg, resolver.opts.Request.Server)
if err != nil {
return resp, fmt.Errorf("badcookie: DNS exchange: %w", err)
}
}
case "NOERR":
break
}
resolver.opts.Logger.Info("Request successful")
if resp.DNS.MsgHdr.Truncated && !resolver.opts.Truncate {
fmt.Printf(";; Truncated, retrying with TCP\n\n")
dnsClient.Net = tcp
switch {
case resolver.opts.IPv4:
dnsClient.Net += "4"
case resolver.opts.IPv6:
dnsClient.Net += "6"
}
resp.DNS, resp.RTT, err = dnsClient.Exchange(msg, resolver.opts.Request.Server)
}
if err != nil {
return resp, fmt.Errorf("standard: DNS exchange: %w", err)
}
return
}

View File

@ -0,0 +1,141 @@
// SPDX-License-Identifier: BSD-3-Clause
package resolvers_test
import (
"errors"
"os"
"testing"
"time"
"dns.froth.zone/awl/pkg/query"
"dns.froth.zone/awl/pkg/util"
"dns.froth.zone/dnscrypt"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestResolve(t *testing.T) {
t.Parallel()
//nolint:govet // I could not be assed to refactor this, and it is only for tests
tests := []struct {
name string
opts *util.Options
}{
{
"UDP",
&util.Options{
Logger: util.InitLogger(0),
Request: util.Request{
Server: "8.8.4.4",
Port: 53,
Type: dns.TypeAAAA,
Name: "example.com.",
Retries: 3,
},
},
},
{
"UDP (Bad Cookie)",
&util.Options{
Logger: util.InitLogger(0),
BadCookie: false,
Request: util.Request{
Server: "b.root-servers.net",
Port: 53,
Type: dns.TypeNS,
Name: "example.com.",
Retries: 3,
},
EDNS: util.EDNS{
EnableEDNS: true,
Cookie: true,
},
},
},
{
"UDP (Truncated)",
&util.Options{
Logger: util.InitLogger(0),
IPv4: true,
Request: util.Request{
Server: "madns.binarystar.systems",
Port: 5301,
Type: dns.TypeTXT,
Name: "limit.txt.example.",
Retries: 3,
},
},
},
{
"TCP",
&util.Options{
Logger: util.InitLogger(0),
TCP: true,
Request: util.Request{
Server: "8.8.4.4",
Port: 53,
Type: dns.TypeA,
Name: "example.com.",
Retries: 3,
},
},
},
{
"TLS",
&util.Options{
Logger: util.InitLogger(0),
TLS: true,
Request: util.Request{
Server: "dns.google",
Port: 853,
Type: dns.TypeAAAA,
Name: "example.com.",
Retries: 3,
},
},
},
{
"Timeout",
&util.Options{
Logger: util.InitLogger(0),
Request: util.Request{
Server: "8.8.4.1",
Port: 1,
Type: dns.TypeA,
Name: "example.com.",
Timeout: time.Millisecond * 100,
Retries: 0,
},
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
var (
res util.Response
err error
)
for i := 0; i <= test.opts.Request.Retries; i++ {
res, err = query.CreateQuery(test.opts)
if err == nil || errors.Is(err, dnscrypt.ErrInvalidDNSStamp) {
break
}
}
if err == nil {
assert.NilError(t, err)
assert.Assert(t, res != util.Response{})
} else {
assert.ErrorIs(t, err, os.ErrDeadlineExceeded)
}
})
}
}

81
pkg/resolvers/resolver.go Normal file
View File

@ -0,0 +1,81 @@
// SPDX-License-Identifier: BSD-3-Clause
package resolvers
import (
"net"
"strconv"
"strings"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
)
const (
tcp = "tcp"
udp = "udp"
)
// Resolver is the main resolver interface.
type Resolver interface {
LookUp(*dns.Msg) (util.Response, error)
}
// LoadResolver loads the respective resolver for performing a DNS query.
func LoadResolver(opts *util.Options) (resolver Resolver, err error) {
switch {
case opts.HTTPS:
opts.Logger.Info("loading DNS-over-HTTPS resolver")
if !strings.HasPrefix(opts.Request.Server, "https://") {
opts.Request.Server = "https://" + opts.Request.Server
}
// Make sure that the endpoint is defaulted to /dns-query
if !strings.HasSuffix(opts.Request.Server, opts.HTTPSOptions.Endpoint) {
opts.Request.Server += opts.HTTPSOptions.Endpoint
}
resolver = &HTTPSResolver{
opts: opts,
}
return
case opts.QUIC:
opts.Logger.Info("loading DNS-over-QUIC resolver")
if !strings.HasSuffix(opts.Request.Server, ":"+strconv.Itoa(opts.Request.Port)) {
opts.Request.Server = net.JoinHostPort(opts.Request.Server, strconv.Itoa(opts.Request.Port))
}
resolver = &QUICResolver{
opts: opts,
}
return
case opts.DNSCrypt:
opts.Logger.Info("loading DNSCrypt resolver")
if !strings.HasPrefix(opts.Request.Server, "sdns://") {
opts.Request.Server = "sdns://" + opts.Request.Server
}
resolver = &DNSCryptResolver{
opts: opts,
}
return
default:
opts.Logger.Info("loading standard/DNS-over-TLS resolver")
if !strings.HasSuffix(opts.Request.Server, ":"+strconv.Itoa(opts.Request.Port)) {
opts.Request.Server = net.JoinHostPort(opts.Request.Server, strconv.Itoa(opts.Request.Port))
}
resolver = &StandardResolver{
opts: opts,
}
return
}
}

4
pkg/util/docs.go Normal file
View File

@ -0,0 +1,4 @@
// SPDX-License-Identifier: BSD-3-Clause
// Package util contains helper functions that don't belong anywhere else
package util

19
pkg/util/errors.go Normal file
View File

@ -0,0 +1,19 @@
package util
import (
"errors"
"fmt"
)
// ErrHTTPStatus is returned when DoH returns a bad status code.
type ErrHTTPStatus struct {
// Status code
Code int
}
func (e *ErrHTTPStatus) Error() string {
return fmt.Sprintf("doh server responded with HTTP %d", e.Code)
}
// ErrNotError is an error that is not actually an error.
var ErrNotError = errors.New("not an error")

14
pkg/util/logger.go Normal file
View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: BSD-3-Clause
package util
import "dns.froth.zone/awl/pkg/logawl"
// InitLogger initializes the logawl instance.
func InitLogger(verbosity int) (log *logawl.Logger) {
log = logawl.New()
log.SetLevel(logawl.Level(verbosity))
return log
}

View File

@ -5,12 +5,14 @@ package util_test
import (
"testing"
"git.froth.zone/sam/awl/logawl"
"git.froth.zone/sam/awl/util"
"dns.froth.zone/awl/pkg/logawl"
"dns.froth.zone/awl/pkg/util"
"gotest.tools/v3/assert"
)
func TestInitLogger(t *testing.T) {
t.Parallel()
logger := util.InitLogger(0)
assert.Equal(t, logger.Level, logawl.Level(0))
}

200
pkg/util/options.go Normal file
View File

@ -0,0 +1,200 @@
// SPDX-License-Identifier: BSD-3-Clause
package util
import (
"fmt"
"net"
"dns.froth.zone/awl/pkg/logawl"
"github.com/miekg/dns"
)
// Options is the grand structure for all query options.
type Options struct {
// The logger
Logger *logawl.Logger `json:"-"`
// Host to verify TLS cert with
TLSHost string `json:"tlsHost" example:""`
// EDNS Options
EDNS
// HTTPS options :)
HTTPSOptions
// DNS request :)
Request
// Verbosity levels, see [logawl.AllLevels]
Verbosity int `json:"-" example:"0"`
// Display options
Display Display
// Ignore Truncation
Truncate bool `json:"ignoreTruncate" example:"false"`
// Ignore BADCOOKIE
BadCookie bool `json:"ignoreBadCookie" example:"false"`
// Print only the answer
Short bool `json:"short" example:"false"`
// When Short is true, display where the query came from
Identify bool `json:"identify" example:"false"`
// Perform a reverse DNS query when true
Reverse bool `json:"reverse" example:"false"`
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" example:"false"`
// Use DNS-over-TLS to make the query
TLS bool `json:"dnsOverTLS" example:"false"`
// When using TLS, ignore certificates
TLSNoVerify bool `json:"tlsNoVerify" example:"false"`
// Use DNS-over-HTTPS to make the query
HTTPS bool `json:"dnsOverHTTPS" example:"false"`
// Use DNS-over-QUIC to make the query
//nolint:tagliatelle // QUIC is an acronym
QUIC bool `json:"dnsOverQUIC" example:"false"`
// Use DNSCrypt to make the query
DNSCrypt bool `json:"dnscrypt" example:"false"`
// Force IPv4 only
IPv4 bool `json:"forceIPv4" example:"false"`
// Force IPv6 only
IPv6 bool `json:"forceIPv6" example:"false"`
// Trace from the root
Trace bool `json:"trace" example:"false"`
}
// HTTPSOptions are options exclusively for DNS-over-HTTPS queries.
type HTTPSOptions struct {
// URL endpoint
Endpoint string `json:"endpoint" example:"/dns-query"`
// True, make GET request.
// False, make POST request.
Get bool `json:"get" example:"false"`
}
// HeaderFlags are the flags that are in DNS headers.
type HeaderFlags struct {
// Authoritative Answer DNS query flag
AA bool `json:"authoritative" example:"false"`
// Authenticated Data DNS query flag
AD bool `json:"authenticatedData" example:"false"`
// Checking Disabled DNS query flag
CD bool `json:"checkingDisabled" example:"false"`
// QueRy DNS query flag
QR bool `json:"query" example:"false"`
// Recursion Desired DNS query flag
RD bool `json:"recursionDesired" example:"true"`
// Recursion Available DNS query flag
RA bool `json:"recursionAvailable" example:"false"`
// TrunCated DNS query flag
TC bool `json:"truncated" example:"false"`
// Zero DNS query flag
Z bool `json:"zero" example:"false"`
}
// Display contains toggles for what to (and not to) display.
type Display struct {
/* Section displaying */
// Comments?
Comments bool `json:"comments" example:"true"`
// QUESTION SECTION
Question bool `json:"question" example:"true"`
// OPT PSEUDOSECTION
Opt bool `json:"opt" example:"true"`
// ANSWER SECTION
Answer bool `json:"answer" example:"true"`
// AUTHORITY SECTION
Authority bool `json:"authority" example:"true"`
// ADDITIONAL SECTION
Additional bool `json:"additional" example:"true"`
// Query time, message size, etc.
Statistics bool `json:"statistics" example:"true"`
// Display TTL in response
TTL bool `json:"ttl" example:"true"`
/* Answer formatting */
// Display Class in response
ShowClass bool `json:"showClass" example:"true"`
// Display query before it is sent
ShowQuery bool `json:"showQuery" example:"false"`
// Display TTL as human-readable
HumanTTL bool `json:"humanTTL" example:"false"`
// Translate Punycode back to Unicode
UcodeTranslate bool `json:"unicode" example:"true"`
}
// 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" example:"0"`
// UDP buffer size
BufSize uint16 `json:"bufSize" example:"1232"`
// Enable/Disable EDNS entirely
EnableEDNS bool `json:"edns" example:"false"`
// Sending EDNS cookie
Cookie bool `json:"cookie" example:"true"`
// Enabling DNSSEC
DNSSEC bool `json:"dnssec" example:"false"`
// Sending EDNS Expire
Expire bool `json:"expire" example:"false"`
// Sending EDNS TCP keepopen
KeepOpen bool `json:"keepOpen" example:"false"`
// Sending EDNS NSID
Nsid bool `json:"nsid" example:"false"`
// Send EDNS Padding
Padding bool `json:"padding" example:"false"`
// Set EDNS version (default: 0)
Version uint8 `json:"version" example:"0"`
}
// 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
}

36
pkg/util/options_test.go Normal file
View File

@ -0,0 +1,36 @@
// SPDX-License-Identifier: BSD-3-Clause
package util_test
import (
"testing"
"dns.froth.zone/awl/pkg/util"
"gotest.tools/v3/assert"
)
func TestSubnet(t *testing.T) {
t.Parallel()
subnet := []string{
"0.0.0.0/0",
"::0/0",
"0",
"127.0.0.1/32",
"Invalid",
}
for _, test := range subnet {
test := test
t.Run(test, func(t *testing.T) {
t.Parallel()
err := util.ParseSubnet(test, new(util.Options))
if err != nil {
assert.ErrorContains(t, err, "invalid CIDR address")
} else {
assert.NilError(t, err)
}
})
}
}

35
pkg/util/query.go Normal file
View File

@ -0,0 +1,35 @@
// SPDX-License-Identifier: BSD-3-Clause
package util
import (
"time"
"github.com/miekg/dns"
)
// Response is the DNS response.
type Response struct {
// The full DNS response
DNS *dns.Msg `json:"response"`
// The time it took to make the DNS query
RTT time.Duration `json:"rtt" example:"2000000000"`
}
// Request is a structure for a DNS query.
type Request struct {
// Server to query
Server string `json:"server" example:"1.0.0.1"`
// Domain to query
Name string `json:"name" example:"example.com"`
// Duration to wait until marking request as failed
Timeout time.Duration `json:"timeout" example:"2000000000"`
// Port to make DNS request on
Port int `json:"port" example:"53"`
// Number of failures to make before giving up
Retries int `json:"retries" example:"2"`
// Request type, eg. A, AAAA, NAPTR
Type uint16 `json:"type" example:"1"`
// Request class, eg. IN
Class uint16 `json:"class" example:"1"`
}

View File

@ -3,18 +3,30 @@
package util
import (
"errors"
"fmt"
"strings"
"github.com/miekg/dns"
)
// Given an IP or phone number, return a canonical string to be queried.
type errReverseDNS struct {
addr string
}
func (errDNS *errReverseDNS) Error() string {
return fmt.Sprintf("reverseDNS: invalid value %s given", errDNS.addr)
}
// ReverseDNS is given an IP or phone number and returns a canonical string to be queried.
func ReverseDNS(address string, querInt uint16) (string, error) {
query := dns.TypeToString[querInt]
if query == "PTR" {
return dns.ReverseAddr(address)
str, err := dns.ReverseAddr(address)
if err != nil {
return "", fmt.Errorf("PTR reverse: %w", err)
}
return str, nil
} else if query == "NAPTR" {
// get rid of characters not needed
replacer := strings.NewReplacer("+", "", " ", "", "-", "")
@ -27,10 +39,11 @@ func ReverseDNS(address string, querInt uint16) (string, error) {
fmt.Fprintf(&arpa, "%c.", c)
}
arpa.WriteString("e164.arpa.")
return arpa.String(), nil
}
return "", errors.New("ReverseDNS: -x flag given but no IP found")
return "", &errReverseDNS{address}
}
// Reverse a string, return the string in reverse.
@ -39,5 +52,6 @@ func reverse(s string) string {
for i, j := 0, len(rns)-1; i < j; i, j = i+1, j-1 {
rns[i], rns[j] = rns[j], rns[i]
}
return string(rns)
}

View File

@ -0,0 +1,79 @@
// SPDX-License-Identifier: BSD-3-Clause
package util_test
import (
"testing"
"dns.froth.zone/awl/pkg/util"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestPTR(t *testing.T) {
t.Parallel()
tests := []struct {
name string
in string
expected string
}{
{
"IPv4",
"8.8.4.4", "4.4.8.8.in-addr.arpa.",
},
{
"IPv6",
"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.",
},
{
"Inavlid value",
"AAAAA", "",
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
act, err := util.ReverseDNS(test.in, dns.StringToType["PTR"])
if err == nil {
assert.NilError(t, err)
} else {
assert.ErrorContains(t, err, "unrecognized address")
}
assert.Equal(t, act, test.expected)
})
}
}
func TestNAPTR(t *testing.T) {
t.Parallel()
tests := []struct {
in string
want string
}{
{"1-800-555-1234", "4.3.2.1.5.5.5.0.0.8.1.e164.arpa."},
{"+1 800555 1234", "4.3.2.1.5.5.5.0.0.8.1.e164.arpa."},
{"+46766861004", "4.0.0.1.6.8.6.6.7.6.4.e164.arpa."},
{"17705551212", "2.1.2.1.5.5.5.0.7.7.1.e164.arpa."},
}
for _, test := range tests {
// Thanks Goroutines, very cool!
test := test
t.Run(test.in, func(t *testing.T) {
t.Parallel()
act, err := util.ReverseDNS(test.in, dns.StringToType["NAPTR"])
assert.NilError(t, err)
assert.Equal(t, test.want, act)
})
}
}
func TestInvalidAll(t *testing.T) {
_, err := util.ReverseDNS("q", 15236)
assert.ErrorContains(t, err, "invalid value")
}

View File

@ -1,58 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package query
import (
"time"
"git.froth.zone/sam/awl/cli"
"git.froth.zone/sam/awl/internal/helpers"
"github.com/ameshkov/dnscrypt/v2"
"github.com/miekg/dns"
)
type DNSCryptResolver struct {
opts cli.Options
}
func (r *DNSCryptResolver) LookUp(msg *dns.Msg) (helpers.Response, error) {
client := dnscrypt.Client{
Timeout: r.opts.Request.Timeout,
UDPSize: 1232,
}
if r.opts.TCP || r.opts.TLS {
client.Net = "tcp"
} else {
client.Net = "udp"
}
switch {
case r.opts.IPv4:
client.Net += "4"
case r.opts.IPv6:
client.Net += "6"
}
r.opts.Logger.Debug("Using", client.Net, "for making the request")
resolverInf, err := client.Dial(r.opts.Request.Server)
if err != nil {
return helpers.Response{}, err
}
now := time.Now()
res, err := client.Exchange(msg, resolverInf)
rtt := time.Since(now)
if err != nil {
return helpers.Response{}, err
}
r.opts.Logger.Info("Request successful")
return helpers.Response{
DNS: res,
RTT: rtt,
}, nil
}

View File

@ -1,52 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package query_test
import (
"testing"
"git.froth.zone/sam/awl/cli"
"git.froth.zone/sam/awl/internal/helpers"
"git.froth.zone/sam/awl/query"
"git.froth.zone/sam/awl/util"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestDNSCrypt(t *testing.T) {
tests := []struct {
opt cli.Options
}{
{
cli.Options{
Logger: util.InitLogger(0),
DNSCrypt: true,
Request: helpers.Request{
Server: "sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20",
Type: dns.TypeA,
Name: "example.com.",
},
},
},
{
cli.Options{
Logger: util.InitLogger(0),
DNSCrypt: true,
TCP: true,
IPv4: true,
Request: helpers.Request{
Server: "sdns://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20",
Type: dns.TypeAAAA,
Name: "example.com.",
},
},
},
}
for _, test := range tests {
res, err := query.CreateQuery(test.opt)
assert.NilError(t, err)
assert.Assert(t, res != helpers.Response{})
}
}

View File

@ -1,64 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package query
import (
"bytes"
"fmt"
"io"
"net/http"
"time"
"git.froth.zone/sam/awl/cli"
"git.froth.zone/sam/awl/internal/helpers"
"github.com/miekg/dns"
)
type HTTPSResolver struct {
opts cli.Options
}
func (r *HTTPSResolver) LookUp(msg *dns.Msg) (helpers.Response, error) {
var resp helpers.Response
httpR := &http.Client{
Timeout: r.opts.Request.Timeout,
}
buf, err := msg.Pack()
if err != nil {
return helpers.Response{}, err
}
r.opts.Logger.Debug("making DoH request")
// query := server + "?dns=" + base64.RawURLEncoding.EncodeToString(buf)
req, err := http.NewRequest("POST", r.opts.Request.Server, bytes.NewBuffer(buf))
if err != nil {
return helpers.Response{}, fmt.Errorf("DoH: %w", err)
}
req.Header.Set("Content-Type", "application/dns-message")
req.Header.Set("Accept", "application/dns-message")
now := time.Now()
res, err := httpR.Do(req)
resp.RTT = time.Since(now)
if err != nil {
return helpers.Response{}, fmt.Errorf("DoH HTTP request error: %w", err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return helpers.Response{}, fmt.Errorf("DoH server responded with HTTP %d", res.StatusCode)
}
fullRes, err := io.ReadAll(res.Body)
if err != nil {
return helpers.Response{}, fmt.Errorf("DoH body read error: %w", err)
}
resp.DNS = &dns.Msg{}
r.opts.Logger.Debug("unpacking response")
err = resp.DNS.Unpack(fullRes)
if err != nil {
return helpers.Response{}, fmt.Errorf("DoH dns message unpack error: %w", err)
}
return resp, nil
}

View File

@ -1,105 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package query_test
import (
"fmt"
"strings"
"testing"
"git.froth.zone/sam/awl/cli"
"git.froth.zone/sam/awl/internal/helpers"
"git.froth.zone/sam/awl/query"
"git.froth.zone/sam/awl/util"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestResolveHTTPS(t *testing.T) {
t.Parallel()
var err error
opts := cli.Options{
HTTPS: true,
Logger: util.InitLogger(0),
Request: helpers.Request{
Server: "https://dns9.quad9.net/dns-query",
Type: dns.TypeA,
Name: "git.froth.zone.",
},
}
// testCase := helpers.Request{Server: "https://dns9.quad9.net/dns-query", Type: dns.TypeA, Name: "git.froth.zone."}
resolver, err := query.LoadResolver(opts)
assert.NilError(t, err)
msg := new(dns.Msg)
msg.SetQuestion(opts.Request.Name, opts.Request.Type)
// msg = msg.SetQuestion(testCase.Name, testCase.Type)
res, err := resolver.LookUp(msg)
assert.NilError(t, err)
assert.Assert(t, res != helpers.Response{})
}
func Test2ResolveHTTPS(t *testing.T) {
t.Parallel()
opts := cli.Options{
HTTPS: true,
Logger: util.InitLogger(0),
}
var err error
testCase := helpers.Request{Server: "dns9.quad9.net/dns-query", Type: dns.TypeA, Name: "git.froth.zone"}
resolver, err := query.LoadResolver(opts)
assert.NilError(t, err)
msg := new(dns.Msg)
msg.SetQuestion(testCase.Name, testCase.Type)
// msg = msg.SetQuestion(testCase.Name, testCase.Type)
res, err := resolver.LookUp(msg)
assert.ErrorContains(t, err, "fully qualified")
assert.Equal(t, res, helpers.Response{})
}
func Test3ResolveHTTPS(t *testing.T) {
t.Parallel()
opts := cli.Options{
HTTPS: true,
Logger: util.InitLogger(0),
}
var err error
testCase := helpers.Request{Server: "dns9..quad9.net/dns-query", Type: dns.TypeA, Name: "git.froth.zone."}
// if the domain is not canonical, make it canonical
if !strings.HasSuffix(testCase.Name, ".") {
testCase.Name = fmt.Sprintf("%s.", testCase.Name)
}
resolver, err := query.LoadResolver(opts)
assert.NilError(t, err)
msg := new(dns.Msg)
msg.SetQuestion(testCase.Name, testCase.Type)
// msg = msg.SetQuestion(testCase.Name, testCase.Type)
res, err := resolver.LookUp(msg)
assert.ErrorContains(t, err, "request error")
assert.Equal(t, res, helpers.Response{})
}
func Test404ResolveHTTPS(t *testing.T) {
t.Parallel()
var err error
opts := cli.Options{
HTTPS: true,
Logger: util.InitLogger(0),
Request: helpers.Request{
Server: "https://dns9.quad9.net/dns",
Type: dns.TypeA,
Name: "git.froth.zone.",
},
}
// testCase := helpers.Request{Server: "https://dns9.quad9.net/dns-query", Type: dns.TypeA, Name: "git.froth.zone."}
resolver, err := query.LoadResolver(opts)
assert.NilError(t, err)
msg := new(dns.Msg)
msg.SetQuestion(opts.Request.Name, opts.Request.Type)
// msg = msg.SetQuestion(testCase.Name, testCase.Type)
res, err := resolver.LookUp(msg)
assert.ErrorContains(t, err, "404")
assert.Equal(t, res, helpers.Response{})
}

View File

@ -1,76 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package query
import (
"crypto/tls"
"io"
"time"
"git.froth.zone/sam/awl/cli"
"git.froth.zone/sam/awl/internal/helpers"
"github.com/lucas-clemente/quic-go"
"github.com/miekg/dns"
)
type QUICResolver struct {
opts cli.Options
}
func (r *QUICResolver) LookUp(msg *dns.Msg) (helpers.Response, error) {
var resp helpers.Response
tls := &tls.Config{
MinVersion: tls.VersionTLS12,
NextProtos: []string{"doq"},
}
conf := new(quic.Config)
conf.HandshakeIdleTimeout = r.opts.Request.Timeout
r.opts.Logger.Debug("making DoQ request")
connection, err := quic.DialAddr(r.opts.Request.Server, tls, conf)
if err != nil {
return helpers.Response{}, err
}
// Compress request to over-the-wire
buf, err := msg.Pack()
if err != nil {
return helpers.Response{}, err
}
t := time.Now()
stream, err := connection.OpenStream()
if err != nil {
return helpers.Response{}, err
}
_, err = stream.Write(buf)
if err != nil {
return helpers.Response{}, err
}
fullRes, err := io.ReadAll(stream)
if err != nil {
return helpers.Response{}, err
}
resp.RTT = time.Since(t)
// Close with error: no error
err = connection.CloseWithError(0, "")
if err != nil {
return helpers.Response{}, err
}
err = stream.Close()
if err != nil {
return helpers.Response{}, err
}
resp.DNS = &dns.Msg{}
r.opts.Logger.Debug("unpacking DoQ response")
err = resp.DNS.Unpack(fullRes)
if err != nil {
return helpers.Response{}, err
}
return resp, nil
}

View File

@ -1,84 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
package query_test
import (
"fmt"
"net"
"strconv"
"strings"
"testing"
"time"
"git.froth.zone/sam/awl/cli"
"git.froth.zone/sam/awl/internal/helpers"
"git.froth.zone/sam/awl/query"
"git.froth.zone/sam/awl/util"
"github.com/miekg/dns"
"gotest.tools/v3/assert"
)
func TestQuic(t *testing.T) {
t.Parallel()
opts := cli.Options{
QUIC: true,
Logger: util.InitLogger(0),
Port: 853,
Request: helpers.Request{Server: "dns.adguard.com"},
}
testCase := helpers.Request{Server: "dns.//./,,adguard.com", Type: dns.TypeA, Name: "git.froth.zone"}
testCase2 := helpers.Request{Server: "dns.adguard.com", Type: dns.TypeA, Name: "git.froth.zone"}
var testCases []helpers.Request
testCases = append(testCases, testCase)
testCases = append(testCases, testCase2)
for i := range testCases {
switch i {
case 0:
resolver, err := query.LoadResolver(opts)
assert.NilError(t, err)
// if the domain is not canonical, make it canonical
if !strings.HasSuffix(testCase.Name, ".") {
testCases[i].Name = fmt.Sprintf("%s.", testCases[i].Name)
}
msg := new(dns.Msg)
msg.SetQuestion(testCase.Name, testCase.Type)
msg = msg.SetQuestion(testCase.Name, testCase.Type)
res, err := resolver.LookUp(msg)
assert.ErrorContains(t, err, "fully qualified")
assert.Equal(t, res, helpers.Response{})
case 1:
resolver, err := query.LoadResolver(opts)
assert.NilError(t, err)
testCase2.Server = net.JoinHostPort(testCase2.Server, strconv.Itoa(opts.Port))
// if the domain is not canonical, make it canonical
if !strings.HasSuffix(testCase2.Name, ".") {
testCase2.Name = fmt.Sprintf("%s.", testCase2.Name)
}
msg := new(dns.Msg)
msg.SetQuestion(testCase2.Name, testCase2.Type)
msg = msg.SetQuestion(testCase2.Name, testCase2.Type)
res, err := resolver.LookUp(msg)
assert.NilError(t, err)
assert.Assert(t, res != helpers.Response{})
}
}
}
func TestInvalidQuic(t *testing.T) {
t.Parallel()
opts := cli.Options{
QUIC: true,
Logger: util.InitLogger(0),
Port: 853,
Request: helpers.Request{Server: "example.com", Type: dns.TypeA, Name: "git.froth.zone", Timeout: 10 * time.Millisecond},
}
resolver, err := query.LoadResolver(opts)
assert.NilError(t, err)
msg := new(dns.Msg)
msg.SetQuestion(opts.Request.Name, opts.Request.Type)
res, err := resolver.LookUp(msg)
assert.ErrorContains(t, err, "timeout")
assert.Equal(t, res, helpers.Response{})
}

View File

@ -1,2 +0,0 @@
// Package for the special query types
package query

Some files were not shown because too many files have changed in this diff Show More