Resolver cli changes

- Max of 10 simultaneous goroutines to avoid being throttled by DNS
- All template formatting moved to formatLine function
- resolveRepeat is synchronous to avoid being throttled by DNS
This commit is contained in:
Quentin McGaw
2020-06-02 23:10:04 +00:00
parent 20a3327815
commit f262ee6454

View File

@@ -25,20 +25,17 @@ func _main(ctx context.Context) int {
resolver := newResolver(*resolverAddress)
lookupIP := newLookupIP(resolver)
var domain, template string
var domain string
var servers []server
switch *provider {
case "pia":
domain = "privateinternetaccess.com"
template = "{Region: models.PIARegion(%q), IPs: []net.IP{%s}},"
servers = piaServers()
case "windscribe":
domain = "windscribe.com"
template = "{Region: models.WindscribeRegion(%q), IPs: []net.IP{%s}},"
servers = windscribeServers()
case "surfshark":
domain = "prod.surfshark.com"
template = "{Region: models.SurfsharkRegion(%q), IPs: []net.IP{%s}},"
servers = surfsharkServers()
default:
fmt.Printf("Provider %q is not supported\n", *provider)
@@ -60,17 +57,19 @@ func _main(ctx context.Context) int {
stringChannel := make(chan string)
errorChannel := make(chan error)
const maxGoroutines = 10
guard := make(chan struct{}, maxGoroutines)
for _, s := range servers {
s := s
go func() {
go func(s server) {
guard <- struct{}{}
ips, err := resolveRepeat(ctx, lookupIP, s.subdomain+"."+domain, 3)
<-guard
if err != nil {
errorChannel <- err
return
}
ipsString := formatIPs(ips)
stringChannel <- fmt.Sprintf(template, s.region, ipsString)
}()
stringChannel <- formatLine(*provider, s, ips)
}(s)
}
var lines []string
var errors []error
@@ -98,6 +97,32 @@ func _main(ctx context.Context) int {
return 0
}
func formatLine(provider string, s server, ips []net.IP) string {
ipStrings := make([]string, len(ips))
for i := range ips {
ipStrings[i] = fmt.Sprintf("{%s}", strings.ReplaceAll(ips[i].String(), ".", ", "))
}
ipString := strings.Join(ipStrings, ", ")
switch provider {
case "pia":
return fmt.Sprintf(
"{Region: models.PIARegion(%q), IPs: []net.IP{%s}},",
s.region, ipString,
)
case "windscribe":
return fmt.Sprintf(
"{Region: models.WindscribeRegion(%q), IPs: []net.IP{%s}},",
s.region, ipString,
)
case "surfshark":
return fmt.Sprintf(
"{Region: models.SurfsharkRegion(%q), IPs: []net.IP{%s}},",
s.region, ipString,
)
}
return ""
}
type lookupIPFunc func(ctx context.Context, host string) (ips []net.IP, err error)
func newLookupIP(r *net.Resolver) lookupIPFunc {
@@ -125,29 +150,12 @@ func newResolver(ip string) *net.Resolver {
}
func resolveRepeat(ctx context.Context, lookupIP lookupIPFunc, host string, n int) (ips []net.IP, err error) {
ipsChannel := make(chan []net.IP)
errorsChannel := make(chan error)
for i := 0; i < n; i++ {
go func() {
ips, err := lookupIP(ctx, host)
if err != nil {
errorsChannel <- err
} else {
ipsChannel <- ips
}
}()
}
for i := 0; i < n; i++ {
select {
case err = <-errorsChannel:
case newIPs := <-ipsChannel:
ips = append(ips, newIPs...)
newIPs, err := lookupIP(ctx, host)
if err != nil {
return nil, err
}
}
close(errorsChannel)
close(ipsChannel)
if err != nil {
return nil, err
ips = append(ips, newIPs...)
}
return uniqueSortedIPs(ips), nil
}
@@ -169,14 +177,6 @@ func uniqueSortedIPs(ips []net.IP) []net.IP {
return ips
}
func formatIPs(ips []net.IP) (s string) {
ipStrings := make([]string, len(ips))
for i := range ips {
ipStrings[i] = fmt.Sprintf("{%s}", strings.ReplaceAll(ips[i].String(), ".", ", "))
}
return strings.Join(ipStrings, ", ")
}
type server struct {
subdomain string
region string