feat(go): port socket detectors
This commit is contained in:
parent
fc9b5f0448
commit
c6f7219de8
23 changed files with 693 additions and 28 deletions
66
go-agent/internal/netutil/netutil.go
Normal file
66
go-agent/internal/netutil/netutil.go
Normal 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:]
|
||||
}
|
||||
36
go-agent/internal/netutil/netutil_test.go
Normal file
36
go-agent/internal/netutil/netutil_test.go
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package netutil
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPublicIPMatchesPythonCases(t *testing.T) {
|
||||
for _, address := range []string{"8.8.8.8", "1.1.1.1"} {
|
||||
if !IsPublicIP(address) {
|
||||
t.Fatalf("expected public: %s", address)
|
||||
}
|
||||
}
|
||||
for _, address := range []string{
|
||||
"10.0.0.5", "192.168.1.1", "172.16.0.1", "127.0.0.1",
|
||||
"169.254.1.1", "100.64.0.1", "::1", "not-an-ip", "",
|
||||
} {
|
||||
if IsPublicIP(address) {
|
||||
t.Fatalf("expected non-public: %s", address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCIDRAndEndpointHelpers(t *testing.T) {
|
||||
if !IPInCIDRs("203.0.113.55", []string{"203.0.113.0/24"}) ||
|
||||
IPInCIDRs("8.8.8.8", []string{"203.0.113.0/24"}) {
|
||||
t.Fatal("CIDR matching failed")
|
||||
}
|
||||
host, port := SplitHostPort("[2001:db8::1]:22")
|
||||
if host != "2001:db8::1" || port != "22" {
|
||||
t.Fatalf("unexpected IPv6 split: %q %q", host, port)
|
||||
}
|
||||
host, port = SplitHostPort("10.2.0.2%proton0:61877")
|
||||
if host != "10.2.0.2%proton0" || port != "61877" {
|
||||
t.Fatalf("unexpected zone split: %q %q", host, port)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue