feat(plugin): add abuse blocker runtime - #46
Draft
l0nelynx wants to merge 3 commits into
Draft
Conversation
This was referenced Aug 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Suggested PR title
feat(plugin): add abuse blocker runtimeSummary
This PR adds the Node-side runtime for the new optional
abuseBlockerplugin introduced by remnawave/backend#207.It observes Xray routing webhooks, detects scan-like behavior per numeric user ID, maintains a rolling in-memory score, buffers idempotent reports for the backend, exposes health and coverage data, and temporarily blocks the current source IP in a dedicated nftables set when the configured score reaches the blocking threshold.
This is PR 2 of 3. It targets
devand is intentionally opened as a Draft while@remnawave/node-plugins@0.7.0is awaiting publication and the final@remnawave/node-contractrelease version is coordinated with the backend runtime PR.Motivation
torrentBlockercan react to one Xray protocol classification. Scan detection is stateful: it must aggregate unique destinations across multiple routing events for the same user, port, and time window without changing the selected outbound.The implementation therefore observes routing decisions through Xray webhooks and keeps only bounded, ephemeral detector state on each Node. Xray-core is not patched, traffic is not sent through
loopback, and Node-local scores are not combined across Nodes.Detection and scoring
Only events with all of the following are processed:
userIdfrom the Xray email field;The destination is selected in this order:
originalTarget,routeTarget, thendestination. Domain-only destinations and malformed endpoints are ignored.The default detectors are:
Horizontal scan
/24or IPv6/64;Destination sweep
Score events are retained for a rolling hour by default:
suspiciousreport;alertreport and retain enhanced evidence;blockedreport and block the current source IP for 10 minutes.A continuously active detector key scores once. It is re-armed only after its rolling set falls below the threshold and the default 300-second cooldown has elapsed. If both detectors cross their thresholds on the same observation, their scores are aggregated into one event and one action.
Buffered reports are keyed by
eventId. Later traffic can expand evidence for an existing alert without adding score or repeating the action. Collection uses the same destructive-flush model astorrentBlocker.Xray routing instrumentation
The generated routing configuration now uses separate internal endpoints:
/internal/webhook/torrent;/internal/webhook/abuse;/internal/webhook/combined;/internal/webhookremains a torrent-compatible alias.When Abuse Blocker is enabled:
deduplication: 0;IPIfNonMatchuses an IPv4/IPv6 catch-all so Xray's DNS second pass remains intact;The generated configurations for
AsIs,IPOnDemand, andIPIfNonMatchwere validated with Xrayv26.7.28, including unchanged selected outbounds.State and memory bounds
All detector state is local RAM and is reset when Node restarts or the plugin configuration is replaced.
Map<destinationIp, lastSeen>rolling windows;The plugin honors user, source-IP/CIDR, and destination-IP/CIDR ignore lists, including resolved shared
ext:IP lists.nftables enforcement
abuse-blockeringress address set to the existingremnanodetable.nftables-napi.initialBlockSeconds(600 seconds by default).remove -> addwith a new timeout for backend repeat-offender escalation.DropConnectionsEventafter a block or refresh so active connections are terminated.torrent-blockerandingress-filtersets.Node contract additions
The embedded
@remnawave/node-contractsource adds:eventId, user/source/destination data, rule hits, score transition, severity, evidence, action result, full policy snapshot, config fingerprint, coverage mode, and raw Xray report;POST /node/plugin/abuse-blocker/collect;POST /node/plugin/abuse-blocker/refresh-block;The package version is deliberately not bumped in this Draft branch because the repository's package workflow publishes on any push that changes
libs/**/package.json. The coordinated release bump will be added only when the dependent backend PR is ready. The expected next version is3.3.0unless maintainers choose another release number.Health fields
System stats now include:
availableandenabled;Compatibility and limitations
abuseBlockerremain unchanged.Tests
Added 25 focused tests covering:
/24and IPv6/64aggregation;Local validation:
All 25 focused tests, typecheck, Node build, contract build, and Xray validation pass using the locally packed
@remnawave/node-plugins@0.7.0schema from PR 1.Dependency chain
@remnawave/node-plugins@0.7.0.@remnawave/node-contractversion.Before this Draft is marked ready, the registry dependency and lockfile will be finalized and the full repository CI suite will be rerun.