update sing-box core v1.11

This commit is contained in:
wyx2685
2024-12-13 06:22:44 +09:00
parent 7dbe5fda85
commit 981e59b836
8 changed files with 168 additions and 250 deletions

View File

@@ -6,8 +6,6 @@ import (
"net"
"sync"
"github.com/sagernet/sing-box/common/urltest"
"github.com/InazumaV/V2bX/common/format"
"github.com/InazumaV/V2bX/common/rate"
@@ -17,14 +15,11 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/log"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service"
)
var _ adapter.ClashServer = (*HookServer)(nil)
var _ adapter.ConnectionTracker = (*HookServer)(nil)
type HookServer struct {
ctx context.Context
urlTestHistory *urltest.HistoryStorage
EnableConnClear bool
counter sync.Map
connClears sync.Map
@@ -61,65 +56,30 @@ func (h *HookServer) ModeList() []string {
return nil
}
func NewHookServer(ctx context.Context, enableClear bool) *HookServer {
func NewHookServer(enableClear bool) *HookServer {
server := &HookServer{
ctx: ctx,
EnableConnClear: enableClear,
counter: sync.Map{},
connClears: sync.Map{},
}
server.urlTestHistory = service.PtrFromContext[urltest.HistoryStorage](ctx)
if server.urlTestHistory == nil {
server.urlTestHistory = urltest.NewHistoryStorage()
}
return server
}
func (h *HookServer) Start() error {
return nil
}
func (h *HookServer) Close() error {
h.urlTestHistory.Close()
return nil
}
func (h *HookServer) PreStart() error {
return nil
}
func (h *HookServer) RoutedConnection(_ context.Context, conn net.Conn, m adapter.InboundContext, _ adapter.Rule) (net.Conn, adapter.Tracker) {
t := &Tracker{}
func (h *HookServer) RoutedConnection(_ context.Context, conn net.Conn, m adapter.InboundContext, _ adapter.Rule, _ adapter.Outbound) net.Conn {
l, err := limiter.GetLimiter(m.Inbound)
if err != nil {
log.Warn("get limiter for ", m.Inbound, " error: ", err)
return conn, t
}
if l.CheckDomainRule(m.Domain) {
conn.Close()
log.Error("[", m.Inbound, "] ",
"Limited ", m.User, " access to ", m.Domain, " by domain rule")
return conn, t
}
if l.CheckProtocolRule(m.Protocol) {
conn.Close()
log.Error("[", m.Inbound, "] ",
"Limited ", m.User, " use ", m.Domain, " by protocol rule")
return conn, t
return conn
}
ip := m.Source.Addr.String()
if b, r := l.CheckLimit(format.UserTag(m.Inbound, m.User), ip, true, true); r {
conn.Close()
log.Error("[", m.Inbound, "] ", "Limited ", m.User, " by ip or conn")
return conn, t
return conn
} else if b != nil {
conn = rate.NewConnRateLimiter(conn, b)
}
t.AddLeave(func() {
l.ConnLimiter.DelConnCount(m.User, ip)
})
if h.EnableConnClear {
var key int
cc := &ConnClear{
conns: map[int]io.Closer{
0: conn,
@@ -127,50 +87,32 @@ func (h *HookServer) RoutedConnection(_ context.Context, conn net.Conn, m adapte
}
if v, ok := h.connClears.LoadOrStore(m.Inbound+m.User, cc); ok {
cc = v.(*ConnClear)
key = cc.AddConn(conn)
}
t.AddLeave(func() {
cc.DelConn(key)
})
}
if c, ok := h.counter.Load(m.Inbound); ok {
return counter.NewConnCounter(conn, c.(*counter.TrafficCounter).GetCounter(m.User)), t
return counter.NewConnCounter(conn, c.(*counter.TrafficCounter).GetCounter(m.User))
} else {
c := counter.NewTrafficCounter()
h.counter.Store(m.Inbound, c)
return counter.NewConnCounter(conn, c.GetCounter(m.User)), t
return counter.NewConnCounter(conn, c.GetCounter(m.User))
}
}
func (h *HookServer) RoutedPacketConnection(_ context.Context, conn N.PacketConn, m adapter.InboundContext, _ adapter.Rule) (N.PacketConn, adapter.Tracker) {
t := &Tracker{}
func (h *HookServer) RoutedPacketConnection(_ context.Context, conn N.PacketConn, m adapter.InboundContext, _ adapter.Rule, _ adapter.Outbound) N.PacketConn {
l, err := limiter.GetLimiter(m.Inbound)
if err != nil {
log.Warn("get limiter for ", m.Inbound, " error: ", err)
return conn, t
}
if l.CheckDomainRule(m.Domain) {
conn.Close()
log.Error("[", m.Inbound, "] ",
"Limited ", m.User, " access to ", m.Domain, " by domain rule")
return conn, t
}
if l.CheckProtocolRule(m.Protocol) {
conn.Close()
log.Error("[", m.Inbound, "] ",
"Limited ", m.User, " use ", m.Domain, " by protocol rule")
return conn, t
return conn
}
ip := m.Source.Addr.String()
if b, r := l.CheckLimit(format.UserTag(m.Inbound, m.User), ip, false, false); r {
conn.Close()
log.Error("[", m.Inbound, "] ", "Limited ", m.User, " by ip or conn")
return conn, t
return conn
} else if b != nil {
//conn = rate.NewPacketConnCounter(conn, b)
}
if h.EnableConnClear {
var key int
cc := &ConnClear{
conns: map[int]io.Closer{
0: conn,
@@ -178,57 +120,20 @@ func (h *HookServer) RoutedPacketConnection(_ context.Context, conn N.PacketConn
}
if v, ok := h.connClears.LoadOrStore(m.Inbound+m.User, cc); ok {
cc = v.(*ConnClear)
key = cc.AddConn(conn)
}
t.AddLeave(func() {
cc.DelConn(key)
})
}
if c, ok := h.counter.Load(m.Inbound); ok {
return counter.NewPacketConnCounter(conn, c.(*counter.TrafficCounter).GetCounter(m.User)), t
return counter.NewPacketConnCounter(conn, c.(*counter.TrafficCounter).GetCounter(m.User))
} else {
c := counter.NewTrafficCounter()
h.counter.Store(m.Inbound, c)
return counter.NewPacketConnCounter(conn, c.GetCounter(m.User)), t
return counter.NewPacketConnCounter(conn, c.GetCounter(m.User))
}
}
// not need
func (h *HookServer) Mode() string {
return ""
}
func (h *HookServer) StoreSelected() bool {
return false
}
func (h *HookServer) CacheFile() adapter.CacheFile {
return nil
}
func (h *HookServer) HistoryStorage() *urltest.HistoryStorage {
return h.urlTestHistory
}
func (h *HookServer) StoreFakeIP() bool {
return false
}
func (h *HookServer) ClearConn(inbound string, user string) {
if v, ok := h.connClears.Load(inbound + user); ok {
v.(*ConnClear).ClearConn()
h.connClears.Delete(inbound + user)
}
}
type Tracker struct {
l []func()
}
func (t *Tracker) AddLeave(f func()) {
t.l = append(t.l, f)
}
func (t *Tracker) Leave() {
for i := range t.l {
t.l[i]()
}
}

View File

@@ -13,9 +13,9 @@ import (
"github.com/InazumaV/V2bX/api/panel"
"github.com/InazumaV/V2bX/conf"
"github.com/goccy/go-json"
"github.com/sagernet/sing-box/inbound"
"github.com/sagernet/sing-box/option"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json/badoption"
)
type HttpNetworkConfig struct {
@@ -59,9 +59,9 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
domainStrategy = c.SingOptions.DomainStrategy
}
listen := option.ListenOptions{
Listen: (*option.ListenAddress)(&addr),
ListenPort: uint16(info.Common.ServerPort),
TCPFastOpen: c.SingOptions.TCPFastOpen,
Listen: (*badoption.Addr)(&addr),
ListenPort: uint16(info.Common.ServerPort),
TCPFastOpen: c.SingOptions.TCPFastOpen,
InboundOptions: option.InboundOptions{
SniffEnabled: c.SingOptions.SniffEnabled,
SniffOverrideDestination: c.SingOptions.SniffOverrideDestination,
@@ -112,14 +112,14 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
Enabled: true,
ShortID: []string{v.TlsSettings.ShortId},
PrivateKey: v.TlsSettings.PrivateKey,
Xver: uint8(v.TlsSettings.Xver),
//Xver: uint8(v.TlsSettings.Xver),
Handshake: option.InboundRealityHandshakeOptions{
ServerOptions: option.ServerOptions{
Server: dest,
ServerPort: uint16(port),
},
},
MaxTimeDifference: option.Duration(mtd),
MaxTimeDifference: badoption.Duration(mtd),
}
}
in := option.Inbound{
@@ -162,7 +162,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
var (
path string
ed int
headers map[string]option.Listable[string]
headers map[string]badoption.Listable[string]
)
if len(n.NetworkSettings) != 0 {
network := WsNetworkConfig{}
@@ -177,9 +177,9 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
}
path = u.Path
ed, _ = strconv.Atoi(u.Query().Get("ed"))
headers = make(map[string]option.Listable[string], len(network.Headers))
headers = make(map[string]badoption.Listable[string], len(network.Headers))
for k, v := range network.Headers {
headers[k] = option.Listable[string]{
headers[k] = badoption.Listable[string]{
v,
}
}
@@ -216,7 +216,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
}
if info.Type == "vless" {
in.Type = "vless"
in.VLESSOptions = option.VLESSInboundOptions{
in.Options = &option.VLESSInboundOptions{
ListenOptions: listen,
InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{
TLS: &tls,
@@ -226,7 +226,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
}
} else {
in.Type = "vmess"
in.VMessOptions = option.VMessInboundOptions{
in.Options = &option.VMessInboundOptions{
ListenOptions: listen,
InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{
TLS: &tls,
@@ -247,7 +247,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
default:
keyLength = 16
}
in.ShadowsocksOptions = option.ShadowsocksInboundOptions{
ssoption := &option.ShadowsocksInboundOptions{
ListenOptions: listen,
Method: n.Cipher,
Multiplex: multiplex,
@@ -256,12 +256,13 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
_, _ = rand.Read(p)
randomPasswd := string(p)
if strings.Contains(n.Cipher, "2022") {
in.ShadowsocksOptions.Password = n.ServerKey
ssoption.Password = n.ServerKey
randomPasswd = base64.StdEncoding.EncodeToString([]byte(randomPasswd))
}
in.ShadowsocksOptions.Users = []option.ShadowsocksUser{{
ssoption.Users = []option.ShadowsocksUser{{
Password: randomPasswd,
}}
in.Options = ssoption
case "trojan":
n := info.Trojan
t := option.V2RayTransportOptions{
@@ -274,7 +275,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
var (
path string
ed int
headers map[string]option.Listable[string]
headers map[string]badoption.Listable[string]
)
if len(n.NetworkSettings) != 0 {
network := WsNetworkConfig{}
@@ -289,9 +290,9 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
}
path = u.Path
ed, _ = strconv.Atoi(u.Query().Get("ed"))
headers = make(map[string]option.Listable[string], len(network.Headers))
headers = make(map[string]badoption.Listable[string], len(network.Headers))
for k, v := range network.Headers {
headers[k] = option.Listable[string]{
headers[k] = badoption.Listable[string]{
v,
}
}
@@ -317,7 +318,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
t.Type = ""
}
in.Type = "trojan"
in.TrojanOptions = option.TrojanInboundOptions{
trojanoption := &option.TrojanInboundOptions{
ListenOptions: listen,
InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{
TLS: &tls,
@@ -330,7 +331,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
fallback := c.SingOptions.FallBackConfigs.FallBack
fallbackPort, err := strconv.Atoi(fallback.ServerPort)
if err == nil {
in.TrojanOptions.Fallback = &option.ServerOptions{
trojanoption.Fallback = &option.ServerOptions{
Server: fallback.Server,
ServerPort: uint16(fallbackPort),
}
@@ -338,12 +339,13 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
fallbackForALPNMap := c.SingOptions.FallBackConfigs.FallBackForALPN
fallbackForALPN := make(map[string]*option.ServerOptions, len(fallbackForALPNMap))
if err := processFallback(c, fallbackForALPN); err == nil {
in.TrojanOptions.FallbackForALPN = fallbackForALPN
trojanoption.FallbackForALPN = fallbackForALPN
}
}
in.Options = trojanoption
case "hysteria":
in.Type = "hysteria"
in.HysteriaOptions = option.HysteriaInboundOptions{
in.Options = &option.HysteriaInboundOptions{
ListenOptions: listen,
UpMbps: info.Hysteria.UpMbps,
DownMbps: info.Hysteria.DownMbps,
@@ -366,7 +368,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
Password: info.Hysteria2.ObfsType,
}
}
in.Hysteria2Options = option.Hysteria2InboundOptions{
in.Options = &option.Hysteria2InboundOptions{
ListenOptions: listen,
UpMbps: info.Hysteria2.UpMbps,
DownMbps: info.Hysteria2.DownMbps,
@@ -380,32 +382,20 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
}
func (b *Sing) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error {
err := updateDNSConfig(info)
if err != nil {
return fmt.Errorf("build dns error: %s", err)
}
c, err := getInboundOptions(tag, info, config)
if err != nil {
return err
}
in, err := inbound.New(
in := b.box.Inbound()
err = in.Create(
b.ctx,
b.box.Router(),
b.logFactory.NewLogger(F.ToString("inbound/", c.Type, "[", tag, "]")),
tag,
c,
nil,
c.Type,
c.Options,
)
if err != nil {
return fmt.Errorf("init inbound error %s", err)
}
err = in.Start()
if err != nil {
return fmt.Errorf("start inbound error: %s", err)
}
b.inbounds[tag] = in
err = b.router.AddInbound(in)
if err != nil {
return fmt.Errorf("add inbound error: %s", err)
}
@@ -413,11 +403,8 @@ func (b *Sing) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) e
}
func (b *Sing) 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)
in := b.box.Inbound()
err := in.Remove(tag)
if err != nil {
return fmt.Errorf("delete inbound error: %s", err)
}

View File

@@ -5,14 +5,15 @@ import (
"fmt"
"os"
"github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log"
"github.com/InazumaV/V2bX/conf"
vCore "github.com/InazumaV/V2bX/core"
"github.com/goccy/go-json"
box "github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/json"
)
var _ vCore.Core = (*Sing)(nil)
@@ -36,13 +37,15 @@ func init() {
}
func New(c *conf.CoreConfig) (vCore.Core, error) {
ctx := context.Background()
ctx = box.Context(ctx, include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry())
options := option.Options{}
if len(c.SingConfig.OriginalPath) != 0 {
data, err := os.ReadFile(c.SingConfig.OriginalPath)
if err != nil {
return nil, fmt.Errorf("read original config error: %s", err)
}
err = json.Unmarshal(data, &options)
options, err = json.UnmarshalExtendedContext[option.Options](ctx, data)
if err != nil {
return nil, fmt.Errorf("unmarshal original config error: %s", err)
}
@@ -63,21 +66,20 @@ func New(c *conf.CoreConfig) (vCore.Core, error) {
}
os.Setenv("SING_DNS_PATH", "")
b, err := box.New(box.Options{
Context: context.Background(),
Context: ctx,
Options: options,
})
if err != nil {
return nil, err
}
hs := NewHookServer(b.Router().GetCtx(), c.SingConfig.EnableConnClear)
b.Router().SetClashServer(hs)
hs := NewHookServer(c.SingConfig.EnableConnClear)
b.Router().SetTracker(hs)
return &Sing{
ctx: b.Router().GetCtx(),
box: b,
hookServer: hs,
router: b.Router(),
logFactory: b.LogFactory(),
inbounds: make(map[string]adapter.Inbound),
}, nil
}

View File

@@ -7,11 +7,20 @@ import (
"github.com/InazumaV/V2bX/api/panel"
"github.com/InazumaV/V2bX/common/counter"
"github.com/InazumaV/V2bX/core"
"github.com/sagernet/sing-box/inbound"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/protocol/hysteria"
"github.com/sagernet/sing-box/protocol/hysteria2"
"github.com/sagernet/sing-box/protocol/shadowsocks"
"github.com/sagernet/sing-box/protocol/trojan"
"github.com/sagernet/sing-box/protocol/vless"
"github.com/sagernet/sing-box/protocol/vmess"
)
func (b *Sing) AddUsers(p *core.AddUsersParams) (added int, err error) {
in, found := b.box.Inbound().Get(p.Tag)
if !found {
return 0, errors.New("the inbound not found")
}
switch p.NodeInfo.Type {
case "vmess", "vless":
if p.NodeInfo.Type == "vless" {
@@ -23,7 +32,7 @@ func (b *Sing) AddUsers(p *core.AddUsersParams) (added int, err error) {
UUID: p.Users[i].Uuid,
}
}
err = b.inbounds[p.Tag].(*inbound.VLESS).AddUsers(us)
err = in.(*vless.Inbound).AddUsers(us)
} else {
us := make([]option.VMessUser, len(p.Users))
for i := range p.Users {
@@ -32,7 +41,7 @@ func (b *Sing) AddUsers(p *core.AddUsersParams) (added int, err error) {
UUID: p.Users[i].Uuid,
}
}
err = b.inbounds[p.Tag].(*inbound.VMess).AddUsers(us)
err = in.(*vmess.Inbound).AddUsers(us)
}
case "shadowsocks":
us := make([]option.ShadowsocksUser, len(p.Users))
@@ -49,7 +58,7 @@ func (b *Sing) AddUsers(p *core.AddUsersParams) (added int, err error) {
Password: password,
}
}
err = b.inbounds[p.Tag].(*inbound.ShadowsocksMulti).AddUsers(us)
err = in.(*shadowsocks.MultiInbound).AddUsers(us)
case "trojan":
us := make([]option.TrojanUser, len(p.Users))
for i := range p.Users {
@@ -58,7 +67,7 @@ func (b *Sing) AddUsers(p *core.AddUsersParams) (added int, err error) {
Password: p.Users[i].Uuid,
}
}
err = b.inbounds[p.Tag].(*inbound.Trojan).AddUsers(us)
err = in.(*trojan.Inbound).AddUsers(us)
case "hysteria":
us := make([]option.HysteriaUser, len(p.Users))
for i := range p.Users {
@@ -67,7 +76,7 @@ func (b *Sing) AddUsers(p *core.AddUsersParams) (added int, err error) {
AuthString: p.Users[i].Uuid,
}
}
err = b.inbounds[p.Tag].(*inbound.Hysteria).AddUsers(us)
err = in.(*hysteria.Inbound).AddUsers(us)
case "hysteria2":
us := make([]option.Hysteria2User, len(p.Users))
id := make([]int, len(p.Users))
@@ -78,7 +87,7 @@ func (b *Sing) AddUsers(p *core.AddUsersParams) (added int, err error) {
}
id[i] = p.Users[i].Id
}
err = b.inbounds[p.Tag].(*inbound.Hysteria2).AddUsers(us, id)
err = in.(*hysteria2.Inbound).AddUsers(us, id)
}
if err != nil {
return 0, err
@@ -108,17 +117,17 @@ func (b *Sing) DelUsers(users []panel.UserInfo, tag string) error {
if i, ok := b.inbounds[tag]; ok {
switch i.Type() {
case "vmess":
del = i.(*inbound.VMess)
del = i.(*vmess.Inbound)
case "vless":
del = i.(*inbound.VLESS)
del = i.(*vless.Inbound)
case "shadowsocks":
del = i.(*inbound.ShadowsocksMulti)
del = i.(*shadowsocks.MultiInbound)
case "trojan":
del = i.(*inbound.Trojan)
del = i.(*trojan.Inbound)
case "hysteria":
del = i.(*inbound.Hysteria)
del = i.(*hysteria.Inbound)
case "hysteria2":
del = i.(*inbound.Hysteria2)
del = i.(*hysteria2.Inbound)
}
} else {
return errors.New("the inbound not found")