From 276055b3d113b5ae848b4c183919c5217c60645b Mon Sep 17 00:00:00 2001 From: Ice3man Date: Sat, 15 Jan 2022 06:04:29 +0530 Subject: [PATCH 1/2] Added internal range check option to retryabledns --- client.go | 21 +++++++++++ validate.go | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 validate.go diff --git a/client.go b/client.go index b7efc38..98caeaa 100644 --- a/client.go +++ b/client.go @@ -18,8 +18,16 @@ import ( "github.com/projectdiscovery/retryabledns/hostsfile" ) +var internalRangeCheckerInstance *internalRangeChecker + func init() { rand.Seed(time.Now().UnixNano()) + + var err error + internalRangeCheckerInstance, err = newInternalRangeChecker() + if err != nil { + panic(err) + } } // Client is a DNS resolver client to resolve hostnames. @@ -391,6 +399,7 @@ type DNSData struct { NS []string `json:"ns,omitempty"` TXT []string `json:"txt,omitempty"` Raw string `json:"raw,omitempty"` + Internal bool `json:"internal,omitempty"` StatusCode string `json:"status_code,omitempty"` StatusCodeRaw int `json:"status_code_raw,omitempty"` TraceData *TraceData `json:"trace,omitempty"` @@ -398,13 +407,21 @@ type DNSData struct { Timestamp time.Time `json:"timestamp,omitempty"` } +// CheckInternalIPs when set to true returns if DNS response IPs +// belong to internal IP ranges. +var CheckInternalIPs = false + // ParseFromMsg and enrich data func (d *DNSData) ParseFromMsg(msg *dns.Msg) error { allRecords := append(msg.Answer, msg.Extra...) allRecords = append(allRecords, msg.Ns...) + for _, record := range allRecords { switch recordType := record.(type) { case *dns.A: + if CheckInternalIPs && internalRangeCheckerInstance.ContainsIPv4(recordType.A) { + d.Internal = true + } d.A = append(d.A, trimChars(recordType.A.String())) case *dns.NS: d.NS = append(d.NS, trimChars(recordType.Ns)) @@ -422,9 +439,13 @@ func (d *DNSData) ParseFromMsg(msg *dns.Msg) error { d.TXT = append(d.TXT, trimChars(txt)) } case *dns.AAAA: + if CheckInternalIPs && internalRangeCheckerInstance.ContainsIPv6(recordType.AAAA) { + d.Internal = true + } d.AAAA = append(d.AAAA, trimChars(recordType.AAAA.String())) } } + return nil } diff --git a/validate.go b/validate.go new file mode 100644 index 0000000..e15c88d --- /dev/null +++ b/validate.go @@ -0,0 +1,104 @@ +package retryabledns + +import "net" + +// ipv4InternalRanges contains the IP ranges internal in IPv4 range. +var ipv4InternalRanges = []string{ + "0.0.0.0/8", // Current network (only valid as source address) + "10.0.0.0/8", // Private network + "100.64.0.0/10", // Shared Address Space + "127.0.0.0/8", // Loopback + "169.254.0.0/16", // Link-local (Also many cloud providers Metadata endpoint) + "172.16.0.0/12", // Private network + "192.0.0.0/24", // IETF Protocol Assignments + "192.0.2.0/24", // TEST-NET-1, documentation and examples + "192.88.99.0/24", // IPv6 to IPv4 relay (includes 2002::/16) + "192.168.0.0/16", // Private network + "198.18.0.0/15", // Network benchmark tests + "198.51.100.0/24", // TEST-NET-2, documentation and examples + "203.0.113.0/24", // TEST-NET-3, documentation and examples + "224.0.0.0/4", // IP multicast (former Class D network) + "240.0.0.0/4", // Reserved (former Class E network) +} + +// ipv6InternalRanges contains the IP ranges internal in IPv6 range. +var ipv6InternalRanges = []string{ + "::1/128", // Loopback + "64:ff9b::/96", // IPv4/IPv6 translation (RFC 6052) + "100::/64", // Discard prefix (RFC 6666) + "2001::/32", // Teredo tunneling + "2001:10::/28", // Deprecated (previously ORCHID) + "2001:20::/28", // ORCHIDv2 + "2001:db8::/32", // Addresses used in documentation and example source code + "2002::/16", // 6to4 + "fc00::/7", // Unique local address + "fe80::/10", // Link-local address + "ff00::/8", // Multicast +} + +// internalRangeChecker contains a list of internal IP ranges. +type internalRangeChecker struct { + ipv4 []*net.IPNet + ipv6 []*net.IPNet +} + +// newInternalRangeChecker creates a structure for checking if a host is from +// a internal IP range whether its ipv4 or ipv6. +func newInternalRangeChecker() (*internalRangeChecker, error) { + rangeChecker := internalRangeChecker{} + + err := rangeChecker.appendIPv4Ranges(ipv4InternalRanges) + if err != nil { + return nil, err + } + + err = rangeChecker.appendIPv6Ranges(ipv6InternalRanges) + if err != nil { + return nil, err + } + return &rangeChecker, nil +} + +// appendIPv4Ranges adds a list of IPv4 Ranges to the list. +func (r *internalRangeChecker) appendIPv4Ranges(ranges []string) error { + for _, ip := range ranges { + _, rangeNet, err := net.ParseCIDR(ip) + if err != nil { + return err + } + r.ipv4 = append(r.ipv4, rangeNet) + } + return nil +} + +// appendIPv6Ranges adds a list of IPv6 Ranges to the list. +func (r *internalRangeChecker) appendIPv6Ranges(ranges []string) error { + for _, ip := range ranges { + _, rangeNet, err := net.ParseCIDR(ip) + if err != nil { + return err + } + r.ipv6 = append(r.ipv6, rangeNet) + } + return nil +} + +// ContainsIPv4 checks whether a given IP address exists in the internal IPv4 ranges. +func (r *internalRangeChecker) ContainsIPv4(IP net.IP) bool { + for _, net := range r.ipv4 { + if net.Contains(IP) { + return true + } + } + return false +} + +// ContainsIPv6 checks whether a given IP address exists in the internal IPv6 ranges. +func (r *internalRangeChecker) ContainsIPv6(IP net.IP) bool { + for _, net := range r.ipv6 { + if net.Contains(IP) { + return true + } + } + return false +} From 21ec131ac263b753881c81048c4c8ee5ba0d546d Mon Sep 17 00:00:00 2001 From: Ice3man Date: Sat, 22 Jan 2022 17:17:14 +0530 Subject: [PATCH 2/2] Removed panic --- client.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index 98caeaa..3ce98ae 100644 --- a/client.go +++ b/client.go @@ -5,6 +5,7 @@ import ( "encoding/gob" "encoding/json" "errors" + "fmt" "math/rand" "net" "strings" @@ -26,7 +27,7 @@ func init() { var err error internalRangeCheckerInstance, err = newInternalRangeChecker() if err != nil { - panic(err) + fmt.Printf("could not initialize range checker: %s\n", err) } } @@ -419,7 +420,7 @@ func (d *DNSData) ParseFromMsg(msg *dns.Msg) error { for _, record := range allRecords { switch recordType := record.(type) { case *dns.A: - if CheckInternalIPs && internalRangeCheckerInstance.ContainsIPv4(recordType.A) { + if CheckInternalIPs && internalRangeCheckerInstance != nil && internalRangeCheckerInstance.ContainsIPv4(recordType.A) { d.Internal = true } d.A = append(d.A, trimChars(recordType.A.String()))