feat: add config_parser

This commit is contained in:
mzz2017 2023-01-27 02:10:27 +08:00
parent 916a55d480
commit edbce81e88
53 changed files with 6696 additions and 733 deletions

View File

@ -6,14 +6,25 @@
# The development version of clang is distributed as the 'clang' binary,
# while stable/released versions have a version number attached.
# Pin the default clang to a stable version.
CLANG ?= clang
CLANG ?= clang-14
STRIP ?= llvm-strip
CFLAGS := -O2 -g -Wall -Werror $(CFLAGS)
#CFLAGS := -O2 -g -Wall -Werror $(CFLAGS)
CFLAGS := -O2 -Wall -Werror $(CFLAGS)
# Get version from .git.
date=$(shell git log -1 --format="%cd" --date=short | sed s/-//g)
count=$(shell git rev-list --count HEAD)
commit=$(shell git rev-parse --short HEAD)
ifeq ($(wildcard .git/.),)
version=unstable-0.nogit
else
version=unstable-$(date).r$(count).$(commit)
endif
.PHONY: ebpf dae
dae: ebpf
go build -ldflags "-s -w" .
go build -ldflags "-s -w -X github.com/v2rayA/dae/cmd.Version=$(version)" .
# $BPF_CLANG is used in go:generate invocations.
ebpf: export BPF_CLANG := $(CLANG)

View File

@ -10,6 +10,9 @@ As a successor of [v2rayA](https://github.com/v2rayA/v2rayA), dae abandoned v2ra
## TODO
1. Dns upstream. Check dns upstream and source loop (whether upstream is also a client of us) and remind user to add source rule.
1. Check dns upstream and source loop (whether upstream is also a client of us) and remind the user to add sip rule.
1. Domain routing performance optimization.
1. Support not operator for RoutingA rule.
1. DisableL4Checksum by link.
1. Config file.
1. ...

113
cmd/cmd.go Normal file
View File

@ -0,0 +1,113 @@
package cmd
import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/v2rayA/dae/common/consts"
"github.com/v2rayA/dae/component/control"
"github.com/v2rayA/dae/component/outbound"
"github.com/v2rayA/dae/component/outbound/dialer"
"github.com/v2rayA/dae/pkg/logger"
"os"
"os/signal"
"syscall"
)
var (
v *viper.Viper
Version = "unknown"
verbose int
rootCmd = &cobra.Command{
Use: "dae [flags] [command [argument ...]]",
Short: "dae is a lightweight and high-performance transparent proxy solution.",
Long: `dae is a lightweight and high-performance transparent proxy solution.`,
Version: Version,
Run: func(cmd *cobra.Command, args []string) {
const (
tproxyPort = 12345
ifname = "docker0"
)
logrus.SetLevel(logrus.DebugLevel)
log := logger.NewLogger(2)
log.Println("Running")
d, err := dialer.NewFromLink(log, "socks5://localhost:1080#proxy")
if err != nil {
panic(err)
}
group := outbound.NewDialerGroup(log, "proxy",
[]*dialer.Dialer{d},
outbound.DialerSelectionPolicy{
Policy: consts.DialerSelectionPolicy_MinAverage10Latencies,
})
t, err := control.NewControlPlane(log, []*outbound.DialerGroup{group}, `
#sip(172.17.0.2)->proxy
#mac("02:42:ac:11:00:02")->block
#ipversion(4)->proxy
#l4proto(tcp)->proxy
#ip(119.29.29.29) -> proxy
#ip(223.5.5.5) -> direct
ip(geoip:cn) -> direct
domain(full:google.com) && port(443) && l4proto(tcp) -> proxy
domain(geosite:cn, suffix:"ip.sb") -> direct
#ip("91.105.192.0/23","91.108.4.0/22","91.108.8.0/21","91.108.16.0/21","91.108.56.0/22","95.161.64.0/20","149.154.160.0/20","185.76.151.0/24")->proxy
#domain(geosite:category-scholar-!cn, geosite:category-scholar-cn)->direct
final: proxy
`)
if err != nil {
panic(err)
}
if err = t.BindLink(ifname); err != nil {
panic(err)
}
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGILL)
go func() {
if err := t.ListenAndServe(tproxyPort); err != nil {
log.Errorln("ListenAndServe:", err)
sigs <- nil
}
}()
<-sigs
if e := t.Close(); e != nil {
log.Errorln("Close control plane:", err)
}
},
}
)
// Execute executes the root command.
func Execute() error {
return rootCmd.Execute()
}
func init() {
rootCmd.PersistentFlags().CountVarP(&verbose, "verbose", "v", "verbose (-v, or -vv)")
rootCmd.PersistentFlags().StringP("node", "n", "", "node share-link of your modern proxy")
rootCmd.PersistentFlags().StringP("subscription", "s", "", "subscription-link of your modern proxy")
rootCmd.PersistentFlags().Bool("noudp", false, "do not redirect UDP traffic, even though the proxy server supports")
rootCmd.PersistentFlags().String("testnode", "true", "test the connectivity before connecting to the node")
rootCmd.PersistentFlags().Bool("select", false, "manually select the node to connect from the subscription")
//rootCmd.AddCommand(configCmd)
}
func NewLogger(verbose int) *logrus.Logger {
log := logrus.New()
var level logrus.Level
switch verbose {
case 0:
level = logrus.WarnLevel
case 1:
level = logrus.InfoLevel
default:
level = logrus.TraceLevel
}
log.SetLevel(level)
return log
}

43
cmd/infra/su.go Normal file
View File

@ -0,0 +1,43 @@
package infra
import (
"fmt"
"github.com/sirupsen/logrus"
"os"
"os/exec"
"path/filepath"
)
func AutoSu() {
if os.Getuid() == 0 {
return
}
program := filepath.Base(os.Args[0])
pathSudo, err := exec.LookPath("sudo")
if err != nil {
// skip
return
}
// https://github.com/WireGuard/wireguard-tools/blob/71799a8f6d1450b63071a21cad6ed434b348d3d5/src/wg-quick/linux.bash#L85
p, err := os.StartProcess(pathSudo, append([]string{
pathSudo,
"-E",
"-p",
fmt.Sprintf("%v must be run as root. Please enter the password for %%u to continue: ", program),
"--",
}, os.Args...), &os.ProcAttr{
Files: []*os.File{
os.Stdin,
os.Stdout,
os.Stderr,
},
})
if err != nil {
logrus.Fatal(err)
}
stat, err := p.Wait()
if err != nil {
os.Exit(1)
}
os.Exit(stat.ExitCode())
}

View File

@ -20,8 +20,6 @@ const (
BigEndianTproxyPortKey
DisableL4TxChecksumKey
DisableL4RxChecksumKey
EpochKey
RoutingsLenKey
)
type DisableL4ChecksumPolicy uint32
@ -50,6 +48,7 @@ type OutboundIndex uint8
const (
OutboundDirect OutboundIndex = 0
OutboundBlock OutboundIndex = 1
OutboundControlPlaneDirect OutboundIndex = 0xFE
OutboundLogicalAnd OutboundIndex = 0xFF
)
@ -58,6 +57,8 @@ func (i OutboundIndex) String() string {
switch i {
case OutboundDirect:
return "direct"
case OutboundBlock:
return "block"
case OutboundControlPlaneDirect:
return "<Control Plane Direct>"
case OutboundLogicalAnd:

View File

@ -19,4 +19,6 @@ const (
Function_Mac = "mac"
Function_L4Proto = "l4proto"
Function_IpVersion = "ipversion"
Declaration_Final = "final"
)

28
common/debug.go Normal file
View File

@ -0,0 +1,28 @@
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) since 2023, mzz2017 (mzz@tuta.io). All rights reserved.
*/
package common
import (
"github.com/sirupsen/logrus"
"os"
"path/filepath"
"strconv"
"strings"
)
func ReportMemory(tag string) {
if !logrus.IsLevelEnabled(logrus.DebugLevel) {
return
}
b, err := os.ReadFile(filepath.Join("/proc", strconv.Itoa(os.Getpid()), "status"))
if err != nil {
panic(err)
}
str := strings.TrimSpace(string(b))
_, after, _ := strings.Cut(str, "VmHWM:")
usage, _, _ := strings.Cut(after, "\n")
logrus.Debugln(tag+": memory usage:", strings.TrimSpace(usage))
}

View File

@ -16,7 +16,7 @@ type bpfLpmKey struct {
Data [4]uint32
}
func (o *bpfObjects) NewLpmMap(keys []bpfLpmKey, values []uint32) (m *ebpf.Map, err error) {
func (o *bpfObjects) newLpmMap(keys []bpfLpmKey, values []uint32) (m *ebpf.Map, err error) {
m, err = ebpf.NewMap(&ebpf.MapSpec{
Type: ebpf.LPMTrie,
Flags: o.UnusedLpmType.Flags(),

View File

@ -6,4 +6,4 @@
package control
// $BPF_CLANG and $BPF_CFLAGS are set by the Makefile.
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -strip $BPF_STRIP -cflags $BPF_CFLAGS bpf kern/tproxy.c -- -I../headers
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -strip $BPF_STRIP -cflags $BPF_CFLAGS bpf kern/tproxy.c --

View File

@ -42,31 +42,31 @@ type ControlPlane struct {
Final string
// mutex protects the dnsCache.
mutex sync.Mutex
dnsCache map[string]*dnsCache
// Deprecated
epoch uint32
mutex sync.Mutex
dnsCache map[string]*dnsCache
dnsUpstream netip.AddrPort
deferFuncs []func() error
}
func NewControlPlane(log *logrus.Logger, routingA string) (*ControlPlane, error) {
func NewControlPlane(log *logrus.Logger, dialerGroups []*outbound.DialerGroup, routingA string) (*ControlPlane, error) {
// Allow the current process to lock memory for eBPF resources.
if err := rlimit.RemoveMemlock(); err != nil {
return nil, fmt.Errorf("rlimit.RemoveMemlock:%v", err)
}
pinPath := filepath.Join(consts.BpfPinRoot, consts.AppName)
os.MkdirAll(pinPath, 0755)
// Load pre-compiled programs and maps into the kernel.
var bpf bpfObjects
retry_load:
retryLoadBpf:
if err := loadBpfObjects(&bpf, &ebpf.CollectionOptions{
Maps: ebpf.MapOptions{
PinPath: pinPath,
},
}); err != nil {
if errors.Is(err, ebpf.ErrMapIncompatible) {
// Map property is incompatible. Remove the old map and try again.
prefix := "use pinned map "
_, after, ok := strings.Cut(err.Error(), prefix)
if !ok {
@ -75,72 +75,35 @@ retry_load:
mapName, _, _ := strings.Cut(after, ":")
_ = os.Remove(filepath.Join(pinPath, mapName))
log.Warnf("New map format was incompatible with existing map %v, and the old one was removed.", mapName)
goto retry_load
goto retryLoadBpf
}
return nil, fmt.Errorf("loading objects: %w", err)
}
// Flush dst_map.
//_ = os.Remove(filepath.Join(pinPath, "dst_map"))
//if err := bpf.ParamMap.Update(consts.IpsLenKey, uint32(1), ebpf.UpdateAny); err != nil {
// return nil, err
//}
//if err := bpf.ParamMap.Update(consts.BigEndianTproxyPortKey, uint32(swap16(tproxyPort)), ebpf.UpdateAny); err != nil {
// return nil, err
//}
// Write params.
if err := bpf.ParamMap.Update(consts.DisableL4TxChecksumKey, consts.DisableL4ChecksumPolicy_SetZero, ebpf.UpdateAny); err != nil {
return nil, err
}
if err := bpf.ParamMap.Update(consts.DisableL4RxChecksumKey, consts.DisableL4ChecksumPolicy_SetZero, ebpf.UpdateAny); err != nil {
return nil, err
}
//var epoch uint32
//bpf.ParamMap.Lookup(consts.EpochKey, &epoch)
//epoch++
//if err := bpf.ParamMap.Update(consts.EpochKey, epoch, ebpf.UpdateAny); err != nil {
// return nil, err
//}
//if err := bpf.ParamMap.Update(consts.InterfaceIpParamOff, binary.LittleEndian.Uint32([]byte{172, 17, 0, 1}), ebpf.UpdateAny); err != nil { // 172.17.0.1
// return nil, err
//}
//if err := bpf.ParamMap.Update(InterfaceIpParamOff+1, binary.LittleEndian.Uint32([]byte{10, 249, 40, 166}), ebpf.UpdateAny); err != nil { // 10.249.40.166
// log.Println(err)
// return
//}
//if err := bpf.ParamMap.Update(InterfaceIpParamOff+2, binary.LittleEndian.Uint32([]byte{10, 250, 52, 180}), ebpf.UpdateAny); err != nil { // 10.250.52.180
// log.Println(err)
// return
//}
cfDnsAddr := netip.AddrFrom4([4]byte{1, 1, 1, 1})
cfDnsAddr16 := cfDnsAddr.As16()
cfDnsPort := uint16(53)
if err := bpf.DnsUpstreamMap.Update(consts.ZeroKey, bpfIpPort{
Ip: common.Ipv6ByteSliceToUint32Array(cfDnsAddr16[:]),
Port: swap16(cfDnsPort),
}, ebpf.UpdateAny); err != nil {
return nil, err
}
/**/
// TODO:
d, err := dialer.NewFromLink("socks5://localhost:1080#proxy")
if err != nil {
return nil, err
}
// DialerGroups (outbounds).
outbounds := []*outbound.DialerGroup{
outbound.NewDialerGroup(log, consts.OutboundDirect.String(),
[]*dialer.Dialer{dialer.FullconeDirectDialer},
[]*dialer.Dialer{dialer.NewDirectDialer(log, true)},
outbound.DialerSelectionPolicy{
Policy: consts.DialerSelectionPolicy_Fixed,
FixedIndex: 0,
}),
outbound.NewDialerGroup(log, "proxy",
[]*dialer.Dialer{d},
outbound.NewDialerGroup(log, consts.OutboundBlock.String(),
[]*dialer.Dialer{dialer.NewBlockDialer(log)},
outbound.DialerSelectionPolicy{
Policy: consts.DialerSelectionPolicy_MinAverage10Latencies,
Policy: consts.DialerSelectionPolicy_Fixed,
FixedIndex: 0,
}),
}
outbounds = append(outbounds, dialerGroups...)
// Generate outboundName2Id from outbounds.
if len(outbounds) > 0xff {
return nil, fmt.Errorf("too many outbounds")
@ -177,7 +140,17 @@ retry_load:
if err := builder.Build(); err != nil {
return nil, fmt.Errorf("RoutingMatcherBuilder.Build: %w", err)
}
/**/
// DNS upstream.
cfDnsAddr := netip.AddrFrom4([4]byte{1, 1, 1, 1})
cfDnsAddr16 := cfDnsAddr.As16()
cfDnsPort := uint16(53)
if err := bpf.DnsUpstreamMap.Update(consts.ZeroKey, bpfIpPort{
Ip: common.Ipv6ByteSliceToUint32Array(cfDnsAddr16[:]),
Port: swap16(cfDnsPort),
}, ebpf.UpdateAny); err != nil {
return nil, err
}
return &ControlPlane{
log: log,
@ -190,8 +163,7 @@ retry_load:
mutex: sync.Mutex{},
dnsCache: make(map[string]*dnsCache),
dnsUpstream: netip.AddrPortFrom(cfDnsAddr, cfDnsPort),
//epoch: epoch,
deferFuncs: []func() error{bpf.Close},
deferFuncs: []func() error{bpf.Close},
}, nil
}
@ -235,9 +207,26 @@ func (c *ControlPlane) BindLink(ifname string) error {
break
}
}
if err := c.bpf.IfindexIpMap.Update(uint32(link.Attrs().Index), linkIp, ebpf.UpdateAny); err != nil {
if err := c.bpf.IfindexTproxyIpMap.Update(uint32(link.Attrs().Index), linkIp, ebpf.UpdateAny); err != nil {
return fmt.Errorf("update IfindexIpsMap: %w", err)
}
// FIXME: not only this link ip.
if linkIp.HasIp4 {
if err := c.bpf.HostIpLpm.Update(bpfLpmKey{
PrefixLen: 128,
Data: linkIp.Ip4,
}, uint32(1), ebpf.UpdateAny); err != nil {
return fmt.Errorf("update IfindexIpsMap: %w", err)
}
}
if linkIp.HasIp6 {
if err := c.bpf.HostIpLpm.Update(bpfLpmKey{
PrefixLen: 128,
Data: linkIp.Ip6,
}, uint32(1), ebpf.UpdateAny); err != nil {
return fmt.Errorf("update IfindexIpsMap: %w", err)
}
}
// Insert qdisc and filters.
qdisc := &netlink.GenericQdisc{

View File

@ -7,9 +7,9 @@ package control
import (
"fmt"
"github.com/cilium/ebpf"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/common/consts"
"github.com/cilium/ebpf"
"golang.org/x/net/dns/dnsmessage"
"net/netip"
"strings"
@ -53,7 +53,6 @@ func (c *ControlPlane) BatchUpdateDomainRouting(cache *dnsCache) error {
keys = append(keys, common.Ipv6ByteSliceToUint32Array(ip6[:]))
vals = append(vals, bpfDomainRouting{
Bitmap: cache.DomainBitmap,
Epoch: c.epoch,
})
}
if _, err := c.bpf.DomainRoutingMap.BatchUpdate(keys, vals, &ebpf.BatchOptions{

View File

@ -12,7 +12,7 @@ import (
)
func (c *ControlPlane) MatchDomainBitmap(domain string) (bitmap [consts.MaxRoutingLen / 32]uint32) {
// FIXME: high performance implementation.
// TODO: high performance implementation.
for _, s := range c.SimulatedDomainSet {
for _, d := range s.Domains {
var hit bool

View File

@ -0,0 +1,99 @@
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#ifndef __BPF_ENDIAN__
#define __BPF_ENDIAN__
/*
* Isolate byte #n and put it into byte #m, for __u##b type.
* E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64:
* 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx
* 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000
* 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn
* 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000
*/
#define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8))
#define ___bpf_swab16(x) ((__u16)( \
___bpf_mvb(x, 16, 0, 1) | \
___bpf_mvb(x, 16, 1, 0)))
#define ___bpf_swab32(x) ((__u32)( \
___bpf_mvb(x, 32, 0, 3) | \
___bpf_mvb(x, 32, 1, 2) | \
___bpf_mvb(x, 32, 2, 1) | \
___bpf_mvb(x, 32, 3, 0)))
#define ___bpf_swab64(x) ((__u64)( \
___bpf_mvb(x, 64, 0, 7) | \
___bpf_mvb(x, 64, 1, 6) | \
___bpf_mvb(x, 64, 2, 5) | \
___bpf_mvb(x, 64, 3, 4) | \
___bpf_mvb(x, 64, 4, 3) | \
___bpf_mvb(x, 64, 5, 2) | \
___bpf_mvb(x, 64, 6, 1) | \
___bpf_mvb(x, 64, 7, 0)))
/* LLVM's BPF target selects the endianness of the CPU
* it compiles on, or the user specifies (bpfel/bpfeb),
* respectively. The used __BYTE_ORDER__ is defined by
* the compiler, we cannot rely on __BYTE_ORDER from
* libc headers, since it doesn't reflect the actual
* requested byte order.
*
* Note, LLVM's BPF target has different __builtin_bswapX()
* semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE
* in bpfel and bpfeb case, which means below, that we map
* to cpu_to_be16(). We could use it unconditionally in BPF
* case, but better not rely on it, so that this header here
* can be used from application and BPF program side, which
* use different targets.
*/
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define __bpf_ntohs(x) __builtin_bswap16(x)
# define __bpf_htons(x) __builtin_bswap16(x)
# define __bpf_constant_ntohs(x) ___bpf_swab16(x)
# define __bpf_constant_htons(x) ___bpf_swab16(x)
# define __bpf_ntohl(x) __builtin_bswap32(x)
# define __bpf_htonl(x) __builtin_bswap32(x)
# define __bpf_constant_ntohl(x) ___bpf_swab32(x)
# define __bpf_constant_htonl(x) ___bpf_swab32(x)
# define __bpf_be64_to_cpu(x) __builtin_bswap64(x)
# define __bpf_cpu_to_be64(x) __builtin_bswap64(x)
# define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x)
# define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define __bpf_ntohs(x) (x)
# define __bpf_htons(x) (x)
# define __bpf_constant_ntohs(x) (x)
# define __bpf_constant_htons(x) (x)
# define __bpf_ntohl(x) (x)
# define __bpf_htonl(x) (x)
# define __bpf_constant_ntohl(x) (x)
# define __bpf_constant_htonl(x) (x)
# define __bpf_be64_to_cpu(x) (x)
# define __bpf_cpu_to_be64(x) (x)
# define __bpf_constant_be64_to_cpu(x) (x)
# define __bpf_constant_cpu_to_be64(x) (x)
#else
# error "Fix your compiler's __BYTE_ORDER__?!"
#endif
#define bpf_htons(x) \
(__builtin_constant_p(x) ? \
__bpf_constant_htons(x) : __bpf_htons(x))
#define bpf_ntohs(x) \
(__builtin_constant_p(x) ? \
__bpf_constant_ntohs(x) : __bpf_ntohs(x))
#define bpf_htonl(x) \
(__builtin_constant_p(x) ? \
__bpf_constant_htonl(x) : __bpf_htonl(x))
#define bpf_ntohl(x) \
(__builtin_constant_p(x) ? \
__bpf_constant_ntohl(x) : __bpf_ntohl(x))
#define bpf_cpu_to_be64(x) \
(__builtin_constant_p(x) ? \
__bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x))
#define bpf_be64_to_cpu(x) \
(__builtin_constant_p(x) ? \
__bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x))
#endif /* __BPF_ENDIAN__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,263 @@
// Copied from https://github.com/cilium/ebpf/blob/e0ada270a5/examples/headers/bpf_helpers.h
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#ifndef __BPF_HELPERS__
#define __BPF_HELPERS__
/*
* Note that bpf programs need to include either
* vmlinux.h (auto-generated from BTF) or linux/types.h
* in advance since bpf_helper_defs.h uses such types
* as __u64.
*/
#include "bpf_helper_defs.h"
#define __uint(name, val) int (*name)[val]
#define __type(name, val) typeof(val) *name
#define __array(name, val) typeof(val) *name[]
/*
* Helper macro to place programs, maps, license in
* different sections in elf_bpf file. Section names
* are interpreted by libbpf depending on the context (BPF programs, BPF maps,
* extern variables, etc).
* To allow use of SEC() with externs (e.g., for extern .maps declarations),
* make sure __attribute__((unused)) doesn't trigger compilation warning.
*/
#define SEC(name) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wignored-attributes\"") \
__attribute__((section(name), used)) \
_Pragma("GCC diagnostic pop") \
/* Avoid 'linux/stddef.h' definition of '__always_inline'. */
#undef __always_inline
#define __always_inline inline __attribute__((always_inline))
#ifndef __noinline
#define __noinline __attribute__((noinline))
#endif
#ifndef __weak
#define __weak __attribute__((weak))
#endif
/*
* Use __hidden attribute to mark a non-static BPF subprogram effectively
* static for BPF verifier's verification algorithm purposes, allowing more
* extensive and permissive BPF verification process, taking into account
* subprogram's caller context.
*/
#define __hidden __attribute__((visibility("hidden")))
/* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include
* any system-level headers (such as stddef.h, linux/version.h, etc), and
* commonly-used macros like NULL and KERNEL_VERSION aren't available through
* vmlinux.h. This just adds unnecessary hurdles and forces users to re-define
* them on their own. So as a convenience, provide such definitions here.
*/
#ifndef NULL
#define NULL ((void *)0)
#endif
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))
#endif
/*
* Helper macros to manipulate data structures
*/
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER)
#endif
#ifndef container_of
#define container_of(ptr, type, member) \
({ \
void *__mptr = (void *)(ptr); \
((type *)(__mptr - offsetof(type, member))); \
})
#endif
/*
* Helper macro to throw a compilation error if __bpf_unreachable() gets
* built into the resulting code. This works given BPF back end does not
* implement __builtin_trap(). This is useful to assert that certain paths
* of the program code are never used and hence eliminated by the compiler.
*
* For example, consider a switch statement that covers known cases used by
* the program. __bpf_unreachable() can then reside in the default case. If
* the program gets extended such that a case is not covered in the switch
* statement, then it will throw a build error due to the default case not
* being compiled out.
*/
#ifndef __bpf_unreachable
# define __bpf_unreachable() __builtin_trap()
#endif
/*
* Helper function to perform a tail call with a constant/immediate map slot.
*/
#if __clang_major__ >= 8 && defined(__bpf__)
static __always_inline void
bpf_tail_call_static(void *ctx, const void *map, const __u32 slot)
{
if (!__builtin_constant_p(slot))
__bpf_unreachable();
/*
* Provide a hard guarantee that LLVM won't optimize setting r2 (map
* pointer) and r3 (constant map index) from _different paths_ ending
* up at the _same_ call insn as otherwise we won't be able to use the
* jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel
* given they mismatch. See also d2e4c1e6c294 ("bpf: Constant map key
* tracking for prog array pokes") for details on verifier tracking.
*
* Note on clobber list: we need to stay in-line with BPF calling
* convention, so even if we don't end up using r0, r4, r5, we need
* to mark them as clobber so that LLVM doesn't end up using them
* before / after the call.
*/
asm volatile("r1 = %[ctx]\n\t"
"r2 = %[map]\n\t"
"r3 = %[slot]\n\t"
"call 12"
:: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot)
: "r0", "r1", "r2", "r3", "r4", "r5");
}
#endif
/*
* Helper structure used by eBPF C program
* to describe BPF map attributes to libbpf loader
*/
struct bpf_map_def {
unsigned int type;
unsigned int key_size;
unsigned int value_size;
unsigned int max_entries;
unsigned int map_flags;
};
enum libbpf_pin_type {
LIBBPF_PIN_NONE,
/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
LIBBPF_PIN_BY_NAME,
};
enum libbpf_tristate {
TRI_NO = 0,
TRI_YES = 1,
TRI_MODULE = 2,
};
#define __kconfig __attribute__((section(".kconfig")))
#define __ksym __attribute__((section(".ksyms")))
#ifndef ___bpf_concat
#define ___bpf_concat(a, b) a ## b
#endif
#ifndef ___bpf_apply
#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)
#endif
#ifndef ___bpf_nth
#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N
#endif
#ifndef ___bpf_narg
#define ___bpf_narg(...) \
___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#endif
#define ___bpf_fill0(arr, p, x) do {} while (0)
#define ___bpf_fill1(arr, p, x) arr[p] = x
#define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args)
#define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args)
#define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args)
#define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args)
#define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args)
#define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args)
#define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args)
#define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args)
#define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args)
#define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args)
#define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args)
#define ___bpf_fill(arr, args...) \
___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args)
/*
* BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values
* in a structure.
*/
#define BPF_SEQ_PRINTF(seq, fmt, args...) \
({ \
static const char ___fmt[] = fmt; \
unsigned long long ___param[___bpf_narg(args)]; \
\
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
___bpf_fill(___param, args); \
_Pragma("GCC diagnostic pop") \
\
bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \
___param, sizeof(___param)); \
})
/*
* BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of
* an array of u64.
*/
#define BPF_SNPRINTF(out, out_size, fmt, args...) \
({ \
static const char ___fmt[] = fmt; \
unsigned long long ___param[___bpf_narg(args)]; \
\
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
___bpf_fill(___param, args); \
_Pragma("GCC diagnostic pop") \
\
bpf_snprintf(out, out_size, ___fmt, \
___param, sizeof(___param)); \
})
#ifdef BPF_NO_GLOBAL_DATA
#define BPF_PRINTK_FMT_MOD
#else
#define BPF_PRINTK_FMT_MOD static const
#endif
#define __bpf_printk(fmt, ...) \
({ \
BPF_PRINTK_FMT_MOD char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), \
##__VA_ARGS__); \
})
/*
* __bpf_vprintk wraps the bpf_trace_vprintk helper with variadic arguments
* instead of an array of u64.
*/
#define __bpf_vprintk(fmt, args...) \
({ \
static const char ___fmt[] = fmt; \
unsigned long long ___param[___bpf_narg(args)]; \
\
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
___bpf_fill(___param, args); \
_Pragma("GCC diagnostic pop") \
\
bpf_trace_vprintk(___fmt, sizeof(___fmt), \
___param, sizeof(___param)); \
})
/* Use __bpf_printk when bpf_printk call has 3 or fewer fmt args
* Otherwise use __bpf_vprintk
*/
#define ___bpf_pick_printk(...) \
___bpf_nth(_, ##__VA_ARGS__, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \
__bpf_vprintk, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \
__bpf_vprintk, __bpf_vprintk, __bpf_printk /*3*/, __bpf_printk /*2*/,\
__bpf_printk /*1*/, __bpf_printk /*0*/)
/* Helper macro to print out debug messages */
#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)
#endif

View File

@ -1,30 +1,23 @@
// +build ignore
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) since 2022, mzz2017 (mzz@tuta.io). All rights reserved.
*/
#include <asm-generic/errno-base.h>
#include <iproute2/bpf_elf.h>
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/kernel.h>
#include <linux/pkt_cls.h>
#include <linux/tcp.h>
#include <linux/types.h>
#include <linux/udp.h>
#include <net/if.h>
#include <stdbool.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include "bpf_endian.h"
#include "bpf_helpers.h"
// #include "addr.h"
// #define likely(x) x
// #define unlikely(x) x
@ -41,12 +34,15 @@
#define MAX_PARAM_LEN 16
#define MAX_INTERFACE_NUM 128
#define MAX_ROUTING_LEN 96
#define MAX_ROUTING_LEN (32 * 3)
#define MAX_LPM_SIZE 20480
//#define MAX_LPM_SIZE 20480
#define MAX_LPM_NUM (MAX_ROUTING_LEN + 8)
#define MAX_DEST_MAPPING_NUM (65536 * 2)
#define IPV6_MAX_EXTENSIONS 4
#define OUTBOUND_DIRECT 0
#define OUTBOUND_BLOCK 1
#define OUTBOUND_CONTROL_PLANE_DIRECT 0xFE
#define OUTBOUND_LOGICAL_AND 0xFF
@ -62,10 +58,6 @@ static const __u32 zero_key = 0;
static const __u32 tproxy_port_key = 1;
static const __u32 disable_l4_tx_checksum_key = 2;
static const __u32 disable_l4_rx_checksum_key = 3;
static const __u32 epoch_key __attribute__((unused, deprecated)) = 4;
static const __u32 routings_len_key __attribute__((unused, deprecated)) = 5;
static __be32 unspecific_ipv6[4] __attribute__((__unused__)) = {0, 0, 0, 0};
struct ip_port {
__be32 ip[4];
@ -96,7 +88,7 @@ struct {
// enough for identifier. And UDP client
// side does not care it (full-cone).
__type(value, struct ip_port_outbound); // Original target.
__uint(max_entries, 0xFF << 2);
__uint(max_entries, MAX_DEST_MAPPING_NUM);
/// NOTICE: It MUST be pinned.
__uint(pinning, LIBBPF_PIN_BY_NAME);
} dst_map SEC(".maps");
@ -132,7 +124,7 @@ struct {
__uint(max_entries, MAX_INTERFACE_NUM);
/// NOTICE: No persistence.
// __uint(pinning, LIBBPF_PIN_BY_NAME);
} ifindex_ip_map SEC(".maps");
} ifindex_tproxy_ip_map SEC(".maps");
// Array of LPM tries:
struct lpm_key {
@ -145,12 +137,12 @@ struct map_lpm_type {
__uint(max_entries, MAX_LPM_SIZE);
__uint(key_size, sizeof(struct lpm_key));
__uint(value_size, sizeof(__u32));
} unused_lpm_type SEC(".maps");
} unused_lpm_type SEC(".maps"), host_ip_lpm SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
__uint(key_size, sizeof(__u32));
__uint(max_entries, MAX_LPM_NUM);
__uint(pinning, LIBBPF_PIN_BY_NAME);
// __uint(pinning, LIBBPF_PIN_BY_NAME);
__array(values, struct map_lpm_type);
} lpm_array_map SEC(".maps");
@ -199,16 +191,11 @@ struct {
__type(key, __u32);
__type(value, struct routing);
__uint(max_entries, MAX_ROUTING_LEN);
__uint(pinning, LIBBPF_PIN_BY_NAME);
// __uint(pinning, LIBBPF_PIN_BY_NAME);
} routing_map SEC(".maps");
struct domain_routing {
__u32 bitmap[MAX_ROUTING_LEN / 32];
/// DEPRECATED: Epoch is the epoch at the write time. Every time the control
/// plane restarts, epoch += 1. It was deprecated because long connection will
/// keep their states by persistent dst_map (we only need to know if it is a
/// old connection).
__u32 epoch;
};
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
@ -220,7 +207,7 @@ struct {
// Functions:
static __always_inline bool equal_ipv6(__be32 x[4], __be32 y[4]) {
static __always_inline bool equal_ipv6_format(__be32 x[4], __be32 y[4]) {
#if __clang_major__ >= 10
return ((__be64 *)x)[0] == ((__be64 *)y)[0] &&
((__be64 *)x)[1] == ((__be64 *)y)[1];
@ -248,7 +235,7 @@ static __always_inline long rewrite_ip(struct __sk_buff *skb, bool is_ipv6,
__u8 proto, __u8 ihl, __be32 old_ip[4],
__be32 new_ip[4], bool is_dest) {
// Nothing to do.
if (equal_ipv6(old_ip, new_ip)) {
if (equal_ipv6_format(old_ip, new_ip)) {
return 0;
}
// bpf_printk("%pI6->%pI6", old_ip, new_ip);
@ -486,28 +473,26 @@ parse_transport(struct __sk_buff *skb, struct ethhdr **ethh, struct iphdr **iph,
}
static __always_inline long ip_is_host(bool is_ipv6, __u32 ifindex,
__be32 ip[4],
__be32 (*first_interface_ip)[4]) {
struct if_ip *if_ip = bpf_map_lookup_elem(&ifindex_ip_map, &ifindex);
if (unlikely(!if_ip)) {
return -1;
__be32 ip[4], __be32 tproxy_ip[4]) {
if (tproxy_ip) {
struct if_ip *if_ip = bpf_map_lookup_elem(&ifindex_tproxy_ip_map, &ifindex);
if (unlikely(!if_ip)) {
return -1;
}
if (!is_ipv6 && (*if_ip).hasIp4) {
__builtin_memcpy(tproxy_ip, (*if_ip).ip4, IPV6_BYTE_LENGTH);
} else if (is_ipv6 && (*if_ip).hasIp6) {
__builtin_memcpy(tproxy_ip, (*if_ip).ip6, IPV6_BYTE_LENGTH);
} else {
// Should TC_ACT_OK outer.
return -EFAULT;
}
}
__u32 host_ip[4];
if (!is_ipv6 && (*if_ip).hasIp4) {
__builtin_memcpy(host_ip, (*if_ip).ip4, IPV6_BYTE_LENGTH);
} else if (is_ipv6 && (*if_ip).hasIp6) {
__builtin_memcpy(host_ip, (*if_ip).ip6, IPV6_BYTE_LENGTH);
} else {
// Should TC_ACT_OK outer.
return -EFAULT;
}
if (first_interface_ip) {
__builtin_memcpy(*first_interface_ip, host_ip, IPV6_BYTE_LENGTH);
}
if (equal_ipv6(ip, host_ip)) {
return 1;
}
return 0;
struct lpm_key lpm_key;
lpm_key.trie_key.prefixlen = IPV6_BYTE_LENGTH * 8;
__builtin_memcpy(lpm_key.data, ip, IPV6_BYTE_LENGTH);
return bpf_map_lookup_elem(&host_ip_lpm, &lpm_key) ? 1 : 0;
}
static __always_inline long adjust_udp_len(struct __sk_buff *skb, __u16 oldlen,
@ -597,9 +582,9 @@ static __always_inline long encap_after_udp_hdr(struct __sk_buff *skb,
__be16 iphdr_tot_len,
void *newhdr, __u32 newhdrlen) {
if (unlikely(newhdrlen % 4 != 0)) {
bpf_trace_printk("encap_after_udp_hdr: unexpected newhdrlen value %u :must "
"be a multiple of 4",
newhdrlen);
bpf_printk("encap_after_udp_hdr: unexpected newhdrlen value %u :must "
"be a multiple of 4",
newhdrlen);
return -EINVAL;
}
@ -664,10 +649,9 @@ static __always_inline int decap_after_udp_hdr(struct __sk_buff *skb,
__be16 iphdr_tot_len, void *to,
__u32 decap_hdrlen) {
if (unlikely(decap_hdrlen % 4 != 0)) {
bpf_trace_printk(
"encap_after_udp_hdr: unexpected decap_hdrlen value %u :must "
"be a multiple of 4",
decap_hdrlen);
bpf_printk("encap_after_udp_hdr: unexpected decap_hdrlen value %u :must "
"be a multiple of 4",
decap_hdrlen);
return -EINVAL;
}
long ret = 0;
@ -742,15 +726,7 @@ static long routing(__u8 flag[2], void *l4_hdr, __be32 saddr[4],
__be32 daddr[4], __be32 mac[4]) {
#define _l4proto flag[0]
#define _ipversion flag[1]
// // Get len of routings and epoch from param_map.
// __u32 *routings_len = bpf_map_lookup_elem(&param_map, &routings_len_key);
// if (!routings_len) {
// return -EINVAL;
// }
// __u32 *epoch = bpf_map_lookup_elem(&param_map, &epoch_key);
// if (!epoch) {
// return -EINVAL;
// }
// Define variables for further use.
__u16 h_dport;
__u16 h_sport;
@ -786,13 +762,6 @@ static long routing(__u8 flag[2], void *l4_hdr, __be32 saddr[4],
bool bad_rule = false;
struct domain_routing *domain_routing;
/// DEPRECATED: Epoch was deprecated and domain_routing_map was unpinned, thus
/// this branch will never hit.
// if (domain_routing && domain_routing->epoch != *epoch) {
// // Dirty (epoch dismatch) traffic should be routed by the control plane.
// return OUTBOUND_CONTROL_PLANE_DIRECT;
// }
#pragma unroll
for (__u32 key = 0; key < MAX_ROUTING_LEN; key++) {
__u32 k = key; // Clone to pass code checker.
@ -895,6 +864,7 @@ int tproxy_ingress(struct __sk_buff *skb) {
struct udphdr *udph;
__sum16 bak_cksm;
__u8 ihl;
bool tcp_state_syn;
long ret = parse_transport(skb, &ethh, &iph, &ipv6h, &tcph, &udph, &ihl);
if (ret) {
bpf_printk("parse_transport: %ld", ret);
@ -906,13 +876,7 @@ int tproxy_ingress(struct __sk_buff *skb) {
// Backup for further use.
__u8 l4_proto;
if (tcph) {
l4_proto = IPPROTO_TCP;
} else if (udph) {
l4_proto = IPPROTO_UDP;
} else {
return TC_ACT_OK;
}
__be16 ip_tot_len = 0;
// Parse saddr and daddr as ipv6 format.
__be32 saddr[4];
@ -927,6 +891,8 @@ int tproxy_ingress(struct __sk_buff *skb) {
daddr[1] = 0;
daddr[2] = bpf_htonl(0x0000ffff);
daddr[3] = iph->daddr;
ip_tot_len = iph->tot_len;
} else if (ipv6h) {
__builtin_memcpy(daddr, &ipv6h->daddr, IPV6_BYTE_LENGTH);
__builtin_memcpy(saddr, &ipv6h->saddr, IPV6_BYTE_LENGTH);
@ -935,8 +901,8 @@ int tproxy_ingress(struct __sk_buff *skb) {
}
// If this packet is sent to this host, accept it.
__u32 first_interface_ip[4];
long to_host = ip_is_host(ipv6h, skb->ifindex, daddr, &first_interface_ip);
__u32 tproxy_ip[4];
long to_host = ip_is_host(ipv6h, skb->ifindex, daddr, tproxy_ip);
if (to_host < 0) { // error
// bpf_printk("to_host: %ld", to_host);
return TC_ACT_OK;
@ -946,7 +912,6 @@ int tproxy_ingress(struct __sk_buff *skb) {
// To host:53. Process it.
} else {
// To host. Accept.
/// FIXME: all host ip.
return TC_ACT_OK;
}
}
@ -958,8 +923,9 @@ int tproxy_ingress(struct __sk_buff *skb) {
if (tcph) {
// Backup for further use.
l4_proto = IPPROTO_TCP;
bak_cksm = tcph->check;
bool tcp_state_syn = tcph->syn && !tcph->ack;
tcp_state_syn = tcph->syn && !tcph->ack;
struct ip_port_proto key_src;
__builtin_memset(&key_src, 0, sizeof(key_src));
__builtin_memcpy(key_src.ip, saddr, IPV6_BYTE_LENGTH);
@ -1003,6 +969,8 @@ int tproxy_ingress(struct __sk_buff *skb) {
bpf_printk("tcp: outbound: %u, %pI6", outbound, daddr);
if (outbound == OUTBOUND_DIRECT) {
return TC_ACT_OK;
} else if (unlikely(outbound == OUTBOUND_BLOCK)) {
return TC_ACT_SHOT;
} else {
// Rewrite to control plane.
@ -1017,8 +985,8 @@ int tproxy_ingress(struct __sk_buff *skb) {
__u32 *dst_ip = daddr;
__u16 dst_port = tcph->dest;
if ((ret = rewrite_ip(skb, ipv6h, IPPROTO_TCP, ihl, dst_ip,
first_interface_ip, true))) {
if ((ret = rewrite_ip(skb, ipv6h, IPPROTO_TCP, ihl, dst_ip, tproxy_ip,
true))) {
bpf_printk("Shot IP: %ld", ret);
return TC_ACT_SHOT;
}
@ -1031,6 +999,7 @@ int tproxy_ingress(struct __sk_buff *skb) {
} else if (udph) {
// Backup for further use.
bak_cksm = udph->check;
l4_proto = IPPROTO_UDP;
struct ip_port_outbound new_hdr;
__builtin_memset(&new_hdr, 0, sizeof(new_hdr));
__builtin_memcpy(new_hdr.ip, daddr, IPV6_BYTE_LENGTH);
@ -1059,18 +1028,19 @@ int tproxy_ingress(struct __sk_buff *skb) {
if (new_hdr.outbound == OUTBOUND_DIRECT) {
return TC_ACT_OK;
} else if (unlikely(new_hdr.outbound == OUTBOUND_BLOCK)) {
return TC_ACT_SHOT;
} else {
// Rewrite to control plane.
// Encap a header to transmit fullcone tuple.
__be16 ip_tot_len = iph ? iph->tot_len : 0;
encap_after_udp_hdr(skb, ipv6h, ihl, ip_tot_len, &new_hdr,
sizeof(new_hdr));
// Rewrite udp dst ip.
// bpf_printk("rewrite dst ip from %pI4", &ori_dst.ip);
if ((ret = rewrite_ip(skb, ipv6h, IPPROTO_UDP, ihl, new_hdr.ip,
first_interface_ip, true))) {
if ((ret = rewrite_ip(skb, ipv6h, IPPROTO_UDP, ihl, new_hdr.ip, tproxy_ip,
true))) {
bpf_printk("Shot IP: %ld", ret);
return TC_ACT_SHOT;
}
@ -1129,6 +1099,7 @@ int tproxy_egress(struct __sk_buff *skb) {
struct tcphdr *tcph;
struct udphdr *udph;
__sum16 bak_cksm;
__u8 l4_proto;
__u8 ihl;
long ret = parse_transport(skb, &ethh, &iph, &ipv6h, &tcph, &udph, &ihl);
if (ret) {
@ -1138,6 +1109,7 @@ int tproxy_egress(struct __sk_buff *skb) {
// Parse saddr and daddr as ipv6 format.
__be32 saddr[4];
__be32 daddr[4];
__be16 ip_tot_len = 0;
if (iph) {
saddr[0] = 0;
saddr[1] = 0;
@ -1148,6 +1120,8 @@ int tproxy_egress(struct __sk_buff *skb) {
daddr[1] = 0;
daddr[2] = bpf_htonl(0x0000ffff);
daddr[3] = iph->daddr;
ip_tot_len = iph->tot_len;
} else if (ipv6h) {
__builtin_memcpy(daddr, ipv6h->daddr.in6_u.u6_addr32, IPV6_BYTE_LENGTH);
__builtin_memcpy(saddr, ipv6h->saddr.in6_u.u6_addr32, IPV6_BYTE_LENGTH);
@ -1160,23 +1134,17 @@ int tproxy_egress(struct __sk_buff *skb) {
if (!tproxy_port) {
return TC_ACT_OK;
}
long from_host = ip_is_host(ipv6h, skb->ifindex, saddr, NULL);
if (!(from_host == 1)) {
// Not from localhost.
__be32 tproxy_ip[4];
ret = ip_is_host(ipv6h, skb->ifindex, saddr, tproxy_ip);
if (!(ret == 1)) {
return TC_ACT_OK;
}
if (!equal_ipv6_format(saddr, tproxy_ip)) {
return TC_ACT_OK;
}
// Backup for further use.
__u8 l4_proto;
if (tcph) {
l4_proto = IPPROTO_TCP;
} else if (udph) {
l4_proto = IPPROTO_UDP;
} else {
return TC_ACT_OK;
}
if (tcph) {
if (tcph->source != *tproxy_port) {
return TC_ACT_OK;
}
@ -1216,6 +1184,7 @@ int tproxy_egress(struct __sk_buff *skb) {
return TC_ACT_SHOT;
}
} else if (udph) {
l4_proto = IPPROTO_UDP;
if (udph->source != *tproxy_port) {
return TC_ACT_OK;
}
@ -1233,7 +1202,6 @@ int tproxy_egress(struct __sk_buff *skb) {
// Get source ip/port from our packet header.
// Decap header to get fullcone tuple.
__be16 ip_tot_len = iph ? iph->tot_len : 0;
decap_after_udp_hdr(skb, ipv6h, ihl, ip_tot_len, &ori_src, sizeof(ori_src));
// Rewrite udp src ip
@ -1274,7 +1242,7 @@ int tproxy_egress(struct __sk_buff *skb) {
if (*disable_l4_checksum == DISABLE_L4_CHECKSUM_POLICY_SET_ZERO) {
bak_cksm = 0;
}
bpf_skb_store_bytes(skb, l4_cksm_off, &bak_cksm, 2, 0);
bpf_skb_store_bytes(skb, l4_cksm_off, &bak_cksm, sizeof(bak_cksm), 0);
}
}
return TC_ACT_OK;

View File

@ -20,6 +20,7 @@ type DomainSet struct {
RuleIndex int
Domains []string
}
type RoutingMatcherBuilder struct {
*routing.DefaultMatcherBuilder
outboundName2Id map[string]uint8
@ -74,7 +75,7 @@ func (b *RoutingMatcherBuilder) AddDomain(key string, values []string, outbound
})
}
func (b *RoutingMatcherBuilder) AddMac(macAddrs [][6]byte, outbound string) {
func (b *RoutingMatcherBuilder) AddSourceMac(macAddrs [][6]byte, outbound string) {
if b.err != nil {
return
}
@ -108,7 +109,7 @@ func (b *RoutingMatcherBuilder) AddIp(values []netip.Prefix, outbound string) {
})
}
func (b *RoutingMatcherBuilder) AddSource(values []netip.Prefix, outbound string) {
func (b *RoutingMatcherBuilder) AddSourceIp(values []netip.Prefix, outbound string) {
if b.err != nil {
return
}
@ -166,9 +167,9 @@ func (b *RoutingMatcherBuilder) Build() (err error) {
keys = append(keys, cidrToBpfLpmKey(cidr))
values = append(values, 1)
}
m, err := b.bpf.NewLpmMap(keys, values)
m, err := b.bpf.newLpmMap(keys, values)
if err != nil {
return fmt.Errorf("NewLpmMap: %w", err)
return fmt.Errorf("newLpmMap: %w", err)
}
// ebpf.Map cannot be BatchUpdate
if err = b.bpf.LpmArrayMap.Update(uint32(i), m, ebpf.UpdateAny); err != nil {
@ -177,7 +178,12 @@ func (b *RoutingMatcherBuilder) Build() (err error) {
}
m.Close()
}
// Update routings.
// Write routings.
// Final rule MUST be the last.
if b.rules[len(b.rules)-1].Type != uint8(consts.RoutingType_Final) {
b.err = fmt.Errorf("final rule MUST be the last")
return b.err
}
routingsLen := uint32(len(b.rules))
routingsKeys := common.ARangeU32(routingsLen)
if _, err = b.bpf.RoutingMap.BatchUpdate(routingsKeys, b.rules, &ebpf.BatchOptions{
@ -185,8 +191,5 @@ func (b *RoutingMatcherBuilder) Build() (err error) {
}); err != nil {
return fmt.Errorf("BatchUpdate: %w", err)
}
if err = b.bpf.ParamMap.Update(consts.RoutingsLenKey, routingsLen, ebpf.UpdateAny); err != nil {
return fmt.Errorf("Update: %w", err)
}
return nil
}

View File

@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) since 2023, mzz2017 (mzz@tuta.io). All rights reserved.
*/
package dialer
import (
"github.com/sirupsen/logrus"
"net"
)
type blockDialer struct{}
func (*blockDialer) Dial(network string, addr string) (c net.Conn, err error) {
return nil, net.ErrClosed
}
func NewBlockDialer(log *logrus.Logger) *Dialer {
return newDialer(&blockDialer{}, log, true, "block", "block", "")
}

View File

@ -24,6 +24,8 @@ var (
)
type Dialer struct {
log *logrus.Logger
proxy.Dialer
supportUDP bool
name string
@ -40,16 +42,17 @@ type Dialer struct {
}
// NewDialer is for register in general.
func NewDialer(dialer proxy.Dialer, supportUDP bool, name string, protocol string, link string) *Dialer {
d := newDialer(dialer, supportUDP, name, protocol, link)
func NewDialer(dialer proxy.Dialer, log *logrus.Logger, supportUDP bool, name string, protocol string, link string) *Dialer {
d := newDialer(dialer, log, supportUDP, name, protocol, link)
go d.aliveBackground()
return d
}
// newDialer does not run background tasks.
func newDialer(dialer proxy.Dialer, supportUDP bool, name string, protocol string, link string) *Dialer {
func newDialer(dialer proxy.Dialer, log *logrus.Logger, supportUDP bool, name string, protocol string, link string) *Dialer {
d := &Dialer{
Dialer: dialer,
log: log,
supportUDP: supportUDP,
name: name,
protocol: protocol,
@ -132,13 +135,13 @@ func (d *Dialer) Test(timeout time.Duration, url string) (ok bool, err error) {
// No error.
latency := time.Since(start)
// FIXME: Use log instead of logrus.
logrus.Debugf("Connectivity Test <%v>: %v", d.name, latency)
d.log.Debugf("Connectivity Test <%v>: %v", d.name, latency)
d.Latencies10.AppendLatency(latency)
alive = true
} else {
// Append timeout if there is any error or unexpected status code.
if err != nil {
logrus.Debugf("Connectivity Test <%v>: %v", d.name, err.Error())
d.log.Debugf("Connectivity Test <%v>: %v", d.name, err.Error())
}
d.Latencies10.AppendLatency(timeout)
}

View File

@ -1,15 +1,21 @@
package dialer
import (
"github.com/sirupsen/logrus"
"golang.org/x/net/proxy"
"net"
)
var SymmetricDirect = NewDirect(false)
var FullconeDirect = NewDirect(true)
var SymmetricDirect = newDirect(false)
var FullconeDirect = newDirect(true)
var SymmetricDirectDialer = newDialer(SymmetricDirect, true, "direct", "direct", "")
var FullconeDirectDialer = newDialer(FullconeDirect, true, "direct", "direct", "")
func NewDirectDialer(log *logrus.Logger, fullcone bool) *Dialer {
if fullcone {
return newDialer(FullconeDirect, log, true, "direct", "direct", "")
} else {
return newDialer(SymmetricDirect, log, true, "direct", "direct", "")
}
}
type direct struct {
proxy.Dialer
@ -17,7 +23,7 @@ type direct struct {
fullCone bool
}
func NewDirect(fullCone bool) proxy.Dialer {
func newDirect(fullCone bool) proxy.Dialer {
return &direct{
netDialer: net.Dialer{},
fullCone: fullCone,

View File

@ -2,9 +2,9 @@ package http
import (
"fmt"
"github.com/v2rayA/dae/component/outbound/dialer"
"github.com/mzz2017/softwind/protocol/http"
"gopkg.in/yaml.v3"
"github.com/sirupsen/logrus"
"github.com/v2rayA/dae/component/outbound/dialer"
"net"
"net/url"
"strconv"
@ -13,7 +13,6 @@ import (
func init() {
dialer.FromLinkRegister("http", NewHTTP)
dialer.FromLinkRegister("https", NewHTTP)
dialer.FromClashRegister("http", NewSocks5FromClashObj)
}
type HTTP struct {
@ -26,20 +25,12 @@ type HTTP struct {
Protocol string `json:"protocol"`
}
func NewHTTP(link string) (*dialer.Dialer, error) {
func NewHTTP(log *logrus.Logger, link string) (*dialer.Dialer, error) {
s, err := ParseHTTPURL(link)
if err != nil {
return nil, fmt.Errorf("%w: %v", dialer.InvalidParameterErr, err)
}
return s.Dialer()
}
func NewSocks5FromClashObj(o *yaml.Node) (*dialer.Dialer, error) {
s, err := ParseClash(o)
if err != nil {
return nil, err
}
return s.Dialer()
return s.Dialer(log)
}
func ParseHTTPURL(link string) (data *HTTP, err error) {
@ -71,46 +62,13 @@ func ParseHTTPURL(link string) (data *HTTP, err error) {
}, nil
}
func ParseClash(o *yaml.Node) (data *HTTP, err error) {
type HttpOption struct {
Name string `yaml:"name"`
Server string `yaml:"server"`
Port int `yaml:"port"`
UserName string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"`
TLS bool `yaml:"tls,omitempty"`
SNI string `yaml:"sni,omitempty"`
SkipCertVerify bool `yaml:"skip-cert-verify,omitempty"`
}
var option HttpOption
if err = o.Decode(&option); err != nil {
return nil, err
}
scheme := "http"
if option.TLS {
scheme = "https"
}
if option.SkipCertVerify {
return nil, fmt.Errorf("%w: skip-cert-verify=true", dialer.UnexpectedFieldErr)
}
return &HTTP{
Name: option.Name,
Server: option.Server,
Port: option.Port,
Username: option.UserName,
Password: option.Password,
SNI: option.SNI,
Protocol: scheme,
}, nil
}
func (s *HTTP) Dialer() (*dialer.Dialer, error) {
func (s *HTTP) Dialer(log *logrus.Logger) (*dialer.Dialer, error) {
u := s.URL()
d, err := http.NewHTTPProxy(&u, dialer.SymmetricDirect)
d, err := http.NewHTTPProxy(&u, dialer.SymmetricDirect) // HTTP Proxy does not support full-cone.
if err != nil {
return nil, err
}
return dialer.NewDialer(d, false, s.Name, s.Protocol, u.String()), nil
return dialer.NewDialer(d, log, false, s.Name, s.Protocol, u.String()), nil
}
func (s *HTTP) URL() url.URL {

View File

@ -7,11 +7,11 @@ package dialer
import (
"fmt"
"gopkg.in/yaml.v3"
"github.com/sirupsen/logrus"
"net/url"
)
type FromLinkCreator func(link string) (dialer *Dialer, err error)
type FromLinkCreator func(log *logrus.Logger, link string) (dialer *Dialer, err error)
var fromLinkCreators = make(map[string]FromLinkCreator)
@ -19,35 +19,14 @@ func FromLinkRegister(name string, creator FromLinkCreator) {
fromLinkCreators[name] = creator
}
func NewFromLink(link string) (dialer *Dialer, err error) {
func NewFromLink(log *logrus.Logger, link string) (dialer *Dialer, err error) {
u, err := url.Parse(link)
if err != nil {
return nil, err
}
if creator, ok := fromLinkCreators[u.Scheme]; ok {
return creator(link)
return creator(log, link)
} else {
return nil, fmt.Errorf("unexpected link type: %v", u.Scheme)
}
}
type FromClashCreator func(clashObj *yaml.Node) (dialer *Dialer, err error)
var fromClashCreators = make(map[string]FromClashCreator)
func FromClashRegister(name string, creator FromClashCreator) {
fromClashCreators[name] = creator
}
func NewFromClash(clashObj *yaml.Node) (dialer *Dialer, err error) {
preUnload := make(map[string]interface{})
if err := clashObj.Decode(&preUnload); err != nil {
return nil, err
}
name, _ := preUnload["type"].(string)
if creator, ok := fromClashCreators[name]; ok {
return creator(clashObj)
} else {
return nil, fmt.Errorf("unexpected link type: %v", name)
}
}

View File

@ -3,12 +3,12 @@ package shadowsocks
import (
"encoding/base64"
"fmt"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/component/outbound/dialer"
"github.com/v2rayA/dae/component/outbound/dialer/transport/simpleobfs"
"github.com/mzz2017/softwind/protocol"
"github.com/mzz2017/softwind/protocol/shadowsocks"
"gopkg.in/yaml.v3"
"github.com/sirupsen/logrus"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/component/outbound/dialer"
"github.com/v2rayA/dae/component/outbound/transport/simpleobfs"
"net"
"net/url"
"strconv"
@ -21,7 +21,6 @@ func init() {
dialer.FromLinkRegister("shadowsocks", NewShadowsocksFromLink)
dialer.FromLinkRegister("ss", NewShadowsocksFromLink)
dialer.FromClashRegister("ss", NewShadowsocksFromClashObj)
}
type Shadowsocks struct {
@ -35,23 +34,15 @@ type Shadowsocks struct {
Protocol string `json:"protocol"`
}
func NewShadowsocksFromLink(link string) (*dialer.Dialer, error) {
func NewShadowsocksFromLink(log *logrus.Logger, link string) (*dialer.Dialer, error) {
s, err := ParseSSURL(link)
if err != nil {
return nil, err
}
return s.Dialer()
return s.Dialer(log)
}
func NewShadowsocksFromClashObj(o *yaml.Node) (*dialer.Dialer, error) {
s, err := ParseClash(o)
if err != nil {
return nil, err
}
return s.Dialer()
}
func (s *Shadowsocks) Dialer() (*dialer.Dialer, error) {
func (s *Shadowsocks) Dialer(log *logrus.Logger) (*dialer.Dialer, error) {
// FIXME: support plain/none.
switch s.Cipher {
case "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305":
@ -59,7 +50,7 @@ func (s *Shadowsocks) Dialer() (*dialer.Dialer, error) {
return nil, fmt.Errorf("unsupported shadowsocks encryption method: %v", s.Cipher)
}
supportUDP := s.UDP
d := dialer.SymmetricDirect
d := dialer.FullconeDirect // Shadowsocks Proxy supports full-cone.
d, err := protocol.NewDialer("shadowsocks", d, protocol.Header{
ProxyAddress: net.JoinHostPort(s.Server, strconv.Itoa(s.Port)),
Cipher: s.Cipher,
@ -86,46 +77,7 @@ func (s *Shadowsocks) Dialer() (*dialer.Dialer, error) {
}
supportUDP = false
}
return dialer.NewDialer(d, supportUDP, s.Name, s.Protocol, s.ExportToURL()), nil
}
func ParseClash(o *yaml.Node) (data *Shadowsocks, err error) {
type simpleObfsOption struct {
Mode string `obfs:"mode,omitempty"`
Host string `obfs:"host,omitempty"`
}
type ShadowSocksOption struct {
Name string `yaml:"name"`
Server string `yaml:"server"`
Port int `yaml:"port"`
Password string `yaml:"password"`
Cipher string `yaml:"cipher"`
UDP bool `yaml:"udp,omitempty"`
Plugin string `yaml:"plugin,omitempty"`
PluginOpts simpleObfsOption `yaml:"plugin-opts,omitempty"`
}
var option ShadowSocksOption
if err = o.Decode(&option); err != nil {
return nil, err
}
data = &Shadowsocks{
Name: option.Name,
Server: option.Server,
Port: option.Port,
Password: option.Password,
Cipher: option.Cipher,
UDP: option.UDP,
Protocol: "shadowsocks",
}
if option.Plugin == "obfs" {
data.Plugin.Name = "simple-obfs"
data.Plugin.Opts.Obfs = option.PluginOpts.Mode
data.Plugin.Opts.Host = data.Plugin.Opts.Host
if data.Plugin.Opts.Host == "" {
data.Plugin.Opts.Host = "bing.com"
}
}
return data, nil
return dialer.NewDialer(d, log, supportUDP, s.Name, s.Protocol, s.ExportToURL()), nil
}
func ParseSSURL(u string) (data *Shadowsocks, err error) {

View File

@ -3,10 +3,10 @@ package shadowsocksr
import (
"encoding/base64"
"fmt"
"github.com/sirupsen/logrus"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/component/outbound/dialer"
ssr "github.com/v2rayA/shadowsocksR/client"
"gopkg.in/yaml.v3"
"net"
"net/url"
"strconv"
@ -16,7 +16,6 @@ import (
func init() {
dialer.FromLinkRegister("shadowsocksr", NewShadowsocksR)
dialer.FromLinkRegister("ssr", NewShadowsocksR)
dialer.FromClashRegister("ssr", NewShadowsocksRFromClashObj)
}
type ShadowsocksR struct {
@ -32,23 +31,15 @@ type ShadowsocksR struct {
Protocol string `json:"protocol"`
}
func NewShadowsocksR(link string) (*dialer.Dialer, error) {
func NewShadowsocksR(log *logrus.Logger, link string) (*dialer.Dialer, error) {
s, err := ParseSSRURL(link)
if err != nil {
return nil, err
}
return s.Dialer()
return s.Dialer(log)
}
func NewShadowsocksRFromClashObj(o *yaml.Node) (*dialer.Dialer, error) {
s, err := ParseClash(o)
if err != nil {
return nil, err
}
return s.Dialer()
}
func (s *ShadowsocksR) Dialer() (*dialer.Dialer, error) {
func (s *ShadowsocksR) Dialer(log *logrus.Logger) (*dialer.Dialer, error) {
u := url.URL{
Scheme: "ssr",
User: url.UserPassword(s.Cipher, s.Password),
@ -60,42 +51,11 @@ func (s *ShadowsocksR) Dialer() (*dialer.Dialer, error) {
"obfs_param": []string{s.ObfsParam},
}.Encode(),
}
d, err := ssr.NewSSR(u.String(), dialer.SymmetricDirect, nil)
d, err := ssr.NewSSR(u.String(), dialer.SymmetricDirect, nil) // SSR Proxy does not support full-cone.
if err != nil {
return nil, err
}
return dialer.NewDialer(d, false, s.Name, s.Protocol, s.ExportToURL()), nil
}
func ParseClash(o *yaml.Node) (data *ShadowsocksR, err error) {
type ShadowSocksROption struct {
Name string `yaml:"name"`
Server string `yaml:"server"`
Port int `yaml:"port"`
Password string `yaml:"password"`
Cipher string `yaml:"cipher"`
Obfs string `yaml:"obfs"`
ObfsParam string `yaml:"obfs-param,omitempty"`
Protocol string `yaml:"protocol"`
ProtocolParam string `yaml:"protocol-param,omitempty"`
UDP bool `yaml:"udp,omitempty"`
}
var option ShadowSocksROption
if err = o.Decode(&option); err != nil {
return nil, err
}
return &ShadowsocksR{
Name: option.Name,
Server: option.Server,
Port: option.Port,
Password: option.Password,
Cipher: option.Cipher,
Proto: option.Protocol,
ProtoParam: option.ProtocolParam,
Obfs: option.Obfs,
ObfsParam: option.ObfsParam,
Protocol: "shadowsocksr",
}, nil
return dialer.NewDialer(d, log, false, s.Name, s.Protocol, s.ExportToURL()), nil
}
func ParseSSRURL(u string) (data *ShadowsocksR, err error) {

View File

@ -2,10 +2,10 @@ package socks
import (
"fmt"
"github.com/sirupsen/logrus"
"github.com/v2rayA/dae/component/outbound/dialer"
//"github.com/mzz2017/softwind/protocol/socks4"
"github.com/mzz2017/softwind/protocol/socks5"
"gopkg.in/yaml.v3"
"net"
"net/url"
"strconv"
@ -16,7 +16,6 @@ func init() {
//dialer.FromLinkRegister("socks4", NewSocks)
//dialer.FromLinkRegister("socks4a", NewSocks)
dialer.FromLinkRegister("socks5", NewSocks)
dialer.FromClashRegister("socks5", NewSocks5FromClashObj)
}
type Socks struct {
@ -28,31 +27,23 @@ type Socks struct {
Protocol string `json:"protocol"`
}
func NewSocks(link string) (*dialer.Dialer, error) {
func NewSocks(log *logrus.Logger, link string) (*dialer.Dialer, error) {
s, err := ParseSocksURL(link)
if err != nil {
return nil, dialer.InvalidParameterErr
}
return s.Dialer()
return s.Dialer(log)
}
func NewSocks5FromClashObj(o *yaml.Node) (*dialer.Dialer, error) {
s, err := ParseClashSocks5(o)
if err != nil {
return nil, err
}
return s.Dialer()
}
func (s *Socks) Dialer() (*dialer.Dialer, error) {
func (s *Socks) Dialer(log *logrus.Logger) (*dialer.Dialer, error) {
link := s.ExportToURL()
switch s.Protocol {
case "", "socks", "socks5":
d, err := socks5.NewSocks5Dialer(link, dialer.FullconeDirectDialer)
d, err := socks5.NewSocks5Dialer(link, dialer.FullconeDirect) // Socks5 Proxy supports full-cone.
if err != nil {
return nil, err
}
return dialer.NewDialer(d, true, s.Name, s.Protocol, link), nil
return dialer.NewDialer(d, log, true, s.Name, s.Protocol, link), nil
//case "socks4", "socks4a":
// d, err := socks4.NewSocks4Dialer(link, &proxy.Direct{})
// if err != nil {
@ -64,37 +55,6 @@ func (s *Socks) Dialer() (*dialer.Dialer, error) {
}
}
func ParseClashSocks5(o *yaml.Node) (data *Socks, err error) {
type Socks5Option struct {
Name string `yaml:"name"`
Server string `yaml:"server"`
Port int `yaml:"port"`
UserName string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"`
TLS bool `yaml:"tls,omitempty"`
UDP bool `yaml:"udp,omitempty"`
SkipCertVerify bool `yaml:"skip-cert-verify,omitempty"`
}
var option Socks5Option
if err = o.Decode(&option); err != nil {
return nil, err
}
if option.TLS {
return nil, fmt.Errorf("%w: tls=true", dialer.UnexpectedFieldErr)
}
if option.SkipCertVerify {
return nil, fmt.Errorf("%w: skip-cert-verify=true", dialer.UnexpectedFieldErr)
}
return &Socks{
Name: option.Name,
Server: option.Server,
Port: option.Port,
Username: option.UserName,
Password: option.Password,
Protocol: "socks5",
}, nil
}
func ParseSocksURL(link string) (data *Socks, err error) {
u, err := url.Parse(link)
if err != nil {

View File

@ -2,13 +2,13 @@ package trojan
import (
"fmt"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/component/outbound/dialer"
"github.com/v2rayA/dae/component/outbound/dialer/transport/tls"
"github.com/v2rayA/dae/component/outbound/dialer/transport/ws"
"github.com/mzz2017/softwind/protocol"
"github.com/mzz2017/softwind/transport/grpc"
"gopkg.in/yaml.v3"
"github.com/sirupsen/logrus"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/component/outbound/dialer"
"github.com/v2rayA/dae/component/outbound/transport/tls"
"github.com/v2rayA/dae/component/outbound/transport/ws"
"net"
"net/url"
"strconv"
@ -18,7 +18,6 @@ import (
func init() {
dialer.FromLinkRegister("trojan", NewTrojan)
dialer.FromLinkRegister("trojan-go", NewTrojan)
dialer.FromClashRegister("trojan", NewTrojanFromClashObj)
}
type Trojan struct {
@ -36,24 +35,16 @@ type Trojan struct {
Protocol string `json:"protocol"`
}
func NewTrojan(link string) (*dialer.Dialer, error) {
func NewTrojan(log *logrus.Logger, link string) (*dialer.Dialer, error) {
s, err := ParseTrojanURL(link)
if err != nil {
return nil, err
}
return s.Dialer()
return s.Dialer(log)
}
func NewTrojanFromClashObj(o *yaml.Node) (*dialer.Dialer, error) {
s, err := ParseClash(o)
if err != nil {
return nil, err
}
return s.Dialer()
}
func (s *Trojan) Dialer() (*dialer.Dialer, error) {
d := dialer.SymmetricDirect
func (s *Trojan) Dialer(log *logrus.Logger) (*dialer.Dialer, error) {
d := dialer.FullconeDirect // Trojan Proxy supports full-cone.
u := url.URL{
Scheme: "tls",
Host: net.JoinHostPort(s.Server, strconv.Itoa(s.Port)),
@ -111,7 +102,7 @@ func (s *Trojan) Dialer() (*dialer.Dialer, error) {
}); err != nil {
return nil, err
}
return dialer.NewDialer(d, true, s.Name, s.Protocol, s.ExportToURL()), nil
return dialer.NewDialer(d, log, true, s.Name, s.Protocol, s.ExportToURL()), nil
}
func ParseTrojanURL(u string) (data *Trojan, err error) {
@ -160,53 +151,6 @@ func ParseTrojanURL(u string) (data *Trojan, err error) {
return data, nil
}
func ParseClash(o *yaml.Node) (data *Trojan, err error) {
type WSOptions struct {
Path string `yaml:"path,omitempty"`
Headers map[string]string `yaml:"headers,omitempty"`
MaxEarlyData int `yaml:"max-early-data,omitempty"`
EarlyDataHeaderName string `yaml:"early-data-header-name,omitempty"`
}
type GrpcOptions struct {
GrpcServiceName string `proxy:"grpc-service-name,omitempty"`
}
type TrojanOption struct {
Name string `yaml:"name"`
Server string `yaml:"server"`
Port int `yaml:"port"`
Password string `yaml:"password"`
ALPN []string `yaml:"alpn,omitempty"`
SNI string `yaml:"sni,omitempty"`
SkipCertVerify bool `yaml:"skip-cert-verify,omitempty"`
UDP bool `yaml:"udp,omitempty"`
Network string `yaml:"network,omitempty"`
GrpcOpts GrpcOptions `yaml:"grpc-opts,omitempty"`
WSOpts WSOptions `yaml:"ws-opts,omitempty"`
}
var option TrojanOption
if err = o.Decode(&option); err != nil {
return nil, err
}
proto := "trojan"
if option.Network != "" && option.Network != "origin" {
proto = "trojan-go"
}
return &Trojan{
Name: option.Name,
Server: option.Server,
Port: option.Port,
Password: option.Password,
Sni: option.SNI,
Type: option.Network,
Encryption: "",
Host: option.WSOpts.Headers["Host"],
Path: option.WSOpts.Path,
AllowInsecure: option.SkipCertVerify,
ServiceName: option.GrpcOpts.GrpcServiceName,
Protocol: proto,
}, nil
}
func (t *Trojan) ExportToURL() string {
u := &url.URL{
Scheme: "trojan",

View File

@ -3,25 +3,24 @@ package v2ray
import (
"encoding/base64"
"fmt"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/component/outbound/dialer"
"github.com/v2rayA/dae/component/outbound/dialer/transport/tls"
"github.com/v2rayA/dae/component/outbound/dialer/transport/ws"
jsoniter "github.com/json-iterator/go"
"github.com/mzz2017/softwind/protocol"
"github.com/mzz2017/softwind/transport/grpc"
"gopkg.in/yaml.v3"
"github.com/sirupsen/logrus"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/component/outbound/dialer"
"github.com/v2rayA/dae/component/outbound/transport/tls"
"github.com/v2rayA/dae/component/outbound/transport/ws"
"golang.org/x/net/proxy"
"net"
"net/url"
"regexp"
"strconv"
"strings"
)
func init() {
dialer.FromLinkRegister("vmess", NewV2Ray)
dialer.FromLinkRegister("vless", NewV2Ray)
dialer.FromClashRegister("vmess", NewVMessFromClashObj)
}
type V2Ray struct {
@ -43,7 +42,7 @@ type V2Ray struct {
Protocol string `json:"protocol"`
}
func NewV2Ray(link string) (*dialer.Dialer, error) {
func NewV2Ray(log *logrus.Logger, link string) (*dialer.Dialer, error) {
var (
s *V2Ray
err error
@ -65,21 +64,19 @@ func NewV2Ray(link string) (*dialer.Dialer, error) {
default:
return nil, dialer.InvalidParameterErr
}
return s.Dialer()
return s.Dialer(log)
}
func NewVMessFromClashObj(o *yaml.Node) (*dialer.Dialer, error) {
s, err := ParseClashVMess(o)
if err != nil {
return nil, err
func (s *V2Ray) Dialer(log *logrus.Logger) (data *dialer.Dialer, err error) {
var d proxy.Dialer
switch s.Protocol {
case "vmess":
d = dialer.FullconeDirect // VMess Proxy supports full-cone.
case "vless":
d = dialer.SymmetricDirect // VLESS Proxy does not yet support full-cone by softwind.
default:
return nil, fmt.Errorf("V2Ray.Dialer: unexpected protocol: %v", s.Protocol)
}
return s.Dialer()
}
func (s *V2Ray) Dialer() (data *dialer.Dialer, err error) {
var (
d = dialer.SymmetricDirect
)
switch strings.ToLower(s.Net) {
case "ws":
@ -151,91 +148,9 @@ func (s *V2Ray) Dialer() (data *dialer.Dialer, err error) {
}); err != nil {
return nil, err
}
return dialer.NewDialer(d, true, s.Ps, s.Protocol, s.ExportToURL()), nil
return dialer.NewDialer(d, log, true, s.Ps, s.Protocol, s.ExportToURL()), nil
}
func ParseClashVMess(o *yaml.Node) (data *V2Ray, err error) {
type WSOptions struct {
Path string `yaml:"path,omitempty"`
Headers map[string]string `yaml:"headers,omitempty"`
MaxEarlyData int `yaml:"max-early-data,omitempty"`
EarlyDataHeaderName string `yaml:"early-data-header-name,omitempty"`
}
type GrpcOptions struct {
GrpcServiceName string `proxy:"grpc-service-name,omitempty"`
}
type HTTP2Options struct {
Host []string `proxy:"host,omitempty"`
Path string `proxy:"path,omitempty"`
}
type VmessOption struct {
Name string `yaml:"name"`
Server string `yaml:"server"`
Port int `yaml:"port"`
UUID string `yaml:"uuid"`
AlterID int `yaml:"alterId"`
Cipher string `yaml:"cipher"`
UDP bool `yaml:"udp,omitempty"`
Network string `yaml:"network,omitempty"`
TLS bool `yaml:"tls,omitempty"`
SkipCertVerify bool `yaml:"skip-cert-verify,omitempty"`
ServerName string `yaml:"servername,omitempty"`
HTTPOpts interface{} `yaml:"http-opts,omitempty"`
HTTP2Opts HTTP2Options `yaml:"h2-opts,omitempty"`
GrpcOpts GrpcOptions `yaml:"grpc-opts,omitempty"`
WSOpts WSOptions `yaml:"ws-opts,omitempty"`
}
var option VmessOption
if err = o.Decode(&option); err != nil {
return nil, err
}
if option.Network == "" {
option.Network = "tcp"
}
var (
path string
host string
alpn string
)
switch option.Network {
case "ws":
path = option.WSOpts.Path
host = option.WSOpts.Headers["Host"]
alpn = "http/1.1"
case "grpc":
path = option.GrpcOpts.GrpcServiceName
case "h2":
host = strings.Join(option.HTTP2Opts.Host, ",")
path = option.HTTP2Opts.Path
alpn = "h2"
case "http":
// TODO
}
s := &V2Ray{
Ps: option.Name,
Add: option.Server,
Port: strconv.Itoa(option.Port),
ID: option.UUID,
Aid: strconv.Itoa(option.AlterID),
Net: option.Network,
Type: "none", // FIXME
Host: host,
SNI: option.ServerName,
Path: path,
AllowInsecure: false,
Alpn: alpn,
V: "2",
Protocol: "vmess",
}
if option.SkipCertVerify {
return nil, fmt.Errorf("%w: skip-cert-verify=true", dialer.UnexpectedFieldErr)
}
if option.TLS {
s.TLS = "tls"
}
return s, nil
}
func ParseVlessURL(vless string) (data *V2Ray, err error) {
u, err := url.Parse(vless)
if err != nil {

View File

@ -7,9 +7,9 @@ package outbound
import (
"fmt"
"github.com/sirupsen/logrus"
"github.com/v2rayA/dae/common/consts"
"github.com/v2rayA/dae/component/outbound/dialer"
"github.com/sirupsen/logrus"
"golang.org/x/net/proxy"
"net"
)
@ -21,6 +21,7 @@ type DialerSelectionPolicy struct {
type DialerGroup struct {
proxy.Dialer
block *dialer.Dialer
log *logrus.Logger
Name string
@ -58,6 +59,7 @@ func NewDialerGroup(log *logrus.Logger, name string, dialers []*dialer.Dialer, p
log: log,
Name: name,
Dialers: dialers,
block: dialer.NewBlockDialer(log),
AliveDialerSet: a,
registeredAliveDialerSet: registeredAliveDialerSet,
selectionPolicy: &p,
@ -89,9 +91,8 @@ func (g *DialerGroup) Select() (*dialer.Dialer, error) {
d := g.AliveDialerSet.GetRand()
if d == nil {
// No alive dialer.
// TODO: Should we throw an error to block the connection in this condition?
g.log.Warnf("No alive dialer in DialerGroup %v, use DIRECT. It may cause IP leaking.", g.Name)
return dialer.FullconeDirectDialer, nil
g.log.Warnf("No alive dialer in DialerGroup %v, use \"block\".", g.Name)
return g.block, nil
}
return d, nil
@ -105,9 +106,8 @@ func (g *DialerGroup) Select() (*dialer.Dialer, error) {
d := g.AliveDialerSet.GetMinLatency()
if d == nil {
// No alive dialer.
// TODO: Should we throw an error to block the connection in this condition?
g.log.Warnf("No alive dialer in DialerGroup %v, use DIRECT. It may cause IP leaking.", g.Name)
return dialer.FullconeDirectDialer, nil
g.log.Warnf("No alive dialer in DialerGroup %v, use \"block\".", g.Name)
return g.block, nil
}
return d, nil

View File

@ -6,10 +6,10 @@
package outbound
import (
"github.com/mzz2017/softwind/pkg/fastrand"
"github.com/v2rayA/dae/common/consts"
"github.com/v2rayA/dae/component/outbound/dialer"
"github.com/v2rayA/dae/pkg/logger"
"github.com/mzz2017/softwind/pkg/fastrand"
"testing"
"time"
)
@ -17,8 +17,8 @@ import (
func TestDialerGroup_Select_Fixed(t *testing.T) {
log := logger.NewLogger(2)
dialers := []*dialer.Dialer{
dialer.SymmetricDirectDialer,
dialer.FullconeDirectDialer,
dialer.NewDirectDialer(log, true),
dialer.NewDirectDialer(log, false),
}
fixedIndex := 1
g := NewDialerGroup(log, "test-group", dialers, DialerSelectionPolicy{
@ -51,16 +51,16 @@ func TestDialerGroup_Select_Fixed(t *testing.T) {
func TestDialerGroup_Select_MinLastLatency(t *testing.T) {
log := logger.NewLogger(2)
dialers := []*dialer.Dialer{
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
}
g := NewDialerGroup(log, "test-group", dialers, DialerSelectionPolicy{
Policy: consts.DialerSelectionPolicy_MinLastLatency,
@ -114,11 +114,11 @@ func TestDialerGroup_Select_MinLastLatency(t *testing.T) {
func TestDialerGroup_Select_Random(t *testing.T) {
log := logger.NewLogger(2)
dialers := []*dialer.Dialer{
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
}
g := NewDialerGroup(log, "test-group", dialers, DialerSelectionPolicy{
Policy: consts.DialerSelectionPolicy_Random,
@ -147,11 +147,11 @@ func TestDialerGroup_Select_Random(t *testing.T) {
func TestDialerGroup_SetAlive(t *testing.T) {
log := logger.NewLogger(2)
dialers := []*dialer.Dialer{
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDialer(dialer.SymmetricDirect, true, "direct", "direct", ""),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
dialer.NewDirectDialer(log, false),
}
g := NewDialerGroup(log, "test-group", dialers, DialerSelectionPolicy{
Policy: consts.DialerSelectionPolicy_Random,

View File

@ -6,14 +6,14 @@
package outbound
import (
_ "github.com/mzz2017/softwind/protocol/shadowsocks"
_ "github.com/mzz2017/softwind/protocol/trojanc"
_ "github.com/mzz2017/softwind/protocol/vless"
_ "github.com/mzz2017/softwind/protocol/vmess"
_ "github.com/v2rayA/dae/component/outbound/dialer/http"
_ "github.com/v2rayA/dae/component/outbound/dialer/shadowsocks"
_ "github.com/v2rayA/dae/component/outbound/dialer/shadowsocksr"
_ "github.com/v2rayA/dae/component/outbound/dialer/socks"
_ "github.com/v2rayA/dae/component/outbound/dialer/trojan"
_ "github.com/v2rayA/dae/component/outbound/dialer/v2ray"
_ "github.com/mzz2017/softwind/protocol/shadowsocks"
_ "github.com/mzz2017/softwind/protocol/trojanc"
_ "github.com/mzz2017/softwind/protocol/vless"
_ "github.com/mzz2017/softwind/protocol/vmess"
)

View File

@ -19,14 +19,14 @@ type MatcherBuilder interface {
AddDomain(key string, values []string, outbound string)
AddIp(values []netip.Prefix, outbound string)
AddPort(values [][2]int, outbound string)
AddSource(values []netip.Prefix, outbound string)
AddSourceIp(values []netip.Prefix, outbound string)
AddSourcePort(values [][2]int, outbound string)
AddL4Proto(values consts.L4ProtoType, outbound string)
AddIpVersion(values consts.IpVersion, outbound string)
AddMac(values [][6]byte, outbound string)
AddSourceMac(values [][6]byte, outbound string)
AddFinal(outbound string)
AddAnyBefore(key string, values []string, outbound string)
AddAnyAfter(key string, values []string, outbound string)
AddAnyBefore(function string, key string, values []string, outbound string)
AddAnyAfter(function string, key string, values []string, outbound string)
Build() (err error)
}
@ -65,7 +65,7 @@ func ApplyMatcherBuilder(builder MatcherBuilder, rules []RoutingRule, finalOutbo
if iFunc == len(rule.AndFunctions)-1 {
outbound = rule.Outbound
}
builder.AddAnyBefore(key, paramValueGroup, outbound)
builder.AddAnyBefore(f.Name, key, paramValueGroup, outbound)
switch f.Name {
case consts.Function_Domain:
builder.AddDomain(key, paramValueGroup, outbound)
@ -77,7 +77,7 @@ func ApplyMatcherBuilder(builder MatcherBuilder, rules []RoutingRule, finalOutbo
if f.Name == consts.Function_Ip {
builder.AddIp(cidrs, outbound)
} else {
builder.AddSource(cidrs, outbound)
builder.AddSourceIp(cidrs, outbound)
}
case consts.Function_Mac:
var macAddrs [][6]byte
@ -88,7 +88,7 @@ func ApplyMatcherBuilder(builder MatcherBuilder, rules []RoutingRule, finalOutbo
}
macAddrs = append(macAddrs, mac)
}
builder.AddMac(macAddrs, outbound)
builder.AddSourceMac(macAddrs, outbound)
case consts.Function_Port, consts.Function_SourcePort:
var portRanges [][2]int
for _, v := range paramValueGroup {
@ -128,27 +128,29 @@ func ApplyMatcherBuilder(builder MatcherBuilder, rules []RoutingRule, finalOutbo
default:
return fmt.Errorf("unsupported function name: %v", f.Name)
}
builder.AddAnyAfter(key, paramValueGroup, outbound)
builder.AddAnyAfter(f.Name, key, paramValueGroup, outbound)
}
}
}
builder.AddAnyBefore("", nil, finalOutbound)
builder.AddAnyBefore("final", "", nil, finalOutbound)
builder.AddFinal(finalOutbound)
builder.AddAnyAfter("", nil, finalOutbound)
builder.AddAnyAfter("final", "", nil, finalOutbound)
return nil
}
type DefaultMatcherBuilder struct{}
func (d *DefaultMatcherBuilder) AddDomain(values []string, outbound string) {}
func (d *DefaultMatcherBuilder) AddIp(values []netip.Prefix, outbound string) {}
func (d *DefaultMatcherBuilder) AddPort(values [][2]int, outbound string) {}
func (d *DefaultMatcherBuilder) AddSource(values []netip.Prefix, outbound string) {}
func (d *DefaultMatcherBuilder) AddSourcePort(values [][2]int, outbound string) {}
func (d *DefaultMatcherBuilder) AddL4Proto(values consts.L4ProtoType, outbound string) {}
func (d *DefaultMatcherBuilder) AddIpVersion(values consts.IpVersion, outbound string) {}
func (d *DefaultMatcherBuilder) AddMac(values [][6]byte, outbound string) {}
func (d *DefaultMatcherBuilder) AddFinal(outbound string) {}
func (d *DefaultMatcherBuilder) AddAnyBefore(key string, values []string, outbound string) {}
func (d *DefaultMatcherBuilder) AddAnyAfter(key string, values []string, outbound string) {}
func (d *DefaultMatcherBuilder) Build() (err error) { return nil }
func (d *DefaultMatcherBuilder) AddDomain(values []string, outbound string) {}
func (d *DefaultMatcherBuilder) AddIp(values []netip.Prefix, outbound string) {}
func (d *DefaultMatcherBuilder) AddPort(values [][2]int, outbound string) {}
func (d *DefaultMatcherBuilder) AddSource(values []netip.Prefix, outbound string) {}
func (d *DefaultMatcherBuilder) AddSourcePort(values [][2]int, outbound string) {}
func (d *DefaultMatcherBuilder) AddL4Proto(values consts.L4ProtoType, outbound string) {}
func (d *DefaultMatcherBuilder) AddIpVersion(values consts.IpVersion, outbound string) {}
func (d *DefaultMatcherBuilder) AddMac(values [][6]byte, outbound string) {}
func (d *DefaultMatcherBuilder) AddFinal(outbound string) {}
func (d *DefaultMatcherBuilder) AddAnyBefore(function string, key string, values []string, outbound string) {
}
func (d *DefaultMatcherBuilder) AddAnyAfter(function string, key string, values []string, outbound string) {
}
func (d *DefaultMatcherBuilder) Build() (err error) { return nil }

View File

@ -184,7 +184,7 @@ func (s *RoutingAWalker) EnterDeclaration(ctx *routingA.DeclarationContext) {
switch valueCtx := children[2].(type) {
case *routingA.LiteralContext:
value := getValueFromLiteral(valueCtx)
if key == "default" {
if key == consts.Declaration_Final {
s.FinalOutbound = value
} else {
s.ReportError(ctx, ErrorType_Unsupported)
@ -201,6 +201,7 @@ func (s *RoutingAWalker) EnterDeclaration(ctx *routingA.DeclarationContext) {
func (s *RoutingAWalker) EnterRoutingRule(ctx *routingA.RoutingRuleContext) {
children := ctx.GetChildren()
//logrus.Debugln(ctx.GetText(), children)
left, ok := children[0].(*routingA.RoutingRuleLeftContext)
if !ok {
s.ReportError(ctx, ErrorType_Unsupported, "not *RoutingRuleLeftContext: "+ctx.GetText())

254
config/bind.go Normal file
View File

@ -0,0 +1,254 @@
package config
import (
"fmt"
"github.com/spf13/viper"
"reflect"
"strconv"
"strings"
)
var (
ErrRequired = fmt.Errorf("required")
ErrMutualReference = fmt.Errorf("mutual reference or invalid value")
ErrOverlayHierarchicalKey = fmt.Errorf("overlay hierarchical key")
)
type Binder struct {
viper *viper.Viper
toResolve map[string]string
resolved map[string]interface{}
}
func MustGetMapKeys(m interface{}) (keys []string) {
v := reflect.ValueOf(m)
vKeys := v.MapKeys()
for _, k := range vKeys {
keys = append(keys, k.String())
}
return keys
}
func NewBinder(viper *viper.Viper) *Binder {
return &Binder{
viper: viper,
toResolve: make(map[string]string),
resolved: make(map[string]interface{}),
}
}
func (b *Binder) Bind(iface interface{}) error {
if err := b.bind(iface); err != nil {
return err
}
for len(b.toResolve) > 0 {
var changed bool
for key, expr := range b.toResolve {
ok, err := b.bindKey(key, expr)
if err != nil {
return err
}
if ok {
changed = true
if err := SetValueHierarchicalMap(b.resolved, key, b.viper.Get(key)); err != nil {
return fmt.Errorf("%w: %v", err, key)
}
delete(b.toResolve, key)
}
}
if !changed {
return fmt.Errorf("%v: %w", strings.Join(MustGetMapKeys(b.toResolve), ", "), ErrMutualReference)
}
}
return nil
}
func (b *Binder) bind(iface interface{}, parts ...string) error {
// https://github.com/spf13/viper/issues/188
ifv := reflect.ValueOf(iface)
ift := reflect.TypeOf(iface)
nextField:
for i := 0; i < ift.NumField(); i++ {
v := ifv.Field(i)
t := ift.Field(i)
tv, ok := t.Tag.Lookup("mapstructure")
if !ok {
continue
}
fields := strings.Split(tv, ",")
tv = fields[0]
switch v.Kind() {
case reflect.Struct:
if err := b.bind(v.Interface(), append(parts, tv)...); err != nil {
return err
}
default:
key := strings.Join(append(parts, tv), ".")
if b.viper.Get(key) == nil {
if defaultValue, ok := t.Tag.Lookup("default"); ok {
ok, err := b.bindKey(key, defaultValue)
if err != nil {
return err
}
if !ok {
b.toResolve[key] = defaultValue
continue nextField
}
} else if _, ok := t.Tag.Lookup("required"); ok {
if desc, ok := t.Tag.Lookup("desc"); ok {
key += " (" + desc + ")"
}
return fmt.Errorf("%w: %v", ErrRequired, key)
} else if len(fields) == 1 || fields[1] != "omitempty" {
// write an empty value
b.viper.Set(key, "")
}
}
if err := SetValueHierarchicalMap(b.resolved, key, b.viper.Get(key)); err != nil {
return fmt.Errorf("%w: %v", err, key)
}
}
}
return nil
}
func (b *Binder) bindKey(key string, expr string) (ok bool, err error) {
b.viper.Set(key, expr)
return true, nil
}
func SetValueHierarchicalMap(m map[string]interface{}, key string, val interface{}) error {
keys := strings.Split(key, ".")
lastKey := keys[len(keys)-1]
keys = keys[:len(keys)-1]
p := &m
for _, key := range keys {
if v, ok := (*p)[key]; ok {
vv, ok := v.(map[string]interface{})
if !ok {
return ErrOverlayHierarchicalKey
}
p = &vv
} else {
(*p)[key] = make(map[string]interface{})
vv := (*p)[key].(map[string]interface{})
p = &vv
}
}
(*p)[lastKey] = val
return nil
}
func SetValueHierarchicalStruct(m interface{}, key string, val string) error {
ifv, err := GetValueHierarchicalStruct(m, key)
if err != nil {
return err
}
if !FuzzyDecode(ifv.Addr().Interface(), val) {
return fmt.Errorf("type does not match: type \"%v\" and value \"%v\"", ifv.Kind(), val)
}
return nil
}
func GetValueHierarchicalStruct(m interface{}, key string) (reflect.Value, error) {
keys := strings.Split(key, ".")
ifv := reflect.Indirect(reflect.ValueOf(m))
ift := ifv.Type()
lastK := ""
for _, k := range keys {
found := false
if ift.Kind() == reflect.Struct {
for i := 0; i < ifv.NumField(); i++ {
name, ok := ift.Field(i).Tag.Lookup("mapstructure")
if ok && name == k {
found = true
ifv = ifv.Field(i)
ift = ifv.Type()
lastK = k
break
}
}
}
if !found {
return reflect.Value{}, fmt.Errorf(`unexpected key "%v": "%v" (%v type) has no member "%v"`, key, lastK, ift.Kind().String(), k)
}
}
return ifv, nil
}
func FuzzyDecode(to interface{}, val string) bool {
v := reflect.Indirect(reflect.ValueOf(to))
switch v.Kind() {
case reflect.Int:
i, err := strconv.ParseInt(val, 10, strconv.IntSize)
if err != nil {
return false
}
v.SetInt(i)
case reflect.Int8:
i, err := strconv.ParseInt(val, 10, 8)
if err != nil {
return false
}
v.SetInt(i)
case reflect.Int16:
i, err := strconv.ParseInt(val, 10, 16)
if err != nil {
return false
}
v.SetInt(i)
case reflect.Int32:
i, err := strconv.ParseInt(val, 10, 32)
if err != nil {
return false
}
v.SetInt(i)
case reflect.Int64:
i, err := strconv.ParseInt(val, 10, 64)
if err != nil {
return false
}
v.SetInt(i)
case reflect.Uint:
i, err := strconv.ParseUint(val, 10, strconv.IntSize)
if err != nil {
return false
}
v.SetUint(i)
case reflect.Uint8:
i, err := strconv.ParseUint(val, 10, 8)
if err != nil {
return false
}
v.SetUint(i)
case reflect.Uint16:
i, err := strconv.ParseUint(val, 10, 16)
if err != nil {
return false
}
v.SetUint(i)
case reflect.Uint32:
i, err := strconv.ParseUint(val, 10, 32)
if err != nil {
return false
}
v.SetUint(i)
case reflect.Uint64:
i, err := strconv.ParseUint(val, 10, 64)
if err != nil {
return false
}
v.SetUint(i)
case reflect.Bool:
if val == "true" || val == "1" {
v.SetBool(true)
} else if val == "false" || val == "0" {
v.SetBool(false)
} else {
return false
}
case reflect.String:
v.SetString(val)
}
return true
}

26
config/config.go Normal file
View File

@ -0,0 +1,26 @@
package config
type Subscription struct {
Link string `mapstructure:"link"`
Select string `mapstructure:"select" default:"first"`
CacheLastNode bool `mapstructure:"cache_last_node" default:"true"`
}
type Cache struct {
Subscription CacheSubscription `mapstructure:"subscription"`
}
type CacheSubscription struct {
LastNode string `mapstructure:"last_node"`
}
type Params struct {
Node string `mapstructure:"node"`
Subscription Subscription `mapstructure:"subscription"`
Cache Cache `mapstructure:"cache"`
NoUDP bool `mapstructure:"no_udp"`
TestNode bool `mapstructure:"test_node_before_use" default:"true"`
TestURL string `mapstructure:"test_url" default:"https://connectivitycheck.gstatic.com/generate_204"`
}
var ParamsObj Params

34
go.mod
View File

@ -5,20 +5,21 @@ go 1.19
require (
github.com/adrg/xdg v0.4.0
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12
github.com/cilium/ebpf v0.9.3
github.com/cilium/ebpf v0.10.0
github.com/gorilla/websocket v1.5.0
github.com/json-iterator/go v1.1.12
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/mzz2017/softwind v0.0.0-20230124072602-aabc556ba332
github.com/sirupsen/logrus v1.9.0
github.com/v2fly/v2ray-core/v5 v5.2.1
github.com/v2rayA/RoutingA-dist/go/routingA v0.0.0-20230124054934-e2204d89186f
github.com/spf13/cobra v1.6.1
github.com/spf13/viper v1.15.0
github.com/v2rayA/RoutingA-dist/go/routingA v0.0.0-20230124191403-ef9c0530cb53
github.com/v2rayA/dae-config-dist/go/dae_config v0.0.0-20230126180746-eae2d0e30c27
github.com/v2rayA/shadowsocksR v1.0.4
github.com/vishvananda/netlink v1.1.0
golang.org/x/net v0.5.0
golang.org/x/sys v0.4.0
google.golang.org/protobuf v1.28.1
gopkg.in/yaml.v3 v3.0.1
)
require (
@ -27,19 +28,36 @@ require (
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 // indirect
github.com/dgryski/go-rc2 v0.0.0-20150621095337-8a9021637152 // indirect
github.com/eknkc/basex v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mzz2017/disk-bloom v1.0.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
gitlab.com/yawning/chacha20.git v0.0.0-20190903091407-6d1cb28dc72c // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/text v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71 // indirect
google.golang.org/grpc v1.51.0 // indirect
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect
google.golang.org/grpc v1.52.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
//replace github.com/mzz2017/softwind => /home/mzz/goProjects/softwind
replace github.com/mzz2017/softwind => /home/mzz/goProjects/softwind
//replace github.com/cilium/ebpf => /home/mzz/goProjects/ebpf
//replace github.com/v2rayA/RoutingA-dist/go/routingA => /home/mzz/antlrProjects/RoutingA-antlr4/build/go/routingA
//replace github.com/v2rayA/dae-config-dist/go/dae_config => /home/mzz/antlrProjects/dae-config/build/go/dae_config

417
go.sum
View File

@ -1,20 +1,58 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cilium/ebpf v0.9.3 h1:5KtxXZU+scyERvkJMEm16TbScVvuuMrlhPly78ZMbSc=
github.com/cilium/ebpf v0.9.3/go.mod h1:w27N4UjpaQ9X/DGrSugxUG+H+NhgntDuPb5lCzxCn8A=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ=
github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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=
@ -33,16 +71,32 @@ github.com/eknkc/basex v1.0.1/go.mod h1:k/F/exNEHFdbs3ZHuasoP2E7zeWwZblG84Y7Z59v
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@ -54,61 +108,122 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mzz2017/disk-bloom v1.0.1 h1:rEF9MiXd9qMW3ibRpqcerLXULoTgRlM21yqqJl1B90M=
github.com/mzz2017/disk-bloom v1.0.1/go.mod h1:JLHETtUu44Z6iBmsqzkOtFlRvXSlKnxjwiBRDapizDI=
github.com/mzz2017/softwind v0.0.0-20230124072602-aabc556ba332 h1:wIHkkJcBo3ln0cdl607LAg+O8yj7oLQ3FIlBhLfWxUo=
github.com/mzz2017/softwind v0.0.0-20230124072602-aabc556ba332/go.mod h1:K1nXwtBokwEsfOfdT/5zV6R8QabGkyhcR0iuTrRZcYY=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/v2fly/v2ray-core/v5 v5.2.1 h1:bWc0cxvzCbbcsIE7/C+NFeUytQJYWgjtcRMG242I2Rs=
github.com/v2fly/v2ray-core/v5 v5.2.1/go.mod h1:7MBSerlH+Wyq9Bvm90txc8Ey9C9MAwkM+ZtkMbKT0Zo=
github.com/v2rayA/RoutingA-dist/go/routingA v0.0.0-20230124054934-e2204d89186f h1:qmnamMCAaJbGw+XtQJfTGtL3gm7+7dYMY8neh+MTUkE=
github.com/v2rayA/RoutingA-dist/go/routingA v0.0.0-20230124054934-e2204d89186f/go.mod h1:BGhPbUF5jE2YhQiomx2F48N2lVNppcAlNCGfVhf5Lx4=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/v2rayA/RoutingA-dist/go/routingA v0.0.0-20230124191403-ef9c0530cb53 h1:seZfccOo70jrXD4LZAvM7AbW6IFXY2r230GgV7tsnro=
github.com/v2rayA/RoutingA-dist/go/routingA v0.0.0-20230124191403-ef9c0530cb53/go.mod h1:BGhPbUF5jE2YhQiomx2F48N2lVNppcAlNCGfVhf5Lx4=
github.com/v2rayA/dae-config-dist/go/dae_config v0.0.0-20230126180746-eae2d0e30c27 h1:IXDCb9A8PBdB+bBMVdCBP3c61DzUqLYQ4lb6tw8RXOo=
github.com/v2rayA/dae-config-dist/go/dae_config v0.0.0-20230126180746-eae2d0e30c27/go.mod h1:JiTWeZybOkBfCqv/fy5jbFhXTxuLlyrI76gRNazz2sU=
github.com/v2rayA/shadowsocksR v1.0.4 h1:65Ltdy+I/DnlkQTJj+R+X85zhZ63ORE1Roy+agAcF/s=
github.com/v2rayA/shadowsocksR v1.0.4/go.mod h1:CyOhDLy8/AKedsi16xRYAMmkxSCH1ukJPaacaTdRfQg=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
@ -116,97 +231,306 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
gitlab.com/yawning/chacha20.git v0.0.0-20190903091407-6d1cb28dc72c h1:yrfrd1u7MWIwWIulet2TZPEkeNQhQ/GcPLdPXgiEEr0=
gitlab.com/yawning/chacha20.git v0.0.0-20190903091407-6d1cb28dc72c/go.mod h1:3x6b94nWCP/a2XB/joOPMiGYUBvqbLfeY/BkHLeDs6s=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71 h1:z+ErRPu0+KS02Td3fOAgdX+lnPDh/VyaABEJPD4JRQs=
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY=
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk=
google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -215,20 +539,31 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@ -5,11 +5,13 @@ sudo tc qdisc add dev $dev clsact > /dev/null 2>&1
set -ex
# clang -fno-stack-protector -O2 -g -emit-llvm -c component/control/kern/tproxy.c -o - | llc -march=bpf -mcpu=probe -filetype=obj -o foo.o
sudo rm -rf /sys/fs/bpf/tc/globals/*
# clang -fno-stack-protector -O2 -g -emit-llvm -c component/control/kern/tproxy.c -o - | llc -march=bpf -mcpu=v3 -filetype=obj -o foo.o
clang -O2 -g -Wall -Werror -c component/control/kern/tproxy.c -target bpf -o foo.o
sudo tc filter del dev $dev ingress
sudo tc filter add dev $dev ingress bpf direct-action obj foo.o sec tc/ingress
sudo tc filter del dev $dev egress
sudo tc filter add dev $dev ingress bpf direct-action obj foo.o sec tc/ingress
sudo tc filter add dev $dev egress bpf direct-action obj foo.o sec tc/egress
exit 0

52
main.go
View File

@ -8,51 +8,19 @@
package main
import (
"github.com/sirupsen/logrus"
"github.com/v2rayA/dae/component/control"
"github.com/v2rayA/dae/pkg/logger"
"github.com/json-iterator/go/extra"
"github.com/v2rayA/dae/cmd"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
const (
tproxyPort = 12345
ifname = "docker0"
)
logrus.SetLevel(logrus.DebugLevel)
log := logger.NewLogger(2)
log.Println("Running")
t, err := control.NewControlPlane(log, `
default:proxy
#sip(172.17.0.2)->proxy
#mac("02:42:ac:11:00:02")->proxy
#ipversion(4)->proxy
#l4proto(tcp)->proxy
ip(119.29.29.29) -> proxy
ip(223.5.5.5) -> direct
ip(geoip:cn) -> direct
domain(geosite:cn, suffix:"ip.sb") -> direct
ip("91.105.192.0/23","91.108.4.0/22","91.108.8.0/21","91.108.16.0/21","91.108.56.0/22","95.161.64.0/20","149.154.160.0/20","185.76.151.0/24")->proxy
domain(geosite:category-scholar-!cn, geosite:category-scholar-cn)->direct
`)
if err != nil {
panic(err)
}
if err = t.BindLink(ifname); err != nil {
panic(err)
}
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGILL)
go func() {
if err := t.ListenAndServe(tproxyPort); err != nil {
log.Errorln("ListenAndServe:", err)
sigs <- nil
}
}()
<-sigs
if e := t.Close(); e != nil {
log.Errorln("Close control plane:", err)
extra.RegisterFuzzyDecoders()
http.DefaultClient.Timeout = 30 * time.Second
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
os.Exit(0)
}

View File

@ -0,0 +1,34 @@
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) since 2023, mzz2017 (mzz@tuta.io). All rights reserved.
*/
package config_parser
import (
"fmt"
"github.com/antlr/antlr4/runtime/Go/antlr/v4"
"github.com/v2rayA/dae-config-dist/go/dae_config"
)
func Parse(in string) (sections []*Section, err error) {
errorListener := NewConsoleErrorListener()
lexer := dae_config.Newdae_configLexer(antlr.NewInputStream(in))
lexer.RemoveErrorListeners()
lexer.AddErrorListener(errorListener)
input := antlr.NewCommonTokenStream(lexer, 0)
parser := dae_config.Newdae_configParser(input)
parser.RemoveErrorListeners()
parser.AddErrorListener(errorListener)
parser.BuildParseTrees = true
tree := parser.Start()
walker := NewWalker(parser)
antlr.ParseTreeWalkerDefault.Walk(walker, tree)
if errorListener.ErrorBuilder.Len() != 0 {
return nil, fmt.Errorf("%v", errorListener.ErrorBuilder.String())
}
return walker.Sections, nil
}

View File

@ -0,0 +1,91 @@
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) since 2023, mzz2017 (mzz@tuta.io). All rights reserved.
*/
package config_parser
import "testing"
func TestParse(t *testing.T) {
sections, err := Parse(`
# gugu
include {
another.conf
}
global {
# tproxy port to listen.
tproxy_port: 12345
# Node connectivity check url.
check_url: 'https://connectivitycheck.gstatic.com/generate_204'
# Now only support UDP and IP:Port.
# Please make sure DNS traffic will go through and be forwarded by dae.
dns_upstream: '1.1.1.1:53'
# Now only support one interface.
ingress_interface: docker0
}
# subscription will be resolved as nodes and merged into node pool below.
subscription {
https://LINK
}
node {
'ss://LINK'
'ssr://LINK'
'vmess://LINK'
'vless://LINK'
'trojan://LINK'
'trojan-go://LINK'
'socks5://LINK#name'
'http://LINK#name'
'https://LINK#name'
}
group {
my_group {
# Pass node links as input of lua script filter.
# gugu
filter: link(lua:filename.lua)
# Randomly select a node from the group for every connection.
policy: random
}
disney {
# Pass node names as input of keyword/regex filter.
filter: name(regex:'^.*hk.*$', keyword:'sg') && name(keyword:'disney')
# Select the node with min average of the last 10 latencies from the group for every connection.
policy: min_avg10
}
netflix {
# Pass node names as input of keyword filter.
filter: name(keyword:netflix)
# Select the first node from the group for every connection.
policy: fixed(0)
}
}
routing {
domain(geosite:category-ads) -> block
domain(geosite:disney) -> disney
domain(geosite:netflix) -> netflix
ip(geoip:cn) -> direct
domain(geosite:cn) -> direct
final: my_group
}
`)
if err != nil {
t.Fatalf("\n%v", err)
}
for _, section := range sections {
t.Logf("\n%v", section.String())
}
}

View File

@ -0,0 +1,91 @@
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) since 2022, mzz2017 (mzz@tuta.io). All rights reserved.
*/
package config_parser
import (
"fmt"
"github.com/antlr/antlr4/runtime/Go/antlr/v4"
"reflect"
"strings"
)
type ErrorType string
const (
ErrorType_Unsupported ErrorType = "is not supported"
ErrorType_NotSet ErrorType = "is not set"
)
type ConsoleErrorListener struct {
ErrorBuilder strings.Builder
}
func NewConsoleErrorListener() *ConsoleErrorListener {
return &ConsoleErrorListener{}
}
func (d *ConsoleErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
// Do not accumulate errors.
if d.ErrorBuilder.Len() > 0 {
return
}
backtrack := column
if backtrack > 30 {
backtrack = 30
}
starting := fmt.Sprintf("line %v:%v ", line, column)
offset := len(starting) + backtrack
var (
simplyWrite bool
token antlr.Token
)
if offendingSymbol == nil {
simplyWrite = true
} else {
token = offendingSymbol.(antlr.Token)
simplyWrite = token.GetTokenType() == -1
}
if simplyWrite {
d.ErrorBuilder.WriteString(fmt.Sprintf("%v%v", starting, msg))
return
}
beginOfLine := token.GetStart() - backtrack
strPeek := token.GetInputStream().GetText(beginOfLine, token.GetStop()+30)
wrap := strings.IndexByte(strPeek, '\n')
if wrap == -1 {
wrap = token.GetStop() + 30
} else {
wrap += beginOfLine - 1
}
strLine := token.GetInputStream().GetText(beginOfLine, wrap)
d.ErrorBuilder.WriteString(fmt.Sprintf("%v%v\n%v%v: %v\n", starting, strLine, strings.Repeat(" ", offset), strings.Repeat("^", token.GetStop()-token.GetStart()+1), msg))
}
func (d *ConsoleErrorListener) ReportAmbiguity(recognizer antlr.Parser, dfa *antlr.DFA, startIndex, stopIndex int, exact bool, ambigAlts *antlr.BitSet, configs antlr.ATNConfigSet) {
}
func (d *ConsoleErrorListener) ReportAttemptingFullContext(recognizer antlr.Parser, dfa *antlr.DFA, startIndex, stopIndex int, conflictingAlts *antlr.BitSet, configs antlr.ATNConfigSet) {
}
func (d *ConsoleErrorListener) ReportContextSensitivity(recognizer antlr.Parser, dfa *antlr.DFA, startIndex, stopIndex, prediction int, configs antlr.ATNConfigSet) {
}
func BaseContext(ctx interface{}) (baseCtx *antlr.BaseParserRuleContext) {
val := reflect.ValueOf(ctx)
for val.Kind() == reflect.Pointer && val.Type() != reflect.TypeOf(&antlr.BaseParserRuleContext{}) {
val = val.Elem()
}
if val.Type() == reflect.TypeOf(&antlr.BaseParserRuleContext{}) {
baseCtx = val.Interface().(*antlr.BaseParserRuleContext)
} else {
baseCtxVal := val.FieldByName("BaseParserRuleContext")
if !baseCtxVal.IsValid() {
panic("has no field BaseParserRuleContext")
}
baseCtx = baseCtxVal.Interface().(*antlr.BaseParserRuleContext)
}
return baseCtx
}

View File

@ -0,0 +1,187 @@
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) since 2023, mzz2017 (mzz@tuta.io). All rights reserved.
*/
package config_parser
import (
"fmt"
"strconv"
"strings"
)
type ItemType int
const (
ItemType_RoutingRule ItemType = iota
ItemType_Param
ItemType_Section
)
func (t ItemType) String() string {
switch t {
case ItemType_RoutingRule:
return "RoutingRule"
case ItemType_Param:
return "Param"
case ItemType_Section:
return "Section"
default:
return "<Unknown>"
}
}
func NewRoutingRuleItem(rule *RoutingRule) *Item {
return &Item{
Type: ItemType_RoutingRule,
Value: rule,
}
}
func NewParamItem(param *Param) *Item {
return &Item{
Type: ItemType_Param,
Value: param,
}
}
func NewSectionItem(section *Section) *Item {
return &Item{
Type: ItemType_Param,
Value: section,
}
}
type Item struct {
Type ItemType
Value interface{}
}
func (i *Item) String() string {
var builder strings.Builder
builder.WriteString("type: " + i.Type.String() + "\n")
var content string
switch val := i.Value.(type) {
case *RoutingRule:
content = val.String(false)
case *Param:
content = val.String()
case *Section:
content = val.String()
default:
return "<Unknown>\n"
}
lines := strings.Split(content, "\n")
for i := range lines {
lines[i] = "\t" + lines[i]
}
builder.WriteString(strings.Join(lines, "\n"))
return builder.String()
}
type Section struct {
Name string
Items []*Item
}
func (s *Section) String() string {
var builder strings.Builder
builder.WriteString("section: " + s.Name + "\n")
var strItemList []string
for _, item := range s.Items {
lines := strings.Split(item.String(), "\n")
for i := range lines {
lines[i] = "\t" + lines[i]
}
strItemList = append(strItemList, strings.Join(lines, "\n"))
}
builder.WriteString(strings.Join(strItemList, "\n"))
return builder.String()
}
type Param struct {
Key string
Val string
AndFunctions []*Function
}
func (p *Param) String() string {
if p.Key == "" {
return p.Val
}
if p.AndFunctions != nil {
a := paramAndFunctions{
Key: p.Key,
AndFunctions: p.AndFunctions,
}
return a.String()
}
return p.Key + ": " + p.Val
}
type Function struct {
Name string
Params []*Param
}
func (f *Function) String() string {
var builder strings.Builder
builder.WriteString(f.Name + "(")
var strParamList []string
for _, p := range f.Params {
strParamList = append(strParamList, p.String())
}
builder.WriteString(strings.Join(strParamList, ", "))
builder.WriteString(")")
return builder.String()
}
type paramAndFunctions struct {
Key string
AndFunctions []*Function
}
func (p *paramAndFunctions) String() string {
var builder strings.Builder
builder.WriteString(p.Key + ": ")
var strFunctionList []string
for _, f := range p.AndFunctions {
strFunctionList = append(strFunctionList, f.String())
}
builder.WriteString(strings.Join(strFunctionList, " && "))
return builder.String()
}
type RoutingRule struct {
AndFunctions []*Function
Outbound string
}
func (r *RoutingRule) String(calcN bool) string {
var builder strings.Builder
var n int
for _, f := range r.AndFunctions {
if builder.Len() != 0 {
builder.WriteString(" && ")
}
var paramBuilder strings.Builder
n += len(f.Params)
for _, p := range f.Params {
if paramBuilder.Len() != 0 {
paramBuilder.WriteString(", ")
}
if p.Key != "" {
paramBuilder.WriteString(p.Key + ": " + p.Val)
} else {
paramBuilder.WriteString(p.Val)
}
}
builder.WriteString(fmt.Sprintf("%v(%v)", f.Name, paramBuilder.String()))
}
builder.WriteString(" -> " + r.Outbound)
if calcN {
builder.WriteString(" [n = " + strconv.Itoa(n) + "]")
}
return builder.String()
}

239
pkg/config_parser/walker.go Normal file
View File

@ -0,0 +1,239 @@
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) since 2022, mzz2017 (mzz@tuta.io). All rights reserved.
*/
package config_parser
import (
"fmt"
"github.com/antlr/antlr4/runtime/Go/antlr/v4"
"github.com/v2rayA/dae-config-dist/go/dae_config"
"log"
"strconv"
)
type Walker struct {
*dae_config.Basedae_configListener
parser antlr.Parser
Sections []*Section
}
func NewWalker(parser antlr.Parser) *Walker {
return &Walker{
parser: parser,
}
}
type paramParser struct {
list []*Param
}
func getValueFromLiteral(literal *dae_config.LiteralContext) string {
quote := literal.Quote_literal()
if quote == nil {
return literal.GetText()
}
text := quote.GetText()
return text[1 : len(text)-1]
}
func (p *paramParser) parseParam(ctx *dae_config.ParameterContext) *Param {
children := ctx.GetChildren()
if len(children) == 3 {
return &Param{
Key: children[0].(*antlr.TerminalNodeImpl).GetText(),
Val: getValueFromLiteral(children[2].(*dae_config.LiteralContext)),
}
} else if len(children) == 1 {
return &Param{
Key: "",
Val: getValueFromLiteral(children[0].(*dae_config.LiteralContext)),
}
}
panic("unexpected")
}
func (p *paramParser) parseNonEmptyParamList(ctx *dae_config.NonEmptyParameterListContext) {
children := ctx.GetChildren()
if len(children) == 3 {
p.list = append(p.list, p.parseParam(children[2].(*dae_config.ParameterContext)))
p.parseNonEmptyParamList(children[0].(*dae_config.NonEmptyParameterListContext))
} else if len(children) == 1 {
p.list = append(p.list, p.parseParam(children[0].(*dae_config.ParameterContext)))
}
}
func (w *Walker) parseNonEmptyParamList(list *dae_config.NonEmptyParameterListContext) []*Param {
paramParser := new(paramParser)
paramParser.parseNonEmptyParamList(list)
return paramParser.list
}
func (w *Walker) reportKeyUnsupportedError(ctx interface{}, keyName, funcName string) {
w.ReportError(ctx, ErrorType_Unsupported, fmt.Sprintf("key %v in %v()", strconv.Quote(keyName), funcName))
}
type functionVerifier func(function *Function, ctx interface{}) bool
func (w *Walker) parseFunctionPrototype(ctx *dae_config.FunctionPrototypeContext, verifier functionVerifier) *Function {
children := ctx.GetChildren()
funcName := children[0].(*antlr.TerminalNodeImpl).GetText()
paramList := children[2].(*dae_config.OptParameterListContext)
children = paramList.GetChildren()
if len(children) == 0 {
w.ReportError(ctx, ErrorType_Unsupported, "empty parameter list")
return nil
}
nonEmptyParamList := children[0].(*dae_config.NonEmptyParameterListContext)
params := w.parseNonEmptyParamList(nonEmptyParamList)
f := &Function{
Name: funcName,
Params: params,
}
// Verify function name and param keys.
if verifier != nil && !verifier(f, ctx) {
return nil
}
return f
}
func (w *Walker) ReportError(ctx interface{}, errorType ErrorType, target ...string) {
//debug.PrintStack()
bCtx := BaseContext(ctx)
tgt := strconv.Quote(bCtx.GetStart().GetText())
if len(target) != 0 {
tgt = target[0]
}
if errorType == ErrorType_NotSet {
w.parser.NotifyErrorListeners(fmt.Sprintf("%v %v.", tgt, errorType), nil, nil)
return
}
w.parser.NotifyErrorListeners(fmt.Sprintf("%v %v.", tgt, errorType), bCtx.GetStart(), nil)
}
func (w *Walker) parseDeclaration(ctx dae_config.IDeclarationContext) *Param {
children := ctx.GetChildren()
key := children[0].(*antlr.TerminalNodeImpl).GetText()
switch valueCtx := children[2].(type) {
case *dae_config.LiteralContext:
value := getValueFromLiteral(valueCtx)
return &Param{
Key: key,
Val: value,
}
case *dae_config.FunctionPrototypeExpressionContext:
andFunctions := w.parseFunctionPrototypeExpression(valueCtx, nil)
return &Param{
Key: key,
AndFunctions: andFunctions,
}
default:
w.ReportError(valueCtx, ErrorType_Unsupported)
return nil
}
}
func (w *Walker) parseFunctionPrototypeExpression(ctx dae_config.IFunctionPrototypeExpressionContext, verifier functionVerifier) (andFunctions []*Function) {
children := ctx.GetChildren()
for _, child := range children {
// And rules.
if child, ok := child.(*dae_config.FunctionPrototypeContext); ok {
function := w.parseFunctionPrototype(child, verifier)
andFunctions = append(andFunctions, function)
}
}
return andFunctions
}
func (w *Walker) parseRoutingRule(ctx dae_config.IRoutingRuleContext) *RoutingRule {
children := ctx.GetChildren()
//logrus.Debugln(ctx.GetText(), children)
left, ok := children[0].(*dae_config.RoutingRuleLeftContext)
if !ok {
w.ReportError(ctx, ErrorType_Unsupported, "not *RoutingRuleLeftContext: "+ctx.GetText())
return nil
}
outbound := children[2].(*dae_config.Bare_literalContext).GetText()
// Parse functions.
children = left.GetChildren()
functionList, ok := children[1].(*dae_config.FunctionPrototypeExpressionContext)
if !ok {
w.ReportError(ctx, ErrorType_Unsupported, "not *FunctionPrototypeExpressionContext: "+ctx.GetText())
return nil
}
andFunctions := w.parseFunctionPrototypeExpression(functionList, nil)
return &RoutingRule{
AndFunctions: andFunctions,
Outbound: outbound,
}
}
type routingRuleOrDeclarationOrLiteralOrExpressionListParser struct {
Items []*Item
Walker *Walker
}
func (p *routingRuleOrDeclarationOrLiteralOrExpressionListParser) Parse(ctx dae_config.IRoutingRuleOrDeclarationOrLiteralOrExpressionListContext) {
for _, elem := range ctx.GetChildren() {
switch elem := elem.(type) {
case dae_config.IRoutingRuleContext:
rule := p.Walker.parseRoutingRule(elem)
if rule == nil {
return
}
p.Items = append(p.Items, NewRoutingRuleItem(rule))
case dae_config.IDeclarationContext:
param := p.Walker.parseDeclaration(elem)
if param == nil {
return
}
p.Items = append(p.Items, NewParamItem(param))
case *dae_config.LiteralContext:
p.Items = append(p.Items, NewParamItem(&Param{
Key: "",
Val: getValueFromLiteral(elem),
}))
case dae_config.IExpressionContext:
section := p.Walker.parseExpression(elem)
if section == nil {
return
}
p.Items = append(p.Items, NewSectionItem(section))
case dae_config.IRoutingRuleOrDeclarationOrLiteralOrExpressionListContext:
p.Parse(elem)
default:
log.Printf("? %v", elem.(*dae_config.ExpressionContext))
p.Walker.ReportError(elem, ErrorType_Unsupported)
return
}
}
}
func (w *Walker) parseRoutingRuleOrDeclarationOrLiteralOrExpressionListContext(ctx dae_config.IRoutingRuleOrDeclarationOrLiteralOrExpressionListContext) []*Item {
parser := routingRuleOrDeclarationOrLiteralOrExpressionListParser{
Items: nil,
Walker: w,
}
parser.Parse(ctx)
return parser.Items
}
func (w *Walker) parseExpression(exp dae_config.IExpressionContext) *Section {
children := exp.GetChildren()
name := children[0].(*antlr.TerminalNodeImpl).GetText()
list := children[2].(dae_config.IRoutingRuleOrDeclarationOrLiteralOrExpressionListContext)
items := w.parseRoutingRuleOrDeclarationOrLiteralOrExpressionListContext(list)
return &Section{
Name: name,
Items: items,
}
}
func (w *Walker) EnterProgramStructureBlcok(ctx *dae_config.ProgramStructureBlcokContext) {
section := w.parseExpression(ctx.Expression())
if section == nil {
return
}
w.Sections = append(w.Sections, section)
}

View File

@ -3,11 +3,11 @@
package geodata
import (
_ "github.com/v2fly/v2ray-core/v5/common/protoext"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
_ "github.com/v2rayA/dae/pkg/geodata/protoext"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoimpl"
"reflect"
"sync"
)
const (

View File

@ -0,0 +1,355 @@
// Copied from https://github.com/v2fly/v2ray-core/tree/42b166760b2ba8d984e514b830fcd44e23728e43
package protoext
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
descriptorpb "google.golang.org/protobuf/types/descriptorpb"
reflect "reflect"
sync "sync"
)
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 MessageOpt struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type []string `protobuf:"bytes,1,rep,name=type,proto3" json:"type,omitempty"`
ShortName []string `protobuf:"bytes,2,rep,name=short_name,json=shortName,proto3" json:"short_name,omitempty"`
TransportOriginalName string `protobuf:"bytes,86001,opt,name=transport_original_name,json=transportOriginalName,proto3" json:"transport_original_name,omitempty"`
}
func (x *MessageOpt) Reset() {
*x = MessageOpt{}
if protoimpl.UnsafeEnabled {
mi := &file_common_protoext_extensions_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MessageOpt) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MessageOpt) ProtoMessage() {}
func (x *MessageOpt) ProtoReflect() protoreflect.Message {
mi := &file_common_protoext_extensions_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MessageOpt.ProtoReflect.Descriptor instead.
func (*MessageOpt) Descriptor() ([]byte, []int) {
return file_common_protoext_extensions_proto_rawDescGZIP(), []int{0}
}
func (x *MessageOpt) GetType() []string {
if x != nil {
return x.Type
}
return nil
}
func (x *MessageOpt) GetShortName() []string {
if x != nil {
return x.ShortName
}
return nil
}
func (x *MessageOpt) GetTransportOriginalName() string {
if x != nil {
return x.TransportOriginalName
}
return ""
}
type FieldOpt struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AnyWants []string `protobuf:"bytes,1,rep,name=any_wants,json=anyWants,proto3" json:"any_wants,omitempty"`
AllowedValues []string `protobuf:"bytes,2,rep,name=allowed_values,json=allowedValues,proto3" json:"allowed_values,omitempty"`
AllowedValueTypes []string `protobuf:"bytes,3,rep,name=allowed_value_types,json=allowedValueTypes,proto3" json:"allowed_value_types,omitempty"`
// convert_time_read_file_into read a file into another field, and clear this field during input parsing
ConvertTimeReadFileInto string `protobuf:"bytes,4,opt,name=convert_time_read_file_into,json=convertTimeReadFileInto,proto3" json:"convert_time_read_file_into,omitempty"`
// forbidden marks a boolean to be inaccessible to user
Forbidden bool `protobuf:"varint,5,opt,name=forbidden,proto3" json:"forbidden,omitempty"`
// convert_time_resource_loading read a file, and place its resource hash into another field
ConvertTimeResourceLoading string `protobuf:"bytes,6,opt,name=convert_time_resource_loading,json=convertTimeResourceLoading,proto3" json:"convert_time_resource_loading,omitempty"`
// convert_time_parse_ip parse a string ip address, and put its binary representation into another field
ConvertTimeParseIp string `protobuf:"bytes,7,opt,name=convert_time_parse_ip,json=convertTimeParseIp,proto3" json:"convert_time_parse_ip,omitempty"`
}
func (x *FieldOpt) Reset() {
*x = FieldOpt{}
if protoimpl.UnsafeEnabled {
mi := &file_common_protoext_extensions_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *FieldOpt) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FieldOpt) ProtoMessage() {}
func (x *FieldOpt) ProtoReflect() protoreflect.Message {
mi := &file_common_protoext_extensions_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FieldOpt.ProtoReflect.Descriptor instead.
func (*FieldOpt) Descriptor() ([]byte, []int) {
return file_common_protoext_extensions_proto_rawDescGZIP(), []int{1}
}
func (x *FieldOpt) GetAnyWants() []string {
if x != nil {
return x.AnyWants
}
return nil
}
func (x *FieldOpt) GetAllowedValues() []string {
if x != nil {
return x.AllowedValues
}
return nil
}
func (x *FieldOpt) GetAllowedValueTypes() []string {
if x != nil {
return x.AllowedValueTypes
}
return nil
}
func (x *FieldOpt) GetConvertTimeReadFileInto() string {
if x != nil {
return x.ConvertTimeReadFileInto
}
return ""
}
func (x *FieldOpt) GetForbidden() bool {
if x != nil {
return x.Forbidden
}
return false
}
func (x *FieldOpt) GetConvertTimeResourceLoading() string {
if x != nil {
return x.ConvertTimeResourceLoading
}
return ""
}
func (x *FieldOpt) GetConvertTimeParseIp() string {
if x != nil {
return x.ConvertTimeParseIp
}
return ""
}
var file_common_protoext_extensions_proto_extTypes = []protoimpl.ExtensionInfo{
{
ExtendedType: (*descriptorpb.MessageOptions)(nil),
ExtensionType: (*MessageOpt)(nil),
Field: 50000,
Name: "v2ray.core.common.protoext.message_opt",
Tag: "bytes,50000,opt,name=message_opt",
Filename: "common/protoext/extensions.proto",
},
{
ExtendedType: (*descriptorpb.FieldOptions)(nil),
ExtensionType: (*FieldOpt)(nil),
Field: 50000,
Name: "v2ray.core.common.protoext.field_opt",
Tag: "bytes,50000,opt,name=field_opt",
Filename: "common/protoext/extensions.proto",
},
}
// Extension fields to descriptorpb.MessageOptions.
var (
// optional v2ray.core.common.protoext.MessageOpt message_opt = 50000;
E_MessageOpt = &file_common_protoext_extensions_proto_extTypes[0]
)
// Extension fields to descriptorpb.FieldOptions.
var (
// optional v2ray.core.common.protoext.FieldOpt field_opt = 50000;
E_FieldOpt = &file_common_protoext_extensions_proto_extTypes[1]
)
var File_common_protoext_extensions_proto protoreflect.FileDescriptor
var file_common_protoext_extensions_proto_rawDesc = []byte{
0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78,
0x74, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x74, 0x1a, 0x20,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f,
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0x79, 0x0a, 0x0a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x12, 0x12,
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,
0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d,
0x65, 0x12, 0x38, 0x0a, 0x17, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6f,
0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0xf1, 0x9f, 0x05,
0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4f,
0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xd0, 0x02, 0x0a, 0x08,
0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x6e, 0x79, 0x5f,
0x77, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x61, 0x6e, 0x79,
0x57, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64,
0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x61,
0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x13,
0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x74, 0x79,
0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x1b,
0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x65, 0x61,
0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x17, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65,
0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x74, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x6f,
0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x66,
0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x41, 0x0a, 0x1d, 0x63, 0x6f, 0x6e, 0x76,
0x65, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
0x1a, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x31, 0x0a, 0x15, 0x63,
0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73,
0x65, 0x5f, 0x69, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x63, 0x6f, 0x6e, 0x76,
0x65, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x50, 0x61, 0x72, 0x73, 0x65, 0x49, 0x70, 0x3a, 0x6a,
0x0a, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x12, 0x1f, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd0,
0x86, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x65, 0x78, 0x74, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x52, 0x0a,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x3a, 0x62, 0x0a, 0x09, 0x66, 0x69,
0x65, 0x6c, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd0, 0x86, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24,
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x74, 0x2e, 0x46, 0x69, 0x65, 0x6c,
0x64, 0x4f, 0x70, 0x74, 0x52, 0x08, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x42, 0x6f,
0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x74,
0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76,
0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f,
0x76, 0x35, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65,
0x78, 0x74, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e,
0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x45, 0x78, 0x74, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_protoext_extensions_proto_rawDescOnce sync.Once
file_common_protoext_extensions_proto_rawDescData = file_common_protoext_extensions_proto_rawDesc
)
func file_common_protoext_extensions_proto_rawDescGZIP() []byte {
file_common_protoext_extensions_proto_rawDescOnce.Do(func() {
file_common_protoext_extensions_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_protoext_extensions_proto_rawDescData)
})
return file_common_protoext_extensions_proto_rawDescData
}
var file_common_protoext_extensions_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_common_protoext_extensions_proto_goTypes = []interface{}{
(*MessageOpt)(nil), // 0: v2ray.core.common.protoext.MessageOpt
(*FieldOpt)(nil), // 1: v2ray.core.common.protoext.FieldOpt
(*descriptorpb.MessageOptions)(nil), // 2: google.protobuf.MessageOptions
(*descriptorpb.FieldOptions)(nil), // 3: google.protobuf.FieldOptions
}
var file_common_protoext_extensions_proto_depIdxs = []int32{
2, // 0: v2ray.core.common.protoext.message_opt:extendee -> google.protobuf.MessageOptions
3, // 1: v2ray.core.common.protoext.field_opt:extendee -> google.protobuf.FieldOptions
0, // 2: v2ray.core.common.protoext.message_opt:type_name -> v2ray.core.common.protoext.MessageOpt
1, // 3: v2ray.core.common.protoext.field_opt:type_name -> v2ray.core.common.protoext.FieldOpt
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
2, // [2:4] is the sub-list for extension type_name
0, // [0:2] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_common_protoext_extensions_proto_init() }
func file_common_protoext_extensions_proto_init() {
if File_common_protoext_extensions_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_protoext_extensions_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MessageOpt); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_common_protoext_extensions_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*FieldOpt); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_protoext_extensions_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 2,
NumServices: 0,
},
GoTypes: file_common_protoext_extensions_proto_goTypes,
DependencyIndexes: file_common_protoext_extensions_proto_depIdxs,
MessageInfos: file_common_protoext_extensions_proto_msgTypes,
ExtensionInfos: file_common_protoext_extensions_proto_extTypes,
}.Build()
File_common_protoext_extensions_proto = out.File
file_common_protoext_extensions_proto_rawDesc = nil
file_common_protoext_extensions_proto_goTypes = nil
file_common_protoext_extensions_proto_depIdxs = nil
}

View File

@ -19,6 +19,7 @@ func NewLogger(verbose int) *logrus.Logger {
default:
level = logrus.TraceLevel
}
log.SetLevel(level)
return log