Skip to content

Commit

Permalink
Simplified reverse DNS lookups.
Browse files Browse the repository at this point in the history
When the user tries to query an IP address dnslookup will detect
it and convert it to a proper PTR query (if RRTYPE is not specified).

Closes #71
  • Loading branch information
ameshkov committed Jun 18, 2024
1 parent 63175b2 commit beff2a9
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 9 deletions.
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ DNS-over-HTTPS with IP:
dnslookup example.org https://dns.adguard.com/dns-query 94.140.14.14
```

DNS-over-HTTPS with basic auth (supported by [AdGuard DNS](https://adguard-dns.io/)):
DNS-over-HTTPS with basic auth (supported
by [AdGuard DNS](https://adguard-dns.io/)):

```shell
dnslookup example.org https://username:[email protected]/dns-query
```


DNSCrypt (stamp):

```shell
Expand All @@ -102,6 +102,20 @@ DNS-over-QUIC:
dnslookup example.org quic://dns.adguard.com
```

Sending a PTR query for an IPv4 address (IP address is recognized automatically
when RRTYPE is not specified):

```shell
dnslookup 8.8.8.8
```

Sending a PTR query for an IPv6 address (IP address is recognized automatically
when RRTYPE is not specified):

```shell
dnslookup 2606:4700:4700::1111
```

Machine-readable format:

```shell
Expand Down Expand Up @@ -154,6 +168,7 @@ EDNSOPT=65074:3132333435363738 RRTYPE=TXT dnslookup o-o.myaddr.l.google.com tls:
```

Combine multiple options:

```shell
RRTYPE=TXT SUBNET=1.1.1.1/24 PAD=1 dnslookup o-o.myaddr.l.google.com tls://8.8.8.8
```
Expand Down
67 changes: 60 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ func main() {
http3Enabled := os.Getenv("HTTP3") == "1"
verbose := os.Getenv("VERBOSE") == "1"
padding := os.Getenv("PAD") == "1"
class := getClass()
do := os.Getenv("DNSSEC") == "1"
subnetOpt := getSubnet()
ednsOpt := getEDNSOpt()
rrType := getRRType()
question := getQuestion()

if verbose {
log.SetLevel(log.DEBUG)
Expand Down Expand Up @@ -84,8 +83,6 @@ func main() {
timeout = i
}

domain := os.Args[1]

var server string
if len(os.Args) > 2 {
server = os.Args[2]
Expand Down Expand Up @@ -149,9 +146,7 @@ func main() {
req := &dns.Msg{}
req.Id = dns.Id()
req.RecursionDesired = true
req.Question = []dns.Question{
{Name: domain + ".", Qtype: rrType, Qclass: class},
}
req.Question = []dns.Question{question}

if subnetOpt != nil {
opt := getOrCreateOpt(req, do)
Expand Down Expand Up @@ -239,6 +234,64 @@ func getEDNSOpt() (option *dns.EDNS0_LOCAL) {
}
}

// getQuestion returns a DNS question for the query.
func getQuestion() (q dns.Question) {
domain := os.Args[1]
rrType := getRRType()
qClass := getClass()

// If the user tries to query an IP address and does not specify any
// query type, convert to PTR automatically.
ip := net.ParseIP(domain)
if os.Getenv("RRTYPE") == "" && ip != nil {
domain = ipToPtr(ip)
rrType = dns.TypePTR
}

q.Name = dns.Fqdn(domain)
q.Qtype = rrType
q.Qclass = qClass

return q
}

func ipToPtr(ip net.IP) (ptr string) {
if ip.To4() != nil {
return ip4ToPtr(ip)
}

return ip6ToPtr(ip)
}

func ip4ToPtr(ip net.IP) (ptr string) {
parts := strings.Split(ip.String(), ".")
for i := range parts {
ptr = parts[i] + "." + ptr
}
ptr = ptr + "in-addr.arpa."

return
}

func ip6ToPtr(ip net.IP) (ptr string) {
addr, _ := netip.ParseAddr(ip.String())
str := addr.StringExpanded()

// Remove colons and reverse the order of characters.
str = strings.ReplaceAll(str, ":", "")
reversed := ""
for i := len(str) - 1; i >= 0; i-- {
reversed += string(str[i])
if i != 0 {
reversed += "."
}
}

ptr = reversed + ".ip6.arpa."

return ptr
}

func getSubnet() (option *dns.EDNS0_SUBNET) {
subnetStr := os.Getenv("SUBNET")
if subnetStr == "" {
Expand Down

0 comments on commit beff2a9

Please sign in to comment.