From 3ab82849d4806efc6188114ccdaf5aef207ac94b Mon Sep 17 00:00:00 2001 From: adlyq Date: Fri, 20 May 2022 23:17:16 +0800 Subject: [PATCH] feat: IN-TYPE rule support eg. IN-TYPE,SOCKS/REDIR/INNER,Proxy support list: HTTP HTTPS SOCKS SOCKS4 SOCKS5 REDIR TPROXY TUN INNER --- adapter/inbound/https.go | 2 +- constant/metadata.go | 31 +++++++++++++++-- constant/rule.go | 3 ++ hub/route/rules.go | 2 +- rule/common/in_type.go | 74 ++++++++++++++++++++++++++++++++++++++++ rule/logic/common.go | 2 ++ rule/parser.go | 5 +-- rule/provider/parse.go | 2 ++ 8 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 rule/common/in_type.go diff --git a/adapter/inbound/https.go b/adapter/inbound/https.go index e7e92211..99bc433f 100644 --- a/adapter/inbound/https.go +++ b/adapter/inbound/https.go @@ -11,7 +11,7 @@ import ( // NewHTTPS receive CONNECT request and return ConnContext func NewHTTPS(request *http.Request, conn net.Conn) *context.ConnContext { metadata := parseHTTPAddr(request) - metadata.Type = C.HTTPCONNECT + metadata.Type = C.HTTPS if ip, port, err := parseAddr(conn.RemoteAddr().String()); err == nil { metadata.SrcIP = ip metadata.SrcPort = port diff --git a/constant/metadata.go b/constant/metadata.go index 350d82b2..b58847ff 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -19,7 +19,7 @@ const ( ALLNet HTTP Type = iota - HTTPCONNECT + HTTPS SOCKS4 SOCKS5 REDIR @@ -49,8 +49,8 @@ func (t Type) String() string { switch t { case HTTP: return "HTTP" - case HTTPCONNECT: - return "HTTP Connect" + case HTTPS: + return "HTTPS" case SOCKS4: return "Socks4" case SOCKS5: @@ -68,6 +68,31 @@ func (t Type) String() string { } } +func ParseType(t string) (*Type, error) { + var res Type + switch t { + case "HTTP": + res = HTTP + case "HTTPS": + res = HTTPS + case "SOCKS4": + res = SOCKS4 + case "SOCKS5": + res = SOCKS5 + case "REDIR": + res = REDIR + case "TPROXY": + res = TPROXY + case "TUN": + res = TUN + case "INNER": + res = INNER + default: + return nil, fmt.Errorf("unknown type: %s", t) + } + return &res, nil +} + func (t Type) MarshalJSON() ([]byte, error) { return json.Marshal(t.String()) } diff --git a/constant/rule.go b/constant/rule.go index e41309f0..7c7eea96 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -16,6 +16,7 @@ const ( RuleSet Network Uid + INTYPE MATCH AND OR @@ -56,6 +57,8 @@ func (rt RuleType) String() string { return "Network" case Uid: return "Uid" + case INTYPE: + return "InType" case AND: return "AND" case OR: diff --git a/hub/route/rules.go b/hub/route/rules.go index de4c9f11..51f8f01c 100644 --- a/hub/route/rules.go +++ b/hub/route/rules.go @@ -20,7 +20,7 @@ type Rule struct { Type string `json:"type"` Payload string `json:"payload"` Proxy string `json:"proxy"` - Size int `json:"Size"` + Size int `json:"size"` } func getRules(w http.ResponseWriter, r *http.Request) { diff --git a/rule/common/in_type.go b/rule/common/in_type.go new file mode 100644 index 00000000..c577c843 --- /dev/null +++ b/rule/common/in_type.go @@ -0,0 +1,74 @@ +package common + +import ( + "fmt" + C "github.com/Dreamacro/clash/constant" + "strings" +) + +type InType struct { + *Base + types []C.Type + adapter string + payload string +} + +func (u *InType) Match(metadata *C.Metadata) bool { + for _, tp := range u.types { + if metadata.Type == tp { + return true + } + } + return false +} + +func (u *InType) RuleType() C.RuleType { + return C.INTYPE +} + +func (u *InType) Adapter() string { + return u.adapter +} + +func (u *InType) Payload() string { + return u.payload +} + +func NewInType(iTypes, adapter string) (*InType, error) { + types := strings.Split(iTypes, "/") + if len(types) == 0 { + return nil, fmt.Errorf("in type could be empty") + } + + tps, err := parseInTypes(types) + if err != nil { + return nil, err + } + + return &InType{ + Base: &Base{}, + types: tps, + adapter: adapter, + payload: strings.ToUpper(iTypes), + }, nil +} + +func parseInTypes(tps []string) (res []C.Type, err error) { + for _, tp := range tps { + utp := strings.ToUpper(tp) + var r *C.Type + if utp == "SOCKS" { + r, _ = C.ParseType("SOCKS4") + res = append(res, *r) + r, _ = C.ParseType("SOCKS5") + res = append(res, *r) + } else { + r, err = C.ParseType(utp) + if err != nil { + return + } + res = append(res, *r) + } + } + return +} diff --git a/rule/logic/common.go b/rule/logic/common.go index 1f9a56c1..89e62d76 100644 --- a/rule/logic/common.go +++ b/rule/logic/common.go @@ -104,6 +104,8 @@ func parseRule(tp, payload string, params []string) (C.Rule, error) { case "RULE-SET": noResolve := RC.HasNoResolve(params) parsed, parseErr = provider.NewRuleSet(payload, "", noResolve) + case "IN-TYPE": + parsed, parseErr = RC.NewInType(payload, "") case "NOT": parsed, parseErr = NewNOT(payload, "") case "AND": diff --git a/rule/parser.go b/rule/parser.go index f59f92a2..e82e3fda 100644 --- a/rule/parser.go +++ b/rule/parser.go @@ -3,7 +3,6 @@ package rules import ( "fmt" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" RC "github.com/Dreamacro/clash/rule/common" "github.com/Dreamacro/clash/rule/logic" RP "github.com/Dreamacro/clash/rule/provider" @@ -47,8 +46,10 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) { if runtime.GOOS == "linux" || runtime.GOOS == "android" { parsed, parseErr = RC.NewUid(payload, target) } else { - log.Warnln("uid rule not support this platform") + parseErr = fmt.Errorf("uid rule not support this platform") } + case "IN-TYPE": + parsed, parseErr = RC.NewInType(payload, target) case "AND": parsed, parseErr = logic.NewAND(payload, target) case "OR": diff --git a/rule/provider/parse.go b/rule/provider/parse.go index c520b53f..206e55ef 100644 --- a/rule/provider/parse.go +++ b/rule/provider/parse.go @@ -84,6 +84,8 @@ func parseRule(tp, payload, target string, params []string) (C.Rule, error) { parsed, parseErr = RC.NewProcess(payload, target, false) case "NETWORK": parsed, parseErr = RC.NewNetworkType(payload, target) + case "IN-TYPE": + parsed, parseErr = RC.NewInType(payload, target) default: parseErr = fmt.Errorf("unsupported rule type %s", tp) }