cf-haproxy.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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. #if !defined(CURL_DISABLE_PROXY)
  26. #include <curl/curl.h>
  27. #include "urldata.h"
  28. #include "cfilters.h"
  29. #include "cf-haproxy.h"
  30. #include "curl_log.h"
  31. #include "multiif.h"
  32. /* The last 3 #include files should be in this order */
  33. #include "curl_printf.h"
  34. #include "curl_memory.h"
  35. #include "memdebug.h"
  36. typedef enum {
  37. HAPROXY_INIT, /* init/default/no tunnel state */
  38. HAPROXY_SEND, /* data_out being sent */
  39. HAPROXY_DONE /* all work done */
  40. } haproxy_state;
  41. struct cf_haproxy_ctx {
  42. int state;
  43. struct dynbuf data_out;
  44. };
  45. static void cf_haproxy_ctx_reset(struct cf_haproxy_ctx *ctx)
  46. {
  47. DEBUGASSERT(ctx);
  48. ctx->state = HAPROXY_INIT;
  49. Curl_dyn_reset(&ctx->data_out);
  50. }
  51. static void cf_haproxy_ctx_free(struct cf_haproxy_ctx *ctx)
  52. {
  53. if(ctx) {
  54. Curl_dyn_free(&ctx->data_out);
  55. free(ctx);
  56. }
  57. }
  58. static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
  59. struct Curl_easy *data)
  60. {
  61. struct cf_haproxy_ctx *ctx = cf->ctx;
  62. CURLcode result;
  63. const char *tcp_version;
  64. const char *client_ip;
  65. DEBUGASSERT(ctx);
  66. DEBUGASSERT(ctx->state == HAPROXY_INIT);
  67. #ifdef USE_UNIX_SOCKETS
  68. if(cf->conn->unix_domain_socket)
  69. /* the buffer is large enough to hold this! */
  70. result = Curl_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n"));
  71. else {
  72. #endif /* USE_UNIX_SOCKETS */
  73. /* Emit the correct prefix for IPv6 */
  74. tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4";
  75. if(data->set.str[STRING_HAPROXY_CLIENT_IP])
  76. client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
  77. else
  78. client_ip = data->info.conn_primary_ip;
  79. result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
  80. tcp_version,
  81. data->info.conn_local_ip,
  82. client_ip,
  83. data->info.conn_local_port,
  84. data->info.conn_primary_port);
  85. #ifdef USE_UNIX_SOCKETS
  86. }
  87. #endif /* USE_UNIX_SOCKETS */
  88. return result;
  89. }
  90. static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
  91. struct Curl_easy *data,
  92. bool blocking, bool *done)
  93. {
  94. struct cf_haproxy_ctx *ctx = cf->ctx;
  95. CURLcode result;
  96. size_t len;
  97. DEBUGASSERT(ctx);
  98. if(cf->connected) {
  99. *done = TRUE;
  100. return CURLE_OK;
  101. }
  102. result = cf->next->cft->do_connect(cf->next, data, blocking, done);
  103. if(result || !*done)
  104. return result;
  105. switch(ctx->state) {
  106. case HAPROXY_INIT:
  107. result = cf_haproxy_date_out_set(cf, data);
  108. if(result)
  109. goto out;
  110. ctx->state = HAPROXY_SEND;
  111. /* FALLTHROUGH */
  112. case HAPROXY_SEND:
  113. len = Curl_dyn_len(&ctx->data_out);
  114. if(len > 0) {
  115. ssize_t written = Curl_conn_send(data, cf->sockindex,
  116. Curl_dyn_ptr(&ctx->data_out),
  117. len, &result);
  118. if(written < 0)
  119. goto out;
  120. Curl_dyn_tail(&ctx->data_out, len - (size_t)written);
  121. if(Curl_dyn_len(&ctx->data_out) > 0) {
  122. result = CURLE_OK;
  123. goto out;
  124. }
  125. }
  126. ctx->state = HAPROXY_DONE;
  127. /* FALLTHROUGH */
  128. default:
  129. Curl_dyn_free(&ctx->data_out);
  130. break;
  131. }
  132. out:
  133. *done = (!result) && (ctx->state == HAPROXY_DONE);
  134. cf->connected = *done;
  135. return result;
  136. }
  137. static void cf_haproxy_destroy(struct Curl_cfilter *cf,
  138. struct Curl_easy *data)
  139. {
  140. (void)data;
  141. DEBUGF(LOG_CF(data, cf, "destroy"));
  142. cf_haproxy_ctx_free(cf->ctx);
  143. }
  144. static void cf_haproxy_close(struct Curl_cfilter *cf,
  145. struct Curl_easy *data)
  146. {
  147. DEBUGF(LOG_CF(data, cf, "close"));
  148. cf->connected = FALSE;
  149. cf_haproxy_ctx_reset(cf->ctx);
  150. if(cf->next)
  151. cf->next->cft->do_close(cf->next, data);
  152. }
  153. static int cf_haproxy_get_select_socks(struct Curl_cfilter *cf,
  154. struct Curl_easy *data,
  155. curl_socket_t *socks)
  156. {
  157. int fds;
  158. fds = cf->next->cft->get_select_socks(cf->next, data, socks);
  159. if(!fds && cf->next->connected && !cf->connected) {
  160. /* If we are not connected, but the filter "below" is
  161. * and not waiting on something, we are sending. */
  162. socks[0] = Curl_conn_cf_get_socket(cf, data);
  163. return GETSOCK_WRITESOCK(0);
  164. }
  165. return fds;
  166. }
  167. struct Curl_cftype Curl_cft_haproxy = {
  168. "HAPROXY",
  169. 0,
  170. 0,
  171. cf_haproxy_destroy,
  172. cf_haproxy_connect,
  173. cf_haproxy_close,
  174. Curl_cf_def_get_host,
  175. cf_haproxy_get_select_socks,
  176. Curl_cf_def_data_pending,
  177. Curl_cf_def_send,
  178. Curl_cf_def_recv,
  179. Curl_cf_def_cntrl,
  180. Curl_cf_def_conn_is_alive,
  181. Curl_cf_def_conn_keep_alive,
  182. Curl_cf_def_query,
  183. };
  184. static CURLcode cf_haproxy_create(struct Curl_cfilter **pcf,
  185. struct Curl_easy *data)
  186. {
  187. struct Curl_cfilter *cf = NULL;
  188. struct cf_haproxy_ctx *ctx;
  189. CURLcode result;
  190. (void)data;
  191. ctx = calloc(sizeof(*ctx), 1);
  192. if(!ctx) {
  193. result = CURLE_OUT_OF_MEMORY;
  194. goto out;
  195. }
  196. ctx->state = HAPROXY_INIT;
  197. Curl_dyn_init(&ctx->data_out, DYN_HAXPROXY);
  198. result = Curl_cf_create(&cf, &Curl_cft_haproxy, ctx);
  199. if(result)
  200. goto out;
  201. ctx = NULL;
  202. out:
  203. cf_haproxy_ctx_free(ctx);
  204. *pcf = result? NULL : cf;
  205. return result;
  206. }
  207. CURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at,
  208. struct Curl_easy *data)
  209. {
  210. struct Curl_cfilter *cf;
  211. CURLcode result;
  212. result = cf_haproxy_create(&cf, data);
  213. if(result)
  214. goto out;
  215. Curl_conn_cf_insert_after(cf_at, cf);
  216. out:
  217. return result;
  218. }
  219. #endif /* !CURL_DISABLE_PROXY */