github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/route/rule_item_cidr.go (about)

     1  package route
     2  
     3  import (
     4  	"net/netip"
     5  	"strings"
     6  
     7  	"github.com/inazumav/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 ip_cidr [", i, "]")
    35  	}
    36  	var description string
    37  	if isSource {
    38  		description = "source_ipcidr="
    39  	} else {
    40  		description = "ipcidr="
    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 (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
    61  	if r.isSource {
    62  		return r.ipSet.Contains(metadata.Source.Addr)
    63  	} else {
    64  		if metadata.Destination.IsIP() {
    65  			return r.ipSet.Contains(metadata.Destination.Addr)
    66  		} else {
    67  			for _, address := range metadata.DestinationAddresses {
    68  				if r.ipSet.Contains(address) {
    69  					return true
    70  				}
    71  			}
    72  		}
    73  	}
    74  	return false
    75  }
    76  
    77  func (r *IPCIDRItem) String() string {
    78  	return r.description
    79  }