mirror of
https://github.com/fosrl/newt.git
synced 2026-03-05 18:26:42 +00:00
Export wireguard logger
This commit is contained in:
@@ -35,8 +35,9 @@ type WgConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Target struct {
|
type Target struct {
|
||||||
CIDR string `json:"cidr"`
|
SourcePrefix string `json:"sourcePrefix"`
|
||||||
PortRange []PortRange `json:"portRange,omitempty"`
|
DestPrefix string `json:"destPrefix"`
|
||||||
|
PortRange []PortRange `json:"portRange,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PortRange struct {
|
type PortRange struct {
|
||||||
@@ -332,9 +333,9 @@ func (s *WireGuardService) handleConfig(msg websocket.WSMessage) {
|
|||||||
logger.Error("Failed to ensure WireGuard peers: %v", err)
|
logger.Error("Failed to ensure WireGuard peers: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if err := s.ensureTargets(config.Targets); err != nil {
|
if err := s.ensureTargets(config.Targets); err != nil {
|
||||||
// logger.Error("Failed to ensure WireGuard targets: %v", err)
|
logger.Error("Failed to ensure WireGuard targets: %v", err)
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
|
func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
|
||||||
@@ -460,15 +461,15 @@ func (s *WireGuardService) ensureTargets(targets []Target) error {
|
|||||||
return fmt.Errorf("netstack not initialized")
|
return fmt.Errorf("netstack not initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
// handler.AddSubnetRule(subnet2, []PortRange{
|
|
||||||
// {Min: 12000, Max: 12001},
|
|
||||||
// {Min: 8000, Max: 8000},
|
|
||||||
// })
|
|
||||||
|
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
prefix, err := netip.ParsePrefix(target.CIDR)
|
sourcePrefix, err := netip.ParsePrefix(target.SourcePrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid CIDR %s: %v", target.CIDR, err)
|
return fmt.Errorf("invalid CIDR %s: %v", target.SourcePrefix, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
destPrefix, err := netip.ParsePrefix(target.DestPrefix)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid CIDR %s: %v", target.DestPrefix, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var portRanges []netstack2.PortRange
|
var portRanges []netstack2.PortRange
|
||||||
@@ -479,9 +480,9 @@ func (s *WireGuardService) ensureTargets(targets []Target) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
s.tnet.AddProxySubnetRule(prefix, portRanges)
|
s.tnet.AddProxySubnetRule(sourcePrefix, destPrefix, portRanges)
|
||||||
|
|
||||||
logger.Info("Added target subnet %s with port ranges: %v", target.CIDR, target.PortRange)
|
logger.Info("Added target subnet %s with port ranges: %v", target.SourcePrefix, target.PortRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -830,7 +831,6 @@ func (s *WireGuardService) reportPeerBandwidth() error {
|
|||||||
// filterReadOnlyFields removes read-only fields from WireGuard IPC configuration
|
// filterReadOnlyFields removes read-only fields from WireGuard IPC configuration
|
||||||
func (s *WireGuardService) handleAddTarget(msg websocket.WSMessage) {
|
func (s *WireGuardService) handleAddTarget(msg websocket.WSMessage) {
|
||||||
logger.Debug("Received message: %v", msg.Data)
|
logger.Debug("Received message: %v", msg.Data)
|
||||||
var target Target
|
|
||||||
|
|
||||||
jsonData, err := json.Marshal(msg.Data)
|
jsonData, err := json.Marshal(msg.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -838,33 +838,86 @@ func (s *WireGuardService) handleAddTarget(msg websocket.WSMessage) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(jsonData, &target); err != nil {
|
|
||||||
logger.Info("Error unmarshaling target data: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.tnet == nil {
|
if s.tnet == nil {
|
||||||
logger.Info("Netstack not initialized")
|
logger.Info("Netstack not initialized")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix, err := netip.ParsePrefix(target.CIDR)
|
// Try to unmarshal as array first
|
||||||
if err != nil {
|
var targets []Target
|
||||||
logger.Info("Invalid CIDR %s: %v", target.CIDR, err)
|
if err := json.Unmarshal(jsonData, &targets); err != nil {
|
||||||
|
logger.Warn("Error unmarshaling target data: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var portRanges []netstack2.PortRange
|
// Process all targets
|
||||||
for _, pr := range target.PortRange {
|
for _, target := range targets {
|
||||||
portRanges = append(portRanges, netstack2.PortRange{
|
sourcePrefix, err := netip.ParsePrefix(target.SourcePrefix)
|
||||||
Min: pr.Min,
|
if err != nil {
|
||||||
Max: pr.Max,
|
logger.Info("Invalid CIDR %s: %v", target.SourcePrefix, err)
|
||||||
})
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
destPrefix, err := netip.ParsePrefix(target.DestPrefix)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Invalid CIDR %s: %v", target.DestPrefix, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var portRanges []netstack2.PortRange
|
||||||
|
for _, pr := range target.PortRange {
|
||||||
|
portRanges = append(portRanges, netstack2.PortRange{
|
||||||
|
Min: pr.Min,
|
||||||
|
Max: pr.Max,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
s.tnet.AddProxySubnetRule(sourcePrefix, destPrefix, portRanges)
|
||||||
|
|
||||||
|
logger.Info("Added target subnet %s with port ranges: %v", target.SourcePrefix, target.PortRange)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// filterReadOnlyFields removes read-only fields from WireGuard IPC configuration
|
||||||
|
func (s *WireGuardService) handleRemoveTarget(msg websocket.WSMessage) {
|
||||||
|
logger.Debug("Received message: %v", msg.Data)
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(msg.Data)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Error marshaling data: %v", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.tnet.AddProxySubnetRule(prefix, portRanges)
|
if s.tnet == nil {
|
||||||
|
logger.Info("Netstack not initialized")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
logger.Info("Added target subnet %s with port ranges: %v", target.CIDR, target.PortRange)
|
// Try to unmarshal as array first
|
||||||
|
var targets []Target
|
||||||
|
if err := json.Unmarshal(jsonData, &targets); err != nil {
|
||||||
|
logger.Warn("Error unmarshaling target data: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process all targets
|
||||||
|
for _, target := range targets {
|
||||||
|
sourcePrefix, err := netip.ParsePrefix(target.SourcePrefix)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Invalid CIDR %s: %v", target.SourcePrefix, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
destPrefix, err := netip.ParsePrefix(target.DestPrefix)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Invalid CIDR %s: %v", target.DestPrefix, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.tnet.RemoveProxySubnetRule(sourcePrefix, destPrefix)
|
||||||
|
|
||||||
|
logger.Info("Removed target subnet %s", target.SourcePrefix)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WireGuardService) handleUpdateTarget(msg websocket.WSMessage) {
|
func (s *WireGuardService) handleUpdateTarget(msg websocket.WSMessage) {
|
||||||
@@ -872,8 +925,8 @@ func (s *WireGuardService) handleUpdateTarget(msg websocket.WSMessage) {
|
|||||||
|
|
||||||
// you are going to get a oldTarget and a newTarget in the message
|
// you are going to get a oldTarget and a newTarget in the message
|
||||||
type UpdateTargetRequest struct {
|
type UpdateTargetRequest struct {
|
||||||
OldTarget Target `json:"oldTarget"`
|
OldTargets []Target `json:"oldTargets"`
|
||||||
NewTarget Target `json:"newTarget"`
|
NewTargets []Target `json:"newTargets"`
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonData, err := json.Marshal(msg.Data)
|
jsonData, err := json.Marshal(msg.Data)
|
||||||
@@ -882,78 +935,59 @@ func (s *WireGuardService) handleUpdateTarget(msg websocket.WSMessage) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var request UpdateTargetRequest
|
|
||||||
if err := json.Unmarshal(jsonData, &request); err != nil {
|
|
||||||
logger.Info("Error unmarshaling data: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.tnet == nil {
|
if s.tnet == nil {
|
||||||
logger.Info("Netstack not initialized")
|
logger.Info("Netstack not initialized")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix, err := netip.ParsePrefix(request.OldTarget.CIDR)
|
// Try to unmarshal as array first
|
||||||
if err != nil {
|
var requests UpdateTargetRequest
|
||||||
logger.Info("Invalid CIDR %s: %v", request.OldTarget.CIDR, err)
|
if err := json.Unmarshal(jsonData, &requests); err != nil {
|
||||||
|
logger.Warn("Error unmarshaling target data: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.tnet.RemoveProxySubnetRule(prefix)
|
// Process all update requests
|
||||||
|
for _, target := range requests.OldTargets {
|
||||||
|
sourcePrefix, err := netip.ParsePrefix(target.SourcePrefix)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Invalid CIDR %s: %v", target.SourcePrefix, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Now add the new target
|
destPrefix, err := netip.ParsePrefix(target.DestPrefix)
|
||||||
newPrefix, err := netip.ParsePrefix(request.NewTarget.CIDR)
|
if err != nil {
|
||||||
if err != nil {
|
logger.Info("Invalid CIDR %s: %v", target.DestPrefix, err)
|
||||||
logger.Info("Invalid CIDR %s: %v", request.NewTarget.CIDR, err)
|
continue
|
||||||
return
|
}
|
||||||
|
|
||||||
|
s.tnet.RemoveProxySubnetRule(sourcePrefix, destPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
var portRanges []netstack2.PortRange
|
for _, target := range requests.NewTargets {
|
||||||
for _, pr := range request.NewTarget.PortRange {
|
// Now add the new target
|
||||||
portRanges = append(portRanges, netstack2.PortRange{
|
sourcePrefix, err := netip.ParsePrefix(target.SourcePrefix)
|
||||||
Min: pr.Min,
|
if err != nil {
|
||||||
Max: pr.Max,
|
logger.Info("Invalid CIDR %s: %v", target.SourcePrefix, err)
|
||||||
})
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
destPrefix, err := netip.ParsePrefix(target.DestPrefix)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Invalid CIDR %s: %v", target.DestPrefix, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var portRanges []netstack2.PortRange
|
||||||
|
for _, pr := range target.PortRange {
|
||||||
|
portRanges = append(portRanges, netstack2.PortRange{
|
||||||
|
Min: pr.Min,
|
||||||
|
Max: pr.Max,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
s.tnet.AddProxySubnetRule(sourcePrefix, destPrefix, portRanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.tnet.AddProxySubnetRule(newPrefix, portRanges)
|
|
||||||
|
|
||||||
logger.Info("Updated target subnet from %s to %s", request.OldTarget.CIDR, request.NewTarget.CIDR)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *WireGuardService) handleRemoveTarget(msg websocket.WSMessage) {
|
|
||||||
logger.Debug("Received message: %v", msg.Data)
|
|
||||||
|
|
||||||
type RemoveTargetRequest struct {
|
|
||||||
CIDR string `json:"cidr"`
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonData, err := json.Marshal(msg.Data)
|
|
||||||
if err != nil {
|
|
||||||
logger.Info("Error marshaling data: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var request RemoveTargetRequest
|
|
||||||
if err := json.Unmarshal(jsonData, &request); err != nil {
|
|
||||||
logger.Info("Error unmarshaling data: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.tnet == nil {
|
|
||||||
logger.Info("Netstack not initialized")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix, err := netip.ParsePrefix(request.CIDR)
|
|
||||||
if err != nil {
|
|
||||||
logger.Info("Invalid CIDR %s: %v", request.CIDR, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
s.tnet.RemoveProxySubnetRule(prefix)
|
|
||||||
|
|
||||||
logger.Info("Removed target subnet %s", request.CIDR)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterReadOnlyFields removes read-only fields from WireGuard IPC configuration
|
// filterReadOnlyFields removes read-only fields from WireGuard IPC configuration
|
||||||
|
|||||||
@@ -173,10 +173,10 @@ func (m *Manager) runMultipleExitNodes(exitNodes []ExitNode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ticker := time.NewTicker(250 * time.Millisecond)
|
ticker := time.NewTicker(1 * time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
timeout := time.NewTimer(15 * time.Second)
|
timeout := time.NewTimer(5 * time.Second)
|
||||||
defer timeout.Stop()
|
defer timeout.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -226,10 +226,10 @@ func (m *Manager) runSingleEndpoint(endpoint, serverPubKey string) {
|
|||||||
logger.Warn("Failed to send initial hole punch: %v", err)
|
logger.Warn("Failed to send initial hole punch: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ticker := time.NewTicker(250 * time.Millisecond)
|
ticker := time.NewTicker(1 * time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
timeout := time.NewTimer(15 * time.Second)
|
timeout := time.NewTimer(5 * time.Second)
|
||||||
defer timeout.Stop()
|
defer timeout.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|||||||
@@ -127,3 +127,22 @@ func Fatal(format string, args ...interface{}) {
|
|||||||
func SetOutput(output *os.File) {
|
func SetOutput(output *os.File) {
|
||||||
GetLogger().SetOutput(output)
|
GetLogger().SetOutput(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WireGuardLogger is a wrapper type that matches WireGuard's Logger interface
|
||||||
|
type WireGuardLogger struct {
|
||||||
|
Verbosef func(format string, args ...any)
|
||||||
|
Errorf func(format string, args ...any)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWireGuardLogger returns a WireGuard-compatible logger that writes to the newt logger
|
||||||
|
// The prepend string is added as a prefix to all log messages
|
||||||
|
func (l *Logger) GetWireGuardLogger(prepend string) *WireGuardLogger {
|
||||||
|
return &WireGuardLogger{
|
||||||
|
Verbosef: func(format string, args ...any) {
|
||||||
|
l.Debug(prepend+format, args...)
|
||||||
|
},
|
||||||
|
Errorf: func(format string, args ...any) {
|
||||||
|
l.Error(prepend+format, args...)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -368,7 +368,7 @@ func main() {
|
|||||||
tlsClientCAs = append(tlsClientCAs, tlsClientCAsFlag...)
|
tlsClientCAs = append(tlsClientCAs, tlsClientCAsFlag...)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Init()
|
logger.Init(nil)
|
||||||
loggerLevel := util.ParseLogLevel(logLevel)
|
loggerLevel := util.ParseLogLevel(logLevel)
|
||||||
logger.GetLogger().SetLevel(loggerLevel)
|
logger.GetLogger().SetLevel(loggerLevel)
|
||||||
|
|
||||||
|
|||||||
@@ -23,68 +23,95 @@ type PortRange struct {
|
|||||||
Max uint16
|
Max uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubnetRule represents a subnet with optional port restrictions
|
// SubnetRule represents a subnet with optional port restrictions and source address
|
||||||
type SubnetRule struct {
|
type SubnetRule struct {
|
||||||
Prefix netip.Prefix
|
SourcePrefix netip.Prefix // Source IP prefix (who is sending)
|
||||||
PortRanges []PortRange // empty slice means all ports allowed
|
DestPrefix netip.Prefix // Destination IP prefix (where it's going)
|
||||||
|
PortRanges []PortRange // empty slice means all ports allowed
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubnetLookup provides fast IP subnet and port matching
|
// ruleKey is used as a map key for fast O(1) lookups
|
||||||
|
type ruleKey struct {
|
||||||
|
sourcePrefix string
|
||||||
|
destPrefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubnetLookup provides fast IP subnet and port matching with O(1) lookup performance
|
||||||
type SubnetLookup struct {
|
type SubnetLookup struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
rules []SubnetRule
|
rules map[ruleKey]*SubnetRule // Map for O(1) lookups by prefix combination
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSubnetLookup creates a new subnet lookup table
|
// NewSubnetLookup creates a new subnet lookup table
|
||||||
func NewSubnetLookup() *SubnetLookup {
|
func NewSubnetLookup() *SubnetLookup {
|
||||||
return &SubnetLookup{
|
return &SubnetLookup{
|
||||||
rules: make([]SubnetRule, 0),
|
rules: make(map[ruleKey]*SubnetRule),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSubnet adds a subnet to the lookup table with optional port restrictions
|
// AddSubnet adds a subnet rule with source and destination prefixes and optional port restrictions
|
||||||
// If portRanges is nil or empty, all ports are allowed for this subnet
|
// If portRanges is nil or empty, all ports are allowed for this subnet
|
||||||
func (sl *SubnetLookup) AddSubnet(prefix netip.Prefix, portRanges []PortRange) {
|
func (sl *SubnetLookup) AddSubnet(sourcePrefix, destPrefix netip.Prefix, portRanges []PortRange) {
|
||||||
sl.mu.Lock()
|
sl.mu.Lock()
|
||||||
defer sl.mu.Unlock()
|
defer sl.mu.Unlock()
|
||||||
|
|
||||||
sl.rules = append(sl.rules, SubnetRule{
|
key := ruleKey{
|
||||||
Prefix: prefix,
|
sourcePrefix: sourcePrefix.String(),
|
||||||
PortRanges: portRanges,
|
destPrefix: destPrefix.String(),
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveSubnet removes a subnet from the lookup table
|
sl.rules[key] = &SubnetRule{
|
||||||
func (sl *SubnetLookup) RemoveSubnet(prefix netip.Prefix) {
|
SourcePrefix: sourcePrefix,
|
||||||
sl.mu.Lock()
|
DestPrefix: destPrefix,
|
||||||
defer sl.mu.Unlock()
|
PortRanges: portRanges,
|
||||||
|
|
||||||
for i, rule := range sl.rules {
|
|
||||||
if rule.Prefix == prefix {
|
|
||||||
sl.rules = append(sl.rules[:i], sl.rules[i+1:]...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match checks if an IP and port match any subnet rule
|
// RemoveSubnet removes a subnet rule from the lookup table
|
||||||
// Returns true if the IP is in a matching subnet AND the port is in an allowed range
|
func (sl *SubnetLookup) RemoveSubnet(sourcePrefix, destPrefix netip.Prefix) {
|
||||||
func (sl *SubnetLookup) Match(ip netip.Addr, port uint16) bool {
|
sl.mu.Lock()
|
||||||
|
defer sl.mu.Unlock()
|
||||||
|
|
||||||
|
key := ruleKey{
|
||||||
|
sourcePrefix: sourcePrefix.String(),
|
||||||
|
destPrefix: destPrefix.String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(sl.rules, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match checks if a source IP, destination IP, and port match any subnet rule
|
||||||
|
// Returns true if BOTH:
|
||||||
|
// - The source IP is in the rule's source prefix
|
||||||
|
// - The destination IP is in the rule's destination prefix
|
||||||
|
// - The port is in an allowed range (or no port restrictions exist)
|
||||||
|
//
|
||||||
|
// This implementation uses O(n) iteration but checks exact prefix matches first for common cases
|
||||||
|
func (sl *SubnetLookup) Match(srcIP, dstIP netip.Addr, port uint16) bool {
|
||||||
sl.mu.RLock()
|
sl.mu.RLock()
|
||||||
defer sl.mu.RUnlock()
|
defer sl.mu.RUnlock()
|
||||||
|
|
||||||
|
// Iterate through all rules to find matching source and destination prefixes
|
||||||
|
// This is O(n) but necessary since we need to check prefix containment, not exact match
|
||||||
for _, rule := range sl.rules {
|
for _, rule := range sl.rules {
|
||||||
if rule.Prefix.Contains(ip) {
|
// Check if source and destination IPs match their respective prefixes
|
||||||
// If no port ranges specified, all ports are allowed
|
if !rule.SourcePrefix.Contains(srcIP) {
|
||||||
if len(rule.PortRanges) == 0 {
|
continue
|
||||||
return true
|
}
|
||||||
}
|
if !rule.DestPrefix.Contains(dstIP) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Check if port is in any of the allowed ranges
|
// Both IPs match - now check port restrictions
|
||||||
for _, pr := range rule.PortRanges {
|
// If no port ranges specified, all ports are allowed
|
||||||
if port >= pr.Min && port <= pr.Max {
|
if len(rule.PortRanges) == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if port is in any of the allowed ranges
|
||||||
|
for _, pr := range rule.PortRanges {
|
||||||
|
if port >= pr.Min && port <= pr.Max {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,37 +177,42 @@ func NewProxyHandler(options ProxyHandlerOptions) (*ProxyHandler, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Example 1: Add a subnet with no port restrictions (all ports allowed)
|
// // Example 1: Add a rule with no port restrictions (all ports allowed)
|
||||||
// // This accepts all traffic to 10.20.20.0/24
|
// // This accepts all traffic FROM 10.0.0.0/24 TO 10.20.20.0/24
|
||||||
// subnet1 := netip.MustParsePrefix("10.20.20.0/24")
|
// sourceSubnet := netip.MustParsePrefix("10.0.0.0/24")
|
||||||
// handler.AddSubnetRule(subnet1, nil)
|
// destSubnet := netip.MustParsePrefix("10.20.20.0/24")
|
||||||
|
// handler.AddSubnetRule(sourceSubnet, destSubnet, nil)
|
||||||
|
|
||||||
// // Example 2: Add a subnet with specific port ranges
|
// // Example 2: Add a rule with specific port ranges
|
||||||
// // This accepts traffic to 192.168.1.0/24 only on ports 80, 443, and 8000-9000
|
// // This accepts traffic FROM 10.0.0.5/32 TO 10.20.21.21/32 only on ports 80, 443, and 8000-9000
|
||||||
// subnet2 := netip.MustParsePrefix("10.20.21.21/32")
|
// sourceIP := netip.MustParsePrefix("10.0.0.5/32")
|
||||||
// handler.AddSubnetRule(subnet2, []PortRange{
|
// destIP := netip.MustParsePrefix("10.20.21.21/32")
|
||||||
// {Min: 12000, Max: 12001},
|
// handler.AddSubnetRule(sourceIP, destIP, []PortRange{
|
||||||
// {Min: 8000, Max: 8000},
|
// {Min: 80, Max: 80},
|
||||||
|
// {Min: 443, Max: 443},
|
||||||
|
// {Min: 8000, Max: 9000},
|
||||||
// })
|
// })
|
||||||
|
|
||||||
return handler, nil
|
return handler, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSubnetRule adds a subnet with optional port restrictions to the proxy handler
|
// AddSubnetRule adds a subnet with optional port restrictions to the proxy handler
|
||||||
|
// sourcePrefix: The IP prefix of the peer sending the data
|
||||||
|
// destPrefix: The IP prefix of the destination
|
||||||
// If portRanges is nil or empty, all ports are allowed for this subnet
|
// If portRanges is nil or empty, all ports are allowed for this subnet
|
||||||
func (p *ProxyHandler) AddSubnetRule(prefix netip.Prefix, portRanges []PortRange) {
|
func (p *ProxyHandler) AddSubnetRule(sourcePrefix, destPrefix netip.Prefix, portRanges []PortRange) {
|
||||||
if p == nil || !p.enabled {
|
if p == nil || !p.enabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.subnetLookup.AddSubnet(prefix, portRanges)
|
p.subnetLookup.AddSubnet(sourcePrefix, destPrefix, portRanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveSubnetRule removes a subnet from the proxy handler
|
// RemoveSubnetRule removes a subnet from the proxy handler
|
||||||
func (p *ProxyHandler) RemoveSubnetRule(prefix netip.Prefix) {
|
func (p *ProxyHandler) RemoveSubnetRule(sourcePrefix, destPrefix netip.Prefix) {
|
||||||
if p == nil || !p.enabled {
|
if p == nil || !p.enabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.subnetLookup.RemoveSubnet(prefix)
|
p.subnetLookup.RemoveSubnet(sourcePrefix, destPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize sets up the promiscuous NIC with the netTun's notification system
|
// Initialize sets up the promiscuous NIC with the netTun's notification system
|
||||||
@@ -239,11 +271,14 @@ func (p *ProxyHandler) HandleIncomingPacket(packet []byte) bool {
|
|||||||
|
|
||||||
// Parse IPv4 header
|
// Parse IPv4 header
|
||||||
ipv4Header := header.IPv4(packet)
|
ipv4Header := header.IPv4(packet)
|
||||||
|
srcIP := ipv4Header.SourceAddress()
|
||||||
dstIP := ipv4Header.DestinationAddress()
|
dstIP := ipv4Header.DestinationAddress()
|
||||||
|
|
||||||
// Convert gvisor tcpip.Address to netip.Addr
|
// Convert gvisor tcpip.Address to netip.Addr
|
||||||
|
srcBytes := srcIP.As4()
|
||||||
|
srcAddr := netip.AddrFrom4(srcBytes)
|
||||||
dstBytes := dstIP.As4()
|
dstBytes := dstIP.As4()
|
||||||
addr := netip.AddrFrom4(dstBytes)
|
dstAddr := netip.AddrFrom4(dstBytes)
|
||||||
|
|
||||||
// Parse transport layer to get destination port
|
// Parse transport layer to get destination port
|
||||||
var dstPort uint16
|
var dstPort uint16
|
||||||
@@ -269,8 +304,8 @@ func (p *ProxyHandler) HandleIncomingPacket(packet []byte) bool {
|
|||||||
dstPort = 0
|
dstPort = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the destination IP and port match any subnet rule
|
// Check if the source IP, destination IP, and port match any subnet rule
|
||||||
if p.subnetLookup.Match(addr, dstPort) {
|
if p.subnetLookup.Match(srcAddr, dstAddr, dstPort) {
|
||||||
// Inject into proxy stack
|
// Inject into proxy stack
|
||||||
pkb := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
pkb := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||||
Payload: buffer.MakeWithData(packet),
|
Payload: buffer.MakeWithData(packet),
|
||||||
|
|||||||
@@ -350,18 +350,18 @@ func (net *Net) ListenUDP(laddr *net.UDPAddr) (*gonet.UDPConn, error) {
|
|||||||
|
|
||||||
// AddProxySubnetRule adds a subnet rule to the proxy handler
|
// AddProxySubnetRule adds a subnet rule to the proxy handler
|
||||||
// If portRanges is nil or empty, all ports are allowed for this subnet
|
// If portRanges is nil or empty, all ports are allowed for this subnet
|
||||||
func (net *Net) AddProxySubnetRule(prefix netip.Prefix, portRanges []PortRange) {
|
func (net *Net) AddProxySubnetRule(sourcePrefix, destPrefix netip.Prefix, portRanges []PortRange) {
|
||||||
tun := (*netTun)(net)
|
tun := (*netTun)(net)
|
||||||
if tun.proxyHandler != nil {
|
if tun.proxyHandler != nil {
|
||||||
tun.proxyHandler.AddSubnetRule(prefix, portRanges)
|
tun.proxyHandler.AddSubnetRule(sourcePrefix, destPrefix, portRanges)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveProxySubnetRule removes a subnet rule from the proxy handler
|
// RemoveProxySubnetRule removes a subnet rule from the proxy handler
|
||||||
func (net *Net) RemoveProxySubnetRule(prefix netip.Prefix) {
|
func (net *Net) RemoveProxySubnetRule(sourcePrefix, destPrefix netip.Prefix) {
|
||||||
tun := (*netTun)(net)
|
tun := (*netTun)(net)
|
||||||
if tun.proxyHandler != nil {
|
if tun.proxyHandler != nil {
|
||||||
tun.proxyHandler.RemoveSubnetRule(prefix)
|
tun.proxyHandler.RemoveSubnetRule(sourcePrefix, destPrefix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user