diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e71eda3..01b4295 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -110,7 +110,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: '1.19' + go-version: '1.20' - name: Get project dependencies run: go mod download @@ -126,13 +126,13 @@ jobs: run: | echo "version: $version" mkdir -p build_assets - go build -v -o build_assets/V2bX -tags "xray hy" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid=" + go build -v -o build_assets/V2bX -tags "sing xray with_reality_server with_quic" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid=" - name: Build Mips softfloat V2bX if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle' run: | echo "version: $version" - GOMIPS=softfloat go build -v -o build_assets/V2bX_softfloat -tags "xray hy" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid=" + GOMIPS=softfloat go build -v -o build_assets/V2bX_softfloat -tags "sing xray with_reality_server with_quic" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid=" - name: Rename Windows V2bX if: matrix.goos == 'windows' run: | @@ -146,8 +146,7 @@ jobs: cp ${GITHUB_WORKSPACE}/example/route.json ./build_assets/route.json cp ${GITHUB_WORKSPACE}/example/custom_outbound.json ./build_assets/custom_outbound.json cp ${GITHUB_WORKSPACE}/example/custom_inbound.json ./build_assets/custom_inbound.json - cp ${GITHUB_WORKSPACE}/example/rulelist ./build_assets/rulelist - cp ${GITHUB_WORKSPACE}/example/config.yml.example ./build_assets/config.yml + cp ${GITHUB_WORKSPACE}/example/config.yml.example ./build_assets/config.json LIST=('geoip geoip geoip' 'domain-list-community dlc geosite') for i in "${LIST[@]}" do diff --git a/README.md b/README.md index 46ab813..0afca58 100644 --- a/README.md +++ b/README.md @@ -28,22 +28,19 @@ A V2board node server based on multi core, modified from XrayR. | 自动申请tls证书 | √ | √ | √ | √ | | 自动续签tls证书 | √ | √ | √ | √ | | 在线人数统计 | √ | √ | √ | √ | -| 审计规则 | √ | √ | √ | | +| 审计规则 | √ | √ | √ | √ | | 自定义DNS | √ | √ | √ | √ | | 在线IP数限制 | √ | √ | √ | √ | -| 连接数限制 | √ | √ | √ | | -| 跨节点IP数限制 | √ | √ | √ | | -| 按照用户限速 | √ | √ | √ | | -| 动态限速(未测试) | √ | √ | √ | | +| 连接数限制 | √ | √ | √ | √ | +| 跨节点IP数限制 | | | | | +| 按照用户限速 | √ | √ | √ | √ | +| 动态限速(未测试) | √ | √ | √ | √ | ## TODO - [ ] 重新实现动态限速 - [ ] 重新实现在线IP同步(跨节点在线IP限制) -- [x] 集成基本操作Command(Start, Stop, Restart, Status, Uninstall) -- [ ] 完善Hysteria内核支持 - [ ] 完善使用文档 -- [ ] 尽可能统一日志输出格式 ## 软件安装 @@ -59,8 +56,8 @@ wget -N https://raw.githubusercontents.com/InazumaV/V2bX-script/master/install.s ## 构建 ``` bash -# 通过-tag选项指定要编译的内核, 可选 xray, hy -go build -o V2bX -ldflags '-s -w' -gcflags="all=-trimpath=${PWD}" -asmflags="all=-trimpath=${PWD} -tags "xray hy" +# 通过-tags选项指定要编译的内核, 可选 xray, sing +go build -o V2bX -ldflags '-s -w' -gcflags="all=-trimpath=${PWD}" -asmflags="all=-trimpath=${PWD} -tags "xray sing" ``` ## 配置文件及详细使用教程 diff --git a/api/panel/node.go b/api/panel/node.go index 1d8fd0f..aabb1d6 100644 --- a/api/panel/node.go +++ b/api/panel/node.go @@ -1,10 +1,8 @@ package panel import ( - "bytes" "encoding/base64" "fmt" - "os" "reflect" "strconv" "strings" @@ -12,65 +10,99 @@ import ( "github.com/InazumaV/V2bX/common/crypt" "github.com/goccy/go-json" - log "github.com/sirupsen/logrus" - coreConf "github.com/xtls/xray-core/infra/conf" ) -type CommonNodeRsp struct { - Host string `json:"host"` - ServerPort int `json:"server_port"` - ServerName string `json:"server_name"` - Routes []Route `json:"routes"` - BaseConfig BaseConfig `json:"base_config"` +// Security type +const ( + None = 0 + Tls = 1 + Reality = 2 +) + +type NodeInfo struct { + Id int + Type string + Security int + PushInterval time.Duration + PullInterval time.Duration + RawDNS RawDNS + Rules Rules + + // origin + VAllss *VAllssNode + Shadowsocks *ShadowsocksNode + Trojan *TrojanNode + Hysteria *HysteriaNode + Common *CommonNode +} + +type CommonNode struct { + Host string `json:"host"` + ServerPort int `json:"server_port"` + ServerName string `json:"server_name"` + Routes []Route `json:"routes"` + BaseConfig *BaseConfig `json:"base_config"` } type Route struct { - Id int `json:"id"` - Match interface{} `json:"match"` - Action string `json:"action"` - //ActionValue interface{} `json:"action_value"` + Id int `json:"id"` + Match interface{} `json:"match"` + Action string `json:"action"` + ActionValue string `json:"action_value"` } type BaseConfig struct { PushInterval any `json:"push_interval"` PullInterval any `json:"pull_interval"` } -type V2rayNodeRsp struct { - Tls int `json:"tls"` - Network string `json:"network"` - NetworkSettings json.RawMessage `json:"networkSettings"` - ServerName string `json:"server_name"` +// VAllssNode is vmess and vless node info +type VAllssNode struct { + CommonNode + Tls int `json:"tls"` + TlsSettings TlsSettings `json:"tls_settings"` + TlsSettingsBack *TlsSettings `json:"tlsSettings"` + Network string `json:"network"` + NetworkSettings json.RawMessage `json:"network_settings"` + NetworkSettingsBack json.RawMessage `json:"networkSettings"` + ServerName string `json:"server_name"` + + // vless only + Flow string `json:"flow"` + RealityConfig RealityConfig `json:"-"` } -type ShadowsocksNodeRsp struct { +type TlsSettings struct { + ServerName string `json:"server_name"` + ServerPort string `json:"server_port"` + ShortId string `json:"short_id"` + PrivateKey string `json:"private_key"` +} + +type RealityConfig struct { + Xver uint64 `json:"Xver"` + MinClientVer string `json:"MinClientVer"` + MaxClientVer string `json:"MaxClientVer"` + MaxTimeDiff string `json:"MaxTimeDiff"` +} + +type ShadowsocksNode struct { + CommonNode Cipher string `json:"cipher"` ServerKey string `json:"server_key"` } -type HysteriaNodeRsp struct { +type TrojanNode CommonNode + +type HysteriaNode struct { + CommonNode UpMbps int `json:"up_mbps"` DownMbps int `json:"down_mbps"` Obfs string `json:"obfs"` } -type NodeInfo struct { - Id int - Type string - Rules Rules - Host string - Port int - Network string - ExtraConfig V2rayExtraConfig - NetworkSettings json.RawMessage - Tls bool - ServerName string - UpMbps int - DownMbps int - ServerKey string - Cipher string - HyObfs string - PushInterval time.Duration - PullInterval time.Duration +type RawDNS struct { + DNSMap map[string]map[string]interface{} + DNSJson []byte } type Rules struct { @@ -78,24 +110,6 @@ type Rules struct { Protocol []string } -type V2rayExtraConfig struct { - EnableVless string `json:"EnableVless"` - VlessFlow string `json:"VlessFlow"` - EnableReality string `json:"EnableReality"` - RealityConfig *RealityConfig `json:"RealityConfig"` -} - -type RealityConfig struct { - Dest interface{} `yaml:"Dest" json:"Dest"` - Xver string `yaml:"Xver" json:"Xver"` - ServerNames []string `yaml:"ServerNames" json:"ServerNames"` - PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"` - MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"` - MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"` - MaxTimeDiff string `yaml:"MaxTimeDiff" json:"MaxTimeDiff"` - ShortIds []string `yaml:"ShortIds" json:"ShortIds"` -} - func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { const path = "/api/v1/server/UniProxy/config" r, err := c.client. @@ -108,30 +122,90 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { if r.StatusCode() == 304 { return nil, nil } - // parse common params node = &NodeInfo{ Id: c.NodeId, Type: c.NodeType, + RawDNS: RawDNS{ + DNSMap: make(map[string]map[string]interface{}), + DNSJson: []byte(""), + }, } - common := CommonNodeRsp{} - err = json.Unmarshal(r.Body(), &common) - if err != nil { - return nil, fmt.Errorf("decode common params error: %s", err) + // parse protocol params + var cm *CommonNode + switch c.NodeType { + case "vmess", "vless": + rsp := &VAllssNode{} + err = json.Unmarshal(r.Body(), rsp) + if err != nil { + return nil, fmt.Errorf("decode v2ray params error: %s", err) + } + if len(rsp.NetworkSettingsBack) > 0 { + rsp.NetworkSettings = rsp.NetworkSettingsBack + rsp.NetworkSettingsBack = nil + } + if rsp.TlsSettingsBack != nil { + rsp.TlsSettings = *rsp.TlsSettingsBack + rsp.TlsSettingsBack = nil + } + cm = &rsp.CommonNode + node.VAllss = rsp + node.Security = node.VAllss.Tls + if len(rsp.NetworkSettings) > 0 { + err = json.Unmarshal(rsp.NetworkSettings, &rsp.RealityConfig) + if err != nil { + return nil, fmt.Errorf("decode reality config error: %s", err) + } + } + if node.Security == Reality { + if rsp.TlsSettings.PrivateKey == "" { + key := crypt.GenX25519Private([]byte("vless" + c.Token)) + rsp.TlsSettings.PrivateKey = base64.RawURLEncoding.EncodeToString(key) + } + } + case "shadowsocks": + rsp := &ShadowsocksNode{} + err = json.Unmarshal(r.Body(), rsp) + if err != nil { + return nil, fmt.Errorf("decode v2ray params error: %s", err) + } + cm = &rsp.CommonNode + node.Shadowsocks = rsp + node.Security = None + case "trojan": + rsp := &TrojanNode{} + err = json.Unmarshal(r.Body(), rsp) + if err != nil { + return nil, fmt.Errorf("decode v2ray params error: %s", err) + } + cm = (*CommonNode)(rsp) + node.Trojan = rsp + node.Security = Tls + case "hysteria": + rsp := &HysteriaNode{} + err = json.Unmarshal(r.Body(), rsp) + if err != nil { + return nil, fmt.Errorf("decode v2ray params error: %s", err) + } + cm = &rsp.CommonNode + node.Hysteria = rsp + node.Security = Tls } - for i := range common.Routes { // parse rules from routes + + // parse rules and dns + for i := range cm.Routes { var matchs []string - if _, ok := common.Routes[i].Match.(string); ok { - matchs = strings.Split(common.Routes[i].Match.(string), ",") - } else if _, ok = common.Routes[i].Match.([]string); ok { - matchs = common.Routes[i].Match.([]string) + if _, ok := cm.Routes[i].Match.(string); ok { + matchs = strings.Split(cm.Routes[i].Match.(string), ",") + } else if _, ok = cm.Routes[i].Match.([]string); ok { + matchs = cm.Routes[i].Match.([]string) } else { - temp := common.Routes[i].Match.([]interface{}) + temp := cm.Routes[i].Match.([]interface{}) matchs = make([]string, len(temp)) for i := range temp { matchs[i] = temp[i].(string) } } - switch common.Routes[i].Action { + switch cm.Routes[i].Action { case "block": for _, v := range matchs { if strings.HasPrefix(v, "protocol:") { @@ -143,90 +217,32 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { } } case "dns": + var domains []string + for _, v := range matchs { + domains = append(domains, v) + } if matchs[0] != "main" { - break - } - dnsPath := os.Getenv("XRAY_DNS_PATH") - if dnsPath == "" { - break - } - dns := []byte(strings.Join(matchs[1:], "")) - currentData, err := os.ReadFile(dnsPath) - if err != nil { - log.WithField("err", err).Panic("Failed to read XRAY_DNS_PATH") - break - } - if !bytes.Equal(currentData, dns) { - coreDnsConfig := &coreConf.DNSConfig{} - if err = json.NewDecoder(bytes.NewReader(dns)).Decode(coreDnsConfig); err != nil { - log.WithField("err", err).Panic("Failed to unmarshal DNS config") + node.RawDNS.DNSMap[strconv.Itoa(i)] = map[string]interface{}{ + "address": cm.Routes[i].ActionValue, + "domains": domains, } - _, err := coreDnsConfig.Build() - if err != nil { - log.WithField("err", err).Panic("Failed to understand DNS config, Please check: https://xtls.github.io/config/dns.html for help") - break - } - if err = os.Truncate(dnsPath, 0); err != nil { - log.WithField("err", err).Panic("Failed to clear XRAY DNS PATH file") - } - if err = os.WriteFile(dnsPath, dns, 0644); err != nil { - log.WithField("err", err).Panic("Failed to write DNS to XRAY DNS PATH file") - } - } - } - } - node.ServerName = common.ServerName - node.Host = common.Host - node.Port = common.ServerPort - node.PullInterval = intervalToTime(common.BaseConfig.PullInterval) - node.PushInterval = intervalToTime(common.BaseConfig.PushInterval) - // parse protocol params - switch c.NodeType { - case "v2ray": - rsp := V2rayNodeRsp{} - err = json.Unmarshal(r.Body(), &rsp) - if err != nil { - return nil, fmt.Errorf("decode v2ray params error: %s", err) - } - node.Network = rsp.Network - node.NetworkSettings = rsp.NetworkSettings - node.ServerName = rsp.ServerName - if rsp.Tls == 1 { - node.Tls = true - } - err = json.Unmarshal(rsp.NetworkSettings, &node.ExtraConfig) - if err != nil { - return nil, fmt.Errorf("decode v2ray extra error: %s", err) - } - if node.ExtraConfig.EnableReality == "true" { - if node.ExtraConfig.RealityConfig == nil { - node.ExtraConfig.EnableReality = "false" } else { - key := crypt.GenX25519Private([]byte(strconv.Itoa(c.NodeId) + c.NodeType + c.Token + - node.ExtraConfig.RealityConfig.PrivateKey)) - node.ExtraConfig.RealityConfig.PrivateKey = base64.RawURLEncoding.EncodeToString(key) + dns := []byte(strings.Join(matchs[1:], "")) + node.RawDNS.DNSJson = dns + break } } - case "shadowsocks": - rsp := ShadowsocksNodeRsp{} - err = json.Unmarshal(r.Body(), &rsp) - if err != nil { - return nil, fmt.Errorf("decode v2ray params error: %s", err) - } - node.ServerKey = rsp.ServerKey - node.Cipher = rsp.Cipher - case "trojan": - node.Tls = true - case "hysteria": - rsp := HysteriaNodeRsp{} - err = json.Unmarshal(r.Body(), &rsp) - if err != nil { - return nil, fmt.Errorf("decode v2ray params error: %s", err) - } - node.DownMbps = rsp.DownMbps - node.UpMbps = rsp.UpMbps - node.HyObfs = rsp.Obfs } + + // set interval + node.PushInterval = intervalToTime(cm.BaseConfig.PushInterval) + node.PullInterval = intervalToTime(cm.BaseConfig.PullInterval) + + node.Common = cm + // clear + cm.Routes = nil + cm.BaseConfig = nil + c.nodeEtag = r.Header().Get("ETag") return } diff --git a/api/panel/panel.go b/api/panel/panel.go index 566b235..431bfcd 100644 --- a/api/panel/panel.go +++ b/api/panel/panel.go @@ -1,15 +1,14 @@ package panel import ( - "bufio" + "errors" "fmt" - "log" - "os" - "regexp" "strconv" "strings" "time" + "github.com/sirupsen/logrus" + "github.com/InazumaV/V2bX/conf" "github.com/go-resty/resty/v2" ) @@ -17,14 +16,13 @@ import ( // Panel is the interface for different panel's api. type Client struct { - client *resty.Client - APIHost string - Token string - NodeType string - NodeId int - LocalRuleList []*regexp.Regexp - nodeEtag string - userEtag string + client *resty.Client + APIHost string + Token string + NodeType string + NodeId int + nodeEtag string + userEtag string } func New(c *conf.ApiConfig) (*Client, error) { @@ -36,17 +34,25 @@ func New(c *conf.ApiConfig) (*Client, error) { client.SetTimeout(5 * time.Second) } client.OnError(func(req *resty.Request, err error) { - if v, ok := err.(*resty.ResponseError); ok { + var v *resty.ResponseError + if errors.As(err, &v) { // v.Response contains the last response from the server // v.Err contains the original error - log.Print(v.Err) + logrus.Error(v.Err) } }) client.SetBaseURL(c.APIHost) // Check node type c.NodeType = strings.ToLower(c.NodeType) switch c.NodeType { - case "v2ray", "trojan", "shadowsocks", "hysteria": + case "v2ray": + c.NodeType = "vmess" + case + "vmess", + "trojan", + "shadowsocks", + "hysteria", + "vless": default: return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType) } @@ -56,39 +62,11 @@ func New(c *conf.ApiConfig) (*Client, error) { "node_id": strconv.Itoa(c.NodeID), "token": c.Key, }) - // Read local rule list - localRuleList := readLocalRuleList(c.RuleListPath) return &Client{ - client: client, - Token: c.Key, - APIHost: c.APIHost, - NodeType: c.NodeType, - NodeId: c.NodeID, - LocalRuleList: localRuleList, + client: client, + Token: c.Key, + APIHost: c.APIHost, + NodeType: c.NodeType, + NodeId: c.NodeID, }, nil } - -// readLocalRuleList reads the local rule list file -func readLocalRuleList(path string) (LocalRuleList []*regexp.Regexp) { - LocalRuleList = make([]*regexp.Regexp, 0) - if path != "" { - // open the file - file, err := os.Open(path) - //handle errors while opening - if err != nil { - log.Printf("Error when opening file: %s", err) - return - } - fileScanner := bufio.NewScanner(file) - // read line by line - for fileScanner.Scan() { - LocalRuleList = append(LocalRuleList, regexp.MustCompile(fileScanner.Text())) - } - // handle first encountered error while reading - if err := fileScanner.Err(); err != nil { - log.Fatalf("Error while reading file: %s", err) - return - } - } - return -} diff --git a/api/panel/user.go b/api/panel/user.go index 8357a7d..c54f83f 100644 --- a/api/panel/user.go +++ b/api/panel/user.go @@ -2,6 +2,7 @@ package panel import ( "fmt" + log "github.com/sirupsen/logrus" "github.com/goccy/go-json" ) @@ -66,5 +67,6 @@ func (c *Client) ReportUserTraffic(userTraffic []UserTraffic) error { if err != nil { return err } + log.Println(r.String()) return nil } diff --git a/cmd/server.go b/cmd/server.go index 16aec39..b2e074e 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -1,19 +1,17 @@ package cmd import ( + "github.com/InazumaV/V2bX/conf" + vCore "github.com/InazumaV/V2bX/core" + "github.com/InazumaV/V2bX/limiter" + "github.com/InazumaV/V2bX/node" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "gopkg.in/natefinch/lumberjack.v2" "os" "os/signal" "runtime" "syscall" - - log "github.com/sirupsen/logrus" - - vCore "github.com/InazumaV/V2bX/core" - - "github.com/InazumaV/V2bX/conf" - "github.com/InazumaV/V2bX/limiter" - "github.com/InazumaV/V2bX/node" - "github.com/spf13/cobra" ) var ( @@ -31,7 +29,7 @@ var serverCommand = cobra.Command{ func init() { serverCommand.PersistentFlags(). StringVarP(&config, "config", "c", - "/etc/V2bX/config.yml", "config file path") + "/etc/V2bX/config.json", "config file path") serverCommand.PersistentFlags(). BoolVarP(&watch, "watch", "w", true, "watch file path change") @@ -46,9 +44,29 @@ func serverHandle(_ *cobra.Command, _ []string) { log.WithField("err", err).Error("Load config file failed") return } + switch c.LogConfig.Level { + case "debug": + log.SetLevel(log.DebugLevel) + case "info": + log.SetLevel(log.InfoLevel) + case "warn": + log.SetLevel(log.WarnLevel) + case "error": + log.SetLevel(log.ErrorLevel) + } + if c.LogConfig.Output != "" { + w := &lumberjack.Logger{ + Filename: c.LogConfig.Output, + MaxSize: 100, + MaxBackups: 3, + MaxAge: 28, + Compress: true, + } + log.SetOutput(w) + } limiter.Init() log.Info("Start V2bX...") - vc, err := vCore.NewCore(&c.CoreConfig) + vc, err := vCore.NewCore(c.CoresConfig) if err != nil { log.WithField("err", err).Error("new core failed") return @@ -59,22 +77,25 @@ func serverHandle(_ *cobra.Command, _ []string) { return } defer vc.Close() + log.Info("Core ", vc.Type(), " started") nodes := node.New() - err = nodes.Start(c.NodesConfig, vc) + err = nodes.Start(c.NodeConfig, vc) if err != nil { log.WithField("err", err).Error("Run nodes failed") return } - dns := os.Getenv("XRAY_DNS_PATH") + log.Info("Nodes started") + xdns := os.Getenv("XRAY_DNS_PATH") + sdns := os.Getenv("SING_DNS_PATH") if watch { - err = c.Watch(config, dns, func() { + err = c.Watch(config, xdns, sdns, func() { nodes.Close() err = vc.Close() if err != nil { log.WithField("err", err).Error("Restart node failed") return } - vc, err = vCore.NewCore(&c.CoreConfig) + vc, err = vCore.NewCore(c.CoresConfig) if err != nil { log.WithField("err", err).Error("New core failed") return @@ -84,11 +105,13 @@ func serverHandle(_ *cobra.Command, _ []string) { log.WithField("err", err).Error("Start core failed") return } - err = nodes.Start(c.NodesConfig, vc) + log.Info("Core ", vc.Type(), " restarted") + err = nodes.Start(c.NodeConfig, vc) if err != nil { log.WithField("err", err).Error("Run nodes failed") return } + log.Info("Nodes restarted") runtime.GC() }) if err != nil { diff --git a/common/counter/conn.go b/common/counter/conn.go index 8f9db03..e90c1ef 100644 --- a/common/counter/conn.go +++ b/common/counter/conn.go @@ -24,23 +24,23 @@ func NewConnCounter(conn net.Conn, s *TrafficStorage) net.Conn { ExtendedConn: bufio.NewExtendedConn(conn), storage: s, readFunc: func(n int64) { - s.DownCounter.Add(n) + s.UpCounter.Add(n) }, writeFunc: func(n int64) { - s.UpCounter.Add(n) + s.DownCounter.Add(n) }, } } func (c *ConnCounter) Read(b []byte) (n int, err error) { n, err = c.ExtendedConn.Read(b) - c.storage.DownCounter.Store(int64(n)) + c.storage.UpCounter.Store(int64(n)) return } func (c *ConnCounter) Write(b []byte) (n int, err error) { n, err = c.ExtendedConn.Write(b) - c.storage.UpCounter.Store(int64(n)) + c.storage.DownCounter.Store(int64(n)) return } @@ -50,7 +50,7 @@ func (c *ConnCounter) ReadBuffer(buffer *buf.Buffer) error { return err } if buffer.Len() > 0 { - c.storage.DownCounter.Add(int64(buffer.Len())) + c.storage.UpCounter.Add(int64(buffer.Len())) } return nil } @@ -62,7 +62,7 @@ func (c *ConnCounter) WriteBuffer(buffer *buf.Buffer) error { return err } if dataLen > 0 { - c.storage.UpCounter.Add(dataLen) + c.storage.DownCounter.Add(dataLen) } return nil } @@ -95,10 +95,10 @@ func NewPacketConnCounter(conn network.PacketConn, s *TrafficStorage) network.Pa PacketConn: conn, storage: s, readFunc: func(n int64) { - s.DownCounter.Add(n) + s.UpCounter.Add(n) }, writeFunc: func(n int64) { - s.UpCounter.Add(n) + s.DownCounter.Add(n) }, } } @@ -108,7 +108,7 @@ func (p *PacketConnCounter) ReadPacket(buff *buf.Buffer) (destination M.Socksadd if err != nil { return } - p.storage.DownCounter.Add(int64(buff.Len())) + p.storage.UpCounter.Add(int64(buff.Len())) return } @@ -119,7 +119,7 @@ func (p *PacketConnCounter) WritePacket(buff *buf.Buffer, destination M.Socksadd return } if n > 0 { - p.storage.UpCounter.Add(int64(n)) + p.storage.DownCounter.Add(int64(n)) } return } diff --git a/common/json5/json5.go b/common/json5/json5.go new file mode 100644 index 0000000..166ad78 --- /dev/null +++ b/common/json5/json5.go @@ -0,0 +1,112 @@ +package json5 + +import ( + "bytes" + "io" +) + +type TrimNodeReader struct { + r io.Reader + br *bytes.Reader +} + +func isNL(c byte) bool { + return c == '\n' || c == '\r' +} + +func isWS(c byte) bool { + return c == ' ' || c == '\t' || isNL(c) +} + +func consumeComment(s []byte, i int) int { + if i < len(s) && s[i] == '/' { + s[i-1] = ' ' + for ; i < len(s) && !isNL(s[i]); i += 1 { + s[i] = ' ' + } + } + if i < len(s) && s[i] == '*' { + s[i-1] = ' ' + s[i] = ' ' + for ; i < len(s); i += 1 { + if s[i] != '*' { + s[i] = ' ' + } else { + s[i] = ' ' + i++ + if i < len(s) { + if s[i] == '/' { + s[i] = ' ' + break + } + } + } + } + } + return i +} + +func prep(r io.Reader) (s []byte, err error) { + buf := &bytes.Buffer{} + _, err = io.Copy(buf, r) + s = buf.Bytes() + if err != nil { + return + } + + i := 0 + for i < len(s) { + switch s[i] { + case '"': + i += 1 + for i < len(s) { + if s[i] == '"' { + i += 1 + break + } else if s[i] == '\\' { + i += 1 + } + i += 1 + } + case '/': + i = consumeComment(s, i+1) + case ',': + j := i + for { + i += 1 + if i >= len(s) { + break + } else if s[i] == '}' || s[i] == ']' { + s[j] = ' ' + break + } else if s[i] == '/' { + i = consumeComment(s, i+1) + } else if !isWS(s[i]) { + break + } + } + default: + i += 1 + } + } + return +} + +// Read acts as a proxy for the underlying reader and cleans p +// of comments and trailing commas preceeding ] and } +// comments are delimitted by // up until the end the line +func (st *TrimNodeReader) Read(p []byte) (n int, err error) { + if st.br == nil { + var s []byte + if s, err = prep(st.r); err != nil { + return + } + st.br = bytes.NewReader(s) + } + return st.br.Read(p) +} + +// NewTrimNodeReader New returns an io.Reader acting as proxy to r +func NewTrimNodeReader(r io.Reader) io.Reader { + return &TrimNodeReader{r: r} +} diff --git a/conf/cert.go b/conf/cert.go index a921964..23c2c96 100644 --- a/conf/cert.go +++ b/conf/cert.go @@ -1,24 +1,18 @@ package conf type CertConfig struct { - CertMode string `yaml:"CertMode"` // none, file, http, dns - RejectUnknownSni bool `yaml:"RejectUnknownSni"` - CertDomain string `yaml:"CertDomain"` - CertFile string `yaml:"CertFile"` - KeyFile string `yaml:"KeyFile"` - Provider string `yaml:"Provider"` // alidns, cloudflare, gandi, godaddy.... - Email string `yaml:"Email"` - DNSEnv map[string]string `yaml:"DNSEnv"` - RealityConfig *RealityConfig `yaml:"RealityConfig"` + CertMode string `json:"CertMode"` // none, file, http, dns + RejectUnknownSni bool `json:"RejectUnknownSni"` + CertDomain string `json:"CertDomain"` + CertFile string `json:"CertFile"` + KeyFile string `json:"KeyFile"` + Provider string `json:"Provider"` // alidns, cloudflare, gandi, godaddy.... + Email string `json:"Email"` + DNSEnv map[string]string `json:"DNSEnv"` } -type RealityConfig struct { - Dest interface{} `yaml:"Dest" json:"Dest"` - Xver uint64 `yaml:"Xver" json:"Xver"` - ServerNames []string `yaml:"ServerNames" json:"ServerNames"` - PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"` - MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"` - MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"` - MaxTimeDiff uint64 `yaml:"MaxTimeDiff" json:"MaxTimeDiff"` - ShortIds []string `yaml:"ShortIds" json:"ShortIds"` +func NewCertConfig() *CertConfig { + return &CertConfig{ + CertMode: "none", + } } diff --git a/conf/conf.go b/conf/conf.go index b466bea..7fdd933 100644 --- a/conf/conf.go +++ b/conf/conf.go @@ -2,25 +2,24 @@ package conf import ( "fmt" - "io" + "github.com/InazumaV/V2bX/common/json5" "os" - "gopkg.in/yaml.v3" + "github.com/goccy/go-json" ) type Conf struct { - CoreConfig CoreConfig `yaml:"CoreConfig"` - NodesConfig []*NodeConfig `yaml:"Nodes"` + LogConfig LogConfig `json:"Log"` + CoresConfig []CoreConfig `json:"Cores"` + NodeConfig []NodeConfig `json:"Nodes"` } func New() *Conf { return &Conf{ - CoreConfig: CoreConfig{ - Type: "xray", - XrayConfig: NewXrayConfig(), - SingConfig: NewSingConfig(), + LogConfig: LogConfig{ + Level: "info", + Output: "", }, - NodesConfig: []*NodeConfig{}, } } @@ -30,13 +29,5 @@ func (p *Conf) LoadFromPath(filePath string) error { return fmt.Errorf("open config file error: %s", err) } defer f.Close() - content, err := io.ReadAll(f) - if err != nil { - return fmt.Errorf("read file error: %s", err) - } - err = yaml.Unmarshal(content, p) - if err != nil { - return fmt.Errorf("decode config error: %s", err) - } - return nil + return json.NewDecoder(json5.NewTrimNodeReader(f)).Decode(p) } diff --git a/conf/conf_test.go b/conf/conf_test.go index c466a6c..531395c 100644 --- a/conf/conf_test.go +++ b/conf/conf_test.go @@ -1,17 +1,16 @@ package conf import ( - "log" - "strings" "testing" ) func TestConf_LoadFromPath(t *testing.T) { c := New() - t.Log(c.LoadFromPath("../example/config.yml.example")) + t.Log(c.LoadFromPath("../example/config.json"), c.NodeConfig) } func TestConf_Watch(t *testing.T) { - //c := New() - log.Println(strings.Split("aaaa", " ")) + c := New() + t.Log(c.Watch("./1.json", "", func() {})) + select {} } diff --git a/conf/core.go b/conf/core.go index 625a28b..547aa54 100644 --- a/conf/core.go +++ b/conf/core.go @@ -1,7 +1,30 @@ package conf +import ( + "encoding/json" +) + type CoreConfig struct { - Type string `yaml:"Type"` - XrayConfig *XrayConfig `yaml:"XrayConfig"` - SingConfig *SingConfig `yaml:"SingConfig"` + Type string `json:"Type"` + Name string `json:"Name"` + XrayConfig *XrayConfig `json:"-"` + SingConfig *SingConfig `json:"-"` +} + +type _CoreConfig CoreConfig + +func (c *CoreConfig) UnmarshalJSON(b []byte) error { + err := json.Unmarshal(b, (*_CoreConfig)(c)) + if err != nil { + return err + } + switch c.Type { + case "xray": + c.XrayConfig = NewXrayConfig() + return json.Unmarshal(b, c.XrayConfig) + case "sing": + c.SingConfig = NewSingConfig() + return json.Unmarshal(b, c.SingConfig) + } + return nil } diff --git a/conf/limit.go b/conf/limit.go index b4ce6e3..3d9f4d1 100644 --- a/conf/limit.go +++ b/conf/limit.go @@ -1,40 +1,40 @@ package conf type LimitConfig struct { - EnableRealtime bool `yaml:"EnableRealtime"` - SpeedLimit int `yaml:"SpeedLimit"` - IPLimit int `yaml:"DeviceLimit"` - ConnLimit int `yaml:"ConnLimit"` - EnableIpRecorder bool `yaml:"EnableIpRecorder"` - IpRecorderConfig *IpReportConfig `yaml:"IpRecorderConfig"` - EnableDynamicSpeedLimit bool `yaml:"EnableDynamicSpeedLimit"` - DynamicSpeedLimitConfig *DynamicSpeedLimitConfig `yaml:"DynamicSpeedLimitConfig"` + EnableRealtime bool `json:"EnableRealtime"` + SpeedLimit int `json:"SpeedLimit"` + IPLimit int `json:"DeviceLimit"` + ConnLimit int `json:"ConnLimit"` + EnableIpRecorder bool `json:"EnableIpRecorder"` + IpRecorderConfig *IpReportConfig `json:"IpRecorderConfig"` + EnableDynamicSpeedLimit bool `json:"EnableDynamicSpeedLimit"` + DynamicSpeedLimitConfig *DynamicSpeedLimitConfig `json:"DynamicSpeedLimitConfig"` } type RecorderConfig struct { - Url string `yaml:"Url"` - Token string `yaml:"Token"` - Timeout int `yaml:"Timeout"` + Url string `json:"Url"` + Token string `json:"Token"` + Timeout int `json:"Timeout"` } type RedisConfig struct { - Address string `yaml:"Address"` - Password string `yaml:"Password"` - Db int `yaml:"Db"` + Address string `json:"Address"` + Password string `json:"Password"` + Db int `json:"Db"` Expiry int `json:"Expiry"` } type IpReportConfig struct { - Periodic int `yaml:"Periodic"` - Type string `yaml:"Type"` - RecorderConfig *RecorderConfig `yaml:"RecorderConfig"` - RedisConfig *RedisConfig `yaml:"RedisConfig"` - EnableIpSync bool `yaml:"EnableIpSync"` + Periodic int `json:"Periodic"` + Type string `json:"Type"` + RecorderConfig *RecorderConfig `json:"RecorderConfig"` + RedisConfig *RedisConfig `json:"RedisConfig"` + EnableIpSync bool `json:"EnableIpSync"` } type DynamicSpeedLimitConfig struct { - Periodic int `yaml:"Periodic"` - Traffic int64 `yaml:"Traffic"` - SpeedLimit int `yaml:"SpeedLimit"` - ExpireTime int `yaml:"ExpireTime"` + Periodic int `json:"Periodic"` + Traffic int64 `json:"Traffic"` + SpeedLimit int `json:"SpeedLimit"` + ExpireTime int `json:"ExpireTime"` } diff --git a/conf/log.go b/conf/log.go new file mode 100644 index 0000000..0f580f0 --- /dev/null +++ b/conf/log.go @@ -0,0 +1,6 @@ +package conf + +type LogConfig struct { + Level string `json:"Level"` + Output string `json:"Output"` +} diff --git a/conf/node.go b/conf/node.go index 365f20b..459a781 100644 --- a/conf/node.go +++ b/conf/node.go @@ -1,15 +1,135 @@ package conf +import ( + "fmt" + "github.com/InazumaV/V2bX/common/json5" + "github.com/goccy/go-json" + "io" + "net/http" + "os" + "strings" +) + type NodeConfig struct { - ApiConfig *ApiConfig `yaml:"ApiConfig"` - Options *Options `yaml:"Options"` + ApiConfig ApiConfig `json:"-"` + Options Options `json:"-"` +} + +type rawNodeConfig struct { + Include string `json:"Include"` + ApiRaw json.RawMessage `json:"ApiConfig"` + OptRaw json.RawMessage `json:"Options"` } type ApiConfig struct { - APIHost string `yaml:"ApiHost"` - NodeID int `yaml:"NodeID"` - Key string `yaml:"ApiKey"` - NodeType string `yaml:"NodeType"` - Timeout int `yaml:"Timeout"` - RuleListPath string `yaml:"RuleListPath"` + APIHost string `json:"ApiHost"` + NodeID int `json:"NodeID"` + Key string `json:"ApiKey"` + NodeType string `json:"NodeType"` + Timeout int `json:"Timeout"` + RuleListPath string `json:"RuleListPath"` +} + +func (n *NodeConfig) UnmarshalJSON(data []byte) (err error) { + rn := rawNodeConfig{} + err = json.Unmarshal(data, &rn) + if err != nil { + return err + } + if len(rn.Include) != 0 { + file, _ := strings.CutPrefix(rn.Include, ":") + switch file { + case "http", "https": + rsp, err := http.Get(file) + if err != nil { + return err + } + defer rsp.Body.Close() + data, err = io.ReadAll(json5.NewTrimNodeReader(rsp.Body)) + if err != nil { + return fmt.Errorf("open include file error: %s", err) + } + default: + f, err := os.Open(rn.Include) + if err != nil { + return fmt.Errorf("open include file error: %s", err) + } + defer f.Close() + data, err = io.ReadAll(json5.NewTrimNodeReader(f)) + if err != nil { + return fmt.Errorf("open include file error: %s", err) + } + } + err = json.Unmarshal(data, &rn) + if err != nil { + return fmt.Errorf("unmarshal include file error: %s", err) + } + } + + n.ApiConfig = ApiConfig{ + APIHost: "http://127.0.0.1", + Timeout: 30, + } + if len(rn.ApiRaw) > 0 { + err = json.Unmarshal(rn.ApiRaw, &n.ApiConfig) + if err != nil { + return + } + } else { + err = json.Unmarshal(data, &n.ApiConfig) + if err != nil { + return + } + } + + n.Options = Options{ + ListenIP: "0.0.0.0", + SendIP: "0.0.0.0", + CertConfig: NewCertConfig(), + } + if len(rn.OptRaw) > 0 { + err = json.Unmarshal(rn.OptRaw, &n.Options) + if err != nil { + return + } + } else { + err = json.Unmarshal(data, &n.Options) + if err != nil { + return + } + } + return +} + +type Options struct { + Name string `json:"Name"` + Core string `json:"Core"` + CoreName string `json:"CoreName"` + ListenIP string `json:"ListenIP"` + SendIP string `json:"SendIP"` + LimitConfig LimitConfig `json:"LimitConfig"` + RawOptions json.RawMessage `json:"RawOptions"` + XrayOptions *XrayOptions `json:"XrayOptions"` + SingOptions *SingOptions `json:"SingOptions"` + CertConfig *CertConfig `json:"CertConfig"` +} + +func (o *Options) UnmarshalJSON(data []byte) error { + type opt Options + err := json.Unmarshal(data, (*opt)(o)) + if err != nil { + return err + } + switch o.Core { + case "xray": + o.XrayOptions = NewXrayOptions() + return json.Unmarshal(data, o.XrayOptions) + case "sing": + o.SingOptions = NewSingOptions() + return json.Unmarshal(data, o.SingOptions) + default: + o.Core = "" + o.RawOptions = data + } + return nil } diff --git a/conf/option.go b/conf/option.go deleted file mode 100644 index 1fc389b..0000000 --- a/conf/option.go +++ /dev/null @@ -1,36 +0,0 @@ -package conf - -type Options struct { - ListenIP string `yaml:"ListenIP"` - SendIP string `yaml:"SendIP"` - LimitConfig LimitConfig `yaml:"LimitConfig"` - CertConfig *CertConfig `yaml:"CertConfig"` - XrayOptions XrayOptions `yaml:"-"` - HyOptions HyOptions `yaml:"-"` -} - -type XrayOptions struct { - EnableProxyProtocol bool `yaml:"EnableProxyProtocol"` - EnableDNS bool `yaml:"EnableDNS"` - DNSType string `yaml:"DNSType"` - EnableUot bool `yaml:"EnableUot"` - EnableTFO bool `yaml:"EnableTFO"` - DisableIVCheck bool `yaml:"DisableIVCheck"` - DisableSniffing bool `yaml:"DisableSniffing"` - EnableFallback bool `yaml:"EnableFallback"` - FallBackConfigs []FallBackConfig `yaml:"FallBackConfigs"` -} - -type FallBackConfig struct { - SNI string `yaml:"SNI"` - Alpn string `yaml:"Alpn"` - Path string `yaml:"Path"` - Dest string `yaml:"Dest"` - ProxyProtocolVer uint64 `yaml:"ProxyProtocolVer"` -} - -type HyOptions struct { - Resolver string `yaml:"Resolver"` - ResolvePreference string `yaml:"ResolvePreference"` - SendDevice string `yaml:"SendDevice"` -} diff --git a/conf/sing.go b/conf/sing.go index d734642..a334190 100644 --- a/conf/sing.go +++ b/conf/sing.go @@ -1,15 +1,21 @@ package conf +import ( + "github.com/inazumav/sing-box/option" +) + type SingConfig struct { - LogConfig SingLogConfig `yaml:"LogConfig"` - OriginalPath string `yaml:"OriginalPath"` + LogConfig SingLogConfig `json:"Log"` + NtpConfig SingNtpConfig `json:"NTP"` + DnsConfigPath string `json:"DnsConfigPath"` + OriginalPath string `json:"OriginalPath"` } type SingLogConfig struct { - Disabled bool `yaml:"Disable"` - Level string `yaml:"Level"` - Output string `yaml:"Output"` - Timestamp bool `yaml:"Timestamp"` + Disabled bool `json:"Disable"` + Level string `json:"Level"` + Output string `json:"Output"` + Timestamp bool `json:"Timestamp"` } func NewSingConfig() *SingConfig { @@ -18,5 +24,48 @@ func NewSingConfig() *SingConfig { Level: "error", Timestamp: true, }, + NtpConfig: SingNtpConfig{ + Enable: false, + Server: "time.apple.com", + ServerPort: 0, + }, + } +} + +type SingOptions struct { + EnableProxyProtocol bool `json:"EnableProxyProtocol"` + TCPFastOpen bool `json:"EnableTFO"` + SniffEnabled bool `json:"EnableSniff"` + EnableDNS bool `json:"EnableDNS"` + DomainStrategy option.DomainStrategy `json:"DomainStrategy"` + SniffOverrideDestination bool `json:"SniffOverrideDestination"` + FallBackConfigs *FallBackConfigForSing `json:"FallBackConfigs"` +} + +type SingNtpConfig struct { + Enable bool `json:"Enable"` + Server string `json:"Server"` + ServerPort uint16 `json:"ServerPort"` +} + +type FallBackConfigForSing struct { + // sing-box + FallBack FallBack `json:"FallBack"` + FallBackForALPN map[string]FallBack `json:"FallBackForALPN"` +} + +type FallBack struct { + Server string `json:"Server"` + ServerPort string `json:"ServerPort"` +} + +func NewSingOptions() *SingOptions { + return &SingOptions{ + EnableDNS: false, + EnableProxyProtocol: false, + TCPFastOpen: false, + SniffEnabled: true, + SniffOverrideDestination: true, + FallBackConfigs: &FallBackConfigForSing{}, } } diff --git a/conf/watch.go b/conf/watch.go index 0a2d0d8..73921c7 100644 --- a/conf/watch.go +++ b/conf/watch.go @@ -5,10 +5,12 @@ import ( "github.com/fsnotify/fsnotify" "log" "path" + "path/filepath" + "strings" "time" ) -func (p *Conf) Watch(filePath, dnsPath string, reload func()) error { +func (p *Conf) Watch(filePath, xDnsPath string, sDnsPath string, reload func()) error { watcher, err := fsnotify.NewWatcher() if err != nil { return fmt.Errorf("new watcher error: %s", err) @@ -27,10 +29,11 @@ func (p *Conf) Watch(filePath, dnsPath string, reload func()) error { } pre = time.Now() go func() { - time.Sleep(10 * time.Second) - if e.Name == dnsPath { + time.Sleep(5 * time.Second) + switch filepath.Base(strings.TrimSuffix(e.Name, "~")) { + case filepath.Base(xDnsPath), filepath.Base(sDnsPath): log.Println("DNS file changed, reloading...") - } else { + default: log.Println("config dir changed, reloading...") } *p = *New() @@ -52,8 +55,14 @@ func (p *Conf) Watch(filePath, dnsPath string, reload func()) error { if err != nil { return fmt.Errorf("watch file error: %s", err) } - if dnsPath != "" { - err = watcher.Add(path.Dir(dnsPath)) + if xDnsPath != "" { + err = watcher.Add(path.Dir(xDnsPath)) + if err != nil { + return fmt.Errorf("watch dns file error: %s", err) + } + } + if sDnsPath != "" { + err = watcher.Add(path.Dir(sDnsPath)) if err != nil { return fmt.Errorf("watch dns file error: %s", err) } diff --git a/conf/xray.go b/conf/xray.go index d43c60d..a535423 100644 --- a/conf/xray.go +++ b/conf/xray.go @@ -1,27 +1,27 @@ package conf type XrayConfig struct { - LogConfig *XrayLogConfig `yaml:"Log"` - AssetPath string `yaml:"AssetPath"` - DnsConfigPath string `yaml:"DnsConfigPath"` - RouteConfigPath string `yaml:"RouteConfigPath"` - ConnectionConfig *XrayConnectionConfig `yaml:"XrayConnectionConfig"` - InboundConfigPath string `yaml:"InboundConfigPath"` - OutboundConfigPath string `yaml:"OutboundConfigPath"` + LogConfig *XrayLogConfig `json:"Log"` + AssetPath string `json:"AssetPath"` + DnsConfigPath string `json:"DnsConfigPath"` + RouteConfigPath string `json:"RouteConfigPath"` + ConnectionConfig *XrayConnectionConfig `json:"XrayConnectionConfig"` + InboundConfigPath string `json:"InboundConfigPath"` + OutboundConfigPath string `json:"OutboundConfigPath"` } type XrayLogConfig struct { - Level string `yaml:"Level"` - AccessPath string `yaml:"AccessPath"` - ErrorPath string `yaml:"ErrorPath"` + Level string `json:"Level"` + AccessPath string `json:"AccessPath"` + ErrorPath string `json:"ErrorPath"` } type XrayConnectionConfig struct { - Handshake uint32 `yaml:"handshake"` - ConnIdle uint32 `yaml:"connIdle"` - UplinkOnly uint32 `yaml:"uplinkOnly"` - DownlinkOnly uint32 `yaml:"downlinkOnly"` - BufferSize int32 `yaml:"bufferSize"` + Handshake uint32 `json:"handshake"` + ConnIdle uint32 `json:"connIdle"` + UplinkOnly uint32 `json:"uplinkOnly"` + DownlinkOnly uint32 `json:"downlinkOnly"` + BufferSize int32 `json:"bufferSize"` } func NewXrayConfig() *XrayConfig { @@ -45,3 +45,36 @@ func NewXrayConfig() *XrayConfig { }, } } + +type XrayOptions struct { + EnableProxyProtocol bool `json:"EnableProxyProtocol"` + EnableDNS bool `json:"EnableDNS"` + DNSType string `json:"DNSType"` + EnableUot bool `json:"EnableUot"` + EnableTFO bool `json:"EnableTFO"` + DisableIVCheck bool `json:"DisableIVCheck"` + DisableSniffing bool `json:"DisableSniffing"` + EnableFallback bool `json:"EnableFallback"` + FallBackConfigs []FallBackConfigForXray `json:"FallBackConfigs"` +} + +type FallBackConfigForXray struct { + SNI string `json:"SNI"` + Alpn string `json:"Alpn"` + Path string `json:"Path"` + Dest string `json:"Dest"` + ProxyProtocolVer uint64 `json:"ProxyProtocolVer"` +} + +func NewXrayOptions() *XrayOptions { + return &XrayOptions{ + EnableProxyProtocol: false, + EnableDNS: false, + DNSType: "AsIs", + EnableUot: false, + EnableTFO: false, + DisableIVCheck: false, + DisableSniffing: false, + EnableFallback: false, + } +} diff --git a/core/core.go b/core/core.go index dbaabea..9f10d17 100644 --- a/core/core.go +++ b/core/core.go @@ -2,7 +2,6 @@ package core import ( "errors" - "strings" "github.com/InazumaV/V2bX/conf" ) @@ -11,28 +10,17 @@ var ( cores = map[string]func(c *conf.CoreConfig) (Core, error){} ) -func NewCore(c *conf.CoreConfig) (Core, error) { +func NewCore(c []conf.CoreConfig) (Core, error) { + if len(c) < 0 { + return nil, errors.New("no have vail core") + } // multi core - if types := strings.Split(c.Type, " "); len(types) > 1 { - var cs []Core - for _, t := range types { - f, ok := cores[strings.ToLower(t)] - if !ok { - return nil, errors.New("unknown core type: " + t) - } - core1, err := f(c) - if err != nil { - return nil, err - } - cs = append(cs, core1) - } - return &Selector{ - cores: cs, - }, nil + if len(c) > 1 { + return NewSelector(c) } // one core - if f, ok := cores[strings.ToLower(c.Type)]; ok { - return f(c) + if f, ok := cores[c[0].Type]; ok { + return f(&c[0]) } else { return nil, errors.New("unknown core type") } diff --git a/core/hy/config.go b/core/hy/config.go deleted file mode 100644 index e7f02d5..0000000 --- a/core/hy/config.go +++ /dev/null @@ -1,26 +0,0 @@ -package hy - -const ( - mbpsToBps = 125000 - minSpeedBPS = 16384 - - DefaultALPN = "hysteria" - - DefaultStreamReceiveWindow = 16777216 // 16 MB - DefaultConnectionReceiveWindow = DefaultStreamReceiveWindow * 5 / 2 // 40 MB - - DefaultMaxIncomingStreams = 1024 - - DefaultMMDBFilename = "GeoLite2-Country.mmdb" - - ServerMaxIdleTimeoutSec = 60 - DefaultClientIdleTimeoutSec = 20 - - DefaultClientHopIntervalSec = 10 -) - -func SpeedTrans(upM, downM int) (uint64, uint64) { - up := uint64(upM) * mbpsToBps - down := uint64(downM) * mbpsToBps - return up, down -} diff --git a/core/hy/hy.go b/core/hy/hy.go deleted file mode 100644 index b09b280..0000000 --- a/core/hy/hy.go +++ /dev/null @@ -1,49 +0,0 @@ -package hy - -import ( - "fmt" - "sync" - - "github.com/InazumaV/V2bX/conf" - vCore "github.com/InazumaV/V2bX/core" - "github.com/hashicorp/go-multierror" -) - -func init() { - vCore.RegisterCore("hy", NewHy) -} - -type Hy struct { - servers sync.Map -} - -func NewHy(_ *conf.CoreConfig) (vCore.Core, error) { - return &Hy{ - servers: sync.Map{}, - }, nil -} - -func (h *Hy) Start() error { - return nil -} - -func (h *Hy) Close() error { - var errs error - h.servers.Range(func(tag, s any) bool { - err := s.(*Server).Close() - if err != nil { - errs = multierror.Append(errs, fmt.Errorf("close %s error: %s", tag, err)) - } - return true - }) - if errs != nil { - return errs - } - return nil -} - -func (h *Hy) Protocols() []string { - return []string{ - "hysteria", - } -} diff --git a/core/hy/ipmasker.go b/core/hy/ipmasker.go deleted file mode 100644 index 46a4549..0000000 --- a/core/hy/ipmasker.go +++ /dev/null @@ -1,43 +0,0 @@ -package hy - -import ( - "net" -) - -type ipMasker struct { - IPv4Mask net.IPMask - IPv6Mask net.IPMask -} - -// Mask masks an address with the configured CIDR. -// addr can be "host:port" or just host. -func (m *ipMasker) Mask(addr string) string { - if m.IPv4Mask == nil && m.IPv6Mask == nil { - return addr - } - - host, port, err := net.SplitHostPort(addr) - if err != nil { - // just host - host, port = addr, "" - } - ip := net.ParseIP(host) - if ip == nil { - // not an IP address, return as is - return addr - } - if ip4 := ip.To4(); ip4 != nil && m.IPv4Mask != nil { - // IPv4 - host = ip4.Mask(m.IPv4Mask).String() - } else if ip6 := ip.To16(); ip6 != nil && m.IPv6Mask != nil { - // IPv6 - host = ip6.Mask(m.IPv6Mask).String() - } - if port != "" { - return net.JoinHostPort(host, port) - } else { - return host - } -} - -var defaultIPMasker = &ipMasker{} diff --git a/core/hy/kploader.go b/core/hy/kploader.go deleted file mode 100644 index d73c097..0000000 --- a/core/hy/kploader.go +++ /dev/null @@ -1,95 +0,0 @@ -package hy - -import ( - "crypto/tls" - "sync" - - "github.com/fsnotify/fsnotify" - "github.com/sirupsen/logrus" -) - -type keypairLoader struct { - certMu sync.RWMutex - cert *tls.Certificate - certPath string - keyPath string -} - -func newKeypairLoader(certPath, keyPath string) (*keypairLoader, error) { - loader := &keypairLoader{ - certPath: certPath, - keyPath: keyPath, - } - cert, err := tls.LoadX509KeyPair(certPath, keyPath) - if err != nil { - return nil, err - } - loader.cert = &cert - watcher, err := fsnotify.NewWatcher() - if err != nil { - return nil, err - } - go func() { - for { - select { - case event, ok := <-watcher.Events: - if !ok { - return - } - switch event.Op { - case fsnotify.Create, fsnotify.Write, fsnotify.Rename, fsnotify.Chmod: - logrus.WithFields(logrus.Fields{ - "file": event.Name, - }).Info("Keypair change detected, reloading...") - if err := loader.load(); err != nil { - logrus.WithFields(logrus.Fields{ - "error": err, - }).Error("Failed to reload keypair") - } else { - logrus.Info("Keypair successfully reloaded") - } - case fsnotify.Remove: - _ = watcher.Add(event.Name) // Workaround for vim - // https://github.com/fsnotify/fsnotify/issues/92 - } - case err, ok := <-watcher.Errors: - if !ok { - return - } - logrus.WithFields(logrus.Fields{ - "error": err, - }).Error("Failed to watch keypair files for changes") - } - } - }() - err = watcher.Add(certPath) - if err != nil { - _ = watcher.Close() - return nil, err - } - err = watcher.Add(keyPath) - if err != nil { - _ = watcher.Close() - return nil, err - } - return loader, nil -} - -func (kpr *keypairLoader) load() error { - cert, err := tls.LoadX509KeyPair(kpr.certPath, kpr.keyPath) - if err != nil { - return err - } - kpr.certMu.Lock() - kpr.cert = &cert - kpr.certMu.Unlock() - return nil -} - -func (kpr *keypairLoader) GetCertificateFunc() func(*tls.ClientHelloInfo) (*tls.Certificate, error) { - return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { - kpr.certMu.RLock() - defer kpr.certMu.RUnlock() - return kpr.cert, nil - } -} diff --git a/core/hy/mmdb.go b/core/hy/mmdb.go deleted file mode 100644 index 57cc528..0000000 --- a/core/hy/mmdb.go +++ /dev/null @@ -1,26 +0,0 @@ -package hy - -import ( - "os" - - "github.com/oschwald/geoip2-golang" - "github.com/sirupsen/logrus" -) - -func loadMMDBReader(filename string) (*geoip2.Reader, error) { - if _, err := os.Stat(filename); err != nil { - if os.IsNotExist(err) { - logrus.Info("GeoLite2 database not found, downloading...") - logrus.WithFields(logrus.Fields{ - "file": filename, - }).Info("GeoLite2 database downloaded") - return geoip2.Open(filename) - } else { - // some other error - return nil, err - } - } else { - // file exists, just open it - return geoip2.Open(filename) - } -} diff --git a/core/hy/node.go b/core/hy/node.go deleted file mode 100644 index 47b6eb4..0000000 --- a/core/hy/node.go +++ /dev/null @@ -1,43 +0,0 @@ -package hy - -import ( - "errors" - "fmt" - - "github.com/InazumaV/V2bX/api/panel" - "github.com/InazumaV/V2bX/conf" - "github.com/InazumaV/V2bX/limiter" -) - -func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.Options) error { - if info.Type != "hysteria" { - return errors.New("the core not support " + info.Type) - } - switch c.CertConfig.CertMode { - case "reality", "none", "": - return errors.New("hysteria need normal tls cert") - } - l, err := limiter.GetLimiter(tag) - if err != nil { - return fmt.Errorf("get limiter error: %s", err) - } - s := NewServer(tag, l) - err = s.runServer(info, c) - if err != nil { - return fmt.Errorf("run hy server error: %s", err) - } - h.servers.Store(tag, s) - return nil -} - -func (h *Hy) DelNode(tag string) error { - if s, e := h.servers.Load(tag); e { - err := s.(*Server).Close() - if err != nil { - return err - } - h.servers.Delete(tag) - return nil - } - return errors.New("the node is not have") -} diff --git a/core/hy/resolver.go b/core/hy/resolver.go deleted file mode 100644 index cc5edd9..0000000 --- a/core/hy/resolver.go +++ /dev/null @@ -1,123 +0,0 @@ -package hy - -import ( - "crypto/tls" - "errors" - "net" - "net/url" - "strings" - - "github.com/Yuzuki616/hysteria/core/utils" - rdns "github.com/folbricht/routedns" -) - -var errInvalidSyntax = errors.New("invalid syntax") - -func setResolver(dns string) error { - if net.ParseIP(dns) != nil { - // Just an IP address, treat as UDP 53 - dns = "udp://" + net.JoinHostPort(dns, "53") - } - var r rdns.Resolver - if strings.HasPrefix(dns, "udp://") { - // Standard UDP DNS resolver - dns = strings.TrimPrefix(dns, "udp://") - if dns == "" { - return errInvalidSyntax - } - if _, _, err := utils.SplitHostPort(dns); err != nil { - // Append the default DNS port - dns = net.JoinHostPort(dns, "53") - } - client, err := rdns.NewDNSClient("dns-udp", dns, "udp", rdns.DNSClientOptions{}) - if err != nil { - return err - } - r = client - } else if strings.HasPrefix(dns, "tcp://") { - // Standard TCP DNS resolver - dns = strings.TrimPrefix(dns, "tcp://") - if dns == "" { - return errInvalidSyntax - } - if _, _, err := utils.SplitHostPort(dns); err != nil { - // Append the default DNS port - dns = net.JoinHostPort(dns, "53") - } - client, err := rdns.NewDNSClient("dns-tcp", dns, "tcp", rdns.DNSClientOptions{}) - if err != nil { - return err - } - r = client - } else if strings.HasPrefix(dns, "https://") { - // DoH resolver - if dohURL, err := url.Parse(dns); err != nil { - return err - } else { - // Need to set bootstrap address to avoid loopback DNS lookup - dohIPAddr, err := net.ResolveIPAddr("ip", dohURL.Hostname()) - if err != nil { - return err - } - client, err := rdns.NewDoHClient("doh", dns, rdns.DoHClientOptions{ - BootstrapAddr: dohIPAddr.String(), - }) - if err != nil { - return err - } - r = client - } - } else if strings.HasPrefix(dns, "tls://") { - // DoT resolver - dns = strings.TrimPrefix(dns, "tls://") - if dns == "" { - return errInvalidSyntax - } - dotHost, _, err := utils.SplitHostPort(dns) - if err != nil { - // Append the default DNS port - dns = net.JoinHostPort(dns, "853") - } - // Need to set bootstrap address to avoid loopback DNS lookup - dotIPAddr, err := net.ResolveIPAddr("ip", dotHost) - if err != nil { - return err - } - client, err := rdns.NewDoTClient("dot", dns, rdns.DoTClientOptions{ - BootstrapAddr: dotIPAddr.String(), - TLSConfig: new(tls.Config), - }) - if err != nil { - return err - } - r = client - } else if strings.HasPrefix(dns, "quic://") { - // DoQ resolver - dns = strings.TrimPrefix(dns, "quic://") - if dns == "" { - return errInvalidSyntax - } - doqHost, _, err := utils.SplitHostPort(dns) - if err != nil { - // Append the default DNS port - dns = net.JoinHostPort(dns, "853") - } - // Need to set bootstrap address to avoid loopback DNS lookup - doqIPAddr, err := net.ResolveIPAddr("ip", doqHost) - if err != nil { - return err - } - client, err := rdns.NewDoQClient("doq", dns, rdns.DoQClientOptions{ - BootstrapAddr: doqIPAddr.String(), - }) - if err != nil { - return err - } - r = client - } else { - return errInvalidSyntax - } - cache := rdns.NewCache("cache", r, rdns.CacheOptions{}) - net.DefaultResolver = rdns.NewNetResolver(cache) - return nil -} diff --git a/core/hy/server.go b/core/hy/server.go deleted file mode 100644 index 7131d12..0000000 --- a/core/hy/server.go +++ /dev/null @@ -1,257 +0,0 @@ -package hy - -import ( - "crypto/tls" - "fmt" - "io" - "net" - "sync" - "sync/atomic" - "time" - - "github.com/InazumaV/V2bX/common/counter" - - "github.com/InazumaV/V2bX/api/panel" - "github.com/InazumaV/V2bX/conf" - "github.com/InazumaV/V2bX/limiter" - "github.com/Yuzuki616/hysteria/core/sockopt" - "github.com/Yuzuki616/quic-go" - - "github.com/Yuzuki616/hysteria/core/acl" - "github.com/Yuzuki616/hysteria/core/cs" - "github.com/Yuzuki616/hysteria/core/pktconns" - "github.com/Yuzuki616/hysteria/core/pmtud" - "github.com/Yuzuki616/hysteria/core/transport" - "github.com/sirupsen/logrus" -) - -var serverPacketConnFuncFactoryMap = map[string]pktconns.ServerPacketConnFuncFactory{ - "": pktconns.NewServerUDPConnFunc, - "udp": pktconns.NewServerUDPConnFunc, - "wechat": pktconns.NewServerWeChatConnFunc, - "wechat-video": pktconns.NewServerWeChatConnFunc, - "faketcp": pktconns.NewServerFakeTCPConnFunc, -} - -type Server struct { - tag string - l *limiter.Limiter - counter *counter.TrafficCounter - users sync.Map - running atomic.Bool - *cs.Server -} - -func NewServer(tag string, l *limiter.Limiter) *Server { - return &Server{ - tag: tag, - l: l, - } -} - -func (s *Server) runServer(node *panel.NodeInfo, c *conf.Options) error { - /*if c.HyOptions == nil { - return errors.New("hy options is not vail") - }*/ - // Resolver - if len(c.HyOptions.Resolver) > 0 { - err := setResolver(c.HyOptions.Resolver) - if err != nil { - return fmt.Errorf("set resolver error: %s", err) - } - } - // tls config - kpl, err := newKeypairLoader(c.CertConfig.CertFile, c.CertConfig.KeyFile) - if err != nil { - return fmt.Errorf("load cert error: %s", err) - } - tlsConfig := &tls.Config{ - GetCertificate: kpl.GetCertificateFunc(), - NextProtos: []string{DefaultALPN}, - MinVersion: tls.VersionTLS13, - } - // QUIC config - quicConfig := &quic.Config{ - InitialStreamReceiveWindow: DefaultStreamReceiveWindow, - MaxStreamReceiveWindow: DefaultStreamReceiveWindow, - InitialConnectionReceiveWindow: DefaultConnectionReceiveWindow, - MaxConnectionReceiveWindow: DefaultConnectionReceiveWindow, - MaxIncomingStreams: int64(DefaultMaxIncomingStreams), - MaxIdleTimeout: ServerMaxIdleTimeoutSec * time.Second, - KeepAlivePeriod: 0, // Keep alive should solely be client's responsibility - DisablePathMTUDiscovery: false, - EnableDatagrams: true, - } - if !quicConfig.DisablePathMTUDiscovery && pmtud.DisablePathMTUDiscovery { - logrus.Info("Path MTU Discovery is not yet supported on this platform") - } - // Resolve preference - if len(c.HyOptions.ResolvePreference) > 0 { - pref, err := transport.ResolvePreferenceFromString(c.HyOptions.Resolver) - if err != nil { - logrus.WithFields(logrus.Fields{ - "error": err, - }).Fatal("Failed to parse the resolve preference") - } - transport.DefaultServerTransport.ResolvePreference = pref - } - /*// SOCKS5 outbound - if config.SOCKS5Outbound.Server != "" { - transport.DefaultServerTransport.SOCKS5Client = transport.NewSOCKS5Client(config.SOCKS5Outbound.Server, - config.SOCKS5Outbound.User, config.SOCKS5Outbound.Password) - }*/ - // Bind outbound - if c.HyOptions.SendDevice != "" { - iface, err := net.InterfaceByName(c.HyOptions.SendDevice) - if err != nil { - logrus.WithFields(logrus.Fields{ - "error": err, - }).Fatal("Failed to find the interface") - } - transport.DefaultServerTransport.LocalUDPIntf = iface - sockopt.BindDialer(transport.DefaultServerTransport.Dialer, iface) - } - if c.SendIP != "" { - ip := net.ParseIP(c.SendIP) - if ip == nil { - logrus.WithFields(logrus.Fields{ - "error": err, - }).Fatal("Failed to parse the address") - } - transport.DefaultServerTransport.Dialer.LocalAddr = &net.TCPAddr{IP: ip} - transport.DefaultServerTransport.LocalUDPAddr = &net.UDPAddr{IP: ip} - } - // ACL - var aclEngine *acl.Engine - // Prometheus - s.counter = counter.NewTrafficCounter() - // Packet conn - pktConnFuncFactory := serverPacketConnFuncFactoryMap[""] - if pktConnFuncFactory == nil { - return fmt.Errorf("unsopport protocol") - } - pktConnFunc := pktConnFuncFactory(node.HyObfs) - addr := fmt.Sprintf("%s:%d", c.ListenIP, node.Port) - pktConn, err := pktConnFunc(addr) - if err != nil { - logrus.WithFields(logrus.Fields{ - "error": err, - "addr": addr, - }).Fatal("Failed to listen on the UDP address") - } - // Server - up, down := SpeedTrans(node.UpMbps, node.DownMbps) - s.Server, err = cs.NewServer(tlsConfig, quicConfig, pktConn, - transport.DefaultServerTransport, up, down, false, aclEngine, - s.connectFunc, s.disconnectFunc, tcpRequestFunc, tcpErrorFunc, udpRequestFunc, udpErrorFunc, s.counter) - if err != nil { - return fmt.Errorf("new server error: %s", err) - } - logrus.WithField("addr", addr).Info("Server up and running") - go func() { - s.running.Store(true) - defer func() { - s.running.Store(false) - }() - err = s.Server.Serve() - if err != nil { - logrus.WithField("addr", addr).Errorf("serve error: %s", err) - } - }() - return nil -} - -func (s *Server) authByUser(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) { - if _, r := s.l.CheckLimit(string(auth), addr.String(), false); r { - return false, "device limited" - } - if _, ok := s.users.Load(string(auth)); ok { - return true, "Done" - } - return false, "Failed" -} - -func (s *Server) connectFunc(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) { - s.l.ConnLimiter.AddConnCount(addr.String(), string(auth), false) - ok, msg := s.authByUser(addr, auth, sSend, sRecv) - if !ok { - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - }).Info("Authentication failed, client rejected") - return false, msg - } - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - "Uuid": string(auth), - "Tag": s.tag, - }).Info("Client connected") - return ok, msg -} - -func (s *Server) disconnectFunc(addr net.Addr, auth []byte, err error) { - s.l.ConnLimiter.DelConnCount(addr.String(), string(auth)) - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - "error": err, - }).Info("Client disconnected") -} - -func tcpRequestFunc(addr net.Addr, auth []byte, reqAddr string, action acl.Action, arg string) { - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - "dst": defaultIPMasker.Mask(reqAddr), - "action": actionToString(action, arg), - }).Debug("TCP request") -} - -func tcpErrorFunc(addr net.Addr, auth []byte, reqAddr string, err error) { - if err != io.EOF { - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - "dst": defaultIPMasker.Mask(reqAddr), - "error": err, - }).Info("TCP error") - } else { - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - "dst": defaultIPMasker.Mask(reqAddr), - }).Debug("TCP EOF") - } -} - -func udpRequestFunc(addr net.Addr, auth []byte, sessionID uint32) { - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - "session": sessionID, - }).Debug("UDP request") -} - -func udpErrorFunc(addr net.Addr, auth []byte, sessionID uint32, err error) { - if err != io.EOF { - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - "session": sessionID, - "error": err, - }).Info("UDP error") - } else { - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - "session": sessionID, - }).Debug("UDP EOF") - } -} - -func actionToString(action acl.Action, arg string) string { - switch action { - case acl.ActionDirect: - return "Direct" - case acl.ActionProxy: - return "Proxy" - case acl.ActionBlock: - return "Block" - case acl.ActionHijack: - return "Hijack to " + arg - default: - return "Unknown" - } -} diff --git a/core/hy/server_test.go b/core/hy/server_test.go deleted file mode 100644 index ec7e29e..0000000 --- a/core/hy/server_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package hy - -import ( - "encoding/base64" - "log" - "testing" - "time" - - "github.com/InazumaV/V2bX/api/panel" - "github.com/InazumaV/V2bX/conf" - "github.com/InazumaV/V2bX/limiter" - "github.com/sirupsen/logrus" -) - -func TestServer(t *testing.T) { - logrus.SetLevel(logrus.DebugLevel) - limiter.Init() - l := limiter.AddLimiter("test", &conf.LimitConfig{}, nil) - s := NewServer("test", l) - t.Log(s.runServer(&panel.NodeInfo{ - Port: 1145, - UpMbps: 100, - DownMbps: 100, - HyObfs: "atresssdaaaadd", - }, &conf.Options{ - ListenIP: "127.0.0.1", - HyOptions: conf.HyOptions{}, - CertConfig: &conf.CertConfig{ - CertFile: "../../test_data/1.pem", - KeyFile: "../../test_data/1.key", - }, - })) - s.users.Store("test1111", struct{}{}) - go func() { - for { - time.Sleep(10 * time.Second) - auth := base64.StdEncoding.EncodeToString([]byte("test1111")) - log.Println(auth) - log.Println(s.counter.GetUpCount(auth)) - } - }() - select {} -} diff --git a/core/hy/user.go b/core/hy/user.go deleted file mode 100644 index 49b2b93..0000000 --- a/core/hy/user.go +++ /dev/null @@ -1,46 +0,0 @@ -package hy - -import ( - "encoding/base64" - "errors" - - "github.com/InazumaV/V2bX/api/panel" - "github.com/InazumaV/V2bX/core" -) - -func (h *Hy) AddUsers(p *core.AddUsersParams) (int, error) { - s, ok := h.servers.Load(p.Tag) - if !ok { - return 0, errors.New("the node not have") - } - u := &s.(*Server).users - for i := range p.UserInfo { - u.Store(p.UserInfo[i].Uuid, struct{}{}) - } - return len(p.UserInfo), nil -} - -func (h *Hy) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) { - v, _ := h.servers.Load(tag) - s := v.(*Server) - auth := base64.StdEncoding.EncodeToString([]byte(uuid)) - up = s.counter.GetCounter(auth).UpCounter.Load() - down = s.counter.GetCounter(auth).DownCounter.Load() - if reset { - s.counter.Reset(auth) - } - return -} - -func (h *Hy) DelUsers(users []panel.UserInfo, tag string) error { - v, e := h.servers.Load(tag) - if !e { - return errors.New("the node is not have") - } - s := v.(*Server) - for i := range users { - s.users.Delete(users[i].Uuid) - s.counter.Delete(base64.StdEncoding.EncodeToString([]byte(users[i].Uuid))) - } - return nil -} diff --git a/core/imports/hy.go b/core/imports/hy.go deleted file mode 100644 index 7a80f39..0000000 --- a/core/imports/hy.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build hy - -package imports - -import _ "github.com/InazumaV/V2bX/core/hy" diff --git a/core/interface.go b/core/interface.go index 7d47148..464baa0 100644 --- a/core/interface.go +++ b/core/interface.go @@ -6,11 +6,11 @@ import ( ) type AddUsersParams struct { - Tag string - Config *conf.Options - UserInfo []panel.UserInfo - NodeInfo *panel.NodeInfo + Tag string + Users []panel.UserInfo + *panel.NodeInfo } + type Core interface { Start() error Close() error @@ -20,4 +20,5 @@ type Core interface { GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) DelUsers(users []panel.UserInfo, tag string) error Protocols() []string + Type() string } diff --git a/core/selector.go b/core/selector.go index 9c729cc..2757e34 100644 --- a/core/selector.go +++ b/core/selector.go @@ -2,6 +2,8 @@ package core import ( "errors" + "fmt" + "strings" "sync" "github.com/InazumaV/V2bX/api/panel" @@ -10,14 +12,38 @@ import ( ) type Selector struct { - cores []Core + cores map[string]Core nodes sync.Map } +func NewSelector(c []conf.CoreConfig) (Core, error) { + cs := make(map[string]Core, len(c)) + for _, t := range c { + f, ok := cores[strings.ToLower(t.Type)] + if !ok { + return nil, errors.New("unknown core type: " + t.Type) + } + core1, err := f(&t) + if err != nil { + return nil, err + } + if t.Name == "" { + cs[t.Type] = core1 + } else { + cs[t.Name] = core1 + } + } + return &Selector{ + cores: cs, + }, nil +} + func (s *Selector) Start() error { for i := range s.cores { err := s.cores[i].Start() - return err + if err != nil { + return err + } } return nil } @@ -39,24 +65,48 @@ func isSupported(protocol string, protocols []string) bool { return false } -func (s *Selector) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error { - for i := range s.cores { - if !isSupported(info.Type, s.cores[i].Protocols()) { - continue +func (s *Selector) AddNode(tag string, info *panel.NodeInfo, option *conf.Options) error { + var core Core + if len(option.CoreName) > 0 { + // use name to select core + if c, ok := s.cores[option.CoreName]; ok { + core = c } - err := s.cores[i].AddNode(tag, info, config) - if err != nil { - return err + } else { + // use type to select core + for _, c := range s.cores { + if len(option.Core) == 0 { + if !isSupported(info.Type, c.Protocols()) { + continue + } + } else if option.Core != c.Type() { + continue + } + core = c } - s.nodes.Store(tag, i) - return nil } - return errors.New("the node type is not support") + if core == nil { + return errors.New("the node type is not support") + } + if len(option.Core) == 0 { + option.Core = core.Type() + err := option.UnmarshalJSON(option.RawOptions) + if err != nil { + return fmt.Errorf("unmarshal option error: %s", err) + } + option.RawOptions = nil + } + err := core.AddNode(tag, info, option) + if err != nil { + return err + } + s.nodes.Store(tag, core) + return nil } func (s *Selector) DelNode(tag string) error { if t, e := s.nodes.Load(tag); e { - err := s.cores[t.(int)].DelNode(tag) + err := s.cores[t.(string)].DelNode(tag) if err != nil { return err } @@ -71,7 +121,7 @@ func (s *Selector) AddUsers(p *AddUsersParams) (added int, err error) { if !e { return 0, errors.New("the node is not have") } - return s.cores[t.(int)].AddUsers(p) + return t.(Core).AddUsers(p) } func (s *Selector) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) { @@ -79,7 +129,7 @@ func (s *Selector) GetUserTraffic(tag, uuid string, reset bool) (up int64, down if !e { return 0, 0 } - return s.cores[t.(int)].GetUserTraffic(tag, uuid, reset) + return t.(Core).GetUserTraffic(tag, uuid, reset) } func (s *Selector) DelUsers(users []panel.UserInfo, tag string) error { @@ -87,7 +137,7 @@ func (s *Selector) DelUsers(users []panel.UserInfo, tag string) error { if !e { return errors.New("the node is not have") } - return s.cores[t.(int)].DelUsers(users, tag) + return t.(Core).DelUsers(users, tag) } func (s *Selector) Protocols() []string { @@ -97,3 +147,22 @@ func (s *Selector) Protocols() []string { } return protocols } + +func (s *Selector) Type() string { + t := "Selector(" + var flag bool + for n, c := range s.cores { + if flag { + t += " " + } else { + flag = true + } + if len(n) == 0 { + t += c.Type() + } else { + t += n + } + } + t += ")" + return t +} diff --git a/core/sing/dns.go b/core/sing/dns.go new file mode 100644 index 0000000..c843dde --- /dev/null +++ b/core/sing/dns.go @@ -0,0 +1,81 @@ +package sing + +import ( + "bytes" + "github.com/InazumaV/V2bX/api/panel" + "github.com/goccy/go-json" + log "github.com/sirupsen/logrus" + "os" + "strings" +) + +func updateDNSConfig(node *panel.NodeInfo) (err error) { + dnsPath := os.Getenv("SING_DNS_PATH") + if len(node.RawDNS.DNSJson) != 0 { + err = saveDnsConfig(node.RawDNS.DNSJson, dnsPath) + } else if len(node.RawDNS.DNSMap) != 0 { + dnsConfig := DNSConfig{ + Servers: []map[string]interface{}{ + { + "tag": "default", + "address": "https://8.8.8.8/dns-query", + "detour": "direct", + }, + }, + } + for id, value := range node.RawDNS.DNSMap { + dnsConfig.Servers = append(dnsConfig.Servers, + map[string]interface{}{ + "tag": id, + "address": value["address"], + "address_resolver": "default", + "detour": "direct", + }, + ) + rule := map[string]interface{}{ + "server": id, + "disable_cache": true, + } + for _, ruleType := range []string{"domain_suffix", "domain_keyword", "domain_regex", "geosite"} { + var domains []string + for _, v := range value["domains"].([]string) { + split := strings.SplitN(v, ":", 2) + prefix := strings.ToLower(split[0]) + if prefix == ruleType || (prefix == "domain" && ruleType == "domain_suffix") { + if len(split) > 1 { + domains = append(domains, split[1]) + } + if len(domains) > 0 { + rule[ruleType] = domains + } + } + } + } + dnsConfig.Rules = append(dnsConfig.Rules, rule) + } + dnsConfigJSON, err := json.MarshalIndent(dnsConfig, "", " ") + if err != nil { + log.WithField("err", err).Error("Error marshaling dnsConfig to JSON") + return err + } + err = saveDnsConfig(dnsConfigJSON, dnsPath) + } + return err +} + +func saveDnsConfig(dns []byte, dnsPath string) (err error) { + currentData, err := os.ReadFile(dnsPath) + if err != nil { + log.WithField("err", err).Error("Failed to read SING_DNS_PATH") + return err + } + if !bytes.Equal(currentData, dns) { + if err = os.Truncate(dnsPath, 0); err != nil { + log.WithField("err", err).Error("Failed to clear SING DNS PATH file") + } + if err = os.WriteFile(dnsPath, dns, 0644); err != nil { + log.WithField("err", err).Error("Failed to write DNS to SING DNS PATH file") + } + } + return err +} diff --git a/core/sing/hook.go b/core/sing/hook.go index afd4c70..3da31f3 100644 --- a/core/sing/hook.go +++ b/core/sing/hook.go @@ -1,10 +1,12 @@ package sing import ( + "context" "net" - "strings" "sync" + "github.com/inazumav/sing-box/common/urltest" + "github.com/InazumaV/V2bX/common/rate" "github.com/InazumaV/V2bX/limiter" @@ -16,15 +18,18 @@ import ( ) type HookServer struct { - hooker *Hooker + logger log.Logger + counter sync.Map +} + +func (h *HookServer) ModeList() []string { + return nil } func NewHookServer(logger log.Logger) *HookServer { return &HookServer{ - hooker: &Hooker{ - logger: logger, - counter: sync.Map{}, - }, + logger: logger, + counter: sync.Map{}, } } @@ -36,47 +41,108 @@ func (h *HookServer) Close() error { return nil } -func (h *HookServer) StatsService() adapter.V2RayStatsService { - return h.hooker +func (h *HookServer) PreStart() error { + return nil } -func (h *HookServer) Hooker() *Hooker { - return h.hooker -} - -type Hooker struct { - logger log.Logger - counter sync.Map -} - -func (h *Hooker) RoutedConnection(inbound string, outbound string, user string, conn net.Conn) net.Conn { - l, err := limiter.GetLimiter(inbound) +func (h *HookServer) RoutedConnection(_ context.Context, conn net.Conn, m adapter.InboundContext, _ adapter.Rule) (net.Conn, adapter.Tracker) { + t := &Tracker{l: func() {}} + l, err := limiter.GetLimiter(m.Inbound) if err != nil { - log.Error("get limiter for ", inbound, " error: ", err) + log.Error("get limiter for ", m.Inbound, " error: ", err) } - ip, _, _ := strings.Cut(conn.RemoteAddr().String(), ":") - if b, r := l.CheckLimit(user, ip, true); r { + if l.CheckDomainRule(m.Domain) { conn.Close() - h.logger.Error("[", inbound, "] ", "Limited ", user, " by ip or conn") - return conn + h.logger.Error("[", m.Inbound, "] ", + "Limited ", m.User, " access to ", m.Domain, " by domain rule") + return conn, t + } + if l.CheckProtocolRule(m.Protocol) { + conn.Close() + h.logger.Error("[", m.Inbound, "] ", + "Limited ", m.User, " use ", m.Domain, " by protocol rule") + return conn, t + } + ip := m.Source.Addr.String() + if b, r := l.CheckLimit(m.User, ip, true); r { + conn.Close() + h.logger.Error("[", m.Inbound, "] ", "Limited ", m.User, " by ip or conn") + return conn, t } else if b != nil { conn = rate.NewConnRateLimiter(conn, b) } - if c, ok := h.counter.Load(inbound); ok { - return counter.NewConnCounter(conn, c.(*counter.TrafficCounter).GetCounter(user)) + t.l = func() { + l.ConnLimiter.DelConnCount(m.User, ip) + } + if c, ok := h.counter.Load(m.Inbound); ok { + return counter.NewConnCounter(conn, c.(*counter.TrafficCounter).GetCounter(m.User)), t } else { c := counter.NewTrafficCounter() - h.counter.Store(inbound, c) - return counter.NewConnCounter(conn, c.GetCounter(user)) + h.counter.Store(m.Inbound, c) + return counter.NewConnCounter(conn, c.GetCounter(m.User)), t } } -func (h *Hooker) RoutedPacketConnection(inbound string, outbound string, user string, conn N.PacketConn) N.PacketConn { - if c, ok := h.counter.Load(inbound); ok { - return counter.NewPacketConnCounter(conn, c.(*counter.TrafficCounter).GetCounter(user)) +func (h *HookServer) RoutedPacketConnection(_ context.Context, conn N.PacketConn, m adapter.InboundContext, _ adapter.Rule) (N.PacketConn, adapter.Tracker) { + t := &Tracker{ + l: func() {}, + } + l, err := limiter.GetLimiter(m.Inbound) + if err != nil { + log.Error("get limiter for ", m.Inbound, " error: ", err) + } + if l.CheckDomainRule(m.Domain) { + conn.Close() + h.logger.Error("[", m.Inbound, "] ", + "Limited ", m.User, " access to ", m.Domain, " by domain rule") + return conn, t + } + if l.CheckProtocolRule(m.Protocol) { + conn.Close() + h.logger.Error("[", m.Inbound, "] ", + "Limited ", m.User, " use ", m.Domain, " by protocol rule") + return conn, t + } + ip := m.Source.Addr.String() + if b, r := l.CheckLimit(m.User, ip, true); r { + conn.Close() + h.logger.Error("[", m.Inbound, "] ", "Limited ", m.User, " by ip or conn") + return conn, &Tracker{l: func() {}} + } else if b != nil { + conn = rate.NewPacketConnCounter(conn, b) + } + if c, ok := h.counter.Load(m.Inbound); ok { + return counter.NewPacketConnCounter(conn, c.(*counter.TrafficCounter).GetCounter(m.User)), t } else { c := counter.NewTrafficCounter() - h.counter.Store(inbound, c) - return counter.NewPacketConnCounter(conn, c.GetCounter(user)) + h.counter.Store(m.Inbound, c) + return counter.NewPacketConnCounter(conn, c.GetCounter(m.User)), t } } + +// not need + +func (h *HookServer) Mode() string { + return "" +} +func (h *HookServer) StoreSelected() bool { + return false +} +func (h *HookServer) CacheFile() adapter.ClashCacheFile { + return nil +} +func (h *HookServer) HistoryStorage() *urltest.HistoryStorage { + return nil +} + +func (h *HookServer) StoreFakeIP() bool { + return false +} + +type Tracker struct { + l func() +} + +func (t *Tracker) Leave() { + t.l() +} diff --git a/core/sing/node.go b/core/sing/node.go index e43bf7c..6573503 100644 --- a/core/sing/node.go +++ b/core/sing/node.go @@ -4,12 +4,12 @@ import ( "context" "crypto/rand" "encoding/base64" - "encoding/hex" "fmt" "net/netip" "net/url" "strconv" "strings" + "time" "github.com/inazumav/sing-box/inbound" F "github.com/sagernet/sing/common/format" @@ -30,59 +30,107 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio if err != nil { return option.Inbound{}, fmt.Errorf("the listen ip not vail") } - listen := option.ListenOptions{ - //ProxyProtocol: true, - Listen: (*option.ListenAddress)(&addr), - ListenPort: uint16(info.Port), + var domainStrategy option.DomainStrategy + if c.SingOptions.EnableDNS { + domainStrategy = c.SingOptions.DomainStrategy } - tls := option.InboundTLSOptions{ - Enabled: info.Tls, - CertificatePath: c.CertConfig.CertFile, - KeyPath: c.CertConfig.KeyFile, - ServerName: info.ServerName, + listen := option.ListenOptions{ + Listen: (*option.ListenAddress)(&addr), + ListenPort: uint16(info.Common.ServerPort), + ProxyProtocol: c.SingOptions.EnableProxyProtocol, + TCPFastOpen: c.SingOptions.TCPFastOpen, + InboundOptions: option.InboundOptions{ + SniffEnabled: c.SingOptions.SniffEnabled, + SniffOverrideDestination: c.SingOptions.SniffOverrideDestination, + DomainStrategy: domainStrategy, + }, + } + var tls option.InboundTLSOptions + switch info.Security { + case panel.Tls: + if c.CertConfig == nil { + return option.Inbound{}, fmt.Errorf("the CertConfig is not vail") + } + switch c.CertConfig.CertMode { + case "none", "": + break // disable + default: + tls.Enabled = true + tls.CertificatePath = c.CertConfig.CertFile + tls.KeyPath = c.CertConfig.KeyFile + } + case panel.Reality: + tls.Enabled = true + v := info.VAllss + tls.ServerName = v.TlsSettings.ServerName + dest, _ := strconv.Atoi(v.TlsSettings.ServerPort) + mtd, _ := time.ParseDuration(v.RealityConfig.MaxTimeDiff) + tls.Reality = &option.InboundRealityOptions{ + Enabled: true, + ShortID: []string{v.TlsSettings.ShortId}, + PrivateKey: v.TlsSettings.PrivateKey, + Handshake: option.InboundRealityHandshakeOptions{ + ServerOptions: option.ServerOptions{ + Server: tls.ServerName, + ServerPort: uint16(dest), + }, + }, + MaxTimeDifference: option.Duration(mtd), + } } in := option.Inbound{ Tag: tag, } switch info.Type { - case "v2ray": + case "vmess", "vless": + n := info.VAllss t := option.V2RayTransportOptions{ - Type: info.Network, + Type: n.Network, } - switch info.Network { + switch n.Network { case "tcp": t.Type = "" case "ws": - network := WsNetworkConfig{} - err := json.Unmarshal(info.NetworkSettings, &network) - if err != nil { - return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err) - } - var u *url.URL - u, err = url.Parse(network.Path) - if err != nil { - return option.Inbound{}, fmt.Errorf("parse path error: %s", err) - } - ed, _ := strconv.Atoi(u.Query().Get("ed")) - h := make(map[string]option.Listable[string], len(network.Headers)) - for k, v := range network.Headers { - h[k] = option.Listable[string]{ - v, + var ( + path string + ed int + headers map[string]option.Listable[string] + ) + if len(n.NetworkSettings) != 0 { + network := WsNetworkConfig{} + err := json.Unmarshal(n.NetworkSettings, &network) + if err != nil { + return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err) + } + var u *url.URL + u, err = url.Parse(network.Path) + if err != nil { + return option.Inbound{}, fmt.Errorf("parse path error: %s", err) + } + path = u.Path + ed, _ = strconv.Atoi(u.Query().Get("ed")) + headers = make(map[string]option.Listable[string], len(network.Headers)) + for k, v := range network.Headers { + headers[k] = option.Listable[string]{ + v, + } } } t.WebsocketOptions = option.V2RayWebsocketOptions{ - Path: u.Path, + Path: path, EarlyDataHeaderName: "Sec-WebSocket-Protocol", MaxEarlyData: uint32(ed), - Headers: h, + Headers: headers, } case "grpc": - err := json.Unmarshal(info.NetworkSettings, &t.GRPCOptions) - if err != nil { - return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err) + if len(n.NetworkSettings) != 0 { + err := json.Unmarshal(n.NetworkSettings, &t.GRPCOptions) + if err != nil { + return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err) + } } } - if info.ExtraConfig.EnableVless == "true" { + if info.Type == "vless" { in.Type = "vless" in.VLESSOptions = option.VLESSInboundOptions{ ListenOptions: listen, @@ -99,27 +147,70 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio } case "shadowsocks": in.Type = "shadowsocks" - p := make([]byte, 32) - _, _ = rand.Read(p) - randomPasswd := hex.EncodeToString(p) - if strings.Contains(info.Cipher, "2022") { - randomPasswd = base64.StdEncoding.EncodeToString([]byte(randomPasswd)) + n := info.Shadowsocks + var keyLength int + switch n.Cipher { + case "2022-blake3-aes-128-gcm": + keyLength = 16 + case "2022-blake3-aes-256-gcm": + keyLength = 32 + default: + keyLength = 16 } in.ShadowsocksOptions = option.ShadowsocksInboundOptions{ ListenOptions: listen, - Method: info.Cipher, - Password: info.ServerKey, - Users: []option.ShadowsocksUser{ - { - Password: randomPasswd, - }, - }, + Method: n.Cipher, + } + p := make([]byte, keyLength) + _, _ = rand.Read(p) + randomPasswd := string(p) + if strings.Contains(n.Cipher, "2022") { + in.ShadowsocksOptions.Password = n.ServerKey + randomPasswd = base64.StdEncoding.EncodeToString([]byte(randomPasswd)) + } + in.ShadowsocksOptions.Users = []option.ShadowsocksUser{{ + Password: randomPasswd, + }} + case "trojan": + in.Type = "trojan" + in.TrojanOptions = option.TrojanInboundOptions{ + ListenOptions: listen, + TLS: &tls, + } + if c.SingOptions.FallBackConfigs != nil { + // fallback handling + fallback := c.SingOptions.FallBackConfigs.FallBack + fallbackPort, err := strconv.Atoi(fallback.ServerPort) + if err == nil { + in.TrojanOptions.Fallback = &option.ServerOptions{ + Server: fallback.Server, + ServerPort: uint16(fallbackPort), + } + } + fallbackForALPNMap := c.SingOptions.FallBackConfigs.FallBackForALPN + fallbackForALPN := make(map[string]*option.ServerOptions, len(fallbackForALPNMap)) + if err := processFallback(c, fallbackForALPN); err == nil { + in.TrojanOptions.FallbackForALPN = fallbackForALPN + } + } + case "hysteria": + in.Type = "hysteria" + in.HysteriaOptions = option.HysteriaInboundOptions{ + ListenOptions: listen, + UpMbps: info.Hysteria.UpMbps, + DownMbps: info.Hysteria.DownMbps, + Obfs: info.Hysteria.Obfs, + TLS: &tls, } } return in, nil } func (b *Box) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error { + err := updateDNSConfig(info) + if err != nil { + return fmt.Errorf("build dns error: %s", err) + } c, err := getInboundOptions(tag, info, config) if err != nil { return err @@ -131,11 +222,14 @@ func (b *Box) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) er c, nil, ) - b.inbounds[tag] = in + if err != nil { + return fmt.Errorf("init inbound error: %s", err) + } err = in.Start() if err != nil { return fmt.Errorf("start inbound error: %s", err) } + b.inbounds[tag] = in err = b.router.AddInbound(in) if err != nil { return fmt.Errorf("add inbound error: %s", err) diff --git a/core/sing/sing.go b/core/sing/sing.go index 9c6e6ff..f230d49 100644 --- a/core/sing/sing.go +++ b/core/sing/sing.go @@ -3,6 +3,7 @@ package sing import ( "context" "fmt" + "github.com/goccy/go-json" "io" "os" "runtime/debug" @@ -10,7 +11,6 @@ import ( "github.com/InazumaV/V2bX/conf" vCore "github.com/InazumaV/V2bX/core" - "github.com/inazumav/sing-box/adapter" "github.com/inazumav/sing-box/inbound" "github.com/inazumav/sing-box/log" @@ -20,11 +20,16 @@ import ( "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" F "github.com/sagernet/sing/common/format" - "github.com/sagernet/sing/service/pause" + "github.com/sagernet/sing/service" ) var _ adapter.Service = (*Box)(nil) +type DNSConfig struct { + Servers []map[string]interface{} `json:"servers"` + Rules []map[string]interface{} `json:"rules"` +} + type Box struct { createdAt time.Time router adapter.Router @@ -42,13 +47,44 @@ func init() { func New(c *conf.CoreConfig) (vCore.Core, error) { options := option.Options{} + if len(c.SingConfig.OriginalPath) != 0 { + f, err := os.Open(c.SingConfig.OriginalPath) + if err != nil { + return nil, fmt.Errorf("open original config error: %s", err) + } + defer f.Close() + err = json.NewDecoder(f).Decode(&options) + if err != nil { + return nil, fmt.Errorf("decode original config error: %s", err) + } + } options.Log = &option.LogOptions{ Disabled: c.SingConfig.LogConfig.Disabled, Level: c.SingConfig.LogConfig.Level, Timestamp: c.SingConfig.LogConfig.Timestamp, Output: c.SingConfig.LogConfig.Output, } + options.NTP = &option.NTPOptions{ + Enabled: c.SingConfig.NtpConfig.Enable, + WriteToSystem: true, + ServerOptions: option.ServerOptions{ + Server: c.SingConfig.NtpConfig.Server, + ServerPort: c.SingConfig.NtpConfig.ServerPort, + }, + } + os.Setenv("SING_DNS_PATH", "") + if c.SingConfig.DnsConfigPath != "" { + if f, err := os.Open(c.SingConfig.DnsConfigPath); err != nil { + log.Error("Failed to read DNS config file") + } else { + if err = json.NewDecoder(f).Decode(&option.DNSOptions{}); err != nil { + log.Error("Failed to unmarshal DNS config") + } + } + os.Setenv("SING_DNS_PATH", c.SingConfig.DnsConfigPath) + } ctx := context.Background() + ctx = service.ContextWithDefaultRegistry(ctx) ctx = pause.ContextWithDefaultManager(ctx) createdAt := time.Now() experimentalOptions := common.PtrValueOrDefault(options.Experimental) @@ -131,7 +167,7 @@ func New(c *conf.CoreConfig) (vCore.Core, error) { if err != nil { return nil, E.Cause(err, "create v2ray api server") } - router.SetV2RayServer(server) + router.SetClashServer(server) return &Box{ router: router, inbounds: inMap, @@ -265,7 +301,14 @@ func (b *Box) Router() adapter.Router { func (b *Box) Protocols() []string { return []string{ - "v2ray", + "vmess", + "vless", "shadowsocks", + "trojan", + "hysteria", } } + +func (b *Box) Type() string { + return "sing" +} diff --git a/core/sing/user.go b/core/sing/user.go index cfab779..23e7eea 100644 --- a/core/sing/user.go +++ b/core/sing/user.go @@ -1,6 +1,7 @@ package sing import ( + "encoding/base64" "errors" "github.com/InazumaV/V2bX/api/panel" @@ -12,44 +13,70 @@ import ( func (b *Box) AddUsers(p *core.AddUsersParams) (added int, err error) { switch p.NodeInfo.Type { - case "v2ray": - if p.NodeInfo.ExtraConfig.EnableVless == "true" { - us := make([]option.VLESSUser, len(p.UserInfo)) - for i := range p.UserInfo { + case "vmess", "vless": + if p.NodeInfo.Type == "vless" { + us := make([]option.VLESSUser, len(p.Users)) + for i := range p.Users { us[i] = option.VLESSUser{ - Name: p.UserInfo[i].Uuid, - Flow: p.NodeInfo.ExtraConfig.VlessFlow, - UUID: p.UserInfo[i].Uuid, + Name: p.Users[i].Uuid, + Flow: p.VAllss.Flow, + UUID: p.Users[i].Uuid, } } err = b.inbounds[p.Tag].(*inbound.VLESS).AddUsers(us) } else { - us := make([]option.VMessUser, len(p.UserInfo)) - for i := range p.UserInfo { + us := make([]option.VMessUser, len(p.Users)) + for i := range p.Users { us[i] = option.VMessUser{ - Name: p.UserInfo[i].Uuid, - UUID: p.UserInfo[i].Uuid, + Name: p.Users[i].Uuid, + UUID: p.Users[i].Uuid, } } err = b.inbounds[p.Tag].(*inbound.VMess).AddUsers(us) } case "shadowsocks": - us := make([]option.ShadowsocksUser, len(p.UserInfo)) - for i := range p.UserInfo { + us := make([]option.ShadowsocksUser, len(p.Users)) + for i := range p.Users { + var password = p.Users[i].Uuid + switch p.Shadowsocks.Cipher { + case "2022-blake3-aes-128-gcm": + password = base64.StdEncoding.EncodeToString([]byte(password[:16])) + case "2022-blake3-aes-256-gcm": + password = base64.StdEncoding.EncodeToString([]byte(password[:32])) + } us[i] = option.ShadowsocksUser{ - Name: p.UserInfo[i].Uuid, - Password: p.UserInfo[i].Uuid, + Name: p.Users[i].Uuid, + Password: password, } } + err = b.inbounds[p.Tag].(*inbound.ShadowsocksMulti).AddUsers(us) + case "trojan": + us := make([]option.TrojanUser, len(p.Users)) + for i := range p.Users { + us[i] = option.TrojanUser{ + Name: p.Users[i].Uuid, + Password: p.Users[i].Uuid, + } + } + err = b.inbounds[p.Tag].(*inbound.Trojan).AddUsers(us) + case "hysteria": + us := make([]option.HysteriaUser, len(p.Users)) + for i := range p.Users { + us[i] = option.HysteriaUser{ + Name: p.Users[i].Uuid, + AuthString: p.Users[i].Uuid, + } + } + err = b.inbounds[p.Tag].(*inbound.Hysteria).AddUsers(us) } if err != nil { return 0, err } - return len(p.UserInfo), err + return len(p.Users), err } func (b *Box) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) { - if v, ok := b.hookServer.Hooker().counter.Load(tag); ok { + if v, ok := b.hookServer.counter.Load(tag); ok { c := v.(*counter.TrafficCounter) up = c.GetUpCount(uuid) down = c.GetDownCount(uuid) @@ -71,8 +98,14 @@ func (b *Box) DelUsers(users []panel.UserInfo, tag string) error { switch i.Type() { case "vmess": del = i.(*inbound.VMess) + case "vless": + del = i.(*inbound.VLESS) case "shadowsocks": del = i.(*inbound.ShadowsocksMulti) + case "trojan": + del = i.(*inbound.Trojan) + case "hysteria": + del = i.(*inbound.Hysteria) } } else { return errors.New("the inbound not found") diff --git a/core/sing/utils.go b/core/sing/utils.go new file mode 100644 index 0000000..2db7ebf --- /dev/null +++ b/core/sing/utils.go @@ -0,0 +1,19 @@ +package sing + +import ( + "fmt" + "github.com/InazumaV/V2bX/conf" + "github.com/inazumav/sing-box/option" + "strconv" +) + +func processFallback(c *conf.Options, fallbackForALPN map[string]*option.ServerOptions) error { + for k, v := range c.SingOptions.FallBackConfigs.FallBackForALPN { + fallbackPort, err := strconv.Atoi(v.ServerPort) + if err != nil { + return fmt.Errorf("unable to parse fallbackForALPN server port error: %s", err) + } + fallbackForALPN[k] = &option.ServerOptions{Server: v.Server, ServerPort: uint16(fallbackPort)} + } + return nil +} diff --git a/core/xray/app/dispatcher/config.pb.go b/core/xray/app/dispatcher/config.pb.go index 0f2b69b..702a12a 100644 --- a/core/xray/app/dispatcher/config.pb.go +++ b/core/xray/app/dispatcher/config.pb.go @@ -1,17 +1,16 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v3.21.12 +// protoc-gen-go v1.31.0 +// protoc v4.23.4 // source: config.proto package dispatcher import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( @@ -117,15 +116,15 @@ var file_config_proto_rawDesc = []byte{ 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x76, 0x32, 0x62, 0x78, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x6a, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x6e, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x62, 0x78, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x50, 0x01, - 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x59, 0x75, 0x7a, - 0x75, 0x6b, 0x69, 0x36, 0x31, 0x36, 0x2f, 0x56, 0x32, 0x62, 0x58, 0x2f, 0x63, 0x6f, 0x72, 0x65, - 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0xaa, - 0x02, 0x18, 0x56, 0x32, 0x62, 0x58, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, - 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x49, 0x6e, 0x61, + 0x7a, 0x75, 0x6d, 0x61, 0x56, 0x2f, 0x56, 0x32, 0x62, 0x58, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, + 0x78, 0x72, 0x61, 0x79, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, + 0x68, 0x65, 0x72, 0xaa, 0x02, 0x18, 0x56, 0x32, 0x62, 0x58, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, + 0x61, 0x70, 0x70, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/core/xray/app/dispatcher/default.go b/core/xray/app/dispatcher/default.go index aba145b..9995c7d 100644 --- a/core/xray/app/dispatcher/default.go +++ b/core/xray/app/dispatcher/default.go @@ -11,7 +11,6 @@ import ( "github.com/InazumaV/V2bX/common/rate" "github.com/InazumaV/V2bX/limiter" - routingSession "github.com/xtls/xray-core/features/routing/session" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" @@ -24,6 +23,7 @@ import ( "github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/routing" + routing_session "github.com/xtls/xray-core/features/routing/session" "github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport/pipe" @@ -138,77 +138,10 @@ func (*DefaultDispatcher) Start() error { // Close implements common.Closable. func (*DefaultDispatcher) Close() error { return nil } -func (d *DefaultDispatcher) getLink(ctx context.Context, network net.Network, sniffing session.SniffingRequest) (*transport.Link, *transport.Link, *limiter.Limiter, error) { - downOpt := pipe.OptionsFromContext(ctx) - upOpt := downOpt - - if network == net.Network_UDP { - var ip2domain *sync.Map // net.IP.String() => domain, this map is used by server side when client turn on fakedns - // Client will send domain address in the buffer.UDP.Address, server record all possible target IP addrs. - // When target replies, server will restore the domain and send back to client. - // Note: this map is not global but per connection context - upOpt = append(upOpt, pipe.OnTransmission(func(mb buf.MultiBuffer) buf.MultiBuffer { - for i, buffer := range mb { - if buffer.UDP == nil { - continue - } - addr := buffer.UDP.Address - if addr.Family().IsIP() { - if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && fkr0.IsIPInIPPool(addr) && sniffing.Enabled { - domain := fkr0.GetDomainFromFakeDNS(addr) - if len(domain) > 0 { - buffer.UDP.Address = net.DomainAddress(domain) - newError("[fakedns client] override with domain: ", domain, " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx)) - } else { - newError("[fakedns client] failed to find domain! :", addr.String(), " for xUDP buffer at ", i).AtWarning().WriteToLog(session.ExportIDToError(ctx)) - } - } - } else { - if ip2domain == nil { - ip2domain = new(sync.Map) - newError("[fakedns client] create a new map").WriteToLog(session.ExportIDToError(ctx)) - } - domain := addr.Domain() - ips, err := d.dns.LookupIP(domain, dns.IPOption{true, true, false}) - if err == nil { - for _, ip := range ips { - ip2domain.Store(ip.String(), domain) - } - newError("[fakedns client] candidate ip: "+fmt.Sprintf("%v", ips), " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx)) - } else { - newError("[fakedns client] failed to look up IP for ", domain, " for xUDP buffer at ", i).Base(err).WriteToLog(session.ExportIDToError(ctx)) - } - } - } - return mb - })) - downOpt = append(downOpt, pipe.OnTransmission(func(mb buf.MultiBuffer) buf.MultiBuffer { - for i, buffer := range mb { - if buffer.UDP == nil { - continue - } - addr := buffer.UDP.Address - if addr.Family().IsIP() { - if ip2domain == nil { - continue - } - if domain, found := ip2domain.Load(addr.IP().String()); found { - buffer.UDP.Address = net.DomainAddress(domain.(string)) - newError("[fakedns client] restore domain: ", domain.(string), " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx)) - } - } else { - if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok { - fakeIp := fkr0.GetFakeIPForDomain(addr.Domain()) - buffer.UDP.Address = fakeIp[0] - newError("[fakedns client] restore FakeIP: ", buffer.UDP, fmt.Sprintf("%v", fakeIp), " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx)) - } - } - } - return mb - })) - } - uplinkReader, uplinkWriter := pipe.New(upOpt...) - downlinkReader, downlinkWriter := pipe.New(downOpt...) +func (d *DefaultDispatcher) getLink(ctx context.Context, network net.Network) (*transport.Link, *transport.Link, *limiter.Limiter, error) { + opt := pipe.OptionsFromContext(ctx) + uplinkReader, uplinkWriter := pipe.New(opt...) + downlinkReader, downlinkWriter := pipe.New(opt...) inboundLink := &transport.Link{ Reader: downlinkReader, @@ -225,9 +158,10 @@ func (d *DefaultDispatcher) getLink(ctx context.Context, network net.Network, sn if sessionInbound != nil { user = sessionInbound.User } + var limit *limiter.Limiter + var err error if user != nil && len(user.Email) > 0 { - var err error limit, err = limiter.GetLimiter(sessionInbound.Tag) if err != nil { newError("Get limit info error: ", err).AtError().WriteToLog() @@ -292,7 +226,7 @@ func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResu protocolString = resComp.ProtocolForDomainResult() } for _, p := range request.OverrideDestinationForProtocol { - if strings.HasPrefix(protocolString, p) { + if strings.HasPrefix(protocolString, p) || strings.HasPrefix(protocolString, p) { return true } if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" && @@ -316,7 +250,8 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin panic("Dispatcher: Invalid destination.") } ob := &session.Outbound{ - Target: destination, + OriginalTarget: destination, + Target: destination, } ctx = session.ContextWithOutbound(ctx, ob) content := session.ContentFromContext(ctx) @@ -325,25 +260,19 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin ctx = session.ContextWithContent(ctx, content) } sniffingRequest := content.SniffingRequest - inbound, outbound, l, err := d.getLink(ctx, destination.Network, sniffingRequest) + inbound, outbound, l, err := d.getLink(ctx, destination.Network) if err != nil { return nil, err } if !sniffingRequest.Enabled { - go d.routedDispatch(ctx, outbound, destination, l) + go d.routedDispatch(ctx, outbound, destination, l, "") } else { go func() { cReader := &cachedReader{ reader: outbound.Reader.(*pipe.Reader), } outbound.Reader = cReader - result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network, l) - if _, ok := err.(limitedError); ok { - newError(err).AtInfo().WriteToLog() - common.Close(outbound.Writer) - common.Interrupt(outbound.Reader) - return - } + result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network) if err == nil { content.Protocol = result.Protocol() } @@ -351,13 +280,21 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin domain := result.Domain() newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx)) destination.Address = net.ParseAddress(domain) - if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" { + protocol := result.Protocol() + if resComp, ok := result.(SnifferResultComposite); ok { + protocol = resComp.ProtocolForDomainResult() + } + isFakeIP := false + if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && ob.Target.Address.Family().IsIP() && fkr0.IsIPInIPPool(ob.Target.Address) { + isFakeIP = true + } + if sniffingRequest.RouteOnly && protocol != "fakedns" && protocol != "fakedns+others" && !isFakeIP { ob.RouteTarget = destination } else { ob.Target = destination } } - d.routedDispatch(ctx, outbound, destination, l) + d.routedDispatch(ctx, outbound, destination, l, content.Protocol) }() } return inbound, nil @@ -369,7 +306,8 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De return newError("Dispatcher: Invalid destination.") } ob := &session.Outbound{ - Target: destination, + OriginalTarget: destination, + Target: destination, } ctx = session.ContextWithOutbound(ctx, ob) content := session.ContentFromContext(ctx) @@ -379,83 +317,53 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De } sniffingRequest := content.SniffingRequest if !sniffingRequest.Enabled { - go d.routedDispatch(ctx, outbound, destination, nil) + d.routedDispatch(ctx, outbound, destination, nil, "") } else { - go func() { - cReader := &cachedReader{ - reader: outbound.Reader.(*pipe.Reader), + cReader := &cachedReader{ + reader: outbound.Reader.(*pipe.Reader), + } + outbound.Reader = cReader + result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network) + if err == nil { + content.Protocol = result.Protocol() + } + if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) { + domain := result.Domain() + newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx)) + destination.Address = net.ParseAddress(domain) + protocol := result.Protocol() + if resComp, ok := result.(SnifferResultComposite); ok { + protocol = resComp.ProtocolForDomainResult() } - outbound.Reader = cReader - result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network, nil) - if _, ok := err.(limitedError); ok { - newError(err).AtInfo().WriteToLog() - common.Close(outbound.Writer) - common.Interrupt(outbound.Reader) - return + isFakeIP := false + if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && ob.Target.Address.Family().IsIP() && fkr0.IsIPInIPPool(ob.Target.Address) { + isFakeIP = true } - if err == nil { - content.Protocol = result.Protocol() + if sniffingRequest.RouteOnly && protocol != "fakedns" && protocol != "fakedns+others" && !isFakeIP { + ob.RouteTarget = destination + } else { + ob.Target = destination } - if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) { - domain := result.Domain() - newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx)) - destination.Address = net.ParseAddress(domain) - if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" { - ob.RouteTarget = destination - } else { - ob.Target = destination - } - } - d.routedDispatch(ctx, outbound, destination, nil) - }() + destination.Address.Family() + } + d.routedDispatch(ctx, outbound, destination, nil, content.Protocol) } + return nil } -type limitedError string - -func (l limitedError) Error() string { - return string(l) -} - -func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network, l *limiter.Limiter) (result SniffResult, err error) { +func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) { payload := buf.New() defer payload.Release() - defer func() { - if err != nil { - return - } - // Check if domain and protocol hit the rule - sessionInbound := session.InboundFromContext(ctx) - // Whether the inbound connection contains a user - if sessionInbound.User != nil { - if l == nil { - l, err = limiter.GetLimiter(sessionInbound.Tag) - if err != nil { - return - } - } - if l.CheckDomainRule(result.Domain()) { - err = limitedError(fmt.Sprintf( - "User %s access domain %s reject by rule", - sessionInbound.User.Email, - result.Domain())) - } - if l.CheckProtocolRule(result.Protocol()) { - err = limitedError(fmt.Sprintf( - "User %s access protocol %s reject by rule", - sessionInbound.User.Email, - result.Protocol())) - } - } - }() - sniffer := NewSniffer(ctx) + metaresult, metadataErr := sniffer.SniffMetadata(ctx) + if metadataOnly { return metaresult, metadataErr } + contentResult, contentErr := func() (SniffResult, error) { totalAttempt := 0 for { @@ -490,7 +398,7 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw return contentResult, contentErr } -func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination, l *limiter.Limiter) { +func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination, l *limiter.Limiter, protocol string) { ob := session.OutboundFromContext(ctx) if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() { proxied := hosts.LookupHosts(ob.Target.String()) @@ -504,11 +412,10 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport. } } } - var handler outbound.Handler - // del connect count + sessionInbound := session.InboundFromContext(ctx) if l != nil { - sessionInbound := session.InboundFromContext(ctx) + // del connect count if sessionInbound.User != nil { if destination.Network == net.Network_TCP { defer func() { @@ -516,9 +423,46 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport. }() } } + } else { + var err error + l, err = limiter.GetLimiter(sessionInbound.Tag) + if err != nil { + newError("get limiter error: ", err).AtError().WriteToLog(session.ExportIDToError(ctx)) + common.Close(link.Writer) + common.Interrupt(link.Reader) + return + } + } + var destStr string + if destination.Address.Family().IsDomain() { + destStr = destination.Address.Domain() + } else { + destStr = destination.Address.IP().String() + } + if l.CheckDomainRule(destStr) { + newError(fmt.Sprintf( + "User %s access domain %s reject by rule", + sessionInbound.User.Email, + destStr)).AtWarning().WriteToLog(session.ExportIDToError(ctx)) + common.Close(link.Writer) + common.Interrupt(link.Reader) + return + } + if len(protocol) != 0 { + if l.CheckProtocolRule(protocol) { + newError(fmt.Sprintf( + "User %s access protocol %s reject by rule", + sessionInbound.User.Email, + protocol)).AtWarning().WriteToLog(session.ExportIDToError(ctx)) + common.Close(link.Writer) + common.Interrupt(link.Reader) + return + } } - routingLink := routingSession.AsRoutingContext(ctx) + var handler outbound.Handler + + routingLink := routing_session.AsRoutingContext(ctx) inTag := routingLink.GetInboundTag() isPickRoute := 0 if forcedOutboundTag := session.GetForcedOutboundTagFromContext(ctx); forcedOutboundTag != "" { @@ -548,11 +492,6 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport. } } - if handler == nil { - handler = d.ohm.GetHandler(inTag) // Default outbound handier tag should be as same as the inbound tag - } - - // If there is no outbound with tag as same as the inbound tag if handler == nil { handler = d.ohm.GetDefaultHandler() } diff --git a/core/xray/dns.go b/core/xray/dns.go new file mode 100644 index 0000000..8ceecde --- /dev/null +++ b/core/xray/dns.go @@ -0,0 +1,60 @@ +package xray + +import ( + "bytes" + "github.com/InazumaV/V2bX/api/panel" + "github.com/goccy/go-json" + log "github.com/sirupsen/logrus" + coreConf "github.com/xtls/xray-core/infra/conf" + "os" +) + +func updateDNSConfig(node *panel.NodeInfo) (err error) { + dnsPath := os.Getenv("XRAY_DNS_PATH") + if len(node.RawDNS.DNSJson) != 0 { + err = saveDnsConfig(node.RawDNS.DNSJson, dnsPath) + } else if len(node.RawDNS.DNSMap) != 0 { + dnsConfig := DNSConfig{ + Servers: []interface{}{ + "1.1.1.1", + "localhost"}, + Tag: "dns_inbound", + } + for _, value := range node.RawDNS.DNSMap { + dnsConfig.Servers = append(dnsConfig.Servers, value) + } + dnsConfigJSON, err := json.MarshalIndent(dnsConfig, "", " ") + if err != nil { + log.WithField("err", err).Error("Error marshaling dnsConfig to JSON") + return err + } + err = saveDnsConfig(dnsConfigJSON, dnsPath) + } + return err +} + +func saveDnsConfig(dns []byte, dnsPath string) (err error) { + currentData, err := os.ReadFile(dnsPath) + if err != nil { + log.WithField("err", err).Error("Failed to read XRAY_DNS_PATH") + return err + } + if !bytes.Equal(currentData, dns) { + coreDnsConfig := &coreConf.DNSConfig{} + if err = json.NewDecoder(bytes.NewReader(dns)).Decode(coreDnsConfig); err != nil { + log.WithField("err", err).Error("Failed to unmarshal DNS config") + } + _, err := coreDnsConfig.Build() + if err != nil { + log.WithField("err", err).Error("Failed to understand DNS config, Please check: https://xtls.github.io/config/dns.html for help") + return err + } + if err = os.Truncate(dnsPath, 0); err != nil { + log.WithField("err", err).Error("Failed to clear XRAY DNS PATH file") + } + if err = os.WriteFile(dnsPath, dns, 0644); err != nil { + log.WithField("err", err).Error("Failed to write DNS to XRAY DNS PATH file") + } + } + return err +} diff --git a/core/xray/inbound.go b/core/xray/inbound.go index fb2ae4d..34cae89 100644 --- a/core/xray/inbound.go +++ b/core/xray/inbound.go @@ -6,7 +6,7 @@ import ( "encoding/hex" "errors" "fmt" - "strconv" + "time" "github.com/InazumaV/V2bX/api/panel" "github.com/InazumaV/V2bX/conf" @@ -17,141 +17,121 @@ import ( ) // BuildInbound build Inbound config for different protocol -func buildInbound(config *conf.Options, nodeInfo *panel.NodeInfo, tag string) (*core.InboundHandlerConfig, error) { +func buildInbound(option *conf.Options, nodeInfo *panel.NodeInfo, tag string) (*core.InboundHandlerConfig, error) { in := &coreConf.InboundDetourConfig{} - // Set network protocol - t := coreConf.TransportProtocol(nodeInfo.Network) - in.StreamSetting = &coreConf.StreamConfig{Network: &t} var err error + var network string switch nodeInfo.Type { - case "v2ray": - err = buildV2ray(config, nodeInfo, in) + case "vmess", "vless": + err = buildV2ray(option, nodeInfo, in) + network = nodeInfo.VAllss.Network case "trojan": - err = buildTrojan(config, in) + err = buildTrojan(option, in) + network = "tcp" case "shadowsocks": - err = buildShadowsocks(config, nodeInfo, in) + err = buildShadowsocks(option, nodeInfo, in) + network = "tcp" default: return nil, fmt.Errorf("unsupported node type: %s, Only support: V2ray, Trojan, Shadowsocks", nodeInfo.Type) } if err != nil { return nil, err } + // Set network protocol // Set server port in.PortList = &coreConf.PortList{ - Range: []coreConf.PortRange{{From: uint32(nodeInfo.Port), To: uint32(nodeInfo.Port)}}, + Range: []coreConf.PortRange{ + { + From: uint32(nodeInfo.Common.ServerPort), + To: uint32(nodeInfo.Common.ServerPort), + }}, } // Set Listen IP address - ipAddress := net.ParseAddress(config.ListenIP) + ipAddress := net.ParseAddress(option.ListenIP) in.ListenOn = &coreConf.Address{Address: ipAddress} // Set SniffingConfig sniffingConfig := &coreConf.SniffingConfig{ Enabled: true, DestOverride: &coreConf.StringList{"http", "tls"}, } - if config.XrayOptions.DisableSniffing { + if option.XrayOptions.DisableSniffing { sniffingConfig.Enabled = false } in.SniffingConfig = sniffingConfig - if *in.StreamSetting.Network == "tcp" { + switch network { + case "tcp": if in.StreamSetting.TCPSettings != nil { - in.StreamSetting.TCPSettings.AcceptProxyProtocol = config.XrayOptions.EnableProxyProtocol + in.StreamSetting.TCPSettings.AcceptProxyProtocol = option.XrayOptions.EnableProxyProtocol } else { tcpSetting := &coreConf.TCPConfig{ - AcceptProxyProtocol: config.XrayOptions.EnableProxyProtocol, + AcceptProxyProtocol: option.XrayOptions.EnableProxyProtocol, } //Enable proxy protocol in.StreamSetting.TCPSettings = tcpSetting } - } else if *in.StreamSetting.Network == "ws" { + case "ws": in.StreamSetting.WSSettings = &coreConf.WebSocketConfig{ - AcceptProxyProtocol: config.XrayOptions.EnableProxyProtocol} //Enable proxy protocol - } - // Set TLS or Reality settings - if nodeInfo.Tls { - if config.CertConfig == nil { - return nil, errors.New("the CertConfig is not vail") - } - switch config.CertConfig.CertMode { - case "none", "": - break // disable - case "reality": - // Reality - in.StreamSetting.Security = "reality" - d, err := json.Marshal(config.CertConfig.RealityConfig.Dest) - if err != nil { - return nil, fmt.Errorf("marshal reality dest error: %s", err) - } - if len(config.CertConfig.RealityConfig.ShortIds) == 0 { - config.CertConfig.RealityConfig.ShortIds = []string{""} - } - in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{ - Dest: d, - Xver: config.CertConfig.RealityConfig.Xver, - ServerNames: config.CertConfig.RealityConfig.ServerNames, - PrivateKey: config.CertConfig.RealityConfig.PrivateKey, - MinClientVer: config.CertConfig.RealityConfig.MinClientVer, - MaxClientVer: config.CertConfig.RealityConfig.MaxClientVer, - MaxTimeDiff: config.CertConfig.RealityConfig.MaxTimeDiff, - ShortIds: config.CertConfig.RealityConfig.ShortIds, - } - break - case "remote": - if nodeInfo.ExtraConfig.EnableReality == "true" { - rc := nodeInfo.ExtraConfig.RealityConfig - in.StreamSetting.Security = "reality" - d, err := json.Marshal(rc.Dest) - if err != nil { - return nil, fmt.Errorf("marshal reality dest error: %s", err) - } - if len(rc.ShortIds) == 0 { - rc.ShortIds = []string{""} - } - Xver, _ := strconv.ParseUint(rc.Xver, 10, 64) - MaxTimeDiff, _ := strconv.ParseUint(rc.Xver, 10, 64) - in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{ - Dest: d, - Xver: Xver, - ServerNames: rc.ServerNames, - PrivateKey: rc.PrivateKey, - MinClientVer: rc.MinClientVer, - MaxClientVer: rc.MaxClientVer, - MaxTimeDiff: MaxTimeDiff, - ShortIds: rc.ShortIds, - } - break - } - default: - { - // Normal tls - in.StreamSetting.Security = "tls" - in.StreamSetting.TLSSettings = &coreConf.TLSConfig{ - Certs: []*coreConf.TLSCertConfig{ - { - CertFile: config.CertConfig.CertFile, - KeyFile: config.CertConfig.KeyFile, - OcspStapling: 3600, - }, - }, - RejectUnknownSNI: config.CertConfig.RejectUnknownSni, - } - } - } - } - // Support ProxyProtocol for any transport protocol - if *in.StreamSetting.Network != "tcp" && - *in.StreamSetting.Network != "ws" && - config.XrayOptions.EnableProxyProtocol { + AcceptProxyProtocol: option.XrayOptions.EnableProxyProtocol} //Enable proxy protocol + default: socketConfig := &coreConf.SocketConfig{ - AcceptProxyProtocol: config.XrayOptions.EnableProxyProtocol, - TFO: config.XrayOptions.EnableTFO, + AcceptProxyProtocol: option.XrayOptions.EnableProxyProtocol, + TFO: option.XrayOptions.EnableTFO, } //Enable proxy protocol in.StreamSetting.SocketSettings = socketConfig } + // Set TLS or Reality settings + switch nodeInfo.Security { + case panel.Tls: + // Normal tls + if option.CertConfig == nil { + return nil, errors.New("the CertConfig is not vail") + } + switch option.CertConfig.CertMode { + case "none", "": + break // disable + default: + in.StreamSetting.Security = "tls" + in.StreamSetting.TLSSettings = &coreConf.TLSConfig{ + Certs: []*coreConf.TLSCertConfig{ + { + CertFile: option.CertConfig.CertFile, + KeyFile: option.CertConfig.KeyFile, + OcspStapling: 3600, + }, + }, + RejectUnknownSNI: option.CertConfig.RejectUnknownSni, + } + } + case panel.Reality: + // Reality + in.StreamSetting.Security = "reality" + v := nodeInfo.VAllss + d, err := json.Marshal(fmt.Sprintf( + "%s:%s", + v.TlsSettings.ServerName, + v.TlsSettings.ServerPort)) + if err != nil { + return nil, fmt.Errorf("marshal reality dest error: %s", err) + } + mtd, _ := time.ParseDuration(v.RealityConfig.MaxTimeDiff) + in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{ + Dest: d, + Xver: v.RealityConfig.Xver, + ServerNames: []string{v.TlsSettings.ServerName}, + PrivateKey: v.TlsSettings.PrivateKey, + MinClientVer: v.RealityConfig.MinClientVer, + MaxClientVer: v.RealityConfig.MaxClientVer, + MaxTimeDiff: uint64(mtd.Microseconds()), + ShortIds: []string{v.TlsSettings.ShortId}, + } + break + } in.Tag = tag return in.Build() } func buildV2ray(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error { - if nodeInfo.ExtraConfig.EnableVless == "true" { + v := nodeInfo.VAllss + if nodeInfo.Type == "vless" { //Set vless inbound.Protocol = "vless" if config.XrayOptions.EnableFallback { @@ -188,22 +168,25 @@ func buildV2ray(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *coreCon } inbound.Settings = (*json.RawMessage)(&s) } - if len(nodeInfo.NetworkSettings) == 0 { + if len(v.NetworkSettings) == 0 { return nil } - switch nodeInfo.Network { + + t := coreConf.TransportProtocol(nodeInfo.VAllss.Network) + inbound.StreamSetting = &coreConf.StreamConfig{Network: &t} + switch v.Network { case "tcp": - err := json.Unmarshal(nodeInfo.NetworkSettings, &inbound.StreamSetting.TCPSettings) + err := json.Unmarshal(v.NetworkSettings, &inbound.StreamSetting.TCPSettings) if err != nil { return fmt.Errorf("unmarshal tcp settings error: %s", err) } case "ws": - err := json.Unmarshal(nodeInfo.NetworkSettings, &inbound.StreamSetting.WSSettings) + err := json.Unmarshal(v.NetworkSettings, &inbound.StreamSetting.WSSettings) if err != nil { return fmt.Errorf("unmarshal ws settings error: %s", err) } case "grpc": - err := json.Unmarshal(nodeInfo.NetworkSettings, &inbound.StreamSetting.GRPCConfig) + err := json.Unmarshal(v.NetworkSettings, &inbound.StreamSetting.GRPCConfig) if err != nil { return fmt.Errorf("unmarshal grpc settings error: %s", err) } @@ -239,8 +222,9 @@ func buildTrojan(config *conf.Options, inbound *coreConf.InboundDetourConfig) er func buildShadowsocks(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error { inbound.Protocol = "shadowsocks" + s := nodeInfo.Shadowsocks settings := &coreConf.ShadowsocksServerConfig{ - Cipher: nodeInfo.Cipher, + Cipher: s.Cipher, } p := make([]byte, 32) _, err := rand.Read(p) @@ -248,9 +232,9 @@ func buildShadowsocks(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *c return fmt.Errorf("generate random password error: %s", err) } randomPasswd := hex.EncodeToString(p) - cipher := nodeInfo.Cipher - if nodeInfo.ServerKey != "" { - settings.Password = nodeInfo.ServerKey + cipher := s.Cipher + if s.ServerKey != "" { + settings.Password = s.ServerKey randomPasswd = base64.StdEncoding.EncodeToString([]byte(randomPasswd)) cipher = "" } @@ -266,15 +250,15 @@ func buildShadowsocks(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *c } t := coreConf.TransportProtocol("tcp") inbound.StreamSetting = &coreConf.StreamConfig{Network: &t} - s, err := json.Marshal(settings) - inbound.Settings = (*json.RawMessage)(&s) + sets, err := json.Marshal(settings) + inbound.Settings = (*json.RawMessage)(&sets) if err != nil { return fmt.Errorf("marshal shadowsocks settings error: %s", err) } return nil } -func buildVlessFallbacks(fallbackConfigs []conf.FallBackConfig) ([]*coreConf.VLessInboundFallback, error) { +func buildVlessFallbacks(fallbackConfigs []conf.FallBackConfigForXray) ([]*coreConf.VLessInboundFallback, error) { if fallbackConfigs == nil { return nil, fmt.Errorf("you must provide FallBackConfigs") } @@ -299,7 +283,7 @@ func buildVlessFallbacks(fallbackConfigs []conf.FallBackConfig) ([]*coreConf.VLe return vlessFallBacks, nil } -func buildTrojanFallbacks(fallbackConfigs []conf.FallBackConfig) ([]*coreConf.TrojanInboundFallback, error) { +func buildTrojanFallbacks(fallbackConfigs []conf.FallBackConfigForXray) ([]*coreConf.TrojanInboundFallback, error) { if fallbackConfigs == nil { return nil, fmt.Errorf("you must provide FallBackConfigs") } diff --git a/core/xray/node.go b/core/xray/node.go index df1b23c..78fc0a8 100644 --- a/core/xray/node.go +++ b/core/xray/node.go @@ -3,7 +3,6 @@ package xray import ( "context" "fmt" - "github.com/InazumaV/V2bX/api/panel" "github.com/InazumaV/V2bX/conf" "github.com/xtls/xray-core/core" @@ -11,7 +10,16 @@ import ( "github.com/xtls/xray-core/features/outbound" ) +type DNSConfig struct { + Servers []interface{} `json:"servers"` + Tag string `json:"tag"` +} + func (c *Core) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error { + err := updateDNSConfig(info) + if err != nil { + return fmt.Errorf("build dns error: %s", err) + } inboundConfig, err := buildInbound(config, info, tag) if err != nil { return fmt.Errorf("build inbound error: %s", err) diff --git a/core/xray/user.go b/core/xray/user.go index 2fc6351..a1c86c7 100644 --- a/core/xray/user.go +++ b/core/xray/user.go @@ -71,21 +71,19 @@ func (c *Core) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int6 } func (c *Core) AddUsers(p *vCore.AddUsersParams) (added int, err error) { - users := make([]*protocol.User, 0, len(p.UserInfo)) + users := make([]*protocol.User, 0, len(p.Users)) switch p.NodeInfo.Type { - case "v2ray": - if p.NodeInfo.ExtraConfig.EnableVless == "true" { - users = buildVlessUsers(p.Tag, p.UserInfo, p.NodeInfo.ExtraConfig.VlessFlow) - } else { - users = buildVmessUsers(p.Tag, p.UserInfo) - } + case "vmess": + users = buildVmessUsers(p.Tag, p.Users) + case "vless": + users = buildVlessUsers(p.Tag, p.Users, p.VAllss.Flow) case "trojan": - users = buildTrojanUsers(p.Tag, p.UserInfo) + users = buildTrojanUsers(p.Tag, p.Users) case "shadowsocks": users = buildSSUsers(p.Tag, - p.UserInfo, - p.NodeInfo.Cipher, - p.NodeInfo.ServerKey) + p.Users, + p.Shadowsocks.Cipher, + p.Shadowsocks.ServerKey) default: return 0, fmt.Errorf("unsupported node type: %s", p.NodeInfo.Type) } diff --git a/core/xray/xray.go b/core/xray/xray.go index 96bb466..659856f 100644 --- a/core/xray/xray.go +++ b/core/xray/xray.go @@ -67,7 +67,7 @@ func getCore(c *conf.XrayConfig) *core.Instance { log.WithField("err", err).Panic("Failed to read DNS config file") } else { if err = json.NewDecoder(f).Decode(coreDnsConfig); err != nil { - log.WithField("err", err).Panic("Failed to unmarshal DNS config") + log.WithField("err", err).Error("Failed to unmarshal DNS config") } } os.Setenv("XRAY_DNS_PATH", c.DnsConfigPath) @@ -188,8 +188,13 @@ func (c *Core) Close() error { func (c *Core) Protocols() []string { return []string{ - "v2ray", + "vmess", + "vless", "shadowsocks", "trojan", } } + +func (c *Core) Type() string { + return "xray" +} diff --git a/example/config.json b/example/config.json new file mode 100644 index 0000000..34fbf26 --- /dev/null +++ b/example/config.json @@ -0,0 +1,49 @@ +{ + "Log": { + "Level": "info", + "Output": "" + }, + "Cores": [ + { + "Type": "sing", + "Log": { + "Level": "error", + "Timestamp": true + }, + "DnsConfigPath": "/etc/V2bX/dns.json", + "NTP": { + "Enable": true, + "Server": "time.apple.com", + "ServerPort": 0 + } + } + ], + "Nodes": [ + { + "Core": "sing", + "ApiHost": "http://127.0.0.1", + "ApiKey": "test", + "NodeID": 33, + "NodeType": "shadowsocks", + "Timeout": 30, + "ListenIP": "0.0.0.0", + "SendIP": "0.0.0.0", + "EnableProxyProtocol": false, + "EnableDNS": true, + "DomainStrategy": "ipv4_only", + "LimitConfig": { + "EnableRealtime": false, + "SpeedLimit": 0, + "IPLimit": 0, + "ConnLimit": 0, + "EnableDynamicSpeedLimit": false, + "DynamicSpeedLimitConfig": { + "Periodic": 60, + "Traffic": 1000, + "SpeedLimit": 100, + "ExpireTime": 60 + } + } + } + ] +} \ No newline at end of file diff --git a/example/config.yml.example b/example/config.yml.example deleted file mode 100644 index b6098de..0000000 --- a/example/config.yml.example +++ /dev/null @@ -1,117 +0,0 @@ -CoreConfig: - Type: "xray" # Core type, default support "xray" and "hy". If you need many cores, use " " to split - XrayConfig: - Log: - Level: warning # Log level: none, error, warning, info, debug - AccessPath: # /etc/XrayR/access.Log - ErrorPath: # /etc/XrayR/error.log - DnsConfigPath: # /etc/XrayR/dns.json # Path to dns config, check https://xtls.github.io/config/dns.html for help - RouteConfigPath: # /etc/XrayR/route.json # Path to route config, check https://xtls.github.io/config/routing.html for help - InboundConfigPath: # /etc/XrayR/custom_inbound.json # Path to custom inbound config, check https://xtls.github.io/config/inbound.html for help - OutboundConfigPath: # /etc/XrayR/custom_outbound.json # Path to custom outbound config, check https://xtls.github.io/config/outbound.html for help - ConnectionConfig: - Handshake: 4 # Handshake time limit, Second - ConnIdle: 30 # Connection idle time limit, Second - UplinkOnly: 2 # Time limit when the connection downstream is closed, Second - DownlinkOnly: 4 # Time limit when the connection is closed after the uplink is closed, Second - BufferSize: 64 # The internal cache size of each connection, kB -Nodes: - - ApiConfig: - ApiHost: "http://127.0.0.1:667" - ApiKey: "123" - NodeID: 41 - NodeType: V2ray # Node type: V2ray, Shadowsocks, Trojan - Timeout: 30 # Timeout for the api request - RuleListPath: # /etc/XrayR/rulelist Path to local rulelist file - ControllerConfig: - ListenIP: 0.0.0.0 # IP address you want to listen - SendIP: 0.0.0.0 # IP address you want to send pacakage - XrayOptions: - EnableDNS: false # Use custom DNS config, Please ensure that you set the dns.json well - DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy - EnableTFO: false # Enable TCP Fast Open - EnableProxyProtocol: false # Only works for WebSocket and TCP - EnableFallback: false # Only support for Trojan and Vless - FallBackConfigs: # Support multiple fallbacks - - SNI: # TLS SNI(Server Name Indication), Empty for any - Alpn: # Alpn, Empty for any - Path: # HTTP PATH, Empty for any - Dest: 80 # Required, Destination of fallback, check https://xtls.github.io/config/features/fallback.html for details. - ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for disable - HyOptions: - Resolver: "udp://1.1.1.1:53" # DNS resolver address - ResolvePreference: 64 # DNS IPv4/IPv6 preference. Available options: "64" (IPv6 first, fallback to IPv4), "46" (IPv4 first, fallback to IPv6), "6" (IPv6 only), "4" (IPv4 only) - SendDevice: "eth0" # Bind device for outbound connections (usually requires root) - LimitConfig: - EnableRealtime: false # Check device limit on real time - SpeedLimit: 0 # Mbps, Local settings will replace remote settings, 0 means disable - DeviceLimit: 0 # Local settings will replace remote settings, 0 means disable - ConnLimit: 0 # Connecting limit, only working for TCP, 0mean - EnableIpRecorder: false # Enable online ip report - IpRecorderConfig: - Type: "Recorder" # Recorder type: Recorder, Redis - RecorderConfig: - Url: "http://127.0.0.1:123" # Report url - Token: "123" # Report token - Timeout: 10 # Report timeout, sec. - RedisConfig: - Address: "127.0.0.1:6379" # Redis address - Password: "" # Redis password - DB: 0 # Redis DB - Expiry: 60 # redis expiry time, sec. - Periodic: 60 # Report interval, sec. - EnableIpSync: false # Enable online ip sync - EnableDynamicSpeedLimit: false # Enable dynamic speed limit - DynamicSpeedLimitConfig: - Periodic: 60 # Time to check the user traffic , sec. - Traffic: 0 # Traffic limit, MB - SpeedLimit: 0 # Speed limit, Mbps - ExpireTime: 0 # Time limit, sec. - CertConfig: - CertMode: dns # Option about how to get certificate: none, file, http, dns, reality, remote. Choose "none" will forcedly disable the tls config. - CertDomain: "node1.test.com" # Domain to cert - CertFile: /etc/XrayR/cert/node1.test.com.cert # Provided if the CertMode is file - KeyFile: /etc/XrayR/cert/node1.test.com.key - Provider: alidns # DNS cert provider, Get the full support list here: https://go-acme.github.io/lego/dns/ - Email: test@me.com - DNSEnv: # DNS ENV option used by DNS provider - ALICLOUD_ACCESS_KEY: aaa - ALICLOUD_SECRET_KEY: bbb - RealityConfig: # This config like RealityObject for xray-core, please check https://xtls.github.io/config/transport.html#realityobject - Dest: 80 # Same fallback dest - Xver: 0 # Same fallback xver - ServerNames: - - "example.com" - - "www.example.com" - PrivateKey: "" # Private key for server - MinClientVer: "" # Min client version - MaxClientVer: "" # Max client version - MaxTimeDiff: 0 # Max time difference, ms - ShortIds: # Short ids - - "" - - "0123456789abcdef" - # - - # ApiConfig: - # ApiHost: "http://127.0.0.1:668" - # ApiKey: "123" - # NodeID: 4 - # NodeType: Shadowsocks # Node type: V2ray, Shadowsocks, Trojan - # Timeout: 30 # Timeout for the api request - # EnableVless: false # Enable Vless for V2ray Type - # EnableXTLS: false # Enable XTLS for V2ray and Trojan - # SpeedLimit: 0 # Mbps, Local settings will replace remote settings - # DeviceLimit: 0 # Local settings will replace remote settings - # ControllerConfig: - # ListenIP: 0.0.0.0 # IP address you want to listen - # EnableDNS: false # Use custom DNS config, Please ensure that you set the dns.json well - # CertConfig: - # CertMode: dns # Option about how to get certificate: none, file, http, dns - # CertDomain: "node1.test.com" # Domain to cert - # CertFile: /etc/XrayR/cert/node1.test.com.cert # Provided if the CertMode is file - # KeyFile: /etc/XrayR/cert/node1.test.com.pem - # Provider: alidns # DNS cert provider, Get the full support list here: https://go-acme.github.io/lego/dns/ - # Email: test@me.com - # DNSEnv: # DNS ENV option used by DNS provider - # ALICLOUD_ACCESS_KEY: aaa - # ALICLOUD_SECRET_KEY: bbb - diff --git a/example/config_full.json b/example/config_full.json new file mode 100644 index 0000000..a188bd7 --- /dev/null +++ b/example/config_full.json @@ -0,0 +1,259 @@ +{ + "Log": { + // V2bX 的日志配置,独立于各 Core 的 log 配置 + + // 日志等级,info, warn, error, none + "Level": "error", + // 日志输出路径,默认输出到标准输出 + "Output": "" + }, + "Cores": [ + { + // Core类型 + "Type": "sing", + // Core标识名,可选,如果需要启动多个同类型内核则必填 + "Name": "sing1", + "Log": { + // 同 SingBox log 部分配置 + + "Level": "error", + "Timestamp": true + }, + "NTP": { + // 同 SingBox ntp 部分配置 + // VMess VLESS 建议开启 + "Enable": true, + "Server": "time.apple.com", + "ServerPort": 0 + }, + "DnsConfigPath": "/etc/V2bX/dns.json", + // SingBox源配置文件目录,用于引用标准SingBox配置文件 + "OriginalPath": "/etc/V2bX/sing_origin.json" + }, + { + "Type": "sing", + "Name": "sing2", + "Log": { + "Level": "info", + "Timestamp": false + } + }, + { + "Type": "xray", + "Log": { + // 同 Xray-core log 部分配置 + + "Level": "error" + }, + // 静态资源文件目录 + "AssetPath": "", + // DNS配置文件目录 + "DnsConfigPath": "", + // 路由配置文件目录 + "RouteConfigPath": "", + // 本地策略相关配置 + "ConnectionConfig": { + // 详见 https://xtls.github.io/config/policy.html#levelpolicyobject + + "handshake": 4, + "connIdle": 300, + "uplinkOnly": 2, + "downlinkOnly": 5, + "statsUserUplink": false, + "statsUserDownlink": false, + "bufferSize": 4 + }, + // Inbound配置文件目录 + "InboundConfigPath": "", + // Outbound配置文件目录 + "OutboundConfigPath": "" + } + ], + "Nodes": [ + // Node配置有两种写法 + { + // 写法1 + // sing内核 + + // Node标识名,便于查看日志,不填将通过下发的节点配置自动生成 + // 务必注意不要重复,否则会出现问题 + "Name": "sing_node1", + + // 要使用的Core的类型 + // 如果填写了CoreName可不填,但单内核务必填写 + // 建议视情况填写Core和CoreName其中一个,如果均没有填写将随机选择支持的内核 + "Core": "sing", + + // 要使用的Core的标识名,如果没有定义多个同类型内核可不填 + "CoreName": "sing1", + + // API接口地址 + "ApiHost": "http://127.0.0.1", + + // API密钥,即Token + "ApiKey": "test", + + // 节点ID + "NodeID": 33, + + // 节点类型 + "NodeType": "shadowsocks", + + // 请求超时时间 + "Timeout": 30, + + // 监听IP + "ListenIP": "0.0.0.0", + + // 发送IP + "SendIP": "0.0.0.0", + + // 开启 Proxy Protocol,参见 https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt + "EnableProxyProtocol": false, + + // 开启 TCP Fast Open + "EnableTFO": true, + + // 开启 DNS + "EnableDNS" : true, + // 设置 Domain Strategy 需要开启 DNS ,默认 AsIS + // 可选 prefer_ipv4 / prefer_ipv6 / ipv4_only / ipv6_only + "DomainStrategy": "ipv4_only", + + // 限制器相关配置 + "LimitConfig": { + // 开启实时连接数及IP数限制 + "EnableRealtime": false, + + // 用户速度限制 + "SpeedLimit": 0, + + // 用户IP限制 + "IPLimit": 0, + + // 用户连接数限制 + "ConnLimit": 0, + + // 开启动态限速 + "EnableDynamicSpeedLimit": false, + + // 动态限速相关配置 + "DynamicSpeedLimitConfig": { + // 检查周期 + "Periodic": 60, + + // 检查周期内触发限制的流量数 + "Traffic": 1000, + + // 触发限制后的速度限制 + "SpeedLimit": 100, + + // 速度限制过期时间 + "ExpireTime": 60 + + } + }, + + // 证书相关配置 + "CertConfig": { + // 证书申请模式,none、http、dns、self + "CertMode": "none", + + "RejectUnknownSni": false, + + // 证书域名 + "CertDomain": "test.com", + + // 证书文件目录 + "CertFile": "/etc/V2bX/cert/1.pem", + + // 密钥文件目录 + "KeyFile": "/etc/V2bX/cert/1.key", + + // 申请证书时使用的用户邮箱 + "Email": "1@test.com", + + // DNS解析提供者 + "Provider": "cloudflare", + + // DNS解析提供者的环境变量,详见 https://go-acme.github.io/lego/dns/ + "DNSEnv": { + "EnvName": "env1" + } + } + }, + { + // xray内核 + + "Name": "xray_node1", + "Core": "xray", + "CoreName": "", + "ApiHost": "http://127.0.0.1", + "ApiKey": "test", + "NodeID": 33, + "NodeType": "shadowsocks", + "Timeout": 30, + "ListenIP": "0.0.0.0", + "SendIP": "0.0.0.0", + "EnableProxyProtocol": true, + "EnableTFO": true, + // 以上同 sing + + // 开启自定义DNS + "EnableDNS": false, + + // DNS解析类型,AsIs、UseIP、UseIPv4、UseIPv6 + "DNSType": "AsIs", + + // 开启udp over tcp + "EnableUot": false, + + // 禁用IVCheck + "DisableIVCheck": false, + + // 禁用嗅探 + "DisableSniffing": false, + + // 开启回落 + "EnableFallback": false, + + // 回落相关配置 + "FallBackConfigs":{ + // 详见 https://xtls.github.io/config/features/fallback.html#fallbackobject + + "SNI": "", + "Alpn": "", + "Path": "", + "Dest": "", + "ProxyProtocolVer": 0 + } + }, + { + // 写法2 + + // 类似旧配置文件 ApiConfig 部分 + "ApiConfig": { + "ApiHost": "http://127.0.0.1", + "ApiKey": "test", + "NodeID": 33, + "Timeout": 30 + }, + // 类似旧配置文件 ControllerConfig 部分 + "Options": { + "Core": "sing", + "EnableProxyProtocol": true, + "EnableTFO": true, + "DomainStrategy": "ipv4_only" + // More + } + }, + { + // 引用本地其他配置文件 + "Include": "../example/config_full_node1.json" + }, + { + // 通过Http引用远端配置文件 + "Include": "http://127.0.0.1:11451/config_full_node1.json" + } + ] +} \ No newline at end of file diff --git a/example/config_full_node1.json b/example/config_full_node1.json new file mode 100644 index 0000000..85b1caf --- /dev/null +++ b/example/config_full_node1.json @@ -0,0 +1,13 @@ +{ + "Core": "xray", + "ApiHost": "https://127.0.0.1", + "ApiKey": "key", + "NodeID": 1, + "NodeType": "vmess", + "Timeout": 30, + "ListenIP": "0.0.0.0", + "SendIP": "0.0.0.0", + "EnableProxyProtocol": false, + "EnableTFO": true, + "DNSType": "ipv4_only" +} \ No newline at end of file diff --git a/example/rulelist b/example/rulelist deleted file mode 100644 index 1182665..0000000 --- a/example/rulelist +++ /dev/null @@ -1,3 +0,0 @@ -(.+\.|^)(360|so)\.(cn|com) -baidu.com -google.com \ No newline at end of file diff --git a/go.mod b/go.mod index 40073d0..4d7eabe 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,10 @@ module github.com/InazumaV/V2bX -go 1.19 +go 1.21 require ( - github.com/Yuzuki616/hysteria/core v0.0.0-20230722103310-05508b7e5490 - github.com/Yuzuki616/quic-go v0.34.1 github.com/beevik/ntp v1.2.0 github.com/dustin/go-humanize v1.0.1 - github.com/folbricht/routedns v0.1.20 github.com/fsnotify/fsnotify v1.6.0 github.com/go-acme/lego/v4 v4.13.2 github.com/go-chi/chi/v5 v5.0.10 @@ -15,22 +12,21 @@ require ( github.com/go-resty/resty/v2 v2.7.0 github.com/goccy/go-json v0.10.2 github.com/hashicorp/go-multierror v1.1.1 - github.com/inazumav/sing-box v0.0.0-20230730105931-e8479113c010 + github.com/inazumav/sing-box v0.0.0-20230910163731-3c2fdcaf9d80 github.com/juju/ratelimit v1.0.2 - github.com/oschwald/geoip2-golang v1.9.0 - github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a + github.com/sagernet/sing v0.2.10-0.20230907044649-03c21c0a1205 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 - github.com/xtls/xray-core v1.8.3 - golang.org/x/crypto v0.11.0 - golang.org/x/sys v0.10.0 + github.com/xtls/xray-core v1.8.4 + golang.org/x/crypto v0.13.0 + golang.org/x/sys v0.12.0 google.golang.org/protobuf v1.31.0 - gopkg.in/yaml.v3 v3.0.1 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( berty.tech/go-libtor v1.0.385 // indirect - cloud.google.com/go/compute v1.19.1 // indirect + cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect @@ -52,20 +48,18 @@ require ( github.com/Dreamacro/clash v1.17.0 // indirect github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 // indirect github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect - github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91 // indirect github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/aws/aws-sdk-go v1.39.0 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect - github.com/caddyserver/certmagic v0.19.0 // indirect + github.com/caddyserver/certmagic v0.19.2 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/civo/civogo v0.3.11 // indirect github.com/cloudflare/circl v1.3.3 // indirect github.com/cloudflare/cloudflare-go v0.70.0 // indirect - github.com/coreos/go-iptables v0.6.0 // indirect github.com/cpu/goacmedns v0.1.1 // indirect github.com/cretz/bine v0.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -77,42 +71,41 @@ require ( github.com/exoscale/egoscale v0.100.1 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/gaukas/godicttls v0.0.3 // indirect + github.com/gaukas/godicttls v0.0.4 // indirect github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 // indirect github.com/go-errors/errors v1.0.1 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gofrs/uuid/v5 v5.0.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect + github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect + github.com/google/s2a-go v0.1.4 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.7.1 // indirect + github.com/googleapis/gax-go/v2 v2.11.0 // indirect github.com/gophercloud/gophercloud v1.0.0 // indirect github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.4 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/jtacoma/uritemplates v1.0.0 // indirect github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect - github.com/klauspost/compress v1.16.6 // indirect + github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect github.com/labbsr0x/goh v1.0.1 // indirect @@ -122,11 +115,6 @@ require ( github.com/liquidweb/liquidweb-cli v0.6.9 // indirect github.com/liquidweb/liquidweb-go v1.6.3 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect - github.com/lucas-clemente/quic-go v0.31.1 // indirect - github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect - github.com/marten-seemann/qpack v0.3.0 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.4 // indirect - github.com/marten-seemann/qtls-go1-19 v0.1.2 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mholt/acmez v1.2.0 // indirect github.com/miekg/dns v1.1.55 // indirect @@ -145,46 +133,41 @@ require ( github.com/nrdcg/nodion v0.1.0 // indirect github.com/nrdcg/porkbun v0.2.0 // indirect github.com/nzdjb/go-metaname v1.0.0 // indirect - github.com/onsi/ginkgo/v2 v2.11.0 // indirect + github.com/onsi/ginkgo/v2 v2.12.0 // indirect github.com/ooni/go-libtor v1.1.8 // indirect github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect - github.com/oschwald/maxminddb-golang v1.11.0 // indirect + github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/ovh/go-ovh v1.4.1 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect - github.com/pion/dtls/v2 v2.2.4 // indirect - github.com/pion/logging v0.2.2 // indirect - github.com/pion/transport/v2 v2.0.0 // indirect - github.com/pion/udp v0.1.4 // indirect github.com/pires/go-proxyproto v0.7.0 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pquerna/otp v1.4.0 // indirect - github.com/quic-go/qtls-go1-18 v0.2.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect - github.com/quic-go/quic-go v0.35.1 // indirect - github.com/refraction-networking/utls v1.3.2 // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/qtls-go1-20 v0.3.3 // indirect + github.com/quic-go/quic-go v0.38.1 // indirect + github.com/refraction-networking/utls v1.4.3 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/sacloud/api-client-go v0.2.8 // indirect github.com/sacloud/go-http v0.1.6 // indirect github.com/sacloud/iaas-api-go v1.11.1 // indirect github.com/sacloud/packages-go v0.0.9 // indirect - github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 // indirect + github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/quic-go v0.0.0-20230615020047-10f05c797c02 // indirect + github.com/sagernet/quic-go v0.0.0-20230831052420-45809eee2e86 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect - github.com/sagernet/sing-dns v0.1.8 // indirect - github.com/sagernet/sing-mux v0.1.2 // indirect - github.com/sagernet/sing-shadowsocks v0.2.4 // indirect - github.com/sagernet/sing-shadowsocks2 v0.1.3 // indirect + github.com/sagernet/sing-dns v0.1.9-0.20230824120133-4d5cbceb40c1 // indirect + github.com/sagernet/sing-mux v0.1.3-0.20230907005326-7befbadbf314 // indirect + github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0 // indirect + github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect - github.com/sagernet/sing-tun v0.1.10-0.20230723061951-767ce42377f1 // indirect - github.com/sagernet/sing-vmess v0.1.7 // indirect + github.com/sagernet/sing-tun v0.1.12-0.20230821065522-7545dc2d5641 // indirect + github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect - github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect + github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c // indirect @@ -202,15 +185,12 @@ require ( github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 // indirect github.com/transip/gotransip/v6 v6.20.0 // indirect - github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf // indirect - github.com/txthinking/socks5 v0.0.0-20220212043548-414499347d4a // indirect - github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe // indirect github.com/ultradns/ultradns-go-sdk v1.5.0-20230427130837-23c9b0c // indirect github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect github.com/vinyldns/go-vinyldns v0.9.16 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/vultr/govultr/v2 v2.17.2 // indirect - github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983 // indirect + github.com/xtls/reality v0.0.0-20230828171259-e426190d57f6 // indirect github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f // indirect github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997 // indirect github.com/zeebo/blake3 v0.2.3 // indirect @@ -218,24 +198,27 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect - go.uber.org/zap v1.24.0 // indirect - go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 // indirect - golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect - golang.org/x/mod v0.11.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/oauth2 v0.9.0 // indirect - golang.org/x/text v0.11.0 // indirect + go.uber.org/zap v1.25.0 // indirect + go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.10.0 // indirect - google.golang.org/api v0.114.0 // indirect + golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect + google.golang.org/api v0.126.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.56.2 // indirect + google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/grpc v1.58.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ns1/ns1-go.v2 v2.7.6 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gvisor.dev/gvisor v0.0.0-20230822212503-5bf4e5f98744 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) -exclude gvisor.dev/gvisor v0.0.0-20230313184804-9bf6dd27710d +replace github.com/sagernet/sing-shadowsocks v0.2.4 => github.com/inazumav/sing-shadowsocks v0.0.0-20230815111927-7c68cbaeec5c diff --git a/go.sum b/go.sum index f40ffa0..264ba5e 100644 --- a/go.sum +++ b/go.sum @@ -9,15 +9,13 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/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.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= @@ -39,9 +37,11 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aov github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0 h1:8iR6OLffWWorFdzL2JFCab5xpD8VKEE2DUBBl+HNTDY= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0/go.mod h1:copqlcjMWc/wgQ1N2fzsJFQxDdqKGg1EQt8T5wJMOGE= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2/go.mod h1:FbdwsQ2EzwvXxOPcMFYO8ogEc9uMMIj3YkmCdXdAFmk= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0 h1:rR8ZW79lE/ppfXTfiYSnMFv5EzmVuY4pfZWIkscIJ64= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0/go.mod h1:y2zXtLSMM/X5Mfawq0lOftpWn3f4V6OCsRdINsvWBPI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.24 h1:1fIGgHKqVm54KIPT+q8Zmd1QlVsmHqeUGso5qm2BqqE= @@ -73,12 +73,6 @@ github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158/go.mod h1:Qvm github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24= github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= -github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91 h1:vX+gnvBc56EbWYrmlhYbFYRaeikAke1GL84N4BEYOFE= -github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91/go.mod h1:cDLGBht23g0XQdLjzn6xOGXDkLK182YfINAaZEQLCHQ= -github.com/Yuzuki616/hysteria/core v0.0.0-20230722103310-05508b7e5490 h1:OqS0ywNFR0fEWteLyTcexUNkpdb3vTl5EdMn9gMJMCc= -github.com/Yuzuki616/hysteria/core v0.0.0-20230722103310-05508b7e5490/go.mod h1:Byg39a10tXQ6ysRz5r59YhVMUKgXAThI+0/LcVr+WOE= -github.com/Yuzuki616/quic-go v0.34.1 h1:9Is+Dofzn6qJ9a9t4Ixe4oX7Cb4LU7u4zDozVB8DBDY= -github.com/Yuzuki616/quic-go v0.34.1/go.mod h1:089qZpsXn7CL8kE7G2HurF0bLiZnzQdRIrT7PM0MMQs= github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 h1:F1j7z+/DKEsYqZNoxC6wvfmaiDneLsQOFQmuq9NADSY= github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2/go.mod h1:QlXr/TrICfQ/ANa76sLeQyhAJyNR9sEcfNuZBkY9jgY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -98,7 +92,8 @@ github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/ntp v1.2.0 h1:n1teVGbd4YM36FlGvWYfccBIdGzeaakHrTlo6RSL8mw= github.com/beevik/ntp v1.2.0/go.mod h1:vD6h1um4kzXpqmLTuu0cCLcC+NfvC0IC+ltmEDA8E78= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -110,8 +105,8 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw= github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= -github.com/caddyserver/certmagic v0.19.0 h1:HuJ1Yf1H1jAfmBGrSSQN1XRkafnWcpDtyIiyMV6vmpM= -github.com/caddyserver/certmagic v0.19.0/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8= +github.com/caddyserver/certmagic v0.19.2 h1:HZd1AKLx4592MalEGQS39DKs2ZOAJCEM/xYPMQ2/ui0= +github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -131,12 +126,13 @@ github.com/cloudflare/cloudflare-go v0.70.0 h1:4opGbUygM8DjirUuaz23jn3akuAcnOCEx github.com/cloudflare/cloudflare-go v0.70.0/go.mod h1:VW6GuazkaZ4xEDkFt24lkXQUsE8q7BiGqDniC2s8WEM= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= -github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -167,6 +163,7 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dnsimple/dnsimple-go v1.2.0 h1:ddTGyLVKly5HKb5L65AkLqFqwZlWo3WnR0BlFZlIddM= github.com/dnsimple/dnsimple-go v1.2.0/go.mod h1:z/cs26v/eiRvUyXsHQBLd8lWF8+cD6GbmkPH84plM4U= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -183,11 +180,10 @@ github.com/exoscale/egoscale v0.100.1 h1:iXsV1Ei7daqe/6FYSCSDyrFs1iUG1l1X9qNh2uM github.com/exoscale/egoscale v0.100.1/go.mod h1:BAb9p4rmyU+Wl400CJZO5270H2sXtdsZjLcm5xMKkz4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/folbricht/routedns v0.1.20 h1:OCbHLzgcctbp+GRE4QVfnZYd1du3G0muO/Ba9o4QCsw= -github.com/folbricht/routedns v0.1.20/go.mod h1:D8Vd2zJKkIQncvKTBJyed2poKqgpWKFhwIFGdWxnmCQ= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -195,8 +191,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gaukas/godicttls v0.0.3 h1:YNDIf0d9adcxOijiLrEzpfZGAkNwLRzPaG6OjU7EITk= -github.com/gaukas/godicttls v0.0.3/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= +github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= +github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4= @@ -219,8 +215,9 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -239,10 +236,12 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78 github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b h1:/vQ+oYKu+JoyaMPDsv5FzwuL2wwWBgBbtj/YLCi4LuA= +github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw= github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -256,8 +255,9 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= 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= @@ -295,21 +295,22 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 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-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f h1:pDhu5sgp8yJlEF/g6osliIIpF9K4F5jvkULXa4daRDQ= +github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -320,8 +321,8 @@ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= 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/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= +github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= github.com/gophercloud/gophercloud v1.0.0 h1:9nTGx0jizmHxDobe4mck89FyQHVyA3CaXLIUSGJjP9k= github.com/gophercloud/gophercloud v1.0.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c= @@ -350,6 +351,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= @@ -366,8 +368,6 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 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/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4= -github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= @@ -379,8 +379,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df h1:MZf03xP9WdakyXhOWuAD5uPK3wHh96wCsqe3hCMKh8E= github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= -github.com/inazumav/sing-box v0.0.0-20230730105931-e8479113c010 h1:AbH2HERgLu8Jgi4vHi8aRvkds+biIqxw+Btz3L+XTJY= -github.com/inazumav/sing-box v0.0.0-20230730105931-e8479113c010/go.mod h1:W91us/coe3lvl5jCtw2n6acyagpRbOO16h1IV3/0nrc= +github.com/inazumav/sing-box v0.0.0-20230910163731-3c2fdcaf9d80 h1:fIFH9MUmiAW6hQx4pJ0EB7We3aBQOLqKsTCyBKmrg7c= +github.com/inazumav/sing-box v0.0.0-20230910163731-3c2fdcaf9d80/go.mod h1:kNWj0m7bf+gpBzGcyQ3prgc5+Q0UzvlL4VEjjRUfV3c= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= @@ -388,6 +388,7 @@ github.com/infobloxopen/infoblox-go-client v1.1.1 h1:728A6LbLjptj/7kZjHyIxQnm768 github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= +github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -402,8 +403,6 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u 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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtacoma/uritemplates v1.0.0 h1:xwx5sBF7pPAb0Uj8lDC1Q/aBPpOFyQza7OC705ZlLCo= -github.com/jtacoma/uritemplates v1.0.0/go.mod h1:IhIICdE9OcvgUnGwTtJxgBQ+VrTrti5PcbLVSJianO8= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI= github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= @@ -412,8 +411,8 @@ github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcM github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= -github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= @@ -426,6 +425,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -461,22 +461,12 @@ github.com/liquidweb/liquidweb-go v1.6.3 h1:NVHvcnX3eb3BltiIoA+gLYn15nOpkYkdizOE github.com/liquidweb/liquidweb-go v1.6.3/go.mod h1:SuXXp+thr28LnjEw18AYtWwIbWMHSUiajPQs8T9c/Rc= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/lucas-clemente/quic-go v0.31.1 h1:O8Od7hfioqq0PMYHDyBkxU2aA7iZ2W9pjbrWuja2YR4= -github.com/lucas-clemente/quic-go v0.31.1/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g= -github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= -github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE= -github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g= -github.com/marten-seemann/qtls-go1-18 v0.1.4 h1:ogomB+lWV3Vmwiu6RTwDVTMGx+9j7SEi98e8QB35Its= -github.com/marten-seemann/qtls-go1-18 v0.1.4/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-19 v0.1.2 h1:ZevAEqKXH0bZmoOBPiqX2h5rhQ7cbZi+X+rlq2JUbCE= -github.com/marten-seemann/qtls-go1-19 v0.1.2/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -484,6 +474,7 @@ github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= @@ -496,6 +487,7 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= +github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= @@ -558,25 +550,25 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI= +github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/ooni/go-libtor v1.1.8 h1:Wo3V3DVTxl5vZdxtQakqYP+DAHx7pPtAFSl1bnAa08w= github.com/ooni/go-libtor v1.1.8/go.mod h1:q1YyLwRD9GeMyeerVvwc0vJ2YgwDLTp2bdVcrh/JXyI= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/oracle/oci-go-sdk v24.3.0+incompatible h1:x4mcfb4agelf1O4/1/auGlZ1lr97jXRSSN5MxTgG/zU= github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= -github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc= -github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y= -github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0= -github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg= +github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= +github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= github.com/ovh/go-ovh v1.4.1 h1:VBGa5wMyQtTP7Zb+w97zRCh9sLtM/2YKRyy+MEJmWaM= github.com/ovh/go-ovh v1.4.1/go.mod h1:6bL6pPyUT7tBfI0pqOegJgRjgjuO+mOo+MyXd1EEC0M= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -585,14 +577,7 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pion/dtls/v2 v2.2.4 h1:YSfYwDQgrxMYXLBc/m7PFY5BVtWlNm/DN4qoU2CbcWg= -github.com/pion/dtls/v2 v2.2.4/go.mod h1:WGKfxqhrddne4Kg3p11FUMJrynkOY4lb25zHNO49wuw= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= -github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/transport/v2 v2.0.0 h1:bsMYyqHCbkvHwj+eNCFBuxtlKndKfyGI2vaQmM3fIE4= -github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc= -github.com/pion/udp v0.1.4 h1:OowsTmu1Od3sD6i3fQUJxJn2fEvJO6L1TidgadtbTI8= -github.com/pion/udp v0.1.4/go.mod h1:G8LDo56HsFwC24LIcnT4YIDU5qcB6NepqqjP0keL2us= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= @@ -628,16 +613,14 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U= -github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc= -github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= -github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= -github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/quic-go/quic-go v0.35.1 h1:b0kzj6b/cQAf05cT0CkQubHM31wiA+xH3IBkxP62poo= -github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g= -github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8= -github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= +github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE= +github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4= +github.com/refraction-networking/utls v1.4.3 h1:BdWS3BSzCwWCFfMIXP3mjLAyQkdmog7diaD/OqFbAzM= +github.com/refraction-networking/utls v1.4.3/go.mod h1:4u9V/awOSBrRw6+federGmVJQfPtemEqLBXkML1b0bo= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -645,7 +628,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -658,40 +642,40 @@ github.com/sacloud/iaas-api-go v1.11.1 h1:2MsFZ4H1uRdRVx2nVXuERWQ3swoFc3XreIV5hJ github.com/sacloud/iaas-api-go v1.11.1/go.mod h1:uBDSa06F/V0OnoR66jGdbH0PVnCJw+NeE9RVbVgMfss= github.com/sacloud/packages-go v0.0.9 h1:GbinkBLC/eirFhHpLjoDW6JV7+95Rnd2d8RWj7Afeks= github.com/sacloud/packages-go v0.0.9/go.mod h1:k+EEUMF2LlncjbNIJNOqLyZ9wjTESPIWIk1OA7x9j2Q= -github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 h1:KyhtFFt1Jtp5vW2ohNvstvQffTOQ/s5vENuGXzdA+TM= -github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I= +github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a h1:wZHruBxZCsQLXHAozWpnJBL3wJ/XufDpz0qKtgpSnA4= +github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a/go.mod h1:dNV1ZP9y3qx5ltULeKaQZTZWTLHflgW5DES+Ses7cMI= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 h1:dnkKrzapqtAwjTSWt6hdPrARORfoYvuUczynvRLrueo= github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2/go.mod h1:1JUiV7nGuf++YFm9eWZ8q2lrwHmhcUGzptMl/vL1+LA= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/quic-go v0.0.0-20230615020047-10f05c797c02 h1:9S+L1n/4hbe1pCLNTZnnddSNseQda8tuSm/+uRy6p8s= -github.com/sagernet/quic-go v0.0.0-20230615020047-10f05c797c02/go.mod h1:rth94YcHJfkC4mG03JTXmv7mJsDc8MOIIqQrCtoaV4U= +github.com/sagernet/quic-go v0.0.0-20230831052420-45809eee2e86 h1:g4TEg9inAtA1FDTXpNrvmx72nN5mTOLQrJce6fVxF9g= +github.com/sagernet/quic-go v0.0.0-20230831052420-45809eee2e86/go.mod h1:O4Cj7TmMOvqD6S0XMqJRZfcYzA3m0H0ARbbaJFB0p7A= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.9 h1:3wsTz+JG5Wzy65eZnh6AuCrD2QqcRF6Iq6f7ttmJsAo= -github.com/sagernet/sing v0.2.9/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-dns v0.1.8 h1:zTYnxzA7mssg/Lwd70+RFPi8i3djioGnVS7zKwSF6cg= -github.com/sagernet/sing-dns v0.1.8/go.mod h1:lHv8WMl9GKfMV8Wt1AJTtjVTF/h5/owpGY2YutYZF6g= -github.com/sagernet/sing-mux v0.1.2 h1:av2/m6e+Gh+ECTuJZqYCjJz55BNkot0VyRMkREqyF/g= -github.com/sagernet/sing-mux v0.1.2/go.mod h1:r2V8AlOzXaRCHXK7fILCUGzuI2iILweTaG8C5xlpHxo= -github.com/sagernet/sing-shadowsocks v0.2.4 h1:s/CqXlvFAZhlIoHWUwPw5CoNnQ9Ibki9pckjuugtVfY= -github.com/sagernet/sing-shadowsocks v0.2.4/go.mod h1:80fNKP0wnqlu85GZXV1H1vDPC/2t+dQbFggOw4XuFUM= -github.com/sagernet/sing-shadowsocks2 v0.1.3 h1:WXoLvCFi5JTFBRYorf1YePGYIQyJ/zbsBM6Fwbl5kGA= -github.com/sagernet/sing-shadowsocks2 v0.1.3/go.mod h1:DOhJc/cLeqRv0wuePrQso+iUmDxOnWF4eT/oMcRzYFw= +github.com/sagernet/sing v0.2.10-0.20230907044649-03c21c0a1205 h1:U/OwMlCH1XFjrDrw5BESGxGsnynT6nDnHvNI9Xv0U78= +github.com/sagernet/sing v0.2.10-0.20230907044649-03c21c0a1205/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= +github.com/sagernet/sing-dns v0.1.9-0.20230824120133-4d5cbceb40c1 h1:5w+jXz8y/8UQAxO74TjftN5okYkpg5mGvVxXunlKdqI= +github.com/sagernet/sing-dns v0.1.9-0.20230824120133-4d5cbceb40c1/go.mod h1:Kg98PBJEg/08jsNFtmZWmPomhskn9Ausn50ecNm4M+8= +github.com/sagernet/sing-mux v0.1.3-0.20230907005326-7befbadbf314 h1:P5+NZGMH8KSI3L8lKw1znxdRi0tIpWbGYjmv8GrFHrQ= +github.com/sagernet/sing-mux v0.1.3-0.20230907005326-7befbadbf314/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY= +github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0 h1:9wHYWxH+fcs01PM2+DylA8LNNY3ElnZykQo9rysng8U= +github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0/go.mod h1:80fNKP0wnqlu85GZXV1H1vDPC/2t+dQbFggOw4XuFUM= +github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248 h1:JTFfy/LDmVFEK4KZJEujmC1iO8+aoF4unYhhZZRzRq4= +github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248/go.mod h1:DOhJc/cLeqRv0wuePrQso+iUmDxOnWF4eT/oMcRzYFw= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.10-0.20230723061951-767ce42377f1 h1:PCA1u3HMLt1BcsMGVTR+0xRENEyHZrLQsF+/l99iOio= -github.com/sagernet/sing-tun v0.1.10-0.20230723061951-767ce42377f1/go.mod h1:XsyIVKd/Qp+2SdLZWGbavHtcpE7J7XU3S1zJmcoj9Ck= -github.com/sagernet/sing-vmess v0.1.7 h1:TM8FFLsXmlXH9XT8/oDgc6PC5BOzrg6OzyEe01is2r4= -github.com/sagernet/sing-vmess v0.1.7/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss= +github.com/sagernet/sing-tun v0.1.12-0.20230821065522-7545dc2d5641 h1:a8lktNrCWZJisB+nPraW+qB73ZofgPtGmlfqNYcO79g= +github.com/sagernet/sing-tun v0.1.12-0.20230821065522-7545dc2d5641/go.mod h1:+YImslQMLgMQcVgZZ9IK4ue1o/605VSU90amHUcp4hA= +github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b h1:2ezfJtH5JosiEwJhVa+rimQ6ps/t2+7h+mOzMoiaZnA= +github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= -github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= -github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= +github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGVnWH5A8eR7JhNnIV3rGQmBxA7cw6Q= +github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs= @@ -737,10 +721,12 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 h1:hp2CYQUINdZMHdvTdXtPOY2ainKl4IoMcpAXEf2xj3Q= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/gunit v1.0.4 h1:tpTjnuH7MLlqhoD21vRoMZbMIi5GmBsAJDFyF67GhZA= +github.com/smartystreets/gunit v1.0.4/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ= github.com/softlayer/softlayer-go v1.1.2 h1:rUSSGCyaxymvTOsaFjwr+cGxA8muw3xg2LSrIMNcN/c= github.com/softlayer/softlayer-go v1.1.2/go.mod h1:hvAbzGH4LRXA6yXY8BNx99yoqZ7urfDdtl9mvBf0G+g= github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e h1:3OgWYFw7jxCZPcvAg+4R8A50GZ+CCkARF10lxu2qDsQ= @@ -789,12 +775,6 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490/go.mod github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/transip/gotransip/v6 v6.20.0 h1:AuvwyOZ51f2brzMbTqlRy/wmaM3kF7Vx5Wds8xcDflY= github.com/transip/gotransip/v6 v6.20.0/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c= -github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf h1:7PflaKRtU4np/epFxRXlFhlzLXZzKFrH5/I4so5Ove0= -github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf/go.mod h1:CLUSJbazqETbaR+i0YAhXBICV9TrKH93pziccMhmhpM= -github.com/txthinking/socks5 v0.0.0-20220212043548-414499347d4a h1:BOqgJ4jku0LHPDoR51RD8Mxmo0LHxCzJT/M9MemYdHo= -github.com/txthinking/socks5 v0.0.0-20220212043548-414499347d4a/go.mod h1:7NloQcrxaZYKURWph5HLxVDlIwMHJXCPkeWPtpftsIg= -github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe h1:gMWxZxBFRAXqoGkwkYlPX2zvyyKNWJpxOxCrjqJkm5A= -github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe/go.mod h1:WgqbSEmUYSjEV3B1qmee/PpP2NYEz4bL9/+mF1ma+s4= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= @@ -817,10 +797,10 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983 h1:AMyzgjkh54WocjQSlCnT1LhDc/BKiUqtNOv40AkpURs= -github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983/go.mod h1:rkuAY1S9F8eI8gDiPDYvACE8e2uwkyg8qoOTuwWov7Y= -github.com/xtls/xray-core v1.8.3 h1:lxaVklPjLKqUU4ua4qH8SBaRcAaNHlH+LmXOx0U/Ejg= -github.com/xtls/xray-core v1.8.3/go.mod h1:i7t4JFnq828P2+XK0XjGQ8W9x78iu+EJ7jI4l3sonIw= +github.com/xtls/reality v0.0.0-20230828171259-e426190d57f6 h1:T+YCYGfFdzyaKTDCdZn/hEiKvsw6yUfd+e4hze0rCUw= +github.com/xtls/reality v0.0.0-20230828171259-e426190d57f6/go.mod h1:rkuAY1S9F8eI8gDiPDYvACE8e2uwkyg8qoOTuwWov7Y= +github.com/xtls/xray-core v1.8.4 h1:YEoY3iLx/5zoNbt5HORG5LtPyzwICInFfoS+oPkYDIw= +github.com/xtls/xray-core v1.8.4/go.mod h1:GGD9elFSHa4IqOArW8gzMsEksPIqK/jdNLo8RcSMfnI= github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f h1:cG+ehPRJSlqljSufLf1KXeXpUd1dLNjnzA18mZcB/O0= github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE= github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997 h1:2wzke3JH7OtN20WsNDZx2VH/TCmsbqtDEbXzjF+i05E= @@ -845,18 +825,19 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 h1:nJAwRlGWZZDOD+6wni9KVUNHMpHko/OnRwsrCYeAzPo= -go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y= +go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= +go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -879,17 +860,17 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= 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-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= 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-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -900,19 +881,17 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl 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-20200302205851-738671d3881b/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.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -946,21 +925,19 @@ golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/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-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs= -golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 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= @@ -974,6 +951,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -995,7 +973,6 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1028,23 +1005,21 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.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/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= 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= @@ -1053,13 +1028,12 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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= @@ -1088,7 +1062,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/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-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1096,8 +1069,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= 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= @@ -1110,8 +1083,8 @@ google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E 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.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= +google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1136,8 +1109,12 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1152,8 +1129,9 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv 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.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= +google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= 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= @@ -1186,6 +1164,8 @@ gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 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/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/ns1/ns1-go.v2 v2.7.6 h1:mCPl7q0jbIGACXvGBljAuuApmKZo3rRi4tlRIEbMvjA= gopkg.in/ns1/ns1-go.v2 v2.7.6/go.mod h1:GMnKY+ZuoJ+lVLL+78uSTjwTz2jMazq6AfGKQOYhsPk= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -1206,8 +1186,8 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= -gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4= -gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM= +gvisor.dev/gvisor v0.0.0-20230822212503-5bf4e5f98744 h1:tE44CyJgxEGzoPtHs9GI7ddKdgEGCREQBP54AmaVM+I= +gvisor.dev/gvisor v0.0.0-20230822212503-5bf4e5f98744/go.mod h1:lYEMhXbxgudVhALYsMQrBaUAjM3NMinh8mKL1CJv7rc= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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= diff --git a/node/cert.go b/node/cert.go index 9f9f3df..55c0cf0 100644 --- a/node/cert.go +++ b/node/cert.go @@ -1,15 +1,22 @@ package node import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" "fmt" + "math/big" + "os" + "time" "github.com/InazumaV/V2bX/common/file" - "github.com/InazumaV/V2bX/node/lego" log "github.com/sirupsen/logrus" ) func (c *Controller) renewCertTask() error { - l, err := lego.New(c.CertConfig) + l, err := NewLego(c.CertConfig) if err != nil { log.WithField("tag", c.tag).Info("new lego error: ", err) return nil @@ -24,13 +31,11 @@ func (c *Controller) renewCertTask() error { func (c *Controller) requestCert() error { switch c.CertConfig.CertMode { - case "reality", "none", "": - return nil + case "none", "": case "file": if c.CertConfig.CertFile == "" || c.CertConfig.KeyFile == "" { return fmt.Errorf("cert file path or key file path not exist") } - return nil case "dns", "http": if c.CertConfig.CertFile == "" || c.CertConfig.KeyFile == "" { return fmt.Errorf("cert file path or key file path not exist") @@ -38,15 +43,74 @@ func (c *Controller) requestCert() error { if file.IsExist(c.CertConfig.CertFile) && file.IsExist(c.CertConfig.KeyFile) { return nil } - l, err := lego.New(c.CertConfig) + l, err := NewLego(c.CertConfig) if err != nil { return fmt.Errorf("create lego object error: %s", err) } err = l.CreateCert() if err != nil { - return fmt.Errorf("create cert error: %s", err) + return fmt.Errorf("create lego cert error: %s", err) } - return nil + case "self": + if c.CertConfig.CertFile == "" || c.CertConfig.KeyFile == "" { + return fmt.Errorf("cert file path or key file path not exist") + } + if file.IsExist(c.CertConfig.CertFile) && file.IsExist(c.CertConfig.KeyFile) { + return nil + } + err := generateSelfSslCertificate( + c.CertConfig.CertDomain, + c.CertConfig.CertFile, + c.CertConfig.KeyFile) + if err != nil { + return fmt.Errorf("generate self cert error: %s", err) + } + default: + return fmt.Errorf("unsupported certmode: %s", c.CertConfig.CertMode) } - return fmt.Errorf("unsupported certmode: %s", c.CertConfig.CertMode) + return nil +} + +func generateSelfSslCertificate(domain, certPath, keyPath string) error { + key, _ := rsa.GenerateKey(rand.Reader, 2048) + tmpl := &x509.Certificate{ + Version: 3, + SerialNumber: big.NewInt(time.Now().Unix()), + Subject: pkix.Name{ + CommonName: domain, + }, + DNSNames: []string{domain}, + BasicConstraintsValid: true, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(30, 0, 0), + } + cert, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key) + if err != nil { + return err + } + f, err := os.OpenFile(certPath, os.O_CREATE|os.O_RDWR, 0644) + if err != nil { + return err + } + err = pem.Encode(f, &pem.Block{ + Type: "CERTIFICATE", + Bytes: cert, + }) + if err != nil { + return err + } + f, err = os.OpenFile(keyPath, os.O_CREATE|os.O_RDWR, 0644) + if err != nil { + return err + } + err = pem.Encode(f, &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(key), + }) + if err != nil { + return err + } + return nil } diff --git a/node/cert_test.go b/node/cert_test.go new file mode 100644 index 0000000..d26b478 --- /dev/null +++ b/node/cert_test.go @@ -0,0 +1,7 @@ +package node + +import "testing" + +func Test_generateSelfSslCertificate(t *testing.T) { + t.Log(generateSelfSslCertificate("domain.com", "1.pem", "1.key")) +} diff --git a/node/controller.go b/node/controller.go index 84daebb..d4ece3e 100644 --- a/node/controller.go +++ b/node/controller.go @@ -56,7 +56,11 @@ func (c *Controller) Start() error { if len(c.userList) == 0 { return errors.New("add users error: not have any user") } - c.tag = c.buildNodeTag(node) + if len(c.Options.Name) == 0 { + c.tag = c.buildNodeTag(node) + } else { + c.tag = c.Options.Name + } // add limiter l := limiter.AddLimiter(c.tag, &c.LimitConfig, c.userList) @@ -65,7 +69,7 @@ func (c *Controller) Start() error { return fmt.Errorf("update rule error: %s", err) } c.limiter = l - if node.Tls || node.Type == "hysteria" { + if node.Security == panel.Tls { err = c.requestCert() if err != nil { return fmt.Errorf("request cert error: %s", err) @@ -78,8 +82,7 @@ func (c *Controller) Start() error { } added, err := c.server.AddUsers(&vCore.AddUsersParams{ Tag: c.tag, - Config: c.Options, - UserInfo: c.userList, + Users: c.userList, NodeInfo: node, }) if err != nil { @@ -113,5 +116,5 @@ func (c *Controller) Close() error { } func (c *Controller) buildNodeTag(node *panel.NodeInfo) string { - return fmt.Sprintf("%s-%s-%d", c.apiClient.APIHost, node.Type, node.Id) + return fmt.Sprintf("[%s]-%s:%d", c.apiClient.APIHost, node.Type, node.Id) } diff --git a/node/lego.go b/node/lego.go new file mode 100644 index 0000000..1c32726 --- /dev/null +++ b/node/lego.go @@ -0,0 +1,273 @@ +package node + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "encoding/pem" + "fmt" + "os" + "path" + "strings" + "time" + + "github.com/go-acme/lego/v4/certificate" + "github.com/go-acme/lego/v4/challenge/http01" + "github.com/go-acme/lego/v4/providers/dns" + "github.com/go-acme/lego/v4/registration" + "github.com/goccy/go-json" + + "github.com/InazumaV/V2bX/common/file" + "github.com/InazumaV/V2bX/conf" + "github.com/go-acme/lego/v4/certcrypto" + "github.com/go-acme/lego/v4/lego" +) + +type Lego struct { + client *lego.Client + config *conf.CertConfig +} + +func NewLego(config *conf.CertConfig) (*Lego, error) { + user, err := NewLegoUser(path.Join(path.Dir(config.CertFile), + "user", + fmt.Sprintf("user-%s.json", config.Email)), + config.Email) + if err != nil { + return nil, fmt.Errorf("create user error: %s", err) + } + c := lego.NewConfig(user) + //c.CADirURL = "http://192.168.99.100:4000/directory" + c.Certificate.KeyType = certcrypto.RSA2048 + client, err := lego.NewClient(c) + if err != nil { + return nil, err + } + l := Lego{ + client: client, + config: config, + } + err = l.SetProvider() + if err != nil { + return nil, fmt.Errorf("set provider error: %s", err) + } + return &l, nil +} + +func checkPath(p string) error { + if !file.IsExist(path.Dir(p)) { + err := os.MkdirAll(path.Dir(p), 0755) + if err != nil { + return fmt.Errorf("create dir error: %s", err) + } + } + return nil +} + +func (l *Lego) SetProvider() error { + switch l.config.CertMode { + case "http": + err := l.client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", "80")) + if err != nil { + return err + } + case "dns": + for k, v := range l.config.DNSEnv { + os.Setenv(k, v) + } + p, err := dns.NewDNSChallengeProviderByName(l.config.Provider) + if err != nil { + return fmt.Errorf("create dns challenge provider error: %s", err) + } + err = l.client.Challenge.SetDNS01Provider(p) + if err != nil { + return fmt.Errorf("set dns provider error: %s", err) + } + } + return nil +} + +func (l *Lego) CreateCert() (err error) { + request := certificate.ObtainRequest{ + Domains: []string{l.config.CertDomain}, + Bundle: true, + } + certificates, err := l.client.Certificate.Obtain(request) + if err != nil { + return fmt.Errorf("obtain certificate error: %s", err) + } + err = l.writeCert(certificates) + return nil +} + +func (l *Lego) RenewCert() error { + file, err := os.ReadFile(l.config.CertFile) + if err != nil { + return fmt.Errorf("read cert file error: %s", err) + } + if e, err := l.CheckCert(file); !e { + return nil + } else if err != nil { + return fmt.Errorf("check cert error: %s", err) + } + res, err := l.client.Certificate.Renew(certificate.Resource{ + Domain: l.config.CertDomain, + Certificate: file, + }, true, false, "") + if err != nil { + return err + } + err = l.writeCert(res) + return nil +} + +func (l *Lego) CheckCert(file []byte) (bool, error) { + cert, err := certcrypto.ParsePEMCertificate(file) + if err != nil { + return false, err + } + notAfter := int(time.Until(cert.NotAfter).Hours() / 24.0) + if notAfter > 30 { + return false, nil + } + return true, nil +} +func (l *Lego) parseParams(path string) string { + r := strings.NewReplacer("{domain}", l.config.CertDomain, + "{email}", l.config.Email) + return r.Replace(path) +} +func (l *Lego) writeCert(certificates *certificate.Resource) error { + err := checkPath(l.config.CertFile) + if err != nil { + return fmt.Errorf("check path error: %s", err) + } + err = os.WriteFile(l.parseParams(l.config.CertFile), certificates.Certificate, 0644) + if err != nil { + return err + } + err = checkPath(l.config.KeyFile) + if err != nil { + return fmt.Errorf("check path error: %s", err) + } + err = os.WriteFile(l.parseParams(l.config.KeyFile), certificates.PrivateKey, 0644) + if err != nil { + return err + } + return nil +} + +type User struct { + Email string `json:"Email"` + Registration *registration.Resource `json:"Registration"` + key crypto.PrivateKey + KeyEncoded string `json:"Key"` +} + +func (u *User) GetEmail() string { + return u.Email +} +func (u *User) GetRegistration() *registration.Resource { + return u.Registration +} +func (u *User) GetPrivateKey() crypto.PrivateKey { + return u.key +} + +func NewLegoUser(path string, email string) (*User, error) { + var user User + if file.IsExist(path) { + err := user.Load(path) + if err != nil { + return nil, err + } + if user.Email != email { + user.Registration = nil + user.Email = email + err := registerUser(&user, path) + if err != nil { + return nil, err + } + } + } else { + user.Email = email + err := registerUser(&user, path) + if err != nil { + return nil, err + } + } + return &user, nil +} + +func registerUser(user *User, path string) error { + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return fmt.Errorf("generate key error: %s", err) + } + user.key = privateKey + c := lego.NewConfig(user) + client, err := lego.NewClient(c) + if err != nil { + return fmt.Errorf("create lego client error: %s", err) + } + reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) + if err != nil { + return err + } + user.Registration = reg + err = user.Save(path) + if err != nil { + return fmt.Errorf("save user error: %s", err) + } + return nil +} + +func EncodePrivate(privKey *ecdsa.PrivateKey) (string, error) { + encoded, err := x509.MarshalECPrivateKey(privKey) + if err != nil { + return "", err + } + pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: encoded}) + return string(pemEncoded), nil +} +func (u *User) Save(path string) error { + err := checkPath(path) + if err != nil { + return fmt.Errorf("check path error: %s", err) + } + u.KeyEncoded, _ = EncodePrivate(u.key.(*ecdsa.PrivateKey)) + f, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) + if err != nil { + return err + } + err = json.NewEncoder(f).Encode(u) + if err != nil { + return fmt.Errorf("marshal json error: %s", err) + } + u.KeyEncoded = "" + return nil +} + +func (u *User) DecodePrivate(pemEncodedPriv string) (*ecdsa.PrivateKey, error) { + blockPriv, _ := pem.Decode([]byte(pemEncodedPriv)) + x509EncodedPriv := blockPriv.Bytes + privateKey, err := x509.ParseECPrivateKey(x509EncodedPriv) + return privateKey, err +} +func (u *User) Load(path string) error { + f, err := os.Open(path) + if err != nil { + return fmt.Errorf("open file error: %s", err) + } + err = json.NewDecoder(f).Decode(u) + if err != nil { + return fmt.Errorf("unmarshal json error: %s", err) + } + u.key, err = u.DecodePrivate(u.KeyEncoded) + if err != nil { + return fmt.Errorf("decode private key error: %s", err) + } + return nil +} diff --git a/node/lego/cert.go b/node/lego/cert.go deleted file mode 100644 index 1f5a36e..0000000 --- a/node/lego/cert.go +++ /dev/null @@ -1,104 +0,0 @@ -package lego - -import ( - "fmt" - "github.com/go-acme/lego/v4/certcrypto" - "github.com/go-acme/lego/v4/certificate" - "github.com/go-acme/lego/v4/challenge/http01" - "github.com/go-acme/lego/v4/providers/dns" - "os" - "strings" - "time" -) - -func (l *Lego) SetProvider() error { - switch l.config.CertMode { - case "http": - err := l.client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", "80")) - if err != nil { - return err - } - case "dns": - for k, v := range l.config.DNSEnv { - os.Setenv(k, v) - } - p, err := dns.NewDNSChallengeProviderByName(l.config.Provider) - if err != nil { - return fmt.Errorf("create dns challenge provider error: %s", err) - } - err = l.client.Challenge.SetDNS01Provider(p) - if err != nil { - return fmt.Errorf("set dns provider error: %s", err) - } - } - return nil -} - -func (l *Lego) CreateCert() (err error) { - request := certificate.ObtainRequest{ - Domains: []string{l.config.CertDomain}, - } - certificates, err := l.client.Certificate.Obtain(request) - if err != nil { - return fmt.Errorf("obtain certificate error: %s", err) - } - err = l.writeCert(certificates) - return nil -} - -func (l *Lego) RenewCert() error { - file, err := os.ReadFile(l.config.CertFile) - if err != nil { - return fmt.Errorf("read cert file error: %s", err) - } - if e, err := l.CheckCert(file); !e { - return nil - } else if err != nil { - return fmt.Errorf("check cert error: %s", err) - } - res, err := l.client.Certificate.Renew(certificate.Resource{ - Domain: l.config.CertDomain, - Certificate: file, - }, false, false, "") - if err != nil { - return err - } - err = l.writeCert(res) - return nil -} - -func (l *Lego) CheckCert(file []byte) (bool, error) { - cert, err := certcrypto.ParsePEMCertificate(file) - if err != nil { - return false, err - } - notAfter := int(time.Until(cert.NotAfter).Hours() / 24.0) - if notAfter > 30 { - return false, nil - } - return true, nil -} -func (l *Lego) parseParams(path string) string { - r := strings.NewReplacer("{domain}", l.config.CertDomain, - "{email}", l.config.Email) - return r.Replace(path) -} -func (l *Lego) writeCert(certificates *certificate.Resource) error { - err := checkPath(l.config.CertFile) - if err != nil { - return fmt.Errorf("check path error: %s", err) - } - err = os.WriteFile(l.parseParams(l.config.CertFile), certificates.Certificate, 0644) - if err != nil { - return err - } - err = checkPath(l.config.KeyFile) - if err != nil { - return fmt.Errorf("check path error: %s", err) - } - err = os.WriteFile(l.parseParams(l.config.KeyFile), certificates.PrivateKey, 0644) - if err != nil { - return err - } - return nil -} diff --git a/node/lego/lego.go b/node/lego/lego.go deleted file mode 100644 index 9a5c0d1..0000000 --- a/node/lego/lego.go +++ /dev/null @@ -1,53 +0,0 @@ -package lego - -import ( - "fmt" - "os" - "path" - - "github.com/InazumaV/V2bX/common/file" - "github.com/InazumaV/V2bX/conf" - "github.com/go-acme/lego/v4/certcrypto" - "github.com/go-acme/lego/v4/lego" -) - -type Lego struct { - client *lego.Client - config *conf.CertConfig -} - -func New(config *conf.CertConfig) (*Lego, error) { - user, err := NewUser(path.Join(path.Dir(config.CertFile), - "user", - fmt.Sprintf("user-%s.json", config.Email)), - config.Email) - if err != nil { - return nil, fmt.Errorf("create user error: %s", err) - } - c := lego.NewConfig(user) - //c.CADirURL = "http://192.168.99.100:4000/directory" - c.Certificate.KeyType = certcrypto.RSA2048 - client, err := lego.NewClient(c) - if err != nil { - return nil, err - } - l := Lego{ - client: client, - config: config, - } - err = l.SetProvider() - if err != nil { - return nil, fmt.Errorf("set provider error: %s", err) - } - return &l, nil -} - -func checkPath(p string) error { - if !file.IsExist(path.Dir(p)) { - err := os.MkdirAll(path.Dir(p), 0755) - if err != nil { - return fmt.Errorf("create dir error: %s", err) - } - } - return nil -} diff --git a/node/lego/user.go b/node/lego/user.go deleted file mode 100644 index d2d3b18..0000000 --- a/node/lego/user.go +++ /dev/null @@ -1,130 +0,0 @@ -package lego - -import ( - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/x509" - "encoding/pem" - "fmt" - "os" - - "github.com/InazumaV/V2bX/common/file" - "github.com/go-acme/lego/v4/lego" - "github.com/go-acme/lego/v4/registration" - "github.com/goccy/go-json" -) - -type User struct { - Email string `json:"Email"` - Registration *registration.Resource `json:"Registration"` - key crypto.PrivateKey - KeyEncoded string `json:"Key"` -} - -func (u *User) GetEmail() string { - return u.Email -} -func (u *User) GetRegistration() *registration.Resource { - return u.Registration -} -func (u *User) GetPrivateKey() crypto.PrivateKey { - return u.key -} - -func NewUser(path string, email string) (*User, error) { - var user User - if file.IsExist(path) { - err := user.Load(path) - if err != nil { - return nil, err - } - if user.Email != email { - user.Registration = nil - user.Email = email - err := registerUser(&user, path) - if err != nil { - return nil, err - } - } - } else { - user.Email = email - err := registerUser(&user, path) - if err != nil { - return nil, err - } - } - return &user, nil -} - -func registerUser(user *User, path string) error { - privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - return fmt.Errorf("generate key error: %s", err) - } - user.key = privateKey - c := lego.NewConfig(user) - client, err := lego.NewClient(c) - if err != nil { - return fmt.Errorf("create lego client error: %s", err) - } - reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) - if err != nil { - return err - } - user.Registration = reg - err = user.Save(path) - if err != nil { - return fmt.Errorf("save user error: %s", err) - } - return nil -} - -func EncodePrivate(privKey *ecdsa.PrivateKey) (string, error) { - encoded, err := x509.MarshalECPrivateKey(privKey) - if err != nil { - return "", err - } - pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: encoded}) - return string(pemEncoded), nil -} -func (u *User) Save(path string) error { - err := checkPath(path) - if err != nil { - return fmt.Errorf("check path error: %s", err) - } - u.KeyEncoded, _ = EncodePrivate(u.key.(*ecdsa.PrivateKey)) - f, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) - if err != nil { - return err - } - err = json.NewEncoder(f).Encode(u) - if err != nil { - return fmt.Errorf("marshal json error: %s", err) - } - u.KeyEncoded = "" - return nil -} - -func (u *User) DecodePrivate(pemEncodedPriv string) (*ecdsa.PrivateKey, error) { - blockPriv, _ := pem.Decode([]byte(pemEncodedPriv)) - x509EncodedPriv := blockPriv.Bytes - privateKey, err := x509.ParseECPrivateKey(x509EncodedPriv) - return privateKey, err -} -func (u *User) Load(path string) error { - f, err := os.Open(path) - if err != nil { - return fmt.Errorf("open file error: %s", err) - } - err = json.NewDecoder(f).Decode(u) - if err != nil { - return fmt.Errorf("unmarshal json error: %s", err) - } - u.key, err = u.DecodePrivate(u.KeyEncoded) - if err != nil { - return fmt.Errorf("decode private key error: %s", err) - } - return nil -} diff --git a/node/lego/lego_test.go b/node/lego_test.go similarity index 92% rename from node/lego/lego_test.go rename to node/lego_test.go index 69b2eab..128014d 100644 --- a/node/lego/lego_test.go +++ b/node/lego_test.go @@ -1,4 +1,4 @@ -package lego +package node import ( "log" @@ -12,7 +12,7 @@ var l *Lego func init() { var err error - l, err = New(&conf.CertConfig{ + l, err = NewLego(&conf.CertConfig{ CertMode: "dns", Email: "test@test.com", CertDomain: "test.test.com", diff --git a/node/node.go b/node/node.go index ad3a58c..f8a4738 100644 --- a/node/node.go +++ b/node/node.go @@ -16,21 +16,21 @@ func New() *Node { return &Node{} } -func (n *Node) Start(nodes []*conf.NodeConfig, core vCore.Core) error { +func (n *Node) Start(nodes []conf.NodeConfig, core vCore.Core) error { n.controllers = make([]*Controller, len(nodes)) - for i, c := range nodes { - p, err := panel.New(c.ApiConfig) + for i := range nodes { + p, err := panel.New(&nodes[i].ApiConfig) if err != nil { return err } // Register controller service - n.controllers[i] = NewController(core, p, c.Options) + n.controllers[i] = NewController(core, p, &nodes[i].Options) err = n.controllers[i].Start() if err != nil { return fmt.Errorf("start node controller [%s-%s-%d] error: %s", - c.ApiConfig.NodeType, - c.ApiConfig.APIHost, - c.ApiConfig.NodeID, + nodes[i].ApiConfig.APIHost, + nodes[i].ApiConfig.NodeType, + nodes[i].ApiConfig.NodeID, err) } } diff --git a/node/task.go b/node/task.go index 86297bb..51c12f2 100644 --- a/node/task.go +++ b/node/task.go @@ -26,9 +26,9 @@ func (c *Controller) startTasks(node *panel.NodeInfo) { _ = c.nodeInfoMonitorPeriodic.Start(false) log.WithField("tag", c.tag).Info("Start report node status") _ = c.userReportPeriodic.Start(false) - if node.Tls { + if node.Security == panel.Tls { switch c.CertConfig.CertMode { - case "reality", "none", "": + case "none", "", "file", "self": default: c.renewCertPeriodic = &task.Task{ Interval: time.Hour * 24, @@ -45,12 +45,13 @@ func (c *Controller) startTasks(node *panel.NodeInfo) { Interval: time.Duration(c.LimitConfig.DynamicSpeedLimitConfig.Periodic) * time.Second, Execute: c.SpeedChecker, } + log.Printf("[%s: %d] Start dynamic speed limit", c.apiClient.NodeType, c.apiClient.NodeId) } } func (c *Controller) nodeInfoMonitor() (err error) { // get node info - newNodeInfo, err := c.apiClient.GetNodeInfo() + newN, err := c.apiClient.GetNodeInfo() if err != nil { log.WithFields(log.Fields{ "tag": c.tag, @@ -59,7 +60,7 @@ func (c *Controller) nodeInfoMonitor() (err error) { return nil } // get user info - newUserInfo, err := c.apiClient.GetUserList() + newU, err := c.apiClient.GetUserList() if err != nil { log.WithFields(log.Fields{ "tag": c.tag, @@ -67,14 +68,14 @@ func (c *Controller) nodeInfoMonitor() (err error) { }).Error("Get user list failed") return nil } - if newNodeInfo != nil { - c.info = newNodeInfo + if newN != nil { + c.info = newN // nodeInfo changed - if newUserInfo != nil { - c.userList = newUserInfo + if newU != nil { + c.userList = newU } c.traffic = make(map[string]int64) - // Remove old tag + // Remove old node log.WithField("tag", c.tag).Info("Node changed, reload") err = c.server.DelNode(c.tag) if err != nil { @@ -84,13 +85,28 @@ func (c *Controller) nodeInfoMonitor() (err error) { }).Error("Delete node failed") return nil } - // Remove Old limiter - limiter.DeleteLimiter(c.tag) - // Add new Limiter - c.tag = c.buildNodeTag(newNodeInfo) - l := limiter.AddLimiter(c.tag, &c.LimitConfig, c.userList) + + // Update limiter + if len(c.Options.Name) == 0 { + c.tag = c.buildNodeTag(newN) + // Remove Old limiter + limiter.DeleteLimiter(c.tag) + // Add new Limiter + l := limiter.AddLimiter(c.tag, &c.LimitConfig, c.userList) + c.limiter = l + } + // Update rule + err = c.limiter.UpdateRule(&newN.Rules) + if err != nil { + log.WithFields(log.Fields{ + "tag": c.tag, + "err": err, + }).Error("Update Rule failed") + return nil + } + // check cert - if newNodeInfo.Tls || newNodeInfo.Type == "hysteria" { + if newN.Security == panel.Tls { err = c.requestCert() if err != nil { log.WithFields(log.Fields{ @@ -101,7 +117,7 @@ func (c *Controller) nodeInfoMonitor() (err error) { } } // add new node - err = c.server.AddNode(c.tag, newNodeInfo, c.Options) + err = c.server.AddNode(c.tag, newN, c.Options) if err != nil { log.WithFields(log.Fields{ "tag": c.tag, @@ -111,9 +127,8 @@ func (c *Controller) nodeInfoMonitor() (err error) { } _, err = c.server.AddUsers(&vCore.AddUsersParams{ Tag: c.tag, - Config: c.Options, - UserInfo: c.userList, - NodeInfo: newNodeInfo, + Users: c.userList, + NodeInfo: newN, }) if err != nil { log.WithFields(log.Fields{ @@ -122,25 +137,16 @@ func (c *Controller) nodeInfoMonitor() (err error) { }).Error("Add users failed") return nil } - err = l.UpdateRule(&newNodeInfo.Rules) - if err != nil { - log.WithFields(log.Fields{ - "tag": c.tag, - "err": err, - }).Error("Update Rule failed") - return nil - } - c.limiter = l // Check interval - if c.nodeInfoMonitorPeriodic.Interval != newNodeInfo.PullInterval && - newNodeInfo.PullInterval != 0 { - c.nodeInfoMonitorPeriodic.Interval = newNodeInfo.PullInterval + if c.nodeInfoMonitorPeriodic.Interval != newN.PullInterval && + newN.PullInterval != 0 { + c.nodeInfoMonitorPeriodic.Interval = newN.PullInterval c.nodeInfoMonitorPeriodic.Close() _ = c.nodeInfoMonitorPeriodic.Start(false) } - if c.userReportPeriodic.Interval != newNodeInfo.PushInterval && - newNodeInfo.PushInterval != 0 { - c.userReportPeriodic.Interval = newNodeInfo.PullInterval + if c.userReportPeriodic.Interval != newN.PushInterval && + newN.PushInterval != 0 { + c.userReportPeriodic.Interval = newN.PullInterval c.userReportPeriodic.Close() _ = c.userReportPeriodic.Start(false) } @@ -150,10 +156,10 @@ func (c *Controller) nodeInfoMonitor() (err error) { } // node no changed, check users - if len(newUserInfo) == 0 { + if len(newU) == 0 { return nil } - deleted, added := compareUserList(c.userList, newUserInfo) + deleted, added := compareUserList(c.userList, newU) if len(deleted) > 0 { // have deleted users err = c.server.DelUsers(deleted, c.tag) @@ -169,9 +175,8 @@ func (c *Controller) nodeInfoMonitor() (err error) { // have added users _, err = c.server.AddUsers(&vCore.AddUsersParams{ Tag: c.tag, - Config: c.Options, NodeInfo: c.info, - UserInfo: added, + Users: added, }) if err != nil { log.WithFields(log.Fields{ @@ -198,7 +203,7 @@ func (c *Controller) nodeInfoMonitor() (err error) { } } } - c.userList = newUserInfo + c.userList = newU if len(added)+len(deleted) != 0 { log.WithField("tag", c.tag). Infof("%d user deleted, %d user added", len(deleted), len(added)) diff --git a/node/user.go b/node/user.go index dcfd22e..0b3ea50 100644 --- a/node/user.go +++ b/node/user.go @@ -1,7 +1,6 @@ package node import ( - "runtime" "strconv" "github.com/InazumaV/V2bX/api/panel" @@ -39,7 +38,6 @@ func (c *Controller) reportUserTrafficTask() (err error) { } } userTraffic = nil - runtime.GC() return nil }