diff --git a/main.go b/main.go index 8345596..eb8af96 100644 --- a/main.go +++ b/main.go @@ -31,7 +31,7 @@ func main() { flag.StringVar(&in, "in", "", "Specify a file that contains multiple "+ "IPs, IP CIDRs or domains to scan, divided by line break") flag.IntVar(&port, "port", 443, "Specify a HTTPS port to check") - flag.IntVar(&thread, "thread", 1, "Count of concurrent tasks") + flag.IntVar(&thread, "thread", 2, "Count of concurrent tasks") flag.StringVar(&out, "out", "out.csv", "Output file to store the result") flag.IntVar(&timeout, "timeout", 10, "Timeout for every check") flag.BoolVar(&verbose, "v", false, "Verbose output") @@ -39,6 +39,10 @@ func main() { flag.StringVar(&url, "url", "", "Crawl the domain list from a URL, "+ "e.g. https://launchpad.net/ubuntu/+archivemirrors") flag.Parse() + s := Scanner{ + mu: new(sync.Mutex), + } + if verbose { slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ Level: slog.LevelDebug, @@ -66,7 +70,7 @@ func main() { } var hostChan <-chan Host if addr != "" { - hostChan = Iterate(strings.NewReader(addr)) + hostChan = Iterate(strings.NewReader(addr), true) } else if in != "" { f, err := os.Open(in) if err != nil { @@ -74,7 +78,7 @@ func main() { return } defer f.Close() - hostChan = Iterate(f) + hostChan = Iterate(f, false) } else { slog.Info("Fetching url...") resp, err := http.Get(url) @@ -95,7 +99,7 @@ func main() { } domains = RemoveDuplicateStr(domains) slog.Info("Parsed domains", "count", len(domains)) - hostChan = Iterate(strings.NewReader(strings.Join(domains, "\n"))) + hostChan = Iterate(strings.NewReader(strings.Join(domains, "\n")), len(domains) <= 1) } outCh := OutWriter(outWriter) defer close(outCh) @@ -104,7 +108,13 @@ func main() { for i := 0; i < thread; i++ { go func() { for ip := range hostChan { - ScanTLS(ip, outCh) + s.Scan(ip, outCh, true) + if ip.Infinity { // only one ip + for i := 0; i < thread - 1; i++ { + go s.Scan(ip, outCh, i%2 == 1) + } + for {} + } } wg.Done() }() diff --git a/scanner.go b/scanner.go index fdb4054..40cda96 100644 --- a/scanner.go +++ b/scanner.go @@ -3,13 +3,44 @@ package main import ( "crypto/tls" "log/slog" + "math/big" "net" "strconv" "strings" + "sync" "time" ) -func ScanTLS(host Host, out chan<- string) { +type Scanner struct { + mu *sync.Mutex + high net.IP + low net.IP +} + +func (s *Scanner) Scan(host Host, out chan<- string, increment bool) { + if host.Infinity && host.IP != nil { + s.mu.Lock() + if s.high == nil { + s.high = host.IP + s.low = host.IP + host.Origin = "" + host.Type = HostTypeIP + } else if increment { + s.high = nextIP(s.high, increment) + host.IP = s.high + } else { + s.low = nextIP(s.low, increment) + host.IP = s.low + } + s.mu.Unlock() + } + ScanTLS(host, out, increment) + if host.Infinity && host.IP != nil { + go s.Scan(host, out, increment) + } +} + +func ScanTLS(host Host, out chan<- string, increment bool) { if host.IP == nil { ips, err := net.LookupIP(host.Origin) if err != nil { @@ -71,3 +102,18 @@ func ScanTLS(host Host, out chan<- string) { "origin", host.Origin, "tls", tls.VersionName(state.Version), "alpn", alpn, "cert-domain", domain, "cert-issuer", issuers) } + +func nextIP(ip net.IP, increment bool) net.IP { + // Convert to big.Int and increment + ipb := big.NewInt(0).SetBytes([]byte(ip)) + if increment { + ipb.Add(ipb, big.NewInt(1)) + } else { + ipb.Sub(ipb, big.NewInt(1)) + } + + // Add leading zeros + b := ipb.Bytes() + b = append(make([]byte, len(ip)-len(b)), b...) + return net.IP(b) +} diff --git a/utils.go b/utils.go index 913d63b..8b80797 100644 --- a/utils.go +++ b/utils.go @@ -21,12 +21,13 @@ const ( type HostType int type Host struct { - IP net.IP - Origin string - Type HostType + IP net.IP + Origin string + Type HostType + Infinity bool } -func Iterate(reader io.Reader) <-chan Host { +func Iterate(reader io.Reader, infinity bool) <-chan Host { scanner := bufio.NewScanner(reader) hostChan := make(chan Host) go func() { @@ -40,9 +41,10 @@ func Iterate(reader io.Reader) <-chan Host { if ip != nil && (ip.To4() != nil || enableIPv6) { // ip address hostChan <- Host{ - IP: ip, - Origin: line, - Type: HostTypeIP, + IP: ip, + Origin: line, + Type: HostTypeIP, + Infinity: infinity, } continue } @@ -65,9 +67,10 @@ func Iterate(reader io.Reader) <-chan Host { ip = net.ParseIP(addr.String()) if ip != nil { hostChan <- Host{ - IP: ip, - Origin: line, - Type: HostTypeCIDR, + IP: ip, + Origin: line, + Type: HostTypeCIDR, + Infinity: false, } } addr = addr.Next() @@ -77,9 +80,10 @@ func Iterate(reader io.Reader) <-chan Host { if ValidateDomainName(line) { // domain hostChan <- Host{ - IP: nil, - Origin: line, - Type: HostTypeDomain, + IP: nil, + Origin: line, + Type: HostTypeDomain, + Infinity: infinity, } continue }