Add TCP port scan persistence and API endpoint.

Probe configured ports for alive hosts, persist port states, and expose scan port results via REST.

Made-with: Cursor
This commit is contained in:
Andrey Lutsenko
2026-04-09 21:54:17 +10:00
parent 9afbbbb762
commit e9452dcc0a
6 changed files with 159 additions and 1 deletions
+30 -1
View File
@@ -3,6 +3,7 @@ package scans
import (
"log"
"net"
"net/netip"
"os/exec"
"runtime"
"strconv"
@@ -70,11 +71,22 @@ func (r *Runner) run(job ScanJob) {
defer wg.Done()
for ip := range workCh {
isUp := probeHost(ip, job.Options.PingTimeoutMS)
checkedAt := time.Now().UTC()
_ = r.store.SaveHostResult(job.ID, HostResult{
IP: ip,
IsUp: isUp,
CheckedAt: time.Now().UTC(),
CheckedAt: checkedAt,
})
if isUp && job.Options.PortScanEnabled {
for _, p := range job.Options.Ports {
_ = r.store.SaveOpenPortResult(job.ID, OpenPortResult{
IP: ip,
Port: p,
IsOpen: probeTCPPort(ip, p, job.Options.PingTimeoutMS),
CheckedAt: checkedAt,
})
}
}
mu.Lock()
done++
@@ -166,6 +178,23 @@ func probeHost(ip string, timeoutMS int) bool {
return true
}
func probeTCPPort(ip string, port int, timeoutMS int) bool {
if timeoutMS <= 0 {
timeoutMS = 700
}
addr, err := netip.ParseAddr(ip)
if err != nil {
return false
}
target := net.JoinHostPort(addr.String(), strconv.Itoa(port))
conn, err := net.DialTimeout("tcp", target, time.Duration(timeoutMS)*time.Millisecond)
if err != nil {
return false
}
_ = conn.Close()
return true
}
func dupIP(ip net.IP) net.IP {
out := make(net.IP, len(ip))
copy(out, ip)