mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2024-11-14 21:31:16 +08:00
Feature: support multiport condition for rule SRC-PORT and DST-PORT
This commit is contained in:
parent
e2c7b19000
commit
56dff65149
20
README.md
20
README.md
@ -31,7 +31,7 @@
|
||||
## Getting Started
|
||||
Documentations are now moved to [GitHub Wiki](https://github.com/Dreamacro/clash/wiki).
|
||||
|
||||
## Advanced usage for this fork repository
|
||||
## Advanced usage for this fork branch
|
||||
### TUN configuration
|
||||
Support macOS Linux and Windows.
|
||||
|
||||
@ -46,25 +46,33 @@ tun:
|
||||
```
|
||||
### Rules configuration
|
||||
- Support rule `GEOSITE`
|
||||
- Support rule `GEOIP` not match condition
|
||||
- Support `multiport` condition for rule `SRC-PORT` and `DST-PORT`
|
||||
- Support not match condition for rule `GEOIP`
|
||||
- Support `network` condition for all rules
|
||||
|
||||
The `GEOSITE` and `GEOIP` databases via https://github.com/Loyalsoldier/v2ray-rules-dat
|
||||
```yaml
|
||||
rules:
|
||||
# network condition for rules
|
||||
- DOMAIN-SUFFIX,tabao.com,DIRECT,tcp
|
||||
- DST-PORT,123,DIRECT,udp
|
||||
- DOMAIN-SUFFIX,bilibili.com,DIRECT,tcp
|
||||
- DOMAIN-SUFFIX,bilibili.com,REJECT,udp
|
||||
|
||||
# multiport condition for rule SRC-PORT and DST-PORT
|
||||
- DST-PORT,123/136/137-139,DIRECT,udp
|
||||
|
||||
# rule GEOSITE
|
||||
- GEOSITE,category-ads-all,REJECT
|
||||
- GEOSITE,icloud@cn,DIRECT
|
||||
- GEOSITE,apple@cn,DIRECT
|
||||
- GEOSITE,microsoft@cn,DIRECT
|
||||
- GEOSITE,facebook,PROXY
|
||||
- GEOSITE,youtube,PROXY
|
||||
- GEOSITE,geolocation-cn,DIRECT
|
||||
- GEOSITE,gfw,PROXY
|
||||
- GEOSITE,greatfire,PROXY
|
||||
#- GEOSITE,geolocation-!cn,PROXY
|
||||
|
||||
- GEOIP,telegram,PROXY,no-resolve
|
||||
- GEOIP,private,DIRECT,no-resolve
|
||||
- GEOIP,cn,DIRECT
|
||||
|
||||
@ -76,7 +84,7 @@ rules:
|
||||
### IPTABLES auto-configuration
|
||||
Only work on Linux OS who support `iptables`, Clash will auto-configuration iptables for tproxy listener when `tproxy-port` value isn't zero.
|
||||
|
||||
When `TPROXY` is enabled, the `TUN` must be disabled.
|
||||
If `TPROXY` is enabled, the `TUN` must be disabled.
|
||||
```yaml
|
||||
# Enable the TPROXY listener
|
||||
tproxy-port: 9898
|
||||
@ -84,7 +92,7 @@ tproxy-port: 9898
|
||||
tun:
|
||||
enable: false
|
||||
```
|
||||
Create user give name `clash`, run `$ sudo useradd -M clash` in command line.
|
||||
Create user given name `clash`
|
||||
|
||||
Run Clash by user `clash` as a daemon.
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter"
|
||||
@ -433,6 +434,8 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, error) {
|
||||
rules = append(rules, parsed)
|
||||
}
|
||||
|
||||
runtime.GC()
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
_ "github.com/Dreamacro/clash/rule/geodata/standard"
|
||||
)
|
||||
|
||||
var geoIPMatcher *router.GeoIPMatcher
|
||||
var multiGeoIPMatcher *router.MultiGeoIPMatcher
|
||||
|
||||
type fallbackIPFilter interface {
|
||||
Match(net.IP) bool
|
||||
@ -19,35 +19,49 @@ type fallbackIPFilter interface {
|
||||
type geoipFilter struct{}
|
||||
|
||||
func (gf *geoipFilter) Match(ip net.IP) bool {
|
||||
if geoIPMatcher == nil {
|
||||
countryCode := "cn"
|
||||
if multiGeoIPMatcher == nil {
|
||||
countryCodeCN := "cn"
|
||||
countryCodePrivate := "private"
|
||||
geoLoader, err := geodata.GetGeoDataLoader("standard")
|
||||
if err != nil {
|
||||
log.Errorln("[GeoIPFilter] GetGeoDataLoader error: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
records, err := geoLoader.LoadGeoIP(countryCode)
|
||||
recordsCN, err := geoLoader.LoadGeoIP(countryCodeCN)
|
||||
if err != nil {
|
||||
log.Errorln("[GeoIPFilter] LoadGeoIP error: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
geoIP := &router.GeoIP{
|
||||
CountryCode: countryCode,
|
||||
Cidr: records,
|
||||
ReverseMatch: false,
|
||||
recordsPrivate, err := geoLoader.LoadGeoIP(countryCodePrivate)
|
||||
if err != nil {
|
||||
log.Errorln("[GeoIPFilter] LoadGeoIP error: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
geoIPMatcher, err = router.NewGeoIPMatcher(geoIP)
|
||||
geoips := []*router.GeoIP{
|
||||
{
|
||||
CountryCode: countryCodeCN,
|
||||
Cidr: recordsCN,
|
||||
ReverseMatch: false,
|
||||
},
|
||||
{
|
||||
CountryCode: countryCodePrivate,
|
||||
Cidr: recordsPrivate,
|
||||
ReverseMatch: false,
|
||||
},
|
||||
}
|
||||
|
||||
multiGeoIPMatcher, err = router.NewMultiGeoIPMatcher(geoips)
|
||||
|
||||
if err != nil {
|
||||
log.Errorln("[GeoIPFilter] NewGeoIPMatcher error: %s", err.Error())
|
||||
log.Errorln("[GeoIPFilter] NewMultiGeoIPMatcher error: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return !geoIPMatcher.Match(ip)
|
||||
return !multiGeoIPMatcher.ApplyIp(ip)
|
||||
}
|
||||
|
||||
type ipnetFilter struct {
|
||||
@ -61,6 +75,7 @@ func (inf *ipnetFilter) Match(ip net.IP) bool {
|
||||
type fallbackDomainFilter interface {
|
||||
Match(domain string) bool
|
||||
}
|
||||
|
||||
type domainFilter struct {
|
||||
tree *trie.DomainTrie
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ type TunDevice interface {
|
||||
}
|
||||
|
||||
func SetLinuxAutoRoute() {
|
||||
log.Infoln("Tun adapter auto setting MacOS route")
|
||||
log.Infoln("Tun adapter auto setting global route")
|
||||
addLinuxSystemRoute("1")
|
||||
addLinuxSystemRoute("2/7")
|
||||
addLinuxSystemRoute("4/6")
|
||||
@ -32,7 +32,7 @@ func SetLinuxAutoRoute() {
|
||||
}
|
||||
|
||||
func RemoveLinuxAutoRoute() {
|
||||
log.Infoln("Tun adapter removing MacOS route")
|
||||
log.Infoln("Tun adapter removing global route")
|
||||
delLinuxSystemRoute("1")
|
||||
delLinuxSystemRoute("2/7")
|
||||
delLinuxSystemRoute("4/6")
|
||||
@ -50,7 +50,7 @@ func addLinuxSystemRoute(net string) {
|
||||
}
|
||||
cmd := exec.Command("route", "add", "-net", net, "198.18.0.1")
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Errorln("[MacOS auto route] Failed to add system route: %s, cmd: %s", err.Error(), cmd.String())
|
||||
log.Errorln("[auto route] Failed to add system route: %s, cmd: %s", err.Error(), cmd.String())
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,6 +61,6 @@ func delLinuxSystemRoute(net string) {
|
||||
cmd := exec.Command("route", "delete", "-net", net, "198.18.0.1")
|
||||
_ = cmd.Run()
|
||||
//if err := cmd.Run(); err != nil {
|
||||
// log.Errorln("[MacOS auto route]Failed to delete system route: %s, cmd: %s", err.Error(), cmd.String())
|
||||
// log.Errorln("[auto route]Failed to delete system route: %s, cmd: %s", err.Error(), cmd.String())
|
||||
//}
|
||||
}
|
||||
|
73
rule/port.go
73
rule/port.go
@ -1,15 +1,23 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
||||
type portReal struct {
|
||||
portStart int
|
||||
portEnd int
|
||||
}
|
||||
|
||||
type Port struct {
|
||||
adapter string
|
||||
port string
|
||||
isSource bool
|
||||
portList []portReal
|
||||
network C.NetWork
|
||||
}
|
||||
|
||||
@ -22,9 +30,9 @@ func (p *Port) RuleType() C.RuleType {
|
||||
|
||||
func (p *Port) Match(metadata *C.Metadata) bool {
|
||||
if p.isSource {
|
||||
return metadata.SrcPort == p.port
|
||||
return p.matchPortReal(metadata.SrcPort)
|
||||
}
|
||||
return metadata.DstPort == p.port
|
||||
return p.matchPortReal(metadata.DstPort)
|
||||
}
|
||||
|
||||
func (p *Port) Adapter() string {
|
||||
@ -43,15 +51,72 @@ func (p *Port) NetWork() C.NetWork {
|
||||
return p.network
|
||||
}
|
||||
|
||||
func (p *Port) matchPortReal(portRef string) bool {
|
||||
port, _ := strconv.Atoi(portRef)
|
||||
var rs bool
|
||||
for _, pr := range p.portList {
|
||||
if pr.portEnd == -1 {
|
||||
rs = port == pr.portStart
|
||||
} else {
|
||||
rs = port >= pr.portStart && port <= pr.portEnd
|
||||
}
|
||||
if rs {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func NewPort(port string, adapter string, isSource bool, network C.NetWork) (*Port, error) {
|
||||
_, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
ports := strings.Split(port, "/")
|
||||
if len(ports) > 28 {
|
||||
return nil, fmt.Errorf("%s, too many ports to use, maximum support 28 ports", errPayload.Error())
|
||||
}
|
||||
|
||||
var portList []portReal
|
||||
for _, p := range ports {
|
||||
if p == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
subPort := strings.Split(strings.Trim(p, "[ ]"), "-")
|
||||
subPortLen := len(subPort)
|
||||
if subPortLen > 2 {
|
||||
return nil, errPayload
|
||||
}
|
||||
|
||||
portStart, err := strconv.Atoi(subPort[0])
|
||||
if err != nil || portStart < 0 || portStart > 65535 {
|
||||
return nil, errPayload
|
||||
}
|
||||
|
||||
if subPortLen == 1 {
|
||||
portList = append(portList, portReal{portStart, -1})
|
||||
|
||||
} else if subPortLen == 2 {
|
||||
portEnd, err1 := strconv.Atoi(subPort[1])
|
||||
if err1 != nil || portEnd < 0 || portEnd > 65535 {
|
||||
return nil, errPayload
|
||||
}
|
||||
|
||||
shouldReverse := portStart > portEnd
|
||||
if shouldReverse {
|
||||
portList = append(portList, portReal{portEnd, portStart})
|
||||
} else {
|
||||
portList = append(portList, portReal{portStart, portEnd})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(portList) == 0 {
|
||||
return nil, errPayload
|
||||
}
|
||||
|
||||
return &Port{
|
||||
adapter: adapter,
|
||||
port: port,
|
||||
isSource: isSource,
|
||||
portList: portList,
|
||||
network: network,
|
||||
}, nil
|
||||
}
|
||||
|
@ -35,8 +35,7 @@ var (
|
||||
|
||||
preProcessCacheFinder, _ = R.NewProcess("", "", C.ALLNet)
|
||||
|
||||
fakeIpMask = net.IPv4Mask(0, 0, 0xff, 0xff)
|
||||
fakeIpMaxIp = net.IPv4(0, 0, 255, 255)
|
||||
tunBroadcastAddr = net.IPv4(198, 18, 255, 255)
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -144,7 +143,7 @@ func preHandleMetadata(metadata *C.Metadata) error {
|
||||
// redir-host should lookup the hosts
|
||||
metadata.DstIP = node.Data.(net.IP)
|
||||
}
|
||||
} else if resolver.IsFakeIP(metadata.DstIP) && !fakeIpMaxIp.Equal(metadata.DstIP.Mask(fakeIpMask)) {
|
||||
} else if resolver.IsFakeIP(metadata.DstIP) && !tunBroadcastAddr.Equal(metadata.DstIP) {
|
||||
return fmt.Errorf("fake DNS record %s missing", metadata.DstIP)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user