This commit is contained in:
yuzuki999 2022-06-03 01:22:56 +08:00
parent 358b5888b4
commit a5c6483402
7 changed files with 205 additions and 114 deletions

View File

@ -59,15 +59,19 @@ type TrojanUserInfo struct {
Password string `json:"password"` Password string `json:"password"`
} }
type UserInfo struct { type UserInfo struct {
UID int `json:"id"`
DeviceLimit int `json:"device_limit"` DeviceLimit int `json:"device_limit"`
SpeedLimit uint64 `json:"speed_limit"` SpeedLimit uint64 `json:"speed_limit"`
UID int `json:"id"`
Port int `json:"port"` Port int `json:"port"`
Cipher string `json:"cipher"` Cipher string `json:"cipher"`
Secret string `json:"secret"` Secret string `json:"secret"`
V2rayUser *V2RayUserInfo `json:"v2ray_user"` V2rayUser *V2RayUserInfo `json:"v2ray_user"`
TrojanUser *TrojanUserInfo `json:"trojan_user"` TrojanUser *TrojanUserInfo `json:"trojan_user"`
} }
type UserListBody struct {
//Msg string `json:"msg"`
Data []UserInfo `json:"data"`
}
func (p *UserInfo) GetUserEmail() string { func (p *UserInfo) GetUserEmail() string {
if p.V2rayUser != nil { if p.V2rayUser != nil {
@ -79,14 +83,16 @@ func (p *UserInfo) GetUserEmail() string {
} }
type NodeInfo struct { type NodeInfo struct {
NodeType string RspMd5 string
NodeId int NodeType string
TLSType string NodeId int
EnableVless bool TLSType string
EnableTls bool EnableVless bool
V2ray *V2rayConfig EnableTls bool
Trojan *TrojanConfig EnableSS2022 bool
SS *SSConfig V2ray *V2rayConfig
Trojan *TrojanConfig
SS *SSConfig
} }
type SSConfig struct { type SSConfig struct {

View File

@ -2,10 +2,11 @@ package v2board
import ( import (
"bufio" "bufio"
md52 "crypto/md5"
"fmt" "fmt"
"github.com/Yuzuki616/V2bX/api" "github.com/Yuzuki616/V2bX/api"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
json "github.com/goccy/go-json" "github.com/goccy/go-json"
"log" "log"
"os" "os"
"regexp" "regexp"
@ -16,18 +17,21 @@ import (
// APIClient create an api client to the panel. // APIClient create an api client to the panel.
type APIClient struct { type APIClient struct {
client *resty.Client client *resty.Client
APIHost string APIHost string
NodeID int NodeID int
Key string Key string
NodeType string NodeType string
EnableVless bool EnableSS2022 bool
EnableXTLS bool EnableVless bool
SpeedLimit float64 EnableXTLS bool
DeviceLimit int SpeedLimit float64
LocalRuleList []api.DetectRule DeviceLimit int
RemoteRuleCache *api.Rule LocalRuleList []api.DetectRule
access sync.Mutex RemoteRuleCache *api.Rule
access sync.Mutex
NodeInfoRspMd5 [16]byte
UserListCheckNum int
} }
// New create an api instance // New create an api instance
@ -61,6 +65,7 @@ func New(apiConfig *api.Config) *APIClient {
Key: apiConfig.Key, Key: apiConfig.Key,
APIHost: apiConfig.APIHost, APIHost: apiConfig.APIHost,
NodeType: apiConfig.NodeType, NodeType: apiConfig.NodeType,
EnableSS2022: apiConfig.EnableSS2022,
EnableVless: apiConfig.EnableVless, EnableVless: apiConfig.EnableVless,
EnableXTLS: apiConfig.EnableXTLS, EnableXTLS: apiConfig.EnableXTLS,
SpeedLimit: apiConfig.SpeedLimit, SpeedLimit: apiConfig.SpeedLimit,
@ -96,7 +101,7 @@ func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {
// handle first encountered error while reading // handle first encountered error while reading
if err := fileScanner.Err(); err != nil { if err := fileScanner.Err(); err != nil {
log.Fatalf("Error while reading file: %s", err) log.Fatalf("Error while reading file: %s", err)
return make([]api.DetectRule, 0) return []api.DetectRule{}
} }
file.Close() file.Close()
@ -153,6 +158,13 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
default: default:
return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType) return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType)
} }
md := md52.Sum(res.Body())
if c.NodeInfoRspMd5 != [16]byte{} {
if c.NodeInfoRspMd5 == md {
return nil, nil
}
}
c.NodeInfoRspMd5 = md
res, err = c.client.R(). res, err = c.client.R().
SetQueryParam("local_port", "1"). SetQueryParam("local_port", "1").
ForceContentType("application/json"). ForceContentType("application/json").
@ -168,10 +180,6 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
nodeInfo, err = c.ParseV2rayNodeResponse(res.Body()) nodeInfo, err = c.ParseV2rayNodeResponse(res.Body())
case "Trojan": case "Trojan":
nodeInfo, err = c.ParseTrojanNodeResponse(res.Body()) nodeInfo, err = c.ParseTrojanNodeResponse(res.Body())
case "Shadowsocks":
nodeInfo, err = c.ParseSSNodeResponse()
default:
return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType)
} }
return nodeInfo, nil return nodeInfo, nil
} }
@ -192,16 +200,25 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
res, err := c.client.R(). res, err := c.client.R().
ForceContentType("application/json"). ForceContentType("application/json").
Get(path) Get(path)
var userList []api.UserInfo
err = c.checkResponse(res, path, err) err = c.checkResponse(res, path, err)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var userList *api.UserListBody
err = json.Unmarshal(res.Body(), &userList) err = json.Unmarshal(res.Body(), &userList)
if err != nil { if err != nil {
return nil, fmt.Errorf("unmarshal userlist error: %s", err) return nil, fmt.Errorf("unmarshal userlist error: %s", err)
} }
return &userList, nil checkNum := userList.Data[len(userList.Data)-1].UID +
userList.Data[len(userList.Data)/2-1].UID +
userList.Data[0].UID
if c.UserListCheckNum != 0 {
if c.UserListCheckNum == checkNum {
return nil, nil
}
}
c.UserListCheckNum = userList.Data[len(userList.Data)-1].UID
return &userList.Data, nil
} }
// ReportUserTraffic reports the user traffic // ReportUserTraffic reports the user traffic
@ -286,8 +303,9 @@ func (c *APIClient) ParseSSNodeResponse() (*api.NodeInfo, error) {
return nil, err return nil, err
} }
node := &api.NodeInfo{ node := &api.NodeInfo{
NodeType: c.NodeType, EnableSS2022: c.EnableSS2022,
NodeId: c.NodeID, NodeType: c.NodeType,
NodeId: c.NodeID,
SS: &api.SSConfig{ SS: &api.SSConfig{
Port: port, Port: port,
TransportProtocol: "tcp", TransportProtocol: "tcp",
@ -300,6 +318,10 @@ func (c *APIClient) ParseSSNodeResponse() (*api.NodeInfo, error) {
// ParseV2rayNodeResponse parse the response for the given nodeinfor format // ParseV2rayNodeResponse parse the response for the given nodeinfor format
func (c *APIClient) ParseV2rayNodeResponse(body []byte) (*api.NodeInfo, error) { func (c *APIClient) ParseV2rayNodeResponse(body []byte) (*api.NodeInfo, error) {
node := &api.NodeInfo{V2ray: &api.V2rayConfig{}} node := &api.NodeInfo{V2ray: &api.V2rayConfig{}}
err := json.Unmarshal(body, node.V2ray)
if err != nil {
return nil, fmt.Errorf("unmarshal nodeinfo error: %s", err)
}
node.NodeType = c.NodeType node.NodeType = c.NodeType
node.NodeId = c.NodeID node.NodeId = c.NodeID
c.RemoteRuleCache = &node.V2ray.Routing.Rules[0] c.RemoteRuleCache = &node.V2ray.Routing.Rules[0]

View File

@ -54,18 +54,18 @@ func (l *Limiter) AddInboundLimiter(tag string, nodeSpeedLimit uint64, userList
return nil return nil
} }
func (l *Limiter) UpdateInboundLimiter(tag string, updatedUserList *[]api.UserInfo) error { func (l *Limiter) UpdateInboundLimiter(tag string, updatedUserList *[]api.UserInfo, usersIndex *[]int) error {
if value, ok := l.InboundInfo.Load(tag); ok { if value, ok := l.InboundInfo.Load(tag); ok {
inboundInfo := value.(*InboundInfo) inboundInfo := value.(*InboundInfo)
// Update User info // Update User info
for _, u := range *updatedUserList { for _, u := range *usersIndex {
inboundInfo.UserInfo.Store(fmt.Sprintf("%s|%s|%d", tag, u.GetUserEmail(), u.UID), UserInfo{ inboundInfo.UserInfo.Store(fmt.Sprintf("%s|%s|%d", tag, (*updatedUserList)[u].GetUserEmail(), (*updatedUserList)[u].UID), UserInfo{
UID: u.UID, UID: (*updatedUserList)[u].UID,
SpeedLimit: u.SpeedLimit, SpeedLimit: (*updatedUserList)[u].SpeedLimit,
DeviceLimit: u.DeviceLimit, DeviceLimit: (*updatedUserList)[u].DeviceLimit,
}) })
inboundInfo.BucketHub.Delete(fmt.Sprintf("%s|%s|%d", tag, u.GetUserEmail(), u.UID)) // Delete old limiter bucket inboundInfo.BucketHub.Delete(fmt.Sprintf("%s|%s|%d", tag, (*updatedUserList)[u].GetUserEmail(), (*updatedUserList)[u].UID)) // Delete old limiter bucket
} }
} else { } else {
return fmt.Errorf("no such inbound in limiter: %s", tag) return fmt.Errorf("no such inbound in limiter: %s", tag)
@ -142,7 +142,7 @@ func (l *Limiter) GetUserBucket(tag string, email string, ip string) (limiter *r
} }
limit := determineRate(nodeLimit, userLimit) // If need the Speed limit limit := determineRate(nodeLimit, userLimit) // If need the Speed limit
if limit > 0 { if limit > 0 {
limiter := ratelimit.NewBucketWithQuantum(time.Duration(time.Second), int64(limit), int64(limit)) // Byte/s limiter := ratelimit.NewBucketWithQuantum(time.Second, int64(limit), int64(limit)) // Byte/s
if v, ok := inboundInfo.BucketHub.LoadOrStore(email, limiter); ok { if v, ok := inboundInfo.BucketHub.LoadOrStore(email, limiter); ok {
bucket := v.(*ratelimit.Bucket) bucket := v.(*ratelimit.Bucket)
return bucket, true, false return bucket, true, false

View File

@ -63,7 +63,7 @@ func (c *Controller) addUsers(users []*protocol.User, tag string) error {
inboundManager := c.server.GetFeature(inbound.ManagerType()).(inbound.Manager) inboundManager := c.server.GetFeature(inbound.ManagerType()).(inbound.Manager)
handler, err := inboundManager.GetHandler(context.Background(), tag) handler, err := inboundManager.GetHandler(context.Background(), tag)
if err != nil { if err != nil {
return fmt.Errorf("No such inbound tag: %s", err) return fmt.Errorf("no such inbound tag: %s", err)
} }
inboundInstance, ok := handler.(proxy.GetInbound) inboundInstance, ok := handler.(proxy.GetInbound)
if !ok { if !ok {
@ -91,7 +91,7 @@ func (c *Controller) removeUsers(users []string, tag string) error {
inboundManager := c.server.GetFeature(inbound.ManagerType()).(inbound.Manager) inboundManager := c.server.GetFeature(inbound.ManagerType()).(inbound.Manager)
handler, err := inboundManager.GetHandler(context.Background(), tag) handler, err := inboundManager.GetHandler(context.Background(), tag)
if err != nil { if err != nil {
return fmt.Errorf("No such inbound tag: %s", err) return fmt.Errorf("no such inbound tag: %s", err)
} }
inboundInstance, ok := handler.(proxy.GetInbound) inboundInstance, ok := handler.(proxy.GetInbound)
if !ok { if !ok {
@ -135,9 +135,9 @@ func (c *Controller) AddInboundLimiter(tag string, nodeSpeedLimit uint64, userLi
return err return err
} }
func (c *Controller) UpdateInboundLimiter(tag string, updatedUserList *[]api.UserInfo) error { func (c *Controller) UpdateInboundLimiter(tag string, updatedUserList *[]api.UserInfo, usersIndex *[]int) error {
dispather := c.server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher) dispather := c.server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher)
err := dispather.Limiter.UpdateInboundLimiter(tag, updatedUserList) err := dispather.Limiter.UpdateInboundLimiter(tag, updatedUserList, usersIndex)
return err return err
} }

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"log" "log"
"math" "math"
"reflect"
"time" "time"
"github.com/Yuzuki616/V2bX/api" "github.com/Yuzuki616/V2bX/api"
@ -65,6 +64,9 @@ func (c *Controller) Start() error {
} }
//sync controller userList //sync controller userList
c.userList = userInfo c.userList = userInfo
if err := c.AddInboundLimiter(c.Tag, 0, userInfo); err != nil {
log.Print(err)
}
// Add Rule Manager // Add Rule Manager
if !c.config.DisableGetRule { if !c.config.DisableGetRule {
if ruleList, err := c.apiClient.GetNodeRule(); err != nil { if ruleList, err := c.apiClient.GetNodeRule(); err != nil {
@ -124,7 +126,6 @@ func (c *Controller) nodeInfoMonitor() (err error) {
log.Print(err) log.Print(err)
return nil return nil
} }
// Update User // Update User
newUserInfo, err := c.apiClient.GetUserList() newUserInfo, err := c.apiClient.GetUserList()
if err != nil { if err != nil {
@ -134,7 +135,7 @@ func (c *Controller) nodeInfoMonitor() (err error) {
var nodeInfoChanged = false var nodeInfoChanged = false
// If nodeInfo changed // If nodeInfo changed
if !reflect.DeepEqual(c.nodeInfo, newNodeInfo) { if newNodeInfo != nil {
// Remove old tag // Remove old tag
oldtag := c.Tag oldtag := c.Tag
err := c.removeOldTag(oldtag) err := c.removeOldTag(oldtag)
@ -142,13 +143,6 @@ func (c *Controller) nodeInfoMonitor() (err error) {
log.Print(err) log.Print(err)
return nil return nil
} }
if c.nodeInfo.NodeType == "Shadowsocks-Plugin" {
err = c.removeOldTag(fmt.Sprintf("dokodemo-door_%s+1", c.Tag))
}
if err != nil {
log.Print(err)
return nil
}
// Add new tag // Add new tag
c.nodeInfo = newNodeInfo c.nodeInfo = newNodeInfo
c.Tag = c.buildNodeTag() c.Tag = c.buildNodeTag()
@ -188,7 +182,9 @@ func (c *Controller) nodeInfoMonitor() (err error) {
log.Print(err) log.Print(err)
} }
} }
if newUserInfo == nil {
return nil
}
if nodeInfoChanged { if nodeInfoChanged {
err = c.addNewUser(newUserInfo, newNodeInfo) err = c.addNewUser(newUserInfo, newNodeInfo)
if err != nil { if err != nil {
@ -199,8 +195,10 @@ func (c *Controller) nodeInfoMonitor() (err error) {
deleted, added := compareUserList(c.userList, newUserInfo) deleted, added := compareUserList(c.userList, newUserInfo)
if len(deleted) > 0 { if len(deleted) > 0 {
deletedEmail := make([]string, len(deleted)) deletedEmail := make([]string, len(deleted))
for i, u := range deleted { for i := range deleted {
deletedEmail[i] = fmt.Sprintf("%s|%d|%d", c.Tag, c.nodeInfo.NodeId, u.UID) deletedEmail[i] = fmt.Sprintf("%s|%s|%d", c.Tag,
(*c.userList)[deleted[i]].GetUserEmail(),
(*c.userList)[deleted[i]].UID)
} }
err := c.removeUsers(deletedEmail, c.Tag) err := c.removeUsers(deletedEmail, c.Tag)
if err != nil { if err != nil {
@ -208,12 +206,17 @@ func (c *Controller) nodeInfoMonitor() (err error) {
} }
} }
if len(added) > 0 { if len(added) > 0 {
err = c.addNewUser(&added, c.nodeInfo) err = c.addNewUserFromIndex(newUserInfo, &added, c.nodeInfo)
if err != nil { if err != nil {
log.Print(err) log.Print(err)
} }
// Add Limiter
if err := c.AddInboundLimiter(c.Tag, 0, newUserInfo); err != nil {
log.Print(err)
return nil
}
// Update Limiter // Update Limiter
if err := c.UpdateInboundLimiter(c.Tag, &added); err != nil { if err := c.UpdateInboundLimiter(c.Tag, newUserInfo, &added); err != nil {
log.Print(err) log.Print(err)
} }
} }
@ -263,21 +266,21 @@ func (c *Controller) addNewUser(userInfo *[]api.UserInfo, nodeInfo *api.NodeInfo
users := make([]*protocol.User, 0) users := make([]*protocol.User, 0)
if nodeInfo.NodeType == "V2ray" { if nodeInfo.NodeType == "V2ray" {
if nodeInfo.EnableVless { if nodeInfo.EnableVless {
users = c.buildVlessUser(userInfo) users = c.buildVlessUsers(userInfo)
} else { } else {
alterID := 0 alterID := 0
alterID = (*userInfo)[0].V2rayUser.AlterId alterID = (*userInfo)[0].V2rayUser.AlterId
if alterID >= 0 && alterID < math.MaxUint16 { if alterID >= 0 && alterID < math.MaxUint16 {
users = c.buildVmessUser(userInfo, uint16(alterID)) users = c.buildVmessUsers(userInfo, uint16(alterID))
} else { } else {
users = c.buildVmessUser(userInfo, 0) users = c.buildVmessUsers(userInfo, 0)
return fmt.Errorf("AlterID should between 0 to 1<<16 - 1, set it to 0 for now") return fmt.Errorf("AlterID should between 0 to 1<<16 - 1, set it to 0 for now")
} }
} }
} else if nodeInfo.NodeType == "Trojan" { } else if nodeInfo.NodeType == "Trojan" {
users = c.buildTrojanUser(userInfo) users = c.buildTrojanUsers(userInfo)
} else if nodeInfo.NodeType == "Shadowsocks" { } else if nodeInfo.NodeType == "Shadowsocks" {
users = c.buildSSUser(userInfo, nodeInfo.SS.CypherMethod) users = c.buildSSUsers(userInfo, nodeInfo.SS.CypherMethod)
} else { } else {
return fmt.Errorf("unsupported node type: %s", nodeInfo.NodeType) return fmt.Errorf("unsupported node type: %s", nodeInfo.NodeType)
} }
@ -289,28 +292,59 @@ func (c *Controller) addNewUser(userInfo *[]api.UserInfo, nodeInfo *api.NodeInfo
return nil return nil
} }
func compareUserList(old, new *[]api.UserInfo) (deleted, added []api.UserInfo) { func (c *Controller) addNewUserFromIndex(userInfo *[]api.UserInfo, userIndex *[]int, nodeInfo *api.NodeInfo) (err error) {
users := make([]*protocol.User, 0, len(*userIndex))
for _, v := range *userIndex {
if nodeInfo.NodeType == "V2ray" {
if nodeInfo.EnableVless {
users = append(users, c.buildVlessUser(&(*userInfo)[v]))
} else {
alterID := 0
alterID = (*userInfo)[0].V2rayUser.AlterId
if alterID >= 0 && alterID < math.MaxUint16 {
users = append(users, c.buildVmessUser(&(*userInfo)[v], uint16(alterID)))
} else {
users = append(users, c.buildVmessUser(&(*userInfo)[v], 0))
return fmt.Errorf("AlterID should between 0 to 1<<16 - 1, set it to 0 for now")
}
}
} else if nodeInfo.NodeType == "Trojan" {
users = append(users, c.buildTrojanUser(&(*userInfo)[v]))
} else if nodeInfo.NodeType == "Shadowsocks" {
users = append(users, c.buildSSUser(&(*userInfo)[v], nodeInfo.SS.CypherMethod))
} else {
return fmt.Errorf("unsupported node type: %s", nodeInfo.NodeType)
}
}
err = c.addUsers(users, c.Tag)
if err != nil {
return err
}
log.Printf("[%s: %d] Added %d new users", c.nodeInfo.NodeType, c.nodeInfo.NodeId, len(*userIndex))
return nil
}
func compareUserList(old, new *[]api.UserInfo) (deleted, added []int) {
tmp := map[int]int{} tmp := map[int]int{}
tmp2 := map[int]int{}
for i := range *old { for i := range *old {
tmp[(*old)[i].UID] = i tmp[(*old)[i].UID] = i
} }
l := len(tmp) l := len(tmp)
for i := range *new { for i := range *new {
tmp[(*new)[i].UID] = i tmp[(*new)[i].UID] = i
tmp2[(*new)[i].UID] = i
if l != len(tmp) { if l != len(tmp) {
tmp[(*new)[i].UID] = i added = append(added, i)
added = append(added, (*new)[i])
l++ l++
} else {
delete(tmp, (*new)[i].UID)
l--
} }
} }
tmp = nil
l = len(tmp2)
for i := range *old { for i := range *old {
tmp[(*old)[i].UID] = i tmp2[(*old)[i].UID] = i
if l == len(tmp) { if l != len(tmp2) {
deleted = append(deleted, (*old)[i]) deleted = append(deleted, i)
} else {
l++ l++
} }
} }

View File

@ -62,8 +62,7 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
nodeInfo.V2ray.Inbounds[0].StreamSetting = &conf.StreamConfig{Network: &t} nodeInfo.V2ray.Inbounds[0].StreamSetting = &conf.StreamConfig{Network: &t}
} else if nodeInfo.NodeType == "Shadowsocks" { } else if nodeInfo.NodeType == "Shadowsocks" {
nodeInfo.V2ray = &api.V2rayConfig{} nodeInfo.V2ray = &api.V2rayConfig{}
nodeInfo.V2ray.Inbounds = make([]conf.InboundDetourConfig, 1) nodeInfo.V2ray.Inbounds = []conf.InboundDetourConfig{{Protocol: "shadowsocks"}}
nodeInfo.V2ray.Inbounds[0].Protocol = "shadowsocks"
proxySetting = &conf.ShadowsocksServerConfig{} proxySetting = &conf.ShadowsocksServerConfig{}
randomPasswd := uuid.New() randomPasswd := uuid.New()
defaultSSuser := &conf.ShadowsocksUserConfig{ defaultSSuser := &conf.ShadowsocksUserConfig{
@ -82,7 +81,9 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
} }
t := conf.TransportProtocol(nodeInfo.SS.TransportProtocol) t := conf.TransportProtocol(nodeInfo.SS.TransportProtocol)
nodeInfo.V2ray.Inbounds[0].StreamSetting = &conf.StreamConfig{Network: &t} nodeInfo.V2ray.Inbounds[0].StreamSetting = &conf.StreamConfig{Network: &t}
} else if nodeInfo.NodeType == "dokodemo-door" { } else {
return nil, fmt.Errorf("unsupported node type: %s, Only support: V2ray, Trojan, Shadowsocks, and Shadowsocks-Plugin", nodeInfo.NodeType)
} /*else if nodeInfo.NodeType == "dokodemo-door" {
nodeInfo.V2ray = &api.V2rayConfig{} nodeInfo.V2ray = &api.V2rayConfig{}
nodeInfo.V2ray.Inbounds = make([]conf.InboundDetourConfig, 1) nodeInfo.V2ray.Inbounds = make([]conf.InboundDetourConfig, 1)
nodeInfo.V2ray.Inbounds[0].Protocol = "dokodemo-door" nodeInfo.V2ray.Inbounds[0].Protocol = "dokodemo-door"
@ -93,9 +94,7 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
Host: "v1.mux.cool", Host: "v1.mux.cool",
NetworkList: []string{"tcp", "udp"}, NetworkList: []string{"tcp", "udp"},
} }
} else { }*/
return nil, fmt.Errorf("unsupported node type: %s, Only support: V2ray, Trojan, Shadowsocks, and Shadowsocks-Plugin", nodeInfo.NodeType)
}
// Build Listen IP address // Build Listen IP address
ipAddress := net.ParseAddress(config.ListenIP) ipAddress := net.ParseAddress(config.ListenIP)
nodeInfo.V2ray.Inbounds[0].ListenOn = &conf.Address{Address: ipAddress} nodeInfo.V2ray.Inbounds[0].ListenOn = &conf.Address{Address: ipAddress}
@ -120,13 +119,15 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
if *nodeInfo.V2ray.Inbounds[0].StreamSetting.Network == "tcp" { if *nodeInfo.V2ray.Inbounds[0].StreamSetting.Network == "tcp" {
if nodeInfo.NodeType == "V2ray" { if nodeInfo.NodeType == "V2ray" {
nodeInfo.V2ray.Inbounds[0].StreamSetting.TCPSettings.AcceptProxyProtocol = config.EnableProxyProtocol nodeInfo.V2ray.Inbounds[0].StreamSetting.TCPSettings.AcceptProxyProtocol = config.EnableProxyProtocol
} else {
tcpSetting := &conf.TCPConfig{
AcceptProxyProtocol: config.EnableProxyProtocol,
}
nodeInfo.V2ray.Inbounds[0].StreamSetting.TCPSettings = tcpSetting
} }
tcpSetting := &conf.TCPConfig{ } else if *nodeInfo.V2ray.Inbounds[0].StreamSetting.Network == "ws" {
AcceptProxyProtocol: config.EnableProxyProtocol, nodeInfo.V2ray.Inbounds[0].StreamSetting.WSSettings = &conf.WebSocketConfig{
} AcceptProxyProtocol: config.EnableProxyProtocol}
nodeInfo.V2ray.Inbounds[0].StreamSetting.TCPSettings = tcpSetting
} else if *nodeInfo.V2ray.Inbounds[0].StreamSetting.Network == "websocket" {
nodeInfo.V2ray.Inbounds[0].StreamSetting.WSSettings.AcceptProxyProtocol = config.EnableProxyProtocol
} }
// Build TLS and XTLS settings // Build TLS and XTLS settings
if nodeInfo.EnableTls && config.CertConfig.CertMode != "none" { if nodeInfo.EnableTls && config.CertConfig.CertMode != "none" {
@ -162,8 +163,8 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
} }
nodeInfo.V2ray.Inbounds[0].StreamSetting.SocketSettings = sockoptConfig nodeInfo.V2ray.Inbounds[0].StreamSetting.SocketSettings = sockoptConfig
} }
*nodeInfo.V2ray.Inbounds[0].Settings = setting nodeInfo.V2ray.Inbounds[0].Settings = &setting
nodeInfo.V2ray.Inbounds[0].Tag = tag
return nodeInfo.V2ray.Inbounds[0].Build() return nodeInfo.V2ray.Inbounds[0].Build()
} }

View File

@ -13,9 +13,7 @@ import (
"github.com/xtls/xray-core/proxy/vless" "github.com/xtls/xray-core/proxy/vless"
) )
var AEADMethod = []shadowsocks.CipherType{shadowsocks.CipherType_AES_128_GCM, shadowsocks.CipherType_AES_256_GCM, shadowsocks.CipherType_CHACHA20_POLY1305, shadowsocks.CipherType_XCHACHA20_POLY1305} func (c *Controller) buildVmessUsers(userInfo *[]api.UserInfo, serverAlterID uint16) (users []*protocol.User) {
func (c *Controller) buildVmessUser(userInfo *[]api.UserInfo, serverAlterID uint16) (users []*protocol.User) {
users = make([]*protocol.User, len(*userInfo)) users = make([]*protocol.User, len(*userInfo))
for i, user := range *userInfo { for i, user := range *userInfo {
vmessAccount := &conf.VMessAccount{ vmessAccount := &conf.VMessAccount{
@ -32,7 +30,21 @@ func (c *Controller) buildVmessUser(userInfo *[]api.UserInfo, serverAlterID uint
return users return users
} }
func (c *Controller) buildVlessUser(userInfo *[]api.UserInfo) (users []*protocol.User) { func (c *Controller) buildVmessUser(userInfo *api.UserInfo, serverAlterID uint16) (user *protocol.User) {
vmessAccount := &conf.VMessAccount{
ID: userInfo.V2rayUser.Uuid,
AlterIds: serverAlterID,
Security: "auto",
}
user = &protocol.User{
Level: 0,
Email: c.buildUserTag(userInfo), // Email: InboundTag|email|uid
Account: serial.ToTypedMessage(vmessAccount.Build()),
}
return user
}
func (c *Controller) buildVlessUsers(userInfo *[]api.UserInfo) (users []*protocol.User) {
users = make([]*protocol.User, len(*userInfo)) users = make([]*protocol.User, len(*userInfo))
for i, user := range *userInfo { for i, user := range *userInfo {
vlessAccount := &vless.Account{ vlessAccount := &vless.Account{
@ -48,7 +60,20 @@ func (c *Controller) buildVlessUser(userInfo *[]api.UserInfo) (users []*protocol
return users return users
} }
func (c *Controller) buildTrojanUser(userInfo *[]api.UserInfo) (users []*protocol.User) { func (c *Controller) buildVlessUser(userInfo *api.UserInfo) (user *protocol.User) {
vlessAccount := &vless.Account{
Id: userInfo.V2rayUser.Uuid,
Flow: "xtls-rprx-direct",
}
user = &protocol.User{
Level: 0,
Email: c.buildUserTag(userInfo),
Account: serial.ToTypedMessage(vlessAccount),
}
return user
}
func (c *Controller) buildTrojanUsers(userInfo *[]api.UserInfo) (users []*protocol.User) {
users = make([]*protocol.User, len(*userInfo)) users = make([]*protocol.User, len(*userInfo))
for i, user := range *userInfo { for i, user := range *userInfo {
trojanAccount := &trojan.Account{ trojanAccount := &trojan.Account{
@ -64,6 +89,19 @@ func (c *Controller) buildTrojanUser(userInfo *[]api.UserInfo) (users []*protoco
return users return users
} }
func (c *Controller) buildTrojanUser(userInfo *api.UserInfo) (user *protocol.User) {
trojanAccount := &trojan.Account{
Password: userInfo.V2rayUser.Uuid,
Flow: "xtls-rprx-direct",
}
user = &protocol.User{
Level: 0,
Email: c.buildUserTag(userInfo),
Account: serial.ToTypedMessage(trojanAccount),
}
return user
}
func cipherFromString(c string) shadowsocks.CipherType { func cipherFromString(c string) shadowsocks.CipherType {
switch strings.ToLower(c) { switch strings.ToLower(c) {
case "aes-128-gcm", "aead_aes_128_gcm": case "aes-128-gcm", "aead_aes_128_gcm":
@ -79,7 +117,7 @@ func cipherFromString(c string) shadowsocks.CipherType {
} }
} }
func (c *Controller) buildSSUser(userInfo *[]api.UserInfo, method string) (users []*protocol.User) { func (c *Controller) buildSSUsers(userInfo *[]api.UserInfo, method string) (users []*protocol.User) {
users = make([]*protocol.User, 0) users = make([]*protocol.User, 0)
cypherMethod := cipherFromString(method) cypherMethod := cipherFromString(method)
@ -97,28 +135,18 @@ func (c *Controller) buildSSUser(userInfo *[]api.UserInfo, method string) (users
return users return users
} }
func (c *Controller) buildSSPluginUser(userInfo *[]api.UserInfo) (users []*protocol.User) { func (c *Controller) buildSSUser(userInfo *api.UserInfo, method string) (user *protocol.User) {
users = make([]*protocol.User, 0) cypherMethod := cipherFromString(method)
ssAccount := &shadowsocks.Account{
for _, user := range *userInfo { Password: userInfo.Secret,
// Check if the cypher method is AEAD CipherType: cypherMethod,
cypherMethod := cipherFromString(user.Cipher)
for _, aeadMethod := range AEADMethod {
if aeadMethod == cypherMethod {
ssAccount := &shadowsocks.Account{
Password: user.Secret,
CipherType: cypherMethod,
}
users = append(users, &protocol.User{
Level: 0,
Email: c.buildUserTag(&user),
Account: serial.ToTypedMessage(ssAccount),
})
}
}
} }
return users user = &protocol.User{
Level: 0,
Email: c.buildUserTag(userInfo),
Account: serial.ToTypedMessage(ssAccount),
}
return user
} }
func (c *Controller) buildUserTag(user *api.UserInfo) string { func (c *Controller) buildUserTag(user *api.UserInfo) string {