Skip to content

Commit

Permalink
feat: add mrs format ipcidr ruleset
Browse files Browse the repository at this point in the history
  • Loading branch information
wwqgtxx committed Jul 27, 2024
1 parent 303f6e4 commit 4f8a5a5
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 44 deletions.
77 changes: 77 additions & 0 deletions component/cidr/ipcidr_set_bin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package cidr

import (
"encoding/binary"
"errors"
"io"
"net/netip"

"go4.org/netipx"
)

func (ss *IpCidrSet) WriteBin(w io.Writer) (err error) {
// version
_, err = w.Write([]byte{1})
if err != nil {
return err
}

// rr
err = binary.Write(w, binary.BigEndian, int64(len(ss.rr)))
if err != nil {
return err
}
for _, r := range ss.rr {
err = binary.Write(w, binary.BigEndian, r.From().As16())
if err != nil {
return err
}
err = binary.Write(w, binary.BigEndian, r.To().As16())
if err != nil {
return err
}
}

return nil
}

func ReadIpCidrSet(r io.Reader) (ss *IpCidrSet, err error) {
// version
version := make([]byte, 1)
_, err = io.ReadFull(r, version)
if err != nil {
return nil, err
}
if version[0] != 1 {
return nil, errors.New("version is invalid")
}

ss = NewIpCidrSet()
var length int64

// rr
err = binary.Read(r, binary.BigEndian, &length)
if err != nil {
return nil, err
}
if length < 1 {
return nil, errors.New("length is invalid")
}
ss.rr = make([]netipx.IPRange, length)
for i := int64(0); i < length; i++ {
var a16 [16]byte
err = binary.Read(r, binary.BigEndian, &a16)
if err != nil {
return nil, err
}
from := netip.AddrFrom16(a16).Unmap()
err = binary.Read(r, binary.BigEndian, &a16)
if err != nil {
return nil, err
}
to := netip.AddrFrom16(a16).Unmap()
ss.rr[i] = netipx.IPRangeFrom(from, to)
}

return ss, nil
}
40 changes: 14 additions & 26 deletions component/trie/domain_set_bin.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,13 @@ import (
"io"
)

func (ss *DomainSet) WriteBin(w io.Writer, count int64) (err error) {
func (ss *DomainSet) WriteBin(w io.Writer) (err error) {
// version
_, err = w.Write([]byte{1})
if err != nil {
return err
}

// count
err = binary.Write(w, binary.BigEndian, count)
if err != nil {
return err
}

// leaves
err = binary.Write(w, binary.BigEndian, int64(len(ss.leaves)))
if err != nil {
Expand Down Expand Up @@ -56,21 +50,15 @@ func (ss *DomainSet) WriteBin(w io.Writer, count int64) (err error) {
return nil
}

func ReadDomainSetBin(r io.Reader) (ds *DomainSet, count int64, err error) {
func ReadDomainSetBin(r io.Reader) (ds *DomainSet, err error) {
// version
version := make([]byte, 1)
_, err = io.ReadFull(r, version)
if err != nil {
return nil, 0, err
return nil, err
}
if version[0] != 1 {
return nil, 0, errors.New("version is invalid")
}

// count
err = binary.Read(r, binary.BigEndian, &count)
if err != nil {
return nil, 0, err
return nil, errors.New("version is invalid")
}

ds = &DomainSet{}
Expand All @@ -79,49 +67,49 @@ func ReadDomainSetBin(r io.Reader) (ds *DomainSet, count int64, err error) {
// leaves
err = binary.Read(r, binary.BigEndian, &length)
if err != nil {
return nil, 0, err
return nil, err
}
if length < 1 {
return nil, 0, errors.New("length is invalid")
return nil, errors.New("length is invalid")
}
ds.leaves = make([]uint64, length)
for i := int64(0); i < length; i++ {
err = binary.Read(r, binary.BigEndian, &ds.leaves[i])
if err != nil {
return nil, 0, err
return nil, err
}
}

// labelBitmap
err = binary.Read(r, binary.BigEndian, &length)
if err != nil {
return nil, 0, err
return nil, err
}
if length < 1 {
return nil, 0, errors.New("length is invalid")
return nil, errors.New("length is invalid")
}
ds.labelBitmap = make([]uint64, length)
for i := int64(0); i < length; i++ {
err = binary.Read(r, binary.BigEndian, &ds.labelBitmap[i])
if err != nil {
return nil, 0, err
return nil, err
}
}

// labels
err = binary.Read(r, binary.BigEndian, &length)
if err != nil {
return nil, 0, err
return nil, err
}
if length < 1 {
return nil, 0, errors.New("length is invalid")
return nil, errors.New("length is invalid")
}
ds.labels = make([]byte, length)
_, err = io.ReadFull(r, ds.labels)
if err != nil {
return nil, 0, err
return nil, err
}

ds.init()
return ds, count, nil
return ds, nil
}
13 changes: 13 additions & 0 deletions constant/provider/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,19 @@ func (rt RuleBehavior) String() string {
}
}

func (rt RuleBehavior) Byte() byte {
switch rt {
case Domain:
return 0
case IPCIDR:
return 1
case Classical:
return 2
default:
return 255
}
}

func ParseBehavior(s string) (behavior RuleBehavior, err error) {
switch s {
case "domain":
Expand Down
2 changes: 1 addition & 1 deletion docs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@ rule-providers:
interval: 259200
path: /path/to/save/file.yaml
type: file
rule3: # mrs类型ruleset,目前仅支持domain,可以通过“mihomo convert-ruleset domain yaml XXX.yaml XXX.mrs”转换得到
rule3: # mrs类型ruleset,目前仅支持domain和ipcidr,可以通过“mihomo convert-ruleset domain yaml XXX.yaml XXX.mrs”转换得到
type: http
url: "url"
format: mrs
Expand Down
5 changes: 5 additions & 0 deletions rules/provider/classical_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"strings"

C "github.com/metacubex/mihomo/constant"
P "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/log"
)

Expand All @@ -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 {
Expand Down
13 changes: 9 additions & 4 deletions rules/provider/domain_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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)
Expand Down
28 changes: 28 additions & 0 deletions rules/provider/ipcidr_strategy.go
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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
}
Expand Down Expand Up @@ -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()
}
Expand Down
33 changes: 33 additions & 0 deletions rules/provider/mrs_converter.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package provider

import (
"encoding/binary"
"io"
"os"

Expand All @@ -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
Expand Down
Loading

0 comments on commit 4f8a5a5

Please sign in to comment.