mirror of
https://github.com/wyx2685/V2bX.git
synced 2026-02-04 20:50:09 +00:00
Compare commits
10 Commits
v0.0.0-202
...
v0.0.4-202
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96b457d679 | ||
|
|
55b20f5550 | ||
|
|
c0b31837e4 | ||
|
|
bf4a52df4d | ||
|
|
423ac622b5 | ||
|
|
625265148f | ||
|
|
73f9b19222 | ||
|
|
0d274bcf61 | ||
|
|
77ec03016c | ||
|
|
1d4945af8d |
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -109,7 +109,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21.4'
|
||||
go-version: '1.22.0'
|
||||
|
||||
- name: Get project dependencies
|
||||
run: go mod download
|
||||
@@ -125,13 +125,13 @@ jobs:
|
||||
run: |
|
||||
echo "version: $version"
|
||||
mkdir -p build_assets
|
||||
go build -v -o build_assets/V2bX -tags "sing xray with_reality_server with_quic with_grpc with_utls with_wireguard with_acme" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid="
|
||||
go build -v -o build_assets/V2bX -tags "sing xray hysteria2 with_reality_server with_quic with_grpc with_utls with_wireguard with_acme" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid="
|
||||
|
||||
- name: Build Mips softfloat V2bX
|
||||
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
|
||||
run: |
|
||||
echo "version: $version"
|
||||
GOMIPS=softfloat go build -v -o build_assets/V2bX_softfloat -tags "sing xray with_reality_server with_quic with_grpc with_utls with_wireguard with_acme" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid="
|
||||
GOMIPS=softfloat go build -v -o build_assets/V2bX_softfloat -tags "sing xray hysteria2 with_reality_server with_quic with_grpc with_utls with_wireguard with_acme" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid="
|
||||
- name: Rename Windows V2bX
|
||||
if: matrix.goos == 'windows'
|
||||
run: |
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -12,4 +12,6 @@ app/legocmd/.lego/
|
||||
example/.lego
|
||||
example/cert
|
||||
./vscode
|
||||
.idea/*
|
||||
output/*
|
||||
.idea/*
|
||||
newV2bX.sh
|
||||
@@ -1,10 +1,10 @@
|
||||
# Build go
|
||||
FROM golang:1.21.4-alpine AS builder
|
||||
FROM golang:1.22.0-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
ENV CGO_ENABLED=0
|
||||
RUN go mod download
|
||||
RUN go build -v -o V2bX -tags "sing xray with_reality_server with_quic with_grpc with_utls with_wireguard with_acme"
|
||||
RUN go build -v -o V2bX -tags "sing xray hysteria2 with_reality_server with_quic with_grpc with_utls with_wireguard with_acme"
|
||||
|
||||
# Release
|
||||
FROM alpine
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package panel
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
@@ -130,7 +132,19 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
||||
r, err := c.client.
|
||||
R().
|
||||
SetHeader("If-None-Match", c.nodeEtag).
|
||||
ForceContentType("application/json").
|
||||
Get(path)
|
||||
|
||||
if r.StatusCode() == 304 {
|
||||
return nil, nil
|
||||
}
|
||||
hash := sha256.Sum256(r.Body())
|
||||
newBodyHash := hex.EncodeToString(hash[:])
|
||||
if c.responseBodyHash == newBodyHash {
|
||||
return nil, nil
|
||||
}
|
||||
c.responseBodyHash = newBodyHash
|
||||
c.nodeEtag = r.Header().Get("ETag")
|
||||
if err = c.checkResponse(r, path, err); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -141,9 +155,6 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
||||
r.RawBody().Close()
|
||||
}
|
||||
}()
|
||||
if r.StatusCode() == 304 {
|
||||
return nil, nil
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("received nil response")
|
||||
}
|
||||
@@ -274,8 +285,7 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
||||
cm.Routes = nil
|
||||
cm.BaseConfig = nil
|
||||
|
||||
c.nodeEtag = r.Header().Get("ETag")
|
||||
return
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func intervalToTime(i interface{}) time.Duration {
|
||||
|
||||
@@ -23,6 +23,7 @@ type Client struct {
|
||||
NodeId int
|
||||
nodeEtag string
|
||||
userEtag string
|
||||
responseBodyHash string
|
||||
LastReportOnline map[int]int
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ func (c *Client) GetUserList() (UserList []UserInfo, err error) {
|
||||
const path = "/api/v1/server/UniProxy/user"
|
||||
r, err := c.client.R().
|
||||
SetHeader("If-None-Match", c.userEtag).
|
||||
ForceContentType("application/json").
|
||||
Get(path)
|
||||
if err = c.checkResponse(r, path, err); err != nil {
|
||||
return nil, err
|
||||
@@ -47,8 +48,10 @@ func (c *Client) GetUserList() (UserList []UserInfo, err error) {
|
||||
return nil, fmt.Errorf("received nil response")
|
||||
}
|
||||
var userList *UserListBody
|
||||
err = json.Unmarshal(r.Body(), &userList)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read body error: %s", err)
|
||||
}
|
||||
if err := json.Unmarshal(r.Body(), &userList); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal userlist error: %s", err)
|
||||
}
|
||||
c.userEtag = r.Header().Get("ETag")
|
||||
|
||||
12
conf/core.go
12
conf/core.go
@@ -5,10 +5,11 @@ import (
|
||||
)
|
||||
|
||||
type CoreConfig struct {
|
||||
Type string `json:"Type"`
|
||||
Name string `json:"Name"`
|
||||
XrayConfig *XrayConfig `json:"-"`
|
||||
SingConfig *SingConfig `json:"-"`
|
||||
Type string `json:"Type"`
|
||||
Name string `json:"Name"`
|
||||
XrayConfig *XrayConfig `json:"-"`
|
||||
SingConfig *SingConfig `json:"-"`
|
||||
Hysteria2Config *Hysteria2Config `json:"-"`
|
||||
}
|
||||
|
||||
type _CoreConfig CoreConfig
|
||||
@@ -25,6 +26,9 @@ func (c *CoreConfig) UnmarshalJSON(b []byte) error {
|
||||
case "sing":
|
||||
c.SingConfig = NewSingConfig()
|
||||
return json.Unmarshal(b, c.SingConfig)
|
||||
case "hysteria2":
|
||||
c.Hysteria2Config = NewHysteria2Config()
|
||||
return json.Unmarshal(b, c.Hysteria2Config)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
101
conf/hy.go
Normal file
101
conf/hy.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package conf
|
||||
|
||||
import "time"
|
||||
|
||||
type Hysteria2Config struct {
|
||||
LogConfig Hysteria2LogConfig `json:"Log"`
|
||||
}
|
||||
|
||||
type Hysteria2LogConfig struct {
|
||||
Level string `json:"Level"`
|
||||
}
|
||||
|
||||
func NewHysteria2Config() *Hysteria2Config {
|
||||
return &Hysteria2Config{
|
||||
LogConfig: Hysteria2LogConfig{
|
||||
Level: "error",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type Hysteria2Options struct {
|
||||
Hysteria2ConfigPath string `json:"Hysteria2ConfigPath"`
|
||||
QUICConfig QUICConfig `json:"QUICConfig"`
|
||||
Outbounds []Outbounds `json:"Outbounds"`
|
||||
IgnoreClientBandwidth bool `json:"IgnoreClientBandwidth"`
|
||||
DisableUDP bool `json:"DisableUDP"`
|
||||
UDPIdleTimeout time.Duration `json:"UDPIdleTimeout"`
|
||||
Masquerade serverConfigMasquerade `json:"Masquerade"`
|
||||
}
|
||||
|
||||
type QUICConfig struct {
|
||||
InitialStreamReceiveWindow uint64
|
||||
MaxStreamReceiveWindow uint64
|
||||
InitialConnectionReceiveWindow uint64
|
||||
MaxConnectionReceiveWindow uint64
|
||||
MaxIdleTimeout time.Duration
|
||||
MaxIncomingStreams int64
|
||||
DisablePathMTUDiscovery bool // The server may still override this to true on unsupported platforms.
|
||||
}
|
||||
|
||||
type ServerConfigOutboundDirect struct {
|
||||
Mode string `json:"mode"`
|
||||
BindIPv4 string `json:"bindIPv4"`
|
||||
BindIPv6 string `json:"bindIPv6"`
|
||||
BindDevice string `json:"bindDevice"`
|
||||
}
|
||||
|
||||
type ServerConfigOutboundSOCKS5 struct {
|
||||
Addr string `json:"addr"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type ServerConfigOutboundHTTP struct {
|
||||
URL string `json:"url"`
|
||||
Insecure bool `json:"insecure"`
|
||||
}
|
||||
|
||||
type Outbounds struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Direct ServerConfigOutboundDirect `json:"direct"`
|
||||
SOCKS5 ServerConfigOutboundSOCKS5 `json:"socks5"`
|
||||
HTTP ServerConfigOutboundHTTP `json:"http"`
|
||||
}
|
||||
|
||||
type serverConfigMasqueradeFile struct {
|
||||
Dir string `json:"dir"`
|
||||
}
|
||||
|
||||
type serverConfigMasqueradeProxy struct {
|
||||
URL string `json:"url"`
|
||||
RewriteHost bool `json:"rewriteHost"`
|
||||
}
|
||||
|
||||
type serverConfigMasqueradeString struct {
|
||||
Content string `json:"content"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
StatusCode int `json:"statusCode"`
|
||||
}
|
||||
|
||||
type serverConfigMasquerade struct {
|
||||
Type string `json:"type"`
|
||||
File serverConfigMasqueradeFile `json:"file"`
|
||||
Proxy serverConfigMasqueradeProxy `json:"proxy"`
|
||||
String serverConfigMasqueradeString `json:"string"`
|
||||
ListenHTTP string `json:"listenHTTP"`
|
||||
ListenHTTPS string `json:"listenHTTPS"`
|
||||
ForceHTTPS bool `json:"forceHTTPS"`
|
||||
}
|
||||
|
||||
func NewHysteria2Options() *Hysteria2Options {
|
||||
return &Hysteria2Options{
|
||||
QUICConfig: QUICConfig{},
|
||||
Outbounds: []Outbounds{},
|
||||
IgnoreClientBandwidth: false,
|
||||
DisableUDP: false,
|
||||
UDPIdleTimeout: time.Duration(time.Duration.Seconds(30)),
|
||||
Masquerade: serverConfigMasquerade{},
|
||||
}
|
||||
}
|
||||
26
conf/node.go
26
conf/node.go
@@ -103,17 +103,18 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) (err error) {
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Name string `json:"Name"`
|
||||
Core string `json:"Core"`
|
||||
CoreName string `json:"CoreName"`
|
||||
ListenIP string `json:"ListenIP"`
|
||||
SendIP string `json:"SendIP"`
|
||||
DeviceOnlineMinTraffic int64 `json:"DeviceOnlineMinTraffic"`
|
||||
LimitConfig LimitConfig `json:"LimitConfig"`
|
||||
RawOptions json.RawMessage `json:"RawOptions"`
|
||||
XrayOptions *XrayOptions `json:"XrayOptions"`
|
||||
SingOptions *SingOptions `json:"SingOptions"`
|
||||
CertConfig *CertConfig `json:"CertConfig"`
|
||||
Name string `json:"Name"`
|
||||
Core string `json:"Core"`
|
||||
CoreName string `json:"CoreName"`
|
||||
ListenIP string `json:"ListenIP"`
|
||||
SendIP string `json:"SendIP"`
|
||||
DeviceOnlineMinTraffic int64 `json:"DeviceOnlineMinTraffic"`
|
||||
LimitConfig LimitConfig `json:"LimitConfig"`
|
||||
RawOptions json.RawMessage `json:"RawOptions"`
|
||||
XrayOptions *XrayOptions `json:"XrayOptions"`
|
||||
SingOptions *SingOptions `json:"SingOptions"`
|
||||
Hysteria2Options *Hysteria2Options `json:"Hysteria2Options"`
|
||||
CertConfig *CertConfig `json:"CertConfig"`
|
||||
}
|
||||
|
||||
func (o *Options) UnmarshalJSON(data []byte) error {
|
||||
@@ -129,6 +130,9 @@ func (o *Options) UnmarshalJSON(data []byte) error {
|
||||
case "sing":
|
||||
o.SingOptions = NewSingOptions()
|
||||
return json.Unmarshal(data, o.SingOptions)
|
||||
case "hysteria2":
|
||||
o.Hysteria2Options = NewHysteria2Options()
|
||||
return json.Unmarshal(data, o.Hysteria2Options)
|
||||
default:
|
||||
o.Core = ""
|
||||
o.RawOptions = data
|
||||
|
||||
314
core/hy2/config.go
Normal file
314
core/hy2/config.go
Normal file
@@ -0,0 +1,314 @@
|
||||
package hy2
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/InazumaV/V2bX/api/panel"
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/apernet/hysteria/core/server"
|
||||
"github.com/apernet/hysteria/extras/correctnet"
|
||||
"github.com/apernet/hysteria/extras/masq"
|
||||
"github.com/apernet/hysteria/extras/obfs"
|
||||
"github.com/apernet/hysteria/extras/outbounds"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type masqHandlerLogWrapper struct {
|
||||
H http.Handler
|
||||
QUIC bool
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
func (m *masqHandlerLogWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
m.Logger.Debug("masquerade request",
|
||||
zap.String("addr", r.RemoteAddr),
|
||||
zap.String("method", r.Method),
|
||||
zap.String("host", r.Host),
|
||||
zap.String("url", r.URL.String()),
|
||||
zap.Bool("quic", m.QUIC))
|
||||
m.H.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
const (
|
||||
Byte = 1
|
||||
Kilobyte = Byte * 1000
|
||||
Megabyte = Kilobyte * 1000
|
||||
Gigabyte = Megabyte * 1000
|
||||
Terabyte = Gigabyte * 1000
|
||||
)
|
||||
|
||||
const (
|
||||
defaultStreamReceiveWindow = 8388608 // 8MB
|
||||
defaultConnReceiveWindow = defaultStreamReceiveWindow * 5 / 2 // 20MB
|
||||
defaultMaxIdleTimeout = 30 * time.Second
|
||||
defaultMaxIncomingStreams = 1024
|
||||
defaultUDPIdleTimeout = 60 * time.Second
|
||||
)
|
||||
|
||||
func (n *Hysteria2node) getTLSConfig(config *conf.Options) (*server.TLSConfig, error) {
|
||||
if config.CertConfig == nil {
|
||||
return nil, fmt.Errorf("the CertConfig is not vail")
|
||||
}
|
||||
switch config.CertConfig.CertMode {
|
||||
case "none", "":
|
||||
return nil, fmt.Errorf("the CertMode cannot be none")
|
||||
default:
|
||||
var certs []tls.Certificate
|
||||
cert, err := tls.LoadX509KeyPair(config.CertConfig.CertFile, config.CertConfig.KeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certs = append(certs, cert)
|
||||
return &server.TLSConfig{
|
||||
Certificates: certs,
|
||||
GetCertificate: func(tlsinfo *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
cert, err := tls.LoadX509KeyPair(config.CertConfig.CertFile, config.CertConfig.KeyFile)
|
||||
return &cert, err
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Hysteria2node) getQUICConfig(config *conf.Options) (*server.QUICConfig, error) {
|
||||
quic := &server.QUICConfig{}
|
||||
if config.Hysteria2Options.QUICConfig.InitialStreamReceiveWindow == 0 {
|
||||
quic.InitialStreamReceiveWindow = defaultStreamReceiveWindow
|
||||
} else if config.Hysteria2Options.QUICConfig.InitialStreamReceiveWindow < 16384 {
|
||||
return nil, fmt.Errorf("QUICConfig.InitialStreamReceiveWindowf must be at least 16384")
|
||||
}
|
||||
if config.Hysteria2Options.QUICConfig.MaxStreamReceiveWindow == 0 {
|
||||
quic.MaxStreamReceiveWindow = defaultStreamReceiveWindow
|
||||
} else if config.Hysteria2Options.QUICConfig.MaxStreamReceiveWindow < 16384 {
|
||||
return nil, fmt.Errorf("QUICConfig.MaxStreamReceiveWindowf must be at least 16384")
|
||||
}
|
||||
if config.Hysteria2Options.QUICConfig.InitialConnectionReceiveWindow == 0 {
|
||||
quic.InitialConnectionReceiveWindow = defaultConnReceiveWindow
|
||||
} else if config.Hysteria2Options.QUICConfig.InitialConnectionReceiveWindow < 16384 {
|
||||
return nil, fmt.Errorf("QUICConfig.InitialConnectionReceiveWindowf must be at least 16384")
|
||||
}
|
||||
if config.Hysteria2Options.QUICConfig.MaxConnectionReceiveWindow == 0 {
|
||||
quic.MaxConnectionReceiveWindow = defaultConnReceiveWindow
|
||||
} else if config.Hysteria2Options.QUICConfig.MaxConnectionReceiveWindow < 16384 {
|
||||
return nil, fmt.Errorf("QUICConfig.MaxConnectionReceiveWindowf must be at least 16384")
|
||||
}
|
||||
if config.Hysteria2Options.QUICConfig.MaxIdleTimeout == 0 {
|
||||
quic.MaxIdleTimeout = defaultMaxIdleTimeout
|
||||
} else if config.Hysteria2Options.QUICConfig.MaxIdleTimeout < 4*time.Second || config.Hysteria2Options.QUICConfig.MaxIdleTimeout > 120*time.Second {
|
||||
return nil, fmt.Errorf("QUICConfig.MaxIdleTimeoutf must be between 4s and 120s")
|
||||
}
|
||||
if config.Hysteria2Options.QUICConfig.MaxIncomingStreams == 0 {
|
||||
quic.MaxIncomingStreams = defaultMaxIncomingStreams
|
||||
} else if config.Hysteria2Options.QUICConfig.MaxIncomingStreams < 8 {
|
||||
return nil, fmt.Errorf("QUICConfig.MaxIncomingStreamsf must be at least 8")
|
||||
}
|
||||
// todo fix !linux && !windows && !darwin
|
||||
quic.DisablePathMTUDiscovery = false
|
||||
|
||||
return quic, nil
|
||||
}
|
||||
func (n *Hysteria2node) getConn(info *panel.NodeInfo, config *conf.Options) (net.PacketConn, error) {
|
||||
uAddr, err := net.ResolveUDPAddr("udp", formatAddress(config.ListenIP, info.Common.ServerPort))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := correctnet.ListenUDP("udp", uAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch strings.ToLower(info.Hysteria2.ObfsType) {
|
||||
case "", "plain":
|
||||
return conn, nil
|
||||
case "salamander":
|
||||
ob, err := obfs.NewSalamanderObfuscator([]byte(info.Hysteria2.ObfsPassword))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obfs.WrapPacketConn(conn, ob), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported obfuscation type")
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Hysteria2node) getBandwidthConfig(info *panel.NodeInfo) *server.BandwidthConfig {
|
||||
band := &server.BandwidthConfig{}
|
||||
if info.Hysteria2.UpMbps != 0 {
|
||||
band.MaxTx = (uint64)(info.Hysteria2.UpMbps * Megabyte / 8)
|
||||
}
|
||||
if info.Hysteria2.DownMbps != 0 {
|
||||
band.MaxRx = (uint64)(info.Hysteria2.DownMbps * Megabyte / 8)
|
||||
|
||||
}
|
||||
return band
|
||||
}
|
||||
|
||||
func (n *Hysteria2node) getOutboundConfig(config *conf.Options) (server.Outbound, error) {
|
||||
var obs []outbounds.OutboundEntry
|
||||
if len(config.Hysteria2Options.Outbounds) == 0 {
|
||||
// Guarantee we have at least one outbound
|
||||
obs = []outbounds.OutboundEntry{{
|
||||
Name: "default",
|
||||
Outbound: outbounds.NewDirectOutboundSimple(outbounds.DirectOutboundModeAuto),
|
||||
}}
|
||||
} else {
|
||||
obs = make([]outbounds.OutboundEntry, len(config.Hysteria2Options.Outbounds))
|
||||
for i, entry := range config.Hysteria2Options.Outbounds {
|
||||
if entry.Name == "" {
|
||||
return nil, fmt.Errorf("outbounds.name empty outbound name")
|
||||
}
|
||||
var ob outbounds.PluggableOutbound
|
||||
var err error
|
||||
switch strings.ToLower(entry.Type) {
|
||||
case "direct":
|
||||
ob, err = serverConfigOutboundDirectToOutbound(entry.Direct)
|
||||
case "socks5":
|
||||
ob, err = serverConfigOutboundSOCKS5ToOutbound(entry.SOCKS5)
|
||||
case "http":
|
||||
ob, err = serverConfigOutboundHTTPToOutbound(entry.HTTP)
|
||||
default:
|
||||
err = fmt.Errorf("outbounds.type unsupported outbound type")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
obs[i] = outbounds.OutboundEntry{Name: entry.Name, Outbound: ob}
|
||||
}
|
||||
}
|
||||
var uOb outbounds.PluggableOutbound // "unified" outbound
|
||||
|
||||
hasACL := false
|
||||
if hasACL {
|
||||
// todo fix ACL
|
||||
} else {
|
||||
// No ACL, use the first outbound
|
||||
uOb = obs[0].Outbound
|
||||
}
|
||||
Outbound := &outbounds.PluggableOutboundAdapter{PluggableOutbound: uOb}
|
||||
|
||||
return Outbound, nil
|
||||
}
|
||||
|
||||
func (n *Hysteria2node) getMasqHandler(tlsconfig *server.TLSConfig, conn net.PacketConn, info *panel.NodeInfo, config *conf.Options) (http.Handler, error) {
|
||||
var handler http.Handler
|
||||
switch strings.ToLower(config.Hysteria2Options.Masquerade.Type) {
|
||||
case "", "404":
|
||||
handler = http.NotFoundHandler()
|
||||
case "file":
|
||||
if config.Hysteria2Options.Masquerade.File.Dir == "" {
|
||||
return nil, fmt.Errorf("masquerade.file.dir empty file directory")
|
||||
}
|
||||
handler = http.FileServer(http.Dir(config.Hysteria2Options.Masquerade.File.Dir))
|
||||
case "proxy":
|
||||
if config.Hysteria2Options.Masquerade.Proxy.URL == "" {
|
||||
return nil, fmt.Errorf("masquerade.proxy.url empty proxy url")
|
||||
}
|
||||
u, err := url.Parse(config.Hysteria2Options.Masquerade.Proxy.URL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(fmt.Sprintf("masquerade.proxy.url %s", err))
|
||||
}
|
||||
handler = &httputil.ReverseProxy{
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
r.SetURL(u)
|
||||
// SetURL rewrites the Host header,
|
||||
// but we don't want that if rewriteHost is false
|
||||
if !config.Hysteria2Options.Masquerade.Proxy.RewriteHost {
|
||||
r.Out.Host = r.In.Host
|
||||
}
|
||||
},
|
||||
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
n.Logger.Error("HTTP reverse proxy error", zap.Error(err))
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
},
|
||||
}
|
||||
case "string":
|
||||
if config.Hysteria2Options.Masquerade.String.Content == "" {
|
||||
return nil, fmt.Errorf("masquerade.string.content empty string content")
|
||||
}
|
||||
if config.Hysteria2Options.Masquerade.String.StatusCode != 0 &&
|
||||
(config.Hysteria2Options.Masquerade.String.StatusCode < 200 ||
|
||||
config.Hysteria2Options.Masquerade.String.StatusCode > 599 ||
|
||||
config.Hysteria2Options.Masquerade.String.StatusCode == 233) {
|
||||
// 233 is reserved for Hysteria authentication
|
||||
return nil, fmt.Errorf("masquerade.string.statusCode invalid status code (must be 200-599, except 233)")
|
||||
}
|
||||
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
for k, v := range config.Hysteria2Options.Masquerade.String.Headers {
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
if config.Hysteria2Options.Masquerade.String.StatusCode != 0 {
|
||||
w.WriteHeader(config.Hysteria2Options.Masquerade.String.StatusCode)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK) // Use 200 OK by default
|
||||
}
|
||||
_, _ = w.Write([]byte(config.Hysteria2Options.Masquerade.String.Content))
|
||||
})
|
||||
default:
|
||||
return nil, fmt.Errorf("masquerade.type unsupported masquerade type")
|
||||
}
|
||||
MasqHandler := &masqHandlerLogWrapper{H: handler, QUIC: true, Logger: n.Logger}
|
||||
|
||||
if config.Hysteria2Options.Masquerade.ListenHTTP != "" || config.Hysteria2Options.Masquerade.ListenHTTPS != "" {
|
||||
if config.Hysteria2Options.Masquerade.ListenHTTP != "" && config.Hysteria2Options.Masquerade.ListenHTTPS == "" {
|
||||
return nil, fmt.Errorf("masquerade.listenHTTPS having only HTTP server without HTTPS is not supported")
|
||||
}
|
||||
s := masq.MasqTCPServer{
|
||||
QUICPort: extractPortFromAddr(conn.LocalAddr().String()),
|
||||
HTTPSPort: extractPortFromAddr(config.Hysteria2Options.Masquerade.ListenHTTPS),
|
||||
Handler: &masqHandlerLogWrapper{H: handler, QUIC: false},
|
||||
TLSConfig: &tls.Config{
|
||||
Certificates: tlsconfig.Certificates,
|
||||
GetCertificate: tlsconfig.GetCertificate,
|
||||
},
|
||||
ForceHTTPS: config.Hysteria2Options.Masquerade.ForceHTTPS,
|
||||
}
|
||||
go runMasqTCPServer(&s, config.Hysteria2Options.Masquerade.ListenHTTP, config.Hysteria2Options.Masquerade.ListenHTTPS, n.Logger)
|
||||
}
|
||||
|
||||
return MasqHandler, nil
|
||||
}
|
||||
|
||||
func runMasqTCPServer(s *masq.MasqTCPServer, httpAddr, httpsAddr string, logger *zap.Logger) {
|
||||
errChan := make(chan error, 2)
|
||||
if httpAddr != "" {
|
||||
go func() {
|
||||
logger.Info("masquerade HTTP server up and running", zap.String("listen", httpAddr))
|
||||
errChan <- s.ListenAndServeHTTP(httpAddr)
|
||||
}()
|
||||
}
|
||||
if httpsAddr != "" {
|
||||
go func() {
|
||||
logger.Info("masquerade HTTPS server up and running", zap.String("listen", httpsAddr))
|
||||
errChan <- s.ListenAndServeHTTPS(httpsAddr)
|
||||
}()
|
||||
}
|
||||
err := <-errChan
|
||||
if err != nil {
|
||||
logger.Fatal("failed to serve masquerade HTTP(S)", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func extractPortFromAddr(addr string) int {
|
||||
_, portStr, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
func formatAddress(ip string, port int) string {
|
||||
if strings.Contains(ip, ":") {
|
||||
return fmt.Sprintf("[%s]:%d", ip, port)
|
||||
}
|
||||
return fmt.Sprintf("%s:%d", ip, port)
|
||||
}
|
||||
30
core/hy2/hook.go
Normal file
30
core/hy2/hook.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package hy2
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/InazumaV/V2bX/common/counter"
|
||||
)
|
||||
|
||||
type HookServer struct {
|
||||
Tag string
|
||||
Counter sync.Map
|
||||
}
|
||||
|
||||
func (h *HookServer) Log(id string, tx, rx uint64) (ok bool) {
|
||||
var c interface{}
|
||||
var exists bool
|
||||
|
||||
if c, exists = h.Counter.Load(h.Tag); !exists {
|
||||
c = counter.NewTrafficCounter()
|
||||
h.Counter.Store(h.Tag, c)
|
||||
}
|
||||
|
||||
if tc, ok := c.(*counter.TrafficCounter); ok {
|
||||
tc.Rx(id, int(rx))
|
||||
tc.Tx(id, int(tx))
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
61
core/hy2/hy2.go
Normal file
61
core/hy2/hy2.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package hy2
|
||||
|
||||
import (
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
vCore "github.com/InazumaV/V2bX/core"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ vCore.Core = (*Hysteria2)(nil)
|
||||
|
||||
type Hysteria2 struct {
|
||||
Hy2nodes map[string]Hysteria2node
|
||||
Auth *V2bX
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
func init() {
|
||||
vCore.RegisterCore("hysteria2", New)
|
||||
}
|
||||
|
||||
func New(c *conf.CoreConfig) (vCore.Core, error) {
|
||||
loglever := "error"
|
||||
if c.Hysteria2Config.LogConfig.Level != "" {
|
||||
loglever = c.Hysteria2Config.LogConfig.Level
|
||||
}
|
||||
log, err := initLogger(loglever, "console")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Hysteria2{
|
||||
Hy2nodes: make(map[string]Hysteria2node),
|
||||
Auth: &V2bX{
|
||||
usersMap: make(map[string]int),
|
||||
},
|
||||
Logger: log,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Hysteria2) Protocols() []string {
|
||||
return []string{
|
||||
"hysteria2",
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Hysteria2) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hysteria2) Close() error {
|
||||
for _, n := range h.Hy2nodes {
|
||||
err := n.Hy2server.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hysteria2) Type() string {
|
||||
return "hysteria2"
|
||||
}
|
||||
137
core/hy2/logger.go
Normal file
137
core/hy2/logger.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package hy2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
type serverLogger struct {
|
||||
Tag string
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
var logLevelMap = map[string]zapcore.Level{
|
||||
"debug": zapcore.DebugLevel,
|
||||
"info": zapcore.InfoLevel,
|
||||
"warn": zapcore.WarnLevel,
|
||||
"error": zapcore.ErrorLevel,
|
||||
}
|
||||
|
||||
var logFormatMap = map[string]zapcore.EncoderConfig{
|
||||
"console": {
|
||||
TimeKey: "time",
|
||||
LevelKey: "level",
|
||||
NameKey: "logger",
|
||||
MessageKey: "msg",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeLevel: zapcore.CapitalColorLevelEncoder,
|
||||
EncodeTime: zapcore.RFC3339TimeEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
},
|
||||
"json": {
|
||||
TimeKey: "time",
|
||||
LevelKey: "level",
|
||||
NameKey: "logger",
|
||||
MessageKey: "msg",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeLevel: zapcore.LowercaseLevelEncoder,
|
||||
EncodeTime: zapcore.EpochMillisTimeEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
},
|
||||
}
|
||||
|
||||
func (l *serverLogger) Connect(addr net.Addr, uuid string, tx uint64) {
|
||||
limiter, err := limiter.GetLimiter(l.Tag)
|
||||
if err != nil {
|
||||
l.logger.Panic("Get limiter error", zap.String("tag", l.Tag), zap.Error(err))
|
||||
}
|
||||
if _, r := limiter.CheckLimit(uuid, extractIPFromAddr(addr), addr.Network() == "tcp"); r {
|
||||
l.logger.Warn("Need Reject", zap.String("addr", addr.String()), zap.String("uuid", uuid))
|
||||
}
|
||||
l.logger.Info("client connected", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.Uint64("tx", tx))
|
||||
}
|
||||
|
||||
func (l *serverLogger) Disconnect(addr net.Addr, uuid string, err error) {
|
||||
l.logger.Info("client disconnected", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.Error(err))
|
||||
}
|
||||
|
||||
func (l *serverLogger) TCPRequest(addr net.Addr, uuid, reqAddr string) {
|
||||
limiter, err := limiter.GetLimiter(l.Tag)
|
||||
if err != nil {
|
||||
l.logger.Panic("Get limiter error", zap.String("tag", l.Tag), zap.Error(err))
|
||||
}
|
||||
if _, r := limiter.CheckLimit(uuid, extractIPFromAddr(addr), addr.Network() == "tcp"); r {
|
||||
l.logger.Warn("Need Reject", zap.String("addr", addr.String()), zap.String("uuid", uuid))
|
||||
}
|
||||
l.logger.Debug("TCP request", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.String("reqAddr", reqAddr))
|
||||
}
|
||||
|
||||
func (l *serverLogger) TCPError(addr net.Addr, uuid, reqAddr string, err error) {
|
||||
if err == nil {
|
||||
l.logger.Debug("TCP closed", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.String("reqAddr", reqAddr))
|
||||
} else {
|
||||
l.logger.Debug("TCP error", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.String("reqAddr", reqAddr), zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *serverLogger) UDPRequest(addr net.Addr, uuid string, sessionId uint32, reqAddr string) {
|
||||
limiter, err := limiter.GetLimiter(l.Tag)
|
||||
if err != nil {
|
||||
l.logger.Panic("Get limiter error", zap.String("tag", l.Tag), zap.Error(err))
|
||||
}
|
||||
if _, r := limiter.CheckLimit(uuid, extractIPFromAddr(addr), addr.Network() == "tcp"); r {
|
||||
l.logger.Warn("Need Reject", zap.String("addr", addr.String()), zap.String("uuid", uuid))
|
||||
}
|
||||
l.logger.Debug("UDP request", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.Uint32("sessionId", sessionId), zap.String("reqAddr", reqAddr))
|
||||
}
|
||||
|
||||
func (l *serverLogger) UDPError(addr net.Addr, uuid string, sessionId uint32, err error) {
|
||||
if err == nil {
|
||||
l.logger.Debug("UDP closed", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.Uint32("sessionId", sessionId))
|
||||
} else {
|
||||
l.logger.Debug("UDP error", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.Uint32("sessionId", sessionId), zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func initLogger(logLevel string, logFormat string) (*zap.Logger, error) {
|
||||
level, ok := logLevelMap[strings.ToLower(logLevel)]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(fmt.Sprintf("unsupported log level: %s\n", logLevel))
|
||||
}
|
||||
enc, ok := logFormatMap[strings.ToLower(logFormat)]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(fmt.Sprintf("unsupported log format: %s\n", logFormat))
|
||||
}
|
||||
c := zap.Config{
|
||||
Level: zap.NewAtomicLevelAt(level),
|
||||
DisableCaller: true,
|
||||
DisableStacktrace: true,
|
||||
Encoding: strings.ToLower(logFormat),
|
||||
EncoderConfig: enc,
|
||||
OutputPaths: []string{"stderr"},
|
||||
ErrorOutputPaths: []string{"stderr"},
|
||||
}
|
||||
logger, err := c.Build()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(fmt.Sprintf("failed to initialize logger: %s\n", err))
|
||||
}
|
||||
return logger, nil
|
||||
}
|
||||
|
||||
func extractIPFromAddr(addr net.Addr) string {
|
||||
switch v := addr.(type) {
|
||||
case *net.TCPAddr:
|
||||
return v.IP.String()
|
||||
case *net.UDPAddr:
|
||||
return v.IP.String()
|
||||
case *net.IPAddr:
|
||||
return v.IP.String()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
109
core/hy2/node.go
Normal file
109
core/hy2/node.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package hy2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/InazumaV/V2bX/api/panel"
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/apernet/hysteria/core/server"
|
||||
"github.com/goccy/go-json"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Hysteria2node struct {
|
||||
Hy2server server.Server
|
||||
Tag string
|
||||
Logger *zap.Logger
|
||||
EventLogger server.EventLogger
|
||||
TrafficLogger server.TrafficLogger
|
||||
}
|
||||
|
||||
func (n *Hysteria2node) getHyConfig(tag string, info *panel.NodeInfo, config *conf.Options) (*server.Config, error) {
|
||||
tls, err := n.getTLSConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
quic, err := n.getQUICConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := n.getConn(info, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
Outbound, err := n.getOutboundConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
Masq, err := n.getMasqHandler(tls, conn, info, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &server.Config{
|
||||
TLSConfig: *tls,
|
||||
QUICConfig: *quic,
|
||||
Conn: conn,
|
||||
Outbound: Outbound,
|
||||
BandwidthConfig: *n.getBandwidthConfig(info),
|
||||
IgnoreClientBandwidth: config.Hysteria2Options.IgnoreClientBandwidth,
|
||||
DisableUDP: config.Hysteria2Options.DisableUDP,
|
||||
UDPIdleTimeout: config.Hysteria2Options.UDPIdleTimeout,
|
||||
EventLogger: n.EventLogger,
|
||||
TrafficLogger: n.TrafficLogger,
|
||||
MasqHandler: Masq,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Hysteria2) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error {
|
||||
var err error
|
||||
hyconfig := &server.Config{}
|
||||
if len(config.Hysteria2Options.Hysteria2ConfigPath) != 0 {
|
||||
data, err := os.ReadFile(config.Hysteria2Options.Hysteria2ConfigPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read hysteria2 config error: %s", err)
|
||||
}
|
||||
err = json.Unmarshal(data, hyconfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal original config error: %s", err)
|
||||
}
|
||||
}
|
||||
n := Hysteria2node{
|
||||
Tag: tag,
|
||||
Logger: h.Logger,
|
||||
EventLogger: &serverLogger{
|
||||
Tag: tag,
|
||||
logger: h.Logger,
|
||||
},
|
||||
TrafficLogger: &HookServer{
|
||||
Tag: tag,
|
||||
},
|
||||
}
|
||||
|
||||
hyconfig, err = n.getHyConfig(tag, info, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hyconfig.Authenticator = h.Auth
|
||||
s, err := server.NewServer(hyconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.Hy2server = s
|
||||
h.Hy2nodes[tag] = n
|
||||
go func() {
|
||||
if err := s.Serve(); err != nil {
|
||||
h.Logger.Error("Server Error", zap.Error(err))
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hysteria2) DelNode(tag string) error {
|
||||
err := h.Hy2nodes[tag].Hy2server.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
delete(h.Hy2nodes, tag)
|
||||
return nil
|
||||
}
|
||||
61
core/hy2/outbound.go
Normal file
61
core/hy2/outbound.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package hy2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/apernet/hysteria/extras/outbounds"
|
||||
)
|
||||
|
||||
func serverConfigOutboundDirectToOutbound(c conf.ServerConfigOutboundDirect) (outbounds.PluggableOutbound, error) {
|
||||
var mode outbounds.DirectOutboundMode
|
||||
switch strings.ToLower(c.Mode) {
|
||||
case "", "auto":
|
||||
mode = outbounds.DirectOutboundModeAuto
|
||||
case "64":
|
||||
mode = outbounds.DirectOutboundMode64
|
||||
case "46":
|
||||
mode = outbounds.DirectOutboundMode46
|
||||
case "6":
|
||||
mode = outbounds.DirectOutboundMode6
|
||||
case "4":
|
||||
mode = outbounds.DirectOutboundMode4
|
||||
default:
|
||||
return nil, fmt.Errorf("outbounds.direct.mode unsupported mode")
|
||||
}
|
||||
bindIP := len(c.BindIPv4) > 0 || len(c.BindIPv6) > 0
|
||||
bindDevice := len(c.BindDevice) > 0
|
||||
if bindIP && bindDevice {
|
||||
return nil, fmt.Errorf("outbounds.direct cannot bind both IP and device")
|
||||
}
|
||||
if bindIP {
|
||||
ip4, ip6 := net.ParseIP(c.BindIPv4), net.ParseIP(c.BindIPv6)
|
||||
if len(c.BindIPv4) > 0 && ip4 == nil {
|
||||
return nil, fmt.Errorf("outbounds.direct.bindIPv4 invalid IPv4 address")
|
||||
}
|
||||
if len(c.BindIPv6) > 0 && ip6 == nil {
|
||||
return nil, fmt.Errorf("outbounds.direct.bindIPv6 invalid IPv6 address")
|
||||
}
|
||||
return outbounds.NewDirectOutboundBindToIPs(mode, ip4, ip6)
|
||||
}
|
||||
if bindDevice {
|
||||
return outbounds.NewDirectOutboundBindToDevice(mode, c.BindDevice)
|
||||
}
|
||||
return outbounds.NewDirectOutboundSimple(mode), nil
|
||||
}
|
||||
|
||||
func serverConfigOutboundSOCKS5ToOutbound(c conf.ServerConfigOutboundSOCKS5) (outbounds.PluggableOutbound, error) {
|
||||
if c.Addr == "" {
|
||||
return nil, fmt.Errorf("outbounds.socks5.addr empty socks5 address")
|
||||
}
|
||||
return outbounds.NewSOCKS5Outbound(c.Addr, c.Username, c.Password), nil
|
||||
}
|
||||
|
||||
func serverConfigOutboundHTTPToOutbound(c conf.ServerConfigOutboundHTTP) (outbounds.PluggableOutbound, error) {
|
||||
if c.URL == "" {
|
||||
return nil, fmt.Errorf("outbounds.http.url empty http address")
|
||||
}
|
||||
return outbounds.NewHTTPOutbound(c.URL, c.Insecure)
|
||||
}
|
||||
70
core/hy2/user.go
Normal file
70
core/hy2/user.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package hy2
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/InazumaV/V2bX/api/panel"
|
||||
"github.com/InazumaV/V2bX/common/counter"
|
||||
vCore "github.com/InazumaV/V2bX/core"
|
||||
"github.com/apernet/hysteria/core/server"
|
||||
)
|
||||
|
||||
var _ server.Authenticator = &V2bX{}
|
||||
|
||||
type V2bX struct {
|
||||
usersMap map[string]int
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (v *V2bX) Authenticate(addr net.Addr, auth string, tx uint64) (ok bool, id string) {
|
||||
v.mutex.Lock()
|
||||
defer v.mutex.Unlock()
|
||||
if _, exists := v.usersMap[auth]; exists {
|
||||
return true, auth
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (h *Hysteria2) AddUsers(p *vCore.AddUsersParams) (added int, err error) {
|
||||
var wg sync.WaitGroup
|
||||
for _, user := range p.Users {
|
||||
wg.Add(1)
|
||||
go func(u panel.UserInfo) {
|
||||
defer wg.Done()
|
||||
h.Auth.mutex.Lock()
|
||||
h.Auth.usersMap[u.Uuid] = u.Id
|
||||
h.Auth.mutex.Unlock()
|
||||
}(user)
|
||||
}
|
||||
wg.Wait()
|
||||
return len(p.Users), nil
|
||||
}
|
||||
|
||||
func (h *Hysteria2) DelUsers(users []panel.UserInfo, tag string) error {
|
||||
var wg sync.WaitGroup
|
||||
for _, user := range users {
|
||||
wg.Add(1)
|
||||
go func(u panel.UserInfo) {
|
||||
defer wg.Done()
|
||||
h.Auth.mutex.Lock()
|
||||
delete(h.Auth.usersMap, u.Uuid)
|
||||
h.Auth.mutex.Unlock()
|
||||
}(user)
|
||||
}
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hysteria2) GetUserTraffic(tag string, uuid string, reset bool) (up int64, down int64) {
|
||||
if v, ok := h.Hy2nodes[tag].TrafficLogger.(*HookServer).Counter.Load(tag); ok {
|
||||
c := v.(*counter.TrafficCounter)
|
||||
up = c.GetUpCount(uuid)
|
||||
down = c.GetDownCount(uuid)
|
||||
if reset {
|
||||
c.Reset(uuid)
|
||||
}
|
||||
return up, down
|
||||
}
|
||||
return 0, 0
|
||||
}
|
||||
5
core/imports/hy2.go
Normal file
5
core/imports/hy2.go
Normal file
@@ -0,0 +1,5 @@
|
||||
//go:build hysteria2
|
||||
|
||||
package imports
|
||||
|
||||
import _ "github.com/InazumaV/V2bX/core/hy2"
|
||||
@@ -70,13 +70,15 @@ func (b *Sing) AddUsers(p *core.AddUsersParams) (added int, err error) {
|
||||
err = b.inbounds[p.Tag].(*inbound.Hysteria).AddUsers(us)
|
||||
case "hysteria2":
|
||||
us := make([]option.Hysteria2User, len(p.Users))
|
||||
id := make([]int, len(p.Users))
|
||||
for i := range p.Users {
|
||||
us[i] = option.Hysteria2User{
|
||||
Name: p.Users[i].Uuid,
|
||||
Password: p.Users[i].Uuid,
|
||||
}
|
||||
id[i] = p.Users[i].Id
|
||||
}
|
||||
err = b.inbounds[p.Tag].(*inbound.Hysteria2).AddUsers(us)
|
||||
err = b.inbounds[p.Tag].(*inbound.Hysteria2).AddUsers(us, id)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
||||
46
go.mod
46
go.mod
@@ -1,8 +1,12 @@
|
||||
module github.com/InazumaV/V2bX
|
||||
|
||||
go 1.21.4
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.0
|
||||
|
||||
require (
|
||||
github.com/apernet/hysteria/core v1.3.5-0.20240201034858-bb99579bb92c
|
||||
github.com/apernet/hysteria/extras v0.0.0-20240201034858-bb99579bb92c
|
||||
github.com/beevik/ntp v1.2.0
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/go-acme/lego/v4 v4.13.2
|
||||
@@ -10,13 +14,14 @@ require (
|
||||
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/sagernet/sing v0.3.1-0.20240105061852-782bc05c5573
|
||||
github.com/sagernet/sing-box v1.8.2
|
||||
github.com/sagernet/sing v0.3.1-beta.2
|
||||
github.com/sagernet/sing-box v1.9.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/xtls/xray-core v1.8.8-0.20240120214034-53de58fad3a0
|
||||
golang.org/x/crypto v0.18.0
|
||||
golang.org/x/sys v0.16.0
|
||||
github.com/xtls/xray-core v1.8.8-0.20240219151643-ad3dd3df56b9
|
||||
go.uber.org/zap v1.26.0
|
||||
golang.org/x/crypto v0.19.0
|
||||
golang.org/x/sys v0.17.0
|
||||
google.golang.org/protobuf v1.32.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
)
|
||||
@@ -47,7 +52,9 @@ require (
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755 // indirect
|
||||
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/apernet/quic-go v0.41.1-0.20240122005439-5bf4609c416f // indirect
|
||||
github.com/aws/aws-sdk-go v1.39.0 // indirect
|
||||
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/caddyserver/certmagic v0.20.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
@@ -90,6 +97,7 @@ require (
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
@@ -144,7 +152,7 @@ require (
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/quic-go/quic-go v0.41.0 // indirect
|
||||
github.com/refraction-networking/utls v1.6.1 // indirect
|
||||
github.com/refraction-networking/utls v1.6.2 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/sacloud/api-client-go v0.2.8 // indirect
|
||||
github.com/sacloud/go-http v0.1.6 // indirect
|
||||
@@ -152,16 +160,16 @@ require (
|
||||
github.com/sacloud/packages-go v0.0.9 // indirect
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20240214044702-a3d61928a32f // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||
github.com/sagernet/quic-go v0.40.1-beta.2 // indirect
|
||||
github.com/sagernet/sing-dns v0.1.12 // indirect
|
||||
github.com/sagernet/quic-go v0.41.0-beta.2 // indirect
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.6 // indirect
|
||||
github.com/sagernet/sing-mux v0.2.0 // indirect
|
||||
github.com/sagernet/sing-quic v0.1.7 // indirect
|
||||
github.com/sagernet/sing-quic v0.1.9-beta.1 // indirect
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6 // indirect
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 // indirect
|
||||
github.com/sagernet/sing-tun v0.2.0 // indirect
|
||||
github.com/sagernet/sing-tun v0.2.2-beta.3 // indirect
|
||||
github.com/sagernet/sing-vmess v0.1.8 // indirect
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
|
||||
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 // indirect
|
||||
@@ -182,6 +190,8 @@ require (
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 // indirect
|
||||
github.com/transip/gotransip/v6 v6.20.0 // indirect
|
||||
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf // indirect
|
||||
github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301 // indirect
|
||||
github.com/ultradns/ultradns-go-sdk v1.5.0-20230427130837-23c9b0c // indirect
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
||||
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
|
||||
@@ -196,12 +206,11 @@ require (
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/ratelimit v0.2.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
|
||||
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/oauth2 v0.13.0 // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/oauth2 v0.14.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.17.0 // indirect
|
||||
@@ -212,7 +221,7 @@ require (
|
||||
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||
google.golang.org/grpc v1.60.1 // indirect
|
||||
google.golang.org/grpc v1.61.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/ns1/ns1-go.v2 v2.7.6 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
@@ -221,4 +230,5 @@ require (
|
||||
lukechampine.com/blake3 v1.2.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/sagernet/sing-box v1.8.2 => github.com/wyx2685/sing-box_mod v0.0.0-20240122043647-0854bf9053ab
|
||||
//github.com/apernet/hysteria/core v1.3.5-0.20240201034858-bb99579bb92c => /root/hysteria/core
|
||||
replace github.com/sagernet/sing-box v1.9.0 => github.com/wyx2685/sing-box_mod v0.0.4
|
||||
|
||||
89
go.sum
89
go.sum
@@ -81,11 +81,19 @@ github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sx
|
||||
github.com/andybalholm/brotli v1.0.6/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/core v1.3.5-0.20240201034858-bb99579bb92c h1:rtlUELUe5VAh+4M8W3aX0Ia5Gez9/suH1m5mVpnZibc=
|
||||
github.com/apernet/hysteria/core v1.3.5-0.20240201034858-bb99579bb92c/go.mod h1:AFHu72Vc6ctm7KwHd28EgIeK4v/FWNVzRJaeqs2dqvQ=
|
||||
github.com/apernet/hysteria/extras v0.0.0-20240201034858-bb99579bb92c h1:w54no07c0oyuD0qNV2ZPs7CwQk/ATRAqRulR51LlPV0=
|
||||
github.com/apernet/hysteria/extras v0.0.0-20240201034858-bb99579bb92c/go.mod h1:oH9DY1/YNQYYZARtCnSLJcJBkAv6e80WhkhyqXXBgd8=
|
||||
github.com/apernet/quic-go v0.41.1-0.20240122005439-5bf4609c416f h1:4jBGc3SlgQT8YFqHhfnK7EVFVY292CxagfNqfPiQZhY=
|
||||
github.com/apernet/quic-go v0.41.1-0.20240122005439-5bf4609c416f/go.mod h1:4GInxO6ypy63J2NaO5rQx1wRp6K8YHI6zqLG+VswU6I=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
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/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0=
|
||||
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg=
|
||||
github.com/beevik/ntp v1.2.0 h1:n1teVGbd4YM36FlGvWYfccBIdGzeaakHrTlo6RSL8mw=
|
||||
github.com/beevik/ntp v1.2.0/go.mod h1:vD6h1um4kzXpqmLTuu0cCLcC+NfvC0IC+ltmEDA8E78=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
@@ -356,6 +364,8 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
@@ -484,6 +494,7 @@ github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt
|
||||
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=
|
||||
github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c=
|
||||
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||
github.com/mimuret/golang-iij-dpf v0.9.1 h1:Gj6EhHJkOhr+q2RnvRPJsPMcjuVnWPSccEHyoEehU34=
|
||||
@@ -609,8 +620,8 @@ github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
|
||||
github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
|
||||
github.com/refraction-networking/utls v1.6.1 h1:n1JG5karzdGWsI6iZmGrOv3SNzR4c+4M8J6KWGsk3lA=
|
||||
github.com/refraction-networking/utls v1.6.1/go.mod h1:+EbcQOvQvXoFV9AEKbuGlljt1doLRKAVY1jJHe9EtDo=
|
||||
github.com/refraction-networking/utls v1.6.2 h1:iTeeGY0o6nMNcGyirxkD5bFIsVctP5InGZ3E0HrzS7k=
|
||||
github.com/refraction-networking/utls v1.6.2/go.mod h1:yil9+7qSl+gBwJqztoQseO6Pr3h62pQoY1lXiNR/FPs=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
@@ -636,29 +647,29 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQEMdlk9oFSKYWRqVuu9qzNiOayIonKmv1gCXY=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k=
|
||||
github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e h1:DOkjByVeAR56dkszjnMZke4wr7yM/1xHaJF3G9olkEE=
|
||||
github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e/go.mod h1:fLxq/gtp0qzkaEwywlRRiGmjOK5ES/xUzyIKIFP2Asw=
|
||||
github.com/sagernet/gvisor v0.0.0-20240214044702-a3d61928a32f h1:7hj/CcCkUiC6gfhX4D+QNyodmhfurW2L2Q4qzJ1bPnI=
|
||||
github.com/sagernet/gvisor v0.0.0-20240214044702-a3d61928a32f/go.mod h1:bLmnT/4M4+yKB6F7JtRsbUr+YJ64yXwFIygjyYDFQzQ=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/quic-go v0.40.1-beta.2 h1:USRwm36XuAFdcrmv4vDRD+YUOO08DfvLNruXThrVHZU=
|
||||
github.com/sagernet/quic-go v0.40.1-beta.2/go.mod h1:CcKTpzTAISxrM4PA5M20/wYuz9Tj6Tx4DwGbNl9UQrU=
|
||||
github.com/sagernet/quic-go v0.41.0-beta.2 h1:NtFC1Ief+SYJkfRq68D1OEqZQTNh2jYSpyRLhjT+m6U=
|
||||
github.com/sagernet/quic-go v0.41.0-beta.2/go.mod h1:X10Mf9DVHuSEReOLov/XuflD13MVLH3WtppVVFnSItU=
|
||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing v0.3.1-0.20240105061852-782bc05c5573 h1:1wGN3eNanp8r+Y3bNBys3ZnAVF5gdtDoDwtosMZEbgA=
|
||||
github.com/sagernet/sing v0.3.1-0.20240105061852-782bc05c5573/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g=
|
||||
github.com/sagernet/sing-dns v0.1.12 h1:1HqZ+ln+Rezx/aJMStaS0d7oPeX2EobSV1NT537kyj4=
|
||||
github.com/sagernet/sing-dns v0.1.12/go.mod h1:rx/DTOisneQpCgNQ4jbFU/JNEtnz0lYcHXenlVzpjEU=
|
||||
github.com/sagernet/sing v0.3.1-beta.2 h1:QEbBAXStZ/l4fPKbTkJZZrR/hPDOstEsZ5B9JbvkZO4=
|
||||
github.com/sagernet/sing v0.3.1-beta.2/go.mod h1:qHySJ7u8po9DABtMYEkNBcOumx7ZZJf/fbv2sfTkNHE=
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.6 h1:e167d8lW4VEagPGh/fPCgdtGGAPFBgY8g/c4WqKRkQk=
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.6/go.mod h1:IxOqfSb6Zt6UVCy8fJpDxb2XxqzHUytNqeOuJfaiLu8=
|
||||
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
||||
github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ=
|
||||
github.com/sagernet/sing-quic v0.1.7 h1:SC45rAnvQ9BuyO0V186OdDScMBitmZo0XcM9LBYRUW8=
|
||||
github.com/sagernet/sing-quic v0.1.7/go.mod h1:wUg1Z6AGKeJguruZo0lhrie3dqPiRCKaidLAbK2ttEs=
|
||||
github.com/sagernet/sing-quic v0.1.9-beta.1 h1:rCmgLUq2d4EA643EAvjbfUYYVMPCss0GpmS4pJCT2Lw=
|
||||
github.com/sagernet/sing-quic v0.1.9-beta.1/go.mod h1:F4AXCZiwtRtYdLUTjVMO6elTpA/lLJe17sFlHhHmDVw=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
||||
github.com/sagernet/sing-tun v0.2.0 h1:/WloeRTWvwKIuiIvY+HVJaaZsTGb3XqJXZUbn6wVhz4=
|
||||
github.com/sagernet/sing-tun v0.2.0/go.mod h1:vJHzPAbwFUHxdFHUFQlH+Fb4rT3K4/SHODdMLU1rrQI=
|
||||
github.com/sagernet/sing-tun v0.2.2-beta.3 h1:LEzxRkn10iicWdZAlIKtc0/G9hgzrt/WMZSkRtsbzCw=
|
||||
github.com/sagernet/sing-tun v0.2.2-beta.3/go.mod h1:TaUYOzyBWK43Si6TadJ4gc7fj2iYZ7kxcp6CzzKey3E=
|
||||
github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc=
|
||||
github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA=
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||
@@ -764,6 +775,10 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490/go.mod
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/transip/gotransip/v6 v6.20.0 h1:AuvwyOZ51f2brzMbTqlRy/wmaM3kF7Vx5Wds8xcDflY=
|
||||
github.com/transip/gotransip/v6 v6.20.0/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c=
|
||||
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf h1:7PflaKRtU4np/epFxRXlFhlzLXZzKFrH5/I4so5Ove0=
|
||||
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf/go.mod h1:CLUSJbazqETbaR+i0YAhXBICV9TrKH93pziccMhmhpM=
|
||||
github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301 h1:d/Wr/Vl/wiJHc3AHYbYs5I3PucJvRuw3SvbmlIRf+oM=
|
||||
github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301/go.mod h1:ntmMHL/xPq1WLeKiw8p/eRATaae6PiVRNipHFJxI8PM=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
@@ -785,16 +800,16 @@ github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1Y
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs=
|
||||
github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI=
|
||||
github.com/wyx2685/sing-box_mod v0.0.0-20240122043647-0854bf9053ab h1:8nEgSATWz3rd8Slefbcby6jTsmPmY8r6fhbETjbyYZQ=
|
||||
github.com/wyx2685/sing-box_mod v0.0.0-20240122043647-0854bf9053ab/go.mod h1:YZrQibfEgKg7P4qQbcc7ZMFCFJk3WyExsh1QVN+EV04=
|
||||
github.com/wyx2685/sing-box_mod v0.0.4 h1:fEZnkrtUwqJS/6M3drSdv9RXyRvhnuD2UV6rK5U6rLA=
|
||||
github.com/wyx2685/sing-box_mod v0.0.4/go.mod h1:Q5C14BKQoRzkJ+JPGuMdffHZEoOrlU1zsiBkTtfPoA0=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19 h1:capMfFYRgH9BCLd6A3Er/cH3A9Nz3CU2KwxwOQZIePI=
|
||||
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
|
||||
github.com/xtls/xray-core v1.8.8-0.20240120214034-53de58fad3a0 h1:IfUeBSlGlxy9BachfXhZu1nwNwrwLuuE/ZXjzUB0KeU=
|
||||
github.com/xtls/xray-core v1.8.8-0.20240120214034-53de58fad3a0/go.mod h1:gAw8EAQONCedbAfKz3j9kaaCIl1RhE33vIOY2ePecg0=
|
||||
github.com/xtls/xray-core v1.8.8-0.20240219151643-ad3dd3df56b9 h1:dcDLQ7Bg8ql4Dxy3bLm8e1jeecBus710h8zdU2fhZ/8=
|
||||
github.com/xtls/xray-core v1.8.8-0.20240219151643-ad3dd3df56b9/go.mod h1:6s2tcNd+RI/BF9T+7ccuCrby8RM+EeNdvoE/I9Lr28I=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f h1:cG+ehPRJSlqljSufLf1KXeXpUd1dLNjnzA18mZcB/O0=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997 h1:2wzke3JH7OtN20WsNDZx2VH/TCmsbqtDEbXzjF+i05E=
|
||||
@@ -819,8 +834,8 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
@@ -857,15 +872,15 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo=
|
||||
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -884,6 +899,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
@@ -920,19 +936,20 @@ golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
|
||||
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
|
||||
golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
|
||||
golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -999,22 +1016,24 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@@ -1024,6 +1043,7 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
@@ -1063,6 +1083,7 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
@@ -1128,8 +1149,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
|
||||
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
|
||||
google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
|
||||
google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
||||
@@ -120,15 +120,15 @@ func (l *Limiter) UpdateDynamicSpeedLimit(tag, uuid string, limit int, expire ti
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Limiter) CheckLimit(email string, ip string, isTcp bool) (Bucket *ratelimit.Bucket, Reject bool) {
|
||||
func (l *Limiter) CheckLimit(uuid string, ip string, isTcp bool) (Bucket *ratelimit.Bucket, Reject bool) {
|
||||
// ip and conn limiter
|
||||
if l.ConnLimiter.AddConnCount(email, ip, isTcp) {
|
||||
if l.ConnLimiter.AddConnCount(uuid, ip, isTcp) {
|
||||
return nil, true
|
||||
}
|
||||
// check and gen speed limit Bucket
|
||||
nodeLimit := l.SpeedLimit
|
||||
userLimit := 0
|
||||
if v, ok := l.UserLimitInfo.Load(email); ok {
|
||||
if v, ok := l.UserLimitInfo.Load(uuid); ok {
|
||||
u := v.(*UserLimitInfo)
|
||||
if u.ExpireTime < time.Now().Unix() && u.ExpireTime != 0 {
|
||||
if u.SpeedLimit != 0 {
|
||||
@@ -136,7 +136,7 @@ func (l *Limiter) CheckLimit(email string, ip string, isTcp bool) (Bucket *ratel
|
||||
u.DynamicSpeedLimit = 0
|
||||
u.ExpireTime = 0
|
||||
} else {
|
||||
l.UserLimitInfo.Delete(email)
|
||||
l.UserLimitInfo.Delete(uuid)
|
||||
}
|
||||
} else {
|
||||
userLimit = determineSpeedLimit(u.SpeedLimit, u.DynamicSpeedLimit)
|
||||
@@ -145,10 +145,10 @@ func (l *Limiter) CheckLimit(email string, ip string, isTcp bool) (Bucket *ratel
|
||||
|
||||
// Store online user for device limit
|
||||
ipMap := new(sync.Map)
|
||||
uid := l.UUIDtoUID[email]
|
||||
uid := l.UUIDtoUID[uuid]
|
||||
ipMap.Store(ip, uid)
|
||||
// If any device is online
|
||||
if v, ok := l.UserOnlineIP.LoadOrStore(email, ipMap); ok {
|
||||
if v, ok := l.UserOnlineIP.LoadOrStore(uuid, ipMap); ok {
|
||||
ipMap := v.(*sync.Map)
|
||||
// If this is a new ip
|
||||
if _, ok := ipMap.LoadOrStore(ip, uid); !ok {
|
||||
@@ -163,10 +163,10 @@ func (l *Limiter) CheckLimit(email string, ip string, isTcp bool) (Bucket *ratel
|
||||
limit := int64(determineSpeedLimit(nodeLimit, userLimit)) * 1000000 / 8 // If you need the Speed limit
|
||||
if limit > 0 {
|
||||
Bucket = ratelimit.NewBucketWithQuantum(time.Second, limit, limit) // Byte/s
|
||||
if v, ok := l.SpeedLimiter.LoadOrStore(email, Bucket); ok {
|
||||
if v, ok := l.SpeedLimiter.LoadOrStore(uuid, Bucket); ok {
|
||||
return v.(*ratelimit.Bucket), false
|
||||
} else {
|
||||
l.SpeedLimiter.Store(email, Bucket)
|
||||
l.SpeedLimiter.Store(uuid, Bucket)
|
||||
return Bucket, false
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user