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 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  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_dynamic_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->flags & RDNS_AUTH
  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->flags & RDNS_AUTH);
  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_dynamic_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. /* Callback is not called in this case */
  441. if (cbdata->cbref != -1) {
  442. luaL_unref (L, LUA_REGISTRYINDEX, cbdata->cbref);
  443. }
  444. if (!pool) {
  445. /* Free resources */
  446. g_free (cbdata->to_resolve);
  447. g_free (cbdata->user_str);
  448. g_free (cbdata);
  449. }
  450. lua_pushnil (L);
  451. return 1;
  452. }
  453. /***
  454. * @method resolver:resolve_a(table)
  455. * Resolve A record for a specified host.
  456. * Table elements:
  457. * * `task` - task element (preferred, required to track dependencies) -or-
  458. * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
  459. * * `mempool` - pool memory pool for storing intermediate data
  460. * * `name` - host name to resolve
  461. * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
  462. * * `forced` - true if needed to override normal limit for DNS requests
  463. * @return {boolean} `true` if DNS request has been scheduled
  464. */
  465. static int
  466. lua_dns_resolver_resolve_a (lua_State *L)
  467. {
  468. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  469. if (dns_resolver) {
  470. return lua_dns_resolver_resolve_common (L,
  471. dns_resolver,
  472. RDNS_REQUEST_A,
  473. 2);
  474. }
  475. else {
  476. lua_pushnil (L);
  477. }
  478. return 1;
  479. }
  480. /***
  481. * @method resolver:resolve_ptr(table)
  482. * Resolve PTR record for a specified host.
  483. * Table elements:
  484. * * `task` - task element (preferred, required to track dependencies) -or-
  485. * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
  486. * * `mempool` - pool memory pool for storing intermediate data
  487. * * `name` - host name to resolve
  488. * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
  489. * * `forced` - true if needed to override normal limit for DNS requests
  490. * @return {boolean} `true` if DNS request has been scheduled
  491. */
  492. static int
  493. lua_dns_resolver_resolve_ptr (lua_State *L)
  494. {
  495. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  496. if (dns_resolver) {
  497. return lua_dns_resolver_resolve_common (L,
  498. dns_resolver,
  499. RDNS_REQUEST_PTR,
  500. 2);
  501. }
  502. else {
  503. lua_pushnil (L);
  504. }
  505. return 1;
  506. }
  507. /***
  508. * @method resolver:resolve_txt(table)
  509. * Resolve TXT record for a specified host.
  510. * Table elements:
  511. * * `task` - task element (preferred, required to track dependencies) -or-
  512. * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
  513. * * `mempool` - pool memory pool for storing intermediate data
  514. * * `name` - host name to resolve
  515. * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
  516. * * `forced` - true if needed to override normal limit for DNS requests
  517. * @return {boolean} `true` if DNS request has been scheduled
  518. */
  519. static int
  520. lua_dns_resolver_resolve_txt (lua_State *L)
  521. {
  522. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  523. if (dns_resolver) {
  524. return lua_dns_resolver_resolve_common (L,
  525. dns_resolver,
  526. RDNS_REQUEST_TXT,
  527. 2);
  528. }
  529. else {
  530. lua_pushnil (L);
  531. }
  532. return 1;
  533. }
  534. /***
  535. * @method resolver:resolve_mx(table)
  536. * Resolve MX record for a specified host.
  537. * Table elements:
  538. * * `task` - task element (preferred, required to track dependencies) -or-
  539. * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
  540. * * `mempool` - pool memory pool for storing intermediate data
  541. * * `name` - host name to resolve
  542. * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
  543. * * `forced` - true if needed to override normal limit for DNS requests
  544. * @return {boolean} `true` if DNS request has been scheduled
  545. */
  546. static int
  547. lua_dns_resolver_resolve_mx (lua_State *L)
  548. {
  549. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  550. if (dns_resolver) {
  551. return lua_dns_resolver_resolve_common (L,
  552. dns_resolver,
  553. RDNS_REQUEST_MX,
  554. 2);
  555. }
  556. else {
  557. lua_pushnil (L);
  558. }
  559. return 1;
  560. }
  561. /***
  562. * @method resolver:resolve_ns(table)
  563. * Resolve NS records for a specified host.
  564. * Table elements:
  565. * * `task` - task element (preferred, required to track dependencies) -or-
  566. * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
  567. * * `mempool` - pool memory pool for storing intermediate data
  568. * * `name` - host name to resolve
  569. * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
  570. * * `forced` - true if needed to override normal limit for DNS requests
  571. * @return {boolean} `true` if DNS request has been scheduled
  572. */
  573. static int
  574. lua_dns_resolver_resolve_ns (lua_State *L)
  575. {
  576. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  577. if (dns_resolver) {
  578. return lua_dns_resolver_resolve_common (L,
  579. dns_resolver,
  580. RDNS_REQUEST_NS,
  581. 2);
  582. }
  583. else {
  584. lua_pushnil (L);
  585. }
  586. return 1;
  587. }
  588. /* XXX: broken currently */
  589. static int
  590. lua_dns_resolver_resolve (lua_State *L)
  591. {
  592. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  593. int type;
  594. type = lua_dns_get_type (L, 2);
  595. if (dns_resolver && type != 0) {
  596. return lua_dns_resolver_resolve_common (L, dns_resolver, type, 3);
  597. }
  598. else {
  599. lua_pushnil (L);
  600. }
  601. return 1;
  602. }
  603. /***
  604. * @method resolver:idna_convert_utf8(hostname[, pool])
  605. * Converts domain name from IDN (in utf8 format) to punycode
  606. * @return {string} new name converted
  607. */
  608. static int
  609. lua_dns_resolver_idna_convert_utf8 (lua_State *L)
  610. {
  611. struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L, 1);
  612. gsize hlen;
  613. guint conv_len = 0;
  614. const gchar *hname = luaL_checklstring (L, 2, &hlen);
  615. gchar *converted;
  616. rspamd_mempool_t *pool = rspamd_lua_check_udata_maybe (L, 3, "rspamd{mempool}");
  617. if (dns_resolver && hname) {
  618. if (!rspamd_str_has_8bit (hname, hlen)) {
  619. /* No 8 bit, no reasons to call idna */
  620. lua_pushlstring (L, hname, hlen);
  621. }
  622. else {
  623. converted = rspamd_dns_resolver_idna_convert_utf8 (dns_resolver, pool,
  624. hname, hlen, &conv_len);
  625. if (converted == NULL) {
  626. lua_pushnil (L);
  627. }
  628. else {
  629. lua_pushlstring (L, converted, conv_len);
  630. if (pool == NULL) {
  631. g_free (converted);
  632. }
  633. }
  634. }
  635. }
  636. else {
  637. return luaL_error (L, "invalid arguments");
  638. }
  639. return 1;
  640. }
  641. static gint
  642. lua_load_dns_resolver (lua_State *L)
  643. {
  644. lua_newtable (L);
  645. luaL_register (L, NULL, dns_resolverlib_f);
  646. return 1;
  647. }
  648. void
  649. luaopen_dns_resolver (lua_State * L)
  650. {
  651. rspamd_lua_new_class (L, "rspamd{resolver}", dns_resolverlib_m);
  652. {
  653. LUA_ENUM (L, DNS_A, RDNS_REQUEST_A);
  654. LUA_ENUM (L, DNS_PTR, RDNS_REQUEST_PTR);
  655. LUA_ENUM (L, DNS_MX, RDNS_REQUEST_MX);
  656. LUA_ENUM (L, DNS_TXT, RDNS_REQUEST_TXT);
  657. LUA_ENUM (L, DNS_SRV, RDNS_REQUEST_SRV);
  658. LUA_ENUM (L, DNS_SPF, RDNS_REQUEST_SPF);
  659. LUA_ENUM (L, DNS_AAAA, RDNS_REQUEST_AAAA);
  660. LUA_ENUM (L, DNS_SOA, RDNS_REQUEST_SOA);
  661. }
  662. lua_pop (L, 1);
  663. rspamd_lua_add_preload (L, "rspamd_resolver", lua_load_dns_resolver);
  664. }