94 Commits

Author SHA1 Message Date
dependabot[bot]
59d4454cd8 build(deps): bump github.com/sagernet/sing from 0.4.1 to 0.5.1
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.4.1 to 0.5.1.
- [Commits](https://github.com/sagernet/sing/compare/v0.4.1...v0.5.1)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-18 16:04:22 +00:00
dependabot[bot]
b1f5ccfee8 build(deps): bump github.com/eko/gocache/store/go_cache/v4 (#701)
Bumps [github.com/eko/gocache/store/go_cache/v4](https://github.com/eko/gocache) from 4.2.1 to 4.2.2.
- [Release notes](https://github.com/eko/gocache/releases)
- [Commits](https://github.com/eko/gocache/compare/store/redis/v4.2.1...store/redis/v4.2.2)

---
updated-dependencies:
- dependency-name: github.com/eko/gocache/store/go_cache/v4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-31 11:30:13 +08:00
dependabot[bot]
2f88334373 build(deps): bump golang.org/x/crypto from 0.25.0 to 0.28.0 (#704)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.25.0 to 0.28.0.
- [Commits](https://github.com/golang/crypto/compare/v0.25.0...v0.28.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-31 11:29:51 +08:00
dependabot[bot]
35e726e766 build(deps): bump golang.org/x/time from 0.5.0 to 0.7.0 (#703)
Bumps [golang.org/x/time](https://github.com/golang/time) from 0.5.0 to 0.7.0.
- [Commits](https://github.com/golang/time/compare/v0.5.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/time
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-31 11:29:31 +08:00
sakzri
4bbf3c9899 fix: handle domain with wildcards (#690) 2024-10-19 22:04:08 +08:00
RyarX
9391c759c9 New transports and api changes for V2RaySocks (#685)
* New transports and api changes for V2RaySocks

* version++
2024-10-19 22:03:05 +08:00
dependabot[bot]
eb16b709e2 build(deps): bump github.com/shirou/gopsutil/v3 from 3.24.2 to 3.24.5 (#666)
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.24.2 to 3.24.5.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.24.2...v3.24.5)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-19 22:01:46 +08:00
dependabot[bot]
1f09502613 build(deps): bump github.com/spf13/cobra from 1.8.0 to 1.8.1 (#665)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.8.0...v1.8.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-19 22:01:24 +08:00
dependabot[bot]
0ae73a0eca build(deps): bump actions/download-artifact in /.github/workflows (#688)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 3 to 4.1.7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v3...v4.1.7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-19 22:00:58 +08:00
pings
63c1a18a7d Optimize and upgrade docking parameters (#696) 2024-10-19 22:00:11 +08:00
dependabot[bot]
34726d1659 build(deps): bump github.com/eko/gocache/lib/v4 from 4.1.5 to 4.1.6 (#668)
Bumps [github.com/eko/gocache/lib/v4](https://github.com/eko/gocache) from 4.1.5 to 4.1.6.
- [Release notes](https://github.com/eko/gocache/releases)
- [Commits](https://github.com/eko/gocache/compare/lib/v4.1.5...lib/v4.1.6)

---
updated-dependencies:
- dependency-name: github.com/eko/gocache/lib/v4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-19 21:59:06 +08:00
dependabot[bot]
5edc68d475 build(deps): bump github.com/redis/go-redis/v9 from 9.5.1 to 9.7.0 (#699)
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.5.1 to 9.7.0.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.5.1...v9.7.0)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-19 21:57:38 +08:00
mengxin239
944e8cd6a8 version++ 2024-07-21 13:12:31 +08:00
wyx2685
c4581ad34b Xray core1.8.20 & support splitHTTP (#661)
* upgrade xray core 1.8.20

* support splitHTTP
2024-07-21 10:59:38 +08:00
dependabot[bot]
127318ccbd build(deps): bump github.com/go-resty/resty/v2 from 2.11.0 to 2.13.1 (#660)
Bumps [github.com/go-resty/resty/v2](https://github.com/go-resty/resty) from 2.11.0 to 2.13.1.
- [Release notes](https://github.com/go-resty/resty/releases)
- [Commits](https://github.com/go-resty/resty/compare/v2.11.0...v2.13.1)

---
updated-dependencies:
- dependency-name: github.com/go-resty/resty/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-20 20:49:16 +08:00
dependabot[bot]
db784f18e6 build(deps): bump google.golang.org/grpc from 1.64.0 to 1.64.1 (#659)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.64.0 to 1.64.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.64.0...v1.64.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-20 19:59:59 +08:00
dependabot[bot]
8a5a5e4356 build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azidentity (#658)
Bumps [github.com/Azure/azure-sdk-for-go/sdk/azidentity](https://github.com/Azure/azure-sdk-for-go) from 1.5.1 to 1.6.0.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/internal/v1.5.1...sdk/azcore/v1.6.0)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/azidentity
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-20 19:56:22 +08:00
dependabot[bot]
cfdb5166f3 build(deps): bump github.com/gogf/gf/v2 from 2.6.4 to 2.7.0 (#632)
Bumps [github.com/gogf/gf/v2](https://github.com/gogf/gf) from 2.6.4 to 2.7.0.
- [Release notes](https://github.com/gogf/gf/releases)
- [Commits](https://github.com/gogf/gf/compare/v2.6.4...v2.7.0)

---
updated-dependencies:
- dependency-name: github.com/gogf/gf/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-20 19:54:40 +08:00
dependabot[bot]
540be1b7c8 build(deps): bump github.com/hashicorp/go-retryablehttp (#657)
Bumps [github.com/hashicorp/go-retryablehttp](https://github.com/hashicorp/go-retryablehttp) from 0.7.5 to 0.7.7.
- [Changelog](https://github.com/hashicorp/go-retryablehttp/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/go-retryablehttp/compare/v0.7.5...v0.7.7)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-retryablehttp
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-20 19:53:05 +08:00
dependabot[bot]
98014fa60f build(deps): bump golang.org/x/net from 0.26.0 to 0.27.0 (#656)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.26.0 to 0.27.0.
- [Commits](https://github.com/golang/net/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-20 19:41:24 +08:00
mengxin239
1de718a5fc Adjusting docker.yml triggers 2024-07-20 19:16:09 +08:00
MengXin239
81c068bad4 update config.yml.example 2024-06-21 12:49:12 +08:00
MengXin239
dbde0c24fc version++ 2024-06-09 22:19:33 +08:00
MengXin239
1bbd061d42 upgrade xray core 2024-06-09 22:12:24 +08:00
MengXin239
793f26e763 fixed some bug 2024-06-09 20:52:32 +08:00
MengXin239
175e46d0b7 add quic support and fixed some bug 2024-06-09 17:58:22 +08:00
_rave_cat_
9261a6063d chore: fix typos. (#640)
* chore: fix typos.

* chore: makes go-staticcheck happy.
2024-06-09 15:21:27 +08:00
Blank Paper
5ee2679924 fix compatibility with Xray-core v1.8.10 (#629) 2024-04-16 22:46:28 +08:00
thh1451
06fe198243 add DeviceLimit to V2RaySocks (#622) 2024-04-10 17:57:19 +08:00
thh1451
b3f31bf06b Modify the way v2raysocks obtains methods and audits (#616)
Co-authored-by: thank243 <thank243@gmail.com>
2024-03-19 00:01:19 +08:00
thank243
0010a876f3 Remove unnecessary user retrieval in v2raysocks (#617)
The updated code eliminates a redundant user retrieval operation in the v2raysocks module. This operation was not needed because the desired information (method) can be inferred elsewhere in the application. This change simplifies the code, improves efficiency, and may reduce potential errors related to user data retrieval.
2024-03-18 23:50:18 +08:00
Senis
dbed635aae fixes, enhancing the efficiency and robustness of the system. 2024-03-15 21:44:15 +08:00
Senis
561f317e24 Update dependencies and upgrade Google Cloud services
Upgraded various dependencies and Google Cloud services to improve the application's performance and stability. Multiple version upgrades reflect ongoing development efforts and bug
2024-02-20 23:50:54 +08:00
dependabot[bot]
c24a2a28f2 build(deps): bump github.com/shirou/gopsutil/v3 from 3.23.12 to 3.24.1 (#589)
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.23.12 to 3.24.1.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.23.12...v3.24.1)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-03 20:34:51 +08:00
dependabot[bot]
fa80ed8014 build(deps): bump github.com/go-acme/lego/v4 from 4.14.2 to 4.15.0 (#588)
Bumps [github.com/go-acme/lego/v4](https://github.com/go-acme/lego) from 4.14.2 to 4.15.0.
- [Release notes](https://github.com/go-acme/lego/releases)
- [Changelog](https://github.com/go-acme/lego/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-acme/lego/compare/v4.14.2...v4.15.0)

---
updated-dependencies:
- dependency-name: github.com/go-acme/lego/v4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-30 12:28:50 +08:00
dependabot[bot]
5409cb2dc3 build(deps): bump github.com/gogf/gf/v2 from 2.6.1 to 2.6.2 (#585)
Bumps [github.com/gogf/gf/v2](https://github.com/gogf/gf) from 2.6.1 to 2.6.2.
- [Release notes](https://github.com/gogf/gf/releases)
- [Commits](https://github.com/gogf/gf/compare/v2.6.1...v2.6.2)

---
updated-dependencies:
- dependency-name: github.com/gogf/gf/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-23 06:28:05 +08:00
壳壳中的宇宙
b8b3a16d3b fix custom inbound listener to not use 0.0.0.0 (#584) 2024-01-20 09:23:12 +08:00
Jat
d1e5762937 support passing redis network and redis username to redis client (#576)
Signed-off-by: Jat <jat@sinosky.org>
2024-01-12 22:22:28 +08:00
dependabot[bot]
4f1dafa8ed build(deps): bump golang.org/x/net from 0.19.0 to 0.20.0 (#578)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.19.0 to 0.20.0.
- [Commits](https://github.com/golang/net/compare/v0.19.0...v0.20.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-12 22:01:32 +08:00
dependabot[bot]
aae0f9b24d build(deps): bump github.com/redis/go-redis/v9 from 9.3.1 to 9.4.0 (#574)
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.3.1 to 9.4.0.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.3.1...v9.4.0)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-09 18:21:53 +08:00
dependabot[bot]
aee8ca2980 build(deps): bump github.com/xtls/xray-core from 1.8.6 to 1.8.7 (#573)
Bumps [github.com/xtls/xray-core](https://github.com/xtls/xray-core) from 1.8.6 to 1.8.7.
- [Release notes](https://github.com/xtls/xray-core/releases)
- [Commits](https://github.com/xtls/xray-core/compare/v1.8.6...v1.8.7)

---
updated-dependencies:
- dependency-name: github.com/xtls/xray-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-09 06:37:38 +08:00
dependabot[bot]
933e745a70 build(deps): bump github.com/sagernet/sing from 0.2.20 to 0.2.21 (#569)
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.2.20 to 0.2.21.
- [Commits](https://github.com/sagernet/sing/compare/v0.2.20...v0.2.21)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-07 10:26:37 +08:00
wyx2685
515fc708dc Remove dragonfly compile. (#567)
Fix Actions
2024-01-03 10:21:46 +08:00
dependabot[bot]
5e134967fd build(deps): bump github.com/shirou/gopsutil/v3 from 3.23.11 to 3.23.12 (#566)
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.23.11 to 3.23.12.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.23.11...v3.23.12)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-03 10:20:56 +08:00
Senis
4a234d50e2 Add debug level logging option
This update introduces the ability to enable logging from the caller when the log level is set to "debug". This additional logging feature will provide more specificity and context for debugging tasks, aiding in quicker issue resolution.
2023-12-29 12:25:33 +08:00
Senis
115d7bad6f Replace standard log package with logrus
The standard "log" package was replaced by the structured logger "github.com/sirupsen/logrus" for better log control in various files. This change will allow to tailor the logging information more precisely and make logs easier to read and analyze. All calls of standard log methods were replaced by their logrus counterparts.
2023-12-28 13:40:31 +08:00
dependabot[bot]
5ba0624bbc build(deps): bump github.com/go-resty/resty/v2 from 2.10.0 to 2.11.0 (#564)
Bumps [github.com/go-resty/resty/v2](https://github.com/go-resty/resty) from 2.10.0 to 2.11.0.
- [Release notes](https://github.com/go-resty/resty/releases)
- [Commits](https://github.com/go-resty/resty/compare/v2.10.0...v2.11.0)

---
updated-dependencies:
- dependency-name: github.com/go-resty/resty/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-28 00:41:09 +08:00
dependabot[bot]
4439afa29b build(deps): bump github.com/sagernet/sing from 0.2.19 to 0.2.20 (#558)
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.2.19 to 0.2.20.
- [Commits](https://github.com/sagernet/sing/compare/v0.2.19...v0.2.20)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-24 02:50:55 +08:00
dependabot[bot]
03c9fe4218 build(deps): bump github.com/gogf/gf/v2 from 2.6.0 to 2.6.1 (#560)
Bumps [github.com/gogf/gf/v2](https://github.com/gogf/gf) from 2.6.0 to 2.6.1.
- [Release notes](https://github.com/gogf/gf/releases)
- [Commits](https://github.com/gogf/gf/compare/v2.6.0...v2.6.1)

---
updated-dependencies:
- dependency-name: github.com/gogf/gf/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-24 02:49:39 +08:00
dependabot[bot]
f648aedc91 build(deps): bump google.golang.org/protobuf from 1.31.0 to 1.32.0 (#561)
Bumps google.golang.org/protobuf from 1.31.0 to 1.32.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-24 02:49:28 +08:00
dependabot[bot]
1720fbdc4c build(deps): bump github.com/redis/go-redis/v9 from 9.3.0 to 9.3.1 (#555)
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.3.0 to 9.3.1.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.3.0...v9.3.1)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-24 02:49:13 +08:00
dependabot[bot]
cd7907c4c9 build(deps): bump github.com/spf13/viper from 1.18.1 to 1.18.2 (#556)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.18.1 to 1.18.2.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.18.1...v1.18.2)

---
updated-dependencies:
- dependency-name: github.com/spf13/viper
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-24 02:49:05 +08:00
dependabot[bot]
296ba86bdd build(deps): bump golang.org/x/crypto from 0.16.0 to 0.17.0 (#554)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.16.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.16.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 08:18:48 +08:00
dependabot[bot]
43e6ec85cd build(deps): bump github.com/gogf/gf/v2 from 2.5.7 to 2.6.0 (#553)
Bumps [github.com/gogf/gf/v2](https://github.com/gogf/gf) from 2.5.7 to 2.6.0.
- [Release notes](https://github.com/gogf/gf/releases)
- [Commits](https://github.com/gogf/gf/compare/v2.5.7...v2.6.0)

---
updated-dependencies:
- dependency-name: github.com/gogf/gf/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 00:03:33 +08:00
dependabot[bot]
7ba2d999f0 build(deps): bump github.com/sagernet/sing from 0.2.18 to 0.2.19 (#550)
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.2.18 to 0.2.19.
- [Commits](https://github.com/sagernet/sing/compare/v0.2.18...v0.2.19)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-12 21:22:06 +08:00
dependabot[bot]
53141f4416 build(deps): bump github.com/spf13/viper from 1.17.0 to 1.18.1 (#548)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.17.0 to 1.18.1.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.17.0...v1.18.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/viper
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-09 22:46:41 +08:00
dependabot[bot]
e378f0a367 build(deps): bump github.com/sagernet/sing-shadowsocks (#549)
Bumps [github.com/sagernet/sing-shadowsocks](https://github.com/sagernet/sing-shadowsocks) from 0.2.5 to 0.2.6.
- [Commits](https://github.com/sagernet/sing-shadowsocks/compare/v0.2.5...v0.2.6)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing-shadowsocks
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-09 22:42:35 +08:00
dependabot[bot]
d01a4265cd build(deps): bump github.com/sagernet/sing from 0.2.17 to 0.2.18 (#542)
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.2.17 to 0.2.18.
- [Commits](https://github.com/sagernet/sing/compare/v0.2.17...v0.2.18)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-05 06:59:19 +08:00
dependabot[bot]
94d2c7c23a build(deps): bump github.com/shirou/gopsutil/v3 from 3.23.10 to 3.23.11 (#538)
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.23.10 to 3.23.11.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.23.10...v3.23.11)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-03 19:42:23 +08:00
isluckys
3de7600a4c 修复类型判断问题 (#539)
之前一个pr写的if直接写成了vmess导致其他的比如说ss、Trojan的都会被覆盖
2023-12-03 19:42:03 +08:00
dependabot[bot]
a0378b6cff build(deps): bump golang.org/x/net from 0.18.0 to 0.19.0 (#536)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.18.0 to 0.19.0.
- [Commits](https://github.com/golang/net/compare/v0.18.0...v0.19.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-29 18:13:52 +08:00
dependabot[bot]
4688833bc7 build(deps): bump golang.org/x/time from 0.4.0 to 0.5.0 (#537)
Bumps [golang.org/x/time](https://github.com/golang/time) from 0.4.0 to 0.5.0.
- [Commits](https://github.com/golang/time/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/time
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-29 17:57:19 +08:00
dependabot[bot]
294a2dfacb build(deps): bump golang.org/x/crypto from 0.15.0 to 0.16.0 (#535)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.15.0 to 0.16.0.
- [Commits](https://github.com/golang/crypto/compare/v0.15.0...v0.16.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-29 17:55:38 +08:00
pennyMorant
5780731cd3 add bunpanel (#533) 2023-11-28 20:08:59 +08:00
betaxab
911b0c2ff5 api: newV2board: add Vless support (#534) 2023-11-28 20:08:44 +08:00
dependabot[bot]
fa7fb7087f build(deps): bump github.com/gogf/gf/v2 from 2.5.6 to 2.5.7 (#526)
Bumps [github.com/gogf/gf/v2](https://github.com/gogf/gf) from 2.5.6 to 2.5.7.
- [Release notes](https://github.com/gogf/gf/releases)
- [Commits](https://github.com/gogf/gf/compare/v2.5.6...v2.5.7)

---
updated-dependencies:
- dependency-name: github.com/gogf/gf/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-25 08:36:36 +08:00
dependabot[bot]
0a6bca9755 build(deps): bump github.com/go-jose/go-jose/v3 from 3.0.0 to 3.0.1 (#524)
Bumps [github.com/go-jose/go-jose/v3](https://github.com/go-jose/go-jose) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/go-jose/go-jose/releases)
- [Changelog](https://github.com/go-jose/go-jose/blob/v3/CHANGELOG.md)
- [Commits](https://github.com/go-jose/go-jose/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: github.com/go-jose/go-jose/v3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-25 08:36:27 +08:00
dependabot[bot]
8562c798a9 build(deps): bump github.com/xtls/xray-core from 1.8.5 to 1.8.6 (#523)
Bumps [github.com/xtls/xray-core](https://github.com/xtls/xray-core) from 1.8.5 to 1.8.6.
- [Release notes](https://github.com/xtls/xray-core/releases)
- [Commits](https://github.com/xtls/xray-core/compare/v1.8.5...v1.8.6)

---
updated-dependencies:
- dependency-name: github.com/xtls/xray-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-25 08:36:18 +08:00
thh1451
56199afa90 V2RaySocks supports Reality (remote config) (#521) 2023-11-18 06:21:08 +08:00
Senis
c688cf02b4 Update Go version and dependencies for better compatibility
Updated Go version in Dockerfile and go.mod to ensure better compatibility and unpinned the Go version in Dockerfile for increased flexibility. Multiple dependencies in go.mod and go.sum have been updated to their newer versions for improved functionality and security. This will keep the project up-to-date with the latest features and bug fixes offered by these dependencies. Removed unused dependencies to keep the project clean and efficient.
2023-11-14 11:32:21 +08:00
thh1451
c170272f40 Add Etag for V2RaySocks (#518) 2023-11-12 06:21:13 +08:00
dependabot[bot]
6ffbe599b4 build(deps): bump golang.org/x/net from 0.17.0 to 0.18.0 (#514)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.18.0.
- [Commits](https://github.com/golang/net/compare/v0.17.0...v0.18.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 21:24:01 +08:00
thh1451
78c2e31bdf add 2 acts to V2RaySocks (#516) 2023-11-10 21:23:44 +08:00
dependabot[bot]
c04d52330d 合并拉取请求 #513
* build(deps): bump golang.org/x/crypto from 0.14.0 to 0.15.0
2023-11-10 11:52:49 +08:00
dependabot[bot]
6f4bf62113 build(deps): bump golang.org/x/time from 0.3.0 to 0.4.0 (#506)
Bumps [golang.org/x/time](https://github.com/golang/time) from 0.3.0 to 0.4.0.
- [Commits](https://github.com/golang/time/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: golang.org/x/time
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 19:28:10 +08:00
dependabot[bot]
56e993ce43 build(deps): bump github.com/spf13/cobra from 1.7.0 to 1.8.0 (#505)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 19:28:00 +08:00
dependabot[bot]
6d3d6f9e53 build(deps): bump github.com/sagernet/sing from 0.2.15 to 0.2.17 (#504)
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.2.15 to 0.2.17.
- [Commits](https://github.com/sagernet/sing/compare/v0.2.15...v0.2.17)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 19:27:49 +08:00
Senis
76076b2d6a Refactor variable assignments in sspanel.go
Simplified the variable assignment logic in sspanel.go to increase code efficiency and readability. "tlsType" is now conditionally initialized once instead of reset multiple times, and it is also properly scoped. Removed an unnecessary check for "nodeConfig.Security" in the "Trojan" case as this value is already taken into account in the efficient, updated logic.
2023-11-08 19:26:38 +08:00
dependabot[bot]
4e48fdbe61 build(deps): bump github.com/shirou/gopsutil/v3 from 3.23.9 to 3.23.10 (#502)
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.23.9 to 3.23.10.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.23.9...v3.23.10)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 01:11:00 +08:00
dependabot[bot]
0f3a4a0008 build(deps): bump github.com/redis/go-redis/v9 from 9.2.1 to 9.3.0 (#501)
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.2.1 to 9.3.0.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.2.1...v9.3.0)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-01 07:01:12 +08:00
Senis John
d9971b2181 Initialize server port in sspanel
This commit initializes the server port in sspanel.go if the userListResponse is not empty. This adds a level of preventative measure to ensure port is not left uninitialized.
2023-10-28 13:19:17 +08:00
dependabot[bot]
4d1ed21dc7 build(deps): bump github.com/sagernet/sing from 0.2.14 to 0.2.15 (#497)
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.2.14 to 0.2.15.
- [Commits](https://github.com/sagernet/sing/compare/v0.2.14...v0.2.15)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-27 07:05:28 +08:00
dependabot[bot]
9a03f85930 build(deps): bump github.com/gogf/gf/v2 from 2.5.5 to 2.5.6 (#495)
Bumps [github.com/gogf/gf/v2](https://github.com/gogf/gf) from 2.5.5 to 2.5.6.
- [Release notes](https://github.com/gogf/gf/releases)
- [Commits](https://github.com/gogf/gf/compare/v2.5.5...v2.5.6)

---
updated-dependencies:
- dependency-name: github.com/gogf/gf/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-24 23:51:15 +08:00
dependabot[bot]
11b46ea485 build(deps): bump github.com/fsnotify/fsnotify from 1.6.0 to 1.7.0 (#494)
Bumps [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) from 1.6.0 to 1.7.0.
- [Release notes](https://github.com/fsnotify/fsnotify/releases)
- [Changelog](https://github.com/fsnotify/fsnotify/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fsnotify/fsnotify/compare/v1.6.0...v1.7.0)

---
updated-dependencies:
- dependency-name: github.com/fsnotify/fsnotify
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-24 23:51:06 +08:00
dependabot[bot]
dc3d256d85 build(deps): bump github.com/gogf/gf/v2 from 2.5.4 to 2.5.5 (#491)
Bumps [github.com/gogf/gf/v2](https://github.com/gogf/gf) from 2.5.4 to 2.5.5.
- [Release notes](https://github.com/gogf/gf/releases)
- [Commits](https://github.com/gogf/gf/compare/v2.5.4...v2.5.5)

---
updated-dependencies:
- dependency-name: github.com/gogf/gf/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-21 00:36:35 +08:00
Senis John
287c30e7d0 Update application dependencies and improve error logging
This commit updates the version of many dependencies in go.sum and go.mod. It improves error handling in sspanel.go by including both the HTTP response body and error in the logged message. It also updates the xray-core version.
2023-10-18 20:58:39 +08:00
Senis John
97d89549dd Update application version and enhance error handling
The commit increases the version number from 0.9.1 to 0.9.2 in version.go. Additionally, an error check has been added in x25519.go to validate the private key size. Also, panel.go has been modified to accept both "NewV2board" and "V2board" as valid panel types.
2023-10-17 15:36:32 +08:00
dependabot[bot]
cac4288e07 build(deps): bump github.com/sagernet/sing from 0.2.13 to 0.2.14 (#485)
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.2.13 to 0.2.14.
- [Commits](https://github.com/sagernet/sing/compare/v0.2.13...v0.2.14)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 06:43:26 +08:00
dependabot[bot]
d1d5193cec build(deps): bump github.com/spf13/cobra from 1.1.1 to 1.7.0 (#486)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.1.1 to 1.7.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.1.1...v1.7.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 06:42:44 +08:00
dependabot[bot]
85607527a5 build(deps): bump github.com/go-resty/resty/v2 from 2.9.1 to 2.10.0 (#484)
Bumps [github.com/go-resty/resty/v2](https://github.com/go-resty/resty) from 2.9.1 to 2.10.0.
- [Release notes](https://github.com/go-resty/resty/releases)
- [Commits](https://github.com/go-resty/resty/compare/v2.9.1...v2.10.0)

---
updated-dependencies:
- dependency-name: github.com/go-resty/resty/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 06:41:58 +08:00
Senis John
fd0a23bf6c "Add option to input private key for x25519 command"
Added a command line flag to allow the user to provide an input for the private key while utilizing the x25519 command. The function `x25519` was also modified to account for the possibility of a user-inputted private key. If no private key is provided, random bytes will be generated for the private key as before. This feature provides flexibility for the user in key management.
2023-10-14 21:46:00 +08:00
Senis John
b1bfd04895 Refactor main to use Cobra command line framework and package restructure
Reorganized the Go package structure, moving the main package to 'cmd'. Upgraded the flag library to Cobra for better management of CLI commands. This included moving the X25519 key generation from a flag to its own standalone Cobra command, which improves user interaction and code modularity. This structural change will benefit future additions and code maintainability.
2023-10-14 11:21:45 +08:00
Senis John
edf02307ad Update Go dependencies and add secure key pair generation
Updated several Go dependencies for enhanced security and performance. Additionally, a command (`-x25519`) has been added for generating a secure key pair using X25519. This provides an easier and safer way for users to generate keys for secure communication. Further instructions have been reflected in the `config.yml.example` file.
2023-10-13 21:55:30 +08:00
dependabot[bot]
551e2d4299 build(deps): bump golang.org/x/net from 0.16.0 to 0.17.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.16.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.16.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-11 15:27:30 +00:00
58 changed files with 3360 additions and 1164 deletions

View File

@@ -1,19 +1,8 @@
name: Publish Docker image name: Publish Docker image
on: on:
workflow_dispatch: release:
push: types:
branches: - published
- master
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
tags:
- 'v*'
pull_request:
branches:
- 'master'
env: env:
REGISTRY: ghcr.io REGISTRY: ghcr.io
IMAGE_NAME: xrayr-project/xrayr IMAGE_NAME: xrayr-project/xrayr
@@ -75,7 +64,7 @@ jobs:
- build - build
steps: steps:
- name: Download digests - name: Download digests
uses: actions/download-artifact@v3 uses: actions/download-artifact@v4.1.7
with: with:
name: digests name: digests
path: /tmp/digests path: /tmp/digests

View File

@@ -26,12 +26,10 @@ jobs:
strategy: strategy:
matrix: matrix:
# Include amd64 on all platforms. # Include amd64 on all platforms.
goos: [ windows, freebsd, openbsd, linux, dragonfly, darwin ] goos: [ windows, freebsd, openbsd, linux, darwin ]
goarch: [ amd64, 386 ] goarch: [ amd64, 386 ]
exclude: exclude:
# Exclude i386 on darwin and dragonfly. # Exclude i386 on darwin.
- goarch: 386
goos: dragonfly
- goarch: 386 - goarch: 386
goos: darwin goos: darwin
- goarch: 386 - goarch: 386
@@ -122,12 +120,12 @@ jobs:
- name: Build XrayR - name: Build XrayR
run: | run: |
mkdir -p build_assets mkdir -p build_assets
go build -v -o build_assets/XrayR -trimpath -ldflags "-s -w -buildid=" ./main go build -v -o build_assets/XrayR -trimpath -ldflags "-s -w -buildid="
- name: Build Mips softfloat XrayR - name: Build Mips softfloat XrayR
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle' if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
run: | run: |
GOMIPS=softfloat go build -v -o build_assets/XrayR_softfloat -trimpath -ldflags "-s -w -buildid=" ./main GOMIPS=softfloat go build -v -o build_assets/XrayR_softfloat -trimpath -ldflags "-s -w -buildid="
- name: Rename Windows XrayR - name: Rename Windows XrayR
if: matrix.goos == 'windows' if: matrix.goos == 'windows'
run: | run: |
@@ -143,12 +141,12 @@ jobs:
command: | command: |
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
cp ${GITHUB_WORKSPACE}/main/dns.json ./build_assets/dns.json cp ${GITHUB_WORKSPACE}/release/config/dns.json ./build_assets/dns.json
cp ${GITHUB_WORKSPACE}/main/route.json ./build_assets/route.json cp ${GITHUB_WORKSPACE}/release/config/route.json ./build_assets/route.json
cp ${GITHUB_WORKSPACE}/main/custom_outbound.json ./build_assets/custom_outbound.json cp ${GITHUB_WORKSPACE}/release/config/custom_outbound.json ./build_assets/custom_outbound.json
cp ${GITHUB_WORKSPACE}/main/custom_inbound.json ./build_assets/custom_inbound.json cp ${GITHUB_WORKSPACE}/release/config/custom_inbound.json ./build_assets/custom_inbound.json
cp ${GITHUB_WORKSPACE}/main/rulelist ./build_assets/rulelist cp ${GITHUB_WORKSPACE}/release/config/rulelist ./build_assets/rulelist
cp ${GITHUB_WORKSPACE}/main/config.yml.example ./build_assets/config.yml cp ${GITHUB_WORKSPACE}/release/config/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')
for i in "${LIST[@]}" for i in "${LIST[@]}"
do do

38
.gitignore vendored
View File

@@ -1,18 +1,20 @@
main/main .idea
main/XrayR *.iml
main/XrayR* out
main/mytest gen
main/access.logo *.exe
main/error.log *.exe~
api/chooseparser.go.bak *.dll
common/Inboundbuilder/.lego/ *.so
common/legocmd/.lego/ *.dylib
.vscode/launch.json *.test
main/.lego *.out
main/cert go.work
main/config.yml main
./vscode XrayR
.idea/* XrayR*
.DS_Store access.log
*.bak error.log
go.work* .lego
cert
config.yml

View File

@@ -1,10 +1,10 @@
# Build go # Build go
FROM golang:1.21-alpine AS builder FROM golang:1.22.0-alpine AS builder
WORKDIR /app WORKDIR /app
COPY . . COPY . .
ENV CGO_ENABLED=0 ENV CGO_ENABLED=0
RUN go mod download RUN go mod download
RUN go build -v -o XrayR -trimpath -ldflags "-s -w -buildid=" ./main RUN go build -v -o XrayR -trimpath -ldflags "-s -w -buildid="
# Release # Release
FROM alpine FROM alpine

View File

@@ -64,6 +64,7 @@ This project is just my personal learning and development and maintenance. I do
| [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/) | √ | √ | √ | | [WHMCS (V2RaySocks)](https://v2raysocks.doxtex.com/) | √ | √ | √ |
| [BunPanel](https://github.com/pennyMorant/bunpanel-release) | √ | √ | √ |
## Software Installation ## Software Installation

View File

@@ -61,6 +61,7 @@ Dự án này chỉ là học tập và phát triển và bảo trì cá nhân c
| [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/) | √ | √ | √ | | [WHMCS (V2RaySocks)](https://v2raysocks.doxtex.com/) | √ | √ | √ |
| [BunPanel](https://github.com/pennyMorant/bunpanel-release) | √ | √ | √ |
## Cài đặt phần mềm ## Cài đặt phần mềm

View File

@@ -63,6 +63,7 @@ A Xray backend framework that can easily support many panels.
| [ProxyPanel](https://github.com/ProxyPanel/ProxyPanel) | √ | √ | √ | | [ProxyPanel](https://github.com/ProxyPanel/ProxyPanel) | √ | √ | √ |
| [WHMCS (V2RaySocks)](https://v2raysocks.doxtex.com/) | √ | √ | √ | | [WHMCS (V2RaySocks)](https://v2raysocks.doxtex.com/) | √ | √ | √ |
| [GoV2Panel](https://github.com/pingProMax/gov2panel) | √ | √ | √ | | [GoV2Panel](https://github.com/pingProMax/gov2panel) | √ | √ | √ |
| [BunPanel](https://github.com/pennyMorant/bunpanel-release) | √ | √ | √ |
## 软件安装 ## 软件安装

View File

@@ -59,6 +59,7 @@
| [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/) | √ | √ | √ | | [WHMCS (V2RaySocks)](https://v2raysocks.doxtex.com/) | √ | √ | √ |
| [BunPanel](https://github.com/pennyMorant/bunpanel-release) | √ | √ | √ |
## نصب نرم افزار ## نصب نرم افزار

View File

@@ -37,25 +37,47 @@ type NodeStatus struct {
} }
type NodeInfo struct { type NodeInfo struct {
NodeType string // Must be V2ray, Trojan, and Shadowsocks AcceptProxyProtocol bool
NodeID int Authority string
Port uint32 NodeType string // Must be V2ray, Trojan, and Shadowsocks
SpeedLimit uint64 // Bps NodeID int
AlterID uint16 Port uint32
TransportProtocol string SpeedLimit uint64 // Bps
FakeType string AlterID uint16
Host string TransportProtocol string
Path string FakeType string
EnableTLS bool Host string
EnableVless bool Path string
VlessFlow string EnableTLS bool
CypherMethod string EnableSniffing bool
ServerKey string RouteOnly bool
ServiceName string EnableVless bool
Header json.RawMessage VlessFlow string
NameServerConfig []*conf.NameServerConfig CypherMethod string
EnableREALITY bool ServerKey string
REALITYConfig *REALITYConfig ServiceName string
Method string
Header json.RawMessage
HttpHeaders map[string]*conf.StringList
Headers map[string]string
NameServerConfig []*conf.NameServerConfig
EnableREALITY bool
REALITYConfig *REALITYConfig
Show bool
EnableTFO bool
Dest string
ProxyProtocolVer uint64
ServerNames []string
PrivateKey string
MinClientVer string
MaxClientVer string
MaxTimeDiff uint64
ShortIds []string
Xver uint64
Flow string
Security string
Key string
RejectUnknownSni bool
} }
type UserInfo struct { type UserInfo struct {

427
api/bunpanel/bunpanel.go Normal file
View File

@@ -0,0 +1,427 @@
package bunpanel
import (
"bufio"
"encoding/json"
"errors"
"fmt"
"os"
"reflect"
"regexp"
"strconv"
"strings"
"sync"
"time"
log "github.com/sirupsen/logrus"
"github.com/go-resty/resty/v2"
"github.com/XrayR-project/XrayR/api"
)
type APIClient struct {
client *resty.Client
APIHost string
NodeID int
Key string
NodeType string
EnableVless bool
VlessFlow string
SpeedLimit float64
DeviceLimit int
LocalRuleList []api.DetectRule
LastReportOnline map[int]int
access sync.Mutex
eTags map[string]string
}
// ReportIllegal implements api.API.
func (*APIClient) ReportIllegal(detectResultList *[]api.DetectResult) (err error) {
return nil
}
// ReportNodeStatus implements api.API.
func (*APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
return nil
}
// GetNodeRule implements api.API.
func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
ruleList := c.LocalRuleList
return &ruleList, nil
}
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)
}
})
client.SetBaseURL(apiConfig.APIHost)
// Create Key for each requests
client.SetQueryParams(map[string]string{
"serverId": strconv.Itoa(apiConfig.NodeID),
"nodeType": strings.ToLower(apiConfig.NodeType),
"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,
VlessFlow: apiConfig.VlessFlow,
SpeedLimit: apiConfig.SpeedLimit,
DeviceLimit: apiConfig.DeviceLimit,
LocalRuleList: localRuleList,
eTags: make(map[string]string),
}
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
}
defer file.Close()
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
}
}
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) (*Response, 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, %v", c.assembleURL(path), string(body), err)
}
response := res.Result().(*Response)
if response.StatusCode != 200 {
res, _ := json.Marshal(&response)
return nil, fmt.Errorf("statusCode %s invalid", string(res))
}
return response, nil
}
func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
path := fmt.Sprintf("/v2/server/%d/get", c.NodeID)
res, err := c.client.R().
SetResult(&Response{}).
SetHeader("If-None-Match", c.eTags["node"]).
ForceContentType("application/json").
Get(path)
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
if res.StatusCode() == 304 {
return nil, errors.New(api.NodeNotModified)
}
if res.Header().Get("ETag") != "" && res.Header().Get("ETag") != c.eTags["node"] {
c.eTags["node"] = res.Header().Get("ETag")
}
response, err := c.parseResponse(res, path, err)
if err != nil {
return nil, err
}
nodeInfoResponse := new(Server)
if err := json.Unmarshal(response.Datas, nodeInfoResponse); err != nil {
return nil, fmt.Errorf("unmarshal %s failed: %s", reflect.TypeOf(nodeInfoResponse), err)
}
nodeInfo, err = c.ParseNodeInfo(nodeInfoResponse)
if err != nil {
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://xrayr-project.github.io/XrayR-doc/dui-jie-sspanel/sspanel/sspanel_custom_config", string(res), err)
}
if err != nil {
res, _ := json.Marshal(nodeInfoResponse)
return nil, fmt.Errorf("parse node info failed: %s, \nError: %s", string(res), err)
}
return nodeInfo, nil
}
func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
path := "/v2/user/get"
res, err := c.client.R().
SetQueryParam("serverId", strconv.Itoa(c.NodeID)).
SetHeader("If-None-Match", c.eTags["users"]).
SetResult(&Response{}).
ForceContentType("application/json").
Get(path)
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
if res.StatusCode() == 304 {
return nil, errors.New(api.UserNotModified)
}
if res.Header().Get("ETag") != "" && res.Header().Get("ETag") != c.eTags["users"] {
c.eTags["users"] = res.Header().Get("ETag")
}
response, err := c.parseResponse(res, path, err)
if err != nil {
return nil, err
}
userListResponse := new([]User)
if err := json.Unmarshal(response.Datas, userListResponse); err != nil {
return nil, fmt.Errorf("unmarshal %s failed: %s", reflect.TypeOf(userListResponse), err)
}
userList, err := c.ParseUserListResponse(userListResponse)
if err != nil {
res, _ := json.Marshal(userListResponse)
return nil, fmt.Errorf("parse user list failed: %s", string(res))
}
return userList, nil
}
func (c *APIClient) ReportNodeOnlineUsers(onlineUserList *[]api.OnlineUser) error {
c.access.Lock()
defer c.access.Unlock()
reportOnline := make(map[int]int)
data := make([]OnlineUser, len(*onlineUserList))
for i, user := range *onlineUserList {
data[i] = OnlineUser{UID: user.UID, IP: user.IP}
reportOnline[user.UID]++
}
c.LastReportOnline = reportOnline // Update LastReportOnline
postData := &PostData{Data: data}
path := "/v2/user/online/create"
res, err := c.client.R().
SetQueryParam("serverId", strconv.Itoa(c.NodeID)).
SetBody(postData).
SetResult(&Response{}).
ForceContentType("application/json").
Post(path)
_, err = c.parseResponse(res, path, err)
if err != nil {
return err
}
return nil
}
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}
}
postData := &PostData{Data: data}
path := "/v2/user/data-usage/create"
res, err := c.client.R().
SetQueryParam("serverId", strconv.Itoa(c.NodeID)).
SetBody(postData).
SetResult(&Response{}).
ForceContentType("application/json").
Post(path)
_, err = c.parseResponse(res, path, err)
if err != nil {
return err
}
return nil
}
func (c *APIClient) ParseUserListResponse(userInfoResponse *[]User) (*[]api.UserInfo, error) {
c.access.Lock()
// Clear Last report log
defer func() {
c.LastReportOnline = make(map[int]int)
c.access.Unlock()
}()
var deviceLimit, localDeviceLimit = 0, 0
var speedLimit uint64 = 0
var userList []api.UserInfo
for _, user := range *userInfoResponse {
if c.DeviceLimit > 0 {
deviceLimit = c.DeviceLimit
} else {
deviceLimit = user.DeviceLimit
}
// If there is still device available, add the user
if deviceLimit > 0 && user.AliveIP > 0 {
lastOnline := 0
if v, ok := c.LastReportOnline[user.ID]; ok {
lastOnline = v
}
// If there are any available device.
if localDeviceLimit = deviceLimit - user.AliveIP + lastOnline; localDeviceLimit > 0 {
deviceLimit = localDeviceLimit
// If this backend server has reported any user in the last reporting period.
} else if lastOnline > 0 {
deviceLimit = lastOnline
// Remove this user.
} else {
continue
}
}
if c.SpeedLimit > 0 {
speedLimit = uint64((c.SpeedLimit * 1000000) / 8)
} else {
speedLimit = uint64((user.SpeedLimit * 1000000) / 8)
}
userList = append(userList, api.UserInfo{
UID: user.ID,
UUID: user.UUID,
SpeedLimit: speedLimit,
DeviceLimit: deviceLimit,
Passwd: user.UUID,
Email: user.UUID + "@bunpanel.user",
})
}
return &userList, nil
}
func (c *APIClient) ParseNodeInfo(nodeInfoResponse *Server) (*api.NodeInfo, error) {
var (
speedLimit uint64 = 0
enableTLS, enableVless, enableREALITY bool
alterID uint16 = 0
tlsType, transportProtocol string
)
nodeConfig := nodeInfoResponse
port := uint32(nodeConfig.Port)
switch c.NodeType {
case "Shadowsocks":
transportProtocol = "tcp"
case "V2ray":
transportProtocol = nodeConfig.Network
tlsType = nodeConfig.Security
if tlsType == "tls" || tlsType == "xtls" {
enableTLS = true
}
if tlsType == "reality" {
enableREALITY = true
enableVless = true
}
case "Trojan":
enableTLS = true
tlsType = "tls"
transportProtocol = "tcp"
}
// parse reality config
realityConfig := new(api.REALITYConfig)
if nodeConfig.RealitySettings != nil {
r := new(RealitySettings)
json.Unmarshal(nodeConfig.RealitySettings, r)
realityConfig = &api.REALITYConfig{
Dest: r.Dest,
ProxyProtocolVer: r.ProxyProtocolVer,
ServerNames: r.ServerNames,
PrivateKey: r.PrivateKey,
MinClientVer: r.MinClientVer,
MaxClientVer: r.MaxClientVer,
MaxTimeDiff: r.MaxTimeDiff,
ShortIds: r.ShortIds,
}
}
wsConfig := new(WsSettings)
if nodeConfig.WsSettings != nil {
json.Unmarshal(nodeConfig.WsSettings, wsConfig)
}
grpcConfig := new(GrpcSettigns)
if nodeConfig.GrpcSettings != nil {
json.Unmarshal(nodeConfig.GrpcSettings, grpcConfig)
}
tcpConfig := new(TcpSettings)
if nodeConfig.TcpSettings != nil {
json.Unmarshal(nodeConfig.TcpSettings, tcpConfig)
}
// Create GeneralNodeInfo
nodeInfo := &api.NodeInfo{
NodeType: c.NodeType,
NodeID: c.NodeID,
Port: port,
SpeedLimit: speedLimit,
AlterID: alterID,
TransportProtocol: transportProtocol,
Host: wsConfig.Headers.Host,
Path: wsConfig.Path,
EnableTLS: enableTLS,
EnableVless: enableVless,
VlessFlow: nodeConfig.Flow,
CypherMethod: nodeConfig.Method,
ServiceName: grpcConfig.ServiceName,
Header: tcpConfig.Header,
EnableREALITY: enableREALITY,
REALITYConfig: realityConfig,
}
return nodeInfo, nil
}

View File

@@ -0,0 +1,101 @@
package bunpanel_test
import (
"testing"
"github.com/XrayR-project/XrayR/api"
"github.com/XrayR-project/XrayR/api/bunpanel"
)
func CreateClient() api.API {
apiConfig := &api.Config{
APIHost: "http://localhost:8080",
Key: "123456",
NodeID: 1,
NodeType: "V2ray",
}
client := bunpanel.New(apiConfig)
return client
}
func TestGetV2rayNodeInfo(t *testing.T) {
client := CreateClient()
nodeInfo, err := client.GetNodeInfo()
if err != nil {
t.Error(err)
}
t.Log(nodeInfo)
}
func TestGetSSNodeInfo(t *testing.T) {
apiConfig := &api.Config{
APIHost: "http://127.0.0.1:668",
Key: "qwertyuiopasdfghjkl",
NodeID: 1,
NodeType: "Shadowsocks",
}
client := bunpanel.New(apiConfig)
nodeInfo, err := client.GetNodeInfo()
if err != nil {
t.Error(err)
}
t.Log(nodeInfo)
}
func TestGetTrojanNodeInfo(t *testing.T) {
apiConfig := &api.Config{
APIHost: "http://127.0.0.1:668",
Key: "qwertyuiopasdfghjkl",
NodeID: 1,
NodeType: "Trojan",
}
client := bunpanel.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: 1111,
Download: 2222,
}
}
// 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)
}

72
api/bunpanel/model.go Normal file
View File

@@ -0,0 +1,72 @@
package bunpanel
import "encoding/json"
type Server struct {
Port int `json:"serverPort"`
Network string `json:"network"`
Method string `json:"method"`
Security string `json:"security"`
Flow string `json:"flow"`
WsSettings json.RawMessage `json:"wsSettings"`
RealitySettings json.RawMessage `json:"realitySettings"`
GrpcSettings json.RawMessage `json:"grpcSettings"`
TcpSettings json.RawMessage `json:"tcpSettings"`
}
type WsSettings struct {
Path string `json:"path"`
Headers struct {
Host string `json:"Host"`
} `json:"headers"`
}
type GrpcSettigns struct {
ServiceName string `json:"serviceName"`
}
type TcpSettings struct {
Header json.RawMessage `json:"header"`
}
type RealitySettings struct {
Show bool `json:"show"`
Dest string `json:"dest"`
Xver uint64 `json:"xver"`
ServerNames []string `json:"serverNames"`
PrivateKey string `json:"privateKey"`
MinClientVer string `json:"minClientVer"`
MaxClientVer string `json:"maxClientVer"`
MaxTimeDiff uint64 `json:"maxTimeDiff"`
ProxyProtocolVer uint64 `json:"proxyProtocolVer"`
ShortIds []string `json:"shortIds"`
}
type User struct {
ID int `json:"id"`
UUID string `json:"uuid"`
SpeedLimit float64 `json:"speedLimit"`
DeviceLimit int `json:"ipLimit"`
AliveIP int `json:"onlineIp"`
}
type OnlineUser struct {
UID int `json:"userId"`
IP string `json:"ip"`
}
// UserTraffic is the data structure of traffic
type UserTraffic struct {
UID int `json:"userId"`
Upload int64 `json:"u"`
Download int64 `json:"d"`
}
type Response struct {
StatusCode int `json:"statusCode"`
Datas json.RawMessage `json:"datas"`
}
type PostData struct {
Data interface{} `json:"data"`
}

View File

@@ -2,91 +2,71 @@ package gov2panel
import ( import (
"bufio" "bufio"
"encoding/json" "context"
"errors" "errors"
"fmt" "fmt"
"log" "log"
"os" "os"
"regexp" "regexp"
"strconv"
"strings"
"sync/atomic"
"time" "time"
"github.com/bitly/go-simplejson" "github.com/XrayR-project/XrayR/api"
"github.com/go-resty/resty/v2" "github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gclient"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/infra/conf" "github.com/xtls/xray-core/infra/conf"
"github.com/XrayR-project/XrayR/api"
) )
// APIClient create an api client to the panel. // APIClient API config
type APIClient struct { type APIClient struct {
client *resty.Client ctx context.Context
APIHost string APIHost string
NodeID int NodeID int
Key string Key string
NodeType string NodeType string
EnableVless bool EnableVless bool
VlessFlow string VlessFlow string
SpeedLimit float64 Timeout int
DeviceLimit int SpeedLimit float64
DeviceLimit int
RuleListPath string
DisableCustomConfig bool
LocalRuleList []api.DetectRule LocalRuleList []api.DetectRule
resp atomic.Value
eTags map[string]string
} }
// New create an api instance // New create an api instance
func New(apiConfig *api.Config) *APIClient { func New(apiConfig *api.Config) *APIClient {
client := resty.New()
client.SetRetryCount(3) //https://goframe.org/pages/viewpage.action?pageId=1114381
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)
}
})
client.SetBaseURL(apiConfig.APIHost)
// Create Key for each requests
client.SetQueryParams(map[string]string{
"node_id": strconv.Itoa(apiConfig.NodeID),
"node_type": strings.ToLower(apiConfig.NodeType),
"token": apiConfig.Key,
})
// Read local rule list
localRuleList := readLocalRuleList(apiConfig.RuleListPath)
apiClient := &APIClient{ apiClient := &APIClient{
client: client, ctx: context.Background(),
NodeID: apiConfig.NodeID, APIHost: apiConfig.APIHost,
Key: apiConfig.Key, NodeID: apiConfig.NodeID,
APIHost: apiConfig.APIHost, Key: apiConfig.Key,
NodeType: apiConfig.NodeType, NodeType: apiConfig.NodeType,
EnableVless: apiConfig.EnableVless, EnableVless: apiConfig.EnableVless,
VlessFlow: apiConfig.VlessFlow, VlessFlow: apiConfig.VlessFlow,
SpeedLimit: apiConfig.SpeedLimit, Timeout: apiConfig.Timeout,
DeviceLimit: apiConfig.DeviceLimit, DeviceLimit: apiConfig.DeviceLimit,
LocalRuleList: localRuleList, RuleListPath: apiConfig.RuleListPath,
eTags: make(map[string]string), DisableCustomConfig: apiConfig.DisableCustomConfig,
LocalRuleList: readLocalRuleList(apiConfig.RuleListPath), //加载本地路由规则
} }
return apiClient return apiClient
} }
// readLocalRuleList reads the local rule list file // readLocalRuleList reads the local rule list file
func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) { func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {
LocalRuleList = make([]api.DetectRule, 0)
LocalRuleList = make([]api.DetectRule, 0)
if path != "" { if path != "" {
// open the file // open the file
file, err := os.Open(path) file, err := os.Open(path)
defer file.Close()
// handle errors while opening // handle errors while opening
if err != nil { if err != nil {
log.Printf("Error when opening file: %s", err) log.Printf("Error when opening file: %s", err)
@@ -107,127 +87,96 @@ func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {
log.Fatalf("Error while reading file: %s", err) log.Fatalf("Error while reading file: %s", err)
return return
} }
file.Close()
} }
return LocalRuleList 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: %v", c.assembleURL(path), err)
}
if res.StatusCode() > 399 {
return nil, fmt.Errorf("request %s failed: %s, %v", c.assembleURL(path), res.String(), 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 panel
func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) { func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
server := new(serverConfig)
path := "/api/server/config"
res, err := c.client.R(). apiPath := "/api/server/config"
SetHeader("If-None-Match", c.eTags["node"]). reslutJson, err := c.sendRequest(
ForceContentType("application/json"). nil,
Get(path) "POST",
apiPath,
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed g.Map{})
if res.StatusCode() == 304 {
return nil, errors.New(api.NodeNotModified)
}
// update etag
if res.Header().Get("Etag") != "" && res.Header().Get("Etag") != c.eTags["node"] {
c.eTags["node"] = res.Header().Get("Etag")
}
nodeInfoResp, err := c.parseResponse(res, path, err)
if err != nil { if err != nil {
return nil, err return nil, err
} }
b, _ := nodeInfoResp.Encode()
json.Unmarshal(b, server)
if gconv.Uint32(server.Port) == 0 { if reslutJson.Get("data").String() == "" {
return nil, errors.New("gov2panel node config data is null")
}
if reslutJson.Get("data.port").Int() == 0 {
return nil, errors.New("server port must > 0") return nil, errors.New("server port must > 0")
} }
c.resp.Store(server) nodeInfo = new(api.NodeInfo)
err = reslutJson.Get("data").Scan(nodeInfo)
switch c.NodeType {
case "V2ray":
nodeInfo, err = c.parseV2rayNodeResponse(server)
case "Trojan":
nodeInfo, err = c.parseTrojanNodeResponse(server)
case "Shadowsocks":
nodeInfo, err = c.parseSSNodeResponse(server)
default:
return nil, fmt.Errorf("unsupported node type: %s", c.NodeType)
}
if err != nil { if err != nil {
return nil, fmt.Errorf("parse node info failed: %s, \nError: %v", res.String(), err) return nil, fmt.Errorf("parse node info failed: \nError: %v", err)
} }
routes := make([]route, 0)
err = reslutJson.Get("data.routes").Scan(&routes)
if err != nil {
return nil, fmt.Errorf("parse node routes failed: \nError: %v", err)
}
nodeInfo.NodeType = c.NodeType
nodeInfo.NodeID = c.NodeID
nodeInfo.EnableVless = c.EnableVless
nodeInfo.VlessFlow = c.VlessFlow
nodeInfo.AlterID = 0
nodeInfo.NameServerConfig = parseDNSConfig(routes)
return nodeInfo, nil return nodeInfo, nil
}
func parseDNSConfig(routes []route) (nameServerList []*conf.NameServerConfig) {
nameServerList = make([]*conf.NameServerConfig, 0)
for i := range routes {
if routes[i].Action == "dns" {
nameServerList = append(nameServerList, &conf.NameServerConfig{
Address: &conf.Address{Address: net.ParseAddress(routes[i].ActionValue)},
Domains: routes[i].Match,
})
}
}
return
} }
// GetUserList will pull user form panel // GetUserList will pull user form panel
func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) { func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
var users []*user
path := "/api/server/user" apiPath := "/api/server/user"
switch c.NodeType { switch c.NodeType {
case "V2ray", "Trojan", "Shadowsocks": case "V2ray", "Trojan", "Shadowsocks", "Vmess", "Vless":
break break
default: default:
return nil, fmt.Errorf("unsupported node type: %s", c.NodeType) return nil, fmt.Errorf("unsupported node type: %s", c.NodeType)
} }
res, err := c.client.R(). reslutJson, err := c.sendRequest(
SetHeader("If-None-Match", c.eTags["users"]). nil,
ForceContentType("application/json"). "GET",
Get(path) apiPath,
g.Map{})
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
if res.StatusCode() == 304 {
return nil, errors.New(api.UserNotModified)
}
// update etag
if res.Header().Get("Etag") != "" && res.Header().Get("Etag") != c.eTags["users"] {
c.eTags["users"] = res.Header().Get("Etag")
}
usersResp, err := c.parseResponse(res, path, err)
if err != nil { if err != nil {
return nil, err return nil, err
} }
b, _ := usersResp.Get("users").Encode()
json.Unmarshal(b, &users) var users []*user
if len(users) == 0 { reslutJson.Get("data.users").Scan(&users)
return nil, errors.New("users is null")
}
userList := make([]api.UserInfo, len(users)) userList := make([]api.UserInfo, len(users))
for i := 0; i < len(users); i++ { for i := 0; i < len(users); i++ {
@@ -254,148 +203,126 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
return &userList, nil return &userList, nil
} }
// ReportUserTraffic reports the user traffic func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) error { return
path := "/api/server/push" }
res, err := c.client.R().SetBody(userTraffic).ForceContentType("application/json").Post(path) func (c *APIClient) ReportNodeOnlineUsers(onlineUser *[]api.OnlineUser) (err error) {
_, err = c.parseResponse(res, path, err) return
}
// ReportUserTraffic reports the user traffic
func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) (err error) {
apiPath := "/api/server/push"
reslutJson, err := c.sendRequest(
nil,
"POST",
apiPath,
g.Map{
"data": userTraffic,
})
if err != nil { if err != nil {
return err return err
} }
return nil if reslutJson.Get("code").Int() != 0 {
} return errors.New(reslutJson.Get("message").String())
}
// GetNodeRule implements the API interface
func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) { return
routes := c.resp.Load().(*serverConfig).Routes }
ruleList := c.LocalRuleList func (c *APIClient) Describe() api.ClientInfo {
return api.ClientInfo{APIHost: c.APIHost, NodeID: c.NodeID, Key: c.Key, NodeType: c.NodeType}
for i := range routes { }
if routes[i].Action == "block" {
// GetNodeRule implements the API interface
ruleList = append(ruleList, api.DetectRule{ func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
ID: i, ruleList := c.LocalRuleList
Pattern: regexp.MustCompile(strings.Join(routes[i].Match, "|")),
}) apiPath := "/api/server/config"
} reslutJson, err := c.sendRequest(
} nil,
"POST",
return &ruleList, nil apiPath,
} g.Map{})
if err != nil {
// ReportNodeStatus implements the API interface return nil, err
func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) { }
return nil
} routes := make([]route, 0)
err = reslutJson.Get("data.routes").Scan(&routes)
// ReportNodeOnlineUsers implements the API interface if err != nil {
func (c *APIClient) ReportNodeOnlineUsers(onlineUserList *[]api.OnlineUser) error { return nil, fmt.Errorf("parse node routes failed: \nError: %v", err)
return nil }
}
for i := range routes {
// ReportIllegal implements the API interface if routes[i].Action == "block" {
func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) error { for _, v := range routes[i].Match {
return nil ruleList = append(ruleList, api.DetectRule{
} ID: i,
Pattern: regexp.MustCompile(v),
// parseTrojanNodeResponse parse the response for the given nodeInfo format })
func (c *APIClient) parseTrojanNodeResponse(s *serverConfig) (*api.NodeInfo, error) { }
// Create GeneralNodeInfo
nodeInfo := &api.NodeInfo{ }
NodeType: c.NodeType, }
NodeID: c.NodeID,
Port: gconv.Uint32(s.Port), return &ruleList, nil
TransportProtocol: "tcp",
EnableTLS: true, }
Host: s.Host,
ServiceName: s.Sni, func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) (err error) {
NameServerConfig: s.parseDNSConfig(), return
} }
return nodeInfo, nil
} func (c *APIClient) Debug() {
// parseSSNodeResponse parse the response for the given nodeInfo format }
func (c *APIClient) parseSSNodeResponse(s *serverConfig) (*api.NodeInfo, error) {
var header json.RawMessage // request 统一请求接口
func (c *APIClient) sendRequest(headerM map[string]string, method string, url string, data g.Map) (reslutJson *gjson.Json, err error) {
if s.Obfs == "http" { url = c.APIHost + url
path := "/"
if p := s.ObfsSettings.Path; p != "" { client := gclient.New()
if strings.HasPrefix(p, "/") {
path = p var gResponse *gclient.Response
} else {
path += p if c.Timeout > 0 {
} client.SetTimeout(time.Duration(c.Timeout) * time.Second) //方法用于设置当前请求超时时间
} } else {
h := simplejson.New() client.SetTimeout(5 * time.Second)
h.Set("type", "http") }
h.SetPath([]string{"request", "path"}, path) client.Retry(3, 10*time.Second) //方法用于设置请求失败时重连次数和重连间隔。
header, _ = h.Encode()
} client.SetHeaderMap(headerM)
// Create GeneralNodeInfo client.SetHeader("Content-Type", "application/json")
return &api.NodeInfo{
NodeType: c.NodeType, data["token"] = c.Key
NodeID: c.NodeID, data["node_id"] = c.NodeID
Port: gconv.Uint32(s.Port),
TransportProtocol: "tcp", switch method {
CypherMethod: s.Encryption, case "GET":
ServerKey: s.ServerKey, // shadowsocks2022 share key gResponse, err = client.Get(c.ctx, url, data)
NameServerConfig: s.parseDNSConfig(), case "POST":
Header: header, gResponse, err = client.Post(c.ctx, url, data)
}, nil default:
} err = fmt.Errorf("unsupported method: %s", method)
return
// parseV2rayNodeResponse parse the response for the given nodeInfo format }
func (c *APIClient) parseV2rayNodeResponse(s *serverConfig) (*api.NodeInfo, error) {
var ( if err != nil {
header json.RawMessage return
enableTLS bool }
) defer gResponse.Close()
switch s.Net { reslutJson = gjson.New(gResponse.ReadAllString())
case "tcp": if reslutJson == nil {
if s.Header != nil { err = fmt.Errorf("http reslut to json, err : %s", gResponse.ReadAllString())
if httpHeader, err := s.Header.MarshalJSON(); err != nil { }
return nil, err if reslutJson.Get("code").Int() != 0 {
} else { err = errors.New(reslutJson.Get("message").String())
header = httpHeader return
}
}
}
if s.TLS == "tls" {
enableTLS = true
}
// Create GeneralNodeInfo
return &api.NodeInfo{
NodeType: c.NodeType,
NodeID: c.NodeID,
Port: gconv.Uint32(s.Port),
AlterID: 0,
TransportProtocol: s.Net,
EnableTLS: enableTLS,
Path: s.Path,
Host: s.Host,
EnableVless: c.EnableVless,
VlessFlow: c.VlessFlow,
ServiceName: s.Sni,
Header: header,
NameServerConfig: s.parseDNSConfig(),
}, nil
}
func (s *serverConfig) parseDNSConfig() (nameServerList []*conf.NameServerConfig) {
for i := range s.Routes {
if s.Routes[i].Action == "dns" {
nameServerList = append(nameServerList, &conf.NameServerConfig{
Address: &conf.Address{Address: net.ParseAddress(s.Routes[i].ActionValue)},
Domains: s.Routes[i].Match,
})
}
} }
return return

View File

@@ -5,56 +5,31 @@ import (
"github.com/XrayR-project/XrayR/api" "github.com/XrayR-project/XrayR/api"
"github.com/XrayR-project/XrayR/api/gov2panel" "github.com/XrayR-project/XrayR/api/gov2panel"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/util/gconv"
) )
func CreateClient() api.API { func CreateClient() api.API {
apiConfig := &api.Config{ apiConfig := &api.Config{
APIHost: "http://localhost:8080", APIHost: "http://localhost:8080",
Key: "123456", Key: "123456",
NodeID: 1, NodeID: 90,
NodeType: "V2ray", NodeType: "V2ray",
} }
client := gov2panel.New(apiConfig) client := gov2panel.New(apiConfig)
return client return client
} }
func TestGetV2rayNodeInfo(t *testing.T) { func TestGetNodeInfo(t *testing.T) {
client := CreateClient() client := CreateClient()
nodeInfo, err := client.GetNodeInfo() nodeInfo, err := client.GetNodeInfo()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
t.Log(nodeInfo)
}
func TestGetSSNodeInfo(t *testing.T) { nodeInfoJson := gjson.New(nodeInfo)
apiConfig := &api.Config{ t.Log(nodeInfoJson.String())
APIHost: "http://127.0.0.1:668", t.Log(nodeInfoJson.String())
Key: "qwertyuiopasdfghjkl",
NodeID: 1,
NodeType: "Shadowsocks",
}
client := gov2panel.New(apiConfig)
nodeInfo, err := client.GetNodeInfo()
if err != nil {
t.Error(err)
}
t.Log(nodeInfo)
}
func TestGetTrojanNodeInfo(t *testing.T) {
apiConfig := &api.Config{
APIHost: "http://127.0.0.1:668",
Key: "qwertyuiopasdfghjkl",
NodeID: 1,
NodeType: "Trojan",
}
client := gov2panel.New(apiConfig)
nodeInfo, err := client.GetNodeInfo()
if err != nil {
t.Error(err)
}
t.Log(nodeInfo)
} }
func TestGetUserList(t *testing.T) { func TestGetUserList(t *testing.T) {
@@ -65,6 +40,7 @@ func TestGetUserList(t *testing.T) {
t.Error(err) t.Error(err)
} }
t.Log(len(*userList))
t.Log(userList) t.Log(userList)
} }
@@ -74,24 +50,30 @@ func TestReportReportUserTraffic(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
t.Log(userList)
generalUserTraffic := make([]api.UserTraffic, len(*userList)) generalUserTraffic := make([]api.UserTraffic, len(*userList))
for i, userInfo := range *userList { for i, userInfo := range *userList {
generalUserTraffic[i] = api.UserTraffic{ generalUserTraffic[i] = api.UserTraffic{
UID: userInfo.UID, UID: userInfo.UID,
Upload: 1111, Upload: 1073741824,
Download: 2222, Download: 1073741824,
} }
} }
// client.Debug()
t.Log(gconv.String(generalUserTraffic))
client = CreateClient()
err = client.ReportUserTraffic(&generalUserTraffic) err = client.ReportUserTraffic(&generalUserTraffic)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
t.Error(err)
} }
func TestGetNodeRule(t *testing.T) { func TestGetNodeRule(t *testing.T) {
client := CreateClient() client := CreateClient()
client.Debug() client.Debug()
ruleList, err := client.GetNodeRule() ruleList, err := client.GetNodeRule()
if err != nil { if err != nil {
t.Error(err) t.Error(err)

View File

@@ -1,35 +1,9 @@
package gov2panel package gov2panel
import "encoding/json" type user struct {
Id int `json:"id"`
type serverConfig struct { Uuid string `json:"uuid"`
v2ray SpeedLimit int `json:"speed_limit"`
shadowsocks
//---
Routes []route `json:"routes"`
Header *json.RawMessage `json:"header"`
}
type v2ray struct {
Port string `json:"port"`
Scy string `json:"scy"`
Net string `json:"net"`
Type string `json:"type"`
Host string `json:"host"`
Path string `json:"path"`
TLS string `json:"tls"`
Sni string `json:"sni"`
Alpn string `json:"alpn"`
}
type shadowsocks struct {
Encryption string `json:"encryption"`
Obfs string `json:"obfs"`
ObfsSettings struct {
Path string `json:"path"`
Host string `json:"host"`
} `json:"obfs_settings"`
ServerKey string `json:"server_key"`
} }
type route struct { type route struct {
@@ -38,9 +12,3 @@ type route struct {
Action string `json:"action"` Action string `json:"action"`
ActionValue string `json:"action_value"` ActionValue string `json:"action_value"`
} }
type user struct {
Id int `json:"id"`
Uuid string `json:"uuid"`
SpeedLimit int `json:"speed_limit"`
}

View File

@@ -31,10 +31,27 @@ type v2ray struct {
Network string `json:"network"` Network string `json:"network"`
NetworkSettings struct { NetworkSettings struct {
Path string `json:"path"` Path string `json:"path"`
Host string `json:"host"`
Headers *json.RawMessage `json:"headers"` Headers *json.RawMessage `json:"headers"`
ServiceName string `json:"serviceName"` ServiceName string `json:"serviceName"`
Header *json.RawMessage `json:"header"` Header *json.RawMessage `json:"header"`
} `json:"networkSettings"` } `json:"networkSettings"`
VlessNetworkSettings struct {
Path string `json:"path"`
Host string `json:"host"`
Headers *json.RawMessage `json:"headers"`
ServiceName string `json:"serviceName"`
Header *json.RawMessage `json:"header"`
} `json:"network_settings"`
VlessFlow string `json:"flow"`
VlessTlsSettings struct {
ServerPort string `json:"server_port"`
Dest string `json:"dest"`
xVer uint64 `json:"xver"`
Sni string `json:"server_name"`
PrivateKey string `json:"private_key"`
ShortId string `json:"short_id"`
} `json:"tls_settings"`
Tls int `json:"tls"` Tls int `json:"tls"`
} }

View File

@@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"log"
"os" "os"
"regexp" "regexp"
"strconv" "strconv"
@@ -13,6 +12,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
log "github.com/sirupsen/logrus"
"github.com/bitly/go-simplejson" "github.com/bitly/go-simplejson"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
@@ -54,10 +55,18 @@ func New(apiConfig *api.Config) *APIClient {
} }
}) })
client.SetBaseURL(apiConfig.APIHost) client.SetBaseURL(apiConfig.APIHost)
var nodeType string
if apiConfig.NodeType == "V2ray" && apiConfig.EnableVless {
nodeType = "vless"
} else {
nodeType = strings.ToLower(apiConfig.NodeType)
}
// Create Key for each requests // Create Key for each requests
client.SetQueryParams(map[string]string{ client.SetQueryParams(map[string]string{
"node_id": strconv.Itoa(apiConfig.NodeID), "node_id": strconv.Itoa(apiConfig.NodeID),
"node_type": strings.ToLower(apiConfig.NodeType), "node_type": nodeType,
"token": apiConfig.Key, "token": apiConfig.Key,
}) })
// Read local rule list // Read local rule list
@@ -175,7 +184,7 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
c.resp.Store(server) c.resp.Store(server)
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
nodeInfo, err = c.parseV2rayNodeResponse(server) nodeInfo, err = c.parseV2rayNodeResponse(server)
case "Trojan": case "Trojan":
nodeInfo, err = c.parseTrojanNodeResponse(server) nodeInfo, err = c.parseTrojanNodeResponse(server)
@@ -198,7 +207,7 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
path := "/api/v1/server/UniProxy/user" path := "/api/v1/server/UniProxy/user"
switch c.NodeType { switch c.NodeType {
case "V2ray", "Trojan", "Shadowsocks": case "V2ray", "Trojan", "Shadowsocks", "Vmess", "Vless":
break break
default: default:
return nil, fmt.Errorf("unsupported node type: %s", c.NodeType) return nil, fmt.Errorf("unsupported node type: %s", c.NodeType)
@@ -355,11 +364,37 @@ func (c *APIClient) parseSSNodeResponse(s *serverConfig) (*api.NodeInfo, error)
// parseV2rayNodeResponse parse the response for the given nodeInfo format // parseV2rayNodeResponse parse the response for the given nodeInfo format
func (c *APIClient) parseV2rayNodeResponse(s *serverConfig) (*api.NodeInfo, error) { func (c *APIClient) parseV2rayNodeResponse(s *serverConfig) (*api.NodeInfo, error) {
var ( var (
host string host string
header json.RawMessage header json.RawMessage
enableTLS bool enableTLS bool
enableREALITY bool
dest string
xVer uint64
) )
if s.VlessTlsSettings.Dest != "" {
dest = s.VlessTlsSettings.Dest
} else {
dest = s.VlessTlsSettings.Sni
}
if s.VlessTlsSettings.xVer != 0 {
xVer = s.VlessTlsSettings.xVer
} else {
xVer = 0
}
realityConfig := api.REALITYConfig{
Dest: dest + ":" + s.VlessTlsSettings.ServerPort,
ProxyProtocolVer: xVer,
ServerNames: []string{s.VlessTlsSettings.Sni},
PrivateKey: s.VlessTlsSettings.PrivateKey,
ShortIds: []string{s.VlessTlsSettings.ShortId},
}
if c.EnableVless {
s.NetworkSettings = s.VlessNetworkSettings
}
switch s.Network { switch s.Network {
case "ws": case "ws":
if s.NetworkSettings.Headers != nil { if s.NetworkSettings.Headers != nil {
@@ -378,10 +413,30 @@ func (c *APIClient) parseV2rayNodeResponse(s *serverConfig) (*api.NodeInfo, erro
header = httpHeader header = httpHeader
} }
} }
case "httpupgrade", "splithttp":
if s.NetworkSettings.Headers != nil {
if httpHeaders, err := s.NetworkSettings.Headers.MarshalJSON(); err != nil {
return nil, err
} else {
b, _ := simplejson.NewJson(httpHeaders)
host = b.Get("Host").MustString()
}
}
if s.NetworkSettings.Host != "" {
host = s.NetworkSettings.Host
}
} }
if s.Tls == 1 { switch s.Tls {
case 0:
enableTLS = false
enableREALITY = false
case 1:
enableTLS = true enableTLS = true
enableREALITY = false
case 2:
enableTLS = true
enableREALITY = true
} }
// Create GeneralNodeInfo // Create GeneralNodeInfo
@@ -395,9 +450,11 @@ func (c *APIClient) parseV2rayNodeResponse(s *serverConfig) (*api.NodeInfo, erro
Path: s.NetworkSettings.Path, Path: s.NetworkSettings.Path,
Host: host, Host: host,
EnableVless: c.EnableVless, EnableVless: c.EnableVless,
VlessFlow: c.VlessFlow, VlessFlow: s.VlessFlow,
ServiceName: s.NetworkSettings.ServiceName, ServiceName: s.NetworkSettings.ServiceName,
Header: header, Header: header,
EnableREALITY: enableREALITY,
REALITYConfig: &realityConfig,
NameServerConfig: s.parseDNSConfig(), NameServerConfig: s.parseDNSConfig(),
}, nil }, nil
} }

View File

@@ -4,13 +4,14 @@ import (
"bufio" "bufio"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"os" "os"
"reflect" "reflect"
"regexp" "regexp"
"strconv" "strconv"
"time" "time"
log "github.com/sirupsen/logrus"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/XrayR-project/XrayR/api" "github.com/XrayR-project/XrayR/api"

View File

@@ -4,13 +4,14 @@ import (
"bufio" "bufio"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"os" "os"
"reflect" "reflect"
"regexp" "regexp"
"strconv" "strconv"
"time" "time"
log "github.com/sirupsen/logrus"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/XrayR-project/XrayR/api" "github.com/XrayR-project/XrayR/api"
@@ -144,7 +145,7 @@ func (c *APIClient) parseResponse(res *resty.Response, path string, err error) (
func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) { func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
var path string var path string
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
path = fmt.Sprintf("/api/v2ray/v1/node/%d", c.NodeID) path = fmt.Sprintf("/api/v2ray/v1/node/%d", c.NodeID)
case "Trojan": case "Trojan":
path = fmt.Sprintf("/api/trojan/v1/node/%d", c.NodeID) path = fmt.Sprintf("/api/trojan/v1/node/%d", c.NodeID)
@@ -165,7 +166,7 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
} }
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
nodeInfo, err = c.ParseV2rayNodeResponse(&response.Data) nodeInfo, err = c.ParseV2rayNodeResponse(&response.Data)
case "Trojan": case "Trojan":
nodeInfo, err = c.ParseTrojanNodeResponse(&response.Data) nodeInfo, err = c.ParseTrojanNodeResponse(&response.Data)
@@ -177,7 +178,7 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
if err != nil { if err != nil {
res, _ := json.Marshal(response.Data) res, _ := json.Marshal(response.Data)
return nil, fmt.Errorf("Parse node info failed: %s, \nError: %s", string(res), err) return nil, fmt.Errorf("parse node info failed: %s, \nError: %s", string(res), err)
} }
return nodeInfo, nil return nodeInfo, nil
@@ -187,7 +188,7 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) { func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
var path string var path string
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
path = fmt.Sprintf("/api/v2ray/v1/userList/%d", c.NodeID) path = fmt.Sprintf("/api/v2ray/v1/userList/%d", c.NodeID)
case "Trojan": case "Trojan":
path = fmt.Sprintf("/api/trojan/v1/userList/%d", c.NodeID) path = fmt.Sprintf("/api/trojan/v1/userList/%d", c.NodeID)
@@ -208,7 +209,7 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
} }
userList := new([]api.UserInfo) userList := new([]api.UserInfo)
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
userList, err = c.ParseV2rayUserListResponse(&response.Data) userList, err = c.ParseV2rayUserListResponse(&response.Data)
case "Trojan": case "Trojan":
userList, err = c.ParseTrojanUserListResponse(&response.Data) userList, err = c.ParseTrojanUserListResponse(&response.Data)
@@ -228,7 +229,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) {
var path string var path string
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
path = fmt.Sprintf("/api/v2ray/v1/nodeStatus/%d", c.NodeID) path = fmt.Sprintf("/api/v2ray/v1/nodeStatus/%d", c.NodeID)
case "Trojan": case "Trojan":
path = fmt.Sprintf("/api/trojan/v1/nodeStatus/%d", c.NodeID) path = fmt.Sprintf("/api/trojan/v1/nodeStatus/%d", c.NodeID)
@@ -264,7 +265,7 @@ func (c *APIClient) ReportNodeOnlineUsers(onlineUserList *[]api.OnlineUser) erro
var path string var path string
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
path = fmt.Sprintf("/api/v2ray/v1/nodeOnline/%d", c.NodeID) path = fmt.Sprintf("/api/v2ray/v1/nodeOnline/%d", c.NodeID)
case "Trojan": case "Trojan":
path = fmt.Sprintf("/api/trojan/v1/nodeOnline/%d", c.NodeID) path = fmt.Sprintf("/api/trojan/v1/nodeOnline/%d", c.NodeID)
@@ -297,7 +298,7 @@ func (c *APIClient) ReportNodeOnlineUsers(onlineUserList *[]api.OnlineUser) erro
func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) error { func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) error {
var path string var path string
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
path = fmt.Sprintf("/api/v2ray/v1/userTraffic/%d", c.NodeID) path = fmt.Sprintf("/api/v2ray/v1/userTraffic/%d", c.NodeID)
case "Trojan": case "Trojan":
path = fmt.Sprintf("/api/trojan/v1/userTraffic/%d", c.NodeID) path = fmt.Sprintf("/api/trojan/v1/userTraffic/%d", c.NodeID)
@@ -332,7 +333,7 @@ func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) error {
func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) { func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
var path string var path string
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
path = fmt.Sprintf("/api/v2ray/v1/nodeRule/%d", c.NodeID) path = fmt.Sprintf("/api/v2ray/v1/nodeRule/%d", c.NodeID)
case "Trojan": case "Trojan":
path = fmt.Sprintf("/api/trojan/v1/nodeRule/%d", c.NodeID) path = fmt.Sprintf("/api/trojan/v1/nodeRule/%d", c.NodeID)
@@ -380,7 +381,7 @@ func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) error { func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) error {
var path string var path string
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
path = fmt.Sprintf("/api/v2ray/v1/trigger/%d", c.NodeID) path = fmt.Sprintf("/api/v2ray/v1/trigger/%d", c.NodeID)
case "Trojan": case "Trojan":
path = fmt.Sprintf("/api/trojan/v1/trigger/%d", c.NodeID) path = fmt.Sprintf("/api/trojan/v1/trigger/%d", c.NodeID)

View File

@@ -154,8 +154,8 @@ func TestReportIllegal(t *testing.T) {
client := CreateClient() client := CreateClient()
detectResult := []api.DetectResult{ detectResult := []api.DetectResult{
{1, 1}, {UID: 1, RuleID: 1},
{1, 2}, {UID: 1, RuleID: 2},
} }
client.Debug() client.Debug()
err := client.ReportIllegal(&detectResult) err := client.ReportIllegal(&detectResult)

View File

@@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"log"
"os" "os"
"reflect" "reflect"
"regexp" "regexp"
@@ -14,6 +13,8 @@ import (
"sync" "sync"
"time" "time"
log "github.com/sirupsen/logrus"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/XrayR-project/XrayR/api" "github.com/XrayR-project/XrayR/api"
@@ -94,8 +95,13 @@ func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {
if path != "" { if path != "" {
// open the file // open the file
file, err := os.Open(path) file, err := os.Open(path)
defer file.Close()
defer func(file *os.File) {
err := file.Close()
if err != nil {
log.Printf("Error when closing file: %s", err)
}
}(file)
// handle errors while opening // handle errors while opening
if err != nil { if err != nil {
log.Printf("Error when opening file: %s", err) log.Printf("Error when opening file: %s", err)
@@ -142,7 +148,7 @@ func (c *APIClient) parseResponse(res *resty.Response, path string, err error) (
if res.StatusCode() > 400 { if res.StatusCode() > 400 {
body := res.Body() body := res.Body()
return nil, fmt.Errorf("request %s failed: %s, %s", c.assembleURL(path), string(body), err) return nil, fmt.Errorf("request %s failed: %s, %v", c.assembleURL(path), string(body), err)
} }
response := res.Result().(*Response) response := res.Result().(*Response)
@@ -209,13 +215,13 @@ 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://xrayr-project.github.io/XrayR-doc/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)
} }
} }
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", string(res), err) return nil, fmt.Errorf("parse node info failed: %s, \nError: %s", string(res), err)
} }
return nodeInfo, nil return nodeInfo, nil
@@ -290,16 +296,12 @@ func (c *APIClient) ReportNodeOnlineUsers(onlineUserList *[]api.OnlineUser) erro
data := make([]OnlineUser, len(*onlineUserList)) data := make([]OnlineUser, len(*onlineUserList))
for i, user := range *onlineUserList { for i, user := range *onlineUserList {
data[i] = OnlineUser{UID: user.UID, IP: user.IP} data[i] = OnlineUser{UID: user.UID, IP: user.IP}
if _, ok := reportOnline[user.UID]; ok { reportOnline[user.UID]++ // will start from 1 if key doesnt exist
reportOnline[user.UID]++
} else {
reportOnline[user.UID] = 1
}
} }
c.LastReportOnline = reportOnline // Update LastReportOnline c.LastReportOnline = reportOnline // Update LastReportOnline
postData := &PostData{Data: data} postData := &PostData{Data: data}
path := fmt.Sprintf("/mod_mu/users/aliveip") path := "/mod_mu/users/aliveip"
res, err := c.client.R(). res, err := c.client.R().
SetQueryParam("node_id", strconv.Itoa(c.NodeID)). SetQueryParam("node_id", strconv.Itoa(c.NodeID)).
SetBody(postData). SetBody(postData).
@@ -473,7 +475,7 @@ func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *NodeInfoResponse) (
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("marshal Header Type %s into config fialed: %s", header, err) return nil, fmt.Errorf("marshal Header Type %s into config failed: %s", header, err)
} }
// Create GeneralNodeInfo // Create GeneralNodeInfo
@@ -519,6 +521,11 @@ func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *NodeInfoResponse) (*ap
return nil, fmt.Errorf("unmarshal %s failed: %s", reflect.TypeOf(userListResponse), err) return nil, fmt.Errorf("unmarshal %s failed: %s", reflect.TypeOf(userListResponse), err)
} }
// init server port
if len(*userListResponse) != 0 {
port = (*userListResponse)[0].Port
}
if c.SpeedLimit > 0 { if c.SpeedLimit > 0 {
speedLimit = uint64((c.SpeedLimit * 1000000) / 8) speedLimit = uint64((c.SpeedLimit * 1000000) / 8)
} else { } else {
@@ -682,7 +689,7 @@ func (c *APIClient) ParseUserListResponse(userInfoResponse *[]UserResponse) (*[]
c.access.Unlock() c.access.Unlock()
}() }()
var deviceLimit, localDeviceLimit int = 0, 0 var deviceLimit, localDeviceLimit = 0, 0
var speedLimit uint64 = 0 var speedLimit uint64 = 0
var userList []api.UserInfo var userList []api.UserInfo
for _, user := range *userInfoResponse { for _, user := range *userInfoResponse {
@@ -733,10 +740,10 @@ func (c *APIClient) ParseUserListResponse(userInfoResponse *[]UserResponse) (*[]
// Only available for SSPanel version >= 2021.11 // Only available for SSPanel version >= 2021.11
func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error) { func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error) {
var ( var (
speedLimit uint64 = 0 speedLimit uint64 = 0
enableTLS, enableVless bool enableTLS, enableVless bool
alterID uint16 = 0 alterID uint16 = 0
tlsType, transportProtocol string transportProtocol string
) )
// Check if custom_config is null // Check if custom_config is null
@@ -768,8 +775,8 @@ func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*a
transportProtocol = "tcp" transportProtocol = "tcp"
case "V2ray": case "V2ray":
transportProtocol = nodeConfig.Network transportProtocol = nodeConfig.Network
tlsType = nodeConfig.Security
tlsType := nodeConfig.Security
if tlsType == "tls" || tlsType == "xtls" { if tlsType == "tls" || tlsType == "xtls" {
enableTLS = true enableTLS = true
} }
@@ -779,13 +786,8 @@ func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*a
} }
case "Trojan": case "Trojan":
enableTLS = true enableTLS = true
tlsType = "tls"
transportProtocol = "tcp" transportProtocol = "tcp"
if nodeConfig.Security != "" {
tlsType = nodeConfig.Security // try to read security from config
}
// Select transport protocol // Select transport protocol
if nodeConfig.Network != "" { if nodeConfig.Network != "" {
transportProtocol = nodeConfig.Network // try to read transport protocol from config transportProtocol = nodeConfig.Network // try to read transport protocol from config

View File

@@ -148,8 +148,8 @@ func TestReportIllegal(t *testing.T) {
client := CreateClient() client := CreateClient()
detectResult := []api.DetectResult{ detectResult := []api.DetectResult{
{1, 2}, {UID: 1, RuleID: 2},
{1, 3}, {UID: 1, RuleID: 3},
} }
client.Debug() client.Debug()
err := client.ReportIllegal(&detectResult) err := client.ReportIllegal(&detectResult)

View File

@@ -1,7 +1,35 @@
package v2raysocks package v2raysocks
type UserTraffic struct { type UserTraffic struct {
UID int `json:"user_id"` UID int `json:"uid"`
Upload int64 `json:"u"` Upload int64 `json:"u"`
Download int64 `json:"d"` Download int64 `json:"d"`
} }
type NodeStatus struct {
CPU string `json:"cpu"`
Mem string `json:"mem"`
Net string `json:"net"`
Disk string `json:"disk"`
Uptime int `json:"uptime"`
}
type NodeOnline struct {
UID int `json:"uid"`
IP string `json:"ip"`
}
type IllegalItem struct {
UID int `json:"uid"`
}
type REALITYConfig struct {
Dest string `json:"dest,omitempty"`
ProxyProtocolVer uint64 `json:"proxy_protocol_ver,omitempty"`
ServerNames []string `json:"server_names,omitempty"`
PrivateKey string `json:"private_key,omitempty"`
MinClientVer string `json:"min_client_ver,omitempty"`
MaxClientVer string `json:"max_client_ver,omitempty"`
MaxTimeDiff uint64 `json:"max_time_diff,omitempty"`
ShortIds []string `json:"short_ids,omitempty"`
}

View File

@@ -3,8 +3,8 @@ package v2raysocks
import ( import (
"bufio" "bufio"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"log"
"os" "os"
"regexp" "regexp"
"strconv" "strconv"
@@ -12,6 +12,8 @@ import (
"sync" "sync"
"time" "time"
log "github.com/sirupsen/logrus"
"github.com/bitly/go-simplejson" "github.com/bitly/go-simplejson"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022" "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
@@ -34,6 +36,7 @@ type APIClient struct {
LocalRuleList []api.DetectRule LocalRuleList []api.DetectRule
ConfigResp *simplejson.Json ConfigResp *simplejson.Json
access sync.Mutex access sync.Mutex
eTags map[string]string
} }
// New create an api instance // New create an api instance
@@ -46,13 +49,16 @@ func New(apiConfig *api.Config) *APIClient {
} else { } else {
client.SetTimeout(5 * time.Second) client.SetTimeout(5 * time.Second)
} }
client.OnError(func(req *resty.Request, err error) { client.OnError(func(req *resty.Request, err error) {
if v, ok := err.(*resty.ResponseError); ok { var v *resty.ResponseError
if errors.As(err, &v) {
// v.Response contains the last response from the server // v.Response contains the last response from the server
// v.Err contains the original error // v.Err contains the original error
log.Print(v.Err) log.Print(v.Err)
} }
}) })
// Create Key for each requests // Create Key for each requests
client.SetQueryParams(map[string]string{ client.SetQueryParams(map[string]string{
"node_id": strconv.Itoa(apiConfig.NodeID), "node_id": strconv.Itoa(apiConfig.NodeID),
@@ -71,6 +77,7 @@ func New(apiConfig *api.Config) *APIClient {
SpeedLimit: apiConfig.SpeedLimit, SpeedLimit: apiConfig.SpeedLimit,
DeviceLimit: apiConfig.DeviceLimit, DeviceLimit: apiConfig.DeviceLimit,
LocalRuleList: localRuleList, LocalRuleList: localRuleList,
eTags: make(map[string]string),
} }
return apiClient return apiClient
} }
@@ -144,19 +151,29 @@ func (c *APIClient) parseResponse(res *resty.Response, path string, err error) (
func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) { func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
var nodeType string var nodeType string
switch c.NodeType { switch c.NodeType {
case "V2ray", "Trojan", "Shadowsocks": case "V2ray", "Vmess", "Vless", "Trojan", "Shadowsocks":
nodeType = strings.ToLower(c.NodeType) nodeType = strings.ToLower(c.NodeType)
default: default:
return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType) return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType)
} }
res, err := c.client.R(). res, err := c.client.R().
SetHeader("If-None-Match", c.eTags["config"]).
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"act": "config", "act": "config",
"nodetype": nodeType, "node_type": nodeType,
}). }).
ForceContentType("application/json"). ForceContentType("application/json").
Get(c.APIHost) Get(c.APIHost)
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
if res.StatusCode() == 304 {
return nil, errors.New(api.NodeNotModified)
}
// update etag
if res.Header().Get("Etag") != "" && res.Header().Get("Etag") != c.eTags["config"] {
c.eTags["config"] = res.Header().Get("Etag")
}
response, err := c.parseResponse(res, "", err) response, err := c.parseResponse(res, "", err)
c.access.Lock() c.access.Lock()
defer c.access.Unlock() defer c.access.Unlock()
@@ -166,7 +183,7 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
} }
switch c.NodeType { switch c.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
nodeInfo, err = c.ParseV2rayNodeResponse(response) nodeInfo, err = c.ParseV2rayNodeResponse(response)
case "Trojan": case "Trojan":
nodeInfo, err = c.ParseTrojanNodeResponse(response) nodeInfo, err = c.ParseTrojanNodeResponse(response)
@@ -188,19 +205,29 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) { func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
var nodeType string var nodeType string
switch c.NodeType { switch c.NodeType {
case "V2ray", "Trojan", "Shadowsocks": case "V2ray", "Vmess", "Vless", "Trojan", "Shadowsocks":
nodeType = strings.ToLower(c.NodeType) nodeType = strings.ToLower(c.NodeType)
default: default:
return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType) return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType)
} }
res, err := c.client.R(). res, err := c.client.R().
SetHeader("If-None-Match", c.eTags["user"]).
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"act": "user", "act": "user",
"nodetype": nodeType, "node_type": nodeType,
}). }).
ForceContentType("application/json"). ForceContentType("application/json").
Get(c.APIHost) Get(c.APIHost)
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
if res.StatusCode() == 304 {
return nil, errors.New(api.UserNotModified)
}
// update etag
if res.Header().Get("Etag") != "" && res.Header().Get("Etag") != c.eTags["user"] {
c.eTags["user"] = res.Header().Get("Etag")
}
response, err := c.parseResponse(res, "", err) response, err := c.parseResponse(res, "", err)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -212,24 +239,30 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
user.UID = response.Get("data").GetIndex(i).Get("id").MustInt() user.UID = response.Get("data").GetIndex(i).Get("id").MustInt()
switch c.NodeType { switch c.NodeType {
case "Shadowsocks": case "Shadowsocks":
user.Email = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("secret").MustString() user.Email = response.Get("data").GetIndex(i).Get("secret").MustString()
user.Passwd = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("secret").MustString() user.Passwd = response.Get("data").GetIndex(i).Get("secret").MustString()
user.Method = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("cipher").MustString() user.Method = response.Get("data").GetIndex(i).Get("cipher").MustString()
user.SpeedLimit = response.Get("data").GetIndex(i).Get("shadowsocks_user").Get("speed_limit").MustUint64() * 1000000 / 8 user.SpeedLimit = response.Get("data").GetIndex(i).Get("st").MustUint64() * 1000000 / 8
user.DeviceLimit = response.Get("data").GetIndex(i).Get("dt").MustInt()
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("password").MustString()
user.Email = response.Get("data").GetIndex(i).Get("trojan_user").Get("password").MustString() user.Email = response.Get("data").GetIndex(i).Get("password").MustString()
user.SpeedLimit = response.Get("data").GetIndex(i).Get("trojan_user").Get("speed_limit").MustUint64() * 1000000 / 8 user.SpeedLimit = response.Get("data").GetIndex(i).Get("st").MustUint64() * 1000000 / 8
case "V2ray": user.DeviceLimit = response.Get("data").GetIndex(i).Get("dt").MustInt()
user.UUID = response.Get("data").GetIndex(i).Get("v2ray_user").Get("uuid").MustString() case "V2ray", "Vmess", "Vless":
user.Email = response.Get("data").GetIndex(i).Get("v2ray_user").Get("email").MustString() user.UUID = response.Get("data").GetIndex(i).Get("uuid").MustString()
user.AlterID = uint16(response.Get("data").GetIndex(i).Get("v2ray_user").Get("alter_id").MustUint64()) user.Email = user.UUID + "@x.com"
user.SpeedLimit = response.Get("data").GetIndex(i).Get("v2ray_user").Get("speed_limit").MustUint64() * 1000000 / 8 user.SpeedLimit = response.Get("data").GetIndex(i).Get("st").MustUint64() * 1000000 / 8
user.DeviceLimit = response.Get("data").GetIndex(i).Get("dt").MustInt()
} }
if c.SpeedLimit > 0 { if c.SpeedLimit > 0 {
user.SpeedLimit = uint64((c.SpeedLimit * 1000000) / 8) user.SpeedLimit = uint64((c.SpeedLimit * 1000000) / 8)
} }
user.DeviceLimit = c.DeviceLimit
if c.DeviceLimit > 0 {
user.DeviceLimit = c.DeviceLimit
}
userList[i] = user userList[i] = user
} }
return &userList, nil return &userList, nil
@@ -249,8 +282,8 @@ func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) error {
res, err := c.client.R(). res, err := c.client.R().
SetQueryParam("node_id", strconv.Itoa(c.NodeID)). SetQueryParam("node_id", strconv.Itoa(c.NodeID)).
SetQueryParams(map[string]string{ SetQueryParams(map[string]string{
"act": "submit", "act": "submit",
"nodetype": strings.ToLower(c.NodeType), "node_type": strings.ToLower(c.NodeType),
}). }).
SetBody(data). SetBody(data).
ForceContentType("application/json"). ForceContentType("application/json").
@@ -265,11 +298,7 @@ func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) error {
// GetNodeRule implements the API interface // GetNodeRule implements the API interface
func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) { func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
ruleList := c.LocalRuleList ruleList := c.LocalRuleList
if c.NodeType != "V2ray" {
return &ruleList, nil
}
// Only support the rule for v2ray
// fix: reuse config response // fix: reuse config response
c.access.Lock() c.access.Lock()
defer c.access.Unlock() defer c.access.Unlock()
@@ -287,16 +316,74 @@ func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
// ReportNodeStatus implements the API interface // ReportNodeStatus implements the API interface
func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) { func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
systemload := NodeStatus{
Uptime: int(nodeStatus.Uptime),
CPU: fmt.Sprintf("%d%%", int(nodeStatus.CPU)),
Mem: fmt.Sprintf("%d%%", int(nodeStatus.Mem)),
Disk: fmt.Sprintf("%d%%", int(nodeStatus.Disk)),
}
res, err := c.client.R().
SetQueryParam("node_id", strconv.Itoa(c.NodeID)).
SetQueryParams(map[string]string{
"act": "nodestatus",
"node_type": strings.ToLower(c.NodeType),
}).
SetBody(systemload).
ForceContentType("application/json").
Post(c.APIHost)
_, err = c.parseResponse(res, "", err)
if err != nil {
return err
}
return nil return nil
} }
// ReportNodeOnlineUsers implements the API interface // ReportNodeOnlineUsers implements the API interface
func (c *APIClient) ReportNodeOnlineUsers(onlineUserList *[]api.OnlineUser) error { func (c *APIClient) ReportNodeOnlineUsers(onlineUserList *[]api.OnlineUser) error {
data := make([]NodeOnline, len(*onlineUserList))
for i, user := range *onlineUserList {
data[i] = NodeOnline{UID: user.UID, IP: user.IP}
}
res, err := c.client.R().
SetQueryParam("node_id", strconv.Itoa(c.NodeID)).
SetQueryParams(map[string]string{
"act": "onlineusers",
"node_type": strings.ToLower(c.NodeType),
}).
SetBody(data).
ForceContentType("application/json").
Post(c.APIHost)
_, err = c.parseResponse(res, "", err)
if err != nil {
return err
}
return nil return nil
} }
// ReportIllegal implements the API interface // ReportIllegal implements the API interface
func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) error { func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) error {
data := make([]IllegalItem, len(*detectResultList))
for i, r := range *detectResultList {
data[i] = IllegalItem{
UID: r.UID,
}
}
res, err := c.client.R().
SetQueryParam("node_id", strconv.Itoa(c.NodeID)).
SetQueryParams(map[string]string{
"act": "illegal",
"node_type": strings.ToLower(c.NodeType),
}).
SetBody(data).
ForceContentType("application/json").
Post(c.APIHost)
_, err = c.parseResponse(res, "", err)
if err != nil {
return err
}
return nil return nil
} }
@@ -333,14 +420,6 @@ func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *simplejson.Json) (*api
// Shadowsocks 2022 // Shadowsocks 2022
if C.Contains(shadowaead_2022.List, method) { if C.Contains(shadowaead_2022.List, method) {
serverPsk = inboundInfo.Get("settings").Get("password").MustString() serverPsk = inboundInfo.Get("settings").Get("password").MustString()
} else {
userInfo, err := c.GetUserList()
if err != nil {
return nil, err
}
if len(*userInfo) > 0 {
method = (*userInfo)[0].Method
}
} }
// Create GeneralNodeInfo // Create GeneralNodeInfo
@@ -361,7 +440,9 @@ 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 uint16 = 0 var enableVless bool
var enableReality bool
var vlessFlow string
tmpInboundInfo := nodeInfoResponse.Get("inbounds").MustArray() tmpInboundInfo := nodeInfoResponse.Get("inbounds").MustArray()
marshalByte, _ := json.Marshal(tmpInboundInfo[0].(map[string]interface{})) marshalByte, _ := json.Marshal(tmpInboundInfo[0].(map[string]interface{}))
@@ -374,6 +455,12 @@ func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *simplejson.Json) (*
case "ws": case "ws":
path = inboundInfo.Get("streamSettings").Get("wsSettings").Get("path").MustString() path = inboundInfo.Get("streamSettings").Get("wsSettings").Get("path").MustString()
host = inboundInfo.Get("streamSettings").Get("wsSettings").Get("headers").Get("Host").MustString() host = inboundInfo.Get("streamSettings").Get("wsSettings").Get("headers").Get("Host").MustString()
case "httpupgrade":
host = inboundInfo.Get("streamSettings").Get("httpupgradeSettings").Get("Host").MustString()
path = inboundInfo.Get("streamSettings").Get("httpupgradeSettings").Get("path").MustString()
case "splithttp":
host = inboundInfo.Get("streamSettings").Get("splithttpSettings").Get("Host").MustString()
path = inboundInfo.Get("streamSettings").Get("splithttpSettings").Get("path").MustString()
case "grpc": case "grpc":
if data, ok := inboundInfo.Get("streamSettings").Get("grpcSettings").CheckGet("serviceName"); ok { if data, ok := inboundInfo.Get("streamSettings").Get("grpcSettings").CheckGet("serviceName"); ok {
serviceName = data.MustString() serviceName = data.MustString()
@@ -386,12 +473,32 @@ func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *simplejson.Json) (*
header = httpHeader header = httpHeader
} }
} }
} }
if inboundInfo.Get("streamSettings").Get("security").MustString() == "tls" {
enableTLS = true enableTLS = inboundInfo.Get("streamSettings").Get("security").MustString() == "tls"
enableVless = inboundInfo.Get("protocol").MustString() == "vless"
enableReality = inboundInfo.Get("streamSettings").Get("security").MustString() == "reality"
realityConfig := new(api.REALITYConfig)
if enableVless {
// parse reality config
realityConfig = &api.REALITYConfig{
Dest: inboundInfo.Get("streamSettings").Get("realitySettings").Get("dest").MustString(),
ProxyProtocolVer: inboundInfo.Get("streamSettings").Get("realitySettings").Get("xver").MustUint64(),
ServerNames: inboundInfo.Get("streamSettings").Get("realitySettings").Get("serverNames").MustStringArray(),
PrivateKey: inboundInfo.Get("streamSettings").Get("realitySettings").Get("privateKey").MustString(),
MinClientVer: inboundInfo.Get("streamSettings").Get("realitySettings").Get("minClientVer").MustString(),
MaxClientVer: inboundInfo.Get("streamSettings").Get("realitySettings").Get("maxClientVer").MustString(),
MaxTimeDiff: inboundInfo.Get("streamSettings").Get("realitySettings").Get("maxTimeDiff").MustUint64(),
ShortIds: inboundInfo.Get("streamSettings").Get("realitySettings").Get("shortIds").MustStringArray(),
}
}
// XTLS only supports TLS and REALITY directly for now
if transportProtocol == "tcp" && enableReality {
vlessFlow = "xtls-rprx-vision"
} else { } else {
enableTLS = false vlessFlow = c.VlessFlow
} }
// Create GeneralNodeInfo // Create GeneralNodeInfo
@@ -400,15 +507,17 @@ func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *simplejson.Json) (*
NodeType: c.NodeType, NodeType: c.NodeType,
NodeID: c.NodeID, NodeID: c.NodeID,
Port: port, Port: port,
AlterID: alterID, AlterID: 0,
TransportProtocol: transportProtocol, TransportProtocol: transportProtocol,
EnableTLS: enableTLS, EnableTLS: enableTLS,
Path: path, Path: path,
Host: host, Host: host,
EnableVless: c.EnableVless, EnableVless: enableVless,
VlessFlow: c.VlessFlow, VlessFlow: vlessFlow,
ServiceName: serviceName, ServiceName: serviceName,
Header: header, Header: header,
EnableREALITY: enableReality,
REALITYConfig: realityConfig,
} }
return nodeInfo, nil return nodeInfo, nil
} }

View File

@@ -11,6 +11,7 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
@@ -169,7 +170,7 @@ func (d *DefaultDispatcher) getLink(ctx context.Context, network net.Network, sn
// Speed Limit and Device Limit // Speed Limit and Device Limit
bucket, ok, reject := d.Limiter.GetUserBucket(sessionInbound.Tag, user.Email, sessionInbound.Source.Address.IP().String()) bucket, ok, reject := d.Limiter.GetUserBucket(sessionInbound.Tag, user.Email, sessionInbound.Source.Address.IP().String())
if reject { if reject {
newError("Devices reach the limit: ", user.Email).AtWarning().WriteToLog() errors.LogWarning(ctx, "Devices reach the limit: ", user.Email)
common.Close(outboundLink.Writer) common.Close(outboundLink.Writer)
common.Close(inboundLink.Writer) common.Close(inboundLink.Writer)
common.Interrupt(outboundLink.Reader) common.Interrupt(outboundLink.Reader)
@@ -217,12 +218,12 @@ func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResu
protocolString = resComp.ProtocolForDomainResult() protocolString = resComp.ProtocolForDomainResult()
} }
for _, p := range request.OverrideDestinationForProtocol { for _, p := range request.OverrideDestinationForProtocol {
if strings.HasPrefix(protocolString, p) { if strings.HasPrefix(protocolString, p) || strings.HasPrefix(p, protocolString) {
return true return true
} }
if fkr0, ok := d.fdns.(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)) errors.LogInfo(ctx, "Using sniffer ", protocolString, " since the fake DNS missed")
return true return true
} }
if resultSubset, ok := result.(SnifferIsProtoSubsetOf); ok { if resultSubset, ok := result.(SnifferIsProtoSubsetOf); ok {
@@ -240,10 +241,14 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
if !destination.IsValid() { if !destination.IsValid() {
panic("Dispatcher: Invalid destination.") panic("Dispatcher: Invalid destination.")
} }
ob := &session.Outbound{ outbounds := session.OutboundsFromContext(ctx)
Target: destination, if len(outbounds) == 0 {
outbounds = []*session.Outbound{{}}
ctx = session.ContextWithOutbounds(ctx, outbounds)
} }
ctx = session.ContextWithOutbound(ctx, ob) ob := outbounds[len(outbounds)-1]
ob.OriginalTarget = destination
ob.Target = destination
content := session.ContentFromContext(ctx) content := session.ContentFromContext(ctx)
if content == nil { if content == nil {
content = new(session.Content) content = new(session.Content)
@@ -269,7 +274,7 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
} }
if err == nil && d.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)) errors.LogInfo(ctx, "sniffed domain: ", domain)
destination.Address = net.ParseAddress(domain) destination.Address = net.ParseAddress(domain)
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" { if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
ob.RouteTarget = destination ob.RouteTarget = destination
@@ -288,10 +293,14 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
if !destination.IsValid() { if !destination.IsValid() {
return newError("Dispatcher: Invalid destination.") return newError("Dispatcher: Invalid destination.")
} }
ob := &session.Outbound{ outbounds := session.OutboundsFromContext(ctx)
Target: destination, if len(outbounds) == 0 {
outbounds = []*session.Outbound{{}}
ctx = session.ContextWithOutbounds(ctx, outbounds)
} }
ctx = session.ContextWithOutbound(ctx, ob) ob := outbounds[len(outbounds)-1]
ob.OriginalTarget = destination
ob.Target = destination
content := session.ContentFromContext(ctx) content := session.ContentFromContext(ctx)
if content == nil { if content == nil {
content = new(session.Content) content = new(session.Content)
@@ -312,7 +321,7 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
} }
if err == nil && d.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)) errors.LogInfo(ctx, "sniffed domain: ", domain)
destination.Address = net.ParseAddress(domain) destination.Address = net.ParseAddress(domain)
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" { if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
ob.RouteTarget = destination ob.RouteTarget = destination
@@ -374,7 +383,8 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
} }
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) outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1]
if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() { if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() {
proxied := hosts.LookupHosts(ob.Target.String()) proxied := hosts.LookupHosts(ob.Target.String())
if proxied != nil { if proxied != nil {
@@ -395,7 +405,7 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
// Whether the inbound connection contains a user // Whether the inbound connection contains a user
if sessionInbound.User != nil { if sessionInbound.User != nil {
if d.RuleManager.Detect(sessionInbound.Tag, destination.String(), sessionInbound.User.Email) { if d.RuleManager.Detect(sessionInbound.Tag, destination.String(), sessionInbound.User.Email) {
newError(fmt.Sprintf("User %s access %s reject by rule", sessionInbound.User.Email, destination.String())).AtError().WriteToLog() errors.LogError(ctx, fmt.Sprintf("User %s access %s reject by rule", sessionInbound.User.Email, destination.String()))
newError("destination is reject by rule") newError("destination is reject by rule")
common.Close(link.Writer) common.Close(link.Writer)
common.Interrupt(link.Reader) common.Interrupt(link.Reader)
@@ -410,10 +420,10 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
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 isPickRoute = 1
newError("taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]")
handler = h handler = h
} else { } else {
newError("non existing tag for platform initialized detour: ", forcedOutboundTag).AtError().WriteToLog(session.ExportIDToError(ctx)) errors.LogError(ctx, "non existing tag for platform initialized detour: ", forcedOutboundTag)
common.Close(link.Writer) common.Close(link.Writer)
common.Interrupt(link.Reader) common.Interrupt(link.Reader)
return return
@@ -423,13 +433,13 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
outTag := route.GetOutboundTag() outTag := route.GetOutboundTag()
if h := d.ohm.GetHandler(outTag); h != nil { if h := d.ohm.GetHandler(outTag); h != nil {
isPickRoute = 2 isPickRoute = 2
newError("taking detour [", outTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "taking detour [", outTag, "] for [", destination, "]")
handler = h handler = h
} else { } else {
newError("non existing outTag: ", outTag).AtWarning().WriteToLog(session.ExportIDToError(ctx)) errors.LogWarning(ctx, "non existing outTag: ", outTag)
} }
} else { } else {
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "default route for ", destination)
} }
} }
@@ -443,7 +453,7 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
} }
if handler == nil { if handler == nil {
newError("default outbound handler not exist").WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "default outbound handler not exist")
common.Close(link.Writer) common.Close(link.Writer)
common.Interrupt(link.Reader) common.Interrupt(link.Reader)
return return

View File

@@ -5,6 +5,7 @@ import (
"strings" "strings"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
@@ -26,11 +27,13 @@ func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error)
return protocolSnifferWithMetadata{}, errNotInit return protocolSnifferWithMetadata{}, errNotInit
} }
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) { return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
Target := session.OutboundFromContext(ctx).Target outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1]
Target := ob.Target
if Target.Network == net.Network_TCP || Target.Network == net.Network_UDP { if Target.Network == net.Network_TCP || Target.Network == net.Network_UDP {
domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(Target.Address) domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(Target.Address)
if domainFromFakeDNS != "" { if domainFromFakeDNS != "" {
newError("fake dns got domain: ", domainFromFakeDNS, " for ip: ", Target.Address.String()).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "fake dns got domain: ", domainFromFakeDNS, " for ip: ", ob.Target.Address.String())
return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil
} }
} }
@@ -107,10 +110,10 @@ func newFakeDNSThenOthers(ctx context.Context, fakeDNSSniffer protocolSnifferWit
} }
return nil, common.ErrNoClue return nil, common.ErrNoClue
} }
newError("ip address not in fake dns range, return as is").AtDebug().WriteToLog() errors.LogDebug(ctx, "ip address not in fake dns range, return as is")
return nil, common.ErrNoClue return nil, common.ErrNoClue
} }
newError("fake dns sniffer did not set address in range option, assume false.").AtWarning().WriteToLog() errors.LogWarning(ctx, "fake dns sniffer did not set address in range option, assume false.")
return nil, common.ErrNoClue return nil, common.ErrNoClue
}, },
metadataSniffer: false, metadataSniffer: false,

View File

@@ -1,9 +1,7 @@
package main package cmd
import ( import (
"flag"
"fmt" "fmt"
"log"
"os" "os"
"os/signal" "os/signal"
"path" "path"
@@ -12,36 +10,40 @@ import (
"syscall" "syscall"
"time" "time"
log "github.com/sirupsen/logrus"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/XrayR-project/XrayR/panel" "github.com/XrayR-project/XrayR/panel"
) )
var ( var (
configFile = flag.String("config", "", "Config file for XrayR.") cfgFile string
printVersion = flag.Bool("version", false, "show version") rootCmd = &cobra.Command{
Use: "XrayR",
Run: func(cmd *cobra.Command, args []string) {
if err := run(); err != nil {
log.Fatal(err)
}
},
}
) )
var ( func init() {
version = "0.9.1" rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "Config file for XrayR.")
codename = "XrayR"
intro = "A Xray backend that supports many panels"
)
func showVersion() {
fmt.Printf("%s %s (%s) \n", codename, version, intro)
} }
func getConfig() *viper.Viper { func getConfig() *viper.Viper {
config := viper.New() config := viper.New()
// Set custom path and name // Set custom path and name
if *configFile != "" { if cfgFile != "" {
configName := path.Base(*configFile) configName := path.Base(cfgFile)
configFileExt := path.Ext(*configFile) configFileExt := path.Ext(cfgFile)
configNameOnly := strings.TrimSuffix(configName, configFileExt) configNameOnly := strings.TrimSuffix(configName, configFileExt)
configPath := path.Dir(*configFile) configPath := path.Dir(cfgFile)
config.SetConfigName(configNameOnly) config.SetConfigName(configNameOnly)
config.SetConfigType(strings.TrimPrefix(configFileExt, ".")) config.SetConfigType(strings.TrimPrefix(configFileExt, "."))
config.AddConfigPath(configPath) config.AddConfigPath(configPath)
@@ -65,18 +67,19 @@ func getConfig() *viper.Viper {
return config return config
} }
func main() { func run() error {
flag.Parse()
showVersion() showVersion()
if *printVersion {
return
}
config := getConfig() config := getConfig()
panelConfig := &panel.Config{} panelConfig := &panel.Config{}
if err := config.Unmarshal(panelConfig); err != nil { if err := config.Unmarshal(panelConfig); err != nil {
log.Panicf("Parse config file %v failed: %s \n", configFile, err) return fmt.Errorf("Parse config file %v failed: %s \n", cfgFile, err)
} }
if panelConfig.LogConfig.Level == "debug" {
log.SetReportCaller(true)
}
p := panel.New(panelConfig) p := panel.New(panelConfig)
lastTime := time.Now() lastTime := time.Now()
config.OnConfigChange(func(e fsnotify.Event) { config.OnConfigChange(func(e fsnotify.Event) {
@@ -88,21 +91,31 @@ func main() {
// Delete old instance and trigger GC // Delete old instance and trigger GC
runtime.GC() runtime.GC()
if err := config.Unmarshal(panelConfig); err != nil { if err := config.Unmarshal(panelConfig); err != nil {
log.Panicf("Parse config file %v failed: %s \n", configFile, err) log.Panicf("Parse config file %v failed: %s \n", cfgFile, err)
} }
if panelConfig.LogConfig.Level == "debug" {
log.SetReportCaller(true)
}
p.Start() p.Start()
lastTime = time.Now() lastTime = time.Now()
} }
}) })
p.Start() p.Start()
defer p.Close() defer p.Close()
// Explicitly triggering GC to remove garbage from config loading. // Explicitly triggering GC to remove garbage from config loading.
runtime.GC() runtime.GC()
// Running backend // Running backend
{ osSignals := make(chan os.Signal, 1)
osSignals := make(chan os.Signal, 1) signal.Notify(osSignals, os.Interrupt, os.Kill, syscall.SIGTERM)
signal.Notify(osSignals, os.Interrupt, os.Kill, syscall.SIGTERM) <-osSignals
<-osSignals
} return nil
}
func Execute() error {
return rootCmd.Execute()
} }

27
cmd/version.go Normal file
View File

@@ -0,0 +1,27 @@
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var (
version = "0.9.5"
codename = "XrayR"
intro = "A Xray backend that supports many panels"
)
func init() {
rootCmd.AddCommand(&cobra.Command{
Use: "version",
Short: "Print current version of XrayR",
Run: func(cmd *cobra.Command, args []string) {
showVersion()
},
})
}
func showVersion() {
fmt.Printf("%s %s (%s) \n", codename, version, intro)
}

66
cmd/x25519.go Normal file
View File

@@ -0,0 +1,66 @@
package cmd
import (
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"github.com/spf13/cobra"
"golang.org/x/crypto/curve25519"
)
var (
priKey string
x25519Cmd = &cobra.Command{
Use: "x25519",
Short: "Generate key pair for x25519 key exchange",
Run: func(cmd *cobra.Command, args []string) {
if err := x25519(); err != nil {
fmt.Println(err)
}
},
}
)
func init() {
x25519Cmd.PersistentFlags().StringVarP(&priKey, "input", "i", "", "Input private key (base64.RawURLEncoding)")
rootCmd.AddCommand(x25519Cmd)
}
func x25519() error {
privateKey := make([]byte, curve25519.ScalarSize)
if priKey == "" {
if _, err := rand.Read(privateKey); err != nil {
return err
}
} else {
p, err := base64.RawURLEncoding.DecodeString(priKey)
if err != nil {
return err
}
if len(p) != curve25519.ScalarSize {
return errors.New("invalid private key")
}
privateKey = p
}
// Modify random bytes using algorithm described at:
// https://cr.yp.to/ecdh.html.
privateKey[0] &= 248
privateKey[31] &= 127
privateKey[31] |= 64
publicKey, err := curve25519.X25519(privateKey, curve25519.Basepoint)
if err != nil {
return err
}
output := fmt.Sprintf("Private key: %v\nPublic key: %v",
base64.RawURLEncoding.EncodeToString(privateKey),
base64.RawURLEncoding.EncodeToString(publicKey))
fmt.Println(output)
return nil
}

View File

@@ -1,7 +0,0 @@
package limiter
import "github.com/xtls/xray-core/common/errors"
func newError(values ...interface{}) *errors.Error {
return errors.New(values...)
}

View File

@@ -16,6 +16,7 @@ import (
redisStore "github.com/eko/gocache/store/redis/v4" redisStore "github.com/eko/gocache/store/redis/v4"
goCache "github.com/patrickmn/go-cache" goCache "github.com/patrickmn/go-cache"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"github.com/xtls/xray-core/common/errors"
"golang.org/x/time/rate" "golang.org/x/time/rate"
"github.com/XrayR-project/XrayR/api" "github.com/XrayR-project/XrayR/api"
@@ -66,7 +67,9 @@ func (l *Limiter) AddInboundLimiter(tag string, nodeSpeedLimit uint64, userList
// init redis store // init redis store
rs := redisStore.NewRedis(redis.NewClient( rs := redisStore.NewRedis(redis.NewClient(
&redis.Options{ &redis.Options{
Network: globalLimit.RedisNetwork,
Addr: globalLimit.RedisAddr, Addr: globalLimit.RedisAddr,
Username: globalLimit.RedisUsername,
Password: globalLimit.RedisPassword, Password: globalLimit.RedisPassword,
DB: globalLimit.RedisDB, DB: globalLimit.RedisDB,
}), }),
@@ -216,7 +219,7 @@ func (l *Limiter) GetUserBucket(tag string, email string, ip string) (limiter *r
return nil, false, false return nil, false, false
} }
} else { } else {
newError("Get Inbound Limiter information failed").AtDebug().WriteToLog() errors.LogDebug(context.Background(), "Get Inbound Limiter information failed")
return nil, false, false return nil, false, false
} }
} }
@@ -236,7 +239,7 @@ func globalLimit(inboundInfo *InboundInfo, email string, uid int, ip string, dev
// If the email is a new device // If the email is a new device
go pushIP(inboundInfo, uniqueKey, &map[string]int{ip: uid}) go pushIP(inboundInfo, uniqueKey, &map[string]int{ip: uid})
} else { } else {
newError("cache service").Base(err).AtError().WriteToLog() errors.LogErrorInner(context.Background(), err, "cache service")
} }
return false return false
} }
@@ -262,7 +265,7 @@ func pushIP(inboundInfo *InboundInfo, uniqueKey string, ipMap *map[string]int) {
defer cancel() defer cancel()
if err := inboundInfo.GlobalLimit.globalOnlineIP.Set(ctx, uniqueKey, ipMap); err != nil { if err := inboundInfo.GlobalLimit.globalOnlineIP.Set(ctx, uniqueKey, ipMap); err != nil {
newError("cache service").Base(err).AtError().WriteToLog() errors.LogErrorInner(context.Background(), err, "cache service")
} }
} }

View File

@@ -2,7 +2,9 @@ package limiter
type GlobalDeviceLimitConfig struct { type GlobalDeviceLimitConfig struct {
Enable bool `mapstructure:"Enable"` Enable bool `mapstructure:"Enable"`
RedisAddr string `mapstructure:"RedisAddr"` // host:port RedisNetwork string `mapstructure:"RedisNetwork"` // tcp or unix
RedisAddr string `mapstructure:"RedisAddr"` // host:port, or /path/to/unix.sock
RedisUsername string `mapstructure:"RedisUsername"`
RedisPassword string `mapstructure:"RedisPassword"` RedisPassword string `mapstructure:"RedisPassword"`
RedisDB int `mapstructure:"RedisDB"` RedisDB int `mapstructure:"RedisDB"`
Timeout int `mapstructure:"Timeout"` Timeout int `mapstructure:"Timeout"`

View File

@@ -6,12 +6,13 @@ import (
"encoding/json" "encoding/json"
"encoding/pem" "encoding/pem"
"errors" "errors"
"log"
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
log "github.com/sirupsen/logrus"
"github.com/go-acme/lego/v4/certcrypto" "github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/lego" "github.com/go-acme/lego/v4/lego"
"github.com/go-acme/lego/v4/registration" "github.com/go-acme/lego/v4/registration"

View File

@@ -4,11 +4,12 @@ import (
"bytes" "bytes"
"crypto/x509" "crypto/x509"
"encoding/json" "encoding/json"
"log"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
log "github.com/sirupsen/logrus"
"github.com/go-acme/lego/v4/certcrypto" "github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/certificate" "github.com/go-acme/lego/v4/certificate"
"golang.org/x/net/idna" "golang.org/x/net/idna"

View File

@@ -149,8 +149,8 @@ func (l *LegoCMD) RenewCert() (CertPath string, KeyPath string, ok bool, err err
} }
func checkCertFile(domain string) (string, string, error) { func checkCertFile(domain string) (string, string, error) {
keyPath := path.Join(defaultPath, "certificates", fmt.Sprintf("%s.key", domain)) keyPath := path.Join(defaultPath, "certificates", fmt.Sprintf("%s.key", sanitizedDomain(domain)))
certPath := path.Join(defaultPath, "certificates", fmt.Sprintf("%s.crt", domain)) certPath := path.Join(defaultPath, "certificates", fmt.Sprintf("%s.crt", sanitizedDomain(domain)))
if _, err := os.Stat(keyPath); os.IsNotExist(err) { if _, err := os.Stat(keyPath); os.IsNotExist(err) {
return "", "", fmt.Errorf("cert key failed: %s", domain) return "", "", fmt.Errorf("cert key failed: %s", domain)
} }

View File

@@ -3,9 +3,10 @@ package mylego
import ( import (
"crypto" "crypto"
"crypto/x509" "crypto/x509"
"log"
"time" "time"
log "github.com/sirupsen/logrus"
"github.com/go-acme/lego/v4/certcrypto" "github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/certificate" "github.com/go-acme/lego/v4/certificate"
"github.com/go-acme/lego/v4/lego" "github.com/go-acme/lego/v4/lego"

View File

@@ -2,11 +2,11 @@ package mylego
import ( import (
"fmt" "fmt"
"log"
"github.com/go-acme/lego/v4/certificate" "github.com/go-acme/lego/v4/certificate"
"github.com/go-acme/lego/v4/lego" "github.com/go-acme/lego/v4/lego"
"github.com/go-acme/lego/v4/registration" "github.com/go-acme/lego/v4/registration"
log "github.com/sirupsen/logrus"
) )
const rootPathWarningMessage = `!!!! HEADS UP !!!! const rootPathWarningMessage = `!!!! HEADS UP !!!!

View File

@@ -1,10 +1,11 @@
package mylego package mylego
import ( import (
"log"
"os" "os"
"time" "time"
log "github.com/sirupsen/logrus"
"github.com/go-acme/lego/v4/certcrypto" "github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/challenge/dns01" "github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/challenge/http01" "github.com/go-acme/lego/v4/challenge/http01"

View File

@@ -1,7 +0,0 @@
package rule
import "github.com/xtls/xray-core/common/errors"
func newError(values ...interface{}) *errors.Error {
return errors.New(values...)
}

View File

@@ -2,6 +2,7 @@
package rule package rule
import ( import (
"context"
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
@@ -9,6 +10,7 @@ import (
"sync" "sync"
mapset "github.com/deckarep/golang-set" mapset "github.com/deckarep/golang-set"
"github.com/xtls/xray-core/common/errors"
"github.com/XrayR-project/XrayR/api" "github.com/XrayR-project/XrayR/api"
) )
@@ -65,7 +67,7 @@ func (r *Manager) Detect(tag string, destination string, email string) (reject b
l := strings.Split(email, "|") l := strings.Split(email, "|")
uid, err := strconv.Atoi(l[len(l)-1]) uid, err := strconv.Atoi(l[len(l)-1])
if err != nil { if err != nil {
newError(fmt.Sprintf("Record illegal behavior failed! Cannot find user's uid: %s", email)).AtDebug().WriteToLog() errors.LogDebug(context.Background(), fmt.Sprintf("Record illegal behavior failed! Cannot find user's uid: %s", email))
return reject return reject
} }
newSet := mapset.NewSetWith(api.DetectResult{UID: uid, RuleID: hitRuleID}) newSet := mapset.NewSetWith(api.DetectResult{UID: uid, RuleID: hitRuleID})

359
go.mod
View File

@@ -1,136 +1,184 @@
module github.com/XrayR-project/XrayR module github.com/XrayR-project/XrayR
go 1.21 go 1.22.0
toolchain go1.21.1
require ( require (
dario.cat/mergo v1.0.0 dario.cat/mergo v1.0.0
github.com/bitly/go-simplejson v0.5.1 github.com/bitly/go-simplejson v0.5.1
github.com/deckarep/golang-set v1.8.0 github.com/deckarep/golang-set v1.8.0
github.com/eko/gocache/lib/v4 v4.1.5 github.com/eko/gocache/lib/v4 v4.1.6
github.com/eko/gocache/store/go_cache/v4 v4.2.1 github.com/eko/gocache/store/go_cache/v4 v4.2.2
github.com/eko/gocache/store/redis/v4 v4.2.1 github.com/eko/gocache/store/redis/v4 v4.2.1
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.7.0
github.com/go-acme/lego/v4 v4.14.2 github.com/go-acme/lego/v4 v4.16.1
github.com/go-resty/resty/v2 v2.9.1 github.com/go-resty/resty/v2 v2.13.1
github.com/gogf/gf/v2 v2.5.4 github.com/gogf/gf/v2 v2.7.0
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/r3labs/diff/v2 v2.15.1 github.com/r3labs/diff/v2 v2.15.1
github.com/redis/go-redis/v9 v9.2.1 github.com/redis/go-redis/v9 v9.7.0
github.com/sagernet/sing v0.2.13 github.com/sagernet/sing v0.5.1
github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks v0.2.7
github.com/shirou/gopsutil/v3 v3.23.9 github.com/shirou/gopsutil/v3 v3.24.5
github.com/spf13/viper v1.17.0 github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.4 github.com/spf13/cobra v1.8.1
github.com/xtls/xray-core v1.8.4 github.com/spf13/viper v1.18.2
golang.org/x/crypto v0.14.0 github.com/stretchr/testify v1.9.0
golang.org/x/net v0.16.0 github.com/xtls/xray-core v1.8.20
golang.org/x/time v0.3.0 golang.org/x/crypto v0.28.0
google.golang.org/protobuf v1.31.0 golang.org/x/net v0.27.0
golang.org/x/time v0.7.0
google.golang.org/protobuf v1.34.2
) )
require ( require (
cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0 // 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.29 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // 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/logger v0.2.1 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect
github.com/CloudyKit/jet/v6 v6.2.0 // indirect
github.com/Joker/jade v1.1.3 // indirect
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 // indirect
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755 // indirect github.com/aliyun/alibaba-cloud-sdk-go v1.62.695 // indirect
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/andybalholm/brotli v1.1.0 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.19.0 // indirect github.com/aws/aws-sdk-go-v2 v1.25.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.18.28 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.7 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.27 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.7 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect
github.com/aws/aws-sdk-go-v2/service/lightsail v1.27.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.28.4 // indirect github.com/aws/aws-sdk-go-v2/service/lightsail v1.36.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 // indirect github.com/aws/aws-sdk-go-v2/service/route53 v1.40.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 // indirect
github.com/aws/smithy-go v1.13.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 // indirect
github.com/aws/smithy-go v1.20.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/boombuler/barcode v1.0.1 // indirect
github.com/bytedance/sonic v1.11.3 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/civo/civogo v0.3.11 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/cloudflare/cloudflare-go v0.70.0 // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/civo/civogo v0.3.63 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/cloudflare/circl v1.3.9 // indirect
github.com/cloudflare/cloudflare-go v0.90.0 // indirect
github.com/cpu/goacmedns v0.1.1 // indirect github.com/cpu/goacmedns v0.1.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/deepmap/oapi-codegen v1.9.1 // indirect github.com/deepmap/oapi-codegen v1.16.2 // 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/dnsimple/dnsimple-go v1.2.0 // indirect github.com/dnsimple/dnsimple-go v1.7.0 // indirect
github.com/exoscale/egoscale v0.100.1 // indirect github.com/exoscale/egoscale v1.19.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fatih/structs v1.1.0 // indirect github.com/fatih/structs v1.1.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/flosch/pongo2/v4 v4.0.2 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect github.com/francoispqt/gojay v1.2.13 // indirect
github.com/gaukas/godicttls v0.0.4 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 // indirect github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 // indirect
github.com/go-errors/errors v1.0.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-errors/errors v1.5.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.19.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect github.com/golang/mock v1.7.0-rc.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 // indirect
github.com/google/btree v1.1.2 // indirect github.com/google/btree v1.1.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
github.com/google/s2a-go v0.1.7 // indirect github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.3.1 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/googleapis/gax-go/v2 v2.12.3 // indirect
github.com/gophercloud/gophercloud v1.0.0 // indirect github.com/gophercloud/gophercloud v1.11.0 // indirect
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
github.com/gorilla/websocket v1.5.0 // indirect github.com/gorilla/css v1.0.1 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect
github.com/grokify/html-strip-tags-go v0.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-uuid v1.0.3 // 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/inconshreveable/mousetrap v1.1.0 // indirect
github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect
github.com/iris-contrib/schema v0.0.6 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.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/klauspost/compress v1.17.0 // indirect github.com/kataras/blocks v0.0.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kataras/golog v0.1.11 // indirect
github.com/kataras/iris/v12 v12.2.10 // indirect
github.com/kataras/pio v0.0.13 // indirect
github.com/kataras/sitemap v0.0.6 // indirect
github.com/kataras/tunnel v0.0.4 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
github.com/kylelemons/godebug v1.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // 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.17.2 // indirect github.com/labstack/echo/v4 v4.11.4 // indirect
github.com/liquidweb/go-lwApi v0.0.5 // indirect github.com/labstack/gommon v0.4.2 // indirect
github.com/liquidweb/liquidweb-cli v0.6.9 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/liquidweb/liquidweb-go v1.6.3 // indirect github.com/linode/linodego v1.30.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
github.com/liquidweb/liquidweb-go v1.6.4 // indirect
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mailgun/raymond/v2 v2.0.48 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/miekg/dns v1.1.55 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/microcosm-cc/bluemonday v1.0.26 // indirect
github.com/miekg/dns v1.1.61 // indirect
github.com/mimuret/golang-iij-dpf v0.9.1 // indirect github.com/mimuret/golang-iij-dpf v0.9.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.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -138,95 +186,124 @@ require (
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
github.com/nrdcg/auroradns v1.1.0 // indirect github.com/nrdcg/auroradns v1.1.0 // indirect
github.com/nrdcg/bunny-go v0.0.0-20230728143221-c9dda82568d9 // indirect github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 // indirect
github.com/nrdcg/desec v0.7.0 // indirect github.com/nrdcg/desec v0.7.0 // indirect
github.com/nrdcg/dnspod-go v0.4.0 // indirect github.com/nrdcg/dnspod-go v0.4.0 // indirect
github.com/nrdcg/freemyip v0.2.0 // indirect github.com/nrdcg/freemyip v0.2.0 // indirect
github.com/nrdcg/goinwx v0.8.2 // indirect github.com/nrdcg/goinwx v0.10.0 // indirect
github.com/nrdcg/mailinabox v0.2.0 // indirect
github.com/nrdcg/namesilo v0.2.1 // indirect github.com/nrdcg/namesilo v0.2.1 // indirect
github.com/nrdcg/nodion v0.1.0 // indirect github.com/nrdcg/nodion v0.1.0 // indirect
github.com/nrdcg/porkbun v0.2.0 // indirect github.com/nrdcg/porkbun v0.3.0 // indirect
github.com/nzdjb/go-metaname v1.0.0 // indirect github.com/nzdjb/go-metaname v1.0.0 // indirect
github.com/onsi/ginkgo/v2 v2.12.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect
github.com/ovh/go-ovh v1.4.2 // indirect github.com/ovh/go-ovh v1.4.3 // 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.1.0 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pires/go-proxyproto v0.7.0 // indirect github.com/pires/go-proxyproto v0.7.0 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/pquerna/otp v1.4.0 // indirect github.com/pquerna/otp v1.4.0 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/client_model v0.6.0 // indirect
github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/common v0.50.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect github.com/prometheus/procfs v0.13.0 // indirect
github.com/quic-go/qtls-go1-20 v0.3.3 // indirect github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/quic-go v0.38.1 // indirect github.com/quic-go/quic-go v0.45.1 // indirect
github.com/refraction-networking/utls v1.4.3 // indirect github.com/refraction-networking/utls v1.6.7 // 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/sacloud/api-client-go v0.2.8 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/sacloud/go-http v0.1.6 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sacloud/iaas-api-go v1.11.1 // indirect github.com/sacloud/api-client-go v0.2.10 // indirect
github.com/sacloud/packages-go v0.0.9 // indirect github.com/sacloud/go-http v0.1.8 // indirect
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c // indirect github.com/sacloud/iaas-api-go v1.11.2 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sacloud/packages-go v0.0.10 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.17 // indirect github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25 // indirect
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect github.com/shopspring/decimal v1.3.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.1.2 // indirect github.com/softlayer/softlayer-go v1.1.3 // indirect
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.10.0 // indirect github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.5.1 // indirect github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.0 // indirect github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect github.com/tdewolff/minify/v2 v2.20.19 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 // indirect github.com/tdewolff/parse/v2 v2.7.12 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.878 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.878 // indirect
github.com/transip/gotransip/v6 v6.20.0 // indirect github.com/tklauser/go-sysconf v0.3.13 // indirect
github.com/ultradns/ultradns-go-sdk v1.5.0-20230427130837-23c9b0c // indirect github.com/tklauser/numcpus v0.7.0 // indirect
github.com/transip/gotransip/v6 v6.23.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/ultradns/ultradns-go-sdk v1.6.1-20231103022937-8589b6a // 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/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/vinyldns/go-vinyldns v0.9.16 // indirect github.com/vinyldns/go-vinyldns v0.9.16 // indirect
github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/vultr/govultr/v2 v2.17.2 // indirect github.com/vultr/govultr/v2 v2.17.2 // indirect
github.com/xtls/reality v0.0.0-20230828171259-e426190d57f6 // indirect github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d // indirect
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f // indirect github.com/yandex-cloud/go-genproto v0.0.0-20240311082839-58e1a7554a75 // indirect
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997 // indirect github.com/yandex-cloud/go-sdk v0.0.0-20240311083148-81c0846b96cd // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/yosssi/ace v0.0.5 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.22.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.9.0 // indirect go.uber.org/mock v0.4.0 // indirect
go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect go.uber.org/ratelimit v0.3.1 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/mod v0.12.0 // indirect golang.org/x/arch v0.7.0 // indirect
golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
golang.org/x/sys v0.13.0 // indirect golang.org/x/mod v0.18.0 // indirect
golang.org/x/text v0.13.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect
golang.org/x/tools v0.13.0 // indirect golang.org/x/sync v0.8.0 // indirect
google.golang.org/api v0.143.0 // indirect golang.org/x/sys v0.26.0 // indirect
google.golang.org/appengine v1.6.7 // indirect golang.org/x/text v0.19.0 // indirect
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect golang.org/x/tools v0.22.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
google.golang.org/grpc v1.58.2 // indirect google.golang.org/api v0.170.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240314234333-6e1732d8331c // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/grpc v1.65.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/ns1/ns1-go.v2 v2.7.6 // indirect gopkg.in/ns1/ns1-go.v2 v2.9.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
gvisor.dev/gvisor v0.0.0-20230822212503-5bf4e5f98744 // indirect gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect
lukechampine.com/blake3 v1.2.1 // indirect k8s.io/api v0.29.2 // indirect
k8s.io/apimachinery v0.29.2 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
) )
replace github.com/exoscale/egoscale => github.com/exoscale/egoscale v0.102.0 replace github.com/exoscale/egoscale => github.com/exoscale/egoscale v0.102.3

1941
go.sum

File diff suppressed because it is too large Load Diff

13
main.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import (
log "github.com/sirupsen/logrus"
"github.com/XrayR-project/XrayR/cmd"
)
func main() {
if err := cmd.Execute(); err != nil {
log.Fatal(err)
}
}

View File

@@ -2,16 +2,12 @@ package panel
import ( import (
"encoding/json" "encoding/json"
"log"
"os" "os"
"sync" "sync"
"github.com/XrayR-project/XrayR/api/gov2panel"
"github.com/XrayR-project/XrayR/api/newV2board"
"github.com/XrayR-project/XrayR/app/mydispatcher"
"dario.cat/mergo" "dario.cat/mergo"
"github.com/r3labs/diff/v2" "github.com/r3labs/diff/v2"
log "github.com/sirupsen/logrus"
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
@@ -19,11 +15,15 @@ import (
"github.com/xtls/xray-core/infra/conf" "github.com/xtls/xray-core/infra/conf"
"github.com/XrayR-project/XrayR/api" "github.com/XrayR-project/XrayR/api"
"github.com/XrayR-project/XrayR/api/bunpanel"
"github.com/XrayR-project/XrayR/api/gov2panel"
"github.com/XrayR-project/XrayR/api/newV2board"
"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/v2raysocks" "github.com/XrayR-project/XrayR/api/v2raysocks"
_ "github.com/XrayR-project/XrayR/main/distro/all" "github.com/XrayR-project/XrayR/app/mydispatcher"
_ "github.com/XrayR-project/XrayR/cmd/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"
) )
@@ -154,7 +154,6 @@ func (p *Panel) loadCore(panelConfig *Config) *core.Instance {
if err != nil { if err != nil {
log.Panicf("failed to create instance: %s", err) log.Panicf("failed to create instance: %s", err)
} }
log.Printf("Xray Core Version: %s", core.Version())
return server return server
} }
@@ -177,7 +176,7 @@ func (p *Panel) Start() {
switch nodeConfig.PanelType { switch nodeConfig.PanelType {
case "SSpanel": case "SSpanel":
apiClient = sspanel.New(nodeConfig.ApiConfig) apiClient = sspanel.New(nodeConfig.ApiConfig)
case "NewV2board": case "NewV2board", "V2board":
apiClient = newV2board.New(nodeConfig.ApiConfig) apiClient = newV2board.New(nodeConfig.ApiConfig)
case "PMpanel": case "PMpanel":
apiClient = pmpanel.New(nodeConfig.ApiConfig) apiClient = pmpanel.New(nodeConfig.ApiConfig)
@@ -187,6 +186,8 @@ func (p *Panel) Start() {
apiClient = v2raysocks.New(nodeConfig.ApiConfig) apiClient = v2raysocks.New(nodeConfig.ApiConfig)
case "GoV2Panel": case "GoV2Panel":
apiClient = gov2panel.New(nodeConfig.ApiConfig) apiClient = gov2panel.New(nodeConfig.ApiConfig)
case "BunPanel":
apiClient = bunpanel.New(nodeConfig.ApiConfig)
default: default:
log.Panicf("Unsupport panel type: %s", nodeConfig.PanelType) log.Panicf("Unsupport panel type: %s", nodeConfig.PanelType)
} }
@@ -207,7 +208,7 @@ func (p *Panel) Start() {
for _, s := range p.Service { for _, s := range p.Service {
err := s.Start() err := s.Start()
if err != nil { if err != nil {
log.Panicf("Panel Start fialed: %s", err) log.Panicf("Panel Start failed: %s", err)
} }
} }
p.Running = true p.Running = true
@@ -221,7 +222,7 @@ func (p *Panel) Close() {
for _, s := range p.Service { for _, s := range p.Service {
err := s.Close() err := s.Close()
if err != nil { if err != nil {
log.Panicf("Panel Close fialed: %s", err) log.Panicf("Panel Close failed: %s", err)
} }
} }
p.Service = nil p.Service = nil

View File

@@ -1,5 +1,5 @@
Log: Log:
Level: warning # Log level: none, error, warning, info, debug Level: warning # Log level: none, error, warning, info, debug
AccessPath: # /etc/XrayR/access.Log AccessPath: # /etc/XrayR/access.Log
ErrorPath: # /etc/XrayR/error.log ErrorPath: # /etc/XrayR/error.log
DnsConfigPath: # /etc/XrayR/dns.json # Path to dns config, check https://xtls.github.io/config/dns.html for help DnsConfigPath: # /etc/XrayR/dns.json # Path to dns config, check https://xtls.github.io/config/dns.html for help
@@ -13,12 +13,12 @@ ConnectionConfig:
DownlinkOnly: 4 # Time limit when the connection is closed after the uplink is closed, Second DownlinkOnly: 4 # Time limit when the connection is closed after the uplink is closed, Second
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, NewV2board, PMpanel, Proxypanel, V2RaySocks, GoV2Panel - PanelType: "SSpanel" # Panel type: SSpanel, NewV2board, PMpanel, Proxypanel, V2RaySocks, GoV2Panel, BunPanel
ApiConfig: ApiConfig:
ApiHost: "http://127.0.0.1:667" ApiHost: "http://127.0.0.1:667"
ApiKey: "123" ApiKey: "123"
NodeID: 41 NodeID: 41
NodeType: V2ray # Node type: V2ray, Shadowsocks, Trojan, Shadowsocks-Plugin NodeType: V2ray # Node type: V2ray, Vmess, Vless, Shadowsocks, Trojan, Shadowsocks-Plugin
Timeout: 30 # Timeout for the api request Timeout: 30 # Timeout for the api request
EnableVless: false # Enable Vless for V2ray Type EnableVless: false # Enable Vless for V2ray Type
VlessFlow: "xtls-rprx-vision" # Only support vless VlessFlow: "xtls-rprx-vision" # Only support vless
@@ -40,7 +40,9 @@ Nodes:
LimitDuration: 0 # How many minutes will the limiting last (unit: minute) LimitDuration: 0 # How many minutes will the limiting last (unit: minute)
GlobalDeviceLimitConfig: GlobalDeviceLimitConfig:
Enable: false # Enable the global device limit of a user Enable: false # Enable the global device limit of a user
RedisAddr: 127.0.0.1:6379 # The redis server address RedisNetwork: tcp # Redis protocol, tcp or unix
RedisAddr: 127.0.0.1:6379 # Redis server address, or unix socket path
RedisUsername: # Redis username
RedisPassword: YOUR PASSWORD # Redis password RedisPassword: YOUR PASSWORD # Redis password
RedisDB: 0 # Redis DB RedisDB: 0 # Redis DB
Timeout: 5 # Timeout for redis request Timeout: 5 # Timeout for redis request
@@ -53,14 +55,14 @@ Nodes:
Dest: 80 # Required, Destination of fallback, check https://xtls.github.io/config/features/fallback.html for details. Dest: 80 # Required, Destination of fallback, check https://xtls.github.io/config/features/fallback.html for details.
ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for disable ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for disable
DisableLocalREALITYConfig: false # disable local reality config DisableLocalREALITYConfig: false # disable local reality config
EnableREALITY: true # Enable REALITY EnableREALITY: false # Enable REALITY
REALITYConfigs: REALITYConfigs:
Show: true # Show REALITY debug Show: true # Show REALITY debug
Dest: www.smzdm.com:443 # Required, Same as fallback Dest: www.amazon.com:443 # Required, Same as fallback
ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for disable ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for disable
ServerNames: # Required, list of available serverNames for the client, * wildcard is not supported at the moment. ServerNames: # Required, list of available serverNames for the client, * wildcard is not supported at the moment.
- www.smzdm.com - www.amazon.com
PrivateKey: YOUR_PRIVATE_KEY # Required, execute './xray x25519' to generate. PrivateKey: YOUR_PRIVATE_KEY # Required, execute './XrayR x25519' to generate.
MinClientVer: # Optional, minimum version of Xray client, format is x.y.z. MinClientVer: # Optional, minimum version of Xray client, format is x.y.z.
MaxClientVer: # Optional, maximum version of Xray client, format is x.y.z. MaxClientVer: # Optional, maximum version of Xray client, format is x.y.z.
MaxTimeDiff: 0 # Optional, maximum allowed time difference, unit is in milliseconds. MaxTimeDiff: 0 # Optional, maximum allowed time difference, unit is in milliseconds.
@@ -119,11 +121,11 @@ Nodes:
# EnableREALITY: true # Enable REALITY # EnableREALITY: true # Enable REALITY
# REALITYConfigs: # REALITYConfigs:
# Show: true # Show REALITY debug # Show: true # Show REALITY debug
# Dest: www.smzdm.com:443 # Required, Same as fallback # Dest: www.amazon.com:443 # Required, Same as fallback
# ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for disable # ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for disable
# ServerNames: # Required, list of available serverNames for the client, * wildcard is not supported at the moment. # ServerNames: # Required, list of available serverNames for the client, * wildcard is not supported at the moment.
# - www.smzdm.com # - www.amazon.com
# PrivateKey: YOUR_PRIVATE_KEY # Required, execute './xray x25519' to generate. # PrivateKey: YOUR_PRIVATE_KEY # Required, execute './XrayR x25519' to generate.
# MinClientVer: # Optional, minimum version of Xray client, format is x.y.z. # MinClientVer: # Optional, minimum version of Xray client, format is x.y.z.
# MaxClientVer: # Optional, maximum version of Xray client, format is x.y.z. # MaxClientVer: # Optional, maximum version of Xray client, format is x.y.z.
# MaxTimeDiff: 0 # Optional, maximum allowed time difference, unit is in milliseconds. # MaxTimeDiff: 0 # Optional, maximum allowed time difference, unit is in milliseconds.

View File

@@ -1,6 +1,6 @@
[ [
{ {
"listen": "0.0.0.0", "listen": "127.0.0.1",
"port": 1234, "port": 1234,
"protocol": "socks", "protocol": "socks",
"settings": { "settings": {

View File

@@ -3,10 +3,10 @@ package controller
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"reflect" "reflect"
"time" "time"
log "github.com/sirupsen/logrus"
"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"
@@ -44,6 +44,7 @@ type Controller struct {
stm stats.Manager stm stats.Manager
dispatcher *mydispatcher.DefaultDispatcher dispatcher *mydispatcher.DefaultDispatcher
startAt time.Time startAt time.Time
logger *log.Entry
} }
type periodicTask struct { type periodicTask struct {
@@ -53,6 +54,11 @@ type periodicTask struct {
// 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 {
logger := log.NewEntry(log.StandardLogger()).WithFields(log.Fields{
"Host": api.Describe().APIHost,
"Type": api.Describe().NodeType,
"ID": api.Describe().NodeID,
})
controller := &Controller{ controller := &Controller{
server: server, server: server,
config: config, config: config,
@@ -63,6 +69,7 @@ func New(server *core.Instance, api api.API, config *Config, panelType string) *
stm: server.GetFeature(stats.ManagerType()).(stats.Manager), stm: server.GetFeature(stats.ManagerType()).(stats.Manager),
dispatcher: server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher), dispatcher: server.GetFeature(routing.DispatcherType()).(*mydispatcher.DefaultDispatcher),
startAt: time.Now(), startAt: time.Now(),
logger: logger,
} }
return controller return controller
@@ -85,7 +92,7 @@ func (c *Controller) Start() error {
// Add new tag // Add new tag
err = c.addNewTag(newNodeInfo) err = c.addNewTag(newNodeInfo)
if err != nil { if err != nil {
log.Panic(err) c.logger.Panic(err)
return err return err
} }
// Update user // Update user
@@ -104,16 +111,16 @@ func (c *Controller) Start() error {
// Add Limiter // Add Limiter
if err := c.AddInboundLimiter(c.Tag, newNodeInfo.SpeedLimit, userInfo, c.config.GlobalDeviceLimitConfig); err != nil { if err := c.AddInboundLimiter(c.Tag, newNodeInfo.SpeedLimit, userInfo, c.config.GlobalDeviceLimitConfig); err != nil {
log.Print(err) c.logger.Print(err)
} }
// Add Rule Manager // Add Rule Manager
if !c.config.DisableGetRule { if !c.config.DisableGetRule {
if ruleList, err := c.apiClient.GetNodeRule(); err != nil { if ruleList, err := c.apiClient.GetNodeRule(); err != nil {
log.Printf("Get rule list filed: %s", err) c.logger.Printf("Get rule list filed: %s", err)
} else if len(*ruleList) > 0 { } else if len(*ruleList) > 0 {
if err := c.UpdateRule(c.Tag, *ruleList); err != nil { if err := c.UpdateRule(c.Tag, *ruleList); err != nil {
log.Print(err) c.logger.Print(err)
} }
} }
} }
@@ -155,7 +162,7 @@ func (c *Controller) Start() error {
// Start periodic tasks // Start periodic tasks
for i := range c.tasks { for i := range c.tasks {
log.Printf("%s Start %s periodic task", c.logPrefix(), c.tasks[i].tag) c.logger.Printf("Start %s periodic task", c.tasks[i].tag)
go c.tasks[i].Start() go c.tasks[i].Start()
} }
@@ -167,7 +174,7 @@ func (c *Controller) Close() error {
for i := range c.tasks { for i := range c.tasks {
if c.tasks[i].Periodic != nil { if c.tasks[i].Periodic != nil {
if err := c.tasks[i].Periodic.Close(); err != nil { if err := c.tasks[i].Periodic.Close(); err != nil {
log.Panicf("%s %s periodic task close failed: %s", c.logPrefix(), c.tasks[i].tag, err) c.logger.Panicf("%s periodic task close failed: %s", c.tasks[i].tag, err)
} }
} }
} }
@@ -189,7 +196,7 @@ func (c *Controller) nodeInfoMonitor() (err error) {
nodeInfoChanged = false nodeInfoChanged = false
newNodeInfo = c.nodeInfo newNodeInfo = c.nodeInfo
} else { } else {
log.Print(err) c.logger.Print(err)
return nil return nil
} }
} }
@@ -205,7 +212,7 @@ func (c *Controller) nodeInfoMonitor() (err error) {
usersChanged = false usersChanged = false
newUserInfo = c.userList newUserInfo = c.userList
} else { } else {
log.Print(err) c.logger.Print(err)
return nil return nil
} }
} }
@@ -217,14 +224,14 @@ func (c *Controller) nodeInfoMonitor() (err error) {
oldTag := c.Tag oldTag := c.Tag
err := c.removeOldTag(oldTag) err := c.removeOldTag(oldTag)
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
return nil return nil
} }
if c.nodeInfo.NodeType == "Shadowsocks-Plugin" { if c.nodeInfo.NodeType == "Shadowsocks-Plugin" {
err = c.removeOldTag(fmt.Sprintf("dokodemo-door_%s+1", c.Tag)) err = c.removeOldTag(fmt.Sprintf("dokodemo-door_%s+1", c.Tag))
} }
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
return nil return nil
} }
// Add new tag // Add new tag
@@ -232,13 +239,13 @@ func (c *Controller) nodeInfoMonitor() (err error) {
c.Tag = c.buildNodeTag() c.Tag = c.buildNodeTag()
err = c.addNewTag(newNodeInfo) err = c.addNewTag(newNodeInfo)
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
return nil return nil
} }
nodeInfoChanged = true nodeInfoChanged = true
// Remove Old limiter // Remove Old limiter
if err = c.DeleteInboundLimiter(oldTag); err != nil { if err = c.DeleteInboundLimiter(oldTag); err != nil {
log.Print(err) c.logger.Print(err)
return nil return nil
} }
} else { } else {
@@ -250,11 +257,11 @@ func (c *Controller) nodeInfoMonitor() (err error) {
if !c.config.DisableGetRule { if !c.config.DisableGetRule {
if ruleList, err := c.apiClient.GetNodeRule(); err != nil { if ruleList, err := c.apiClient.GetNodeRule(); err != nil {
if err.Error() != api.RuleNotModified { if err.Error() != api.RuleNotModified {
log.Printf("Get rule list filed: %s", err) c.logger.Printf("Get rule list filed: %s", err)
} }
} else if len(*ruleList) > 0 { } else if len(*ruleList) > 0 {
if err := c.UpdateRule(c.Tag, *ruleList); err != nil { if err := c.UpdateRule(c.Tag, *ruleList); err != nil {
log.Print(err) c.logger.Print(err)
} }
} }
} }
@@ -262,13 +269,13 @@ func (c *Controller) nodeInfoMonitor() (err error) {
if nodeInfoChanged { if nodeInfoChanged {
err = c.addNewUser(newUserInfo, newNodeInfo) err = c.addNewUser(newUserInfo, newNodeInfo)
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
return nil return nil
} }
// Add Limiter // Add Limiter
if err := c.AddInboundLimiter(c.Tag, newNodeInfo.SpeedLimit, newUserInfo, c.config.GlobalDeviceLimitConfig); err != nil { if err := c.AddInboundLimiter(c.Tag, newNodeInfo.SpeedLimit, newUserInfo, c.config.GlobalDeviceLimitConfig); err != nil {
log.Print(err) c.logger.Print(err)
return nil return nil
} }
@@ -283,21 +290,21 @@ func (c *Controller) nodeInfoMonitor() (err error) {
} }
err := c.removeUsers(deletedEmail, c.Tag) err := c.removeUsers(deletedEmail, c.Tag)
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
} }
} }
if len(added) > 0 { if len(added) > 0 {
err = c.addNewUser(&added, c.nodeInfo) err = c.addNewUser(&added, c.nodeInfo)
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
} }
// Update Limiter // Update Limiter
if err := c.UpdateInboundLimiter(c.Tag, &added); err != nil { if err := c.UpdateInboundLimiter(c.Tag, &added); err != nil {
log.Print(err) c.logger.Print(err)
} }
} }
} }
log.Printf("%s %d user deleted, %d user added", c.logPrefix(), len(deleted), len(added)) c.logger.Printf("%d user deleted, %d user added", len(deleted), len(added))
} }
c.userList = newUserInfo c.userList = newUserInfo
return nil return nil
@@ -398,8 +405,8 @@ func (c *Controller) addInboundForSSPlugin(newNodeInfo api.NodeInfo) (err error)
func (c *Controller) addNewUser(userInfo *[]api.UserInfo, nodeInfo *api.NodeInfo) (err error) { func (c *Controller) addNewUser(userInfo *[]api.UserInfo, nodeInfo *api.NodeInfo) (err error) {
users := make([]*protocol.User, 0) users := make([]*protocol.User, 0)
switch nodeInfo.NodeType { switch nodeInfo.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
if nodeInfo.EnableVless { if nodeInfo.EnableVless || (nodeInfo.NodeType == "Vless" && nodeInfo.NodeType != "Vmess") {
users = c.buildVlessUser(userInfo) users = c.buildVlessUser(userInfo)
} else { } else {
users = c.buildVmessUser(userInfo) users = c.buildVmessUser(userInfo)
@@ -418,7 +425,7 @@ func (c *Controller) addNewUser(userInfo *[]api.UserInfo, nodeInfo *api.NodeInfo
if err != nil { if err != nil {
return err return err
} }
log.Printf("%s Added %d new users", c.logPrefix(), len(*userInfo)) c.logger.Printf("Added %d new users", len(*userInfo))
return nil return nil
} }
@@ -466,7 +473,7 @@ func limitUser(c *Controller, user api.UserInfo, silentUsers *[]api.UserInfo) {
currentSpeedLimit: c.config.AutoSpeedLimitConfig.LimitSpeed, currentSpeedLimit: c.config.AutoSpeedLimitConfig.LimitSpeed,
originSpeedLimit: user.SpeedLimit, originSpeedLimit: user.SpeedLimit,
} }
log.Printf("Limit User: %s Speed: %d End: %s", c.buildUserTag(&user), c.config.AutoSpeedLimitConfig.LimitSpeed, time.Unix(c.limitedUsers[user].end, 0).Format("01-02 15:04:05")) c.logger.Printf("Limit User: %s Speed: %d End: %s", c.buildUserTag(&user), c.config.AutoSpeedLimitConfig.LimitSpeed, time.Unix(c.limitedUsers[user].end, 0).Format("01-02 15:04:05"))
user.SpeedLimit = uint64((c.config.AutoSpeedLimitConfig.LimitSpeed * 1000000) / 8) user.SpeedLimit = uint64((c.config.AutoSpeedLimitConfig.LimitSpeed * 1000000) / 8)
*silentUsers = append(*silentUsers, user) *silentUsers = append(*silentUsers, user)
} }
@@ -480,7 +487,7 @@ func (c *Controller) userInfoMonitor() (err error) {
// Get server status // Get server status
CPU, Mem, Disk, Uptime, err := serverstatus.GetSystemInfo() CPU, Mem, Disk, Uptime, err := serverstatus.GetSystemInfo()
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
} }
err = c.apiClient.ReportNodeStatus( err = c.apiClient.ReportNodeStatus(
&api.NodeStatus{ &api.NodeStatus{
@@ -490,25 +497,25 @@ func (c *Controller) userInfoMonitor() (err error) {
Uptime: Uptime, Uptime: Uptime,
}) })
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
} }
// Unlock users // Unlock users
if c.config.AutoSpeedLimitConfig.Limit > 0 && len(c.limitedUsers) > 0 { if c.config.AutoSpeedLimitConfig.Limit > 0 && len(c.limitedUsers) > 0 {
log.Printf("%s Limited users:", c.logPrefix()) c.logger.Printf("Limited users:")
toReleaseUsers := make([]api.UserInfo, 0) toReleaseUsers := make([]api.UserInfo, 0)
for user, limitInfo := range c.limitedUsers { for user, limitInfo := range c.limitedUsers {
if time.Now().Unix() > limitInfo.end { if time.Now().Unix() > limitInfo.end {
user.SpeedLimit = limitInfo.originSpeedLimit user.SpeedLimit = limitInfo.originSpeedLimit
toReleaseUsers = append(toReleaseUsers, user) toReleaseUsers = append(toReleaseUsers, user)
log.Printf("User: %s Speed: %d End: nil (Unlimit)", c.buildUserTag(&user), user.SpeedLimit) c.logger.Printf("User: %s Speed: %d End: nil (Unlimit)", c.buildUserTag(&user), user.SpeedLimit)
delete(c.limitedUsers, user) delete(c.limitedUsers, user)
} else { } else {
log.Printf("User: %s Speed: %d End: %s", c.buildUserTag(&user), limitInfo.currentSpeedLimit, time.Unix(c.limitedUsers[user].end, 0).Format("01-02 15:04:05")) c.logger.Printf("User: %s Speed: %d End: %s", c.buildUserTag(&user), limitInfo.currentSpeedLimit, time.Unix(c.limitedUsers[user].end, 0).Format("01-02 15:04:05"))
} }
} }
if len(toReleaseUsers) > 0 { if len(toReleaseUsers) > 0 {
if err := c.UpdateInboundLimiter(c.Tag, &toReleaseUsers); err != nil { if err := c.UpdateInboundLimiter(c.Tag, &toReleaseUsers); err != nil {
log.Print(err) c.logger.Print(err)
} }
} }
} }
@@ -559,7 +566,7 @@ func (c *Controller) userInfoMonitor() (err error) {
} }
if len(limitedUsers) > 0 { if len(limitedUsers) > 0 {
if err := c.UpdateInboundLimiter(c.Tag, &limitedUsers); err != nil { if err := c.UpdateInboundLimiter(c.Tag, &limitedUsers); err != nil {
log.Print(err) c.logger.Print(err)
} }
} }
if len(userTraffic) > 0 { if len(userTraffic) > 0 {
@@ -569,7 +576,7 @@ func (c *Controller) userInfoMonitor() (err error) {
} }
// If report traffic error, not clear the traffic // If report traffic error, not clear the traffic
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
} else { } else {
c.resetTraffic(&upCounterList, &downCounterList) c.resetTraffic(&upCounterList, &downCounterList)
} }
@@ -577,23 +584,23 @@ func (c *Controller) userInfoMonitor() (err error) {
// Report Online info // Report Online info
if onlineDevice, err := c.GetOnlineDevice(c.Tag); err != nil { if onlineDevice, err := c.GetOnlineDevice(c.Tag); err != nil {
log.Print(err) c.logger.Print(err)
} else if len(*onlineDevice) > 0 { } else if len(*onlineDevice) > 0 {
if err = c.apiClient.ReportNodeOnlineUsers(onlineDevice); err != nil { if err = c.apiClient.ReportNodeOnlineUsers(onlineDevice); err != nil {
log.Print(err) c.logger.Print(err)
} else { } else {
log.Printf("%s Report %d online users", c.logPrefix(), len(*onlineDevice)) c.logger.Printf("Report %d online users", len(*onlineDevice))
} }
} }
// Report Illegal user // Report Illegal user
if detectResult, err := c.GetDetectResult(c.Tag); err != nil { if detectResult, err := c.GetDetectResult(c.Tag); err != nil {
log.Print(err) c.logger.Print(err)
} else if len(*detectResult) > 0 { } else if len(*detectResult) > 0 {
if err = c.apiClient.ReportIllegal(detectResult); err != nil { if err = c.apiClient.ReportIllegal(detectResult); err != nil {
log.Print(err) c.logger.Print(err)
} else { } else {
log.Printf("%s Report %d illegal behaviors", c.logPrefix(), len(*detectResult)) c.logger.Printf("Report %d illegal behaviors", len(*detectResult))
} }
} }
@@ -604,9 +611,9 @@ func (c *Controller) buildNodeTag() string {
return fmt.Sprintf("%s_%s_%d", c.nodeInfo.NodeType, c.config.ListenIP, c.nodeInfo.Port) return fmt.Sprintf("%s_%s_%d", c.nodeInfo.NodeType, c.config.ListenIP, c.nodeInfo.Port)
} }
func (c *Controller) logPrefix() string { // func (c *Controller) logPrefix() string {
return fmt.Sprintf("[%s] %s(ID=%d)", c.clientInfo.APIHost, c.nodeInfo.NodeType, c.nodeInfo.NodeID) // return fmt.Sprintf("[%s] %s(ID=%d)", c.clientInfo.APIHost, c.nodeInfo.NodeType, c.nodeInfo.NodeID)
} // }
// Check Cert // Check Cert
func (c *Controller) certMonitor() error { func (c *Controller) certMonitor() error {
@@ -615,12 +622,12 @@ func (c *Controller) certMonitor() error {
case "dns", "http", "tls": case "dns", "http", "tls":
lego, err := mylego.New(c.config.CertConfig) lego, err := mylego.New(c.config.CertConfig)
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
} }
// Xray-core supports the OcspStapling certification hot renew // Xray-core supports the OcspStapling certification hot renew
_, _, _, err = lego.RenewCert() _, _, _, err = lego.RenewCert()
if err != nil { if err != nil {
log.Print(err) c.logger.Print(err)
} }
} }
} }

View File

@@ -13,8 +13,8 @@ import (
"github.com/XrayR-project/XrayR/api" "github.com/XrayR-project/XrayR/api"
"github.com/XrayR-project/XrayR/api/sspanel" "github.com/XrayR-project/XrayR/api/sspanel"
_ "github.com/XrayR-project/XrayR/cmd/distro/all"
"github.com/XrayR-project/XrayR/common/mylego" "github.com/XrayR-project/XrayR/common/mylego"
_ "github.com/XrayR-project/XrayR/main/distro/all"
. "github.com/XrayR-project/XrayR/service/controller" . "github.com/XrayR-project/XrayR/service/controller"
) )

View File

@@ -41,7 +41,7 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
// SniffingConfig // SniffingConfig
sniffingConfig := &conf.SniffingConfig{ sniffingConfig := &conf.SniffingConfig{
Enabled: true, Enabled: true,
DestOverride: &conf.StringList{"http", "tls"}, DestOverride: &conf.StringList{"http", "tls", "quic", "fakedns"},
} }
if config.DisableSniffing { if config.DisableSniffing {
sniffingConfig.Enabled = false sniffingConfig.Enabled = false
@@ -57,8 +57,8 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
var proxySetting any var proxySetting any
// Build Protocol and Protocol setting // Build Protocol and Protocol setting
switch nodeInfo.NodeType { switch nodeInfo.NodeType {
case "V2ray": case "V2ray", "Vmess", "Vless":
if nodeInfo.EnableVless { if nodeInfo.EnableVless || (nodeInfo.NodeType == "Vless" && nodeInfo.NodeType != "Vmess") {
protocol = "vless" protocol = "vless"
// Enable fallback // Enable fallback
if config.EnableFallback { if config.EnableFallback {
@@ -139,7 +139,7 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
setting, err := json.Marshal(proxySetting) setting, err := json.Marshal(proxySetting)
if err != nil { if err != nil {
return nil, fmt.Errorf("marshal proxy %s config fialed: %s", nodeInfo.NodeType, err) return nil, fmt.Errorf("marshal proxy %s config failed: %s", nodeInfo.NodeType, err)
} }
inboundDetourConfig.Protocol = protocol inboundDetourConfig.Protocol = protocol
inboundDetourConfig.Settings = &setting inboundDetourConfig.Settings = &setting
@@ -164,6 +164,7 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
headers["Host"] = nodeInfo.Host headers["Host"] = nodeInfo.Host
wsSettings := &conf.WebSocketConfig{ wsSettings := &conf.WebSocketConfig{
AcceptProxyProtocol: config.EnableProxyProtocol, AcceptProxyProtocol: config.EnableProxyProtocol,
Host: nodeInfo.Host,
Path: nodeInfo.Path, Path: nodeInfo.Path,
Headers: headers, Headers: headers,
} }
@@ -171,17 +172,40 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I
case "http": case "http":
hosts := conf.StringList{nodeInfo.Host} hosts := conf.StringList{nodeInfo.Host}
httpSettings := &conf.HTTPConfig{ httpSettings := &conf.HTTPConfig{
Host: &hosts, Host: &hosts,
Path: nodeInfo.Path, Path: nodeInfo.Path,
Method: nodeInfo.Method,
Headers: nodeInfo.HttpHeaders,
} }
streamSetting.HTTPSettings = httpSettings streamSetting.HTTPSettings = httpSettings
case "grpc": case "grpc":
grpcSettings := &conf.GRPCConfig{ grpcSettings := &conf.GRPCConfig{
ServiceName: nodeInfo.ServiceName, ServiceName: nodeInfo.ServiceName,
Authority: nodeInfo.Authority,
} }
streamSetting.GRPCConfig = grpcSettings streamSetting.GRPCConfig = grpcSettings
case "quic":
quicSettings := &conf.QUICConfig{
Header: nodeInfo.Header,
Security: nodeInfo.Security,
Key: nodeInfo.Key,
}
streamSetting.QUICSettings = quicSettings
case "httpupgrade":
httpupgradeSettings := &conf.HttpUpgradeConfig{
Headers: nodeInfo.Headers,
Path: nodeInfo.Path,
Host: nodeInfo.Host,
AcceptProxyProtocol: nodeInfo.AcceptProxyProtocol,
}
streamSetting.HTTPUPGRADESettings = httpupgradeSettings
case "splithttp":
splithttpSetting := &conf.SplitHTTPConfig{
Path: nodeInfo.Path,
Host: nodeInfo.Host,
}
streamSetting.SplitHTTPSettings = splithttpSetting
} }
streamSetting.Network = &transportProtocol streamSetting.Network = &transportProtocol
// Build TLS and REALITY settings // Build TLS and REALITY settings
@@ -287,13 +311,13 @@ func buildVlessFallbacks(fallbackConfigs []*FallBackConfig) ([]*conf.VLessInboun
for i, c := range fallbackConfigs { for i, c := range fallbackConfigs {
if c.Dest == "" { if c.Dest == "" {
return nil, fmt.Errorf("dest is required for fallback fialed") return nil, fmt.Errorf("dest is required for fallback failed")
} }
var dest json.RawMessage var dest json.RawMessage
dest, err := json.Marshal(c.Dest) dest, err := json.Marshal(c.Dest)
if err != nil { if err != nil {
return nil, fmt.Errorf("marshal dest %s config fialed: %s", dest, err) return nil, fmt.Errorf("marshal dest %s config failed: %s", dest, err)
} }
vlessFallBacks[i] = &conf.VLessInboundFallback{ vlessFallBacks[i] = &conf.VLessInboundFallback{
Name: c.SNI, Name: c.SNI,
@@ -315,13 +339,13 @@ func buildTrojanFallbacks(fallbackConfigs []*FallBackConfig) ([]*conf.TrojanInbo
for i, c := range fallbackConfigs { for i, c := range fallbackConfigs {
if c.Dest == "" { if c.Dest == "" {
return nil, fmt.Errorf("dest is required for fallback fialed") return nil, fmt.Errorf("dest is required for fallback failed")
} }
var dest json.RawMessage var dest json.RawMessage
dest, err := json.Marshal(c.Dest) dest, err := json.Marshal(c.Dest)
if err != nil { if err != nil {
return nil, fmt.Errorf("marshal dest %s config fialed: %s", dest, err) return nil, fmt.Errorf("marshal dest %s config failed: %s", dest, err)
} }
trojanFallBacks[i] = &conf.TrojanInboundFallback{ trojanFallBacks[i] = &conf.TrojanInboundFallback{
Name: c.SNI, Name: c.SNI,

View File

@@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf" "github.com/xtls/xray-core/infra/conf"
@@ -17,11 +16,8 @@ func OutboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.
outboundDetourConfig.Protocol = "freedom" outboundDetourConfig.Protocol = "freedom"
outboundDetourConfig.Tag = tag outboundDetourConfig.Tag = tag
// Build Send IP address // SendThrough setting
if config.SendIP != "" { outboundDetourConfig.SendThrough = &config.SendIP
ipAddress := net.ParseAddress(config.SendIP)
outboundDetourConfig.SendThrough = &conf.Address{Address: ipAddress}
}
// Freedom Protocol setting // Freedom Protocol setting
var domainStrategy = "Asis" var domainStrategy = "Asis"
@@ -42,7 +38,7 @@ func OutboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.
var setting json.RawMessage var setting json.RawMessage
setting, err := json.Marshal(proxySetting) setting, err := json.Marshal(proxySetting)
if err != nil { if err != nil {
return nil, fmt.Errorf("marshal proxy %s config fialed: %s", nodeInfo.NodeType, err) return nil, fmt.Errorf("marshal proxy %s config failed: %s", nodeInfo.NodeType, err)
} }
outboundDetourConfig.Settings = &setting outboundDetourConfig.Settings = &setting
return outboundDetourConfig.Build() return outboundDetourConfig.Build()

View File

@@ -1,12 +1,14 @@
package controller package controller
import ( import (
"context"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"strings" "strings"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022" "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
C "github.com/sagernet/sing/common" C "github.com/sagernet/sing/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/infra/conf" "github.com/xtls/xray-core/infra/conf"
@@ -81,7 +83,7 @@ func (c *Controller) buildSSUser(userInfo *[]api.UserInfo, method string) (users
e := c.buildUserTag(&user) e := c.buildUserTag(&user)
userKey, err := c.checkShadowsocksPassword(user.Passwd, method) userKey, err := c.checkShadowsocksPassword(user.Passwd, method)
if err != nil { if err != nil {
newError(fmt.Errorf("[UID: %d] %s", user.UID, err)).AtError().WriteToLog() errors.LogError(context.Background(), "[UID: %d] %s", user.UID, err)
continue continue
} }
users[i] = &protocol.User{ users[i] = &protocol.User{
@@ -116,7 +118,7 @@ func (c *Controller) buildSSPluginUser(userInfo *[]api.UserInfo) (users []*proto
e := c.buildUserTag(&user) e := c.buildUserTag(&user)
userKey, err := c.checkShadowsocksPassword(user.Passwd, user.Method) userKey, err := c.checkShadowsocksPassword(user.Passwd, user.Method)
if err != nil { if err != nil {
newError(fmt.Errorf("[UID: %d] %s", user.UID, err)).AtError().WriteToLog() errors.LogError(context.Background(), "[UID: %d] %s", user.UID, err)
continue continue
} }
users[i] = &protocol.User{ users[i] = &protocol.User{