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)