Skip to content

Commit 3497738

Browse files
authored
Merge pull request projectdiscovery#6760 from JawsKim/fix/issue-5579-large-exclusion-hang
fix(input): optimize removeTargets to prevent hang on large exclusions
2 parents d221732 + 95258ec commit 3497738

File tree

2 files changed

+111
-24
lines changed

2 files changed

+111
-24
lines changed

pkg/input/provider/list/hmap.go

Lines changed: 110 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"fmt"
99
"io"
10+
"net"
1011
"os"
1112
"regexp"
1213
"strings"
@@ -337,11 +338,14 @@ func (i *ListInputProvider) initializeInputSources(opts *Options) error {
337338
for _, target := range options.ExcludeTargets {
338339
switch {
339340
case iputil.IsCIDR(target):
340-
ips := expand.CIDR(target)
341-
i.removeTargets(ips)
341+
i.removeTargets([]string{target})
342342
case asn.IsASN(target):
343-
ips := expand.ASN(target)
344-
i.removeTargets(ips)
343+
cidrs, _ := asn.GetCIDRsForASNNum(target)
344+
cidrStrs := make([]string, 0, len(cidrs))
345+
for _, cidr := range cidrs {
346+
cidrStrs = append(cidrStrs, cidr.String())
347+
}
348+
i.removeTargets(cidrStrs)
345349
default:
346350
i.Del(options.ExecutionId, target)
347351
}
@@ -500,37 +504,57 @@ func (i *ListInputProvider) setItem(metaInput *contextargs.MetaInput) {
500504
}
501505
}
502506

503-
// setItem in the kv store
504-
func (i *ListInputProvider) delItem(metaInput *contextargs.MetaInput) {
505-
targetUrl, err := urlutil.ParseURL(metaInput.Input, true)
506-
if err != nil {
507-
gologger.Warning().Msgf("%s\n", err)
507+
const removeTargetsChunkSize = 5000
508+
509+
// delItem removes all hostMap entries matching any of the given targets in a single scan.
510+
func (i *ListInputProvider) delItem(targets ...*contextargs.MetaInput) {
511+
type parsedTarget struct {
512+
host string
513+
regex *regexp.Regexp
514+
}
515+
516+
var parsed []parsedTarget
517+
for _, mi := range targets {
518+
targetUrl, err := urlutil.ParseURL(mi.Input, true)
519+
if err != nil {
520+
continue
521+
}
522+
re, _ := regexp.Compile(mi.Input)
523+
parsed = append(parsed, parsedTarget{host: targetUrl.Host, regex: re})
524+
}
525+
if len(parsed) == 0 {
508526
return
509527
}
510528

529+
var keysToDelete []string
511530
i.hostMap.Scan(func(k, _ []byte) error {
512531
var tmpMetaInput contextargs.MetaInput
513532
if err := tmpMetaInput.Unmarshal(string(k)); err != nil {
514-
return err
533+
return nil
515534
}
516535
tmpKey, err := tmpMetaInput.MarshalString()
517536
if err != nil {
518-
return err
537+
return nil
519538
}
520539
tmpUrl, err := urlutil.ParseURL(tmpMetaInput.Input, true)
521540
if err != nil {
522-
return err
541+
return nil
523542
}
524-
525-
matched, _ := regexp.MatchString(metaInput.Input, tmpUrl.Host)
526-
if tmpUrl.Host == targetUrl.Host || matched {
527-
_ = i.hostMap.Del(tmpKey)
528-
i.excludedHosts[tmpKey] = struct{}{}
529-
i.excludedCount++
530-
i.inputCount--
543+
for _, pt := range parsed {
544+
if tmpUrl.Host == pt.host || (pt.regex != nil && pt.regex.MatchString(tmpUrl.Host)) {
545+
keysToDelete = append(keysToDelete, tmpKey)
546+
break
547+
}
531548
}
532549
return nil
533550
})
551+
552+
for _, key := range keysToDelete {
553+
_ = i.hostMap.Del(key)
554+
i.excludedHosts[key] = struct{}{}
555+
i.excludedCount++
556+
i.inputCount--
557+
}
534558
}
535559

536560
// setHostMapStream sets item in stream mode
@@ -548,9 +572,72 @@ func (i *ListInputProvider) addTargets(executionId string, targets []string) {
548572
}
549573

550574
func (i *ListInputProvider) removeTargets(targets []string) {
551-
for _, target := range targets {
552-
metaInput := contextargs.NewMetaInput()
553-
metaInput.Input = target
554-
i.delItem(metaInput)
575+
var cidrs []*net.IPNet
576+
var otherTargets []string
577+
578+
for _, t := range targets {
579+
if _, ipnet, err := net.ParseCIDR(t); err == nil {
580+
cidrs = append(cidrs, ipnet)
581+
} else {
582+
otherTargets = append(otherTargets, t)
583+
}
584+
}
585+
586+
// CIDR targets: single scan with containment check
587+
if len(cidrs) > 0 {
588+
var keysToDelete []string
589+
i.hostMap.Scan(func(k, _ []byte) error {
590+
var mi contextargs.MetaInput
591+
if err := mi.Unmarshal(string(k)); err != nil {
592+
return nil
593+
}
594+
key, err := mi.MarshalString()
595+
if err != nil {
596+
return nil
597+
}
598+
parsed, err := urlutil.ParseURL(mi.Input, true)
599+
if err != nil {
600+
return nil
601+
}
602+
if matchesCIDR(parsed.Hostname(), cidrs) || (mi.CustomIP != "" && matchesCIDR(mi.CustomIP, cidrs)) {
603+
keysToDelete = append(keysToDelete, key)
604+
}
605+
return nil
606+
})
607+
for _, key := range keysToDelete {
608+
_ = i.hostMap.Del(key)
609+
i.excludedHosts[key] = struct{}{}
610+
i.excludedCount++
611+
i.inputCount--
612+
}
613+
}
614+
615+
// other targets: chunked delItem with existing hostname+regex matching
616+
for start := 0; start < len(otherTargets); start += removeTargetsChunkSize {
617+
end := start + removeTargetsChunkSize
618+
if end > len(otherTargets) {
619+
end = len(otherTargets)
620+
}
621+
chunk := otherTargets[start:end]
622+
metaInputs := make([]*contextargs.MetaInput, 0, len(chunk))
623+
for _, target := range chunk {
624+
mi := contextargs.NewMetaInput()
625+
mi.Input = target
626+
metaInputs = append(metaInputs, mi)
627+
}
628+
i.delItem(metaInputs...)
629+
}
630+
}
631+
632+
func matchesCIDR(host string, cidrs []*net.IPNet) bool {
633+
ip := net.ParseIP(host)
634+
if ip == nil {
635+
return false
636+
}
637+
for _, ipnet := range cidrs {
638+
if ipnet.Contains(ip) {
639+
return true
640+
}
555641
}
642+
return false
556643
}

pkg/js/devtools/bindgen/generator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func CreateTemplateData(directory string, packagePrefix string) (*TemplateData,
105105
fmt.Println(directory)
106106
fset := token.NewFileSet()
107107

108-
pkgs, err := parser.ParseDir(fset, directory, nil, parser.ParseComments)
108+
pkgs, err := parser.ParseDir(fset, directory, nil, parser.ParseComments) //nolint
109109
if err != nil {
110110
return nil, errors.Wrap(err, "could not parse directory")
111111
}

0 commit comments

Comments
 (0)