fix(scan): handles nil (*ListenHandler).IPConn#1466
Conversation
Signed-off-by: Dwi Siswanto <git@dw1.io>
WalkthroughThe changes introduce a new concurrent SYN scan test in the runner's test suite and refactor the network packet sending logic in the Unix scanner implementation. The test function, Changes
Assessment against linked issues
Poem
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (6)
pkg/scan/scan_unix.go (3)
253-257: Consider deduplicating repetitive connection-nil checksIntroducing the early‐exit
nilchecks forTcpConn4,UdpConn4,TcpConn6, andUdpConn6is a solid safety guard against dereferencing a nil*IPConn.
However, the pattern is now duplicated four times. Extracting a tiny helper such asfunc checkConn(conn net.PacketConn, proto, ip string, port int) bool { if conn == nil { gologger.Debug().Msgf("%s connection is nil, cannot send packet to %s:%d\n", proto, ip, port) return false } return true }and using it like
if !checkConn(listenHandler.TcpConn4, "TcpConn4", ip, p.Port) { return }would reduce boilerplate, make future maintenance easier, and keep the senders symmetric.
Also applies to: 298-302, 359-363, 404-408
480-503: Add an explicitnilguard for the suppliedconnand streamline error return
sendWithConnnow retries in a loop—good move! Two small nits:
- If a caller accidentally passes
nilyou’ll get a panic onWriteTo. A cheap guard prevents that.- After the retry loop exits
erris guaranteed to be non-nil; the subsequentif err != nilis therefore redundant.func sendWithConn(destIP string, conn net.PacketConn, l ...gopacket.SerializableLayer) error { - var err error + if conn == nil { + return fmt.Errorf("cannot send packet to %s: nil PacketConn", destIP) + } + var err error … - for retries := 0; retries < maxRetries; retries++ { + for retries := 0; retries < maxRetries; retries++ { _, err = conn.WriteTo(data, addr) if err == nil { return nil } time.Sleep(time.Duration(sendDelayMsec) * time.Millisecond) } - if err != nil { - return fmt.Errorf("could not send packet to %s: %s", destIP, err) - } - return nil + return fmt.Errorf("could not send packet to %s after %d retries: %w", + destIP, maxRetries, err) }This both avoids a potential panic path and simplifies the tail logic.
506-534:sendWithHandlershares retry logic withsendWithConn– factor out common codeThe retry block here is identical to the one in
sendWithConn. Extracting a small reusable helper such asfunc retrySend(max int, delay time.Duration, send func() error) error { for i := 0; i < max; i++ { if err := send(); err == nil { return nil } time.Sleep(delay) } return fmt.Errorf("exceeded %d retries", max) }would DRY up both functions and ensure future tweaks (back-off strategy, metrics, etc.) are applied consistently.
pkg/runner/runner_test.go (3)
880-884: Root-required test will be skipped in most CI environmentsThe
os.Geteuid() != 0guard is practical for local runs, but it means the new concurrency stress-test won’t execute in typical CI pipelines (which run unprivileged).
Consider one of:
- Adding a build tag (e.g.,
//go:build privileged) so regulargo test ./...doesn’t report a large chunk of skipped tests, or- Falling back to a mocked scanner when not root, so the concurrency logic is still exercised.
This will preserve coverage without needing root everywhere.
889-897: Channel capacity might dead-lock if more than one error per goroutine is sent
errChanis buffered withnumGoroutines, under the assumption that each goroutine emits at most one error. While currently true, a future change (e.g., logging both runner creation and enumeration errors) would block the goroutine and stall the test.Two defensive tweaks:
-errChan := make(chan error, numGoroutines) +errChan := make(chan error, numGoroutines*2) // allow >1 error per goroutineor send with a non-blocking select:
select { case errChan <- err: default: t.Log("error dropped:", err) }Either avoids accidental deadlocks down the road.
927-931: Minor: context timeout may be tight on slower systemsThe test times out after 20 s irrespective of CPU count or network conditions. In resource-constrained CI this could yield spurious failures.
Consider making the timeout proportional tonumGoroutines(or an env override) to keep the test robust:-timeout := 20 * time.Second +timeout := time.Duration(numGoroutines*15) * time.Second // ≈15 s per worker
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
pkg/runner/runner_test.go(2 hunks)pkg/scan/scan_unix.go(5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (7)
- GitHub Check: build-windows
- GitHub Check: release-test-mac
- GitHub Check: build-linux
- GitHub Check: Functional Test (ubuntu-latest)
- GitHub Check: build-mac
- GitHub Check: release-test-linux
- GitHub Check: Analyze (go)
Closes #1422
Test:
Summary by CodeRabbit
Tests
Bug Fixes
Refactor