Hi all, Please find enclosed a few patches which adds a new HTTP action into HAProxy: do-resolve. This action can be used to perform DNS resolution based on information found in the client request and the result is stored in an HAProxy variable (to discover the IP address of the server on the fly or logging purpose, etc...).
This feature should not be used "as is" to find out the server IP address since an attacker may use it to scan your network. So always combine it with some ACLs to refuse destination IP such as loopback, private subnets, HAProxy's public IP,etc... Enjoy! Baptiste
From e0b9d65ef140f6eba2909891fa98cb837caf62c7 Mon Sep 17 00:00:00 2001 From: Baptiste Assmann <[email protected]> Date: Tue, 30 Jan 2018 08:18:57 +0100 Subject: [PATCH 4/4] MINOR: action: new 'http-request do-resolve' action The 'do-resolve' action is an http-request action which allows to run DNS resolution at run time in HAProxy. The name to be resolved can be picked up in the request sent by the client and the result of the resolution is stored in a variable. The time the resolution is being performed, the request is on pause. If the resolution can't provide a suitable result, then the variable will be empty. It's up to the admin to take decisions based on this statement (return 503 to prevent loops). Read carefully the documentation concerning this feature, to ensure your setup is secure and safe to be used in production. --- doc/configuration.txt | 57 ++++++++++- include/proto/action.h | 3 + include/proto/dns.h | 2 + include/types/action.h | 8 ++ include/types/stream.h | 10 ++ src/action.c | 34 +++++++ src/cfgparse.c | 18 ++++ src/dns.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++ src/proto_http.c | 16 +++ src/stream.c | 11 +++ 10 files changed, 415 insertions(+), 1 deletion(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 1ce423b..683a6ea 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -3906,7 +3906,8 @@ http-request { allow | auth [realm <realm>] | redirect <rule> | reject | sc-set-gpt0(<sc-id>) <int> | silent-drop | send-spoe-group | - cache-use + cache-use | + do-resolve(<var>,<resolvers>,[ipv4,ipv6]) <expr> } [ { if | unless } <condition> ] Access control for Layer 7 requests @@ -4328,6 +4329,60 @@ http-request { allow | auth [realm <realm>] | redirect <rule> | reject | <group-name> The SPOE group name as specified in the engine configuration. + - do-resolve(<var>,<resolvers>,[ipv4,ipv6]) <expr> : + This action performs a DNS resolution of the output of <expr> and stores + the result in the variable <var>. It uses the DNS resolvers section + pointed by <resolvers>. + It is possible to choose a resolution preference using the optional + arguments 'ipv4' or 'ipv6'. + When performing the DNS resolution, the client side connection is on + pause waiting till the end of the resolution. + If an IP address can be found, it is stored into <var>. If any kind of + error occurs, then <var> is not set. + One can use this action to discover a server IP address at run time and + based on information found in the request (IE a Host header). + If this action is used to find the server's IP address (using the + "set-dst" action), then the server IP address in the backend must be set + to 0.0.0.0. + + Example: + resolvers mydns + nameserver local 127.0.0.53:53 + nameserver google 8.8.8.8:53 + timeout retry 1s + hold valid 10s + hold nx 3s + hold other 3s + hold obsolete 0s + accepted_payload_size 8192 + + frontend fe + bind 10.42.0.1:80 + http-request do-resolve(txn.myip,mydns,ipv4) hdr(Host),lower + http-request capture var(txn.myip) len 40 + + # return 503 when the variable is not set, + # which mean DNS resolution error + use_backend b_503 unless { var(txn.myip) -m found } + + default_backend be + + backend b_503 + # dummy backend used to return 503. + # one can use the errorfile directive to send a nice + # 503 error page to end users + + backend be + # rule to prevent HAProxy from reconnecting to services + # on the local network (forged DNS name used to scan the network) + http-request deny if { var(txn.myip) -m ip 127.0.0.0/8 10.0.0.0/8 } + http-request set-dst var(txn.myip) + server clear 0.0.0.0:0 + + NOTE: Don't forget to set the "protection" rules to ensure HAProxy won't + be used to scan the network or worst won't loop over itself... + + 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 diff --git a/include/proto/action.h b/include/proto/action.h index e3015ec..0a8a1a9 100644 --- a/include/proto/action.h +++ b/include/proto/action.h @@ -24,6 +24,9 @@ #include <types/action.h> +int act_resolution_cb(struct dns_requester *requester, struct dns_nameserver *nameserver); +int act_resolution_error_cb(struct dns_requester *requester, int error_code); + static inline struct action_kw *action_lookup(struct list *keywords, const char *kw) { struct action_kw_list *kw_list; diff --git a/include/proto/dns.h b/include/proto/dns.h index 3ad79c3..f3e8ab8 100644 --- a/include/proto/dns.h +++ b/include/proto/dns.h @@ -22,6 +22,7 @@ #ifndef _PROTO_DNS_H #define _PROTO_DNS_H +#include <types/action.h> #include <types/dns.h> extern struct list dns_resolvers; @@ -43,6 +44,7 @@ int dns_get_ip_from_response(struct dns_response_packet *dns_p, int dns_link_resolution(void *requester, int requester_type, int requester_locked); void dns_unlink_resolution(struct dns_requester *requester); void dns_trigger_resolution(struct dns_requester *requester); +enum act_parse_ret dns_parse_do_resolve(const char **args, int *orig_arg, struct proxy *px, struct act_rule *rule, char **err); #endif // _PROTO_DNS_H diff --git a/include/types/action.h b/include/types/action.h index 04a9f18..505387f 100644 --- a/include/types/action.h +++ b/include/types/action.h @@ -77,6 +77,7 @@ enum act_name { ACT_HTTP_DEL_ACL, ACT_HTTP_DEL_MAP, ACT_HTTP_SET_MAP, + ACT_HTTP_DO_RESOLVE, /* http request actions. */ ACT_HTTP_REQ_TARPIT, @@ -107,6 +108,13 @@ struct act_rule { struct applet applet; /* used for the applet registration. */ union { struct { + struct sample_expr *expr; + char *varname; + char *resolvers_id; + struct dns_resolvers *resolvers; + struct dns_options dns_opts; + } dns; /* dns resolution */ + struct { char *realm; } auth; /* arg used by "auth" */ struct { diff --git a/include/types/stream.h b/include/types/stream.h index a2b650e..29e52c5 100644 --- a/include/types/stream.h +++ b/include/types/stream.h @@ -167,6 +167,16 @@ struct stream { struct list *current_rule_list; /* this is used to store the current executed rule list. */ void *current_rule; /* this is used to store the current rule to be resumed. */ struct hlua *hlua; /* lua runtime context */ + + /* Context */ + union { + struct { + struct dns_requester *dns_requester; + char *hostname_dn; + int hostname_dn_len; + struct act_rule *parent; + } dns; + } ctx; }; #endif /* _TYPES_STREAM_H */ diff --git a/src/action.c b/src/action.c index 54d27a0..6bc61a9 100644 --- a/src/action.c +++ b/src/action.c @@ -16,8 +16,10 @@ #include <common/standard.h> #include <proto/action.h> +#include <proto/obj_type.h> #include <proto/proxy.h> #include <proto/stick_table.h> +#include <proto/task.h> /* Find and check the target table used by an action ACT_ACTION_TRK_*. This @@ -62,3 +64,35 @@ int check_trk_action(struct act_rule *rule, struct proxy *px, char **err) return 1; } +int act_resolution_cb(struct dns_requester *requester, struct dns_nameserver *nameserver) +{ + struct stream *stream = NULL; + + if (requester->resolution == NULL) + return 0; + + stream = objt_stream(requester->owner); + if (stream == NULL) + return 0; + + task_wakeup(stream->task, TASK_WOKEN_MSG); + + return 0; +} + +int act_resolution_error_cb(struct dns_requester *requester, int error_code) +{ + struct stream *stream = NULL; + + if (requester->resolution == NULL) + return 0; + + stream = objt_stream(requester->owner); + if (stream == NULL) + return 0; + + task_wakeup(stream->task, TASK_WOKEN_MSG); + + return 0; +} + diff --git a/src/cfgparse.c b/src/cfgparse.c index 2e10e35..49206ba 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -8087,6 +8087,24 @@ int check_config_validity() free(err); cfgerr++; } + /* link do-resolve HTTP action to its resolvers section */ + if (arule->action == ACT_HTTP_DO_RESOLVE) { + struct dns_resolvers *resolvers = NULL; + + if (arule->arg.dns.resolvers_id == NULL) { + ha_alert("Proxy '%s': %s.\n", curproxy->id, "do-resolve action without resolvers"); + cfgerr++; + err_code |= ERR_FATAL; + } + else if ((resolvers = find_resolvers_by_id(arule->arg.dns.resolvers_id)) == NULL) { + ha_alert("Proxy '%s': %s.\n", curproxy->id, "resolvers of do-resolve action is unknown"); + cfgerr++; + err_code |= ERR_FATAL; + } + + arule->arg.dns.resolvers = resolvers; + } + } /* check validity for 'http-response' layer 7 rules */ diff --git a/src/dns.c b/src/dns.c index 1d1636f..6fb2746 100644 --- a/src/dns.c +++ b/src/dns.c @@ -24,23 +24,28 @@ #include <common/ticks.h> #include <common/net_helper.h> +#include <types/action.h> #include <types/applet.h> #include <types/cli.h> #include <types/global.h> #include <types/dns.h> #include <types/stats.h> +#include <proto/action.h> #include <proto/channel.h> #include <proto/cli.h> #include <proto/checks.h> #include <proto/dns.h> #include <proto/fd.h> +#include <proto/proto_http.h> #include <proto/log.h> +#include <proto/sample.h> #include <proto/server.h> #include <proto/task.h> #include <proto/proto_udp.h> #include <proto/proxy.h> #include <proto/stream_interface.h> +#include <proto/vars.h> struct list dns_resolvers = LIST_HEAD_INIT(dns_resolvers); struct list dns_srvrq_list = LIST_HEAD_INIT(dns_srvrq_list); @@ -1328,6 +1333,7 @@ int dns_link_resolution(void *requester, int requester_type, int requester_locke struct dns_resolvers *resolvers; struct server *srv = NULL; struct dns_srvrq *srvrq = NULL; + struct stream *stream = NULL; char **hostname_dn; int hostname_dn_len, query_type; @@ -1350,6 +1356,15 @@ int dns_link_resolution(void *requester, int requester_type, int requester_locke query_type = DNS_RTYPE_SRV; break; + case OBJ_TYPE_STREAM: + stream = (struct stream *)requester; + hostname_dn = &stream->ctx.dns.hostname_dn; + hostname_dn_len = stream->ctx.dns.hostname_dn_len; + resolvers = stream->ctx.dns.parent->arg.dns.resolvers; + query_type = ((stream->ctx.dns.parent->arg.dns.dns_opts.family_prio == AF_INET) + ? DNS_RTYPE_A + : DNS_RTYPE_AAAA); + break; default: goto err; } @@ -1391,6 +1406,19 @@ int dns_link_resolution(void *requester, int requester_type, int requester_locke req->requester_cb = snr_resolution_cb; req->requester_error_cb = snr_resolution_error_cb; } + else if (stream) { + if (stream->ctx.dns.dns_requester == NULL) { + if ((req = pool_alloc(dns_requester_pool)) == NULL) + goto err; + req->owner = &stream->obj_type; + stream->ctx.dns.dns_requester = req; + } + else + req = stream->ctx.dns.dns_requester; + + req->requester_cb = act_resolution_cb; + req->requester_error_cb = act_resolution_error_cb; + } else goto err; @@ -1440,6 +1468,10 @@ void dns_unlink_resolution(struct dns_requester *requester) res->hostname_dn = objt_dns_srvrq(req->owner)->hostname_dn; res->hostname_dn_len = objt_dns_srvrq(req->owner)->hostname_dn_len; break; + case OBJ_TYPE_STREAM: + res->hostname_dn = objt_stream(req->owner)->ctx.dns.hostname_dn; + res->hostname_dn_len = objt_stream(req->owner)->ctx.dns.hostname_dn_len; + break; default: res->hostname_dn = NULL; res->hostname_dn_len = 0; @@ -2058,6 +2090,231 @@ static struct cli_kw_list cli_kws = {{ }, { } }; +/* + * Prepare <rule> for hostname resolution. + * Returns -1 in case of any allocation failure, 0 if not. + */ +static int action_prepare_for_resolution(struct stream *stream, const char *hostname) +{ + char *hostname_dn; + int hostname_len, hostname_dn_len; + struct chunk *tmp = get_trash_chunk(); + + if (!hostname) + return 0; + + hostname_len = strlen(hostname); + hostname_dn = tmp->str; + hostname_dn_len = dns_str_to_dn_label(hostname, hostname_len + 1, + hostname_dn, tmp->size); + if (hostname_dn_len == -1) + goto err; + + + stream->ctx.dns.hostname_dn = strdup(hostname_dn); + stream->ctx.dns.hostname_dn_len = hostname_dn_len; + if (!stream->ctx.dns.hostname_dn) + goto err; + + return 0; + + err: + free(stream->ctx.dns.hostname_dn); stream->ctx.dns.hostname_dn = NULL; + return -1; +} + + +/* + * Execute the "do-resolution" action. May be called from {tcp,http}request. + */ +enum act_return dns_action_do_resolve(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + struct connection *cli_conn; + struct dns_resolution *resolution; + + /* we have a response to our DNS resolution */ + if (s->ctx.dns.dns_requester && s->ctx.dns.dns_requester->resolution != NULL) { + resolution = s->ctx.dns.dns_requester->resolution; + if (resolution->step == RSLV_STEP_NONE) { + /* We update the variable only if we have a valid response. */ + if (resolution->status == RSLV_STATUS_VALID) { + struct sample smp; + short ip_sin_family = 0; + void *ip = NULL; + + dns_get_ip_from_response(&resolution->response, &rule->arg.dns.dns_opts, NULL, + 0, &ip, &ip_sin_family, NULL); + + switch (ip_sin_family) { + case AF_INET: + smp.data.type = SMP_T_IPV4; + memcpy(&smp.data.u.ipv4, ip, 4); + break; + case AF_INET6: + smp.data.type = SMP_T_IPV6; + memcpy(&smp.data.u.ipv6, ip, 16); + break; + default: + ip = NULL; + } + + if (ip) { + smp.px = px; + smp.sess = sess; + smp.strm = s; + + vars_set_by_name(rule->arg.dns.varname, strlen(rule->arg.dns.varname), &smp); + } + } + } + + free(s->ctx.dns.hostname_dn); s->ctx.dns.hostname_dn = NULL; + s->ctx.dns.hostname_dn_len = 0; + dns_unlink_resolution(s->ctx.dns.dns_requester); + + pool_free(dns_requester_pool, s->ctx.dns.dns_requester); + s->ctx.dns.dns_requester = NULL; + + return ACT_RET_CONT; + } + + /* need to configure and start a new DNS resolution */ + if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) { + struct sample *smp; + + conn_get_from_addr(cli_conn); + + smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.dns.expr, SMP_T_STR); + if (smp) { + char *fqdn; + + fqdn = smp->data.u.str.str; + if (action_prepare_for_resolution(s, fqdn) == -1) { + ha_alert("Can't create DNS resolution for server 'http request action'\n"); + return ACT_RET_ERR; + } + + s->ctx.dns.parent = rule; + dns_link_resolution(s, OBJ_TYPE_STREAM, 0); + dns_trigger_resolution(s->ctx.dns.dns_requester); + } + } + return ACT_RET_YIELD; +} + + +/* parse "do-resolve" action + * This action takes the following arguments: + * do-resolve(<varName>,<resolversSectionName>,<resolvePrefer>) <expr> + * + * - <varName> is the variable name where the result of the DNS resolution will be stored + * (mandatory) + * - <resolversSectionName> is the name of the resolvers section to use to perform the resolution + * (mandatory) + * - <resolvePrefer> can be either 'ipv4' or 'ipv6' and is the IP family we would like to resolve first + * (optional), defaults to ipv6 + * - <expr> is an HAProxy expression used to fetch the name to be resolved + */ +enum act_parse_ret dns_parse_do_resolve(const char **args, int *orig_arg, struct proxy *px, struct act_rule *rule, char **err) +{ + int cur_arg; + struct sample_expr *expr; + unsigned int where; + const char *beg, *end; + + cur_arg = *orig_arg; + + /* locate varName, which is mandatory */ + beg = strchr(args[cur_arg], '('); + if (beg == NULL) + goto do_resolve_parse_error; + beg = beg + 1; /* beg should points to the first character after opening parenthesis '(' */ + end = strchr(beg, ','); + if (end == NULL) + goto do_resolve_parse_error; + rule->arg.dns.varname = my_strndup(beg, end - beg); + + + /* locate resolversSectionName, which is mandatory. + * Since next parameters are optional, the delimiter may be comma ',' + * or closing parenthesis ')' + */ + beg = end + 1; + if (beg == '\0') + goto do_resolve_parse_error; + end = strchr(beg, ','); + if (end == NULL) + end = strchr(beg, ')'); + if (end == NULL) + goto do_resolve_parse_error; + rule->arg.dns.resolvers_id = my_strndup(beg, end - beg); + + + if (!rule->arg.dns.varname || !rule->arg.dns.resolvers_id) + goto do_resolve_parse_error; + + + /* Default priority is ipv6 */ + rule->arg.dns.dns_opts.family_prio = AF_INET6; + + /* optional arguments accepted for now: + * ipv4 or ipv6 + */ + while (*end != ')') { + beg = end + 1; + if (beg == '\0') + goto do_resolve_parse_error; + end = strchr(beg, ','); + if (end == NULL) + end = strchr(beg, ')'); + if (end == NULL) + goto do_resolve_parse_error; + + if (strncmp(beg, "ipv4", end - beg) == 0) { + rule->arg.dns.dns_opts.family_prio = AF_INET; + } + else if (strncmp(beg, "ipv6", end - beg) == 0) { + rule->arg.dns.dns_opts.family_prio = AF_INET6; + } + else { + goto do_resolve_parse_error; + } + } + + cur_arg = cur_arg + 1; + + expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args); + if (!expr) + goto do_resolve_parse_error; + + + where = 0; + if (px->cap & PR_CAP_FE) + where |= SMP_VAL_FE_HRQ_HDR; + if (px->cap & PR_CAP_BE) + where |= SMP_VAL_BE_HRQ_HDR; + + if (!(expr->fetch->val & where)) { + memprintf(err, + "fetch method '%s' extracts information from '%s', none of which is available here", + args[cur_arg-1], sample_src_names(expr->fetch->use)); + free(expr); + return ACT_RET_PRS_ERR; + } + rule->arg.dns.expr = expr; + rule->action = ACT_HTTP_DO_RESOLVE; + rule->action_ptr = dns_action_do_resolve; + *orig_arg += cur_arg; + + return ACT_RET_PRS_OK; + + do_resolve_parse_error: + memprintf(err, "Can't parse '%s'. Expects 'do-resolve(<varname>,<resolvers>[,<options>]) <expr>'. Available options are 'ipv4' and 'ipv6'", + args[cur_arg]); + return ACT_RET_PRS_ERR; +} + __attribute__((constructor)) static void __dns_init(void) diff --git a/src/proto_http.c b/src/proto_http.c index 6990176..0f58b3f 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -55,6 +55,7 @@ #include <proto/checks.h> #include <proto/cli.h> #include <proto/compression.h> +#include <proto/dns.h> #include <proto/stats.h> #include <proto/fd.h> #include <proto/filters.h> @@ -2728,6 +2729,7 @@ resume_execution: break; } + case ACT_HTTP_DO_RESOLVE: case ACT_CUSTOM: if ((s->req.flags & CF_READ_ERROR) || ((s->req.flags & (CF_SHUTR|CF_READ_NULL)) && @@ -8619,6 +8621,20 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li redir->cond = NULL; cur_arg = 2; return rule; + } else if (strncmp(args[0], "do-resolve(", 11) == 0) { + int ret; + + error = NULL; + cur_arg = 0; + ret = dns_parse_do_resolve(args, &cur_arg, proxy, rule, &error); + + /* cur_arg is set by dns_parse_do_resolve() */ + + if (ret == ACT_RET_PRS_ERR) { + ha_alert("parsing [%s:%d]: %s\n", + file, linenum, error); + goto out_err; + } } else if (strncmp(args[0], "add-acl", 7) == 0) { /* http-request add-acl(<reference (acl name)>) <key pattern> */ rule->action = ACT_HTTP_ADD_ACL; diff --git a/src/stream.c b/src/stream.c index 92f9c0a..2c8328a 100644 --- a/src/stream.c +++ b/src/stream.c @@ -36,6 +36,7 @@ #include <proto/checks.h> #include <proto/cli.h> #include <proto/connection.h> +#include <proto/dns.h> #include <proto/stats.h> #include <proto/fd.h> #include <proto/filters.h> @@ -80,6 +81,7 @@ int stream_create_from_cs(struct conn_stream *cs) if (strm == NULL) return -1; + strm->obj_type = OBJ_TYPE_STREAM; task_wakeup(strm->task, TASK_WOKEN_INIT); return 0; } @@ -2509,6 +2511,15 @@ struct task *process_stream(struct task *t) /* update time stats for this stream */ stream_update_time_stats(s); + if (s->ctx.dns.dns_requester) { + free(s->ctx.dns.hostname_dn); s->ctx.dns.hostname_dn = NULL; + s->ctx.dns.hostname_dn_len = 0; + dns_unlink_resolution(s->ctx.dns.dns_requester); + + pool_free(dns_requester_pool, s->ctx.dns.dns_requester); + s->ctx.dns.dns_requester = NULL; + } + /* the task MUST not be in the run queue anymore */ stream_free(s); task_delete(t); -- 2.7.4
From 03f39f7f600e09f2cbe7048e69925d4ed3c9b00e Mon Sep 17 00:00:00 2001 From: Baptiste Assmann <[email protected]> Date: Tue, 30 Jan 2018 08:10:20 +0100 Subject: [PATCH 3/4] MINOR: obj_type: new object type for struct stream This patch creates a new obj_type for the struct stream in HAProxy. --- include/proto/obj_type.h | 13 +++++++++++++ include/types/obj_type.h | 1 + include/types/stream.h | 1 + 3 files changed, 15 insertions(+) diff --git a/include/proto/obj_type.h b/include/proto/obj_type.h index 617464c..45311de 100644 --- a/include/proto/obj_type.h +++ b/include/proto/obj_type.h @@ -30,6 +30,7 @@ #include <types/obj_type.h> #include <types/proxy.h> #include <types/server.h> +#include <types/stream.h> #include <types/stream_interface.h> static inline enum obj_type obj_type(enum obj_type *t) @@ -155,6 +156,18 @@ static inline struct dns_srvrq *objt_dns_srvrq(enum obj_type *t) return __objt_dns_srvrq(t); } +static inline struct stream *__objt_stream(enum obj_type *t) +{ + return container_of(t, struct stream, obj_type); +} + +static inline struct stream *objt_stream(enum obj_type *t) +{ + if (!t || *t != OBJ_TYPE_STREAM) + return NULL; + return __objt_stream(t); +} + static inline void *obj_base_ptr(enum obj_type *t) { switch (obj_type(t)) { diff --git a/include/types/obj_type.h b/include/types/obj_type.h index e141d69..9410718 100644 --- a/include/types/obj_type.h +++ b/include/types/obj_type.h @@ -41,6 +41,7 @@ enum obj_type { OBJ_TYPE_CONN, /* object is a struct connection */ OBJ_TYPE_SRVRQ, /* object is a struct dns_srvrq */ OBJ_TYPE_CS, /* object is a struct conn_stream */ + OBJ_TYPE_STREAM, /* object is a struct stream */ OBJ_TYPE_ENTRIES /* last one : number of entries */ } __attribute__((packed)) ; diff --git a/include/types/stream.h b/include/types/stream.h index 227b0ff..a2b650e 100644 --- a/include/types/stream.h +++ b/include/types/stream.h @@ -112,6 +112,7 @@ struct strm_logs { }; struct stream { + enum obj_type obj_type; /* object type == OBJ_TYPE_STREAM */ int flags; /* some flags describing the stream */ unsigned int uniq_id; /* unique ID used for the traces */ enum obj_type *target; /* target to use for this stream */ -- 2.7.4
From 5118e5452b11e42f5639736bdf4903f9eb9a2fea Mon Sep 17 00:00:00 2001 From: Baptiste Assmann <[email protected]> Date: Tue, 30 Jan 2018 08:08:04 +0100 Subject: [PATCH 2/4] MINOR: dns: move callback affection in dns_link_resolution() In dns.c, dns_link_resolution(), each type of dns requester is managed separately, that said, the callback function is affected globaly (and points to server type callbacks only). This design prevents the addition of new dns requester type and this patch aims at fixing this limitation: now, the callback setting is done directly into the portion of code dedicated to each requester type. --- src/dns.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/dns.c b/src/dns.c index 9fd41e9..1d1636f 100644 --- a/src/dns.c +++ b/src/dns.c @@ -1374,6 +1374,9 @@ int dns_link_resolution(void *requester, int requester_type, int requester_locke req = srv->dns_requester; if (!requester_locked) HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock); + + req->requester_cb = snr_resolution_cb; + req->requester_error_cb = snr_resolution_error_cb; } else if (srvrq) { if (srvrq->dns_requester == NULL) { @@ -1384,13 +1387,14 @@ int dns_link_resolution(void *requester, int requester_type, int requester_locke } else req = srvrq->dns_requester; + + req->requester_cb = snr_resolution_cb; + req->requester_error_cb = snr_resolution_error_cb; } else goto err; req->resolution = res; - req->requester_cb = snr_resolution_cb; - req->requester_error_cb = snr_resolution_error_cb; LIST_ADDQ(&res->requesters, &req->list); return 0; -- 2.7.4
From c7565cc2a4a3e513eb701c925ce3bda2d1229d59 Mon Sep 17 00:00:00 2001 From: Baptiste Assmann <[email protected]> Date: Tue, 30 Jan 2018 08:01:42 +0100 Subject: [PATCH 1/4] MINOR: dns: dns_requester structures are now in a memory pool dns_requester structure can be allocated at run time when servers get associated to DNS resolution (this happens when SRV records are used in conjunction with service discovery). Well, this memory allocation is safer if managed in an HAProxy pool, furthermore with upcoming HTTP action which can perform DNS resolution at runtime. This patch moves the memory management of the dns_requester structure into its own pool. --- include/types/dns.h | 2 ++ src/dns.c | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/types/dns.h b/include/types/dns.h index 9b1d08d..ebdfd1b 100644 --- a/include/types/dns.h +++ b/include/types/dns.h @@ -34,6 +34,8 @@ #include <types/server.h> #include <types/task.h> +extern struct pool_head *dns_requester_pool; + /*DNS maximum values */ /* * Maximum issued from RFC: diff --git a/src/dns.c b/src/dns.c index 280bc15..9fd41e9 100644 --- a/src/dns.c +++ b/src/dns.c @@ -48,6 +48,7 @@ struct list dns_srvrq_list = LIST_HEAD_INIT(dns_srvrq_list); static THREAD_LOCAL int64_t dns_query_id_seed = 0; /* random seed */ static struct pool_head *dns_answer_item_pool = NULL; static struct pool_head *dns_resolution_pool = NULL; +struct pool_head *dns_requester_pool = NULL; static unsigned int resolution_uuid = 1; /* Returns a pointer to the resolvers matching the id <id>. NULL is returned if @@ -1361,7 +1362,7 @@ int dns_link_resolution(void *requester, int requester_type, int requester_locke if (!requester_locked) HA_SPIN_LOCK(SERVER_LOCK, &srv->lock); if (srv->dns_requester == NULL) { - if ((req = calloc(1, sizeof(*req))) == NULL) { + if ((req = pool_alloc(dns_requester_pool)) == NULL) { if (!requester_locked) HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock); goto err; @@ -1376,7 +1377,7 @@ int dns_link_resolution(void *requester, int requester_type, int requester_locke } else if (srvrq) { if (srvrq->dns_requester == NULL) { - if ((req = calloc(1, sizeof(*req))) == NULL) + if ((req = pool_alloc(dns_requester_pool)) == NULL) goto err; req->owner = &srvrq->obj_type; srvrq->dns_requester = req; @@ -1839,6 +1840,7 @@ static void dns_deinit(void) pool_destroy(dns_answer_item_pool); pool_destroy(dns_resolution_pool); + pool_destroy(dns_requester_pool); } /* Finalizes the DNS configuration by allocating required resources and checking @@ -2058,6 +2060,7 @@ static void __dns_init(void) { dns_answer_item_pool = create_pool("dns_answer_item", sizeof(struct dns_answer_item), MEM_F_SHARED); dns_resolution_pool = create_pool("dns_resolution", sizeof(struct dns_resolution), MEM_F_SHARED); + dns_requester_pool = create_pool("dns_requester", sizeof(struct dns_requester), MEM_F_SHARED); hap_register_post_check(dns_finalize_config); hap_register_post_deinit(dns_deinit); -- 2.7.4

