feat: IN-TYPE rule support

eg. IN-TYPE,SOCKS/REDIR/INNER,Proxy
support list: HTTP HTTPS SOCKS SOCKS4 SOCKS5 REDIR TPROXY TUN INNER
This commit is contained in:
adlyq 2022-05-20 23:17:16 +08:00
parent 0f43a19fdb
commit 3ab82849d4
8 changed files with 114 additions and 7 deletions

View file

@ -11,7 +11,7 @@ import (
// NewHTTPS receive CONNECT request and return ConnContext // NewHTTPS receive CONNECT request and return ConnContext
func NewHTTPS(request *http.Request, conn net.Conn) *context.ConnContext { func NewHTTPS(request *http.Request, conn net.Conn) *context.ConnContext {
metadata := parseHTTPAddr(request) metadata := parseHTTPAddr(request)
metadata.Type = C.HTTPCONNECT metadata.Type = C.HTTPS
if ip, port, err := parseAddr(conn.RemoteAddr().String()); err == nil { if ip, port, err := parseAddr(conn.RemoteAddr().String()); err == nil {
metadata.SrcIP = ip metadata.SrcIP = ip
metadata.SrcPort = port metadata.SrcPort = port

View file

@ -19,7 +19,7 @@ const (
ALLNet ALLNet
HTTP Type = iota HTTP Type = iota
HTTPCONNECT HTTPS
SOCKS4 SOCKS4
SOCKS5 SOCKS5
REDIR REDIR
@ -49,8 +49,8 @@ func (t Type) String() string {
switch t { switch t {
case HTTP: case HTTP:
return "HTTP" return "HTTP"
case HTTPCONNECT: case HTTPS:
return "HTTP Connect" return "HTTPS"
case SOCKS4: case SOCKS4:
return "Socks4" return "Socks4"
case SOCKS5: 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) { func (t Type) MarshalJSON() ([]byte, error) {
return json.Marshal(t.String()) return json.Marshal(t.String())
} }

View file

@ -16,6 +16,7 @@ const (
RuleSet RuleSet
Network Network
Uid Uid
INTYPE
MATCH MATCH
AND AND
OR OR
@ -56,6 +57,8 @@ func (rt RuleType) String() string {
return "Network" return "Network"
case Uid: case Uid:
return "Uid" return "Uid"
case INTYPE:
return "InType"
case AND: case AND:
return "AND" return "AND"
case OR: case OR:

View file

@ -20,7 +20,7 @@ type Rule struct {
Type string `json:"type"` Type string `json:"type"`
Payload string `json:"payload"` Payload string `json:"payload"`
Proxy string `json:"proxy"` Proxy string `json:"proxy"`
Size int `json:"Size"` Size int `json:"size"`
} }
func getRules(w http.ResponseWriter, r *http.Request) { func getRules(w http.ResponseWriter, r *http.Request) {

74
rule/common/in_type.go Normal file
View file

@ -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
}

View file

@ -104,6 +104,8 @@ func parseRule(tp, payload string, params []string) (C.Rule, error) {
case "RULE-SET": case "RULE-SET":
noResolve := RC.HasNoResolve(params) noResolve := RC.HasNoResolve(params)
parsed, parseErr = provider.NewRuleSet(payload, "", noResolve) parsed, parseErr = provider.NewRuleSet(payload, "", noResolve)
case "IN-TYPE":
parsed, parseErr = RC.NewInType(payload, "")
case "NOT": case "NOT":
parsed, parseErr = NewNOT(payload, "") parsed, parseErr = NewNOT(payload, "")
case "AND": case "AND":

View file

@ -3,7 +3,6 @@ package rules
import ( import (
"fmt" "fmt"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
RC "github.com/Dreamacro/clash/rule/common" RC "github.com/Dreamacro/clash/rule/common"
"github.com/Dreamacro/clash/rule/logic" "github.com/Dreamacro/clash/rule/logic"
RP "github.com/Dreamacro/clash/rule/provider" 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" { if runtime.GOOS == "linux" || runtime.GOOS == "android" {
parsed, parseErr = RC.NewUid(payload, target) parsed, parseErr = RC.NewUid(payload, target)
} else { } 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": case "AND":
parsed, parseErr = logic.NewAND(payload, target) parsed, parseErr = logic.NewAND(payload, target)
case "OR": case "OR":

View file

@ -84,6 +84,8 @@ func parseRule(tp, payload, target string, params []string) (C.Rule, error) {
parsed, parseErr = RC.NewProcess(payload, target, false) parsed, parseErr = RC.NewProcess(payload, target, false)
case "NETWORK": case "NETWORK":
parsed, parseErr = RC.NewNetworkType(payload, target) parsed, parseErr = RC.NewNetworkType(payload, target)
case "IN-TYPE":
parsed, parseErr = RC.NewInType(payload, target)
default: default:
parseErr = fmt.Errorf("unsupported rule type %s", tp) parseErr = fmt.Errorf("unsupported rule type %s", tp)
} }