From: William Lallemand Date: Thu, 28 Apr 2022 14:55:02 +0000 (+0200) Subject: MEDIUM: httpclient: http-request rules for resolving X-Git-Tag: v2.6-dev9~109 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5392ff6e3c201f27307600d73af71ad26f4a0b53;p=thirdparty%2Fhaproxy.git MEDIUM: httpclient: http-request rules for resolving The httpclient_resolve_init() adds http-request actions which does the resolving using the Host header of the HTTP request. The parse_http_req_cond function is directly used over an array of http rules. The do-resolve rule uses the "default" resolvers section. If this section does not exist in the configuration, the resolving is disabling. --- diff --git a/src/http_client.c b/src/http_client.c index 282963592c..e45653fb05 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -27,9 +27,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -516,6 +518,7 @@ struct appctx *httpclient_start(struct httpclient *hc) struct ist host = IST_NULL; enum http_scheme scheme; int port; + int doresolve = 0; /* if the client was started and not ended, an applet is already * running, we shouldn't try anything */ @@ -529,7 +532,8 @@ struct appctx *httpclient_start(struct httpclient *hc) ist2str(trash.area, host); ss_dst = str2ip2(trash.area, &ss_url, 0); - sock_inet_set_port(&ss_url, port); + if (!ss_dst) /* couldn't get an IP from that, try to resolve */ + doresolve = 1; /* The HTTP client will be created in the same thread as the caller, * avoiding threading issues */ @@ -567,8 +571,15 @@ struct appctx *httpclient_start(struct httpclient *hc) if (hc->dst) ss_dst = hc->dst; - /* TODO: if ss_dst == NULL, must resolve the domain */ + if (doresolve) /* when resolving, must set-dst from 0.0.0.0 */ + ss_dst = str2ip2("0.0.0.0", &ss_url, 0); + + sock_inet_set_port(&ss_url, port); + if (!ss_dst) { + ha_alert("httpclient: Failed to initialize address %s:%d.\n", __FUNCTION__, __LINE__); + goto out_free_sess; + } if (!sockaddr_alloc(&addr, ss_dst, sizeof(*hc->dst))) goto out_free_sess; @@ -1027,6 +1038,39 @@ static struct applet httpclient_applet = { .release = httpclient_applet_release, }; + +static int httpclient_resolve_init() +{ + struct act_rule *rule; + int i; + const char *http_rules[][11] = { + { "set-var(txn.hc_ip)", "dst", "" }, + { "do-resolve(txn.hc_ip,default)", "hdr(Host),lower", "if", "{", "var(txn.hc_ip)", "-m", "ip", "0.0.0.0", "}", "" }, + { "return", "status", "503", "if", "{", "var(txn.hc_ip)", "-m", "ip", "0.0.0.0", "}", "" }, + { "capture", "var(txn.hc_ip)", "len", "40", "" }, + { "set-dst", "var(txn.hc_ip)", "" }, + { "" } + }; + + /* if the "default" resolver does not exist, simply ignore resolving */ + if (!find_resolvers_by_id("default")) + return 0; + + + for (i = 0; *http_rules[i][0] != '\0'; i++) { + rule = parse_http_req_cond((const char **)http_rules[i], "httpclient", 0, httpclient_proxy); + if (!rule) { + ha_alert("Couldn't setup the httpclient resolver.\n"); + return 1; + } + LIST_APPEND(&httpclient_proxy->http_req_rules, &rule->list); + } + + return 0; +} + + + /* * Initialize the proxy for the HTTP client with 2 servers, one for raw HTTP, * the other for HTTPS. @@ -1108,6 +1152,9 @@ static int httpclient_precheck() httpclient_proxy->next = proxies_list; proxies_list = httpclient_proxy; + if (httpclient_resolve_init() != 0) + goto err; + /* link the 2 servers in the proxy */ httpclient_srv_raw->next = httpclient_proxy->srv; httpclient_proxy->srv = httpclient_srv_raw;