cf-haproxy.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include "curl_setup.h"
  25. #ifndef CURL_DISABLE_PROXY
  26. #include "urldata.h"
  27. #include "cfilters.h"
  28. #include "cf-haproxy.h"
  29. #include "curl_trc.h"
  30. #include "select.h"
  31. typedef enum {
  32. HAPROXY_INIT, /* init/default/no tunnel state */
  33. HAPROXY_SEND, /* data_out being sent */
  34. HAPROXY_DONE /* all work done */
  35. } haproxy_state;
  36. struct cf_haproxy_ctx {
  37. int state;
  38. struct dynbuf data_out;
  39. };
  40. static void cf_haproxy_ctx_reset(struct cf_haproxy_ctx *ctx)
  41. {
  42. DEBUGASSERT(ctx);
  43. ctx->state = HAPROXY_INIT;
  44. curlx_dyn_reset(&ctx->data_out);
  45. }
  46. static void cf_haproxy_ctx_free(struct cf_haproxy_ctx *ctx)
  47. {
  48. if(ctx) {
  49. curlx_dyn_free(&ctx->data_out);
  50. curlx_free(ctx);
  51. }
  52. }
  53. static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter *cf,
  54. struct Curl_easy *data)
  55. {
  56. struct cf_haproxy_ctx *ctx = cf->ctx;
  57. CURLcode result;
  58. const char *client_ip;
  59. struct ip_quadruple ipquad;
  60. bool is_ipv6;
  61. DEBUGASSERT(ctx);
  62. DEBUGASSERT(ctx->state == HAPROXY_INIT);
  63. #ifdef USE_UNIX_SOCKETS
  64. if(cf->conn->unix_domain_socket)
  65. /* the buffer is large enough to hold this! */
  66. result = curlx_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n"));
  67. else {
  68. #endif /* USE_UNIX_SOCKETS */
  69. result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad);
  70. if(result)
  71. return result;
  72. /* Emit the correct prefix for IPv6 */
  73. if(data->set.str[STRING_HAPROXY_CLIENT_IP])
  74. client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
  75. else
  76. client_ip = ipquad.local_ip;
  77. result = curlx_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
  78. is_ipv6 ? "TCP6" : "TCP4",
  79. client_ip, ipquad.remote_ip,
  80. ipquad.local_port, ipquad.remote_port);
  81. #ifdef USE_UNIX_SOCKETS
  82. }
  83. #endif /* USE_UNIX_SOCKETS */
  84. return result;
  85. }
  86. static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
  87. struct Curl_easy *data,
  88. bool *done)
  89. {
  90. struct cf_haproxy_ctx *ctx = cf->ctx;
  91. CURLcode result;
  92. size_t len;
  93. DEBUGASSERT(ctx);
  94. if(cf->connected) {
  95. *done = TRUE;
  96. return CURLE_OK;
  97. }
  98. result = cf->next->cft->do_connect(cf->next, data, done);
  99. if(result || !*done)
  100. return result;
  101. switch(ctx->state) {
  102. case HAPROXY_INIT:
  103. result = cf_haproxy_date_out_set(cf, data);
  104. if(result)
  105. goto out;
  106. ctx->state = HAPROXY_SEND;
  107. FALLTHROUGH();
  108. case HAPROXY_SEND:
  109. len = curlx_dyn_len(&ctx->data_out);
  110. if(len > 0) {
  111. size_t nwritten;
  112. result = Curl_conn_cf_send(cf->next, data,
  113. curlx_dyn_uptr(&ctx->data_out), len, FALSE,
  114. &nwritten);
  115. if(result) {
  116. if(result != CURLE_AGAIN)
  117. goto out;
  118. result = CURLE_OK;
  119. nwritten = 0;
  120. }
  121. curlx_dyn_tail(&ctx->data_out, len - nwritten);
  122. if(curlx_dyn_len(&ctx->data_out) > 0) {
  123. result = CURLE_OK;
  124. goto out;
  125. }
  126. }
  127. ctx->state = HAPROXY_DONE;
  128. FALLTHROUGH();
  129. default:
  130. curlx_dyn_free(&ctx->data_out);
  131. break;
  132. }
  133. out:
  134. *done = (!result) && (ctx->state == HAPROXY_DONE);
  135. cf->connected = *done;
  136. return result;
  137. }
  138. static void cf_haproxy_destroy(struct Curl_cfilter *cf,
  139. struct Curl_easy *data)
  140. {
  141. (void)data;
  142. CURL_TRC_CF(data, cf, "destroy");
  143. cf_haproxy_ctx_free(cf->ctx);
  144. }
  145. static void cf_haproxy_close(struct Curl_cfilter *cf,
  146. struct Curl_easy *data)
  147. {
  148. CURL_TRC_CF(data, cf, "close");
  149. cf->connected = FALSE;
  150. cf_haproxy_ctx_reset(cf->ctx);
  151. if(cf->next)
  152. cf->next->cft->do_close(cf->next, data);
  153. }
  154. static CURLcode cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
  155. struct Curl_easy *data,
  156. struct easy_pollset *ps)
  157. {
  158. if(cf->next->connected && !cf->connected) {
  159. /* If we are not connected, but the filter "below" is
  160. * and not waiting on something, we are sending. */
  161. return Curl_pollset_set_out_only(
  162. data, ps, Curl_conn_cf_get_socket(cf, data));
  163. }
  164. return CURLE_OK;
  165. }
  166. struct Curl_cftype Curl_cft_haproxy = {
  167. "HAPROXY",
  168. CF_TYPE_PROXY,
  169. 0,
  170. cf_haproxy_destroy,
  171. cf_haproxy_connect,
  172. cf_haproxy_close,
  173. Curl_cf_def_shutdown,
  174. cf_haproxy_adjust_pollset,
  175. Curl_cf_def_data_pending,
  176. Curl_cf_def_send,
  177. Curl_cf_def_recv,
  178. Curl_cf_def_cntrl,
  179. Curl_cf_def_conn_is_alive,
  180. Curl_cf_def_conn_keep_alive,
  181. Curl_cf_def_query,
  182. };
  183. static CURLcode cf_haproxy_create(struct Curl_cfilter **pcf,
  184. struct Curl_easy *data)
  185. {
  186. struct Curl_cfilter *cf = NULL;
  187. struct cf_haproxy_ctx *ctx;
  188. CURLcode result;
  189. (void)data;
  190. ctx = curlx_calloc(1, sizeof(*ctx));
  191. if(!ctx) {
  192. result = CURLE_OUT_OF_MEMORY;
  193. goto out;
  194. }
  195. ctx->state = HAPROXY_INIT;
  196. curlx_dyn_init(&ctx->data_out, DYN_HAXPROXY);
  197. result = Curl_cf_create(&cf, &Curl_cft_haproxy, ctx);
  198. if(result)
  199. goto out;
  200. ctx = NULL;
  201. out:
  202. cf_haproxy_ctx_free(ctx);
  203. *pcf = result ? NULL : cf;
  204. return result;
  205. }
  206. CURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at,
  207. struct Curl_easy *data)
  208. {
  209. struct Curl_cfilter *cf;
  210. CURLcode result;
  211. result = cf_haproxy_create(&cf, data);
  212. if(result)
  213. goto out;
  214. Curl_conn_cf_insert_after(cf_at, cf);
  215. out:
  216. return result;
  217. }
  218. #endif /* !CURL_DISABLE_PROXY */