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.

dns.c 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  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 <contrib/librdns/rdns.h>
  17. #include <contrib/librdns/dns_private.h>
  18. #include "config.h"
  19. #include "dns.h"
  20. #include "rspamd.h"
  21. #include "utlist.h"
  22. #include "rdns_event.h"
  23. #include "unix-std.h"
  24. static const gchar *M = "rspamd dns";
  25. static struct rdns_upstream_elt* rspamd_dns_select_upstream (const char *name,
  26. size_t len, void *ups_data);
  27. static struct rdns_upstream_elt* rspamd_dns_select_upstream_retransmit (
  28. const char *name,
  29. size_t len, void *ups_data);
  30. static void rspamd_dns_upstream_ok (struct rdns_upstream_elt *elt,
  31. void *ups_data);
  32. static void rspamd_dns_upstream_fail (struct rdns_upstream_elt *elt,
  33. void *ups_data);
  34. static unsigned int rspamd_dns_upstream_count (void *ups_data);
  35. static struct rdns_upstream_context rspamd_ups_ctx = {
  36. .select = rspamd_dns_select_upstream,
  37. .select_retransmit = rspamd_dns_select_upstream_retransmit,
  38. .ok = rspamd_dns_upstream_ok,
  39. .fail = rspamd_dns_upstream_fail,
  40. .count = rspamd_dns_upstream_count,
  41. .data = NULL
  42. };
  43. struct rspamd_dns_request_ud {
  44. struct rspamd_async_session *session;
  45. dns_callback_type cb;
  46. gpointer ud;
  47. rspamd_mempool_t *pool;
  48. struct rspamd_task *task;
  49. struct rspamd_symcache_item *item;
  50. struct rdns_request *req;
  51. struct rdns_reply *reply;
  52. };
  53. static void
  54. rspamd_dns_fin_cb (gpointer arg)
  55. {
  56. struct rspamd_dns_request_ud *reqdata = (struct rspamd_dns_request_ud *)arg;
  57. if (reqdata->item) {
  58. rspamd_symcache_set_cur_item (reqdata->task, reqdata->item);
  59. }
  60. if (reqdata->reply) {
  61. reqdata->cb (reqdata->reply, reqdata->ud);
  62. }
  63. else {
  64. struct rdns_reply fake_reply;
  65. memset (&fake_reply, 0, sizeof (fake_reply));
  66. fake_reply.code = RDNS_RC_TIMEOUT;
  67. fake_reply.request = reqdata->req;
  68. fake_reply.resolver = reqdata->req->resolver;
  69. fake_reply.requested_name = reqdata->req->requested_names[0].name;
  70. reqdata->cb (&fake_reply, reqdata->ud);
  71. }
  72. rdns_request_release (reqdata->req);
  73. if (reqdata->item) {
  74. rspamd_symcache_item_async_dec_check (reqdata->task,
  75. reqdata->item, M);
  76. }
  77. if (reqdata->pool == NULL) {
  78. g_free (reqdata);
  79. }
  80. }
  81. static void
  82. rspamd_dns_callback (struct rdns_reply *reply, gpointer ud)
  83. {
  84. struct rspamd_dns_request_ud *reqdata = ud;
  85. reqdata->reply = reply;
  86. if (reqdata->session) {
  87. /*
  88. * Ref event to avoid double unref by
  89. * event removing
  90. */
  91. rdns_request_retain (reply->request);
  92. rspamd_session_remove_event (reqdata->session, rspamd_dns_fin_cb, reqdata);
  93. }
  94. else {
  95. reqdata->cb (reply, reqdata->ud);
  96. if (reqdata->pool == NULL) {
  97. g_free (reqdata);
  98. }
  99. }
  100. }
  101. struct rspamd_dns_request_ud *
  102. make_dns_request (struct rspamd_dns_resolver *resolver,
  103. struct rspamd_async_session *session,
  104. rspamd_mempool_t *pool,
  105. dns_callback_type cb,
  106. gpointer ud,
  107. enum rdns_request_type type,
  108. const char *name)
  109. {
  110. struct rdns_request *req;
  111. struct rspamd_dns_request_ud *reqdata = NULL;
  112. g_assert (resolver != NULL);
  113. if (resolver->r == NULL) {
  114. return NULL;
  115. }
  116. if (session && rspamd_session_blocked (session)) {
  117. return NULL;
  118. }
  119. if (pool != NULL) {
  120. reqdata =
  121. rspamd_mempool_alloc0 (pool, sizeof (struct rspamd_dns_request_ud));
  122. }
  123. else {
  124. reqdata = g_malloc0 (sizeof (struct rspamd_dns_request_ud));
  125. }
  126. reqdata->pool = pool;
  127. reqdata->session = session;
  128. reqdata->cb = cb;
  129. reqdata->ud = ud;
  130. req = rdns_make_request_full (resolver->r, rspamd_dns_callback, reqdata,
  131. resolver->request_timeout, resolver->max_retransmits, 1, name,
  132. type);
  133. reqdata->req = req;
  134. if (session) {
  135. if (req != NULL) {
  136. rspamd_session_add_event (session,
  137. (event_finalizer_t) rspamd_dns_fin_cb,
  138. reqdata,
  139. M);
  140. }
  141. }
  142. if (req == NULL) {
  143. if (pool == NULL) {
  144. g_free (reqdata);
  145. }
  146. return NULL;
  147. }
  148. return reqdata;
  149. }
  150. static gboolean
  151. make_dns_request_task_common (struct rspamd_task *task,
  152. dns_callback_type cb,
  153. gpointer ud,
  154. enum rdns_request_type type,
  155. const char *name,
  156. gboolean forced)
  157. {
  158. struct rspamd_dns_request_ud *reqdata;
  159. if (!forced && task->dns_requests >= task->cfg->dns_max_requests) {
  160. return FALSE;
  161. }
  162. reqdata = make_dns_request (task->resolver, task->s, task->task_pool, cb, ud,
  163. type, name);
  164. if (reqdata) {
  165. task->dns_requests ++;
  166. reqdata->task = task;
  167. reqdata->item = rspamd_symcache_get_cur_item (task);
  168. if (reqdata->item) {
  169. /* We are inside some session */
  170. rspamd_symcache_item_async_inc (task, reqdata->item, M);
  171. }
  172. if (!forced && task->dns_requests >= task->cfg->dns_max_requests) {
  173. msg_info_task ("<%s> stop resolving on reaching %ud requests",
  174. task->message_id, task->dns_requests);
  175. }
  176. return TRUE;
  177. }
  178. return FALSE;
  179. }
  180. gboolean
  181. make_dns_request_task (struct rspamd_task *task,
  182. dns_callback_type cb,
  183. gpointer ud,
  184. enum rdns_request_type type,
  185. const char *name)
  186. {
  187. return make_dns_request_task_common (task, cb, ud, type, name, FALSE);
  188. }
  189. gboolean
  190. make_dns_request_task_forced (struct rspamd_task *task,
  191. dns_callback_type cb,
  192. gpointer ud,
  193. enum rdns_request_type type,
  194. const char *name)
  195. {
  196. return make_dns_request_task_common (task, cb, ud, type, name, TRUE);
  197. }
  198. static void rspamd_rnds_log_bridge (
  199. void *log_data,
  200. enum rdns_log_level level,
  201. const char *function,
  202. const char *format,
  203. va_list args)
  204. {
  205. rspamd_logger_t *logger = log_data;
  206. rspamd_common_logv (logger, (GLogLevelFlags)level, "rdns", NULL,
  207. function, format, args);
  208. }
  209. static void
  210. rspamd_dns_server_init (struct upstream *up, guint idx, gpointer ud)
  211. {
  212. struct rspamd_dns_resolver *r = ud;
  213. rspamd_inet_addr_t *addr;
  214. void *serv;
  215. struct rdns_upstream_elt *elt;
  216. addr = rspamd_upstream_addr (up);
  217. if (r->cfg) {
  218. serv = rdns_resolver_add_server (r->r, rspamd_inet_address_to_string (addr),
  219. rspamd_inet_address_get_port (addr), 0, r->cfg->dns_io_per_server);
  220. }
  221. else {
  222. serv = rdns_resolver_add_server (r->r, rspamd_inet_address_to_string (addr),
  223. rspamd_inet_address_get_port (addr), 0, 8);
  224. }
  225. g_assert (serv != NULL);
  226. elt = g_malloc0 (sizeof (*elt));
  227. elt->server = serv;
  228. elt->lib_data = up;
  229. rspamd_upstream_set_data (up, elt);
  230. }
  231. static void
  232. rspamd_dns_server_reorder (struct upstream *up, guint idx, gpointer ud)
  233. {
  234. struct rspamd_dns_resolver *r = ud;
  235. rspamd_upstream_set_weight (up, rspamd_upstreams_count (r->ups) - idx + 1);
  236. }
  237. static bool
  238. rspamd_dns_resolv_conf_on_server (struct rdns_resolver *resolver,
  239. const char *name, unsigned int port,
  240. int priority, unsigned int io_cnt, void *ud)
  241. {
  242. struct rspamd_dns_resolver *dns_resolver = ud;
  243. struct rspamd_config *cfg;
  244. rspamd_inet_addr_t *addr;
  245. gint test_fd;
  246. cfg = dns_resolver->cfg;
  247. msg_info_config ("parsed nameserver %s from resolv.conf", name);
  248. /* Try to open a connection */
  249. if (!rspamd_parse_inet_address (&addr, name, strlen (name))) {
  250. msg_warn_config ("cannot parse nameserver address %s", name);
  251. return FALSE;
  252. }
  253. rspamd_inet_address_set_port (addr, port);
  254. test_fd = rspamd_inet_address_connect (addr, SOCK_DGRAM, TRUE);
  255. if (test_fd == -1) {
  256. msg_warn_config ("cannot open connection to nameserver at address %s: %s",
  257. name, strerror (errno));
  258. rspamd_inet_address_free (addr);
  259. return FALSE;
  260. }
  261. rspamd_inet_address_free (addr);
  262. close (test_fd);
  263. return rspamd_upstreams_add_upstream (dns_resolver->ups, name, port,
  264. RSPAMD_UPSTREAM_PARSE_NAMESERVER,
  265. NULL);
  266. }
  267. static void
  268. rspamd_dns_resolver_config_ucl (struct rspamd_config *cfg,
  269. struct rspamd_dns_resolver *dns_resolver,
  270. const ucl_object_t *dns_section)
  271. {
  272. const ucl_object_t *fake_replies, *cur;
  273. ucl_object_iter_t it;
  274. /* Process fake replies */
  275. fake_replies = ucl_object_lookup_any (dns_section, "fake_records",
  276. "fake_replies", NULL);
  277. if (fake_replies && ucl_object_type (fake_replies) == UCL_ARRAY) {
  278. it = ucl_object_iterate_new (fake_replies);
  279. while ((cur = ucl_object_iterate_safe (it, true))) {
  280. const ucl_object_t *type_obj, *name_obj, *code_obj, *replies_obj;
  281. enum rdns_request_type rtype = RDNS_REQUEST_A;
  282. enum dns_rcode rcode = RDNS_RC_NOERROR;
  283. struct rdns_reply_entry *replies = NULL;
  284. const gchar *name = NULL;
  285. if (ucl_object_type (cur) != UCL_OBJECT) {
  286. continue;
  287. }
  288. name_obj = ucl_object_lookup (cur, "name");
  289. if (name_obj == NULL ||
  290. (name = ucl_object_tostring (name_obj)) == NULL) {
  291. msg_err_config ("no name for fake dns reply");
  292. continue;
  293. }
  294. type_obj = ucl_object_lookup (cur, "type");
  295. if (type_obj) {
  296. rtype = rdns_type_fromstr (ucl_object_tostring (type_obj));
  297. if (rtype == RDNS_REQUEST_INVALID) {
  298. msg_err_config ("invalid type for %s: %s", name,
  299. ucl_object_tostring (type_obj));
  300. continue;
  301. }
  302. }
  303. code_obj = ucl_object_lookup_any (cur, "code", "rcode", NULL);
  304. if (code_obj) {
  305. rcode = rdns_rcode_fromstr (ucl_object_tostring (code_obj));
  306. if (rcode == RDNS_RC_INVALID) {
  307. msg_err_config ("invalid rcode for %s: %s", name,
  308. ucl_object_tostring (code_obj));
  309. continue;
  310. }
  311. }
  312. if (rcode == RDNS_RC_NOERROR) {
  313. /* We want replies to be set for this rcode */
  314. replies_obj = ucl_object_lookup (cur, "replies");
  315. if (replies_obj == NULL || ucl_object_type (replies_obj) != UCL_ARRAY) {
  316. msg_err_config ("invalid replies for fake DNS record %s", name);
  317. continue;
  318. }
  319. ucl_object_iter_t rep_it;
  320. const ucl_object_t *rep_obj;
  321. rep_it = ucl_object_iterate_new (replies_obj);
  322. while ((rep_obj = ucl_object_iterate_safe (rep_it, true))) {
  323. const gchar *str_rep = ucl_object_tostring (rep_obj);
  324. struct rdns_reply_entry *rep;
  325. gchar **svec;
  326. if (str_rep == NULL) {
  327. msg_err_config ("invalid reply element for fake DNS record %s",
  328. name);
  329. continue;
  330. }
  331. rep = calloc (1, sizeof (*rep));
  332. g_assert (rep != NULL);
  333. rep->type = rtype;
  334. rep->ttl = 0;
  335. switch (rtype) {
  336. case RDNS_REQUEST_A:
  337. if (inet_pton (AF_INET, str_rep, &rep->content.a.addr) != 1) {
  338. msg_err_config ("invalid A reply element for fake "
  339. "DNS record %s: %s",
  340. name, str_rep);
  341. free (rep);
  342. }
  343. else {
  344. DL_APPEND (replies, rep);
  345. }
  346. break;
  347. case RDNS_REQUEST_NS:
  348. rep->content.ns.name = strdup (str_rep);
  349. DL_APPEND (replies, rep);
  350. break;
  351. case RDNS_REQUEST_PTR:
  352. rep->content.ptr.name = strdup (str_rep);
  353. DL_APPEND (replies, rep);
  354. break;
  355. case RDNS_REQUEST_MX:
  356. svec = g_strsplit_set (str_rep, " :", -1);
  357. if (svec && svec[0] && svec[1]) {
  358. rep->content.mx.priority = strtoul (svec[0], NULL, 10);
  359. rep->content.mx.name = strdup (svec[1]);
  360. DL_APPEND (replies, rep);
  361. }
  362. else {
  363. msg_err_config ("invalid MX reply element for fake "
  364. "DNS record %s: %s",
  365. name, str_rep);
  366. free (rep);
  367. }
  368. g_strfreev (svec);
  369. break;
  370. case RDNS_REQUEST_TXT:
  371. rep->content.txt.data = strdup (str_rep);
  372. DL_APPEND (replies, rep);
  373. break;
  374. case RDNS_REQUEST_SOA:
  375. svec = g_strsplit_set (str_rep, " :", -1);
  376. /* 7 elements */
  377. if (svec && svec[0] && svec[1] && svec[2] &&
  378. svec[3] && svec[4] && svec[5] && svec[6]) {
  379. rep->content.soa.mname = strdup (svec[0]);
  380. rep->content.soa.admin = strdup (svec[1]);
  381. rep->content.soa.serial = strtoul (svec[2], NULL, 10);
  382. rep->content.soa.refresh = strtol (svec[3], NULL, 10);
  383. rep->content.soa.retry = strtol (svec[4], NULL, 10);
  384. rep->content.soa.expire = strtol (svec[5], NULL, 10);
  385. rep->content.soa.minimum = strtoul (svec[6], NULL, 10);
  386. DL_APPEND (replies, rep);
  387. }
  388. else {
  389. msg_err_config ("invalid MX reply element for fake "
  390. "DNS record %s: %s",
  391. name, str_rep);
  392. free (rep);
  393. }
  394. g_strfreev (svec);
  395. break;
  396. case RDNS_REQUEST_AAAA:
  397. if (inet_pton (AF_INET6, str_rep, &rep->content.aaa.addr) != 1) {
  398. msg_err_config ("invalid AAAA reply element for fake "
  399. "DNS record %s: %s",
  400. name, str_rep);
  401. free (rep);
  402. }
  403. else {
  404. DL_APPEND (replies, rep);
  405. }
  406. case RDNS_REQUEST_SRV:
  407. default:
  408. msg_err_config ("invalid or unsupported reply element "
  409. "for fake DNS record %s(%s): %s",
  410. name, rdns_str_from_type (rtype), str_rep);
  411. free (rep);
  412. break;
  413. }
  414. }
  415. ucl_object_iterate_free (rep_it);
  416. if (replies) {
  417. struct rdns_reply_entry *tmp_entry;
  418. guint i = 0;
  419. DL_COUNT (replies, tmp_entry, i);
  420. msg_info_config ("added fake record: %s(%s); %d replies", name,
  421. rdns_str_from_type (rtype), i);
  422. rdns_resolver_set_fake_reply (dns_resolver->r,
  423. name, rtype, rcode, replies);
  424. }
  425. else {
  426. msg_warn_config ("record %s has no replies, not adding",
  427. name);
  428. }
  429. }
  430. else {
  431. /* This entry returns some non valid code, no replies are possible */
  432. replies_obj = ucl_object_lookup (cur, "replies");
  433. if (replies_obj) {
  434. msg_warn_config ("replies are set for non-successful return "
  435. "code for %s(%s), they will be ignored", name, rdns_str_from_type (rtype));
  436. }
  437. rdns_resolver_set_fake_reply (dns_resolver->r,
  438. name, rtype, rcode, NULL);
  439. }
  440. }
  441. ucl_object_iterate_free (it);
  442. }
  443. }
  444. struct rspamd_dns_resolver *
  445. dns_resolver_init (rspamd_logger_t *logger,
  446. struct event_base *ev_base,
  447. struct rspamd_config *cfg)
  448. {
  449. struct rspamd_dns_resolver *dns_resolver;
  450. dns_resolver = g_malloc0 (sizeof (struct rspamd_dns_resolver));
  451. dns_resolver->ev_base = ev_base;
  452. if (cfg != NULL) {
  453. dns_resolver->request_timeout = cfg->dns_timeout;
  454. dns_resolver->max_retransmits = cfg->dns_retransmits;
  455. }
  456. else {
  457. dns_resolver->request_timeout = 1;
  458. dns_resolver->max_retransmits = 2;
  459. }
  460. dns_resolver->r = rdns_resolver_new ();
  461. rdns_bind_libevent (dns_resolver->r, dns_resolver->ev_base);
  462. if (cfg != NULL) {
  463. rdns_resolver_set_log_level (dns_resolver->r, cfg->log_level);
  464. dns_resolver->cfg = cfg;
  465. rdns_resolver_set_dnssec (dns_resolver->r, cfg->enable_dnssec);
  466. if (cfg->nameservers == NULL) {
  467. /* Parse resolv.conf */
  468. dns_resolver->ups = rspamd_upstreams_create (cfg->ups_ctx);
  469. rspamd_upstreams_set_flags (dns_resolver->ups,
  470. RSPAMD_UPSTREAM_FLAG_NORESOLVE);
  471. rspamd_upstreams_set_rotation (dns_resolver->ups,
  472. RSPAMD_UPSTREAM_MASTER_SLAVE);
  473. if (!rdns_resolver_parse_resolv_conf_cb (dns_resolver->r,
  474. "/etc/resolv.conf",
  475. rspamd_dns_resolv_conf_on_server,
  476. dns_resolver)) {
  477. msg_err ("cannot parse resolv.conf and no nameservers defined, "
  478. "so no ways to resolve addresses");
  479. rdns_resolver_release (dns_resolver->r);
  480. dns_resolver->r = NULL;
  481. return dns_resolver;
  482. }
  483. /* Use normal resolv.conf rules */
  484. rspamd_upstreams_foreach (dns_resolver->ups, rspamd_dns_server_reorder,
  485. dns_resolver);
  486. }
  487. else {
  488. dns_resolver->ups = rspamd_upstreams_create (cfg->ups_ctx);
  489. rspamd_upstreams_set_flags (dns_resolver->ups,
  490. RSPAMD_UPSTREAM_FLAG_NORESOLVE);
  491. if (!rspamd_upstreams_from_ucl (dns_resolver->ups, cfg->nameservers,
  492. 53, dns_resolver)) {
  493. msg_err_config ("cannot parse DNS nameservers definitions");
  494. rdns_resolver_release (dns_resolver->r);
  495. dns_resolver->r = NULL;
  496. return dns_resolver;
  497. }
  498. }
  499. rspamd_upstreams_foreach (dns_resolver->ups, rspamd_dns_server_init,
  500. dns_resolver);
  501. rdns_resolver_set_upstream_lib (dns_resolver->r, &rspamd_ups_ctx,
  502. dns_resolver->ups);
  503. cfg->dns_resolver = dns_resolver;
  504. if (cfg->rcl_obj) {
  505. /* Configure additional options */
  506. const ucl_object_t *opts_section, *dns_section;
  507. opts_section = ucl_object_lookup (cfg->rcl_obj, "options");
  508. if (opts_section) {
  509. dns_section = ucl_object_lookup (opts_section, "dns");
  510. if (dns_section) {
  511. rspamd_dns_resolver_config_ucl (cfg, dns_resolver, dns_section);
  512. }
  513. }
  514. }
  515. }
  516. rdns_resolver_set_logger (dns_resolver->r, rspamd_rnds_log_bridge, logger);
  517. rdns_resolver_init (dns_resolver->r);
  518. return dns_resolver;
  519. }
  520. static struct rdns_upstream_elt*
  521. rspamd_dns_select_upstream (const char *name,
  522. size_t len, void *ups_data)
  523. {
  524. struct upstream_list *ups = ups_data;
  525. struct upstream *up;
  526. up = rspamd_upstream_get (ups, RSPAMD_UPSTREAM_ROUND_ROBIN, name, len);
  527. if (up) {
  528. msg_debug ("select %s", rspamd_upstream_name (up));
  529. return rspamd_upstream_get_data (up);
  530. }
  531. return NULL;
  532. }
  533. static struct rdns_upstream_elt*
  534. rspamd_dns_select_upstream_retransmit (
  535. const char *name,
  536. size_t len, void *ups_data)
  537. {
  538. struct upstream_list *ups = ups_data;
  539. struct upstream *up;
  540. up = rspamd_upstream_get_forced (ups, RSPAMD_UPSTREAM_RANDOM, name, len);
  541. if (up) {
  542. msg_debug ("select forced %s", rspamd_upstream_name (up));
  543. return rspamd_upstream_get_data (up);
  544. }
  545. return NULL;
  546. }
  547. static void
  548. rspamd_dns_upstream_ok (struct rdns_upstream_elt *elt,
  549. void *ups_data)
  550. {
  551. struct upstream *up = elt->lib_data;
  552. rspamd_upstream_ok (up);
  553. }
  554. static void
  555. rspamd_dns_upstream_fail (struct rdns_upstream_elt *elt,
  556. void *ups_data)
  557. {
  558. struct upstream *up = elt->lib_data;
  559. rspamd_upstream_fail (up, FALSE);
  560. }
  561. static unsigned int
  562. rspamd_dns_upstream_count (void *ups_data)
  563. {
  564. struct upstream_list *ups = ups_data;
  565. return rspamd_upstreams_alive (ups);
  566. }