diff --git a/include/haproxy/stream-t.h b/include/haproxy/stream-t.h index 363b7eb75..9589c3048 100644 --- a/include/haproxy/stream-t.h +++ b/include/haproxy/stream-t.h @@ -289,8 +289,11 @@ struct stream { void *current_rule; /* this is used to store the current rule to be resumed. */ int rules_exp; /* expiration date for current rules execution */ int tunnel_timeout; - const char *last_rule_file; /* last evaluated final rule's file (def: NULL) */ - int last_rule_line; /* last evaluated final rule's line (def: 0) */ + + struct { + void *ptr; /* Pointer on the entity (def: NULL) */ + int type; /* entity type (0: undef, 1: rule) */ + } last_entity; /* last evaluated entity that interrupted processing */ unsigned int stream_epoch; /* copy of stream_epoch when the stream was created */ struct hlua *hlua[2]; /* lua runtime context (0: global, 1: per-thread) */ diff --git a/src/http_ana.c b/src/http_ana.c index ab9124d79..d83709af7 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -2739,8 +2739,8 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis break; case ACT_RET_STOP: rule_ret = HTTP_RULE_RES_STOP; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_YIELD: s->current_rule = rule; @@ -2748,8 +2748,8 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis send_log(s->be, LOG_WARNING, "Internal error: action yields while it is no long allowed " "for the http-request actions."); - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; rule_ret = HTTP_RULE_RES_ERROR; goto end; } @@ -2757,30 +2757,30 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis goto end; case ACT_RET_ERR: rule_ret = HTTP_RULE_RES_ERROR; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_DONE: rule_ret = HTTP_RULE_RES_DONE; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_DENY: if (txn->status == -1) txn->status = 403; rule_ret = HTTP_RULE_RES_DENY; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_ABRT: rule_ret = HTTP_RULE_RES_ABRT; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_INV: rule_ret = HTTP_RULE_RES_BADREQ; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; } continue; /* eval the next rule */ @@ -2790,16 +2790,16 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis switch (rule->action) { case ACT_ACTION_ALLOW: rule_ret = HTTP_RULE_RES_STOP; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_ACTION_DENY: txn->status = rule->arg.http_reply->status; txn->http_reply = rule->arg.http_reply; rule_ret = HTTP_RULE_RES_DENY; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_HTTP_REQ_TARPIT: @@ -2807,8 +2807,8 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis txn->status = rule->arg.http_reply->status; txn->http_reply = rule->arg.http_reply; rule_ret = HTTP_RULE_RES_DENY; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_HTTP_REDIR: { @@ -2818,8 +2818,8 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis break; rule_ret = ret ? HTTP_RULE_RES_ABRT : HTTP_RULE_RES_ERROR; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; } @@ -2913,8 +2913,8 @@ static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct lis break; case ACT_RET_STOP: rule_ret = HTTP_RULE_RES_STOP; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_YIELD: s->current_rule = rule; @@ -2922,8 +2922,8 @@ static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct lis send_log(s->be, LOG_WARNING, "Internal error: action yields while it is no long allowed " "for the http-response/http-after-response actions."); - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; rule_ret = HTTP_RULE_RES_ERROR; goto end; } @@ -2931,30 +2931,30 @@ static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct lis goto end; case ACT_RET_ERR: rule_ret = HTTP_RULE_RES_ERROR; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_DONE: rule_ret = HTTP_RULE_RES_DONE; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_DENY: if (txn->status == -1) txn->status = 502; rule_ret = HTTP_RULE_RES_DENY; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_ABRT: rule_ret = HTTP_RULE_RES_ABRT; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_INV: rule_ret = HTTP_RULE_RES_BADREQ; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; } continue; /* eval the next rule */ @@ -2964,16 +2964,16 @@ static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct lis switch (rule->action) { case ACT_ACTION_ALLOW: rule_ret = HTTP_RULE_RES_STOP; /* "allow" rules are OK */ - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_ACTION_DENY: txn->status = rule->arg.http_reply->status; txn->http_reply = rule->arg.http_reply; rule_ret = HTTP_RULE_RES_DENY; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_HTTP_REDIR: { @@ -2983,8 +2983,8 @@ static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct lis break; rule_ret = ret ? HTTP_RULE_RES_ABRT : HTTP_RULE_RES_ERROR; - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; } /* other flags exists, but normally, they never be matched. */ diff --git a/src/stream.c b/src/stream.c index 34696bd2c..618f350f7 100644 --- a/src/stream.c +++ b/src/stream.c @@ -389,8 +389,8 @@ struct stream *stream_new(struct session *sess, struct stconn *sc, struct buffer s->current_rule_list = NULL; s->current_rule = NULL; s->rules_exp = TICK_ETERNITY; - s->last_rule_file = NULL; - s->last_rule_line = 0; + s->last_entity.type = 0; + s->last_entity.ptr = NULL; s->stkctr = NULL; if (pool_head_stk_ctr) { @@ -4095,25 +4095,51 @@ static int smp_fetch_cur_tunnel_timeout(const struct arg *args, struct sample *s static int smp_fetch_last_rule_file(const struct arg *args, struct sample *smp, const char *km, void *private) { + struct act_rule *rule; + smp->flags = SMP_F_VOL_TXN; smp->data.type = SMP_T_STR; - if (!smp->strm || !smp->strm->last_rule_file) + if (!smp->strm || smp->strm->last_entity.type != 1) return 0; + rule = smp->strm->last_entity.ptr; smp->flags |= SMP_F_CONST; - smp->data.u.str.area = (char *)smp->strm->last_rule_file; - smp->data.u.str.data = strlen(smp->strm->last_rule_file); + smp->data.u.str.area = (char *)rule->conf.file; + smp->data.u.str.data = strlen(rule->conf.file); return 1; } static int smp_fetch_last_rule_line(const struct arg *args, struct sample *smp, const char *km, void *private) { + struct act_rule *rule; + smp->flags = SMP_F_VOL_TXN; smp->data.type = SMP_T_SINT; - if (!smp->strm || !smp->strm->last_rule_line) + if (!smp->strm || smp->strm->last_entity.type != 1) + return 0; + + rule = smp->strm->last_entity.ptr; + smp->data.u.sint = rule->conf.line; + return 1; +} + +static int smp_fetch_last_entity(const struct arg *args, struct sample *smp, const char *km, void *private) +{ + smp->flags = SMP_F_VOL_TXN; + smp->data.type = SMP_T_STR; + if (!smp->strm) + return 0; + + if (smp->strm->last_entity.type == 1) { + struct act_rule *rule = smp->strm->last_entity.ptr; + struct buffer *trash = get_trash_chunk(); + + trash->data = snprintf(trash->area, trash->size, "%s:%d", rule->conf.file, rule->conf.line); + smp->data.u.str = *trash; + } + else return 0; - smp->data.u.sint = smp->strm->last_rule_line; return 1; } @@ -4178,6 +4204,7 @@ static struct sample_fetch_kw_list smp_kws = {ILH, { { "cur_client_timeout", smp_fetch_cur_client_timeout, 0, NULL, SMP_T_SINT, SMP_USE_FTEND, }, { "cur_server_timeout", smp_fetch_cur_server_timeout, 0, NULL, SMP_T_SINT, SMP_USE_BKEND, }, { "cur_tunnel_timeout", smp_fetch_cur_tunnel_timeout, 0, NULL, SMP_T_SINT, SMP_USE_BKEND, }, + { "last_entity", smp_fetch_last_entity, 0, NULL, SMP_T_STR, SMP_USE_INTRN, }, { "last_rule_file", smp_fetch_last_rule_file, 0, NULL, SMP_T_STR, SMP_USE_INTRN, }, { "last_rule_line", smp_fetch_last_rule_line, 0, NULL, SMP_T_SINT, SMP_USE_INTRN, }, { "txn.conn_retries", smp_fetch_conn_retries, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV, }, diff --git a/src/tcp_rules.c b/src/tcp_rules.c index 2613056f7..d3263b075 100644 --- a/src/tcp_rules.c +++ b/src/tcp_rules.c @@ -166,8 +166,8 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit) break; case ACT_RET_STOP: case ACT_RET_DONE: - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_YIELD: s->current_rule = rule; @@ -175,26 +175,26 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit) send_log(s->be, LOG_WARNING, "Internal error: yield not allowed if the inspect-delay expired " "for the tcp-request content actions."); - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto internal; } goto missing_data; case ACT_RET_DENY: - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto deny; case ACT_RET_ABRT: - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto abort; case ACT_RET_ERR: - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto internal; case ACT_RET_INV: - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto invalid; } continue; /* eval the next rule */ @@ -202,13 +202,13 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit) /* If not action function defined, check for known actions */ if (rule->action == ACT_ACTION_ALLOW) { - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; } else if (rule->action == ACT_ACTION_DENY) { - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto deny; } } @@ -350,8 +350,8 @@ int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit) break; case ACT_RET_STOP: case ACT_RET_DONE: - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; case ACT_RET_YIELD: s->current_rule = rule; @@ -359,27 +359,27 @@ int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit) send_log(s->be, LOG_WARNING, "Internal error: yield not allowed if the inspect-delay expired " "for the tcp-response content actions."); - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto internal; } channel_dont_close(rep); goto missing_data; case ACT_RET_DENY: - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto deny; case ACT_RET_ABRT: - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto abort; case ACT_RET_ERR: - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto internal; case ACT_RET_INV: - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto invalid; } continue; /* eval the next rule */ @@ -387,13 +387,13 @@ int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit) /* If not action function defined, check for known actions */ if (rule->action == ACT_ACTION_ALLOW) { - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; } else if (rule->action == ACT_ACTION_DENY) { - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto deny; } else if (rule->action == ACT_TCP_CLOSE) { @@ -401,8 +401,8 @@ int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit) sc_must_kill_conn(s->scb); sc_abort(s->scb); sc_shutdown(s->scb); - s->last_rule_file = rule->conf.file; - s->last_rule_line = rule->conf.line; + s->last_entity.type = 1; + s->last_entity.ptr = rule; goto end; } }