diff --git a/internal/web/job/check_client_ip_job.go b/internal/web/job/check_client_ip_job.go index 8dc547e5d..93a8cef12 100644 --- a/internal/web/job/check_client_ip_job.go +++ b/internal/web/job/check_client_ip_job.go @@ -634,10 +634,11 @@ func (j *CheckClientIpJob) disconnectClientTemporarily(inbound *model.Inbound, c return } - // Only perform remove/re-add for protocols supported by XrayAPI.AddUser + // Protocols XrayAPI can remove and re-add from a marshaled model.Client. + // wireguard stays out: keepAlive marshals as a number, AddUser wants a string. protocol := string(inbound.Protocol) switch protocol { - case "vmess", "vless", "trojan", "shadowsocks": + case "vmess", "vless", "trojan", "shadowsocks", "hysteria": // supported protocols, continue default: logger.Warningf("[LIMIT_IP] Temporary disconnect is not supported for protocol %s on inbound %s", protocol, inbound.Tag) diff --git a/internal/web/job/limit_ip_disconnect_test.go b/internal/web/job/limit_ip_disconnect_test.go new file mode 100644 index 000000000..2d8012375 --- /dev/null +++ b/internal/web/job/limit_ip_disconnect_test.go @@ -0,0 +1,42 @@ +package job + +import ( + "strings" + "testing" + + "github.com/mhsanaei/3x-ui/v3/internal/database/model" + "github.com/mhsanaei/3x-ui/v3/internal/logger" +) + +// The protocol gate must let hysteria through: XrayAPI supports it, and the +// skip left over-limit Hysteria2 sessions alive until the fail2ban ban caught up. +func TestDisconnectClientTemporarilyAllowsHysteria(t *testing.T) { + setupIntegrationDB(t) + + const email = "hy2-limit-probe" + inbound := &model.Inbound{ + Id: 1, + Protocol: model.Hysteria, + Tag: "hy2-limit-probe-tag", + Settings: `{"clients":[]}`, + } + clients := []model.Client{{Email: email, Auth: "secret"}} + + (&CheckClientIpJob{}).disconnectClientTemporarily(inbound, email, clients) + + var unsupported, attempted bool + for _, line := range logger.GetLogs(500, "warning") { + if strings.Contains(line, "Temporary disconnect is not supported for protocol hysteria") { + unsupported = true + } + if strings.Contains(line, "Failed to remove user "+email) { + attempted = true + } + } + if unsupported { + t.Fatal("hysteria was rejected by the protocol gate") + } + if !attempted { + t.Fatal("expected a remove attempt against the Xray API for hysteria") + } +}