add singbox core(just started)

This commit is contained in:
Yuzuki616
2023-07-28 09:13:11 +08:00
parent 989a9a1ba0
commit 2812b366b3
28 changed files with 1110 additions and 105 deletions

View File

@@ -1,68 +0,0 @@
package hy
import (
"sync"
"sync/atomic"
)
type UserTrafficCounter struct {
counters map[string]*counters
lock sync.RWMutex
}
type counters struct {
UpCounter atomic.Int64
DownCounter atomic.Int64
//ConnGauge atomic.Int64
}
func NewUserTrafficCounter() *UserTrafficCounter {
return &UserTrafficCounter{
counters: map[string]*counters{},
}
}
func (c *UserTrafficCounter) getCounters(auth string) *counters {
c.lock.RLock()
cts, ok := c.counters[auth]
c.lock.RUnlock()
if !ok {
cts = &counters{}
c.counters[auth] = cts
}
return cts
}
func (c *UserTrafficCounter) Rx(auth string, n int) {
cts := c.getCounters(auth)
cts.DownCounter.Add(int64(n))
}
func (c *UserTrafficCounter) Tx(auth string, n int) {
cts := c.getCounters(auth)
cts.UpCounter.Add(int64(n))
}
func (c *UserTrafficCounter) IncConn(_ string) {
/*cts := c.getCounters(auth)
cts.ConnGauge.Add(1)*/
return
}
func (c *UserTrafficCounter) DecConn(_ string) {
/*cts := c.getCounters(auth)
cts.ConnGauge.Add(1)*/
return
}
func (c *UserTrafficCounter) Reset(auth string) {
cts := c.getCounters(auth)
cts.UpCounter.Store(0)
cts.DownCounter.Store(0)
}
func (c *UserTrafficCounter) Delete(auth string) {
c.lock.Lock()
delete(c.counters, auth)
c.lock.Unlock()
}

View File

@@ -1,7 +0,0 @@
package hy
import "testing"
func TestUserTrafficCounter_Rx(t *testing.T) {
}

View File

@@ -3,6 +3,7 @@ package hy
import (
"errors"
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/limiter"

View File

@@ -3,11 +3,12 @@ package hy
import (
"crypto/tls"
"errors"
"github.com/Yuzuki616/hysteria/core/utils"
rdns "github.com/folbricht/routedns"
"net"
"net/url"
"strings"
"github.com/Yuzuki616/hysteria/core/utils"
rdns "github.com/folbricht/routedns"
)
var errInvalidSyntax = errors.New("invalid syntax")

View File

@@ -9,6 +9,8 @@ import (
"sync/atomic"
"time"
"github.com/Yuzuki616/V2bX/common/counter"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/limiter"
@@ -34,7 +36,7 @@ var serverPacketConnFuncFactoryMap = map[string]pktconns.ServerPacketConnFuncFac
type Server struct {
tag string
l *limiter.Limiter
counter *UserTrafficCounter
counter *counter.TrafficCounter
users sync.Map
running atomic.Bool
*cs.Server
@@ -122,7 +124,7 @@ func (s *Server) runServer(node *panel.NodeInfo, c *conf.ControllerConfig) error
// ACL
var aclEngine *acl.Engine
// Prometheus
s.counter = NewUserTrafficCounter()
s.counter = counter.NewTrafficCounter()
// Packet conn
pktConnFuncFactory := serverPacketConnFuncFactoryMap[""]
if pktConnFuncFactory == nil {

View File

@@ -2,13 +2,14 @@ package hy
import (
"encoding/base64"
"log"
"testing"
"time"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/limiter"
"github.com/sirupsen/logrus"
"log"
"testing"
"time"
)
func TestServer(t *testing.T) {

View File

@@ -3,6 +3,7 @@ package hy
import (
"encoding/base64"
"errors"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/core"
)
@@ -23,8 +24,8 @@ func (h *Hy) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64)
v, _ := h.servers.Load(tag)
s := v.(*Server)
auth := base64.StdEncoding.EncodeToString([]byte(uuid))
up = s.counter.getCounters(auth).UpCounter.Load()
down = s.counter.getCounters(auth).DownCounter.Load()
up = s.counter.GetCounter(auth).UpCounter.Load()
down = s.counter.GetCounter(auth).DownCounter.Load()
if reset {
s.counter.Reset(auth)
}

5
core/imports/sing.go Normal file
View File

@@ -0,0 +1,5 @@
//go:build sing
package imports
import _ "github.com/Yuzuki616/V2bX/core/sing"

79
core/sing/box_outbound.go Normal file
View File

@@ -0,0 +1,79 @@
package sing
import (
"strings"
"github.com/inazumav/sing-box/adapter"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
)
func (b *Box) startOutbounds() error {
outboundTags := make(map[adapter.Outbound]string)
outbounds := make(map[string]adapter.Outbound)
for i, outboundToStart := range b.outbounds {
var outboundTag string
if outboundToStart.Tag() == "" {
outboundTag = F.ToString(i)
} else {
outboundTag = outboundToStart.Tag()
}
if _, exists := outbounds[outboundTag]; exists {
return E.New("outbound tag ", outboundTag, " duplicated")
}
outboundTags[outboundToStart] = outboundTag
outbounds[outboundTag] = outboundToStart
}
started := make(map[string]bool)
for {
canContinue := false
startOne:
for _, outboundToStart := range b.outbounds {
outboundTag := outboundTags[outboundToStart]
if started[outboundTag] {
continue
}
dependencies := outboundToStart.Dependencies()
for _, dependency := range dependencies {
if !started[dependency] {
continue startOne
}
}
started[outboundTag] = true
canContinue = true
if starter, isStarter := outboundToStart.(common.Starter); isStarter {
b.logger.Trace("initializing outbound/", outboundToStart.Type(), "[", outboundTag, "]")
err := starter.Start()
if err != nil {
return E.Cause(err, "initialize outbound/", outboundToStart.Type(), "[", outboundTag, "]")
}
}
}
if len(started) == len(b.outbounds) {
break
}
if canContinue {
continue
}
currentOutbound := common.Find(b.outbounds, func(it adapter.Outbound) bool {
return !started[outboundTags[it]]
})
var lintOutbound func(oTree []string, oCurrent adapter.Outbound) error
lintOutbound = func(oTree []string, oCurrent adapter.Outbound) error {
problemOutboundTag := common.Find(oCurrent.Dependencies(), func(it string) bool {
return !started[it]
})
if common.Contains(oTree, problemOutboundTag) {
return E.New("circular outbound dependency: ", strings.Join(oTree, " -> "), " -> ", problemOutboundTag)
}
problemOutbound := outbounds[problemOutboundTag]
if problemOutbound == nil {
return E.New("dependency[", problemOutbound, "] not found for outbound[", outboundTags[oCurrent], "]")
}
return lintOutbound(append(oTree, problemOutboundTag), problemOutbound)
}
return lintOutbound([]string{outboundTags[currentOutbound]}, currentOutbound)
}
return nil
}

36
core/sing/debug_go118.go Normal file
View File

@@ -0,0 +1,36 @@
//go:build !go1.19
package sing
import (
"runtime/debug"
"github.com/inazumav/sing-box/common/dialer/conntrack"
"github.com/inazumav/sing-box/option"
)
func applyDebugOptions(options option.DebugOptions) {
applyDebugListenOption(options)
if options.GCPercent != nil {
debug.SetGCPercent(*options.GCPercent)
}
if options.MaxStack != nil {
debug.SetMaxStack(*options.MaxStack)
}
if options.MaxThreads != nil {
debug.SetMaxThreads(*options.MaxThreads)
}
if options.PanicOnFault != nil {
debug.SetPanicOnFault(*options.PanicOnFault)
}
if options.TraceBack != "" {
debug.SetTraceback(options.TraceBack)
}
if options.MemoryLimit != 0 {
// debug.SetMemoryLimit(int64(options.MemoryLimit))
conntrack.MemoryLimit = int64(options.MemoryLimit)
}
if options.OOMKiller != nil {
conntrack.KillerEnabled = *options.OOMKiller
}
}

36
core/sing/debug_go119.go Normal file
View File

@@ -0,0 +1,36 @@
//go:build go1.19
package sing
import (
"runtime/debug"
"github.com/inazumav/sing-box/common/dialer/conntrack"
"github.com/inazumav/sing-box/option"
)
func applyDebugOptions(options option.DebugOptions) {
applyDebugListenOption(options)
if options.GCPercent != nil {
debug.SetGCPercent(*options.GCPercent)
}
if options.MaxStack != nil {
debug.SetMaxStack(*options.MaxStack)
}
if options.MaxThreads != nil {
debug.SetMaxThreads(*options.MaxThreads)
}
if options.PanicOnFault != nil {
debug.SetPanicOnFault(*options.PanicOnFault)
}
if options.TraceBack != "" {
debug.SetTraceback(options.TraceBack)
}
if options.MemoryLimit != 0 {
debug.SetMemoryLimit(int64(options.MemoryLimit))
conntrack.MemoryLimit = int64(options.MemoryLimit)
}
if options.OOMKiller != nil {
conntrack.KillerEnabled = *options.OOMKiller
}
}

67
core/sing/debug_http.go Normal file
View File

@@ -0,0 +1,67 @@
package sing
import (
"net/http"
"net/http/pprof"
"runtime"
"runtime/debug"
"github.com/inazumav/sing-box/common/badjson"
"github.com/inazumav/sing-box/common/json"
"github.com/inazumav/sing-box/log"
"github.com/inazumav/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
"github.com/dustin/go-humanize"
"github.com/go-chi/chi/v5"
)
var debugHTTPServer *http.Server
func applyDebugListenOption(options option.DebugOptions) {
if debugHTTPServer != nil {
debugHTTPServer.Close()
debugHTTPServer = nil
}
if options.Listen == "" {
return
}
r := chi.NewMux()
r.Route("/debug", func(r chi.Router) {
r.Get("/gc", func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(http.StatusNoContent)
go debug.FreeOSMemory()
})
r.Get("/memory", func(writer http.ResponseWriter, request *http.Request) {
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
var memObject badjson.JSONObject
memObject.Put("heap", humanize.IBytes(memStats.HeapInuse))
memObject.Put("stack", humanize.IBytes(memStats.StackInuse))
memObject.Put("idle", humanize.IBytes(memStats.HeapIdle-memStats.HeapReleased))
memObject.Put("goroutines", runtime.NumGoroutine())
memObject.Put("rss", rusageMaxRSS())
encoder := json.NewEncoder(writer)
encoder.SetIndent("", " ")
encoder.Encode(memObject)
})
r.HandleFunc("/pprof", pprof.Index)
r.HandleFunc("/pprof/*", pprof.Index)
r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
r.HandleFunc("/pprof/profile", pprof.Profile)
r.HandleFunc("/pprof/symbol", pprof.Symbol)
r.HandleFunc("/pprof/trace", pprof.Trace)
})
debugHTTPServer = &http.Server{
Addr: options.Listen,
Handler: r,
}
go func() {
err := debugHTTPServer.ListenAndServe()
if err != nil && !E.IsClosed(err) {
log.Error(E.Cause(err, "serve debug HTTP server"))
}
}()
}

23
core/sing/debug_linux.go Normal file
View File

@@ -0,0 +1,23 @@
package sing
import (
"runtime"
"syscall"
)
func rusageMaxRSS() float64 {
ru := syscall.Rusage{}
err := syscall.Getrusage(syscall.RUSAGE_SELF, &ru)
if err != nil {
return 0
}
rss := float64(ru.Maxrss)
if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
rss /= 1 << 20 // ru_maxrss is bytes on darwin
} else {
// ru_maxrss is kilobytes elsewhere (linux, openbsd, etc)
rss /= 1 << 10
}
return rss
}

7
core/sing/debug_stub.go Normal file
View File

@@ -0,0 +1,7 @@
//go:build !linux
package sing
func rusageMaxRSS() float64 {
return -1
}

58
core/sing/hook.go Normal file
View File

@@ -0,0 +1,58 @@
package sing
import (
"net"
"github.com/Yuzuki616/V2bX/common/counter"
"github.com/inazumav/sing-box/adapter"
"github.com/inazumav/sing-box/log"
N "github.com/sagernet/sing/common/network"
)
type HookServer struct {
hooker *Hooker
}
func NewHookServer(logger log.Logger) *HookServer {
return &HookServer{
hooker: &Hooker{
logger: logger,
counter: make(map[string]*counter.TrafficCounter),
},
}
}
func (h *HookServer) Start() error {
return nil
}
func (h *HookServer) Close() error {
return nil
}
func (h *HookServer) StatsService() adapter.V2RayStatsService {
return h.hooker
}
func (h *HookServer) Hooker() *Hooker {
return h.hooker
}
type Hooker struct {
logger log.Logger
counter map[string]*counter.TrafficCounter
}
func (h *Hooker) RoutedConnection(inbound string, outbound string, user string, conn net.Conn) net.Conn {
if c, ok := h.counter[inbound]; ok {
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 {
return counter.NewPacketConnCounter(conn, c.GetCounter(user))
}
return conn
}

133
core/sing/node.go Normal file
View File

@@ -0,0 +1,133 @@
package sing
import (
"context"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"fmt"
"net/netip"
"net/url"
"strconv"
"strings"
"github.com/inazumav/sing-box/inbound"
F "github.com/sagernet/sing/common/format"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/goccy/go-json"
"github.com/inazumav/sing-box/option"
)
type WsNetworkConfig struct {
Path string `json:"path"`
}
func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.ControllerConfig) (option.Inbound, error) {
addr, _ := netip.ParseAddr("0.0.0.0")
listen := option.ListenOptions{
Listen: (*option.ListenAddress)(&addr),
ListenPort: uint16(info.Port),
}
tls := option.InboundTLSOptions{
Enabled: info.Tls,
CertificatePath: c.CertConfig.CertFile,
KeyPath: c.CertConfig.KeyFile,
ServerName: info.ServerName,
}
in := option.Inbound{
Tag: tag,
}
switch info.Type {
case "v2ray":
in.Type = "vmess"
t := option.V2RayTransportOptions{
Type: info.Network,
}
switch info.Network {
case "tcp":
case "ws":
network := WsNetworkConfig{}
err := json.Unmarshal(info.NetworkSettings, &network)
if err != nil {
return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err)
}
var u *url.URL
u, err = url.Parse(network.Path)
if err != nil {
return option.Inbound{}, fmt.Errorf("parse path error: %s", err)
}
ed, _ := strconv.Atoi(u.Query().Get("ed"))
t.WebsocketOptions = option.V2RayWebsocketOptions{
Path: u.Path,
EarlyDataHeaderName: "Sec-WebSocket-Protocol",
MaxEarlyData: uint32(ed),
}
case "grpc":
t.GRPCOptions = option.V2RayGRPCOptions{
ServiceName: info.ServerName,
}
}
in.VMessOptions = option.VMessInboundOptions{
ListenOptions: listen,
TLS: &tls,
Transport: &t,
}
case "shadowsocks":
in.Type = "shadowsocks"
p := make([]byte, 32)
_, _ = rand.Read(p)
randomPasswd := hex.EncodeToString(p)
if strings.Contains(info.Cipher, "2022") {
randomPasswd = base64.StdEncoding.EncodeToString([]byte(randomPasswd))
}
in.ShadowsocksOptions = option.ShadowsocksInboundOptions{
ListenOptions: listen,
Method: info.Cipher,
Password: info.ServerKey,
Users: []option.ShadowsocksUser{
{
Password: randomPasswd,
},
},
}
}
return in, nil
}
func (b *Box) AddNode(tag string, info *panel.NodeInfo, config *conf.ControllerConfig) error {
c, err := getInboundOptions(tag, info, config)
if err != nil {
return err
}
in, err := inbound.New(
context.Background(),
b.router,
b.logFactory.NewLogger(F.ToString("inbound/", c.Type, "[", tag, "]")),
c,
nil,
)
b.inbounds[tag] = in
err = in.Start()
if err != nil {
return fmt.Errorf("start inbound error: %s", err)
}
err = b.router.AddInbound(in)
if err != nil {
return fmt.Errorf("add inbound error: %s", err)
}
return nil
}
func (b *Box) DelNode(tag string) error {
err := b.inbounds[tag].Close()
if err != nil {
return fmt.Errorf("close inbound error: %s", err)
}
err = b.router.DelInbound(tag)
if err != nil {
return fmt.Errorf("delete inbound error: %s", err)
}
return nil
}

263
core/sing/sing.go Normal file
View File

@@ -0,0 +1,263 @@
package sing
import (
"context"
"fmt"
"io"
"os"
"runtime/debug"
"time"
"github.com/Yuzuki616/V2bX/conf"
vCore "github.com/Yuzuki616/V2bX/core"
"github.com/inazumav/sing-box/adapter"
"github.com/inazumav/sing-box/inbound"
"github.com/inazumav/sing-box/log"
"github.com/inazumav/sing-box/option"
"github.com/inazumav/sing-box/outbound"
"github.com/inazumav/sing-box/route"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
)
var _ adapter.Service = (*Box)(nil)
type Box struct {
createdAt time.Time
router adapter.Router
inbounds map[string]adapter.Inbound
outbounds []adapter.Outbound
logFactory log.Factory
logger log.ContextLogger
hookServer *HookServer
done chan struct{}
}
func init() {
vCore.RegisterCore("sing", New)
}
func New(_ *conf.CoreConfig) (vCore.Core, error) {
options := option.Options{}
ctx := context.Background()
createdAt := time.Now()
experimentalOptions := common.PtrValueOrDefault(options.Experimental)
applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
var defaultLogWriter io.Writer
logFactory, err := log.New(log.Options{
Context: ctx,
Options: common.PtrValueOrDefault(options.Log),
DefaultWriter: defaultLogWriter,
BaseTime: createdAt,
})
if err != nil {
return nil, E.Cause(err, "create log factory")
}
router, err := route.NewRouter(
ctx,
logFactory,
common.PtrValueOrDefault(options.Route),
common.PtrValueOrDefault(options.DNS),
common.PtrValueOrDefault(options.NTP),
options.Inbounds,
nil,
)
if err != nil {
return nil, E.Cause(err, "parse route options")
}
inbounds := make([]adapter.Inbound, len(options.Inbounds))
inMap := make(map[string]adapter.Inbound, len(inbounds))
outbounds := make([]adapter.Outbound, 0, len(options.Outbounds))
for i, inboundOptions := range options.Inbounds {
var in adapter.Inbound
var tag string
if inboundOptions.Tag != "" {
tag = inboundOptions.Tag
} else {
tag = F.ToString(i)
}
in, err = inbound.New(
ctx,
router,
logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
inboundOptions,
nil,
)
if err != nil {
return nil, E.Cause(err, "parse inbound[", i, "]")
}
inbounds[i] = in
inMap[inboundOptions.Tag] = in
}
for i, outboundOptions := range options.Outbounds {
var out adapter.Outbound
var tag string
if outboundOptions.Tag != "" {
tag = outboundOptions.Tag
} else {
tag = F.ToString(i)
}
out, err = outbound.New(
ctx,
router,
logFactory.NewLogger(F.ToString("outbound/", outboundOptions.Type, "[", tag, "]")),
tag,
outboundOptions)
if err != nil {
return nil, E.Cause(err, "parse outbound[", i, "]")
}
outbounds = append(outbounds, out)
}
err = router.Initialize(inbounds, outbounds, func() adapter.Outbound {
out, oErr := outbound.New(ctx, router, logFactory.NewLogger("outbound/direct"), "direct", option.Outbound{Type: "direct", Tag: "default"})
common.Must(oErr)
outbounds = append(outbounds, out)
return out
})
if err != nil {
return nil, err
}
server := NewHookServer(logFactory.NewLogger("Hook-Server"))
if err != nil {
return nil, E.Cause(err, "create v2ray api server")
}
router.SetV2RayServer(server)
return &Box{
router: router,
inbounds: inMap,
outbounds: outbounds,
createdAt: createdAt,
logFactory: logFactory,
logger: logFactory.Logger(),
hookServer: server,
done: make(chan struct{}),
}, nil
}
func (b *Box) PreStart() error {
err := b.preStart()
if err != nil {
// TODO: remove catch error
defer func() {
v := recover()
if v != nil {
log.Error(E.Cause(err, "origin error"))
debug.PrintStack()
panic("panic on early close: " + fmt.Sprint(v))
}
}()
b.Close()
return err
}
b.logger.Info("sing-box pre-started (", F.Seconds(time.Since(b.createdAt).Seconds()), "s)")
return nil
}
func (b *Box) Start() error {
err := b.start()
if err != nil {
// TODO: remove catch error
defer func() {
v := recover()
if v != nil {
log.Error(E.Cause(err, "origin error"))
debug.PrintStack()
panic("panic on early close: " + fmt.Sprint(v))
}
}()
b.Close()
return err
}
b.logger.Info("sing-box started (", F.Seconds(time.Since(b.createdAt).Seconds()), "s)")
return nil
}
func (b *Box) preStart() error {
err := b.startOutbounds()
if err != nil {
return err
}
return b.router.Start()
}
func (b *Box) start() error {
err := b.preStart()
if err != nil {
return err
}
for i, in := range b.inbounds {
var tag string
if in.Tag() == "" {
tag = F.ToString(i)
} else {
tag = in.Tag()
}
b.logger.Trace("initializing inbound/", in.Type(), "[", tag, "]")
err = in.Start()
if err != nil {
return E.Cause(err, "initialize inbound/", in.Type(), "[", tag, "]")
}
}
return nil
}
func (b *Box) postStart() error {
for serviceName, service := range b.outbounds {
if lateService, isLateService := service.(adapter.PostStarter); isLateService {
b.logger.Trace("post-starting ", service)
err := lateService.PostStart()
if err != nil {
return E.Cause(err, "post-start ", serviceName)
}
}
}
return nil
}
func (b *Box) Close() error {
select {
case <-b.done:
return os.ErrClosed
default:
close(b.done)
}
var errors error
for i, in := range b.inbounds {
b.logger.Trace("closing inbound/", in.Type(), "[", i, "]")
errors = E.Append(errors, in.Close(), func(err error) error {
return E.Cause(err, "close inbound/", in.Type(), "[", i, "]")
})
}
for i, out := range b.outbounds {
b.logger.Trace("closing outbound/", out.Type(), "[", i, "]")
errors = E.Append(errors, common.Close(out), func(err error) error {
return E.Cause(err, "close outbound/", out.Type(), "[", i, "]")
})
}
b.logger.Trace("closing router")
if err := common.Close(b.router); err != nil {
errors = E.Append(errors, err, func(err error) error {
return E.Cause(err, "close router")
})
}
b.logger.Trace("closing log factory")
if err := common.Close(b.logFactory); err != nil {
errors = E.Append(errors, err, func(err error) error {
return E.Cause(err, "close log factory")
})
}
return errors
}
func (b *Box) Router() adapter.Router {
return b.router
}
func (b *Box) Protocols() []string {
return []string{
"v2ray",
"shadowsocks",
}
}

75
core/sing/user.go Normal file
View File

@@ -0,0 +1,75 @@
package sing
import (
"errors"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/core"
"github.com/inazumav/sing-box/inbound"
"github.com/inazumav/sing-box/option"
)
func (b *Box) AddUsers(p *core.AddUsersParams) (added int, err error) {
switch p.NodeInfo.Type {
case "v2ray":
us := make([]option.VMessUser, len(p.UserInfo))
for i := range p.UserInfo {
us[i] = option.VMessUser{
Name: p.UserInfo[i].Uuid,
UUID: p.UserInfo[i].Uuid,
}
}
err = b.inbounds[p.Tag].(*inbound.VMess).AddUsers(us)
if err != nil {
return 0, err
}
case "shadowsocks":
us := make([]option.ShadowsocksUser, len(p.UserInfo))
for i := range p.UserInfo {
us[i] = option.ShadowsocksUser{
Name: p.UserInfo[i].Uuid,
Password: p.UserInfo[i].Uuid,
}
}
}
return len(p.UserInfo), err
}
func (b *Box) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) {
if c, ok := b.hookServer.Hooker().counter[tag]; ok {
up = c.GetUpCount(uuid)
down = c.GetDownCount(uuid)
if reset {
c.Reset(uuid)
}
return
}
return 0, 0
}
type UserDeleter interface {
DelUsers(uuid []string) error
}
func (b *Box) DelUsers(users []panel.UserInfo, tag string) error {
var del UserDeleter
if i, ok := b.inbounds[tag]; ok {
switch i.Type() {
case "vmess":
del = i.(*inbound.VMess)
case "shadowsocks":
del = i.(*inbound.ShadowsocksMulti)
}
} else {
return errors.New("the inbound not found")
}
uuids := make([]string, len(users))
for i := range users {
uuids[i] = users[i].Uuid
}
err := del.DelUsers(uuids)
if err != nil {
return err
}
return nil
}

View File

@@ -7,10 +7,11 @@
package dispatcher
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (

View File

@@ -70,5 +70,5 @@ import (
_ "github.com/xtls/xray-core/transport/internet/headers/tls"
_ "github.com/xtls/xray-core/transport/internet/headers/utp"
_ "github.com/xtls/xray-core/transport/internet/headers/wechat"
_ "github.com/xtls/xray-core/transport/internet/headers/wireguard"
//_ "github.com/xtls/xray-core/transport/internet/headers/wireguard"
)

View File

@@ -3,6 +3,7 @@ package xray
import (
"context"
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/xtls/xray-core/core"

View File

@@ -2,6 +2,7 @@ package xray
import (
"fmt"
conf2 "github.com/Yuzuki616/V2bX/conf"
"github.com/goccy/go-json"
"github.com/xtls/xray-core/common/net"

View File

@@ -2,13 +2,14 @@ package xray
import (
"encoding/base64"
"strings"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/common/format"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/shadowsocks"
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
"strings"
)
func buildSSUsers(tag string, userInfo []panel.UserInfo, cypher string, serverKey string) (users []*protocol.User) {