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_upstream.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /* Copyright (c) 2010-2011, 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 "lua_common.h"
  25. #include "upstream.h"
  26. #include "cfg_file.h"
  27. /* Upstream timeouts */
  28. #define DEFAULT_UPSTREAM_ERROR_TIME 10
  29. #define DEFAULT_UPSTREAM_DEAD_TIME 300
  30. #define DEFAULT_UPSTREAM_MAXERRORS 10
  31. /**
  32. * This module implements upstreams manipulation from lua
  33. */
  34. /* Upstream list functions */
  35. LUA_FUNCTION_DEF (upstream_list, create);
  36. LUA_FUNCTION_DEF (upstream_list, destroy);
  37. LUA_FUNCTION_DEF (upstream_list, get_upstream_by_hash);
  38. LUA_FUNCTION_DEF (upstream_list, get_upstream_round_robin);
  39. LUA_FUNCTION_DEF (upstream_list, get_upstream_master_slave);
  40. static const struct luaL_reg upstream_list_m[] = {
  41. LUA_INTERFACE_DEF (upstream_list, get_upstream_by_hash),
  42. LUA_INTERFACE_DEF (upstream_list, get_upstream_round_robin),
  43. LUA_INTERFACE_DEF (upstream_list, get_upstream_master_slave),
  44. {"__tostring", rspamd_lua_class_tostring},
  45. {"__gc", lua_upstream_list_destroy},
  46. {NULL, NULL}
  47. };
  48. static const struct luaL_reg upstream_list_f[] = {
  49. LUA_INTERFACE_DEF (upstream_list, create),
  50. {NULL, NULL}
  51. };
  52. /* Upstream functions */
  53. LUA_FUNCTION_DEF (upstream, create);
  54. LUA_FUNCTION_DEF (upstream, destroy);
  55. LUA_FUNCTION_DEF (upstream, ok);
  56. LUA_FUNCTION_DEF (upstream, fail);
  57. LUA_FUNCTION_DEF (upstream, get_ip);
  58. LUA_FUNCTION_DEF (upstream, get_port);
  59. LUA_FUNCTION_DEF (upstream, get_ip_string);
  60. LUA_FUNCTION_DEF (upstream, get_priority);
  61. static const struct luaL_reg upstream_m[] = {
  62. LUA_INTERFACE_DEF (upstream, ok),
  63. LUA_INTERFACE_DEF (upstream, fail),
  64. LUA_INTERFACE_DEF (upstream, get_ip),
  65. LUA_INTERFACE_DEF (upstream, get_ip_string),
  66. LUA_INTERFACE_DEF (upstream, get_port),
  67. LUA_INTERFACE_DEF (upstream, get_priority),
  68. LUA_INTERFACE_DEF (upstream, destroy),
  69. {"__tostring", rspamd_lua_class_tostring},
  70. {NULL, NULL}
  71. };
  72. static const struct luaL_reg upstream_f[] = {
  73. LUA_INTERFACE_DEF (upstream, create),
  74. {NULL, NULL}
  75. };
  76. /* Upstream class */
  77. struct lua_upstream {
  78. struct upstream up;
  79. gchar *def;
  80. guint16 port;
  81. gchar *addr;
  82. };
  83. static struct lua_upstream *
  84. lua_check_upstream (lua_State * L)
  85. {
  86. void *ud = luaL_checkudata (L, 1, "rspamd{upstream}");
  87. luaL_argcheck (L, ud != NULL, 1, "'upstream' expected");
  88. return ud ? *((struct lua_upstream **)ud) : NULL;
  89. }
  90. /**
  91. * Create new upstream from its string definition like 'ip[:port[:priority]]' or 'host[:port[:priority]]'
  92. * @param L
  93. * @return upstream structure
  94. */
  95. static gint
  96. lua_upstream_create (lua_State *L)
  97. {
  98. struct lua_upstream *new, **pnew;
  99. const gchar *def;
  100. def = luaL_checkstring (L, 1);
  101. if (def) {
  102. new = g_slice_alloc0 (sizeof (struct lua_upstream));
  103. new->def = g_strdup (def);
  104. new->addr = g_malloc (INET6_ADDRSTRLEN);
  105. if (!rspamd_parse_host_port_priority (NULL, new->def, &new->addr,
  106. &new->port, &new->up.priority)) {
  107. g_free (new->def);
  108. g_slice_free1 (sizeof (struct lua_upstream), new);
  109. lua_pushnil (L);
  110. }
  111. else {
  112. pnew = lua_newuserdata (L, sizeof (struct lua_upstream *));
  113. rspamd_lua_setclass (L, "rspamd{upstream}", -1);
  114. *pnew = new;
  115. }
  116. }
  117. return 1;
  118. }
  119. /**
  120. * Destroy a single upstream object
  121. * @param L
  122. * @return
  123. */
  124. static gint
  125. lua_upstream_destroy (lua_State *L)
  126. {
  127. struct lua_upstream *up = lua_check_upstream (L);
  128. if (up) {
  129. g_free (up->def);
  130. g_free (up->addr);
  131. g_slice_free1 (sizeof (struct lua_upstream), up);
  132. }
  133. return 0;
  134. }
  135. /**
  136. * Get ip of upstream in numeric form (guint32)
  137. * @param L
  138. * @return
  139. */
  140. static gint
  141. lua_upstream_get_ip (lua_State *L)
  142. {
  143. struct lua_upstream *up = lua_check_upstream (L);
  144. if (up) {
  145. lua_pushstring (L, up->addr);
  146. }
  147. else {
  148. lua_pushnil (L);
  149. }
  150. return 1;
  151. }
  152. /**
  153. * Get ip of upstream in string form
  154. * @param L
  155. * @return
  156. */
  157. static gint
  158. lua_upstream_get_ip_string (lua_State *L)
  159. {
  160. struct lua_upstream *up = lua_check_upstream (L);
  161. if (up) {
  162. lua_pushstring (L, up->addr);
  163. }
  164. else {
  165. lua_pushnil (L);
  166. }
  167. return 1;
  168. }
  169. /**
  170. * Get port of upstream in numeric form
  171. * @param L
  172. * @return
  173. */
  174. static gint
  175. lua_upstream_get_port (lua_State *L)
  176. {
  177. struct lua_upstream *up = lua_check_upstream (L);
  178. if (up) {
  179. lua_pushinteger (L, up->port);
  180. }
  181. else {
  182. lua_pushnil (L);
  183. }
  184. return 1;
  185. }
  186. /**
  187. * Get port of upstream in numeric form
  188. * @param L
  189. * @return
  190. */
  191. static gint
  192. lua_upstream_get_priority (lua_State *L)
  193. {
  194. struct lua_upstream *up = lua_check_upstream (L);
  195. if (up) {
  196. lua_pushinteger (L, up->up.priority);
  197. }
  198. else {
  199. lua_pushnil (L);
  200. }
  201. return 1;
  202. }
  203. /**
  204. * Make upstream fail, the second argument is time, if absent the current time is used
  205. * @param L
  206. * @return
  207. */
  208. static gint
  209. lua_upstream_fail (lua_State *L)
  210. {
  211. struct lua_upstream *up = lua_check_upstream (L);
  212. time_t now;
  213. if (up) {
  214. if (lua_gettop (L) >= 2) {
  215. now = luaL_checkinteger (L, 2);
  216. }
  217. else {
  218. now = time (NULL);
  219. }
  220. upstream_fail (&up->up, now);
  221. }
  222. return 0;
  223. }
  224. /**
  225. * Make upstream success, the second argument is time, if absent the current time is used
  226. * @param L
  227. * @return
  228. */
  229. static gint
  230. lua_upstream_ok (lua_State *L)
  231. {
  232. struct lua_upstream *up = lua_check_upstream (L);
  233. time_t now;
  234. if (up) {
  235. if (lua_gettop (L) >= 2) {
  236. now = luaL_checkinteger (L, 2);
  237. }
  238. else {
  239. now = time (NULL);
  240. }
  241. upstream_ok (&up->up, now);
  242. }
  243. return 0;
  244. }
  245. /* Upstream list class */
  246. struct lua_upstream_list {
  247. struct lua_upstream *upstreams;
  248. guint count;
  249. };
  250. static struct lua_upstream_list *
  251. lua_check_upstream_list (lua_State * L)
  252. {
  253. void *ud = luaL_checkudata (L, 1, "rspamd{upstream_list}");
  254. luaL_argcheck (L, ud != NULL, 1, "'upstream_list' expected");
  255. return ud ? *((struct lua_upstream_list **)ud) : NULL;
  256. }
  257. /**
  258. * Create new upstream list from its string definition like '<upstream>,<upstream>;<upstream>'
  259. * @param L
  260. * @return upstream list structure
  261. */
  262. static gint
  263. lua_upstream_list_create (lua_State *L)
  264. {
  265. struct lua_upstream_list *new, **pnew;
  266. struct lua_upstream *cur;
  267. const gchar *def;
  268. char **tokens;
  269. guint i, default_port = 0;
  270. def = luaL_checkstring (L, 1);
  271. if (def) {
  272. if (lua_gettop (L) >= 2) {
  273. default_port = luaL_checkinteger (L, 2);
  274. }
  275. new = g_slice_alloc0 (sizeof (struct lua_upstream_list));
  276. tokens = g_strsplit_set (def, ",;", 0);
  277. if (!tokens || !tokens[0]) {
  278. goto err;
  279. }
  280. new->count = g_strv_length (tokens);
  281. new->upstreams =
  282. g_slice_alloc0 (new->count * sizeof (struct lua_upstream));
  283. for (i = 0; i < new->count; i++) {
  284. cur = &new->upstreams[i];
  285. cur->addr = g_malloc (INET6_ADDRSTRLEN);
  286. if (!rspamd_parse_host_port_priority (NULL, tokens[i], &cur->addr,
  287. &cur->port, &cur->up.priority)) {
  288. goto err;
  289. }
  290. if (cur->port == 0) {
  291. cur->port = default_port;
  292. }
  293. }
  294. pnew = lua_newuserdata (L, sizeof (struct upstream_list *));
  295. rspamd_lua_setclass (L, "rspamd{upstream_list}", -1);
  296. *pnew = new;
  297. }
  298. return 1;
  299. err:
  300. if (tokens) {
  301. g_strfreev (tokens);
  302. }
  303. if (new->upstreams) {
  304. for (i = 0; i < new->count; i++) {
  305. cur = &new->upstreams[i];
  306. if (cur->addr) {
  307. g_free (cur->addr);
  308. }
  309. }
  310. g_slice_free1 (new->count * sizeof (struct lua_upstream),
  311. new->upstreams);
  312. }
  313. g_slice_free1 (sizeof (struct lua_upstream_list), new);
  314. lua_pushnil (L);
  315. return 1;
  316. }
  317. /**
  318. * Destroy a single upstream list object
  319. * @param L
  320. * @return
  321. */
  322. static gint
  323. lua_upstream_list_destroy (lua_State *L)
  324. {
  325. struct lua_upstream_list *upl = lua_check_upstream_list (L);
  326. struct lua_upstream *cur;
  327. guint i;
  328. if (upl) {
  329. if (upl->upstreams) {
  330. for (i = 0; i < upl->count; i++) {
  331. cur = &upl->upstreams[i];
  332. if (cur->addr) {
  333. g_free (cur->addr);
  334. }
  335. }
  336. g_slice_free1 (upl->count * sizeof (struct lua_upstream),
  337. upl->upstreams);
  338. }
  339. g_slice_free1 (sizeof (struct lua_upstream_list), upl);
  340. }
  341. return 0;
  342. }
  343. /**
  344. * Get upstream by hash from key, params are: key and time (optional)
  345. * @param L
  346. * @return
  347. */
  348. static gint
  349. lua_upstream_list_get_upstream_by_hash (lua_State *L)
  350. {
  351. struct lua_upstream_list *upl;
  352. struct lua_upstream *selected, **pselected;
  353. time_t now;
  354. const gchar *key;
  355. upl = lua_check_upstream_list (L);
  356. if (upl) {
  357. key = luaL_checkstring (L, 2);
  358. if (key) {
  359. if (lua_gettop (L) >= 3) {
  360. now = luaL_checkinteger (L, 3);
  361. }
  362. else {
  363. now = time (NULL);
  364. }
  365. selected = (struct lua_upstream *)get_upstream_by_hash (
  366. upl->upstreams,
  367. upl->count,
  368. sizeof (struct lua_upstream),
  369. now,
  370. DEFAULT_UPSTREAM_ERROR_TIME,
  371. DEFAULT_UPSTREAM_DEAD_TIME,
  372. DEFAULT_UPSTREAM_MAXERRORS,
  373. key,
  374. 0);
  375. if (selected) {
  376. pselected = lua_newuserdata (L, sizeof (struct lua_upstream *));
  377. rspamd_lua_setclass (L, "rspamd{upstream}", -1);
  378. *pselected = selected;
  379. }
  380. else {
  381. lua_pushnil (L);
  382. }
  383. }
  384. else {
  385. lua_pushnil (L);
  386. }
  387. }
  388. else {
  389. lua_pushnil (L);
  390. }
  391. return 1;
  392. }
  393. /**
  394. * Get upstream round robin (by current weight), params are: time (optional)
  395. * @param L
  396. * @return
  397. */
  398. static gint
  399. lua_upstream_list_get_upstream_round_robin (lua_State *L)
  400. {
  401. struct lua_upstream_list *upl;
  402. struct lua_upstream *selected, **pselected;
  403. time_t now;
  404. upl = lua_check_upstream_list (L);
  405. if (upl) {
  406. if (lua_gettop (L) >= 2) {
  407. now = luaL_checkinteger (L, 2);
  408. }
  409. else {
  410. now = time (NULL);
  411. }
  412. selected = (struct lua_upstream *)get_upstream_round_robin (
  413. upl->upstreams,
  414. upl->count,
  415. sizeof (struct lua_upstream),
  416. now,
  417. DEFAULT_UPSTREAM_ERROR_TIME,
  418. DEFAULT_UPSTREAM_DEAD_TIME,
  419. DEFAULT_UPSTREAM_MAXERRORS);
  420. if (selected) {
  421. pselected = lua_newuserdata (L, sizeof (struct lua_upstream *));
  422. rspamd_lua_setclass (L, "rspamd{upstream}", -1);
  423. *pselected = selected;
  424. }
  425. else {
  426. lua_pushnil (L);
  427. }
  428. }
  429. else {
  430. lua_pushnil (L);
  431. }
  432. return 1;
  433. }
  434. /**
  435. * Get upstream master slave order (by static priority), params are: time (optional)
  436. * @param L
  437. * @return
  438. */
  439. static gint
  440. lua_upstream_list_get_upstream_master_slave (lua_State *L)
  441. {
  442. struct lua_upstream_list *upl;
  443. struct lua_upstream *selected, **pselected;
  444. time_t now;
  445. upl = lua_check_upstream_list (L);
  446. if (upl) {
  447. if (lua_gettop (L) >= 2) {
  448. now = luaL_checkinteger (L, 2);
  449. }
  450. else {
  451. now = time (NULL);
  452. }
  453. selected = (struct lua_upstream *)get_upstream_master_slave (
  454. upl->upstreams,
  455. upl->count,
  456. sizeof (struct lua_upstream),
  457. now,
  458. DEFAULT_UPSTREAM_ERROR_TIME,
  459. DEFAULT_UPSTREAM_DEAD_TIME,
  460. DEFAULT_UPSTREAM_MAXERRORS);
  461. if (selected) {
  462. pselected = lua_newuserdata (L, sizeof (struct lua_upstream *));
  463. rspamd_lua_setclass (L, "rspamd{upstream}", -1);
  464. *pselected = selected;
  465. }
  466. else {
  467. lua_pushnil (L);
  468. }
  469. }
  470. else {
  471. lua_pushnil (L);
  472. }
  473. return 1;
  474. }
  475. static gint
  476. lua_load_upstream (lua_State * L)
  477. {
  478. lua_newtable (L);
  479. luaL_register (L, NULL, upstream_f);
  480. return 1;
  481. }
  482. static gint
  483. lua_load_upstream_list (lua_State * L)
  484. {
  485. lua_newtable (L);
  486. luaL_register (L, NULL, upstream_list_f);
  487. return 1;
  488. }
  489. void
  490. luaopen_upstream (lua_State * L)
  491. {
  492. luaL_newmetatable (L, "rspamd{upstream_list}");
  493. lua_pushstring (L, "__index");
  494. lua_pushvalue (L, -2);
  495. lua_settable (L, -3);
  496. lua_pushstring (L, "class");
  497. lua_pushstring (L, "rspamd{upstream_list}");
  498. lua_rawset (L, -3);
  499. luaL_register (L, NULL, upstream_list_m);
  500. rspamd_lua_add_preload (L, "upstream_list", lua_load_upstream_list);
  501. lua_pop (L, 1); /* remove metatable from stack */
  502. luaL_newmetatable (L, "rspamd{upstream}");
  503. lua_pushstring (L, "__index");
  504. lua_pushvalue (L, -2);
  505. lua_settable (L, -3);
  506. lua_pushstring (L, "class");
  507. lua_pushstring (L, "rspamd{upstream}");
  508. lua_rawset (L, -3);
  509. luaL_register (L, NULL, upstream_m);
  510. rspamd_lua_add_preload (L, "upstream", lua_load_upstream);
  511. lua_pop (L, 1); /* remove metatable from stack */
  512. }