mirror of
https://github.com/XrayR-project/XrayR.git
synced 2025-08-03 07:56:54 +00:00
Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d9089520db | ||
![]() |
bdbf916a14 | ||
![]() |
1ec1765517 | ||
![]() |
f29d2db235 | ||
![]() |
337f441c32 | ||
![]() |
c9895fa02f | ||
![]() |
5d6eeb4f29 | ||
![]() |
fc9cb4ac10 | ||
![]() |
01ef6fb699 | ||
![]() |
e46dc1d8d7 | ||
![]() |
84db0453cb | ||
![]() |
b934a52875 | ||
![]() |
246f9374a4 | ||
![]() |
4dd827d94d | ||
![]() |
c349d3d9a1 | ||
![]() |
48ca6d9648 | ||
![]() |
f7d1114fb2 | ||
![]() |
dbf7727bcd | ||
![]() |
09f27ec1f1 | ||
![]() |
61b501de3d | ||
![]() |
9947d7e4f3 | ||
![]() |
a0e1491bb5 | ||
![]() |
b31bef02da | ||
![]() |
25594bf9e2 | ||
![]() |
1566ffd937 | ||
![]() |
5682ab37db | ||
![]() |
454afe5285 | ||
![]() |
807a7182bb | ||
![]() |
911d06bece | ||
![]() |
7f823007cb | ||
![]() |
943660ee56 | ||
![]() |
8195f72eaa | ||
![]() |
35a6585db1 | ||
![]() |
f0911f6239 | ||
![]() |
afc11dbb41 | ||
![]() |
e1b0cd3c79 | ||
![]() |
6ce4d4e7a2 | ||
![]() |
febeee6b2c | ||
![]() |
fbe57822ce | ||
![]() |
63697586a2 | ||
![]() |
6b6e2a03d8 | ||
![]() |
674445afae | ||
![]() |
bf29bd11c4 | ||
![]() |
40ba9b202b | ||
![]() |
39a09bea92 | ||
![]() |
5c0eea8d44 | ||
![]() |
69b0afcb35 |
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v1
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v1
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
@@ -64,4 +64,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v1
|
uses: github/codeql-action/analyze@v2
|
||||||
|
25
.github/workflows/docker.yml
vendored
25
.github/workflows/docker.yml
vendored
@@ -2,8 +2,18 @@ name: Publish Docker image
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- "**/*.go"
|
||||||
|
- "go.mod"
|
||||||
|
- "go.sum"
|
||||||
|
- ".github/workflows/*.yml"
|
||||||
tags:
|
tags:
|
||||||
- 'v*'
|
- 'v*'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
jobs:
|
jobs:
|
||||||
push_to_registry:
|
push_to_registry:
|
||||||
name: Push Docker image to Docker Hub
|
name: Push Docker image to Docker Hub
|
||||||
@@ -13,13 +23,10 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
-
|
-
|
||||||
name: Docker meta
|
name: Docker meta
|
||||||
id: docker_meta
|
id: meta
|
||||||
uses: crazy-max/ghaction-docker-meta@v1
|
uses: docker/metadata-action@v4
|
||||||
with:
|
with:
|
||||||
images: crackair/xrayr
|
images: mengxin239/xrayr
|
||||||
tag-semver: |
|
|
||||||
{{version}}
|
|
||||||
{{major}}.{{minor}}
|
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v1
|
||||||
@@ -34,7 +41,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/arm/v7,linux/arm64,linux/amd64
|
platforms: linux/arm/v7,linux/arm64,linux/amd64,linux/s390x
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
7
.github/workflows/release.yml
vendored
7
.github/workflows/release.yml
vendored
@@ -74,8 +74,8 @@ jobs:
|
|||||||
goarch: mips
|
goarch: mips
|
||||||
# END MIPS
|
# END MIPS
|
||||||
# BEGIN PPC
|
# BEGIN PPC
|
||||||
- goos: linux
|
# - goos: linux # Removed due to the unsupport of shirou/gopsutil
|
||||||
goarch: ppc64
|
# goarch: ppc64
|
||||||
- goos: linux
|
- goos: linux
|
||||||
goarch: ppc64le
|
goarch: ppc64le
|
||||||
# END PPC
|
# END PPC
|
||||||
@@ -113,7 +113,7 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: ^1.17.2
|
go-version: ^1.18
|
||||||
|
|
||||||
- name: Get project dependencies
|
- name: Get project dependencies
|
||||||
run: go mod download
|
run: go mod download
|
||||||
@@ -141,6 +141,7 @@ jobs:
|
|||||||
cp ${GITHUB_WORKSPACE}/main/dns.json ./build_assets/dns.json
|
cp ${GITHUB_WORKSPACE}/main/dns.json ./build_assets/dns.json
|
||||||
cp ${GITHUB_WORKSPACE}/main/route.json ./build_assets/route.json
|
cp ${GITHUB_WORKSPACE}/main/route.json ./build_assets/route.json
|
||||||
cp ${GITHUB_WORKSPACE}/main/custom_outbound.json ./build_assets/custom_outbound.json
|
cp ${GITHUB_WORKSPACE}/main/custom_outbound.json ./build_assets/custom_outbound.json
|
||||||
|
cp ${GITHUB_WORKSPACE}/main/custom_inbound.json ./build_assets/custom_inbound.json
|
||||||
cp ${GITHUB_WORKSPACE}/main/rulelist ./build_assets/rulelist
|
cp ${GITHUB_WORKSPACE}/main/rulelist ./build_assets/rulelist
|
||||||
cp ${GITHUB_WORKSPACE}/main/config.yml.example ./build_assets/config.yml
|
cp ${GITHUB_WORKSPACE}/main/config.yml.example ./build_assets/config.yml
|
||||||
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
|
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
|
||||||
|
20
.github/workflows/sync.yml
vendored
Normal file
20
.github/workflows/sync.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
name: Sync to Gitlab
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
delete:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
to_gitlab:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: pixta-dev/repository-mirroring-action@v1
|
||||||
|
with:
|
||||||
|
target_repo_url:
|
||||||
|
git@gitlab.com:xrayr-project/XrayR.git
|
||||||
|
ssh_private_key:
|
||||||
|
${{ secrets.SSH_PRIVATEKEY }}
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -12,4 +12,5 @@ main/.lego
|
|||||||
main/cert
|
main/cert
|
||||||
main/config.yml
|
main/config.yml
|
||||||
./vscode
|
./vscode
|
||||||
.idea/*
|
.idea/*
|
||||||
|
.DS_Store
|
@@ -1,5 +1,5 @@
|
|||||||
# Build go
|
# Build go
|
||||||
FROM golang:1.17-alpine AS builder
|
FROM golang:1.18-alpine AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
ENV CGO_ENABLED=0
|
ENV CGO_ENABLED=0
|
||||||
|
13
README.md
13
README.md
@@ -8,7 +8,7 @@ A Xray backend framework that can easily support many panels.
|
|||||||
|
|
||||||
如果您喜欢本项目,可以右上角点个star+watch,持续关注本项目的进展。
|
如果您喜欢本项目,可以右上角点个star+watch,持续关注本项目的进展。
|
||||||
|
|
||||||
使用教程:[详细使用教程](https://crackair.gitbook.io/xrayr-project/)
|
使用教程:[详细使用教程](https://xrayr-project.github.io/XrayR-doc/)
|
||||||
## 免责声明
|
## 免责声明
|
||||||
|
|
||||||
本项目只是本人个人学习开发并维护,本人不保证任何可用性,也不对使用本软件造成的任何后果负责。
|
本项目只是本人个人学习开发并维护,本人不保证任何可用性,也不对使用本软件造成的任何后果负责。
|
||||||
@@ -48,21 +48,22 @@ A Xray backend framework that can easily support many panels.
|
|||||||
| v2board | √ | √ | √ |
|
| v2board | √ | √ | √ |
|
||||||
| [PMPanel](https://github.com/ByteInternetHK/PMPanel) | √ | √ | √ |
|
| [PMPanel](https://github.com/ByteInternetHK/PMPanel) | √ | √ | √ |
|
||||||
| [ProxyPanel](https://github.com/ProxyPanel/ProxyPanel) | √ | √ | √ |
|
| [ProxyPanel](https://github.com/ProxyPanel/ProxyPanel) | √ | √ | √ |
|
||||||
|
| [WHMCS (v2raysocks)](https://v2raysocks.doxtex.com/) | √ | √ | √ |
|
||||||
|
|
||||||
## 软件安装
|
## 软件安装
|
||||||
### 一键安装
|
### 一键安装
|
||||||
```
|
```
|
||||||
bash <(curl -Ls https://raw.githubusercontent.com/XrayR-project/XrayR-release/master/install.sh)
|
wget -N https://raw.githubusercontent.com/XrayR-project/XrayR-release/master/install.sh && bash install.sh
|
||||||
```
|
```
|
||||||
### 使用Docker部署软件
|
### 使用Docker部署软件
|
||||||
[Docker部署教程](https://crackair.gitbook.io/xrayr-project/xrayr-xia-zai-he-an-zhuang/install/docker)
|
[Docker部署教程](https://xrayr-project.github.io/XrayR-doc/xrayr-xia-zai-he-an-zhuang/install/docker)
|
||||||
|
|
||||||
### 手动安装
|
### 手动安装
|
||||||
[手动安装教程](https://crackair.gitbook.io/xrayr-project/xrayr-xia-zai-he-an-zhuang/install/manual)
|
[手动安装教程](https://xrayr-project.github.io/XrayR-doc/xrayr-xia-zai-he-an-zhuang/install/manual)
|
||||||
|
|
||||||
## 配置文件及详细使用教程
|
## 配置文件及详细使用教程
|
||||||
|
|
||||||
[详细使用教程](https://crackair.gitbook.io/xrayr-project/)
|
[详细使用教程](https://xrayr-project.github.io/XrayR-doc/)
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
|
|
||||||
@@ -80,7 +81,9 @@ bash <(curl -Ls https://raw.githubusercontent.com/XrayR-project/XrayR-release/ma
|
|||||||
[XrayR后端讨论](https://t.me/XrayR_project)
|
[XrayR后端讨论](https://t.me/XrayR_project)
|
||||||
|
|
||||||
[XrayR通知](https://t.me/XrayR_channel)
|
[XrayR通知](https://t.me/XrayR_channel)
|
||||||
|
|
||||||
## Stargazers over time
|
## Stargazers over time
|
||||||
|
|
||||||
[](https://starchart.cc/XrayR-project/XrayR)
|
[](https://starchart.cc/XrayR-project/XrayR)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -25,15 +25,15 @@ type NodeStatus struct {
|
|||||||
CPU float64
|
CPU float64
|
||||||
Mem float64
|
Mem float64
|
||||||
Disk float64
|
Disk float64
|
||||||
Uptime int
|
Uptime uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeInfo struct {
|
type NodeInfo struct {
|
||||||
NodeType string // Must be V2ray, Trojan, and Shadowsocks
|
NodeType string // Must be V2ray, Trojan, and Shadowsocks
|
||||||
NodeID int
|
NodeID int
|
||||||
Port int
|
Port uint32
|
||||||
SpeedLimit uint64 // Bps
|
SpeedLimit uint64 // Bps
|
||||||
AlterID int
|
AlterID uint16
|
||||||
TransportProtocol string
|
TransportProtocol string
|
||||||
FakeType string
|
FakeType string
|
||||||
Host string
|
Host string
|
||||||
@@ -50,7 +50,7 @@ type UserInfo struct {
|
|||||||
UID int
|
UID int
|
||||||
Email string
|
Email string
|
||||||
Passwd string
|
Passwd string
|
||||||
Port int
|
Port uint32
|
||||||
Method string
|
Method string
|
||||||
SpeedLimit uint64 // Bps
|
SpeedLimit uint64 // Bps
|
||||||
DeviceLimit int
|
DeviceLimit int
|
||||||
@@ -59,7 +59,7 @@ type UserInfo struct {
|
|||||||
Obfs string
|
Obfs string
|
||||||
ObfsParam string
|
ObfsParam string
|
||||||
UUID string
|
UUID string
|
||||||
AlterID int
|
AlterID uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
type OnlineUser struct {
|
type OnlineUser struct {
|
||||||
|
@@ -9,8 +9,8 @@ type NodeInfoResponse struct {
|
|||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
TrafficRate float64 `json:"trafficRate"`
|
TrafficRate float64 `json:"trafficRate"`
|
||||||
RawServerString string `json:"outServer"`
|
RawServerString string `json:"outServer"`
|
||||||
Port int `json:"outPort"`
|
Port uint32 `json:"outPort"`
|
||||||
AlterId int `json:"alterId"`
|
AlterId uint16 `json:"alterId"`
|
||||||
Network string `json:"network"`
|
Network string `json:"network"`
|
||||||
Security string `json:"security"`
|
Security string `json:"security"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
|
@@ -411,11 +411,8 @@ func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *NodeInfoResponse) (
|
|||||||
|
|
||||||
// ParseSSNodeResponse parse the response for the given nodeinfor format
|
// ParseSSNodeResponse parse the response for the given nodeinfor format
|
||||||
func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error) {
|
func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error) {
|
||||||
var port int = 0
|
|
||||||
var speedlimit uint64 = 0
|
var speedlimit uint64 = 0
|
||||||
|
|
||||||
port = nodeInfoResponse.Port
|
|
||||||
|
|
||||||
if c.SpeedLimit > 0 {
|
if c.SpeedLimit > 0 {
|
||||||
speedlimit = uint64((c.SpeedLimit * 1000000) / 8)
|
speedlimit = uint64((c.SpeedLimit * 1000000) / 8)
|
||||||
} else {
|
} else {
|
||||||
@@ -425,7 +422,7 @@ func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *NodeInfoResponse) (*ap
|
|||||||
nodeinfo := &api.NodeInfo{
|
nodeinfo := &api.NodeInfo{
|
||||||
NodeType: c.NodeType,
|
NodeType: c.NodeType,
|
||||||
NodeID: c.NodeID,
|
NodeID: c.NodeID,
|
||||||
Port: port,
|
Port: nodeInfoResponse.Port,
|
||||||
SpeedLimit: speedlimit,
|
SpeedLimit: speedlimit,
|
||||||
TransportProtocol: "tcp",
|
TransportProtocol: "tcp",
|
||||||
CypherMethod: nodeInfoResponse.Method,
|
CypherMethod: nodeInfoResponse.Method,
|
||||||
|
@@ -19,8 +19,8 @@ type V2rayNodeInfo struct {
|
|||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Cert string `json:"pem"`
|
Cert string `json:"pem"`
|
||||||
V2License string `json:"v2_license"`
|
V2License string `json:"v2_license"`
|
||||||
V2AlterID int `json:"v2_alter_id"`
|
V2AlterID uint16 `json:"v2_alter_id"`
|
||||||
V2Port int `json:"v2_port"`
|
V2Port uint32 `json:"v2_port"`
|
||||||
V2Method string `json:"v2_method"`
|
V2Method string `json:"v2_method"`
|
||||||
V2Net string `json:"v2_net"`
|
V2Net string `json:"v2_net"`
|
||||||
V2Type string `json:"v2_type"`
|
V2Type string `json:"v2_type"`
|
||||||
@@ -37,7 +37,7 @@ type ShadowsocksNodeInfo struct {
|
|||||||
SpeedLimit uint64 `json:"speed_limit"`
|
SpeedLimit uint64 `json:"speed_limit"`
|
||||||
ClientLimit int `json:"client_limit"`
|
ClientLimit int `json:"client_limit"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Port int `json:"port"`
|
Port uint32 `json:"port"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TrojanNodeInfo struct {
|
type TrojanNodeInfo struct {
|
||||||
@@ -46,7 +46,7 @@ type TrojanNodeInfo struct {
|
|||||||
SpeedLimit uint64 `json:"speed_limit"`
|
SpeedLimit uint64 `json:"speed_limit"`
|
||||||
ClientLimit int `json:"client_limit"`
|
ClientLimit int `json:"client_limit"`
|
||||||
PushPort int `json:"push_port"`
|
PushPort int `json:"push_port"`
|
||||||
TrojanPort int `json:"trojan_port"`
|
TrojanPort uint32 `json:"trojan_port"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node status report
|
// Node status report
|
||||||
|
@@ -238,7 +238,7 @@ func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
systemload := NodeStatus{
|
systemload := NodeStatus{
|
||||||
Uptime: nodeStatus.Uptime,
|
Uptime: int(nodeStatus.Uptime),
|
||||||
CPU: fmt.Sprintf("%d%%", int(nodeStatus.CPU)),
|
CPU: fmt.Sprintf("%d%%", int(nodeStatus.CPU)),
|
||||||
Mem: fmt.Sprintf("%d%%", int(nodeStatus.Mem)),
|
Mem: fmt.Sprintf("%d%%", int(nodeStatus.Mem)),
|
||||||
Disk: fmt.Sprintf("%d%%", int(nodeStatus.Disk)),
|
Disk: fmt.Sprintf("%d%%", int(nodeStatus.Disk)),
|
||||||
|
@@ -49,7 +49,7 @@ type UserResponse struct {
|
|||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Passwd string `json:"passwd"`
|
Passwd string `json:"passwd"`
|
||||||
Port int `json:"port"`
|
Port uint32 `json:"port"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
SpeedLimit float64 `json:"node_speedlimit"`
|
SpeedLimit float64 `json:"node_speedlimit"`
|
||||||
DeviceLimit int `json:"node_connector"`
|
DeviceLimit int `json:"node_connector"`
|
||||||
|
@@ -183,7 +183,7 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
|
|||||||
nodeInfo, err = c.ParseSSPanelNodeInfo(nodeInfoResponse)
|
nodeInfo, err = c.ParseSSPanelNodeInfo(nodeInfoResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res, _ := json.Marshal(nodeInfoResponse)
|
res, _ := json.Marshal(nodeInfoResponse)
|
||||||
return nil, fmt.Errorf("Parse node info failed: %s, \nError: %s, \nPlease check the doc of custom_config for help: https://crackair.gitbook.io/xrayr-project/dui-jie-sspanel/sspanel/sspanel_custom_config", string(res), err)
|
return nil, fmt.Errorf("Parse node info failed: %s, \nError: %s, \nPlease check the doc of custom_config for help: https://xrayr-project.github.io/XrayR-doc/dui-jie-sspanel/sspanel/sspanel_custom_config", string(res), err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch c.NodeType {
|
switch c.NodeType {
|
||||||
@@ -239,7 +239,7 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
|
|||||||
func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
|
func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
|
||||||
path := fmt.Sprintf("/mod_mu/nodes/%d/info", c.NodeID)
|
path := fmt.Sprintf("/mod_mu/nodes/%d/info", c.NodeID)
|
||||||
systemload := SystemLoad{
|
systemload := SystemLoad{
|
||||||
Uptime: strconv.Itoa(nodeStatus.Uptime),
|
Uptime: strconv.FormatUint(nodeStatus.Uptime, 10),
|
||||||
Load: fmt.Sprintf("%.2f %.2f %.2f", nodeStatus.CPU/100, nodeStatus.CPU/100, nodeStatus.CPU/100),
|
Load: fmt.Sprintf("%.2f %.2f %.2f", nodeStatus.CPU/100, nodeStatus.CPU/100, nodeStatus.CPU/100),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,14 +382,19 @@ func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *NodeInfoResponse) (
|
|||||||
}
|
}
|
||||||
//nodeInfo.RawServerString = strings.ToLower(nodeInfo.RawServerString)
|
//nodeInfo.RawServerString = strings.ToLower(nodeInfo.RawServerString)
|
||||||
serverConf := strings.Split(nodeInfoResponse.RawServerString, ";")
|
serverConf := strings.Split(nodeInfoResponse.RawServerString, ";")
|
||||||
port, err := strconv.Atoi(serverConf[1])
|
|
||||||
|
parsedPort, err := strconv.ParseInt(serverConf[1], 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
alterID, err := strconv.Atoi(serverConf[2])
|
port := uint32(parsedPort)
|
||||||
|
|
||||||
|
parsedAlterID, err := strconv.ParseInt(serverConf[2], 10, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
alterID := uint16(parsedAlterID)
|
||||||
|
|
||||||
// Compatible with more node types config
|
// Compatible with more node types config
|
||||||
for _, value := range serverConf[3:5] {
|
for _, value := range serverConf[3:5] {
|
||||||
switch value {
|
switch value {
|
||||||
@@ -464,7 +469,7 @@ func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *NodeInfoResponse) (
|
|||||||
|
|
||||||
// ParseSSNodeResponse parse the response for the given nodeinfor format
|
// ParseSSNodeResponse parse the response for the given nodeinfor format
|
||||||
func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error) {
|
func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error) {
|
||||||
var port int = 0
|
var port uint32 = 0
|
||||||
var speedlimit uint64 = 0
|
var speedlimit uint64 = 0
|
||||||
var method string
|
var method string
|
||||||
path := "/mod_mu/users"
|
path := "/mod_mu/users"
|
||||||
@@ -521,10 +526,11 @@ func (c *APIClient) ParseSSPluginNodeResponse(nodeInfoResponse *NodeInfoResponse
|
|||||||
var speedlimit uint64 = 0
|
var speedlimit uint64 = 0
|
||||||
|
|
||||||
serverConf := strings.Split(nodeInfoResponse.RawServerString, ";")
|
serverConf := strings.Split(nodeInfoResponse.RawServerString, ";")
|
||||||
port, err := strconv.Atoi(serverConf[1])
|
parsedPort, err := strconv.ParseInt(serverConf[1], 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
port := uint32(parsedPort)
|
||||||
port = port - 1 // Shadowsocks-Plugin requires two ports, one for ss the other for other stream protocol
|
port = port - 1 // Shadowsocks-Plugin requires two ports, one for ss the other for other stream protocol
|
||||||
if port <= 0 {
|
if port <= 0 {
|
||||||
return nil, fmt.Errorf("Shadowsocks-Plugin listen port must bigger than 1")
|
return nil, fmt.Errorf("Shadowsocks-Plugin listen port must bigger than 1")
|
||||||
@@ -615,10 +621,11 @@ func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *NodeInfoResponse)
|
|||||||
p = outsidePort
|
p = outsidePort
|
||||||
}
|
}
|
||||||
|
|
||||||
port, err := strconv.Atoi(p)
|
parsedPort, err := strconv.ParseInt(p, 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
port := uint32(parsedPort)
|
||||||
|
|
||||||
serverConf := strings.Split(nodeInfoResponse.RawServerString, ";")
|
serverConf := strings.Split(nodeInfoResponse.RawServerString, ";")
|
||||||
extraServerConf := strings.Split(serverConf[1], "|")
|
extraServerConf := strings.Split(serverConf[1], "|")
|
||||||
@@ -727,7 +734,7 @@ func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*a
|
|||||||
|
|
||||||
var speedlimit uint64 = 0
|
var speedlimit uint64 = 0
|
||||||
var EnableTLS, EnableVless bool
|
var EnableTLS, EnableVless bool
|
||||||
var AlterID int = 0
|
var AlterID uint16 = 0
|
||||||
var TLSType, transportProtocol string
|
var TLSType, transportProtocol string
|
||||||
|
|
||||||
nodeConfig := new(CustomConfig)
|
nodeConfig := new(CustomConfig)
|
||||||
@@ -739,10 +746,11 @@ func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*a
|
|||||||
speedlimit = uint64((nodeInfoResponse.SpeedLimit * 1000000) / 8)
|
speedlimit = uint64((nodeInfoResponse.SpeedLimit * 1000000) / 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
port, err := strconv.Atoi(nodeConfig.OffsetPortNode)
|
parsedPort, err := strconv.ParseInt(nodeConfig.OffsetPortNode, 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
port := uint32(parsedPort)
|
||||||
|
|
||||||
if c.NodeType == "Shadowsocks" {
|
if c.NodeType == "Shadowsocks" {
|
||||||
transportProtocol = "tcp"
|
transportProtocol = "tcp"
|
||||||
@@ -751,9 +759,12 @@ func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*a
|
|||||||
if c.NodeType == "V2ray" {
|
if c.NodeType == "V2ray" {
|
||||||
transportProtocol = nodeConfig.Network
|
transportProtocol = nodeConfig.Network
|
||||||
TLSType = nodeConfig.Security
|
TLSType = nodeConfig.Security
|
||||||
if AlterID, err = strconv.Atoi(nodeConfig.AlterID); err != nil {
|
if parsedAlterID, err := strconv.ParseInt(nodeConfig.AlterID, 10, 16); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else {
|
||||||
|
AlterID = uint16(parsedAlterID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if TLSType == "tls" || TLSType == "xtls" {
|
if TLSType == "tls" || TLSType == "xtls" {
|
||||||
EnableTLS = true
|
EnableTLS = true
|
||||||
}
|
}
|
||||||
@@ -764,16 +775,22 @@ func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*a
|
|||||||
|
|
||||||
if c.NodeType == "Trojan" {
|
if c.NodeType == "Trojan" {
|
||||||
EnableTLS = true
|
EnableTLS = true
|
||||||
TLSType = "tls"
|
TLSType = nodeConfig.Security // try to read security from config
|
||||||
if nodeConfig.Grpc == "1" {
|
|
||||||
transportProtocol = "grpc"
|
|
||||||
} else {
|
|
||||||
transportProtocol = "tcp"
|
|
||||||
}
|
|
||||||
|
|
||||||
if nodeConfig.EnableXtls == "1" {
|
if nodeConfig.EnableXtls == "1" {
|
||||||
TLSType = "xtls"
|
TLSType = "xtls"
|
||||||
}
|
}
|
||||||
|
if TLSType == "" {
|
||||||
|
TLSType = "tls" // default
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select transport protocol
|
||||||
|
transportProtocol = nodeConfig.Network // try to read transport protocol from config
|
||||||
|
if nodeConfig.Grpc == "1" {
|
||||||
|
transportProtocol = "grpc"
|
||||||
|
}
|
||||||
|
if nodeConfig.Network != "" {
|
||||||
|
transportProtocol = "tcp" // default
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create GeneralNodeInfo
|
// Create GeneralNodeInfo
|
||||||
|
@@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -219,14 +220,14 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
|
|||||||
user.Email = response.Get("data").GetIndex(i).Get("secret").MustString()
|
user.Email = response.Get("data").GetIndex(i).Get("secret").MustString()
|
||||||
user.Passwd = response.Get("data").GetIndex(i).Get("secret").MustString()
|
user.Passwd = response.Get("data").GetIndex(i).Get("secret").MustString()
|
||||||
user.Method = response.Get("data").GetIndex(i).Get("cipher").MustString()
|
user.Method = response.Get("data").GetIndex(i).Get("cipher").MustString()
|
||||||
user.Port = response.Get("data").GetIndex(i).Get("port").MustInt()
|
user.Port = uint32(response.Get("data").GetIndex(i).Get("port").MustUint64())
|
||||||
case "Trojan":
|
case "Trojan":
|
||||||
user.UUID = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString()
|
user.UUID = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString()
|
||||||
user.Email = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString()
|
user.Email = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString()
|
||||||
case "V2ray":
|
case "V2ray":
|
||||||
user.UUID = response.Get("data").GetIndex(i).Get("v2ray_user").Get("uuid").MustString()
|
user.UUID = response.Get("data").GetIndex(i).Get("v2ray_user").Get("uuid").MustString()
|
||||||
user.Email = response.Get("data").GetIndex(i).Get("v2ray_user").Get("email").MustString()
|
user.Email = response.Get("data").GetIndex(i).Get("v2ray_user").Get("email").MustString()
|
||||||
user.AlterID = response.Get("data").GetIndex(i).Get("v2ray_user").Get("alter_id").MustInt()
|
user.AlterID = uint16(response.Get("data").GetIndex(i).Get("v2ray_user").Get("alter_id").MustUint64())
|
||||||
}
|
}
|
||||||
userList[i] = user
|
userList[i] = user
|
||||||
}
|
}
|
||||||
@@ -278,6 +279,7 @@ func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
|
|||||||
defer c.access.Unlock()
|
defer c.access.Unlock()
|
||||||
ruleListResponse := c.ConfigResp.Get("routing").Get("rules").GetIndex(1).Get("domain").MustStringArray()
|
ruleListResponse := c.ConfigResp.Get("routing").Get("rules").GetIndex(1).Get("domain").MustStringArray()
|
||||||
for i, rule := range ruleListResponse {
|
for i, rule := range ruleListResponse {
|
||||||
|
rule = strings.TrimPrefix(rule, "regexp:")
|
||||||
ruleListItem := api.DetectRule{
|
ruleListItem := api.DetectRule{
|
||||||
ID: i,
|
ID: i,
|
||||||
Pattern: regexp.MustCompile(rule),
|
Pattern: regexp.MustCompile(rule),
|
||||||
@@ -308,7 +310,7 @@ func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *simplejson.Json) (
|
|||||||
if c.EnableXTLS {
|
if c.EnableXTLS {
|
||||||
TLSType = "xtls"
|
TLSType = "xtls"
|
||||||
}
|
}
|
||||||
port := nodeInfoResponse.Get("local_port").MustInt()
|
port := uint32(nodeInfoResponse.Get("local_port").MustUint64())
|
||||||
host := nodeInfoResponse.Get("ssl").Get("sni").MustString()
|
host := nodeInfoResponse.Get("ssl").Get("sni").MustString()
|
||||||
|
|
||||||
// Create GeneralNodeInfo
|
// Create GeneralNodeInfo
|
||||||
@@ -326,7 +328,7 @@ func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *simplejson.Json) (
|
|||||||
|
|
||||||
// ParseSSNodeResponse parse the response for the given nodeinfor format
|
// ParseSSNodeResponse parse the response for the given nodeinfor format
|
||||||
func (c *APIClient) ParseSSNodeResponse() (*api.NodeInfo, error) {
|
func (c *APIClient) ParseSSNodeResponse() (*api.NodeInfo, error) {
|
||||||
var port int
|
var port uint32
|
||||||
var method string
|
var method string
|
||||||
userInfo, err := c.GetUserList()
|
userInfo, err := c.GetUserList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -355,7 +357,7 @@ func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *simplejson.Json) (*
|
|||||||
var path, host, serviceName string
|
var path, host, serviceName string
|
||||||
var header json.RawMessage
|
var header json.RawMessage
|
||||||
var enableTLS bool
|
var enableTLS bool
|
||||||
var alterID int = 0
|
var alterID uint16 = 0
|
||||||
if c.EnableXTLS {
|
if c.EnableXTLS {
|
||||||
TLSType = "xtls"
|
TLSType = "xtls"
|
||||||
}
|
}
|
||||||
@@ -372,7 +374,7 @@ func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *simplejson.Json) (*
|
|||||||
return nil, fmt.Errorf("Unable to find inbound(s) in the nodeInfo.")
|
return nil, fmt.Errorf("Unable to find inbound(s) in the nodeInfo.")
|
||||||
}
|
}
|
||||||
|
|
||||||
port := inboundInfo.Get("port").MustInt()
|
port := uint32(inboundInfo.Get("port").MustUint64())
|
||||||
transportProtocol := inboundInfo.Get("streamSettings").Get("network").MustString()
|
transportProtocol := inboundInfo.Get("streamSettings").Get("network").MustString()
|
||||||
|
|
||||||
switch transportProtocol {
|
switch transportProtocol {
|
||||||
|
7
api/v2raysocks/model.go
Normal file
7
api/v2raysocks/model.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package v2raysocks
|
||||||
|
|
||||||
|
type UserTraffic struct {
|
||||||
|
UID int `json:"user_id"`
|
||||||
|
Upload int64 `json:"u"`
|
||||||
|
Download int64 `json:"d"`
|
||||||
|
}
|
413
api/v2raysocks/v2raysocks.go
Normal file
413
api/v2raysocks/v2raysocks.go
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
package v2raysocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/XrayR-project/XrayR/api"
|
||||||
|
"github.com/bitly/go-simplejson"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// APIClient create an api client to the panel.
|
||||||
|
type APIClient struct {
|
||||||
|
client *resty.Client
|
||||||
|
APIHost string
|
||||||
|
NodeID int
|
||||||
|
Key string
|
||||||
|
NodeType string
|
||||||
|
EnableVless bool
|
||||||
|
EnableXTLS bool
|
||||||
|
SpeedLimit float64
|
||||||
|
DeviceLimit int
|
||||||
|
LocalRuleList []api.DetectRule
|
||||||
|
ConfigResp *simplejson.Json
|
||||||
|
access sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// New create an api instance
|
||||||
|
func New(apiConfig *api.Config) *APIClient {
|
||||||
|
|
||||||
|
client := resty.New()
|
||||||
|
client.SetRetryCount(3)
|
||||||
|
if apiConfig.Timeout > 0 {
|
||||||
|
client.SetTimeout(time.Duration(apiConfig.Timeout) * time.Second)
|
||||||
|
} else {
|
||||||
|
client.SetTimeout(5 * time.Second)
|
||||||
|
}
|
||||||
|
client.OnError(func(req *resty.Request, err error) {
|
||||||
|
if v, ok := err.(*resty.ResponseError); ok {
|
||||||
|
// v.Response contains the last response from the server
|
||||||
|
// v.Err contains the original error
|
||||||
|
log.Print(v.Err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// Create Key for each requests
|
||||||
|
client.SetQueryParams(map[string]string{
|
||||||
|
"node_id": strconv.Itoa(apiConfig.NodeID),
|
||||||
|
"token": apiConfig.Key,
|
||||||
|
})
|
||||||
|
// Read local rule list
|
||||||
|
localRuleList := readLocalRuleList(apiConfig.RuleListPath)
|
||||||
|
apiClient := &APIClient{
|
||||||
|
client: client,
|
||||||
|
NodeID: apiConfig.NodeID,
|
||||||
|
Key: apiConfig.Key,
|
||||||
|
APIHost: apiConfig.APIHost,
|
||||||
|
NodeType: apiConfig.NodeType,
|
||||||
|
EnableVless: apiConfig.EnableVless,
|
||||||
|
EnableXTLS: apiConfig.EnableXTLS,
|
||||||
|
SpeedLimit: apiConfig.SpeedLimit,
|
||||||
|
DeviceLimit: apiConfig.DeviceLimit,
|
||||||
|
LocalRuleList: localRuleList,
|
||||||
|
}
|
||||||
|
return apiClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// readLocalRuleList reads the local rule list file
|
||||||
|
func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {
|
||||||
|
|
||||||
|
LocalRuleList = make([]api.DetectRule, 0)
|
||||||
|
if path != "" {
|
||||||
|
// open the file
|
||||||
|
file, err := os.Open(path)
|
||||||
|
|
||||||
|
//handle errors while opening
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error when opening file: %s", err)
|
||||||
|
return LocalRuleList
|
||||||
|
}
|
||||||
|
|
||||||
|
fileScanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
// read line by line
|
||||||
|
for fileScanner.Scan() {
|
||||||
|
LocalRuleList = append(LocalRuleList, api.DetectRule{
|
||||||
|
ID: -1,
|
||||||
|
Pattern: regexp.MustCompile(fileScanner.Text()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// handle first encountered error while reading
|
||||||
|
if err := fileScanner.Err(); err != nil {
|
||||||
|
log.Fatalf("Error while reading file: %s", err)
|
||||||
|
return make([]api.DetectRule, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
file.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return LocalRuleList
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe return a description of the client
|
||||||
|
func (c *APIClient) Describe() api.ClientInfo {
|
||||||
|
return api.ClientInfo{APIHost: c.APIHost, NodeID: c.NodeID, Key: c.Key, NodeType: c.NodeType}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug set the client debug for client
|
||||||
|
func (c *APIClient) Debug() {
|
||||||
|
c.client.SetDebug(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *APIClient) assembleURL(path string) string {
|
||||||
|
return c.APIHost + path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *APIClient) parseResponse(res *resty.Response, path string, err error) (*simplejson.Json, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("request %s failed: %s", c.assembleURL(path), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode() > 400 {
|
||||||
|
body := res.Body()
|
||||||
|
return nil, fmt.Errorf("request %s failed: %s, %s", c.assembleURL(path), string(body), err)
|
||||||
|
}
|
||||||
|
rtn, err := simplejson.NewJson(res.Body())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Ret %s invalid", res.String())
|
||||||
|
}
|
||||||
|
return rtn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodeInfo will pull NodeInfo Config from sspanel
|
||||||
|
func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
|
||||||
|
var nodeType string
|
||||||
|
switch c.NodeType {
|
||||||
|
case "V2ray", "Trojan", "Shadowsocks":
|
||||||
|
nodeType = strings.ToLower(c.NodeType)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType)
|
||||||
|
}
|
||||||
|
res, err := c.client.R().
|
||||||
|
SetQueryParams(map[string]string{
|
||||||
|
"act": "config",
|
||||||
|
"nodetype": nodeType,
|
||||||
|
}).
|
||||||
|
ForceContentType("application/json").
|
||||||
|
Get(c.APIHost)
|
||||||
|
|
||||||
|
response, err := c.parseResponse(res, "", err)
|
||||||
|
c.access.Lock()
|
||||||
|
defer c.access.Unlock()
|
||||||
|
c.ConfigResp = response
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c.NodeType {
|
||||||
|
case "V2ray":
|
||||||
|
nodeInfo, err = c.ParseV2rayNodeResponse(response)
|
||||||
|
case "Trojan":
|
||||||
|
nodeInfo, err = c.ParseTrojanNodeResponse(response)
|
||||||
|
case "Shadowsocks":
|
||||||
|
nodeInfo, err = c.ParseSSNodeResponse(response)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
res, _ := response.MarshalJSON()
|
||||||
|
return nil, fmt.Errorf("Parse node info failed: %s, \nError: %s", string(res), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserList will pull user form sspanel
|
||||||
|
func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
|
||||||
|
var nodeType string
|
||||||
|
switch c.NodeType {
|
||||||
|
case "V2ray", "Trojan", "Shadowsocks":
|
||||||
|
nodeType = strings.ToLower(c.NodeType)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType)
|
||||||
|
}
|
||||||
|
res, err := c.client.R().
|
||||||
|
SetQueryParams(map[string]string{
|
||||||
|
"act": "user",
|
||||||
|
"nodetype": nodeType,
|
||||||
|
}).
|
||||||
|
ForceContentType("application/json").
|
||||||
|
Get(c.APIHost)
|
||||||
|
|
||||||
|
response, err := c.parseResponse(res, "", err)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
numOfUsers := len(response.Get("data").MustArray())
|
||||||
|
userList := make([]api.UserInfo, numOfUsers)
|
||||||
|
for i := 0; i < numOfUsers; i++ {
|
||||||
|
user := api.UserInfo{}
|
||||||
|
user.UID = response.Get("data").GetIndex(i).Get("id").MustInt()
|
||||||
|
switch c.NodeType {
|
||||||
|
case "Shadowsocks":
|
||||||
|
user.Email = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("secret").MustString()
|
||||||
|
user.Passwd = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("secret").MustString()
|
||||||
|
user.Method = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("cipher").MustString()
|
||||||
|
user.SpeedLimit = uint64(response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("speed_limit").MustUint64() * 1000000 / 8)
|
||||||
|
case "Trojan":
|
||||||
|
user.UUID = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString()
|
||||||
|
user.Email = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString()
|
||||||
|
user.SpeedLimit = uint64(response.Get("data").GetIndex(i).Get("trojan_user").Get("speed_limit").MustUint64() * 1000000 / 8)
|
||||||
|
case "V2ray":
|
||||||
|
user.UUID = response.Get("data").GetIndex(i).Get("v2ray_user").Get("uuid").MustString()
|
||||||
|
user.Email = response.Get("data").GetIndex(i).Get("v2ray_user").Get("email").MustString()
|
||||||
|
user.AlterID = uint16(response.Get("data").GetIndex(i).Get("v2ray_user").Get("alter_id").MustUint64())
|
||||||
|
user.SpeedLimit = uint64(response.Get("data").GetIndex(i).Get("v2ray_user").Get("speed_limit").MustUint64() * 1000000 / 8)
|
||||||
|
}
|
||||||
|
if c.SpeedLimit > 0 {
|
||||||
|
user.SpeedLimit = uint64((c.SpeedLimit * 1000000) / 8)
|
||||||
|
}
|
||||||
|
user.DeviceLimit = c.DeviceLimit
|
||||||
|
userList[i] = user
|
||||||
|
}
|
||||||
|
return &userList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReportUserTraffic reports the user traffic
|
||||||
|
func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) error {
|
||||||
|
|
||||||
|
data := make([]UserTraffic, len(*userTraffic))
|
||||||
|
for i, traffic := range *userTraffic {
|
||||||
|
data[i] = UserTraffic{
|
||||||
|
UID: traffic.UID,
|
||||||
|
Upload: traffic.Upload,
|
||||||
|
Download: traffic.Download}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.R().
|
||||||
|
SetQueryParam("node_id", strconv.Itoa(c.NodeID)).
|
||||||
|
SetQueryParams(map[string]string{
|
||||||
|
"act": "submit",
|
||||||
|
"nodetype": strings.ToLower(c.NodeType),
|
||||||
|
}).
|
||||||
|
SetBody(data).
|
||||||
|
ForceContentType("application/json").
|
||||||
|
Post(c.APIHost)
|
||||||
|
_, err = c.parseResponse(res, "", err)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodeRule implements the API interface
|
||||||
|
func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
|
||||||
|
ruleList := c.LocalRuleList
|
||||||
|
if c.NodeType != "V2ray" {
|
||||||
|
return &ruleList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// V2board only support the rule for v2ray
|
||||||
|
// fix: reuse config response
|
||||||
|
c.access.Lock()
|
||||||
|
defer c.access.Unlock()
|
||||||
|
ruleListResponse := c.ConfigResp.Get("routing").Get("rules").GetIndex(1).Get("domain").MustStringArray()
|
||||||
|
for i, rule := range ruleListResponse {
|
||||||
|
rule = strings.TrimPrefix(rule, "regexp:")
|
||||||
|
ruleListItem := api.DetectRule{
|
||||||
|
ID: i,
|
||||||
|
Pattern: regexp.MustCompile(rule),
|
||||||
|
}
|
||||||
|
ruleList = append(ruleList, ruleListItem)
|
||||||
|
}
|
||||||
|
return &ruleList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReportNodeStatus implements the API interface
|
||||||
|
func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//ReportNodeOnlineUsers implements the API interface
|
||||||
|
func (c *APIClient) ReportNodeOnlineUsers(onlineUserList *[]api.OnlineUser) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReportIllegal implements the API interface
|
||||||
|
func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseTrojanNodeResponse parse the response for the given nodeinfor format
|
||||||
|
func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) {
|
||||||
|
var TLSType = "tls"
|
||||||
|
if c.EnableXTLS {
|
||||||
|
TLSType = "xtls"
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpInboundInfo := nodeInfoResponse.Get("inbounds").MustArray()
|
||||||
|
marshalByte, _ := json.Marshal(tmpInboundInfo[0].(map[string]interface{}))
|
||||||
|
inboundInfo, _ := simplejson.NewJson(marshalByte)
|
||||||
|
|
||||||
|
port := uint32(inboundInfo.Get("port").MustUint64())
|
||||||
|
host := inboundInfo.Get("streamSettings").Get("tlsSettings").Get("serverName").MustString()
|
||||||
|
|
||||||
|
// Create GeneralNodeInfo
|
||||||
|
nodeinfo := &api.NodeInfo{
|
||||||
|
NodeType: c.NodeType,
|
||||||
|
NodeID: c.NodeID,
|
||||||
|
Port: port,
|
||||||
|
TransportProtocol: "tcp",
|
||||||
|
EnableTLS: true,
|
||||||
|
TLSType: TLSType,
|
||||||
|
Host: host,
|
||||||
|
}
|
||||||
|
return nodeinfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseSSNodeResponse parse the response for the given nodeinfor format
|
||||||
|
func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) {
|
||||||
|
var method string
|
||||||
|
tmpInboundInfo := nodeInfoResponse.Get("inbounds").MustArray()
|
||||||
|
marshalByte, _ := json.Marshal(tmpInboundInfo[0].(map[string]interface{}))
|
||||||
|
inboundInfo, _ := simplejson.NewJson(marshalByte)
|
||||||
|
|
||||||
|
port := uint32(inboundInfo.Get("port").MustUint64())
|
||||||
|
userInfo, err := c.GetUserList()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(*userInfo) > 0 {
|
||||||
|
method = (*userInfo)[0].Method
|
||||||
|
}
|
||||||
|
// Create GeneralNodeInfo
|
||||||
|
nodeinfo := &api.NodeInfo{
|
||||||
|
NodeType: c.NodeType,
|
||||||
|
NodeID: c.NodeID,
|
||||||
|
Port: port,
|
||||||
|
TransportProtocol: "tcp",
|
||||||
|
CypherMethod: method,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeinfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseV2rayNodeResponse parse the response for the given nodeinfor format
|
||||||
|
func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *simplejson.Json) (*api.NodeInfo, error) {
|
||||||
|
var TLSType string = "tls"
|
||||||
|
var path, host, serviceName string
|
||||||
|
var header json.RawMessage
|
||||||
|
var enableTLS bool
|
||||||
|
var alterID uint16 = 0
|
||||||
|
if c.EnableXTLS {
|
||||||
|
TLSType = "xtls"
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpInboundInfo := nodeInfoResponse.Get("inbounds").MustArray()
|
||||||
|
marshalByte, _ := json.Marshal(tmpInboundInfo[0].(map[string]interface{}))
|
||||||
|
inboundInfo, _ := simplejson.NewJson(marshalByte)
|
||||||
|
|
||||||
|
port := uint32(inboundInfo.Get("port").MustUint64())
|
||||||
|
transportProtocol := inboundInfo.Get("streamSettings").Get("network").MustString()
|
||||||
|
|
||||||
|
switch transportProtocol {
|
||||||
|
case "ws":
|
||||||
|
path = inboundInfo.Get("streamSettings").Get("wsSettings").Get("path").MustString()
|
||||||
|
host = inboundInfo.Get("streamSettings").Get("wsSettings").Get("headers").Get("Host").MustString()
|
||||||
|
case "grpc":
|
||||||
|
if data, ok := inboundInfo.Get("streamSettings").Get("grpcSettings").CheckGet("serviceName"); ok {
|
||||||
|
serviceName = data.MustString()
|
||||||
|
}
|
||||||
|
case "tcp":
|
||||||
|
if data, ok := inboundInfo.Get("streamSettings").Get("tcpSettings").CheckGet("header"); ok {
|
||||||
|
if httpHeader, err := data.MarshalJSON(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
header = httpHeader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if inboundInfo.Get("streamSettings").Get("security").MustString() == "tls" {
|
||||||
|
enableTLS = true
|
||||||
|
} else {
|
||||||
|
enableTLS = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create GeneralNodeInfo
|
||||||
|
// AlterID will be updated after next sync
|
||||||
|
nodeInfo := &api.NodeInfo{
|
||||||
|
NodeType: c.NodeType,
|
||||||
|
NodeID: c.NodeID,
|
||||||
|
Port: port,
|
||||||
|
AlterID: alterID,
|
||||||
|
TransportProtocol: transportProtocol,
|
||||||
|
EnableTLS: enableTLS,
|
||||||
|
TLSType: TLSType,
|
||||||
|
Path: path,
|
||||||
|
Host: host,
|
||||||
|
EnableVless: c.EnableVless,
|
||||||
|
ServiceName: serviceName,
|
||||||
|
Header: header,
|
||||||
|
}
|
||||||
|
return nodeInfo, nil
|
||||||
|
}
|
102
api/v2raysocks/v2raysocks_test.go
Normal file
102
api/v2raysocks/v2raysocks_test.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package v2raysocks_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/XrayR-project/XrayR/api"
|
||||||
|
"github.com/XrayR-project/XrayR/api/v2raysocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateClient() api.API {
|
||||||
|
apiConfig := &api.Config{
|
||||||
|
APIHost: "https://127.0.0.1/",
|
||||||
|
Key: "123456789",
|
||||||
|
NodeID: 280002,
|
||||||
|
NodeType: "V2ray",
|
||||||
|
}
|
||||||
|
client := v2raysocks.New(apiConfig)
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetV2rayNodeinfo(t *testing.T) {
|
||||||
|
client := CreateClient()
|
||||||
|
client.Debug()
|
||||||
|
nodeInfo, err := client.GetNodeInfo()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
t.Log(nodeInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetSSNodeinfo(t *testing.T) {
|
||||||
|
apiConfig := &api.Config{
|
||||||
|
APIHost: "https://127.0.0.1/",
|
||||||
|
Key: "123456789",
|
||||||
|
NodeID: 280009,
|
||||||
|
NodeType: "Shadowsocks",
|
||||||
|
}
|
||||||
|
client := v2raysocks.New(apiConfig)
|
||||||
|
nodeInfo, err := client.GetNodeInfo()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
t.Log(nodeInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTrojanNodeinfo(t *testing.T) {
|
||||||
|
apiConfig := &api.Config{
|
||||||
|
APIHost: "https://127.0.0.1/",
|
||||||
|
Key: "123456789",
|
||||||
|
NodeID: 280008,
|
||||||
|
NodeType: "Trojan",
|
||||||
|
}
|
||||||
|
client := v2raysocks.New(apiConfig)
|
||||||
|
nodeInfo, err := client.GetNodeInfo()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
t.Log(nodeInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetUserList(t *testing.T) {
|
||||||
|
client := CreateClient()
|
||||||
|
|
||||||
|
userList, err := client.GetUserList()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log(userList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReportReportUserTraffic(t *testing.T) {
|
||||||
|
client := CreateClient()
|
||||||
|
userList, err := client.GetUserList()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
generalUserTraffic := make([]api.UserTraffic, len(*userList))
|
||||||
|
for i, userInfo := range *userList {
|
||||||
|
generalUserTraffic[i] = api.UserTraffic{
|
||||||
|
UID: userInfo.UID,
|
||||||
|
Upload: 114514,
|
||||||
|
Download: 114514,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//client.Debug()
|
||||||
|
err = client.ReportUserTraffic(&generalUserTraffic)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetNodeRule(t *testing.T) {
|
||||||
|
client := CreateClient()
|
||||||
|
client.Debug()
|
||||||
|
ruleList, err := client.GetNodeRule()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log(ruleList)
|
||||||
|
}
|
@@ -1,8 +1,8 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.26.0
|
// protoc-gen-go v1.28.0
|
||||||
// protoc v3.19.4
|
// protoc v3.19.4
|
||||||
// source: config.proto
|
// source: app/mydispatcher/config.proto
|
||||||
|
|
||||||
package mydispatcher
|
package mydispatcher
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ type SessionConfig struct {
|
|||||||
func (x *SessionConfig) Reset() {
|
func (x *SessionConfig) Reset() {
|
||||||
*x = SessionConfig{}
|
*x = SessionConfig{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_config_proto_msgTypes[0]
|
mi := &file_app_mydispatcher_config_proto_msgTypes[0]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ func (x *SessionConfig) String() string {
|
|||||||
func (*SessionConfig) ProtoMessage() {}
|
func (*SessionConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SessionConfig) ProtoReflect() protoreflect.Message {
|
func (x *SessionConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_config_proto_msgTypes[0]
|
mi := &file_app_mydispatcher_config_proto_msgTypes[0]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -55,7 +55,7 @@ func (x *SessionConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SessionConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SessionConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*SessionConfig) Descriptor() ([]byte, []int) {
|
func (*SessionConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_config_proto_rawDescGZIP(), []int{0}
|
return file_app_mydispatcher_config_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -69,7 +69,7 @@ type Config struct {
|
|||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_config_proto_msgTypes[1]
|
mi := &file_app_mydispatcher_config_proto_msgTypes[1]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ func (x *Config) String() string {
|
|||||||
func (*Config) ProtoMessage() {}
|
func (*Config) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_config_proto_msgTypes[1]
|
mi := &file_app_mydispatcher_config_proto_msgTypes[1]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -95,7 +95,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
func (*Config) Descriptor() ([]byte, []int) {
|
||||||
return file_config_proto_rawDescGZIP(), []int{1}
|
return file_app_mydispatcher_config_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetSettings() *SessionConfig {
|
func (x *Config) GetSettings() *SessionConfig {
|
||||||
@@ -105,45 +105,46 @@ func (x *Config) GetSettings() *SessionConfig {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_config_proto protoreflect.FileDescriptor
|
var File_app_mydispatcher_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_config_proto_rawDesc = []byte{
|
var file_app_mydispatcher_config_proto_rawDesc = []byte{
|
||||||
0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16,
|
0x0a, 0x1d, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x79, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x72, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x79, 0x64, 0x69, 0x73, 0x70,
|
0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||||
0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x22, 0x15, 0x0a, 0x0d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
|
0x16, 0x78, 0x72, 0x61, 0x79, 0x72, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x79, 0x64, 0x69, 0x73,
|
||||||
0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x4b, 0x0a,
|
0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x22, 0x15, 0x0a, 0x0d, 0x53, 0x65, 0x73, 0x73, 0x69,
|
||||||
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69,
|
0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x4b,
|
||||||
0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74,
|
||||||
0x72, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x79, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68,
|
0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61,
|
||||||
0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x79, 0x72, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x79, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63,
|
||||||
0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x67, 0x0a, 0x1a, 0x63, 0x6f,
|
0x68, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x72, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x79, 0x64, 0x69,
|
0x67, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x67, 0x0a, 0x1a, 0x63,
|
||||||
0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68,
|
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x72, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x79, 0x64,
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x58, 0x72, 0x61, 0x79, 0x52, 0x2d, 0x70, 0x72, 0x6f,
|
0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74,
|
||||||
0x6a, 0x65, 0x63, 0x74, 0x2f, 0x58, 0x72, 0x61, 0x79, 0x52, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6d,
|
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x58, 0x72, 0x61, 0x79, 0x52, 0x2d, 0x70, 0x72,
|
||||||
0x79, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0xaa, 0x02, 0x15, 0x58, 0x72,
|
0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x58, 0x72, 0x61, 0x79, 0x52, 0x2f, 0x61, 0x70, 0x70, 0x2f,
|
||||||
0x61, 0x79, 0x52, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4d, 0x79, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63,
|
0x6d, 0x79, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0xaa, 0x02, 0x15, 0x58,
|
||||||
0x68, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x72, 0x61, 0x79, 0x52, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4d, 0x79, 0x69, 0x73, 0x70, 0x61, 0x74,
|
||||||
|
0x63, 0x68, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_config_proto_rawDescOnce sync.Once
|
file_app_mydispatcher_config_proto_rawDescOnce sync.Once
|
||||||
file_config_proto_rawDescData = file_config_proto_rawDesc
|
file_app_mydispatcher_config_proto_rawDescData = file_app_mydispatcher_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_config_proto_rawDescGZIP() []byte {
|
func file_app_mydispatcher_config_proto_rawDescGZIP() []byte {
|
||||||
file_config_proto_rawDescOnce.Do(func() {
|
file_app_mydispatcher_config_proto_rawDescOnce.Do(func() {
|
||||||
file_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_config_proto_rawDescData)
|
file_app_mydispatcher_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_mydispatcher_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_config_proto_rawDescData
|
return file_app_mydispatcher_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
var file_app_mydispatcher_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
var file_config_proto_goTypes = []interface{}{
|
var file_app_mydispatcher_config_proto_goTypes = []interface{}{
|
||||||
(*SessionConfig)(nil), // 0: xrayr.app.mydispatcher.SessionConfig
|
(*SessionConfig)(nil), // 0: xrayr.app.mydispatcher.SessionConfig
|
||||||
(*Config)(nil), // 1: xrayr.app.mydispatcher.Config
|
(*Config)(nil), // 1: xrayr.app.mydispatcher.Config
|
||||||
}
|
}
|
||||||
var file_config_proto_depIdxs = []int32{
|
var file_app_mydispatcher_config_proto_depIdxs = []int32{
|
||||||
0, // 0: xrayr.app.mydispatcher.Config.settings:type_name -> xrayr.app.mydispatcher.SessionConfig
|
0, // 0: xrayr.app.mydispatcher.Config.settings:type_name -> xrayr.app.mydispatcher.SessionConfig
|
||||||
1, // [1:1] is the sub-list for method output_type
|
1, // [1:1] is the sub-list for method output_type
|
||||||
1, // [1:1] is the sub-list for method input_type
|
1, // [1:1] is the sub-list for method input_type
|
||||||
@@ -152,13 +153,13 @@ var file_config_proto_depIdxs = []int32{
|
|||||||
0, // [0:1] is the sub-list for field type_name
|
0, // [0:1] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_config_proto_init() }
|
func init() { file_app_mydispatcher_config_proto_init() }
|
||||||
func file_config_proto_init() {
|
func file_app_mydispatcher_config_proto_init() {
|
||||||
if File_config_proto != nil {
|
if File_app_mydispatcher_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !protoimpl.UnsafeEnabled {
|
if !protoimpl.UnsafeEnabled {
|
||||||
file_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
file_app_mydispatcher_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*SessionConfig); i {
|
switch v := v.(*SessionConfig); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -170,7 +171,7 @@ func file_config_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
file_app_mydispatcher_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Config); i {
|
switch v := v.(*Config); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -187,18 +188,18 @@ func file_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_config_proto_rawDesc,
|
RawDescriptor: file_app_mydispatcher_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 2,
|
NumMessages: 2,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
GoTypes: file_config_proto_goTypes,
|
GoTypes: file_app_mydispatcher_config_proto_goTypes,
|
||||||
DependencyIndexes: file_config_proto_depIdxs,
|
DependencyIndexes: file_app_mydispatcher_config_proto_depIdxs,
|
||||||
MessageInfos: file_config_proto_msgTypes,
|
MessageInfos: file_app_mydispatcher_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_config_proto = out.File
|
File_app_mydispatcher_config_proto = out.File
|
||||||
file_config_proto_rawDesc = nil
|
file_app_mydispatcher_config_proto_rawDesc = nil
|
||||||
file_config_proto_goTypes = nil
|
file_app_mydispatcher_config_proto_goTypes = nil
|
||||||
file_config_proto_depIdxs = nil
|
file_app_mydispatcher_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
@@ -95,7 +95,8 @@ type DefaultDispatcher struct {
|
|||||||
router routing.Router
|
router routing.Router
|
||||||
policy policy.Manager
|
policy policy.Manager
|
||||||
stats stats.Manager
|
stats stats.Manager
|
||||||
hosts dns.HostsLookup
|
dns dns.Client
|
||||||
|
fdns dns.FakeDNSEngine
|
||||||
Limiter *limiter.Limiter
|
Limiter *limiter.Limiter
|
||||||
RuleManager *rule.RuleManager
|
RuleManager *rule.RuleManager
|
||||||
}
|
}
|
||||||
@@ -104,6 +105,9 @@ func init() {
|
|||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
d := new(DefaultDispatcher)
|
d := new(DefaultDispatcher)
|
||||||
if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
|
if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
|
||||||
|
core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||||
|
d.fdns = fdns
|
||||||
|
})
|
||||||
return d.Init(config.(*Config), om, router, pm, sm, dc)
|
return d.Init(config.(*Config), om, router, pm, sm, dc)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -113,16 +117,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes DefaultDispatcher.
|
// Init initializes DefaultDispatcher.
|
||||||
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
|
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dns dns.Client) error {
|
||||||
d.ohm = om
|
d.ohm = om
|
||||||
d.router = router
|
d.router = router
|
||||||
d.policy = pm
|
d.policy = pm
|
||||||
d.stats = sm
|
d.stats = sm
|
||||||
d.Limiter = limiter.New()
|
d.Limiter = limiter.New()
|
||||||
d.RuleManager = rule.New()
|
d.RuleManager = rule.New()
|
||||||
if hosts, ok := dc.(dns.HostsLookup); ok {
|
d.dns = dns
|
||||||
d.hosts = hosts
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,10 +141,77 @@ func (*DefaultDispatcher) Start() error {
|
|||||||
// Close implements common.Closable.
|
// Close implements common.Closable.
|
||||||
func (*DefaultDispatcher) Close() error { return nil }
|
func (*DefaultDispatcher) Close() error { return nil }
|
||||||
|
|
||||||
func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *transport.Link, error) {
|
func (d *DefaultDispatcher) getLink(ctx context.Context, network net.Network, sniffing session.SniffingRequest) (*transport.Link, *transport.Link, error) {
|
||||||
opt := pipe.OptionsFromContext(ctx)
|
downOpt := pipe.OptionsFromContext(ctx)
|
||||||
uplinkReader, uplinkWriter := pipe.New(opt...)
|
upOpt := downOpt
|
||||||
downlinkReader, downlinkWriter := pipe.New(opt...)
|
|
||||||
|
if network == net.Network_UDP {
|
||||||
|
var ip2domain *sync.Map // net.IP.String() => domain, this map is used by server side when client turn on fakedns
|
||||||
|
// Client will send domain address in the buffer.UDP.Address, server record all possible target IP addrs.
|
||||||
|
// When target replies, server will restore the domain and send back to client.
|
||||||
|
// Note: this map is not global but per connection context
|
||||||
|
upOpt = append(upOpt, pipe.OnTransmission(func(mb buf.MultiBuffer) buf.MultiBuffer {
|
||||||
|
for i, buffer := range mb {
|
||||||
|
if buffer.UDP == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr := buffer.UDP.Address
|
||||||
|
if addr.Family().IsIP() {
|
||||||
|
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && fkr0.IsIPInIPPool(addr) && sniffing.Enabled {
|
||||||
|
domain := fkr0.GetDomainFromFakeDNS(addr)
|
||||||
|
if len(domain) > 0 {
|
||||||
|
buffer.UDP.Address = net.DomainAddress(domain)
|
||||||
|
newError("[fakedns client] override with domain: ", domain, " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
} else {
|
||||||
|
newError("[fakedns client] failed to find domain! :", addr.String(), " for xUDP buffer at ", i).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ip2domain == nil {
|
||||||
|
ip2domain = new(sync.Map)
|
||||||
|
newError("[fakedns client] create a new map").WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
domain := addr.Domain()
|
||||||
|
ips, err := d.dns.LookupIP(domain, dns.IPOption{true, true, false})
|
||||||
|
if err == nil {
|
||||||
|
for _, ip := range ips {
|
||||||
|
ip2domain.Store(ip.String(), domain)
|
||||||
|
}
|
||||||
|
newError("[fakedns client] candidate ip: "+fmt.Sprintf("%v", ips), " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
} else {
|
||||||
|
newError("[fakedns client] failed to look up IP for ", domain, " for xUDP buffer at ", i).Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mb
|
||||||
|
}))
|
||||||
|
downOpt = append(downOpt, pipe.OnTransmission(func(mb buf.MultiBuffer) buf.MultiBuffer {
|
||||||
|
for i, buffer := range mb {
|
||||||
|
if buffer.UDP == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr := buffer.UDP.Address
|
||||||
|
if addr.Family().IsIP() {
|
||||||
|
if ip2domain == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if domain, found := ip2domain.Load(addr.IP().String()); found {
|
||||||
|
buffer.UDP.Address = net.DomainAddress(domain.(string))
|
||||||
|
newError("[fakedns client] restore domain: ", domain.(string), " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok {
|
||||||
|
fakeIp := fkr0.GetFakeIPForDomain(addr.Domain())
|
||||||
|
buffer.UDP.Address = fakeIp[0]
|
||||||
|
newError("[fakedns client] restore FakeIP: ", buffer.UDP, fmt.Sprintf("%v", fakeIp), " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mb
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
uplinkReader, uplinkWriter := pipe.New(upOpt...)
|
||||||
|
downlinkReader, downlinkWriter := pipe.New(downOpt...)
|
||||||
|
|
||||||
inboundLink := &transport.Link{
|
inboundLink := &transport.Link{
|
||||||
Reader: downlinkReader,
|
Reader: downlinkReader,
|
||||||
@@ -199,17 +268,13 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||||||
return inboundLink, outboundLink, nil
|
return inboundLink, outboundLink, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
for _, d := range request.ExcludeForDomain {
|
for _, d := range request.ExcludeForDomain {
|
||||||
if strings.ToLower(domain) == d {
|
if strings.ToLower(domain) == d {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var fakeDNSEngine dns.FakeDNSEngine
|
|
||||||
core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
|
||||||
fakeDNSEngine = fdns
|
|
||||||
})
|
|
||||||
protocolString := result.Protocol()
|
protocolString := result.Protocol()
|
||||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
if resComp, ok := result.(SnifferResultComposite); ok {
|
||||||
protocolString = resComp.ProtocolForDomainResult()
|
protocolString = resComp.ProtocolForDomainResult()
|
||||||
@@ -218,7 +283,7 @@ func shouldOverride(ctx context.Context, result SniffResult, request session.Sni
|
|||||||
if strings.HasPrefix(protocolString, p) {
|
if strings.HasPrefix(protocolString, p) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" &&
|
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" &&
|
||||||
destination.Address.Family().IsIP() && fkr0.IsIPInIPPool(destination.Address) {
|
destination.Address.Family().IsIP() && fkr0.IsIPInIPPool(destination.Address) {
|
||||||
newError("Using sniffer ", protocolString, " since the fake DNS missed").WriteToLog(session.ExportIDToError(ctx))
|
newError("Using sniffer ", protocolString, " since the fake DNS missed").WriteToLog(session.ExportIDToError(ctx))
|
||||||
return true
|
return true
|
||||||
@@ -242,17 +307,17 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||||||
Target: destination,
|
Target: destination,
|
||||||
}
|
}
|
||||||
ctx = session.ContextWithOutbound(ctx, ob)
|
ctx = session.ContextWithOutbound(ctx, ob)
|
||||||
|
|
||||||
inbound, outbound, err := d.getLink(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
content := session.ContentFromContext(ctx)
|
content := session.ContentFromContext(ctx)
|
||||||
if content == nil {
|
if content == nil {
|
||||||
content = new(session.Content)
|
content = new(session.Content)
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
sniffingRequest := content.SniffingRequest
|
sniffingRequest := content.SniffingRequest
|
||||||
|
inbound, outbound, err := d.getLink(ctx, destination.Network, sniffingRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
switch {
|
switch {
|
||||||
case !sniffingRequest.Enabled:
|
case !sniffingRequest.Enabled:
|
||||||
go d.routedDispatch(ctx, outbound, destination)
|
go d.routedDispatch(ctx, outbound, destination)
|
||||||
@@ -261,7 +326,7 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||||||
result, err := sniffer(ctx, nil, true)
|
result, err := sniffer(ctx, nil, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
content.Protocol = result.Protocol()
|
content.Protocol = result.Protocol()
|
||||||
if shouldOverride(ctx, result, sniffingRequest, destination) {
|
if d.shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||||
destination.Address = net.ParseAddress(domain)
|
destination.Address = net.ParseAddress(domain)
|
||||||
@@ -283,7 +348,7 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
content.Protocol = result.Protocol()
|
content.Protocol = result.Protocol()
|
||||||
}
|
}
|
||||||
if err == nil && shouldOverride(ctx, result, sniffingRequest, destination) {
|
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||||
destination.Address = net.ParseAddress(domain)
|
destination.Address = net.ParseAddress(domain)
|
||||||
@@ -322,7 +387,7 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
|||||||
result, err := sniffer(ctx, nil, true)
|
result, err := sniffer(ctx, nil, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
content.Protocol = result.Protocol()
|
content.Protocol = result.Protocol()
|
||||||
if shouldOverride(ctx, result, sniffingRequest, destination) {
|
if d.shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||||
destination.Address = net.ParseAddress(domain)
|
destination.Address = net.ParseAddress(domain)
|
||||||
@@ -344,7 +409,7 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
content.Protocol = result.Protocol()
|
content.Protocol = result.Protocol()
|
||||||
}
|
}
|
||||||
if err == nil && shouldOverride(ctx, result, sniffingRequest, destination) {
|
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||||
destination.Address = net.ParseAddress(domain)
|
destination.Address = net.ParseAddress(domain)
|
||||||
@@ -408,8 +473,8 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool) (Sni
|
|||||||
|
|
||||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||||
ob := session.OutboundFromContext(ctx)
|
ob := session.OutboundFromContext(ctx)
|
||||||
if d.hosts != nil && destination.Address.Family().IsDomain() {
|
if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() {
|
||||||
proxied := d.hosts.LookupHosts(ob.Target.String())
|
proxied := hosts.LookupHosts(ob.Target.String())
|
||||||
if proxied != nil {
|
if proxied != nil {
|
||||||
ro := ob.RouteTarget == destination
|
ro := ob.RouteTarget == destination
|
||||||
destination.Address = *proxied
|
destination.Address = *proxied
|
||||||
@@ -438,10 +503,11 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
|||||||
|
|
||||||
routingLink := routing_session.AsRoutingContext(ctx)
|
routingLink := routing_session.AsRoutingContext(ctx)
|
||||||
inTag := routingLink.GetInboundTag()
|
inTag := routingLink.GetInboundTag()
|
||||||
|
isPickRoute := 0
|
||||||
if forcedOutboundTag := session.GetForcedOutboundTagFromContext(ctx); forcedOutboundTag != "" {
|
if forcedOutboundTag := session.GetForcedOutboundTagFromContext(ctx); forcedOutboundTag != "" {
|
||||||
ctx = session.SetForcedOutboundTagToContext(ctx, "")
|
ctx = session.SetForcedOutboundTagToContext(ctx, "")
|
||||||
if h := d.ohm.GetHandler(forcedOutboundTag); h != nil {
|
if h := d.ohm.GetHandler(forcedOutboundTag); h != nil {
|
||||||
|
isPickRoute = 1
|
||||||
newError("taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
|
newError("taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
|
||||||
handler = h
|
handler = h
|
||||||
} else {
|
} else {
|
||||||
@@ -451,13 +517,14 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if d.router != nil {
|
} else if d.router != nil {
|
||||||
if route, err := d.router.PickRoute(routing_session.AsRoutingContext(ctx)); err == nil {
|
if route, err := d.router.PickRoute(routingLink); err == nil {
|
||||||
tag := route.GetOutboundTag()
|
outTag := route.GetOutboundTag()
|
||||||
if h := d.ohm.GetHandler(tag); h != nil {
|
if h := d.ohm.GetHandler(outTag); h != nil {
|
||||||
newError("taking detour [", tag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
|
isPickRoute = 2
|
||||||
|
newError("taking detour [", outTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
|
||||||
handler = h
|
handler = h
|
||||||
} else {
|
} else {
|
||||||
newError("non existing outTag: ", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
newError("non existing outTag: ", outTag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx))
|
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx))
|
||||||
@@ -482,7 +549,15 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
|||||||
|
|
||||||
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
|
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
|
||||||
if tag := handler.Tag(); tag != "" {
|
if tag := handler.Tag(); tag != "" {
|
||||||
accessMessage.Detour = tag
|
if inTag == "" {
|
||||||
|
accessMessage.Detour = tag
|
||||||
|
} else if isPickRoute == 1 {
|
||||||
|
accessMessage.Detour = inTag + " ==> " + tag
|
||||||
|
} else if isPickRoute == 2 {
|
||||||
|
accessMessage.Detour = inTag + " -> " + tag
|
||||||
|
} else {
|
||||||
|
accessMessage.Detour = inTag + " >> " + tag
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log.Record(accessMessage)
|
log.Record(accessMessage)
|
||||||
}
|
}
|
||||||
|
@@ -14,12 +14,13 @@ import (
|
|||||||
// newFakeDNSSniffer Create a Fake DNS metadata sniffer
|
// newFakeDNSSniffer Create a Fake DNS metadata sniffer
|
||||||
func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error) {
|
func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error) {
|
||||||
var fakeDNSEngine dns.FakeDNSEngine
|
var fakeDNSEngine dns.FakeDNSEngine
|
||||||
err := core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
{
|
||||||
fakeDNSEngine = fdns
|
fakeDNSEngineFeat := core.MustFromContext(ctx).GetFeature((*dns.FakeDNSEngine)(nil))
|
||||||
})
|
if fakeDNSEngineFeat != nil {
|
||||||
if err != nil {
|
fakeDNSEngine = fakeDNSEngineFeat.(dns.FakeDNSEngine)
|
||||||
return protocolSnifferWithMetadata{}, err
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if fakeDNSEngine == nil {
|
if fakeDNSEngine == nil {
|
||||||
errNotInit := newError("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
|
errNotInit := newError("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
|
||||||
return protocolSnifferWithMetadata{}, errNotInit
|
return protocolSnifferWithMetadata{}, errNotInit
|
||||||
|
@@ -3,39 +3,51 @@ package serverstatus
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/shirou/gopsutil/cpu"
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
"github.com/shirou/gopsutil/disk"
|
"github.com/shirou/gopsutil/v3/disk"
|
||||||
"github.com/shirou/gopsutil/mem"
|
"github.com/shirou/gopsutil/v3/host"
|
||||||
|
"github.com/shirou/gopsutil/v3/mem"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetSystemInfo get the system info of a given periodic
|
// GetSystemInfo get the system info of a given periodic
|
||||||
func GetSystemInfo() (Cpu float64, Mem float64, Disk float64, Uptime int, err error) {
|
func GetSystemInfo() (Cpu float64, Mem float64, Disk float64, Uptime uint64, err error) {
|
||||||
|
|
||||||
|
error_string := ""
|
||||||
|
|
||||||
upTime := time.Now()
|
|
||||||
cpuPercent, err := cpu.Percent(0, false)
|
cpuPercent, err := cpu.Percent(0, false)
|
||||||
// Check if cpuPercent is empty
|
// Check if cpuPercent is empty
|
||||||
if len(cpuPercent) > 0 {
|
if len(cpuPercent) > 0 && err == nil {
|
||||||
Cpu = cpuPercent[0]
|
Cpu = cpuPercent[0]
|
||||||
} else {
|
} else {
|
||||||
Cpu = 0
|
Cpu = 0
|
||||||
}
|
error_string += fmt.Sprintf("get cpu usage failed: %s ", err)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, 0, 0, fmt.Errorf("get cpu usage failed: %s", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memUsage, err := mem.VirtualMemory()
|
memUsage, err := mem.VirtualMemory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, 0, 0, fmt.Errorf("get mem usage failed: %s", err)
|
error_string += fmt.Sprintf("get mem usage failed: %s ", err)
|
||||||
|
} else {
|
||||||
|
Mem = memUsage.UsedPercent
|
||||||
}
|
}
|
||||||
|
|
||||||
diskUsage, err := disk.Usage("/")
|
diskUsage, err := disk.Usage("/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, 0, 0, fmt.Errorf("et disk usage failed: %s", err)
|
error_string += fmt.Sprintf("get disk usage failed: %s ", err)
|
||||||
|
} else {
|
||||||
|
Disk = diskUsage.UsedPercent
|
||||||
}
|
}
|
||||||
|
|
||||||
Uptime = int(time.Since(upTime).Seconds())
|
uptime, err := host.Uptime()
|
||||||
return Cpu, memUsage.UsedPercent, diskUsage.UsedPercent, Uptime, nil
|
if err != nil {
|
||||||
|
error_string += fmt.Sprintf("get uptime failed: %s ", err)
|
||||||
|
} else {
|
||||||
|
Uptime = uptime
|
||||||
|
}
|
||||||
|
|
||||||
|
if error_string != "" {
|
||||||
|
err = fmt.Errorf(error_string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cpu, Mem, Disk, Uptime, err
|
||||||
}
|
}
|
||||||
|
154
go.mod
154
go.mod
@@ -1,38 +1,33 @@
|
|||||||
module github.com/XrayR-project/XrayR
|
module github.com/XrayR-project/XrayR
|
||||||
|
|
||||||
go 1.17
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bitly/go-simplejson v0.5.0
|
github.com/bitly/go-simplejson v0.5.0
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
|
||||||
github.com/deckarep/golang-set v1.8.0
|
github.com/deckarep/golang-set v1.8.0
|
||||||
github.com/fsnotify/fsnotify v1.5.4
|
github.com/fsnotify/fsnotify v1.5.4
|
||||||
github.com/go-acme/lego/v4 v4.6.0
|
github.com/go-acme/lego/v4 v4.8.0
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
|
||||||
github.com/go-resty/resty/v2 v2.7.0
|
github.com/go-resty/resty/v2 v2.7.0
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/imdario/mergo v0.3.13
|
||||||
github.com/imdario/mergo v0.3.12
|
github.com/juju/ratelimit v1.0.2
|
||||||
github.com/juju/ratelimit v1.0.1
|
|
||||||
github.com/r3labs/diff/v2 v2.15.1
|
github.com/r3labs/diff/v2 v2.15.1
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
github.com/shirou/gopsutil/v3 v3.22.7
|
||||||
github.com/spf13/viper v1.11.0
|
github.com/spf13/viper v1.12.0
|
||||||
github.com/stretchr/testify v1.7.1
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
github.com/urfave/cli v1.22.9
|
||||||
github.com/urfave/cli v1.22.7
|
github.com/xtls/xray-core v1.5.9
|
||||||
github.com/xtls/xray-core v1.5.5
|
golang.org/x/net v0.0.0-20220812174116-3211cb980234
|
||||||
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861
|
google.golang.org/protobuf v1.28.1
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
|
||||||
google.golang.org/protobuf v1.28.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/compute v1.5.0 // indirect
|
cloud.google.com/go/compute v1.6.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go v62.0.0+incompatible // indirect
|
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible // indirect
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||||
github.com/Azure/go-autorest/autorest v0.11.24 // indirect
|
github.com/Azure/go-autorest/autorest v0.11.19 // indirect
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
|
||||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect
|
github.com/Azure/go-autorest/autorest/azure/auth v0.5.8 // indirect
|
||||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect
|
github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 // indirect
|
||||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||||
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||||
@@ -40,60 +35,66 @@ require (
|
|||||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
|
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
|
||||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 // indirect
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 // indirect
|
||||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1505 // indirect
|
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183 // indirect
|
||||||
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
|
github.com/aws/aws-sdk-go v1.39.0 // indirect
|
||||||
github.com/aws/aws-sdk-go v1.43.12 // indirect
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
||||||
github.com/boombuler/barcode v1.0.1 // indirect
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
|
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
|
||||||
github.com/cheekybits/genny v1.0.0 // indirect
|
github.com/cheekybits/genny v1.0.0 // indirect
|
||||||
github.com/cloudflare/cloudflare-go v0.34.0 // indirect
|
github.com/cloudflare/cloudflare-go v0.20.0 // indirect
|
||||||
github.com/cpu/goacmedns v0.1.1 // indirect
|
github.com/cpu/goacmedns v0.1.1 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/deepmap/oapi-codegen v1.9.1 // indirect
|
github.com/deepmap/oapi-codegen v1.6.1 // indirect
|
||||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
||||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||||
github.com/dnsimple/dnsimple-go v0.71.1 // indirect
|
github.com/dnsimple/dnsimple-go v0.70.1 // indirect
|
||||||
github.com/exoscale/egoscale v1.19.0 // indirect
|
github.com/exoscale/egoscale v0.67.0 // indirect
|
||||||
github.com/fatih/structs v1.1.0 // indirect
|
github.com/fatih/structs v1.1.0 // indirect
|
||||||
|
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
|
||||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect
|
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect
|
||||||
github.com/go-errors/errors v1.4.2 // indirect
|
github.com/go-errors/errors v1.0.1 // indirect
|
||||||
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
github.com/gofrs/uuid v3.2.0+incompatible // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.3.0 // indirect
|
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||||
github.com/gophercloud/gophercloud v0.24.0 // indirect
|
github.com/gophercloud/gophercloud v0.16.0 // indirect
|
||||||
github.com/gophercloud/utils v0.0.0-20220209210848-d0ab9f2a8909 // indirect
|
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
|
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
|
||||||
github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect
|
github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect
|
||||||
github.com/jarcoal/httpmock v1.1.0 // indirect
|
github.com/jarcoal/httpmock v1.0.8 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect
|
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect
|
||||||
github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b // indirect
|
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
|
||||||
|
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b // indirect
|
||||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect
|
github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect
|
||||||
github.com/labbsr0x/goh v1.0.1 // indirect
|
github.com/labbsr0x/goh v1.0.1 // indirect
|
||||||
github.com/linode/linodego v1.3.0 // indirect
|
github.com/linode/linodego v0.31.1 // indirect
|
||||||
github.com/liquidweb/go-lwApi v0.0.5 // indirect
|
github.com/liquidweb/go-lwApi v0.0.5 // indirect
|
||||||
github.com/liquidweb/liquidweb-cli v0.6.10 // indirect
|
github.com/liquidweb/liquidweb-cli v0.6.9 // indirect
|
||||||
github.com/liquidweb/liquidweb-go v1.6.3 // indirect
|
github.com/liquidweb/liquidweb-go v1.6.3 // indirect
|
||||||
github.com/lucas-clemente/quic-go v0.27.0 // indirect
|
github.com/lucas-clemente/quic-go v0.28.0 // indirect
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||||
github.com/magiconair/properties v1.8.6 // indirect
|
github.com/magiconair/properties v1.8.6 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
|
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
|
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
||||||
|
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/miekg/dns v1.1.48 // indirect
|
github.com/miekg/dns v1.1.50 // indirect
|
||||||
|
github.com/mimuret/golang-iij-dpf v0.7.1 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
|
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
|
||||||
@@ -110,59 +111,64 @@ require (
|
|||||||
github.com/ovh/go-ovh v1.1.0 // indirect
|
github.com/ovh/go-ovh v1.1.0 // indirect
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||||
github.com/pires/go-proxyproto v0.6.2 // indirect
|
github.com/pires/go-proxyproto v0.6.2 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||||
github.com/pquerna/otp v1.3.0 // indirect
|
github.com/pquerna/otp v1.3.0 // indirect
|
||||||
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2 // indirect
|
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2 // indirect
|
||||||
github.com/refraction-networking/utls v1.0.0 // indirect
|
github.com/refraction-networking/utls v1.1.0 // indirect
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.8.1 // indirect
|
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
|
||||||
github.com/sacloud/libsacloud v1.36.2 // indirect
|
github.com/sacloud/libsacloud v1.36.2 // indirect
|
||||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9 // indirect
|
github.com/sagernet/sing v0.0.0-20220714145306-09b55ce4b6d0 // indirect
|
||||||
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220716012931-952ae62e05d7 // indirect
|
||||||
|
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f // indirect
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
|
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
|
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
|
||||||
github.com/softlayer/softlayer-go v1.0.4 // indirect
|
github.com/softlayer/softlayer-go v1.0.3 // indirect
|
||||||
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
|
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
|
||||||
github.com/spf13/afero v1.8.2 // indirect
|
github.com/spf13/afero v1.8.2 // indirect
|
||||||
github.com/spf13/cast v1.4.1 // indirect
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/stretchr/objx v0.3.0 // indirect
|
github.com/stretchr/objx v0.4.0 // indirect
|
||||||
github.com/subosito/gotenv v1.2.0 // indirect
|
github.com/subosito/gotenv v1.3.0 // indirect
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.360 // indirect
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.287 // indirect
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.360 // indirect
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.287 // indirect
|
||||||
|
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||||
github.com/transip/gotransip/v6 v6.14.0 // indirect
|
github.com/transip/gotransip/v6 v6.6.1 // indirect
|
||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
||||||
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
|
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||||
github.com/vultr/govultr/v2 v2.14.1 // indirect
|
github.com/vultr/govultr/v2 v2.16.0 // indirect
|
||||||
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 // indirect
|
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
go.opencensus.io v0.23.0 // indirect
|
go.opencensus.io v0.23.0 // indirect
|
||||||
go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd // indirect
|
go.starlark.net v0.0.0-20220714194419-4cadf0a12139 // indirect
|
||||||
go.uber.org/ratelimit v0.2.0 // indirect
|
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
|
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
|
||||||
golang.org/x/tools v0.1.10 // indirect
|
golang.org/x/tools v0.1.11 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
google.golang.org/api v0.81.0 // indirect
|
||||||
google.golang.org/api v0.74.0 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220422154200-b37d22cd5731 // indirect
|
google.golang.org/genproto v0.0.0-20220715211116-798f69b842b9 // indirect
|
||||||
google.golang.org/grpc v1.46.0 // indirect
|
google.golang.org/grpc v1.48.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||||
gopkg.in/ns1/ns1-go.v2 v2.6.3 // indirect
|
gopkg.in/ns1/ns1-go.v2 v2.6.2 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
lukechampine.com/blake3 v1.1.7 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/linode/linodego => github.com/linode/linodego v0.31.1
|
replace github.com/linode/linodego => github.com/linode/linodego v0.31.1
|
||||||
|
@@ -14,7 +14,7 @@ ConnetionConfig:
|
|||||||
BufferSize: 64 # The internal cache size of each connection, kB
|
BufferSize: 64 # The internal cache size of each connection, kB
|
||||||
Nodes:
|
Nodes:
|
||||||
-
|
-
|
||||||
PanelType: "SSpanel" # Panel type: SSpanel, V2board, PMpanel, , Proxypanel
|
PanelType: "SSpanel" # Panel type: SSpanel, V2board, PMpanel, Proxypanel, V2RaySocks
|
||||||
ApiConfig:
|
ApiConfig:
|
||||||
ApiHost: "http://127.0.0.1:667"
|
ApiHost: "http://127.0.0.1:667"
|
||||||
ApiKey: "123"
|
ApiKey: "123"
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"tag": "IPv4_out",
|
"tag": "IPv4_out",
|
||||||
"protocol": "freedom"
|
"protocol": "freedom",
|
||||||
|
"settings": {}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tag": "IPv6_out",
|
"tag": "IPv6_out",
|
||||||
@@ -10,6 +11,16 @@
|
|||||||
"domainStrategy": "UseIPv6"
|
"domainStrategy": "UseIPv6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"tag": "socks5-warp",
|
||||||
|
"protocol": "socks",
|
||||||
|
"settings": {
|
||||||
|
"servers": [{
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"port": 1080
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"protocol": "blackhole",
|
"protocol": "blackhole",
|
||||||
"tag": "block"
|
"tag": "block"
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
// Required features. Can't remove unless there is replacements.
|
// Required features. Can't remove unless there is replacements.
|
||||||
// _ "github.com/xtls/xray-core/app/dispatcher"
|
// _ "github.com/xtls/xray-core/app/dispatcher"
|
||||||
|
_ "github.com/XrayR-project/XrayR/app/mydispatcher"
|
||||||
_ "github.com/xtls/xray-core/app/proxyman/inbound"
|
_ "github.com/xtls/xray-core/app/proxyman/inbound"
|
||||||
_ "github.com/xtls/xray-core/app/proxyman/outbound"
|
_ "github.com/xtls/xray-core/app/proxyman/outbound"
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ import (
|
|||||||
// Other optional features.
|
// Other optional features.
|
||||||
_ "github.com/xtls/xray-core/app/dns"
|
_ "github.com/xtls/xray-core/app/dns"
|
||||||
_ "github.com/xtls/xray-core/app/log"
|
_ "github.com/xtls/xray-core/app/log"
|
||||||
|
_ "github.com/xtls/xray-core/app/metrics"
|
||||||
_ "github.com/xtls/xray-core/app/policy"
|
_ "github.com/xtls/xray-core/app/policy"
|
||||||
_ "github.com/xtls/xray-core/app/reverse"
|
_ "github.com/xtls/xray-core/app/reverse"
|
||||||
_ "github.com/xtls/xray-core/app/router"
|
_ "github.com/xtls/xray-core/app/router"
|
||||||
|
BIN
main/geoip.dat
BIN
main/geoip.dat
Binary file not shown.
46817
main/geosite.dat
46817
main/geosite.dat
File diff suppressed because one or more lines are too long
@@ -23,7 +23,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
version = "0.8.0"
|
version = "0.8.2"
|
||||||
codename = "XrayR"
|
codename = "XrayR"
|
||||||
intro = "A Xray backend that supports many panels"
|
intro = "A Xray backend that supports many panels"
|
||||||
)
|
)
|
||||||
|
@@ -15,12 +15,22 @@
|
|||||||
"bittorrent"
|
"bittorrent"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"outboundTag": "socks5-warp",
|
||||||
|
"domain": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "field",
|
||||||
"outboundTag": "IPv6_out",
|
"outboundTag": "IPv6_out",
|
||||||
"domain": [
|
"domain": [
|
||||||
"geosite:netflix"
|
"geosite:netflix"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"outboundTag": "IPv4_out",
|
||||||
|
"network": "udp,tcp"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@@ -6,12 +6,14 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/XrayR-project/XrayR/app/mydispatcher"
|
||||||
|
|
||||||
"github.com/XrayR-project/XrayR/api"
|
"github.com/XrayR-project/XrayR/api"
|
||||||
"github.com/XrayR-project/XrayR/api/pmpanel"
|
"github.com/XrayR-project/XrayR/api/pmpanel"
|
||||||
"github.com/XrayR-project/XrayR/api/proxypanel"
|
"github.com/XrayR-project/XrayR/api/proxypanel"
|
||||||
"github.com/XrayR-project/XrayR/api/sspanel"
|
"github.com/XrayR-project/XrayR/api/sspanel"
|
||||||
"github.com/XrayR-project/XrayR/api/v2board"
|
"github.com/XrayR-project/XrayR/api/v2board"
|
||||||
"github.com/XrayR-project/XrayR/app/mydispatcher"
|
"github.com/XrayR-project/XrayR/api/v2raysocks"
|
||||||
_ "github.com/XrayR-project/XrayR/main/distro/all"
|
_ "github.com/XrayR-project/XrayR/main/distro/all"
|
||||||
"github.com/XrayR-project/XrayR/service"
|
"github.com/XrayR-project/XrayR/service"
|
||||||
"github.com/XrayR-project/XrayR/service/controller"
|
"github.com/XrayR-project/XrayR/service/controller"
|
||||||
@@ -171,6 +173,8 @@ func (p *Panel) Start() {
|
|||||||
apiClient = pmpanel.New(nodeConfig.ApiConfig)
|
apiClient = pmpanel.New(nodeConfig.ApiConfig)
|
||||||
case "Proxypanel":
|
case "Proxypanel":
|
||||||
apiClient = proxypanel.New(nodeConfig.ApiConfig)
|
apiClient = proxypanel.New(nodeConfig.ApiConfig)
|
||||||
|
case "V2RaySocks":
|
||||||
|
apiClient = v2raysocks.New(nodeConfig.ApiConfig)
|
||||||
default:
|
default:
|
||||||
log.Panicf("Unsupport panel type: %s", nodeConfig.PanelType)
|
log.Panicf("Unsupport panel type: %s", nodeConfig.PanelType)
|
||||||
}
|
}
|
||||||
|
@@ -5,30 +5,24 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/XrayR-project/XrayR/api"
|
"github.com/XrayR-project/XrayR/api"
|
||||||
"github.com/XrayR-project/XrayR/app/mydispatcher"
|
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/inbound"
|
"github.com/xtls/xray-core/features/inbound"
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
|
||||||
"github.com/xtls/xray-core/features/stats"
|
|
||||||
"github.com/xtls/xray-core/proxy"
|
"github.com/xtls/xray-core/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) removeInbound(tag string) error {
|
func (c *Controller) removeInbound(tag string) error {
|
||||||
inboundManager := c.server.GetFeature(inbound.ManagerType()).(inbound.Manager)
|
err := c.ihm.RemoveHandler(context.Background(), tag)
|
||||||
err := inboundManager.RemoveHandler(context.Background(), tag)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) removeOutbound(tag string) error {
|
func (c *Controller) removeOutbound(tag string) error {
|
||||||
outboundManager := c.server.GetFeature(outbound.ManagerType()).(outbound.Manager)
|
err := c.ohm.RemoveHandler(context.Background(), tag)
|
||||||
err := outboundManager.RemoveHandler(context.Background(), tag)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) addInbound(config *core.InboundHandlerConfig) error {
|
func (c *Controller) addInbound(config *core.InboundHandlerConfig) error {
|
||||||
inboundManager := c.server.GetFeature(inbound.ManagerType()).(inbound.Manager)
|
|
||||||
rawHandler, err := core.CreateObject(c.server, config)
|
rawHandler, err := core.CreateObject(c.server, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -37,14 +31,13 @@ func (c *Controller) addInbound(config *core.InboundHandlerConfig) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("not an InboundHandler: %s", err)
|
return fmt.Errorf("not an InboundHandler: %s", err)
|
||||||
}
|
}
|
||||||
if err := inboundManager.AddHandler(context.Background(), handler); err != nil {
|
if err := c.ihm.AddHandler(context.Background(), handler); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) addOutbound(config *core.OutboundHandlerConfig) error {
|
func (c *Controller) addOutbound(config *core.OutboundHandlerConfig) error {
|
||||||
outboundManager := c.server.GetFeature(outbound.ManagerType()).(outbound.Manager)
|
|
||||||
rawHandler, err := core.CreateObject(c.server, config)
|
rawHandler, err := core.CreateObject(c.server, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -53,26 +46,25 @@ func (c *Controller) addOutbound(config *core.OutboundHandlerConfig) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("not an InboundHandler: %s", err)
|
return fmt.Errorf("not an InboundHandler: %s", err)
|
||||||
}
|
}
|
||||||
if err := outboundManager.AddHandler(context.Background(), handler); err != nil {
|
if err := c.ohm.AddHandler(context.Background(), handler); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) addUsers(users []*protocol.User, tag string) error {
|
func (c *Controller) addUsers(users []*protocol.User, tag string) error {
|
||||||
inboundManager := c.server.GetFeature(inbound.ManagerType()).(inbound.Manager)
|
handler, err := c.ihm.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 {
|
||||||
return fmt.Errorf("handler %s is not implement proxy.GetInbound", tag)
|
return fmt.Errorf("handler %s has not implemented proxy.GetInbound", tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
userManager, ok := inboundInstance.GetInbound().(proxy.UserManager)
|
userManager, ok := inboundInstance.GetInbound().(proxy.UserManager)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("handler %s is not implement proxy.UserManager", err)
|
return fmt.Errorf("handler %s has not implemented proxy.UserManager", tag)
|
||||||
}
|
}
|
||||||
for _, item := range users {
|
for _, item := range users {
|
||||||
mUser, err := item.ToMemoryUser()
|
mUser, err := item.ToMemoryUser()
|
||||||
@@ -88,8 +80,7 @@ func (c *Controller) addUsers(users []*protocol.User, tag string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) removeUsers(users []string, tag string) error {
|
func (c *Controller) removeUsers(users []string, tag string) error {
|
||||||
inboundManager := c.server.GetFeature(inbound.ManagerType()).(inbound.Manager)
|
handler, err := c.ihm.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)
|
||||||
}
|
}
|
||||||
@@ -114,9 +105,8 @@ func (c *Controller) removeUsers(users []string, tag string) error {
|
|||||||
func (c *Controller) getTraffic(email string) (up int64, down int64) {
|
func (c *Controller) getTraffic(email string) (up int64, down int64) {
|
||||||
upName := "user>>>" + email + ">>>traffic>>>uplink"
|
upName := "user>>>" + email + ">>>traffic>>>uplink"
|
||||||
downName := "user>>>" + email + ">>>traffic>>>downlink"
|
downName := "user>>>" + email + ">>>traffic>>>downlink"
|
||||||
statsManager := c.server.GetFeature(stats.ManagerType()).(stats.Manager)
|
upCounter := c.stm.GetCounter(upName)
|
||||||
upCounter := statsManager.GetCounter(upName)
|
downCounter := c.stm.GetCounter(downName)
|
||||||
downCounter := statsManager.GetCounter(downName)
|
|
||||||
if upCounter != nil {
|
if upCounter != nil {
|
||||||
up = upCounter.Value()
|
up = upCounter.Value()
|
||||||
upCounter.Set(0)
|
upCounter.Set(0)
|
||||||
@@ -130,35 +120,29 @@ func (c *Controller) getTraffic(email string) (up int64, down int64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) AddInboundLimiter(tag string, nodeSpeedLimit uint64, userList *[]api.UserInfo) error {
|
func (c *Controller) AddInboundLimiter(tag string, nodeSpeedLimit uint64, userList *[]api.UserInfo) error {
|
||||||
dispather := c.server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher)
|
err := c.dispatcher.Limiter.AddInboundLimiter(tag, nodeSpeedLimit, userList)
|
||||||
err := dispather.Limiter.AddInboundLimiter(tag, nodeSpeedLimit, userList)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) UpdateInboundLimiter(tag string, updatedUserList *[]api.UserInfo) error {
|
func (c *Controller) UpdateInboundLimiter(tag string, updatedUserList *[]api.UserInfo) error {
|
||||||
dispather := c.server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher)
|
err := c.dispatcher.Limiter.UpdateInboundLimiter(tag, updatedUserList)
|
||||||
err := dispather.Limiter.UpdateInboundLimiter(tag, updatedUserList)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) DeleteInboundLimiter(tag string) error {
|
func (c *Controller) DeleteInboundLimiter(tag string) error {
|
||||||
dispather := c.server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher)
|
err := c.dispatcher.Limiter.DeleteInboundLimiter(tag)
|
||||||
err := dispather.Limiter.DeleteInboundLimiter(tag)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) GetOnlineDevice(tag string) (*[]api.OnlineUser, error) {
|
func (c *Controller) GetOnlineDevice(tag string) (*[]api.OnlineUser, error) {
|
||||||
dispather := c.server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher)
|
return c.dispatcher.Limiter.GetOnlineDevice(tag)
|
||||||
return dispather.Limiter.GetOnlineDevice(tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) UpdateRule(tag string, newRuleList []api.DetectRule) error {
|
func (c *Controller) UpdateRule(tag string, newRuleList []api.DetectRule) error {
|
||||||
dispather := c.server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher)
|
err := c.dispatcher.RuleManager.UpdateRule(tag, newRuleList)
|
||||||
err := dispather.RuleManager.UpdateRule(tag, newRuleList)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) GetDetectResult(tag string) (*[]api.DetectResult, error) {
|
func (c *Controller) GetDetectResult(tag string) (*[]api.DetectResult, error) {
|
||||||
dispather := c.server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher)
|
return c.dispatcher.RuleManager.GetDetectResult(tag)
|
||||||
return dispather.RuleManager.GetDetectResult(tag)
|
|
||||||
}
|
}
|
||||||
|
@@ -3,16 +3,20 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/XrayR-project/XrayR/api"
|
"github.com/XrayR-project/XrayR/api"
|
||||||
|
"github.com/XrayR-project/XrayR/app/mydispatcher"
|
||||||
"github.com/XrayR-project/XrayR/common/legocmd"
|
"github.com/XrayR-project/XrayR/common/legocmd"
|
||||||
"github.com/XrayR-project/XrayR/common/serverstatus"
|
"github.com/XrayR-project/XrayR/common/serverstatus"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
|
"github.com/xtls/xray-core/features/inbound"
|
||||||
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
|
"github.com/xtls/xray-core/features/routing"
|
||||||
|
"github.com/xtls/xray-core/features/stats"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
@@ -26,15 +30,23 @@ type Controller struct {
|
|||||||
nodeInfoMonitorPeriodic *task.Periodic
|
nodeInfoMonitorPeriodic *task.Periodic
|
||||||
userReportPeriodic *task.Periodic
|
userReportPeriodic *task.Periodic
|
||||||
panelType string
|
panelType string
|
||||||
|
ihm inbound.Manager
|
||||||
|
ohm outbound.Manager
|
||||||
|
stm stats.Manager
|
||||||
|
dispatcher *mydispatcher.DefaultDispatcher
|
||||||
}
|
}
|
||||||
|
|
||||||
// New return a Controller service with default parameters.
|
// New return a Controller service with default parameters.
|
||||||
func New(server *core.Instance, api api.API, config *Config, panelType string) *Controller {
|
func New(server *core.Instance, api api.API, config *Config, panelType string) *Controller {
|
||||||
controller := &Controller{
|
controller := &Controller{
|
||||||
server: server,
|
server: server,
|
||||||
config: config,
|
config: config,
|
||||||
apiClient: api,
|
apiClient: api,
|
||||||
panelType: panelType,
|
panelType: panelType,
|
||||||
|
ihm: server.GetFeature(inbound.ManagerType()).(inbound.Manager),
|
||||||
|
ohm: server.GetFeature(outbound.ManagerType()).(outbound.Manager),
|
||||||
|
stm: server.GetFeature(stats.ManagerType()).(stats.Manager),
|
||||||
|
dispatcher: server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher),
|
||||||
}
|
}
|
||||||
return controller
|
return controller
|
||||||
}
|
}
|
||||||
@@ -333,19 +345,14 @@ func (c *Controller) addNewUser(userInfo *[]api.UserInfo, nodeInfo *api.NodeInfo
|
|||||||
if nodeInfo.EnableVless {
|
if nodeInfo.EnableVless {
|
||||||
users = c.buildVlessUser(userInfo)
|
users = c.buildVlessUser(userInfo)
|
||||||
} else {
|
} else {
|
||||||
alterID := 0
|
var alterID uint16 = 0
|
||||||
if c.panelType == "V2board" {
|
if (c.panelType == "V2board" || c.panelType == "V2RaySocks") && len(*userInfo) > 0 {
|
||||||
// use latest userInfo
|
// use latest userInfo
|
||||||
alterID = (*userInfo)[0].AlterID
|
alterID = (*userInfo)[0].AlterID
|
||||||
} else {
|
} else {
|
||||||
alterID = nodeInfo.AlterID
|
alterID = nodeInfo.AlterID
|
||||||
}
|
}
|
||||||
if alterID >= 0 && alterID < math.MaxUint16 {
|
users = c.buildVmessUser(userInfo, alterID)
|
||||||
users = c.buildVmessUser(userInfo, uint16(alterID))
|
|
||||||
} else {
|
|
||||||
users = c.buildVmessUser(userInfo, 0)
|
|
||||||
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.buildTrojanUser(userInfo)
|
||||||
|
@@ -62,7 +62,7 @@ func TestController(t *testing.T) {
|
|||||||
NodeType: "V2ray",
|
NodeType: "V2ray",
|
||||||
}
|
}
|
||||||
apiclient := sspanel.New(apiConfig)
|
apiclient := sspanel.New(apiConfig)
|
||||||
c := New(server, apiclient, controlerconfig)
|
c := New(server, apiclient, controlerconfig, "SSpanel")
|
||||||
fmt.Println("Sleep 1s")
|
fmt.Println("Sleep 1s")
|
||||||
err = c.Start()
|
err = c.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -27,7 +27,7 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
|
|||||||
|
|
||||||
// Build Port
|
// Build Port
|
||||||
portList := &conf.PortList{
|
portList := &conf.PortList{
|
||||||
Range: []conf.PortRange{{From: uint32(nodeInfo.Port), To: uint32(nodeInfo.Port)}},
|
Range: []conf.PortRange{{From: nodeInfo.Port, To: nodeInfo.Port}},
|
||||||
}
|
}
|
||||||
inboundDetourConfig.PortList = portList
|
inboundDetourConfig.PortList = portList
|
||||||
// Build Tag
|
// Build Tag
|
||||||
|
@@ -29,7 +29,7 @@ func TestBuildV2ray(t *testing.T) {
|
|||||||
config := &Config{
|
config := &Config{
|
||||||
CertConfig: certConfig,
|
CertConfig: certConfig,
|
||||||
}
|
}
|
||||||
_, err := InboundBuilder(config, nodeInfo)
|
_, err := InboundBuilder(config, nodeInfo, "test_tag")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ func TestBuildTrojan(t *testing.T) {
|
|||||||
config := &Config{
|
config := &Config{
|
||||||
CertConfig: certConfig,
|
CertConfig: certConfig,
|
||||||
}
|
}
|
||||||
_, err := InboundBuilder(config, nodeInfo)
|
_, err := InboundBuilder(config, nodeInfo, "test_tag")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ func TestBuildSS(t *testing.T) {
|
|||||||
config := &Config{
|
config := &Config{
|
||||||
CertConfig: certConfig,
|
CertConfig: certConfig,
|
||||||
}
|
}
|
||||||
_, err := InboundBuilder(config, nodeInfo)
|
_, err := InboundBuilder(config, nodeInfo, "test_tag")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user