Closed teodorescuserban closed 1 month ago
You could use https://github.com/tuzzmaniandevil/caddy-dynamic-clientip which allows you to have a dynamic list of IPs loaded into the matcher (detached from the config lifecycle, managed by the module), so you could have an IPSource module that you write that can read the list from a file and cache it for a few seconds.
Thank you for the quick reply, @francislavoie!
Ok, this sounds complicated, although I might do it.
I was actually wondering if there is a way to have and
/ or
operation between matchers to obtain a new matcher.
For my case, I could easily use
(bad_ips) {
client_ip 192.168.65.0/24
}
and
(our_ips) {
client_ip 10.0.0.0/8
}
for
zone bad_ip {
match {
import bad_ips
}
key {remote_host}
events 1
window 5s
}
and
zone our_ip {
match {
import our_ips
}
key {remote_host}
events 4
window 1s
}
but the real issue is how do i build the matcher for zone unknown_source
???
I would need to compose somehow the bad_ips
and our_ips
matchers to exclude both ranges from the unknown_source zone.
Explicit &&
and ||
is only possible via expression
. You can use client_ip()
inside a CEL expression. But you won't be able to import
into the middle of an expression or w/e.
and I can't use named matchers inside an expression
, correct?
Then back to the map
idea. Can I use named matchers in the
map? or maybe i can use
client_ip('10.0.0.0/8')` in the map? - I guess no.
No and no.
Really, you're best off writing your own plugin to manage this I think.
FWIW, plugins can "wrap" other plugins, so you just invoke their logic, and use their config structure, with anything extra that you want to add :)
You miiiight have more control over the matchers in JSON configuration though than you do in Caddyfile.
FWIW, plugins can "wrap" other plugins, so you just invoke their logic, and use their config structure, with anything extra that you want to add :)
Oh, that sounds really nice since my plan was to shamelessly copy paste from the http.handlers.map
, remove all regex magic and add a simple net.ParseIP
and net.ParseCIDR
.
Do you have an example plugin that wraps other plugin to point to? It's a bit unclear for me at this point how to wrap map so I wont need any pasta work.
You miiiight have more control over the matchers in JSON configuration though than you do in Caddyfile.
As I said. Shameless pasta job 😁 https://github.com/teodorescuserban/caddy-ip-map
As always, @francislavoie and @mholt to the rescue. Thank you guys! ❤️
Closing this one.
Cool, glad you got something working.
In the future, you could literally embed the maphandler.Handler
into your own struct, and as long as you also Provision()
it during your Provision()
, it you can then call its ServeHTTP() and benefit from reusing its code.
Thank you for suggestions!
The testing config looks like this and everything is working great:
{
log {
output file /logs/main.log
format json {
time_format iso8601
}
}
local_certs
}
test.rate.local {
# add here any naughty IP.
ipmap {http.request.remote.host} {is_bad_ip} {
default 0
172.16.23.128/25 1
}
# add here any referrer that would need a higher rate limit than the rest.
map {http.request.header.Referer} {is_our_app} {
default 0
~^https://(myhost|trusted\.app)\.local 1
}
# ipmap {http.request.remote.host} {is_our_ip} {
ipmap {remote_ip} {is_our_ip} {
default 0
127.0.0.1 1
10.0.0.0/8 1
192.168.22.59 1
}
rate_limit {
log_key
zone bad_ip {
match expression `{is_bad_ip} == "1"`
key {remote_host}
events 1
window 5s
}
zone our_ip {
match expression `{is_our_ip} == "1"`
key {remote_host}
events 4
window 1s
}
zone our_app {
match expression `{is_our_app} == "1"`
key {remote_host}
events 5
window 1s
}
zone unknown_source {
match expression `{is_bad_ip} == "0" && {is_our_ip} == "0" && {is_our_app} == "0"`
key {remote_host}
events 1
window 3s
}
}
respond "{remote_ip} - {http.request.header.Referer}" 200
}
Hello,
I am testing this amazing plugin, hoping i can migrate to caddy the ratelimiting part that is still in nginx.
After some trial and errors, I have a configuration that is working as expected. I would only need another feature and that is to be able to add IP ranges / classes to the
bad_ips
andour_ips
map; unfortunately I was not able to do it.How do you think I should approach this?
My current test config is below. Please note that I would rather keep the rate-limit block simple and obvious; in the real production environment I have quite a few dozens IP/subnets on both of those, as well as multiple domains to do the rate limit on; I will use snippets and templates, but I think it would be best to have the rate-limit matcher clear or enything else other than simple expressions (I know I can use
client_ip
matcher in the rate-limit, but can I use it in the map???).The regex works but it is awful. 😄
Thank you in advance!