Skip to content

Add adaptive advert flood rate limiter#2545

Draft
ViezeVingertjes wants to merge 7 commits into
meshcore-dev:devfrom
ViezeVingertjes:advert-flood-protection
Draft

Add adaptive advert flood rate limiter#2545
ViezeVingertjes wants to merge 7 commits into
meshcore-dev:devfrom
ViezeVingertjes:advert-flood-protection

Conversation

@ViezeVingertjes
Copy link
Copy Markdown
Contributor

@ViezeVingertjes ViezeVingertjes commented May 13, 2026

Adds an adaptive rate limiter on advert forwarding so one node cannot flood the mesh with bogus or abusive adverts. Bursts are still allowed when traffic is normal; the cap tightens when someone tries to hammer fake adverts.

The limit uses a small EWMA of recent advert traffic, so it can rise a bit when there is normal activity and fall back down again after things go quiet. Floods (in the sense of spam) hit the cap fast and the rest is dropped until the next window.

Kept the behavior as small/simple as possible and on by default for happy neighbors.
get advert.ratelimit
set advert.ratelimit <state>
state: on|off

Also added a repeater-only stats command so we can see what the limiter is doing without guessing:
stats-advert-ratelimit

That reports the current limit, remaining budget, denied advert count, load average, limit reached count, and seconds since last limit reached. clear stats clears the reporting counters, but does not reset the active limiter state or give a fresh advert budget.

Added native unit tests for adaptive behavior, window rollover, long idle decay, timestamp wraparound, advert limiter stats counters, and clear stats behavior.

Context:
Most intentional abuse we had so far was spamming fake adverts, as it's one of the easiest things one can make. I tried to keep this as small/simple as possible, while still putting a brake on it so it doesnt flood further into the mesh.

Copy link
Copy Markdown

@4np 4np left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for creating this :) I understand you want to keep a minimal footprint to alleviate some of the issues we're seeing with bad actors, but I wonder if it would be better to be able to detect bad actors and penalize them by silencing them with an increasing amount of time? Sometimes people genuinely send a message split in multiple packets, which can occasionally be more than 3, whereas bad actors can still flood the mesh by sending 3 messages and then staying silent for 5 mins.

};

class AdaptiveRateLimiter {
enum {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding some documentation explaining the approach uses Exponentially Weighted Moving Average (EWMA). It might be good to have unit tests for this class to verify its behavior.

Copy link
Copy Markdown
Contributor Author

@ViezeVingertjes ViezeVingertjes May 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unit tests

We do unit tests these days?! haha.
No, all jokes aside, that should be easy to add in this case so will definetely do.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests are added.

Comment thread examples/simple_repeater/RateLimiter.h Outdated
}

public:
AdaptiveRateLimiter(uint16_t secs, uint8_t burst, uint8_t floor)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding some in-line documentation explaining what these arguments mean.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it as comments first, but later changed my mind and went with renaming the parameters to be more descriptive. What do you think? should do right?

(Idea is that comments would be visible at the code site only, but intellisense (depending on the IDE) shows the parameter names as-is)

https://github.com/meshcore-dev/MeshCore/pull/2545/changes#diff-8f2f69866b0adc556228c368f2e7a54e512eece12e2dfd7edc97c072f5698bd0R102-R103

@ViezeVingertjes ViezeVingertjes changed the title Add adaptive advert flood rate limiter WIP: Add adaptive advert flood rate limiter May 13, 2026
@ViezeVingertjes
Copy link
Copy Markdown
Contributor Author

ViezeVingertjes commented May 13, 2026

I understand you want to keep a minimal footprint to alleviate some of the issues we're seeing with bad actors

Correct, the attack is on-going so we needed something quick and simple. 💯

but I wonder if it would be better to be able to detect bad actors and penalize them by silencing them with an increasing amount of time?

I think it depends on the attack, what they seem to prefer so far is just generating random keys/names and flood-adverting those to annoy people with auto-add and generate some congestion on the mesh.

Sometimes people genuinely send a message split in multiple packets, which can occasionally be more than 3

Very true, this rate limit only apply to PAYLOAD_TYPE_ADVERT though as that is the challenge on hand, it did cross my mind for a second to look at other packets, but my first thought would be, that it would be to easy to abuse it for DoS and left it at that for now. So far they dont seem to spam channels (yet) fingers crossed.

Thanks for the review!
Will polish it once it has proven itself in the mesh for a bit. 👍🏼

@ViezeVingertjes ViezeVingertjes changed the title WIP: Add adaptive advert flood rate limiter Add adaptive advert flood rate limiter May 13, 2026
@ViezeVingertjes
Copy link
Copy Markdown
Contributor Author

ViezeVingertjes commented May 14, 2026

In the first day of testing it turned out those stats were needed badly after all to get the proper insights, i didnt see those stats-* commands before but it seemed like the perfect place for the implementation.

Few hours after updating the repeater, the advert attack started once more and i noticed due to having those stats, so that works. It grows to the appropiate limit within a few hours as expected and drops in the less busy hours.

So, so far so good, i will run and monitor it a bit more so i can fine-tune EWMA values and then put it on ready to review so anyone can shoot their thoughts/idea's on it.

@4np
Copy link
Copy Markdown

4np commented May 14, 2026

Will this be able to cope with the H5181A54 spam as well?

image

I assume not with these changes as it is not really spamming a bunch of flood messages within a certain amount of minutes. We may need another way to handle such super spammy nodes dumping garbage in many channels. Preferably automated in firmware to prevent it from distribution throughout the mesh.

@ViezeVingertjes
Copy link
Copy Markdown
Contributor Author

ViezeVingertjes commented May 14, 2026

Will this be able to cope with the H5181A54 spam as well?

No, in this case it wont do anything for those, as those arent adverts indeed. That's a different problem i'm affraid, which is much harder to solve. Dropping an legitimate advert in a bunch of spam adverts is acceptable, dropping messages however when someone is spamming the channels... that becomes tricky/hard to sell really quickly.

If it comes through a certain repeater, one could lower its duty cycle for a bit, that will put a brake on it, but also will affect legit messages.

(Today we have excluded a whole city + cities around it, just to get rid of the channel spam, hopefully at some point MC has the functionality to defend it in other ways... who knows)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants