mirror of
https://github.com/skidoodle/ipinfo.git
synced 2026-04-28 01:27:34 +02:00
fix dns lookup and asn prefixes
This commit is contained in:
@@ -6,6 +6,7 @@ require (
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/likexian/whois v1.15.6
|
||||
github.com/likexian/whois-parser v1.24.20
|
||||
github.com/miekg/dns v1.1.68
|
||||
github.com/oschwald/maxminddb-golang v1.13.1
|
||||
golang.org/x/net v0.44.0
|
||||
)
|
||||
@@ -15,6 +16,9 @@ require (
|
||||
github.com/likexian/gokit v0.25.15 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/stretchr/testify v1.10.0 // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/tools v0.36.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/likexian/gokit v0.25.15 h1:QjospM1eXhdMMHwZRpMKKAHY/Wig9wgcREmLtf9NslY=
|
||||
@@ -8,17 +10,25 @@ github.com/likexian/whois v1.15.6 h1:hizngFHJTNQDlhwhU+FEGyPGxy8bRnf25gHDNrSB4Ag
|
||||
github.com/likexian/whois v1.15.6/go.mod h1:vx3kt3sZ4mx4XFgpaNp3GXQCZQIzAoyrUAkRtJwoM2I=
|
||||
github.com/likexian/whois-parser v1.24.20 h1:oxEkRi0GxgqWQRLDMJpXU1EhgWmLmkqEFZ2ChXTeQLE=
|
||||
github.com/likexian/whois-parser v1.24.20/go.mod h1:rAtaofg2luol09H+ogDzGIfcG8ig1NtM5R16uQADDz4=
|
||||
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
|
||||
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
|
||||
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
+81
-61
@@ -11,6 +11,7 @@ import (
|
||||
"ipinfo/internal/db"
|
||||
|
||||
"github.com/likexian/whois-parser"
|
||||
"github.com/miekg/dns"
|
||||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
@@ -94,11 +95,14 @@ func LookupASNData(geoIP *db.GeoIPManager, targetASN uint) (*ASNDataResponse, er
|
||||
|
||||
var ipv4Prefixes, ipv6Prefixes []string
|
||||
for _, prefix := range prefixes {
|
||||
prefixStr := prefix.String()
|
||||
if strings.Contains(prefixStr, ":") {
|
||||
ipv6Prefixes = append(ipv6Prefixes, prefixStr)
|
||||
} else {
|
||||
ipv4Prefixes = append(ipv4Prefixes, prefixStr)
|
||||
// Filter out bogon prefixes before adding them to the list.
|
||||
if !IsBogon(prefix.IP) {
|
||||
prefixStr := prefix.String()
|
||||
if strings.Contains(prefixStr, ":") {
|
||||
ipv6Prefixes = append(ipv6Prefixes, prefixStr)
|
||||
} else {
|
||||
ipv4Prefixes = append(ipv4Prefixes, prefixStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Strings(ipv4Prefixes)
|
||||
@@ -119,6 +123,25 @@ func LookupASNData(geoIP *db.GeoIPManager, targetASN uint) (*ASNDataResponse, er
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// queryDns performs a DNS query for a specific type against a public resolver.
|
||||
func queryDns(domain string, recordType uint16) ([]dns.RR, error) {
|
||||
c := new(dns.Client)
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion(dns.Fqdn(domain), recordType)
|
||||
m.RecursionDesired = true
|
||||
|
||||
r, _, err := c.Exchange(m, "1.1.1.1:53") // Using Cloudflare's public resolver
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r.Rcode != dns.RcodeSuccess {
|
||||
return nil, nil // No error, just no records found
|
||||
}
|
||||
|
||||
return r.Answer, nil
|
||||
}
|
||||
|
||||
// LookupDomainData looks up domain data with caching.
|
||||
func LookupDomainData(domain string) (*DomainDataResponse, error) {
|
||||
if data, found := cache.Get(domain); found {
|
||||
@@ -149,68 +172,65 @@ func LookupDomainData(domain string) (*DomainDataResponse, error) {
|
||||
var wg sync.WaitGroup
|
||||
var mu sync.Mutex
|
||||
|
||||
lookupTasks := []func(){
|
||||
func() { // A and AAAA records
|
||||
ips, err := net.LookupIP(domain)
|
||||
if err == nil {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, ip := range ips {
|
||||
if ip.To4() != nil {
|
||||
dnsData.A = append(dnsData.A, ip.String())
|
||||
} else {
|
||||
dnsData.AAAA = append(dnsData.AAAA, ip.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
func() { // CNAME record
|
||||
cname, err := net.LookupCNAME(domain)
|
||||
if err == nil && cname != domain+"." && cname != "" {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
dnsData.CNAME = strings.TrimSuffix(cname, ".")
|
||||
}
|
||||
},
|
||||
func() { // MX records
|
||||
mxs, err := net.LookupMX(domain)
|
||||
if err == nil {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, mx := range mxs {
|
||||
dnsData.MX = append(dnsData.MX, fmt.Sprintf("%d %s", mx.Pref, strings.TrimSuffix(mx.Host, ".")))
|
||||
}
|
||||
}
|
||||
},
|
||||
func() { // TXT records
|
||||
txts, err := net.LookupTXT(domain)
|
||||
if err == nil {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
dnsData.TXT = append(dnsData.TXT, txts...)
|
||||
}
|
||||
},
|
||||
func() { // NS records
|
||||
nss, err := net.LookupNS(eTLD)
|
||||
if err == nil {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, ns := range nss {
|
||||
dnsData.NS = append(dnsData.NS, strings.TrimSuffix(ns.Host, "."))
|
||||
}
|
||||
}
|
||||
},
|
||||
recordTypes := map[string]uint16{
|
||||
"A": dns.TypeA,
|
||||
"AAAA": dns.TypeAAAA,
|
||||
"CNAME": dns.TypeCNAME,
|
||||
"MX": dns.TypeMX,
|
||||
"TXT": dns.TypeTXT,
|
||||
"NS": dns.TypeNS,
|
||||
"SOA": dns.TypeSOA,
|
||||
"CAA": dns.TypeCAA,
|
||||
}
|
||||
|
||||
wg.Add(len(lookupTasks))
|
||||
for _, task := range lookupTasks {
|
||||
go func(t func()) {
|
||||
for key, rType := range recordTypes {
|
||||
wg.Add(1)
|
||||
go func(name string, recordType uint16) {
|
||||
defer wg.Done()
|
||||
t()
|
||||
}(task)
|
||||
answers, err := queryDns(domain, recordType)
|
||||
if err != nil {
|
||||
slog.Debug("dns lookup failed for type", "type", name, "domain", domain, "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, ans := range answers {
|
||||
switch rr := ans.(type) {
|
||||
case *dns.A:
|
||||
dnsData.A = append(dnsData.A, rr.A.String())
|
||||
case *dns.AAAA:
|
||||
dnsData.AAAA = append(dnsData.AAAA, rr.AAAA.String())
|
||||
case *dns.CNAME:
|
||||
dnsData.CNAME = strings.TrimSuffix(rr.Target, ".")
|
||||
case *dns.MX:
|
||||
dnsData.MX = append(dnsData.MX, fmt.Sprintf("%d %s", rr.Preference, strings.TrimSuffix(rr.Mx, ".")))
|
||||
case *dns.TXT:
|
||||
dnsData.TXT = append(dnsData.TXT, strings.Join(rr.Txt, " "))
|
||||
case *dns.NS:
|
||||
dnsData.NS = append(dnsData.NS, strings.TrimSuffix(rr.Ns, "."))
|
||||
case *dns.SOA:
|
||||
soaStr := fmt.Sprintf("%s %s %d %d %d %d %d",
|
||||
strings.TrimSuffix(rr.Ns, "."), strings.TrimSuffix(rr.Mbox, "."),
|
||||
rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl)
|
||||
dnsData.SOA = append(dnsData.SOA, soaStr)
|
||||
case *dns.CAA:
|
||||
dnsData.CAA = append(dnsData.CAA, fmt.Sprintf(`%d %s "%s"`, rr.Flag, rr.Tag, rr.Value))
|
||||
}
|
||||
}
|
||||
}(key, rType)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
// Sort MX records for consistent output
|
||||
sort.Slice(dnsData.MX, func(i, j int) bool {
|
||||
var prefI, prefJ int
|
||||
_, _ = fmt.Sscanf(dnsData.MX[i], "%d", &prefI)
|
||||
_, _ = fmt.Sscanf(dnsData.MX[j], "%d", &prefJ)
|
||||
return prefI < prefJ
|
||||
})
|
||||
|
||||
response := &DomainDataResponse{
|
||||
Whois: whoisResult,
|
||||
DNS: dnsData,
|
||||
|
||||
@@ -44,6 +44,8 @@ type DNSData struct {
|
||||
MX []string `json:"MX,omitempty"`
|
||||
TXT []string `json:"TXT,omitempty"`
|
||||
NS []string `json:"NS,omitempty"`
|
||||
SOA []string `json:"SOA,omitempty"`
|
||||
CAA []string `json:"CAA,omitempty"`
|
||||
}
|
||||
|
||||
// WhoisInfo is a sanitized version of the parsed whois data for the API response.
|
||||
|
||||
Reference in New Issue
Block a user