fix some bugs

This commit is contained in:
yuzuki999 2023-06-09 12:36:49 +08:00
parent 42bb7bc90f
commit 9827d442d5
14 changed files with 103 additions and 80 deletions

View File

@ -23,18 +23,18 @@ A V2board node server based on multi core, modified from XrayR.
## 功能介绍 ## 功能介绍
| 功能 | v2ray | trojan | shadowsocks | | 功能 | v2ray | trojan | shadowsocks | hysteria |
|-----------|-------|--------|-------------| |-----------|-------|--------|-------------|----------|
| 自动申请tls证书 | √ | √ | √ | | 自动申请tls证书 | √ | √ | √ | √ |
| 自动续签tls证书 | √ | √ | √ | | 自动续签tls证书 | √ | √ | √ | √ |
| 在线人数统计 | √ | √ | √ | | 在线人数统计 | √ | √ | √ | √ |
| 审计规则 | √ | √ | √ | | 审计规则 | √ | √ | √ | |
| 自定义DNS | √ | √ | √ | | 自定义DNS | √ | √ | √ | √ |
| 在线IP数限制 | √ | √ | √ | | 在线IP数限制 | √ | √ | √ | |
| 连接数限制 | √ | √ | √ | | 连接数限制 | √ | √ | √ | |
| 跨节点IP数限制 | √ | √ | √ | | 跨节点IP数限制 | √ | √ | √ | |
| 按照用户限速 | √ | √ | √ | | 按照用户限速 | √ | √ | √ | |
| 动态限速(未测试) | √ | √ | √ | | 动态限速(未测试) | √ | √ | √ | |
## TODO ## TODO

View File

@ -11,7 +11,9 @@ import (
) )
type CommonNodeRsp struct { type CommonNodeRsp struct {
Host string `json:"host"`
ServerPort int `json:"server_port"` ServerPort int `json:"server_port"`
ServerName string `json:"server_name"`
Routes []Route `json:"routes"` Routes []Route `json:"routes"`
BaseConfig BaseConfig `json:"base_config"` BaseConfig BaseConfig `json:"base_config"`
} }
@ -54,11 +56,11 @@ type NodeInfo struct {
Id int Id int
Type string Type string
Rules []*regexp.Regexp Rules []*regexp.Regexp
Host string
Port int Port int
Network string Network string
NetworkSettings json.RawMessage NetworkSettings json.RawMessage
Tls bool Tls bool
Host string
ServerName string ServerName string
UpMbps int UpMbps int
DownMbps int DownMbps int
@ -75,16 +77,14 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
if err = c.checkResponse(r, path, err); err != nil { if err = c.checkResponse(r, path, err); err != nil {
return return
} }
err = json.Unmarshal(r.Body(), &node)
if err != nil {
return
}
if c.etag == r.Header().Get("ETag") { // node info not changed if c.etag == r.Header().Get("ETag") { // node info not changed
return nil, nil return nil, nil
} }
// parse common params // parse common params
node.Id = c.NodeId node = &NodeInfo{
node.Type = c.NodeType Id: c.NodeId,
Type: c.NodeType,
}
common := CommonNodeRsp{} common := CommonNodeRsp{}
err = json.Unmarshal(r.Body(), &common) err = json.Unmarshal(r.Body(), &common)
if err != nil { 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.PullInterval = intervalToTime(common.BaseConfig.PullInterval)
node.PushInterval = intervalToTime(common.BaseConfig.PushInterval) node.PushInterval = intervalToTime(common.BaseConfig.PushInterval)
// parse protocol params // parse protocol params

View File

@ -43,9 +43,9 @@ func New(c *conf.ApiConfig) (*Client, error) {
client.SetBaseURL(c.APIHost) client.SetBaseURL(c.APIHost)
// Check node type // Check node type
c.NodeType = strings.ToLower(c.NodeType) c.NodeType = strings.ToLower(c.NodeType)
if c.NodeType != "v2ray" && switch c.NodeType {
c.NodeType != "trojan" && case "v2ray", "trojan", "shadowsocks", "hysteria":
c.NodeType != "shadowsocks" { default:
return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType) return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType)
} }
// Create Key for each requests // Create Key for each requests

View File

@ -20,7 +20,7 @@ func (c *Client) checkResponse(res *resty.Response, path string, err error) erro
} }
if res.StatusCode() != 200 { if res.StatusCode() != 200 {
body := res.Body() 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 return nil
} }

View File

@ -25,7 +25,7 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s
case "v2ray": case "v2ray":
err = buildV2ray(config, nodeInfo, in) err = buildV2ray(config, nodeInfo, in)
case "trojan": case "trojan":
err = buildTrojan(config, nodeInfo, in) err = buildTrojan(config, in)
case "shadowsocks": case "shadowsocks":
err = buildShadowsocks(config, nodeInfo, in) err = buildShadowsocks(config, nodeInfo, in)
default: default:
@ -104,7 +104,6 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s
// Support ProxyProtocol for any transport protocol // Support ProxyProtocol for any transport protocol
if *in.StreamSetting.Network != "tcp" && if *in.StreamSetting.Network != "tcp" &&
*in.StreamSetting.Network != "ws" && *in.StreamSetting.Network != "ws" &&
*in.StreamSetting.Network != "" &&
config.EnableProxyProtocol { config.EnableProxyProtocol {
socketConfig := &coreConf.SocketConfig{ socketConfig := &coreConf.SocketConfig{
AcceptProxyProtocol: config.EnableProxyProtocol, AcceptProxyProtocol: config.EnableProxyProtocol,
@ -177,7 +176,7 @@ func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound
return nil 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" inbound.Protocol = "trojan"
if config.XrayOptions.EnableFallback { if config.XrayOptions.EnableFallback {
// Set fallback // Set fallback
@ -196,10 +195,7 @@ func buildTrojan(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inboun
s := []byte("{}") s := []byte("{}")
inbound.Settings = (*json.RawMessage)(&s) inbound.Settings = (*json.RawMessage)(&s)
} }
if nodeInfo.Network == "" { t := coreConf.TransportProtocol("tcp")
nodeInfo.Network = "tcp"
}
t := coreConf.TransportProtocol(nodeInfo.Network)
inbound.StreamSetting = &coreConf.StreamConfig{Network: &t} inbound.StreamSetting = &coreConf.StreamConfig{Network: &t}
return nil return nil
} }

View File

@ -15,15 +15,15 @@ type ApiConfig struct {
} }
type ControllerConfig struct { type ControllerConfig struct {
DisableUploadTraffic bool `yaml:"DisableUploadTraffic"` DisableUploadTraffic bool `yaml:"DisableUploadTraffic"`
DisableGetRule bool `yaml:"DisableGetRule"` DisableGetRule bool `yaml:"DisableGetRule"`
ListenIP string `yaml:"ListenIP"` ListenIP string `yaml:"ListenIP"`
SendIP string `yaml:"SendIP"` SendIP string `yaml:"SendIP"`
EnableProxyProtocol bool `yaml:"EnableProxyProtocol"` EnableProxyProtocol bool `yaml:"EnableProxyProtocol"`
XrayOptions *XrayOptions `yaml:"XrayOptions"` XrayOptions XrayOptions `yaml:"XrayOptions"`
HyOptions *HyOptions `yaml:"HyOptions"` HyOptions HyOptions `yaml:"HyOptions"`
LimitConfig LimitConfig `yaml:"LimitConfig"` LimitConfig LimitConfig `yaml:"LimitConfig"`
CertConfig *CertConfig `yaml:"CertConfig"` CertConfig *CertConfig `yaml:"CertConfig"`
} }
type XrayOptions struct { type XrayOptions struct {

View File

@ -1,7 +1,6 @@
package hy package hy
import ( import (
"github.com/apernet/hysteria/core/cs"
"sync" "sync"
"sync/atomic" "sync/atomic"
) )
@ -17,8 +16,10 @@ type counters struct {
//ConnGauge atomic.Int64 //ConnGauge atomic.Int64
} }
func NewUserTrafficCounter() cs.TrafficCounter { func NewUserTrafficCounter() *UserTrafficCounter {
return new(UserTrafficCounter) return &UserTrafficCounter{
counters: map[string]*counters{},
}
} }
func (c *UserTrafficCounter) getCounters(auth string) *counters { func (c *UserTrafficCounter) getCounters(auth string) *counters {

View File

@ -3,15 +3,20 @@ package hy
import ( import (
"fmt" "fmt"
"github.com/Yuzuki616/V2bX/conf" "github.com/Yuzuki616/V2bX/conf"
vCore "github.com/Yuzuki616/V2bX/core"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"sync" "sync"
) )
func init() {
vCore.RegisterCore("hy", NewHy)
}
type Hy struct { type Hy struct {
servers sync.Map servers sync.Map
} }
func New(_ *conf.CoreConfig) (*Hy, error) { func NewHy(_ *conf.CoreConfig) (vCore.Core, error) {
return &Hy{ return &Hy{
servers: sync.Map{}, servers: sync.Map{},
}, nil }, nil

View File

@ -12,6 +12,10 @@ func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.ControllerConfig)
if info.Type != "hysteria" { if info.Type != "hysteria" {
return errors.New("the core not support " + info.Type) 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) s := NewServer(tag)
err := s.runServer(info, c) err := s.runServer(info, c)
if err != nil { if err != nil {

View File

@ -2,7 +2,6 @@ package hy
import ( import (
"crypto/tls" "crypto/tls"
"errors"
"fmt" "fmt"
"github.com/Yuzuki616/V2bX/api/panel" "github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf" "github.com/Yuzuki616/V2bX/conf"
@ -33,7 +32,7 @@ var serverPacketConnFuncFactoryMap = map[string]pktconns.ServerPacketConnFuncFac
type Server struct { type Server struct {
tag string tag string
counter UserTrafficCounter counter *UserTrafficCounter
users sync.Map users sync.Map
running atomic.Bool running atomic.Bool
*cs.Server *cs.Server
@ -46,9 +45,9 @@ func NewServer(tag string) *Server {
} }
func (s *Server) runServer(node *panel.NodeInfo, c *conf.ControllerConfig) error { 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") return errors.New("hy options is not vail")
} }*/
// Resolver // Resolver
if len(c.HyOptions.Resolver) > 0 { if len(c.HyOptions.Resolver) > 0 {
err := setResolver(c.HyOptions.Resolver) err := setResolver(c.HyOptions.Resolver)
@ -136,7 +135,7 @@ func (s *Server) runServer(node *panel.NodeInfo, c *conf.ControllerConfig) error
aclEngine.DefaultAction = acl.ActionDirect aclEngine.DefaultAction = acl.ActionDirect
}*/ }*/
// Prometheus // Prometheus
trafficCounter := NewUserTrafficCounter() s.counter = NewUserTrafficCounter()
// Packet conn // Packet conn
pktConnFuncFactory := serverPacketConnFuncFactoryMap[""] pktConnFuncFactory := serverPacketConnFuncFactoryMap[""]
if pktConnFuncFactory == nil { 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) up, down := SpeedTrans(node.UpMbps, node.DownMbps)
s.Server, err = cs.NewServer(tlsConfig, quicConfig, pktConn, s.Server, err = cs.NewServer(tlsConfig, quicConfig, pktConn,
transport.DefaultServerTransport, up, down, false, aclEngine, 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 { if err != nil {
return fmt.Errorf("new server error: %s", err) 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 return nil
} }
func (s *Server) authByUser(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string, string) { func (s *Server) authByUser(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
if email, ok := s.users.Load(string(auth)); ok { if _, ok := s.users.Load(string(auth)); ok {
return true, email.(string), "Done" return true, "Done"
} }
return false, "", "Failed" return false, "Failed"
} }
func (s *Server) connectFunc(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) { 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 { if !ok {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"src": defaultIPMasker.Mask(addr.String()), "src": defaultIPMasker.Mask(addr.String()),
}).Info("Authentication failed, client rejected") }).Info("Authentication failed, client rejected")
} else { return false, msg
logrus.WithFields(logrus.Fields{
"src": defaultIPMasker.Mask(addr.String()),
"email": email,
}).Info("Client connected")
} }
logrus.WithFields(logrus.Fields{
"src": defaultIPMasker.Mask(addr.String()),
"Uuid": string(auth),
"Tag": s.tag,
}).Info("Client connected")
return ok, msg return ok, msg
} }

View File

@ -3,10 +3,12 @@ package hy
import ( import (
"github.com/Yuzuki616/V2bX/api/panel" "github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf" "github.com/Yuzuki616/V2bX/conf"
"github.com/sirupsen/logrus"
"testing" "testing"
) )
func TestServer(t *testing.T) { func TestServer(t *testing.T) {
logrus.SetLevel(logrus.DebugLevel)
s := NewServer("test") s := NewServer("test")
t.Log(s.runServer(&panel.NodeInfo{ t.Log(s.runServer(&panel.NodeInfo{
Port: 11415, Port: 11415,
@ -15,11 +17,12 @@ func TestServer(t *testing.T) {
HyObfs: "atresssdaaaadd", HyObfs: "atresssdaaaadd",
}, &conf.ControllerConfig{ }, &conf.ControllerConfig{
ListenIP: "127.0.0.1", ListenIP: "127.0.0.1",
HyOptions: &conf.HyOptions{}, HyOptions: conf.HyOptions{},
CertConfig: &conf.CertConfig{ CertConfig: &conf.CertConfig{
CertFile: "../../test_data/1.pem", CertFile: "../../test_data/1.pem",
KeyFile: "../../test_data/1.key", KeyFile: "../../test_data/1.key",
}, },
})) }))
s.users.Store("test1111", struct{}{})
select {} select {}
} }

View File

@ -1,6 +1,7 @@
package hy package hy
import ( import (
"encoding/base64"
"errors" "errors"
"github.com/Yuzuki616/V2bX/core" "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) { func (h *Hy) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) {
s, _ := h.servers.Load(tag) v, _ := h.servers.Load(tag)
c := &s.(*Server).counter s := v.(*Server)
up = c.getCounters(uuid).UpCounter.Load() auth := base64.StdEncoding.EncodeToString([]byte(uuid))
down = c.getCounters(uuid).DownCounter.Load() up = s.counter.getCounters(auth).UpCounter.Load()
down = s.counter.getCounters(uuid).DownCounter.Load()
if reset { if reset {
c.Reset(uuid) s.counter.Reset(uuid)
} }
return return
} }

View File

@ -26,20 +26,24 @@ Nodes:
ControllerConfig: ControllerConfig:
ListenIP: 0.0.0.0 # IP address you want to listen ListenIP: 0.0.0.0 # IP address you want to listen
SendIP: 0.0.0.0 # IP address you want to send pacakage 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 XrayOptions:
DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy EnableDNS: false # Use custom DNS config, Please ensure that you set the dns.json well
EnableTFO: false # Enable TCP Fast Open DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy
EnableVless: false # Enable Vless for V2ray Type EnableTFO: false # Enable TCP Fast Open
EnableXtls: false # Enable xtls-rprx-vision, only vless EnableVless: false # Enable Vless for V2ray Type
EnableProxyProtocol: false # Only works for WebSocket and TCP EnableXtls: false # Enable xtls-rprx-vision, only vless
EnableFallback: false # Only support for Trojan and Vless EnableProxyProtocol: false # Only works for WebSocket and TCP
FallBackConfigs: # Support multiple fallbacks EnableFallback: false # Only support for Trojan and Vless
- SNI: # TLS SNI(Server Name Indication), Empty for any FallBackConfigs: # Support multiple fallbacks
Alpn: # Alpn, Empty for any - SNI: # TLS SNI(Server Name Indication), Empty for any
Path: # HTTP PATH, Empty for any Alpn: # Alpn, Empty for any
Dest: 80 # Required, Destination of fallback, check https://xtls.github.io/config/features/fallback.html for details. Path: # HTTP PATH, Empty for any
ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for dsable 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: LimitConfig:
EnableRealtime: false # Check device limit on real time EnableRealtime: false # Check device limit on real time
SpeedLimit: 0 # Mbps, Local settings will replace remote settings, 0 means disable SpeedLimit: 0 # Mbps, Local settings will replace remote settings, 0 means disable

View File

@ -1,6 +1,7 @@
package node package node
import ( import (
"fmt"
"github.com/Yuzuki616/V2bX/api/panel" "github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf" "github.com/Yuzuki616/V2bX/conf"
vCore "github.com/Yuzuki616/V2bX/core" 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) n.controllers[i] = NewController(core, p, c.ControllerConfig)
err = n.controllers[i].Start() err = n.controllers[i].Start()
if err != nil { 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 return nil