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.

smtp_proxy.c 30KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  1. /* Copyright (c) 2010-2012, Vsevolod Stakhov
  2. * All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above copyright
  9. * notice, this list of conditions and the following disclaimer in the
  10. * documentation and/or other materials provided with the distribution.
  11. *
  12. * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
  13. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  16. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #include "config.h"
  24. #include "main.h"
  25. #include "cfg_file.h"
  26. #include "cfg_xml.h"
  27. #include "util.h"
  28. #include "smtp_proto.h"
  29. #include "map.h"
  30. #include "message.h"
  31. #include "settings.h"
  32. #include "dns.h"
  33. #include "upstream.h"
  34. #include "proxy.h"
  35. /*
  36. * SMTP proxy is a simple smtp proxy worker for dns resolving and
  37. * load balancing. It uses XCLIENT command and is designed for MTA
  38. * that supports that (postfix and exim).
  39. */
  40. /* Upstream timeouts */
  41. #define DEFAULT_UPSTREAM_ERROR_TIME 10
  42. #define DEFAULT_UPSTREAM_DEAD_TIME 300
  43. #define DEFAULT_UPSTREAM_MAXERRORS 10
  44. #define DEFAULT_PROXY_BUF_LEN 100 * 1024
  45. #define SMTP_MAXERRORS 15
  46. static sig_atomic_t wanna_die = 0;
  47. /* Init functions */
  48. gpointer init_smtp_proxy (void);
  49. void start_smtp_proxy (struct rspamd_worker *worker);
  50. worker_t smtp_proxy_worker = {
  51. "smtp_proxy", /* Name */
  52. init_smtp_proxy, /* Init function */
  53. start_smtp_proxy, /* Start function */
  54. TRUE, /* Has socket */
  55. FALSE, /* Non unique */
  56. FALSE, /* Non threaded */
  57. TRUE, /* Killable */
  58. SOCK_STREAM /* TCP socket */
  59. };
  60. struct smtp_proxy_ctx {
  61. struct smtp_upstream upstreams[MAX_SMTP_UPSTREAMS];
  62. size_t upstream_num;
  63. gchar *upstreams_str;
  64. memory_pool_t *pool;
  65. guint32 smtp_delay;
  66. guint32 delay_jitter;
  67. guint32 smtp_timeout_raw;
  68. struct timeval smtp_timeout;
  69. gboolean use_xclient;
  70. gboolean instant_reject;
  71. gsize proxy_buf_len;
  72. struct rspamd_dns_resolver *resolver;
  73. struct event_base *ev_base;
  74. GList *rbls;
  75. };
  76. enum rspamd_smtp_proxy_state {
  77. SMTP_PROXY_STATE_RESOLVE_REVERSE = 0,
  78. SMTP_PROXY_STATE_RESOLVE_NORMAL,
  79. SMTP_PROXY_STATE_RESOLVE_RBL,
  80. SMTP_PROXY_STATE_DELAY,
  81. SMTP_PROXY_STATE_GREETING,
  82. SMTP_PROXY_STATE_XCLIENT,
  83. SMTP_PROXY_STATE_PROXY,
  84. SMTP_PROXY_STATE_REJECT,
  85. SMTP_PROXY_STATE_REJECT_EMULATE
  86. };
  87. struct smtp_proxy_session {
  88. struct smtp_proxy_ctx *ctx;
  89. memory_pool_t *pool;
  90. enum rspamd_smtp_proxy_state state;
  91. struct rspamd_worker *worker;
  92. struct in_addr client_addr;
  93. gchar *hostname;
  94. gchar *error;
  95. gchar *temp_name;
  96. gint sock;
  97. gint upstream_sock;
  98. struct rspamd_async_session *s;
  99. rspamd_io_dispatcher_t *dispatcher;
  100. rspamd_proxy_t *proxy;
  101. struct smtp_upstream *upstream;
  102. struct event *delay_timer;
  103. struct event upstream_ev;
  104. gboolean resolved;
  105. struct rspamd_dns_resolver *resolver;
  106. struct event_base *ev_base;
  107. GString *upstream_greeting;
  108. guint rbl_requests;
  109. gchar *dnsbl_applied;
  110. gchar *from;
  111. gchar *rcpt;
  112. guint errors;
  113. };
  114. #ifndef HAVE_SA_SIGINFO
  115. static void
  116. sig_handler (gint signo)
  117. #else
  118. static void
  119. sig_handler (gint signo, siginfo_t *info, void *unused)
  120. #endif
  121. {
  122. struct timeval tv;
  123. switch (signo) {
  124. case SIGINT:
  125. case SIGTERM:
  126. if (!wanna_die) {
  127. wanna_die = 1;
  128. tv.tv_sec = 0;
  129. tv.tv_usec = 0;
  130. event_loopexit (&tv);
  131. #ifdef WITH_GPERF_TOOLS
  132. ProfilerStop ();
  133. #endif
  134. }
  135. break;
  136. }
  137. }
  138. /*
  139. * Config reload is designed by sending sigusr to active workers and pending shutdown of them
  140. */
  141. static void
  142. sigusr2_handler (gint fd, short what, void *arg)
  143. {
  144. struct rspamd_worker *worker = (struct rspamd_worker *)arg;
  145. /* Do not accept new connections, preparing to end worker's process */
  146. struct timeval tv;
  147. if (! wanna_die) {
  148. tv.tv_sec = SOFT_SHUTDOWN_TIME;
  149. tv.tv_usec = 0;
  150. event_del (&worker->sig_ev_usr1);
  151. event_del (&worker->sig_ev_usr2);
  152. worker_stop_accept (worker);
  153. msg_info ("worker's shutdown is pending in %d sec", SOFT_SHUTDOWN_TIME);
  154. event_loopexit (&tv);
  155. }
  156. return;
  157. }
  158. /*
  159. * Reopen log is designed by sending sigusr1 to active workers and pending shutdown of them
  160. */
  161. static void
  162. sigusr1_handler (gint fd, short what, void *arg)
  163. {
  164. struct rspamd_worker *worker = (struct rspamd_worker *) arg;
  165. reopen_log (worker->srv->logger);
  166. return;
  167. }
  168. static void
  169. free_smtp_proxy_session (gpointer arg)
  170. {
  171. struct smtp_proxy_session *session = arg;
  172. static const char fatal_smtp_error[] = "521 5.2.1 Internal error" CRLF;
  173. if (session) {
  174. if (session->dispatcher) {
  175. rspamd_remove_dispatcher (session->dispatcher);
  176. }
  177. if (session->upstream_greeting) {
  178. g_string_free (session->upstream_greeting, TRUE);
  179. }
  180. if (session->state != SMTP_PROXY_STATE_PROXY && session->state != SMTP_PROXY_STATE_REJECT &&
  181. session->state != SMTP_PROXY_STATE_REJECT_EMULATE) {
  182. /* Send 521 fatal error */
  183. if (write (session->sock, fatal_smtp_error, sizeof (fatal_smtp_error)) == -1) {
  184. msg_err ("write error to client failed: %s", strerror (errno));
  185. }
  186. }
  187. else if ((session->state == SMTP_PROXY_STATE_REJECT || session->state == SMTP_PROXY_STATE_REJECT_EMULATE) &&
  188. session->from && session->rcpt && session->dnsbl_applied) {
  189. msg_info ("reject by %s mail from <%s> to <%s>, ip: %s", session->dnsbl_applied,
  190. session->from, session->rcpt, inet_ntoa (session->client_addr));
  191. }
  192. close (session->sock);
  193. if (session->proxy) {
  194. rspamd_proxy_close (session->proxy);
  195. }
  196. if (session->upstream_sock != -1) {
  197. event_del (&session->upstream_ev);
  198. close (session->upstream_sock);
  199. }
  200. memory_pool_delete (session->pool);
  201. g_slice_free1 (sizeof (struct smtp_proxy_session), session);
  202. }
  203. }
  204. static void
  205. smtp_proxy_err_proxy (GError * err, void *arg)
  206. {
  207. struct smtp_proxy_session *session = arg;
  208. if (err) {
  209. g_error_free (err);
  210. msg_info ("abnormally closing connection, error: %s", err->message);
  211. }
  212. /* Free buffers */
  213. session->state = SMTP_PROXY_STATE_REJECT;
  214. destroy_session (session->s);
  215. }
  216. /**
  217. * Check whether SMTP greeting is valid
  218. * @param s
  219. * @return
  220. */
  221. static gint
  222. check_valid_smtp_greeting (GString *s)
  223. {
  224. gchar *p;
  225. p = s->str + s->len - 1;
  226. if (s->len < 6 || (*p != '\n' || *(p - 1) != '\r')) {
  227. return 1;
  228. }
  229. p -= 5;
  230. while (p >= s->str) {
  231. /* It is fast to use memcmp here as we compare only 4 bytes */
  232. if (memcmp (p, "220 ", 4) == 0) {
  233. /* Check position */
  234. if (p == s->str || *(p - 1) == '\n') {
  235. return 1;
  236. }
  237. return 0;
  238. }
  239. else if ((*p == '5' || *p == '4' || *p == '3') &&
  240. g_ascii_isdigit (p[1]) && g_ascii_isdigit (p[2]) && p[3] == ' ') {
  241. return -1;
  242. }
  243. p --;
  244. }
  245. return 1;
  246. }
  247. /*
  248. * Handle upstream greeting
  249. */
  250. static void
  251. smtp_proxy_greeting_handler (gint fd, short what, void *arg)
  252. {
  253. struct smtp_proxy_session *session = arg;
  254. gint r;
  255. gchar read_buf[BUFSIZ];
  256. if (what == EV_READ) {
  257. if (session->state == SMTP_PROXY_STATE_GREETING) {
  258. /* Fill greeting buffer with new portion of data */
  259. r = read (fd, read_buf, sizeof (read_buf) - 1);
  260. if (r > 0) {
  261. g_string_append_len (session->upstream_greeting, read_buf, r);
  262. /* Now search line with 220 */
  263. r = check_valid_smtp_greeting (session->upstream_greeting);
  264. if (r == 1) {
  265. /* Send xclient */
  266. if (session->ctx->use_xclient) {
  267. r = rspamd_snprintf (read_buf, sizeof (read_buf), "XCLIENT NAME=%s ADDR=%s" CRLF,
  268. session->hostname, inet_ntoa (session->client_addr));
  269. r = write (session->upstream_sock, read_buf, r);
  270. if (r < 0 && errno == EAGAIN) {
  271. /* Add write event */
  272. event_del (&session->upstream_ev);
  273. event_set (&session->upstream_ev, session->upstream_sock,
  274. EV_WRITE, smtp_proxy_greeting_handler, session);
  275. event_base_set (session->ev_base, &session->upstream_ev);
  276. event_add (&session->upstream_ev, NULL);
  277. }
  278. else if (r > 0) {
  279. session->upstream_greeting->len = 0;
  280. session->state = SMTP_PROXY_STATE_XCLIENT;
  281. }
  282. else {
  283. msg_info ("connection with %s got write error: %s", inet_ntoa (session->client_addr), strerror (errno));
  284. destroy_session (session->s);
  285. }
  286. }
  287. else {
  288. event_del (&session->upstream_ev);
  289. /* Start direct proxy */
  290. r = write (session->sock, session->upstream_greeting->str, session->upstream_greeting->len);
  291. /* TODO: handle client's error here */
  292. if (r > 0) {
  293. session->proxy = rspamd_create_proxy (session->sock, session->upstream_sock, session->pool,
  294. session->ev_base, session->ctx->proxy_buf_len,
  295. &session->ctx->smtp_timeout, smtp_proxy_err_proxy, session);
  296. session->state = SMTP_PROXY_STATE_PROXY;
  297. }
  298. else {
  299. msg_info ("connection with %s got write error: %s", inet_ntoa (session->client_addr), strerror (errno));
  300. destroy_session (session->s);
  301. }
  302. }
  303. }
  304. else if (r == -1) {
  305. /* Proxy sent 500 error */
  306. msg_info ("connection with %s got smtp error for greeting", session->upstream->name);
  307. destroy_session (session->s);
  308. }
  309. }
  310. else {
  311. msg_info ("connection with %s got read error: %s", session->upstream->name, strerror (errno));
  312. destroy_session (session->s);
  313. }
  314. }
  315. else if (session->state == SMTP_PROXY_STATE_XCLIENT) {
  316. /* Fill greeting buffer with new portion of data */
  317. r = read (fd, read_buf, sizeof (read_buf) - 1);
  318. if (r > 0) {
  319. g_string_append_len (session->upstream_greeting, read_buf, r);
  320. /* Now search line with 220 */
  321. r = check_valid_smtp_greeting (session->upstream_greeting);
  322. if (r == 1) {
  323. event_del (&session->upstream_ev);
  324. /* Start direct proxy */
  325. r = write (session->sock, session->upstream_greeting->str, session->upstream_greeting->len);
  326. /* TODO: handle client's error here */
  327. if (r > 0) {
  328. session->proxy = rspamd_create_proxy (session->sock, session->upstream_sock, session->pool,
  329. session->ev_base, session->ctx->proxy_buf_len,
  330. &session->ctx->smtp_timeout, smtp_proxy_err_proxy, session);
  331. session->state = SMTP_PROXY_STATE_PROXY;
  332. }
  333. else {
  334. msg_info ("connection with %s got write error: %s", inet_ntoa (session->client_addr), strerror (errno));
  335. destroy_session (session->s);
  336. }
  337. }
  338. else if (r == -1) {
  339. /* Proxy sent 500 error */
  340. msg_info ("connection with %s got smtp error for xclient", session->upstream->name);
  341. destroy_session (session->s);
  342. }
  343. }
  344. }
  345. else {
  346. msg_info ("connection with %s got read event at improper state: %d", session->upstream->name, session->state);
  347. destroy_session (session->s);
  348. }
  349. }
  350. else if (what == EV_WRITE) {
  351. if (session->state == SMTP_PROXY_STATE_GREETING) {
  352. /* Send xclient again */
  353. r = rspamd_snprintf (read_buf, sizeof (read_buf), "XCLIENT NAME=%s ADDR=%s" CRLF,
  354. session->hostname, inet_ntoa (session->client_addr));
  355. r = write (session->upstream_sock, read_buf, r);
  356. if (r < 0 && errno == EAGAIN) {
  357. /* Add write event */
  358. event_del (&session->upstream_ev);
  359. event_set (&session->upstream_ev, session->upstream_sock,
  360. EV_WRITE, smtp_proxy_greeting_handler, session);
  361. event_base_set (session->ev_base, &session->upstream_ev);
  362. event_add (&session->upstream_ev, NULL);
  363. }
  364. else if (r > 0) {
  365. session->upstream_greeting->len = 0;
  366. session->state = SMTP_PROXY_STATE_XCLIENT;
  367. event_del (&session->upstream_ev);
  368. event_set (&session->upstream_ev, session->upstream_sock,
  369. EV_READ | EV_PERSIST, smtp_proxy_greeting_handler, session);
  370. event_base_set (session->ev_base, &session->upstream_ev);
  371. event_add (&session->upstream_ev, NULL);
  372. }
  373. else {
  374. msg_info ("connection with %s got write error: %s", session->upstream->name, strerror (errno));
  375. destroy_session (session->s);
  376. }
  377. }
  378. else {
  379. msg_info ("connection with %s got write event at improper state: %d", session->upstream->name, session->state);
  380. destroy_session (session->s);
  381. }
  382. }
  383. else {
  384. /* Timeout */
  385. msg_info ("connection with %s timed out", session->upstream->name);
  386. destroy_session (session->s);
  387. }
  388. }
  389. static gboolean
  390. create_smtp_proxy_upstream_connection (struct smtp_proxy_session *session)
  391. {
  392. struct smtp_upstream *selected;
  393. /* Try to select upstream */
  394. selected = (struct smtp_upstream *)get_upstream_round_robin (session->ctx->upstreams,
  395. session->ctx->upstream_num, sizeof (struct smtp_upstream),
  396. time (NULL), DEFAULT_UPSTREAM_ERROR_TIME, DEFAULT_UPSTREAM_DEAD_TIME, DEFAULT_UPSTREAM_MAXERRORS);
  397. if (selected == NULL) {
  398. msg_err ("no upstreams suitable found");
  399. return FALSE;
  400. }
  401. session->upstream = selected;
  402. /* Now try to create socket */
  403. session->upstream_sock = make_universal_socket (selected->name, selected->port, SOCK_STREAM, TRUE, FALSE, FALSE);
  404. if (session->upstream_sock == -1) {
  405. msg_err ("cannot make a connection to %s", selected->name);
  406. upstream_fail (&selected->up, time (NULL));
  407. return FALSE;
  408. }
  409. /* Create a proxy for upstream connection */
  410. rspamd_dispatcher_pause (session->dispatcher);
  411. /* First of all get upstream's greeting */
  412. session->state = SMTP_PROXY_STATE_GREETING;
  413. event_set (&session->upstream_ev, session->upstream_sock, EV_READ | EV_PERSIST, smtp_proxy_greeting_handler, session);
  414. event_base_set (session->ev_base, &session->upstream_ev);
  415. event_add (&session->upstream_ev, &session->ctx->smtp_timeout);
  416. session->upstream_greeting = g_string_sized_new (BUFSIZ);
  417. return TRUE;
  418. }
  419. static void
  420. smtp_dnsbl_cb (struct rspamd_dns_reply *reply, void *arg)
  421. {
  422. struct smtp_proxy_session *session = arg;
  423. const gchar *p;
  424. gint dots = 0;
  425. session->rbl_requests --;
  426. msg_debug ("got reply for %s: %s", reply->request->requested_name, dns_strerror (reply->code));
  427. if (session->state != SMTP_PROXY_STATE_REJECT) {
  428. if (reply->code == DNS_RC_NOERROR) {
  429. /* This means that address is in dnsbl */
  430. p = reply->request->requested_name;
  431. while (*p) {
  432. if (*p == '.') {
  433. dots ++;
  434. }
  435. if (dots == 4) {
  436. session->dnsbl_applied = (gchar *)p + 1;
  437. break;
  438. }
  439. p ++;
  440. }
  441. session->state = SMTP_PROXY_STATE_REJECT;
  442. }
  443. }
  444. if (session->rbl_requests == 0) {
  445. if (session->state != SMTP_PROXY_STATE_REJECT) {
  446. /* Make proxy */
  447. if (!create_smtp_proxy_upstream_connection (session)) {
  448. rspamd_dispatcher_restore (session->dispatcher);
  449. }
  450. }
  451. else {
  452. if (session->ctx->instant_reject) {
  453. msg_info ("reject %s is denied by dnsbl: %s",
  454. inet_ntoa (session->client_addr), session->dnsbl_applied);
  455. if (!rspamd_dispatcher_write (session->dispatcher,
  456. make_smtp_error (session->pool, 521, "%s Client denied by %s", "5.2.1", session->dnsbl_applied),
  457. 0, FALSE, TRUE)) {
  458. msg_err ("cannot write smtp error");
  459. }
  460. }
  461. else {
  462. /* Emulate fake smtp session */
  463. rspamd_set_dispatcher_policy (session->dispatcher, BUFFER_LINE, 0);
  464. if (!rspamd_dispatcher_write (session->dispatcher,
  465. make_smtp_error (session->pool, 220, "smtp ready"),
  466. 0, FALSE, TRUE)) {
  467. msg_err ("cannot write smtp reply");
  468. }
  469. }
  470. rspamd_dispatcher_restore (session->dispatcher);
  471. }
  472. }
  473. }
  474. /*
  475. * Create requests to all rbls
  476. */
  477. static void
  478. make_rbl_requests (struct smtp_proxy_session *session)
  479. {
  480. GList *cur;
  481. gchar *p, *dst;
  482. guint len;
  483. cur = session->ctx->rbls;
  484. while (cur) {
  485. len = INET_ADDRSTRLEN + strlen (cur->data) + 1;
  486. dst = memory_pool_alloc (session->pool, len);
  487. /* Print ipv4 addr */
  488. p = (gchar *)&session->client_addr.s_addr;
  489. rspamd_snprintf (dst, len, "%ud.%ud.%ud.%ud.%s", (guint)p[3],
  490. (guint)p[2], (guint)p[1], (guint)p[0], cur->data);
  491. if (make_dns_request (session->resolver, session->s, session->pool,
  492. smtp_dnsbl_cb, session, DNS_REQUEST_A, dst)) {
  493. session->rbl_requests ++;
  494. msg_debug ("send request to %s", dst);
  495. }
  496. cur = g_list_next (cur);
  497. }
  498. if (session->rbl_requests == 0) {
  499. /* Create proxy */
  500. if (! create_smtp_proxy_upstream_connection (session)) {
  501. rspamd_dispatcher_restore (session->dispatcher);
  502. }
  503. }
  504. }
  505. /* Resolving and delay handlers */
  506. /*
  507. * Return from a delay
  508. */
  509. static void
  510. smtp_delay_handler (gint fd, short what, void *arg)
  511. {
  512. struct smtp_proxy_session *session = arg;
  513. remove_normal_event (session->s, (event_finalizer_t) event_del,
  514. session->delay_timer);
  515. if (session->state == SMTP_PROXY_STATE_DELAY) {
  516. /* TODO: Create upstream connection here */
  517. if (session->ctx->rbls) {
  518. make_rbl_requests (session);
  519. }
  520. else {
  521. if (!create_smtp_proxy_upstream_connection (session)) {
  522. rspamd_dispatcher_restore (session->dispatcher);
  523. }
  524. }
  525. }
  526. else {
  527. /* TODO: Write error here */
  528. session->state = SMTP_PROXY_STATE_REJECT;
  529. if (!rspamd_dispatcher_write (session->dispatcher,
  530. make_smtp_error (session->pool, 521, "%s Improper use of SMTP command pipelining", "5.2.1"),
  531. 0, FALSE, TRUE)) {
  532. msg_err ("cannot write smtp error");
  533. }
  534. rspamd_dispatcher_restore (session->dispatcher);
  535. }
  536. }
  537. /*
  538. * Make delay for a client
  539. */
  540. static void
  541. smtp_make_delay (struct smtp_proxy_session *session)
  542. {
  543. struct event *tev;
  544. struct timeval *tv;
  545. gint32 jitter;
  546. if (session->ctx->smtp_delay != 0 && session->state == SMTP_PROXY_STATE_DELAY) {
  547. tev = memory_pool_alloc (session->pool, sizeof(struct event));
  548. tv = memory_pool_alloc (session->pool, sizeof(struct timeval));
  549. if (session->ctx->delay_jitter != 0) {
  550. jitter = g_random_int_range (0, session->ctx->delay_jitter);
  551. msec_to_tv (session->ctx->smtp_delay + jitter, tv);
  552. }
  553. else {
  554. msec_to_tv (session->ctx->smtp_delay, tv);
  555. }
  556. evtimer_set (tev, smtp_delay_handler, session);
  557. evtimer_add (tev, tv);
  558. register_async_event (session->s, (event_finalizer_t) event_del, tev,
  559. g_quark_from_static_string ("smtp proxy"));
  560. session->delay_timer = tev;
  561. }
  562. else if (session->state == SMTP_PROXY_STATE_DELAY) {
  563. /* TODO: Create upstream connection here */
  564. if (session->ctx->rbls) {
  565. make_rbl_requests (session);
  566. }
  567. else {
  568. if (!create_smtp_proxy_upstream_connection (session)) {
  569. rspamd_dispatcher_restore (session->dispatcher);
  570. }
  571. }
  572. }
  573. }
  574. /*
  575. * Handle DNS replies
  576. */
  577. static void
  578. smtp_dns_cb (struct rspamd_dns_reply *reply, void *arg)
  579. {
  580. struct smtp_proxy_session *session = arg;
  581. gint res = 0;
  582. union rspamd_reply_element *elt;
  583. GList *cur;
  584. switch (session->state)
  585. {
  586. case SMTP_PROXY_STATE_RESOLVE_REVERSE:
  587. /* Parse reverse reply and start resolve of this ip */
  588. if (reply->code != DNS_RC_NOERROR) {
  589. rspamd_conditional_debug (rspamd_main->logger,
  590. session->client_addr.s_addr, __FUNCTION__, "DNS error: %s",
  591. dns_strerror (reply->code));
  592. if (reply->code == DNS_RC_NXDOMAIN) {
  593. session->hostname = memory_pool_strdup (session->pool,
  594. XCLIENT_HOST_UNAVAILABLE);
  595. }
  596. else {
  597. session->hostname = memory_pool_strdup (session->pool,
  598. XCLIENT_HOST_TEMPFAIL);
  599. }
  600. session->state = SMTP_PROXY_STATE_DELAY;
  601. smtp_make_delay (session);
  602. }
  603. else {
  604. if (reply->elements) {
  605. elt = reply->elements->data;
  606. session->hostname = memory_pool_strdup (session->pool,
  607. elt->ptr.name);
  608. session->state = SMTP_PROXY_STATE_RESOLVE_NORMAL;
  609. make_dns_request (session->resolver, session->s, session->pool,
  610. smtp_dns_cb, session, DNS_REQUEST_A, session->hostname);
  611. }
  612. }
  613. break;
  614. case SMTP_PROXY_STATE_RESOLVE_NORMAL:
  615. if (reply->code != DNS_RC_NOERROR) {
  616. rspamd_conditional_debug (rspamd_main->logger,
  617. session->client_addr.s_addr, __FUNCTION__, "DNS error: %s",
  618. dns_strerror (reply->code));
  619. if (reply->code == DNS_RC_NXDOMAIN) {
  620. session->hostname = memory_pool_strdup (session->pool,
  621. XCLIENT_HOST_UNAVAILABLE);
  622. }
  623. else {
  624. session->hostname = memory_pool_strdup (session->pool,
  625. XCLIENT_HOST_TEMPFAIL);
  626. }
  627. session->state = SMTP_PROXY_STATE_DELAY;
  628. smtp_make_delay (session);
  629. }
  630. else {
  631. res = 0;
  632. cur = reply->elements;
  633. while (cur) {
  634. elt = cur->data;
  635. if (memcmp (&session->client_addr, &elt->a.addr[0],
  636. sizeof(struct in_addr)) == 0) {
  637. res = 1;
  638. session->resolved = TRUE;
  639. break;
  640. }
  641. cur = g_list_next (cur);
  642. }
  643. if (res == 0) {
  644. msg_info(
  645. "cannot find address for hostname: %s, ip: %s", session->hostname, inet_ntoa (session->client_addr));
  646. session->hostname = memory_pool_strdup (session->pool,
  647. XCLIENT_HOST_UNAVAILABLE);
  648. }
  649. session->state = SMTP_PROXY_STATE_DELAY;
  650. smtp_make_delay (session);
  651. }
  652. break;
  653. default:
  654. /* TODO: write something about pipelining */
  655. break;
  656. }
  657. }
  658. static void
  659. proxy_parse_smtp_input (f_str_t *line, struct smtp_proxy_session *session)
  660. {
  661. gchar *p, *c, *end;
  662. gsize len;
  663. p = line->begin;
  664. end = line->begin + line->len;
  665. if (line->len >= sizeof("rcpt to: ") - 1 && (*p == 'r' || *p == 'R') && session->rcpt == NULL) {
  666. if (g_ascii_strncasecmp (p, "rcpt to: ", sizeof ("rcpt to: ") - 1) == 0) {
  667. p += sizeof ("rcpt to: ") - 1;
  668. /* Skip spaces */
  669. while ((g_ascii_isspace (*p) || *p == '<') && p < end) {
  670. p ++;
  671. }
  672. c = p;
  673. while (!(g_ascii_isspace (*p) || *p == '>') && p < end) {
  674. p ++;
  675. }
  676. len = p - c;
  677. session->rcpt = memory_pool_alloc (session->pool, len + 1);
  678. rspamd_strlcpy (session->rcpt, c, len + 1);
  679. }
  680. }
  681. else if (line->len >= sizeof("mail from: ") - 1 && (*p == 'm' || *p == 'M') && session->from == NULL) {
  682. if (g_ascii_strncasecmp (p, "mail from: ", sizeof ("mail from: ") - 1) == 0) {
  683. p += sizeof ("mail from: ") - 1;
  684. /* Skip spaces */
  685. while ((g_ascii_isspace (*p) || *p == '<') && p < end) {
  686. p ++;
  687. }
  688. c = p;
  689. while (!(g_ascii_isspace (*p) || *p == '>') && p < end) {
  690. p ++;
  691. }
  692. len = p - c;
  693. session->from = memory_pool_alloc (session->pool, len + 1);
  694. rspamd_strlcpy (session->from, c, len + 1);
  695. }
  696. }
  697. else if (line->len >= sizeof ("quit") - 1 && (*p == 'q' || *p == 'Q')) {
  698. if (g_ascii_strncasecmp (p, "quit", sizeof ("quit") - 1) == 0) {
  699. session->state = SMTP_PROXY_STATE_REJECT;
  700. }
  701. }
  702. }
  703. /*
  704. * Callback that is called when there is data to read in buffer
  705. */
  706. static gboolean
  707. smtp_proxy_read_socket (f_str_t * in, void *arg)
  708. {
  709. struct smtp_proxy_session *session = arg;
  710. gchar *p;
  711. if (session->state != SMTP_PROXY_STATE_REJECT_EMULATE) {
  712. /* This can be called only if client is using invalid pipelining */
  713. session->state = SMTP_PROXY_STATE_REJECT;
  714. if (!rspamd_dispatcher_write (session->dispatcher,
  715. make_smtp_error (session->pool, 521, "%s Improper use of SMTP command pipelining", "5.2.1"),
  716. 0, FALSE, TRUE)) {
  717. msg_err ("cannot write smtp error");
  718. }
  719. destroy_session (session->s);
  720. }
  721. else {
  722. /* Try to extract data */
  723. p = in->begin;
  724. if (in->len >= sizeof ("helo") - 1 && (*p == 'h' || *p == 'H' || *p == 'e' || *p == 'E')) {
  725. return rspamd_dispatcher_write (session->dispatcher,
  726. "220 smtp ready" CRLF,
  727. 0, FALSE, TRUE);
  728. }
  729. else if (in->len > 0) {
  730. proxy_parse_smtp_input (in, session);
  731. }
  732. if (session->state == SMTP_PROXY_STATE_REJECT) {
  733. /* Received QUIT command */
  734. if (!rspamd_dispatcher_write (session->dispatcher,
  735. "221 2.0.0 Bye" CRLF,
  736. 0, FALSE, TRUE)) {
  737. msg_err ("cannot write smtp error");
  738. }
  739. destroy_session (session->s);
  740. return FALSE;
  741. }
  742. if (session->rcpt != NULL) {
  743. session->errors ++;
  744. if (session->errors > SMTP_MAXERRORS) {
  745. if (!rspamd_dispatcher_write (session->dispatcher,
  746. "521 5.2.1 Maximum errors reached" CRLF,
  747. 0, FALSE, TRUE)) {
  748. msg_err ("cannot write smtp error");
  749. }
  750. destroy_session (session->s);
  751. return FALSE;
  752. }
  753. return rspamd_dispatcher_write (session->dispatcher,
  754. make_smtp_error (session->pool, 521, "%s Client denied by %s", "5.2.1", session->dnsbl_applied),
  755. 0, FALSE, TRUE);
  756. }
  757. else {
  758. return rspamd_dispatcher_write (session->dispatcher,
  759. "250 smtp ready" CRLF,
  760. 0, FALSE, TRUE);
  761. }
  762. }
  763. return FALSE;
  764. }
  765. /*
  766. * Actually called only if something goes wrong
  767. */
  768. static gboolean
  769. smtp_proxy_write_socket (void *arg)
  770. {
  771. struct smtp_proxy_session *session = arg;
  772. if (session->ctx->instant_reject) {
  773. destroy_session (session->s);
  774. return FALSE;
  775. }
  776. else {
  777. session->state = SMTP_PROXY_STATE_REJECT_EMULATE;
  778. }
  779. return TRUE;
  780. }
  781. /*
  782. * Called if something goes wrong
  783. */
  784. static void
  785. smtp_proxy_err_socket (GError * err, void *arg)
  786. {
  787. struct smtp_proxy_session *session = arg;
  788. if (err) {
  789. if (err->code == ETIMEDOUT) {
  790. /* Write smtp error */
  791. if (!rspamd_dispatcher_write (session->dispatcher,
  792. "421 4.4.2 Error: timeout exceeded" CRLF,
  793. 0, FALSE, TRUE)) {
  794. msg_err ("cannot write smtp error");
  795. }
  796. }
  797. msg_info ("abnormally closing connection, error: %s", err->message);
  798. g_error_free (err);
  799. }
  800. /* Free buffers */
  801. destroy_session (session->s);
  802. }
  803. /*
  804. * Accept new connection and construct session
  805. */
  806. static void
  807. accept_socket (gint fd, short what, void *arg)
  808. {
  809. struct rspamd_worker *worker = (struct rspamd_worker *)arg;
  810. union sa_union su;
  811. struct smtp_proxy_session *session;
  812. struct smtp_proxy_ctx *ctx;
  813. socklen_t addrlen = sizeof (su.ss);
  814. gint nfd;
  815. if ((nfd = accept_from_socket (fd, (struct sockaddr *)&su.ss, &addrlen)) == -1) {
  816. msg_warn ("accept failed: %s", strerror (errno));
  817. return;
  818. }
  819. /* Check for EAGAIN */
  820. if (nfd == 0) {
  821. return;
  822. }
  823. ctx = worker->ctx;
  824. session = g_slice_alloc0 (sizeof (struct smtp_proxy_session));
  825. session->pool = memory_pool_new (memory_pool_get_size ());
  826. if (su.ss.ss_family == AF_UNIX) {
  827. msg_info ("accepted connection from unix socket");
  828. session->client_addr.s_addr = INADDR_NONE;
  829. }
  830. else if (su.ss.ss_family == AF_INET) {
  831. msg_info ("accepted connection from %s port %d", inet_ntoa (su.s4.sin_addr), ntohs (su.s4.sin_port));
  832. memcpy (&session->client_addr, &su.s4.sin_addr, sizeof (struct in_addr));
  833. }
  834. session->sock = nfd;
  835. session->worker = worker;
  836. session->ctx = ctx;
  837. session->resolver = ctx->resolver;
  838. session->ev_base = ctx->ev_base;
  839. session->upstream_sock = -1;
  840. worker->srv->stat->connections_count++;
  841. /* Resolve client's addr */
  842. /* Set up async session */
  843. session->s = new_async_session (session->pool, NULL, NULL, free_smtp_proxy_session, session);
  844. session->state = SMTP_PROXY_STATE_RESOLVE_REVERSE;
  845. if (! make_dns_request (session->resolver, session->s, session->pool,
  846. smtp_dns_cb, session, DNS_REQUEST_PTR, &session->client_addr)) {
  847. msg_err ("cannot resolve %s", inet_ntoa (session->client_addr));
  848. g_slice_free1 (sizeof (struct smtp_proxy_session), session);
  849. close (nfd);
  850. return;
  851. }
  852. else {
  853. session->dispatcher = rspamd_create_dispatcher (session->ev_base, nfd, BUFFER_ANY,
  854. smtp_proxy_read_socket, smtp_proxy_write_socket, smtp_proxy_err_socket,
  855. &session->ctx->smtp_timeout, session);
  856. session->dispatcher->peer_addr = session->client_addr.s_addr;
  857. }
  858. }
  859. gpointer
  860. init_smtp_proxy (void)
  861. {
  862. struct smtp_proxy_ctx *ctx;
  863. GQuark type;
  864. type = g_quark_try_string ("smtp_proxy");
  865. ctx = g_malloc0 (sizeof (struct smtp_worker_ctx));
  866. ctx->pool = memory_pool_new (memory_pool_get_size ());
  867. /* Set default values */
  868. ctx->smtp_timeout_raw = 300000;
  869. ctx->smtp_delay = 0;
  870. ctx->instant_reject = TRUE;
  871. register_worker_opt (type, "upstreams", xml_handle_string, ctx,
  872. G_STRUCT_OFFSET (struct smtp_proxy_ctx, upstreams_str));
  873. register_worker_opt (type, "timeout", xml_handle_seconds, ctx,
  874. G_STRUCT_OFFSET (struct smtp_proxy_ctx, smtp_timeout_raw));
  875. register_worker_opt (type, "delay", xml_handle_seconds, ctx,
  876. G_STRUCT_OFFSET (struct smtp_proxy_ctx, smtp_delay));
  877. register_worker_opt (type, "jitter", xml_handle_seconds, ctx,
  878. G_STRUCT_OFFSET (struct smtp_proxy_ctx, delay_jitter));
  879. register_worker_opt (type, "xclient", xml_handle_boolean, ctx,
  880. G_STRUCT_OFFSET (struct smtp_proxy_ctx, use_xclient));
  881. register_worker_opt (type, "instant_reject", xml_handle_boolean, ctx,
  882. G_STRUCT_OFFSET (struct smtp_proxy_ctx, instant_reject));
  883. register_worker_opt (type, "proxy_buffer", xml_handle_size, ctx,
  884. G_STRUCT_OFFSET (struct smtp_proxy_ctx, proxy_buf_len));
  885. register_worker_opt (type, "dnsbl", xml_handle_list, ctx,
  886. G_STRUCT_OFFSET (struct smtp_proxy_ctx, rbls));
  887. return ctx;
  888. }
  889. /* Make post-init configuration */
  890. static gboolean
  891. config_smtp_proxy_worker (struct rspamd_worker *worker)
  892. {
  893. struct smtp_proxy_ctx *ctx = worker->ctx;
  894. gchar *value;
  895. /* Init timeval */
  896. msec_to_tv (ctx->smtp_timeout_raw, &ctx->smtp_timeout);
  897. /* Init upstreams */
  898. if ((value = ctx->upstreams_str) != NULL) {
  899. if (!parse_upstreams_line (ctx->pool, ctx->upstreams, value, &ctx->upstream_num)) {
  900. return FALSE;
  901. }
  902. }
  903. else {
  904. msg_err ("no upstreams defined, don't know what to do");
  905. return FALSE;
  906. }
  907. if (ctx->proxy_buf_len == 0) {
  908. ctx->proxy_buf_len = DEFAULT_PROXY_BUF_LEN;
  909. }
  910. return TRUE;
  911. }
  912. /*
  913. * Start worker process
  914. */
  915. void
  916. start_smtp_proxy (struct rspamd_worker *worker)
  917. {
  918. struct smtp_proxy_ctx *ctx = worker->ctx;
  919. ctx->ev_base = prepare_worker (worker, "smtp_proxy", sig_handler, accept_socket);
  920. /* Set smtp options */
  921. if ( !config_smtp_proxy_worker (worker)) {
  922. msg_err ("cannot configure smtp worker, exiting");
  923. exit (EXIT_SUCCESS);
  924. }
  925. /* SIGUSR2 handler */
  926. signal_set (&worker->sig_ev_usr2, SIGUSR2, sigusr2_handler, (void *) worker);
  927. event_base_set (ctx->ev_base, &worker->sig_ev_usr2);
  928. signal_add (&worker->sig_ev_usr2, NULL);
  929. /* SIGUSR1 handler */
  930. signal_set (&worker->sig_ev_usr1, SIGUSR1, sigusr1_handler, (void *) worker);
  931. event_base_set (ctx->ev_base, &worker->sig_ev_usr1);
  932. signal_add (&worker->sig_ev_usr1, NULL);
  933. /* DNS resolver */
  934. ctx->resolver = dns_resolver_init (ctx->ev_base, worker->srv->cfg);
  935. /* Set umask */
  936. umask (S_IWGRP | S_IWOTH | S_IROTH | S_IRGRP);
  937. event_base_loop (ctx->ev_base, 0);
  938. close_log (rspamd_main->logger);
  939. exit (EXIT_SUCCESS);
  940. }