mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-03-19 17:15:49 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e81008cdc | ||
|
|
e33ad809d6 | ||
|
|
d804043a18 | ||
|
|
0fb0df7056 | ||
|
|
73e90e0eaa | ||
|
|
44ef1ac9a6 | ||
|
|
aeac7f2c8b | ||
|
|
39ef172b87 | ||
|
|
0df85cc3d9 | ||
|
|
f0f4f082ae | ||
|
|
b29bd993d4 | ||
|
|
127eaf69b6 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -83,7 +83,7 @@ jobs:
|
|||||||
cd x-ui/bin
|
cd x-ui/bin
|
||||||
|
|
||||||
# Download dependencies
|
# Download dependencies
|
||||||
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v24.12.15/"
|
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v24.12.18/"
|
||||||
if [ "${{ matrix.platform }}" == "amd64" ]; then
|
if [ "${{ matrix.platform }}" == "amd64" ]; then
|
||||||
wget ${Xray_URL}Xray-linux-64.zip
|
wget ${Xray_URL}Xray-linux-64.zip
|
||||||
unzip Xray-linux-64.zip
|
unzip Xray-linux-64.zip
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ case $1 in
|
|||||||
esac
|
esac
|
||||||
mkdir -p build/bin
|
mkdir -p build/bin
|
||||||
cd build/bin
|
cd build/bin
|
||||||
wget "https://github.com/XTLS/Xray-core/releases/download/v24.12.15/Xray-linux-${ARCH}.zip"
|
wget "https://github.com/XTLS/Xray-core/releases/download/v24.12.18/Xray-linux-${ARCH}.zip"
|
||||||
unzip "Xray-linux-${ARCH}.zip"
|
unzip "Xray-linux-${ARCH}.zip"
|
||||||
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
|
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
|
||||||
mv xray "xray-linux-${FNAME}"
|
mv xray "xray-linux-${FNAME}"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.4.9
|
2.4.10
|
||||||
12
go.mod
12
go.mod
@@ -14,10 +14,10 @@ require (
|
|||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/shirou/gopsutil/v4 v4.24.11
|
github.com/shirou/gopsutil/v4 v4.24.11
|
||||||
github.com/valyala/fasthttp v1.58.0
|
github.com/valyala/fasthttp v1.58.0
|
||||||
github.com/xtls/xray-core v1.8.25-0.20241215123619-7d0a80b501d4
|
github.com/xtls/xray-core v1.8.25-0.20241218133935-cab2fdefd321
|
||||||
go.uber.org/atomic v1.11.0
|
go.uber.org/atomic v1.11.0
|
||||||
golang.org/x/text v0.21.0
|
golang.org/x/text v0.21.0
|
||||||
google.golang.org/grpc v1.69.0
|
google.golang.org/grpc v1.69.2
|
||||||
gorm.io/driver/sqlite v1.5.7
|
gorm.io/driver/sqlite v1.5.7
|
||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
)
|
)
|
||||||
@@ -85,17 +85,17 @@ require (
|
|||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||||
golang.org/x/arch v0.12.0 // indirect
|
golang.org/x/arch v0.12.0 // indirect
|
||||||
golang.org/x/crypto v0.31.0 // indirect
|
golang.org/x/crypto v0.31.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect
|
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
|
||||||
golang.org/x/mod v0.22.0 // indirect
|
golang.org/x/mod v0.22.0 // indirect
|
||||||
golang.org/x/net v0.32.0 // indirect
|
golang.org/x/net v0.33.0 // indirect
|
||||||
golang.org/x/sync v0.10.0 // indirect
|
golang.org/x/sync v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
golang.org/x/time v0.8.0 // indirect
|
golang.org/x/time v0.8.0 // indirect
|
||||||
golang.org/x/tools v0.28.0 // indirect
|
golang.org/x/tools v0.28.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 // indirect
|
||||||
google.golang.org/protobuf v1.35.2 // indirect
|
google.golang.org/protobuf v1.36.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect
|
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect
|
||||||
lukechampine.com/blake3 v1.3.0 // indirect
|
lukechampine.com/blake3 v1.3.0 // indirect
|
||||||
|
|||||||
24
go.sum
24
go.sum
@@ -189,8 +189,8 @@ github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zd
|
|||||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM=
|
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM=
|
||||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg=
|
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg=
|
||||||
github.com/xtls/xray-core v1.8.25-0.20241215123619-7d0a80b501d4 h1:zdd86FEjFZjAaRbWxiZQM2QPOzk/d6cig2DaE7c3MDQ=
|
github.com/xtls/xray-core v1.8.25-0.20241218133935-cab2fdefd321 h1:vk+n1RmfhFCj5xSi4I6C3USpcUQ48H3lt/QrtARVz1M=
|
||||||
github.com/xtls/xray-core v1.8.25-0.20241215123619-7d0a80b501d4/go.mod h1:lduNPDkXku+Avphl8g7W0yJrHhWyxdOnPo0XGYdF0Aw=
|
github.com/xtls/xray-core v1.8.25-0.20241218133935-cab2fdefd321/go.mod h1:DCaUwrBk1RIC7hWg/wGoAynE69g3ptua1sEr8i0BWxA=
|
||||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
@@ -215,12 +215,12 @@ golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
|
|||||||
golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
|
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
|
||||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||||
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -241,12 +241,12 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu
|
|||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 h1:Z7FRVJPSMaHQxD0uXU8WdgFh8PseLM8Q8NzhnpMrBhQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
|
||||||
google.golang.org/grpc v1.69.0 h1:quSiOM1GJPmPH5XtU+BCoVXcDVJJAzNcoyfC2cCjGkI=
|
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
|
||||||
google.golang.org/grpc v1.69.0/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
||||||
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
|
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
|
||||||
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
|||||||
@@ -34,10 +34,6 @@ const TLS_VERSION_OPTION = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const TLS_CIPHER_OPTION = {
|
const TLS_CIPHER_OPTION = {
|
||||||
RSA_AES_128_CBC: "TLS_RSA_WITH_AES_128_CBC_SHA",
|
|
||||||
RSA_AES_256_CBC: "TLS_RSA_WITH_AES_256_CBC_SHA",
|
|
||||||
RSA_AES_128_GCM: "TLS_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
RSA_AES_256_GCM: "TLS_RSA_WITH_AES_256_GCM_SHA384",
|
|
||||||
AES_128_GCM: "TLS_AES_128_GCM_SHA256",
|
AES_128_GCM: "TLS_AES_128_GCM_SHA256",
|
||||||
AES_256_GCM: "TLS_AES_256_GCM_SHA384",
|
AES_256_GCM: "TLS_AES_256_GCM_SHA384",
|
||||||
CHACHA20_POLY1305: "TLS_CHACHA20_POLY1305_SHA256",
|
CHACHA20_POLY1305: "TLS_CHACHA20_POLY1305_SHA256",
|
||||||
@@ -64,6 +60,7 @@ const UTLS_FINGERPRINT = {
|
|||||||
UTLS_QQ: "qq",
|
UTLS_QQ: "qq",
|
||||||
UTLS_RANDOM: "random",
|
UTLS_RANDOM: "random",
|
||||||
UTLS_RANDOMIZED: "randomized",
|
UTLS_RANDOMIZED: "randomized",
|
||||||
|
UTLS_UNSAFE: "unsafe",
|
||||||
};
|
};
|
||||||
|
|
||||||
const ALPN_OPTION = {
|
const ALPN_OPTION = {
|
||||||
@@ -496,19 +493,9 @@ class xHTTPStreamSettings extends XrayCommonClass {
|
|||||||
headers = [],
|
headers = [],
|
||||||
scMaxBufferedPosts = 30,
|
scMaxBufferedPosts = 30,
|
||||||
scMaxEachPostBytes = "1000000",
|
scMaxEachPostBytes = "1000000",
|
||||||
scMinPostsIntervalMs = "30",
|
|
||||||
noSSEHeader = false,
|
noSSEHeader = false,
|
||||||
xPaddingBytes = "100-1000",
|
xPaddingBytes = "100-1000",
|
||||||
xmux = {
|
|
||||||
maxConcurrency: "16-32",
|
|
||||||
maxConnections: 0,
|
|
||||||
cMaxReuseTimes: "64-128",
|
|
||||||
cMaxLifetimeMs: 0,
|
|
||||||
hMaxRequestTimes: "800-900",
|
|
||||||
hKeepAlivePeriod: 0,
|
|
||||||
},
|
|
||||||
mode = MODE_OPTION.AUTO,
|
mode = MODE_OPTION.AUTO,
|
||||||
noGRPCHeader = false
|
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.path = path;
|
this.path = path;
|
||||||
@@ -516,12 +503,9 @@ class xHTTPStreamSettings extends XrayCommonClass {
|
|||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
this.scMaxBufferedPosts = scMaxBufferedPosts;
|
this.scMaxBufferedPosts = scMaxBufferedPosts;
|
||||||
this.scMaxEachPostBytes = scMaxEachPostBytes;
|
this.scMaxEachPostBytes = scMaxEachPostBytes;
|
||||||
this.scMinPostsIntervalMs = scMinPostsIntervalMs;
|
|
||||||
this.noSSEHeader = noSSEHeader;
|
this.noSSEHeader = noSSEHeader;
|
||||||
this.xPaddingBytes = xPaddingBytes;
|
this.xPaddingBytes = xPaddingBytes;
|
||||||
this.xmux = xmux;
|
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
this.noGRPCHeader = noGRPCHeader;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addHeader(name, value) {
|
addHeader(name, value) {
|
||||||
@@ -539,12 +523,9 @@ class xHTTPStreamSettings extends XrayCommonClass {
|
|||||||
XrayCommonClass.toHeaders(json.headers),
|
XrayCommonClass.toHeaders(json.headers),
|
||||||
json.scMaxBufferedPosts,
|
json.scMaxBufferedPosts,
|
||||||
json.scMaxEachPostBytes,
|
json.scMaxEachPostBytes,
|
||||||
json.scMinPostsIntervalMs,
|
|
||||||
json.noSSEHeader,
|
json.noSSEHeader,
|
||||||
json.xPaddingBytes,
|
json.xPaddingBytes,
|
||||||
json.xmux,
|
|
||||||
json.mode,
|
json.mode,
|
||||||
json.noGRPCHeader,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,19 +536,9 @@ class xHTTPStreamSettings extends XrayCommonClass {
|
|||||||
headers: XrayCommonClass.toV2Headers(this.headers, false),
|
headers: XrayCommonClass.toV2Headers(this.headers, false),
|
||||||
scMaxBufferedPosts: this.scMaxBufferedPosts,
|
scMaxBufferedPosts: this.scMaxBufferedPosts,
|
||||||
scMaxEachPostBytes: this.scMaxEachPostBytes,
|
scMaxEachPostBytes: this.scMaxEachPostBytes,
|
||||||
scMinPostsIntervalMs: this.scMinPostsIntervalMs,
|
|
||||||
noSSEHeader: this.noSSEHeader,
|
noSSEHeader: this.noSSEHeader,
|
||||||
xPaddingBytes: this.xPaddingBytes,
|
xPaddingBytes: this.xPaddingBytes,
|
||||||
xmux: {
|
|
||||||
maxConcurrency: this.xmux.maxConcurrency,
|
|
||||||
maxConnections: this.xmux.maxConnections,
|
|
||||||
cMaxReuseTimes: this.xmux.cMaxReuseTimes,
|
|
||||||
cMaxLifetimeMs: this.xmux.cMaxLifetimeMs,
|
|
||||||
hMaxRequestTimes: this.xmux.hMaxRequestTimes,
|
|
||||||
hKeepAlivePeriod: this.xmux.hKeepAlivePeriod,
|
|
||||||
},
|
|
||||||
mode: this.mode,
|
mode: this.mode,
|
||||||
noGRPCHeader: this.noGRPCHeader,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -718,7 +689,10 @@ TlsStreamSettings.Cert = class extends XrayCommonClass {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TlsStreamSettings.Settings = class extends XrayCommonClass {
|
TlsStreamSettings.Settings = class extends XrayCommonClass {
|
||||||
constructor(allowInsecure = false, fingerprint = '') {
|
constructor(
|
||||||
|
allowInsecure = false,
|
||||||
|
fingerprint = UTLS_FINGERPRINT.UTLS_CHROME,
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
this.allowInsecure = allowInsecure;
|
this.allowInsecure = allowInsecure;
|
||||||
this.fingerprint = fingerprint;
|
this.fingerprint = fingerprint;
|
||||||
@@ -807,7 +781,7 @@ class RealityStreamSettings extends XrayCommonClass {
|
|||||||
RealityStreamSettings.Settings = class extends XrayCommonClass {
|
RealityStreamSettings.Settings = class extends XrayCommonClass {
|
||||||
constructor(
|
constructor(
|
||||||
publicKey = '',
|
publicKey = '',
|
||||||
fingerprint = UTLS_FINGERPRINT.UTLS_RANDOM,
|
fingerprint = UTLS_FINGERPRINT.UTLS_CHROME,
|
||||||
serverName = '',
|
serverName = '',
|
||||||
spiderX = '/'
|
spiderX = '/'
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ const UTLS_FINGERPRINT = {
|
|||||||
UTLS_QQ: "qq",
|
UTLS_QQ: "qq",
|
||||||
UTLS_RANDOM: "random",
|
UTLS_RANDOM: "random",
|
||||||
UTLS_RANDOMIZED: "randomized",
|
UTLS_RANDOMIZED: "randomized",
|
||||||
|
UTLS_UNSAFE: "unsafe",
|
||||||
};
|
};
|
||||||
|
|
||||||
const ALPN_OPTION = {
|
const ALPN_OPTION = {
|
||||||
@@ -287,11 +288,24 @@ class xHTTPStreamSettings extends CommonClass {
|
|||||||
path = '/',
|
path = '/',
|
||||||
host = '',
|
host = '',
|
||||||
mode = '',
|
mode = '',
|
||||||
|
noGRPCHeader = false,
|
||||||
|
scMinPostsIntervalMs = "30",
|
||||||
|
xmux = {
|
||||||
|
maxConcurrency: "16-32",
|
||||||
|
maxConnections: 0,
|
||||||
|
cMaxReuseTimes: "64-128",
|
||||||
|
cMaxLifetimeMs: 0,
|
||||||
|
hMaxRequestTimes: "800-900",
|
||||||
|
hKeepAlivePeriod: 0,
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
|
this.noGRPCHeader = noGRPCHeader;
|
||||||
|
this.scMinPostsIntervalMs = scMinPostsIntervalMs;
|
||||||
|
this.xmux = xmux;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json = {}) {
|
static fromJson(json = {}) {
|
||||||
@@ -299,6 +313,9 @@ class xHTTPStreamSettings extends CommonClass {
|
|||||||
json.path,
|
json.path,
|
||||||
json.host,
|
json.host,
|
||||||
json.mode,
|
json.mode,
|
||||||
|
json.noGRPCHeader,
|
||||||
|
json.scMinPostsIntervalMs,
|
||||||
|
json.xmux
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +324,16 @@ class xHTTPStreamSettings extends CommonClass {
|
|||||||
path: this.path,
|
path: this.path,
|
||||||
host: this.host,
|
host: this.host,
|
||||||
mode: this.mode,
|
mode: this.mode,
|
||||||
|
noGRPCHeader: this.noGRPCHeader,
|
||||||
|
scMinPostsIntervalMs: this.scMinPostsIntervalMs,
|
||||||
|
xmux: {
|
||||||
|
maxConcurrency: this.xmux.maxConcurrency,
|
||||||
|
maxConnections: this.xmux.maxConnections,
|
||||||
|
cMaxReuseTimes: this.xmux.cMaxReuseTimes,
|
||||||
|
cMaxLifetimeMs: this.xmux.cMaxLifetimeMs,
|
||||||
|
hMaxRequestTimes: this.xmux.hMaxRequestTimes,
|
||||||
|
hKeepAlivePeriod: this.xmux.hKeepAlivePeriod,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"x-ui/web/service"
|
"x-ui/web/service"
|
||||||
"x-ui/web/session"
|
"x-ui/web/session"
|
||||||
|
|
||||||
|
"github.com/gin-contrib/sessions"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,8 +50,8 @@ func (a *IndexController) index(c *gin.Context) {
|
|||||||
|
|
||||||
func (a *IndexController) login(c *gin.Context) {
|
func (a *IndexController) login(c *gin.Context) {
|
||||||
var form LoginForm
|
var form LoginForm
|
||||||
err := c.ShouldBind(&form)
|
|
||||||
if err != nil {
|
if err := c.ShouldBind(&form); err != nil {
|
||||||
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.invalidFormData"))
|
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.invalidFormData"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -68,29 +69,31 @@ func (a *IndexController) login(c *gin.Context) {
|
|||||||
safeUser := template.HTMLEscapeString(form.Username)
|
safeUser := template.HTMLEscapeString(form.Username)
|
||||||
safePass := template.HTMLEscapeString(form.Password)
|
safePass := template.HTMLEscapeString(form.Password)
|
||||||
safeSecret := template.HTMLEscapeString(form.LoginSecret)
|
safeSecret := template.HTMLEscapeString(form.LoginSecret)
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
logger.Warningf("wrong username: \"%s\", password: \"%s\", secret: \"%s\", IP: \"%s\"", safeUser, safePass, safeSecret, getRemoteIp(c))
|
logger.Warningf("wrong username: \"%s\", password: \"%s\", secret: \"%s\", IP: \"%s\"", safeUser, safePass, safeSecret, getRemoteIp(c))
|
||||||
a.tgbot.UserLoginNotify(safeUser, safePass, getRemoteIp(c), timeStr, 0)
|
a.tgbot.UserLoginNotify(safeUser, safePass, getRemoteIp(c), timeStr, 0)
|
||||||
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.wrongUsernameOrPassword"))
|
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.wrongUsernameOrPassword"))
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
logger.Infof("%s logged in successfully, Ip Address: %s\n", safeUser, getRemoteIp(c))
|
|
||||||
a.tgbot.UserLoginNotify(safeUser, ``, getRemoteIp(c), timeStr, 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.Infof("%s logged in successfully, Ip Address: %s\n", safeUser, getRemoteIp(c))
|
||||||
|
a.tgbot.UserLoginNotify(safeUser, ``, getRemoteIp(c), timeStr, 1)
|
||||||
|
|
||||||
sessionMaxAge, err := a.settingService.GetSessionMaxAge()
|
sessionMaxAge, err := a.settingService.GetSessionMaxAge()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warning("Unable to get session's max age from DB")
|
logger.Warning("Unable to get session's max age from DB")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = session.SetMaxAge(c, sessionMaxAge*60)
|
session.SetMaxAge(c, sessionMaxAge*60)
|
||||||
if err != nil {
|
session.SetLoginUser(c, user)
|
||||||
logger.Warning("Unable to set session's max age")
|
if err := sessions.Default(c).Save(); err != nil {
|
||||||
|
logger.Warning("Unable to save session: ", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = session.SetLoginUser(c, user)
|
logger.Infof("%s logged in successfully", safeUser)
|
||||||
logger.Infof("%s logged in successfully", user.Username)
|
jsonMsg(c, I18nWeb(c, "pages.login.toasts.successLogin"), nil)
|
||||||
jsonMsg(c, I18nWeb(c, "pages.login.toasts.successLogin"), err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *IndexController) logout(c *gin.Context) {
|
func (a *IndexController) logout(c *gin.Context) {
|
||||||
@@ -99,6 +102,9 @@ func (a *IndexController) logout(c *gin.Context) {
|
|||||||
logger.Infof("%s logged out successfully", user.Username)
|
logger.Infof("%s logged out successfully", user.Username)
|
||||||
}
|
}
|
||||||
session.ClearSession(c)
|
session.ClearSession(c)
|
||||||
|
if err := sessions.Default(c).Save(); err != nil {
|
||||||
|
logger.Warning("Unable to save session after clearing:", err)
|
||||||
|
}
|
||||||
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
|
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -377,6 +377,30 @@
|
|||||||
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="No gRPC Header" v-if="outbound.stream.xhttp.mode === 'stream-up' || outbound.stream.xhttp.mode === 'stream-one'">
|
||||||
|
<a-switch v-model="outbound.stream.xhttp.noGRPCHeader"></a-switch>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Min Upload Interval (Ms)" v-if="outbound.stream.xhttp.mode === 'packet-up'">
|
||||||
|
<a-input v-model.trim="outbound.stream.xhttp.scMinPostsIntervalMs"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Max Concurrency" v-if="!outbound.stream.xhttp.xmux.maxConnections">
|
||||||
|
<a-input v-model="outbound.stream.xhttp.xmux.maxConcurrency"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Max Connections" v-if="!outbound.stream.xhttp.xmux.maxConcurrency">
|
||||||
|
<a-input v-model="outbound.stream.xhttp.xmux.maxConnections"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Max Reuse Times">
|
||||||
|
<a-input v-model="outbound.stream.xhttp.xmux.cMaxReuseTimes"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Max Lifetime (ms)">
|
||||||
|
<a-input v-model="outbound.stream.xhttp.xmux.cMaxLifetimeMs"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Max Request Times">
|
||||||
|
<a-input v-model="outbound.stream.xhttp.xmux.hMaxRequestTimes"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='Keep Alive Period'>
|
||||||
|
<a-input v-model.number="outbound.stream.xhttp.xmux.hKeepAlivePeriod"></a-input>
|
||||||
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -27,41 +27,17 @@
|
|||||||
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Max Buffered Upload">
|
<a-form-item label="Max Buffered Upload" v-if="inbound.stream.xhttp.mode === 'packet-up'">
|
||||||
<a-input v-model.trim="inbound.stream.xhttp.scMaxBufferedPosts"></a-input>
|
<a-input v-model.trim="inbound.stream.xhttp.scMaxBufferedPosts"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Max Upload Size (Byte)">
|
<a-form-item label="Max Upload Size (Byte)" v-if="inbound.stream.xhttp.mode === 'packet-up'">
|
||||||
<a-input v-model.trim="inbound.stream.xhttp.scMaxEachPostBytes"></a-input>
|
<a-input v-model.trim="inbound.stream.xhttp.scMaxEachPostBytes"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Min Upload Interval (Ms)">
|
|
||||||
<a-input v-model.trim="inbound.stream.xhttp.scMinPostsIntervalMs"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Padding Bytes">
|
<a-form-item label="Padding Bytes">
|
||||||
<a-input v-model.trim="inbound.stream.xhttp.xPaddingBytes"></a-input>
|
<a-input v-model.trim="inbound.stream.xhttp.xPaddingBytes"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="No SSE Header">
|
<a-form-item label="No SSE Header">
|
||||||
<a-switch v-model="inbound.stream.xhttp.noSSEHeader"></a-switch>
|
<a-switch v-model="inbound.stream.xhttp.noSSEHeader"></a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Max Concurrency" v-if="!inbound.stream.xhttp.xmux.maxConnections">
|
|
||||||
<a-input v-model="inbound.stream.xhttp.xmux.maxConcurrency"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Max Connections" v-if="!inbound.stream.xhttp.xmux.maxConcurrency">
|
|
||||||
<a-input v-model="inbound.stream.xhttp.xmux.maxConnections"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Max Reuse Times">
|
|
||||||
<a-input v-model="inbound.stream.xhttp.xmux.cMaxReuseTimes"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Max Lifetime (ms)">
|
|
||||||
<a-input v-model="inbound.stream.xhttp.xmux.cMaxLifetimeMs"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Max Request Times">
|
|
||||||
<a-input v-model="inbound.stream.xhttp.xmux.hMaxRequestTimes"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label='Keep Alive Period'>
|
|
||||||
<a-input v-model.number="inbound.stream.xhttp.xmux.hKeepAlivePeriod"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="No gRPC Header">
|
|
||||||
<a-switch v-model="inbound.stream.xhttp.noGRPCHeader"></a-switch>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
</a-form>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -151,13 +151,13 @@ func (j *CheckClientIpJob) processLogFile() bool {
|
|||||||
}
|
}
|
||||||
sort.Strings(ips)
|
sort.Strings(ips)
|
||||||
|
|
||||||
inboundClientIps, err := j.getInboundClientIps(email)
|
clientIpsRecord, err := j.getInboundClientIps(email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
j.addInboundClientIps(email, ips)
|
j.addInboundClientIps(email, ips)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldCleanLog = j.updateInboundClientIps(inboundClientIps, email, ips) || shouldCleanLog
|
shouldCleanLog = j.updateInboundClientIps(clientIpsRecord, email, ips) || shouldCleanLog
|
||||||
}
|
}
|
||||||
|
|
||||||
return shouldCleanLog
|
return shouldCleanLog
|
||||||
@@ -309,12 +309,12 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
|
|||||||
|
|
||||||
func (j *CheckClientIpJob) getInboundByEmail(clientEmail string) (*model.Inbound, error) {
|
func (j *CheckClientIpJob) getInboundByEmail(clientEmail string) (*model.Inbound, error) {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
var inbounds *model.Inbound
|
inbound := &model.Inbound{}
|
||||||
|
|
||||||
err := db.Model(model.Inbound{}).Where("settings LIKE ?", "%"+clientEmail+"%").Find(&inbounds).Error
|
err := db.Model(&model.Inbound{}).Where("settings LIKE ?", "%"+clientEmail+"%").First(inbound).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return inbounds, nil
|
return inbound, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,38 +10,41 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
loginUser = "LOGIN_USER"
|
loginUserKey = "LOGIN_USER"
|
||||||
defaultPath = "/"
|
defaultPath = "/"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
gob.Register(model.User{})
|
gob.Register(model.User{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetLoginUser(c *gin.Context, user *model.User) error {
|
func SetLoginUser(c *gin.Context, user *model.User) {
|
||||||
|
if user == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
s := sessions.Default(c)
|
s := sessions.Default(c)
|
||||||
s.Set(loginUser, user)
|
s.Set(loginUserKey, *user)
|
||||||
return s.Save()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetMaxAge(c *gin.Context, maxAge int) error {
|
func SetMaxAge(c *gin.Context, maxAge int) {
|
||||||
s := sessions.Default(c)
|
s := sessions.Default(c)
|
||||||
s.Options(sessions.Options{
|
s.Options(sessions.Options{
|
||||||
Path: defaultPath,
|
Path: defaultPath,
|
||||||
MaxAge: maxAge,
|
MaxAge: maxAge,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
})
|
})
|
||||||
return s.Save()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetLoginUser(c *gin.Context) *model.User {
|
func GetLoginUser(c *gin.Context) *model.User {
|
||||||
s := sessions.Default(c)
|
s := sessions.Default(c)
|
||||||
obj := s.Get(loginUser)
|
obj := s.Get(loginUserKey)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
user, ok := obj.(model.User)
|
user, ok := obj.(model.User)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
||||||
|
s.Delete(loginUserKey)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &user
|
return &user
|
||||||
@@ -51,7 +54,7 @@ func IsLogin(c *gin.Context) bool {
|
|||||||
return GetLoginUser(c) != nil
|
return GetLoginUser(c) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClearSession(c *gin.Context) error {
|
func ClearSession(c *gin.Context) {
|
||||||
s := sessions.Default(c)
|
s := sessions.Default(c)
|
||||||
s.Clear()
|
s.Clear()
|
||||||
s.Options(sessions.Options{
|
s.Options(sessions.Options{
|
||||||
@@ -59,5 +62,4 @@ func ClearSession(c *gin.Context) error {
|
|||||||
MaxAge: -1,
|
MaxAge: -1,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
})
|
})
|
||||||
return s.Save()
|
|
||||||
}
|
}
|
||||||
|
|||||||
44
x-ui.sh
44
x-ui.sh
@@ -1278,8 +1278,8 @@ run_speedtest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
create_iplimit_jails() {
|
create_iplimit_jails() {
|
||||||
# Use default bantime if not passed => 15 minutes
|
# Use default bantime if not passed => 30 minutes
|
||||||
local bantime="${1:-15}"
|
local bantime="${1:-30}"
|
||||||
|
|
||||||
# Uncomment 'allowipv6 = auto' in fail2ban.conf
|
# Uncomment 'allowipv6 = auto' in fail2ban.conf
|
||||||
sed -i 's/#allowipv6 = auto/allowipv6 = auto/g' /etc/fail2ban/fail2ban.conf
|
sed -i 's/#allowipv6 = auto/allowipv6 = auto/g' /etc/fail2ban/fail2ban.conf
|
||||||
@@ -1358,10 +1358,12 @@ iplimit_main() {
|
|||||||
echo -e "${green}\t2.${plain} Change Ban Duration"
|
echo -e "${green}\t2.${plain} Change Ban Duration"
|
||||||
echo -e "${green}\t3.${plain} Unban Everyone"
|
echo -e "${green}\t3.${plain} Unban Everyone"
|
||||||
echo -e "${green}\t4.${plain} Ban Logs"
|
echo -e "${green}\t4.${plain} Ban Logs"
|
||||||
echo -e "${green}\t5.${plain} Real-Time Logs"
|
echo -e "${green}\t5.${plain} Unban an IP Address"
|
||||||
echo -e "${green}\t6.${plain} Service Status"
|
echo -e "${green}\t6.${plain} Ban an IP Address"
|
||||||
echo -e "${green}\t7.${plain} Service Restart"
|
echo -e "${green}\t7.${plain} Real-Time Logs"
|
||||||
echo -e "${green}\t8.${plain} Uninstall Fail2ban and IP Limit"
|
echo -e "${green}\t8.${plain} Service Status"
|
||||||
|
echo -e "${green}\t9.${plain} Service Restart"
|
||||||
|
echo -e "${green}\t10.${plain} Uninstall Fail2ban and IP Limit"
|
||||||
echo -e "${green}\t0.${plain} Back to Main Menu"
|
echo -e "${green}\t0.${plain} Back to Main Menu"
|
||||||
read -p "Choose an option: " choice
|
read -p "Choose an option: " choice
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
@@ -1389,7 +1391,7 @@ iplimit_main() {
|
|||||||
3)
|
3)
|
||||||
confirm "Proceed with Unbanning everyone from IP Limit jail?" "y"
|
confirm "Proceed with Unbanning everyone from IP Limit jail?" "y"
|
||||||
if [[ $? == 0 ]]; then
|
if [[ $? == 0 ]]; then
|
||||||
fail2ban-client reload --restart --unban 3x-ipl
|
systemctl restart fail2ban
|
||||||
truncate -s 0 "${iplimit_banned_log_path}"
|
truncate -s 0 "${iplimit_banned_log_path}"
|
||||||
echo -e "${green}All users Unbanned successfully.${plain}"
|
echo -e "${green}All users Unbanned successfully.${plain}"
|
||||||
iplimit_main
|
iplimit_main
|
||||||
@@ -1403,22 +1405,42 @@ iplimit_main() {
|
|||||||
iplimit_main
|
iplimit_main
|
||||||
;;
|
;;
|
||||||
5)
|
5)
|
||||||
tail -f /var/log/fail2ban.log
|
read -rp "Enter the IP address you want to ban: " ban_ip
|
||||||
|
if [[ $ban_ip =~ ^(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9]))$ || $ban_ip =~ ^(([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})$ ]]; then
|
||||||
|
fail2ban-client set 3x-ipl banip "$ban_ip"
|
||||||
|
echo -e "${green}IP Address ${ban_ip} has been banned successfully.${plain}"
|
||||||
|
else
|
||||||
|
echo -e "${red}Invalid IP address format! Please try again.${plain}"
|
||||||
|
fi
|
||||||
iplimit_main
|
iplimit_main
|
||||||
;;
|
;;
|
||||||
6)
|
6)
|
||||||
service fail2ban status
|
read -rp "Enter the IP address you want to unban: " unban_ip
|
||||||
|
if [[ $unban_ip =~ ^(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9]))$ || $unban_ip =~ ^(([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})$ ]]; then
|
||||||
|
fail2ban-client set 3x-ipl unbanip "$unban_ip"
|
||||||
|
echo -e "${green}IP Address ${unban_ip} has been unbanned successfully.${plain}"
|
||||||
|
else
|
||||||
|
echo -e "${red}Invalid IP address format! Please try again.${plain}"
|
||||||
|
fi
|
||||||
iplimit_main
|
iplimit_main
|
||||||
;;
|
;;
|
||||||
7)
|
7)
|
||||||
systemctl restart fail2ban
|
tail -f /var/log/fail2ban.log
|
||||||
iplimit_main
|
iplimit_main
|
||||||
;;
|
;;
|
||||||
8)
|
8)
|
||||||
|
service fail2ban status
|
||||||
|
iplimit_main
|
||||||
|
;;
|
||||||
|
9)
|
||||||
|
systemctl restart fail2ban
|
||||||
|
iplimit_main
|
||||||
|
;;
|
||||||
|
10)
|
||||||
remove_iplimit
|
remove_iplimit
|
||||||
iplimit_main
|
iplimit_main
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
|
echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
|
||||||
iplimit_main
|
iplimit_main
|
||||||
;;
|
;;
|
||||||
|
|||||||
Reference in New Issue
Block a user