{ track-sc0 | track-sc1 | track-sc2 } <key> [table <table>] |
sc-inc-gpc0(<sc-id>) |
sc-set-gpt0(<sc-id>) <int> |
+ silent-drop |
lua <function name>
}
[ { if | unless } <condition> ]
efficient against very dumb robots, and will significantly reduce the
load on firewalls compared to a "deny" rule. But when facing "correctly"
developed robots, it can make things worse by forcing haproxy and the
- front firewall to support insane number of concurrent connections.
+ front firewall to support insane number of concurrent connections. See
+ also the "silent-drop" action below.
- "auth" : this stops the evaluation of the rules and immediately responds
with an HTTP 401 or 407 error code to invite the user to present a valid
When set-src is successful, the source port is set to 0.
+ - "silent-drop" : this stops the evaluation of the rules and makes the
+ client-facing connection suddenly disappear using a system-dependant way
+ that tries to prevent the client from being notified. The effect it then
+ that the client still sees an established connection while there's none
+ on HAProxy. The purpose is to achieve a comparable effect to "tarpit"
+ except that it doesn't use any local resource at all on the machine
+ running HAProxy. It can resist much higher loads than "tarpit", and slow
+ down stronger attackers. It is important to undestand the impact of using
+ this mechanism. All stateful equipments placed between the client and
+ HAProxy (firewalls, proxies, load balancers) will also keep the
+ established connection for a long time and may suffer from this action.
+ On modern Linux systems running with enough privileges, the TCP_REPAIR
+ socket option is used to block the emission of a TCP reset. On other
+ systems, the socket's TTL is reduced to 1 so that the TCP reset doesn't
+ pass the first router, though it's still delivered to local networks. Do
+ not use it unless you fully understand how it works.
+
There is no limit to the number of http-request statements per instance.
It is important to know that http-request rules are processed very early in
set-var(<var-name>) <expr> |
sc-inc-gpc0(<sc-id>) |
sc-set-gpt0(<sc-id>) <int> |
+ silent-drop |
lua <function name>
}
[ { if | unless } <condition> ]
designated by <sc-id>. If an error occurs, this action silently fails and
the actions evaluation continues.
+ - "silent-drop" : this stops the evaluation of the rules and makes the
+ client-facing connection suddenly disappear using a system-dependant way
+ that tries to prevent the client from being notified. The effect it then
+ that the client still sees an established connection while there's none
+ on HAProxy. The purpose is to achieve a comparable effect to "tarpit"
+ except that it doesn't use any local resource at all on the machine
+ running HAProxy. It can resist much higher loads than "tarpit", and slow
+ down stronger attackers. It is important to undestand the impact of using
+ this mechanism. All stateful equipments placed between the client and
+ HAProxy (firewalls, proxies, load balancers) will also keep the
+ established connection for a long time and may suffer from this action.
+ On modern Linux systems running with enough privileges, the TCP_REPAIR
+ socket option is used to block the emission of a TCP reset. On other
+ systems, the socket's TTL is reduced to 1 so that the TCP reset doesn't
+ pass the first router, though it's still delivered to local networks. Do
+ not use it unless you fully understand how it works.
+
There is no limit to the number of http-response statements per instance.
It is important to know that http-response rules are processed very early in
an error occurs, this action silently fails and the actions evaluation
continues.
+ - "silent-drop" :
+ This stops the evaluation of the rules and makes the client-facing
+ connection suddenly disappear using a system-dependant way that tries
+ to prevent the client from being notified. The effect it then that the
+ client still sees an established connection while there's none on
+ HAProxy. The purpose is to achieve a comparable effect to "tarpit"
+ except that it doesn't use any local resource at all on the machine
+ running HAProxy. It can resist much higher loads than "tarpit", and
+ slow down stronger attackers. It is important to undestand the impact
+ of using this mechanism. All stateful equipments placed between the
+ client and HAProxy (firewalls, proxies, load balancers) will also keep
+ the established connection for a long time and may suffer from this
+ action. On modern Linux systems running with enough privileges, the
+ TCP_REPAIR socket option is used to block the emission of a TCP
+ reset. On other systems, the socket's TTL is reduced to 1 so that the
+ TCP reset doesn't pass the first router, though it's still delivered to
+ local networks. Do not use it unless you fully understand how it works.
+
Note that the "if/unless" condition is optional. If no condition is set on
the action, it is simply performed unconditionally. That can be useful for
"track-sc*" actions as well as for changing the default action to a reject.
- set-gpt0(<sc-id>) <int>
- lua <function>
- set-var(<var-name>) <expr>
+ - silent-drop
They have the same meaning as their counter-parts in "tcp-request connection"
so please refer to that section for a complete description.
an error occurs, this action silently fails and the actions evaluation
continues.
+ - "silent-drop" :
+ This stops the evaluation of the rules and makes the client-facing
+ connection suddenly disappear using a system-dependant way that tries
+ to prevent the client from being notified. The effect it then that the
+ client still sees an established connection while there's none on
+ HAProxy. The purpose is to achieve a comparable effect to "tarpit"
+ except that it doesn't use any local resource at all on the machine
+ running HAProxy. It can resist much higher loads than "tarpit", and
+ slow down stronger attackers. It is important to undestand the impact
+ of using this mechanism. All stateful equipments placed between the
+ client and HAProxy (firewalls, proxies, load balancers) will also keep
+ the established connection for a long time and may suffer from this
+ action. On modern Linux systems running with enough privileges, the
+ TCP_REPAIR socket option is used to block the emission of a TCP
+ reset. On other systems, the socket's TTL is reduced to 1 so that the
+ TCP reset doesn't pass the first router, though it's still delivered to
+ local networks. Do not use it unless you fully understand how it works.
+
Note that the "if/unless" condition is optional. If no condition is set on
the action, it is simply performed unconditionally. That can be useful for
for changing the default action to a reject.
#include <sys/un.h>
#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
#include <common/cfgparse.h>
#include <common/compat.h>
#include <types/global.h>
#include <types/capture.h>
#include <types/server.h>
+#include <types/connection.h>
#include <proto/acl.h>
#include <proto/action.h>
#include <proto/log.h>
#include <proto/port_range.h>
#include <proto/protocol.h>
+#include <proto/proto_http.h>
#include <proto/proto_tcp.h>
#include <proto/proxy.h>
#include <proto/sample.h>
return result;
}
+/* Executes the "silent-drop" action. May be called from {tcp,http}{request,response} */
+static enum act_return tcp_exec_action_silent_drop(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *strm, int flags)
+{
+ struct connection *conn = objt_conn(sess->origin);
+
+ if (!conn)
+ goto out;
+
+ if (!conn_ctrl_ready(conn))
+ goto out;
+
+ conn_sock_drain(conn);
+#ifdef TCP_QUICKACK
+ /* re-enable quickack if it was disabled to ack all data and avoid
+ * retransmits from the client that might trigger a real reset.
+ */
+ setsockopt(conn->t.sock.fd, SOL_TCP, TCP_QUICKACK, &one, sizeof(one));
+#endif
+ /* lingering must absolutely be disabled so that we don't send a
+ * shutdown(), this is critical to the TCP_REPAIR trick. When no stream
+ * is present, returning with ERR will cause lingering to be disabled.
+ */
+ if (strm)
+ strm->si[0].flags |= SI_FL_NOLINGER;
+
+#ifdef TCP_REPAIR
+ if (setsockopt(conn->t.sock.fd, SOL_TCP, TCP_REPAIR, &one, sizeof(one)) == 0) {
+ /* socket will be quiet now */
+ goto out;
+ }
+#endif
+ /* either TCP_REPAIR is not defined or it failed (eg: permissions).
+ * Let's fall back on the TTL trick, though it only works for routed
+ * network and has no effect on local net.
+ */
+#ifdef IP_TTL
+ setsockopt(conn->t.sock.fd, SOL_IP, IP_TTL, &one, sizeof(one));
+#endif
+ out:
+ /* kill the stream if any */
+ if (strm) {
+ channel_abort(&strm->req);
+ channel_abort(&strm->res);
+ strm->req.analysers = 0;
+ strm->res.analysers = 0;
+ strm->be->be_counters.denied_req++;
+ if (!(strm->flags & SF_ERR_MASK))
+ strm->flags |= SF_ERR_PRXCOND;
+ if (!(strm->flags & SF_FINST_MASK))
+ strm->flags |= SF_FINST_R;
+ }
+
+ sess->fe->fe_counters.denied_req++;
+ if (sess->listener->counters)
+ sess->listener->counters->denied_req++;
+
+ return ACT_RET_STOP;
+}
+
/* Parse a tcp-response rule. Return a negative value in case of failure */
static int tcp_parse_response_rule(char **args, int arg, int section_type,
struct proxy *curpx, struct proxy *defpx,
return -1;
}
+/* Parse a "silent-drop" action. It takes no argument. It returns ACT_RET_PRS_OK on
+ * success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret tcp_parse_silent_drop(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ rule->action = ACT_CUSTOM;
+ rule->action_ptr = tcp_exec_action_silent_drop;
+ return ACT_RET_PRS_OK;
+}
+
/************************************************************************/
/* All supported sample fetch functions must be declared here */
{ NULL, NULL, 0 },
}};
+
+static struct action_kw_list tcp_req_conn_actions = {ILH, {
+ { "silent-drop", tcp_parse_silent_drop },
+ { /* END */ }
+}};
+
+static struct action_kw_list tcp_req_cont_actions = {ILH, {
+ { "silent-drop", tcp_parse_silent_drop },
+ { /* END */ }
+}};
+
+static struct action_kw_list tcp_res_cont_actions = {ILH, {
+ { "silent-drop", tcp_parse_silent_drop },
+ { /* END */ }
+}};
+
+static struct action_kw_list http_req_actions = {ILH, {
+ { "silent-drop", tcp_parse_silent_drop },
+ { /* END */ }
+}};
+
+static struct action_kw_list http_res_actions = {ILH, {
+ { "silent-drop", tcp_parse_silent_drop },
+ { /* END */ }
+}};
+
+
__attribute__((constructor))
static void __tcp_protocol_init(void)
{
cfg_register_keywords(&cfg_kws);
acl_register_keywords(&acl_kws);
bind_register_keywords(&bind_kws);
+ tcp_req_conn_keywords_register(&tcp_req_conn_actions);
+ tcp_req_cont_keywords_register(&tcp_req_cont_actions);
+ tcp_res_cont_keywords_register(&tcp_res_cont_actions);
+ http_req_keywords_register(&http_req_actions);
+ http_res_keywords_register(&http_res_actions);
}