Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic zone key for network block of {http.request.remote.host} with certain prefix #12

Closed
kellytk opened this issue Aug 26, 2022 · 14 comments
Labels
enhancement New feature or request

Comments

@kellytk
Copy link

kellytk commented Aug 26, 2022

When used as the key of a dynamic zone, can {http.request.remote.host} be reduced to its network block for a certain prefix?

Assuming http.request.remote.host is 1.2.3.4, and a function is used reducing it to /24, requests (and rate-limiting) to any address in the range 1.2.3.0-255 would be grouped.

"key": "reduce_to_network_block({http.request.remote.host}, '/24')",
@mholt mholt added the enhancement New feature or request label Aug 30, 2022
@mholt
Copy link
Owner

mholt commented Aug 30, 2022

Interesting, let me think about this.

@mholt
Copy link
Owner

mholt commented Sep 30, 2022

What if there was a placeholder:

{http.request.remote.host/N} where N could be any bit length that mapped the IP (if an IP, otherwise it would ignore the /N) to, say, 1.2.3.0 for anything in the 1.2.3.0-255 range?

I can implement that upstream in Caddy if that's sufficient for you.

@francislavoie
Copy link
Sponsor

francislavoie commented Sep 30, 2022

What if it's IPv6 though? Need ranges for both cases I think. Kinda tricky.

There must be a way we can set up a var with the right value.

@mholt
Copy link
Owner

mholt commented Sep 30, 2022

@francislavoie I don't think the https://pkg.go.dev/net/netip package cares. It's just more bits, right?

@francislavoie
Copy link
Sponsor

francislavoie commented Sep 30, 2022

My point is, you might want to configure 16 bits for IPv4 but 32 bits for IPv6, like we have in the log ip_mask filter https://caddyserver.com/docs/caddyfile/directives/log#ip-mask

@mholt
Copy link
Owner

mholt commented Sep 30, 2022

True; maybe we could support a /N,M syntax or something; let's wait for a feature request.

mholt added a commit to caddyserver/caddy that referenced this issue Sep 30, 2022
@mholt
Copy link
Owner

mholt commented Sep 30, 2022

Oh what the hey. I did it anyway: caddyserver/caddy@9873ff9

@kellytk Here's what you want: {http.request.remote.host/24,32} (for example; the ,32 is optional if you want both bit lengths for IPv4 and IPv6)

@mholt mholt closed this as completed Sep 30, 2022
@kellytk
Copy link
Author

kellytk commented Sep 30, 2022

Currently traveling. Will ponder and respond within a day or two!

mholt added a commit that referenced this issue Sep 30, 2022
This is using Caddy at HEAD which should allow use of IP ranges. See #12
@kellytk
Copy link
Author

kellytk commented Oct 3, 2022

@mholt This is very exciting; especially the IPv6 support!

I wish to employ this feature in a layered fashion, ala contrived and simplified example: (IPv6 omitted as I don't yet have experience with it)

  • {http.request.remote.host/24} window:1s max_events:2,560
  • {http.request.remote.host/16} window:1s max_events:65,536
  • {http.request.remote.host/8} window:10s max_events:16,777,216

One request from 1.2.3.4 would:

  1. Apply a +1 event to the 1.2.3.0-255 zone key bucket.
  2. Another +1 event to the 1.2.0-255.0-255 bucket.
  3. And finally another +1 event to the 1.0-255.0-255.0-255 bucket.

Is that how this feature, as implemented, is designed to function?

This would enable me to allow burst traffic from individual IPs and small blocks, such as CGNAT, while still applying the events to the quotas of the larger containing blocks. The rationale is that individual IPs and small blocks can legitimately be hot, however amortizing events across larger blocks should yield more moderate figures. If large blocks are also hot, it's possibly an attack scenario.

To thwart my thinking an attacker would need to utilize more evenly distributed addresses from the global space. That can be 'easily' mitigated with active monitoring and dynamic updating of these rate limit policies.

@mholt
Copy link
Owner

mholt commented Oct 4, 2022

@kellytk Yes, I believe that should work. The placeholder {http.request.remote.host/24} for example would reduce 192.168.55.123 to a key of 192.168.55.0/24 -- /16 would become 192.168.0.0/16 and /8 would output 192.0.0.0/8.

You could hard-code those zone keys to test, if you know the IP range you'll be testing with. Then use the placeholder and observe the same behavior.

@kellytk
Copy link
Author

kellytk commented Oct 4, 2022

@mholt Excellent, thank you! Will tests be added to verify the behavior and ensure there're no regressions in the future?

@mholt
Copy link
Owner

mholt commented Oct 4, 2022

@kellytk I did write unit tests: caddyserver/caddy@9873ff9#diff-f7d3f5ac378699eb31c965343929663ac9504606500b9b4f81f10d371bfc9677

We can always add more later if needed.

What are you using this for? Just curious.

@kellytk
Copy link
Author

kellytk commented Oct 4, 2022

@mholt Thank you! I'm using Caddy as the user-facing reverse proxy to Rust-based 'apps' I write.

With enhancements such as this and caddyserver/caddy#4558 Caddy is proving pleasantly mature. Thank you once again.

@mholt
Copy link
Owner

mholt commented Oct 4, 2022

You're welcome! Glad it is working for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants