feat: add mrs format ipcidr ruleset

This commit is contained in:
wwqgtxx
2024-07-27 10:36:11 +08:00
parent 303f6e4567
commit 4f8a5a5f54
10 changed files with 255 additions and 44 deletions

View File

@@ -5,6 +5,7 @@ import (
"strings"
C "github.com/metacubex/mihomo/constant"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
)
@@ -16,6 +17,10 @@ type classicalStrategy struct {
parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)
}
func (c *classicalStrategy) Behavior() P.RuleBehavior {
return P.Classical
}
func (c *classicalStrategy) Match(metadata *C.Metadata) bool {
for _, rule := range c.rules {
if m, _ := rule.Match(metadata); m {

View File

@@ -6,6 +6,7 @@ import (
"github.com/metacubex/mihomo/component/trie"
C "github.com/metacubex/mihomo/constant"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
)
@@ -15,6 +16,10 @@ type domainStrategy struct {
domainSet *trie.DomainSet
}
func (d *domainStrategy) Behavior() P.RuleBehavior {
return P.Domain
}
func (d *domainStrategy) ShouldFindProcess() bool {
return false
}
@@ -51,12 +56,12 @@ func (d *domainStrategy) FinishInsert() {
d.domainTrie = nil
}
func (d *domainStrategy) FromMrs(r io.Reader) error {
domainSet, count, err := trie.ReadDomainSetBin(r)
func (d *domainStrategy) FromMrs(r io.Reader, count int) error {
domainSet, err := trie.ReadDomainSetBin(r)
if err != nil {
return err
}
d.count = int(count)
d.count = count
d.domainSet = domainSet
return nil
}
@@ -65,7 +70,7 @@ func (d *domainStrategy) WriteMrs(w io.Writer) error {
if d.domainSet == nil {
return errors.New("nil domainSet")
}
return d.domainSet.WriteBin(w, int64(d.count))
return d.domainSet.WriteBin(w)
}
var _ mrsRuleStrategy = (*domainStrategy)(nil)

View File

@@ -1,8 +1,12 @@
package provider
import (
"errors"
"io"
"github.com/metacubex/mihomo/component/cidr"
C "github.com/metacubex/mihomo/constant"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
"go4.org/netipx"
@@ -15,6 +19,10 @@ type ipcidrStrategy struct {
//trie *trie.IpCidrTrie
}
func (i *ipcidrStrategy) Behavior() P.RuleBehavior {
return P.IPCIDR
}
func (i *ipcidrStrategy) ShouldFindProcess() bool {
return false
}
@@ -54,6 +62,26 @@ func (i *ipcidrStrategy) FinishInsert() {
i.cidrSet.Merge()
}
func (i *ipcidrStrategy) FromMrs(r io.Reader, count int) error {
cidrSet, err := cidr.ReadIpCidrSet(r)
if err != nil {
return err
}
i.count = count
i.cidrSet = cidrSet
if i.count > 0 {
i.shouldResolveIP = true
}
return nil
}
func (i *ipcidrStrategy) WriteMrs(w io.Writer) error {
if i.cidrSet == nil {
return errors.New("nil cidrSet")
}
return i.cidrSet.WriteBin(w)
}
func (i *ipcidrStrategy) ToIpCidr() *netipx.IPSet {
return i.cidrSet.ToIPSet()
}

View File

@@ -1,6 +1,7 @@
package provider
import (
"encoding/binary"
"io"
"os"
@@ -27,6 +28,38 @@ func ConvertToMrs(buf []byte, behavior P.RuleBehavior, format P.RuleFormat, w io
err = zstdErr
}
}()
// header
_, err = encoder.Write(MrsMagicBytes[:])
if err != nil {
return err
}
// behavior
_behavior := []byte{behavior.Byte()}
_, err = encoder.Write(_behavior[:])
if err != nil {
return err
}
// count
count := int64(_strategy.Count())
err = binary.Write(encoder, binary.BigEndian, count)
if err != nil {
return err
}
// extra (reserved for future using)
var extra []byte
err = binary.Write(encoder, binary.BigEndian, int64(len(extra)))
if err != nil {
return err
}
_, err = encoder.Write(extra)
if err != nil {
return err
}
return _strategy.WriteMrs(encoder)
} else {
return ErrInvalidFormat

View File

@@ -0,0 +1,72 @@
package provider
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"github.com/klauspost/compress/zstd"
)
var MrsMagicBytes = [4]byte{'M', 'R', 'S', 1} // MRSv1
func rulesMrsParse(buf []byte, strategy ruleStrategy) (ruleStrategy, error) {
if _strategy, ok := strategy.(mrsRuleStrategy); ok {
reader, err := zstd.NewReader(bytes.NewReader(buf))
if err != nil {
return nil, err
}
defer reader.Close()
// header
var header [4]byte
_, err = io.ReadFull(reader, header[:])
if err != nil {
return nil, err
}
if header != MrsMagicBytes {
return nil, fmt.Errorf("invalid MrsMagic bytes")
}
// behavior
var _behavior [1]byte
_, err = io.ReadFull(reader, _behavior[:])
if err != nil {
return nil, err
}
if _behavior[0] != strategy.Behavior().Byte() {
return nil, fmt.Errorf("invalid behavior")
}
// count
var count int64
err = binary.Read(reader, binary.BigEndian, &count)
if err != nil {
return nil, err
}
// extra (reserved for future using)
var length int64
err = binary.Read(reader, binary.BigEndian, &length)
if err != nil {
return nil, err
}
if length < 0 {
return nil, errors.New("length is invalid")
}
if length > 0 {
extra := make([]byte, length)
_, err = io.ReadFull(reader, extra)
if err != nil {
return nil, err
}
}
err = _strategy.FromMrs(reader, int(count))
return strategy, err
} else {
return nil, ErrInvalidFormat
}
}

View File

@@ -14,7 +14,6 @@ import (
C "github.com/metacubex/mihomo/constant"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/klauspost/compress/zstd"
"gopkg.in/yaml.v3"
)
@@ -45,6 +44,7 @@ type RulePayload struct {
}
type ruleStrategy interface {
Behavior() P.RuleBehavior
Match(metadata *C.Metadata) bool
Count() int
ShouldResolveIP() bool
@@ -56,7 +56,7 @@ type ruleStrategy interface {
type mrsRuleStrategy interface {
ruleStrategy
FromMrs(r io.Reader) error
FromMrs(r io.Reader, count int) error
WriteMrs(w io.Writer) error
}
@@ -165,17 +165,7 @@ var ErrInvalidFormat = errors.New("invalid format")
func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (ruleStrategy, error) {
strategy.Reset()
if format == P.MrsRule {
if _strategy, ok := strategy.(mrsRuleStrategy); ok {
reader, err := zstd.NewReader(bytes.NewReader(buf))
if err != nil {
return nil, err
}
defer reader.Close()
err = _strategy.FromMrs(reader)
return strategy, err
} else {
return nil, ErrInvalidFormat
}
return rulesMrsParse(buf, strategy)
}
schema := &RulePayload{}