update sing-box support

This commit is contained in:
Yuzuki616 2023-07-29 18:47:47 +08:00
parent 2812b366b3
commit 96493346f9
34 changed files with 418 additions and 297 deletions

View File

@ -1,9 +1,10 @@
package panel
import (
"github.com/Yuzuki616/V2bX/conf"
"log"
"testing"
"github.com/Yuzuki616/V2bX/conf"
)
var client *Client

View File

@ -1,8 +1,11 @@
package counter
import (
"io"
"net"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
@ -10,38 +13,93 @@ import (
)
type ConnCounter struct {
net.Conn
network.ExtendedConn
storage *TrafficStorage
readFunc network.CountFunc
writeFunc network.CountFunc
}
func NewConnCounter(conn net.Conn, s *TrafficStorage) net.Conn {
return &ConnCounter{
Conn: conn,
ExtendedConn: bufio.NewExtendedConn(conn),
storage: s,
readFunc: func(n int64) {
s.DownCounter.Add(n)
},
writeFunc: func(n int64) {
s.UpCounter.Add(n)
},
}
}
func (c *ConnCounter) Read(b []byte) (n int, err error) {
n, err = c.Conn.Read(b)
n, err = c.ExtendedConn.Read(b)
c.storage.DownCounter.Store(int64(n))
return
}
func (c *ConnCounter) Write(b []byte) (n int, err error) {
n, err = c.Conn.Write(b)
n, err = c.ExtendedConn.Write(b)
c.storage.UpCounter.Store(int64(n))
return
}
func (c *ConnCounter) ReadBuffer(buffer *buf.Buffer) error {
err := c.ExtendedConn.ReadBuffer(buffer)
if err != nil {
return err
}
if buffer.Len() > 0 {
c.storage.DownCounter.Add(int64(buffer.Len()))
}
return nil
}
func (c *ConnCounter) WriteBuffer(buffer *buf.Buffer) error {
dataLen := int64(buffer.Len())
err := c.ExtendedConn.WriteBuffer(buffer)
if err != nil {
return err
}
if dataLen > 0 {
c.storage.UpCounter.Add(dataLen)
}
return nil
}
func (c *ConnCounter) UnwrapReader() (io.Reader, []network.CountFunc) {
return c.ExtendedConn, []network.CountFunc{
c.readFunc,
}
}
func (c *ConnCounter) UnwrapWriter() (io.Writer, []network.CountFunc) {
return c.ExtendedConn, []network.CountFunc{
c.writeFunc,
}
}
func (c *ConnCounter) Upstream() any {
return c.ExtendedConn
}
type PacketConnCounter struct {
network.PacketConn
storage *TrafficStorage
readFunc network.CountFunc
writeFunc network.CountFunc
}
func NewPacketConnCounter(conn network.PacketConn, s *TrafficStorage) network.PacketConn {
return &PacketConnCounter{
PacketConn: conn,
storage: s,
readFunc: func(n int64) {
s.DownCounter.Add(n)
},
writeFunc: func(n int64) {
s.UpCounter.Add(n)
},
}
}
@ -55,10 +113,29 @@ func (p *PacketConnCounter) ReadPacket(buff *buf.Buffer) (destination M.Socksadd
}
func (p *PacketConnCounter) WritePacket(buff *buf.Buffer, destination M.Socksaddr) (err error) {
n := buff.Len()
err = p.PacketConn.WritePacket(buff, destination)
if err != nil {
return
}
p.storage.UpCounter.Add(int64(buff.Len()))
if n > 0 {
p.storage.UpCounter.Add(int64(n))
}
return
}
func (p *PacketConnCounter) UnwrapPacketReader() (network.PacketReader, []network.CountFunc) {
return p.PacketConn, []network.CountFunc{
p.readFunc,
}
}
func (p *PacketConnCounter) UnwrapPacketWriter() (network.PacketWriter, []network.CountFunc) {
return p.PacketConn, []network.CountFunc{
p.writeFunc,
}
}
func (p *PacketConnCounter) Upstream() any {
return p.PacketConn
}

View File

@ -52,6 +52,12 @@ func (c *TrafficCounter) GetDownCount(id string) int64 {
return 0
}
func (c *TrafficCounter) Len() int {
c.lock.RLock()
defer c.lock.RUnlock()
return len(c.counters)
}
func (c *TrafficCounter) Reset(id string) {
c.lock.RLock()
cts := c.GetCounter(id)

56
common/rate/conn.go Normal file
View File

@ -0,0 +1,56 @@
package rate
import (
"net"
"github.com/juju/ratelimit"
"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/network"
)
func NewConnRateLimiter(c net.Conn, l *ratelimit.Bucket) *Conn {
return &Conn{
Conn: c,
limiter: l,
}
}
type Conn struct {
net.Conn
limiter *ratelimit.Bucket
}
func (c *Conn) Read(b []byte) (n int, err error) {
c.limiter.Wait(int64(len(b)))
return c.Conn.Read(b)
}
func (c *Conn) Write(b []byte) (n int, err error) {
c.limiter.Wait(int64(len(b)))
return c.Conn.Write(b)
}
type PacketConnCounter struct {
network.PacketConn
limiter *ratelimit.Bucket
}
func NewPacketConnCounter(conn network.PacketConn, l *ratelimit.Bucket) network.PacketConn {
return &PacketConnCounter{
PacketConn: conn,
limiter: l,
}
}
func (p *PacketConnCounter) ReadPacket(buff *buf.Buffer) (destination M.Socksaddr, err error) {
pLen := buff.Len()
destination, err = p.ReadPacket(buff)
p.limiter.Wait(int64(buff.Len() - pLen))
return
}
func (p *PacketConnCounter) WritePacket(buff *buf.Buffer, destination M.Socksaddr) (err error) {
p.limiter.Wait(int64(buff.Len()))
return p.PacketConn.WritePacket(buff, destination)
}

24
conf/cert.go Normal file
View File

@ -0,0 +1,24 @@
package conf
type CertConfig struct {
CertMode string `yaml:"CertMode"` // none, file, http, dns
RejectUnknownSni bool `yaml:"RejectUnknownSni"`
CertDomain string `yaml:"CertDomain"`
CertFile string `yaml:"CertFile"`
KeyFile string `yaml:"KeyFile"`
Provider string `yaml:"Provider"` // alidns, cloudflare, gandi, godaddy....
Email string `yaml:"Email"`
DNSEnv map[string]string `yaml:"DNSEnv"`
RealityConfig *RealityConfig `yaml:"RealityConfig"`
}
type RealityConfig struct {
Dest interface{} `yaml:"Dest" json:"Dest"`
Xver uint64 `yaml:"Xver" json:"Xver"`
ServerNames []string `yaml:"ServerNames" json:"ServerNames"`
PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"`
MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"`
MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"`
MaxTimeDiff uint64 `yaml:"MaxTimeDiff" json:"MaxTimeDiff"`
ShortIds []string `yaml:"ShortIds" json:"ShortIds"`
}

View File

@ -2,9 +2,10 @@ package conf
import (
"fmt"
"gopkg.in/yaml.v3"
"io"
"os"
"gopkg.in/yaml.v3"
)
type Conf struct {
@ -16,15 +17,8 @@ func New() *Conf {
return &Conf{
CoreConfig: CoreConfig{
Type: "xray",
XrayConfig: &XrayConfig{
LogConfig: NewLogConfig(),
AssetPath: "/etc/V2bX/",
DnsConfigPath: "",
InboundConfigPath: "",
OutboundConfigPath: "",
RouteConfigPath: "",
ConnectionConfig: NewConnectionConfig(),
},
XrayConfig: NewXrayConfig(),
SingConfig: NewSingConfig(),
},
NodesConfig: []*NodeConfig{},
}
@ -44,10 +38,5 @@ func (p *Conf) LoadFromPath(filePath string) error {
if err != nil {
return fmt.Errorf("decode config error: %s", err)
}
old := &OldConfig{}
err = yaml.Unmarshal(content, old)
if err == nil {
migrateOldConfig(p, old)
}
return nil
}

View File

@ -2,6 +2,7 @@ package conf
import (
"log"
"strings"
"testing"
)
@ -11,9 +12,6 @@ func TestConf_LoadFromPath(t *testing.T) {
}
func TestConf_Watch(t *testing.T) {
c := New()
log.Println(c.Watch("../example/config.yml.example", func() {
log.Println(1)
}))
select {}
//c := New()
log.Println(strings.Split("aaaa", " "))
}

View File

@ -3,32 +3,5 @@ package conf
type CoreConfig struct {
Type string `yaml:"Type"`
XrayConfig *XrayConfig `yaml:"XrayConfig"`
}
type XrayConfig struct {
LogConfig *LogConfig `yaml:"Log"`
AssetPath string `yaml:"AssetPath"`
DnsConfigPath string `yaml:"DnsConfigPath"`
RouteConfigPath string `yaml:"RouteConfigPath"`
ConnectionConfig *ConnectionConfig `yaml:"ConnectionConfig"`
InboundConfigPath string `yaml:"InboundConfigPath"`
OutboundConfigPath string `yaml:"OutboundConfigPath"`
}
type ConnectionConfig struct {
Handshake uint32 `yaml:"handshake"`
ConnIdle uint32 `yaml:"connIdle"`
UplinkOnly uint32 `yaml:"uplinkOnly"`
DownlinkOnly uint32 `yaml:"downlinkOnly"`
BufferSize int32 `yaml:"bufferSize"`
}
func NewConnectionConfig() *ConnectionConfig {
return &ConnectionConfig{
Handshake: 4,
ConnIdle: 30,
UplinkOnly: 2,
DownlinkOnly: 4,
BufferSize: 64,
}
SingConfig *SingConfig `yaml:"SingConfig"`
}

40
conf/limit.go Normal file
View File

@ -0,0 +1,40 @@
package conf
type LimitConfig struct {
EnableRealtime bool `yaml:"EnableRealtime"`
SpeedLimit int `yaml:"SpeedLimit"`
IPLimit int `yaml:"DeviceLimit"`
ConnLimit int `yaml:"ConnLimit"`
EnableIpRecorder bool `yaml:"EnableIpRecorder"`
IpRecorderConfig *IpReportConfig `yaml:"IpRecorderConfig"`
EnableDynamicSpeedLimit bool `yaml:"EnableDynamicSpeedLimit"`
DynamicSpeedLimitConfig *DynamicSpeedLimitConfig `yaml:"DynamicSpeedLimitConfig"`
}
type RecorderConfig struct {
Url string `yaml:"Url"`
Token string `yaml:"Token"`
Timeout int `yaml:"Timeout"`
}
type RedisConfig struct {
Address string `yaml:"Address"`
Password string `yaml:"Password"`
Db int `yaml:"Db"`
Expiry int `json:"Expiry"`
}
type IpReportConfig struct {
Periodic int `yaml:"Periodic"`
Type string `yaml:"Type"`
RecorderConfig *RecorderConfig `yaml:"RecorderConfig"`
RedisConfig *RedisConfig `yaml:"RedisConfig"`
EnableIpSync bool `yaml:"EnableIpSync"`
}
type DynamicSpeedLimitConfig struct {
Periodic int `yaml:"Periodic"`
Traffic int64 `yaml:"Traffic"`
SpeedLimit int `yaml:"SpeedLimit"`
ExpireTime int `yaml:"ExpireTime"`
}

View File

@ -1,15 +0,0 @@
package conf
type LogConfig struct {
Level string `yaml:"Level"`
AccessPath string `yaml:"AccessPath"`
ErrorPath string `yaml:"ErrorPath"`
}
func NewLogConfig() *LogConfig {
return &LogConfig{
Level: "warning",
AccessPath: "",
ErrorPath: "",
}
}

View File

@ -2,7 +2,7 @@ package conf
type NodeConfig struct {
ApiConfig *ApiConfig `yaml:"ApiConfig"`
ControllerConfig *ControllerConfig `yaml:"ControllerConfig"`
Options *Options `yaml:"Options"`
}
type ApiConfig struct {
@ -13,100 +13,3 @@ type ApiConfig struct {
Timeout int `yaml:"Timeout"`
RuleListPath string `yaml:"RuleListPath"`
}
type ControllerConfig struct {
ListenIP string `yaml:"ListenIP"`
SendIP string `yaml:"SendIP"`
XrayOptions XrayOptions `yaml:"XrayOptions"`
HyOptions HyOptions `yaml:"HyOptions"`
LimitConfig LimitConfig `yaml:"LimitConfig"`
CertConfig *CertConfig `yaml:"CertConfig"`
}
type RealityConfig struct {
Dest interface{} `yaml:"Dest" json:"Dest"`
Xver uint64 `yaml:"Xver" json:"Xver"`
ServerNames []string `yaml:"ServerNames" json:"ServerNames"`
PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"`
MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"`
MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"`
MaxTimeDiff uint64 `yaml:"MaxTimeDiff" json:"MaxTimeDiff"`
ShortIds []string `yaml:"ShortIds" json:"ShortIds"`
}
type XrayOptions struct {
EnableProxyProtocol bool `yaml:"EnableProxyProtocol"`
EnableDNS bool `yaml:"EnableDNS"`
DNSType string `yaml:"DNSType"`
EnableUot bool `yaml:"EnableUot"`
EnableTFO bool `yaml:"EnableTFO"`
DisableIVCheck bool `yaml:"DisableIVCheck"`
DisableSniffing bool `yaml:"DisableSniffing"`
EnableFallback bool `yaml:"EnableFallback"`
FallBackConfigs []FallBackConfig `yaml:"FallBackConfigs"`
}
type HyOptions struct {
Resolver string `yaml:"Resolver"`
ResolvePreference string `yaml:"ResolvePreference"`
SendDevice string `yaml:"SendDevice"`
}
type LimitConfig struct {
EnableRealtime bool `yaml:"EnableRealtime"`
SpeedLimit int `yaml:"SpeedLimit"`
IPLimit int `yaml:"DeviceLimit"`
ConnLimit int `yaml:"ConnLimit"`
EnableIpRecorder bool `yaml:"EnableIpRecorder"`
IpRecorderConfig *IpReportConfig `yaml:"IpRecorderConfig"`
EnableDynamicSpeedLimit bool `yaml:"EnableDynamicSpeedLimit"`
DynamicSpeedLimitConfig *DynamicSpeedLimitConfig `yaml:"DynamicSpeedLimitConfig"`
}
type FallBackConfig struct {
SNI string `yaml:"SNI"`
Alpn string `yaml:"Alpn"`
Path string `yaml:"Path"`
Dest string `yaml:"Dest"`
ProxyProtocolVer uint64 `yaml:"ProxyProtocolVer"`
}
type RecorderConfig struct {
Url string `yaml:"Url"`
Token string `yaml:"Token"`
Timeout int `yaml:"Timeout"`
}
type RedisConfig struct {
Address string `yaml:"Address"`
Password string `yaml:"Password"`
Db int `yaml:"Db"`
Expiry int `json:"Expiry"`
}
type IpReportConfig struct {
Periodic int `yaml:"Periodic"`
Type string `yaml:"Type"`
RecorderConfig *RecorderConfig `yaml:"RecorderConfig"`
RedisConfig *RedisConfig `yaml:"RedisConfig"`
EnableIpSync bool `yaml:"EnableIpSync"`
}
type DynamicSpeedLimitConfig struct {
Periodic int `yaml:"Periodic"`
Traffic int64 `yaml:"Traffic"`
SpeedLimit int `yaml:"SpeedLimit"`
ExpireTime int `yaml:"ExpireTime"`
}
type CertConfig struct {
CertMode string `yaml:"CertMode"` // none, file, http, dns
RejectUnknownSni bool `yaml:"RejectUnknownSni"`
CertDomain string `yaml:"CertDomain"`
CertFile string `yaml:"CertFile"`
KeyFile string `yaml:"KeyFile"`
Provider string `yaml:"Provider"` // alidns, cloudflare, gandi, godaddy....
Email string `yaml:"Email"`
DNSEnv map[string]string `yaml:"DNSEnv"`
RealityConfig *RealityConfig `yaml:"RealityConfig"`
}

View File

@ -1,81 +0,0 @@
package conf
import "log"
type OldConfig struct {
NodesConfig []*struct {
ApiConfig *OldApiConfig `yaml:"ApiConfig"`
ControllerConfig *OldControllerConfig `yaml:"ControllerConfig"`
} `yaml:"Nodes"`
}
type OldControllerConfig struct {
ListenIP string `yaml:"ListenIP"`
SendIP string `yaml:"SendIP"`
EnableDNS bool `yaml:"EnableDNS"`
DNSType string `yaml:"DNSType"`
DisableUploadTraffic bool `yaml:"DisableUploadTraffic"`
DisableGetRule bool `yaml:"DisableGetRule"`
EnableProxyProtocol bool `yaml:"EnableProxyProtocol"`
EnableFallback bool `yaml:"EnableFallback"`
DisableIVCheck bool `yaml:"DisableIVCheck"`
DisableSniffing bool `yaml:"DisableSniffing"`
FallBackConfigs []*FallBackConfig `yaml:"FallBackConfigs"`
EnableIpRecorder bool `yaml:"EnableIpRecorder"`
IpRecorderConfig *IpReportConfig `yaml:"IpRecorderConfig"`
EnableDynamicSpeedLimit bool `yaml:"EnableDynamicSpeedLimit"`
DynamicSpeedLimitConfig *DynamicSpeedLimitConfig `yaml:"DynamicSpeedLimitConfig"`
CertConfig *CertConfig `yaml:"CertConfig"`
}
type OldApiConfig struct {
APIHost string `yaml:"ApiHost"`
NodeID int `yaml:"NodeID"`
Key string `yaml:"ApiKey"`
NodeType string `yaml:"NodeType"`
EnableVless bool `yaml:"EnableVless"`
Timeout int `yaml:"Timeout"`
SpeedLimit int `yaml:"SpeedLimit"`
DeviceLimit int `yaml:"DeviceLimit"`
RuleListPath string `yaml:"RuleListPath"`
DisableCustomConfig bool `yaml:"DisableCustomConfig"`
}
func migrateOldConfig(c *Conf, old *OldConfig) {
changed := false
for i, n := range c.NodesConfig {
if i >= len(old.NodesConfig) {
break
}
// limit config
if old.NodesConfig[i].ApiConfig.SpeedLimit != 0 {
n.ControllerConfig.LimitConfig.SpeedLimit = old.NodesConfig[i].ApiConfig.SpeedLimit
changed = true
}
if old.NodesConfig[i].ApiConfig.DeviceLimit != 0 {
n.ControllerConfig.LimitConfig.IPLimit = old.NodesConfig[i].ApiConfig.DeviceLimit
changed = true
}
if old.NodesConfig[i].ControllerConfig.EnableDynamicSpeedLimit {
n.ControllerConfig.LimitConfig.EnableDynamicSpeedLimit = true
changed = true
}
if old.NodesConfig[i].ControllerConfig.DynamicSpeedLimitConfig != nil {
n.ControllerConfig.LimitConfig.DynamicSpeedLimitConfig =
old.NodesConfig[i].ControllerConfig.DynamicSpeedLimitConfig
changed = true
}
if old.NodesConfig[i].ControllerConfig.EnableIpRecorder {
n.ControllerConfig.LimitConfig.EnableIpRecorder = true
changed = true
}
if old.NodesConfig[i].ControllerConfig.IpRecorderConfig != nil {
n.ControllerConfig.LimitConfig.IpRecorderConfig =
old.NodesConfig[i].ControllerConfig.IpRecorderConfig
changed = true
}
}
if changed {
log.Println("Warning: This config file is old.")
}
}

36
conf/option.go Normal file
View File

@ -0,0 +1,36 @@
package conf
type Options struct {
ListenIP string `yaml:"ListenIP"`
SendIP string `yaml:"SendIP"`
LimitConfig LimitConfig `yaml:"LimitConfig"`
CertConfig *CertConfig `yaml:"CertConfig"`
XrayOptions XrayOptions `yaml:"-"`
HyOptions HyOptions `yaml:"-"`
}
type XrayOptions struct {
EnableProxyProtocol bool `yaml:"EnableProxyProtocol"`
EnableDNS bool `yaml:"EnableDNS"`
DNSType string `yaml:"DNSType"`
EnableUot bool `yaml:"EnableUot"`
EnableTFO bool `yaml:"EnableTFO"`
DisableIVCheck bool `yaml:"DisableIVCheck"`
DisableSniffing bool `yaml:"DisableSniffing"`
EnableFallback bool `yaml:"EnableFallback"`
FallBackConfigs []FallBackConfig `yaml:"FallBackConfigs"`
}
type FallBackConfig struct {
SNI string `yaml:"SNI"`
Alpn string `yaml:"Alpn"`
Path string `yaml:"Path"`
Dest string `yaml:"Dest"`
ProxyProtocolVer uint64 `yaml:"ProxyProtocolVer"`
}
type HyOptions struct {
Resolver string `yaml:"Resolver"`
ResolvePreference string `yaml:"ResolvePreference"`
SendDevice string `yaml:"SendDevice"`
}

22
conf/sing.go Normal file
View File

@ -0,0 +1,22 @@
package conf
type SingConfig struct {
LogConfig SingLogConfig `yaml:"LogConfig"`
OriginalPath string `yaml:"OriginalPath"`
}
type SingLogConfig struct {
Disabled bool `yaml:"Disable"`
Level string `yaml:"Level"`
Output string `yaml:"Output"`
Timestamp bool `yaml:"Timestamp"`
}
func NewSingConfig() *SingConfig {
return &SingConfig{
LogConfig: SingLogConfig{
Level: "error",
Timestamp: true,
},
}
}

47
conf/xray.go Normal file
View File

@ -0,0 +1,47 @@
package conf
type XrayConfig struct {
LogConfig *XrayLogConfig `yaml:"Log"`
AssetPath string `yaml:"AssetPath"`
DnsConfigPath string `yaml:"DnsConfigPath"`
RouteConfigPath string `yaml:"RouteConfigPath"`
ConnectionConfig *XrayConnectionConfig `yaml:"XrayConnectionConfig"`
InboundConfigPath string `yaml:"InboundConfigPath"`
OutboundConfigPath string `yaml:"OutboundConfigPath"`
}
type XrayLogConfig struct {
Level string `yaml:"Level"`
AccessPath string `yaml:"AccessPath"`
ErrorPath string `yaml:"ErrorPath"`
}
type XrayConnectionConfig struct {
Handshake uint32 `yaml:"handshake"`
ConnIdle uint32 `yaml:"connIdle"`
UplinkOnly uint32 `yaml:"uplinkOnly"`
DownlinkOnly uint32 `yaml:"downlinkOnly"`
BufferSize int32 `yaml:"bufferSize"`
}
func NewXrayConfig() *XrayConfig {
return &XrayConfig{
LogConfig: &XrayLogConfig{
Level: "warning",
AccessPath: "",
ErrorPath: "",
},
AssetPath: "/etc/V2bX/",
DnsConfigPath: "",
InboundConfigPath: "",
OutboundConfigPath: "",
RouteConfigPath: "",
ConnectionConfig: &XrayConnectionConfig{
Handshake: 4,
ConnIdle: 30,
UplinkOnly: 2,
DownlinkOnly: 4,
BufferSize: 64,
},
}
}

View File

@ -9,7 +9,7 @@ import (
"github.com/Yuzuki616/V2bX/limiter"
)
func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.ControllerConfig) error {
func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.Options) error {
if info.Type != "hysteria" {
return errors.New("the core not support " + info.Type)
}

View File

@ -49,7 +49,7 @@ func NewServer(tag string, l *limiter.Limiter) *Server {
}
}
func (s *Server) runServer(node *panel.NodeInfo, c *conf.ControllerConfig) error {
func (s *Server) runServer(node *panel.NodeInfo, c *conf.Options) error {
/*if c.HyOptions == nil {
return errors.New("hy options is not vail")
}*/

View File

@ -22,7 +22,7 @@ func TestServer(t *testing.T) {
UpMbps: 100,
DownMbps: 100,
HyObfs: "atresssdaaaadd",
}, &conf.ControllerConfig{
}, &conf.Options{
ListenIP: "127.0.0.1",
HyOptions: conf.HyOptions{},
CertConfig: &conf.CertConfig{
@ -36,7 +36,7 @@ func TestServer(t *testing.T) {
time.Sleep(10 * time.Second)
auth := base64.StdEncoding.EncodeToString([]byte("test1111"))
log.Println(auth)
log.Println(s.counter.getCounters(auth).UpCounter.Load())
log.Println(s.counter.GetUpCount(auth))
}
}()
select {}

View File

@ -7,14 +7,14 @@ import (
type AddUsersParams struct {
Tag string
Config *conf.ControllerConfig
Config *conf.Options
UserInfo []panel.UserInfo
NodeInfo *panel.NodeInfo
}
type Core interface {
Start() error
Close() error
AddNode(tag string, info *panel.NodeInfo, config *conf.ControllerConfig) error
AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error
DelNode(tag string) error
AddUsers(p *AddUsersParams) (added int, err error)
GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64)

View File

@ -39,7 +39,7 @@ func isSupported(protocol string, protocols []string) bool {
return false
}
func (s *Selector) AddNode(tag string, info *panel.NodeInfo, config *conf.ControllerConfig) error {
func (s *Selector) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error {
for i := range s.cores {
if !isSupported(info.Type, s.cores[i].Protocols()) {
continue

View File

@ -2,6 +2,12 @@ package sing
import (
"net"
"strings"
"sync"
"github.com/Yuzuki616/V2bX/common/rate"
"github.com/Yuzuki616/V2bX/limiter"
"github.com/Yuzuki616/V2bX/common/counter"
"github.com/inazumav/sing-box/adapter"
@ -17,7 +23,7 @@ func NewHookServer(logger log.Logger) *HookServer {
return &HookServer{
hooker: &Hooker{
logger: logger,
counter: make(map[string]*counter.TrafficCounter),
counter: sync.Map{},
},
}
}
@ -40,19 +46,37 @@ func (h *HookServer) Hooker() *Hooker {
type Hooker struct {
logger log.Logger
counter map[string]*counter.TrafficCounter
counter sync.Map
}
func (h *Hooker) RoutedConnection(inbound string, outbound string, user string, conn net.Conn) net.Conn {
if c, ok := h.counter[inbound]; ok {
l, err := limiter.GetLimiter(inbound)
if err != nil {
log.Error("get limiter for ", inbound, " error: ", err)
}
ip, _, _ := strings.Cut(conn.RemoteAddr().String(), ":")
if b, r := l.CheckLimit(user, ip, true); r {
conn.Close()
h.logger.Error("[", inbound, "] ", "Limited ", user, " by ip or conn")
return conn
} else if b != nil {
conn = rate.NewConnRateLimiter(conn, b)
}
if c, ok := h.counter.Load(inbound); ok {
return counter.NewConnCounter(conn, c.(*counter.TrafficCounter).GetCounter(user))
} else {
c := counter.NewTrafficCounter()
h.counter.Store(inbound, c)
return counter.NewConnCounter(conn, c.GetCounter(user))
}
return conn
}
func (h *Hooker) RoutedPacketConnection(inbound string, outbound string, user string, conn N.PacketConn) N.PacketConn {
if c, ok := h.counter[inbound]; ok {
if c, ok := h.counter.Load(inbound); ok {
return counter.NewPacketConnCounter(conn, c.(*counter.TrafficCounter).GetCounter(user))
} else {
c := counter.NewTrafficCounter()
h.counter.Store(inbound, c)
return counter.NewPacketConnCounter(conn, c.GetCounter(user))
}
return conn
}

View File

@ -22,11 +22,16 @@ import (
type WsNetworkConfig struct {
Path string `json:"path"`
Headers map[string]string `json:"headers"`
}
func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.ControllerConfig) (option.Inbound, error) {
addr, _ := netip.ParseAddr("0.0.0.0")
func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (option.Inbound, error) {
addr, err := netip.ParseAddr(c.ListenIP)
if err != nil {
return option.Inbound{}, fmt.Errorf("the listen ip not vail")
}
listen := option.ListenOptions{
//ProxyProtocol: true,
Listen: (*option.ListenAddress)(&addr),
ListenPort: uint16(info.Port),
}
@ -47,6 +52,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.ControllerConfi
}
switch info.Network {
case "tcp":
t.Type = ""
case "ws":
network := WsNetworkConfig{}
err := json.Unmarshal(info.NetworkSettings, &network)
@ -59,14 +65,22 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.ControllerConfi
return option.Inbound{}, fmt.Errorf("parse path error: %s", err)
}
ed, _ := strconv.Atoi(u.Query().Get("ed"))
h := make(map[string]option.Listable[string], len(network.Headers))
for k, v := range network.Headers {
h[k] = option.Listable[string]{
v,
}
}
t.WebsocketOptions = option.V2RayWebsocketOptions{
Path: u.Path,
EarlyDataHeaderName: "Sec-WebSocket-Protocol",
MaxEarlyData: uint32(ed),
Headers: h,
}
case "grpc":
t.GRPCOptions = option.V2RayGRPCOptions{
ServiceName: info.ServerName,
err := json.Unmarshal(info.NetworkSettings, &t.GRPCOptions)
if err != nil {
return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err)
}
}
in.VMessOptions = option.VMessInboundOptions{
@ -96,7 +110,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.ControllerConfi
return in, nil
}
func (b *Box) AddNode(tag string, info *panel.NodeInfo, config *conf.ControllerConfig) error {
func (b *Box) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error {
c, err := getInboundOptions(tag, info, config)
if err != nil {
return err

View File

@ -39,8 +39,14 @@ func init() {
vCore.RegisterCore("sing", New)
}
func New(_ *conf.CoreConfig) (vCore.Core, error) {
func New(c *conf.CoreConfig) (vCore.Core, error) {
options := option.Options{}
options.Log = &option.LogOptions{
Disabled: c.SingConfig.LogConfig.Disabled,
Level: c.SingConfig.LogConfig.Level,
Timestamp: c.SingConfig.LogConfig.Timestamp,
Output: c.SingConfig.LogConfig.Output,
}
ctx := context.Background()
createdAt := time.Now()
experimentalOptions := common.PtrValueOrDefault(options.Experimental)

View File

@ -4,6 +4,7 @@ import (
"errors"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/common/counter"
"github.com/Yuzuki616/V2bX/core"
"github.com/inazumav/sing-box/inbound"
"github.com/inazumav/sing-box/option"
@ -36,7 +37,8 @@ func (b *Box) AddUsers(p *core.AddUsersParams) (added int, err error) {
}
func (b *Box) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) {
if c, ok := b.hookServer.Hooker().counter[tag]; ok {
if v, ok := b.hookServer.Hooker().counter.Load(tag); ok {
c := v.(*counter.TrafficCounter)
up = c.GetUpCount(uuid)
down = c.GetDownCount(uuid)
if reset {

View File

@ -17,7 +17,7 @@ import (
)
// BuildInbound build Inbound config for different protocol
func buildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag string) (*core.InboundHandlerConfig, error) {
func buildInbound(config *conf.Options, nodeInfo *panel.NodeInfo, tag string) (*core.InboundHandlerConfig, error) {
in := &coreConf.InboundDetourConfig{}
// Set network protocol
t := coreConf.TransportProtocol(nodeInfo.Network)
@ -150,7 +150,7 @@ func buildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s
return in.Build()
}
func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error {
func buildV2ray(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error {
if nodeInfo.ExtraConfig.EnableVless == "true" {
//Set vless
inbound.Protocol = "vless"
@ -213,7 +213,7 @@ func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound
return nil
}
func buildTrojan(config *conf.ControllerConfig, inbound *coreConf.InboundDetourConfig) error {
func buildTrojan(config *conf.Options, inbound *coreConf.InboundDetourConfig) error {
inbound.Protocol = "trojan"
if config.XrayOptions.EnableFallback {
// Set fallback
@ -237,7 +237,7 @@ func buildTrojan(config *conf.ControllerConfig, inbound *coreConf.InboundDetourC
return nil
}
func buildShadowsocks(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error {
func buildShadowsocks(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error {
inbound.Protocol = "shadowsocks"
settings := &coreConf.ShadowsocksServerConfig{
Cipher: nodeInfo.Cipher,

View File

@ -11,7 +11,7 @@ import (
"github.com/xtls/xray-core/features/outbound"
)
func (c *Core) AddNode(tag string, info *panel.NodeInfo, config *conf.ControllerConfig) error {
func (c *Core) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error {
inboundConfig, err := buildInbound(config, info, tag)
if err != nil {
return fmt.Errorf("build inbound error: %s", err)

View File

@ -11,7 +11,7 @@ import (
)
// BuildOutbound build freedom outbund config for addoutbound
func buildOutbound(config *conf2.ControllerConfig, tag string) (*core.OutboundHandlerConfig, error) {
func buildOutbound(config *conf2.Options, tag string) (*core.OutboundHandlerConfig, error) {
outboundDetourConfig := &conf.OutboundDetourConfig{}
outboundDetourConfig.Protocol = "freedom"
outboundDetourConfig.Tag = tag

View File

@ -39,7 +39,7 @@ func New(c *conf.CoreConfig) (vCore.Core, error) {
return &Core{Server: getCore(c.XrayConfig)}, nil
}
func parseConnectionConfig(c *conf.ConnectionConfig) (policy *coreConf.Policy) {
func parseConnectionConfig(c *conf.XrayConnectionConfig) (policy *coreConf.Policy) {
policy = &coreConf.Policy{
StatsUserUplink: true,
StatsUserDownlink: true,

2
go.mod
View File

@ -15,7 +15,7 @@ require (
github.com/go-resty/resty/v2 v2.7.0
github.com/goccy/go-json v0.10.2
github.com/hashicorp/go-multierror v1.1.1
github.com/inazumav/sing-box v0.0.0-20230728005925-1df6eb0f5bf7
github.com/inazumav/sing-box v0.0.0-20230728123002-eb2ba58e499a
github.com/juju/ratelimit v1.0.2
github.com/oschwald/geoip2-golang v1.9.0
github.com/sagernet/sing v0.2.9

6
go.sum
View File

@ -379,10 +379,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df h1:MZf03xP9WdakyXhOWuAD5uPK3wHh96wCsqe3hCMKh8E=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
github.com/inazumav/sing-box v0.0.0-20230728005628-9c73947a55ad h1:Ho7F+U1n41dX6c+3TjojaCj1NjBlaaCa1Vjtll9BVW4=
github.com/inazumav/sing-box v0.0.0-20230728005628-9c73947a55ad/go.mod h1:W91us/coe3lvl5jCtw2n6acyagpRbOO16h1IV3/0nrc=
github.com/inazumav/sing-box v0.0.0-20230728005925-1df6eb0f5bf7 h1:fHFY6wVkFNFmL+LXVnU+zvrEoULqbZ1eVYCoKsb6/dQ=
github.com/inazumav/sing-box v0.0.0-20230728005925-1df6eb0f5bf7/go.mod h1:W91us/coe3lvl5jCtw2n6acyagpRbOO16h1IV3/0nrc=
github.com/inazumav/sing-box v0.0.0-20230728123002-eb2ba58e499a h1:/FGmhOCu6LYt8zd6DpMEvuHlPnUPMr0zziyJkuU1wVI=
github.com/inazumav/sing-box v0.0.0-20230728123002-eb2ba58e499a/go.mod h1:W91us/coe3lvl5jCtw2n6acyagpRbOO16h1IV3/0nrc=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=

View File

@ -26,14 +26,14 @@ type Controller struct {
renewCertPeriodic *task.Task
dynamicSpeedLimitPeriodic *task.Task
onlineIpReportPeriodic *task.Task
*conf.ControllerConfig
*conf.Options
}
// NewController return a Node controller with default parameters.
func NewController(server vCore.Core, api *panel.Client, config *conf.ControllerConfig) *Controller {
func NewController(server vCore.Core, api *panel.Client, config *conf.Options) *Controller {
controller := &Controller{
server: server,
ControllerConfig: config,
Options: config,
apiClient: api,
}
return controller
@ -71,13 +71,13 @@ func (c *Controller) Start() error {
}
}
// Add new tag
err = c.server.AddNode(c.tag, node, c.ControllerConfig)
err = c.server.AddNode(c.tag, node, c.Options)
if err != nil {
return fmt.Errorf("add new node error: %s", err)
}
added, err := c.server.AddUsers(&vCore.AddUsersParams{
Tag: c.tag,
Config: c.ControllerConfig,
Config: c.Options,
UserInfo: c.userList,
NodeInfo: node,
})

View File

@ -2,6 +2,7 @@ package node
import (
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
vCore "github.com/Yuzuki616/V2bX/core"
@ -23,7 +24,7 @@ func (n *Node) Start(nodes []*conf.NodeConfig, core vCore.Core) error {
return err
}
// Register controller service
n.controllers[i] = NewController(core, p, c.ControllerConfig)
n.controllers[i] = NewController(core, p, c.Options)
err = n.controllers[i].Start()
if err != nil {
return fmt.Errorf("start node controller [%s-%s-%d] error: %s",

View File

@ -100,7 +100,7 @@ func (c *Controller) nodeInfoMonitor() (err error) {
}
}
// add new node
err = c.server.AddNode(c.tag, newNodeInfo, c.ControllerConfig)
err = c.server.AddNode(c.tag, newNodeInfo, c.Options)
if err != nil {
log.WithFields(log.Fields{
"tag": c.tag,
@ -110,7 +110,7 @@ func (c *Controller) nodeInfoMonitor() (err error) {
}
_, err = c.server.AddUsers(&vCore.AddUsersParams{
Tag: c.tag,
Config: c.ControllerConfig,
Config: c.Options,
UserInfo: c.userList,
NodeInfo: newNodeInfo,
})
@ -168,7 +168,7 @@ func (c *Controller) nodeInfoMonitor() (err error) {
// have added users
_, err = c.server.AddUsers(&vCore.AddUsersParams{
Tag: c.tag,
Config: c.ControllerConfig,
Config: c.Options,
UserInfo: added,
})
if err != nil {