-
Notifications
You must be signed in to change notification settings - Fork 0
add a utility for finding all the TCP ports in listen (with the ability to exclude ports) #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…ty to exclude ports)
WalkthroughAdds a cross-platform exported function DetectListeningTCPPorts(exclude ...int) to the network package with Darwin and Linux implementations and a test suite; each implementation enumerates listening TCP ports, applies exclusions, and returns a sorted, unique slice of ports. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Caller
participant N as network.DetectListeningTCPPorts
rect rgb(240,248,255)
Note right of N: Platform dispatch (build tags)
end
C->>N: DetectListeningTCPPorts(exclude...)
alt Darwin build
N->>OS: run `lsof -nP -iTCP -sTCP:LISTEN`
OS-->>N: command stdout (lines)
N->>N: regex parse ports, filter exclude, dedupe, sort
else Linux build
N->>FS: open `/proc/net/tcp` and `/proc/net/tcp6`
FS-->>N: file contents
N->>N: parse entries, filter state==0A, extract hex port, filter exclude, dedupe, sort
end
N-->>C: ([]int, error)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used🧬 Code graph analysis (2)network/port_linux.go (1)
network/port_test.go (2)
🔇 Additional comments (3)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (1)
network/port_linux.go (1)
32-65: Consider checking scanner errors for consistency.The Darwin implementation checks
scanner.Err()after the scanning loop, but the Linux version does not. While scanning errors from/proc/net/tcp*are unlikely, checking for consistency and defensive coding would be prudent.After the loop closes the file (and before moving to the next file), add:
f.Close() if err := scanner.Err(); err != nil { // Log or handle scanner error if needed // For now, continue to next file continue } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
network/port_darwin.go(1 hunks)network/port_linux.go(1 hunks)network/port_test.go(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
network/port_darwin.go (1)
network/port_linux.go (1)
DetectListeningTCPPorts(16-69)
network/port_linux.go (1)
network/port_darwin.go (1)
DetectListeningTCPPorts(18-61)
network/port_test.go (2)
network/port_darwin.go (1)
DetectListeningTCPPorts(18-61)network/port_linux.go (1)
DetectListeningTCPPorts(16-69)
🔇 Additional comments (2)
network/port_darwin.go (1)
18-61: LGTM: Solid implementation with proper deduplication.The Darwin implementation correctly:
- Uses a map to deduplicate ports (multiple processes can listen on the same port)
- Checks
scanner.Err()for scanning errors- Sorts results consistently
- Handles exclusions properly
network/port_test.go (1)
11-129: LGTM: Comprehensive test coverage.The test suite provides excellent coverage:
- Basic functionality and sorting
- Single and multiple exclusions
- Non-existent exclusions (edge case)
- Actual listener detection (integration-style)
- Duplicate prevention (lines 110-119 will catch the Linux implementation bug)
- Valid port range validation
The tests appropriately use
t.Skip()when insufficient ports are available, making them resilient to different system states.
| for _, path := range files { | ||
| f, err := os.Open(path) | ||
| if err != nil { | ||
| continue // skip if file doesn't exist or can't be read | ||
| } | ||
| defer f.Close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix resource leak: defer in loop.
The defer f.Close() executes at function exit, not at the end of each loop iteration. If both /proc/net/tcp and /proc/net/tcp6 exist, the first file remains open until the function returns.
Apply this diff to close immediately after reading:
for _, path := range files {
f, err := os.Open(path)
if err != nil {
continue // skip if file doesn't exist or can't be read
}
- defer f.Close()
scanner := bufio.NewScanner(f)
// Skip the header line
if scanner.Scan() {
for scanner.Scan() {
fields := strings.Fields(scanner.Text())
if len(fields) < 4 {
continue
}
localAddr := fields[1]
state := fields[3]
if state != "0A" { // 0A means LISTEN
continue
}
// localAddr example: 0100007F:1F90
parts := strings.Split(localAddr, ":")
if len(parts) != 2 {
continue
}
portHex := parts[1]
portDec, err := strconv.ParseInt(portHex, 16, 32)
if err != nil {
continue
}
port := int(portDec)
if _, excluded := excludeSet[port]; !excluded {
ports = append(ports, port)
}
}
}
+ f.Close()
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for _, path := range files { | |
| f, err := os.Open(path) | |
| if err != nil { | |
| continue // skip if file doesn't exist or can't be read | |
| } | |
| defer f.Close() | |
| for _, path := range files { | |
| f, err := os.Open(path) | |
| if err != nil { | |
| continue // skip if file doesn't exist or can't be read | |
| } | |
| scanner := bufio.NewScanner(f) | |
| // Skip the header line | |
| if scanner.Scan() { | |
| for scanner.Scan() { | |
| fields := strings.Fields(scanner.Text()) | |
| if len(fields) < 4 { | |
| continue | |
| } | |
| localAddr := fields[1] | |
| state := fields[3] | |
| if state != "0A" { // 0A means LISTEN | |
| continue | |
| } | |
| // localAddr example: 0100007F:1F90 | |
| parts := strings.Split(localAddr, ":") | |
| if len(parts) != 2 { | |
| continue | |
| } | |
| portHex := parts[1] | |
| portDec, err := strconv.ParseInt(portHex, 16, 32) | |
| if err != nil { | |
| continue | |
| } | |
| port := int(portDec) | |
| if _, excluded := excludeSet[port]; !excluded { | |
| ports = append(ports, port) | |
| } | |
| } | |
| } | |
| f.Close() | |
| } |
🤖 Prompt for AI Agents
In network/port_linux.go around lines 25 to 30, the code uses "defer f.Close()"
inside the loop which defers closing until function exit and leaks file
descriptors when iterating multiple files; replace the defer with an explicit
close after the file is read (or wrap the read logic in a short-lived inner
function and defer f.Close() there) so each opened file is closed immediately at
the end of its iteration.
Summary by CodeRabbit
New Features
Tests