mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-11 08:19:29 +00:00
MEDIUM: spoe: Add support of ACLS to enable or disable sending of SPOE messages
Now, it is possible to conditionnaly send a SPOE message by adding an ACL-based condition on the "event" line, in a "spoe-message" section. Here is the example coming for the SPOE documentation: spoe-message get-ip-reputation args ip=src event on-client-session if ! { src -f /etc/haproxy/whitelist.lst } To avoid mixin with proxy's ACLs, each SPOE message has its private ACL list. It possible to declare named ACLs in "spoe-message" section, using the same syntax than for proxies. So we can rewrite the previous example to use a named ACL: spoe-message get-ip-reputation args ip=src acl ip-whitelisted src -f /etc/haproxy/whitelist.lst event on-client-session if ! ip-whitelisted ACL-based conditions are executed in the context of the stream that handle the client and the server connections.
This commit is contained in:
parent
1b421eab87
commit
57583e474e
31
doc/SPOE.txt
31
doc/SPOE.txt
@ -1,7 +1,7 @@
|
||||
-----------------------------------------------
|
||||
Stream Processing Offload Engine (SPOE)
|
||||
Version 1.1
|
||||
( Last update: 2017-02-27 )
|
||||
Version 1.2
|
||||
( Last update: 2017-09-22 )
|
||||
-----------------------------------------------
|
||||
Author : Christopher Faulet
|
||||
Contact : cfaulet at haproxy dot com
|
||||
@ -351,12 +351,20 @@ spoe-message <name>
|
||||
|
||||
Here you define a message that can be referenced in a "spoe-agent"
|
||||
section. Following keywords are supported :
|
||||
- acl
|
||||
- args
|
||||
- event
|
||||
|
||||
See also: "spoe-agent" section.
|
||||
|
||||
|
||||
acl <aclname> <criterion> [flags] [operator] <value> ...
|
||||
|
||||
Declare or complete an access list.
|
||||
|
||||
See section 7 about ACL usage in the HAProxy Configuration Manual.
|
||||
|
||||
|
||||
args [name=]<sample> ...
|
||||
Define arguments passed into the SPOE message.
|
||||
|
||||
@ -371,11 +379,17 @@ args [name=]<sample> ...
|
||||
args frontend=fe_id src dst
|
||||
|
||||
|
||||
event <name>
|
||||
Set the event that triggers sending of the message.
|
||||
event <name> [ { if | unless } <condition> ]
|
||||
Set the event that triggers sending of the message. It may optionally be
|
||||
followed by an ACL-based condition, in which case it will only be evaluated
|
||||
if the condition is true.
|
||||
|
||||
Argument :
|
||||
<name> is the event name.
|
||||
ACL-based conditions are executed in the context of the stream that handle
|
||||
the client and the server connections.
|
||||
|
||||
Arguments :
|
||||
<name> is the event name.
|
||||
<condition> is a standard ACL-based condition.
|
||||
|
||||
Supported events are:
|
||||
- on-client-session
|
||||
@ -387,7 +401,8 @@ event <name>
|
||||
- on-backend-http-request
|
||||
- on-http-response
|
||||
|
||||
See section "Events & Messages".
|
||||
See section "Events & Messages" for more details about supported events.
|
||||
See section 7 about ACL usage in the HAProxy Configuration Manual.
|
||||
|
||||
2.4. Example
|
||||
-------------
|
||||
@ -441,7 +456,7 @@ and 0 a blacklisted IP with no doubt).
|
||||
|
||||
spoe-message get-ip-reputation
|
||||
args ip=src
|
||||
event on-client-session
|
||||
event on-client-session if ! { src -f /etc/haproxy/whitelist.lst }
|
||||
|
||||
|
||||
3. SPOP specification
|
||||
|
@ -184,6 +184,8 @@ struct spoe_message {
|
||||
struct list args; /* Arguments added when the SPOE messages is sent */
|
||||
struct list list; /* Used to chain SPOE messages */
|
||||
|
||||
struct list acls; /* ACL declared on this message */
|
||||
struct acl_cond *cond; /* acl condition to meet */
|
||||
enum spoe_event event; /* SPOE_EV_* */
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <types/global.h>
|
||||
#include <types/spoe.h>
|
||||
|
||||
#include <proto/acl.h>
|
||||
#include <proto/arg.h>
|
||||
#include <proto/backend.h>
|
||||
#include <proto/filters.h>
|
||||
@ -107,18 +108,28 @@ spoe_release_msg_placeholder(struct spoe_msg_placeholder *mp)
|
||||
static void
|
||||
spoe_release_message(struct spoe_message *msg)
|
||||
{
|
||||
struct spoe_arg *arg, *back;
|
||||
struct spoe_arg *arg, *argback;
|
||||
struct acl *acl, *aclback;
|
||||
|
||||
if (!msg)
|
||||
return;
|
||||
free(msg->id);
|
||||
free(msg->conf.file);
|
||||
list_for_each_entry_safe(arg, back, &msg->args, list) {
|
||||
list_for_each_entry_safe(arg, argback, &msg->args, list) {
|
||||
release_sample_expr(arg->expr);
|
||||
free(arg->name);
|
||||
LIST_DEL(&arg->list);
|
||||
free(arg);
|
||||
}
|
||||
list_for_each_entry_safe(acl, aclback, &msg->acls, list) {
|
||||
LIST_DEL(&acl->list);
|
||||
prune_acl(acl);
|
||||
free(acl);
|
||||
}
|
||||
if (msg->cond) {
|
||||
prune_acl_cond(msg->cond);
|
||||
free(msg->cond);
|
||||
}
|
||||
free(msg);
|
||||
}
|
||||
|
||||
@ -2070,7 +2081,8 @@ spoe_queue_context(struct spoe_context *ctx)
|
||||
**************************************************************************/
|
||||
/* Encode SPOE messages for a specific event. Info in <ctx->frag_ctx>, if any,
|
||||
* are used to handle fragmented content. On success it returns 1. If an error
|
||||
* occurred, -1 is returned. */
|
||||
* occurred, -1 is returned. If nothing has been encoded, it returns 0 (this is
|
||||
* only possible for unfragmented payload). */
|
||||
static int
|
||||
spoe_encode_messages(struct stream *s, struct spoe_context *ctx,
|
||||
struct list *messages, int dir)
|
||||
@ -2099,6 +2111,19 @@ spoe_encode_messages(struct stream *s, struct spoe_context *ctx,
|
||||
ctx->frag_ctx.curoff = UINT_MAX;
|
||||
|
||||
encode_message:
|
||||
if (msg->cond) {
|
||||
int ret = 1;
|
||||
|
||||
ret = acl_exec_cond(msg->cond, s->be, s->sess, s, dir|SMP_OPT_FINAL);
|
||||
ret = acl_pass(ret);
|
||||
if (msg->cond->pol == ACL_COND_UNLESS)
|
||||
ret = !ret;
|
||||
|
||||
/* the rule does not match */
|
||||
if (!ret)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Resume encoding of a SPOE argument */
|
||||
if (ctx->frag_ctx.curarg != NULL) {
|
||||
arg = ctx->frag_ctx.curarg;
|
||||
@ -2149,6 +2174,10 @@ spoe_encode_messages(struct stream *s, struct spoe_context *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
/* nothing has been encoded for an unfragmented payload */
|
||||
if (!(ctx->flags & SPOE_CTX_FL_FRAGMENTED) && p == ctx->buffer->p)
|
||||
goto skip;
|
||||
|
||||
SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
|
||||
" - encode %s messages - spoe_appctx=%p"
|
||||
"- max_size=%u - encoded=%ld\n",
|
||||
@ -2163,6 +2192,7 @@ spoe_encode_messages(struct stream *s, struct spoe_context *ctx,
|
||||
ctx->frag_ctx.curarg = NULL;
|
||||
ctx->frag_ctx.curoff = 0;
|
||||
ctx->frag_ctx.flags = SPOE_FRM_FL_FIN;
|
||||
|
||||
return 1;
|
||||
|
||||
too_big:
|
||||
@ -2184,6 +2214,13 @@ spoe_encode_messages(struct stream *s, struct spoe_context *ctx,
|
||||
ctx->flags |= SPOE_CTX_FL_FRAGMENTED;
|
||||
ctx->frag_ctx.flags &= ~SPOE_FRM_FL_FIN;
|
||||
return 1;
|
||||
|
||||
skip:
|
||||
SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
|
||||
" - skip the frame because nothing has been encoded\n",
|
||||
(int)now.tv_sec, (int)now.tv_usec,
|
||||
agent->id, __FUNCTION__, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2477,6 +2514,8 @@ spoe_process_event(struct stream *s, struct spoe_context *ctx,
|
||||
ret = spoe_encode_messages(s, ctx, &(ctx->messages[ev]), dir);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
if (!ret)
|
||||
goto skip;
|
||||
ctx->state = SPOE_CTX_ST_SENDING_MSGS;
|
||||
}
|
||||
|
||||
@ -3320,6 +3359,7 @@ cfg_parse_spoe_message(const char *file, int linenum, char **args, int kwm)
|
||||
curmsg->conf.line = linenum;
|
||||
curmsg->nargs = 0;
|
||||
LIST_INIT(&curmsg->args);
|
||||
LIST_INIT(&curmsg->acls);
|
||||
LIST_ADDQ(&curmsgs, &curmsg->list);
|
||||
}
|
||||
else if (!strcmp(args[0], "args")) {
|
||||
@ -3365,14 +3405,29 @@ cfg_parse_spoe_message(const char *file, int linenum, char **args, int kwm)
|
||||
curproxy->conf.args.file = NULL;
|
||||
curproxy->conf.args.line = 0;
|
||||
}
|
||||
else if (!strcmp(args[0], "acl")) {
|
||||
err = invalid_char(args[1]);
|
||||
if (err) {
|
||||
Alert("parsing [%s:%d] : character '%c' is not permitted in acl name '%s'.\n",
|
||||
file, linenum, *err, args[1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
if (parse_acl((const char **)args + 1, &curmsg->acls, &errmsg, &curproxy->conf.args, file, linenum) == NULL) {
|
||||
Alert("parsing [%s:%d] : error detected while parsing ACL '%s' : %s.\n",
|
||||
file, linenum, args[1], errmsg);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(args[0], "event")) {
|
||||
if (!*args[1]) {
|
||||
Alert("parsing [%s:%d] : missing event name.\n", file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
if (alertif_too_many_args(1, file, linenum, args, &err_code))
|
||||
goto out;
|
||||
/* if (alertif_too_many_args(1, file, linenum, args, &err_code)) */
|
||||
/* goto out; */
|
||||
|
||||
if (!strcmp(args[1], spoe_event_str[SPOE_EV_ON_CLIENT_SESS]))
|
||||
curmsg->event = SPOE_EV_ON_CLIENT_SESS;
|
||||
@ -3398,6 +3453,29 @@ cfg_parse_spoe_message(const char *file, int linenum, char **args, int kwm)
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0) {
|
||||
struct acl_cond *cond;
|
||||
|
||||
cond = build_acl_cond(file, linenum, &curmsg->acls,
|
||||
curproxy, (const char **)args+2,
|
||||
&errmsg);
|
||||
if (cond == NULL) {
|
||||
Alert("parsing [%s:%d] : error detected while "
|
||||
"parsing an 'event %s' condition : %s.\n",
|
||||
file, linenum, args[1], errmsg);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
curmsg->cond = cond;
|
||||
}
|
||||
else if (*args[2]) {
|
||||
Alert("parsing [%s:%d]: 'event %s' expects either 'if' "
|
||||
"or 'unless' followed by a condition but found '%s'.\n",
|
||||
file, linenum, args[1], args[2]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (!*args[0]) {
|
||||
Alert("parsing [%s:%d] : unknown keyword '%s' in spoe-message section.\n",
|
||||
|
Loading…
Reference in New Issue
Block a user