github.com/sagernet/sing-box@v1.9.0-rc.20/route/rule_item_cidr.go (about)

     1  package route
     2  
     3  import (
     4  	"net/netip"
     5  	"strings"
     6  
     7  	"github.com/sagernet/sing-box/adapter"
     8  	E "github.com/sagernet/sing/common/exceptions"
     9  
    10  	"go4.org/netipx"
    11  )
    12  
    13  var _ RuleItem = (*IPCIDRItem)(nil)
    14  
    15  type IPCIDRItem struct {
    16  	ipSet       *netipx.IPSet
    17  	isSource    bool
    18  	description string
    19  }
    20  
    21  func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
    22  	var builder netipx.IPSetBuilder
    23  	for i, prefixString := range prefixStrings {
    24  		prefix, err := netip.ParsePrefix(prefixString)
    25  		if err == nil {
    26  			builder.AddPrefix(prefix)
    27  			continue
    28  		}
    29  		addr, addrErr := netip.ParseAddr(prefixString)
    30  		if addrErr == nil {
    31  			builder.Add(addr)
    32  			continue
    33  		}
    34  		return nil, E.Cause(err, "parse [", i, "]")
    35  	}
    36  	var description string
    37  	if isSource {
    38  		description = "source_ip_cidr="
    39  	} else {
    40  		description = "ip_cidr="
    41  	}
    42  	if dLen := len(prefixStrings); dLen == 1 {
    43  		description += prefixStrings[0]
    44  	} else if dLen > 3 {
    45  		description += "[" + strings.Join(prefixStrings[:3], " ") + "...]"
    46  	} else {
    47  		description += "[" + strings.Join(prefixStrings, " ") + "]"
    48  	}
    49  	ipSet, err := builder.IPSet()
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	return &IPCIDRItem{
    54  		ipSet:       ipSet,
    55  		isSource:    isSource,
    56  		description: description,
    57  	}, nil
    58  }
    59  
    60  func NewRawIPCIDRItem(isSource bool, ipSet *netipx.IPSet) *IPCIDRItem {
    61  	var description string
    62  	if isSource {
    63  		description = "source_ip_cidr="
    64  	} else {
    65  		description = "ip_cidr="
    66  	}
    67  	description += "<binary>"
    68  	return &IPCIDRItem{
    69  		ipSet:       ipSet,
    70  		isSource:    isSource,
    71  		description: description,
    72  	}
    73  }
    74  
    75  func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
    76  	if r.isSource || metadata.IPCIDRMatchSource {
    77  		return r.ipSet.Contains(metadata.Source.Addr)
    78  	} else {
    79  		if metadata.Destination.IsIP() {
    80  			return r.ipSet.Contains(metadata.Destination.Addr)
    81  		} else {
    82  			for _, address := range metadata.DestinationAddresses {
    83  				if r.ipSet.Contains(address) {
    84  					return true
    85  				}
    86  			}
    87  		}
    88  	}
    89  	return false
    90  }
    91  
    92  func (r *IPCIDRItem) String() string {
    93  	return r.description
    94  }