fix(scan): honour the caller context when downloading the ports list (#324)

* fix(scan): honour the caller context when downloading the ports list

the common-scope ports fetch built its request with context.TODO(),
so a cancelled run or -max-time deadline could not abort a hung list
download even though the dialer already used the passed context.

* test(scan): drop redundant comment restating release channel receive
This commit is contained in:
Tigah
2026-07-22 12:52:21 -07:00
committed by GitHub
parent b72e076fc7
commit 41f35acd66
2 changed files with 63 additions and 1 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ func Ports(ctx context.Context, scope string, url string, timeout time.Duration,
var ports []int
switch scope {
case "common":
req, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, commonPorts, http.NoBody)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, commonPorts, http.NoBody)
if err != nil {
log.Error("Error creating request: %s", err)
return nil, err
+62
View File
@@ -0,0 +1,62 @@
/*
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
: :
: █▀ █ █▀▀ · Blazing-fast pentesting suite :
: ▄█ █ █▀ · BSD 3-Clause License :
: :
: (c) 2022-2026 vmfunc, xyzeva, :
: lunchcat alumni & contributors :
: :
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
*/
package scan
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"time"
)
// TestPorts_CancelledContextAbortsListDownload proves the ports-list fetch
// honours the caller context. With a slow list endpoint and an already
// cancelled context, Ports must return promptly instead of blocking on the
// http client timeout.
func TestPorts_CancelledContextAbortsListDownload(t *testing.T) {
release := make(chan struct{})
list := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
<-release
w.WriteHeader(http.StatusOK)
}))
// cleanups run LIFO: release the handler first so any in-flight request can
// drain before Close waits on it, otherwise a request the ctx failed to
// cancel would deadlock teardown.
t.Cleanup(list.Close)
t.Cleanup(func() { close(release) })
orig := commonPorts
commonPorts = list.URL
defer func() { commonPorts = orig }()
ctx, cancel := context.WithCancel(context.Background())
cancel() // cancel before the call so only ctx-awareness can unblock it
done := make(chan error, 1)
go func() {
// a generous client timeout so anything but ctx cancellation would hang
_, err := Ports(ctx, "common", "tcp://127.0.0.1", 30*time.Second, 1, "")
done <- err
}()
select {
case err := <-done:
if err == nil {
t.Fatal("expected error from cancelled context, got nil")
}
case <-time.After(3 * time.Second):
t.Fatal("Ports ignored the cancelled context and blocked on the list download")
}
}