From 42bb7bc90ff0b1bcade4d7cfc253e46edf400c82 Mon Sep 17 00:00:00 2001 From: yuzuki999 Date: Thu, 8 Jun 2023 22:46:33 +0800 Subject: [PATCH 1/3] update initial support for hysteria update config update api change user email format ... --- api/panel/node.go | 131 +++++++++++---- common/builder/inbound.go | 64 ++------ common/builder/outbound.go | 11 +- common/builder/user.go | 10 +- conf/node.go | 44 +++-- conf/old.go | 2 +- core/hy/acme.go | 74 --------- core/hy/config.go | 289 +-------------------------------- core/hy/counter.go | 67 ++++++++ core/hy/counter_test.go | 7 + core/hy/hy.go | 321 +++---------------------------------- core/hy/node.go | 34 ++++ core/hy/prom.go | 71 -------- core/hy/server.go | 263 ++++++++++++++++++++++++++++++ core/hy/server_test.go | 25 +++ core/hy/user.go | 42 +++++ core/imports/hy.go | 4 +- core/interface.go | 2 +- core/xray/node.go | 2 +- core/xray/user.go | 14 +- go.mod | 16 +- go.sum | 64 +------- limiter/limiter.go | 2 +- node/cert.go | 31 ++++ node/controller.go | 32 ++-- node/lego/cert.go | 6 +- node/task.go | 80 ++++----- node/user.go | 34 ++++ test_data/1.key | 27 ++++ test_data/1.pem | 23 +++ 30 files changed, 809 insertions(+), 983 deletions(-) delete mode 100644 core/hy/acme.go create mode 100644 core/hy/counter.go create mode 100644 core/hy/counter_test.go create mode 100644 core/hy/node.go delete mode 100644 core/hy/prom.go create mode 100644 core/hy/server.go create mode 100644 core/hy/server_test.go create mode 100644 core/hy/user.go create mode 100644 node/cert.go create mode 100644 node/user.go create mode 100644 test_data/1.key create mode 100644 test_data/1.pem diff --git a/api/panel/node.go b/api/panel/node.go index 3e8d119..82cb4a8 100644 --- a/api/panel/node.go +++ b/api/panel/node.go @@ -1,6 +1,7 @@ package panel import ( + "fmt" "github.com/goccy/go-json" "reflect" "regexp" @@ -9,21 +10,12 @@ import ( "time" ) -type NodeInfo struct { - NodeId int `json:"-"` - NodeType string `json:"-"` - Rules []*regexp.Regexp `json:"-"` - Host string `json:"host"` - ServerPort int `json:"server_port"` - ServerName string `json:"server_name"` - Network string `json:"network"` - NetworkSettings json.RawMessage `json:"networkSettings"` - Cipher string `json:"cipher"` - ServerKey string `json:"server_key"` - Tls int `json:"tls"` - Routes []Route `json:"routes"` - BaseConfig *BaseConfig `json:"base_config"` +type CommonNodeRsp struct { + ServerPort int `json:"server_port"` + Routes []Route `json:"routes"` + BaseConfig BaseConfig `json:"base_config"` } + type Route struct { Id int `json:"id"` Match interface{} `json:"match"` @@ -35,37 +27,122 @@ type BaseConfig struct { PullInterval any `json:"pull_interval"` } -func (c *Client) GetNodeInfo() (nodeInfo *NodeInfo, err error) { +type V2rayNodeRsp struct { + Tls int `json:"tls"` + Network string `json:"network"` + NetworkSettings json.RawMessage `json:"networkSettings"` + ServerName string `json:"server_name"` +} + +type ShadowsocksNodeRsp struct { + Cipher string `json:"cipher"` + ServerKey string `json:"server_key"` +} + +type TrojanNodeRsp struct { + Host string `json:"host"` + ServerName string `json:"server_name"` +} + +type HysteriaNodeRsp struct { + UpMbps int `json:"up_mbps"` + DownMbps int `json:"down_mbps"` + Obfs string `json:"obfs"` +} + +type NodeInfo struct { + Id int + Type string + Rules []*regexp.Regexp + Port int + Network string + NetworkSettings json.RawMessage + Tls bool + Host string + ServerName string + UpMbps int + DownMbps int + ServerKey string + Cipher string + HyObfs string + PushInterval time.Duration + PullInterval time.Duration +} + +func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { const path = "/api/v1/server/UniProxy/config" r, err := c.client.R().Get(path) if err = c.checkResponse(r, path, err); err != nil { return } - err = json.Unmarshal(r.Body(), &nodeInfo) + err = json.Unmarshal(r.Body(), &node) if err != nil { return } if c.etag == r.Header().Get("ETag") { // node info not changed return nil, nil } - nodeInfo.NodeId = c.NodeId - nodeInfo.NodeType = c.NodeType - for i := range nodeInfo.Routes { // parse rules from routes - if nodeInfo.Routes[i].Action == "block" { + // parse common params + node.Id = c.NodeId + node.Type = c.NodeType + common := CommonNodeRsp{} + err = json.Unmarshal(r.Body(), &common) + if err != nil { + return nil, fmt.Errorf("decode common params error: %s", err) + } + for i := range common.Routes { // parse rules from routes + if common.Routes[i].Action == "block" { var matchs []string - if _, ok := nodeInfo.Routes[i].Match.(string); ok { - matchs = strings.Split(nodeInfo.Routes[i].Match.(string), ",") + if _, ok := common.Routes[i].Match.(string); ok { + matchs = strings.Split(common.Routes[i].Match.(string), ",") } else { - matchs = nodeInfo.Routes[i].Match.([]string) + matchs = common.Routes[i].Match.([]string) } for _, v := range matchs { - nodeInfo.Rules = append(nodeInfo.Rules, regexp.MustCompile(v)) + node.Rules = append(node.Rules, regexp.MustCompile(v)) } } } - nodeInfo.Routes = nil - nodeInfo.BaseConfig.PullInterval = intervalToTime(nodeInfo.BaseConfig.PullInterval) - nodeInfo.BaseConfig.PushInterval = intervalToTime(nodeInfo.BaseConfig.PushInterval) + 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 + } + 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": + rsp := TrojanNodeRsp{} + err = json.Unmarshal(r.Body(), &rsp) + if err != nil { + return nil, fmt.Errorf("decode v2ray params error: %s", err) + } + 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 + } c.etag = r.Header().Get("Etag") return } diff --git a/common/builder/inbound.go b/common/builder/inbound.go index 577749f..ae9f5bb 100644 --- a/common/builder/inbound.go +++ b/common/builder/inbound.go @@ -7,9 +7,7 @@ import ( "errors" "fmt" "github.com/Yuzuki616/V2bX/api/panel" - "github.com/Yuzuki616/V2bX/common/file" "github.com/Yuzuki616/V2bX/conf" - "github.com/Yuzuki616/V2bX/node/lego" "github.com/goccy/go-json" "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/core" @@ -23,7 +21,7 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s t := coreConf.TransportProtocol(nodeInfo.Network) in.StreamSetting = &coreConf.StreamConfig{Network: &t} var err error - switch nodeInfo.NodeType { + switch nodeInfo.Type { case "v2ray": err = buildV2ray(config, nodeInfo, in) case "trojan": @@ -31,14 +29,14 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s case "shadowsocks": err = buildShadowsocks(config, nodeInfo, in) default: - return nil, fmt.Errorf("unsupported node type: %s, Only support: V2ray, Trojan, Shadowsocks", nodeInfo.NodeType) + return nil, fmt.Errorf("unsupported node type: %s, Only support: V2ray, Trojan, Shadowsocks", nodeInfo.Type) } if err != nil { return nil, err } // Set server port in.PortList = &coreConf.PortList{ - Range: []coreConf.PortRange{{From: uint32(nodeInfo.ServerPort), To: uint32(nodeInfo.ServerPort)}}, + Range: []coreConf.PortRange{{From: uint32(nodeInfo.Port), To: uint32(nodeInfo.Port)}}, } // Set Listen IP address ipAddress := net.ParseAddress(config.ListenIP) @@ -48,7 +46,7 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s Enabled: true, DestOverride: &coreConf.StringList{"http", "tls"}, } - if config.DisableSniffing { + if config.XrayOptions.DisableSniffing { sniffingConfig.Enabled = false } in.SniffingConfig = sniffingConfig @@ -66,7 +64,7 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s AcceptProxyProtocol: config.EnableProxyProtocol} //Enable proxy protocol } // Set TLS or Reality settings - if nodeInfo.Tls != 0 { + if nodeInfo.Tls { if config.CertConfig == nil { return nil, errors.New("the CertConfig is not vail") } @@ -91,16 +89,11 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s } default: // Normal tls - in.StreamSetting.Security = "tls" - certFile, keyFile, err := getCertFile(config.CertConfig) - if err != nil { - return nil, err - } in.StreamSetting.TLSSettings = &coreConf.TLSConfig{ Certs: []*coreConf.TLSCertConfig{ { - CertFile: certFile, - KeyFile: keyFile, + CertFile: config.CertConfig.CertFile, + KeyFile: config.CertConfig.KeyFile, OcspStapling: 3600, }, }, @@ -111,24 +104,25 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s // Support ProxyProtocol for any transport protocol if *in.StreamSetting.Network != "tcp" && *in.StreamSetting.Network != "ws" && + *in.StreamSetting.Network != "" && config.EnableProxyProtocol { - sockoptConfig := &coreConf.SocketConfig{ + socketConfig := &coreConf.SocketConfig{ AcceptProxyProtocol: config.EnableProxyProtocol, - TFO: config.EnableTFO, + TFO: config.XrayOptions.EnableTFO, } //Enable proxy protocol - in.StreamSetting.SocketSettings = sockoptConfig + in.StreamSetting.SocketSettings = socketConfig } in.Tag = tag return in.Build() } func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error { - if config.EnableVless { + if config.XrayOptions.EnableVless { //Set vless inbound.Protocol = "vless" - if config.EnableFallback { + if config.XrayOptions.EnableFallback { // Set fallback - fallbackConfigs, err := buildVlessFallbacks(config.FallBackConfigs) + fallbackConfigs, err := buildVlessFallbacks(config.XrayOptions.FallBackConfigs) if err != nil { return err } @@ -185,9 +179,9 @@ func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound func buildTrojan(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error { inbound.Protocol = "trojan" - if config.EnableFallback { + if config.XrayOptions.EnableFallback { // Set fallback - fallbackConfigs, err := buildTrojanFallbacks(config.FallBackConfigs) + fallbackConfigs, err := buildTrojanFallbacks(config.XrayOptions.FallBackConfigs) if err != nil { return err } @@ -234,7 +228,7 @@ func buildShadowsocks(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, i settings.Users = append(settings.Users, defaultSSuser) settings.NetworkList = &coreConf.NetworkList{"tcp", "udp"} settings.IVCheck = true - if config.DisableIVCheck { + if config.XrayOptions.DisableIVCheck { settings.IVCheck = false } t := coreConf.TransportProtocol("tcp") @@ -247,30 +241,6 @@ func buildShadowsocks(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, i return nil } -func getCertFile(certConfig *conf.CertConfig) (certFile string, keyFile string, err error) { - if certConfig.CertFile == "" || certConfig.KeyFile == "" { - return "", "", fmt.Errorf("cert file path or key file path not exist") - } - switch certConfig.CertMode { - case "file": - return certConfig.CertFile, certConfig.KeyFile, nil - case "dns", "http": - if file.IsExist(certConfig.CertFile) && file.IsExist(certConfig.KeyFile) { - return certConfig.CertFile, certConfig.KeyFile, nil - } - l, err := lego.New(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 certConfig.CertFile, certConfig.KeyFile, nil - } - return "", "", fmt.Errorf("unsupported certmode: %s", certConfig.CertMode) -} - func buildVlessFallbacks(fallbackConfigs []conf.FallBackConfig) ([]*coreConf.VLessInboundFallback, error) { if fallbackConfigs == nil { return nil, fmt.Errorf("you must provide FallBackConfigs") diff --git a/common/builder/outbound.go b/common/builder/outbound.go index 66bac83..f3be9b9 100644 --- a/common/builder/outbound.go +++ b/common/builder/outbound.go @@ -2,7 +2,6 @@ package builder import ( "fmt" - "github.com/Yuzuki616/V2bX/api/panel" conf2 "github.com/Yuzuki616/V2bX/conf" "github.com/goccy/go-json" "github.com/xtls/xray-core/common/net" @@ -11,7 +10,7 @@ import ( ) // BuildOutbound build freedom outbund config for addoutbound -func BuildOutbound(config *conf2.ControllerConfig, nodeInfo *panel.NodeInfo, tag string) (*core.OutboundHandlerConfig, error) { +func BuildOutbound(config *conf2.ControllerConfig, tag string) (*core.OutboundHandlerConfig, error) { outboundDetourConfig := &conf.OutboundDetourConfig{} outboundDetourConfig.Protocol = "freedom" outboundDetourConfig.Tag = tag @@ -24,9 +23,9 @@ func BuildOutbound(config *conf2.ControllerConfig, nodeInfo *panel.NodeInfo, tag // Freedom Protocol setting var domainStrategy = "Asis" - if config.EnableDNS { - if config.DNSType != "" { - domainStrategy = config.DNSType + if config.XrayOptions.EnableDNS { + if config.XrayOptions.DNSType != "" { + domainStrategy = config.XrayOptions.DNSType } else { domainStrategy = "UseIP" } @@ -37,7 +36,7 @@ func BuildOutbound(config *conf2.ControllerConfig, nodeInfo *panel.NodeInfo, tag var setting json.RawMessage setting, err := json.Marshal(proxySetting) if err != nil { - return nil, fmt.Errorf("marshal proxy %s config fialed: %s", nodeInfo.NodeType, err) + return nil, fmt.Errorf("marshal proxy config error: %s", err) } outboundDetourConfig.Settings = &setting return outboundDetourConfig.Build() diff --git a/common/builder/user.go b/common/builder/user.go index fdaa4a5..a410a1d 100644 --- a/common/builder/user.go +++ b/common/builder/user.go @@ -32,7 +32,7 @@ func BuildVmessUser(tag string, userInfo *panel.UserInfo) (user *protocol.User) } return &protocol.User{ Level: 0, - Email: BuildUserTag(tag, userInfo), // Uid: InboundTag|email|uid + Email: BuildUserTag(tag, userInfo.Uuid), // Uid: InboundTag|email Account: serial.ToTypedMessage(vmessAccount.Build()), } } @@ -54,7 +54,7 @@ func BuildVlessUser(tag string, userInfo *panel.UserInfo, xtls bool) (user *prot } return &protocol.User{ Level: 0, - Email: BuildUserTag(tag, userInfo), + Email: BuildUserTag(tag, userInfo.Uuid), Account: serial.ToTypedMessage(vlessAccount), } } @@ -73,7 +73,7 @@ func BuildTrojanUser(tag string, userInfo *panel.UserInfo) (user *protocol.User) } return &protocol.User{ Level: 0, - Email: BuildUserTag(tag, userInfo), + Email: BuildUserTag(tag, userInfo.Uuid), Account: serial.ToTypedMessage(trojanAccount), } } @@ -115,8 +115,8 @@ func BuildSSUser(tag string, userInfo *panel.UserInfo, cypher string, serverKey } } -func BuildUserTag(tag string, user *panel.UserInfo) string { - return fmt.Sprintf("%s|%s|%d", tag, user.Uuid, user.Id) +func BuildUserTag(tag string, uuid string) string { + return fmt.Sprintf("%s|%s", tag, uuid) } func getCipherFromString(c string) shadowsocks.CipherType { diff --git a/conf/node.go b/conf/node.go index 4deac93..db0cfda 100644 --- a/conf/node.go +++ b/conf/node.go @@ -15,22 +15,34 @@ type ApiConfig struct { } type ControllerConfig struct { - ListenIP string `yaml:"ListenIP"` - SendIP string `yaml:"SendIP"` - EnableDNS bool `yaml:"EnableDNS"` - DNSType string `yaml:"DNSType"` - EnableVless bool `yaml:"EnableVless"` - EnableXtls bool `yaml:"EnableXtls"` - LimitConfig LimitConfig `yaml:"LimitConfig"` - DisableUploadTraffic bool `yaml:"DisableUploadTraffic"` - DisableGetRule bool `yaml:"DisableGetRule"` - EnableProxyProtocol bool `yaml:"EnableProxyProtocol"` - EnableTFO bool `yaml:"EnableTFO"` - DisableIVCheck bool `yaml:"DisableIVCheck"` - DisableSniffing bool `yaml:"DisableSniffing"` - EnableFallback bool `yaml:"EnableFallback"` - FallBackConfigs []FallBackConfig `yaml:"FallBackConfigs"` - CertConfig *CertConfig `yaml:"CertConfig"` + DisableUploadTraffic bool `yaml:"DisableUploadTraffic"` + DisableGetRule bool `yaml:"DisableGetRule"` + ListenIP string `yaml:"ListenIP"` + SendIP string `yaml:"SendIP"` + EnableProxyProtocol bool `yaml:"EnableProxyProtocol"` + XrayOptions *XrayOptions `yaml:"XrayOptions"` + HyOptions *HyOptions `yaml:"HyOptions"` + LimitConfig LimitConfig `yaml:"LimitConfig"` + CertConfig *CertConfig `yaml:"CertConfig"` +} + +type XrayOptions struct { + EnableDNS bool `yaml:"EnableDNS"` + DNSType string `yaml:"DNSType"` + EnableVless bool `yaml:"EnableVless"` + EnableXtls bool `yaml:"EnableXtls"` + 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 HyOptions struct { + Resolver string `yaml:"Resolver"` + ResolvePreference string `yaml:"ResolvePreference"` + SendDevice string `yaml:"SendDevice"` } type LimitConfig struct { diff --git a/conf/old.go b/conf/old.go index 85f392e..7c8d92e 100644 --- a/conf/old.go +++ b/conf/old.go @@ -49,7 +49,7 @@ func migrateOldConfig(c *Conf, old *OldConfig) { } // node option if old.NodesConfig[i].ApiConfig.EnableVless { - n.ControllerConfig.EnableVless = true + n.ControllerConfig.XrayOptions.EnableVless = true changed = true } // limit config diff --git a/core/hy/acme.go b/core/hy/acme.go deleted file mode 100644 index 5cc7086..0000000 --- a/core/hy/acme.go +++ /dev/null @@ -1,74 +0,0 @@ -package hy - -import ( - "context" - "crypto/tls" - "os" - "path/filepath" - "runtime" - - "go.uber.org/zap" - - "github.com/caddyserver/certmagic" -) - -func acmeTLSConfig(domains []string, email string, disableHTTP bool, disableTLSALPN bool, - altHTTPPort int, altTLSALPNPort int, -) (*tls.Config, error) { - cfg := &certmagic.Config{ - RenewalWindowRatio: certmagic.DefaultRenewalWindowRatio, - KeySource: certmagic.DefaultKeyGenerator, - Storage: &certmagic.FileStorage{Path: dataDir()}, - Logger: zap.NewNop(), - } - issuer := certmagic.NewACMEIssuer(cfg, certmagic.ACMEIssuer{ - CA: certmagic.LetsEncryptProductionCA, - TestCA: certmagic.LetsEncryptStagingCA, - Email: email, - Agreed: true, - DisableHTTPChallenge: disableHTTP, - DisableTLSALPNChallenge: disableTLSALPN, - AltHTTPPort: altHTTPPort, - AltTLSALPNPort: altTLSALPNPort, - Logger: zap.NewNop(), - }) - cfg.Issuers = []certmagic.Issuer{issuer} - - cache := certmagic.NewCache(certmagic.CacheOptions{ - GetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) { - return cfg, nil - }, - Logger: zap.NewNop(), - }) - cfg = certmagic.New(cache, *cfg) - - err := cfg.ManageSync(context.Background(), domains) - if err != nil { - return nil, err - } - return cfg.TLSConfig(), nil -} - -func homeDir() string { - home := os.Getenv("HOME") - if home == "" && runtime.GOOS == "windows" { - drive := os.Getenv("HOMEDRIVE") - path := os.Getenv("HOMEPATH") - home = drive + path - if drive == "" || path == "" { - home = os.Getenv("USERPROFILE") - } - } - if home == "" { - home = "." - } - return home -} - -func dataDir() string { - baseDir := filepath.Join(homeDir(), ".local", "share") - if xdgData := os.Getenv("XDG_DATA_HOME"); xdgData != "" { - baseDir = xdgData - } - return filepath.Join(baseDir, "certmagic") -} diff --git a/core/hy/config.go b/core/hy/config.go index 94c4c5a..e7f02d5 100644 --- a/core/hy/config.go +++ b/core/hy/config.go @@ -1,13 +1,5 @@ package hy -import ( - "errors" - "fmt" - "github.com/yosuke-furukawa/json5/encoding/json5" - "regexp" - "strconv" -) - const ( mbpsToBps = 125000 minSpeedBPS = 16384 @@ -27,281 +19,8 @@ const ( DefaultClientHopIntervalSec = 10 ) -var rateStringRegexp = regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`) - -type serverConfig struct { - Listen string `json:"listen"` - Protocol string `json:"protocol"` - ACME struct { - Domains []string `json:"domains"` - Email string `json:"email"` - DisableHTTPChallenge bool `json:"disable_http"` - DisableTLSALPNChallenge bool `json:"disable_tlsalpn"` - AltHTTPPort int `json:"alt_http_port"` - AltTLSALPNPort int `json:"alt_tlsalpn_port"` - } `json:"acme"` - CertFile string `json:"cert"` - KeyFile string `json:"key"` - // Optional below - Up string `json:"up"` - UpMbps int `json:"up_mbps"` - Down string `json:"down"` - DownMbps int `json:"down_mbps"` - DisableUDP bool `json:"disable_udp"` - ACL string `json:"acl"` - MMDB string `json:"mmdb"` - Obfs string `json:"obfs"` - Auth struct { - Mode string `json:"mode"` - Config json5.RawMessage `json:"config"` - } `json:"auth"` - ALPN string `json:"alpn"` - PrometheusListen string `json:"prometheus_listen"` - ReceiveWindowConn uint64 `json:"recv_window_conn"` - ReceiveWindowClient uint64 `json:"recv_window_client"` - MaxConnClient int `json:"max_conn_client"` - DisableMTUDiscovery bool `json:"disable_mtu_discovery"` - Resolver string `json:"resolver"` - ResolvePreference string `json:"resolve_preference"` - SOCKS5Outbound struct { - Server string `json:"server"` - User string `json:"user"` - Password string `json:"password"` - } `json:"socks5_outbound"` - BindOutbound struct { - Address string `json:"address"` - Device string `json:"device"` - } `json:"bind_outbound"` -} - -func (c *serverConfig) Speed() (uint64, uint64, error) { - var up, down uint64 - if len(c.Up) > 0 { - up = stringToBps(c.Up) - if up == 0 { - return 0, 0, errors.New("invalid speed format") - } - } else { - up = uint64(c.UpMbps) * mbpsToBps - } - if len(c.Down) > 0 { - down = stringToBps(c.Down) - if down == 0 { - return 0, 0, errors.New("invalid speed format") - } - } else { - down = uint64(c.DownMbps) * mbpsToBps - } - return up, down, nil -} - -func (c *serverConfig) Check() error { - if len(c.Listen) == 0 { - return errors.New("missing listen address") - } - if len(c.ACME.Domains) == 0 && (len(c.CertFile) == 0 || len(c.KeyFile) == 0) { - return errors.New("need either ACME info or cert/key files") - } - if len(c.ACME.Domains) > 0 && (len(c.CertFile) > 0 || len(c.KeyFile) > 0) { - return errors.New("cannot use both ACME and cert/key files, they are mutually exclusive") - } - if up, down, err := c.Speed(); err != nil || (up != 0 && up < minSpeedBPS) || (down != 0 && down < minSpeedBPS) { - return errors.New("invalid speed") - } - if (c.ReceiveWindowConn != 0 && c.ReceiveWindowConn < 65536) || - (c.ReceiveWindowClient != 0 && c.ReceiveWindowClient < 65536) { - return errors.New("invalid receive window size") - } - if c.MaxConnClient < 0 { - return errors.New("invalid max connections per client") - } - return nil -} - -func (c *serverConfig) Fill() { - if len(c.ALPN) == 0 { - c.ALPN = DefaultALPN - } - if c.ReceiveWindowConn == 0 { - c.ReceiveWindowConn = DefaultStreamReceiveWindow - } - if c.ReceiveWindowClient == 0 { - c.ReceiveWindowClient = DefaultConnectionReceiveWindow - } - if c.MaxConnClient == 0 { - c.MaxConnClient = DefaultMaxIncomingStreams - } - if len(c.MMDB) == 0 { - c.MMDB = DefaultMMDBFilename - } -} - -func (c *serverConfig) String() string { - return fmt.Sprintf("%+v", *c) -} - -type Relay struct { - Listen string `json:"listen"` - Remote string `json:"remote"` - Timeout int `json:"timeout"` -} - -func (r *Relay) Check() error { - if len(r.Listen) == 0 { - return errors.New("missing relay listen address") - } - if len(r.Remote) == 0 { - return errors.New("missing relay remote address") - } - if r.Timeout != 0 && r.Timeout < 4 { - return errors.New("invalid relay timeout") - } - return nil -} - -type clientConfig struct { - Server string `json:"server"` - Protocol string `json:"protocol"` - Up string `json:"up"` - UpMbps int `json:"up_mbps"` - Down string `json:"down"` - DownMbps int `json:"down_mbps"` - // Optional below - Retry int `json:"retry"` - RetryInterval *int `json:"retry_interval"` - QuitOnDisconnect bool `json:"quit_on_disconnect"` - HandshakeTimeout int `json:"handshake_timeout"` - IdleTimeout int `json:"idle_timeout"` - HopInterval int `json:"hop_interval"` - SOCKS5 struct { - Listen string `json:"listen"` - Timeout int `json:"timeout"` - DisableUDP bool `json:"disable_udp"` - User string `json:"user"` - Password string `json:"password"` - } `json:"socks5"` - HTTP struct { - Listen string `json:"listen"` - Timeout int `json:"timeout"` - User string `json:"user"` - Password string `json:"password"` - Cert string `json:"cert"` - Key string `json:"key"` - } `json:"http"` - TUN struct { - Name string `json:"name"` - Timeout int `json:"timeout"` - MTU uint32 `json:"mtu"` - TCPSendBufferSize string `json:"tcp_sndbuf"` - TCPReceiveBufferSize string `json:"tcp_rcvbuf"` - TCPModerateReceiveBuffer bool `json:"tcp_autotuning"` - } `json:"tun"` - TCPRelays []Relay `json:"relay_tcps"` - TCPRelay Relay `json:"relay_tcp"` // deprecated, but we still support it for backward compatibility - UDPRelays []Relay `json:"relay_udps"` - UDPRelay Relay `json:"relay_udp"` // deprecated, but we still support it for backward compatibility - TCPTProxy struct { - Listen string `json:"listen"` - Timeout int `json:"timeout"` - } `json:"tproxy_tcp"` - UDPTProxy struct { - Listen string `json:"listen"` - Timeout int `json:"timeout"` - } `json:"tproxy_udp"` - TCPRedirect struct { - Listen string `json:"listen"` - Timeout int `json:"timeout"` - } `json:"redirect_tcp"` - ACL string `json:"acl"` - MMDB string `json:"mmdb"` - Obfs string `json:"obfs"` - Auth []byte `json:"auth"` - AuthString string `json:"auth_str"` - ALPN string `json:"alpn"` - ServerName string `json:"server_name"` - Insecure bool `json:"insecure"` - CustomCA string `json:"ca"` - ReceiveWindowConn uint64 `json:"recv_window_conn"` - ReceiveWindow uint64 `json:"recv_window"` - DisableMTUDiscovery bool `json:"disable_mtu_discovery"` - FastOpen bool `json:"fast_open"` - LazyStart bool `json:"lazy_start"` - Resolver string `json:"resolver"` - ResolvePreference string `json:"resolve_preference"` -} - -func (c *clientConfig) Speed() (uint64, uint64, error) { - var up, down uint64 - if len(c.Up) > 0 { - up = stringToBps(c.Up) - if up == 0 { - return 0, 0, errors.New("invalid speed format") - } - } else { - up = uint64(c.UpMbps) * mbpsToBps - } - if len(c.Down) > 0 { - down = stringToBps(c.Down) - if down == 0 { - return 0, 0, errors.New("invalid speed format") - } - } else { - down = uint64(c.DownMbps) * mbpsToBps - } - return up, down, nil -} - -func (c *clientConfig) Fill() { - if len(c.ALPN) == 0 { - c.ALPN = DefaultALPN - } - if c.ReceiveWindowConn == 0 { - c.ReceiveWindowConn = DefaultStreamReceiveWindow - } - if c.ReceiveWindow == 0 { - c.ReceiveWindow = DefaultConnectionReceiveWindow - } - if len(c.MMDB) == 0 { - c.MMDB = DefaultMMDBFilename - } - if c.IdleTimeout == 0 { - c.IdleTimeout = DefaultClientIdleTimeoutSec - } - if c.HopInterval == 0 { - c.HopInterval = DefaultClientHopIntervalSec - } -} - -func (c *clientConfig) String() string { - return fmt.Sprintf("%+v", *c) -} - -func stringToBps(s string) uint64 { - if s == "" { - return 0 - } - m := rateStringRegexp.FindStringSubmatch(s) - if m == nil { - return 0 - } - var n uint64 - switch m[2] { - case "K": - n = 1 << 10 - case "M": - n = 1 << 20 - case "G": - n = 1 << 30 - case "T": - n = 1 << 40 - default: - n = 1 - } - v, _ := strconv.ParseUint(m[1], 10, 64) - n = v * n - if m[3] == "b" { - // Bits, need to convert to bytes - n = n >> 3 - } - return n +func SpeedTrans(upM, downM int) (uint64, uint64) { + up := uint64(upM) * mbpsToBps + down := uint64(downM) * mbpsToBps + return up, down } diff --git a/core/hy/counter.go b/core/hy/counter.go new file mode 100644 index 0000000..5d62a74 --- /dev/null +++ b/core/hy/counter.go @@ -0,0 +1,67 @@ +package hy + +import ( + "github.com/apernet/hysteria/core/cs" + "sync" + "sync/atomic" +) + +type UserTrafficCounter struct { + counters map[string]*counters + lock sync.RWMutex +} + +type counters struct { + UpCounter atomic.Int64 + DownCounter atomic.Int64 + //ConnGauge atomic.Int64 +} + +func NewUserTrafficCounter() cs.TrafficCounter { + return new(UserTrafficCounter) +} + +func (c *UserTrafficCounter) getCounters(auth string) *counters { + c.lock.RLock() + cts, ok := c.counters[auth] + c.lock.RUnlock() + if !ok { + cts = &counters{} + c.counters[auth] = cts + } + return cts +} + +func (c *UserTrafficCounter) Rx(auth string, n int) { + cts := c.getCounters(auth) + cts.DownCounter.Add(int64(n)) +} + +func (c *UserTrafficCounter) Tx(auth string, n int) { + cts := c.getCounters(auth) + cts.UpCounter.Add(int64(n)) +} + +func (c *UserTrafficCounter) IncConn(_ string) { + /*cts := c.getCounters(auth) + cts.ConnGauge.Add(1)*/ + return +} + +func (c *UserTrafficCounter) DecConn(_ string) { + /*cts := c.getCounters(auth) + cts.ConnGauge.Add(1)*/ + return +} + +func (c *UserTrafficCounter) Reset(auth string) { + cts := c.getCounters(auth) + cts.UpCounter.Store(0) + cts.DownCounter.Store(0) +} + +func (c *UserTrafficCounter) Delete(auth string) { + c.lock.Lock() + delete(c.counters, auth) + c.lock.Unlock() +} diff --git a/core/hy/counter_test.go b/core/hy/counter_test.go new file mode 100644 index 0000000..8f97e3e --- /dev/null +++ b/core/hy/counter_test.go @@ -0,0 +1,7 @@ +package hy + +import "testing" + +func TestUserTrafficCounter_Rx(t *testing.T) { + +} diff --git a/core/hy/hy.go b/core/hy/hy.go index ef2e31a..88ced0c 100644 --- a/core/hy/hy.go +++ b/core/hy/hy.go @@ -1,306 +1,37 @@ package hy import ( - "crypto/tls" - "io" - "net" - "net/http" - "time" - - "github.com/oschwald/geoip2-golang" - "github.com/quic-go/quic-go" - - "github.com/apernet/hysteria/app/auth" - "github.com/apernet/hysteria/core/acl" - "github.com/apernet/hysteria/core/cs" - "github.com/apernet/hysteria/core/pktconns" - "github.com/apernet/hysteria/core/pmtud" - "github.com/apernet/hysteria/core/sockopt" - "github.com/apernet/hysteria/core/transport" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/sirupsen/logrus" - "github.com/yosuke-furukawa/json5/encoding/json5" + "fmt" + "github.com/Yuzuki616/V2bX/conf" + "github.com/hashicorp/go-multierror" + "sync" ) -var serverPacketConnFuncFactoryMap = map[string]pktconns.ServerPacketConnFuncFactory{ - "": pktconns.NewServerUDPConnFunc, - "udp": pktconns.NewServerUDPConnFunc, - "wechat": pktconns.NewServerWeChatConnFunc, - "wechat-video": pktconns.NewServerWeChatConnFunc, - "faketcp": pktconns.NewServerFakeTCPConnFunc, +type Hy struct { + servers sync.Map } -func server(config *serverConfig) { - logrus.WithField("config", config.String()).Info("Server configuration loaded") - config.Fill() // Fill default values - // Resolver - if len(config.Resolver) > 0 { - err := setResolver(config.Resolver) +func New(_ *conf.CoreConfig) (*Hy, 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 { - logrus.WithFields(logrus.Fields{ - "error": err, - }).Fatal("Failed to set resolver") + errs = multierror.Append(errs, fmt.Errorf("close %s error: %s", tag, err)) } + return true + }) + if errs != nil { + return errs } - // Load TLS config - var tlsConfig *tls.Config - if len(config.ACME.Domains) > 0 { - // ACME mode - tc, err := acmeTLSConfig(config.ACME.Domains, config.ACME.Email, - config.ACME.DisableHTTPChallenge, config.ACME.DisableTLSALPNChallenge, - config.ACME.AltHTTPPort, config.ACME.AltTLSALPNPort) - if err != nil { - logrus.WithFields(logrus.Fields{ - "error": err, - }).Fatal("Failed to get a certificate with ACME") - } - tc.NextProtos = []string{config.ALPN} - tc.MinVersion = tls.VersionTLS13 - tlsConfig = tc - } else { - // Local cert mode - kpl, err := newKeypairLoader(config.CertFile, config.KeyFile) - if err != nil { - logrus.WithFields(logrus.Fields{ - "error": err, - "cert": config.CertFile, - "key": config.KeyFile, - }).Fatal("Failed to load the certificate") - } - tlsConfig = &tls.Config{ - GetCertificate: kpl.GetCertificateFunc(), - NextProtos: []string{config.ALPN}, - MinVersion: tls.VersionTLS13, - } - } - // QUIC config - quicConfig := &quic.Config{ - InitialStreamReceiveWindow: config.ReceiveWindowConn, - MaxStreamReceiveWindow: config.ReceiveWindowConn, - InitialConnectionReceiveWindow: config.ReceiveWindowClient, - MaxConnectionReceiveWindow: config.ReceiveWindowClient, - MaxIncomingStreams: int64(config.MaxConnClient), - MaxIdleTimeout: ServerMaxIdleTimeoutSec * time.Second, - KeepAlivePeriod: 0, // Keep alive should solely be client's responsibility - DisablePathMTUDiscovery: config.DisableMTUDiscovery, - EnableDatagrams: true, - } - if !quicConfig.DisablePathMTUDiscovery && pmtud.DisablePathMTUDiscovery { - logrus.Info("Path MTU Discovery is not yet supported on this platform") - } - // Auth - var authFunc cs.ConnectFunc - var err error - switch authMode := config.Auth.Mode; authMode { - case "", "none": - if len(config.Obfs) == 0 { - logrus.Warn("Neither authentication nor obfuscation is turned on. " + - "Your server could be used by anyone! Are you sure this is what you want?") - } - authFunc = func(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) { - return true, "Welcome" - } - case "password", "passwords": - authFunc, err = auth.PasswordAuthFunc(config.Auth.Config) - if err != nil { - logrus.WithFields(logrus.Fields{ - "error": err, - }).Fatal("Failed to enable password authentication") - } else { - logrus.Info("Password authentication enabled") - } - case "external": - authFunc, err = auth.ExternalAuthFunc(config.Auth.Config) - if err != nil { - logrus.WithFields(logrus.Fields{ - "error": err, - }).Fatal("Failed to enable external authentication") - } else { - logrus.Info("External authentication enabled") - } - default: - logrus.WithField("mode", config.Auth.Mode).Fatal("Unsupported authentication mode") - } - connectFunc := func(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) { - ok, msg := authFunc(addr, auth, sSend, sRecv) - if !ok { - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - "msg": msg, - }).Info("Authentication failed, client rejected") - } else { - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - }).Info("Client connected") - } - return ok, msg - } - // Resolve preference - if len(config.ResolvePreference) > 0 { - pref, err := transport.ResolvePreferenceFromString(config.ResolvePreference) - 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 config.BindOutbound.Device != "" { - iface, err := net.InterfaceByName(config.BindOutbound.Device) - 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 config.BindOutbound.Address != "" { - ip := net.ParseIP(config.BindOutbound.Address) - 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 - if len(config.ACL) > 0 { - aclEngine, err = acl.LoadFromFile(config.ACL, func(addr string) (*net.IPAddr, error) { - ipAddr, _, err := transport.DefaultServerTransport.ResolveIPAddr(addr) - return ipAddr, err - }, - func() (*geoip2.Reader, error) { - return loadMMDBReader(config.MMDB) - }) - if err != nil { - logrus.WithFields(logrus.Fields{ - "error": err, - "file": config.ACL, - }).Fatal("Failed to parse ACL") - } - aclEngine.DefaultAction = acl.ActionDirect - } - // Prometheus - var trafficCounter cs.TrafficCounter - if len(config.PrometheusListen) > 0 { - promReg := prometheus.NewRegistry() - trafficCounter = NewPrometheusTrafficCounter(promReg) - go func() { - http.Handle("/metrics", promhttp.HandlerFor(promReg, promhttp.HandlerOpts{})) - err := http.ListenAndServe(config.PrometheusListen, nil) - logrus.WithField("error", err).Fatal("Prometheus HTTP server error") - }() - } - // Packet conn - pktConnFuncFactory := serverPacketConnFuncFactoryMap[config.Protocol] - if pktConnFuncFactory == nil { - logrus.WithField("protocol", config.Protocol).Fatal("Unsupported protocol") - } - pktConnFunc := pktConnFuncFactory(config.Obfs) - pktConn, err := pktConnFunc(config.Listen) - if err != nil { - logrus.WithFields(logrus.Fields{ - "error": err, - "addr": config.Listen, - }).Fatal("Failed to listen on the UDP address") - } - // Server - up, down, _ := config.Speed() - server, err := cs.NewServer(tlsConfig, quicConfig, pktConn, - transport.DefaultServerTransport, up, down, config.DisableUDP, aclEngine, - connectFunc, disconnectFunc, tcpRequestFunc, tcpErrorFunc, udpRequestFunc, udpErrorFunc, trafficCounter) - if err != nil { - logrus.WithField("error", err).Fatal("Failed to initialize server") - } - defer server.Close() - logrus.WithField("addr", config.Listen).Info("Server up and running") - - err = server.Serve() - logrus.WithField("error", err).Fatal("Server shutdown") -} - -func disconnectFunc(addr net.Addr, auth []byte, err error) { - 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" - } -} - -func parseServerConfig(cb []byte) (*serverConfig, error) { - var c serverConfig - err := json5.Unmarshal(cb, &c) - if err != nil { - return nil, err - } - return &c, c.Check() + return nil } diff --git a/core/hy/node.go b/core/hy/node.go new file mode 100644 index 0000000..0000c30 --- /dev/null +++ b/core/hy/node.go @@ -0,0 +1,34 @@ +package hy + +import ( + "errors" + "fmt" + "github.com/Yuzuki616/V2bX/api/panel" + "github.com/Yuzuki616/V2bX/conf" + "github.com/apernet/hysteria/core/cs" +) + +func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.ControllerConfig) error { + if info.Type != "hysteria" { + return errors.New("the core not support " + info.Type) + } + s := NewServer(tag) + 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.(*cs.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/prom.go b/core/hy/prom.go deleted file mode 100644 index ef31733..0000000 --- a/core/hy/prom.go +++ /dev/null @@ -1,71 +0,0 @@ -package hy - -import ( - "github.com/apernet/hysteria/core/cs" - "github.com/prometheus/client_golang/prometheus" -) - -type prometheusTrafficCounter struct { - reg *prometheus.Registry - upCounterVec *prometheus.CounterVec - downCounterVec *prometheus.CounterVec - connGaugeVec *prometheus.GaugeVec - counterMap map[string]counters -} - -type counters struct { - UpCounter prometheus.Counter - DownCounter prometheus.Counter - ConnGauge prometheus.Gauge -} - -func NewPrometheusTrafficCounter(reg *prometheus.Registry) cs.TrafficCounter { - c := &prometheusTrafficCounter{ - reg: reg, - upCounterVec: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "hysteria_traffic_uplink_bytes_total", - }, []string{"auth"}), - downCounterVec: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "hysteria_traffic_downlink_bytes_total", - }, []string{"auth"}), - connGaugeVec: prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Name: "hysteria_active_conn", - }, []string{"auth"}), - counterMap: make(map[string]counters), - } - reg.MustRegister(c.upCounterVec, c.downCounterVec, c.connGaugeVec) - return c -} - -func (c *prometheusTrafficCounter) getCounters(auth string) counters { - cts, ok := c.counterMap[auth] - if !ok { - cts = counters{ - UpCounter: c.upCounterVec.WithLabelValues(auth), - DownCounter: c.downCounterVec.WithLabelValues(auth), - ConnGauge: c.connGaugeVec.WithLabelValues(auth), - } - c.counterMap[auth] = cts - } - return cts -} - -func (c *prometheusTrafficCounter) Rx(auth string, n int) { - cts := c.getCounters(auth) - cts.DownCounter.Add(float64(n)) -} - -func (c *prometheusTrafficCounter) Tx(auth string, n int) { - cts := c.getCounters(auth) - cts.UpCounter.Add(float64(n)) -} - -func (c *prometheusTrafficCounter) IncConn(auth string) { - cts := c.getCounters(auth) - cts.ConnGauge.Inc() -} - -func (c *prometheusTrafficCounter) DecConn(auth string) { - cts := c.getCounters(auth) - cts.ConnGauge.Dec() -} diff --git a/core/hy/server.go b/core/hy/server.go new file mode 100644 index 0000000..8fe4de0 --- /dev/null +++ b/core/hy/server.go @@ -0,0 +1,263 @@ +package hy + +import ( + "crypto/tls" + "errors" + "fmt" + "github.com/Yuzuki616/V2bX/api/panel" + "github.com/Yuzuki616/V2bX/conf" + "github.com/apernet/hysteria/core/sockopt" + "io" + "net" + "sync" + "sync/atomic" + "time" + + "github.com/quic-go/quic-go" + + "github.com/apernet/hysteria/core/acl" + "github.com/apernet/hysteria/core/cs" + "github.com/apernet/hysteria/core/pktconns" + "github.com/apernet/hysteria/core/pmtud" + "github.com/apernet/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 + counter UserTrafficCounter + users sync.Map + running atomic.Bool + *cs.Server +} + +func NewServer(tag string) *Server { + return &Server{ + tag: tag, + } +} + +func (s *Server) runServer(node *panel.NodeInfo, c *conf.ControllerConfig) 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 + /*if len(config.ACL) > 0 { + aclEngine, err = acl.LoadFromFile(config.ACL, func(addr string) (*net.IPAddr, error) { + ipAddr, _, err := transport.DefaultServerTransport.ResolveIPAddr(addr) + return ipAddr, err + }, + func() (*geoip2.Reader, error) { + return loadMMDBReader(config.MMDB) + }) + if err != nil { + logrus.WithFields(logrus.Fields{ + "error": err, + "file": config.ACL, + }).Fatal("Failed to parse ACL") + } + aclEngine.DefaultAction = acl.ActionDirect + }*/ + // Prometheus + trafficCounter := NewUserTrafficCounter() + // 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, trafficCounter) + 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, string) { + if email, ok := s.users.Load(string(auth)); ok { + return true, email.(string), "Done" + } + return false, "", "Failed" +} + +func (s *Server) connectFunc(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) { + ok, email, msg := s.authByUser(addr, auth, sSend, sRecv) + if !ok { + logrus.WithFields(logrus.Fields{ + "src": defaultIPMasker.Mask(addr.String()), + }).Info("Authentication failed, client rejected") + } else { + logrus.WithFields(logrus.Fields{ + "src": defaultIPMasker.Mask(addr.String()), + "email": email, + }).Info("Client connected") + } + return ok, msg +} + +func (s *Server) disconnectFunc(addr net.Addr, auth []byte, err error) { + 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 new file mode 100644 index 0000000..5d5f5ce --- /dev/null +++ b/core/hy/server_test.go @@ -0,0 +1,25 @@ +package hy + +import ( + "github.com/Yuzuki616/V2bX/api/panel" + "github.com/Yuzuki616/V2bX/conf" + "testing" +) + +func TestServer(t *testing.T) { + s := NewServer("test") + t.Log(s.runServer(&panel.NodeInfo{ + Port: 11415, + UpMbps: 100, + DownMbps: 100, + HyObfs: "atresssdaaaadd", + }, &conf.ControllerConfig{ + ListenIP: "127.0.0.1", + HyOptions: &conf.HyOptions{}, + CertConfig: &conf.CertConfig{ + CertFile: "../../test_data/1.pem", + KeyFile: "../../test_data/1.key", + }, + })) + select {} +} diff --git a/core/hy/user.go b/core/hy/user.go new file mode 100644 index 0000000..f069b3d --- /dev/null +++ b/core/hy/user.go @@ -0,0 +1,42 @@ +package hy + +import ( + "errors" + "github.com/Yuzuki616/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) { + s, _ := h.servers.Load(tag) + c := &s.(*Server).counter + up = c.getCounters(uuid).UpCounter.Load() + down = c.getCounters(uuid).DownCounter.Load() + if reset { + c.Reset(uuid) + } + return +} + +func (h *Hy) DelUsers(users []string, 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]) + s.counter.Delete(users[i]) + } + return nil +} diff --git a/core/imports/hy.go b/core/imports/hy.go index b59cbc3..650042f 100644 --- a/core/imports/hy.go +++ b/core/imports/hy.go @@ -2,5 +2,5 @@ package imports -// not works for now -//import _ "github.com/Yuzuki616/V2bX/core/hy" +// not yet tested +import _ "github.com/Yuzuki616/V2bX/core/hy" diff --git a/core/interface.go b/core/interface.go index 72980dc..56513e0 100644 --- a/core/interface.go +++ b/core/interface.go @@ -17,6 +17,6 @@ type Core interface { AddNode(tag string, info *panel.NodeInfo, config *conf.ControllerConfig) error DelNode(tag string) error AddUsers(p *AddUsersParams) (added int, err error) - GetUserTraffic(email string, reset bool) (up int64, down int64) + GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) DelUsers(users []string, tag string) error } diff --git a/core/xray/node.go b/core/xray/node.go index 3c2d638..8dabad1 100644 --- a/core/xray/node.go +++ b/core/xray/node.go @@ -20,7 +20,7 @@ func (c *Core) AddNode(tag string, info *panel.NodeInfo, config *conf.Controller if err != nil { return fmt.Errorf("add inbound error: %s", err) } - outBoundConfig, err := builder.BuildOutbound(config, info, tag) + outBoundConfig, err := builder.BuildOutbound(config, tag) if err != nil { return fmt.Errorf("build outbound error: %s", err) } diff --git a/core/xray/user.go b/core/xray/user.go index 4a6cfac..43f2c63 100644 --- a/core/xray/user.go +++ b/core/xray/user.go @@ -40,9 +40,9 @@ func (c *Core) DelUsers(users []string, tag string) error { return nil } -func (c *Core) GetUserTraffic(email string, reset bool) (up int64, down int64) { - upName := "user>>>" + email + ">>>traffic>>>uplink" - downName := "user>>>" + email + ">>>traffic>>>downlink" +func (c *Core) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) { + upName := "user>>>" + builder.BuildUserTag(tag, uuid) + ">>>traffic>>>uplink" + downName := "user>>>" + builder.BuildUserTag(tag, uuid) + ">>>traffic>>>downlink" upCounter := c.shm.GetCounter(upName) downCounter := c.shm.GetCounter(downName) if reset { @@ -65,10 +65,10 @@ func (c *Core) GetUserTraffic(email string, reset bool) (up int64, down int64) { func (c *Core) AddUsers(p *vCore.AddUsersParams) (added int, err error) { users := make([]*protocol.User, 0, len(p.UserInfo)) - switch p.NodeInfo.NodeType { + switch p.NodeInfo.Type { case "v2ray": - if p.Config.EnableVless { - users = builder.BuildVlessUsers(p.Tag, p.UserInfo, p.Config.EnableXtls) + if p.Config.XrayOptions.EnableXtls { + users = builder.BuildVlessUsers(p.Tag, p.UserInfo, true) } else { users = builder.BuildVmessUsers(p.Tag, p.UserInfo) } @@ -80,7 +80,7 @@ func (c *Core) AddUsers(p *vCore.AddUsersParams) (added int, err error) { p.NodeInfo.Cipher, p.NodeInfo.ServerKey) default: - return 0, fmt.Errorf("unsupported node type: %s", p.NodeInfo.NodeType) + return 0, fmt.Errorf("unsupported node type: %s", p.NodeInfo.Type) } man, err := c.GetUserManager(p.Tag) if err != nil { diff --git a/go.mod b/go.mod index 967be96..3e7995a 100644 --- a/go.mod +++ b/go.mod @@ -3,27 +3,23 @@ module github.com/Yuzuki616/V2bX go 1.20 require ( - github.com/apernet/hysteria/app v1.3.4 github.com/apernet/hysteria/core v1.3.4 github.com/beevik/ntp v1.0.0 - github.com/caddyserver/certmagic v0.17.2 github.com/folbricht/routedns v0.1.21-0.20230220022436-4ae86ce30d53 github.com/fsnotify/fsnotify v1.6.0 github.com/go-acme/lego/v4 v4.12.1 github.com/go-redis/redis/v8 v8.11.5 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/juju/ratelimit v1.0.2 github.com/oschwald/geoip2-golang v1.8.0 - github.com/prometheus/client_golang v1.14.0 github.com/quic-go/quic-go v0.33.0 github.com/sagernet/sing-box v1.2.7 github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.15.0 github.com/xtls/xray-core v1.8.1 - github.com/yosuke-furukawa/json5 v0.1.1 - go.uber.org/zap v1.24.0 golang.org/x/crypto v0.9.0 google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v3 v3.0.1 @@ -50,7 +46,6 @@ require ( 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/beorn7/perks v1.0.1 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -89,7 +84,6 @@ require ( 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-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.1 // indirect github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -105,7 +99,6 @@ require ( github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b // indirect github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect github.com/labbsr0x/goh v1.0.1 // indirect - github.com/libdns/libdns v0.2.1 // indirect github.com/linode/linodego v1.9.1 // indirect github.com/liquidweb/go-lwApi v0.0.5 // indirect github.com/liquidweb/liquidweb-cli v0.6.9 // indirect @@ -114,8 +107,6 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.17 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/mholt/acmez v1.1.1 // indirect github.com/miekg/dns v1.1.54 // indirect github.com/mimuret/golang-iij-dpf v0.7.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -145,14 +136,12 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pquerna/otp v1.3.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect github.com/quic-go/qpack v0.4.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/refraction-networking/utls v1.3.2 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/sacloud/api-client-go v0.2.1 // indirect github.com/sacloud/go-http v0.1.2 // indirect github.com/sacloud/iaas-api-go v1.3.2 // indirect @@ -194,7 +183,6 @@ require ( go.opencensus.io v0.24.0 // indirect go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 // indirect go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.10.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect golang.org/x/mod v0.10.0 // indirect diff --git a/go.sum b/go.sum index fc11e1c..6ccd8b3 100644 --- a/go.sum +++ b/go.sum @@ -84,10 +84,7 @@ github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91/go.mod h1:cDLGBht23 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.1 h1:5BIsppVPdWJA29Yb5cYawQYeh5geN413WxAgBZvEtdA= github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.1/go.mod h1:kX6YddBkXqqywAe8c9LyvgTCyFuZCTMF4cRPQhc3Fy8= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755 h1:J45/QHgrzUdqe/Vco/Vxk0wRvdS2nKUxmf/zLgvfass= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= @@ -96,8 +93,6 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/ github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apernet/hysteria/app v1.3.4 h1:xoePo8NUtQ1KsQCqO/MWPqpbt7lbkE5K6RRX5W5Ea3Q= -github.com/apernet/hysteria/app v1.3.4/go.mod h1:hRzfCSWiT6eyPMXIqYyKRYvz+n+MHrbwTErHsodMReo= github.com/apernet/hysteria/core v1.3.4 h1:i5EqGIf7FZqwsOrT7PagLQeh+P5gHfLkDZWn7/pXUjo= github.com/apernet/hysteria/core v1.3.4/go.mod h1:WxFihvoDBhatefn4w8Lipzy97CWjK6NF1/duT0kGUG0= github.com/apernet/quic-go v0.34.1-0.20230507231629-ec008b7e8473 h1:3KFetJ/lUFn0m9xTFg+rMmz2nyHg+D2boJX0Rp4OF6c= @@ -109,10 +104,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.0.0 h1:d0Lgy1xbNNqVyGfvg2Z96ItKcfyn3lzgus/oRoj9vnk= github.com/beevik/ntp v1.0.0/go.mod h1:JN7/74B0Z4GUGO/1aUeRI2adARlfJGUeaJb0y0Wvnf4= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= 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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= @@ -122,14 +115,11 @@ 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.17.2 h1:o30seC1T/dBqBCNNGNHWwj2i5/I/FMjBbTAhjADP3nE= -github.com/caddyserver/certmagic v0.17.2/go.mod h1:ouWUuC490GOLJzkyN35eXfV8bSbwMwSf4bdhkIxtdQE= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -226,13 +216,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= 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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= 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= @@ -428,13 +413,10 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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= @@ -445,7 +427,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV 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= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg= 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= @@ -458,7 +439,6 @@ github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b h1:DzHy0GlWeF0KAglaTMY7Q+khIFoG8toHP+wLFBVBQJc= github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -485,8 +465,6 @@ github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++ github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= github.com/lestrrat-go/jwx v1.2.7/go.mod h1:bw24IXWbavc0R2RsOtpXL7RtMyP589yZ1+L7kd09ZGA= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= -github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/linode/linodego v1.9.1 h1:29UpEPpYcGFnbwiJW8mbk/bjBZpgd/pv68io2IKTo34= github.com/linode/linodego v1.9.1/go.mod h1:h6AuFR/JpqwwM/vkj7s8KV3iGN8/jxn+zc437F8SZ8w= github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs= @@ -525,10 +503,7 @@ github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mholt/acmez v1.1.1 h1:sYeeYd/EHVm9cSmLdWey5oW/fXFVAq5pNLjSczN2ZUg= -github.com/mholt/acmez v1.1.1/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= @@ -557,7 +532,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= @@ -643,37 +617,19 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 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/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= @@ -691,6 +647,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR 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.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= @@ -753,7 +710,6 @@ github.com/simplesurance/bunny-go v0.0.0-20221115111006-e11d9dc91f04 h1:ZTzdx88+ github.com/simplesurance/bunny-go v0.0.0-20221115111006-e11d9dc91f04/go.mod h1:5KS21fpch8TIMyAUv/qQqTa3GZfBDYgjaZbd2KXKYfg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -855,8 +811,6 @@ github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f h1:cG+ehP 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= github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997/go.mod h1:2CHKs/YGbCcNn/BPaCkEBwKz/FNCELi+MLILjR9RaTA= -github.com/yosuke-furukawa/json5 v0.1.1 h1:0F9mNwTvOuDNH243hoPqvf+dxa5QsKnZzU20uNsh3ZI= -github.com/yosuke-furukawa/json5 v0.1.1/go.mod h1:sw49aWDqNdRJ6DYUtIQiaA3xyj2IL9tjeNYmX2ixwcU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -880,15 +834,10 @@ 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.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= -go.uber.org/multierr v1.10.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= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= 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= @@ -1000,12 +949,10 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 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= @@ -1025,8 +972,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= @@ -1072,7 +1017,6 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1087,8 +1031,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1100,20 +1042,17 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1373,7 +1312,6 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/limiter/limiter.go b/limiter/limiter.go index d9b21fd..ff45148 100644 --- a/limiter/limiter.go +++ b/limiter/limiter.go @@ -60,7 +60,7 @@ func AddLimiter(tag string, l *conf.LimitConfig, users []panel.UserInfo) *Limite SpeedLimit: users[i].SpeedLimit, ExpireTime: 0, } - info.UserLimitInfo.Store(builder.BuildUserTag(tag, &users[i]), userLimit) + info.UserLimitInfo.Store(builder.BuildUserTag(tag, users[i].Uuid), userLimit) } } limitLock.Lock() diff --git a/node/cert.go b/node/cert.go new file mode 100644 index 0000000..d80857c --- /dev/null +++ b/node/cert.go @@ -0,0 +1,31 @@ +package node + +import ( + "fmt" + "github.com/Yuzuki616/V2bX/common/file" + "github.com/Yuzuki616/V2bX/node/lego" +) + +func (c *Controller) requestCert() error { + if c.CertConfig.CertFile == "" || c.CertConfig.KeyFile == "" { + return fmt.Errorf("cert file path or key file path not exist") + } + switch c.CertConfig.CertMode { + case "reality", "none", "": + return nil + case "dns", "http": + if file.IsExist(c.CertConfig.CertFile) && file.IsExist(c.CertConfig.KeyFile) { + return nil + } + l, err := lego.New(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 nil + } + return fmt.Errorf("unsupported certmode: %s", c.CertConfig.CertMode) +} diff --git a/node/controller.go b/node/controller.go index 763eef4..d9c1bb1 100644 --- a/node/controller.go +++ b/node/controller.go @@ -44,15 +44,15 @@ func (c *Controller) Start() error { var err error c.nodeInfo, err = c.apiClient.GetNodeInfo() if err != nil { - return fmt.Errorf("get node info failed: %s", err) + return fmt.Errorf("get node info error: %s", err) } // Update user c.userList, err = c.apiClient.GetUserList() if err != nil { - return fmt.Errorf("get user list failed: %s", err) + return fmt.Errorf("get user list error: %s", err) } if len(c.userList) == 0 { - return errors.New("add users failed: not have any user") + return errors.New("add users error: not have any user") } c.Tag = c.buildNodeTag() @@ -61,13 +61,19 @@ func (c *Controller) Start() error { // add rule limiter if !c.DisableGetRule { if err = l.UpdateRule(c.nodeInfo.Rules); err != nil { - log.Printf("Update rule filed: %s", err) + return fmt.Errorf("update rule error: %s", err) + } + } + if c.nodeInfo.Tls { + err = c.requestCert() + if err != nil { + return fmt.Errorf("request cert error: %s", err) } } // Add new tag err = c.server.AddNode(c.Tag, c.nodeInfo, c.ControllerConfig) if err != nil { - return fmt.Errorf("add new tag failed: %s", err) + return fmt.Errorf("add new node error: %s", err) } added, err := c.server.AddUsers(&vCore.AddUsersParams{ Tag: c.Tag, @@ -75,10 +81,10 @@ func (c *Controller) Start() error { UserInfo: c.userList, NodeInfo: c.nodeInfo, }) - log.Printf("[%s: %d] Added %d new users", c.nodeInfo.NodeType, c.nodeInfo.NodeId, added) if err != nil { - return err + return fmt.Errorf("add users error: %s", err) } + log.Printf("[%s: %d] Added %d new users", c.nodeInfo.Type, c.nodeInfo.Id, added) c.initTask() return nil } @@ -89,36 +95,36 @@ func (c *Controller) Close() error { if c.nodeInfoMonitorPeriodic != nil { err := c.nodeInfoMonitorPeriodic.Close() if err != nil { - log.Panicf("node info periodic close failed: %s", err) + return fmt.Errorf("node info periodic close error: %s", err) } } if c.nodeInfoMonitorPeriodic != nil { err := c.userReportPeriodic.Close() if err != nil { - log.Panicf("user report periodic close failed: %s", err) + return fmt.Errorf("user report periodic close error: %s", err) } } if c.renewCertPeriodic != nil { err := c.renewCertPeriodic.Close() if err != nil { - log.Panicf("renew cert periodic close failed: %s", err) + return fmt.Errorf("renew cert periodic close error: %s", err) } } if c.dynamicSpeedLimitPeriodic != nil { err := c.dynamicSpeedLimitPeriodic.Close() if err != nil { - log.Panicf("dynamic speed limit periodic close failed: %s", err) + return fmt.Errorf("dynamic speed limit periodic close error: %s", err) } } if c.onlineIpReportPeriodic != nil { err := c.onlineIpReportPeriodic.Close() if err != nil { - log.Panicf("online ip report periodic close failed: %s", err) + return fmt.Errorf("online ip report periodic close error: %s", err) } } return nil } func (c *Controller) buildNodeTag() string { - return fmt.Sprintf("%s_%s_%d", c.nodeInfo.NodeType, c.ListenIP, c.nodeInfo.NodeId) + return fmt.Sprintf("%s_%s_%d", c.nodeInfo.Type, c.ListenIP, c.nodeInfo.Id) } diff --git a/node/lego/cert.go b/node/lego/cert.go index fe1b9da..1f5a36e 100644 --- a/node/lego/cert.go +++ b/node/lego/cert.go @@ -78,7 +78,7 @@ func (l *Lego) CheckCert(file []byte) (bool, error) { } return true, nil } -func (l *Lego) parseParmas(path string) string { +func (l *Lego) parseParams(path string) string { r := strings.NewReplacer("{domain}", l.config.CertDomain, "{email}", l.config.Email) return r.Replace(path) @@ -88,7 +88,7 @@ func (l *Lego) writeCert(certificates *certificate.Resource) error { if err != nil { return fmt.Errorf("check path error: %s", err) } - err = os.WriteFile(l.parseParmas(l.config.CertFile), certificates.Certificate, 0644) + err = os.WriteFile(l.parseParams(l.config.CertFile), certificates.Certificate, 0644) if err != nil { return err } @@ -96,7 +96,7 @@ func (l *Lego) writeCert(certificates *certificate.Resource) error { if err != nil { return fmt.Errorf("check path error: %s", err) } - err = os.WriteFile(l.parseParmas(l.config.KeyFile), certificates.PrivateKey, 0644) + err = os.WriteFile(l.parseParams(l.config.KeyFile), certificates.PrivateKey, 0644) if err != nil { return err } diff --git a/node/task.go b/node/task.go index bfe93b1..b029ecc 100644 --- a/node/task.go +++ b/node/task.go @@ -4,13 +4,11 @@ import ( "fmt" "log" "runtime" - "strconv" "time" vCore "github.com/Yuzuki616/V2bX/core" "github.com/Yuzuki616/V2bX/api/panel" - "github.com/Yuzuki616/V2bX/common/builder" "github.com/Yuzuki616/V2bX/limiter" "github.com/Yuzuki616/V2bX/node/lego" "github.com/xtls/xray-core/common/task" @@ -19,33 +17,33 @@ import ( func (c *Controller) initTask() { // fetch node info task c.nodeInfoMonitorPeriodic = &task.Periodic{ - Interval: c.nodeInfo.BaseConfig.PullInterval.(time.Duration), + Interval: c.nodeInfo.PullInterval, Execute: c.nodeInfoMonitor, } // fetch user list task c.userReportPeriodic = &task.Periodic{ - Interval: c.nodeInfo.BaseConfig.PushInterval.(time.Duration), + Interval: c.nodeInfo.PushInterval, Execute: c.reportUserTraffic, } - log.Printf("[%s: %d] Start monitor node status", c.nodeInfo.NodeType, c.nodeInfo.NodeId) + log.Printf("[%s: %d] Start monitor node status", c.nodeInfo.Type, c.nodeInfo.Id) // delay to start nodeInfoMonitor go func() { - time.Sleep(c.nodeInfo.BaseConfig.PullInterval.(time.Duration)) + time.Sleep(c.nodeInfo.PullInterval) _ = c.nodeInfoMonitorPeriodic.Start() }() - log.Printf("[%s: %d] Start report node status", c.nodeInfo.NodeType, c.nodeInfo.NodeId) + log.Printf("[%s: %d] Start report node status", c.nodeInfo.Type, c.nodeInfo.Id) // delay to start userReport go func() { - time.Sleep(c.nodeInfo.BaseConfig.PushInterval.(time.Duration)) + time.Sleep(c.nodeInfo.PullInterval) _ = c.userReportPeriodic.Start() }() - if c.nodeInfo.Tls != 0 && c.CertConfig.CertMode != "none" && + if c.nodeInfo.Tls && c.CertConfig.CertMode != "none" && (c.CertConfig.CertMode == "dns" || c.CertConfig.CertMode == "http") { c.renewCertPeriodic = &task.Periodic{ Interval: time.Hour * 24, Execute: c.reportUserTraffic, } - log.Printf("[%s: %d] Start renew cert", c.nodeInfo.NodeType, c.nodeInfo.NodeId) + log.Printf("[%s: %d] Start renew cert", c.nodeInfo.Type, c.nodeInfo.Id) // delay to start renewCert go func() { _ = c.renewCertPeriodic.Start() @@ -80,6 +78,12 @@ func (c *Controller) nodeInfoMonitor() (err error) { log.Print(err) return nil } + if newNodeInfo.Tls { + err = c.requestCert() + if err != nil { + return fmt.Errorf("request cert error: %s", err) + } + } nodeInfoChanged = true } // Update User @@ -93,8 +97,10 @@ func (c *Controller) nodeInfoMonitor() (err error) { // Add new Limiter l := limiter.AddLimiter(c.Tag, &c.LimitConfig, newUserInfo) _, err = c.server.AddUsers(&vCore.AddUsersParams{ - Tag: c.Tag, - Config: c.ControllerConfig, + Tag: c.Tag, + Config: c.ControllerConfig, + UserInfo: newUserInfo, + NodeInfo: newNodeInfo, }) if err != nil { log.Print(err) @@ -105,18 +111,18 @@ func (c *Controller) nodeInfoMonitor() (err error) { log.Printf("Update Rule error: %s", err) } // Check interval - if c.nodeInfoMonitorPeriodic.Interval != newNodeInfo.BaseConfig.PullInterval.(time.Duration) && - newNodeInfo.BaseConfig.PullInterval.(time.Duration) != 0 { - c.nodeInfoMonitorPeriodic.Interval = newNodeInfo.BaseConfig.PullInterval.(time.Duration) + if c.nodeInfoMonitorPeriodic.Interval != newNodeInfo.PullInterval && + newNodeInfo.PullInterval != 0 { + c.nodeInfoMonitorPeriodic.Interval = newNodeInfo.PullInterval _ = c.nodeInfoMonitorPeriodic.Close() go func() { time.Sleep(c.nodeInfoMonitorPeriodic.Interval) _ = c.nodeInfoMonitorPeriodic.Start() }() } - if c.userReportPeriodic.Interval != newNodeInfo.BaseConfig.PushInterval.(time.Duration) && - newNodeInfo.BaseConfig.PushInterval.(time.Duration) != 0 { - c.userReportPeriodic.Interval = newNodeInfo.BaseConfig.PullInterval.(time.Duration) + if c.userReportPeriodic.Interval != newNodeInfo.PushInterval && + newNodeInfo.PushInterval != 0 { + c.userReportPeriodic.Interval = newNodeInfo.PullInterval _ = c.userReportPeriodic.Close() go func() { time.Sleep(c.userReportPeriodic.Interval) @@ -156,46 +162,18 @@ func (c *Controller) nodeInfoMonitor() (err error) { log.Print("update limiter:", err) } } - log.Printf("[%s: %d] %d user deleted, %d user added", c.nodeInfo.NodeType, c.nodeInfo.NodeId, + log.Printf("[%s: %d] %d user deleted, %d user added", c.nodeInfo.Type, c.nodeInfo.Id, len(deleted), len(added)) c.userList = newUserInfo } return nil } -func compareUserList(old, new []panel.UserInfo) (deleted, added []panel.UserInfo) { - tmp := map[string]struct{}{} - tmp2 := map[string]struct{}{} - for i := range old { - tmp[old[i].Uuid+strconv.Itoa(old[i].SpeedLimit)] = struct{}{} - } - l := len(tmp) - for i := range new { - e := new[i].Uuid + strconv.Itoa(new[i].SpeedLimit) - tmp[e] = struct{}{} - tmp2[e] = struct{}{} - if l != len(tmp) { - added = append(added, new[i]) - l++ - } - } - tmp = nil - l = len(tmp2) - for i := range old { - tmp2[old[i].Uuid+strconv.Itoa(old[i].SpeedLimit)] = struct{}{} - if l != len(tmp2) { - deleted = append(deleted, old[i]) - l++ - } - } - return deleted, added -} - func (c *Controller) reportUserTraffic() (err error) { // Get User traffic userTraffic := make([]panel.UserTraffic, 0) for i := range c.userList { - up, down := c.server.GetUserTraffic(builder.BuildUserTag(c.Tag, &c.userList[i]), true) + up, down := c.server.GetUserTraffic(c.Tag, c.userList[i].Uuid, true) if up > 0 || down > 0 { if c.LimitConfig.EnableDynamicSpeedLimit { c.userList[i].Traffic += up + down @@ -211,7 +189,7 @@ func (c *Controller) reportUserTraffic() (err error) { if err != nil { log.Printf("Report user traffic faild: %s", err) } else { - log.Printf("[%s: %d] Report %d online users", c.nodeInfo.NodeType, c.nodeInfo.NodeId, len(userTraffic)) + log.Printf("[%s: %d] Report %d online users", c.nodeInfo.Type, c.nodeInfo.Id, len(userTraffic)) } } userTraffic = nil @@ -222,12 +200,12 @@ func (c *Controller) reportUserTraffic() (err error) { func (c *Controller) RenewCert() { l, err := lego.New(c.CertConfig) if err != nil { - log.Print(err) + log.Print("new lego error: ", err) return } err = l.RenewCert() if err != nil { - log.Print(err) + log.Print("renew cert error: ", err) return } } diff --git a/node/user.go b/node/user.go new file mode 100644 index 0000000..31857f0 --- /dev/null +++ b/node/user.go @@ -0,0 +1,34 @@ +package node + +import ( + "github.com/Yuzuki616/V2bX/api/panel" + "strconv" +) + +func compareUserList(old, new []panel.UserInfo) (deleted, added []panel.UserInfo) { + tmp := map[string]struct{}{} + tmp2 := map[string]struct{}{} + for i := range old { + tmp[old[i].Uuid+strconv.Itoa(old[i].SpeedLimit)] = struct{}{} + } + l := len(tmp) + for i := range new { + e := new[i].Uuid + strconv.Itoa(new[i].SpeedLimit) + tmp[e] = struct{}{} + tmp2[e] = struct{}{} + if l != len(tmp) { + added = append(added, new[i]) + l++ + } + } + tmp = nil + l = len(tmp2) + for i := range old { + tmp2[old[i].Uuid+strconv.Itoa(old[i].SpeedLimit)] = struct{}{} + if l != len(tmp2) { + deleted = append(deleted, old[i]) + l++ + } + } + return deleted, added +} diff --git a/test_data/1.key b/test_data/1.key new file mode 100644 index 0000000..f424250 --- /dev/null +++ b/test_data/1.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAyryUpSI01T4jgPywpt4CIaf+MNgPn9DxHtJmuo1VB7Ysk13Z +uOBVfS9HJoikbrcVeqENkR8Bq1vdgMLbHmlxrSTwe/pynmRvWx+L1hKscxEmR6uV +jgqWsPkoUAKVJlHBfjw6oFEQzmgwDOfyS90TVr4gwDo/GCLX1iX5jC+KrteuAMOp +V6Yiu1FAhd0TeUDPMKs4wbyE8qx3+Mn6FqGorIwyefCX9m9QCz1N/5Ut6I5uT5Vr +28Ox1Q++mZ0s5ZuFpMlzKvrfav7fxt31rgSUro7/NTNuIydHvwMcZYeVm+DT+Vfp +wRZW9uoB4jiwLDxnfMOMLd72yGId+9EJ6HpOIQIDAQABAoIBAHhV/xUVfK6mN4S0 +eFZTqIg5otNzK7L83mIhGQDaKwJsy4CdUEJARf4MNftVV+Svn3wuZFMjSGZiHNP0 +1QL0K5lON8AfJDGIA+DelK34X4vdPg+EdTzeZBufiKIVJlqcZHF9Zn8KHyOlDABd +HKCTFIuERwRSjmjRJbPizoC7J2Ina15pi+35T3x3oye4V5kQlJH3WxlMOhp0Z+iO +qGlqJITWeOqxXaLfPIoOYcJ2LBPzvgv4IRVbmhi4mxphfPTEAlGnvITauDa9fx7S +REBAFyt5NyU9M7dusmlLiTIHryOensBzCQOwbMseeUS0Z1rIfbusqwBM3X5oPcx8 +jOP1QxECgYEA+qCU4Q84hDBhC2SLfH4D1QyOixeho5re6E0NchSposIhrxLdRDDk +04GGNTKUflgfoskaI9loe84MkTqqrjxguRWVXf5qPMAtfpXr2GYiPq+VhiEeo7ZG +f1rHYqK7Ity9jzy7z/CpTLekveUT93I7/yF5iEOUYQgnIZhDg+Hr0ysCgYEAzxUu +DmL7GceRauoD9w3tT2nsa23hXc+jo1QWV5I7veZyosXnz8gxpax4SgwZ/iCH8pDJ +RagWTHQHO3X6DdkovzPEWYiLtLCE2APlfClzkZif5tv7kO4B3BuyuDlNleuCH894 +5WlieyCHcPtXqG/60tXxVrlNrevI+ccsYRb+reMCgYBgu8AaybQnmUCrlAgeacjy +3yDZYKqbqfflM3BAGueKkWFM4HwUiMaZOAHj4Hzd8wdq3jG/qncgadwB5eHg1B8E +8Oaw27SHdClbFWRtJqaLCVwt4/SefYjiONiCIosWHprvgSKAVMQTf0IPpS46sJWl +mHb++A56ERqBZfKRIY7S9wKBgCKf+flx12ZyFgB4bH1MmNdkcKFt1/bllwjiMHIo +A1E3TQema6I0aQi4k8xdxaLWMaT/TIgXGNNjuynYCh1yp/uAXl5SFHn74dp0nFRs +YeSATow9UAzlnu38u59OBYkBvdovyJkjS9ImmD7t57RENP43w4iqpzBjclFBWkxJ +mf/dAoGBAOZa8+FmFyx2VmgwR4qPrNKg6EuhO6OgDJ8NvRnx4Mu5/0L1JoYoM0Yc +2NMKh14fqmDB/CvCbMGxCj86WF8534t+eBqhY6/AUkSolh8139KNmYHNB0ynqDYn +QDm/HJ4cux2rkLUCKlbGBnS9M+PSJA/MJeh0JTIrSOu4bH7aanVl +-----END RSA PRIVATE KEY----- diff --git a/test_data/1.pem b/test_data/1.pem new file mode 100644 index 0000000..48d508d --- /dev/null +++ b/test_data/1.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID2zCCAsOgAwIBAgIRAJP0pRlp9k2eiBLK2a2B7LYwDQYJKoZIhvcNAQELBQAw +XjELMAkGA1UEBhMCQ04xDjAMBgNVBAoTBU15U1NMMSswKQYDVQQLEyJNeVNTTCBU +ZXN0IFJTQSAtIEZvciB0ZXN0IHVzZSBvbmx5MRIwEAYDVQQDEwlNeVNTTC5jb20w +HhcNMjMwNjA4MTQxOTQzWhcNMjgwNjA2MTQxOTQzWjAiMQswCQYDVQQGEwJDTjET +MBEGA1UEAxMKMTE0NTE0LmdheTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMq8lKUiNNU+I4D8sKbeAiGn/jDYD5/Q8R7SZrqNVQe2LJNd2bjgVX0vRyaI +pG63FXqhDZEfAatb3YDC2x5pca0k8Hv6cp5kb1sfi9YSrHMRJkerlY4KlrD5KFAC +lSZRwX48OqBREM5oMAzn8kvdE1a+IMA6Pxgi19Yl+Ywviq7XrgDDqVemIrtRQIXd +E3lAzzCrOMG8hPKsd/jJ+hahqKyMMnnwl/ZvUAs9Tf+VLeiObk+Va9vDsdUPvpmd +LOWbhaTJcyr632r+38bd9a4ElK6O/zUzbiMnR78DHGWHlZvg0/lX6cEWVvbqAeI4 +sCw8Z3zDjC3e9shiHfvRCeh6TiECAwEAAaOBzzCBzDAOBgNVHQ8BAf8EBAMCBaAw +HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFCiBJgXR +NBo/wXMPu5PPFRw/A79/MGMGCCsGAQUFBwEBBFcwVTAhBggrBgEFBQcwAYYVaHR0 +cDovL29jc3AubXlzc2wuY29tMDAGCCsGAQUFBzAChiRodHRwOi8vY2EubXlzc2wu +Y29tL215c3NsdGVzdHJzYS5jcnQwFQYDVR0RBA4wDIIKMTE0NTE0LmdheTANBgkq +hkiG9w0BAQsFAAOCAQEAdlvVKnB1OHojoHfgPKUVTk5+OXk9X/q++wkkrGa1rQs0 +bPikKdc1TQoW/ylpX9wN3rwLLYGf/Hs9SqHr4RkAhAb6v+K1O5HUMqJARONdB7j0 +/1BuKd0wx5pIqJhs6qRf+grsOGj9EdTfKXqElCljAES0t+2ZbZ2666XftwSjybtF +yKg+9iS9PX5VA1SIsa7XSVTlJ8oXy91KuCm07UxnSEKovpzV4TIlxPgKOfWBUYh9 +JfOhwh1rpUy6tqNjFyJdGHxBJsf7HLcO9VJe/RD55c54ovZaTT24Cy/II5DKiQ26 +TUeMj1BMedu5Ou0YCH7W9QhH40fvwi/hSQrjysQAoA== +-----END CERTIFICATE----- From 9827d442d57799b802059a8f51fb20d23e6c8fd2 Mon Sep 17 00:00:00 2001 From: yuzuki999 Date: Fri, 9 Jun 2023 12:36:49 +0800 Subject: [PATCH 2/3] fix some bugs --- README.md | 24 ++++++++++++------------ api/panel/node.go | 17 ++++++++++------- api/panel/panel.go | 6 +++--- api/panel/utils.go | 2 +- common/builder/inbound.go | 10 +++------- conf/node.go | 18 +++++++++--------- core/hy/counter.go | 7 ++++--- core/hy/hy.go | 7 ++++++- core/hy/node.go | 4 ++++ core/hy/server.go | 32 ++++++++++++++++---------------- core/hy/server_test.go | 5 ++++- core/hy/user.go | 12 +++++++----- example/config.yml.example | 32 ++++++++++++++++++-------------- node/node.go | 7 ++++++- 14 files changed, 103 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 7325897..eca3c32 100644 --- a/README.md +++ b/README.md @@ -23,18 +23,18 @@ A V2board node server based on multi core, modified from XrayR. ## 功能介绍 -| 功能 | v2ray | trojan | shadowsocks | -|-----------|-------|--------|-------------| -| 自动申请tls证书 | √ | √ | √ | -| 自动续签tls证书 | √ | √ | √ | -| 在线人数统计 | √ | √ | √ | -| 审计规则 | √ | √ | √ | -| 自定义DNS | √ | √ | √ | -| 在线IP数限制 | √ | √ | √ | -| 连接数限制 | √ | √ | √ | -| 跨节点IP数限制 | √ | √ | √ | -| 按照用户限速 | √ | √ | √ | -| 动态限速(未测试) | √ | √ | √ | +| 功能 | v2ray | trojan | shadowsocks | hysteria | +|-----------|-------|--------|-------------|----------| +| 自动申请tls证书 | √ | √ | √ | √ | +| 自动续签tls证书 | √ | √ | √ | √ | +| 在线人数统计 | √ | √ | √ | √ | +| 审计规则 | √ | √ | √ | | +| 自定义DNS | √ | √ | √ | √ | +| 在线IP数限制 | √ | √ | √ | | +| 连接数限制 | √ | √ | √ | | +| 跨节点IP数限制 | √ | √ | √ | | +| 按照用户限速 | √ | √ | √ | | +| 动态限速(未测试) | √ | √ | √ | | ## TODO diff --git a/api/panel/node.go b/api/panel/node.go index 82cb4a8..e731d42 100644 --- a/api/panel/node.go +++ b/api/panel/node.go @@ -11,7 +11,9 @@ import ( ) 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"` } @@ -54,11 +56,11 @@ type NodeInfo struct { Id int Type string Rules []*regexp.Regexp + Host string Port int Network string NetworkSettings json.RawMessage Tls bool - Host string ServerName string UpMbps int DownMbps int @@ -75,16 +77,14 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { if err = c.checkResponse(r, path, err); err != nil { return } - err = json.Unmarshal(r.Body(), &node) - if err != nil { - return - } if c.etag == r.Header().Get("ETag") { // node info not changed return nil, nil } // parse common params - node.Id = c.NodeId - node.Type = c.NodeType + node = &NodeInfo{ + Id: c.NodeId, + Type: c.NodeType, + } common := CommonNodeRsp{} err = json.Unmarshal(r.Body(), &common) if err != nil { @@ -103,6 +103,9 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) { } } } + 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 diff --git a/api/panel/panel.go b/api/panel/panel.go index 1659ad7..f6e90dd 100644 --- a/api/panel/panel.go +++ b/api/panel/panel.go @@ -43,9 +43,9 @@ func New(c *conf.ApiConfig) (*Client, error) { client.SetBaseURL(c.APIHost) // Check node type c.NodeType = strings.ToLower(c.NodeType) - if c.NodeType != "v2ray" && - c.NodeType != "trojan" && - c.NodeType != "shadowsocks" { + switch c.NodeType { + case "v2ray", "trojan", "shadowsocks", "hysteria": + default: return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType) } // Create Key for each requests diff --git a/api/panel/utils.go b/api/panel/utils.go index 56aeb0f..938bec9 100644 --- a/api/panel/utils.go +++ b/api/panel/utils.go @@ -20,7 +20,7 @@ func (c *Client) checkResponse(res *resty.Response, path string, err error) erro } if res.StatusCode() != 200 { body := res.Body() - return fmt.Errorf("request %s failed: %s, %s", c.assembleURL(path), string(body), err) + return fmt.Errorf("request %s failed: %s", c.assembleURL(path), string(body)) } return nil } diff --git a/common/builder/inbound.go b/common/builder/inbound.go index ae9f5bb..dc576f9 100644 --- a/common/builder/inbound.go +++ b/common/builder/inbound.go @@ -25,7 +25,7 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s case "v2ray": err = buildV2ray(config, nodeInfo, in) case "trojan": - err = buildTrojan(config, nodeInfo, in) + err = buildTrojan(config, in) case "shadowsocks": err = buildShadowsocks(config, nodeInfo, in) default: @@ -104,7 +104,6 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s // Support ProxyProtocol for any transport protocol if *in.StreamSetting.Network != "tcp" && *in.StreamSetting.Network != "ws" && - *in.StreamSetting.Network != "" && config.EnableProxyProtocol { socketConfig := &coreConf.SocketConfig{ AcceptProxyProtocol: config.EnableProxyProtocol, @@ -177,7 +176,7 @@ func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound return nil } -func buildTrojan(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error { +func buildTrojan(config *conf.ControllerConfig, inbound *coreConf.InboundDetourConfig) error { inbound.Protocol = "trojan" if config.XrayOptions.EnableFallback { // Set fallback @@ -196,10 +195,7 @@ func buildTrojan(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inboun s := []byte("{}") inbound.Settings = (*json.RawMessage)(&s) } - if nodeInfo.Network == "" { - nodeInfo.Network = "tcp" - } - t := coreConf.TransportProtocol(nodeInfo.Network) + t := coreConf.TransportProtocol("tcp") inbound.StreamSetting = &coreConf.StreamConfig{Network: &t} return nil } diff --git a/conf/node.go b/conf/node.go index db0cfda..ac1b134 100644 --- a/conf/node.go +++ b/conf/node.go @@ -15,15 +15,15 @@ type ApiConfig struct { } type ControllerConfig struct { - DisableUploadTraffic bool `yaml:"DisableUploadTraffic"` - DisableGetRule bool `yaml:"DisableGetRule"` - ListenIP string `yaml:"ListenIP"` - SendIP string `yaml:"SendIP"` - EnableProxyProtocol bool `yaml:"EnableProxyProtocol"` - XrayOptions *XrayOptions `yaml:"XrayOptions"` - HyOptions *HyOptions `yaml:"HyOptions"` - LimitConfig LimitConfig `yaml:"LimitConfig"` - CertConfig *CertConfig `yaml:"CertConfig"` + DisableUploadTraffic bool `yaml:"DisableUploadTraffic"` + DisableGetRule bool `yaml:"DisableGetRule"` + ListenIP string `yaml:"ListenIP"` + SendIP string `yaml:"SendIP"` + EnableProxyProtocol bool `yaml:"EnableProxyProtocol"` + XrayOptions XrayOptions `yaml:"XrayOptions"` + HyOptions HyOptions `yaml:"HyOptions"` + LimitConfig LimitConfig `yaml:"LimitConfig"` + CertConfig *CertConfig `yaml:"CertConfig"` } type XrayOptions struct { diff --git a/core/hy/counter.go b/core/hy/counter.go index 5d62a74..6228bfa 100644 --- a/core/hy/counter.go +++ b/core/hy/counter.go @@ -1,7 +1,6 @@ package hy import ( - "github.com/apernet/hysteria/core/cs" "sync" "sync/atomic" ) @@ -17,8 +16,10 @@ type counters struct { //ConnGauge atomic.Int64 } -func NewUserTrafficCounter() cs.TrafficCounter { - return new(UserTrafficCounter) +func NewUserTrafficCounter() *UserTrafficCounter { + return &UserTrafficCounter{ + counters: map[string]*counters{}, + } } func (c *UserTrafficCounter) getCounters(auth string) *counters { diff --git a/core/hy/hy.go b/core/hy/hy.go index 88ced0c..a5eca71 100644 --- a/core/hy/hy.go +++ b/core/hy/hy.go @@ -3,15 +3,20 @@ package hy import ( "fmt" "github.com/Yuzuki616/V2bX/conf" + vCore "github.com/Yuzuki616/V2bX/core" "github.com/hashicorp/go-multierror" "sync" ) +func init() { + vCore.RegisterCore("hy", NewHy) +} + type Hy struct { servers sync.Map } -func New(_ *conf.CoreConfig) (*Hy, error) { +func NewHy(_ *conf.CoreConfig) (vCore.Core, error) { return &Hy{ servers: sync.Map{}, }, nil diff --git a/core/hy/node.go b/core/hy/node.go index 0000c30..a39908b 100644 --- a/core/hy/node.go +++ b/core/hy/node.go @@ -12,6 +12,10 @@ func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.ControllerConfig) 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") + } s := NewServer(tag) err := s.runServer(info, c) if err != nil { diff --git a/core/hy/server.go b/core/hy/server.go index 8fe4de0..fda7f6c 100644 --- a/core/hy/server.go +++ b/core/hy/server.go @@ -2,7 +2,6 @@ package hy import ( "crypto/tls" - "errors" "fmt" "github.com/Yuzuki616/V2bX/api/panel" "github.com/Yuzuki616/V2bX/conf" @@ -33,7 +32,7 @@ var serverPacketConnFuncFactoryMap = map[string]pktconns.ServerPacketConnFuncFac type Server struct { tag string - counter UserTrafficCounter + counter *UserTrafficCounter users sync.Map running atomic.Bool *cs.Server @@ -46,9 +45,9 @@ func NewServer(tag string) *Server { } func (s *Server) runServer(node *panel.NodeInfo, c *conf.ControllerConfig) error { - if c.HyOptions == nil { + /*if c.HyOptions == nil { return errors.New("hy options is not vail") - } + }*/ // Resolver if len(c.HyOptions.Resolver) > 0 { err := setResolver(c.HyOptions.Resolver) @@ -136,7 +135,7 @@ func (s *Server) runServer(node *panel.NodeInfo, c *conf.ControllerConfig) error aclEngine.DefaultAction = acl.ActionDirect }*/ // Prometheus - trafficCounter := NewUserTrafficCounter() + s.counter = NewUserTrafficCounter() // Packet conn pktConnFuncFactory := serverPacketConnFuncFactoryMap[""] if pktConnFuncFactory == nil { @@ -155,7 +154,7 @@ func (s *Server) runServer(node *panel.NodeInfo, c *conf.ControllerConfig) error 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, trafficCounter) + s.connectFunc, s.disconnectFunc, tcpRequestFunc, tcpErrorFunc, udpRequestFunc, udpErrorFunc, s.counter) if err != nil { return fmt.Errorf("new server error: %s", err) } @@ -173,25 +172,26 @@ func (s *Server) runServer(node *panel.NodeInfo, c *conf.ControllerConfig) error return nil } -func (s *Server) authByUser(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string, string) { - if email, ok := s.users.Load(string(auth)); ok { - return true, email.(string), "Done" +func (s *Server) authByUser(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) { + if _, ok := s.users.Load(string(auth)); ok { + return true, "Done" } - return false, "", "Failed" + return false, "Failed" } func (s *Server) connectFunc(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) { - ok, email, msg := s.authByUser(addr, auth, sSend, sRecv) + ok, msg := s.authByUser(addr, auth, sSend, sRecv) if !ok { logrus.WithFields(logrus.Fields{ "src": defaultIPMasker.Mask(addr.String()), }).Info("Authentication failed, client rejected") - } else { - logrus.WithFields(logrus.Fields{ - "src": defaultIPMasker.Mask(addr.String()), - "email": email, - }).Info("Client connected") + return false, msg } + logrus.WithFields(logrus.Fields{ + "src": defaultIPMasker.Mask(addr.String()), + "Uuid": string(auth), + "Tag": s.tag, + }).Info("Client connected") return ok, msg } diff --git a/core/hy/server_test.go b/core/hy/server_test.go index 5d5f5ce..95c8f9a 100644 --- a/core/hy/server_test.go +++ b/core/hy/server_test.go @@ -3,10 +3,12 @@ package hy import ( "github.com/Yuzuki616/V2bX/api/panel" "github.com/Yuzuki616/V2bX/conf" + "github.com/sirupsen/logrus" "testing" ) func TestServer(t *testing.T) { + logrus.SetLevel(logrus.DebugLevel) s := NewServer("test") t.Log(s.runServer(&panel.NodeInfo{ Port: 11415, @@ -15,11 +17,12 @@ func TestServer(t *testing.T) { HyObfs: "atresssdaaaadd", }, &conf.ControllerConfig{ ListenIP: "127.0.0.1", - HyOptions: &conf.HyOptions{}, + HyOptions: conf.HyOptions{}, CertConfig: &conf.CertConfig{ CertFile: "../../test_data/1.pem", KeyFile: "../../test_data/1.key", }, })) + s.users.Store("test1111", struct{}{}) select {} } diff --git a/core/hy/user.go b/core/hy/user.go index f069b3d..30cb651 100644 --- a/core/hy/user.go +++ b/core/hy/user.go @@ -1,6 +1,7 @@ package hy import ( + "encoding/base64" "errors" "github.com/Yuzuki616/V2bX/core" ) @@ -18,12 +19,13 @@ func (h *Hy) AddUsers(p *core.AddUsersParams) (int, error) { } func (h *Hy) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) { - s, _ := h.servers.Load(tag) - c := &s.(*Server).counter - up = c.getCounters(uuid).UpCounter.Load() - down = c.getCounters(uuid).DownCounter.Load() + v, _ := h.servers.Load(tag) + s := v.(*Server) + auth := base64.StdEncoding.EncodeToString([]byte(uuid)) + up = s.counter.getCounters(auth).UpCounter.Load() + down = s.counter.getCounters(uuid).DownCounter.Load() if reset { - c.Reset(uuid) + s.counter.Reset(uuid) } return } diff --git a/example/config.yml.example b/example/config.yml.example index 4588845..49f3c37 100644 --- a/example/config.yml.example +++ b/example/config.yml.example @@ -26,20 +26,24 @@ Nodes: ControllerConfig: ListenIP: 0.0.0.0 # IP address you want to listen SendIP: 0.0.0.0 # IP address you want to send pacakage - 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 - EnableVless: false # Enable Vless for V2ray Type - EnableXtls: false # Enable xtls-rprx-vision, only vless - 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 dsable - + 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 + EnableVless: false # Enable Vless for V2ray Type + EnableXtls: false # Enable xtls-rprx-vision, only vless + 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 dsable + 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 diff --git a/node/node.go b/node/node.go index 4cb414b..ae56252 100644 --- a/node/node.go +++ b/node/node.go @@ -1,6 +1,7 @@ package node import ( + "fmt" "github.com/Yuzuki616/V2bX/api/panel" "github.com/Yuzuki616/V2bX/conf" vCore "github.com/Yuzuki616/V2bX/core" @@ -25,7 +26,11 @@ func (n *Node) Start(nodes []*conf.NodeConfig, core vCore.Core) error { n.controllers[i] = NewController(core, p, c.ControllerConfig) err = n.controllers[i].Start() if err != nil { - return err + return fmt.Errorf("start node controller [%s-%s-%d] error: %s", + c.ApiConfig.NodeType, + c.ApiConfig.APIHost, + c.ApiConfig.NodeID, + err) } } return nil From f07629d438974893cbb5671f4912cd2350dd9bfc Mon Sep 17 00:00:00 2001 From: Yuzuki616 Date: Fri, 9 Jun 2023 21:20:41 +0800 Subject: [PATCH 3/3] add run many core at the same time --- conf/conf.go | 4 +- conf/conf_test.go | 6 +-- conf/core.go | 1 + core/core.go | 19 +++++++ core/hy/hy.go | 9 +++- core/interface.go | 1 + core/selecter.go | 98 ++++++++++++++++++++++++++++++++++ core/xray/{core.go => xray.go} | 9 ++++ example/config.yml.example | 4 +- 9 files changed, 142 insertions(+), 9 deletions(-) create mode 100644 core/selecter.go rename core/xray/{core.go => xray.go} (97%) diff --git a/conf/conf.go b/conf/conf.go index 0b46104..e54997c 100644 --- a/conf/conf.go +++ b/conf/conf.go @@ -23,6 +23,7 @@ func New() *Conf { Type: "xray", XrayConfig: &XrayConfig{ LogConfig: NewLogConfig(), + AssetPath: "/etc/V2bX/", DnsConfigPath: "", InboundConfigPath: "", OutboundConfigPath: "", @@ -35,9 +36,6 @@ func New() *Conf { } func (p *Conf) LoadFromPath(filePath string) error { - confPath := path.Dir(filePath) - os.Setenv("XRAY_LOCATION_ASSET", confPath) - os.Setenv("XRAY_LOCATION_CONFIG", confPath) f, err := os.Open(filePath) if err != nil { return fmt.Errorf("open config file error: %s", err) diff --git a/conf/conf_test.go b/conf/conf_test.go index 1c4f917..44bc756 100644 --- a/conf/conf_test.go +++ b/conf/conf_test.go @@ -7,13 +7,13 @@ import ( func TestConf_LoadFromPath(t *testing.T) { c := New() - t.Log(c.LoadFromPath("../example/config.yml.example"), c.NodesConfig[0].ControllerConfig.EnableXtls) + t.Log(c.LoadFromPath("../example/config.yml.example")) } func TestConf_Watch(t *testing.T) { c := New() - c.Watch("../example/config.yml.example", func() { + log.Println(c.Watch("../example/config.yml.example", func() { log.Println(1) - }) + })) select {} } diff --git a/conf/core.go b/conf/core.go index 99eb4a0..ce4fc08 100644 --- a/conf/core.go +++ b/conf/core.go @@ -7,6 +7,7 @@ type CoreConfig struct { type XrayConfig struct { LogConfig *LogConfig `yaml:"Log"` + AssetPath string `yaml:"AssetPath"` DnsConfigPath string `yaml:"DnsConfigPath"` RouteConfigPath string `yaml:"RouteConfigPath"` ConnectionConfig *ConnectionConfig `yaml:"ConnectionConfig"` diff --git a/core/core.go b/core/core.go index 6f02499..ad00877 100644 --- a/core/core.go +++ b/core/core.go @@ -12,6 +12,25 @@ var ( ) func NewCore(c *conf.CoreConfig) (Core, error) { + // multi core + if types := strings.Split(c.Type, " "); len(types) > 1 { + var cs []Core + for _, t := range types { + f, ok := cores[strings.ToLower(c.Type)] + 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 &Selecter{ + cores: cs, + }, nil + } + // one core if f, ok := cores[strings.ToLower(c.Type)]; ok { return f(c) } else { diff --git a/core/hy/hy.go b/core/hy/hy.go index a5eca71..e261e10 100644 --- a/core/hy/hy.go +++ b/core/hy/hy.go @@ -2,10 +2,11 @@ package hy import ( "fmt" + "sync" + "github.com/Yuzuki616/V2bX/conf" vCore "github.com/Yuzuki616/V2bX/core" "github.com/hashicorp/go-multierror" - "sync" ) func init() { @@ -40,3 +41,9 @@ func (h *Hy) Close() error { } return nil } + +func (h *Hy) Protocols() []string { + return []string{ + "hysteria", + } +} diff --git a/core/interface.go b/core/interface.go index 56513e0..0af41fa 100644 --- a/core/interface.go +++ b/core/interface.go @@ -19,4 +19,5 @@ type Core interface { AddUsers(p *AddUsersParams) (added int, err error) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) DelUsers(users []string, tag string) error + Protocols() []string } diff --git a/core/selecter.go b/core/selecter.go new file mode 100644 index 0000000..38127a9 --- /dev/null +++ b/core/selecter.go @@ -0,0 +1,98 @@ +package core + +import ( + "errors" + "sync" + + "github.com/Yuzuki616/V2bX/api/panel" + "github.com/Yuzuki616/V2bX/conf" + "github.com/hashicorp/go-multierror" +) + +type Selecter struct { + cores []Core + nodes sync.Map +} + +func (s *Selecter) Start() error { + for i := range s.cores { + err := s.cores[i].Start() + return err + } + return nil +} + +func (s *Selecter) Close() error { + var errs error + for i := range s.cores { + errs = multierror.Append(errs, s.cores[i].Close()) + } + return errs +} + +func isSupported(protocol string, protocols []string) bool { + for i := range protocols { + if protocol == protocols[i] { + return true + } + } + return false +} + +func (s *Selecter) AddNode(tag string, info *panel.NodeInfo, config *conf.ControllerConfig) error { + for i := range s.cores { + if !isSupported(info.Type, s.cores[i].Protocols()) { + continue + } + err := s.cores[i].AddNode(tag, info, config) + if err != nil { + return err + } + s.nodes.Store(tag, i) + } + return errors.New("the node type is not support") +} + +func (s *Selecter) DelNode(tag string) error { + if t, e := s.nodes.Load(tag); e { + err := s.cores[t.(int)].DelNode(tag) + if err != nil { + return err + } + s.nodes.Delete(tag) + return nil + } + return errors.New("the node is not have") +} + +func (s *Selecter) AddUsers(p *AddUsersParams) (added int, err error) { + t, e := s.nodes.Load(p.Tag) + if !e { + return 0, errors.New("the node is not have") + } + return s.cores[t.(int)].AddUsers(p) +} + +func (s *Selecter) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) { + t, e := s.nodes.Load(tag) + if !e { + return 0, 0 + } + return s.cores[t.(int)].GetUserTraffic(tag, uuid, reset) +} + +func (s *Selecter) DelUsers(users []string, tag string) error { + t, e := s.nodes.Load(tag) + if !e { + return errors.New("the node is not have") + } + return s.cores[t.(int)].DelUsers(users, tag) +} + +func (s *Selecter) Protocols() []string { + protocols := make([]string, 0) + for i := range s.cores { + protocols = append(protocols, s.cores[i].Protocols()...) + } + return protocols +} diff --git a/core/xray/core.go b/core/xray/xray.go similarity index 97% rename from core/xray/core.go rename to core/xray/xray.go index 55fa3fa..280eb10 100644 --- a/core/xray/core.go +++ b/core/xray/xray.go @@ -53,6 +53,7 @@ func parseConnectionConfig(c *conf.ConnectionConfig) (policy *coreConf.Policy) { } func getCore(c *conf.XrayConfig) *core.Instance { + os.Setenv("XRAY_LOCATION_ASSET", c.AssetPath) // Log Config coreLogConfig := &coreConf.LogConfig{} coreLogConfig.LogLevel = c.LogConfig.Level @@ -183,3 +184,11 @@ func (c *Core) Close() error { } return nil } + +func (c *Core) Protocols() []string { + return []string{ + "v2ray", + "shadowsocks", + "trojan", + } +} diff --git a/example/config.yml.example b/example/config.yml.example index 49f3c37..b27f79e 100644 --- a/example/config.yml.example +++ b/example/config.yml.example @@ -1,5 +1,5 @@ CoreConfig: - Type: "xray" # Core type + Type: "xray" # Core type. if you need many cores, use " " to split XrayConfig: Log: Level: warning # Log level: none, error, warning, info, debug @@ -41,7 +41,7 @@ Nodes: 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 dsable HyOptions: - Resolver: "udp://1.1.1.1:53", // DNS resolver address + 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: