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

     1  package route
     2  
     3  import (
     4  	"strconv"
     5  	"strings"
     6  
     7  	"github.com/sagernet/sing-box/adapter"
     8  	E "github.com/sagernet/sing/common/exceptions"
     9  )
    10  
    11  var ErrBadPortRange = E.New("bad port range")
    12  
    13  var _ RuleItem = (*PortRangeItem)(nil)
    14  
    15  type PortRangeItem struct {
    16  	isSource      bool
    17  	portRanges    []string
    18  	portRangeList []rangeItem
    19  }
    20  
    21  type rangeItem struct {
    22  	start uint16
    23  	end   uint16
    24  }
    25  
    26  func NewPortRangeItem(isSource bool, rangeList []string) (*PortRangeItem, error) {
    27  	portRangeList := make([]rangeItem, 0, len(rangeList))
    28  	for _, portRange := range rangeList {
    29  		if !strings.Contains(portRange, ":") {
    30  			return nil, E.Extend(ErrBadPortRange, portRange)
    31  		}
    32  		subIndex := strings.Index(portRange, ":")
    33  		var start, end uint64
    34  		var err error
    35  		if subIndex > 0 {
    36  			start, err = strconv.ParseUint(portRange[:subIndex], 10, 16)
    37  			if err != nil {
    38  				return nil, E.Cause(err, E.Extend(ErrBadPortRange, portRange))
    39  			}
    40  		}
    41  		if subIndex == len(portRange)-1 {
    42  			end = 0xFF
    43  		} else {
    44  			end, err = strconv.ParseUint(portRange[subIndex+1:], 10, 16)
    45  			if err != nil {
    46  				return nil, E.Cause(err, E.Extend(ErrBadPortRange, portRange))
    47  			}
    48  		}
    49  		portRangeList = append(portRangeList, rangeItem{uint16(start), uint16(end)})
    50  	}
    51  	return &PortRangeItem{
    52  		isSource:      isSource,
    53  		portRanges:    rangeList,
    54  		portRangeList: portRangeList,
    55  	}, nil
    56  }
    57  
    58  func (r *PortRangeItem) Match(metadata *adapter.InboundContext) bool {
    59  	var port uint16
    60  	if r.isSource {
    61  		port = metadata.Source.Port
    62  	} else {
    63  		port = metadata.Destination.Port
    64  	}
    65  	for _, portRange := range r.portRangeList {
    66  		if port >= portRange.start && port <= portRange.end {
    67  			return true
    68  		}
    69  	}
    70  	return false
    71  }
    72  
    73  func (r *PortRangeItem) String() string {
    74  	var description string
    75  	if r.isSource {
    76  		description = "source_port_range="
    77  	} else {
    78  		description = "port_range="
    79  	}
    80  	pLen := len(r.portRanges)
    81  	if pLen == 1 {
    82  		description += r.portRanges[0]
    83  	} else {
    84  		description += "[" + strings.Join(r.portRanges, " ") + "]"
    85  	}
    86  	return description
    87  }