mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-22 22:58:03 +03:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20cf00c271 | ||
|
|
c180c5980c | ||
|
|
5b849d51a9 | ||
|
|
61e1153157 | ||
|
|
afcfdbca70 | ||
|
|
2c92339f95 | ||
|
|
9c46a2d55a | ||
|
|
19186edfa1 | ||
|
|
f6a7e93923 | ||
|
|
077070dbe0 | ||
|
|
c3af657c0e | ||
|
|
9a04eecaf9 | ||
|
|
1951a278ac | ||
|
|
f1aee0b7c5 | ||
|
|
5173e5c15d | ||
|
|
daf9cba29f | ||
|
|
445c0d456c | ||
|
|
0a42dba13e | ||
|
|
cd8aab9544 | ||
|
|
59dc2cee2e | ||
|
|
5846f94784 | ||
|
|
e0ee2350fc | ||
|
|
48164c8267 | ||
|
|
2d2102f654 | ||
|
|
262770564f | ||
|
|
777e31302c | ||
|
|
30d6a5221b | ||
|
|
a778d3d273 | ||
|
|
e813a3744f | ||
|
|
66628943d8 |
@@ -95,11 +95,12 @@
|
||||
## GUI Clients
|
||||
|
||||
- OpenWrt
|
||||
- [PassWall](https://github.com/xiaorouji/openwrt-passwall), [PassWall 2](https://github.com/xiaorouji/openwrt-passwall2)
|
||||
- [PassWall](https://github.com/Openwrt-Passwall/openwrt-passwall), [PassWall 2](https://github.com/Openwrt-Passwall/openwrt-passwall2)
|
||||
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
|
||||
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
|
||||
- Asuswrt-Merlin
|
||||
- [XRAYUI](https://github.com/DanielLavrushin/asuswrt-merlin-xrayui)
|
||||
- [fancyss](https://github.com/hq450/fancyss)
|
||||
- Windows
|
||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
@@ -137,6 +138,8 @@
|
||||
- iOS & macOS arm64 & tvOS
|
||||
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
||||
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
||||
- [Egern](https://apps.apple.com/us/app/egern/id1616105820)
|
||||
- [Quantumult X](https://apps.apple.com/us/app/quantumult-x/id1443988620)
|
||||
- Xray Tools
|
||||
- [xray-knife](https://github.com/lilendian0x00/xray-knife)
|
||||
- [xray-checker](https://github.com/kutovoys/xray-checker)
|
||||
|
||||
+27
-3
@@ -12,9 +12,11 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/strmatcher"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
@@ -83,9 +85,31 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
return nil, errors.New("unexpected query strategy ", config.QueryStrategy)
|
||||
}
|
||||
|
||||
hosts, err := NewStaticHosts(config.StaticHosts)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to create hosts").Base(err)
|
||||
var hosts *StaticHosts
|
||||
mphLoaded := false
|
||||
domainMatcherPath := platform.NewEnvFlag(platform.MphCachePath).GetValue(func() string { return "" })
|
||||
if domainMatcherPath != "" {
|
||||
if f, err := os.Open(domainMatcherPath); err == nil {
|
||||
defer f.Close()
|
||||
if m, err := router.LoadGeoSiteMatcher(f, "HOSTS"); err == nil {
|
||||
f.Seek(0, 0)
|
||||
if hostIPs, err := router.LoadGeoSiteHosts(f); err == nil {
|
||||
if sh, err := NewStaticHostsFromCache(m, hostIPs); err == nil {
|
||||
hosts = sh
|
||||
mphLoaded = true
|
||||
errors.LogDebug(ctx, "MphDomainMatcher loaded from cache for DNS hosts, size: ", sh.matchers.Size())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !mphLoaded {
|
||||
sh, err := NewStaticHosts(config.StaticHosts)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to create hosts").Base(err)
|
||||
}
|
||||
hosts = sh
|
||||
}
|
||||
|
||||
var clients []*Client
|
||||
|
||||
+52
-2
@@ -2,6 +2,7 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
@@ -13,7 +14,7 @@ import (
|
||||
// StaticHosts represents static domain-ip mapping in DNS server.
|
||||
type StaticHosts struct {
|
||||
ips [][]net.Address
|
||||
matchers *strmatcher.MatcherGroup
|
||||
matchers strmatcher.IndexMatcher
|
||||
}
|
||||
|
||||
// NewStaticHosts creates a new StaticHosts instance.
|
||||
@@ -24,7 +25,9 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
||||
matchers: g,
|
||||
}
|
||||
|
||||
for _, mapping := range hosts {
|
||||
defer runtime.GC()
|
||||
for i, mapping := range hosts {
|
||||
hosts[i] = nil
|
||||
matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(context.Background(), err, "failed to create domain matcher, ignore domain rule [type: ", mapping.Type, ", domain: ", mapping.Domain, "]")
|
||||
@@ -121,3 +124,50 @@ func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) (
|
||||
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) ([]net.Address, error) {
|
||||
return h.lookup(domain, option, 5)
|
||||
}
|
||||
func NewStaticHostsFromCache(matcher strmatcher.IndexMatcher, hostIPs map[string][]string) (*StaticHosts, error) {
|
||||
sh := &StaticHosts{
|
||||
ips: make([][]net.Address, matcher.Size()+1),
|
||||
matchers: matcher,
|
||||
}
|
||||
|
||||
order := hostIPs["_ORDER"]
|
||||
var offset uint32
|
||||
|
||||
img, ok := matcher.(*strmatcher.IndexMatcherGroup)
|
||||
if !ok {
|
||||
// Single matcher (e.g. only manual or only one geosite)
|
||||
if len(order) > 0 {
|
||||
pattern := order[0]
|
||||
ips := parseIPs(hostIPs[pattern])
|
||||
for i := uint32(1); i <= matcher.Size(); i++ {
|
||||
sh.ips[i] = ips
|
||||
}
|
||||
}
|
||||
return sh, nil
|
||||
}
|
||||
|
||||
for i, m := range img.Matchers {
|
||||
if i < len(order) {
|
||||
pattern := order[i]
|
||||
ips := parseIPs(hostIPs[pattern])
|
||||
for j := uint32(1); j <= m.Size(); j++ {
|
||||
sh.ips[offset+j] = ips
|
||||
}
|
||||
offset += m.Size()
|
||||
}
|
||||
}
|
||||
return sh, nil
|
||||
}
|
||||
|
||||
func parseIPs(raw []string) []net.Address {
|
||||
addrs := make([]net.Address, 0, len(raw))
|
||||
for _, s := range raw {
|
||||
if len(s) > 1 && s[0] == '#' {
|
||||
rcode, _ := strconv.Atoi(s[1:])
|
||||
addrs = append(addrs, dns.RCodeError(rcode))
|
||||
} else {
|
||||
addrs = append(addrs, net.ParseAddress(s))
|
||||
}
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package dns_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
. "github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
@@ -130,3 +132,57 @@ func TestStaticHosts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestStaticHostsFromCache(t *testing.T) {
|
||||
sites := []*router.GeoSite{
|
||||
{
|
||||
CountryCode: "cloudflare-dns.com",
|
||||
Domain: []*router.Domain{
|
||||
{Type: router.Domain_Full, Value: "example.com"},
|
||||
},
|
||||
},
|
||||
{
|
||||
CountryCode: "geosite:cn",
|
||||
Domain: []*router.Domain{
|
||||
{Type: router.Domain_Domain, Value: "baidu.cn"},
|
||||
},
|
||||
},
|
||||
}
|
||||
deps := map[string][]string{
|
||||
"HOSTS": {"cloudflare-dns.com", "geosite:cn"},
|
||||
}
|
||||
hostIPs := map[string][]string{
|
||||
"cloudflare-dns.com": {"1.1.1.1"},
|
||||
"geosite:cn": {"2.2.2.2"},
|
||||
"_ORDER": {"cloudflare-dns.com", "geosite:cn"},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := router.SerializeGeoSiteList(sites, deps, hostIPs, &buf)
|
||||
common.Must(err)
|
||||
|
||||
// Load matcher
|
||||
m, err := router.LoadGeoSiteMatcher(bytes.NewReader(buf.Bytes()), "HOSTS")
|
||||
common.Must(err)
|
||||
|
||||
// Load hostIPs
|
||||
f := bytes.NewReader(buf.Bytes())
|
||||
hips, err := router.LoadGeoSiteHosts(f)
|
||||
common.Must(err)
|
||||
|
||||
hosts, err := NewStaticHostsFromCache(m, hips)
|
||||
common.Must(err)
|
||||
|
||||
{
|
||||
ips, _ := hosts.Lookup("example.com", dns.IPOption{IPv4Enable: true})
|
||||
if len(ips) != 1 || ips[0].String() != "1.1.1.1" {
|
||||
t.Error("failed to lookup example.com from cache")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ips, _ := hosts.Lookup("baidu.cn", dns.IPOption{IPv4Enable: true})
|
||||
if len(ips) != 1 || ips[0].String() != "2.2.2.2" {
|
||||
t.Error("failed to lookup baidu.cn from cache deps")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+61
-18
@@ -3,12 +3,15 @@ package dns
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/strmatcher"
|
||||
"github.com/xtls/xray-core/core"
|
||||
@@ -16,6 +19,18 @@ import (
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
)
|
||||
|
||||
type mphMatcherWrapper struct {
|
||||
m strmatcher.IndexMatcher
|
||||
}
|
||||
|
||||
func (w *mphMatcherWrapper) Match(s string) bool {
|
||||
return w.m.Match(s) != nil
|
||||
}
|
||||
|
||||
func (w *mphMatcherWrapper) String() string {
|
||||
return "mph-matcher"
|
||||
}
|
||||
|
||||
// Server is the interface for Name Server.
|
||||
type Server interface {
|
||||
// Name of the Client.
|
||||
@@ -131,29 +146,53 @@ func NewClient(
|
||||
var rules []string
|
||||
ruleCurr := 0
|
||||
ruleIter := 0
|
||||
for _, domain := range ns.PrioritizedDomain {
|
||||
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to create domain matcher, ignore domain rule [type: ", domain.Type, ", domain: ", domain.Domain, "]")
|
||||
domainRule, _ = toStrMatcher(DomainMatchingType_Full, "hack.fix.index.for.illegal.domain.rule")
|
||||
}
|
||||
originalRuleIdx := ruleCurr
|
||||
if ruleCurr < len(ns.OriginalRules) {
|
||||
rule := ns.OriginalRules[ruleCurr]
|
||||
if ruleCurr >= len(rules) {
|
||||
rules = append(rules, rule.Rule)
|
||||
|
||||
// Check if domain matcher cache is provided via environment
|
||||
domainMatcherPath := platform.NewEnvFlag(platform.MphCachePath).GetValue(func() string { return "" })
|
||||
var mphLoaded bool
|
||||
|
||||
if domainMatcherPath != "" && ns.Tag != "" {
|
||||
f, err := filesystem.NewFileReader(domainMatcherPath)
|
||||
if err == nil {
|
||||
defer f.Close()
|
||||
g, err := router.LoadGeoSiteMatcher(f, ns.Tag)
|
||||
if err == nil {
|
||||
errors.LogDebug(ctx, "MphDomainMatcher loaded from cache for ", ns.Tag, " dns tag)")
|
||||
updateDomainRule(&mphMatcherWrapper{m: g}, 0, *matcherInfos)
|
||||
rules = append(rules, "[MPH Cache]")
|
||||
mphLoaded = true
|
||||
}
|
||||
ruleIter++
|
||||
if ruleIter >= int(rule.Size) {
|
||||
ruleIter = 0
|
||||
}
|
||||
}
|
||||
|
||||
if !mphLoaded {
|
||||
for i, domain := range ns.PrioritizedDomain {
|
||||
ns.PrioritizedDomain[i] = nil
|
||||
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to create domain matcher, ignore domain rule [type: ", domain.Type, ", domain: ", domain.Domain, "]")
|
||||
domainRule, _ = toStrMatcher(DomainMatchingType_Full, "hack.fix.index.for.illegal.domain.rule")
|
||||
}
|
||||
originalRuleIdx := ruleCurr
|
||||
if ruleCurr < len(ns.OriginalRules) {
|
||||
rule := ns.OriginalRules[ruleCurr]
|
||||
if ruleCurr >= len(rules) {
|
||||
rules = append(rules, rule.Rule)
|
||||
}
|
||||
ruleIter++
|
||||
if ruleIter >= int(rule.Size) {
|
||||
ruleIter = 0
|
||||
ruleCurr++
|
||||
}
|
||||
} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)
|
||||
rules = append(rules, domainRule.String())
|
||||
ruleCurr++
|
||||
}
|
||||
} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)
|
||||
rules = append(rules, domainRule.String())
|
||||
ruleCurr++
|
||||
updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
|
||||
}
|
||||
updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
|
||||
}
|
||||
ns.PrioritizedDomain = nil
|
||||
runtime.GC()
|
||||
|
||||
// Establish expected IPs
|
||||
var expectedMatcher router.GeoIPMatcher
|
||||
@@ -162,6 +201,8 @@ func NewClient(
|
||||
if err != nil {
|
||||
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
||||
}
|
||||
ns.ExpectedGeoip = nil
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
// Establish unexpected IPs
|
||||
@@ -171,6 +212,8 @@ func NewClient(
|
||||
if err != nil {
|
||||
return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning()
|
||||
}
|
||||
ns.UnexpectedGeoip = nil
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
if len(clientIP) > 0 {
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
utls "github.com/refraction-networking/utls"
|
||||
@@ -20,6 +19,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
@@ -214,8 +214,7 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
||||
|
||||
req.Header.Add("Accept", "application/dns-message")
|
||||
req.Header.Add("Content-Type", "application/dns-message")
|
||||
|
||||
req.Header.Set("X-Padding", strings.Repeat("X", int(crypto.RandBetween(100, 1000))))
|
||||
req.Header.Set("X-Padding", utils.H2Base62Pad(crypto.RandBetween(100, 1000)))
|
||||
|
||||
hc := s.httpClient
|
||||
|
||||
|
||||
+83
-33
@@ -2,8 +2,9 @@ package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@@ -20,14 +21,23 @@ type Instance struct {
|
||||
errorLogger log.Handler
|
||||
active bool
|
||||
dns bool
|
||||
mask4 int
|
||||
mask6 int
|
||||
}
|
||||
|
||||
// New creates a new log.Instance based on the given config.
|
||||
func New(ctx context.Context, config *Config) (*Instance, error) {
|
||||
m4, m6, err := ParseMaskAddress(config.MaskAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
g := &Instance{
|
||||
config: config,
|
||||
active: false,
|
||||
dns: config.EnableDnsLog,
|
||||
mask4: m4,
|
||||
mask6: m6,
|
||||
}
|
||||
log.RegisterHandler(g)
|
||||
|
||||
@@ -104,7 +114,11 @@ func (g *Instance) Handle(msg log.Message) {
|
||||
|
||||
var Msg log.Message
|
||||
if g.config.MaskAddress != "" {
|
||||
Msg = &MaskedMsgWrapper{Message: msg, config: g.config}
|
||||
Msg = &MaskedMsgWrapper{
|
||||
Message: msg,
|
||||
Mask4: g.mask4,
|
||||
Mask6: g.mask6,
|
||||
}
|
||||
} else {
|
||||
Msg = msg
|
||||
}
|
||||
@@ -149,51 +163,87 @@ func (g *Instance) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseMaskAddress(c string) (int, int, error) {
|
||||
var m4, m6 int
|
||||
switch c {
|
||||
case "half":
|
||||
m4, m6 = 16, 32
|
||||
case "quarter":
|
||||
m4, m6 = 8, 16
|
||||
case "full":
|
||||
m4, m6 = 0, 0
|
||||
case "":
|
||||
// do nothing
|
||||
default:
|
||||
if parts := strings.Split(c, "+"); len(parts) > 0 {
|
||||
if len(parts) >= 1 && parts[0] != "" {
|
||||
i, err := strconv.Atoi(strings.TrimPrefix(parts[0], "/"))
|
||||
if err != nil {
|
||||
return 32, 128, err
|
||||
}
|
||||
m4 = i
|
||||
}
|
||||
if len(parts) >= 2 && parts[1] != "" {
|
||||
i, err := strconv.Atoi(strings.TrimPrefix(parts[1], "/"))
|
||||
if err != nil {
|
||||
return 32, 128, err
|
||||
}
|
||||
m6 = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if m4%8 != 0 || m4 > 32 || m4 < 0 {
|
||||
return 32, 128, errors.New("Log Mask: ipv4 mask must be divisible by 8 and between 0-32")
|
||||
}
|
||||
|
||||
return m4, m6, nil
|
||||
}
|
||||
|
||||
// MaskedMsgWrapper is to wrap the string() method to mask IP addresses in the log.
|
||||
type MaskedMsgWrapper struct {
|
||||
log.Message
|
||||
config *Config
|
||||
Mask4 int
|
||||
Mask6 int
|
||||
}
|
||||
|
||||
var (
|
||||
ipv4Regex = regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`)
|
||||
ipv6Regex = regexp.MustCompile(`(?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7}`)
|
||||
)
|
||||
|
||||
func (m *MaskedMsgWrapper) String() string {
|
||||
str := m.Message.String()
|
||||
|
||||
ipv4Regex := regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`)
|
||||
ipv6Regex := regexp.MustCompile(`((?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7})(?:[\/\\%](\d{1,3}))?`)
|
||||
|
||||
// Process ipv4
|
||||
maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(ip string) string {
|
||||
parts := strings.Split(ip, ".")
|
||||
switch m.config.MaskAddress {
|
||||
case "half":
|
||||
return fmt.Sprintf("%s.%s.*.*", parts[0], parts[1])
|
||||
case "quarter":
|
||||
return fmt.Sprintf("%s.*.*.*", parts[0])
|
||||
case "full":
|
||||
return "[Masked IPv4]"
|
||||
default:
|
||||
return ip
|
||||
maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(s string) string {
|
||||
if m.Mask4 == 32 {
|
||||
return s
|
||||
}
|
||||
if m.Mask4 == 0 {
|
||||
return "[Masked IPv4]"
|
||||
}
|
||||
|
||||
parts := strings.Split(s, ".")
|
||||
for i := m.Mask4 / 8; i < 4; i++ {
|
||||
parts[i] = "*"
|
||||
}
|
||||
return strings.Join(parts, ".")
|
||||
})
|
||||
|
||||
// process ipv6
|
||||
maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(ip string) string {
|
||||
parts := strings.Split(ip, ":")
|
||||
switch m.config.MaskAddress {
|
||||
case "half":
|
||||
if len(parts) >= 2 {
|
||||
return fmt.Sprintf("%s:%s::/32", parts[0], parts[1])
|
||||
}
|
||||
case "quarter":
|
||||
if len(parts) >= 1 {
|
||||
return fmt.Sprintf("%s::/16", parts[0])
|
||||
}
|
||||
case "full":
|
||||
return "Masked IPv6" // Do not use [Masked IPv6] like ipv4, or you will get "[[Masked IPv6]]" (v6 address already has [])
|
||||
default:
|
||||
return ip
|
||||
maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(s string) string {
|
||||
if m.Mask6 == 128 {
|
||||
return s
|
||||
}
|
||||
return ip
|
||||
if m.Mask6 == 0 {
|
||||
return "Masked IPv6"
|
||||
}
|
||||
ip := net.ParseIP(s)
|
||||
if ip == nil {
|
||||
return s
|
||||
}
|
||||
return ip.Mask(net.CIDRMask(m.Mask6, 128)).String() + "/" + strconv.Itoa(m.Mask6)
|
||||
})
|
||||
|
||||
return maskedMsg
|
||||
|
||||
@@ -2,6 +2,7 @@ package log_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
@@ -50,3 +51,39 @@ func TestCustomLogHandler(t *testing.T) {
|
||||
|
||||
common.Must(logger.Close())
|
||||
}
|
||||
|
||||
func TestMaskAddress(t *testing.T) {
|
||||
m4, m6, err := log.ParseMaskAddress("half")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
maskedAddr := log.MaskedMsgWrapper{
|
||||
Mask4: m4,
|
||||
Mask6: m6,
|
||||
}
|
||||
maskedAddr.Message = net.ParseIP("11.45.1.4")
|
||||
if maskedAddr.String() != "11.45.*.*" {
|
||||
t.Fatal("expected '11.45.*.*', but actually ", maskedAddr.String())
|
||||
}
|
||||
maskedAddr.Message = net.ParseIP("11:45:14:19:19:81:0::")
|
||||
if maskedAddr.String() != "11:45::/32" {
|
||||
t.Fatal("expected '11:45::/32', but actually", maskedAddr.String())
|
||||
}
|
||||
|
||||
m4, m6, err = log.ParseMaskAddress("/16+/64")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
maskedAddr = log.MaskedMsgWrapper{
|
||||
Mask4: m4,
|
||||
Mask6: m6,
|
||||
}
|
||||
maskedAddr.Message = net.ParseIP("11.45.1.4")
|
||||
if maskedAddr.String() != "11.45.*.*" {
|
||||
t.Fatal("expected '11.45.*.*', but actually ", maskedAddr.String())
|
||||
}
|
||||
maskedAddr.Message = net.ParseIP("11:45:14:19:19:81:0::")
|
||||
if maskedAddr.String() != "11:45:14:19::/64" {
|
||||
t.Fatal("expected '11:45:14:19::/64', but actually", maskedAddr.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ func (s *routingServer) AddRule(ctx context.Context, request *AddRuleRequest) (*
|
||||
return nil, errors.New("unsupported router implementation")
|
||||
|
||||
}
|
||||
|
||||
func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleRequest) (*RemoveRuleResponse, error) {
|
||||
if bo, ok := s.router.(routing.Router); ok {
|
||||
return &RemoveRuleResponse{}, bo.RemoveRule(request.RuleTag)
|
||||
@@ -67,6 +68,20 @@ func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleReque
|
||||
return nil, errors.New("unsupported router implementation")
|
||||
}
|
||||
|
||||
func (s *routingServer) ListRule(ctx context.Context, request *ListRuleRequest) (*ListRuleResponse, error) {
|
||||
if bo, ok := s.router.(routing.Router); ok {
|
||||
response := &ListRuleResponse{}
|
||||
for _, v := range bo.ListRule() {
|
||||
response.Rules = append(response.Rules, &ListRuleItem{
|
||||
Tag: v.GetOutboundTag(),
|
||||
RuleTag: v.GetRuleTag(),
|
||||
})
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
return nil, errors.New("unsupported router implementation")
|
||||
}
|
||||
|
||||
// NewRoutingServer creates a statistics service with statistics manager.
|
||||
func NewRoutingServer(router routing.Router, routingStats stats.Channel) RoutingServiceServer {
|
||||
return &routingServer{
|
||||
|
||||
+316
-273
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.35.1
|
||||
// protoc v5.28.2
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.2
|
||||
// source: app/router/command/command.proto
|
||||
|
||||
package command
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -26,25 +27,24 @@ const (
|
||||
// It conforms to the structure of xray.features.routing.Context and
|
||||
// xray.features.routing.Route.
|
||||
type RoutingContext struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
InboundTag string `protobuf:"bytes,1,opt,name=InboundTag,proto3" json:"InboundTag,omitempty"`
|
||||
Network net.Network `protobuf:"varint,2,opt,name=Network,proto3,enum=xray.common.net.Network" json:"Network,omitempty"`
|
||||
SourceIPs [][]byte `protobuf:"bytes,3,rep,name=SourceIPs,proto3" json:"SourceIPs,omitempty"`
|
||||
TargetIPs [][]byte `protobuf:"bytes,4,rep,name=TargetIPs,proto3" json:"TargetIPs,omitempty"`
|
||||
SourcePort uint32 `protobuf:"varint,5,opt,name=SourcePort,proto3" json:"SourcePort,omitempty"`
|
||||
TargetPort uint32 `protobuf:"varint,6,opt,name=TargetPort,proto3" json:"TargetPort,omitempty"`
|
||||
TargetDomain string `protobuf:"bytes,7,opt,name=TargetDomain,proto3" json:"TargetDomain,omitempty"`
|
||||
Protocol string `protobuf:"bytes,8,opt,name=Protocol,proto3" json:"Protocol,omitempty"`
|
||||
User string `protobuf:"bytes,9,opt,name=User,proto3" json:"User,omitempty"`
|
||||
Attributes map[string]string `protobuf:"bytes,10,rep,name=Attributes,proto3" json:"Attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
|
||||
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,omitempty"`
|
||||
LocalIPs [][]byte `protobuf:"bytes,13,rep,name=LocalIPs,proto3" json:"LocalIPs,omitempty"`
|
||||
LocalPort uint32 `protobuf:"varint,14,opt,name=LocalPort,proto3" json:"LocalPort,omitempty"`
|
||||
VlessRoute uint32 `protobuf:"varint,15,opt,name=VlessRoute,proto3" json:"VlessRoute,omitempty"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
InboundTag string `protobuf:"bytes,1,opt,name=InboundTag,proto3" json:"InboundTag,omitempty"`
|
||||
Network net.Network `protobuf:"varint,2,opt,name=Network,proto3,enum=xray.common.net.Network" json:"Network,omitempty"`
|
||||
SourceIPs [][]byte `protobuf:"bytes,3,rep,name=SourceIPs,proto3" json:"SourceIPs,omitempty"`
|
||||
TargetIPs [][]byte `protobuf:"bytes,4,rep,name=TargetIPs,proto3" json:"TargetIPs,omitempty"`
|
||||
SourcePort uint32 `protobuf:"varint,5,opt,name=SourcePort,proto3" json:"SourcePort,omitempty"`
|
||||
TargetPort uint32 `protobuf:"varint,6,opt,name=TargetPort,proto3" json:"TargetPort,omitempty"`
|
||||
TargetDomain string `protobuf:"bytes,7,opt,name=TargetDomain,proto3" json:"TargetDomain,omitempty"`
|
||||
Protocol string `protobuf:"bytes,8,opt,name=Protocol,proto3" json:"Protocol,omitempty"`
|
||||
User string `protobuf:"bytes,9,opt,name=User,proto3" json:"User,omitempty"`
|
||||
Attributes map[string]string `protobuf:"bytes,10,rep,name=Attributes,proto3" json:"Attributes,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
|
||||
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,omitempty"`
|
||||
LocalIPs [][]byte `protobuf:"bytes,13,rep,name=LocalIPs,proto3" json:"LocalIPs,omitempty"`
|
||||
LocalPort uint32 `protobuf:"varint,14,opt,name=LocalPort,proto3" json:"LocalPort,omitempty"`
|
||||
VlessRoute uint32 `protobuf:"varint,15,opt,name=VlessRoute,proto3" json:"VlessRoute,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RoutingContext) Reset() {
|
||||
@@ -201,11 +201,10 @@ func (x *RoutingContext) GetVlessRoute() uint32 {
|
||||
//
|
||||
// * If FieldSelectors is left empty, all fields will be returned.
|
||||
type SubscribeRoutingStatsRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
FieldSelectors []string `protobuf:"bytes,1,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
FieldSelectors []string `protobuf:"bytes,1,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SubscribeRoutingStatsRequest) Reset() {
|
||||
@@ -253,13 +252,12 @@ func (x *SubscribeRoutingStatsRequest) GetFieldSelectors() []string {
|
||||
// * PublishResult broadcasts the routing result to routing statistics channel
|
||||
// if set true.
|
||||
type TestRouteRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
RoutingContext *RoutingContext `protobuf:"bytes,1,opt,name=RoutingContext,proto3" json:"RoutingContext,omitempty"`
|
||||
FieldSelectors []string `protobuf:"bytes,2,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
||||
PublishResult bool `protobuf:"varint,3,opt,name=PublishResult,proto3" json:"PublishResult,omitempty"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
RoutingContext *RoutingContext `protobuf:"bytes,1,opt,name=RoutingContext,proto3" json:"RoutingContext,omitempty"`
|
||||
FieldSelectors []string `protobuf:"bytes,2,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
||||
PublishResult bool `protobuf:"varint,3,opt,name=PublishResult,proto3" json:"PublishResult,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TestRouteRequest) Reset() {
|
||||
@@ -314,11 +312,10 @@ func (x *TestRouteRequest) GetPublishResult() bool {
|
||||
}
|
||||
|
||||
type PrincipleTargetInfo struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Tag []string `protobuf:"bytes,1,rep,name=tag,proto3" json:"tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Tag []string `protobuf:"bytes,1,rep,name=tag,proto3" json:"tag,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *PrincipleTargetInfo) Reset() {
|
||||
@@ -359,11 +356,10 @@ func (x *PrincipleTargetInfo) GetTag() []string {
|
||||
}
|
||||
|
||||
type OverrideInfo struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *OverrideInfo) Reset() {
|
||||
@@ -404,12 +400,11 @@ func (x *OverrideInfo) GetTarget() string {
|
||||
}
|
||||
|
||||
type BalancerMsg struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Override *OverrideInfo `protobuf:"bytes,5,opt,name=override,proto3" json:"override,omitempty"`
|
||||
PrincipleTarget *PrincipleTargetInfo `protobuf:"bytes,6,opt,name=principle_target,json=principleTarget,proto3" json:"principle_target,omitempty"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Override *OverrideInfo `protobuf:"bytes,5,opt,name=override,proto3" json:"override,omitempty"`
|
||||
PrincipleTarget *PrincipleTargetInfo `protobuf:"bytes,6,opt,name=principle_target,json=principleTarget,proto3" json:"principle_target,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *BalancerMsg) Reset() {
|
||||
@@ -457,11 +452,10 @@ func (x *BalancerMsg) GetPrincipleTarget() *PrincipleTargetInfo {
|
||||
}
|
||||
|
||||
type GetBalancerInfoRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetBalancerInfoRequest) Reset() {
|
||||
@@ -502,11 +496,10 @@ func (x *GetBalancerInfoRequest) GetTag() string {
|
||||
}
|
||||
|
||||
type GetBalancerInfoResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Balancer *BalancerMsg `protobuf:"bytes,1,opt,name=balancer,proto3" json:"balancer,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Balancer *BalancerMsg `protobuf:"bytes,1,opt,name=balancer,proto3" json:"balancer,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetBalancerInfoResponse) Reset() {
|
||||
@@ -547,12 +540,11 @@ func (x *GetBalancerInfoResponse) GetBalancer() *BalancerMsg {
|
||||
}
|
||||
|
||||
type OverrideBalancerTargetRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
BalancerTag string `protobuf:"bytes,1,opt,name=balancerTag,proto3" json:"balancerTag,omitempty"`
|
||||
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
BalancerTag string `protobuf:"bytes,1,opt,name=balancerTag,proto3" json:"balancerTag,omitempty"`
|
||||
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *OverrideBalancerTargetRequest) Reset() {
|
||||
@@ -600,9 +592,9 @@ func (x *OverrideBalancerTargetRequest) GetTarget() string {
|
||||
}
|
||||
|
||||
type OverrideBalancerTargetResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *OverrideBalancerTargetResponse) Reset() {
|
||||
@@ -636,12 +628,11 @@ func (*OverrideBalancerTargetResponse) Descriptor() ([]byte, []int) {
|
||||
}
|
||||
|
||||
type AddRuleRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Config *serial.TypedMessage `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
|
||||
ShouldAppend bool `protobuf:"varint,2,opt,name=shouldAppend,proto3" json:"shouldAppend,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Config *serial.TypedMessage `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
|
||||
ShouldAppend bool `protobuf:"varint,2,opt,name=shouldAppend,proto3" json:"shouldAppend,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AddRuleRequest) Reset() {
|
||||
@@ -689,9 +680,9 @@ func (x *AddRuleRequest) GetShouldAppend() bool {
|
||||
}
|
||||
|
||||
type AddRuleResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AddRuleResponse) Reset() {
|
||||
@@ -725,11 +716,10 @@ func (*AddRuleResponse) Descriptor() ([]byte, []int) {
|
||||
}
|
||||
|
||||
type RemoveRuleRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
RuleTag string `protobuf:"bytes,1,opt,name=ruleTag,proto3" json:"ruleTag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
RuleTag string `protobuf:"bytes,1,opt,name=ruleTag,proto3" json:"ruleTag,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RemoveRuleRequest) Reset() {
|
||||
@@ -770,9 +760,9 @@ func (x *RemoveRuleRequest) GetRuleTag() string {
|
||||
}
|
||||
|
||||
type RemoveRuleResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RemoveRuleResponse) Reset() {
|
||||
@@ -805,15 +795,147 @@ func (*RemoveRuleResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{13}
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
type ListRuleRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListRuleRequest) Reset() {
|
||||
*x = ListRuleRequest{}
|
||||
mi := &file_app_router_command_command_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListRuleRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListRuleRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListRuleRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_router_command_command_proto_msgTypes[14]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListRuleRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListRuleRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
type ListRuleItem struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
RuleTag string `protobuf:"bytes,2,opt,name=ruleTag,proto3" json:"ruleTag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListRuleItem) Reset() {
|
||||
*x = ListRuleItem{}
|
||||
mi := &file_app_router_command_command_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListRuleItem) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListRuleItem) ProtoMessage() {}
|
||||
|
||||
func (x *ListRuleItem) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_router_command_command_proto_msgTypes[15]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListRuleItem.ProtoReflect.Descriptor instead.
|
||||
func (*ListRuleItem) Descriptor() ([]byte, []int) {
|
||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *ListRuleItem) GetTag() string {
|
||||
if x != nil {
|
||||
return x.Tag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListRuleItem) GetRuleTag() string {
|
||||
if x != nil {
|
||||
return x.RuleTag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ListRuleResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Rules []*ListRuleItem `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListRuleResponse) Reset() {
|
||||
*x = ListRuleResponse{}
|
||||
mi := &file_app_router_command_command_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListRuleResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListRuleResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListRuleResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_router_command_command_proto_msgTypes[16]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListRuleResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListRuleResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
func (x *ListRuleResponse) GetRules() []*ListRuleItem {
|
||||
if x != nil {
|
||||
return x.Rules
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_app_router_command_command_proto_msgTypes[14]
|
||||
mi := &file_app_router_command_command_proto_msgTypes[17]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -825,7 +947,7 @@ func (x *Config) String() string {
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_router_command_command_proto_msgTypes[14]
|
||||
mi := &file_app_router_command_command_proto_msgTypes[17]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -838,187 +960,103 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{14}
|
||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{17}
|
||||
}
|
||||
|
||||
var File_app_router_command_command_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_app_router_command_command_proto_rawDesc = []byte{
|
||||
0x0a, 0x20, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x12, 0x17, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
|
||||
0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x18, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65,
|
||||
0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf6, 0x04, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x49,
|
||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x32, 0x0a, 0x07, 0x4e,
|
||||
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e,
|
||||
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12,
|
||||
0x1c, 0x0a, 0x09, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x50, 0x73, 0x18, 0x03, 0x20, 0x03,
|
||||
0x28, 0x0c, 0x52, 0x09, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a,
|
||||
0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x50, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c,
|
||||
0x52, 0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x50, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x53,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||
0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x54,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||
0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x54,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12,
|
||||
0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x55,
|
||||
0x73, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12,
|
||||
0x57, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f,
|
||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x41, 0x74, 0x74,
|
||||
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x41, 0x74,
|
||||
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x4f, 0x75, 0x74, 0x62,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x18, 0x0b, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f,
|
||||
0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x75, 0x74,
|
||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x49, 0x50, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72,
|
||||
0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f,
|
||||
0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x75,
|
||||
0x74, 0x65, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
||||
0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f,
|
||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74,
|
||||
0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
||||
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xb1, 0x01, 0x0a, 0x10, 0x54, 0x65,
|
||||
0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f,
|
||||
0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52,
|
||||
0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12,
|
||||
0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
|
||||
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65,
|
||||
0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69,
|
||||
0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d,
|
||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x27, 0x0a,
|
||||
0x13, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28,
|
||||
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x26, 0x0a, 0x0c, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||
0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xa9,
|
||||
0x01, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x41,
|
||||
0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
||||
0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
||||
0x65, 0x12, 0x57, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x6e, 0x63,
|
||||
0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x2a, 0x0a, 0x16, 0x47, 0x65,
|
||||
0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x5b, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c,
|
||||
0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x40, 0x0a, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x42, 0x61,
|
||||
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x22, 0x59, 0x0a, 0x1d, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42,
|
||||
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72,
|
||||
0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x20,
|
||||
0x0a, 0x1e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x6e, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c,
|
||||
0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x08, 0x52, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64,
|
||||
0x22, 0x11, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x2d, 0x0a, 0x11, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65,
|
||||
0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54,
|
||||
0x61, 0x67, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x32, 0xbf, 0x05, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
|
||||
0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x35,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
|
||||
0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||
0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00,
|
||||
0x30, 0x01, 0x12, 0x61, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12,
|
||||
0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f,
|
||||
0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74,
|
||||
0x65, 0x78, 0x74, 0x22, 0x00, 0x12, 0x76, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x8b, 0x01,
|
||||
0x0a, 0x16, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x36, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x37, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
||||
0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x07, 0x41,
|
||||
0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x67, 0x0a, 0x0a, 0x52,
|
||||
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x00, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
|
||||
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
const file_app_router_command_command_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
" app/router/command/command.proto\x12\x17xray.app.router.command\x1a\x18common/net/network.proto\x1a!common/serial/typed_message.proto\"\xf6\x04\n" +
|
||||
"\x0eRoutingContext\x12\x1e\n" +
|
||||
"\n" +
|
||||
"InboundTag\x18\x01 \x01(\tR\n" +
|
||||
"InboundTag\x122\n" +
|
||||
"\aNetwork\x18\x02 \x01(\x0e2\x18.xray.common.net.NetworkR\aNetwork\x12\x1c\n" +
|
||||
"\tSourceIPs\x18\x03 \x03(\fR\tSourceIPs\x12\x1c\n" +
|
||||
"\tTargetIPs\x18\x04 \x03(\fR\tTargetIPs\x12\x1e\n" +
|
||||
"\n" +
|
||||
"SourcePort\x18\x05 \x01(\rR\n" +
|
||||
"SourcePort\x12\x1e\n" +
|
||||
"\n" +
|
||||
"TargetPort\x18\x06 \x01(\rR\n" +
|
||||
"TargetPort\x12\"\n" +
|
||||
"\fTargetDomain\x18\a \x01(\tR\fTargetDomain\x12\x1a\n" +
|
||||
"\bProtocol\x18\b \x01(\tR\bProtocol\x12\x12\n" +
|
||||
"\x04User\x18\t \x01(\tR\x04User\x12W\n" +
|
||||
"\n" +
|
||||
"Attributes\x18\n" +
|
||||
" \x03(\v27.xray.app.router.command.RoutingContext.AttributesEntryR\n" +
|
||||
"Attributes\x12,\n" +
|
||||
"\x11OutboundGroupTags\x18\v \x03(\tR\x11OutboundGroupTags\x12 \n" +
|
||||
"\vOutboundTag\x18\f \x01(\tR\vOutboundTag\x12\x1a\n" +
|
||||
"\bLocalIPs\x18\r \x03(\fR\bLocalIPs\x12\x1c\n" +
|
||||
"\tLocalPort\x18\x0e \x01(\rR\tLocalPort\x12\x1e\n" +
|
||||
"\n" +
|
||||
"VlessRoute\x18\x0f \x01(\rR\n" +
|
||||
"VlessRoute\x1a=\n" +
|
||||
"\x0fAttributesEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"F\n" +
|
||||
"\x1cSubscribeRoutingStatsRequest\x12&\n" +
|
||||
"\x0eFieldSelectors\x18\x01 \x03(\tR\x0eFieldSelectors\"\xb1\x01\n" +
|
||||
"\x10TestRouteRequest\x12O\n" +
|
||||
"\x0eRoutingContext\x18\x01 \x01(\v2'.xray.app.router.command.RoutingContextR\x0eRoutingContext\x12&\n" +
|
||||
"\x0eFieldSelectors\x18\x02 \x03(\tR\x0eFieldSelectors\x12$\n" +
|
||||
"\rPublishResult\x18\x03 \x01(\bR\rPublishResult\"'\n" +
|
||||
"\x13PrincipleTargetInfo\x12\x10\n" +
|
||||
"\x03tag\x18\x01 \x03(\tR\x03tag\"&\n" +
|
||||
"\fOverrideInfo\x12\x16\n" +
|
||||
"\x06target\x18\x02 \x01(\tR\x06target\"\xa9\x01\n" +
|
||||
"\vBalancerMsg\x12A\n" +
|
||||
"\boverride\x18\x05 \x01(\v2%.xray.app.router.command.OverrideInfoR\boverride\x12W\n" +
|
||||
"\x10principle_target\x18\x06 \x01(\v2,.xray.app.router.command.PrincipleTargetInfoR\x0fprincipleTarget\"*\n" +
|
||||
"\x16GetBalancerInfoRequest\x12\x10\n" +
|
||||
"\x03tag\x18\x01 \x01(\tR\x03tag\"[\n" +
|
||||
"\x17GetBalancerInfoResponse\x12@\n" +
|
||||
"\bbalancer\x18\x01 \x01(\v2$.xray.app.router.command.BalancerMsgR\bbalancer\"Y\n" +
|
||||
"\x1dOverrideBalancerTargetRequest\x12 \n" +
|
||||
"\vbalancerTag\x18\x01 \x01(\tR\vbalancerTag\x12\x16\n" +
|
||||
"\x06target\x18\x02 \x01(\tR\x06target\" \n" +
|
||||
"\x1eOverrideBalancerTargetResponse\"n\n" +
|
||||
"\x0eAddRuleRequest\x128\n" +
|
||||
"\x06config\x18\x01 \x01(\v2 .xray.common.serial.TypedMessageR\x06config\x12\"\n" +
|
||||
"\fshouldAppend\x18\x02 \x01(\bR\fshouldAppend\"\x11\n" +
|
||||
"\x0fAddRuleResponse\"-\n" +
|
||||
"\x11RemoveRuleRequest\x12\x18\n" +
|
||||
"\aruleTag\x18\x01 \x01(\tR\aruleTag\"\x14\n" +
|
||||
"\x12RemoveRuleResponse\"\x11\n" +
|
||||
"\x0fListRuleRequest\":\n" +
|
||||
"\fListRuleItem\x12\x10\n" +
|
||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12\x18\n" +
|
||||
"\aruleTag\x18\x02 \x01(\tR\aruleTag\"O\n" +
|
||||
"\x10ListRuleResponse\x12;\n" +
|
||||
"\x05rules\x18\x01 \x03(\v2%.xray.app.router.command.ListRuleItemR\x05rules\"\b\n" +
|
||||
"\x06Config2\xa2\x06\n" +
|
||||
"\x0eRoutingService\x12{\n" +
|
||||
"\x15SubscribeRoutingStats\x125.xray.app.router.command.SubscribeRoutingStatsRequest\x1a'.xray.app.router.command.RoutingContext\"\x000\x01\x12a\n" +
|
||||
"\tTestRoute\x12).xray.app.router.command.TestRouteRequest\x1a'.xray.app.router.command.RoutingContext\"\x00\x12v\n" +
|
||||
"\x0fGetBalancerInfo\x12/.xray.app.router.command.GetBalancerInfoRequest\x1a0.xray.app.router.command.GetBalancerInfoResponse\"\x00\x12\x8b\x01\n" +
|
||||
"\x16OverrideBalancerTarget\x126.xray.app.router.command.OverrideBalancerTargetRequest\x1a7.xray.app.router.command.OverrideBalancerTargetResponse\"\x00\x12^\n" +
|
||||
"\aAddRule\x12'.xray.app.router.command.AddRuleRequest\x1a(.xray.app.router.command.AddRuleResponse\"\x00\x12g\n" +
|
||||
"\n" +
|
||||
"RemoveRule\x12*.xray.app.router.command.RemoveRuleRequest\x1a+.xray.app.router.command.RemoveRuleResponse\"\x00\x12a\n" +
|
||||
"\bListRule\x12(.xray.app.router.command.ListRuleRequest\x1a).xray.app.router.command.ListRuleResponse\"\x00Bg\n" +
|
||||
"\x1bcom.xray.app.router.commandP\x01Z,github.com/xtls/xray-core/app/router/command\xaa\x02\x17Xray.App.Router.Commandb\x06proto3"
|
||||
|
||||
var (
|
||||
file_app_router_command_command_proto_rawDescOnce sync.Once
|
||||
file_app_router_command_command_proto_rawDescData = file_app_router_command_command_proto_rawDesc
|
||||
file_app_router_command_command_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_app_router_command_command_proto_rawDescGZIP() []byte {
|
||||
file_app_router_command_command_proto_rawDescOnce.Do(func() {
|
||||
file_app_router_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_router_command_command_proto_rawDescData)
|
||||
file_app_router_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_router_command_command_proto_rawDesc), len(file_app_router_command_command_proto_rawDesc)))
|
||||
})
|
||||
return file_app_router_command_command_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_app_router_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
|
||||
var file_app_router_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
|
||||
var file_app_router_command_command_proto_goTypes = []any{
|
||||
(*RoutingContext)(nil), // 0: xray.app.router.command.RoutingContext
|
||||
(*SubscribeRoutingStatsRequest)(nil), // 1: xray.app.router.command.SubscribeRoutingStatsRequest
|
||||
@@ -1034,36 +1072,42 @@ var file_app_router_command_command_proto_goTypes = []any{
|
||||
(*AddRuleResponse)(nil), // 11: xray.app.router.command.AddRuleResponse
|
||||
(*RemoveRuleRequest)(nil), // 12: xray.app.router.command.RemoveRuleRequest
|
||||
(*RemoveRuleResponse)(nil), // 13: xray.app.router.command.RemoveRuleResponse
|
||||
(*Config)(nil), // 14: xray.app.router.command.Config
|
||||
nil, // 15: xray.app.router.command.RoutingContext.AttributesEntry
|
||||
(net.Network)(0), // 16: xray.common.net.Network
|
||||
(*serial.TypedMessage)(nil), // 17: xray.common.serial.TypedMessage
|
||||
(*ListRuleRequest)(nil), // 14: xray.app.router.command.ListRuleRequest
|
||||
(*ListRuleItem)(nil), // 15: xray.app.router.command.ListRuleItem
|
||||
(*ListRuleResponse)(nil), // 16: xray.app.router.command.ListRuleResponse
|
||||
(*Config)(nil), // 17: xray.app.router.command.Config
|
||||
nil, // 18: xray.app.router.command.RoutingContext.AttributesEntry
|
||||
(net.Network)(0), // 19: xray.common.net.Network
|
||||
(*serial.TypedMessage)(nil), // 20: xray.common.serial.TypedMessage
|
||||
}
|
||||
var file_app_router_command_command_proto_depIdxs = []int32{
|
||||
16, // 0: xray.app.router.command.RoutingContext.Network:type_name -> xray.common.net.Network
|
||||
15, // 1: xray.app.router.command.RoutingContext.Attributes:type_name -> xray.app.router.command.RoutingContext.AttributesEntry
|
||||
19, // 0: xray.app.router.command.RoutingContext.Network:type_name -> xray.common.net.Network
|
||||
18, // 1: xray.app.router.command.RoutingContext.Attributes:type_name -> xray.app.router.command.RoutingContext.AttributesEntry
|
||||
0, // 2: xray.app.router.command.TestRouteRequest.RoutingContext:type_name -> xray.app.router.command.RoutingContext
|
||||
4, // 3: xray.app.router.command.BalancerMsg.override:type_name -> xray.app.router.command.OverrideInfo
|
||||
3, // 4: xray.app.router.command.BalancerMsg.principle_target:type_name -> xray.app.router.command.PrincipleTargetInfo
|
||||
5, // 5: xray.app.router.command.GetBalancerInfoResponse.balancer:type_name -> xray.app.router.command.BalancerMsg
|
||||
17, // 6: xray.app.router.command.AddRuleRequest.config:type_name -> xray.common.serial.TypedMessage
|
||||
1, // 7: xray.app.router.command.RoutingService.SubscribeRoutingStats:input_type -> xray.app.router.command.SubscribeRoutingStatsRequest
|
||||
2, // 8: xray.app.router.command.RoutingService.TestRoute:input_type -> xray.app.router.command.TestRouteRequest
|
||||
6, // 9: xray.app.router.command.RoutingService.GetBalancerInfo:input_type -> xray.app.router.command.GetBalancerInfoRequest
|
||||
8, // 10: xray.app.router.command.RoutingService.OverrideBalancerTarget:input_type -> xray.app.router.command.OverrideBalancerTargetRequest
|
||||
10, // 11: xray.app.router.command.RoutingService.AddRule:input_type -> xray.app.router.command.AddRuleRequest
|
||||
12, // 12: xray.app.router.command.RoutingService.RemoveRule:input_type -> xray.app.router.command.RemoveRuleRequest
|
||||
0, // 13: xray.app.router.command.RoutingService.SubscribeRoutingStats:output_type -> xray.app.router.command.RoutingContext
|
||||
0, // 14: xray.app.router.command.RoutingService.TestRoute:output_type -> xray.app.router.command.RoutingContext
|
||||
7, // 15: xray.app.router.command.RoutingService.GetBalancerInfo:output_type -> xray.app.router.command.GetBalancerInfoResponse
|
||||
9, // 16: xray.app.router.command.RoutingService.OverrideBalancerTarget:output_type -> xray.app.router.command.OverrideBalancerTargetResponse
|
||||
11, // 17: xray.app.router.command.RoutingService.AddRule:output_type -> xray.app.router.command.AddRuleResponse
|
||||
13, // 18: xray.app.router.command.RoutingService.RemoveRule:output_type -> xray.app.router.command.RemoveRuleResponse
|
||||
13, // [13:19] is the sub-list for method output_type
|
||||
7, // [7:13] is the sub-list for method input_type
|
||||
7, // [7:7] is the sub-list for extension type_name
|
||||
7, // [7:7] is the sub-list for extension extendee
|
||||
0, // [0:7] is the sub-list for field type_name
|
||||
20, // 6: xray.app.router.command.AddRuleRequest.config:type_name -> xray.common.serial.TypedMessage
|
||||
15, // 7: xray.app.router.command.ListRuleResponse.rules:type_name -> xray.app.router.command.ListRuleItem
|
||||
1, // 8: xray.app.router.command.RoutingService.SubscribeRoutingStats:input_type -> xray.app.router.command.SubscribeRoutingStatsRequest
|
||||
2, // 9: xray.app.router.command.RoutingService.TestRoute:input_type -> xray.app.router.command.TestRouteRequest
|
||||
6, // 10: xray.app.router.command.RoutingService.GetBalancerInfo:input_type -> xray.app.router.command.GetBalancerInfoRequest
|
||||
8, // 11: xray.app.router.command.RoutingService.OverrideBalancerTarget:input_type -> xray.app.router.command.OverrideBalancerTargetRequest
|
||||
10, // 12: xray.app.router.command.RoutingService.AddRule:input_type -> xray.app.router.command.AddRuleRequest
|
||||
12, // 13: xray.app.router.command.RoutingService.RemoveRule:input_type -> xray.app.router.command.RemoveRuleRequest
|
||||
14, // 14: xray.app.router.command.RoutingService.ListRule:input_type -> xray.app.router.command.ListRuleRequest
|
||||
0, // 15: xray.app.router.command.RoutingService.SubscribeRoutingStats:output_type -> xray.app.router.command.RoutingContext
|
||||
0, // 16: xray.app.router.command.RoutingService.TestRoute:output_type -> xray.app.router.command.RoutingContext
|
||||
7, // 17: xray.app.router.command.RoutingService.GetBalancerInfo:output_type -> xray.app.router.command.GetBalancerInfoResponse
|
||||
9, // 18: xray.app.router.command.RoutingService.OverrideBalancerTarget:output_type -> xray.app.router.command.OverrideBalancerTargetResponse
|
||||
11, // 19: xray.app.router.command.RoutingService.AddRule:output_type -> xray.app.router.command.AddRuleResponse
|
||||
13, // 20: xray.app.router.command.RoutingService.RemoveRule:output_type -> xray.app.router.command.RemoveRuleResponse
|
||||
16, // 21: xray.app.router.command.RoutingService.ListRule:output_type -> xray.app.router.command.ListRuleResponse
|
||||
15, // [15:22] is the sub-list for method output_type
|
||||
8, // [8:15] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_router_command_command_proto_init() }
|
||||
@@ -1075,9 +1119,9 @@ func file_app_router_command_command_proto_init() {
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_app_router_command_command_proto_rawDesc,
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_router_command_command_proto_rawDesc), len(file_app_router_command_command_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 16,
|
||||
NumMessages: 19,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
@@ -1086,7 +1130,6 @@ func file_app_router_command_command_proto_init() {
|
||||
MessageInfos: file_app_router_command_command_proto_msgTypes,
|
||||
}.Build()
|
||||
File_app_router_command_command_proto = out.File
|
||||
file_app_router_command_command_proto_rawDesc = nil
|
||||
file_app_router_command_command_proto_goTypes = nil
|
||||
file_app_router_command_command_proto_depIdxs = nil
|
||||
}
|
||||
|
||||
@@ -104,6 +104,17 @@ message RemoveRuleRequest {
|
||||
|
||||
message RemoveRuleResponse {}
|
||||
|
||||
message ListRuleRequest {}
|
||||
|
||||
message ListRuleItem {
|
||||
string tag = 1;
|
||||
string ruleTag = 2;
|
||||
}
|
||||
|
||||
message ListRuleResponse{
|
||||
repeated ListRuleItem rules = 1;
|
||||
}
|
||||
|
||||
service RoutingService {
|
||||
rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest)
|
||||
returns (stream RoutingContext) {}
|
||||
@@ -114,6 +125,8 @@ service RoutingService {
|
||||
|
||||
rpc AddRule(AddRuleRequest) returns (AddRuleResponse) {}
|
||||
rpc RemoveRule(RemoveRuleRequest) returns (RemoveRuleResponse) {}
|
||||
|
||||
rpc ListRule(ListRuleRequest) returns (ListRuleResponse) {}
|
||||
}
|
||||
|
||||
message Config {}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v5.28.2
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc v6.33.2
|
||||
// source: app/router/command/command.proto
|
||||
|
||||
package command
|
||||
@@ -25,6 +25,7 @@ const (
|
||||
RoutingService_OverrideBalancerTarget_FullMethodName = "/xray.app.router.command.RoutingService/OverrideBalancerTarget"
|
||||
RoutingService_AddRule_FullMethodName = "/xray.app.router.command.RoutingService/AddRule"
|
||||
RoutingService_RemoveRule_FullMethodName = "/xray.app.router.command.RoutingService/RemoveRule"
|
||||
RoutingService_ListRule_FullMethodName = "/xray.app.router.command.RoutingService/ListRule"
|
||||
)
|
||||
|
||||
// RoutingServiceClient is the client API for RoutingService service.
|
||||
@@ -37,6 +38,7 @@ type RoutingServiceClient interface {
|
||||
OverrideBalancerTarget(ctx context.Context, in *OverrideBalancerTargetRequest, opts ...grpc.CallOption) (*OverrideBalancerTargetResponse, error)
|
||||
AddRule(ctx context.Context, in *AddRuleRequest, opts ...grpc.CallOption) (*AddRuleResponse, error)
|
||||
RemoveRule(ctx context.Context, in *RemoveRuleRequest, opts ...grpc.CallOption) (*RemoveRuleResponse, error)
|
||||
ListRule(ctx context.Context, in *ListRuleRequest, opts ...grpc.CallOption) (*ListRuleResponse, error)
|
||||
}
|
||||
|
||||
type routingServiceClient struct {
|
||||
@@ -116,6 +118,16 @@ func (c *routingServiceClient) RemoveRule(ctx context.Context, in *RemoveRuleReq
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *routingServiceClient) ListRule(ctx context.Context, in *ListRuleRequest, opts ...grpc.CallOption) (*ListRuleResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListRuleResponse)
|
||||
err := c.cc.Invoke(ctx, RoutingService_ListRule_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// RoutingServiceServer is the server API for RoutingService service.
|
||||
// All implementations must embed UnimplementedRoutingServiceServer
|
||||
// for forward compatibility.
|
||||
@@ -126,6 +138,7 @@ type RoutingServiceServer interface {
|
||||
OverrideBalancerTarget(context.Context, *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error)
|
||||
AddRule(context.Context, *AddRuleRequest) (*AddRuleResponse, error)
|
||||
RemoveRule(context.Context, *RemoveRuleRequest) (*RemoveRuleResponse, error)
|
||||
ListRule(context.Context, *ListRuleRequest) (*ListRuleResponse, error)
|
||||
mustEmbedUnimplementedRoutingServiceServer()
|
||||
}
|
||||
|
||||
@@ -137,22 +150,25 @@ type RoutingServiceServer interface {
|
||||
type UnimplementedRoutingServiceServer struct{}
|
||||
|
||||
func (UnimplementedRoutingServiceServer) SubscribeRoutingStats(*SubscribeRoutingStatsRequest, grpc.ServerStreamingServer[RoutingContext]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method SubscribeRoutingStats not implemented")
|
||||
return status.Error(codes.Unimplemented, "method SubscribeRoutingStats not implemented")
|
||||
}
|
||||
func (UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method TestRoute not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method TestRoute not implemented")
|
||||
}
|
||||
func (UnimplementedRoutingServiceServer) GetBalancerInfo(context.Context, *GetBalancerInfoRequest) (*GetBalancerInfoResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetBalancerInfo not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetBalancerInfo not implemented")
|
||||
}
|
||||
func (UnimplementedRoutingServiceServer) OverrideBalancerTarget(context.Context, *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method OverrideBalancerTarget not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method OverrideBalancerTarget not implemented")
|
||||
}
|
||||
func (UnimplementedRoutingServiceServer) AddRule(context.Context, *AddRuleRequest) (*AddRuleResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AddRule not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AddRule not implemented")
|
||||
}
|
||||
func (UnimplementedRoutingServiceServer) RemoveRule(context.Context, *RemoveRuleRequest) (*RemoveRuleResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RemoveRule not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RemoveRule not implemented")
|
||||
}
|
||||
func (UnimplementedRoutingServiceServer) ListRule(context.Context, *ListRuleRequest) (*ListRuleResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRule not implemented")
|
||||
}
|
||||
func (UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {}
|
||||
func (UnimplementedRoutingServiceServer) testEmbeddedByValue() {}
|
||||
@@ -165,7 +181,7 @@ type UnsafeRoutingServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterRoutingServiceServer(s grpc.ServiceRegistrar, srv RoutingServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedRoutingServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedRoutingServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@@ -276,6 +292,24 @@ func _RoutingService_RemoveRule_Handler(srv interface{}, ctx context.Context, de
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _RoutingService_ListRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListRuleRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RoutingServiceServer).ListRule(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: RoutingService_ListRule_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RoutingServiceServer).ListRule(ctx, req.(*ListRuleRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// RoutingService_ServiceDesc is the grpc.ServiceDesc for RoutingService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -303,6 +337,10 @@ var RoutingService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "RemoveRule",
|
||||
Handler: _RoutingService_RemoveRule_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListRule",
|
||||
Handler: _RoutingService_ListRule_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
|
||||
+36
-4
@@ -2,6 +2,7 @@ package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
@@ -52,12 +53,40 @@ var matcherTypeMap = map[Domain_Type]strmatcher.Type{
|
||||
}
|
||||
|
||||
type DomainMatcher struct {
|
||||
matchers strmatcher.IndexMatcher
|
||||
Matchers strmatcher.IndexMatcher
|
||||
}
|
||||
|
||||
func SerializeDomainMatcher(domains []*Domain, w io.Writer) error {
|
||||
|
||||
g := strmatcher.NewMphMatcherGroup()
|
||||
for _, d := range domains {
|
||||
matcherType, f := matcherTypeMap[d.Type]
|
||||
if !f {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := g.AddPattern(d.Value, matcherType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
g.Build()
|
||||
// serialize
|
||||
return g.Serialize(w)
|
||||
}
|
||||
|
||||
func NewDomainMatcherFromBuffer(data []byte) (*strmatcher.MphMatcherGroup, error) {
|
||||
matcher, err := strmatcher.NewMphMatcherGroupFromBuffer(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return matcher, nil
|
||||
}
|
||||
|
||||
func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
|
||||
g := strmatcher.NewMphMatcherGroup()
|
||||
for _, d := range domains {
|
||||
for i, d := range domains {
|
||||
domains[i] = nil
|
||||
matcherType, f := matcherTypeMap[d.Type]
|
||||
if !f {
|
||||
errors.LogError(context.Background(), "ignore unsupported domain type ", d.Type, " of rule ", d.Value)
|
||||
@@ -71,12 +100,12 @@ func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
|
||||
}
|
||||
g.Build()
|
||||
return &DomainMatcher{
|
||||
matchers: g,
|
||||
Matchers: g,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *DomainMatcher) ApplyDomain(domain string) bool {
|
||||
return len(m.matchers.Match(strings.ToLower(domain))) > 0
|
||||
return len(m.Matchers.Match(strings.ToLower(domain))) > 0
|
||||
}
|
||||
|
||||
// Apply implements Condition.
|
||||
@@ -358,6 +387,9 @@ func NewProcessNameMatcher(names []string) *ProcessNameMatcher {
|
||||
}
|
||||
|
||||
func (m *ProcessNameMatcher) Apply(ctx routing.Context) bool {
|
||||
if len(ctx.GetSourceIPs()) == 0 {
|
||||
return false
|
||||
}
|
||||
srcPort := ctx.GetSourcePort().String()
|
||||
srcIP := ctx.GetSourceIPs()[0].String()
|
||||
var network string
|
||||
|
||||
@@ -822,7 +822,8 @@ func (f *GeoIPSetFactory) Create(cidrGroups ...[]*CIDR) (*GeoIPSet, error) {
|
||||
var ipv4Builder, ipv6Builder netipx.IPSetBuilder
|
||||
|
||||
for _, cidrGroup := range cidrGroups {
|
||||
for _, cidrEntry := range cidrGroup {
|
||||
for i, cidrEntry := range cidrGroup {
|
||||
cidrGroup[i] = nil
|
||||
ipBytes := cidrEntry.GetIp()
|
||||
prefixLen := int(cidrEntry.GetPrefix())
|
||||
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
package router_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
)
|
||||
|
||||
func TestDomainMatcherSerialization(t *testing.T) {
|
||||
|
||||
domains := []*router.Domain{
|
||||
{Type: router.Domain_Domain, Value: "google.com"},
|
||||
{Type: router.Domain_Domain, Value: "v2ray.com"},
|
||||
{Type: router.Domain_Full, Value: "full.example.com"},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := router.SerializeDomainMatcher(domains, &buf); err != nil {
|
||||
t.Fatalf("Serialize failed: %v", err)
|
||||
}
|
||||
|
||||
matcher, err := router.NewDomainMatcherFromBuffer(buf.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("Deserialize failed: %v", err)
|
||||
}
|
||||
|
||||
dMatcher := &router.DomainMatcher{
|
||||
Matchers: matcher,
|
||||
}
|
||||
testCases := []struct {
|
||||
Input string
|
||||
Match bool
|
||||
}{
|
||||
{"google.com", true},
|
||||
{"maps.google.com", true},
|
||||
{"v2ray.com", true},
|
||||
{"full.example.com", true},
|
||||
|
||||
{"example.com", false},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
if res := dMatcher.ApplyDomain(tc.Input); res != tc.Match {
|
||||
t.Errorf("Match(%s) = %v, want %v", tc.Input, res, tc.Match)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeoSiteSerialization(t *testing.T) {
|
||||
sites := []*router.GeoSite{
|
||||
{
|
||||
CountryCode: "CN",
|
||||
Domain: []*router.Domain{
|
||||
{Type: router.Domain_Domain, Value: "baidu.cn"},
|
||||
{Type: router.Domain_Domain, Value: "qq.com"},
|
||||
},
|
||||
},
|
||||
{
|
||||
CountryCode: "US",
|
||||
Domain: []*router.Domain{
|
||||
{Type: router.Domain_Domain, Value: "google.com"},
|
||||
{Type: router.Domain_Domain, Value: "facebook.com"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := router.SerializeGeoSiteList(sites, nil, nil, &buf); err != nil {
|
||||
t.Fatalf("SerializeGeoSiteList failed: %v", err)
|
||||
}
|
||||
|
||||
tmp := t.TempDir()
|
||||
path := filepath.Join(tmp, "matcher.cache")
|
||||
|
||||
f, err := os.Create(path)
|
||||
require.NoError(t, err)
|
||||
_, err = f.Write(buf.Bytes())
|
||||
require.NoError(t, err)
|
||||
f.Close()
|
||||
|
||||
f, err = os.Open(path)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
require.NoError(t, err)
|
||||
data, _ := filesystem.ReadFile(path)
|
||||
|
||||
// cn
|
||||
gp, err := router.LoadGeoSiteMatcher(bytes.NewReader(data), "CN")
|
||||
if err != nil {
|
||||
t.Fatalf("LoadGeoSiteMatcher(CN) failed: %v", err)
|
||||
}
|
||||
|
||||
cnMatcher := &router.DomainMatcher{
|
||||
Matchers: gp,
|
||||
}
|
||||
|
||||
if !cnMatcher.ApplyDomain("baidu.cn") {
|
||||
t.Error("CN matcher should match baidu.cn")
|
||||
}
|
||||
if cnMatcher.ApplyDomain("google.com") {
|
||||
t.Error("CN matcher should NOT match google.com")
|
||||
}
|
||||
|
||||
// us
|
||||
gp, err = router.LoadGeoSiteMatcher(bytes.NewReader(data), "US")
|
||||
if err != nil {
|
||||
t.Fatalf("LoadGeoSiteMatcher(US) failed: %v", err)
|
||||
}
|
||||
|
||||
usMatcher := &router.DomainMatcher{
|
||||
Matchers: gp,
|
||||
}
|
||||
if !usMatcher.ApplyDomain("google.com") {
|
||||
t.Error("US matcher should match google.com")
|
||||
}
|
||||
if usMatcher.ApplyDomain("baidu.cn") {
|
||||
t.Error("US matcher should NOT match baidu.cn")
|
||||
}
|
||||
|
||||
// unknown
|
||||
_, err = router.LoadGeoSiteMatcher(bytes.NewReader(data), "unknown")
|
||||
if err == nil {
|
||||
t.Error("LoadGeoSiteMatcher(unknown) should fail")
|
||||
}
|
||||
}
|
||||
func TestGeoSiteSerializationWithDeps(t *testing.T) {
|
||||
sites := []*router.GeoSite{
|
||||
{
|
||||
CountryCode: "geosite:cn",
|
||||
Domain: []*router.Domain{
|
||||
{Type: router.Domain_Domain, Value: "baidu.cn"},
|
||||
},
|
||||
},
|
||||
{
|
||||
CountryCode: "geosite:google@cn",
|
||||
Domain: []*router.Domain{
|
||||
{Type: router.Domain_Domain, Value: "google.cn"},
|
||||
},
|
||||
},
|
||||
{
|
||||
CountryCode: "rule-1",
|
||||
Domain: []*router.Domain{
|
||||
{Type: router.Domain_Domain, Value: "google.com"},
|
||||
},
|
||||
},
|
||||
}
|
||||
deps := map[string][]string{
|
||||
"rule-1": {"geosite:cn", "geosite:google@cn"},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := router.SerializeGeoSiteList(sites, deps, nil, &buf)
|
||||
require.NoError(t, err)
|
||||
|
||||
matcher, err := router.LoadGeoSiteMatcher(bytes.NewReader(buf.Bytes()), "rule-1")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, matcher.Match("google.com") != nil)
|
||||
require.True(t, matcher.Match("baidu.cn") != nil)
|
||||
require.True(t, matcher.Match("google.cn") != nil)
|
||||
}
|
||||
+46
-4
@@ -3,9 +3,12 @@ package router
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
)
|
||||
@@ -78,6 +81,8 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
return nil, err
|
||||
}
|
||||
conds.Add(cond)
|
||||
rr.Geoip = nil
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
if len(rr.SourceGeoip) > 0 {
|
||||
@@ -86,6 +91,8 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
return nil, err
|
||||
}
|
||||
conds.Add(cond)
|
||||
rr.SourceGeoip = nil
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
if len(rr.LocalGeoip) > 0 {
|
||||
@@ -95,15 +102,33 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
}
|
||||
conds.Add(cond)
|
||||
errors.LogWarning(context.Background(), "Due to some limitations, in UDP connections, localIP is always equal to listen interface IP, so \"localIP\" rule condition does not work properly on UDP inbound connections that listen on all interfaces")
|
||||
rr.LocalGeoip = nil
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
if len(rr.Domain) > 0 {
|
||||
matcher, err := NewMphMatcherGroup(rr.Domain)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build domain condition with MphDomainMatcher").Base(err)
|
||||
var matcher *DomainMatcher
|
||||
var err error
|
||||
// Check if domain matcher cache is provided via environment
|
||||
domainMatcherPath := platform.NewEnvFlag(platform.MphCachePath).GetValue(func() string { return "" })
|
||||
|
||||
if domainMatcherPath != "" {
|
||||
matcher, err = GetDomainMatcherWithRuleTag(domainMatcherPath, rr.RuleTag)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build domain condition from cached MphDomainMatcher").Base(err)
|
||||
}
|
||||
errors.LogDebug(context.Background(), "MphDomainMatcher loaded from cache for ", rr.RuleTag, " rule tag)")
|
||||
|
||||
} else {
|
||||
matcher, err = NewMphMatcherGroup(rr.Domain)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build domain condition with MphDomainMatcher").Base(err)
|
||||
}
|
||||
errors.LogDebug(context.Background(), "MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)")
|
||||
}
|
||||
errors.LogDebug(context.Background(), "MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)")
|
||||
conds.Add(matcher)
|
||||
rr.Domain = nil
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
if len(rr.Process) > 0 {
|
||||
@@ -163,3 +188,20 @@ func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatch
|
||||
return nil, errors.New("unrecognized balancer type")
|
||||
}
|
||||
}
|
||||
|
||||
func GetDomainMatcherWithRuleTag(domainMatcherPath string, ruleTag string) (*DomainMatcher, error) {
|
||||
f, err := filesystem.NewFileReader(domainMatcherPath)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to load file: ", domainMatcherPath).Base(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
g, err := LoadGeoSiteMatcher(f, ruleTag)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to load file:", domainMatcherPath).Base(err)
|
||||
}
|
||||
return &DomainMatcher{
|
||||
Matchers: g,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/xtls/xray-core/common/strmatcher"
|
||||
)
|
||||
|
||||
type geoSiteListGob struct {
|
||||
Sites map[string][]byte
|
||||
Deps map[string][]string
|
||||
Hosts map[string][]string
|
||||
}
|
||||
|
||||
func SerializeGeoSiteList(sites []*GeoSite, deps map[string][]string, hosts map[string][]string, w io.Writer) error {
|
||||
data := geoSiteListGob{
|
||||
Sites: make(map[string][]byte),
|
||||
Deps: deps,
|
||||
Hosts: hosts,
|
||||
}
|
||||
|
||||
for _, site := range sites {
|
||||
if site == nil {
|
||||
continue
|
||||
}
|
||||
var buf bytesWriter
|
||||
if err := SerializeDomainMatcher(site.Domain, &buf); err != nil {
|
||||
return err
|
||||
}
|
||||
data.Sites[site.CountryCode] = buf.Bytes()
|
||||
}
|
||||
|
||||
return gob.NewEncoder(w).Encode(data)
|
||||
}
|
||||
|
||||
type bytesWriter struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (w *bytesWriter) Write(p []byte) (n int, err error) {
|
||||
w.data = append(w.data, p...)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (w *bytesWriter) Bytes() []byte {
|
||||
return w.data
|
||||
}
|
||||
|
||||
func LoadGeoSiteMatcher(r io.Reader, countryCode string) (strmatcher.IndexMatcher, error) {
|
||||
var data geoSiteListGob
|
||||
if err := gob.NewDecoder(r).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return loadWithDeps(&data, countryCode, make(map[string]bool))
|
||||
}
|
||||
|
||||
func loadWithDeps(data *geoSiteListGob, code string, visited map[string]bool) (strmatcher.IndexMatcher, error) {
|
||||
if visited[code] {
|
||||
return nil, errors.New("cyclic dependency")
|
||||
}
|
||||
visited[code] = true
|
||||
|
||||
var matchers []strmatcher.IndexMatcher
|
||||
|
||||
if siteData, ok := data.Sites[code]; ok {
|
||||
m, err := NewDomainMatcherFromBuffer(siteData)
|
||||
if err == nil {
|
||||
matchers = append(matchers, m)
|
||||
}
|
||||
}
|
||||
|
||||
if deps, ok := data.Deps[code]; ok {
|
||||
for _, dep := range deps {
|
||||
m, err := loadWithDeps(data, dep, visited)
|
||||
if err == nil {
|
||||
matchers = append(matchers, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(matchers) == 0 {
|
||||
return nil, errors.New("matcher not found for: " + code)
|
||||
}
|
||||
if len(matchers) == 1 {
|
||||
return matchers[0], nil
|
||||
}
|
||||
runtime.GC()
|
||||
return &strmatcher.IndexMatcherGroup{Matchers: matchers}, nil
|
||||
}
|
||||
func LoadGeoSiteHosts(r io.Reader) (map[string][]string, error) {
|
||||
var data geoSiteListGob
|
||||
if err := gob.NewDecoder(r).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data.Hosts, nil
|
||||
}
|
||||
+16
-1
@@ -2,7 +2,7 @@ package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
sync "sync"
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
@@ -181,6 +181,21 @@ func (r *Router) RemoveRule(tag string) error {
|
||||
return errors.New("empty tag name!")
|
||||
|
||||
}
|
||||
|
||||
// ListRule implements routing.Router
|
||||
func (r *Router) ListRule() []routing.Route {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
ruleList := make([]routing.Route, 0)
|
||||
for _, rule := range r.rules {
|
||||
ruleList = append(ruleList, &Route{
|
||||
outboundTag: rule.Tag,
|
||||
ruleTag: rule.RuleTag,
|
||||
})
|
||||
}
|
||||
return ruleList
|
||||
}
|
||||
|
||||
func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {
|
||||
// SkipDNSResolve is set from DNS module.
|
||||
// the DOH remote server maybe a domain name,
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
package antireplay
|
||||
|
||||
type GeneralizedReplayFilter interface {
|
||||
Interval() int64
|
||||
Check(sum []byte) bool
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package antireplay
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkMapFilter(b *testing.B) {
|
||||
filter := NewMapFilter[[16]byte](120)
|
||||
var sample [16]byte
|
||||
reader := bufio.NewReader(rand.Reader)
|
||||
reader.Read(sample[:])
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
reader.Read(sample[:])
|
||||
filter.Check(sample)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapFilter(t *testing.T) {
|
||||
filter := NewMapFilter[[16]byte](120)
|
||||
var sample [16]byte
|
||||
rand.Read(sample[:])
|
||||
filter.Check(sample)
|
||||
if filter.Check(sample) {
|
||||
t.Error("Unexpected true negative")
|
||||
}
|
||||
sample[0]++
|
||||
if !filter.Check(sample) {
|
||||
t.Error("Unexpected false positive")
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package antireplay
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
ss_bloomring "github.com/v2fly/ss-bloomring"
|
||||
)
|
||||
|
||||
type BloomRing struct {
|
||||
*ss_bloomring.BloomRing
|
||||
lock *sync.Mutex
|
||||
}
|
||||
|
||||
func (b BloomRing) Interval() int64 {
|
||||
return 9999999
|
||||
}
|
||||
|
||||
func (b BloomRing) Check(sum []byte) bool {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
if b.Test(sum) {
|
||||
return false
|
||||
}
|
||||
b.Add(sum)
|
||||
return true
|
||||
}
|
||||
|
||||
func NewBloomRing() BloomRing {
|
||||
const (
|
||||
DefaultSFCapacity = 1e6
|
||||
// FalsePositiveRate
|
||||
DefaultSFFPR = 1e-6
|
||||
DefaultSFSlot = 10
|
||||
)
|
||||
return BloomRing{ss_bloomring.NewBloomRing(DefaultSFSlot, DefaultSFCapacity, DefaultSFFPR), &sync.Mutex{}}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package antireplay
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ReplayFilter checks for replay attacks.
|
||||
type ReplayFilter[T comparable] struct {
|
||||
lock sync.Mutex
|
||||
poolA map[T]struct{}
|
||||
poolB map[T]struct{}
|
||||
interval time.Duration
|
||||
lastClean time.Time
|
||||
}
|
||||
|
||||
// NewMapFilter create a new filter with specifying the expiration time interval in seconds.
|
||||
func NewMapFilter[T comparable](interval int64) *ReplayFilter[T] {
|
||||
filter := &ReplayFilter[T]{
|
||||
poolA: make(map[T]struct{}),
|
||||
poolB: make(map[T]struct{}),
|
||||
interval: time.Duration(interval) * time.Second,
|
||||
lastClean: time.Now(),
|
||||
}
|
||||
return filter
|
||||
}
|
||||
|
||||
// Check determines if there are duplicate records.
|
||||
func (filter *ReplayFilter[T]) Check(sum T) bool {
|
||||
filter.lock.Lock()
|
||||
defer filter.lock.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
if now.Sub(filter.lastClean) >= filter.interval {
|
||||
filter.poolB = filter.poolA
|
||||
filter.poolA = make(map[T]struct{})
|
||||
filter.lastClean = now
|
||||
}
|
||||
|
||||
_, existsA := filter.poolA[sum]
|
||||
_, existsB := filter.poolB[sum]
|
||||
if !existsA && !existsB {
|
||||
filter.poolA[sum] = struct{}{}
|
||||
}
|
||||
return !(existsA || existsB)
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package antireplay
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
cuckoo "github.com/seiflotfy/cuckoofilter"
|
||||
)
|
||||
|
||||
const replayFilterCapacity = 100000
|
||||
|
||||
// ReplayFilter checks for replay attacks.
|
||||
type ReplayFilter struct {
|
||||
lock sync.Mutex
|
||||
poolA *cuckoo.Filter
|
||||
poolB *cuckoo.Filter
|
||||
poolSwap bool
|
||||
lastSwap int64
|
||||
interval int64
|
||||
}
|
||||
|
||||
// NewReplayFilter create a new filter with specifying the expiration time interval in seconds.
|
||||
func NewReplayFilter(interval int64) *ReplayFilter {
|
||||
filter := &ReplayFilter{}
|
||||
filter.interval = interval
|
||||
return filter
|
||||
}
|
||||
|
||||
// Interval in second for expiration time for duplicate records.
|
||||
func (filter *ReplayFilter) Interval() int64 {
|
||||
return filter.interval
|
||||
}
|
||||
|
||||
// Check determines if there are duplicate records.
|
||||
func (filter *ReplayFilter) Check(sum []byte) bool {
|
||||
filter.lock.Lock()
|
||||
defer filter.lock.Unlock()
|
||||
|
||||
now := time.Now().Unix()
|
||||
if filter.lastSwap == 0 {
|
||||
filter.lastSwap = now
|
||||
filter.poolA = cuckoo.NewFilter(replayFilterCapacity)
|
||||
filter.poolB = cuckoo.NewFilter(replayFilterCapacity)
|
||||
}
|
||||
|
||||
elapsed := now - filter.lastSwap
|
||||
if elapsed >= filter.Interval() {
|
||||
if filter.poolSwap {
|
||||
filter.poolA.Reset()
|
||||
} else {
|
||||
filter.poolB.Reset()
|
||||
}
|
||||
filter.poolSwap = !filter.poolSwap
|
||||
filter.lastSwap = now
|
||||
}
|
||||
|
||||
return filter.poolA.InsertUnique(sum) && filter.poolB.InsertUnique(sum)
|
||||
}
|
||||
@@ -4,22 +4,19 @@ import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// PrintMigrateFeatureInfo prints a notice of the upcoming feature migration.
|
||||
// Place it after the source feature related config file pharser code.
|
||||
// Important note: Only use this when the target migrating feature is under construction.
|
||||
// Important note: Even when the target migrating feature has finished its construction, this notice can still be used yet before announcing deprecation of the old feature.
|
||||
// PrintNonRemovalDeprecatedFeatureWarning prints a warning of the deprecated feature that won't be removed in the near future.
|
||||
// Do not remove this function even there is no reference to it.
|
||||
func PrintMigrateFeatureInfo(sourceFeature string, targetFeature string) {
|
||||
LogInfo(context.Background(), "The feature "+sourceFeature+" will be migrated to "+targetFeature+" in the future.")
|
||||
func PrintNonRemovalDeprecatedFeatureWarning(sourceFeature string, targetFeature string) {
|
||||
LogWarning(context.Background(), "The feature "+sourceFeature+" is deprecated, not recommended for using and might be removed. Please migrate to "+targetFeature+" as soon as possible.")
|
||||
}
|
||||
|
||||
// PrintDeprecatedFeatureWarning prints a warning for deprecated and going to be removed feature.
|
||||
// Do not remove this function even there is no reference to it.
|
||||
func PrintDeprecatedFeatureWarning(feature string, migrateFeature string) {
|
||||
if len(migrateFeature) > 0 {
|
||||
LogWarning(context.Background(), "This feature "+feature+" is deprecated and being migrated to "+migrateFeature+". Please update your config(s) according to release note and documentation before removal.")
|
||||
LogWarning(context.Background(), "This feature "+feature+" is deprecated, will be removed soon and being migrated to "+migrateFeature+". Please update your config(s) according to release note and documentation before removal.")
|
||||
} else {
|
||||
LogWarning(context.Background(), "This feature "+feature+" is deprecated. Please update your config(s) according to release note and documentation before removal.")
|
||||
LogWarning(context.Background(), "This feature "+feature+" is deprecated and will be removed soon. Please update your config(s) according to release note and documentation before removal.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,10 @@ func ReadAsset(file string) ([]byte, error) {
|
||||
return ReadFile(platform.GetAssetLocation(file))
|
||||
}
|
||||
|
||||
func OpenAsset(file string) (io.ReadCloser, error) {
|
||||
return NewFileReader(platform.GetAssetLocation(file))
|
||||
}
|
||||
|
||||
func ReadCert(file string) ([]byte, error) {
|
||||
if filepath.IsAbs(file) {
|
||||
return ReadFile(file)
|
||||
|
||||
@@ -24,6 +24,8 @@ const (
|
||||
XUDPBaseKey = "xray.xudp.basekey"
|
||||
|
||||
TunFdKey = "xray.tun.fd"
|
||||
|
||||
MphCachePath = "xray.mph.cache"
|
||||
)
|
||||
|
||||
type EnvFlag struct {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
@@ -87,10 +88,10 @@ func Organization(org string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func MustGenerate(parent *Certificate, opts ...Option) *Certificate {
|
||||
func MustGenerate(parent *Certificate, opts ...Option) (*Certificate, [32]byte) {
|
||||
cert, err := Generate(parent, opts...)
|
||||
common.Must(err)
|
||||
return cert
|
||||
return cert, sha256.Sum256(cert.Certificate)
|
||||
}
|
||||
|
||||
func publicKey(priv interface{}) interface{} {
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
const validCharCount = 53
|
||||
|
||||
type MatchType struct {
|
||||
matchType Type
|
||||
exist bool
|
||||
Type Type
|
||||
Exist bool
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -17,23 +17,23 @@ const (
|
||||
)
|
||||
|
||||
type Edge struct {
|
||||
edgeType bool
|
||||
nextNode int
|
||||
Type bool
|
||||
NextNode int
|
||||
}
|
||||
|
||||
type ACAutomaton struct {
|
||||
trie [][validCharCount]Edge
|
||||
fail []int
|
||||
exists []MatchType
|
||||
count int
|
||||
Trie [][validCharCount]Edge
|
||||
Fail []int
|
||||
Exists []MatchType
|
||||
Count int
|
||||
}
|
||||
|
||||
func newNode() [validCharCount]Edge {
|
||||
var s [validCharCount]Edge
|
||||
for i := range s {
|
||||
s[i] = Edge{
|
||||
edgeType: FailEdge,
|
||||
nextNode: 0,
|
||||
Type: FailEdge,
|
||||
NextNode: 0,
|
||||
}
|
||||
}
|
||||
return s
|
||||
@@ -123,11 +123,11 @@ var char2Index = []int{
|
||||
|
||||
func NewACAutomaton() *ACAutomaton {
|
||||
ac := new(ACAutomaton)
|
||||
ac.trie = append(ac.trie, newNode())
|
||||
ac.fail = append(ac.fail, 0)
|
||||
ac.exists = append(ac.exists, MatchType{
|
||||
matchType: Full,
|
||||
exist: false,
|
||||
ac.Trie = append(ac.Trie, newNode())
|
||||
ac.Fail = append(ac.Fail, 0)
|
||||
ac.Exists = append(ac.Exists, MatchType{
|
||||
Type: Full,
|
||||
Exist: false,
|
||||
})
|
||||
return ac
|
||||
}
|
||||
@@ -136,53 +136,53 @@ func (ac *ACAutomaton) Add(domain string, t Type) {
|
||||
node := 0
|
||||
for i := len(domain) - 1; i >= 0; i-- {
|
||||
idx := char2Index[domain[i]]
|
||||
if ac.trie[node][idx].nextNode == 0 {
|
||||
ac.count++
|
||||
if len(ac.trie) < ac.count+1 {
|
||||
ac.trie = append(ac.trie, newNode())
|
||||
ac.fail = append(ac.fail, 0)
|
||||
ac.exists = append(ac.exists, MatchType{
|
||||
matchType: Full,
|
||||
exist: false,
|
||||
if ac.Trie[node][idx].NextNode == 0 {
|
||||
ac.Count++
|
||||
if len(ac.Trie) < ac.Count+1 {
|
||||
ac.Trie = append(ac.Trie, newNode())
|
||||
ac.Fail = append(ac.Fail, 0)
|
||||
ac.Exists = append(ac.Exists, MatchType{
|
||||
Type: Full,
|
||||
Exist: false,
|
||||
})
|
||||
}
|
||||
ac.trie[node][idx] = Edge{
|
||||
edgeType: TrieEdge,
|
||||
nextNode: ac.count,
|
||||
ac.Trie[node][idx] = Edge{
|
||||
Type: TrieEdge,
|
||||
NextNode: ac.Count,
|
||||
}
|
||||
}
|
||||
node = ac.trie[node][idx].nextNode
|
||||
node = ac.Trie[node][idx].NextNode
|
||||
}
|
||||
ac.exists[node] = MatchType{
|
||||
matchType: t,
|
||||
exist: true,
|
||||
ac.Exists[node] = MatchType{
|
||||
Type: t,
|
||||
Exist: true,
|
||||
}
|
||||
switch t {
|
||||
case Domain:
|
||||
ac.exists[node] = MatchType{
|
||||
matchType: Full,
|
||||
exist: true,
|
||||
ac.Exists[node] = MatchType{
|
||||
Type: Full,
|
||||
Exist: true,
|
||||
}
|
||||
idx := char2Index['.']
|
||||
if ac.trie[node][idx].nextNode == 0 {
|
||||
ac.count++
|
||||
if len(ac.trie) < ac.count+1 {
|
||||
ac.trie = append(ac.trie, newNode())
|
||||
ac.fail = append(ac.fail, 0)
|
||||
ac.exists = append(ac.exists, MatchType{
|
||||
matchType: Full,
|
||||
exist: false,
|
||||
if ac.Trie[node][idx].NextNode == 0 {
|
||||
ac.Count++
|
||||
if len(ac.Trie) < ac.Count+1 {
|
||||
ac.Trie = append(ac.Trie, newNode())
|
||||
ac.Fail = append(ac.Fail, 0)
|
||||
ac.Exists = append(ac.Exists, MatchType{
|
||||
Type: Full,
|
||||
Exist: false,
|
||||
})
|
||||
}
|
||||
ac.trie[node][idx] = Edge{
|
||||
edgeType: TrieEdge,
|
||||
nextNode: ac.count,
|
||||
ac.Trie[node][idx] = Edge{
|
||||
Type: TrieEdge,
|
||||
NextNode: ac.Count,
|
||||
}
|
||||
}
|
||||
node = ac.trie[node][idx].nextNode
|
||||
ac.exists[node] = MatchType{
|
||||
matchType: t,
|
||||
exist: true,
|
||||
node = ac.Trie[node][idx].NextNode
|
||||
ac.Exists[node] = MatchType{
|
||||
Type: t,
|
||||
Exist: true,
|
||||
}
|
||||
default:
|
||||
break
|
||||
@@ -192,8 +192,8 @@ func (ac *ACAutomaton) Add(domain string, t Type) {
|
||||
func (ac *ACAutomaton) Build() {
|
||||
queue := list.New()
|
||||
for i := 0; i < validCharCount; i++ {
|
||||
if ac.trie[0][i].nextNode != 0 {
|
||||
queue.PushBack(ac.trie[0][i])
|
||||
if ac.Trie[0][i].NextNode != 0 {
|
||||
queue.PushBack(ac.Trie[0][i])
|
||||
}
|
||||
}
|
||||
for {
|
||||
@@ -201,16 +201,16 @@ func (ac *ACAutomaton) Build() {
|
||||
if front == nil {
|
||||
break
|
||||
} else {
|
||||
node := front.Value.(Edge).nextNode
|
||||
node := front.Value.(Edge).NextNode
|
||||
queue.Remove(front)
|
||||
for i := 0; i < validCharCount; i++ {
|
||||
if ac.trie[node][i].nextNode != 0 {
|
||||
ac.fail[ac.trie[node][i].nextNode] = ac.trie[ac.fail[node]][i].nextNode
|
||||
queue.PushBack(ac.trie[node][i])
|
||||
if ac.Trie[node][i].NextNode != 0 {
|
||||
ac.Fail[ac.Trie[node][i].NextNode] = ac.Trie[ac.Fail[node]][i].NextNode
|
||||
queue.PushBack(ac.Trie[node][i])
|
||||
} else {
|
||||
ac.trie[node][i] = Edge{
|
||||
edgeType: FailEdge,
|
||||
nextNode: ac.trie[ac.fail[node]][i].nextNode,
|
||||
ac.Trie[node][i] = Edge{
|
||||
Type: FailEdge,
|
||||
NextNode: ac.Trie[ac.Fail[node]][i].NextNode,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,9 +230,9 @@ func (ac *ACAutomaton) Match(s string) bool {
|
||||
return false
|
||||
}
|
||||
idx := char2Index[chr]
|
||||
fullMatch = fullMatch && ac.trie[node][idx].edgeType
|
||||
node = ac.trie[node][idx].nextNode
|
||||
switch ac.exists[node].matchType {
|
||||
fullMatch = fullMatch && ac.Trie[node][idx].Type
|
||||
node = ac.Trie[node][idx].NextNode
|
||||
switch ac.Exists[node].Type {
|
||||
case Substr:
|
||||
return true
|
||||
case Domain:
|
||||
@@ -243,5 +243,5 @@ func (ac *ACAutomaton) Match(s string) bool {
|
||||
break
|
||||
}
|
||||
}
|
||||
return fullMatch && ac.exists[node].exist
|
||||
return fullMatch && ac.Exists[node].Exist
|
||||
}
|
||||
|
||||
@@ -39,14 +39,18 @@ func (m domainMatcher) String() string {
|
||||
return "domain:" + string(m)
|
||||
}
|
||||
|
||||
type regexMatcher struct {
|
||||
pattern *regexp.Regexp
|
||||
type RegexMatcher struct {
|
||||
Pattern string
|
||||
reg *regexp.Regexp
|
||||
}
|
||||
|
||||
func (m *regexMatcher) Match(s string) bool {
|
||||
return m.pattern.MatchString(s)
|
||||
func (m *RegexMatcher) Match(s string) bool {
|
||||
if m.reg == nil {
|
||||
m.reg = regexp.MustCompile(m.Pattern)
|
||||
}
|
||||
return m.reg.MatchString(s)
|
||||
}
|
||||
|
||||
func (m *regexMatcher) String() string {
|
||||
return "regexp:" + m.pattern.String()
|
||||
func (m *RegexMatcher) String() string {
|
||||
return "regexp:" + m.Pattern
|
||||
}
|
||||
|
||||
@@ -25,40 +25,40 @@ func RollingHash(s string) uint32 {
|
||||
// 2. `substr` patterns are matched by ac automaton;
|
||||
// 3. `regex` patterns are matched with the regex library.
|
||||
type MphMatcherGroup struct {
|
||||
ac *ACAutomaton
|
||||
otherMatchers []matcherEntry
|
||||
rules []string
|
||||
level0 []uint32
|
||||
level0Mask int
|
||||
level1 []uint32
|
||||
level1Mask int
|
||||
count uint32
|
||||
ruleMap *map[string]uint32
|
||||
Ac *ACAutomaton
|
||||
OtherMatchers []MatcherEntry
|
||||
Rules []string
|
||||
Level0 []uint32
|
||||
Level0Mask int
|
||||
Level1 []uint32
|
||||
Level1Mask int
|
||||
Count uint32
|
||||
RuleMap *map[string]uint32
|
||||
}
|
||||
|
||||
func (g *MphMatcherGroup) AddFullOrDomainPattern(pattern string, t Type) {
|
||||
h := RollingHash(pattern)
|
||||
switch t {
|
||||
case Domain:
|
||||
(*g.ruleMap)["."+pattern] = h*PrimeRK + uint32('.')
|
||||
(*g.RuleMap)["."+pattern] = h*PrimeRK + uint32('.')
|
||||
fallthrough
|
||||
case Full:
|
||||
(*g.ruleMap)[pattern] = h
|
||||
(*g.RuleMap)[pattern] = h
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func NewMphMatcherGroup() *MphMatcherGroup {
|
||||
return &MphMatcherGroup{
|
||||
ac: nil,
|
||||
otherMatchers: nil,
|
||||
rules: nil,
|
||||
level0: nil,
|
||||
level0Mask: 0,
|
||||
level1: nil,
|
||||
level1Mask: 0,
|
||||
count: 1,
|
||||
ruleMap: &map[string]uint32{},
|
||||
Ac: nil,
|
||||
OtherMatchers: nil,
|
||||
Rules: nil,
|
||||
Level0: nil,
|
||||
Level0Mask: 0,
|
||||
Level1: nil,
|
||||
Level1Mask: 0,
|
||||
Count: 1,
|
||||
RuleMap: &map[string]uint32{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,10 +66,10 @@ func NewMphMatcherGroup() *MphMatcherGroup {
|
||||
func (g *MphMatcherGroup) AddPattern(pattern string, t Type) (uint32, error) {
|
||||
switch t {
|
||||
case Substr:
|
||||
if g.ac == nil {
|
||||
g.ac = NewACAutomaton()
|
||||
if g.Ac == nil {
|
||||
g.Ac = NewACAutomaton()
|
||||
}
|
||||
g.ac.Add(pattern, t)
|
||||
g.Ac.Add(pattern, t)
|
||||
case Full, Domain:
|
||||
pattern = strings.ToLower(pattern)
|
||||
g.AddFullOrDomainPattern(pattern, t)
|
||||
@@ -78,39 +78,39 @@ func (g *MphMatcherGroup) AddPattern(pattern string, t Type) (uint32, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
g.otherMatchers = append(g.otherMatchers, matcherEntry{
|
||||
m: ®exMatcher{pattern: r},
|
||||
id: g.count,
|
||||
g.OtherMatchers = append(g.OtherMatchers, MatcherEntry{
|
||||
M: &RegexMatcher{Pattern: pattern, reg: r},
|
||||
Id: g.Count,
|
||||
})
|
||||
default:
|
||||
panic("Unknown type")
|
||||
}
|
||||
return g.count, nil
|
||||
return g.Count, nil
|
||||
}
|
||||
|
||||
// Build builds a minimal perfect hash table and ac automaton from insert rules
|
||||
func (g *MphMatcherGroup) Build() {
|
||||
if g.ac != nil {
|
||||
g.ac.Build()
|
||||
if g.Ac != nil {
|
||||
g.Ac.Build()
|
||||
}
|
||||
keyLen := len(*g.ruleMap)
|
||||
keyLen := len(*g.RuleMap)
|
||||
if keyLen == 0 {
|
||||
keyLen = 1
|
||||
(*g.ruleMap)["empty___"] = RollingHash("empty___")
|
||||
(*g.RuleMap)["empty___"] = RollingHash("empty___")
|
||||
}
|
||||
g.level0 = make([]uint32, nextPow2(keyLen/4))
|
||||
g.level0Mask = len(g.level0) - 1
|
||||
g.level1 = make([]uint32, nextPow2(keyLen))
|
||||
g.level1Mask = len(g.level1) - 1
|
||||
sparseBuckets := make([][]int, len(g.level0))
|
||||
g.Level0 = make([]uint32, nextPow2(keyLen/4))
|
||||
g.Level0Mask = len(g.Level0) - 1
|
||||
g.Level1 = make([]uint32, nextPow2(keyLen))
|
||||
g.Level1Mask = len(g.Level1) - 1
|
||||
sparseBuckets := make([][]int, len(g.Level0))
|
||||
var ruleIdx int
|
||||
for rule, hash := range *g.ruleMap {
|
||||
n := int(hash) & g.level0Mask
|
||||
g.rules = append(g.rules, rule)
|
||||
for rule, hash := range *g.RuleMap {
|
||||
n := int(hash) & g.Level0Mask
|
||||
g.Rules = append(g.Rules, rule)
|
||||
sparseBuckets[n] = append(sparseBuckets[n], ruleIdx)
|
||||
ruleIdx++
|
||||
}
|
||||
g.ruleMap = nil
|
||||
g.RuleMap = nil
|
||||
var buckets []indexBucket
|
||||
for n, vals := range sparseBuckets {
|
||||
if len(vals) > 0 {
|
||||
@@ -119,7 +119,7 @@ func (g *MphMatcherGroup) Build() {
|
||||
}
|
||||
sort.Sort(bySize(buckets))
|
||||
|
||||
occ := make([]bool, len(g.level1))
|
||||
occ := make([]bool, len(g.Level1))
|
||||
var tmpOcc []int
|
||||
for _, bucket := range buckets {
|
||||
seed := uint32(0)
|
||||
@@ -127,7 +127,7 @@ func (g *MphMatcherGroup) Build() {
|
||||
findSeed := true
|
||||
tmpOcc = tmpOcc[:0]
|
||||
for _, i := range bucket.vals {
|
||||
n := int(strhashFallback(unsafe.Pointer(&g.rules[i]), uintptr(seed))) & g.level1Mask
|
||||
n := int(strhashFallback(unsafe.Pointer(&g.Rules[i]), uintptr(seed))) & g.Level1Mask
|
||||
if occ[n] {
|
||||
for _, n := range tmpOcc {
|
||||
occ[n] = false
|
||||
@@ -138,10 +138,10 @@ func (g *MphMatcherGroup) Build() {
|
||||
}
|
||||
occ[n] = true
|
||||
tmpOcc = append(tmpOcc, n)
|
||||
g.level1[n] = uint32(i)
|
||||
g.Level1[n] = uint32(i)
|
||||
}
|
||||
if findSeed {
|
||||
g.level0[bucket.n] = seed
|
||||
g.Level0[bucket.n] = seed
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -159,11 +159,11 @@ func nextPow2(v int) int {
|
||||
|
||||
// Lookup searches for s in t and returns its index and whether it was found.
|
||||
func (g *MphMatcherGroup) Lookup(h uint32, s string) bool {
|
||||
i0 := int(h) & g.level0Mask
|
||||
seed := g.level0[i0]
|
||||
i1 := int(strhashFallback(unsafe.Pointer(&s), uintptr(seed))) & g.level1Mask
|
||||
n := g.level1[i1]
|
||||
return s == g.rules[int(n)]
|
||||
i0 := int(h) & g.Level0Mask
|
||||
seed := g.Level0[i0]
|
||||
i1 := int(strhashFallback(unsafe.Pointer(&s), uintptr(seed))) & g.Level1Mask
|
||||
n := g.Level1[i1]
|
||||
return s == g.Rules[int(n)]
|
||||
}
|
||||
|
||||
// Match implements IndexMatcher.Match.
|
||||
@@ -183,13 +183,13 @@ func (g *MphMatcherGroup) Match(pattern string) []uint32 {
|
||||
result = append(result, 1)
|
||||
return result
|
||||
}
|
||||
if g.ac != nil && g.ac.Match(pattern) {
|
||||
if g.Ac != nil && g.Ac.Match(pattern) {
|
||||
result = append(result, 1)
|
||||
return result
|
||||
}
|
||||
for _, e := range g.otherMatchers {
|
||||
if e.m.Match(pattern) {
|
||||
result = append(result, e.id)
|
||||
for _, e := range g.OtherMatchers {
|
||||
if e.M.Match(pattern) {
|
||||
result = append(result, e.Id)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -302,3 +302,7 @@ func readUnaligned64(p unsafe.Pointer) uint64 {
|
||||
q := (*[8]byte)(p)
|
||||
return uint64(q[0]) | uint64(q[1])<<8 | uint64(q[2])<<16 | uint64(q[3])<<24 | uint64(q[4])<<32 | uint64(q[5])<<40 | uint64(q[6])<<48 | uint64(q[7])<<56
|
||||
}
|
||||
|
||||
func (g *MphMatcherGroup) Size() uint32 {
|
||||
return g.Count
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package strmatcher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"io"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(&RegexMatcher{})
|
||||
gob.Register(fullMatcher(""))
|
||||
gob.Register(substrMatcher(""))
|
||||
gob.Register(domainMatcher(""))
|
||||
}
|
||||
|
||||
func (g *MphMatcherGroup) Serialize(w io.Writer) error {
|
||||
data := MphMatcherGroup{
|
||||
Ac: g.Ac,
|
||||
OtherMatchers: g.OtherMatchers,
|
||||
Rules: g.Rules,
|
||||
Level0: g.Level0,
|
||||
Level0Mask: g.Level0Mask,
|
||||
Level1: g.Level1,
|
||||
Level1Mask: g.Level1Mask,
|
||||
Count: g.Count,
|
||||
}
|
||||
return gob.NewEncoder(w).Encode(data)
|
||||
}
|
||||
|
||||
func NewMphMatcherGroupFromBuffer(data []byte) (*MphMatcherGroup, error) {
|
||||
var gData MphMatcherGroup
|
||||
if err := gob.NewDecoder(bytes.NewReader(data)).Decode(&gData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
g := NewMphMatcherGroup()
|
||||
g.Ac = gData.Ac
|
||||
g.OtherMatchers = gData.OtherMatchers
|
||||
g.Rules = gData.Rules
|
||||
g.Level0 = gData.Level0
|
||||
g.Level0Mask = gData.Level0Mask
|
||||
g.Level1 = gData.Level1
|
||||
g.Level1Mask = gData.Level1Mask
|
||||
g.Count = gData.Count
|
||||
|
||||
return g, nil
|
||||
}
|
||||
@@ -41,8 +41,9 @@ func (t Type) New(pattern string) (Matcher, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ®exMatcher{
|
||||
pattern: r,
|
||||
return &RegexMatcher{
|
||||
Pattern: pattern,
|
||||
reg: r,
|
||||
}, nil
|
||||
default:
|
||||
return nil, errors.New("unk type")
|
||||
@@ -53,11 +54,13 @@ func (t Type) New(pattern string) (Matcher, error) {
|
||||
type IndexMatcher interface {
|
||||
// Match returns the index of a matcher that matches the input. It returns empty array if no such matcher exists.
|
||||
Match(input string) []uint32
|
||||
// Size returns the number of matchers in the group.
|
||||
Size() uint32
|
||||
}
|
||||
|
||||
type matcherEntry struct {
|
||||
m Matcher
|
||||
id uint32
|
||||
type MatcherEntry struct {
|
||||
M Matcher
|
||||
Id uint32
|
||||
}
|
||||
|
||||
// MatcherGroup is an implementation of IndexMatcher.
|
||||
@@ -66,7 +69,7 @@ type MatcherGroup struct {
|
||||
count uint32
|
||||
fullMatcher FullMatcherGroup
|
||||
domainMatcher DomainMatcherGroup
|
||||
otherMatchers []matcherEntry
|
||||
otherMatchers []MatcherEntry
|
||||
}
|
||||
|
||||
// Add adds a new Matcher into the MatcherGroup, and returns its index. The index will never be 0.
|
||||
@@ -80,9 +83,9 @@ func (g *MatcherGroup) Add(m Matcher) uint32 {
|
||||
case domainMatcher:
|
||||
g.domainMatcher.addMatcher(tm, c)
|
||||
default:
|
||||
g.otherMatchers = append(g.otherMatchers, matcherEntry{
|
||||
m: m,
|
||||
id: c,
|
||||
g.otherMatchers = append(g.otherMatchers, MatcherEntry{
|
||||
M: m,
|
||||
Id: c,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -95,8 +98,8 @@ func (g *MatcherGroup) Match(pattern string) []uint32 {
|
||||
result = append(result, g.fullMatcher.Match(pattern)...)
|
||||
result = append(result, g.domainMatcher.Match(pattern)...)
|
||||
for _, e := range g.otherMatchers {
|
||||
if e.m.Match(pattern) {
|
||||
result = append(result, e.id)
|
||||
if e.M.Match(pattern) {
|
||||
result = append(result, e.Id)
|
||||
}
|
||||
}
|
||||
return result
|
||||
@@ -106,3 +109,33 @@ func (g *MatcherGroup) Match(pattern string) []uint32 {
|
||||
func (g *MatcherGroup) Size() uint32 {
|
||||
return g.count
|
||||
}
|
||||
|
||||
type IndexMatcherGroup struct {
|
||||
Matchers []IndexMatcher
|
||||
}
|
||||
|
||||
func (g *IndexMatcherGroup) Match(input string) []uint32 {
|
||||
var offset uint32
|
||||
for _, m := range g.Matchers {
|
||||
if res := m.Match(input); len(res) > 0 {
|
||||
if offset == 0 {
|
||||
return res
|
||||
}
|
||||
shifted := make([]uint32, len(res))
|
||||
for i, id := range res {
|
||||
shifted[i] = id + offset
|
||||
}
|
||||
return shifted
|
||||
}
|
||||
offset += m.Size()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *IndexMatcherGroup) Size() uint32 {
|
||||
var count uint32
|
||||
for _, m := range g.Matchers {
|
||||
count += m.Size()
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"math/rand/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
// 8 ÷ (397/62)
|
||||
h2packCorrectionFactor = 1.2493702770780857
|
||||
base62TotalCharsNum = 62
|
||||
base62Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
)
|
||||
|
||||
// H2Base62Pad generates a base62 padding string for HTTP/2 header
|
||||
// The total len will be slightly longer than the input to match the length after h2(h3 also) header huffman encoding
|
||||
func H2Base62Pad[T int32 | int64 | int](expectedLen T) string {
|
||||
actualLenFloat := float64(expectedLen) * h2packCorrectionFactor
|
||||
actualLen := int(actualLenFloat)
|
||||
result := make([]byte, actualLen)
|
||||
for i := range actualLen {
|
||||
result[i] = base62Chars[rand.N(base62TotalCharsNum)]
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
@@ -35,6 +35,7 @@ func init() {
|
||||
if strings.ToLower(platform.NewEnvFlag(platform.XUDPLog).GetValue(func() string { return "" })) == "true" {
|
||||
Show = true
|
||||
}
|
||||
BaseKey = make([]byte, 32)
|
||||
rand.Read(BaseKey)
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) // this is not nice, but need to give some time for Android to setup ENV
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ import (
|
||||
var (
|
||||
Version_x byte = 26
|
||||
Version_y byte = 1
|
||||
Version_z byte = 18
|
||||
Version_z byte = 31
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -16,6 +16,7 @@ type Router interface {
|
||||
PickRoute(ctx Context) (Route, error)
|
||||
AddRule(config *serial.TypedMessage, shouldAppend bool) error
|
||||
RemoveRule(tag string) error
|
||||
ListRule() []Route
|
||||
}
|
||||
|
||||
// Route is the routing result of Router feature.
|
||||
@@ -65,6 +66,11 @@ func (DefaultRouter) RemoveRule(tag string) error {
|
||||
return common.ErrNoClue
|
||||
}
|
||||
|
||||
// ListRule implements Router.
|
||||
func (DefaultRouter) ListRule() []Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start implements common.Runnable.
|
||||
func (DefaultRouter) Start() error {
|
||||
return nil
|
||||
|
||||
@@ -4,20 +4,18 @@ go 1.25.6
|
||||
|
||||
require (
|
||||
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178
|
||||
github.com/cloudflare/circl v1.6.2
|
||||
github.com/cloudflare/circl v1.6.3
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
||||
github.com/golang/mock v1.7.0-rc.1
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/miekg/dns v1.1.70
|
||||
github.com/miekg/dns v1.1.72
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pires/go-proxyproto v0.8.1
|
||||
github.com/pires/go-proxyproto v0.9.2
|
||||
github.com/refraction-networking/utls v1.8.2
|
||||
github.com/sagernet/sing v0.5.1
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
github.com/xtls/reality v0.0.0-20251014195629-e4eec4520535
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
@@ -30,7 +28,7 @@ require (
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gvisor.dev/gvisor v0.0.0-20260109181451-4be7c433dae2
|
||||
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0
|
||||
h12.io/socks v1.0.3
|
||||
lukechampine.com/blake3 v1.4.1
|
||||
)
|
||||
@@ -38,7 +36,6 @@ require (
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/juju/ratelimit v1.0.2 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
@@ -46,7 +43,6 @@ require (
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
golang.org/x/mod v0.31.0 // indirect
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
|
||||
@@ -2,14 +2,11 @@ github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sx
|
||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178 h1:bSq8n+gX4oO/qnM3MKf4kroW75n+phO9Qp6nigJKZ1E=
|
||||
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178/go.mod h1:N1WIjPphkqs4efXWuyDNQ6OjjIK04vM3h+bEgwV+eVU=
|
||||
github.com/cloudflare/circl v1.6.2 h1:hL7VBpHHKzrV5WTfHCaBsgx/HGbBYlgrwvNXEVDYYsQ=
|
||||
github.com/cloudflare/circl v1.6.2/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E=
|
||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
@@ -40,36 +37,28 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/miekg/dns v1.1.70 h1:DZ4u2AV35VJxdD9Fo9fIWm119BsQL5cZU1cQ9s0LkqA=
|
||||
github.com/miekg/dns v1.1.70/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
||||
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
|
||||
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||
github.com/pires/go-proxyproto v0.9.2 h1:H1UdHn695zUVVmB0lQ354lOWHOy6TZSpzBl3tgN0s1U=
|
||||
github.com/pires/go-proxyproto v0.9.2/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo=
|
||||
github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
||||
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1L9iaKCTxdy3Em8Wv4ChIAGnfiz18Cda70g4=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
@@ -154,12 +143,10 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gvisor.dev/gvisor v0.0.0-20260109181451-4be7c433dae2 h1:fr6L00yGG2RP5NMea6njWpdC+bm+cMdFClrSpaicp1c=
|
||||
gvisor.dev/gvisor v0.0.0-20260109181451-4be7c433dae2/go.mod h1:QkHjoMIBaYtpVufgwv3keYAbln78mBoCuShZrPrer1Q=
|
||||
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0 h1:Lk6hARj5UPY47dBep70OD/TIMwikJ5fGUGX0Rm3Xigk=
|
||||
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0/go.mod h1:QkHjoMIBaYtpVufgwv3keYAbln78mBoCuShZrPrer1Q=
|
||||
h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
||||
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
||||
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
||||
|
||||
+96
-91
@@ -1,7 +1,10 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -9,6 +12,7 @@ import (
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -102,7 +106,7 @@ func (c *RouterConfig) Build() (*router.Config, error) {
|
||||
}
|
||||
|
||||
for _, rawRule := range rawRuleList {
|
||||
rule, err := ParseRule(rawRule)
|
||||
rule, err := parseRule(rawRule)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -125,7 +129,7 @@ type RouterRule struct {
|
||||
BalancerTag string `json:"balancerTag"`
|
||||
}
|
||||
|
||||
func ParseIP(s string) (*router.CIDR, error) {
|
||||
func parseIP(s string) (*router.CIDR, error) {
|
||||
var addr, mask string
|
||||
i := strings.Index(s, "/")
|
||||
if i < 0 {
|
||||
@@ -173,125 +177,126 @@ func ParseIP(s string) (*router.CIDR, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func loadGeoIP(code string) ([]*router.CIDR, error) {
|
||||
return loadIP("geoip.dat", code)
|
||||
}
|
||||
|
||||
var (
|
||||
FileCache = make(map[string][]byte)
|
||||
IPCache = make(map[string]*router.GeoIP)
|
||||
SiteCache = make(map[string]*router.GeoSite)
|
||||
)
|
||||
|
||||
func loadFile(file string) ([]byte, error) {
|
||||
if FileCache[file] == nil {
|
||||
bs, err := filesystem.ReadAsset(file)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to open file: ", file).Base(err)
|
||||
}
|
||||
if len(bs) == 0 {
|
||||
return nil, errors.New("empty file: ", file)
|
||||
}
|
||||
// Do not cache file, may save RAM when there
|
||||
// are many files, but consume CPU each time.
|
||||
return bs, nil
|
||||
FileCache[file] = bs
|
||||
func loadFile(file, code string) ([]byte, error) {
|
||||
runtime.GC()
|
||||
r, err := filesystem.OpenAsset(file)
|
||||
defer r.Close()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to open file: ", file).Base(err)
|
||||
}
|
||||
return FileCache[file], nil
|
||||
bs := find(r, []byte(code))
|
||||
if bs == nil {
|
||||
return nil, errors.New("code not found in ", file, ": ", code)
|
||||
}
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
func loadIP(file, code string) ([]*router.CIDR, error) {
|
||||
index := file + ":" + code
|
||||
if IPCache[index] == nil {
|
||||
bs, err := loadFile(file)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to load file: ", file).Base(err)
|
||||
}
|
||||
bs = find(bs, []byte(code))
|
||||
if bs == nil {
|
||||
return nil, errors.New("code not found in ", file, ": ", code)
|
||||
}
|
||||
var geoip router.GeoIP
|
||||
if err := proto.Unmarshal(bs, &geoip); err != nil {
|
||||
return nil, errors.New("error unmarshal IP in ", file, ": ", code).Base(err)
|
||||
}
|
||||
defer runtime.GC() // or debug.FreeOSMemory()
|
||||
return geoip.Cidr, nil // do not cache geoip
|
||||
IPCache[index] = &geoip
|
||||
bs, err := loadFile(file, code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return IPCache[index].Cidr, nil
|
||||
var geoip router.GeoIP
|
||||
if err := proto.Unmarshal(bs, &geoip); err != nil {
|
||||
return nil, errors.New("error unmarshal IP in ", file, ": ", code).Base(err)
|
||||
}
|
||||
defer runtime.GC() // or debug.FreeOSMemory()
|
||||
return geoip.Cidr, nil
|
||||
}
|
||||
|
||||
func loadSite(file, code string) ([]*router.Domain, error) {
|
||||
index := file + ":" + code
|
||||
if SiteCache[index] == nil {
|
||||
bs, err := loadFile(file)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to load file: ", file).Base(err)
|
||||
}
|
||||
bs = find(bs, []byte(code))
|
||||
if bs == nil {
|
||||
return nil, errors.New("list not found in ", file, ": ", code)
|
||||
}
|
||||
var geosite router.GeoSite
|
||||
if err := proto.Unmarshal(bs, &geosite); err != nil {
|
||||
return nil, errors.New("error unmarshal Site in ", file, ": ", code).Base(err)
|
||||
}
|
||||
defer runtime.GC() // or debug.FreeOSMemory()
|
||||
return geosite.Domain, nil // do not cache geosite
|
||||
SiteCache[index] = &geosite
|
||||
|
||||
// Check if domain matcher cache is provided via environment
|
||||
domainMatcherPath := platform.NewEnvFlag(platform.MphCachePath).GetValue(func() string { return "" })
|
||||
if domainMatcherPath != "" {
|
||||
return []*router.Domain{{}}, nil
|
||||
}
|
||||
return SiteCache[index].Domain, nil
|
||||
|
||||
bs, err := loadFile(file, code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var geosite router.GeoSite
|
||||
if err := proto.Unmarshal(bs, &geosite); err != nil {
|
||||
return nil, errors.New("error unmarshal Site in ", file, ": ", code).Base(err)
|
||||
}
|
||||
defer runtime.GC() // or debug.FreeOSMemory()
|
||||
return geosite.Domain, nil
|
||||
}
|
||||
|
||||
func DecodeVarint(buf []byte) (x uint64, n int) {
|
||||
func decodeVarint(r *bufio.Reader) (uint64, error) {
|
||||
var x uint64
|
||||
for shift := uint(0); shift < 64; shift += 7 {
|
||||
if n >= len(buf) {
|
||||
return 0, 0
|
||||
b, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
b := uint64(buf[n])
|
||||
n++
|
||||
x |= (b & 0x7F) << shift
|
||||
x |= (uint64(b) & 0x7F) << shift
|
||||
if (b & 0x80) == 0 {
|
||||
return x, n
|
||||
return x, nil
|
||||
}
|
||||
}
|
||||
|
||||
// The number is too large to represent in a 64-bit value.
|
||||
return 0, 0
|
||||
return 0, errors.New("varint overflow")
|
||||
}
|
||||
|
||||
func find(data, code []byte) []byte {
|
||||
func find(r io.Reader, code []byte) []byte {
|
||||
codeL := len(code)
|
||||
if codeL == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
br := bufio.NewReaderSize(r, 64*1024)
|
||||
need := 2 + codeL
|
||||
prefixBuf := make([]byte, need)
|
||||
|
||||
for {
|
||||
dataL := len(data)
|
||||
if dataL < 2 {
|
||||
if _, err := br.ReadByte(); err != nil {
|
||||
return nil
|
||||
}
|
||||
x, y := DecodeVarint(data[1:])
|
||||
if x == 0 && y == 0 {
|
||||
|
||||
x, err := decodeVarint(br)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
headL, bodyL := 1+y, int(x)
|
||||
dataL -= headL
|
||||
if dataL < bodyL {
|
||||
bodyL := int(x)
|
||||
if bodyL <= 0 {
|
||||
return nil
|
||||
}
|
||||
data = data[headL:]
|
||||
if int(data[1]) == codeL {
|
||||
for i := 0; i < codeL && data[2+i] == code[i]; i++ {
|
||||
if i+1 == codeL {
|
||||
return data[:bodyL]
|
||||
}
|
||||
|
||||
prefixL := bodyL
|
||||
if prefixL > need {
|
||||
prefixL = need
|
||||
}
|
||||
prefix := prefixBuf[:prefixL]
|
||||
if _, err := io.ReadFull(br, prefix); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
match := false
|
||||
if bodyL >= need {
|
||||
if int(prefix[1]) == codeL && bytes.Equal(prefix[2:need], code) {
|
||||
match = true
|
||||
}
|
||||
}
|
||||
if dataL == bodyL {
|
||||
return nil
|
||||
|
||||
remain := bodyL - prefixL
|
||||
if match {
|
||||
out := make([]byte, bodyL)
|
||||
copy(out, prefix)
|
||||
if remain > 0 {
|
||||
if _, err := io.ReadFull(br, out[prefixL:]); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
if remain > 0 {
|
||||
if _, err := br.Discard(remain); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
data = data[bodyL:]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,7 +452,7 @@ func ToCidrList(ips StringList) ([]*router.GeoIP, error) {
|
||||
if len(country) == 0 {
|
||||
return nil, errors.New("empty country name in rule")
|
||||
}
|
||||
geoip, err := loadGeoIP(strings.ToUpper(country))
|
||||
geoip, err := loadIP("geoip.dat", strings.ToUpper(country))
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to load GeoIP: ", country).Base(err)
|
||||
}
|
||||
@@ -501,7 +506,7 @@ func ToCidrList(ips StringList) ([]*router.GeoIP, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
ipRule, err := ParseIP(ip)
|
||||
ipRule, err := parseIP(ip)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid IP: ", ip).Base(err)
|
||||
}
|
||||
@@ -655,7 +660,7 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
func ParseRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
func parseRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
rawRule := new(RouterRule)
|
||||
err := json.Unmarshal(msg, rawRule)
|
||||
if err != nil {
|
||||
|
||||
@@ -46,11 +46,10 @@ type ShadowsocksServerConfig struct {
|
||||
Email string `json:"email"`
|
||||
Users []*ShadowsocksUserConfig `json:"clients"`
|
||||
NetworkList *NetworkList `json:"network"`
|
||||
IVCheck bool `json:"ivCheck"`
|
||||
}
|
||||
|
||||
func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
|
||||
errors.PrintDeprecatedFeatureWarning("Shadowsocks", "VLESS Encryption")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("Shadowsocks (with no Forward Secrecy, etc.)", "VLESS Encryption")
|
||||
|
||||
if C.Contains(shadowaead_2022.List, v.Cipher) {
|
||||
return buildShadowsocks2022(v)
|
||||
@@ -64,7 +63,6 @@ func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
|
||||
account := &shadowsocks.Account{
|
||||
Password: user.Password,
|
||||
CipherType: cipherFromString(user.Cipher),
|
||||
IvCheck: v.IVCheck,
|
||||
}
|
||||
if account.Password == "" {
|
||||
return nil, errors.New("Shadowsocks password is not specified.")
|
||||
@@ -83,7 +81,6 @@ func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
|
||||
account := &shadowsocks.Account{
|
||||
Password: v.Password,
|
||||
CipherType: cipherFromString(v.Cipher),
|
||||
IvCheck: v.IVCheck,
|
||||
}
|
||||
if account.Password == "" {
|
||||
return nil, errors.New("Shadowsocks password is not specified.")
|
||||
@@ -168,7 +165,6 @@ type ShadowsocksServerTarget struct {
|
||||
Email string `json:"email"`
|
||||
Cipher string `json:"method"`
|
||||
Password string `json:"password"`
|
||||
IVCheck bool `json:"ivCheck"`
|
||||
UoT bool `json:"uot"`
|
||||
UoTVersion int `json:"uotVersion"`
|
||||
}
|
||||
@@ -180,14 +176,13 @@ type ShadowsocksClientConfig struct {
|
||||
Email string `json:"email"`
|
||||
Cipher string `json:"method"`
|
||||
Password string `json:"password"`
|
||||
IVCheck bool `json:"ivCheck"`
|
||||
UoT bool `json:"uot"`
|
||||
UoTVersion int `json:"uotVersion"`
|
||||
Servers []*ShadowsocksServerTarget `json:"servers"`
|
||||
}
|
||||
|
||||
func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
||||
errors.PrintDeprecatedFeatureWarning("Shadowsocks", "VLESS Encryption")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("Shadowsocks (with no Forward Secrecy, etc.)", "VLESS Encryption")
|
||||
|
||||
if v.Address != nil {
|
||||
v.Servers = []*ShadowsocksServerTarget{
|
||||
@@ -198,7 +193,6 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
||||
Email: v.Email,
|
||||
Cipher: v.Cipher,
|
||||
Password: v.Password,
|
||||
IVCheck: v.IVCheck,
|
||||
UoT: v.UoT,
|
||||
UoTVersion: v.UoTVersion,
|
||||
},
|
||||
@@ -254,8 +248,6 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
||||
return nil, errors.New("unknown cipher method: ", server.Cipher)
|
||||
}
|
||||
|
||||
account.IvCheck = server.IVCheck
|
||||
|
||||
ss := &protocol.ServerEndpoint{
|
||||
Address: server.Address.Build(),
|
||||
Port: uint32(server.Port),
|
||||
|
||||
@@ -4,72 +4,17 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/dns"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/http"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/noop"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/srtp"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/tls"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/utp"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/wechat"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/wireguard"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type NoOpAuthenticator struct{}
|
||||
|
||||
func (NoOpAuthenticator) Build() (proto.Message, error) {
|
||||
return new(noop.Config), nil
|
||||
}
|
||||
|
||||
type NoOpConnectionAuthenticator struct{}
|
||||
|
||||
func (NoOpConnectionAuthenticator) Build() (proto.Message, error) {
|
||||
return new(noop.ConnectionConfig), nil
|
||||
}
|
||||
|
||||
type SRTPAuthenticator struct{}
|
||||
|
||||
func (SRTPAuthenticator) Build() (proto.Message, error) {
|
||||
return new(srtp.Config), nil
|
||||
}
|
||||
|
||||
type UTPAuthenticator struct{}
|
||||
|
||||
func (UTPAuthenticator) Build() (proto.Message, error) {
|
||||
return new(utp.Config), nil
|
||||
}
|
||||
|
||||
type WechatVideoAuthenticator struct{}
|
||||
|
||||
func (WechatVideoAuthenticator) Build() (proto.Message, error) {
|
||||
return new(wechat.VideoConfig), nil
|
||||
}
|
||||
|
||||
type WireguardAuthenticator struct{}
|
||||
|
||||
func (WireguardAuthenticator) Build() (proto.Message, error) {
|
||||
return new(wireguard.WireguardConfig), nil
|
||||
}
|
||||
|
||||
type DNSAuthenticator struct {
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
func (v *DNSAuthenticator) Build() (proto.Message, error) {
|
||||
config := new(dns.Config)
|
||||
config.Domain = "www.baidu.com"
|
||||
if len(v.Domain) > 0 {
|
||||
config.Domain = v.Domain
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
type DTLSAuthenticator struct{}
|
||||
|
||||
func (DTLSAuthenticator) Build() (proto.Message, error) {
|
||||
return new(tls.PacketConfig), nil
|
||||
}
|
||||
|
||||
type AuthenticatorRequest struct {
|
||||
Version string `json:"version"`
|
||||
Method string `json:"method"`
|
||||
|
||||
@@ -16,7 +16,16 @@ import (
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask/header/dns"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask/header/dtls"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask/header/srtp"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask/header/utp"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask/header/wechat"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask/header/wireguard"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/original"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask/salamander"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask/xdns"
|
||||
"github.com/xtls/xray-core/transport/internet/httpupgrade"
|
||||
"github.com/xtls/xray-core/transport/internet/hysteria"
|
||||
"github.com/xtls/xray-core/transport/internet/kcp"
|
||||
@@ -29,16 +38,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
kcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
||||
"none": func() interface{} { return new(NoOpAuthenticator) },
|
||||
"srtp": func() interface{} { return new(SRTPAuthenticator) },
|
||||
"utp": func() interface{} { return new(UTPAuthenticator) },
|
||||
"wechat-video": func() interface{} { return new(WechatVideoAuthenticator) },
|
||||
"dtls": func() interface{} { return new(DTLSAuthenticator) },
|
||||
"wireguard": func() interface{} { return new(WireguardAuthenticator) },
|
||||
"dns": func() interface{} { return new(DNSAuthenticator) },
|
||||
}, "type", "")
|
||||
|
||||
tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
||||
"none": func() interface{} { return new(NoOpConnectionAuthenticator) },
|
||||
"http": func() interface{} { return new(Authenticator) },
|
||||
@@ -63,9 +62,9 @@ func (c *KCPConfig) Build() (proto.Message, error) {
|
||||
|
||||
if c.Mtu != nil {
|
||||
mtu := *c.Mtu
|
||||
if mtu < 576 || mtu > 1460 {
|
||||
return nil, errors.New("invalid mKCP MTU size: ", mtu).AtError()
|
||||
}
|
||||
// if mtu < 576 || mtu > 1460 {
|
||||
// return nil, errors.New("invalid mKCP MTU size: ", mtu).AtError()
|
||||
// }
|
||||
config.Mtu = &kcp.MTU{Value: mtu}
|
||||
}
|
||||
if c.Tti != nil {
|
||||
@@ -100,20 +99,8 @@ func (c *KCPConfig) Build() (proto.Message, error) {
|
||||
config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}
|
||||
}
|
||||
}
|
||||
if len(c.HeaderConfig) > 0 {
|
||||
headerConfig, _, err := kcpHeaderLoader.Load(c.HeaderConfig)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid mKCP header config.").Base(err).AtError()
|
||||
}
|
||||
ts, err := headerConfig.(Buildable).Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid mKCP header config").Base(err).AtError()
|
||||
}
|
||||
config.HeaderConfig = serial.ToTypedMessage(ts)
|
||||
}
|
||||
|
||||
if c.Seed != nil {
|
||||
config.Seed = &kcp.EncryptionSeed{Seed: *c.Seed}
|
||||
if c.HeaderConfig != nil || c.Seed != nil {
|
||||
return nil, errors.PrintRemovedFeatureError("mkcp header & seed", "finalmask/udp header-* & mkcp-original & mkcp-aes128gcm")
|
||||
}
|
||||
|
||||
return config, nil
|
||||
@@ -228,6 +215,19 @@ type SplitHTTPConfig struct {
|
||||
Mode string `json:"mode"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
XPaddingBytes Int32Range `json:"xPaddingBytes"`
|
||||
XPaddingObfsMode bool `json:"xPaddingObfsMode"`
|
||||
XPaddingKey string `json:"xPaddingKey"`
|
||||
XPaddingHeader string `json:"xPaddingHeader"`
|
||||
XPaddingPlacement string `json:"xPaddingPlacement"`
|
||||
XPaddingMethod string `json:"xPaddingMethod"`
|
||||
UplinkHTTPMethod string `json:"uplinkHTTPMethod"`
|
||||
SessionPlacement string `json:"sessionPlacement"`
|
||||
SessionKey string `json:"sessionKey"`
|
||||
SeqPlacement string `json:"seqPlacement"`
|
||||
SeqKey string `json:"seqKey"`
|
||||
UplinkDataPlacement string `json:"uplinkDataPlacement"`
|
||||
UplinkDataKey string `json:"uplinkDataKey"`
|
||||
UplinkChunkSize uint32 `json:"uplinkChunkSize"`
|
||||
NoGRPCHeader bool `json:"noGRPCHeader"`
|
||||
NoSSEHeader bool `json:"noSSEHeader"`
|
||||
ScMaxEachPostBytes Int32Range `json:"scMaxEachPostBytes"`
|
||||
@@ -287,6 +287,107 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
|
||||
return nil, errors.New("xPaddingBytes cannot be disabled")
|
||||
}
|
||||
|
||||
if c.XPaddingKey == "" {
|
||||
c.XPaddingKey = "x_padding"
|
||||
}
|
||||
|
||||
if c.XPaddingHeader == "" {
|
||||
c.XPaddingHeader = "X-Padding"
|
||||
}
|
||||
|
||||
switch c.XPaddingPlacement {
|
||||
case "":
|
||||
c.XPaddingPlacement = "queryInHeader"
|
||||
case "cookie", "header", "query", "queryInHeader":
|
||||
default:
|
||||
return nil, errors.New("unsupported padding placement: " + c.XPaddingPlacement)
|
||||
}
|
||||
|
||||
switch c.XPaddingMethod {
|
||||
case "":
|
||||
c.XPaddingMethod = "repeat-x"
|
||||
case "repeat-x", "tokenish":
|
||||
default:
|
||||
return nil, errors.New("unsupported padding method: " + c.XPaddingMethod)
|
||||
}
|
||||
|
||||
switch c.UplinkDataPlacement {
|
||||
case "":
|
||||
c.UplinkDataPlacement = "body"
|
||||
case "cookie", "header":
|
||||
if c.Mode != "packet-up" {
|
||||
return nil, errors.New("UplinkDataPlacement can be " + c.UplinkDataPlacement + " only in packet-up mode")
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("unsupported uplink data placement: " + c.UplinkDataPlacement)
|
||||
}
|
||||
|
||||
if c.UplinkHTTPMethod == "" {
|
||||
c.UplinkHTTPMethod = "POST"
|
||||
}
|
||||
c.UplinkHTTPMethod = strings.ToUpper(c.UplinkHTTPMethod)
|
||||
|
||||
if c.UplinkHTTPMethod == "GET" && c.Mode != "packet-up" {
|
||||
return nil, errors.New("uplinkHTTPMethod can be GET only in packet-up mode")
|
||||
}
|
||||
|
||||
switch c.SessionPlacement {
|
||||
case "":
|
||||
c.SessionPlacement = "path"
|
||||
case "cookie", "header", "query":
|
||||
default:
|
||||
return nil, errors.New("unsupported session placement: " + c.SessionPlacement)
|
||||
}
|
||||
|
||||
switch c.SeqPlacement {
|
||||
case "":
|
||||
c.SeqPlacement = "path"
|
||||
case "cookie", "header", "query":
|
||||
if c.SessionPlacement == "path" {
|
||||
return nil, errors.New("SeqPlacement must be path when SessionPlacement is path")
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("unsupported seq placement: " + c.SeqPlacement)
|
||||
}
|
||||
|
||||
if c.SessionPlacement != "path" && c.SessionKey == "" {
|
||||
switch c.SessionPlacement {
|
||||
case "cookie", "query":
|
||||
c.SessionKey = "x_session"
|
||||
case "header":
|
||||
c.SessionKey = "X-Session"
|
||||
}
|
||||
}
|
||||
|
||||
if c.SeqPlacement != "path" && c.SeqKey == "" {
|
||||
switch c.SeqPlacement {
|
||||
case "cookie", "query":
|
||||
c.SeqKey = "x_seq"
|
||||
case "header":
|
||||
c.SeqKey = "X-Seq"
|
||||
}
|
||||
}
|
||||
|
||||
if c.UplinkDataPlacement != "body" && c.UplinkDataKey == "" {
|
||||
switch c.UplinkDataPlacement {
|
||||
case "cookie":
|
||||
c.UplinkDataKey = "x_data"
|
||||
case "header":
|
||||
c.UplinkDataKey = "X-Data"
|
||||
}
|
||||
}
|
||||
|
||||
if c.UplinkChunkSize == 0 {
|
||||
switch c.UplinkDataPlacement {
|
||||
case "cookie":
|
||||
c.UplinkChunkSize = 3 * 1024 // 3KB
|
||||
case "header":
|
||||
c.UplinkChunkSize = 4 * 1024 // 4KB
|
||||
}
|
||||
} else if c.UplinkChunkSize < 64 {
|
||||
c.UplinkChunkSize = 64
|
||||
}
|
||||
|
||||
if c.Xmux.MaxConnections.To > 0 && c.Xmux.MaxConcurrency.To > 0 {
|
||||
return nil, errors.New("maxConnections cannot be specified together with maxConcurrency")
|
||||
}
|
||||
@@ -305,6 +406,19 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
|
||||
Mode: c.Mode,
|
||||
Headers: c.Headers,
|
||||
XPaddingBytes: newRangeConfig(c.XPaddingBytes),
|
||||
XPaddingObfsMode: c.XPaddingObfsMode,
|
||||
XPaddingKey: c.XPaddingKey,
|
||||
XPaddingHeader: c.XPaddingHeader,
|
||||
XPaddingPlacement: c.XPaddingPlacement,
|
||||
XPaddingMethod: c.XPaddingMethod,
|
||||
UplinkHTTPMethod: c.UplinkHTTPMethod,
|
||||
SessionPlacement: c.SessionPlacement,
|
||||
SeqPlacement: c.SeqPlacement,
|
||||
SessionKey: c.SessionKey,
|
||||
SeqKey: c.SeqKey,
|
||||
UplinkDataPlacement: c.UplinkDataPlacement,
|
||||
UplinkDataKey: c.UplinkDataKey,
|
||||
UplinkChunkSize: c.UplinkChunkSize,
|
||||
NoGRPCHeader: c.NoGRPCHeader,
|
||||
NoSSEHeader: c.NoSSEHeader,
|
||||
ScMaxEachPostBytes: newRangeConfig(c.ScMaxEachPostBytes),
|
||||
@@ -387,7 +501,7 @@ func (b Bandwidth) Bps() (uint64, error) {
|
||||
|
||||
type UdpHop struct {
|
||||
PortList json.RawMessage `json:"port"`
|
||||
Interval int64 `json:"interval"`
|
||||
Interval *Int32Range `json:"interval"`
|
||||
}
|
||||
|
||||
type HysteriaConfig struct {
|
||||
@@ -431,13 +545,19 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
|
||||
hop = &PortList{}
|
||||
}
|
||||
|
||||
var inertvalMin, inertvalMax int64
|
||||
if c.UdpHop.Interval != nil {
|
||||
inertvalMin = int64(c.UdpHop.Interval.From)
|
||||
inertvalMax = int64(c.UdpHop.Interval.To)
|
||||
}
|
||||
|
||||
if up > 0 && up < 65536 {
|
||||
return nil, errors.New("Up must be at least 65536 Bps")
|
||||
}
|
||||
if down > 0 && down < 65536 {
|
||||
return nil, errors.New("Down must be at least 65536 Bps")
|
||||
}
|
||||
if c.UdpHop.Interval != 0 && c.UdpHop.Interval < 5 {
|
||||
if (inertvalMin != 0 && inertvalMin < 5) || (inertvalMax != 0 && inertvalMax < 5) {
|
||||
return nil, errors.New("Interval must be at least 5")
|
||||
}
|
||||
|
||||
@@ -467,7 +587,8 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
|
||||
config.Up = up
|
||||
config.Down = down
|
||||
config.Ports = hop.Build().Ports()
|
||||
config.Interval = c.UdpHop.Interval
|
||||
config.IntervalMin = inertvalMin
|
||||
config.IntervalMax = inertvalMax
|
||||
config.InitStreamReceiveWindow = c.InitStreamReceiveWindow
|
||||
config.MaxStreamReceiveWindow = c.MaxStreamReceiveWindow
|
||||
config.InitConnReceiveWindow = c.InitConnectionReceiveWindow
|
||||
@@ -561,7 +682,7 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
|
||||
}
|
||||
|
||||
type TLSConfig struct {
|
||||
Insecure bool `json:"allowInsecure"`
|
||||
AllowInsecure bool `json:"allowInsecure"`
|
||||
Certs []*TLSCertConfig `json:"certificates"`
|
||||
ServerName string `json:"serverName"`
|
||||
ALPN *StringList `json:"alpn"`
|
||||
@@ -572,10 +693,10 @@ type TLSConfig struct {
|
||||
CipherSuites string `json:"cipherSuites"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
RejectUnknownSNI bool `json:"rejectUnknownSni"`
|
||||
PinnedPeerCertSha256 string `json:"pinnedPeerCertSha256"`
|
||||
CurvePreferences *StringList `json:"curvePreferences"`
|
||||
MasterKeyLog string `json:"masterKeyLog"`
|
||||
ServerNameToVerify string `json:"serverNameToVerify"`
|
||||
PinnedPeerCertSha256 string `json:"pinnedPeerCertSha256"`
|
||||
VerifyPeerCertByName string `json:"verifyPeerCertByName"`
|
||||
VerifyPeerCertInNames []string `json:"verifyPeerCertInNames"`
|
||||
ECHServerKeys string `json:"echServerKeys"`
|
||||
ECHConfigList string `json:"echConfigList"`
|
||||
@@ -595,10 +716,6 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
||||
config.Certificate[idx] = cert
|
||||
}
|
||||
serverName := c.ServerName
|
||||
config.AllowInsecure = c.Insecure
|
||||
if config.AllowInsecure {
|
||||
errors.PrintDeprecatedFeatureWarning("allowInsecure", "pinnedPeerCertSha256")
|
||||
}
|
||||
if len(c.ServerName) > 0 {
|
||||
config.ServerName = serverName
|
||||
}
|
||||
@@ -625,30 +742,41 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
||||
return nil, errors.New(`unknown "fingerprint": `, config.Fingerprint)
|
||||
}
|
||||
config.RejectUnknownSni = c.RejectUnknownSNI
|
||||
config.MasterKeyLog = c.MasterKeyLog
|
||||
|
||||
if c.AllowInsecure {
|
||||
return nil, errors.PrintRemovedFeatureError(`"allowInsecure"`, `"pinnedPeerCertSha256"`)
|
||||
}
|
||||
if c.PinnedPeerCertSha256 != "" {
|
||||
config.PinnedPeerCertSha256 = [][]byte{}
|
||||
// Split by tilde separator
|
||||
hashes := strings.Split(c.PinnedPeerCertSha256, "~")
|
||||
for _, v := range hashes {
|
||||
for v := range strings.SplitSeq(c.PinnedPeerCertSha256, ",") {
|
||||
v = strings.TrimSpace(v)
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
hashValue, err := hex.DecodeString(v)
|
||||
// remove colons for OpenSSL format
|
||||
hashValue, err := hex.DecodeString(strings.ReplaceAll(v, ":", ""))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(hashValue) != 32 {
|
||||
return nil, errors.New("incorrect pinnedPeerCertSha256 length: ", v)
|
||||
}
|
||||
config.PinnedPeerCertSha256 = append(config.PinnedPeerCertSha256, hashValue)
|
||||
}
|
||||
}
|
||||
|
||||
config.MasterKeyLog = c.MasterKeyLog
|
||||
|
||||
if c.ServerNameToVerify != "" {
|
||||
return nil, errors.PrintRemovedFeatureError(`"serverNameToVerify"`, `"verifyPeerCertInNames"`)
|
||||
if c.VerifyPeerCertInNames != nil {
|
||||
return nil, errors.PrintRemovedFeatureError(`"verifyPeerCertInNames"`, `"verifyPeerCertByName"`)
|
||||
}
|
||||
if c.VerifyPeerCertByName != "" {
|
||||
for v := range strings.SplitSeq(c.VerifyPeerCertByName, ",") {
|
||||
v = strings.TrimSpace(v)
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
config.VerifyPeerCertByName = append(config.VerifyPeerCertByName, v)
|
||||
}
|
||||
}
|
||||
config.VerifyPeerCertInNames = c.VerifyPeerCertInNames
|
||||
|
||||
if c.ECHServerKeys != "" {
|
||||
EchPrivateKey, err := base64.StdEncoding.DecodeString(c.ECHServerKeys)
|
||||
@@ -903,13 +1031,13 @@ func (p TransportProtocol) Build() (string, error) {
|
||||
case "kcp", "mkcp":
|
||||
return "mkcp", nil
|
||||
case "grpc":
|
||||
errors.PrintDeprecatedFeatureWarning("gRPC transport (with unnecessary costs, etc.)", "XHTTP stream-up H2")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("gRPC transport (with unnecessary costs, etc.)", "XHTTP stream-up H2")
|
||||
return "grpc", nil
|
||||
case "ws", "websocket":
|
||||
errors.PrintDeprecatedFeatureWarning("WebSocket transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("WebSocket transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
|
||||
return "websocket", nil
|
||||
case "httpupgrade":
|
||||
errors.PrintDeprecatedFeatureWarning("HTTPUpgrade transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("HTTPUpgrade transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
|
||||
return "httpupgrade", nil
|
||||
case "h2", "h3", "http":
|
||||
return "", errors.PrintRemovedFeatureError("HTTP transport (without header padding, etc.)", "XHTTP stream-one H2 & H3")
|
||||
@@ -1101,10 +1229,80 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
||||
|
||||
var (
|
||||
udpmaskLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
||||
"salamander": func() interface{} { return new(Salamander) },
|
||||
"header-dns": func() interface{} { return new(Dns) },
|
||||
"header-dtls": func() interface{} { return new(Dtls) },
|
||||
"header-srtp": func() interface{} { return new(Srtp) },
|
||||
"header-utp": func() interface{} { return new(Utp) },
|
||||
"header-wechat": func() interface{} { return new(Wechat) },
|
||||
"header-wireguard": func() interface{} { return new(Wireguard) },
|
||||
"mkcp-original": func() interface{} { return new(Original) },
|
||||
"mkcp-aes128gcm": func() interface{} { return new(Aes128Gcm) },
|
||||
"salamander": func() interface{} { return new(Salamander) },
|
||||
"xdns": func() interface{} { return new(Xdns) },
|
||||
}, "type", "settings")
|
||||
)
|
||||
|
||||
type Dns struct {
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
func (c *Dns) Build() (proto.Message, error) {
|
||||
config := &dns.Config{}
|
||||
config.Domain = "www.baidu.com"
|
||||
|
||||
if len(c.Domain) > 0 {
|
||||
config.Domain = c.Domain
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
type Dtls struct{}
|
||||
|
||||
func (c *Dtls) Build() (proto.Message, error) {
|
||||
return &dtls.Config{}, nil
|
||||
}
|
||||
|
||||
type Srtp struct{}
|
||||
|
||||
func (c *Srtp) Build() (proto.Message, error) {
|
||||
return &srtp.Config{}, nil
|
||||
}
|
||||
|
||||
type Utp struct{}
|
||||
|
||||
func (c *Utp) Build() (proto.Message, error) {
|
||||
return &utp.Config{}, nil
|
||||
}
|
||||
|
||||
type Wechat struct{}
|
||||
|
||||
func (c *Wechat) Build() (proto.Message, error) {
|
||||
return &wechat.Config{}, nil
|
||||
}
|
||||
|
||||
type Wireguard struct{}
|
||||
|
||||
func (c *Wireguard) Build() (proto.Message, error) {
|
||||
return &wireguard.Config{}, nil
|
||||
}
|
||||
|
||||
type Original struct{}
|
||||
|
||||
func (c *Original) Build() (proto.Message, error) {
|
||||
return &original.Config{}, nil
|
||||
}
|
||||
|
||||
type Aes128Gcm struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func (c *Aes128Gcm) Build() (proto.Message, error) {
|
||||
return &aes128gcm.Config{
|
||||
Password: c.Password,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Salamander struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
@@ -1115,14 +1313,28 @@ func (c *Salamander) Build() (proto.Message, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
type FinalMask struct {
|
||||
type Xdns struct {
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
func (c *Xdns) Build() (proto.Message, error) {
|
||||
if c.Domain == "" {
|
||||
return nil, errors.New("empty domain")
|
||||
}
|
||||
|
||||
return &xdns.Config{
|
||||
Domain: c.Domain,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Mask struct {
|
||||
Type string `json:"type"`
|
||||
Settings *json.RawMessage `json:"settings"`
|
||||
}
|
||||
|
||||
func (c *FinalMask) Build(tcpmaskLoader bool) (proto.Message, error) {
|
||||
func (c *Mask) Build(tcp bool) (proto.Message, error) {
|
||||
loader := udpmaskLoader
|
||||
if tcpmaskLoader {
|
||||
if tcp {
|
||||
return nil, errors.New("")
|
||||
}
|
||||
|
||||
@@ -1141,12 +1353,17 @@ func (c *FinalMask) Build(tcpmaskLoader bool) (proto.Message, error) {
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
type FinalMask struct {
|
||||
Tcp []Mask `json:"tcp"`
|
||||
Udp []Mask `json:"udp"`
|
||||
}
|
||||
|
||||
type StreamConfig struct {
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Network *TransportProtocol `json:"network"`
|
||||
Security string `json:"security"`
|
||||
Udpmasks []*FinalMask `json:"udpmasks"`
|
||||
FinalMask *FinalMask `json:"finalmask"`
|
||||
TLSSettings *TLSConfig `json:"tlsSettings"`
|
||||
REALITYSettings *REALITYConfig `json:"realitySettings"`
|
||||
RAWSettings *TCPConfig `json:"rawSettings"`
|
||||
@@ -1296,12 +1513,21 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
||||
config.SocketSettings = ss
|
||||
}
|
||||
|
||||
for _, mask := range c.Udpmasks {
|
||||
u, err := mask.Build(false)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
|
||||
if c.FinalMask != nil {
|
||||
for _, mask := range c.FinalMask.Tcp {
|
||||
u, err := mask.Build(true)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
|
||||
}
|
||||
config.Tcpmasks = append(config.Tcpmasks, serial.ToTypedMessage(u))
|
||||
}
|
||||
for _, mask := range c.FinalMask.Udp {
|
||||
u, err := mask.Build(false)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
|
||||
}
|
||||
config.Udpmasks = append(config.Udpmasks, serial.ToTypedMessage(u))
|
||||
}
|
||||
config.Udpmasks = append(config.Udpmasks, serial.ToTypedMessage(u))
|
||||
}
|
||||
|
||||
return config, nil
|
||||
|
||||
@@ -39,7 +39,7 @@ type TrojanClientConfig struct {
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *TrojanClientConfig) Build() (proto.Message, error) {
|
||||
errors.PrintDeprecatedFeatureWarning("Trojan", "VLESS with flow")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("Trojan (with no Flow, etc.)", "VLESS with Flow & Seed")
|
||||
|
||||
if c.Address != nil {
|
||||
c.Servers = []*TrojanServerTarget{
|
||||
@@ -117,7 +117,7 @@ type TrojanServerConfig struct {
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *TrojanServerConfig) Build() (proto.Message, error) {
|
||||
errors.PrintDeprecatedFeatureWarning("Trojan", "VLESS with flow")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("Trojan (with no Flow, etc.)", "VLESS with Flow & Seed")
|
||||
|
||||
config := &trojan.ServerConfig{
|
||||
Users: make([]*protocol.User, len(c.Clients)),
|
||||
|
||||
+2
-2
@@ -70,7 +70,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
||||
return nil, errors.New(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
|
||||
}
|
||||
if account.Flow == "" {
|
||||
errors.PrintDeprecatedFeatureWarning("VLESS without flow", "VLESS with flow")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("VLESS (with no Flow, etc.)", "VLESS with Flow & Seed")
|
||||
}
|
||||
|
||||
if len(account.Testseed) < 4 {
|
||||
@@ -280,7 +280,7 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
||||
|
||||
switch account.Flow {
|
||||
case "":
|
||||
errors.PrintDeprecatedFeatureWarning("VLESS without flow", "VLESS with flow")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("VLESS (with no Flow, etc.)", "VLESS with Flow & Seed")
|
||||
case vless.XRV, vless.XRV + "-udp443":
|
||||
default:
|
||||
return nil, errors.New(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)
|
||||
|
||||
+2
-2
@@ -64,7 +64,7 @@ type VMessInboundConfig struct {
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *VMessInboundConfig) Build() (proto.Message, error) {
|
||||
errors.PrintDeprecatedFeatureWarning("VMess", "VLESS Encryption")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("VMess (with no Forward Secrecy, etc.)", "VLESS Encryption")
|
||||
|
||||
config := &inbound.Config{}
|
||||
|
||||
@@ -115,7 +115,7 @@ type VMessOutboundConfig struct {
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *VMessOutboundConfig) Build() (proto.Message, error) {
|
||||
errors.PrintDeprecatedFeatureWarning("VMess", "VLESS Encryption")
|
||||
errors.PrintNonRemovalDeprecatedFeatureWarning("VMess (with no Forward Secrecy, etc.)", "VLESS Encryption")
|
||||
|
||||
config := new(outbound.Config)
|
||||
if c.Address != nil {
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/app/dispatcher"
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/app/stats"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
core "github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
@@ -607,6 +612,187 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (c *Config) BuildMPHCache(customMatcherFilePath *string) error {
|
||||
var geosite []*router.GeoSite
|
||||
deps := make(map[string][]string)
|
||||
uniqueGeosites := make(map[string]bool)
|
||||
uniqueTags := make(map[string]bool)
|
||||
matcherFilePath := platform.GetAssetLocation("matcher.cache")
|
||||
|
||||
if customMatcherFilePath != nil {
|
||||
matcherFilePath = *customMatcherFilePath
|
||||
}
|
||||
|
||||
processGeosite := func(dStr string) bool {
|
||||
prefix := ""
|
||||
if strings.HasPrefix(dStr, "geosite:") {
|
||||
prefix = "geosite:"
|
||||
} else if strings.HasPrefix(dStr, "ext-domain:") {
|
||||
prefix = "ext-domain:"
|
||||
}
|
||||
if prefix == "" {
|
||||
return false
|
||||
}
|
||||
key := strings.ToLower(dStr)
|
||||
country := strings.ToUpper(dStr[len(prefix):])
|
||||
if !uniqueGeosites[country] {
|
||||
ds, err := loadGeositeWithAttr("geosite.dat", country)
|
||||
if err == nil {
|
||||
uniqueGeosites[country] = true
|
||||
geosite = append(geosite, &router.GeoSite{CountryCode: key, Domain: ds})
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
processDomains := func(tag string, rawDomains []string) {
|
||||
var manualDomains []*router.Domain
|
||||
var dDeps []string
|
||||
for _, dStr := range rawDomains {
|
||||
if processGeosite(dStr) {
|
||||
dDeps = append(dDeps, strings.ToLower(dStr))
|
||||
} else {
|
||||
ds, err := parseDomainRule(dStr)
|
||||
if err == nil {
|
||||
manualDomains = append(manualDomains, ds...)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(manualDomains) > 0 {
|
||||
if !uniqueTags[tag] {
|
||||
uniqueTags[tag] = true
|
||||
geosite = append(geosite, &router.GeoSite{CountryCode: tag, Domain: manualDomains})
|
||||
}
|
||||
}
|
||||
if len(dDeps) > 0 {
|
||||
deps[tag] = append(deps[tag], dDeps...)
|
||||
}
|
||||
}
|
||||
|
||||
// proccess rules
|
||||
if c.RouterConfig != nil {
|
||||
for _, rawRule := range c.RouterConfig.RuleList {
|
||||
type SimpleRule struct {
|
||||
RuleTag string `json:"ruleTag"`
|
||||
Domain *StringList `json:"domain"`
|
||||
Domains *StringList `json:"domains"`
|
||||
}
|
||||
var sr SimpleRule
|
||||
json.Unmarshal(rawRule, &sr)
|
||||
if sr.RuleTag == "" {
|
||||
continue
|
||||
}
|
||||
var allDomains []string
|
||||
if sr.Domain != nil {
|
||||
allDomains = append(allDomains, *sr.Domain...)
|
||||
}
|
||||
if sr.Domains != nil {
|
||||
allDomains = append(allDomains, *sr.Domains...)
|
||||
}
|
||||
processDomains(sr.RuleTag, allDomains)
|
||||
}
|
||||
}
|
||||
|
||||
// proccess dns servers
|
||||
if c.DNSConfig != nil {
|
||||
for _, ns := range c.DNSConfig.Servers {
|
||||
if ns.Tag == "" {
|
||||
continue
|
||||
}
|
||||
processDomains(ns.Tag, ns.Domains)
|
||||
}
|
||||
}
|
||||
|
||||
var hostIPs map[string][]string
|
||||
if c.DNSConfig != nil && c.DNSConfig.Hosts != nil {
|
||||
hostIPs = make(map[string][]string)
|
||||
var hostDeps []string
|
||||
var hostPatterns []string
|
||||
|
||||
// use raw map to avoid expanding geosites
|
||||
var domains []string
|
||||
for domain := range c.DNSConfig.Hosts.Hosts {
|
||||
domains = append(domains, domain)
|
||||
}
|
||||
sort.Strings(domains)
|
||||
|
||||
manualHostGroups := make(map[string][]*router.Domain)
|
||||
manualHostIPs := make(map[string][]string)
|
||||
manualHostNames := make(map[string]string)
|
||||
|
||||
for _, domain := range domains {
|
||||
ha := c.DNSConfig.Hosts.Hosts[domain]
|
||||
m := getHostMapping(ha)
|
||||
|
||||
var ips []string
|
||||
if m.ProxiedDomain != "" {
|
||||
ips = append(ips, m.ProxiedDomain)
|
||||
} else {
|
||||
for _, ip := range m.Ip {
|
||||
ips = append(ips, net.IPAddress(ip).String())
|
||||
}
|
||||
}
|
||||
|
||||
if processGeosite(domain) {
|
||||
tag := strings.ToLower(domain)
|
||||
hostDeps = append(hostDeps, tag)
|
||||
hostIPs[tag] = ips
|
||||
hostPatterns = append(hostPatterns, domain)
|
||||
} else {
|
||||
// build manual domains by their destination IPs
|
||||
sort.Strings(ips)
|
||||
ipKey := strings.Join(ips, ",")
|
||||
ds, err := parseDomainRule(domain)
|
||||
if err == nil {
|
||||
manualHostGroups[ipKey] = append(manualHostGroups[ipKey], ds...)
|
||||
manualHostIPs[ipKey] = ips
|
||||
if _, ok := manualHostNames[ipKey]; !ok {
|
||||
manualHostNames[ipKey] = domain
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create manual host groups
|
||||
var ipKeys []string
|
||||
for k := range manualHostGroups {
|
||||
ipKeys = append(ipKeys, k)
|
||||
}
|
||||
sort.Strings(ipKeys)
|
||||
|
||||
for _, k := range ipKeys {
|
||||
tag := manualHostNames[k]
|
||||
geosite = append(geosite, &router.GeoSite{CountryCode: tag, Domain: manualHostGroups[k]})
|
||||
hostDeps = append(hostDeps, tag)
|
||||
hostIPs[tag] = manualHostIPs[k]
|
||||
|
||||
// record tag _ORDER links the matcher to IP addresses
|
||||
hostPatterns = append(hostPatterns, tag)
|
||||
}
|
||||
|
||||
deps["HOSTS"] = hostDeps
|
||||
hostIPs["_ORDER"] = hostPatterns
|
||||
}
|
||||
|
||||
f, err := os.Create(matcherFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
if err := router.SerializeGeoSiteList(geosite, deps, hostIPs, &buf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := f.Write(buf.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert string to Address.
|
||||
func ParseSendThough(Addr *string) *Address {
|
||||
var addr Address
|
||||
|
||||
@@ -29,6 +29,7 @@ var CmdAPI = &base.Command{
|
||||
cmdInboundUserCount,
|
||||
cmdAddRules,
|
||||
cmdRemoveRules,
|
||||
cmdListRules,
|
||||
cmdSourceIpBlock,
|
||||
cmdOnlineStats,
|
||||
cmdOnlineStatsIpList,
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
routerService "github.com/xtls/xray-core/app/router/command"
|
||||
"github.com/xtls/xray-core/main/commands/base"
|
||||
)
|
||||
|
||||
var cmdListRules = &base.Command{
|
||||
CustomFlags: true,
|
||||
UsageLine: "{{.Exec}} api lsrules [--server=127.0.0.1:8080]",
|
||||
Short: "List routing rules",
|
||||
Long: `
|
||||
List routing rules in Xray.
|
||||
|
||||
Arguments:
|
||||
|
||||
-s, -server <server:port>
|
||||
The API server address. Default 127.0.0.1:8080
|
||||
|
||||
-t, -timeout <seconds>
|
||||
Timeout in seconds for calling API. Default 3
|
||||
|
||||
Example:
|
||||
|
||||
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080
|
||||
`,
|
||||
Run: executeListRules,
|
||||
}
|
||||
|
||||
func executeListRules(cmd *base.Command, args []string) {
|
||||
setSharedFlags(cmd)
|
||||
cmd.Flag.Parse(args)
|
||||
|
||||
conn, ctx, close := dialAPIServer()
|
||||
defer close()
|
||||
|
||||
client := routerService.NewRoutingServiceClient(conn)
|
||||
resp, err := client.ListRule(ctx, &routerService.ListRuleRequest{})
|
||||
if err != nil {
|
||||
base.Fatalf("failed to list rules: %s", err)
|
||||
}
|
||||
showJSONResponse(resp)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package all
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/infra/conf/serial"
|
||||
"github.com/xtls/xray-core/main/commands/base"
|
||||
)
|
||||
|
||||
var cmdBuildMphCache = &base.Command{
|
||||
UsageLine: `{{.Exec}} buildMphCache [-c config.json] [-o domain.cache]`,
|
||||
Short: `Build domain matcher cache`,
|
||||
Long: `
|
||||
Build domain matcher cache from a configuration file.
|
||||
|
||||
Example: {{.Exec}} buildMphCache -c config.json -o domain.cache
|
||||
`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmdBuildMphCache.Run = executeBuildMphCache
|
||||
}
|
||||
|
||||
var (
|
||||
configPath = cmdBuildMphCache.Flag.String("c", "config.json", "Config file path")
|
||||
outputPath = cmdBuildMphCache.Flag.String("o", "domain.cache", "Output cache file path")
|
||||
)
|
||||
|
||||
func executeBuildMphCache(cmd *base.Command, args []string) {
|
||||
cf, err := os.Open(*configPath)
|
||||
if err != nil {
|
||||
base.Fatalf("failed to open config file: %v", err)
|
||||
}
|
||||
defer cf.Close()
|
||||
|
||||
// prevent using existing cache
|
||||
domainMatcherPath := platform.NewEnvFlag(platform.MphCachePath).GetValue(func() string { return "" })
|
||||
if domainMatcherPath != "" {
|
||||
os.Setenv("XRAY_MPH_CACHE", "")
|
||||
defer os.Setenv("XRAY_MPH_CACHE", domainMatcherPath)
|
||||
}
|
||||
|
||||
config, err := serial.DecodeJSONConfig(cf)
|
||||
if err != nil {
|
||||
base.Fatalf("failed to decode config file: %v", err)
|
||||
}
|
||||
|
||||
if err := config.BuildMPHCache(outputPath); err != nil {
|
||||
base.Fatalf("failed to build MPH cache: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -19,5 +19,6 @@ func init() {
|
||||
cmdMLDSA65,
|
||||
cmdMLKEM768,
|
||||
cmdVLESSEnc,
|
||||
cmdBuildMphCache,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -75,8 +75,6 @@ func executePing(cmd *base.Command, args []string) {
|
||||
NextProtos: []string{"h2", "http/1.1"},
|
||||
MaxVersion: gotls.VersionTLS13,
|
||||
MinVersion: gotls.VersionTLS12,
|
||||
// Do not release tool before v5's refactor
|
||||
// VerifyPeerCertificate: showCert(),
|
||||
})
|
||||
err = tlsConn.Handshake()
|
||||
if err != nil {
|
||||
@@ -101,8 +99,6 @@ func executePing(cmd *base.Command, args []string) {
|
||||
NextProtos: []string{"h2", "http/1.1"},
|
||||
MaxVersion: gotls.VersionTLS13,
|
||||
MinVersion: gotls.VersionTLS12,
|
||||
// Do not release tool before v5's refactor
|
||||
// VerifyPeerCertificate: showCert(),
|
||||
})
|
||||
err = tlsConn.Handshake()
|
||||
if err != nil {
|
||||
@@ -133,6 +129,7 @@ func printCertificates(certs []*x509.Certificate) {
|
||||
fmt.Println("Cert's signature algorithm: ", leaf.SignatureAlgorithm.String())
|
||||
fmt.Println("Cert's publicKey algorithm: ", leaf.PublicKeyAlgorithm.String())
|
||||
fmt.Println("Cert's allowed domains: ", leaf.DNSNames)
|
||||
fmt.Println("Cert's leaf SHA256: ", hex.EncodeToString(GenerateCertHash(leaf)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,17 +150,3 @@ func printTLSConnDetail(tlsConn *gotls.Conn) {
|
||||
fmt.Println("TLS Post-Quantum key exchange: false (RSA Exchange)")
|
||||
}
|
||||
}
|
||||
|
||||
func showCert() func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
var hash []byte
|
||||
for _, asn1Data := range rawCerts {
|
||||
cert, _ := x509.ParseCertificate(asn1Data)
|
||||
if cert.IsCA {
|
||||
hash = GenerateCertHash(cert)
|
||||
}
|
||||
}
|
||||
fmt.Println("Certificate Leaf Hash: ", hex.EncodeToString(hash))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,11 +63,6 @@ import (
|
||||
// Transport headers
|
||||
_ "github.com/xtls/xray-core/transport/internet/headers/http"
|
||||
_ "github.com/xtls/xray-core/transport/internet/headers/noop"
|
||||
_ "github.com/xtls/xray-core/transport/internet/headers/srtp"
|
||||
_ "github.com/xtls/xray-core/transport/internet/headers/tls"
|
||||
_ "github.com/xtls/xray-core/transport/internet/headers/utp"
|
||||
_ "github.com/xtls/xray-core/transport/internet/headers/wechat"
|
||||
_ "github.com/xtls/xray-core/transport/internet/headers/wireguard"
|
||||
|
||||
// JSON & TOML & YAML
|
||||
_ "github.com/xtls/xray-core/main/json"
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"io"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/antireplay"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
@@ -24,8 +24,6 @@ type MemoryAccount struct {
|
||||
CipherType CipherType
|
||||
Key []byte
|
||||
Password string
|
||||
|
||||
replayFilter antireplay.GeneralizedReplayFilter
|
||||
}
|
||||
|
||||
var ErrIVNotUnique = errors.New("IV is not unique")
|
||||
@@ -42,20 +40,9 @@ func (a *MemoryAccount) ToProto() proto.Message {
|
||||
return &Account{
|
||||
CipherType: a.CipherType,
|
||||
Password: a.Password,
|
||||
IvCheck: a.replayFilter != nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *MemoryAccount) CheckIV(iv []byte) error {
|
||||
if a.replayFilter == nil {
|
||||
return nil
|
||||
}
|
||||
if a.replayFilter.Check(iv) {
|
||||
return nil
|
||||
}
|
||||
return ErrIVNotUnique
|
||||
}
|
||||
|
||||
func createAesGcm(key []byte) cipher.AEAD {
|
||||
return crypto.NewAesGcm(key)
|
||||
}
|
||||
@@ -116,12 +103,6 @@ func (a *Account) AsAccount() (protocol.Account, error) {
|
||||
CipherType: a.CipherType,
|
||||
Key: passwordToCipherKey([]byte(a.Password), Cipher.KeySize()),
|
||||
Password: a.Password,
|
||||
replayFilter: func() antireplay.GeneralizedReplayFilter {
|
||||
if a.IvCheck {
|
||||
return antireplay.NewBloomRing()
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -139,9 +139,6 @@ func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Wri
|
||||
if account.Cipher.IVSize() > 0 {
|
||||
iv = make([]byte, account.Cipher.IVSize())
|
||||
common.Must2(rand.Read(iv))
|
||||
if ivError := account.CheckIV(iv); ivError != nil {
|
||||
return nil, errors.New("failed to mark outgoing iv").Base(ivError)
|
||||
}
|
||||
if err := buf.WriteAllBytes(writer, iv, nil); err != nil {
|
||||
return nil, errors.New("failed to write IV")
|
||||
}
|
||||
@@ -188,10 +185,6 @@ func ReadTCPResponse(user *protocol.MemoryUser, reader io.Reader) (buf.Reader, e
|
||||
}
|
||||
}
|
||||
|
||||
if ivError := account.CheckIV(iv); ivError != nil {
|
||||
return nil, drain.WithError(drainer, reader, errors.New("failed iv check").Base(ivError))
|
||||
}
|
||||
|
||||
return account.Cipher.NewDecryptionReader(account.Key, iv, reader)
|
||||
}
|
||||
|
||||
@@ -203,9 +196,6 @@ func WriteTCPResponse(request *protocol.RequestHeader, writer io.Writer) (buf.Wr
|
||||
if account.Cipher.IVSize() > 0 {
|
||||
iv = make([]byte, account.Cipher.IVSize())
|
||||
common.Must2(rand.Read(iv))
|
||||
if ivError := account.CheckIV(iv); ivError != nil {
|
||||
return nil, errors.New("failed to mark outgoing iv").Base(ivError)
|
||||
}
|
||||
if err := buf.WriteAllBytes(writer, iv, nil); err != nil {
|
||||
return nil, errors.New("failed to write IV.").Base(err)
|
||||
}
|
||||
|
||||
@@ -140,7 +140,6 @@ func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol
|
||||
|
||||
if matchErr == nil {
|
||||
u = user
|
||||
err = account.CheckIV(iv)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
||||
+59
-1
@@ -4,7 +4,7 @@ TUN interface support bridges the gap between network layer 3 and layer 7, intro
|
||||
|
||||
This functionality is targeted to assist applications/end devices that don't have proxy support, or can't run external applications (like Smart TV's). Making it possible to run Xray proxy right on network edge devices (routers) with support to route raw network traffic. \
|
||||
Primary targets are Linux based router devices. Like most popular OpenWRT option. \
|
||||
Although support for Windows is also implemented (see below).
|
||||
Support for Windows, macOS, Android and iOS is also implemented (see below).
|
||||
|
||||
## PLEASE READ FOLLOWING CAREFULLY
|
||||
|
||||
@@ -172,3 +172,61 @@ route add 1.1.1.1 mask 255.0.0.0 0.0.0.0 if 47
|
||||
Note on ipv6 support. \
|
||||
Despite Windows also giving the adapter autoconfigured ipv6 address, the ipv6 is not possible until the interface has any _routable_ ipv6 address (given link-local address will not accept traffic from external addresses). \
|
||||
So everything applicable for ipv4 above also works for ipv6, you only need to give the interface some address manually, e.g. anything private like fc00::a:b:c:d/64 will do just fine
|
||||
|
||||
## MAC OS X SUPPORT
|
||||
|
||||
Darwin (Mac OS X) support of the same functionality is implemented through utun (userspace tunnel).
|
||||
|
||||
Interface name in the configuration must comply to the scheme "utunN", where N is some number. \
|
||||
Most running OS'es create some amount of utun interfaces in advance for own needs. Please either check the interfaces you already have occupied by issuing following command:
|
||||
```
|
||||
ifconfig
|
||||
```
|
||||
Produced list will have all system interfaces listed, from which you will see how many "utun" ones already exists.
|
||||
It's not required to select next available number, e.g. if you have utun1-utun7 interfaces, it's not required to have "utun8" in the config. You can choose any available name, even utun20, to get surely available interface number.
|
||||
|
||||
To attach routing to the interface, route command like following can be executed:
|
||||
```
|
||||
sudo route add -net 1.1.1.0/24 -iface utun10
|
||||
```
|
||||
```
|
||||
sudo route add -inet6 -host 2606:4700:4700::1111 -iface utun10
|
||||
sudo route add -inet6 -host 2606:4700:4700::1001 -iface utun10
|
||||
```
|
||||
Important to remember that everything written above about Linux routing concept, also apply to Mac OS X. If you simply route default route through utun interface, that will result network loop and immediate network failure.
|
||||
|
||||
## ANDROID SUPPORT
|
||||
|
||||
Android uses the VpnService API which provides a TUN file descriptor to the application.
|
||||
|
||||
Obtain the fd from VpnService:
|
||||
```kotlin
|
||||
val tunFd = vpnInterface.fd
|
||||
```
|
||||
|
||||
Set the environment variable `xray.tun.fd` (or `XRAY_TUN_FD`) to the fd number before starting Xray. This can be done from Kotlin/Java or by exposing a Go function via gomobile bindings.
|
||||
|
||||
Build using gomobile for Android library integration:
|
||||
```
|
||||
gomobile bind -target=android
|
||||
```
|
||||
|
||||
## iOS SUPPORT
|
||||
|
||||
iOS uses the same utun packet format as macOS, but the file descriptor is provided by NetworkExtension.
|
||||
|
||||
Obtain the fd from NetworkExtension:
|
||||
```swift
|
||||
var buf = [CChar](repeating: 0, count: Int(IFNAMSIZ))
|
||||
let utunPrefix = "utun".utf8CString.dropLast()
|
||||
let tunFd = ((0 ... 1024).first { (_ fd: Int32) -> Bool in var len = socklen_t(buf.count)
|
||||
return getsockopt(fd, 2, 2, &buf, &len) == 0 && buf.starts(with: utunPrefix)
|
||||
}!
|
||||
```
|
||||
|
||||
Set the environment variable `xray.tun.fd` (or `XRAY_TUN_FD`) to the fd number before starting Xray. This can be done from Swift/Objective-C or by exposing a Go function via gomobile bindings.
|
||||
|
||||
Build using gomobile for iOS framework integration:
|
||||
```
|
||||
gomobile bind -target=ios
|
||||
```
|
||||
@@ -106,8 +106,9 @@ func (t *Handler) HandleConnection(conn net.Conn, destination net.Destination) {
|
||||
// to close, send completion packets back to the network, and cleanup
|
||||
defer conn.Close()
|
||||
|
||||
sid := session.NewID()
|
||||
ctx := c.ContextWithID(t.ctx, sid)
|
||||
ctx, cancel := context.WithCancel(t.ctx)
|
||||
defer cancel()
|
||||
ctx = c.ContextWithID(ctx, session.NewID())
|
||||
|
||||
source := net.DestinationFromAddr(conn.RemoteAddr())
|
||||
inbound := session.Inbound{
|
||||
|
||||
@@ -236,6 +236,10 @@ func createStack(ep stack.LinkEndpoint) (*stack.Stack, error) {
|
||||
mOpt := tcpip.TCPModerateReceiveBufferOption(true)
|
||||
gStack.SetTransportProtocolOption(tcp.ProtocolNumber, &mOpt)
|
||||
|
||||
// Disable RACK/TLP loss recovery to fix connection stalls under high load
|
||||
rOpt := tcpip.TCPRecovery(0)
|
||||
gStack.SetTransportProtocolOption(tcp.ProtocolNumber, &rOpt)
|
||||
|
||||
tcpRXBufOpt := tcpip.TCPReceiveBufferSizeRangeOption{
|
||||
Min: tcpRXBufMinSize,
|
||||
Default: tcpRXBufDefSize,
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
var ErrQueueEmpty = errors.New("queue is empty")
|
||||
|
||||
type GVisorDevice interface {
|
||||
WritePacket(packet *stack.PacketBuffer) tcpip.Error
|
||||
ReadPacket() (byte, *stack.PacketBuffer, error)
|
||||
Wait()
|
||||
}
|
||||
|
||||
// LinkEndpoint implements GVisor stack.LinkEndpoint
|
||||
var _ stack.LinkEndpoint = (*LinkEndpoint)(nil)
|
||||
|
||||
type LinkEndpoint struct {
|
||||
deviceMTU uint32
|
||||
device GVisorDevice
|
||||
dispatcherCancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) MTU() uint32 {
|
||||
return e.deviceMTU
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) SetMTU(_ uint32) {
|
||||
// not Implemented, as it is not expected GVisor will be asking tun device to be modified
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) MaxHeaderLength() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) LinkAddress() tcpip.LinkAddress {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) SetLinkAddress(_ tcpip.LinkAddress) {
|
||||
// not Implemented, as it is not expected GVisor will be asking tun device to be modified
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
return stack.CapabilityRXChecksumOffload
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
if e.dispatcherCancel != nil {
|
||||
e.dispatcherCancel()
|
||||
e.dispatcherCancel = nil
|
||||
}
|
||||
|
||||
if dispatcher != nil {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go e.dispatchLoop(ctx, dispatcher)
|
||||
e.dispatcherCancel = cancel
|
||||
}
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) IsAttached() bool {
|
||||
return e.dispatcherCancel != nil
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) Wait() {
|
||||
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
return header.ARPHardwareNone
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) AddHeader(buffer *stack.PacketBuffer) {
|
||||
// tun interface doesn't have link layer header, it will be added by the OS
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) ParseHeader(ptr *stack.PacketBuffer) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) Close() {
|
||||
if e.dispatcherCancel != nil {
|
||||
e.dispatcherCancel()
|
||||
e.dispatcherCancel = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) SetOnCloseAction(_ func()) {
|
||||
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) WritePackets(packetBufferList stack.PacketBufferList) (int, tcpip.Error) {
|
||||
var n int
|
||||
var err tcpip.Error
|
||||
|
||||
for _, packetBuffer := range packetBufferList.AsSlice() {
|
||||
err = e.device.WritePacket(packetBuffer)
|
||||
if err != nil {
|
||||
return n, &tcpip.ErrAborted{}
|
||||
}
|
||||
n++
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (e *LinkEndpoint) dispatchLoop(ctx context.Context, dispatcher stack.NetworkDispatcher) {
|
||||
var networkProtocolNumber tcpip.NetworkProtocolNumber
|
||||
var version byte
|
||||
var packet *stack.PacketBuffer
|
||||
var err error
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
version, packet, err = e.device.ReadPacket()
|
||||
// on "queue empty", ask device to yield slightly and continue
|
||||
if errors.Is(err, ErrQueueEmpty) {
|
||||
e.device.Wait()
|
||||
continue
|
||||
}
|
||||
// stop dispatcher loop on any other interface failure
|
||||
if err != nil {
|
||||
e.Attach(nil)
|
||||
return
|
||||
}
|
||||
|
||||
// extract network protocol number from the packet first byte
|
||||
// (which is returned separately, since it is so incredibly hard to extract one byte from
|
||||
// stack.PacketBuffer without additional memory allocation and full copying it back and forth)
|
||||
switch version {
|
||||
case 4:
|
||||
networkProtocolNumber = header.IPv4ProtocolNumber
|
||||
case 6:
|
||||
networkProtocolNumber = header.IPv6ProtocolNumber
|
||||
default:
|
||||
// discard unknown network protocol packet
|
||||
packet.DecRef()
|
||||
continue
|
||||
}
|
||||
|
||||
// dispatch the buffer to the stack
|
||||
dispatcher.DeliverNetworkPacket(networkProtocolNumber, packet)
|
||||
// signal the buffer that it can be released
|
||||
packet.DecRef()
|
||||
}
|
||||
}
|
||||
}
|
||||
+260
-75
@@ -5,163 +5,348 @@ package tun
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
const (
|
||||
utunControlName = "com.apple.net.utun_control"
|
||||
utunOptIfName = 2
|
||||
sysprotoControl = 2
|
||||
gateway = "169.254.10.1/30"
|
||||
utunHeaderSize = 4
|
||||
)
|
||||
|
||||
const (
|
||||
SIOCAIFADDR6 = 2155899162 // netinet6/in6_var.h
|
||||
IN6_IFF_NODAD = 0x0020 // netinet6/in6_var.h
|
||||
IN6_IFF_SECURED = 0x0400 // netinet6/in6_var.h
|
||||
ND6_INFINITE_LIFETIME = 0xFFFFFFFF // netinet6/nd6.h
|
||||
)
|
||||
|
||||
//go:linkname procyield runtime.procyield
|
||||
func procyield(cycles uint32)
|
||||
|
||||
type DarwinTun struct {
|
||||
tunFd int
|
||||
name string
|
||||
tunFile *os.File
|
||||
options TunOptions
|
||||
ownsFd bool // true for macOS (we created the fd), false for iOS (fd from system)
|
||||
}
|
||||
|
||||
var _ Tun = (*DarwinTun)(nil)
|
||||
var _ GVisorTun = (*DarwinTun)(nil)
|
||||
var _ GVisorDevice = (*DarwinTun)(nil)
|
||||
|
||||
func NewTun(options TunOptions) (Tun, error) {
|
||||
tunFd, name, err := openUTun(options.Name)
|
||||
// Check if fd is provided via environment (iOS mode)
|
||||
fdStr := platform.NewEnvFlag(platform.TunFdKey).GetValue(func() string { return "" })
|
||||
if fdStr != "" {
|
||||
// iOS: use provided fd from NetworkExtension
|
||||
fd, err := strconv.Atoi(fdStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = unix.SetNonblock(fd, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DarwinTun{
|
||||
tunFile: os.NewFile(uintptr(fd), "utun"),
|
||||
options: options,
|
||||
ownsFd: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// macOS: create our own utun interface
|
||||
tunFile, err := open(options.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = setup(options.Name, options.MTU)
|
||||
if err != nil {
|
||||
_ = tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DarwinTun{
|
||||
tunFd: tunFd,
|
||||
name: name,
|
||||
tunFile: tunFile,
|
||||
options: options,
|
||||
ownsFd: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *DarwinTun) Start() error {
|
||||
if t.options.MTU > 0 {
|
||||
if err := setMTU(t.name, int(t.options.MTU)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return setState(t.name, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *DarwinTun) Close() error {
|
||||
_ = setState(t.name, false)
|
||||
return unix.Close(t.tunFd)
|
||||
if t.ownsFd {
|
||||
return t.tunFile.Close()
|
||||
}
|
||||
// iOS: don't close the fd, it's owned by NetworkExtension
|
||||
return nil
|
||||
}
|
||||
|
||||
// WritePacket implements GVisorDevice method to write one packet to the tun device
|
||||
func (t *DarwinTun) WritePacket(packet *stack.PacketBuffer) tcpip.Error {
|
||||
// request memory to write from reusable buffer pool
|
||||
b := buf.NewWithSize(int32(t.options.MTU) + utunHeaderSize)
|
||||
defer b.Release()
|
||||
|
||||
// prepare Darwin specific packet header
|
||||
_, _ = b.Write([]byte{0x0, 0x0, 0x0, 0x0})
|
||||
// copy the bytes of slices that compose the packet into the allocated buffer
|
||||
for _, packetElement := range packet.AsSlices() {
|
||||
_, _ = b.Write(packetElement)
|
||||
}
|
||||
// fill Darwin specific header from the first raw packet byte, that we can access now
|
||||
var family byte
|
||||
switch b.Byte(4) >> 4 {
|
||||
case 4:
|
||||
family = unix.AF_INET
|
||||
case 6:
|
||||
family = unix.AF_INET6
|
||||
default:
|
||||
return &tcpip.ErrAborted{}
|
||||
}
|
||||
b.SetByte(3, family)
|
||||
|
||||
if _, err := t.tunFile.Write(b.Bytes()); err != nil {
|
||||
if errors.Is(err, unix.EAGAIN) {
|
||||
return &tcpip.ErrWouldBlock{}
|
||||
}
|
||||
return &tcpip.ErrAborted{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadPacket implements GVisorDevice method to read one packet from the tun device
|
||||
// It is expected that the method will not block, rather return ErrQueueEmpty when there is nothing on the line,
|
||||
// which will make the stack call Wait which should implement desired push-back
|
||||
func (t *DarwinTun) ReadPacket() (byte, *stack.PacketBuffer, error) {
|
||||
// request memory to write from reusable buffer pool
|
||||
b := buf.NewWithSize(int32(t.options.MTU) + utunHeaderSize)
|
||||
|
||||
// read the bytes to the interface file
|
||||
n, err := b.ReadFrom(t.tunFile)
|
||||
if errors.Is(err, unix.EAGAIN) || errors.Is(err, unix.EINTR) {
|
||||
b.Release()
|
||||
return 0, nil, ErrQueueEmpty
|
||||
}
|
||||
if err != nil {
|
||||
b.Release()
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
// discard empty or sub-empty packets
|
||||
if n <= utunHeaderSize {
|
||||
b.Release()
|
||||
return 0, nil, ErrQueueEmpty
|
||||
}
|
||||
|
||||
// network protocol version from first byte of the raw packet, the one that follows Darwin specific header
|
||||
version := b.Byte(utunHeaderSize) >> 4
|
||||
packetBuffer := buffer.MakeWithData(b.BytesFrom(utunHeaderSize))
|
||||
return version, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Payload: packetBuffer,
|
||||
IsForwardedPacket: true,
|
||||
OnRelease: func() {
|
||||
b.Release()
|
||||
},
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Wait some cpu cycles
|
||||
func (t *DarwinTun) Wait() {
|
||||
procyield(1)
|
||||
}
|
||||
|
||||
func (t *DarwinTun) newEndpoint() (stack.LinkEndpoint, error) {
|
||||
return newDarwinEndpoint(t.tunFd, t.options.MTU), nil
|
||||
return &LinkEndpoint{deviceMTU: t.options.MTU, device: t}, nil
|
||||
}
|
||||
|
||||
func openUTun(name string) (int, string, error) {
|
||||
// open the interface, by creating new utunN if in the system and returning its file descriptor
|
||||
func open(name string) (*os.File, error) {
|
||||
ifIndex := -1
|
||||
_, err := fmt.Sscanf(name, "utun%d", &ifIndex)
|
||||
if err != nil || ifIndex < 0 {
|
||||
return nil, errors.New("interface name must be utunN, where N is a number, e.g. utun9, utun11 and so on")
|
||||
}
|
||||
|
||||
fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, sysprotoControl)
|
||||
if err != nil {
|
||||
return -1, "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctlInfo := &unix.CtlInfo{}
|
||||
copy(ctlInfo.Name[:], utunControlName)
|
||||
if err := unix.IoctlCtlInfo(fd, ctlInfo); err != nil {
|
||||
_ = unix.Close(fd)
|
||||
return -1, "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sockaddr := &unix.SockaddrCtl{
|
||||
ID: ctlInfo.Id,
|
||||
Unit: parseUTunUnit(name),
|
||||
Unit: uint32(ifIndex) + 1,
|
||||
}
|
||||
|
||||
if err := unix.Connect(fd, sockaddr); err != nil {
|
||||
_ = unix.Close(fd)
|
||||
return -1, "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := unix.SetNonblock(fd, true); err != nil {
|
||||
_ = unix.Close(fd)
|
||||
return -1, "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tunName, err := unix.GetsockoptString(fd, sysprotoControl, utunOptIfName)
|
||||
if err != nil {
|
||||
_ = unix.Close(fd)
|
||||
return -1, "", err
|
||||
}
|
||||
|
||||
tunName = strings.TrimRight(tunName, "\x00")
|
||||
if tunName == "" {
|
||||
_ = unix.Close(fd)
|
||||
return -1, "", errors.New("empty utun name")
|
||||
}
|
||||
|
||||
return fd, tunName, nil
|
||||
return os.NewFile(uintptr(fd), name), nil
|
||||
}
|
||||
|
||||
func parseUTunUnit(name string) uint32 {
|
||||
var unit uint32
|
||||
if _, err := fmt.Sscanf(name, "utun%d", &unit); err != nil {
|
||||
return 0
|
||||
}
|
||||
return unit + 1
|
||||
}
|
||||
|
||||
type ifreqMTU struct {
|
||||
Name [unix.IFNAMSIZ]byte
|
||||
MTU int32
|
||||
_ [12]byte
|
||||
}
|
||||
|
||||
type ifreqFlags struct {
|
||||
Name [unix.IFNAMSIZ]byte
|
||||
Flags int16
|
||||
_ [14]byte
|
||||
}
|
||||
|
||||
func setMTU(name string, mtu int) error {
|
||||
if mtu <= 0 {
|
||||
return nil
|
||||
// setup the interface by name
|
||||
func setup(name string, MTU uint32) error {
|
||||
if err := setMTU(name, MTU); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
|
||||
/*
|
||||
* Darwin routing require tunnel type interface to have local and remote address, to be routable.
|
||||
* To simplify inevitable task, assign the interface static ip address, which in current implementation
|
||||
* is just some random ip from link-local pool, allowing to not bother about existing routing intersection.
|
||||
*/
|
||||
syntheticIP, _ := netip.ParsePrefix(gateway)
|
||||
if err := setIPAddress(name, syntheticIP); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setMTU sets MTU on the interface by given name
|
||||
func setMTU(name string, mtu uint32) error {
|
||||
socket, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = unix.Close(fd) }()
|
||||
defer unix.Close(socket)
|
||||
|
||||
ifr := ifreqMTU{MTU: int32(mtu)}
|
||||
ifr := unix.IfreqMTU{MTU: int32(mtu)}
|
||||
copy(ifr.Name[:], name)
|
||||
return ioctlPtr(fd, unix.SIOCSIFMTU, unsafe.Pointer(&ifr))
|
||||
return unix.IoctlSetIfreqMTU(socket, &ifr)
|
||||
}
|
||||
|
||||
func setState(name string, up bool) error {
|
||||
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
|
||||
type ifAliasReq4 struct {
|
||||
Name [unix.IFNAMSIZ]byte
|
||||
Addr unix.RawSockaddrInet4
|
||||
Dstaddr unix.RawSockaddrInet4
|
||||
Mask unix.RawSockaddrInet4
|
||||
}
|
||||
|
||||
type ifAliasReq6 struct {
|
||||
Name [unix.IFNAMSIZ]byte
|
||||
Addr unix.RawSockaddrInet6
|
||||
Dstaddr unix.RawSockaddrInet6
|
||||
Mask unix.RawSockaddrInet6
|
||||
Flags uint32
|
||||
Lifetime addrLifetime6
|
||||
}
|
||||
|
||||
type addrLifetime6 struct {
|
||||
Expire float64
|
||||
Preferred float64
|
||||
Vltime uint32
|
||||
Pltime uint32
|
||||
}
|
||||
|
||||
// setIPAddress sets ipv4 and ipv6 addresses to the interface, required for the routing to work
|
||||
func setIPAddress(name string, gateway netip.Prefix) error {
|
||||
socket4, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = unix.Close(fd) }()
|
||||
defer unix.Close(socket4)
|
||||
|
||||
ifr := ifreqFlags{}
|
||||
copy(ifr.Name[:], name)
|
||||
// assume local ip address is next one from the remote address
|
||||
local4 := gateway.Addr().As4()
|
||||
local4[3]++
|
||||
|
||||
if err := ioctlPtr(fd, unix.SIOCGIFFLAGS, unsafe.Pointer(&ifr)); err != nil {
|
||||
// fill the configuration for ipv4
|
||||
ifReq4 := ifAliasReq4{
|
||||
Addr: unix.RawSockaddrInet4{
|
||||
Len: unix.SizeofSockaddrInet4,
|
||||
Family: unix.AF_INET,
|
||||
Addr: local4,
|
||||
},
|
||||
Dstaddr: unix.RawSockaddrInet4{
|
||||
Len: unix.SizeofSockaddrInet4,
|
||||
Family: unix.AF_INET,
|
||||
Addr: gateway.Addr().As4(),
|
||||
},
|
||||
Mask: unix.RawSockaddrInet4{
|
||||
Len: unix.SizeofSockaddrInet4,
|
||||
Family: unix.AF_INET,
|
||||
Addr: netip.MustParseAddr(net.IP(net.CIDRMask(gateway.Bits(), 32)).String()).As4(),
|
||||
},
|
||||
}
|
||||
copy(ifReq4.Name[:], name)
|
||||
if err = ioctlPtr(socket4, unix.SIOCAIFADDR, unsafe.Pointer(&ifReq4)); err != nil {
|
||||
return os.NewSyscallError("SIOCAIFADDR", err)
|
||||
}
|
||||
|
||||
socket6, err := unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer unix.Close(socket6)
|
||||
|
||||
if up {
|
||||
ifr.Flags |= unix.IFF_UP
|
||||
} else {
|
||||
ifr.Flags &^= unix.IFF_UP
|
||||
// link-local ipv6 address with suffix from ipv6
|
||||
local6 := netip.AddrFrom16([16]byte{0: 0xfe, 1: 0x80, 12: local4[0], 13: local4[1], 14: local4[2], 15: local4[3]})
|
||||
|
||||
// fill the configuration for ipv6
|
||||
// only link-local address without the destination is enough for it
|
||||
ifReq6 := ifAliasReq6{
|
||||
Addr: unix.RawSockaddrInet6{
|
||||
Len: unix.SizeofSockaddrInet6,
|
||||
Family: unix.AF_INET6,
|
||||
Addr: local6.As16(),
|
||||
},
|
||||
Mask: unix.RawSockaddrInet6{
|
||||
Len: unix.SizeofSockaddrInet6,
|
||||
Family: unix.AF_INET6,
|
||||
Addr: netip.MustParseAddr(net.IP(net.CIDRMask(64, 128)).String()).As16(),
|
||||
},
|
||||
Flags: IN6_IFF_NODAD,
|
||||
Lifetime: addrLifetime6{
|
||||
Vltime: ND6_INFINITE_LIFETIME,
|
||||
Pltime: ND6_INFINITE_LIFETIME,
|
||||
},
|
||||
}
|
||||
// assign link-local ipv6 address to the interface.
|
||||
// this will additionally trigger OS level autoconfiguration, which will result two different link-local
|
||||
// addresses - the requested one, and autoconfigured one.
|
||||
// this really has no known side effects, just look excessive. and actually considered pretty normal way to
|
||||
// enable the ipv6 on the interface by macOS concepts.
|
||||
copy(ifReq6.Name[:], name)
|
||||
if err = ioctlPtr(socket6, SIOCAIFADDR6, unsafe.Pointer(&ifReq6)); err != nil {
|
||||
return os.NewSyscallError("SIOCAIFADDR6", err)
|
||||
}
|
||||
|
||||
return ioctlPtr(fd, unix.SIOCSIFFLAGS, unsafe.Pointer(&ifr))
|
||||
return nil
|
||||
}
|
||||
|
||||
func ioctlPtr(fd int, req uint, arg unsafe.Pointer) error {
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
|
||||
_, _, errno := unix.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
//go:build darwin
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
const utunHeaderSize = 4
|
||||
|
||||
var ErrUnsupportedNetworkProtocol = errors.New("unsupported ip version")
|
||||
|
||||
// DarwinEndpoint implements GVisor stack.LinkEndpoint
|
||||
var _ stack.LinkEndpoint = (*DarwinEndpoint)(nil)
|
||||
|
||||
type DarwinEndpoint struct {
|
||||
tunFd int
|
||||
mtu uint32
|
||||
dispatcherCancel context.CancelFunc
|
||||
}
|
||||
|
||||
func newDarwinEndpoint(tunFd int, mtu uint32) *DarwinEndpoint {
|
||||
return &DarwinEndpoint{
|
||||
tunFd: tunFd,
|
||||
mtu: mtu,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) MTU() uint32 {
|
||||
return e.mtu
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) SetMTU(_ uint32) {
|
||||
// not Implemented, as it is not expected GVisor will be asking tun device to be modified
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) MaxHeaderLength() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) LinkAddress() tcpip.LinkAddress {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) SetLinkAddress(_ tcpip.LinkAddress) {
|
||||
// not Implemented, as it is not expected GVisor will be asking tun device to be modified
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
return stack.CapabilityRXChecksumOffload
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
if e.dispatcherCancel != nil {
|
||||
e.dispatcherCancel()
|
||||
e.dispatcherCancel = nil
|
||||
}
|
||||
|
||||
if dispatcher != nil {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go e.dispatchLoop(ctx, dispatcher)
|
||||
e.dispatcherCancel = cancel
|
||||
}
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) IsAttached() bool {
|
||||
return e.dispatcherCancel != nil
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) Wait() {
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
return header.ARPHardwareNone
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) AddHeader(buffer *stack.PacketBuffer) {
|
||||
// tun interface doesn't have link layer header, it will be added by the OS
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) ParseHeader(ptr *stack.PacketBuffer) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) Close() {
|
||||
if e.dispatcherCancel != nil {
|
||||
e.dispatcherCancel()
|
||||
e.dispatcherCancel = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) SetOnCloseAction(_ func()) {
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) WritePackets(packetBufferList stack.PacketBufferList) (int, tcpip.Error) {
|
||||
var n int
|
||||
for _, packetBuffer := range packetBufferList.AsSlice() {
|
||||
family, err := ipFamilyFromPacket(packetBuffer)
|
||||
if err != nil {
|
||||
return n, &tcpip.ErrAborted{}
|
||||
}
|
||||
|
||||
var headerBytes [utunHeaderSize]byte
|
||||
binary.BigEndian.PutUint32(headerBytes[:], family)
|
||||
|
||||
writeSlices := append([][]byte{headerBytes[:]}, packetBuffer.AsSlices()...)
|
||||
if _, err := unix.Writev(e.tunFd, writeSlices); err != nil {
|
||||
if errors.Is(err, unix.EAGAIN) {
|
||||
return n, &tcpip.ErrWouldBlock{}
|
||||
}
|
||||
return n, &tcpip.ErrAborted{}
|
||||
}
|
||||
n++
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) dispatchLoop(ctx context.Context, dispatcher stack.NetworkDispatcher) {
|
||||
readSize := int(e.mtu)
|
||||
if readSize <= 0 {
|
||||
readSize = 65535
|
||||
}
|
||||
readSize += utunHeaderSize
|
||||
|
||||
buf := make([]byte, readSize)
|
||||
for ctx.Err() == nil {
|
||||
|
||||
n, err := unix.Read(e.tunFd, buf)
|
||||
if err != nil {
|
||||
if errors.Is(err, unix.EAGAIN) || errors.Is(err, unix.EINTR) {
|
||||
continue
|
||||
}
|
||||
e.Attach(nil)
|
||||
return
|
||||
}
|
||||
if n <= utunHeaderSize {
|
||||
continue
|
||||
}
|
||||
|
||||
networkProtocol, packet, err := parseUTunPacket(buf[:n])
|
||||
if errors.Is(err, ErrUnsupportedNetworkProtocol) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
e.Attach(nil)
|
||||
return
|
||||
}
|
||||
|
||||
dispatcher.DeliverNetworkPacket(networkProtocol, packet)
|
||||
packet.DecRef()
|
||||
}
|
||||
}
|
||||
|
||||
func parseUTunPacket(packet []byte) (tcpip.NetworkProtocolNumber, *stack.PacketBuffer, error) {
|
||||
if len(packet) <= utunHeaderSize {
|
||||
return 0, nil, errors.New("packet too short")
|
||||
}
|
||||
|
||||
family := binary.BigEndian.Uint32(packet[:utunHeaderSize])
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
switch family {
|
||||
case uint32(unix.AF_INET):
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
case uint32(unix.AF_INET6):
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
default:
|
||||
return 0, nil, ErrUnsupportedNetworkProtocol
|
||||
}
|
||||
|
||||
payload := packet[utunHeaderSize:]
|
||||
packetBuffer := buffer.MakeWithData(payload)
|
||||
return networkProtocol, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Payload: packetBuffer,
|
||||
IsForwardedPacket: true,
|
||||
}), nil
|
||||
}
|
||||
|
||||
func ipFamilyFromPacket(packetBuffer *stack.PacketBuffer) (uint32, error) {
|
||||
for _, slice := range packetBuffer.AsSlices() {
|
||||
if len(slice) == 0 {
|
||||
continue
|
||||
}
|
||||
switch header.IPVersion(slice) {
|
||||
case header.IPv4Version:
|
||||
return uint32(unix.AF_INET), nil
|
||||
case header.IPv6Version:
|
||||
return uint32(unix.AF_INET6), nil
|
||||
default:
|
||||
return 0, ErrUnsupportedNetworkProtocol
|
||||
}
|
||||
}
|
||||
return 0, errors.New("empty packet")
|
||||
}
|
||||
@@ -3,19 +3,28 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
_ "unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wintun"
|
||||
"gvisor.dev/gvisor/pkg/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
//go:linkname procyield runtime.procyield
|
||||
func procyield(cycles uint32)
|
||||
|
||||
// WindowsTun is an object that handles tun network interface on Windows
|
||||
// current version is heavily stripped to do nothing more,
|
||||
// then create a network interface, to be provided as endpoint to gVisor ip stack
|
||||
type WindowsTun struct {
|
||||
options TunOptions
|
||||
adapter *wintun.Adapter
|
||||
session wintun.Session
|
||||
MTU uint32
|
||||
options TunOptions
|
||||
adapter *wintun.Adapter
|
||||
session wintun.Session
|
||||
readWait windows.Handle
|
||||
MTU uint32
|
||||
}
|
||||
|
||||
// WindowsTun implements Tun
|
||||
@@ -24,6 +33,9 @@ var _ Tun = (*WindowsTun)(nil)
|
||||
// WindowsTun implements GVisorTun
|
||||
var _ GVisorTun = (*WindowsTun)(nil)
|
||||
|
||||
// WindowsTun implements GVisorDevice
|
||||
var _ GVisorDevice = (*WindowsTun)(nil)
|
||||
|
||||
// NewTun creates a Wintun interface with the given name. Should a Wintun
|
||||
// interface with the same name exist, it tried to be reused.
|
||||
func NewTun(options TunOptions) (Tun, error) {
|
||||
@@ -41,9 +53,10 @@ func NewTun(options TunOptions) (Tun, error) {
|
||||
}
|
||||
|
||||
tun := &WindowsTun{
|
||||
options: options,
|
||||
adapter: adapter,
|
||||
session: session,
|
||||
options: options,
|
||||
adapter: adapter,
|
||||
session: session,
|
||||
readWait: session.ReadWaitEvent(),
|
||||
// there is currently no iphndl.dll support, which is the netlink library for windows
|
||||
// so there is nowhere to change MTU for the Wintun interface, and we take its default value
|
||||
MTU: wintun.PacketSizeMax,
|
||||
@@ -78,7 +91,54 @@ func (t *WindowsTun) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// newEndpoint builds new gVisor stack.LinkEndpoint (WintunEndpoint) on top of WindowsTun
|
||||
// WritePacket implements GVisorDevice method to write one packet to the tun device
|
||||
func (t *WindowsTun) WritePacket(packetBuffer *stack.PacketBuffer) tcpip.Error {
|
||||
// request buffer from Wintun
|
||||
packet, err := t.session.AllocateSendPacket(packetBuffer.Size())
|
||||
if err != nil {
|
||||
return &tcpip.ErrAborted{}
|
||||
}
|
||||
|
||||
// copy the bytes of slices that compose the packet into the allocated buffer
|
||||
var index int
|
||||
for _, packetElement := range packetBuffer.AsSlices() {
|
||||
index += copy(packet[index:], packetElement)
|
||||
}
|
||||
|
||||
// signal Wintun to send that buffer as the packet
|
||||
t.session.SendPacket(packet)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadPacket implements GVisorDevice method to read one packet from the tun device
|
||||
// It is expected that the method will not block, rather return ErrQueueEmpty when there is nothing on the line,
|
||||
// which will make the stack call Wait which should implement desired push-back
|
||||
func (t *WindowsTun) ReadPacket() (byte, *stack.PacketBuffer, error) {
|
||||
packet, err := t.session.ReceivePacket()
|
||||
if errors.Is(err, windows.ERROR_NO_MORE_ITEMS) {
|
||||
return 0, nil, ErrQueueEmpty
|
||||
}
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
version := packet[0] >> 4
|
||||
packetBuffer := buffer.MakeWithView(buffer.NewViewWithData(packet))
|
||||
return version, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Payload: packetBuffer,
|
||||
IsForwardedPacket: true,
|
||||
OnRelease: func() {
|
||||
t.session.ReleaseReceivePacket(packet)
|
||||
},
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (t *WindowsTun) Wait() {
|
||||
procyield(1)
|
||||
_, _ = windows.WaitForSingleObject(t.readWait, windows.INFINITE)
|
||||
}
|
||||
|
||||
func (t *WindowsTun) newEndpoint() (stack.LinkEndpoint, error) {
|
||||
return &WintunEndpoint{tun: t}, nil
|
||||
return &LinkEndpoint{deviceMTU: t.options.MTU, device: t}, nil
|
||||
}
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
_ "unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"gvisor.dev/gvisor/pkg/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
// WintunEndpoint implements GVisor stack.LinkEndpoint
|
||||
var _ stack.LinkEndpoint = (*WintunEndpoint)(nil)
|
||||
|
||||
type WintunEndpoint struct {
|
||||
tun *WindowsTun
|
||||
dispatcherCancel context.CancelFunc
|
||||
}
|
||||
|
||||
var ErrUnsupportedNetworkProtocol = errors.New("unsupported ip version")
|
||||
|
||||
//go:linkname procyield runtime.procyield
|
||||
func procyield(cycles uint32)
|
||||
|
||||
func (e *WintunEndpoint) MTU() uint32 {
|
||||
return e.tun.MTU
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) SetMTU(mtu uint32) {
|
||||
// not Implemented, as it is not expected GVisor will be asking tun device to be modified
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) MaxHeaderLength() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) LinkAddress() tcpip.LinkAddress {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) SetLinkAddress(addr tcpip.LinkAddress) {
|
||||
// not Implemented, as it is not expected GVisor will be asking tun device to be modified
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
return stack.CapabilityRXChecksumOffload
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
if e.dispatcherCancel != nil {
|
||||
e.dispatcherCancel()
|
||||
e.dispatcherCancel = nil
|
||||
}
|
||||
|
||||
if dispatcher != nil {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go e.dispatchLoop(ctx, dispatcher)
|
||||
e.dispatcherCancel = cancel
|
||||
}
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) IsAttached() bool {
|
||||
return e.dispatcherCancel != nil
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) Wait() {
|
||||
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
return header.ARPHardwareNone
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) AddHeader(buffer *stack.PacketBuffer) {
|
||||
// tun interface doesn't have link layer header, it will be added by the OS
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) ParseHeader(ptr *stack.PacketBuffer) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) Close() {
|
||||
if e.dispatcherCancel != nil {
|
||||
e.dispatcherCancel()
|
||||
e.dispatcherCancel = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) SetOnCloseAction(f func()) {
|
||||
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) WritePackets(packetBufferList stack.PacketBufferList) (int, tcpip.Error) {
|
||||
var n int
|
||||
// for all packets in the list to send
|
||||
for _, packetBuffer := range packetBufferList.AsSlice() {
|
||||
// request buffer from Wintun
|
||||
packet, err := e.tun.session.AllocateSendPacket(packetBuffer.Size())
|
||||
if err != nil {
|
||||
return n, &tcpip.ErrAborted{}
|
||||
}
|
||||
|
||||
// copy the bytes of slices that compose the packet into the allocated buffer
|
||||
var index int
|
||||
for _, packetElement := range packetBuffer.AsSlices() {
|
||||
index += copy(packet[index:], packetElement)
|
||||
}
|
||||
|
||||
// signal Wintun to send that buffer as the packet
|
||||
e.tun.session.SendPacket(packet)
|
||||
n++
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) readPacket() (tcpip.NetworkProtocolNumber, *stack.PacketBuffer, error) {
|
||||
packet, err := e.tun.session.ReceivePacket()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
switch header.IPVersion(packet) {
|
||||
case header.IPv4Version:
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
case header.IPv6Version:
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
default:
|
||||
e.tun.session.ReleaseReceivePacket(packet)
|
||||
return 0, nil, ErrUnsupportedNetworkProtocol
|
||||
}
|
||||
|
||||
packetBuffer := buffer.MakeWithView(buffer.NewViewWithData(packet))
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Payload: packetBuffer,
|
||||
IsForwardedPacket: true,
|
||||
OnRelease: func() {
|
||||
e.tun.session.ReleaseReceivePacket(packet)
|
||||
},
|
||||
})
|
||||
return networkProtocol, pkt, nil
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) dispatchLoop(ctx context.Context, dispatcher stack.NetworkDispatcher) {
|
||||
readWait := e.tun.session.ReadWaitEvent()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
networkProtocolNumber, packet, err := e.readPacket()
|
||||
// read queue empty, yield slightly, wait for the spinlock, retry
|
||||
if errors.Is(err, windows.ERROR_NO_MORE_ITEMS) {
|
||||
procyield(1)
|
||||
_, _ = windows.WaitForSingleObject(readWait, windows.INFINITE)
|
||||
continue
|
||||
}
|
||||
// discard unknown network protocol packet
|
||||
if errors.Is(err, ErrUnsupportedNetworkProtocol) {
|
||||
continue
|
||||
}
|
||||
// stop dispatcher loop on any other interface failure
|
||||
if err != nil {
|
||||
e.Attach(nil)
|
||||
continue
|
||||
}
|
||||
|
||||
// dispatch the buffer to the stack
|
||||
dispatcher.DeliverNetworkPacket(networkProtocolNumber, packet)
|
||||
// signal the buffer that it can be released
|
||||
packet.DecRef()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,12 +68,12 @@ func (aidd *AuthIDDecoder) Decode(data [16]byte) (int64, uint32, int32, []byte)
|
||||
}
|
||||
|
||||
func NewAuthIDDecoderHolder() *AuthIDDecoderHolder {
|
||||
return &AuthIDDecoderHolder{make(map[string]*AuthIDDecoderItem), antireplay.NewReplayFilter(120)}
|
||||
return &AuthIDDecoderHolder{make(map[string]*AuthIDDecoderItem), antireplay.NewMapFilter[[16]byte](120)}
|
||||
}
|
||||
|
||||
type AuthIDDecoderHolder struct {
|
||||
decoders map[string]*AuthIDDecoderItem
|
||||
filter *antireplay.ReplayFilter
|
||||
filter *antireplay.ReplayFilter[[16]byte]
|
||||
}
|
||||
|
||||
type AuthIDDecoderItem struct {
|
||||
@@ -111,7 +111,7 @@ func (a *AuthIDDecoderHolder) Match(authID [16]byte) (interface{}, error) {
|
||||
return nil, ErrInvalidTime
|
||||
}
|
||||
|
||||
if !a.filter.Check(authID[:]) {
|
||||
if !a.filter.Check(authID) {
|
||||
return nil, ErrReplay
|
||||
}
|
||||
|
||||
|
||||
+30
-17
@@ -213,27 +213,40 @@ func testTCPConn2(conn net.Conn, payloadSize int, timeout time.Duration) func()
|
||||
"\tSys =", units.ByteSize(m.Sys).String(),
|
||||
"\tNumGC =", m.NumGC)
|
||||
}()
|
||||
payload := make([]byte, payloadSize)
|
||||
common.Must2(rand.Read(payload))
|
||||
singleWrite := func(length int) error {
|
||||
payload := make([]byte, length)
|
||||
common.Must2(rand.Read(payload))
|
||||
|
||||
nBytes, err := conn.Write(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if nBytes != len(payload) {
|
||||
return errors.New("expect ", len(payload), " written, but actually ", nBytes)
|
||||
}
|
||||
nBytes, err := conn.Write(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if nBytes != len(payload) {
|
||||
return errors.New("expect ", len(payload), " written, but actually ", nBytes)
|
||||
}
|
||||
|
||||
response, err := readFrom2(conn, timeout, payloadSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = response
|
||||
response, err := readFrom2(conn, timeout, length)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = response
|
||||
|
||||
if r := bytes.Compare(response, xor(payload)); r != 0 {
|
||||
return errors.New(r)
|
||||
}
|
||||
if r := bytes.Compare(response, xor(payload)); r != 0 {
|
||||
return errors.New(r)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
for payloadSize > 0 {
|
||||
sizeToWrite := 1024
|
||||
if payloadSize < 1024 {
|
||||
sizeToWrite = payloadSize
|
||||
}
|
||||
if err := singleWrite(sizeToWrite); err != nil {
|
||||
return err
|
||||
}
|
||||
payloadSize -= sizeToWrite
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ func TestSimpleTLSConnection(t *testing.T) {
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
|
||||
ct, ctHash := cert.MustGenerate(nil, cert.CommonName("localhost"))
|
||||
|
||||
userID := protocol.NewID(uuid.New())
|
||||
serverPort := tcp.PickPort()
|
||||
serverConfig := &core.Config{
|
||||
@@ -48,7 +50,7 @@ func TestSimpleTLSConnection(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(ct)},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -104,7 +106,7 @@ func TestSimpleTLSConnection(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{ctHash[:]},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -247,6 +249,8 @@ func TestTLSOverKCP(t *testing.T) {
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
|
||||
ct, ctHash := cert.MustGenerate(nil, cert.CommonName("localhost"))
|
||||
|
||||
userID := protocol.NewID(uuid.New())
|
||||
serverPort := udp.PickPort()
|
||||
serverConfig := &core.Config{
|
||||
@@ -260,7 +264,7 @@ func TestTLSOverKCP(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(ct)},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -317,7 +321,7 @@ func TestTLSOverKCP(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{ctHash[:]},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -343,6 +347,8 @@ func TestTLSOverWebSocket(t *testing.T) {
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
|
||||
ct, ctHash := cert.MustGenerate(nil, cert.CommonName("localhost"))
|
||||
|
||||
userID := protocol.NewID(uuid.New())
|
||||
serverPort := tcp.PickPort()
|
||||
serverConfig := &core.Config{
|
||||
@@ -356,7 +362,7 @@ func TestTLSOverWebSocket(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(ct)},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -419,7 +425,7 @@ func TestTLSOverWebSocket(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{ctHash[:]},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -449,6 +455,8 @@ func TestGRPC(t *testing.T) {
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
|
||||
ct, ctHash := cert.MustGenerate(nil, cert.CommonName("localhost"))
|
||||
|
||||
userID := protocol.NewID(uuid.New())
|
||||
serverPort := tcp.PickPort()
|
||||
serverConfig := &core.Config{
|
||||
@@ -468,7 +476,7 @@ func TestGRPC(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(ct)},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -531,7 +539,7 @@ func TestGRPC(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{ctHash[:]},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -561,6 +569,8 @@ func TestGRPCMultiMode(t *testing.T) {
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
|
||||
ct, ctHash := cert.MustGenerate(nil, cert.CommonName("localhost"))
|
||||
|
||||
userID := protocol.NewID(uuid.New())
|
||||
serverPort := tcp.PickPort()
|
||||
serverConfig := &core.Config{
|
||||
@@ -580,7 +590,7 @@ func TestGRPCMultiMode(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(ct)},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -643,7 +653,7 @@ func TestGRPCMultiMode(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{ctHash[:]},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -672,7 +682,7 @@ func TestSimpleTLSConnectionPinned(t *testing.T) {
|
||||
dest, err := tcpServer.Start()
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
certificateDer := cert.MustGenerate(nil)
|
||||
certificateDer, _ := cert.MustGenerate(nil)
|
||||
certificate := tls.ParseCertificate(certificateDer)
|
||||
certHash := tls.GenerateCertHash(certificateDer.Certificate)
|
||||
userID := protocol.NewID(uuid.New())
|
||||
@@ -743,7 +753,6 @@ func TestSimpleTLSConnectionPinned(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{certHash},
|
||||
}),
|
||||
},
|
||||
@@ -769,7 +778,7 @@ func TestSimpleTLSConnectionPinnedWrongCert(t *testing.T) {
|
||||
dest, err := tcpServer.Start()
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
certificateDer := cert.MustGenerate(nil)
|
||||
certificateDer, _ := cert.MustGenerate(nil)
|
||||
certificate := tls.ParseCertificate(certificateDer)
|
||||
certHash := tls.GenerateCertHash(certificateDer.Certificate)
|
||||
certHash[1] += 1
|
||||
@@ -841,7 +850,6 @@ func TestSimpleTLSConnectionPinnedWrongCert(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{certHash},
|
||||
}),
|
||||
},
|
||||
@@ -867,7 +875,7 @@ func TestUTLSConnectionPinned(t *testing.T) {
|
||||
dest, err := tcpServer.Start()
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
certificateDer := cert.MustGenerate(nil)
|
||||
certificateDer, _ := cert.MustGenerate(nil)
|
||||
certificate := tls.ParseCertificate(certificateDer)
|
||||
certHash := tls.GenerateCertHash(certificateDer.Certificate)
|
||||
userID := protocol.NewID(uuid.New())
|
||||
@@ -939,7 +947,6 @@ func TestUTLSConnectionPinned(t *testing.T) {
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
Fingerprint: "random",
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{certHash},
|
||||
}),
|
||||
},
|
||||
@@ -965,7 +972,7 @@ func TestUTLSConnectionPinnedWrongCert(t *testing.T) {
|
||||
dest, err := tcpServer.Start()
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
certificateDer := cert.MustGenerate(nil)
|
||||
certificateDer, _ := cert.MustGenerate(nil)
|
||||
certificate := tls.ParseCertificate(certificateDer)
|
||||
certHash := tls.GenerateCertHash(certificateDer.Certificate)
|
||||
certHash[1] += 1
|
||||
@@ -1038,7 +1045,6 @@ func TestUTLSConnectionPinnedWrongCert(t *testing.T) {
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
Fingerprint: "random",
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{certHash},
|
||||
}),
|
||||
},
|
||||
|
||||
@@ -97,7 +97,7 @@ func TestVless(t *testing.T) {
|
||||
Vnext: &protocol.ServerEndpoint{
|
||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||
Port: uint32(serverPort),
|
||||
User: &protocol.User{
|
||||
User: &protocol.User{
|
||||
Account: serial.ToTypedMessage(&vless.Account{
|
||||
Id: userID.String(),
|
||||
}),
|
||||
@@ -129,6 +129,8 @@ func TestVlessTls(t *testing.T) {
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
|
||||
ct, ctHash := cert.MustGenerate(nil, cert.CommonName("localhost"))
|
||||
|
||||
userID := protocol.NewID(uuid.New())
|
||||
serverPort := tcp.PickPort()
|
||||
serverConfig := &core.Config{
|
||||
@@ -148,7 +150,7 @@ func TestVlessTls(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(ct)},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -198,7 +200,7 @@ func TestVlessTls(t *testing.T) {
|
||||
Vnext: &protocol.ServerEndpoint{
|
||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||
Port: uint32(serverPort),
|
||||
User: &protocol.User{
|
||||
User: &protocol.User{
|
||||
Account: serial.ToTypedMessage(&vless.Account{
|
||||
Id: userID.String(),
|
||||
}),
|
||||
@@ -217,7 +219,7 @@ func TestVlessTls(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{ctHash[:]},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -247,6 +249,8 @@ func TestVlessXtlsVision(t *testing.T) {
|
||||
common.Must(err)
|
||||
defer tcpServer.Close()
|
||||
|
||||
ct, ctHash := cert.MustGenerate(nil, cert.CommonName("localhost"))
|
||||
|
||||
userID := protocol.NewID(uuid.New())
|
||||
serverPort := tcp.PickPort()
|
||||
serverConfig := &core.Config{
|
||||
@@ -266,7 +270,7 @@ func TestVlessXtlsVision(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
|
||||
Certificate: []*tls.Certificate{tls.ParseCertificate(ct)},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -317,7 +321,7 @@ func TestVlessXtlsVision(t *testing.T) {
|
||||
Vnext: &protocol.ServerEndpoint{
|
||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||
Port: uint32(serverPort),
|
||||
User: &protocol.User{
|
||||
User: &protocol.User{
|
||||
Account: serial.ToTypedMessage(&vless.Account{
|
||||
Id: userID.String(),
|
||||
Flow: vless.XRV,
|
||||
@@ -337,7 +341,7 @@ func TestVlessXtlsVision(t *testing.T) {
|
||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
||||
SecuritySettings: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&tls.Config{
|
||||
AllowInsecure: true,
|
||||
PinnedPeerCertSha256: [][]byte{ctHash[:]},
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -447,7 +451,7 @@ func TestVlessXtlsVisionReality(t *testing.T) {
|
||||
Vnext: &protocol.ServerEndpoint{
|
||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||
Port: uint32(serverPort),
|
||||
User: &protocol.User{
|
||||
User: &protocol.User{
|
||||
Account: serial.ToTypedMessage(&vless.Account{
|
||||
Id: userID.String(),
|
||||
Flow: vless.XRV,
|
||||
|
||||
@@ -4,17 +4,15 @@ import (
|
||||
"net"
|
||||
)
|
||||
|
||||
type ConnSize interface {
|
||||
Size() int32
|
||||
}
|
||||
|
||||
type Udpmask interface {
|
||||
UDP()
|
||||
|
||||
WrapConnClient(net.Conn) (net.Conn, error)
|
||||
WrapConnServer(net.Conn) (net.Conn, error)
|
||||
|
||||
WrapPacketConnClient(net.PacketConn) (net.PacketConn, error)
|
||||
WrapPacketConnServer(net.PacketConn) (net.PacketConn, error)
|
||||
|
||||
Size() int
|
||||
Serialize([]byte)
|
||||
WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error)
|
||||
WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error)
|
||||
}
|
||||
|
||||
type UdpmaskManager struct {
|
||||
@@ -27,66 +25,32 @@ func NewUdpmaskManager(udpmasks []Udpmask) *UdpmaskManager {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *UdpmaskManager) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||
var err error
|
||||
for _, mask := range m.udpmasks {
|
||||
raw, err = mask.WrapConnClient(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (m *UdpmaskManager) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
||||
var err error
|
||||
for _, mask := range m.udpmasks {
|
||||
raw, err = mask.WrapConnServer(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketConn, error) {
|
||||
leaveSize := int32(0)
|
||||
var err error
|
||||
for _, mask := range m.udpmasks {
|
||||
raw, err = mask.WrapPacketConnClient(raw)
|
||||
for i, mask := range m.udpmasks {
|
||||
raw, err = mask.WrapPacketConnClient(raw, i == len(m.udpmasks)-1, leaveSize, i == 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
leaveSize += raw.(ConnSize).Size()
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (m *UdpmaskManager) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) {
|
||||
leaveSize := int32(0)
|
||||
var err error
|
||||
for _, mask := range m.udpmasks {
|
||||
raw, err = mask.WrapPacketConnServer(raw)
|
||||
for i, mask := range m.udpmasks {
|
||||
raw, err = mask.WrapPacketConnServer(raw, i == len(m.udpmasks)-1, leaveSize, i == 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
leaveSize += raw.(ConnSize).Size()
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (m *UdpmaskManager) Size() int {
|
||||
size := 0
|
||||
for _, mask := range m.udpmasks {
|
||||
size += mask.Size()
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func (m *UdpmaskManager) Serialize(b []byte) {
|
||||
index := 0
|
||||
for _, mask := range m.udpmasks {
|
||||
mask.Serialize(b[index:])
|
||||
index += mask.Size()
|
||||
}
|
||||
}
|
||||
|
||||
type Tcpmask interface {
|
||||
TCP()
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (c *Config) UDP() {
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnServer(c, raw, first, leaveSize)
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v6.33.1
|
||||
// source: transport/internet/finalmask/header/dns/config.proto
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_transport_internet_finalmask_header_dns_config_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Config) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_dns_config_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_dns_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Config) GetDomain() string {
|
||||
if x != nil {
|
||||
return x.Domain
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_transport_internet_finalmask_header_dns_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_finalmask_header_dns_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"4transport/internet/finalmask/header/dns/config.proto\x12,xray.transport.internet.finalmask.header.dns\" \n" +
|
||||
"\x06Config\x12\x16\n" +
|
||||
"\x06domain\x18\x01 \x01(\tR\x06domainB\xa6\x01\n" +
|
||||
"0com.xray.transport.internet.finalmask.header.dnsP\x01ZAgithub.com/xtls/xray-core/transport/internet/finalmask/header/dns\xaa\x02,Xray.Transport.Internet.Finalmask.Header.Dnsb\x06proto3"
|
||||
|
||||
var (
|
||||
file_transport_internet_finalmask_header_dns_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_finalmask_header_dns_config_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_transport_internet_finalmask_header_dns_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_finalmask_header_dns_config_proto_rawDescOnce.Do(func() {
|
||||
file_transport_internet_finalmask_header_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_dns_config_proto_rawDesc), len(file_transport_internet_finalmask_header_dns_config_proto_rawDesc)))
|
||||
})
|
||||
return file_transport_internet_finalmask_header_dns_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_finalmask_header_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_transport_internet_finalmask_header_dns_config_proto_goTypes = []any{
|
||||
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.dns.Config
|
||||
}
|
||||
var file_transport_internet_finalmask_header_dns_config_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_finalmask_header_dns_config_proto_init() }
|
||||
func file_transport_internet_finalmask_header_dns_config_proto_init() {
|
||||
if File_transport_internet_finalmask_header_dns_config_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_dns_config_proto_rawDesc), len(file_transport_internet_finalmask_header_dns_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_finalmask_header_dns_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_finalmask_header_dns_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_finalmask_header_dns_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_finalmask_header_dns_config_proto = out.File
|
||||
file_transport_internet_finalmask_header_dns_config_proto_goTypes = nil
|
||||
file_transport_internet_finalmask_header_dns_config_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.finalmask.header.dns;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Dns";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/dns";
|
||||
option java_package = "com.xray.transport.internet.finalmask.header.dns";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Config {
|
||||
string domain = 1;
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
sync "sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
func packDomainName(s string, msg []byte) (off1 int, err error) {
|
||||
off := 0
|
||||
ls := len(s)
|
||||
// Each dot ends a segment of the name.
|
||||
// We trade each dot byte for a length byte.
|
||||
// Except for escaped dots (\.), which are normal dots.
|
||||
// There is also a trailing zero.
|
||||
|
||||
// Emit sequence of counted strings, chopping at dots.
|
||||
var (
|
||||
begin int
|
||||
bs []byte
|
||||
)
|
||||
for i := 0; i < ls; i++ {
|
||||
var c byte
|
||||
if bs == nil {
|
||||
c = s[i]
|
||||
} else {
|
||||
c = bs[i]
|
||||
}
|
||||
|
||||
switch c {
|
||||
case '\\':
|
||||
if off+1 > len(msg) {
|
||||
return len(msg), errors.New("buffer size too small")
|
||||
}
|
||||
|
||||
if bs == nil {
|
||||
bs = []byte(s)
|
||||
}
|
||||
|
||||
copy(bs[i:ls-1], bs[i+1:])
|
||||
ls--
|
||||
case '.':
|
||||
labelLen := i - begin
|
||||
if labelLen >= 1<<6 { // top two bits of length must be clear
|
||||
return len(msg), errors.New("bad rdata")
|
||||
}
|
||||
|
||||
// off can already (we're in a loop) be bigger than len(msg)
|
||||
// this happens when a name isn't fully qualified
|
||||
if off+1+labelLen > len(msg) {
|
||||
return len(msg), errors.New("buffer size too small")
|
||||
}
|
||||
|
||||
// The following is covered by the length check above.
|
||||
msg[off] = byte(labelLen)
|
||||
|
||||
if bs == nil {
|
||||
copy(msg[off+1:], s[begin:i])
|
||||
} else {
|
||||
copy(msg[off+1:], bs[begin:i])
|
||||
}
|
||||
off += 1 + labelLen
|
||||
begin = i + 1
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
if off < len(msg) {
|
||||
msg[off] = 0
|
||||
}
|
||||
|
||||
return off + 1, nil
|
||||
}
|
||||
|
||||
type dns struct {
|
||||
header []byte
|
||||
}
|
||||
|
||||
func (h *dns) Size() int32 {
|
||||
return int32(len(h.header))
|
||||
}
|
||||
|
||||
func (h *dns) Serialize(b []byte) {
|
||||
copy(b, h.header)
|
||||
binary.BigEndian.PutUint16(b[0:], dice.RollUint16())
|
||||
}
|
||||
|
||||
type dnsConn struct {
|
||||
first bool
|
||||
leaveSize int32
|
||||
|
||||
conn net.PacketConn
|
||||
header *dns
|
||||
|
||||
readBuf []byte
|
||||
readMutex sync.Mutex
|
||||
writeBuf []byte
|
||||
writeMutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
var header []byte
|
||||
header = binary.BigEndian.AppendUint16(header, 0x0000) // Transaction ID
|
||||
header = binary.BigEndian.AppendUint16(header, 0x0100) // Flags: Standard query
|
||||
header = binary.BigEndian.AppendUint16(header, 0x0001) // Questions
|
||||
header = binary.BigEndian.AppendUint16(header, 0x0000) // Answer RRs
|
||||
header = binary.BigEndian.AppendUint16(header, 0x0000) // Authority RRs
|
||||
header = binary.BigEndian.AppendUint16(header, 0x0000) // Additional RRs
|
||||
buf := make([]byte, 0x100)
|
||||
off1, err := packDomainName(c.Domain+".", buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
header = append(header, buf[:off1]...)
|
||||
header = binary.BigEndian.AppendUint16(header, 0x0001) // Type: A
|
||||
header = binary.BigEndian.AppendUint16(header, 0x0001) // Class: IN
|
||||
|
||||
conn := &dnsConn{
|
||||
first: first,
|
||||
leaveSize: leaveSize,
|
||||
|
||||
conn: raw,
|
||||
header: &dns{
|
||||
header: header,
|
||||
},
|
||||
}
|
||||
|
||||
if first {
|
||||
conn.readBuf = make([]byte, 8192)
|
||||
conn.writeBuf = make([]byte, 8192)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *dnsConn) Size() int32 {
|
||||
return c.header.Size()
|
||||
}
|
||||
|
||||
func (c *dnsConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
if c.first {
|
||||
c.readMutex.Lock()
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(c.readBuf)
|
||||
if err != nil {
|
||||
c.readMutex.Unlock()
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
if len(p) < n-int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, c.readBuf[c.Size():n])
|
||||
|
||||
c.readMutex.Unlock()
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(p)
|
||||
if err != nil {
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, p[c.Size():n])
|
||||
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
func (c *dnsConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if c.first {
|
||||
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
|
||||
return 0, errors.New("too many masks")
|
||||
}
|
||||
|
||||
c.writeMutex.Lock()
|
||||
|
||||
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
|
||||
n += int(c.leaveSize) + int(c.Size())
|
||||
|
||||
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
|
||||
|
||||
if err != nil {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if nn != n {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, errors.New("nn != n")
|
||||
}
|
||||
|
||||
c.writeMutex.Unlock()
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
return c.conn.WriteTo(p, addr)
|
||||
}
|
||||
|
||||
func (c *dnsConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *dnsConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *dnsConn) SetDeadline(t time.Time) error {
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *dnsConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *dnsConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (c *Config) UDP() {
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnServer(c, raw, first, leaveSize)
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v6.33.1
|
||||
// source: transport/internet/finalmask/header/dtls/config.proto
|
||||
|
||||
package dtls
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_transport_internet_finalmask_header_dtls_config_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Config) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_dtls_config_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_dtls_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
var File_transport_internet_finalmask_header_dtls_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_finalmask_header_dtls_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"5transport/internet/finalmask/header/dtls/config.proto\x12-xray.transport.internet.finalmask.header.dtls\"\b\n" +
|
||||
"\x06ConfigB\xa9\x01\n" +
|
||||
"1com.xray.transport.internet.finalmask.header.dtlsP\x01ZBgithub.com/xtls/xray-core/transport/internet/finalmask/header/dtls\xaa\x02-Xray.Transport.Internet.Finalmask.Header.Dtlsb\x06proto3"
|
||||
|
||||
var (
|
||||
file_transport_internet_finalmask_header_dtls_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_finalmask_header_dtls_config_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_transport_internet_finalmask_header_dtls_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_finalmask_header_dtls_config_proto_rawDescOnce.Do(func() {
|
||||
file_transport_internet_finalmask_header_dtls_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_dtls_config_proto_rawDesc), len(file_transport_internet_finalmask_header_dtls_config_proto_rawDesc)))
|
||||
})
|
||||
return file_transport_internet_finalmask_header_dtls_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_finalmask_header_dtls_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_transport_internet_finalmask_header_dtls_config_proto_goTypes = []any{
|
||||
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.dtls.Config
|
||||
}
|
||||
var file_transport_internet_finalmask_header_dtls_config_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_finalmask_header_dtls_config_proto_init() }
|
||||
func file_transport_internet_finalmask_header_dtls_config_proto_init() {
|
||||
if File_transport_internet_finalmask_header_dtls_config_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_dtls_config_proto_rawDesc), len(file_transport_internet_finalmask_header_dtls_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_finalmask_header_dtls_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_finalmask_header_dtls_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_finalmask_header_dtls_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_finalmask_header_dtls_config_proto = out.File
|
||||
file_transport_internet_finalmask_header_dtls_config_proto_goTypes = nil
|
||||
file_transport_internet_finalmask_header_dtls_config_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.finalmask.header.dtls;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Dtls";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/dtls";
|
||||
option java_package = "com.xray.transport.internet.finalmask.header.dtls";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Config {}
|
||||
@@ -0,0 +1,178 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
sync "sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
type dtls struct {
|
||||
epoch uint16
|
||||
length uint16
|
||||
sequence uint32
|
||||
}
|
||||
|
||||
func (*dtls) Size() int32 {
|
||||
return 1 + 2 + 2 + 6 + 2
|
||||
}
|
||||
|
||||
func (h *dtls) Serialize(b []byte) {
|
||||
b[0] = 23
|
||||
b[1] = 254
|
||||
b[2] = 253
|
||||
b[3] = byte(h.epoch >> 8)
|
||||
b[4] = byte(h.epoch)
|
||||
b[5] = 0
|
||||
b[6] = 0
|
||||
b[7] = byte(h.sequence >> 24)
|
||||
b[8] = byte(h.sequence >> 16)
|
||||
b[9] = byte(h.sequence >> 8)
|
||||
b[10] = byte(h.sequence)
|
||||
h.sequence++
|
||||
b[11] = byte(h.length >> 8)
|
||||
b[12] = byte(h.length)
|
||||
h.length += 17
|
||||
if h.length > 100 {
|
||||
h.length -= 50
|
||||
}
|
||||
}
|
||||
|
||||
type dtlsConn struct {
|
||||
first bool
|
||||
leaveSize int32
|
||||
|
||||
conn net.PacketConn
|
||||
header *dtls
|
||||
|
||||
readBuf []byte
|
||||
readMutex sync.Mutex
|
||||
writeBuf []byte
|
||||
writeMutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
conn := &dtlsConn{
|
||||
first: first,
|
||||
leaveSize: leaveSize,
|
||||
|
||||
conn: raw,
|
||||
header: &dtls{
|
||||
epoch: dice.RollUint16(),
|
||||
sequence: 0,
|
||||
length: 17,
|
||||
},
|
||||
}
|
||||
|
||||
if first {
|
||||
conn.readBuf = make([]byte, 8192)
|
||||
conn.writeBuf = make([]byte, 8192)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *dtlsConn) Size() int32 {
|
||||
return c.header.Size()
|
||||
}
|
||||
|
||||
func (c *dtlsConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
if c.first {
|
||||
c.readMutex.Lock()
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(c.readBuf)
|
||||
if err != nil {
|
||||
c.readMutex.Unlock()
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
if len(p) < n-int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, c.readBuf[c.Size():n])
|
||||
|
||||
c.readMutex.Unlock()
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(p)
|
||||
if err != nil {
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, p[c.Size():n])
|
||||
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
func (c *dtlsConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if c.first {
|
||||
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
|
||||
return 0, errors.New("too many masks")
|
||||
}
|
||||
|
||||
c.writeMutex.Lock()
|
||||
|
||||
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
|
||||
n += int(c.leaveSize) + int(c.Size())
|
||||
|
||||
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
|
||||
|
||||
if err != nil {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if nn != n {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, errors.New("nn != n")
|
||||
}
|
||||
|
||||
c.writeMutex.Unlock()
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
return c.conn.WriteTo(p, addr)
|
||||
}
|
||||
|
||||
func (c *dtlsConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *dtlsConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *dtlsConn) SetDeadline(t time.Time) error {
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *dtlsConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *dtlsConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package srtp
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (c *Config) UDP() {
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnServer(c, raw, first, leaveSize)
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v6.33.1
|
||||
// source: transport/internet/finalmask/header/srtp/config.proto
|
||||
|
||||
package srtp
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_transport_internet_finalmask_header_srtp_config_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Config) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_srtp_config_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_srtp_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
var File_transport_internet_finalmask_header_srtp_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_finalmask_header_srtp_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"5transport/internet/finalmask/header/srtp/config.proto\x12-xray.transport.internet.finalmask.header.srtp\"\b\n" +
|
||||
"\x06ConfigB\xa9\x01\n" +
|
||||
"1com.xray.transport.internet.finalmask.header.srtpP\x01ZBgithub.com/xtls/xray-core/transport/internet/finalmask/header/srtp\xaa\x02-Xray.Transport.Internet.Finalmask.Header.Srtpb\x06proto3"
|
||||
|
||||
var (
|
||||
file_transport_internet_finalmask_header_srtp_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_finalmask_header_srtp_config_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_transport_internet_finalmask_header_srtp_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_finalmask_header_srtp_config_proto_rawDescOnce.Do(func() {
|
||||
file_transport_internet_finalmask_header_srtp_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_srtp_config_proto_rawDesc), len(file_transport_internet_finalmask_header_srtp_config_proto_rawDesc)))
|
||||
})
|
||||
return file_transport_internet_finalmask_header_srtp_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_finalmask_header_srtp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_transport_internet_finalmask_header_srtp_config_proto_goTypes = []any{
|
||||
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.srtp.Config
|
||||
}
|
||||
var file_transport_internet_finalmask_header_srtp_config_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_finalmask_header_srtp_config_proto_init() }
|
||||
func file_transport_internet_finalmask_header_srtp_config_proto_init() {
|
||||
if File_transport_internet_finalmask_header_srtp_config_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_srtp_config_proto_rawDesc), len(file_transport_internet_finalmask_header_srtp_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_finalmask_header_srtp_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_finalmask_header_srtp_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_finalmask_header_srtp_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_finalmask_header_srtp_config_proto = out.File
|
||||
file_transport_internet_finalmask_header_srtp_config_proto_goTypes = nil
|
||||
file_transport_internet_finalmask_header_srtp_config_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.finalmask.header.srtp;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Srtp";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/srtp";
|
||||
option java_package = "com.xray.transport.internet.finalmask.header.srtp";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Config {}
|
||||
@@ -0,0 +1,162 @@
|
||||
package srtp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
sync "sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
type srtp struct {
|
||||
header uint16
|
||||
number uint16
|
||||
}
|
||||
|
||||
func (*srtp) Size() int32 {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (h *srtp) Serialize(b []byte) {
|
||||
h.number++
|
||||
binary.BigEndian.PutUint16(b, h.header)
|
||||
binary.BigEndian.PutUint16(b[2:], h.number)
|
||||
}
|
||||
|
||||
type srtpConn struct {
|
||||
first bool
|
||||
leaveSize int32
|
||||
|
||||
conn net.PacketConn
|
||||
header *srtp
|
||||
|
||||
readBuf []byte
|
||||
readMutex sync.Mutex
|
||||
writeBuf []byte
|
||||
writeMutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
conn := &srtpConn{
|
||||
first: first,
|
||||
leaveSize: leaveSize,
|
||||
|
||||
conn: raw,
|
||||
header: &srtp{
|
||||
header: 0xB5E8,
|
||||
number: dice.RollUint16(),
|
||||
},
|
||||
}
|
||||
|
||||
if first {
|
||||
conn.readBuf = make([]byte, 8192)
|
||||
conn.writeBuf = make([]byte, 8192)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *srtpConn) Size() int32 {
|
||||
return c.header.Size()
|
||||
}
|
||||
|
||||
func (c *srtpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
if c.first {
|
||||
c.readMutex.Lock()
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(c.readBuf)
|
||||
if err != nil {
|
||||
c.readMutex.Unlock()
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
if len(p) < n-int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, c.readBuf[c.Size():n])
|
||||
|
||||
c.readMutex.Unlock()
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(p)
|
||||
if err != nil {
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, p[c.Size():n])
|
||||
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
func (c *srtpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if c.first {
|
||||
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
|
||||
return 0, errors.New("too many masks")
|
||||
}
|
||||
|
||||
c.writeMutex.Lock()
|
||||
|
||||
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
|
||||
n += int(c.leaveSize) + int(c.Size())
|
||||
|
||||
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
|
||||
|
||||
if err != nil {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if nn != n {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, errors.New("nn != n")
|
||||
}
|
||||
|
||||
c.writeMutex.Unlock()
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
return c.conn.WriteTo(p, addr)
|
||||
}
|
||||
|
||||
func (c *srtpConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *srtpConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *srtpConn) SetDeadline(t time.Time) error {
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *srtpConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *srtpConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (c *Config) UDP() {
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnServer(c, raw, first, leaveSize)
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v6.33.1
|
||||
// source: transport/internet/finalmask/header/utp/config.proto
|
||||
|
||||
package utp
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_transport_internet_finalmask_header_utp_config_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Config) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_utp_config_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_utp_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
var File_transport_internet_finalmask_header_utp_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_finalmask_header_utp_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"4transport/internet/finalmask/header/utp/config.proto\x12,xray.transport.internet.finalmask.header.utp\"\b\n" +
|
||||
"\x06ConfigB\xa6\x01\n" +
|
||||
"0com.xray.transport.internet.finalmask.header.utpP\x01ZAgithub.com/xtls/xray-core/transport/internet/finalmask/header/utp\xaa\x02,Xray.Transport.Internet.Finalmask.Header.Utpb\x06proto3"
|
||||
|
||||
var (
|
||||
file_transport_internet_finalmask_header_utp_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_finalmask_header_utp_config_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_transport_internet_finalmask_header_utp_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_finalmask_header_utp_config_proto_rawDescOnce.Do(func() {
|
||||
file_transport_internet_finalmask_header_utp_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_utp_config_proto_rawDesc), len(file_transport_internet_finalmask_header_utp_config_proto_rawDesc)))
|
||||
})
|
||||
return file_transport_internet_finalmask_header_utp_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_finalmask_header_utp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_transport_internet_finalmask_header_utp_config_proto_goTypes = []any{
|
||||
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.utp.Config
|
||||
}
|
||||
var file_transport_internet_finalmask_header_utp_config_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_finalmask_header_utp_config_proto_init() }
|
||||
func file_transport_internet_finalmask_header_utp_config_proto_init() {
|
||||
if File_transport_internet_finalmask_header_utp_config_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_utp_config_proto_rawDesc), len(file_transport_internet_finalmask_header_utp_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_finalmask_header_utp_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_finalmask_header_utp_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_finalmask_header_utp_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_finalmask_header_utp_config_proto = out.File
|
||||
file_transport_internet_finalmask_header_utp_config_proto_goTypes = nil
|
||||
file_transport_internet_finalmask_header_utp_config_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.finalmask.header.utp;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Utp";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/utp";
|
||||
option java_package = "com.xray.transport.internet.finalmask.header.utp";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Config {}
|
||||
@@ -0,0 +1,164 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
sync "sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
type utp struct {
|
||||
header byte
|
||||
extension byte
|
||||
connectionID uint16
|
||||
}
|
||||
|
||||
func (*utp) Size() int32 {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (h *utp) Serialize(b []byte) {
|
||||
binary.BigEndian.PutUint16(b, h.connectionID)
|
||||
b[2] = h.header
|
||||
b[3] = h.extension
|
||||
}
|
||||
|
||||
type utpConn struct {
|
||||
first bool
|
||||
leaveSize int32
|
||||
|
||||
conn net.PacketConn
|
||||
header *utp
|
||||
|
||||
readBuf []byte
|
||||
readMutex sync.Mutex
|
||||
writeBuf []byte
|
||||
writeMutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
conn := &utpConn{
|
||||
first: first,
|
||||
leaveSize: leaveSize,
|
||||
|
||||
conn: raw,
|
||||
header: &utp{
|
||||
header: 1,
|
||||
extension: 0,
|
||||
connectionID: dice.RollUint16(),
|
||||
},
|
||||
}
|
||||
|
||||
if first {
|
||||
conn.readBuf = make([]byte, 8192)
|
||||
conn.writeBuf = make([]byte, 8192)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *utpConn) Size() int32 {
|
||||
return c.header.Size()
|
||||
}
|
||||
|
||||
func (c *utpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
if c.first {
|
||||
c.readMutex.Lock()
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(c.readBuf)
|
||||
if err != nil {
|
||||
c.readMutex.Unlock()
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
if len(p) < n-int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, c.readBuf[c.Size():n])
|
||||
|
||||
c.readMutex.Unlock()
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(p)
|
||||
if err != nil {
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, p[c.Size():n])
|
||||
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
func (c *utpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if c.first {
|
||||
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
|
||||
return 0, errors.New("too many masks")
|
||||
}
|
||||
|
||||
c.writeMutex.Lock()
|
||||
|
||||
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
|
||||
n += int(c.leaveSize) + int(c.Size())
|
||||
|
||||
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
|
||||
|
||||
if err != nil {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if nn != n {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, errors.New("nn != n")
|
||||
}
|
||||
|
||||
c.writeMutex.Unlock()
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
return c.conn.WriteTo(p, addr)
|
||||
}
|
||||
|
||||
func (c *utpConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *utpConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *utpConn) SetDeadline(t time.Time) error {
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *utpConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *utpConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (c *Config) UDP() {
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnServer(c, raw, first, leaveSize)
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v6.33.1
|
||||
// source: transport/internet/finalmask/header/wechat/config.proto
|
||||
|
||||
package wechat
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_transport_internet_finalmask_header_wechat_config_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Config) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_wechat_config_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_wechat_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
var File_transport_internet_finalmask_header_wechat_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_finalmask_header_wechat_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"7transport/internet/finalmask/header/wechat/config.proto\x12/xray.transport.internet.finalmask.header.wechat\"\b\n" +
|
||||
"\x06ConfigB\xaf\x01\n" +
|
||||
"3com.xray.transport.internet.finalmask.header.wechatP\x01ZDgithub.com/xtls/xray-core/transport/internet/finalmask/header/wechat\xaa\x02/Xray.Transport.Internet.Finalmask.Header.Wechatb\x06proto3"
|
||||
|
||||
var (
|
||||
file_transport_internet_finalmask_header_wechat_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_finalmask_header_wechat_config_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_transport_internet_finalmask_header_wechat_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_finalmask_header_wechat_config_proto_rawDescOnce.Do(func() {
|
||||
file_transport_internet_finalmask_header_wechat_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_wechat_config_proto_rawDesc), len(file_transport_internet_finalmask_header_wechat_config_proto_rawDesc)))
|
||||
})
|
||||
return file_transport_internet_finalmask_header_wechat_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_finalmask_header_wechat_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_transport_internet_finalmask_header_wechat_config_proto_goTypes = []any{
|
||||
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.wechat.Config
|
||||
}
|
||||
var file_transport_internet_finalmask_header_wechat_config_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_finalmask_header_wechat_config_proto_init() }
|
||||
func file_transport_internet_finalmask_header_wechat_config_proto_init() {
|
||||
if File_transport_internet_finalmask_header_wechat_config_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_wechat_config_proto_rawDesc), len(file_transport_internet_finalmask_header_wechat_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_finalmask_header_wechat_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_finalmask_header_wechat_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_finalmask_header_wechat_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_finalmask_header_wechat_config_proto = out.File
|
||||
file_transport_internet_finalmask_header_wechat_config_proto_goTypes = nil
|
||||
file_transport_internet_finalmask_header_wechat_config_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.finalmask.header.wechat;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Wechat";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/wechat";
|
||||
option java_package = "com.xray.transport.internet.finalmask.header.wechat";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Config {}
|
||||
@@ -0,0 +1,168 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
sync "sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
type wechat struct {
|
||||
sn uint32
|
||||
}
|
||||
|
||||
func (*wechat) Size() int32 {
|
||||
return 13
|
||||
}
|
||||
|
||||
func (h *wechat) Serialize(b []byte) {
|
||||
h.sn++
|
||||
b[0] = 0xa1
|
||||
b[1] = 0x08
|
||||
binary.BigEndian.PutUint32(b[2:], h.sn)
|
||||
b[6] = 0x00
|
||||
b[7] = 0x10
|
||||
b[8] = 0x11
|
||||
b[9] = 0x18
|
||||
b[10] = 0x30
|
||||
b[11] = 0x22
|
||||
b[12] = 0x30
|
||||
}
|
||||
|
||||
type wechatConn struct {
|
||||
first bool
|
||||
leaveSize int32
|
||||
|
||||
conn net.PacketConn
|
||||
header *wechat
|
||||
|
||||
readBuf []byte
|
||||
readMutex sync.Mutex
|
||||
writeBuf []byte
|
||||
writeMutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
conn := &wechatConn{
|
||||
first: first,
|
||||
leaveSize: leaveSize,
|
||||
|
||||
conn: raw,
|
||||
header: &wechat{
|
||||
sn: uint32(dice.RollUint16()),
|
||||
},
|
||||
}
|
||||
|
||||
if first {
|
||||
conn.readBuf = make([]byte, 8192)
|
||||
conn.writeBuf = make([]byte, 8192)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *wechatConn) Size() int32 {
|
||||
return c.header.Size()
|
||||
}
|
||||
|
||||
func (c *wechatConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
if c.first {
|
||||
c.readMutex.Lock()
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(c.readBuf)
|
||||
if err != nil {
|
||||
c.readMutex.Unlock()
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
if len(p) < n-int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, c.readBuf[c.Size():n])
|
||||
|
||||
c.readMutex.Unlock()
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(p)
|
||||
if err != nil {
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, p[c.Size():n])
|
||||
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
func (c *wechatConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if c.first {
|
||||
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
|
||||
return 0, errors.New("too many masks")
|
||||
}
|
||||
|
||||
c.writeMutex.Lock()
|
||||
|
||||
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
|
||||
n += int(c.leaveSize) + int(c.Size())
|
||||
|
||||
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
|
||||
|
||||
if err != nil {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if nn != n {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, errors.New("nn != n")
|
||||
}
|
||||
|
||||
c.writeMutex.Unlock()
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
return c.conn.WriteTo(p, addr)
|
||||
}
|
||||
|
||||
func (c *wechatConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *wechatConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *wechatConn) SetDeadline(t time.Time) error {
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *wechatConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *wechatConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (c *Config) UDP() {
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnServer(c, raw, first, leaveSize)
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v6.33.1
|
||||
// source: transport/internet/finalmask/header/wireguard/config.proto
|
||||
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_transport_internet_finalmask_header_wireguard_config_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Config) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_header_wireguard_config_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_header_wireguard_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
var File_transport_internet_finalmask_header_wireguard_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_finalmask_header_wireguard_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
":transport/internet/finalmask/header/wireguard/config.proto\x122xray.transport.internet.finalmask.header.wireguard\"\b\n" +
|
||||
"\x06ConfigB\xb8\x01\n" +
|
||||
"6com.xray.transport.internet.finalmask.header.wireguardP\x01ZGgithub.com/xtls/xray-core/transport/internet/finalmask/header/wireguard\xaa\x022Xray.Transport.Internet.Finalmask.Header.Wireguardb\x06proto3"
|
||||
|
||||
var (
|
||||
file_transport_internet_finalmask_header_wireguard_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_finalmask_header_wireguard_config_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_transport_internet_finalmask_header_wireguard_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_finalmask_header_wireguard_config_proto_rawDescOnce.Do(func() {
|
||||
file_transport_internet_finalmask_header_wireguard_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_wireguard_config_proto_rawDesc), len(file_transport_internet_finalmask_header_wireguard_config_proto_rawDesc)))
|
||||
})
|
||||
return file_transport_internet_finalmask_header_wireguard_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_finalmask_header_wireguard_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_transport_internet_finalmask_header_wireguard_config_proto_goTypes = []any{
|
||||
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.wireguard.Config
|
||||
}
|
||||
var file_transport_internet_finalmask_header_wireguard_config_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_finalmask_header_wireguard_config_proto_init() }
|
||||
func file_transport_internet_finalmask_header_wireguard_config_proto_init() {
|
||||
if File_transport_internet_finalmask_header_wireguard_config_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_wireguard_config_proto_rawDesc), len(file_transport_internet_finalmask_header_wireguard_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_finalmask_header_wireguard_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_finalmask_header_wireguard_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_finalmask_header_wireguard_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_finalmask_header_wireguard_config_proto = out.File
|
||||
file_transport_internet_finalmask_header_wireguard_config_proto_goTypes = nil
|
||||
file_transport_internet_finalmask_header_wireguard_config_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.finalmask.header.wireguard;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Wireguard";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/wireguard";
|
||||
option java_package = "com.xray.transport.internet.finalmask.header.wireguard";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Config {}
|
||||
@@ -0,0 +1,155 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
sync "sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
type wireguare struct{}
|
||||
|
||||
func (*wireguare) Size() int32 {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (h *wireguare) Serialize(b []byte) {
|
||||
b[0] = 0x04
|
||||
b[1] = 0x00
|
||||
b[2] = 0x00
|
||||
b[3] = 0x00
|
||||
}
|
||||
|
||||
type wireguareConn struct {
|
||||
first bool
|
||||
leaveSize int32
|
||||
|
||||
conn net.PacketConn
|
||||
header *wireguare
|
||||
|
||||
readBuf []byte
|
||||
readMutex sync.Mutex
|
||||
writeBuf []byte
|
||||
writeMutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
conn := &wireguareConn{
|
||||
first: first,
|
||||
leaveSize: leaveSize,
|
||||
|
||||
conn: raw,
|
||||
header: &wireguare{},
|
||||
}
|
||||
|
||||
if first {
|
||||
conn.readBuf = make([]byte, 8192)
|
||||
conn.writeBuf = make([]byte, 8192)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *wireguareConn) Size() int32 {
|
||||
return c.header.Size()
|
||||
}
|
||||
|
||||
func (c *wireguareConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
if c.first {
|
||||
c.readMutex.Lock()
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(c.readBuf)
|
||||
if err != nil {
|
||||
c.readMutex.Unlock()
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
if len(p) < n-int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, c.readBuf[c.Size():n])
|
||||
|
||||
c.readMutex.Unlock()
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(p)
|
||||
if err != nil {
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
copy(p, p[c.Size():n])
|
||||
|
||||
return n - int(c.Size()), addr, err
|
||||
}
|
||||
|
||||
func (c *wireguareConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if c.first {
|
||||
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
|
||||
return 0, errors.New("too many masks")
|
||||
}
|
||||
|
||||
c.writeMutex.Lock()
|
||||
|
||||
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
|
||||
n += int(c.leaveSize) + int(c.Size())
|
||||
|
||||
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
|
||||
|
||||
if err != nil {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if nn != n {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, errors.New("nn != n")
|
||||
}
|
||||
|
||||
c.writeMutex.Unlock()
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
|
||||
|
||||
return c.conn.WriteTo(p, addr)
|
||||
}
|
||||
|
||||
func (c *wireguareConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *wireguareConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *wireguareConn) SetDeadline(t time.Time) error {
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *wireguareConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *wireguareConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package aes128gcm_test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
)
|
||||
|
||||
func TestAes128GcmSealInPlace(t *testing.T) {
|
||||
hashedPsk := sha256.Sum256([]byte("psk"))
|
||||
aead := crypto.NewAesGcm(hashedPsk[:16])
|
||||
|
||||
text := []byte("0123456789012")
|
||||
buf := make([]byte, 8192)
|
||||
|
||||
nonceSize := aead.NonceSize()
|
||||
nonce := buf[:nonceSize]
|
||||
rand.Read(nonce)
|
||||
copy(buf[nonceSize:], text)
|
||||
plaintext := buf[nonceSize : nonceSize+len(text)]
|
||||
|
||||
sealed := aead.Seal(nil, nonce, plaintext, nil)
|
||||
|
||||
_ = aead.Seal(plaintext[:0], nonce, plaintext, nil)
|
||||
|
||||
assert.Equal(t, sealed, buf[nonceSize:nonceSize+aead.Overhead()+len(text)])
|
||||
}
|
||||
|
||||
func encrypted(plain []byte) ([]byte, []byte) {
|
||||
hashedPsk := sha256.Sum256([]byte("psk"))
|
||||
aead := crypto.NewAesGcm(hashedPsk[:16])
|
||||
|
||||
nonce := make([]byte, 12)
|
||||
rand.Read(nonce)
|
||||
|
||||
return nonce, aead.Seal(nil, nonce, plain, nil)
|
||||
}
|
||||
|
||||
func TestAes128GcmOpenInPlace(t *testing.T) {
|
||||
a, b := encrypted([]byte("0123456789012"))
|
||||
buf := make([]byte, 8192)
|
||||
copy(buf, a)
|
||||
copy(buf[len(a):], b)
|
||||
|
||||
hashedPsk := sha256.Sum256([]byte("psk"))
|
||||
aead := crypto.NewAesGcm(hashedPsk[:16])
|
||||
|
||||
nonceSize := aead.NonceSize()
|
||||
nonce := buf[:nonceSize]
|
||||
ciphertext := buf[nonceSize : nonceSize+len(b)]
|
||||
|
||||
opened, _ := aead.Open(nil, nonce, ciphertext, nil)
|
||||
_, _ = aead.Open(ciphertext[:0], nonce, ciphertext, nil)
|
||||
|
||||
assert.Equal(t, opened, ciphertext[:len(ciphertext)-aead.Overhead()])
|
||||
}
|
||||
|
||||
func TestAes128GcmBounce(t *testing.T) {
|
||||
hashedPsk := sha256.Sum256([]byte("psk"))
|
||||
aead := crypto.NewAesGcm(hashedPsk[:16])
|
||||
buf := make([]byte, aead.NonceSize()+aead.Overhead())
|
||||
for i := 0; i < 1000; i++ {
|
||||
_, _ = rand.Read(buf)
|
||||
_, err := aead.Open(buf[aead.NonceSize():aead.NonceSize()], buf[:aead.NonceSize()], buf[aead.NonceSize():], nil)
|
||||
assert.NotEqual(t, err, nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package aes128gcm
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (c *Config) UDP() {
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnServer(c, raw, first, leaveSize)
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v6.33.1
|
||||
// source: transport/internet/finalmask/mkcp/aes128gcm/config.proto
|
||||
|
||||
package aes128gcm
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Config) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Config) GetPassword() string {
|
||||
if x != nil {
|
||||
return x.Password
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_transport_internet_finalmask_mkcp_aes128gcm_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"8transport/internet/finalmask/mkcp/aes128gcm/config.proto\x120xray.transport.internet.finalmask.mkcp.aes128gcm\"$\n" +
|
||||
"\x06Config\x12\x1a\n" +
|
||||
"\bpassword\x18\x01 \x01(\tR\bpasswordB\xb2\x01\n" +
|
||||
"4com.xray.transport.internet.finalmask.mkcp.aes128gcmP\x01ZEgithub.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm\xaa\x020Xray.Transport.Internet.Finalmask.Mkcp.Aes128Gcmb\x06proto3"
|
||||
|
||||
var (
|
||||
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescOnce.Do(func() {
|
||||
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDesc), len(file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDesc)))
|
||||
})
|
||||
return file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_goTypes = []any{
|
||||
(*Config)(nil), // 0: xray.transport.internet.finalmask.mkcp.aes128gcm.Config
|
||||
}
|
||||
var file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_init() }
|
||||
func file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_init() {
|
||||
if File_transport_internet_finalmask_mkcp_aes128gcm_config_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDesc), len(file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_finalmask_mkcp_aes128gcm_config_proto = out.File
|
||||
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_goTypes = nil
|
||||
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.finalmask.mkcp.aes128gcm;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Mkcp.Aes128Gcm";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm";
|
||||
option java_package = "com.xray.transport.internet.finalmask.mkcp.aes128gcm";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Config {
|
||||
string password = 1;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package aes128gcm
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
"net"
|
||||
sync "sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
type aes128gcmConn struct {
|
||||
first bool
|
||||
leaveSize int32
|
||||
|
||||
conn net.PacketConn
|
||||
aead cipher.AEAD
|
||||
|
||||
readBuf []byte
|
||||
readMutex sync.Mutex
|
||||
writeBuf []byte
|
||||
writeMutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
hashedPsk := sha256.Sum256([]byte(c.Password))
|
||||
|
||||
conn := &aes128gcmConn{
|
||||
first: first,
|
||||
leaveSize: leaveSize,
|
||||
|
||||
conn: raw,
|
||||
aead: crypto.NewAesGcm(hashedPsk[:16]),
|
||||
}
|
||||
|
||||
if first {
|
||||
conn.readBuf = make([]byte, 8192)
|
||||
conn.writeBuf = make([]byte, 8192)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *aes128gcmConn) Size() int32 {
|
||||
return int32(c.aead.NonceSize()) + int32(c.aead.Overhead())
|
||||
}
|
||||
|
||||
func (c *aes128gcmConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
if c.first {
|
||||
c.readMutex.Lock()
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(c.readBuf)
|
||||
if err != nil {
|
||||
c.readMutex.Unlock()
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
if len(p) < n-int(c.Size()) {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
nonceSize := c.aead.NonceSize()
|
||||
nonce := c.readBuf[:nonceSize]
|
||||
ciphertext := c.readBuf[nonceSize:n]
|
||||
_, err = c.aead.Open(p[:0], nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
c.readMutex.Unlock()
|
||||
return 0, addr, errors.New("aead open").Base(err)
|
||||
}
|
||||
|
||||
c.readMutex.Unlock()
|
||||
return n - int(c.Size()), addr, nil
|
||||
}
|
||||
|
||||
n, addr, err = c.conn.ReadFrom(p)
|
||||
if err != nil {
|
||||
return n, addr, err
|
||||
}
|
||||
|
||||
if n < int(c.Size()) {
|
||||
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
|
||||
}
|
||||
|
||||
nonceSize := c.aead.NonceSize()
|
||||
nonce := p[:nonceSize]
|
||||
ciphertext := p[nonceSize:n]
|
||||
_, err = c.aead.Open(ciphertext[:0], nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return 0, addr, errors.New("aead open").Base(err)
|
||||
}
|
||||
copy(p, p[nonceSize:n-c.aead.Overhead()])
|
||||
|
||||
return n - int(c.Size()), addr, nil
|
||||
}
|
||||
|
||||
func (c *aes128gcmConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if c.first {
|
||||
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
|
||||
return 0, errors.New("too many masks")
|
||||
}
|
||||
|
||||
c.writeMutex.Lock()
|
||||
|
||||
n = copy(c.writeBuf[c.leaveSize+int32(c.aead.NonceSize()):], p)
|
||||
// n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
|
||||
n += int(c.leaveSize) + int(c.Size())
|
||||
|
||||
nonceSize := c.aead.NonceSize()
|
||||
nonce := c.writeBuf[c.leaveSize : c.leaveSize+int32(nonceSize)]
|
||||
common.Must2(rand.Read(nonce))
|
||||
// copy(c.writeBuf[c.leaveSize+int32(nonceSize):], c.writeBuf[c.leaveSize+c.Size():n])
|
||||
plaintext := c.writeBuf[c.leaveSize+int32(nonceSize) : n-c.aead.Overhead()]
|
||||
_ = c.aead.Seal(plaintext[:0], nonce, plaintext, nil)
|
||||
|
||||
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
|
||||
|
||||
if err != nil {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if nn != n {
|
||||
c.writeMutex.Unlock()
|
||||
return 0, errors.New("nn != n")
|
||||
}
|
||||
|
||||
c.writeMutex.Unlock()
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
nonceSize := c.aead.NonceSize()
|
||||
nonce := p[c.leaveSize : c.leaveSize+int32(nonceSize)]
|
||||
common.Must2(rand.Read(nonce))
|
||||
copy(p[c.leaveSize+int32(nonceSize):], p[c.leaveSize+c.Size():])
|
||||
plaintext := p[c.leaveSize+int32(nonceSize) : len(p)-c.aead.Overhead()]
|
||||
_ = c.aead.Seal(plaintext[:0], nonce, plaintext, nil)
|
||||
|
||||
return c.conn.WriteTo(p, addr)
|
||||
}
|
||||
|
||||
func (c *aes128gcmConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *aes128gcmConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *aes128gcmConn) SetDeadline(t time.Time) error {
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *aes128gcmConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *aes128gcmConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package original
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (c *Config) UDP() {
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnClient(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnServer(c, raw, first, leaveSize)
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v6.33.1
|
||||
// source: transport/internet/finalmask/mkcp/original/config.proto
|
||||
|
||||
package original
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_transport_internet_finalmask_mkcp_original_config_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Config) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_finalmask_mkcp_original_config_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_finalmask_mkcp_original_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
var File_transport_internet_finalmask_mkcp_original_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_finalmask_mkcp_original_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"7transport/internet/finalmask/mkcp/original/config.proto\x12/xray.transport.internet.finalmask.mkcp.original\"\b\n" +
|
||||
"\x06ConfigB\xaf\x01\n" +
|
||||
"3com.xray.transport.internet.finalmask.mkcp.originalP\x01ZDgithub.com/xtls/xray-core/transport/internet/finalmask/mkcp/original\xaa\x02/Xray.Transport.Internet.Finalmask.Mkcp.Originalb\x06proto3"
|
||||
|
||||
var (
|
||||
file_transport_internet_finalmask_mkcp_original_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_finalmask_mkcp_original_config_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_transport_internet_finalmask_mkcp_original_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_finalmask_mkcp_original_config_proto_rawDescOnce.Do(func() {
|
||||
file_transport_internet_finalmask_mkcp_original_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_mkcp_original_config_proto_rawDesc), len(file_transport_internet_finalmask_mkcp_original_config_proto_rawDesc)))
|
||||
})
|
||||
return file_transport_internet_finalmask_mkcp_original_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_finalmask_mkcp_original_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_transport_internet_finalmask_mkcp_original_config_proto_goTypes = []any{
|
||||
(*Config)(nil), // 0: xray.transport.internet.finalmask.mkcp.original.Config
|
||||
}
|
||||
var file_transport_internet_finalmask_mkcp_original_config_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_finalmask_mkcp_original_config_proto_init() }
|
||||
func file_transport_internet_finalmask_mkcp_original_config_proto_init() {
|
||||
if File_transport_internet_finalmask_mkcp_original_config_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_mkcp_original_config_proto_rawDesc), len(file_transport_internet_finalmask_mkcp_original_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_finalmask_mkcp_original_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_finalmask_mkcp_original_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_finalmask_mkcp_original_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_finalmask_mkcp_original_config_proto = out.File
|
||||
file_transport_internet_finalmask_mkcp_original_config_proto_goTypes = nil
|
||||
file_transport_internet_finalmask_mkcp_original_config_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.finalmask.mkcp.original;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Mkcp.Original";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/mkcp/original";
|
||||
option java_package = "com.xray.transport.internet.finalmask.mkcp.original";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Config {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user