1 /*
2 * Lua safe functions
3 *
4 * Copyright 2015-2016 Thierry Fournier <tfournier@arpalert.org>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 *
12 * All the functions in this file runs with a Lua stack, and can
13 * return with a longjmp. All of these function must be launched
14 * in an environment able to catch a longjmp, otherwise a
15 * critical error can be raised.
16 */
17 #include <lauxlib.h>
18 #include <lua.h>
19 #include <lualib.h>
20
21 #include <common/time.h>
22 #include <common/uri_auth.h>
23
24 #include <types/cli.h>
25 #include <types/hlua.h>
26 #include <types/proxy.h>
27 #include <types/stats.h>
28
29 #include <proto/proto_http.h>
30 #include <proto/proxy.h>
31 #include <proto/server.h>
32 #include <proto/stats.h>
33
34 /* Contains the class reference of the concat object. */
35 static int class_concat_ref;
36 static int class_proxy_ref;
37 static int class_server_ref;
38 static int class_listener_ref;
39
40 #define STATS_LEN (MAX((int)ST_F_TOTAL_FIELDS, (int)INF_TOTAL_FIELDS))
41
42 static struct field stats[STATS_LEN];
43
hlua_checkboolean(lua_State * L,int index)44 int hlua_checkboolean(lua_State *L, int index)
45 {
46 if (!lua_isboolean(L, index))
47 luaL_argerror(L, index, "boolean expected");
48 return lua_toboolean(L, index);
49 }
50
51 /* This function gets a struct field and convert it in Lua
52 * variable. The variable is pushed at the top of the stak.
53 */
hlua_fcn_pushfield(lua_State * L,struct field * field)54 int hlua_fcn_pushfield(lua_State *L, struct field *field)
55 {
56 /* The lua_Integer is always signed. Its length depends on
57 * compilation opions, so the followinfg code is conditionned
58 * by some macros. Windows maros are not supported.
59 * If the number cannot be represented as integer, we try to
60 * convert to float.
61 */
62 switch (field_format(field, 0)) {
63
64 case FF_EMPTY:
65 lua_pushnil(L);
66 return 1;
67
68 case FF_S32:
69 /* S32 is always supported. */
70 lua_pushinteger(L, field->u.s32);
71 return 1;
72
73 case FF_U32:
74 #if (LUA_MAXINTEGER == LLONG_MAX || ((LUA_MAXINTEGER == LONG_MAX) && (__WORDSIZE == 64)))
75 /* 64 bits case, U32 is always supported */
76 lua_pushinteger(L, field->u.u32);
77 #else
78 /* 32 bits case, U32 is supported until INT_MAX. */
79 if (field->u.u32 > INT_MAX)
80 lua_pushnumber(L, (lua_Number)field->u.u32);
81 else
82 lua_pushinteger(L, field->u.u32);
83 #endif
84 return 1;
85
86 case FF_S64:
87 #if (LUA_MAXINTEGER == LLONG_MAX || ((LUA_MAXINTEGER == LONG_MAX) && (__WORDSIZE == 64)))
88 /* 64 bits case, S64 is always supported */
89 lua_pushinteger(L, field->u.s64);
90 #else
91 /* 64 bits case, S64 is supported beetween INT_MIN and INT_MAX */
92 if (field->u.s64 < INT_MIN || field->u.s64 > INT_MAX)
93 lua_pushnumber(L, (lua_Number)field->u.s64);
94 else
95 lua_pushinteger(L, (int)field->u.s64);
96 #endif
97 return 1;
98
99 case FF_U64:
100 #if (LUA_MAXINTEGER == LLONG_MAX || ((LUA_MAXINTEGER == LONG_MAX) && (__WORDSIZE == 64)))
101 /* 64 bits case, U64 is supported until LLONG_MAX */
102 if (field->u.u64 > LLONG_MAX)
103 lua_pushnumber(L, (lua_Number)field->u.u64);
104 else
105 lua_pushinteger(L, field->u.u64);
106 #else
107 /* 64 bits case, U64 is supported until INT_MAX */
108 if (field->u.u64 > INT_MAX)
109 lua_pushnumber(L, (lua_Number)field->u.u64);
110 else
111 lua_pushinteger(L, (int)field->u.u64);
112 #endif
113 return 1;
114
115 case FF_STR:
116 lua_pushstring(L, field->u.str);
117 return 1;
118
119 default:
120 break;
121 }
122
123 /* Default case, never reached. */
124 lua_pushnil(L);
125 return 1;
126 }
127
128 /* Some string are started or terminated by blank chars,
129 * this function removes the spaces, tabs, \r and
130 * \n at the begin and at the end of the string "str", and
131 * push the result in the lua stack.
132 * Returns a pointer to the Lua internal copy of the string.
133 */
hlua_pushstrippedstring(lua_State * L,const char * str)134 const char *hlua_pushstrippedstring(lua_State *L, const char *str)
135 {
136 const char *p;
137 int l;
138
139 for (p = str; HTTP_IS_LWS(*p); p++);
140
141 for (l = strlen(p); l && HTTP_IS_LWS(p[l-1]); l--);
142
143 return lua_pushlstring(L, p, l);
144 }
145
146 /* The three following functions are useful for adding entries
147 * in a table. These functions takes a string and respectively an
148 * integer, a string or a function and add it to the table in the
149 * top of the stack.
150 *
151 * These functions throws an error if no more stack size is
152 * available.
153 */
hlua_class_const_int(lua_State * L,const char * name,int value)154 void hlua_class_const_int(lua_State *L, const char *name, int value)
155 {
156 lua_pushstring(L, name);
157 lua_pushinteger(L, value);
158 lua_rawset(L, -3);
159 }
hlua_class_const_str(lua_State * L,const char * name,const char * value)160 void hlua_class_const_str(lua_State *L, const char *name, const char *value)
161 {
162 lua_pushstring(L, name);
163 lua_pushstring(L, value);
164 lua_rawset(L, -3);
165 }
hlua_class_function(lua_State * L,const char * name,int (* function)(lua_State * L))166 void hlua_class_function(lua_State *L, const char *name, int (*function)(lua_State *L))
167 {
168 lua_pushstring(L, name);
169 lua_pushcclosure(L, function, 0);
170 lua_rawset(L, -3);
171 }
172
173 /* This function returns a string containg the HAProxy object name. */
hlua_dump_object(struct lua_State * L)174 int hlua_dump_object(struct lua_State *L)
175 {
176 const char *name = (const char *)lua_tostring(L, lua_upvalueindex(1));
177 lua_pushfstring(L, "HAProxy class %s", name);
178 return 1;
179 }
180
181 /* This function register a table as metatable and. It names
182 * the metatable, and returns the associated reference.
183 * The original table is poped from the top of the stack.
184 * "name" is the referenced class name.
185 */
hlua_register_metatable(struct lua_State * L,char * name)186 int hlua_register_metatable(struct lua_State *L, char *name)
187 {
188 /* Check the type of the top element. it must be
189 * a table.
190 */
191 if (lua_type(L, -1) != LUA_TTABLE)
192 luaL_error(L, "hlua_register_metatable() requires a type Table "
193 "in the top of the stack");
194
195 /* Add the __tostring function which identify the
196 * created object.
197 */
198 lua_pushstring(L, "__tostring");
199 lua_pushstring(L, name);
200 lua_pushcclosure(L, hlua_dump_object, 1);
201 lua_rawset(L, -3);
202
203 /* Register a named entry for the table. The table
204 * reference is copyed first because the function
205 * lua_setfield() pop the entry.
206 */
207 lua_pushvalue(L, -1);
208 lua_setfield(L, LUA_REGISTRYINDEX, name);
209
210 /* Creates the reference of the object. The
211 * function luaL_ref pop the top of the stack.
212 */
213 return luaL_ref(L, LUA_REGISTRYINDEX);
214 }
215
216 /* Return an object of the expected type, or throws an error. */
hlua_checkudata(lua_State * L,int ud,int class_ref)217 void *hlua_checkudata(lua_State *L, int ud, int class_ref)
218 {
219 void *p;
220 int ret;
221
222 /* Check if the stack entry is an array. */
223 if (!lua_istable(L, ud))
224 luaL_argerror(L, ud, NULL);
225
226 /* pop the metatable of the referencecd object. */
227 if (!lua_getmetatable(L, ud))
228 luaL_argerror(L, ud, NULL);
229
230 /* pop the expected metatable. */
231 lua_rawgeti(L, LUA_REGISTRYINDEX, class_ref);
232
233 /* Check if the metadata have the expected type. */
234 ret = lua_rawequal(L, -1, -2);
235 lua_pop(L, 2);
236 if (!ret)
237 luaL_argerror(L, ud, NULL);
238
239 /* Push on the stack at the entry [0] of the table. */
240 lua_rawgeti(L, ud, 0);
241
242 /* Check if this entry is userdata. */
243 p = lua_touserdata(L, -1);
244 if (!p)
245 luaL_argerror(L, ud, NULL);
246
247 /* Remove the entry returned by lua_rawgeti(). */
248 lua_pop(L, 1);
249
250 /* Return the associated struct. */
251 return p;
252 }
253
254 /* This function return the current date at epoch format in milliseconds. */
hlua_now(lua_State * L)255 int hlua_now(lua_State *L)
256 {
257 lua_newtable(L);
258 lua_pushstring(L, "sec");
259 lua_pushinteger(L, now.tv_sec);
260 lua_rawset(L, -3);
261 lua_pushstring(L, "usec");
262 lua_pushinteger(L, now.tv_usec);
263 lua_rawset(L, -3);
264 return 1;
265 }
266
267 /* This functions expects a Lua string as HTTP date, parse it and
268 * returns an integer containing the epoch format of the date, or
269 * nil if the parsing fails.
270 */
hlua_parse_date(lua_State * L,int (* fcn)(const char *,int,struct tm *))271 static int hlua_parse_date(lua_State *L, int (*fcn)(const char *, int, struct tm*))
272 {
273 const char *str;
274 size_t len;
275 struct tm tm;
276 time_t time;
277
278 str = luaL_checklstring(L, 1, &len);
279
280 if (!fcn(str, len, &tm)) {
281 lua_pushnil(L);
282 return 1;
283 }
284
285 /* This function considers the content of the broken-down time
286 * is exprimed in the UTC timezone. timegm don't care about
287 * the gnu variable tm_gmtoff. If gmtoff is set, or if you know
288 * the timezone from the broken-down time, it must be fixed
289 * after the conversion.
290 */
291 time = my_timegm(&tm);
292 if (time == -1) {
293 lua_pushnil(L);
294 return 1;
295 }
296
297 lua_pushinteger(L, (int)time);
298 return 1;
299 }
hlua_http_date(lua_State * L)300 static int hlua_http_date(lua_State *L)
301 {
302 return hlua_parse_date(L, parse_http_date);
303 }
hlua_imf_date(lua_State * L)304 static int hlua_imf_date(lua_State *L)
305 {
306 return hlua_parse_date(L, parse_imf_date);
307 }
hlua_rfc850_date(lua_State * L)308 static int hlua_rfc850_date(lua_State *L)
309 {
310 return hlua_parse_date(L, parse_rfc850_date);
311 }
hlua_asctime_date(lua_State * L)312 static int hlua_asctime_date(lua_State *L)
313 {
314 return hlua_parse_date(L, parse_asctime_date);
315 }
316
hlua_get_info(lua_State * L)317 static int hlua_get_info(lua_State *L)
318 {
319 int i;
320
321 stats_fill_info(stats, STATS_LEN);
322
323 lua_newtable(L);
324 for (i=0; i<INF_TOTAL_FIELDS; i++) {
325 lua_pushstring(L, info_field_names[i]);
326 hlua_fcn_pushfield(L, &stats[i]);
327 lua_settable(L, -3);
328 }
329 return 1;
330 }
331
hlua_check_concat(lua_State * L,int ud)332 static struct hlua_concat *hlua_check_concat(lua_State *L, int ud)
333 {
334 return (hlua_checkudata(L, ud, class_concat_ref));
335 }
336
hlua_concat_add(lua_State * L)337 static int hlua_concat_add(lua_State *L)
338 {
339 struct hlua_concat *b;
340 char *buffer;
341 char *new;
342 const char *str;
343 size_t l;
344
345 /* First arg must be a concat object. */
346 b = hlua_check_concat(L, 1);
347
348 /* Second arg must be a string. */
349 str = luaL_checklstring(L, 2, &l);
350
351 /* Get the buffer. */
352 lua_rawgeti(L, 1, 1);
353 buffer = lua_touserdata(L, -1);
354 lua_pop(L, 1);
355
356 /* Update the buffer size if it s required. The old buffer
357 * is crushed by the new in the object array, so it will
358 * be deleted by the GC.
359 * Note that in the first loop, the "new" variable is only
360 * used as a flag.
361 */
362 new = NULL;
363 while (b->size - b->len < l) {
364 b->size += HLUA_CONCAT_BLOCSZ;
365 new = buffer;
366 }
367 if (new) {
368 new = lua_newuserdata(L, b->size);
369 memcpy(new, buffer, b->len);
370 lua_rawseti(L, 1, 1);
371 buffer = new;
372 }
373
374 /* Copy string, and update metadata. */
375 memcpy(buffer + b->len, str, l);
376 b->len += l;
377 return 0;
378 }
379
hlua_concat_dump(lua_State * L)380 static int hlua_concat_dump(lua_State *L)
381 {
382 struct hlua_concat *b;
383 char *buffer;
384
385 /* First arg must be a concat object. */
386 b = hlua_check_concat(L, 1);
387
388 /* Get the buffer. */
389 lua_rawgeti(L, 1, 1);
390 buffer = lua_touserdata(L, -1);
391 lua_pop(L, 1);
392
393 /* Push the soncatenated strng in the stack. */
394 lua_pushlstring(L, buffer, b->len);
395 return 1;
396 }
397
hlua_concat_new(lua_State * L)398 int hlua_concat_new(lua_State *L)
399 {
400 struct hlua_concat *b;
401
402 lua_newtable(L);
403 b = lua_newuserdata(L, sizeof(*b));
404 b->size = HLUA_CONCAT_BLOCSZ;
405 b->len = 0;
406 lua_rawseti(L, -2, 0);
407 lua_newuserdata(L, HLUA_CONCAT_BLOCSZ);
408 lua_rawseti(L, -2, 1);
409
410 lua_rawgeti(L, LUA_REGISTRYINDEX, class_concat_ref);
411 lua_setmetatable(L, -2);
412
413 return 1;
414 }
415
concat_tostring(lua_State * L)416 static int concat_tostring(lua_State *L)
417 {
418 const void *ptr = lua_topointer(L, 1);
419 lua_pushfstring(L, "Concat object: %p", ptr);
420 return 1;
421 }
422
hlua_concat_init(lua_State * L)423 static int hlua_concat_init(lua_State *L)
424 {
425 /* Creates the buffered concat object. */
426 lua_newtable(L);
427
428 lua_pushstring(L, "__tostring");
429 lua_pushcclosure(L, concat_tostring, 0);
430 lua_settable(L, -3);
431
432 lua_pushstring(L, "__index"); /* Creates the index entry. */
433 lua_newtable(L); /* The "__index" content. */
434
435 lua_pushstring(L, "add");
436 lua_pushcclosure(L, hlua_concat_add, 0);
437 lua_settable(L, -3);
438
439 lua_pushstring(L, "dump");
440 lua_pushcclosure(L, hlua_concat_dump, 0);
441 lua_settable(L, -3);
442
443 lua_settable(L, -3); /* Sets the __index entry. */
444 class_concat_ref = luaL_ref(L, LUA_REGISTRYINDEX);
445
446 return 1;
447 }
448
hlua_fcn_new_listener(lua_State * L,struct listener * lst)449 int hlua_fcn_new_listener(lua_State *L, struct listener *lst)
450 {
451 lua_newtable(L);
452
453 /* Pop a class sesison metatable and affect it to the userdata. */
454 lua_rawgeti(L, LUA_REGISTRYINDEX, class_listener_ref);
455 lua_setmetatable(L, -2);
456
457 lua_pushlightuserdata(L, lst);
458 lua_rawseti(L, -2, 0);
459 return 1;
460 }
461
hlua_check_listener(lua_State * L,int ud)462 static struct listener *hlua_check_listener(lua_State *L, int ud)
463 {
464 return hlua_checkudata(L, ud, class_listener_ref);
465 }
466
hlua_listener_get_stats(lua_State * L)467 int hlua_listener_get_stats(lua_State *L)
468 {
469 struct listener *li;
470 int i;
471
472 li = hlua_check_listener(L, 1);
473
474 if (!li->frontend) {
475 lua_pushnil(L);
476 return 1;
477 }
478
479 stats_fill_li_stats(li->frontend, li, ST_SHLGNDS, stats, STATS_LEN);
480
481 lua_newtable(L);
482 for (i=0; i<ST_F_TOTAL_FIELDS; i++) {
483 lua_pushstring(L, stat_field_names[i]);
484 hlua_fcn_pushfield(L, &stats[i]);
485 lua_settable(L, -3);
486 }
487 return 1;
488
489 }
490
hlua_fcn_new_server(lua_State * L,struct server * srv)491 int hlua_fcn_new_server(lua_State *L, struct server *srv)
492 {
493 lua_newtable(L);
494
495 /* Pop a class sesison metatable and affect it to the userdata. */
496 lua_rawgeti(L, LUA_REGISTRYINDEX, class_server_ref);
497 lua_setmetatable(L, -2);
498
499 lua_pushlightuserdata(L, srv);
500 lua_rawseti(L, -2, 0);
501 return 1;
502 }
503
hlua_check_server(lua_State * L,int ud)504 static struct server *hlua_check_server(lua_State *L, int ud)
505 {
506 return hlua_checkudata(L, ud, class_server_ref);
507 }
508
hlua_server_get_stats(lua_State * L)509 int hlua_server_get_stats(lua_State *L)
510 {
511 struct server *srv;
512 int i;
513
514 srv = hlua_check_server(L, 1);
515
516 if (!srv->proxy) {
517 lua_pushnil(L);
518 return 1;
519 }
520
521 stats_fill_sv_stats(srv->proxy, srv, ST_SHLGNDS, stats, STATS_LEN);
522
523 lua_newtable(L);
524 for (i=0; i<ST_F_TOTAL_FIELDS; i++) {
525 lua_pushstring(L, stat_field_names[i]);
526 hlua_fcn_pushfield(L, &stats[i]);
527 lua_settable(L, -3);
528 }
529 return 1;
530
531 }
532
hlua_server_get_addr(lua_State * L)533 int hlua_server_get_addr(lua_State *L)
534 {
535 struct server *srv;
536 char addr[INET6_ADDRSTRLEN];
537 luaL_Buffer b;
538
539 srv = hlua_check_server(L, 1);
540
541 luaL_buffinit(L, &b);
542
543 switch (srv->addr.ss_family) {
544 case AF_INET:
545 inet_ntop(AF_INET, &((struct sockaddr_in *)&srv->addr)->sin_addr,
546 addr, INET_ADDRSTRLEN);
547 luaL_addstring(&b, addr);
548 luaL_addstring(&b, ":");
549 snprintf(addr, INET_ADDRSTRLEN, "%d", srv->svc_port);
550 luaL_addstring(&b, addr);
551 break;
552 case AF_INET6:
553 inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&srv->addr)->sin6_addr,
554 addr, INET6_ADDRSTRLEN);
555 luaL_addstring(&b, addr);
556 luaL_addstring(&b, ":");
557 snprintf(addr, INET_ADDRSTRLEN, "%d", srv->svc_port);
558 luaL_addstring(&b, addr);
559 break;
560 case AF_UNIX:
561 luaL_addstring(&b, (char *)((struct sockaddr_un *)&srv->addr)->sun_path);
562 break;
563 default:
564 luaL_addstring(&b, "<unknown>");
565 break;
566 }
567
568 luaL_pushresult(&b);
569 return 1;
570 }
571
hlua_server_is_draining(lua_State * L)572 int hlua_server_is_draining(lua_State *L)
573 {
574 struct server *srv;
575
576 srv = hlua_check_server(L, 1);
577 lua_pushinteger(L, server_is_draining(srv));
578 return 1;
579 }
580
hlua_server_set_weight(lua_State * L)581 int hlua_server_set_weight(lua_State *L)
582 {
583 struct server *srv;
584 const char *weight;
585 const char *err;
586
587 srv = hlua_check_server(L, 1);
588 weight = luaL_checkstring(L, 2);
589
590 err = server_parse_weight_change_request(srv, weight);
591 if (!err)
592 lua_pushnil(L);
593 else
594 hlua_pushstrippedstring(L, err);
595 return 1;
596 }
597
hlua_server_get_weight(lua_State * L)598 int hlua_server_get_weight(lua_State *L)
599 {
600 struct server *srv;
601
602 srv = hlua_check_server(L, 1);
603 lua_pushinteger(L, srv->uweight);
604 return 1;
605 }
606
hlua_server_set_addr(lua_State * L)607 int hlua_server_set_addr(lua_State *L)
608 {
609 struct server *srv;
610 const char *addr;
611 const char *err;
612
613 srv = hlua_check_server(L, 1);
614 addr = luaL_checkstring(L, 2);
615
616 err = server_parse_addr_change_request(srv, addr, "Lua script");
617 if (!err)
618 lua_pushnil(L);
619 else
620 hlua_pushstrippedstring(L, err);
621 return 1;
622 }
623
hlua_server_shut_sess(lua_State * L)624 int hlua_server_shut_sess(lua_State *L)
625 {
626 struct server *srv;
627
628 srv = hlua_check_server(L, 1);
629 srv_shutdown_streams(srv, SF_ERR_KILLED);
630 return 0;
631 }
632
hlua_server_set_drain(lua_State * L)633 int hlua_server_set_drain(lua_State *L)
634 {
635 struct server *srv;
636
637 srv = hlua_check_server(L, 1);
638 srv_adm_set_drain(srv);
639 return 0;
640 }
641
hlua_server_set_maint(lua_State * L)642 int hlua_server_set_maint(lua_State *L)
643 {
644 struct server *srv;
645
646 srv = hlua_check_server(L, 1);
647 srv_adm_set_maint(srv);
648 return 0;
649 }
650
hlua_server_set_ready(lua_State * L)651 int hlua_server_set_ready(lua_State *L)
652 {
653 struct server *srv;
654
655 srv = hlua_check_server(L, 1);
656 srv_adm_set_ready(srv);
657 return 0;
658 }
659
hlua_server_check_enable(lua_State * L)660 int hlua_server_check_enable(lua_State *L)
661 {
662 struct server *sv;
663
664 sv = hlua_check_server(L, 1);
665 if (sv->check.state & CHK_ST_CONFIGURED) {
666 sv->check.state |= CHK_ST_ENABLED;
667 }
668 return 0;
669 }
670
hlua_server_check_disable(lua_State * L)671 int hlua_server_check_disable(lua_State *L)
672 {
673 struct server *sv;
674
675 sv = hlua_check_server(L, 1);
676 if (sv->check.state & CHK_ST_CONFIGURED) {
677 sv->check.state &= ~CHK_ST_ENABLED;
678 }
679 return 0;
680 }
681
hlua_server_check_force_up(lua_State * L)682 int hlua_server_check_force_up(lua_State *L)
683 {
684 struct server *sv;
685
686 sv = hlua_check_server(L, 1);
687 if (!(sv->track)) {
688 sv->check.health = sv->check.rise + sv->check.fall - 1;
689 srv_set_running(sv, "changed from Lua script");
690 }
691 return 0;
692 }
693
hlua_server_check_force_nolb(lua_State * L)694 int hlua_server_check_force_nolb(lua_State *L)
695 {
696 struct server *sv;
697
698 sv = hlua_check_server(L, 1);
699 if (!(sv->track)) {
700 sv->check.health = sv->check.rise + sv->check.fall - 1;
701 srv_set_stopping(sv, "changed from Lua script");
702 }
703 return 0;
704 }
705
hlua_server_check_force_down(lua_State * L)706 int hlua_server_check_force_down(lua_State *L)
707 {
708 struct server *sv;
709
710 sv = hlua_check_server(L, 1);
711 if (!(sv->track)) {
712 sv->check.health = 0;
713 srv_set_stopped(sv, "changed from Lua script");
714 }
715 return 0;
716 }
717
hlua_server_agent_enable(lua_State * L)718 int hlua_server_agent_enable(lua_State *L)
719 {
720 struct server *sv;
721
722 sv = hlua_check_server(L, 1);
723 if (sv->agent.state & CHK_ST_CONFIGURED) {
724 sv->agent.state |= CHK_ST_ENABLED;
725 }
726 return 0;
727 }
728
hlua_server_agent_disable(lua_State * L)729 int hlua_server_agent_disable(lua_State *L)
730 {
731 struct server *sv;
732
733 sv = hlua_check_server(L, 1);
734 if (sv->agent.state & CHK_ST_CONFIGURED) {
735 sv->agent.state &= ~CHK_ST_ENABLED;
736 }
737 return 0;
738 }
739
hlua_server_agent_force_up(lua_State * L)740 int hlua_server_agent_force_up(lua_State *L)
741 {
742 struct server *sv;
743
744 sv = hlua_check_server(L, 1);
745 if (sv->agent.state & CHK_ST_ENABLED) {
746 sv->agent.health = sv->agent.rise + sv->agent.fall - 1;
747 srv_set_running(sv, "changed from Lua script");
748 }
749 return 0;
750 }
751
hlua_server_agent_force_down(lua_State * L)752 int hlua_server_agent_force_down(lua_State *L)
753 {
754 struct server *sv;
755
756 sv = hlua_check_server(L, 1);
757 if (sv->agent.state & CHK_ST_ENABLED) {
758 sv->agent.health = 0;
759 srv_set_stopped(sv, "changed from Lua script");
760 }
761 return 0;
762 }
763
hlua_fcn_new_proxy(lua_State * L,struct proxy * px)764 int hlua_fcn_new_proxy(lua_State *L, struct proxy *px)
765 {
766 struct server *srv;
767 struct listener *lst;
768 int lid;
769 char buffer[17];
770
771 lua_newtable(L);
772
773 /* Pop a class sesison metatable and affect it to the userdata. */
774 lua_rawgeti(L, LUA_REGISTRYINDEX, class_proxy_ref);
775 lua_setmetatable(L, -2);
776
777 lua_pushlightuserdata(L, px);
778 lua_rawseti(L, -2, 0);
779
780 /* Browse and register servers. */
781 lua_pushstring(L, "servers");
782 lua_newtable(L);
783 for (srv = px->srv; srv; srv = srv->next) {
784 lua_pushstring(L, srv->id);
785 hlua_fcn_new_server(L, srv);
786 lua_settable(L, -3);
787 }
788 lua_settable(L, -3);
789
790 /* Browse and register listeners. */
791 lua_pushstring(L, "listeners");
792 lua_newtable(L);
793 lid = 1;
794 list_for_each_entry(lst, &px->conf.listeners, by_fe) {
795 if (lst->name)
796 lua_pushstring(L, lst->name);
797 else {
798 snprintf(buffer, sizeof(buffer), "sock-%d", lid);
799 lid++;
800 lua_pushstring(L, buffer);
801 }
802 hlua_fcn_new_listener(L, lst);
803 lua_settable(L, -3);
804 }
805 lua_settable(L, -3);
806
807 return 1;
808 }
809
hlua_check_proxy(lua_State * L,int ud)810 static struct proxy *hlua_check_proxy(lua_State *L, int ud)
811 {
812 return hlua_checkudata(L, ud, class_proxy_ref);
813 }
814
hlua_proxy_pause(lua_State * L)815 int hlua_proxy_pause(lua_State *L)
816 {
817 struct proxy *px;
818
819 px = hlua_check_proxy(L, 1);
820 pause_proxy(px);
821 return 0;
822 }
823
hlua_proxy_resume(lua_State * L)824 int hlua_proxy_resume(lua_State *L)
825 {
826 struct proxy *px;
827
828 px = hlua_check_proxy(L, 1);
829 resume_proxy(px);
830 return 0;
831 }
832
hlua_proxy_stop(lua_State * L)833 int hlua_proxy_stop(lua_State *L)
834 {
835 struct proxy *px;
836
837 px = hlua_check_proxy(L, 1);
838 stop_proxy(px);
839 return 0;
840 }
841
hlua_proxy_get_cap(lua_State * L)842 int hlua_proxy_get_cap(lua_State *L)
843 {
844 struct proxy *px;
845 const char *str;
846
847 px = hlua_check_proxy(L, 1);
848 str = proxy_cap_str(px->cap);
849 lua_pushstring(L, str);
850 return 1;
851 }
852
hlua_proxy_get_stats(lua_State * L)853 int hlua_proxy_get_stats(lua_State *L)
854 {
855 struct proxy *px;
856 int i;
857
858 px = hlua_check_proxy(L, 1);
859 if (px->cap & PR_CAP_BE)
860 stats_fill_be_stats(px, ST_SHLGNDS, stats, STATS_LEN);
861 else
862 stats_fill_fe_stats(px, stats, STATS_LEN);
863 lua_newtable(L);
864 for (i=0; i<ST_F_TOTAL_FIELDS; i++) {
865 lua_pushstring(L, stat_field_names[i]);
866 hlua_fcn_pushfield(L, &stats[i]);
867 lua_settable(L, -3);
868 }
869 return 1;
870 }
871
hlua_proxy_get_mode(lua_State * L)872 int hlua_proxy_get_mode(lua_State *L)
873 {
874 struct proxy *px;
875 const char *str;
876
877 px = hlua_check_proxy(L, 1);
878 str = proxy_mode_str(px->mode);
879 lua_pushstring(L, str);
880 return 1;
881 }
882
hlua_proxy_shut_bcksess(lua_State * L)883 int hlua_proxy_shut_bcksess(lua_State *L)
884 {
885 struct proxy *px;
886
887 px = hlua_check_proxy(L, 1);
888 srv_shutdown_backup_streams(px, SF_ERR_KILLED);
889 return 0;
890 }
891
hlua_fcn_post_init(lua_State * L)892 int hlua_fcn_post_init(lua_State *L)
893 {
894 struct proxy *px;
895
896 /* get core array. */
897 if (lua_getglobal(L, "core") != LUA_TTABLE)
898 lua_error(L);
899
900 /* Create proxies entry. */
901 lua_pushstring(L, "proxies");
902 lua_newtable(L);
903
904 /* List all proxies. */
905 for (px = proxy; px; px = px->next) {
906 lua_pushstring(L, px->id);
907 hlua_fcn_new_proxy(L, px);
908 lua_settable(L, -3);
909 }
910
911 /* push "proxies" in "core" */
912 lua_settable(L, -3);
913
914 return 1;
915 }
916
917 /* This Lua function take a string, a list of separators.
918 * It tokenize the input string using the list of separators
919 * as separator.
920 *
921 * The functionreturns a tablle filled with tokens.
922 */
hlua_tokenize(lua_State * L)923 int hlua_tokenize(lua_State *L)
924 {
925 const char *str;
926 const char *sep;
927 int index;
928 const char *token;
929 const char *p;
930 const char *c;
931 int ignore_empty;
932
933 ignore_empty = 0;
934
935 str = luaL_checkstring(L, 1);
936 sep = luaL_checkstring(L, 2);
937 if (lua_gettop(L) == 3)
938 ignore_empty = hlua_checkboolean(L, 3);
939
940 lua_newtable(L);
941 index = 1;
942 token = str;
943 p = str;
944 while(1) {
945 for (c = sep; *c != '\0'; c++)
946 if (*p == *c)
947 break;
948 if (*p == *c) {
949 if ((!ignore_empty) || (p - token > 0)) {
950 lua_pushlstring(L, token, p - token);
951 lua_rawseti(L, -2, index);
952 index++;
953 }
954 token = p + 1;
955 }
956 if (*p == '\0')
957 break;
958 p++;
959 }
960
961 return 1;
962 }
963
hlua_parse_addr(lua_State * L)964 int hlua_parse_addr(lua_State *L)
965 {
966 struct hlua_addr *addr;
967 const char *str = luaL_checkstring(L, 1);
968 unsigned char mask;
969
970 addr = lua_newuserdata(L, sizeof(struct hlua_addr));
971 if (!addr) {
972 lua_pushnil(L);
973 return 1;
974 }
975
976 if (str2net(str, PAT_MF_NO_DNS, &addr->addr.v4.ip, &addr->addr.v4.mask)) {
977 addr->type = AF_INET;
978 return 1;
979 }
980
981 if (str62net(str, &addr->addr.v6.ip, &mask)) {
982 len2mask6(mask, &addr->addr.v6.mask);
983 addr->type = AF_INET6;
984 return 1;
985 }
986
987 lua_pop(L, 1);
988 lua_pushnil(L);
989 return 1;
990 }
991
hlua_match_addr(lua_State * L)992 int hlua_match_addr(lua_State *L)
993 {
994 struct hlua_addr *addr1;
995 struct hlua_addr *addr2;
996
997 if (!lua_isuserdata(L, 1) ||
998 !lua_isuserdata(L, 2)) {
999 lua_pushboolean(L, 0);
1000 return 1;
1001 }
1002
1003 addr1 = lua_touserdata(L, 1);
1004 addr2 = lua_touserdata(L, 2);
1005
1006 if (addr1->type != addr2->type) {
1007 lua_pushboolean(L, 0);
1008 return 1;
1009 }
1010
1011 if (addr1->type == AF_INET) {
1012 if ((addr1->addr.v4.ip.s_addr & addr2->addr.v4.mask.s_addr) ==
1013 (addr2->addr.v4.ip.s_addr & addr1->addr.v4.mask.s_addr)) {
1014 lua_pushboolean(L, 1);
1015 return 1;
1016 }
1017 } else {
1018 int i;
1019
1020 for (i = 0; i < 16; i += 4) {
1021 if ((*(uint32_t *)&addr1->addr.v6.ip.s6_addr[i] &
1022 *(uint32_t *)&addr2->addr.v6.mask.s6_addr[i]) !=
1023 (*(uint32_t *)&addr2->addr.v6.ip.s6_addr[i] &
1024 *(uint32_t *)&addr1->addr.v6.mask.s6_addr[i]))
1025 break;
1026 }
1027 if (i == 16) {
1028 lua_pushboolean(L, 1);
1029 return 1;
1030 }
1031 }
1032
1033 lua_pushboolean(L, 0);
1034 return 1;
1035 }
1036
hlua_fcn_reg_core_fcn(lua_State * L)1037 int hlua_fcn_reg_core_fcn(lua_State *L)
1038 {
1039 if (!hlua_concat_init(L))
1040 return 0;
1041
1042 hlua_class_function(L, "now", hlua_now);
1043 hlua_class_function(L, "http_date", hlua_http_date);
1044 hlua_class_function(L, "imf_date", hlua_imf_date);
1045 hlua_class_function(L, "rfc850_date", hlua_rfc850_date);
1046 hlua_class_function(L, "asctime_date", hlua_asctime_date);
1047 hlua_class_function(L, "concat", hlua_concat_new);
1048 hlua_class_function(L, "get_info", hlua_get_info);
1049 hlua_class_function(L, "parse_addr", hlua_parse_addr);
1050 hlua_class_function(L, "match_addr", hlua_match_addr);
1051 hlua_class_function(L, "tokenize", hlua_tokenize);
1052
1053 /* Create listener object. */
1054 lua_newtable(L);
1055 lua_pushstring(L, "__index");
1056 lua_newtable(L);
1057 hlua_class_function(L, "get_stats", hlua_listener_get_stats);
1058 lua_settable(L, -3); /* -> META["__index"] = TABLE */
1059 class_listener_ref = hlua_register_metatable(L, CLASS_LISTENER);
1060
1061 /* Create server object. */
1062 lua_newtable(L);
1063 lua_pushstring(L, "__index");
1064 lua_newtable(L);
1065 hlua_class_function(L, "is_draining", hlua_server_is_draining);
1066 hlua_class_function(L, "set_weight", hlua_server_set_weight);
1067 hlua_class_function(L, "get_weight", hlua_server_get_weight);
1068 hlua_class_function(L, "set_addr", hlua_server_set_addr);
1069 hlua_class_function(L, "get_addr", hlua_server_get_addr);
1070 hlua_class_function(L, "get_stats", hlua_server_get_stats);
1071 hlua_class_function(L, "shut_sess", hlua_server_shut_sess);
1072 hlua_class_function(L, "set_drain", hlua_server_set_drain);
1073 hlua_class_function(L, "set_maint", hlua_server_set_maint);
1074 hlua_class_function(L, "set_ready", hlua_server_set_ready);
1075 hlua_class_function(L, "check_enable", hlua_server_check_enable);
1076 hlua_class_function(L, "check_disable", hlua_server_check_disable);
1077 hlua_class_function(L, "check_force_up", hlua_server_check_force_up);
1078 hlua_class_function(L, "check_force_nolb", hlua_server_check_force_nolb);
1079 hlua_class_function(L, "check_force_down", hlua_server_check_force_down);
1080 hlua_class_function(L, "agent_enable", hlua_server_agent_enable);
1081 hlua_class_function(L, "agent_disable", hlua_server_agent_disable);
1082 hlua_class_function(L, "agent_force_up", hlua_server_agent_force_up);
1083 hlua_class_function(L, "agent_force_down", hlua_server_agent_force_down);
1084 lua_settable(L, -3); /* -> META["__index"] = TABLE */
1085 class_server_ref = hlua_register_metatable(L, CLASS_SERVER);
1086
1087 /* Create proxy object. */
1088 lua_newtable(L);
1089 lua_pushstring(L, "__index");
1090 lua_newtable(L);
1091 hlua_class_function(L, "pause", hlua_proxy_pause);
1092 hlua_class_function(L, "resume", hlua_proxy_resume);
1093 hlua_class_function(L, "stop", hlua_proxy_stop);
1094 hlua_class_function(L, "shut_bcksess", hlua_proxy_shut_bcksess);
1095 hlua_class_function(L, "get_cap", hlua_proxy_get_cap);
1096 hlua_class_function(L, "get_mode", hlua_proxy_get_mode);
1097 hlua_class_function(L, "get_stats", hlua_proxy_get_stats);
1098 lua_settable(L, -3); /* -> META["__index"] = TABLE */
1099 class_proxy_ref = hlua_register_metatable(L, CLASS_PROXY);
1100
1101 return 5;
1102 }
1103