You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

http_proxy.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "config.h"
  17. #include "libutil/util.h"
  18. #include "libutil/map.h"
  19. #include "libutil/upstream.h"
  20. #include "libserver/protocol.h"
  21. #include "libserver/cfg_file.h"
  22. #include "libserver/url.h"
  23. #include "libserver/dns.h"
  24. #include "libmime/message.h"
  25. #include "rspamd.h"
  26. #include "libserver/worker_util.h"
  27. #include "keypairs_cache.h"
  28. #include "ottery.h"
  29. #include "unix-std.h"
  30. /* Rotate keys each minute by default */
  31. #define DEFAULT_ROTATION_TIME 60.0
  32. gpointer init_http_proxy (struct rspamd_config *cfg);
  33. void start_http_proxy (struct rspamd_worker *worker);
  34. worker_t http_proxy_worker = {
  35. "http_proxy", /* Name */
  36. init_http_proxy, /* Init function */
  37. start_http_proxy, /* Start function */
  38. TRUE, /* Has socket */
  39. FALSE, /* Non unique */
  40. FALSE, /* Non threaded */
  41. TRUE, /* Killable */
  42. SOCK_STREAM /* TCP socket */
  43. };
  44. struct rspamd_http_upstream {
  45. gchar *name;
  46. struct upstream_list *u;
  47. gpointer key;
  48. };
  49. struct http_proxy_ctx {
  50. gdouble timeout;
  51. struct timeval io_tv;
  52. struct rspamd_config *cfg;
  53. /* DNS resolver */
  54. struct rspamd_dns_resolver *resolver;
  55. /* Events base */
  56. struct event_base *ev_base;
  57. /* Encryption key for clients */
  58. gpointer key;
  59. /* Keys cache */
  60. struct rspamd_keypair_cache *keys_cache;
  61. /* Upstreams to use */
  62. GHashTable *upstreams;
  63. /* Default upstream */
  64. struct rspamd_http_upstream *default_upstream;
  65. /* Local rotating keypair for upstreams */
  66. gpointer local_key;
  67. struct event rotate_ev;
  68. gdouble rotate_tm;
  69. };
  70. struct http_proxy_session {
  71. struct http_proxy_ctx *ctx;
  72. struct event_base *ev_base;
  73. gpointer local_key;
  74. gpointer remote_key;
  75. struct upstream *up;
  76. gint client_sock;
  77. gint backend_sock;
  78. rspamd_inet_addr_t *client_addr;
  79. struct rspamd_http_connection *client_conn;
  80. struct rspamd_http_connection *backend_conn;
  81. struct rspamd_dns_resolver *resolver;
  82. gboolean replied;
  83. };
  84. static GQuark
  85. http_proxy_quark (void)
  86. {
  87. return g_quark_from_static_string ("http-proxy");
  88. }
  89. static gboolean
  90. http_proxy_parse_upstream (rspamd_mempool_t *pool,
  91. const ucl_object_t *obj,
  92. gpointer ud,
  93. struct rspamd_rcl_section *section,
  94. GError **err)
  95. {
  96. const ucl_object_t *elt;
  97. struct rspamd_http_upstream *up = NULL;
  98. struct http_proxy_ctx *ctx;
  99. struct rspamd_rcl_struct_parser *pd = ud;
  100. ctx = pd->user_struct;
  101. if (ucl_object_type (obj) != UCL_OBJECT) {
  102. g_set_error (err, http_proxy_quark (), 100,
  103. "upstream option must be an object");
  104. return FALSE;
  105. }
  106. elt = ucl_object_find_key (obj, "name");
  107. if (elt == NULL) {
  108. g_set_error (err, http_proxy_quark (), 100,
  109. "upstream option must have some name definition");
  110. return FALSE;
  111. }
  112. up = g_slice_alloc0 (sizeof (*up));
  113. up->name = g_strdup (ucl_object_tostring (elt));
  114. elt = ucl_object_find_key (obj, "key");
  115. if (elt != NULL) {
  116. up->key = rspamd_http_connection_make_peer_key (ucl_object_tostring (elt));
  117. if (up->key == NULL) {
  118. g_set_error (err, http_proxy_quark (), 100,
  119. "cannot read upstream key");
  120. goto err;
  121. }
  122. }
  123. elt = ucl_object_find_key (obj, "hosts");
  124. if (elt == NULL) {
  125. g_set_error (err, http_proxy_quark (), 100,
  126. "upstream option must have some hosts definition");
  127. goto err;
  128. }
  129. up->u = rspamd_upstreams_create (ctx->cfg->ups_ctx);
  130. if (!rspamd_upstreams_from_ucl (up->u, elt, 11333, NULL)) {
  131. g_set_error (err, http_proxy_quark (), 100,
  132. "upstream has bad hosts definition");
  133. goto err;
  134. }
  135. elt = ucl_object_find_key (obj, "default");
  136. if (elt && ucl_object_toboolean (elt)) {
  137. ctx->default_upstream = up;
  138. }
  139. g_hash_table_insert (ctx->upstreams, up->name, up);
  140. return TRUE;
  141. err:
  142. if (up) {
  143. g_free (up->name);
  144. rspamd_upstreams_destroy (up->u);
  145. if (up->key) {
  146. rspamd_http_connection_key_unref (up->key);
  147. }
  148. g_slice_free1 (sizeof (*up), up);
  149. }
  150. return FALSE;
  151. }
  152. gpointer
  153. init_http_proxy (struct rspamd_config *cfg)
  154. {
  155. struct http_proxy_ctx *ctx;
  156. GQuark type;
  157. type = g_quark_try_string ("http_proxy");
  158. ctx = g_malloc0 (sizeof (struct http_proxy_ctx));
  159. ctx->timeout = 5.0;
  160. ctx->upstreams = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
  161. ctx->rotate_tm = DEFAULT_ROTATION_TIME;
  162. ctx->cfg = cfg;
  163. rspamd_rcl_register_worker_option (cfg,
  164. type,
  165. "timeout",
  166. rspamd_rcl_parse_struct_time,
  167. ctx,
  168. G_STRUCT_OFFSET (struct http_proxy_ctx,
  169. timeout),
  170. RSPAMD_CL_FLAG_TIME_FLOAT,
  171. "IO timeout");
  172. rspamd_rcl_register_worker_option (cfg,
  173. type,
  174. "rotate",
  175. rspamd_rcl_parse_struct_time,
  176. ctx,
  177. G_STRUCT_OFFSET (struct http_proxy_ctx,
  178. rotate_tm),
  179. RSPAMD_CL_FLAG_TIME_FLOAT,
  180. "Rotation keys time, default: "
  181. G_STRINGIFY (DEFAULT_ROTATION_TIME) " seconds");
  182. rspamd_rcl_register_worker_option (cfg,
  183. type,
  184. "keypair",
  185. rspamd_rcl_parse_struct_keypair,
  186. ctx,
  187. G_STRUCT_OFFSET (struct http_proxy_ctx,
  188. key),
  189. 0,
  190. "Server's keypair");
  191. rspamd_rcl_register_worker_option (cfg,
  192. type,
  193. "upstream",
  194. http_proxy_parse_upstream,
  195. ctx,
  196. 0,
  197. 0,
  198. "List of upstreams");
  199. return ctx;
  200. }
  201. static void
  202. proxy_session_cleanup (struct http_proxy_session *session)
  203. {
  204. rspamd_inet_address_destroy (session->client_addr);
  205. if (session->backend_conn) {
  206. rspamd_http_connection_unref (session->backend_conn);
  207. }
  208. if (session->client_conn) {
  209. rspamd_http_connection_unref (session->client_conn);
  210. }
  211. close (session->backend_sock);
  212. close (session->client_sock);
  213. g_slice_free1 (sizeof (*session), session);
  214. }
  215. static void
  216. proxy_client_write_error (struct http_proxy_session *session, gint code)
  217. {
  218. struct rspamd_http_message *reply;
  219. reply = rspamd_http_new_message (HTTP_RESPONSE);
  220. reply->code = code;
  221. rspamd_http_connection_write_message (session->client_conn,
  222. reply, NULL, NULL, session, session->client_sock,
  223. &session->ctx->io_tv, session->ev_base);
  224. }
  225. static void
  226. proxy_backend_error_handler (struct rspamd_http_connection *conn, GError *err)
  227. {
  228. struct http_proxy_session *session = conn->ud;
  229. msg_info ("abnormally closing connection from backend: %s, error: %s",
  230. rspamd_inet_address_to_string (rspamd_upstream_addr (session->up)),
  231. err->message);
  232. rspamd_http_connection_reset (session->backend_conn);
  233. /* Terminate session immediately */
  234. proxy_client_write_error (session, err->code);
  235. }
  236. static gint
  237. proxy_backend_finish_handler (struct rspamd_http_connection *conn,
  238. struct rspamd_http_message *msg)
  239. {
  240. struct http_proxy_session *session = conn->ud;
  241. rspamd_http_connection_steal_msg (session->backend_conn);
  242. rspamd_http_message_remove_header (msg, "Content-Length");
  243. rspamd_http_message_remove_header (msg, "Key");
  244. rspamd_http_connection_reset (session->backend_conn);
  245. rspamd_http_connection_write_message (session->client_conn,
  246. msg, NULL, NULL, session, session->client_sock,
  247. &session->ctx->io_tv, session->ev_base);
  248. return 0;
  249. }
  250. static void
  251. proxy_client_error_handler (struct rspamd_http_connection *conn, GError *err)
  252. {
  253. struct http_proxy_session *session = conn->ud;
  254. msg_info ("abnormally closing connection from: %s, error: %s",
  255. rspamd_inet_address_to_string (session->client_addr), err->message);
  256. /* Terminate session immediately */
  257. proxy_session_cleanup (session);
  258. }
  259. static gint
  260. proxy_client_finish_handler (struct rspamd_http_connection *conn,
  261. struct rspamd_http_message *msg)
  262. {
  263. struct http_proxy_session *session = conn->ud;
  264. struct rspamd_http_upstream *backend = NULL;
  265. const rspamd_ftok_t *host;
  266. gchar hostbuf[512];
  267. if (!session->replied) {
  268. host = rspamd_http_message_find_header (msg, "Host");
  269. if (host == NULL) {
  270. backend = session->ctx->default_upstream;
  271. }
  272. else {
  273. rspamd_strlcpy (hostbuf, host->begin, MIN(host->len + 1, sizeof (hostbuf)));
  274. backend = g_hash_table_lookup (session->ctx->upstreams, hostbuf);
  275. if (backend == NULL) {
  276. backend = session->ctx->default_upstream;
  277. }
  278. }
  279. if (backend == NULL) {
  280. /* No backend */
  281. msg_err ("cannot find upstream for %s", host ? hostbuf : "default");
  282. goto err;
  283. }
  284. else {
  285. session->up = rspamd_upstream_get (backend->u,
  286. RSPAMD_UPSTREAM_ROUND_ROBIN, NULL, 0);
  287. if (session->up == NULL) {
  288. msg_err ("cannot select upstream for %s", host ? hostbuf : "default");
  289. goto err;
  290. }
  291. session->backend_sock = rspamd_inet_address_connect (
  292. rspamd_upstream_addr (session->up), SOCK_STREAM, TRUE);
  293. if (session->backend_sock == -1) {
  294. msg_err ("cannot connect upstream for %s", host ? hostbuf : "default");
  295. rspamd_upstream_fail (session->up);
  296. goto err;
  297. }
  298. rspamd_http_connection_steal_msg (session->client_conn);
  299. rspamd_http_message_remove_header (msg, "Content-Length");
  300. rspamd_http_message_remove_header (msg, "Key");
  301. rspamd_http_connection_reset (session->client_conn);
  302. session->backend_conn = rspamd_http_connection_new (
  303. NULL,
  304. proxy_backend_error_handler,
  305. proxy_backend_finish_handler,
  306. RSPAMD_HTTP_CLIENT_SIMPLE,
  307. RSPAMD_HTTP_CLIENT,
  308. session->ctx->keys_cache);
  309. rspamd_http_connection_set_key (session->backend_conn,
  310. session->ctx->local_key);
  311. msg->peer_key = rspamd_http_connection_key_ref (backend->key);
  312. session->replied = TRUE;
  313. rspamd_http_connection_write_message (session->backend_conn,
  314. msg, NULL, NULL, session, session->backend_sock,
  315. &session->ctx->io_tv, session->ev_base);
  316. }
  317. }
  318. else {
  319. proxy_session_cleanup (session);
  320. }
  321. return 0;
  322. err:
  323. session->replied = TRUE;
  324. proxy_client_write_error (session, 404);
  325. return 0;
  326. }
  327. static void
  328. proxy_accept_socket (gint fd, short what, void *arg)
  329. {
  330. struct rspamd_worker *worker = (struct rspamd_worker *) arg;
  331. struct http_proxy_ctx *ctx;
  332. rspamd_inet_addr_t *addr;
  333. struct http_proxy_session *session;
  334. gint nfd;
  335. ctx = worker->ctx;
  336. if ((nfd =
  337. rspamd_accept_from_socket (fd, &addr)) == -1) {
  338. msg_warn ("accept failed: %s", strerror (errno));
  339. return;
  340. }
  341. /* Check for EAGAIN */
  342. if (nfd == 0) {
  343. return;
  344. }
  345. msg_info ("accepted connection from %s port %d",
  346. rspamd_inet_address_to_string (addr),
  347. rspamd_inet_address_get_port (addr));
  348. session = g_slice_alloc0 (sizeof (*session));
  349. session->client_sock = nfd;
  350. session->client_addr = addr;
  351. session->resolver = ctx->resolver;
  352. session->client_conn = rspamd_http_connection_new (
  353. NULL,
  354. proxy_client_error_handler,
  355. proxy_client_finish_handler,
  356. 0,
  357. RSPAMD_HTTP_SERVER,
  358. ctx->keys_cache);
  359. session->ev_base = ctx->ev_base;
  360. session->ctx = ctx;
  361. if (ctx->key) {
  362. rspamd_http_connection_set_key (session->client_conn, ctx->key);
  363. }
  364. rspamd_http_connection_read_message (session->client_conn,
  365. session,
  366. nfd,
  367. &ctx->io_tv,
  368. ctx->ev_base);
  369. }
  370. static void
  371. proxy_rotate_key (gint fd, short what, void *arg)
  372. {
  373. struct timeval rot_tv;
  374. struct http_proxy_ctx *ctx = arg;
  375. gpointer kp;
  376. double_to_tv (ctx->rotate_tm, &rot_tv);
  377. rot_tv.tv_sec += ottery_rand_range (rot_tv.tv_sec);
  378. event_del (&ctx->rotate_ev);
  379. event_add (&ctx->rotate_ev, &rot_tv);
  380. kp = ctx->local_key;
  381. ctx->local_key = rspamd_http_connection_gen_key ();
  382. rspamd_http_connection_key_unref (kp);
  383. }
  384. void
  385. start_http_proxy (struct rspamd_worker *worker)
  386. {
  387. struct http_proxy_ctx *ctx = worker->ctx;
  388. struct timeval rot_tv;
  389. ctx->ev_base = rspamd_prepare_worker (worker, "http_proxy",
  390. proxy_accept_socket);
  391. rspamd_map_watch (worker->srv->cfg, ctx->ev_base);
  392. ctx->resolver = dns_resolver_init (worker->srv->logger,
  393. ctx->ev_base,
  394. worker->srv->cfg);
  395. double_to_tv (ctx->timeout, &ctx->io_tv);
  396. rspamd_upstreams_library_config (worker->srv->cfg, ctx->cfg->ups_ctx,
  397. ctx->ev_base, ctx->resolver->r);
  398. /* XXX: stupid default */
  399. ctx->keys_cache = rspamd_keypair_cache_new (256);
  400. ctx->local_key = rspamd_http_connection_gen_key ();
  401. double_to_tv (ctx->rotate_tm, &rot_tv);
  402. rot_tv.tv_sec += ottery_rand_range (rot_tv.tv_sec);
  403. event_set (&ctx->rotate_ev, -1, EV_TIMEOUT, proxy_rotate_key, ctx);
  404. event_base_set (ctx->ev_base, &ctx->rotate_ev);
  405. event_add (&ctx->rotate_ev, &rot_tv);
  406. event_base_loop (ctx->ev_base, 0);
  407. rspamd_worker_block_signals ();
  408. g_mime_shutdown ();
  409. rspamd_log_close (worker->srv->logger);
  410. if (ctx->key) {
  411. rspamd_http_connection_key_unref (ctx->key);
  412. }
  413. rspamd_keypair_cache_destroy (ctx->keys_cache);
  414. exit (EXIT_SUCCESS);
  415. }