Created
December 9, 2018 08:25
-
-
Save robbat2/2c8414bd617c013be12cb9b41830e010 to your computer and use it in GitHub Desktop.
rsync haproxy frontend with ratelimiting & deny, uses haproxy-lua
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
# This is a very very minimal rsync config that gives ratelimit and ban messages | |
global | |
lua-load 01-deny-rsync.lua | |
frontend fe_rsync | |
mode tcp | |
bind *:9873 | |
tcp-request content set-var(txn.rsync_deny_message) str("") # Start empty | |
# Track the backend state | |
acl rsync_dead nbsrv(be_rsync) lt 1 | |
# Clients will see 'rsync: did not see server greeting' | |
tcp-request content reject if rsync_dead | |
# Clients will see 'rsync offline' | |
tcp-request content set-var(txn.rsync_deny_message) str("rsync offline") if rsync_dead | |
# Track abuse | |
stick-table type ip size 200k expire 30s store gpc0,conn_rate(10s),http_req_rate(10s) | |
acl source_is_abuser src_get_gpc0 gt 0 | |
acl conn_rate_abuse sc1_conn_rate gt 3 | |
acl mark_as_abuser sc1_inc_gpc0 ge 0 | |
tcp-request connection track-sc1 src | |
tcp-request content set-var(txn.rsync_deny_message) str("BANHAMMER") if conn_rate_abuse mark_as_abuser source_is_abuser | |
# If the deny message is longer than zero, issue deny message | |
# Clients will see the message and the rsync client will exit with a SUCCESS state! | |
tcp-request content use-service lua.deny-rsync if { var(txn.rsync_deny_message) -m len gt 0 } | |
# Otherwise use the backend | |
default_backend be_rsync | |
backend be_rsync | |
mode tcp | |
# This gives pure HAProxy check | |
# Other alternatives would be external-check that execs rsync or very | |
# bleeding edge lua-check | |
option tcp-check | |
tcp-check connect | |
# Step 1 | |
tcp-check comment "Client Initialization" | |
tcp-check send "@RSYNCD: 28.0\n" | |
# Step 2 | |
tcp-check comment "Server Initialization" | |
tcp-check expect rstring "@RSYNCD: [0-9.]+" | |
# Step 3 | |
tcp-check comment "Client Query (module name rsync-health)" | |
tcp-check send "rsync-health\n" | |
# Step 4 | |
tcp-check comment "Data (module name rsync-health)" | |
tcp-check expect string "@RSYNCD: OK\n" | |
# If the directory for the healthcheck does not exist, rsync will generate | |
# "@ERROR: chroot failed" | |
# Step 5 | |
tcp-check comment "Cleanup" | |
tcp-check send "@RSYNCD: EXIT\n" | |
# This still leads to messy logs in rsync itself | |
# and rsync doesn't have the original source IP (does it really need it?) | |
# rsyncd[6562]: connect from localhost (127.0.0.1) | |
# rsyncd[6562]: rsync: safe_read failed to read 1 bytes [Receiver]: Connection reset by peer (104) | |
# rsyncd[6562]: rsync error: error in rsync protocol data stream (code 12) at io.c(276) [Receiver=3.1.3] | |
# This is where we'd put the realservers using discovery | |
server localhost localhost:873 check | |
# Service discovery instead would look like: | |
#server-template gentoo-rsync 50 _gentoo-rsync._tcp.service.consul resolvers consul resolve-prefer ipv4 maxconn 64 check rise 3 fall 2 check | |
#resolvers consul | |
# nameserver consul $consul-client-ip:8600 | |
# resolve_retries 30 | |
# timeout retry 2s | |
# hold valid 120s | |
# accepted_payload_size 8192 |
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
function rsync_deny(applet) | |
applet:send("@RSYNCD: 29.0\n") | |
local banmsg = applet:get_var("txn.rsync_deny_message") | |
if banmsg == nil then | |
banmsg = "MESSAGE GOES HERE" | |
end | |
applet:send(banmsg) | |
applet:send("\n") | |
applet:send("@RSYNCD: EXIT\n") | |
end | |
core.register_service("deny-rsync", "tcp", rsync_deny) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment