mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-05-05 03:38:40 +00:00
Feat: sniffer exclude domain & ip
This commit is contained in:
parent
14189eba07
commit
06fc82bad1
31 changed files with 653 additions and 411 deletions
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/xtls/xray-core/common/matcher/geosite"
|
||||
)
|
||||
|
||||
func ParaseDomainRule(domain string) ([]*dm.Domain, error) {
|
||||
func ParseDomainRule(domain string) ([]*dm.Domain, error) {
|
||||
if strings.HasPrefix(domain, "geosite:") {
|
||||
country := strings.ToUpper(domain[8:])
|
||||
domains, err := geosite.LoadGeositeWithAttr("geosite.dat", country)
|
||||
|
|
60
common/matcher/domain/matcher.go
Normal file
60
common/matcher/domain/matcher.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"github.com/xtls/xray-core/common/matcher/str"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var matcherTypeMap = map[MatchingType]str.Type{
|
||||
MatchingType_Keyword: str.Substr,
|
||||
MatchingType_Regex: str.Regex,
|
||||
MatchingType_Subdomain: str.Domain,
|
||||
MatchingType_Full: str.Full,
|
||||
}
|
||||
|
||||
func domainToMatcher(domain *Domain) (str.Matcher, error) {
|
||||
matcherType, f := matcherTypeMap[domain.Type]
|
||||
if !f {
|
||||
return nil, newError("unsupported domain type", domain.Type)
|
||||
}
|
||||
|
||||
matcher, err := matcherType.New(domain.Value)
|
||||
if err != nil {
|
||||
return nil, newError("failed to create domain matcher").Base(err)
|
||||
}
|
||||
|
||||
return matcher, nil
|
||||
}
|
||||
|
||||
type DomainMatcher struct {
|
||||
matchers str.IndexMatcher
|
||||
}
|
||||
|
||||
func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
|
||||
g := new(str.MatcherGroup)
|
||||
for _, d := range domains {
|
||||
m, err := domainToMatcher(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.Add(m)
|
||||
}
|
||||
|
||||
return &DomainMatcher{
|
||||
matchers: g,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *DomainMatcher) ApplyDomain(domain string) bool {
|
||||
return len(m.matchers.Match(domain)) > 0
|
||||
}
|
||||
|
||||
// Apply implements Condition.
|
||||
func (m *DomainMatcher) Apply(ctx routing.Context) bool {
|
||||
domain := ctx.GetTargetDomain()
|
||||
if len(domain) == 0 {
|
||||
return false
|
||||
}
|
||||
return m.ApplyDomain(strings.ToLower(domain))
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
package geoip
|
||||
|
||||
import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/infra/conf/common"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
|
@ -13,7 +17,7 @@ var (
|
|||
)
|
||||
|
||||
func LoadGeoIP(code string) ([]*CIDR, error) {
|
||||
return LoadIPFile("geoip.dat", code)
|
||||
return LoadIPFile("dat", code)
|
||||
}
|
||||
|
||||
func LoadIPFile(file, code string) ([]*CIDR, error) {
|
||||
|
@ -88,3 +92,117 @@ func find(data, code []byte) []byte {
|
|||
data = data[bodyL:]
|
||||
}
|
||||
}
|
||||
|
||||
func ParaseIPList(ips common.StringList) ([]*GeoIP, error) {
|
||||
var geoipList []*GeoIP
|
||||
var customCidrs []*CIDR
|
||||
|
||||
for _, ip := range ips {
|
||||
if strings.HasPrefix(ip, "geoip:") {
|
||||
country := ip[6:]
|
||||
geoipc, err := LoadGeoIP(strings.ToUpper(country))
|
||||
if err != nil {
|
||||
return nil, newError("failed to load GeoIP: ", country).Base(err)
|
||||
}
|
||||
|
||||
geoipList = append(geoipList, &GeoIP{
|
||||
CountryCode: strings.ToUpper(country),
|
||||
Cidr: geoipc,
|
||||
})
|
||||
continue
|
||||
}
|
||||
var isExtDatFile = 0
|
||||
{
|
||||
const prefix = "ext:"
|
||||
if strings.HasPrefix(ip, prefix) {
|
||||
isExtDatFile = len(prefix)
|
||||
}
|
||||
const prefixQualified = "ext-ip:"
|
||||
if strings.HasPrefix(ip, prefixQualified) {
|
||||
isExtDatFile = len(prefixQualified)
|
||||
}
|
||||
}
|
||||
if isExtDatFile != 0 {
|
||||
kv := strings.Split(ip[isExtDatFile:], ":")
|
||||
if len(kv) != 2 {
|
||||
return nil, newError("invalid external resource: ", ip)
|
||||
}
|
||||
|
||||
filename := kv[0]
|
||||
country := kv[1]
|
||||
geoipc, err := LoadIPFile(filename, strings.ToUpper(country))
|
||||
if err != nil {
|
||||
return nil, newError("failed to load IPs: ", country, " from ", filename).Base(err)
|
||||
}
|
||||
|
||||
geoipList = append(geoipList, &GeoIP{
|
||||
CountryCode: strings.ToUpper(filename + "_" + country),
|
||||
Cidr: geoipc,
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
ipRule, err := ParseIP(ip)
|
||||
if err != nil {
|
||||
return nil, newError("invalid IP: ", ip).Base(err)
|
||||
}
|
||||
customCidrs = append(customCidrs, ipRule)
|
||||
}
|
||||
|
||||
if len(customCidrs) > 0 {
|
||||
geoipList = append(geoipList, &GeoIP{
|
||||
Cidr: customCidrs,
|
||||
})
|
||||
}
|
||||
|
||||
return geoipList, nil
|
||||
}
|
||||
|
||||
func ParseIP(s string) (*CIDR, error) {
|
||||
var addr, mask string
|
||||
i := strings.Index(s, "/")
|
||||
if i < 0 {
|
||||
addr = s
|
||||
} else {
|
||||
addr = s[:i]
|
||||
mask = s[i+1:]
|
||||
}
|
||||
ip := net.ParseAddress(addr)
|
||||
switch ip.Family() {
|
||||
case net.AddressFamilyIPv4:
|
||||
bits := uint32(32)
|
||||
if len(mask) > 0 {
|
||||
bits64, err := strconv.ParseUint(mask, 10, 32)
|
||||
if err != nil {
|
||||
return nil, newError("invalid network mask for router: ", mask).Base(err)
|
||||
}
|
||||
bits = uint32(bits64)
|
||||
}
|
||||
if bits > 32 {
|
||||
return nil, newError("invalid network mask for router: ", bits)
|
||||
}
|
||||
return &CIDR{
|
||||
Ip: ip.IP(),
|
||||
Prefix: bits,
|
||||
}, nil
|
||||
case net.AddressFamilyIPv6:
|
||||
bits := uint32(128)
|
||||
if len(mask) > 0 {
|
||||
bits64, err := strconv.ParseUint(mask, 10, 32)
|
||||
if err != nil {
|
||||
return nil, newError("invalid network mask for router: ", mask).Base(err)
|
||||
}
|
||||
bits = uint32(bits64)
|
||||
}
|
||||
if bits > 128 {
|
||||
return nil, newError("invalid network mask for router: ", bits)
|
||||
}
|
||||
return &CIDR{
|
||||
Ip: ip.IP(),
|
||||
Prefix: bits,
|
||||
}, nil
|
||||
default:
|
||||
return nil, newError("unsupported address for router: ", s)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,3 +45,13 @@ func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MatchIP match given ip.
|
||||
func (m *MultiGeoIPMatcher) MatchIP(ip net.IP) bool {
|
||||
for _, matcher := range m.matchers {
|
||||
if matcher.Match(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package session // import "github.com/xtls/xray-core/common/session"
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/xtls/xray-core/common/matcher/domain"
|
||||
"github.com/xtls/xray-core/common/matcher/geoip"
|
||||
"math/rand"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
|
@ -60,7 +62,8 @@ type Outbound struct {
|
|||
|
||||
// SniffingRequest controls the behavior of content sniffing.
|
||||
type SniffingRequest struct {
|
||||
ExcludeForDomain []string
|
||||
ExcludedDomainMatcher *domain.DomainMatcher
|
||||
ExcludedIPMatcher *geoip.MultiGeoIPMatcher
|
||||
OverrideDestinationForProtocol []string
|
||||
Enabled bool
|
||||
MetadataOnly bool
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue