github.com/yaling888/clash@v1.53.0/rule/port.go (about)

     1  package rules
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	C "github.com/yaling888/clash/constant"
     9  )
    10  
    11  type PortType int
    12  
    13  const (
    14  	PortTypeSrc PortType = iota
    15  	PortTypeDest
    16  	PortTypeInbound
    17  )
    18  
    19  type portReal struct {
    20  	portStart int
    21  	portEnd   int
    22  }
    23  
    24  type Port struct {
    25  	*Base
    26  	adapter  string
    27  	port     string
    28  	portType PortType
    29  	portList []portReal
    30  }
    31  
    32  func (p *Port) RuleType() C.RuleType {
    33  	switch p.portType {
    34  	case PortTypeSrc:
    35  		return C.SrcPort
    36  	case PortTypeDest:
    37  		return C.DstPort
    38  	case PortTypeInbound:
    39  		return C.InboundPort
    40  	default:
    41  		panic(fmt.Errorf("unknown port type: %v", p.portType))
    42  	}
    43  }
    44  
    45  func (p *Port) Match(metadata *C.Metadata) bool {
    46  	switch p.portType {
    47  	case PortTypeSrc:
    48  		return p.matchPortReal(int(metadata.SrcPort))
    49  	case PortTypeDest:
    50  		return p.matchPortReal(int(metadata.DstPort))
    51  	case PortTypeInbound:
    52  		return p.matchPortReal(int(metadata.OriginDst.Port()))
    53  	default:
    54  		panic(fmt.Errorf("unknown port type: %v", p.portType))
    55  	}
    56  }
    57  
    58  func (p *Port) Adapter() string {
    59  	return p.adapter
    60  }
    61  
    62  func (p *Port) Payload() string {
    63  	return p.port
    64  }
    65  
    66  func (p *Port) ShouldResolveIP() bool {
    67  	return false
    68  }
    69  
    70  func (p *Port) matchPortReal(port int) bool {
    71  	var rs bool
    72  	for _, pr := range p.portList {
    73  		if pr.portEnd == -1 {
    74  			rs = port == pr.portStart
    75  		} else {
    76  			rs = port >= pr.portStart && port <= pr.portEnd
    77  		}
    78  		if rs {
    79  			return true
    80  		}
    81  	}
    82  	return false
    83  }
    84  
    85  func NewPort(port string, adapter string, portType PortType) (*Port, error) {
    86  	ports := strings.Split(port, "/")
    87  	if len(ports) > 28 {
    88  		return nil, fmt.Errorf("%s, too many ports to use, maximum support 28 ports", errPayload.Error())
    89  	}
    90  
    91  	var portList []portReal
    92  	for _, p := range ports {
    93  		if p == "" {
    94  			continue
    95  		}
    96  
    97  		subPorts := strings.Split(p, "-")
    98  		subPortsLen := len(subPorts)
    99  		if subPortsLen > 2 {
   100  			return nil, errPayload
   101  		}
   102  
   103  		portStart, err := strconv.ParseUint(strings.Trim(subPorts[0], "[ ]"), 10, 16)
   104  		if err != nil {
   105  			return nil, errPayload
   106  		}
   107  
   108  		switch subPortsLen {
   109  		case 1:
   110  			portList = append(portList, portReal{int(portStart), -1})
   111  		case 2:
   112  			portEnd, err := strconv.ParseUint(strings.Trim(subPorts[1], "[ ]"), 10, 16)
   113  			if err != nil {
   114  				return nil, errPayload
   115  			}
   116  
   117  			shouldReverse := portStart > portEnd
   118  			if shouldReverse {
   119  				portList = append(portList, portReal{int(portEnd), int(portStart)})
   120  			} else {
   121  				portList = append(portList, portReal{int(portStart), int(portEnd)})
   122  			}
   123  		}
   124  	}
   125  
   126  	if len(portList) == 0 {
   127  		return nil, errPayload
   128  	}
   129  
   130  	return &Port{
   131  		Base:     &Base{},
   132  		adapter:  adapter,
   133  		port:     port,
   134  		portType: portType,
   135  		portList: portList,
   136  	}, nil
   137  }
   138  
   139  var _ C.Rule = (*Port)(nil)