package resolve import ( "context" "net" "runtime" "sort" "strings" "sync" "time" ) type ReverseResult struct { IP string `json:"ip"` Hostname string `json:"hostname,omitempty"` } func ReverseLookupAll(ctx context.Context, ips []string, timeout time.Duration, jobs int) []ReverseResult { if jobs <= 0 { jobs = runtime.GOMAXPROCS(0) } in := make(chan string) out := make(chan ReverseResult) var wg sync.WaitGroup worker := func() { defer wg.Done() for ip := range in { r := ReverseResult{IP: ip} cctx, cancel := context.WithTimeout(ctx, timeout) names, err := net.DefaultResolver.LookupAddr(cctx, ip) cancel() if err == nil && len(names) > 0 { // trim trailing dot for readability r.Hostname = strings.TrimSuffix(names[0], ".") } select { case out <- r: case <-ctx.Done(): return } } } wg.Add(jobs) for i := 0; i < jobs; i++ { go worker() } go func() { defer close(in) for _, ip := range ips { select { case in <- ip: case <-ctx.Done(): return } } }() go func() { wg.Wait() close(out) }() var res []ReverseResult for r := range out { res = append(res, r) } sort.Slice(res, func(i, j int) bool { return res[i].IP < res[j].IP }) return res }