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:
parent
0f43a19fdb
commit
3ab82849d4
8 changed files with 114 additions and 7 deletions
|
@ -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
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
74
rule/common/in_type.go
Normal 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
|
||||||
|
}
|
|
@ -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":
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue