init
This commit is contained in:
76
internal/xrpc/services/handler/common.go
Normal file
76
internal/xrpc/services/handler/common.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
cnet "github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/uuid"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
func receiverSettings(port uint32, enableSniff bool) *serial.TypedMessage {
|
||||
pr := cnet.SinglePortRange(cnet.Port(port))
|
||||
rc := &proxyman.ReceiverConfig{
|
||||
PortList: &cnet.PortList{Range: []*cnet.PortRange{pr}},
|
||||
Listen: cnet.NewIPOrDomain(cnet.AnyIP),
|
||||
StreamSettings: &internet.StreamConfig{
|
||||
ProtocolName: "tcp",
|
||||
},
|
||||
}
|
||||
if enableSniff {
|
||||
rc.SniffingSettings = &proxyman.SniffingConfig{
|
||||
Enabled: true,
|
||||
DestinationOverride: []string{"http", "tls"},
|
||||
}
|
||||
}
|
||||
return serial.ToTypedMessage(rc)
|
||||
}
|
||||
|
||||
func senderSettings() *serial.TypedMessage {
|
||||
return serial.ToTypedMessage(&proxyman.SenderConfig{
|
||||
StreamSettings: &internet.StreamConfig{
|
||||
ProtocolName: "tcp",
|
||||
},
|
||||
MultiplexSettings: &proxyman.MultiplexingConfig{
|
||||
Enabled: true,
|
||||
Concurrency: 8,
|
||||
XudpProxyUDP443: "reject",
|
||||
},
|
||||
TargetStrategy: internet.DomainStrategy_USE_IP,
|
||||
})
|
||||
}
|
||||
|
||||
func endpoint(address string, port uint32, user *protocol.User) *protocol.ServerEndpoint {
|
||||
return &protocol.ServerEndpoint{
|
||||
Address: cnet.NewIPOrDomain(cnet.ParseAddress(address)),
|
||||
Port: port,
|
||||
User: user,
|
||||
}
|
||||
}
|
||||
|
||||
func randomUUID() string {
|
||||
u := uuid.New()
|
||||
return (&u).String()
|
||||
}
|
||||
|
||||
func cnetOrDomain(value string) *cnet.IPOrDomain {
|
||||
return cnet.NewIPOrDomain(cnet.ParseAddress(value))
|
||||
}
|
||||
|
||||
func inboundConfig(tag string, receiver *serial.TypedMessage, proxy *serial.TypedMessage) *core.InboundHandlerConfig {
|
||||
return &core.InboundHandlerConfig{
|
||||
Tag: tag,
|
||||
ReceiverSettings: receiver,
|
||||
ProxySettings: proxy,
|
||||
}
|
||||
}
|
||||
|
||||
func outboundConfig(tag string, sender *serial.TypedMessage, proxy *serial.TypedMessage) *core.OutboundHandlerConfig {
|
||||
return &core.OutboundHandlerConfig{
|
||||
Tag: tag,
|
||||
SenderSettings: sender,
|
||||
ProxySettings: proxy,
|
||||
}
|
||||
}
|
||||
274
internal/xrpc/services/handler/inbound.go
Normal file
274
internal/xrpc/services/handler/inbound.go
Normal file
@@ -0,0 +1,274 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman/command"
|
||||
cnet "github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/proxy/dns"
|
||||
"github.com/xtls/xray-core/proxy/dokodemo"
|
||||
"github.com/xtls/xray-core/proxy/http"
|
||||
"github.com/xtls/xray-core/proxy/loopback"
|
||||
"github.com/xtls/xray-core/proxy/shadowsocks"
|
||||
ss2022 "github.com/xtls/xray-core/proxy/shadowsocks_2022"
|
||||
"github.com/xtls/xray-core/proxy/socks"
|
||||
"github.com/xtls/xray-core/proxy/trojan"
|
||||
"github.com/xtls/xray-core/proxy/vless"
|
||||
vlessin "github.com/xtls/xray-core/proxy/vless/inbound"
|
||||
"github.com/xtls/xray-core/proxy/vmess"
|
||||
vmessin "github.com/xtls/xray-core/proxy/vmess/inbound"
|
||||
"github.com/xtls/xray-core/proxy/wireguard"
|
||||
)
|
||||
|
||||
// AddVMessInbound demonstrates HandlerServiceClient.AddInbound for VMess inbound.
|
||||
func AddVMessInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, true),
|
||||
serial.ToTypedMessage(&vmessin.Config{
|
||||
User: []*protocol.User{
|
||||
{
|
||||
Level: 0,
|
||||
Email: "demo@vmess.local",
|
||||
Account: serial.ToTypedMessage(&vmess.Account{
|
||||
Id: randomUUID(),
|
||||
SecuritySettings: &protocol.SecurityConfig{
|
||||
Type: protocol.SecurityType_AUTO,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
Default: &vmessin.DefaultConfig{Level: 0},
|
||||
}),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddVLESSInbound adds a VLESS inbound with Vision style fallbacks.
|
||||
func AddVLESSInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, true),
|
||||
serial.ToTypedMessage(&vlessin.Config{
|
||||
Clients: []*protocol.User{
|
||||
{
|
||||
Level: 1,
|
||||
Email: "client@vless.local",
|
||||
Account: serial.ToTypedMessage(&vless.Account{
|
||||
Id: randomUUID(),
|
||||
Encryption: "none",
|
||||
}),
|
||||
},
|
||||
},
|
||||
Fallbacks: []*vlessin.Fallback{
|
||||
{
|
||||
Name: "websocket",
|
||||
Alpn: "h2",
|
||||
Path: "/ws",
|
||||
Type: "http",
|
||||
Dest: "127.0.0.1:8080",
|
||||
Xver: 1,
|
||||
},
|
||||
},
|
||||
Decryption: "none",
|
||||
Padding: "enable",
|
||||
}),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddTrojanInbound registers a Trojan inbound with two users and ALPN fallback.
|
||||
func AddTrojanInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, true),
|
||||
serial.ToTypedMessage(&trojan.ServerConfig{
|
||||
Users: []*protocol.User{
|
||||
{
|
||||
Level: 0,
|
||||
Email: "alice@trojan.local",
|
||||
Account: serial.ToTypedMessage(&trojan.Account{
|
||||
Password: randomUUID(),
|
||||
}),
|
||||
},
|
||||
{
|
||||
Level: 0,
|
||||
Email: "bob@trojan.local",
|
||||
Account: serial.ToTypedMessage(&trojan.Account{
|
||||
Password: randomUUID(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
Fallbacks: []*trojan.Fallback{
|
||||
{
|
||||
Name: "http",
|
||||
Alpn: "http/1.1",
|
||||
Dest: "127.0.0.1:8081",
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddShadowsocksInbound adds an AEAD Shadowsocks inbound supporting both TCP and UDP.
|
||||
func AddShadowsocksInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, false),
|
||||
serial.ToTypedMessage(&shadowsocks.ServerConfig{
|
||||
Users: []*protocol.User{
|
||||
{
|
||||
Level: 0,
|
||||
Email: "ss@demo.local",
|
||||
Account: serial.ToTypedMessage(&shadowsocks.Account{
|
||||
Password: "s3cret-pass",
|
||||
CipherType: shadowsocks.CipherType_AES_128_GCM,
|
||||
}),
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddShadowsocks2022Inbound covers both single user and multi-user deployment.
|
||||
func AddShadowsocks2022Inbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
|
||||
server := &ss2022.MultiUserServerConfig{
|
||||
Method: "2022-blake3-aes-128-gcm",
|
||||
Key: "0123456789abcdef0123456789abcdef",
|
||||
Users: []*protocol.User{
|
||||
{
|
||||
Level: 0,
|
||||
Email: "user1@ss2022.local",
|
||||
Account: serial.ToTypedMessage(&ss2022.Account{
|
||||
Key: randomUUID(),
|
||||
}),
|
||||
},
|
||||
{
|
||||
Level: 0,
|
||||
Email: "user2@ss2022.local",
|
||||
Account: serial.ToTypedMessage(&ss2022.Account{
|
||||
Key: randomUUID(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, false),
|
||||
serial.ToTypedMessage(server),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddSocksInbound exposes a SOCKS5 server with username/password authentication.
|
||||
func AddSocksInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, false),
|
||||
serial.ToTypedMessage(&socks.ServerConfig{
|
||||
AuthType: socks.AuthType_PASSWORD,
|
||||
Accounts: map[string]string{"demo": "passw0rd"},
|
||||
UdpEnabled: true,
|
||||
UserLevel: 0,
|
||||
}),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddHTTPInbound adds an HTTP proxy inbound with basic auth.
|
||||
func AddHTTPInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, false),
|
||||
serial.ToTypedMessage(&http.ServerConfig{
|
||||
Accounts: map[string]string{"demo": "http-pass"},
|
||||
AllowTransparent: true,
|
||||
UserLevel: 0,
|
||||
}),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddDokodemoInbound configures a dokodemo-door mirror port.
|
||||
func AddDokodemoInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32, targetPort uint32) error {
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, false),
|
||||
serial.ToTypedMessage(&dokodemo.Config{
|
||||
Address: cnetOrDomain("example.com"),
|
||||
Port: targetPort,
|
||||
Networks: []cnet.Network{cnet.Network_TCP, cnet.Network_UDP},
|
||||
FollowRedirect: false,
|
||||
UserLevel: 0,
|
||||
}),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddDNSInbound exposes the built-in DNS server on an API port.
|
||||
func AddDNSInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, false),
|
||||
serial.ToTypedMessage(&dns.Config{
|
||||
Server: &cnet.Endpoint{
|
||||
Network: cnet.Network_UDP,
|
||||
Address: cnetOrDomain("1.1.1.1"),
|
||||
Port: 53,
|
||||
},
|
||||
Non_IPQuery: "drop",
|
||||
BlockTypes: []int32{65, 28},
|
||||
}),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddLoopbackInbound ties an inbound to an existing outbound chain.
|
||||
func AddLoopbackInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32, targetInbound string) error {
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, false),
|
||||
serial.ToTypedMessage(&loopback.Config{InboundTag: targetInbound}),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
|
||||
// AddWireGuardInbound sets up a WireGuard entry point with a single peer.
|
||||
func AddWireGuardInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
|
||||
cfg := &wireguard.DeviceConfig{
|
||||
SecretKey: "yAnExampleSecretKeyBase64==",
|
||||
Endpoint: []string{":51820"},
|
||||
Mtu: 1420,
|
||||
NumWorkers: 2,
|
||||
DomainStrategy: wireguard.DeviceConfig_FORCE_IP46,
|
||||
Peers: []*wireguard.PeerConfig{
|
||||
{
|
||||
PublicKey: "peerPublicKeyBase64==",
|
||||
Endpoint: "203.0.113.1:51820",
|
||||
KeepAlive: 25,
|
||||
AllowedIps: []string{"0.0.0.0/0", "::/0"},
|
||||
},
|
||||
},
|
||||
}
|
||||
inbound := inboundConfig(
|
||||
tag,
|
||||
receiverSettings(port, false),
|
||||
serial.ToTypedMessage(cfg),
|
||||
)
|
||||
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
|
||||
return err
|
||||
}
|
||||
59
internal/xrpc/services/handler/management.go
Normal file
59
internal/xrpc/services/handler/management.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman/command"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
)
|
||||
|
||||
func RemoveInbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
_, err := client.RemoveInbound(ctx, &command.RemoveInboundRequest{Tag: tag})
|
||||
return err
|
||||
}
|
||||
|
||||
func RemoveOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
_, err := client.RemoveOutbound(ctx, &command.RemoveOutboundRequest{Tag: tag})
|
||||
return err
|
||||
}
|
||||
|
||||
func ListInboundTags(ctx context.Context, client command.HandlerServiceClient) ([]string, error) {
|
||||
resp, err := client.ListInbounds(ctx, &command.ListInboundsRequest{IsOnlyTags: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tags := make([]string, 0, len(resp.GetInbounds()))
|
||||
for _, inbound := range resp.GetInbounds() {
|
||||
tags = append(tags, inbound.GetTag())
|
||||
}
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
func GetInboundUsers(ctx context.Context, client command.HandlerServiceClient, inboundTag string) ([]*protocol.User, error) {
|
||||
resp, err := client.GetInboundUsers(ctx, &command.GetInboundUserRequest{
|
||||
Tag: inboundTag,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.GetUsers(), nil
|
||||
}
|
||||
|
||||
func GetInboundUsersCount(ctx context.Context, client command.HandlerServiceClient, inboundTag string) (int64, error) {
|
||||
resp, err := client.GetInboundUsersCount(ctx, &command.GetInboundUserRequest{
|
||||
Tag: inboundTag,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return resp.GetCount(), nil
|
||||
}
|
||||
|
||||
func AlterOutbound(ctx context.Context, client command.HandlerServiceClient, tag string, operation *serial.TypedMessage) error {
|
||||
_, err := client.AlterOutbound(ctx, &command.AlterOutboundRequest{
|
||||
Tag: tag,
|
||||
Operation: operation,
|
||||
})
|
||||
return err
|
||||
}
|
||||
221
internal/xrpc/services/handler/outbound.go
Normal file
221
internal/xrpc/services/handler/outbound.go
Normal file
@@ -0,0 +1,221 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman/command"
|
||||
cnet "github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/proxy/blackhole"
|
||||
"github.com/xtls/xray-core/proxy/dns"
|
||||
"github.com/xtls/xray-core/proxy/freedom"
|
||||
"github.com/xtls/xray-core/proxy/http"
|
||||
"github.com/xtls/xray-core/proxy/shadowsocks"
|
||||
ss2022 "github.com/xtls/xray-core/proxy/shadowsocks_2022"
|
||||
"github.com/xtls/xray-core/proxy/socks"
|
||||
"github.com/xtls/xray-core/proxy/trojan"
|
||||
"github.com/xtls/xray-core/proxy/vless"
|
||||
vlessout "github.com/xtls/xray-core/proxy/vless/outbound"
|
||||
"github.com/xtls/xray-core/proxy/vmess"
|
||||
vmessout "github.com/xtls/xray-core/proxy/vmess/outbound"
|
||||
"github.com/xtls/xray-core/proxy/wireguard"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
func AddFreedomOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&freedom.Config{
|
||||
DomainStrategy: internet.DomainStrategy_AS_IS,
|
||||
UserLevel: 0,
|
||||
Fragment: &freedom.Fragment{
|
||||
PacketsFrom: 5,
|
||||
PacketsTo: 10,
|
||||
LengthMin: 50,
|
||||
LengthMax: 150,
|
||||
IntervalMin: 10,
|
||||
IntervalMax: 20,
|
||||
},
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
|
||||
func AddBlackholeOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&blackhole.Config{
|
||||
Response: serial.ToTypedMessage(&blackhole.HTTPResponse{}),
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
|
||||
func AddDNSOutbound(ctx context.Context, client command.HandlerServiceClient, tag string, upstream string) error {
|
||||
endpointCfg := &cnet.Endpoint{
|
||||
Network: cnet.Network_UDP,
|
||||
Address: cnet.NewIPOrDomain(cnet.ParseAddress(upstream)),
|
||||
Port: 53,
|
||||
}
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&dns.Config{
|
||||
Server: endpointCfg,
|
||||
UserLevel: 0,
|
||||
BlockTypes: []int32{1, 28},
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
|
||||
func AddHTTPOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&http.ClientConfig{
|
||||
Server: endpoint("example.com", 80, nil),
|
||||
Header: []*http.Header{
|
||||
{Key: "User-Agent", Value: "miaomiaowu"},
|
||||
},
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
|
||||
func AddSocksOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&socks.ClientConfig{
|
||||
Server: endpoint("127.0.0.1", 1080, nil),
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
|
||||
func AddTrojanOutbound(ctx context.Context, client command.HandlerServiceClient, tag string, password string) error {
|
||||
user := &protocol.User{
|
||||
Email: "trojan@client.local",
|
||||
Level: 0,
|
||||
Account: serial.ToTypedMessage(&trojan.Account{
|
||||
Password: password,
|
||||
}),
|
||||
}
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&trojan.ClientConfig{
|
||||
Server: endpoint("trojan.example.com", 443, user),
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
|
||||
func AddShadowsocksOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
user := &protocol.User{
|
||||
Email: "ss@client.local",
|
||||
Account: serial.ToTypedMessage(&shadowsocks.Account{
|
||||
Password: "client-pass",
|
||||
CipherType: shadowsocks.CipherType_AES_256_GCM,
|
||||
}),
|
||||
}
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
||||
Server: endpoint("ss.example.com", 8388, user),
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
|
||||
func AddShadowsocks2022Outbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&ss2022.ClientConfig{
|
||||
Address: cnetOrDomain("203.0.113.2"),
|
||||
Port: 8389,
|
||||
Method: "2022-blake3-aes-256-gcm",
|
||||
Key: "clientkeybase64==",
|
||||
UdpOverTcp: true,
|
||||
UdpOverTcpVersion: 2,
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
|
||||
func AddVLESSOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
user := &protocol.User{
|
||||
Email: "vless@client.local",
|
||||
Account: serial.ToTypedMessage(&vless.Account{
|
||||
Id: randomUUID(),
|
||||
Encryption: "none",
|
||||
}),
|
||||
}
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&vlessout.Config{
|
||||
Vnext: endpoint("vless.example.com", 443, user),
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
|
||||
func AddVMessOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
user := &protocol.User{
|
||||
Email: "vmess@client.local",
|
||||
Account: serial.ToTypedMessage(&vmess.Account{
|
||||
Id: randomUUID(),
|
||||
SecuritySettings: &protocol.SecurityConfig{
|
||||
Type: protocol.SecurityType_AUTO,
|
||||
},
|
||||
}),
|
||||
}
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&vmessout.Config{
|
||||
Receiver: endpoint("vmess.example.com", 443, user),
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
|
||||
func AddWireGuardOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
|
||||
cfg := outboundConfig(
|
||||
tag,
|
||||
senderSettings(),
|
||||
serial.ToTypedMessage(&wireguard.DeviceConfig{
|
||||
SecretKey: "clientSecretKeyBase64==",
|
||||
Endpoint: []string{"198.51.100.2:51820"},
|
||||
IsClient: true,
|
||||
Mtu: 1420,
|
||||
DomainStrategy: wireguard.DeviceConfig_FORCE_IP4,
|
||||
Peers: []*wireguard.PeerConfig{
|
||||
{
|
||||
PublicKey: "serverPublicKeyBase64==",
|
||||
AllowedIps: []string{"0.0.0.0/0"},
|
||||
KeepAlive: 30,
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
|
||||
return err
|
||||
}
|
||||
120
internal/xrpc/services/handler/users.go
Normal file
120
internal/xrpc/services/handler/users.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman/command"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/proxy/shadowsocks"
|
||||
ss2022 "github.com/xtls/xray-core/proxy/shadowsocks_2022"
|
||||
"github.com/xtls/xray-core/proxy/trojan"
|
||||
"github.com/xtls/xray-core/proxy/vless"
|
||||
"github.com/xtls/xray-core/proxy/vmess"
|
||||
)
|
||||
|
||||
// AddVMessUser demonstrates AlterInbound(AddUserOperation) for VMess.
|
||||
func AddVMessUser(ctx context.Context, client command.HandlerServiceClient, inboundTag, email string) error {
|
||||
req := &command.AlterInboundRequest{
|
||||
Tag: inboundTag,
|
||||
Operation: serial.ToTypedMessage(&command.AddUserOperation{
|
||||
User: &protocol.User{
|
||||
Level: 0,
|
||||
Email: email,
|
||||
Account: serial.ToTypedMessage(&vmess.Account{
|
||||
Id: randomUUID(),
|
||||
SecuritySettings: &protocol.SecurityConfig{
|
||||
Type: protocol.SecurityType_AUTO,
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
}
|
||||
_, err := client.AlterInbound(ctx, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddVLESSUser shows how to add VLESS users dynamically.
|
||||
func AddVLESSUser(ctx context.Context, client command.HandlerServiceClient, inboundTag, email string) error {
|
||||
req := &command.AlterInboundRequest{
|
||||
Tag: inboundTag,
|
||||
Operation: serial.ToTypedMessage(&command.AddUserOperation{
|
||||
User: &protocol.User{
|
||||
Level: 0,
|
||||
Email: email,
|
||||
Account: serial.ToTypedMessage(&vless.Account{
|
||||
Id: randomUUID(),
|
||||
Encryption: "none",
|
||||
}),
|
||||
},
|
||||
}),
|
||||
}
|
||||
_, err := client.AlterInbound(ctx, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddTrojanUser adds a Trojan password to an inbound handler.
|
||||
func AddTrojanUser(ctx context.Context, client command.HandlerServiceClient, inboundTag, email, password string) error {
|
||||
req := &command.AlterInboundRequest{
|
||||
Tag: inboundTag,
|
||||
Operation: serial.ToTypedMessage(&command.AddUserOperation{
|
||||
User: &protocol.User{
|
||||
Level: 0,
|
||||
Email: email,
|
||||
Account: serial.ToTypedMessage(&trojan.Account{
|
||||
Password: password,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
}
|
||||
_, err := client.AlterInbound(ctx, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddShadowsocksUser sets up a Shadowsocks AEAD credential.
|
||||
func AddShadowsocksUser(ctx context.Context, client command.HandlerServiceClient, inboundTag, email, password string) error {
|
||||
req := &command.AlterInboundRequest{
|
||||
Tag: inboundTag,
|
||||
Operation: serial.ToTypedMessage(&command.AddUserOperation{
|
||||
User: &protocol.User{
|
||||
Level: 0,
|
||||
Email: email,
|
||||
Account: serial.ToTypedMessage(&shadowsocks.Account{
|
||||
Password: password,
|
||||
CipherType: shadowsocks.CipherType_CHACHA20_POLY1305,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
}
|
||||
_, err := client.AlterInbound(ctx, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddShadowsocks2022User covers key rotation for SS2022.
|
||||
func AddShadowsocks2022User(ctx context.Context, client command.HandlerServiceClient, inboundTag, email string) error {
|
||||
req := &command.AlterInboundRequest{
|
||||
Tag: inboundTag,
|
||||
Operation: serial.ToTypedMessage(&command.AddUserOperation{
|
||||
User: &protocol.User{
|
||||
Email: email,
|
||||
Account: serial.ToTypedMessage(&ss2022.Account{
|
||||
Key: randomUUID(),
|
||||
}),
|
||||
},
|
||||
}),
|
||||
}
|
||||
_, err := client.AlterInbound(ctx, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveUser removes any user (identified by email) from an inbound.
|
||||
func RemoveUser(ctx context.Context, client command.HandlerServiceClient, inboundTag, email string) error {
|
||||
req := &command.AlterInboundRequest{
|
||||
Tag: inboundTag,
|
||||
Operation: serial.ToTypedMessage(&command.RemoveUserOperation{
|
||||
Email: email,
|
||||
}),
|
||||
}
|
||||
_, err := client.AlterInbound(ctx, req)
|
||||
return err
|
||||
}
|
||||
16
internal/xrpc/services/logger/logger.go
Normal file
16
internal/xrpc/services/logger/logger.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
loggerpb "github.com/xtls/xray-core/app/log/command"
|
||||
)
|
||||
|
||||
// RestartLogger triggers the LoggerService restartLogger RPC and waits for completion.
|
||||
func RestartLogger(ctx context.Context, client loggerpb.LoggerServiceClient) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
_, err := client.RestartLogger(ctx, &loggerpb.RestartLoggerRequest{})
|
||||
return err
|
||||
}
|
||||
30
internal/xrpc/services/stats/stats.go
Normal file
30
internal/xrpc/services/stats/stats.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
statspb "github.com/xtls/xray-core/app/stats/command"
|
||||
)
|
||||
|
||||
func QueryTraffic(ctx context.Context, client statspb.StatsServiceClient, pattern string, reset bool) (int64, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
resp, err := client.QueryStats(ctx, &statspb.QueryStatsRequest{
|
||||
Pattern: pattern,
|
||||
Reset_: reset,
|
||||
})
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if len(resp.GetStat()) == 0 {
|
||||
return -1, nil
|
||||
}
|
||||
return resp.GetStat()[0].GetValue(), nil
|
||||
}
|
||||
|
||||
func GetSystemStats(ctx context.Context, client statspb.StatsServiceClient) (*statspb.SysStatsResponse, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
return client.GetSysStats(ctx, &statspb.SysStatsRequest{})
|
||||
}
|
||||
Reference in New Issue
Block a user