113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#if !defined(CURL_DISABLE_PROXY) 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#include <curl/curl.h> 3013498266Sopenharmony_ci#include "urldata.h" 3113498266Sopenharmony_ci#include "cfilters.h" 3213498266Sopenharmony_ci#include "cf-haproxy.h" 3313498266Sopenharmony_ci#include "curl_trc.h" 3413498266Sopenharmony_ci#include "multiif.h" 3513498266Sopenharmony_ci 3613498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 3713498266Sopenharmony_ci#include "curl_printf.h" 3813498266Sopenharmony_ci#include "curl_memory.h" 3913498266Sopenharmony_ci#include "memdebug.h" 4013498266Sopenharmony_ci 4113498266Sopenharmony_ci 4213498266Sopenharmony_citypedef enum { 4313498266Sopenharmony_ci HAPROXY_INIT, /* init/default/no tunnel state */ 4413498266Sopenharmony_ci HAPROXY_SEND, /* data_out being sent */ 4513498266Sopenharmony_ci HAPROXY_DONE /* all work done */ 4613498266Sopenharmony_ci} haproxy_state; 4713498266Sopenharmony_ci 4813498266Sopenharmony_cistruct cf_haproxy_ctx { 4913498266Sopenharmony_ci int state; 5013498266Sopenharmony_ci struct dynbuf data_out; 5113498266Sopenharmony_ci}; 5213498266Sopenharmony_ci 5313498266Sopenharmony_cistatic void cf_haproxy_ctx_reset(struct cf_haproxy_ctx *ctx) 5413498266Sopenharmony_ci{ 5513498266Sopenharmony_ci DEBUGASSERT(ctx); 5613498266Sopenharmony_ci ctx->state = HAPROXY_INIT; 5713498266Sopenharmony_ci Curl_dyn_reset(&ctx->data_out); 5813498266Sopenharmony_ci} 5913498266Sopenharmony_ci 6013498266Sopenharmony_cistatic void cf_haproxy_ctx_free(struct cf_haproxy_ctx *ctx) 6113498266Sopenharmony_ci{ 6213498266Sopenharmony_ci if(ctx) { 6313498266Sopenharmony_ci Curl_dyn_free(&ctx->data_out); 6413498266Sopenharmony_ci free(ctx); 6513498266Sopenharmony_ci } 6613498266Sopenharmony_ci} 6713498266Sopenharmony_ci 6813498266Sopenharmony_cistatic CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf, 6913498266Sopenharmony_ci struct Curl_easy *data) 7013498266Sopenharmony_ci{ 7113498266Sopenharmony_ci struct cf_haproxy_ctx *ctx = cf->ctx; 7213498266Sopenharmony_ci CURLcode result; 7313498266Sopenharmony_ci const char *tcp_version; 7413498266Sopenharmony_ci const char *client_ip; 7513498266Sopenharmony_ci 7613498266Sopenharmony_ci DEBUGASSERT(ctx); 7713498266Sopenharmony_ci DEBUGASSERT(ctx->state == HAPROXY_INIT); 7813498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 7913498266Sopenharmony_ci if(cf->conn->unix_domain_socket) 8013498266Sopenharmony_ci /* the buffer is large enough to hold this! */ 8113498266Sopenharmony_ci result = Curl_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n")); 8213498266Sopenharmony_ci else { 8313498266Sopenharmony_ci#endif /* USE_UNIX_SOCKETS */ 8413498266Sopenharmony_ci /* Emit the correct prefix for IPv6 */ 8513498266Sopenharmony_ci tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4"; 8613498266Sopenharmony_ci if(data->set.str[STRING_HAPROXY_CLIENT_IP]) 8713498266Sopenharmony_ci client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP]; 8813498266Sopenharmony_ci else 8913498266Sopenharmony_ci client_ip = data->info.conn_local_ip; 9013498266Sopenharmony_ci 9113498266Sopenharmony_ci result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n", 9213498266Sopenharmony_ci tcp_version, 9313498266Sopenharmony_ci client_ip, 9413498266Sopenharmony_ci data->info.conn_primary_ip, 9513498266Sopenharmony_ci data->info.conn_local_port, 9613498266Sopenharmony_ci data->info.conn_primary_port); 9713498266Sopenharmony_ci 9813498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 9913498266Sopenharmony_ci } 10013498266Sopenharmony_ci#endif /* USE_UNIX_SOCKETS */ 10113498266Sopenharmony_ci return result; 10213498266Sopenharmony_ci} 10313498266Sopenharmony_ci 10413498266Sopenharmony_cistatic CURLcode cf_haproxy_connect(struct Curl_cfilter *cf, 10513498266Sopenharmony_ci struct Curl_easy *data, 10613498266Sopenharmony_ci bool blocking, bool *done) 10713498266Sopenharmony_ci{ 10813498266Sopenharmony_ci struct cf_haproxy_ctx *ctx = cf->ctx; 10913498266Sopenharmony_ci CURLcode result; 11013498266Sopenharmony_ci size_t len; 11113498266Sopenharmony_ci 11213498266Sopenharmony_ci DEBUGASSERT(ctx); 11313498266Sopenharmony_ci if(cf->connected) { 11413498266Sopenharmony_ci *done = TRUE; 11513498266Sopenharmony_ci return CURLE_OK; 11613498266Sopenharmony_ci } 11713498266Sopenharmony_ci 11813498266Sopenharmony_ci result = cf->next->cft->do_connect(cf->next, data, blocking, done); 11913498266Sopenharmony_ci if(result || !*done) 12013498266Sopenharmony_ci return result; 12113498266Sopenharmony_ci 12213498266Sopenharmony_ci switch(ctx->state) { 12313498266Sopenharmony_ci case HAPROXY_INIT: 12413498266Sopenharmony_ci result = cf_haproxy_date_out_set(cf, data); 12513498266Sopenharmony_ci if(result) 12613498266Sopenharmony_ci goto out; 12713498266Sopenharmony_ci ctx->state = HAPROXY_SEND; 12813498266Sopenharmony_ci FALLTHROUGH(); 12913498266Sopenharmony_ci case HAPROXY_SEND: 13013498266Sopenharmony_ci len = Curl_dyn_len(&ctx->data_out); 13113498266Sopenharmony_ci if(len > 0) { 13213498266Sopenharmony_ci ssize_t written = Curl_conn_send(data, cf->sockindex, 13313498266Sopenharmony_ci Curl_dyn_ptr(&ctx->data_out), 13413498266Sopenharmony_ci len, &result); 13513498266Sopenharmony_ci if(written < 0) 13613498266Sopenharmony_ci goto out; 13713498266Sopenharmony_ci Curl_dyn_tail(&ctx->data_out, len - (size_t)written); 13813498266Sopenharmony_ci if(Curl_dyn_len(&ctx->data_out) > 0) { 13913498266Sopenharmony_ci result = CURLE_OK; 14013498266Sopenharmony_ci goto out; 14113498266Sopenharmony_ci } 14213498266Sopenharmony_ci } 14313498266Sopenharmony_ci ctx->state = HAPROXY_DONE; 14413498266Sopenharmony_ci FALLTHROUGH(); 14513498266Sopenharmony_ci default: 14613498266Sopenharmony_ci Curl_dyn_free(&ctx->data_out); 14713498266Sopenharmony_ci break; 14813498266Sopenharmony_ci } 14913498266Sopenharmony_ci 15013498266Sopenharmony_ciout: 15113498266Sopenharmony_ci *done = (!result) && (ctx->state == HAPROXY_DONE); 15213498266Sopenharmony_ci cf->connected = *done; 15313498266Sopenharmony_ci return result; 15413498266Sopenharmony_ci} 15513498266Sopenharmony_ci 15613498266Sopenharmony_cistatic void cf_haproxy_destroy(struct Curl_cfilter *cf, 15713498266Sopenharmony_ci struct Curl_easy *data) 15813498266Sopenharmony_ci{ 15913498266Sopenharmony_ci (void)data; 16013498266Sopenharmony_ci CURL_TRC_CF(data, cf, "destroy"); 16113498266Sopenharmony_ci cf_haproxy_ctx_free(cf->ctx); 16213498266Sopenharmony_ci} 16313498266Sopenharmony_ci 16413498266Sopenharmony_cistatic void cf_haproxy_close(struct Curl_cfilter *cf, 16513498266Sopenharmony_ci struct Curl_easy *data) 16613498266Sopenharmony_ci{ 16713498266Sopenharmony_ci CURL_TRC_CF(data, cf, "close"); 16813498266Sopenharmony_ci cf->connected = FALSE; 16913498266Sopenharmony_ci cf_haproxy_ctx_reset(cf->ctx); 17013498266Sopenharmony_ci if(cf->next) 17113498266Sopenharmony_ci cf->next->cft->do_close(cf->next, data); 17213498266Sopenharmony_ci} 17313498266Sopenharmony_ci 17413498266Sopenharmony_cistatic void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf, 17513498266Sopenharmony_ci struct Curl_easy *data, 17613498266Sopenharmony_ci struct easy_pollset *ps) 17713498266Sopenharmony_ci{ 17813498266Sopenharmony_ci if(cf->next->connected && !cf->connected) { 17913498266Sopenharmony_ci /* If we are not connected, but the filter "below" is 18013498266Sopenharmony_ci * and not waiting on something, we are sending. */ 18113498266Sopenharmony_ci Curl_pollset_set_out_only(data, ps, Curl_conn_cf_get_socket(cf, data)); 18213498266Sopenharmony_ci } 18313498266Sopenharmony_ci} 18413498266Sopenharmony_ci 18513498266Sopenharmony_cistruct Curl_cftype Curl_cft_haproxy = { 18613498266Sopenharmony_ci "HAPROXY", 18713498266Sopenharmony_ci 0, 18813498266Sopenharmony_ci 0, 18913498266Sopenharmony_ci cf_haproxy_destroy, 19013498266Sopenharmony_ci cf_haproxy_connect, 19113498266Sopenharmony_ci cf_haproxy_close, 19213498266Sopenharmony_ci Curl_cf_def_get_host, 19313498266Sopenharmony_ci cf_haproxy_adjust_pollset, 19413498266Sopenharmony_ci Curl_cf_def_data_pending, 19513498266Sopenharmony_ci Curl_cf_def_send, 19613498266Sopenharmony_ci Curl_cf_def_recv, 19713498266Sopenharmony_ci Curl_cf_def_cntrl, 19813498266Sopenharmony_ci Curl_cf_def_conn_is_alive, 19913498266Sopenharmony_ci Curl_cf_def_conn_keep_alive, 20013498266Sopenharmony_ci Curl_cf_def_query, 20113498266Sopenharmony_ci}; 20213498266Sopenharmony_ci 20313498266Sopenharmony_cistatic CURLcode cf_haproxy_create(struct Curl_cfilter **pcf, 20413498266Sopenharmony_ci struct Curl_easy *data) 20513498266Sopenharmony_ci{ 20613498266Sopenharmony_ci struct Curl_cfilter *cf = NULL; 20713498266Sopenharmony_ci struct cf_haproxy_ctx *ctx; 20813498266Sopenharmony_ci CURLcode result; 20913498266Sopenharmony_ci 21013498266Sopenharmony_ci (void)data; 21113498266Sopenharmony_ci ctx = calloc(1, sizeof(*ctx)); 21213498266Sopenharmony_ci if(!ctx) { 21313498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 21413498266Sopenharmony_ci goto out; 21513498266Sopenharmony_ci } 21613498266Sopenharmony_ci ctx->state = HAPROXY_INIT; 21713498266Sopenharmony_ci Curl_dyn_init(&ctx->data_out, DYN_HAXPROXY); 21813498266Sopenharmony_ci 21913498266Sopenharmony_ci result = Curl_cf_create(&cf, &Curl_cft_haproxy, ctx); 22013498266Sopenharmony_ci if(result) 22113498266Sopenharmony_ci goto out; 22213498266Sopenharmony_ci ctx = NULL; 22313498266Sopenharmony_ci 22413498266Sopenharmony_ciout: 22513498266Sopenharmony_ci cf_haproxy_ctx_free(ctx); 22613498266Sopenharmony_ci *pcf = result? NULL : cf; 22713498266Sopenharmony_ci return result; 22813498266Sopenharmony_ci} 22913498266Sopenharmony_ci 23013498266Sopenharmony_ciCURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at, 23113498266Sopenharmony_ci struct Curl_easy *data) 23213498266Sopenharmony_ci{ 23313498266Sopenharmony_ci struct Curl_cfilter *cf; 23413498266Sopenharmony_ci CURLcode result; 23513498266Sopenharmony_ci 23613498266Sopenharmony_ci result = cf_haproxy_create(&cf, data); 23713498266Sopenharmony_ci if(result) 23813498266Sopenharmony_ci goto out; 23913498266Sopenharmony_ci Curl_conn_cf_insert_after(cf_at, cf); 24013498266Sopenharmony_ci 24113498266Sopenharmony_ciout: 24213498266Sopenharmony_ci return result; 24313498266Sopenharmony_ci} 24413498266Sopenharmony_ci 24513498266Sopenharmony_ci#endif /* !CURL_DISABLE_PROXY */ 246