V2bX/core/sing/node.go

278 lines
7.3 KiB
Go
Raw Normal View History

2023-07-27 21:13:11 -04:00
package sing
import (
"crypto/rand"
"encoding/base64"
"fmt"
"net/netip"
"net/url"
"strconv"
"strings"
2023-08-07 02:52:50 -04:00
"time"
2023-07-27 21:13:11 -04:00
2023-07-29 07:27:15 -04:00
"github.com/InazumaV/V2bX/api/panel"
"github.com/InazumaV/V2bX/conf"
2023-07-27 21:13:11 -04:00
"github.com/goccy/go-json"
2023-10-26 01:06:43 -04:00
"github.com/sagernet/sing-box/inbound"
"github.com/sagernet/sing-box/option"
F "github.com/sagernet/sing/common/format"
2023-07-27 21:13:11 -04:00
)
type WsNetworkConfig struct {
2023-07-29 06:47:47 -04:00
Path string `json:"path"`
Headers map[string]string `json:"headers"`
2023-07-27 21:13:11 -04:00
}
2023-07-29 06:47:47 -04:00
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")
}
2023-09-21 00:34:03 -04:00
var domainStrategy option.DomainStrategy
if c.SingOptions.EnableDNS {
domainStrategy = c.SingOptions.DomainStrategy
}
2023-07-27 21:13:11 -04:00
listen := option.ListenOptions{
2023-08-07 00:23:34 -04:00
Listen: (*option.ListenAddress)(&addr),
2023-08-19 08:06:42 -04:00
ListenPort: uint16(info.Common.ServerPort),
2023-08-07 00:23:34 -04:00
ProxyProtocol: c.SingOptions.EnableProxyProtocol,
TCPFastOpen: c.SingOptions.TCPFastOpen,
InboundOptions: option.InboundOptions{
SniffEnabled: c.SingOptions.SniffEnabled,
SniffOverrideDestination: c.SingOptions.SniffOverrideDestination,
2023-09-21 00:34:03 -04:00
DomainStrategy: domainStrategy,
2023-08-07 00:23:34 -04:00
},
2023-07-27 21:13:11 -04:00
}
2023-08-07 02:52:50 -04:00
var tls option.InboundTLSOptions
2023-08-19 08:06:42 -04:00
switch info.Security {
case panel.Tls:
2023-08-07 02:52:50 -04:00
if c.CertConfig == nil {
return option.Inbound{}, fmt.Errorf("the CertConfig is not vail")
}
switch c.CertConfig.CertMode {
case "none", "":
break // disable
default:
2023-08-19 08:06:42 -04:00
tls.Enabled = true
2023-08-07 02:52:50 -04:00
tls.CertificatePath = c.CertConfig.CertFile
tls.KeyPath = c.CertConfig.KeyFile
}
2023-08-19 08:06:42 -04:00
case panel.Reality:
tls.Enabled = true
v := info.VAllss
2023-08-23 07:13:36 -04:00
tls.ServerName = v.TlsSettings.ServerName
2023-11-17 21:59:58 -05:00
port, _ := strconv.Atoi(v.TlsSettings.ServerPort)
var dest string
if v.TlsSettings.Dest != "" {
dest = v.TlsSettings.Dest
} else {
dest = tls.ServerName
}
2023-08-23 10:06:36 -04:00
mtd, _ := time.ParseDuration(v.RealityConfig.MaxTimeDiff)
2023-08-19 08:06:42 -04:00
tls.Reality = &option.InboundRealityOptions{
2023-08-23 10:06:36 -04:00
Enabled: true,
ShortID: []string{v.TlsSettings.ShortId},
PrivateKey: v.TlsSettings.PrivateKey,
2023-08-19 08:06:42 -04:00
Handshake: option.InboundRealityHandshakeOptions{
ServerOptions: option.ServerOptions{
2023-11-17 21:59:58 -05:00
Server: dest,
ServerPort: uint16(port),
2023-08-19 08:06:42 -04:00
},
},
2023-08-23 10:06:36 -04:00
MaxTimeDifference: option.Duration(mtd),
2023-08-19 08:06:42 -04:00
}
2023-07-27 21:13:11 -04:00
}
in := option.Inbound{
Tag: tag,
}
switch info.Type {
2023-08-19 08:06:42 -04:00
case "vmess", "vless":
n := info.VAllss
2023-07-27 21:13:11 -04:00
t := option.V2RayTransportOptions{
2023-08-19 08:06:42 -04:00
Type: n.Network,
2023-07-27 21:13:11 -04:00
}
2023-08-19 08:06:42 -04:00
switch n.Network {
2023-07-27 21:13:11 -04:00
case "tcp":
2023-07-29 06:47:47 -04:00
t.Type = ""
2023-07-27 21:13:11 -04:00
case "ws":
2023-08-27 01:20:31 -04:00
var (
path string
ed int
headers map[string]option.Listable[string]
)
if len(n.NetworkSettings) != 0 {
network := WsNetworkConfig{}
err := json.Unmarshal(n.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)
}
path = u.Path
ed, _ = strconv.Atoi(u.Query().Get("ed"))
headers = make(map[string]option.Listable[string], len(network.Headers))
for k, v := range network.Headers {
headers[k] = option.Listable[string]{
v,
}
2023-07-29 06:47:47 -04:00
}
}
2023-07-27 21:13:11 -04:00
t.WebsocketOptions = option.V2RayWebsocketOptions{
2023-08-27 01:20:31 -04:00
Path: path,
2023-07-27 21:13:11 -04:00
EarlyDataHeaderName: "Sec-WebSocket-Protocol",
MaxEarlyData: uint32(ed),
2023-08-27 01:20:31 -04:00
Headers: headers,
2023-07-27 21:13:11 -04:00
}
case "grpc":
2023-08-27 01:20:31 -04:00
if len(n.NetworkSettings) != 0 {
err := json.Unmarshal(n.NetworkSettings, &t.GRPCOptions)
if err != nil {
return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err)
}
2023-07-27 21:13:11 -04:00
}
}
2023-08-19 08:06:42 -04:00
if info.Type == "vless" {
2023-07-30 07:49:42 -04:00
in.Type = "vless"
in.VLESSOptions = option.VLESSInboundOptions{
ListenOptions: listen,
TLS: &tls,
Transport: &t,
}
} else {
in.Type = "vmess"
in.VMessOptions = option.VMessInboundOptions{
ListenOptions: listen,
TLS: &tls,
Transport: &t,
}
2023-07-27 21:13:11 -04:00
}
case "shadowsocks":
in.Type = "shadowsocks"
2023-08-19 08:06:42 -04:00
n := info.Shadowsocks
2023-08-06 01:02:34 -04:00
var keyLength int
2023-08-19 08:06:42 -04:00
switch n.Cipher {
2023-08-06 01:02:34 -04:00
case "2022-blake3-aes-128-gcm":
keyLength = 16
case "2022-blake3-aes-256-gcm":
keyLength = 32
default:
2023-08-06 22:00:36 -04:00
keyLength = 16
2023-07-27 21:13:11 -04:00
}
in.ShadowsocksOptions = option.ShadowsocksInboundOptions{
ListenOptions: listen,
2023-08-19 08:06:42 -04:00
Method: n.Cipher,
2023-07-27 21:13:11 -04:00
}
2023-08-06 01:02:34 -04:00
p := make([]byte, keyLength)
_, _ = rand.Read(p)
2023-08-06 22:00:36 -04:00
randomPasswd := string(p)
2023-08-19 08:06:42 -04:00
if strings.Contains(n.Cipher, "2022") {
in.ShadowsocksOptions.Password = n.ServerKey
2023-08-06 01:02:34 -04:00
randomPasswd = base64.StdEncoding.EncodeToString([]byte(randomPasswd))
}
in.ShadowsocksOptions.Users = []option.ShadowsocksUser{{
Password: randomPasswd,
}}
2023-08-07 00:23:34 -04:00
case "trojan":
in.Type = "trojan"
in.TrojanOptions = option.TrojanInboundOptions{
ListenOptions: listen,
2023-08-19 08:06:42 -04:00
TLS: &tls,
2023-08-07 00:23:34 -04:00
}
if c.SingOptions.FallBackConfigs != nil {
// fallback handling
fallback := c.SingOptions.FallBackConfigs.FallBack
fallbackPort, err := strconv.Atoi(fallback.ServerPort)
if err == nil {
in.TrojanOptions.Fallback = &option.ServerOptions{
Server: fallback.Server,
ServerPort: uint16(fallbackPort),
}
}
fallbackForALPNMap := c.SingOptions.FallBackConfigs.FallBackForALPN
fallbackForALPN := make(map[string]*option.ServerOptions, len(fallbackForALPNMap))
if err := processFallback(c, fallbackForALPN); err == nil {
in.TrojanOptions.FallbackForALPN = fallbackForALPN
}
}
case "hysteria":
in.Type = "hysteria"
in.HysteriaOptions = option.HysteriaInboundOptions{
ListenOptions: listen,
2023-08-19 08:06:42 -04:00
UpMbps: info.Hysteria.UpMbps,
DownMbps: info.Hysteria.DownMbps,
Obfs: info.Hysteria.Obfs,
TLS: &tls,
}
case "hysteria2":
in.Type = "hysteria2"
var obfs *option.Hysteria2Obfs
2023-11-19 00:35:12 -05:00
if info.Hysteria2.ObfsType != "" && info.Hysteria2.ObfsPassword != "" {
obfs = &option.Hysteria2Obfs{
Type: info.Hysteria2.ObfsType,
Password: info.Hysteria2.ObfsPassword,
}
2023-11-19 00:35:12 -05:00
} else if info.Hysteria2.ObfsType != "" {
obfs = &option.Hysteria2Obfs{
Type: "salamander",
Password: info.Hysteria2.ObfsType,
}
}
in.Hysteria2Options = option.Hysteria2InboundOptions{
ListenOptions: listen,
UpMbps: info.Hysteria2.UpMbps,
DownMbps: info.Hysteria2.DownMbps,
Obfs: obfs,
TLS: &tls,
}
2023-07-27 21:13:11 -04:00
}
return in, nil
}
2023-10-26 01:06:43 -04:00
func (b *Sing) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error {
2023-09-21 00:34:03 -04:00
err := updateDNSConfig(info)
if err != nil {
return fmt.Errorf("build dns error: %s", err)
}
2023-07-27 21:13:11 -04:00
c, err := getInboundOptions(tag, info, config)
if err != nil {
return err
}
2023-07-27 21:13:11 -04:00
in, err := inbound.New(
b.ctx,
2023-11-17 20:37:08 -05:00
b.box.Router(),
2023-07-27 21:13:11 -04:00
b.logFactory.NewLogger(F.ToString("inbound/", c.Type, "[", tag, "]")),
c,
nil,
)
2023-08-23 07:13:36 -04:00
if err != nil {
return fmt.Errorf("init inbound error %s", err)
}
2023-07-27 21:13:11 -04:00
err = in.Start()
if err != nil {
return fmt.Errorf("start inbound error: %s", err)
}
2023-08-23 07:13:36 -04:00
b.inbounds[tag] = in
2023-07-27 21:13:11 -04:00
err = b.router.AddInbound(in)
if err != nil {
return fmt.Errorf("add inbound error: %s", err)
}
return nil
}
2023-10-26 01:06:43 -04:00
func (b *Sing) DelNode(tag string) error {
2023-07-27 21:13:11 -04:00
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
}