Feature: add source ipcidr condition for all rules
This commit is contained in:
parent
92396fc893
commit
66d9aab6cc
14 changed files with 155 additions and 93 deletions
|
@ -52,5 +52,5 @@ type Rule interface {
|
|||
Adapter() string
|
||||
Payload() string
|
||||
ShouldResolveIP() bool
|
||||
NetWork() NetWork
|
||||
RuleExtra() *RuleExtra
|
||||
}
|
||||
|
|
25
constant/rule_extra.go
Normal file
25
constant/rule_extra.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package constant
|
||||
|
||||
import "net"
|
||||
|
||||
type RuleExtra struct {
|
||||
Network NetWork
|
||||
SourceIPs []*net.IPNet
|
||||
}
|
||||
|
||||
func (re *RuleExtra) NotMatchNetwork(network NetWork) bool {
|
||||
return re.Network != ALLNet && re.Network != network
|
||||
}
|
||||
|
||||
func (re *RuleExtra) NotMatchSourceIP(srcIP net.IP) bool {
|
||||
if re.SourceIPs == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, ips := range re.SourceIPs {
|
||||
if ips.Contains(srcIP) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
24
rule/base.go
24
rule/base.go
|
@ -2,6 +2,8 @@ package rules
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
@ -14,6 +16,7 @@ var (
|
|||
|
||||
func HasNoResolve(params []string) bool {
|
||||
for _, p := range params {
|
||||
p = strings.Trim(p, " ")
|
||||
if p == noResolve {
|
||||
return true
|
||||
}
|
||||
|
@ -23,6 +26,7 @@ func HasNoResolve(params []string) bool {
|
|||
|
||||
func findNetwork(params []string) C.NetWork {
|
||||
for _, p := range params {
|
||||
p = strings.Trim(p, " ")
|
||||
if p == "tcp" {
|
||||
return C.TCP
|
||||
} else if p == "udp" {
|
||||
|
@ -31,3 +35,23 @@ func findNetwork(params []string) C.NetWork {
|
|||
}
|
||||
return C.ALLNet
|
||||
}
|
||||
|
||||
func findSourceIPs(params []string) []*net.IPNet {
|
||||
var ips []*net.IPNet
|
||||
for _, p := range params {
|
||||
p = strings.Trim(p, " ")
|
||||
if p == noResolve || len(p) < 7 {
|
||||
continue
|
||||
}
|
||||
_, ipnet, err := net.ParseCIDR(p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
ips = append(ips, ipnet)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
return ips
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ import (
|
|||
)
|
||||
|
||||
type Domain struct {
|
||||
domain string
|
||||
adapter string
|
||||
network C.NetWork
|
||||
domain string
|
||||
adapter string
|
||||
ruleExtra *C.RuleExtra
|
||||
}
|
||||
|
||||
func (d *Domain) RuleType() C.RuleType {
|
||||
|
@ -35,14 +35,14 @@ func (d *Domain) ShouldResolveIP() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (d *Domain) NetWork() C.NetWork {
|
||||
return d.network
|
||||
func (d *Domain) RuleExtra() *C.RuleExtra {
|
||||
return d.ruleExtra
|
||||
}
|
||||
|
||||
func NewDomain(domain string, adapter string, network C.NetWork) *Domain {
|
||||
func NewDomain(domain string, adapter string, ruleExtra *C.RuleExtra) *Domain {
|
||||
return &Domain{
|
||||
domain: strings.ToLower(domain),
|
||||
adapter: adapter,
|
||||
network: network,
|
||||
domain: strings.ToLower(domain),
|
||||
adapter: adapter,
|
||||
ruleExtra: ruleExtra,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ import (
|
|||
)
|
||||
|
||||
type DomainKeyword struct {
|
||||
keyword string
|
||||
adapter string
|
||||
network C.NetWork
|
||||
keyword string
|
||||
adapter string
|
||||
ruleExtra *C.RuleExtra
|
||||
}
|
||||
|
||||
func (dk *DomainKeyword) RuleType() C.RuleType {
|
||||
|
@ -36,14 +36,14 @@ func (dk *DomainKeyword) ShouldResolveIP() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (dk *DomainKeyword) NetWork() C.NetWork {
|
||||
return dk.network
|
||||
func (dk *DomainKeyword) RuleExtra() *C.RuleExtra {
|
||||
return dk.ruleExtra
|
||||
}
|
||||
|
||||
func NewDomainKeyword(keyword string, adapter string, network C.NetWork) *DomainKeyword {
|
||||
func NewDomainKeyword(keyword string, adapter string, ruleExtra *C.RuleExtra) *DomainKeyword {
|
||||
return &DomainKeyword{
|
||||
keyword: strings.ToLower(keyword),
|
||||
adapter: adapter,
|
||||
network: network,
|
||||
keyword: strings.ToLower(keyword),
|
||||
adapter: adapter,
|
||||
ruleExtra: ruleExtra,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ import (
|
|||
)
|
||||
|
||||
type DomainSuffix struct {
|
||||
suffix string
|
||||
adapter string
|
||||
network C.NetWork
|
||||
suffix string
|
||||
adapter string
|
||||
ruleExtra *C.RuleExtra
|
||||
}
|
||||
|
||||
func (ds *DomainSuffix) RuleType() C.RuleType {
|
||||
|
@ -36,14 +36,14 @@ func (ds *DomainSuffix) ShouldResolveIP() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (ds *DomainSuffix) NetWork() C.NetWork {
|
||||
return ds.network
|
||||
func (ds *DomainSuffix) RuleExtra() *C.RuleExtra {
|
||||
return ds.ruleExtra
|
||||
}
|
||||
|
||||
func NewDomainSuffix(suffix string, adapter string, network C.NetWork) *DomainSuffix {
|
||||
func NewDomainSuffix(suffix string, adapter string, ruleExtra *C.RuleExtra) *DomainSuffix {
|
||||
return &DomainSuffix{
|
||||
suffix: strings.ToLower(suffix),
|
||||
adapter: adapter,
|
||||
network: network,
|
||||
suffix: strings.ToLower(suffix),
|
||||
adapter: adapter,
|
||||
ruleExtra: ruleExtra,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ func (f *Match) ShouldResolveIP() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (f *Match) NetWork() C.NetWork {
|
||||
return C.ALLNet
|
||||
func (f *Match) RuleExtra() *C.RuleExtra {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewMatch(adapter string) *Match {
|
||||
|
|
|
@ -15,7 +15,7 @@ type GEOIP struct {
|
|||
country string
|
||||
adapter string
|
||||
noResolveIP bool
|
||||
network C.NetWork
|
||||
ruleExtra *C.RuleExtra
|
||||
geoIPMatcher *router.GeoIPMatcher
|
||||
}
|
||||
|
||||
|
@ -43,11 +43,11 @@ func (g *GEOIP) ShouldResolveIP() bool {
|
|||
return !g.noResolveIP
|
||||
}
|
||||
|
||||
func (g *GEOIP) NetWork() C.NetWork {
|
||||
return g.network
|
||||
func (g *GEOIP) RuleExtra() *C.RuleExtra {
|
||||
return g.ruleExtra
|
||||
}
|
||||
|
||||
func NewGEOIP(country string, adapter string, noResolveIP bool, network C.NetWork) (*GEOIP, error) {
|
||||
func NewGEOIP(country string, adapter string, noResolveIP bool, ruleExtra *C.RuleExtra) (*GEOIP, error) {
|
||||
geoLoaderName := "standard"
|
||||
//geoLoaderName := "memconservative"
|
||||
geoLoader, err := geodata.GetGeoDataLoader(geoLoaderName)
|
||||
|
@ -78,7 +78,7 @@ func NewGEOIP(country string, adapter string, noResolveIP bool, network C.NetWor
|
|||
country: country,
|
||||
adapter: adapter,
|
||||
noResolveIP: noResolveIP,
|
||||
network: network,
|
||||
ruleExtra: ruleExtra,
|
||||
geoIPMatcher: geoIPMatcher,
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,10 @@ import (
|
|||
)
|
||||
|
||||
type GEOSITE struct {
|
||||
country string
|
||||
adapter string
|
||||
network C.NetWork
|
||||
matcher *router.DomainMatcher
|
||||
country string
|
||||
adapter string
|
||||
ruleExtra *C.RuleExtra
|
||||
matcher *router.DomainMatcher
|
||||
}
|
||||
|
||||
func (gs *GEOSITE) RuleType() C.RuleType {
|
||||
|
@ -43,11 +43,11 @@ func (gs *GEOSITE) ShouldResolveIP() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (gs *GEOSITE) NetWork() C.NetWork {
|
||||
return gs.network
|
||||
func (gs *GEOSITE) RuleExtra() *C.RuleExtra {
|
||||
return gs.ruleExtra
|
||||
}
|
||||
|
||||
func NewGEOSITE(country string, adapter string, network C.NetWork) (*GEOSITE, error) {
|
||||
func NewGEOSITE(country string, adapter string, ruleExtra *C.RuleExtra) (*GEOSITE, error) {
|
||||
geoLoaderName := "standard"
|
||||
//geoLoaderName := "memconservative"
|
||||
geoLoader, err := geodata.GetGeoDataLoader(geoLoaderName)
|
||||
|
@ -72,10 +72,10 @@ func NewGEOSITE(country string, adapter string, network C.NetWork) (*GEOSITE, er
|
|||
log.Infoln("Start initial GeoSite rule %s => %s, records: %d", country, adapter, len(domains))
|
||||
|
||||
geoSite := &GEOSITE{
|
||||
country: country,
|
||||
adapter: adapter,
|
||||
network: network,
|
||||
matcher: matcher,
|
||||
country: country,
|
||||
adapter: adapter,
|
||||
ruleExtra: ruleExtra,
|
||||
matcher: matcher,
|
||||
}
|
||||
|
||||
return geoSite, nil
|
||||
|
|
|
@ -23,7 +23,7 @@ func WithIPCIDRNoResolve(noResolve bool) IPCIDROption {
|
|||
type IPCIDR struct {
|
||||
ipnet *net.IPNet
|
||||
adapter string
|
||||
network C.NetWork
|
||||
ruleExtra *C.RuleExtra
|
||||
isSourceIP bool
|
||||
noResolveIP bool
|
||||
}
|
||||
|
@ -55,20 +55,20 @@ func (i *IPCIDR) ShouldResolveIP() bool {
|
|||
return !i.noResolveIP
|
||||
}
|
||||
|
||||
func (i *IPCIDR) NetWork() C.NetWork {
|
||||
return i.network
|
||||
func (i *IPCIDR) RuleExtra() *C.RuleExtra {
|
||||
return i.ruleExtra
|
||||
}
|
||||
|
||||
func NewIPCIDR(s string, adapter string, network C.NetWork, opts ...IPCIDROption) (*IPCIDR, error) {
|
||||
func NewIPCIDR(s string, adapter string, ruleExtra *C.RuleExtra, opts ...IPCIDROption) (*IPCIDR, error) {
|
||||
_, ipnet, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
return nil, errPayload
|
||||
}
|
||||
|
||||
ruleExtra.SourceIPs = nil
|
||||
ipcidr := &IPCIDR{
|
||||
ipnet: ipnet,
|
||||
adapter: adapter,
|
||||
network: network,
|
||||
ipnet: ipnet,
|
||||
adapter: adapter,
|
||||
ruleExtra: ruleExtra,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
|
|
|
@ -10,32 +10,36 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
|||
var (
|
||||
parseErr error
|
||||
parsed C.Rule
|
||||
network = findNetwork(params)
|
||||
)
|
||||
|
||||
ruleExtra := &C.RuleExtra{
|
||||
Network: findNetwork(params),
|
||||
SourceIPs: findSourceIPs(params),
|
||||
}
|
||||
|
||||
switch tp {
|
||||
case "DOMAIN":
|
||||
parsed = NewDomain(payload, target, network)
|
||||
parsed = NewDomain(payload, target, ruleExtra)
|
||||
case "DOMAIN-SUFFIX":
|
||||
parsed = NewDomainSuffix(payload, target, network)
|
||||
parsed = NewDomainSuffix(payload, target, ruleExtra)
|
||||
case "DOMAIN-KEYWORD":
|
||||
parsed = NewDomainKeyword(payload, target, network)
|
||||
parsed = NewDomainKeyword(payload, target, ruleExtra)
|
||||
case "GEOSITE":
|
||||
parsed, parseErr = NewGEOSITE(payload, target, network)
|
||||
parsed, parseErr = NewGEOSITE(payload, target, ruleExtra)
|
||||
case "GEOIP":
|
||||
noResolve := HasNoResolve(params)
|
||||
parsed, parseErr = NewGEOIP(payload, target, noResolve, network)
|
||||
parsed, parseErr = NewGEOIP(payload, target, noResolve, ruleExtra)
|
||||
case "IP-CIDR", "IP-CIDR6":
|
||||
noResolve := HasNoResolve(params)
|
||||
parsed, parseErr = NewIPCIDR(payload, target, network, WithIPCIDRNoResolve(noResolve))
|
||||
parsed, parseErr = NewIPCIDR(payload, target, ruleExtra, WithIPCIDRNoResolve(noResolve))
|
||||
case "SRC-IP-CIDR":
|
||||
parsed, parseErr = NewIPCIDR(payload, target, network, WithIPCIDRSourceIP(true), WithIPCIDRNoResolve(true))
|
||||
parsed, parseErr = NewIPCIDR(payload, target, ruleExtra, WithIPCIDRSourceIP(true), WithIPCIDRNoResolve(true))
|
||||
case "SRC-PORT":
|
||||
parsed, parseErr = NewPort(payload, target, true, network)
|
||||
parsed, parseErr = NewPort(payload, target, true, ruleExtra)
|
||||
case "DST-PORT":
|
||||
parsed, parseErr = NewPort(payload, target, false, network)
|
||||
parsed, parseErr = NewPort(payload, target, false, ruleExtra)
|
||||
case "PROCESS-NAME":
|
||||
parsed, parseErr = NewProcess(payload, target, network)
|
||||
parsed, parseErr = NewProcess(payload, target, ruleExtra)
|
||||
case "MATCH":
|
||||
parsed = NewMatch(target)
|
||||
default:
|
||||
|
|
26
rule/port.go
26
rule/port.go
|
@ -14,11 +14,11 @@ type portReal struct {
|
|||
}
|
||||
|
||||
type Port struct {
|
||||
adapter string
|
||||
port string
|
||||
isSource bool
|
||||
portList []portReal
|
||||
network C.NetWork
|
||||
adapter string
|
||||
port string
|
||||
isSource bool
|
||||
portList []portReal
|
||||
ruleExtra *C.RuleExtra
|
||||
}
|
||||
|
||||
func (p *Port) RuleType() C.RuleType {
|
||||
|
@ -47,8 +47,8 @@ func (p *Port) ShouldResolveIP() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (p *Port) NetWork() C.NetWork {
|
||||
return p.network
|
||||
func (p *Port) RuleExtra() *C.RuleExtra {
|
||||
return p.ruleExtra
|
||||
}
|
||||
|
||||
func (p *Port) matchPortReal(portRef string) bool {
|
||||
|
@ -67,7 +67,7 @@ func (p *Port) matchPortReal(portRef string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func NewPort(port string, adapter string, isSource bool, network C.NetWork) (*Port, error) {
|
||||
func NewPort(port string, adapter string, isSource bool, ruleExtra *C.RuleExtra) (*Port, error) {
|
||||
//the port format should be like this: "123/136/137-139" or "[123]/[136-139]"
|
||||
ports := strings.Split(port, "/")
|
||||
if len(ports) > 28 {
|
||||
|
@ -114,10 +114,10 @@ func NewPort(port string, adapter string, isSource bool, network C.NetWork) (*Po
|
|||
}
|
||||
|
||||
return &Port{
|
||||
adapter: adapter,
|
||||
port: port,
|
||||
isSource: isSource,
|
||||
portList: portList,
|
||||
network: network,
|
||||
adapter: adapter,
|
||||
port: port,
|
||||
isSource: isSource,
|
||||
portList: portList,
|
||||
ruleExtra: ruleExtra,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ import (
|
|||
var processCache = cache.NewLRUCache(cache.WithAge(2), cache.WithSize(64))
|
||||
|
||||
type Process struct {
|
||||
adapter string
|
||||
process string
|
||||
network C.NetWork
|
||||
adapter string
|
||||
process string
|
||||
ruleExtra *C.RuleExtra
|
||||
}
|
||||
|
||||
func (ps *Process) RuleType() C.RuleType {
|
||||
|
@ -71,14 +71,14 @@ func (ps *Process) ShouldResolveIP() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (ps *Process) NetWork() C.NetWork {
|
||||
return ps.network
|
||||
func (ps *Process) RuleExtra() *C.RuleExtra {
|
||||
return ps.ruleExtra
|
||||
}
|
||||
|
||||
func NewProcess(process string, adapter string, network C.NetWork) (*Process, error) {
|
||||
func NewProcess(process string, adapter string, ruleExtra *C.RuleExtra) (*Process, error) {
|
||||
return &Process{
|
||||
adapter: adapter,
|
||||
process: process,
|
||||
network: network,
|
||||
adapter: adapter,
|
||||
process: process,
|
||||
ruleExtra: ruleExtra,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ var (
|
|||
// default timeout for UDP session
|
||||
udpTimeout = 60 * time.Second
|
||||
|
||||
preProcessCacheFinder, _ = R.NewProcess("", "", C.ALLNet)
|
||||
preProcessCacheFinder, _ = R.NewProcess("", "", nil)
|
||||
|
||||
tunBroadcastAddr = net.IPv4(198, 18, 255, 255)
|
||||
)
|
||||
|
@ -235,7 +235,7 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
|
|||
|
||||
switch true {
|
||||
case rule != nil:
|
||||
log.Infoln("[UDP] %s(%s) --> %s:%s match %s(%s) %s using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), metadata.DstPort, rule.RuleType().String(), rule.Payload(), rule.NetWork().String(), rawPc.Chains().String())
|
||||
log.Infoln("[UDP] %s(%s) --> %s:%s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), metadata.DstPort, rule.RuleType().String(), rule.Payload(), rawPc.Chains().String())
|
||||
case mode == Global:
|
||||
log.Infoln("[UDP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
||||
case mode == Direct:
|
||||
|
@ -285,7 +285,7 @@ func handleTCPConn(ctx C.ConnContext) {
|
|||
|
||||
switch true {
|
||||
case rule != nil:
|
||||
log.Infoln("[TCP] %s(%s) --> %s:%s match %s(%s) %s using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), metadata.DstPort, rule.RuleType().String(), rule.Payload(), rule.NetWork().String(), remoteConn.Chains().String())
|
||||
log.Infoln("[TCP] %s(%s) --> %s:%s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), metadata.DstPort, rule.RuleType().String(), rule.Payload(), remoteConn.Chains().String())
|
||||
case mode == Global:
|
||||
log.Infoln("[TCP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
||||
case mode == Direct:
|
||||
|
@ -339,12 +339,21 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
if rule.NetWork() != C.ALLNet && rule.NetWork() != metadata.NetWork {
|
||||
continue
|
||||
extra := rule.RuleExtra()
|
||||
if extra != nil {
|
||||
if extra.NotMatchNetwork(metadata.NetWork) {
|
||||
continue
|
||||
}
|
||||
|
||||
if extra.NotMatchSourceIP(metadata.SrcIP) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return adapter, rule, nil
|
||||
}
|
||||
}
|
||||
|
||||
return proxies["DIRECT"], nil, nil
|
||||
//return proxies["DIRECT"], nil, nil
|
||||
return proxies["REJECT"], nil, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue