mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-11-16 11:42:43 +08:00
Merge 75a7a7e463
into de19f927e8
This commit is contained in:
commit
871b725b8c
|
@ -34,6 +34,8 @@ const (
|
|||
AND
|
||||
OR
|
||||
NOT
|
||||
SrcMAC
|
||||
Schedule
|
||||
)
|
||||
|
||||
type RuleType int
|
||||
|
@ -104,6 +106,10 @@ func (rt RuleType) String() string {
|
|||
return "OR"
|
||||
case NOT:
|
||||
return "NOT"
|
||||
case SrcMAC:
|
||||
return "SrcMAC"
|
||||
case Schedule:
|
||||
return "Schedule"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
|
|
1
go.mod
1
go.mod
|
@ -90,6 +90,7 @@ require (
|
|||
github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec // indirect
|
||||
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -144,6 +144,8 @@ github.com/openacid/must v0.1.3/go.mod h1:luPiXCuJlEo3UUFQngVQokV0MPGryeYvtCbQPs
|
|||
github.com/openacid/testkeys v0.1.6/go.mod h1:MfA7cACzBpbiwekivj8StqX0WIRmqlMsci1c37CA3Do=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
|
127
rules/common/mac.go
Normal file
127
rules/common/mac.go
Normal file
|
@ -0,0 +1,127 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
"github.com/patrickmn/go-cache"
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
var lc = cache.New(5*time.Minute, 10*time.Minute)
|
||||
var arpCommand = "arp"
|
||||
var arpVar = "-a"
|
||||
|
||||
func init() {
|
||||
switch os := runtime.GOOS; os {
|
||||
case "linux":
|
||||
arpCommand = "cat"
|
||||
arpVar = "/proc/net/arp"
|
||||
case "windows":
|
||||
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
type SrcMAC struct {
|
||||
*Base
|
||||
mac string
|
||||
adapter string
|
||||
}
|
||||
|
||||
func (d *SrcMAC) RuleType() C.RuleType {
|
||||
return C.SrcMAC
|
||||
}
|
||||
|
||||
func (d *SrcMAC) Match(metadata *C.Metadata) (bool, string) {
|
||||
arpTable, err := getARPTable(false)
|
||||
if err != nil {
|
||||
log.Errorln("can't initial arp table: %s", err)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
mac, exists := arpTable[metadata.SrcIP.String()]
|
||||
if exists {
|
||||
if mac == d.mac {
|
||||
return true, d.adapter
|
||||
}
|
||||
} else {
|
||||
arpTable, err := getARPTable(true)
|
||||
if err != nil {
|
||||
log.Errorln("can't initial arp table: %s", err)
|
||||
return false, ""
|
||||
}
|
||||
mac, exists := arpTable[metadata.SrcIP.String()]
|
||||
if exists {
|
||||
if mac == d.mac {
|
||||
return true, d.adapter
|
||||
}
|
||||
} else {
|
||||
log.Errorln("can't find the IP address in arp table: %s", metadata.SrcIP.String())
|
||||
}
|
||||
}
|
||||
|
||||
return false, d.adapter
|
||||
}
|
||||
|
||||
func (d *SrcMAC) Adapter() string {
|
||||
return d.adapter
|
||||
}
|
||||
|
||||
func (d *SrcMAC) Payload() string {
|
||||
return d.mac
|
||||
}
|
||||
|
||||
func NewMAC(mac string, adapter string) *SrcMAC {
|
||||
punycode, _ := idna.ToASCII(strings.ToLower(mac))
|
||||
return &SrcMAC{
|
||||
Base: &Base{},
|
||||
mac: punycode,
|
||||
adapter: adapter,
|
||||
}
|
||||
}
|
||||
|
||||
func getARPTable(forceReload bool) (map[string]string, error) {
|
||||
|
||||
item, found := lc.Get("arpTable")
|
||||
if found && !forceReload {
|
||||
arpTable := item.(map[string]string)
|
||||
//log.Infoln("get arpTable from cache")
|
||||
return arpTable, nil
|
||||
}
|
||||
|
||||
// 执行arp命令
|
||||
cmd := exec.Command(arpCommand, arpVar)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipRegex := regexp.MustCompile(`(([0-9]{1,3}\.){3}[0-9]{1,3})`)
|
||||
macRegex := regexp.MustCompile(`(?i)(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}`)
|
||||
|
||||
// 解析arp命令的输出
|
||||
arpTable := make(map[string]string)
|
||||
lines := strings.Split(out.String(), "\n")
|
||||
for _, line := range lines {
|
||||
ip := ipRegex.FindString(line)
|
||||
mac := macRegex.FindString(line)
|
||||
|
||||
if len(ip) > 0 && len(mac) > 0 {
|
||||
punycode, _ := idna.ToASCII(strings.ToLower(mac))
|
||||
arpTable[ip] = punycode
|
||||
}
|
||||
}
|
||||
lc.Set("arpTable", arpTable, cache.DefaultExpiration)
|
||||
return arpTable, nil
|
||||
}
|
||||
|
||||
//var _ C.Rule = (*Mac)(nil)
|
117
rules/common/schedule.go
Normal file
117
rules/common/schedule.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// make sure the system has install related zoneinfo for local time zone!
|
||||
func init() {
|
||||
log.Infoln("current system time is %s", time.Now().Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
|
||||
type Schedule struct {
|
||||
*Base
|
||||
weekDayArr [7]bool
|
||||
startHour int
|
||||
startMinute int
|
||||
endHour int
|
||||
endMinute int
|
||||
schedule string
|
||||
adapter string
|
||||
}
|
||||
|
||||
func (d *Schedule) RuleType() C.RuleType {
|
||||
return C.Schedule
|
||||
}
|
||||
|
||||
func (d *Schedule) Match(metadata *C.Metadata) (bool, string) {
|
||||
now := time.Now()
|
||||
//log.Infoln("system time is %", now.Format("2006-01-02 15:04:05.000 Mon Jan"))
|
||||
if d.weekDayArr[now.Weekday()] {
|
||||
startTime := time.Date(now.Year(), now.Month(), now.Day(), d.startHour, d.startMinute, 0, 0, now.Location())
|
||||
endTime := time.Date(now.Year(), now.Month(), now.Day(), d.endHour, d.endMinute, 59, 999999999, now.Location())
|
||||
if now.After(startTime) && now.Before(endTime) {
|
||||
//log.Infoln("src ip %s in the time %d:%d~%d:%d. adapter is %s.", metadata.SrcIP.String(), d.startHour, d.startMinute, d.endHour, d.endMinute, d.adapter)
|
||||
return true, d.adapter
|
||||
}
|
||||
}
|
||||
return false, d.adapter
|
||||
}
|
||||
|
||||
func (d *Schedule) Adapter() string {
|
||||
return d.adapter
|
||||
}
|
||||
|
||||
func (d *Schedule) Payload() string {
|
||||
return d.schedule
|
||||
}
|
||||
|
||||
func NewSchedule(schedule string, adapter string) (*Schedule, error) {
|
||||
punycode, _ := idna.ToASCII(strings.ToUpper(schedule))
|
||||
weekDayArr := [7]bool{false, false, false, false, false, false, false}
|
||||
if len(punycode) != 19 {
|
||||
return nil, fmt.Errorf("could you initial Schedule rule %s, the rule format is not correct!", punycode)
|
||||
}
|
||||
if punycode[0] == 'S' {
|
||||
weekDayArr[0] = true
|
||||
}
|
||||
if punycode[1] == 'M' {
|
||||
weekDayArr[1] = true
|
||||
}
|
||||
if punycode[2] == 'T' {
|
||||
weekDayArr[2] = true
|
||||
}
|
||||
if punycode[3] == 'W' {
|
||||
weekDayArr[3] = true
|
||||
}
|
||||
if punycode[4] == 'T' {
|
||||
weekDayArr[4] = true
|
||||
}
|
||||
if punycode[5] == 'F' {
|
||||
weekDayArr[5] = true
|
||||
}
|
||||
if punycode[6] == 'S' {
|
||||
weekDayArr[6] = true
|
||||
}
|
||||
startHour, err := strconv.Atoi(punycode[8:10])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could you initial Schedule rule %s, the time format is not correct!", punycode)
|
||||
}
|
||||
startMinute, err := strconv.Atoi(punycode[11:13])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could you initial Schedule rule %s, the time format is not correct!", punycode)
|
||||
}
|
||||
endHour, err := strconv.Atoi(punycode[14:16])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could you initial Schedule rule %s, the time format is not correct!", punycode)
|
||||
}
|
||||
endMinute, err := strconv.Atoi(punycode[17:19])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could you initial Schedule rule %s, the time format is not correct!", punycode)
|
||||
}
|
||||
if startHour > endHour {
|
||||
return nil, fmt.Errorf("could you initial Schedule rule %s, the end time should not be earlier than start time!", punycode)
|
||||
}
|
||||
if startHour == endHour && startMinute > endMinute {
|
||||
return nil, fmt.Errorf("could you initial Schedule rule %s, the end time should not be earlier than start time!", punycode)
|
||||
}
|
||||
return &Schedule{
|
||||
Base: &Base{},
|
||||
weekDayArr: weekDayArr,
|
||||
startHour: startHour,
|
||||
startMinute: startMinute,
|
||||
endHour: endHour,
|
||||
endMinute: endMinute,
|
||||
schedule: punycode,
|
||||
adapter: adapter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
//var _ C.Rule = (*Schedule)(nil)
|
|
@ -6,10 +6,10 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
list "github.com/bahlo/generic-list-go"
|
||||
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/rules/common"
|
||||
|
||||
list "github.com/bahlo/generic-list-go"
|
||||
)
|
||||
|
||||
type Logic struct {
|
||||
|
|
|
@ -75,6 +75,10 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string]
|
|||
parsed, parseErr = logic.NewOR(payload, target, ParseRule)
|
||||
case "NOT":
|
||||
parsed, parseErr = logic.NewNOT(payload, target, ParseRule)
|
||||
case "SRC-MAC":
|
||||
parsed = RC.NewMAC(payload, target)
|
||||
case "SCHEDULE":
|
||||
parsed, parseErr = RC.NewSchedule(payload, target)
|
||||
case "RULE-SET":
|
||||
isSrc, noResolve := RC.ParseParams(params)
|
||||
parsed, parseErr = RP.NewRuleSet(payload, target, isSrc, noResolve)
|
||||
|
|
Loading…
Reference in New Issue
Block a user