feat(go): port socket detectors

This commit is contained in:
Luna 2026-07-10 17:29:07 -07:00
parent fc9b5f0448
commit c6f7219de8
23 changed files with 693 additions and 28 deletions

View file

@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Package netutil contains stdlib address helpers matching the Python oracle.
package netutil
import (
"net/netip"
"strings"
)
var carrierGradeNAT = netip.MustParsePrefix("100.64.0.0/10")
// ParseAddr accepts brackets and IPv6 zone suffixes used by ss.
func ParseAddr(value string) (netip.Addr, bool) {
value = strings.Trim(strings.TrimSpace(value), "[]")
if index := strings.IndexByte(value, '%'); index >= 0 {
value = value[:index]
}
address, err := netip.ParseAddr(value)
return address, err == nil
}
// IsPublicIP reports globally routable addresses and excludes CGNAT.
func IsPublicIP(value string) bool {
address, ok := ParseAddr(value)
// netip's GlobalUnicast includes CGNAT, so explicitly exclude 100.64/10
// to match Python ipaddress.is_global and avoid treating carrier-local
// traffic as public C2 egress.
if !ok || !address.IsGlobalUnicast() || address.IsPrivate() ||
address.IsLoopback() || address.IsLinkLocalUnicast() {
return false
}
return !carrierGradeNAT.Contains(address)
}
// IPInCIDRs checks an address against valid same-family trust prefixes.
func IPInCIDRs(value string, cidrs []string) bool {
address, ok := ParseAddr(value)
if !ok {
return false
}
for _, raw := range cidrs {
// Invalid operator entries are ignored just like Python Config. A typo
// must not crash or disable the detector sweep.
prefix, err := netip.ParsePrefix(strings.TrimSpace(raw))
if err == nil && prefix.Addr().BitLen() == address.BitLen() && prefix.Contains(address) {
return true
}
}
return false
}
// SplitHostPort splits ss-style IPv4, IPv6, and zone-qualified endpoints.
func SplitHostPort(endpoint string) (string, string) {
endpoint = strings.TrimSpace(endpoint)
if strings.HasPrefix(endpoint, "[") {
if end := strings.Index(endpoint, "]"); end >= 0 {
return endpoint[1:end], strings.TrimPrefix(endpoint[end+1:], ":")
}
}
index := strings.LastIndex(endpoint, ":")
if index < 0 {
return "", endpoint
}
return endpoint[:index], endpoint[index+1:]
}