chore: new rule

This commit is contained in:
Adlyq 2023-09-03 23:42:27 +08:00
parent 3fd954d185
commit 1f7a883bfc
8 changed files with 77 additions and 105 deletions

View File

@ -263,8 +263,8 @@ type RawTuicServer struct {
}
type RawMitm struct {
Port int `yaml:"port" json:"port"`
Rules []string `yaml:"rules" json:"rules"`
Port int `yaml:"port" json:"port"`
Rules []rewrites.RawMitmRule `yaml:"rules" json:"rules"`
}
type RawConfig struct {
@ -456,7 +456,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
},
MITM: RawMitm{
Port: 0,
Rules: []string{},
Rules: []rewrites.RawMitmRule{},
},
Profile: Profile{
StoreSelected: true,

View File

@ -162,6 +162,8 @@ func (m *Metadata) SourceAddress() string {
func (m *Metadata) SourceDetail() string {
if m.Type == INNER {
return fmt.Sprintf("%s", ClashName)
} else if m.Type == MITM {
return fmt.Sprintf("%s-MITM", ClashName)
}
switch {

View File

@ -1,6 +1,8 @@
package constant
import (
"encoding/json"
"errors"
regexp "github.com/dlclark/regexp2"
)
@ -37,6 +39,42 @@ const (
type RewriteType int
// UnmarshalYAML unserialize RewriteType with yaml
func (e *RewriteType) UnmarshalYAML(unmarshal func(any) error) error {
var tp string
if err := unmarshal(&tp); err != nil {
return err
}
mode, exist := RewriteTypeMapping[tp]
if !exist {
return errors.New("invalid MITM Action")
}
*e = mode
return nil
}
// MarshalYAML serialize RewriteType with yaml
func (e RewriteType) MarshalYAML() (any, error) {
return e.String(), nil
}
// UnmarshalJSON unserialize RewriteType with json
func (e *RewriteType) UnmarshalJSON(data []byte) error {
var tp string
json.Unmarshal(data, &tp)
mode, exist := RewriteTypeMapping[tp]
if !exist {
return errors.New("invalid MITM Action")
}
*e = mode
return nil
}
// MarshalJSON serialize RewriteType with json
func (e RewriteType) MarshalJSON() ([]byte, error) {
return json.Marshal(e.String())
}
func (rt RewriteType) String() string {
switch rt {
case MitmReject:

View File

@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"errors"
log "github.com/sirupsen/logrus"
"io"
"io/ioutil"
"net/http"
@ -31,6 +32,8 @@ func (*RewriteHandler) HandleRequest(session *mitm.Session) (*http.Request, *htt
return nil, nil
}
log.Infof("[MITM] %s <- request %s", rule.RuleType().String(), request.URL.String())
switch rule.RuleType() {
case C.MitmReject:
response = session.NewResponse(http.StatusNotFound, nil)
@ -113,6 +116,8 @@ func (*RewriteHandler) HandleResponse(session *mitm.Session) *http.Response {
return nil
}
log.Infof("[MITM] %s <- response %s", rule.RuleType().String(), request.URL.String())
switch rule.RuleType() {
case C.MitmResponseHeader:
if len(response.Header) == 0 {
@ -182,7 +187,7 @@ func matchRewriteRule(url string, isRequest bool) (rr C.Rewrite, sub []string, f
if isRequest {
found = rewrites.SearchInRequest(func(r C.Rewrite) bool {
sub, err := r.URLRegx().FindStringMatch(url)
if err != nil {
if err != nil || sub == nil {
return false
}

View File

@ -7,12 +7,7 @@ import (
C "github.com/Dreamacro/clash/constant"
)
func ParseRewrite(line string) (C.Rewrite, error) {
url, others, found := strings.Cut(strings.TrimSpace(line), "url")
if !found {
return nil, errInvalid
}
func ParseRewrite(line RawMitmRule) (C.Rewrite, error) {
var (
urlRegx *regexp.Regexp
ruleType *C.RewriteType
@ -22,57 +17,37 @@ func ParseRewrite(line string) (C.Rewrite, error) {
err error
)
url := line.Url
urlRegx, err = regexp.Compile(strings.Trim(url, " "), regexp.None)
if err != nil {
return nil, err
}
others = strings.Trim(others, " ")
first := strings.Split(others, " ")[0]
for k, v := range C.RewriteTypeMapping {
if k == others {
ruleType = &v
ruleType = &line.Action
switch *ruleType {
case C.Mitm302, C.Mitm307:
{
rulePayload = line.New
break
}
case C.MitmRequestHeader, C.MitmRequestBody, C.MitmResponseHeader, C.MitmResponseBody:
{
var old string
if line.Old == nil {
old = ".*"
} else {
old = *line.Old
}
if k != first {
continue
}
rs := trimArr(strings.Split(others, k))
l := len(rs)
if l > 2 {
continue
}
if l == 1 {
ruleType = &v
rulePayload = rs[0]
break
} else {
ruleRegx, err = regexp.Compile(rs[0], regexp.None)
re, err := regexp.Compile(old, regexp.Singleline)
if err != nil {
return nil, err
}
ruleRegx = re
ruleType = &v
rulePayload = rs[1]
break
rulePayload = line.New
}
}
if ruleType == nil {
return nil, errInvalid
}
return NewRewriteRule(urlRegx, *ruleType, ruleRegx, rulePayload), nil
}
func trimArr(arr []string) (r []string) {
for _, e := range arr {
if s := strings.Trim(e, " "); s != "" {
r = append(r, s)
}
}
return
}

View File

@ -1,56 +0,0 @@
package rewrites
import (
"bytes"
"fmt"
"image"
"image/color"
"image/draw"
"image/png"
"regexp"
"testing"
"github.com/Dreamacro/clash/constant"
"github.com/stretchr/testify/assert"
)
func TestParseRewrite(t *testing.T) {
line0 := `^https?://example\.com/resource1/3/ url reject-dict`
line1 := `^https?://example\.com/(resource2)/ url 307 https://example.com/new-$1`
line2 := `^https?://example\.com/resource4/ url request-header (\r\n)User-Agent:.+(\r\n) request-header $1User-Agent: Fuck-Who$2`
line3 := `should be error`
c0, err0 := ParseRewrite(line0)
c1, err1 := ParseRewrite(line1)
c2, err2 := ParseRewrite(line2)
_, err3 := ParseRewrite(line3)
assert.NotNil(t, err3)
assert.Nil(t, err0)
assert.Equal(t, c0.RuleType(), constant.MitmRejectDict)
assert.Nil(t, err1)
assert.Equal(t, c1.RuleType(), constant.Mitm307)
assert.Equal(t, c1.URLRegx(), regexp.MustCompile(`^https?://example\.com/(resource2)/`))
assert.Equal(t, c1.RulePayload(), "https://example.com/new-$1")
assert.Nil(t, err2)
assert.Equal(t, c2.RuleType(), constant.MitmRequestHeader)
assert.Equal(t, c2.RuleRegx(), regexp.MustCompile(`(\r\n)User-Agent:.+(\r\n)`))
assert.Equal(t, c2.RulePayload(), "$1User-Agent: Fuck-Who$2")
}
func Test1PxPNG(t *testing.T) {
m := image.NewRGBA(image.Rect(0, 0, 1, 1))
draw.Draw(m, m.Bounds(), &image.Uniform{C: color.Transparent}, image.Point{}, draw.Src)
buf := &bytes.Buffer{}
assert.Nil(t, png.Encode(buf, m))
fmt.Printf("len: %d\n", buf.Len())
fmt.Printf("% #x\n", buf.Bytes())
}

View File

@ -1,7 +1,6 @@
package rewrites
import (
"errors"
regexp "github.com/dlclark/regexp2"
"strconv"
"strings"
@ -11,7 +10,12 @@ import (
"github.com/gofrs/uuid"
)
var errInvalid = errors.New("invalid rewrite rule")
type RawMitmRule struct {
Url string `yaml:"url" json:"url"`
Action C.RewriteType `yaml:"action" json:"action"`
Old *string `yaml:"old" json:"old"`
New string `yaml:"new" json:"new"`
}
type RewriteRule struct {
id string

View File

@ -561,6 +561,10 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
}
for _, rule := range getRules(metadata) {
if metadata.Type == C.MITM && rule.Adapter() == "MITM" {
continue
}
if !resolved && shouldResolveIP(rule, metadata) {
func() {
ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout)