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.

lua_dns_resolver.c 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  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 "lua_common.h"
  17. #include "lua_thread_pool.h"
  18. #include "utlist.h"
  19. /***
  20. * @module rspamd_resolver
  21. * This module allows to resolve DNS names from LUA code. All resolving is executed
  22. * asynchronously. Here is an example of name resolution:
  23. * @example
  24. local function symbol_callback(task)
  25. local host = 'example.com'
  26. local function dns_cb(resolver, to_resolve, results, err, _, authenticated)
  27. if not results then
  28. rspamd_logger.infox('DNS resolving of %1 failed: %2', host, err)
  29. return
  30. end
  31. for _,r in ipairs(results) do
  32. -- r is of type rspamd{ip} here, but it can be converted to string
  33. rspamd_logger.infox('Resolved %1 to %2', host, tostring(r))
  34. end
  35. end
  36. task:get_resolver():resolve_a({task = task, name = host, callback = dns_cb})
  37. end
  38. */
  39. static const gchar *M = "rspamd lua dns resolver";
  40. /* Lua bindings */
  41. LUA_FUNCTION_DEF (dns_resolver, init);
  42. LUA_FUNCTION_DEF (dns_resolver, resolve_a);
  43. LUA_FUNCTION_DEF (dns_resolver, resolve_ptr);
  44. LUA_FUNCTION_DEF (dns_resolver, resolve_txt);
  45. LUA_FUNCTION_DEF (dns_resolver, resolve_mx);
  46. LUA_FUNCTION_DEF (dns_resolver, resolve_ns);
  47. LUA_FUNCTION_DEF (dns_resolver, resolve);
  48. LUA_FUNCTION_DEF (dns_resolver, idna_convert_utf8);
  49. void lua_push_dns_reply (lua_State *L, const struct rdns_reply *reply);
  50. static const struct luaL_reg dns_resolverlib_f[] = {
  51. LUA_INTERFACE_DEF (dns_resolver, init),
  52. {NULL, NULL}
  53. };
  54. static const struct luaL_reg dns_resolverlib_m[] = {
  55. LUA_INTERFACE_DEF (dns_resolver, resolve_a),
  56. LUA_INTERFACE_DEF (dns_resolver, resolve_ptr),
  57. LUA_INTERFACE_DEF (dns_resolver, resolve_txt),
  58. LUA_INTERFACE_DEF (dns_resolver, resolve_mx),
  59. LUA_INTERFACE_DEF (dns_resolver, resolve_ns),
  60. LUA_INTERFACE_DEF (dns_resolver, resolve),
  61. LUA_INTERFACE_DEF (dns_resolver, idna_convert_utf8),
  62. {"__tostring", rspamd_lua_class_tostring},
  63. {NULL, NULL}
  64. };
  65. struct rspamd_dns_resolver *
  66. lua_check_dns_resolver (lua_State * L, gint pos)
  67. {
  68. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{resolver}");
  69. luaL_argcheck (L, ud != NULL, pos, "'resolver' expected");
  70. return ud ? *((struct rspamd_dns_resolver **)ud) : NULL;
  71. }
  72. struct lua_dns_cbdata {
  73. struct rspamd_task *task;
  74. rspamd_mempool_t *pool;
  75. struct rspamd_dns_resolver *resolver;
  76. gint cbref;
  77. gchar *to_resolve;
  78. gchar *user_str;
  79. struct rspamd_symcache_item *item;
  80. struct rspamd_async_session *s;
  81. };
  82. static int
  83. lua_dns_get_type (lua_State *L, int argno)
  84. {
  85. int type = RDNS_REQUEST_A;
  86. const gchar *strtype;
  87. if (lua_type (L, argno) != LUA_TSTRING) {
  88. lua_pushvalue (L, argno);
  89. lua_gettable (L, lua_upvalueindex (1));
  90. type = lua_tonumber (L, -1);
  91. lua_pop (L, 1);
  92. if (type == 0) {
  93. rspamd_lua_typerror (L, argno, "dns_request_type");
  94. }
  95. }
  96. else {
  97. strtype = lua_tostring (L, argno);
  98. if (g_ascii_strcasecmp (strtype, "a") == 0) {
  99. type = RDNS_REQUEST_A;
  100. }
  101. else if (g_ascii_strcasecmp (strtype, "aaaa") == 0) {
  102. type = RDNS_REQUEST_AAAA;
  103. }
  104. else if (g_ascii_strcasecmp (strtype, "mx") == 0) {
  105. type = RDNS_REQUEST_MX;
  106. }
  107. else if (g_ascii_strcasecmp (strtype, "txt") == 0) {
  108. type = RDNS_REQUEST_TXT;
  109. }
  110. else if (g_ascii_strcasecmp (strtype, "ptr") == 0) {
  111. type = RDNS_REQUEST_PTR;
  112. }
  113. else if (g_ascii_strcasecmp (strtype, "soa") == 0) {
  114. type = RDNS_REQUEST_SOA;
  115. }
  116. else {
  117. msg_err ("bad DNS type: %s", strtype);
  118. }
  119. }
  120. return type;
  121. }
  122. static void
  123. lua_dns_resolver_callback (struct rdns_reply *reply, gpointer arg)
  124. {
  125. struct lua_dns_cbdata *cd = arg;
  126. struct rspamd_dns_resolver **presolver;
  127. lua_State *L;
  128. struct lua_callback_state cbs;
  129. rspamd_mempool_t *pool;
  130. gint err_idx;
  131. pool = cd->pool;
  132. lua_thread_pool_prepare_callback (cd->resolver->cfg->lua_thread_pool, &cbs);
  133. L = cbs.L;
  134. lua_pushcfunction (L, &rspamd_lua_traceback);
  135. err_idx = lua_gettop (L);
  136. lua_rawgeti (L, LUA_REGISTRYINDEX, cd->cbref);
  137. presolver = lua_newuserdata (L, sizeof (gpointer));
  138. rspamd_lua_setclass (L, "rspamd{resolver}", -1);
  139. *presolver = cd->resolver;
  140. lua_pushstring (L, cd->to_resolve);
  141. lua_push_dns_reply (L, reply);
  142. /*
  143. * 1 - resolver
  144. * 2 - to_resolve
  145. * 3 - entries | nil
  146. * 4 - error | nil
  147. * 5 - user_str
  148. * 6 - reply->authenticated
  149. * 7 - server
  150. */
  151. if (reply->code != RDNS_RC_NOERROR) {
  152. lua_pushnil (L);
  153. lua_pushstring (L, rdns_strerror (reply->code));
  154. }
  155. if (cd->user_str != NULL) {
  156. lua_pushstring (L, cd->user_str);
  157. }
  158. else {
  159. lua_pushnil (L);
  160. }
  161. lua_pushboolean (L, reply->authenticated);
  162. const gchar *servname = rdns_request_get_server (reply->request);
  163. if (servname) {
  164. lua_pushstring (L, servname);
  165. }
  166. else {
  167. lua_pushnil (L);
  168. }
  169. if (cd->item) {
  170. /* We also need to restore the item in case there are some chains */
  171. rspamd_symcache_set_cur_item (cd->task, cd->item);
  172. }
  173. if (lua_pcall (L, 7, 0, err_idx) != 0) {
  174. msg_err_pool_check ("call to dns callback failed: %s",
  175. lua_tostring (L, -1));
  176. }
  177. lua_settop (L, err_idx - 1);
  178. /* Unref function */
  179. luaL_unref (L, LUA_REGISTRYINDEX, cd->cbref);
  180. lua_thread_pool_restore_callback (&cbs);
  181. if (cd->item) {
  182. rspamd_symcache_item_async_dec_check (cd->task, cd->item, M);
  183. }
  184. if (!cd->pool) {
  185. g_free (cd->to_resolve);
  186. g_free (cd->user_str);
  187. g_free (cd);
  188. }
  189. }
  190. void
  191. lua_push_dns_reply (lua_State *L, const struct rdns_reply *reply)
  192. {
  193. gint i = 0, naddrs = 0;
  194. struct rdns_reply_entry *elt;
  195. rspamd_inet_addr_t *addr;
  196. if (reply->code == RDNS_RC_NOERROR) {
  197. LL_FOREACH (reply->entries, elt) {
  198. naddrs ++;
  199. }
  200. lua_createtable (L, naddrs, 0);
  201. LL_FOREACH (reply->entries, elt)
  202. {
  203. switch (elt->type) {
  204. case RDNS_REQUEST_A:
  205. addr = rspamd_inet_address_new (AF_INET, &elt->content.a.addr);
  206. rspamd_lua_ip_push (L, addr);
  207. rspamd_inet_address_free (addr);
  208. lua_rawseti (L, -2, ++i);
  209. break;
  210. case RDNS_REQUEST_AAAA:
  211. addr = rspamd_inet_address_new (AF_INET6, &elt->content.aaa.addr);
  212. rspamd_lua_ip_push (L, addr);
  213. rspamd_inet_address_free (addr);
  214. lua_rawseti (L, -2, ++i);
  215. break;
  216. case RDNS_REQUEST_NS:
  217. lua_pushstring (L, elt->content.ns.name);
  218. lua_rawseti (L, -2, ++i);
  219. break;
  220. case RDNS_REQUEST_PTR:
  221. lua_pushstring (L, elt->content.ptr.name);
  222. lua_rawseti (L, -2, ++i);
  223. break;
  224. case RDNS_REQUEST_TXT:
  225. case RDNS_REQUEST_SPF:
  226. lua_pushstring (L, elt->content.txt.data);
  227. lua_rawseti (L, -2, ++i);
  228. break;
  229. case RDNS_REQUEST_MX:
  230. /* mx['name'], mx['priority'] */
  231. lua_createtable (L, 0, 2);
  232. rspamd_lua_table_set (L, "name", elt->content.mx.name);
  233. lua_pushstring (L, "priority");
  234. lua_pushinteger (L, elt->content.mx.priority);
  235. lua_settable (L, -3);
  236. lua_rawseti (L, -2, ++i);
  237. break;
  238. case RDNS_REQUEST_SOA:
  239. lua_createtable (L, 0, 7);
  240. rspamd_lua_table_set (L, "ns", elt->content.soa.mname);
  241. rspamd_lua_table_set (L, "contact", elt->content.soa.admin);
  242. lua_pushstring (L, "serial");
  243. lua_pushinteger (L, elt->content.soa.serial);
  244. lua_settable (L, -3);
  245. lua_pushstring (L, "refresh");
  246. lua_pushinteger (L, elt->content.soa.refresh);
  247. lua_settable (L, -3);
  248. lua_pushstring (L, "retry");
  249. lua_pushinteger (L, elt->content.soa.retry);
  250. lua_settable (L, -3);
  251. lua_pushstring (L, "expiry");
  252. lua_pushinteger (L, elt->content.soa.expire);
  253. lua_settable (L, -3);
  254. /* Negative TTL */
  255. lua_pushstring (L, "nx");
  256. lua_pushinteger (L, elt->content.soa.minimum);
  257. lua_settable (L, -3);
  258. lua_rawseti (L, -2, ++i);
  259. break;
  260. default:
  261. continue;
  262. }
  263. }
  264. lua_pushnil (L);
  265. }
  266. }
  267. /***
  268. * @function rspamd_resolver.init(ev_base, config)
  269. * @param {event_base} ev_base event base used for asynchronous events
  270. * @param {rspamd_config} config rspamd configuration parameters
  271. * @return {rspamd_resolver} new resolver object associated with the specified base
  272. */
  273. static int
  274. lua_dns_resolver_init (lua_State *L)
  275. {
  276. struct rspamd_dns_resolver *resolver, **presolver;
  277. struct rspamd_config *cfg, **pcfg;
  278. struct ev_loop *base, **pbase;
  279. /* Check args */
  280. pbase = rspamd_lua_check_udata (L, 1, "rspamd{ev_base}");
  281. luaL_argcheck (L, pbase != NULL, 1, "'ev_base' expected");
  282. base = pbase ? *(pbase) : NULL;
  283. pcfg = rspamd_lua_check_udata (L, 2, "rspamd{config}");
  284. luaL_argcheck (L, pcfg != NULL, 2, "'config' expected");
  285. cfg = pcfg ? *(pcfg) : NULL;
  286. if (base != NULL && cfg != NULL) {
  287. resolver = rspamd_dns_resolver_init (NULL, base, cfg);
  288. if (resolver) {
  289. presolver = lua_newuserdata (L, sizeof (gpointer));
  290. rspamd_lua_setclass (L, "rspamd{resolver}", -1);
  291. *presolver = resolver;
  292. }
  293. else {
  294. lua_pushnil (L);
  295. }
  296. }
  297. else {
  298. lua_pushnil (L);
  299. }
  300. return 1;
  301. }
  302. static int
  303. lua_dns_resolver_resolve_common (lua_State *L,
  304. struct rspamd_dns_resolver *resolver,
  305. enum rdns_request_type type,
  306. int first)
  307. {
  308. LUA_TRACE_POINT;
  309. struct rspamd_async_session *session = NULL;
  310. rspamd_mempool_t *pool = NULL;
  311. const gchar *to_resolve = NULL, *user_str = NULL;
  312. struct lua_dns_cbdata *cbdata;
  313. gint cbref = -1, ret;
  314. struct rspamd_task *task = NULL;
  315. GError *err = NULL;
  316. gboolean forced = FALSE;
  317. struct rspamd_symcache_item *item = NULL;
  318. /* Check arguments */
  319. if (!rspamd_lua_parse_table_arguments (L, first, &err,
  320. RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
  321. "session=U{session};mempool=U{mempool};*name=S;*callback=F;"
  322. "option=S;task=U{task};forced=B",
  323. &session, &pool, &to_resolve, &cbref, &user_str, &task, &forced)) {
  324. if (err) {
  325. ret = luaL_error (L, "invalid arguments: %s", err->message);
  326. g_error_free (err);
  327. return ret;
  328. }
  329. return luaL_error (L, "invalid arguments");
  330. }
  331. if (task) {
  332. pool = task->task_pool;
  333. session = task->s;
  334. item = rspamd_symcache_get_cur_item (task);
  335. }
  336. if (to_resolve != NULL) {
  337. if (pool != NULL) {
  338. cbdata = rspamd_mempool_alloc0 (pool, sizeof (struct lua_dns_cbdata));
  339. cbdata->user_str = rspamd_mempool_strdup (pool, user_str);
  340. if (type != RDNS_REQUEST_PTR) {
  341. cbdata->to_resolve = rspamd_mempool_strdup (pool, to_resolve);
  342. }
  343. else {
  344. char *ptr_str;
  345. ptr_str = rdns_generate_ptr_from_str (to_resolve);
  346. if (ptr_str == NULL) {
  347. msg_err_task_check ("wrong resolve string to PTR request: %s",
  348. to_resolve);
  349. goto err;
  350. }
  351. cbdata->to_resolve = rspamd_mempool_strdup (pool, ptr_str);
  352. to_resolve = cbdata->to_resolve;
  353. free (ptr_str);
  354. }
  355. }
  356. else {
  357. cbdata = g_malloc0 (sizeof (struct lua_dns_cbdata));
  358. cbdata->user_str = user_str ? g_strdup (user_str) : NULL;
  359. if (type != RDNS_REQUEST_PTR) {
  360. cbdata->to_resolve = g_strdup (to_resolve);
  361. }
  362. else {
  363. char *ptr_str;
  364. ptr_str = rdns_generate_ptr_from_str (to_resolve);
  365. if (ptr_str == NULL) {
  366. msg_err_task_check ("wrong resolve string to PTR request: %s",
  367. to_resolve);
  368. goto err;
  369. }
  370. cbdata->to_resolve = g_strdup (ptr_str);
  371. free (ptr_str);
  372. }
  373. }
  374. cbdata->resolver = resolver;
  375. cbdata->cbref = cbref;
  376. cbdata->task = task;
  377. cbdata->pool = pool;
  378. if (task == NULL) {
  379. if (rspamd_dns_resolver_request (resolver,
  380. session,
  381. pool,
  382. lua_dns_resolver_callback,
  383. cbdata,
  384. type,
  385. to_resolve)) {
  386. lua_pushboolean (L, TRUE);
  387. if (session) {
  388. cbdata->s = session;
  389. }
  390. }
  391. else {
  392. goto err;
  393. }
  394. }
  395. else {
  396. /* Fail-safety as this function can, in theory, call
  397. * lua_dns_resolver_callback without switching to the event loop
  398. */
  399. if (item) {
  400. rspamd_symcache_item_async_inc (task, item, M);
  401. }
  402. if (forced) {
  403. ret = rspamd_dns_resolver_request_task_forced (task,
  404. lua_dns_resolver_callback,
  405. cbdata,
  406. type,
  407. to_resolve);
  408. } else {
  409. ret = rspamd_dns_resolver_request_task (task,
  410. lua_dns_resolver_callback,
  411. cbdata,
  412. type,
  413. to_resolve);
  414. }
  415. if (ret) {
  416. cbdata->s = session;
  417. if (item) {
  418. cbdata->item = item;
  419. rspamd_symcache_item_async_inc (task, item, M);
  420. }
  421. /* callback was set up */
  422. lua_pushboolean (L, TRUE);
  423. }
  424. else {
  425. if (item) {
  426. rspamd_symcache_item_async_dec_check (task, item, M);
  427. }
  428. goto err;
  429. }
  430. if (item) {
  431. rspamd_symcache_item_async_dec_check (task, item, M);
  432. }
  433. }
  434. }
  435. else {
  436. return luaL_error (L, "invalid arguments to lua_resolve");
  437. }
  438. return 1;
  439. err:
  440. if (!pool) {
  441. /* Free resources */
  442. g_free (cbdata->to_resolve);
  443. g_free (cbdata->user_str);
  444. }
  445. /* Callback is not called in this case */
  446. if (cbdata->cbref != -1) {
  447. luaL_unref (L, LUA_REGISTRYINDEX, cbdata->cbref);
  448. }
  449. lua_pushnil (L);
  450. return 1;
  451. }
  452. /***
  453. * @method resolver:resolve_a(table)
  454. * Resolve A record for a specified host.
  455. * Table elements:
  456. * * `task` - task element (preferred, required to track dependencies) -or-
  457. * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
  458. * * `mempool` - pool memory pool for storing intermediate data
  459. * * `name` - host name to resolve
  460. * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
  461. * * `forced` - true if needed to override notmal limit for DNS requests
  462. * @return {boolean} `true` if DNS request has been scheduled
  463. */
  464. static int
  465. lua_dns_resolver_resolve_a (lua_State *L)
  466. {
  467. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  468. if (dns_resolver) {
  469. return lua_dns_resolver_resolve_common (L,
  470. dns_resolver,
  471. RDNS_REQUEST_A,
  472. 2);
  473. }
  474. else {
  475. lua_pushnil (L);
  476. }
  477. return 1;
  478. }
  479. /***
  480. * @method resolver:resolve_ptr(table)
  481. * Resolve PTR record for a specified host.
  482. * Table elements:
  483. * * `task` - task element (preferred, required to track dependencies) -or-
  484. * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
  485. * * `mempool` - pool memory pool for storing intermediate data
  486. * * `name` - host name to resolve
  487. * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
  488. * * `forced` - true if needed to override notmal limit for DNS requests
  489. * @return {boolean} `true` if DNS request has been scheduled
  490. */
  491. static int
  492. lua_dns_resolver_resolve_ptr (lua_State *L)
  493. {
  494. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  495. if (dns_resolver) {
  496. return lua_dns_resolver_resolve_common (L,
  497. dns_resolver,
  498. RDNS_REQUEST_PTR,
  499. 2);
  500. }
  501. else {
  502. lua_pushnil (L);
  503. }
  504. return 1;
  505. }
  506. /***
  507. * @method resolver:resolve_txt(table)
  508. * Resolve TXT record for a specified host.
  509. * Table elements:
  510. * * `task` - task element (preferred, required to track dependencies) -or-
  511. * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
  512. * * `mempool` - pool memory pool for storing intermediate data
  513. * * `name` - host name to resolve
  514. * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
  515. * * `forced` - true if needed to override notmal limit for DNS requests
  516. * @return {boolean} `true` if DNS request has been scheduled
  517. */
  518. static int
  519. lua_dns_resolver_resolve_txt (lua_State *L)
  520. {
  521. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  522. if (dns_resolver) {
  523. return lua_dns_resolver_resolve_common (L,
  524. dns_resolver,
  525. RDNS_REQUEST_TXT,
  526. 2);
  527. }
  528. else {
  529. lua_pushnil (L);
  530. }
  531. return 1;
  532. }
  533. /***
  534. * @method resolver:resolve_mx(table)
  535. * Resolve MX record for a specified host.
  536. * Table elements:
  537. * * `task` - task element (preferred, required to track dependencies) -or-
  538. * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
  539. * * `mempool` - pool memory pool for storing intermediate data
  540. * * `name` - host name to resolve
  541. * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
  542. * * `forced` - true if needed to override notmal limit for DNS requests
  543. * @return {boolean} `true` if DNS request has been scheduled
  544. */
  545. static int
  546. lua_dns_resolver_resolve_mx (lua_State *L)
  547. {
  548. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  549. if (dns_resolver) {
  550. return lua_dns_resolver_resolve_common (L,
  551. dns_resolver,
  552. RDNS_REQUEST_MX,
  553. 2);
  554. }
  555. else {
  556. lua_pushnil (L);
  557. }
  558. return 1;
  559. }
  560. /***
  561. * @method resolver:resolve_ns(table)
  562. * Resolve NS records for a specified host.
  563. * Table elements:
  564. * * `task` - task element (preferred, required to track dependencies) -or-
  565. * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
  566. * * `mempool` - pool memory pool for storing intermediate data
  567. * * `name` - host name to resolve
  568. * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
  569. * * `forced` - true if needed to override notmal limit for DNS requests
  570. * @return {boolean} `true` if DNS request has been scheduled
  571. */
  572. static int
  573. lua_dns_resolver_resolve_ns (lua_State *L)
  574. {
  575. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  576. if (dns_resolver) {
  577. return lua_dns_resolver_resolve_common (L,
  578. dns_resolver,
  579. RDNS_REQUEST_NS,
  580. 2);
  581. }
  582. else {
  583. lua_pushnil (L);
  584. }
  585. return 1;
  586. }
  587. /* XXX: broken currently */
  588. static int
  589. lua_dns_resolver_resolve (lua_State *L)
  590. {
  591. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  592. int type;
  593. type = lua_dns_get_type (L, 2);
  594. if (dns_resolver && type != 0) {
  595. return lua_dns_resolver_resolve_common (L, dns_resolver, type, 3);
  596. }
  597. else {
  598. lua_pushnil (L);
  599. }
  600. return 1;
  601. }
  602. /***
  603. * @method resolver:idna_convert_utf8(hostname[, pool])
  604. * Converts domain name from IDN (in utf8 format) to punycode
  605. * @return {string} new name converted
  606. */
  607. static int
  608. lua_dns_resolver_idna_convert_utf8 (lua_State *L)
  609. {
  610. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  611. gsize hlen;
  612. guint conv_len = 0;
  613. const gchar *hname = luaL_checklstring (L, 2, &hlen);
  614. gchar *converted;
  615. rspamd_mempool_t *pool = rspamd_lua_check_udata_maybe (L, 3, "rspamd{mempool}");
  616. if (dns_resolver && hname) {
  617. if (!rspamd_str_has_8bit (hname, hlen)) {
  618. /* No 8 bit, no reasons to call idna */
  619. lua_pushlstring (L, hname, hlen);
  620. }
  621. else {
  622. converted = rspamd_dns_resolver_idna_convert_utf8 (dns_resolver, pool,
  623. hname, hlen, &conv_len);
  624. if (converted == NULL) {
  625. lua_pushnil (L);
  626. }
  627. else {
  628. lua_pushlstring (L, converted, conv_len);
  629. if (pool == NULL) {
  630. g_free (converted);
  631. }
  632. }
  633. }
  634. }
  635. else {
  636. return luaL_error (L, "invalid arguments");
  637. }
  638. return 1;
  639. }
  640. static gint
  641. lua_load_dns_resolver (lua_State *L)
  642. {
  643. lua_newtable (L);
  644. luaL_register (L, NULL, dns_resolverlib_f);
  645. return 1;
  646. }
  647. void
  648. luaopen_dns_resolver (lua_State * L)
  649. {
  650. rspamd_lua_new_class (L, "rspamd{resolver}", dns_resolverlib_m);
  651. {
  652. LUA_ENUM (L, DNS_A, RDNS_REQUEST_A);
  653. LUA_ENUM (L, DNS_PTR, RDNS_REQUEST_PTR);
  654. LUA_ENUM (L, DNS_MX, RDNS_REQUEST_MX);
  655. LUA_ENUM (L, DNS_TXT, RDNS_REQUEST_TXT);
  656. LUA_ENUM (L, DNS_SRV, RDNS_REQUEST_SRV);
  657. LUA_ENUM (L, DNS_SPF, RDNS_REQUEST_SPF);
  658. LUA_ENUM (L, DNS_AAAA, RDNS_REQUEST_AAAA);
  659. LUA_ENUM (L, DNS_SOA, RDNS_REQUEST_SOA);
  660. }
  661. lua_pop (L, 1);
  662. rspamd_lua_add_preload (L, "rspamd_resolver", lua_load_dns_resolver);
  663. }