#include #include #include #include #include #include #include #include #ifdef __ANDROID__ #include "andr/ifaddrs.h" #else #include #endif #ifdef __FreeBSD__ #include #elif defined(__linux__) #include #elif defined(__CYGWIN__) #include // header hell conflicts between unix and win32 typedef struct in6_addr IN6_ADDR, *PIN6_ADDR, *LPIN6_ADDR; typedef struct sockaddr *LPSOCKADDR; typedef struct _SOCKET_ADDRESS { LPSOCKADDR lpSockaddr; int iSockaddrLength; } SOCKET_ADDRESS,*PSOCKET_ADDRESS,*LPSOCKET_ADDRESS; #define _WINSOCK2API_ #define _NETIOAPI_H_ #include #endif #include "lua.h" #include "params.h" #include "gzip.h" #include "helpers.h" #include "nfqws.h" #include "conntrack.h" #include "crypto/sha.h" #include "crypto/aes-gcm.h" #include "crypto/aes-ctr.h" void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size) { snprintf(instance, inst_size, "%s_%u_%u", func, dp_n, func_n); } static void lua_check_argc(lua_State *L, const char *where, int argc) { int num_args = lua_gettop(L); if (num_args != argc) luaL_error(L, "%s expect exactly %d arguments, got %d", where, argc, num_args); } static void lua_check_argc_range(lua_State *L, const char *where, int argc_min, int argc_max) { int num_args = lua_gettop(L); if (num_args < argc_min || num_args > argc_max) luaL_error(L, "%s expect from %d to %d arguments, got %d", where, argc_min, argc_max, num_args); } #if LUA_VERSION_NUM < 502 int lua_absindex(lua_State *L, int idx) { // convert relative index to absolute return idx<0 ? lua_gettop(L) + idx + 1 : idx; } #endif static int luacall_DLOG(lua_State *L) { lua_check_argc(L,"DLOG",1); DLOG("LUA: %s\n",luaL_checkstring(L,1)); return 0; } static int luacall_DLOG_ERR(lua_State *L) { lua_check_argc(L,"DLOG_ERR",1); DLOG_ERR("LUA: %s\n",luaL_checkstring(L,1)); return 0; } static int luacall_DLOG_CONDUP(lua_State *L) { lua_check_argc(L,"DLOG_CONDUP",1); DLOG_CONDUP("LUA: %s\n",luaL_checkstring(L,1)); return 0; } const char *lua_reqlstring(lua_State *L,int idx,size_t *len) { luaL_checktype(L,idx,LUA_TSTRING); return lua_tolstring(L,idx,len); } const char *lua_reqstring(lua_State *L,int idx) { luaL_checktype(L,idx,LUA_TSTRING); return lua_tostring(L,idx); } static int luacall_bitlshift(lua_State *L) { lua_check_argc(L,"bitlshift",2); int64_t v=(int64_t)luaL_checklint(L,1); lua_Integer shift = luaL_checkinteger(L,2); if (shift>48 || shift<0 || v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); uint64_t u = v & 0xFFFFFFFFFFFF; lua_pushlint(L,(u << shift) & 0xFFFFFFFFFFFF); return 1; } static int luacall_bitrshift(lua_State *L) { lua_check_argc(L,"bitrshift",2); int64_t v=(int64_t)luaL_checklint(L,1); lua_Integer shift = luaL_checkinteger(L,2); if (shift>48 || shift<0 || v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); uint64_t u = v & 0xFFFFFFFFFFFF; lua_pushlint(L,u >> shift); return 1; } static int luacall_bitand(lua_State *L) { lua_check_argc_range(L,"bitand",2,100); int argc = lua_gettop(L); int64_t v; uint64_t sum=0xFFFFFFFFFFFF; for(int i=1;i<=argc;i++) { v=(int64_t)luaL_checklint(L,i); if (v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); sum &= (uint64_t)v; } lua_pushlint(L,sum); return 1; } static int luacall_bitor(lua_State *L) { lua_check_argc_range(L,"bitor",1,100); int argc = lua_gettop(L); int64_t v; uint64_t sum=0; for(int i=1;i<=argc;i++) { v=(int64_t)luaL_checklint(L,i); if (v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); sum |= (uint64_t)(v & 0xFFFFFFFFFFFF); } lua_pushlint(L,sum); return 1; } static int luacall_bitxor(lua_State *L) { lua_check_argc_range(L,"bitxor",1,100); int argc = lua_gettop(L); int64_t v; uint64_t sum=0; for(int i=1;i<=argc;i++) { v=(int64_t)luaL_checklint(L,i); if (v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); sum ^= (uint64_t)(v & 0xFFFFFFFFFFFF); } lua_pushlint(L,sum); return 1; } static int lua_bitnotx(lua_State *L, int64_t max) { lua_check_argc(L,"bitnot",1); int64_t v=(int64_t)luaL_checklint(L,1); if (v>max || v<-max) luaL_error(L, "out of range"); lua_pushlint(L,~(uint64_t)v & max); return 1; } static int luacall_bitnot8(lua_State *L) { lua_check_argc(L,"bitnot8",1); return lua_bitnotx(L, 0xFF); } static int luacall_bitnot16(lua_State *L) { lua_check_argc(L,"bitnot16",1); return lua_bitnotx(L, 0xFFFF); } static int luacall_bitnot24(lua_State *L) { lua_check_argc(L,"bitnot24",1); return lua_bitnotx(L, 0xFFFFFF); } static int luacall_bitnot32(lua_State *L) { lua_check_argc(L,"bitnot32",1); return lua_bitnotx(L, 0xFFFFFFFF); } static int luacall_bitnot48(lua_State *L) { lua_check_argc(L,"bitnot48",1); return lua_bitnotx(L, 0xFFFFFFFFFFFF); } static int luacall_bitget(lua_State *L) { lua_check_argc(L,"bitget",3); int64_t iwhat = (int64_t)luaL_checklint(L,1); if (iwhat>0xFFFFFFFFFFFF || iwhat<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); uint64_t what = (uint64_t)iwhat; lua_Integer from = luaL_checkinteger(L,2); lua_Integer to = luaL_checkinteger(L,3); if (from<0 || to<0 || from>to || from>47 || to>47) luaL_error(L, "bit range invalid"); what = (what >> from) & ~((uint64_t)-1 << (to-from+1)); lua_pushlint(L,what); return 1; } static int luacall_bitset(lua_State *L) { lua_check_argc(L,"bitset",4); int64_t iwhat = (int64_t)luaL_checklint(L,1); if (iwhat>0xFFFFFFFFFFFF || iwhat<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); uint64_t what = (uint64_t)iwhat; lua_Integer from = luaL_checkinteger(L,2); lua_Integer to = luaL_checkinteger(L,3); int64_t iset = (int64_t)luaL_checklint(L,4); if (iset>0xFFFFFFFFFFFF || iset<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); uint64_t set = (uint64_t)iset; if (from<0 || to<0 || from>to || from>47 || to>47) luaL_error(L, "bit range invalid"); uint64_t mask = ~((uint64_t)-1 << (to-from+1)); set = (set & mask) << from; mask <<= from; what = what & ~mask | set; lua_pushlint(L,what); return 1; } static int luacall_u8(lua_State *L) { lua_check_argc_range(L,"u8",1,2); int argc=lua_gettop(L); size_t l; lua_Integer offset; const uint8_t *p = (uint8_t*)lua_reqlstring(L,1,&l); offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0; if (offset<0 || (offset+1)>l) luaL_error(L, "out of range"); lua_pushinteger(L,p[offset]); return 1; } static int luacall_u16(lua_State *L) { lua_check_argc_range(L,"u16",1,2); int argc=lua_gettop(L); size_t l; lua_Integer offset; const uint8_t *p = (uint8_t*)lua_reqlstring(L,1,&l); offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0; if (offset<0 || (offset+2)>l) luaL_error(L, "out of range"); lua_pushinteger(L,pntoh16(p+offset)); return 1; } static int luacall_u24(lua_State *L) { lua_check_argc_range(L,"u24",1,2); int argc=lua_gettop(L); size_t l; lua_Integer offset; const uint8_t *p = (uint8_t*)lua_reqlstring(L,1,&l); offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0; if (offset<0 || (offset+3)>l) luaL_error(L, "out of range"); lua_pushinteger(L,pntoh24(p+offset)); return 1; } static int luacall_u32(lua_State *L) { lua_check_argc_range(L,"u32",1,2); int argc=lua_gettop(L); size_t l; lua_Integer offset; const uint8_t *p = (uint8_t*)lua_reqlstring(L,1,&l); offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0; if (offset<0 || (offset+4)>l) luaL_error(L, "out of range"); lua_pushlint(L,pntoh32(p+offset)); return 1; } static int luacall_u48(lua_State *L) { lua_check_argc_range(L,"u48",1,2); int argc=lua_gettop(L); size_t l; lua_Integer offset; const uint8_t *p = (uint8_t*)lua_reqlstring(L,1,&l); offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0; if (offset<0 || (offset+6)>l) luaL_error(L, "out of range"); lua_pushlint(L,pntoh48(p+offset)); return 1; } static int luacall_swap16(lua_State *L) { lua_check_argc(L,"swap16",1); int64_t i = (int64_t)luaL_checklint(L,1); if (i>0xFFFF || i<-(int64_t)0xFFFF) luaL_error(L, "out of range"); uint16_t u = (uint16_t)i; lua_pushinteger(L,bswap16(u)); return 1; } static int luacall_swap24(lua_State *L) { lua_check_argc(L,"swap24",1); int64_t i =(int64_t)luaL_checklint(L,1); if (i>0xFFFFFF || i<-(int64_t)0xFFFFFF) luaL_error(L, "out of range"); uint32_t u = (uint32_t)i; lua_pushlint(L,bswap24(u)); return 1; } static int luacall_swap32(lua_State *L) { lua_check_argc(L,"swap32",1); int64_t i =(int64_t)luaL_checklint(L,1); if (i>0xFFFFFFFF || i<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range"); uint32_t u = (uint32_t)i; lua_pushlint(L,__builtin_bswap32(u)); return 1; } static int luacall_swap48(lua_State *L) { lua_check_argc(L,"swap48",1); int64_t i =(int64_t)luaL_checklint(L,1); if (i>0xFFFFFFFFFFFF || i<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); uint64_t u = (uint64_t)i; lua_pushlint(L, bswap48(u)); return 1; } static int lua_uxadd(lua_State *L, int64_t max) { int64_t v; uint64_t sum=0; int argc = lua_gettop(L); for(int i=1;i<=argc;i++) { v = (int64_t)luaL_checklint(L,i); if (v>max || v<-max) luaL_error(L, "out of range"); sum+=(uint64_t)v; } lua_pushlint(L, sum & max); return 1; } static int luacall_u8add(lua_State *L) { lua_check_argc_range(L,"u8add",1,100); return lua_uxadd(L, 0xFF); } static int luacall_u16add(lua_State *L) { lua_check_argc_range(L,"u16add",1,100); return lua_uxadd(L, 0xFFFF); } static int luacall_u24add(lua_State *L) { lua_check_argc_range(L,"u24add",1,100); return lua_uxadd(L, 0xFFFFFF); } static int luacall_u32add(lua_State *L) { lua_check_argc_range(L,"u32add",1,100); return lua_uxadd(L, 0xFFFFFFFF); } static int luacall_u48add(lua_State *L) { lua_check_argc_range(L,"u48add",1,100); return lua_uxadd(L, 0xFFFFFFFFFFFF); } static int luacall_bu8(lua_State *L) { lua_check_argc(L,"bu8",1); int64_t i = (int64_t)luaL_checklint(L,1); if (i>0xFF || i<-(lua_Integer)0xFF) luaL_error(L, "out of range"); uint8_t v=(uint8_t)i; lua_pushlstring(L,(char*)&v,1); return 1; } static int luacall_bu16(lua_State *L) { lua_check_argc(L,"bu16",1); int64_t i = (int64_t)luaL_checklint(L,1); if (i>0xFFFF || i<-(lua_Integer)0xFFFF) luaL_error(L, "out of range"); uint8_t v[2]; phton16(v,(uint16_t)i); lua_pushlstring(L,(char*)v,2); return 1; } static int luacall_bu24(lua_State *L) { lua_check_argc(L,"bu24",1); int64_t i = (int64_t)luaL_checklint(L,1); if (i>0xFFFFFF || i<-(lua_Integer)0xFFFFFF) luaL_error(L, "out of range"); uint8_t v[3]; phton24(v,(uint32_t)i); lua_pushlstring(L,(char*)v,3); return 1; } static int luacall_bu32(lua_State *L) { lua_check_argc(L,"bu32",1); int64_t i = (int64_t)luaL_checklint(L,1); if (i>0xFFFFFFFF || i<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range"); uint8_t v[4]; phton32(v,(uint32_t)i); lua_pushlstring(L,(char*)v,4); return 1; } static int luacall_bu48(lua_State *L) { lua_check_argc(L,"bu48",1); int64_t i = (int64_t)luaL_checklint(L,1); if (i>0xFFFFFFFFFFFF || i<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); uint8_t v[6]; phton48(v,(uint64_t)i); lua_pushlstring(L,(char*)v,6); return 1; } static int luacall_divint(lua_State *L) { lua_check_argc(L,"divint",2); int64_t v1=(int64_t)luaL_checklint(L,1); int64_t v2=(int64_t)luaL_checklint(L,2); if (v2) lua_pushlint(L,v1/v2); else lua_pushnil(L); return 1; } static int luacall_brandom(lua_State *L) { lua_check_argc(L,"brandom",1); LUA_STACK_GUARD_ENTER(L) lua_Integer len = luaL_checkinteger(L,1); if (len<0) luaL_error(L, "brandom: invalid arg"); uint8_t *p = lua_newuserdata(L, len); fill_random_bytes(p,len); lua_pushlstring(L,(char*)p,len); lua_remove(L,-2); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_brandom_az(lua_State *L) { lua_check_argc(L,"brandom_az",1); LUA_STACK_GUARD_ENTER(L) lua_Integer len = luaL_checkinteger(L,1); if (len<0) luaL_error(L, "brandom: invalid arg"); uint8_t *p = lua_newuserdata(L, len); fill_random_az(p,len); lua_pushlstring(L,(char*)p,len); lua_remove(L,-2); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_brandom_az09(lua_State *L) { lua_check_argc(L,"brandom_az09",1); LUA_STACK_GUARD_ENTER(L) lua_Integer len = luaL_checkinteger(L,1); if (len<0) luaL_error(L, "brandom: invalid arg"); uint8_t *p = lua_newuserdata(L, len); fill_random_az09(p,len); lua_pushlstring(L,(char*)p,len); lua_remove(L,-2); LUA_STACK_GUARD_RETURN(L,1) } // hacky function. breaks immutable string behavior. // if you change a string, it will change in all variables that hold the same string /* static int luacall_memcpy(lua_State *L) { // memcpy(to,to_offset,from,from_offset,size) lua_check_argc_range(L,"memcpy",3,5); size_t lfrom,lto; lua_Integer off_from,off_to,size; int argc=lua_gettop(L); const uint8_t *from = (uint8_t*)luaL_checklstring(L,3,&lfrom); uint8_t *to = (uint8_t*)luaL_checklstring(L,1,<o); off_from = argc>=4 ? luaL_checkinteger(L,4)-1 : 0; off_to = luaL_checkinteger(L,2)-1; if (off_from<0 || off_to<0 || off_from>lfrom || off_to>lto) luaL_error(L, "out of range"); size = argc>=5 ? luaL_checkinteger(L,5) : lfrom-off_from; if (size<0 || (off_from+size)>lfrom || (off_to+size)>lto) luaL_error(L, "out of range"); memcpy(to+off_to,from+off_from,size); return 0; } */ static int luacall_parse_hex(lua_State *L) { lua_check_argc(L,"parse_hex",1); LUA_STACK_GUARD_ENTER(L) size_t l; const char *hex = lua_reqlstring(L,1,&l); if ((l&1)) goto err; l>>=1; uint8_t *p = lua_newuserdata(L, l); if (!parse_hex_str(hex,p,&l)) { lua_pop(L,1); goto err; } lua_pushlstring(L,(char*)p,l); lua_remove(L,-2); ex: LUA_STACK_GUARD_RETURN(L,1) err: lua_pushnil(L); goto ex; } static SHAversion lua_hash_type(lua_State *L, const char *s_hash_type) { SHAversion sha_ver; if (!strcmp(s_hash_type,"sha256")) sha_ver = SHA256; else if (!strcmp(s_hash_type,"sha224")) sha_ver = SHA224; else luaL_error(L, "unsupported hash type %s", s_hash_type); return sha_ver; } static int luacall_bcryptorandom(lua_State *L) { lua_check_argc(L,"bcryptorandom",1); LUA_STACK_GUARD_ENTER(L) lua_Integer len = luaL_checkinteger(L,1); if (len<0) luaL_error(L, "bcryptorandom: invalid arg"); uint8_t *p = lua_newuserdata(L, len); if (!fill_crypto_random_bytes(p,len)) { // this is fatal. they expect us to give them crypto secure random blob luaL_error(L, "could not get entropy bytes"); } lua_pushlstring(L,(char*)p,len); lua_remove(L,-2); LUA_STACK_GUARD_RETURN(L,1) } static int luac_bop(lua_State *L, const char *name, void (*op)(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz)) { lua_check_argc(L,name,2); LUA_STACK_GUARD_ENTER(L) size_t sz1,sz2; const uint8_t *d1 = (const uint8_t*)lua_reqlstring(L,1,&sz1); const uint8_t *d2 = (const uint8_t*)lua_reqlstring(L,2,&sz2); if (sz1!=sz2) luaL_error(L, "string lengths must be the same\n"); uint8_t *d3 = lua_newuserdata(L, sz1); op(d1,d2,d3,sz1); lua_pushlstring(L,(char*)d3,sz1); lua_remove(L,-2); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_bxor(lua_State *L) { return luac_bop(L,"bxor",bxor); } static int luacall_bor(lua_State *L) { return luac_bop(L,"bor",bor); } static int luacall_band(lua_State *L) { return luac_bop(L,"band",band); } static int luacall_hash(lua_State *L) { // hash(hash_type, data) returns hash lua_check_argc(L,"hash",2); LUA_STACK_GUARD_ENTER(L) const char *s_hash_type = luaL_checkstring(L,1); SHAversion sha_ver = lua_hash_type(L, s_hash_type); size_t data_len; const uint8_t *data = (uint8_t*)lua_reqlstring(L,2,&data_len); unsigned char hash[USHAMaxHashSize]; USHAContext tcontext; if (USHAReset(&tcontext, sha_ver)!=shaSuccess || USHAInput(&tcontext, data, data_len)!=shaSuccess || USHAResult(&tcontext, hash)!=shaSuccess) luaL_error(L, "hash failure"); lua_pushlstring(L,(char*)hash,USHAHashSize(sha_ver)); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_aes(lua_State *L) { // aes(bEncrypt, key, in) returns out lua_check_argc(L,"aes",3); LUA_STACK_GUARD_ENTER(L) bool bEncrypt = lua_toboolean(L,1); size_t key_len; const uint8_t *key = (uint8_t*)lua_reqlstring(L,2,&key_len); if (key_len!=16 && key_len!=24 && key_len!=32) luaL_error(L, "aes: wrong key length %u. should be 16,24,32.", (unsigned)key_len); size_t input_len; const uint8_t *input = (uint8_t*)lua_reqlstring(L,3,&input_len); if (input_len!=16) luaL_error(L, "aes: wrong data length %u. should be 16.", (unsigned)input_len); aes_context ctx; uint8_t output[16]; if (aes_setkey(&ctx, bEncrypt, key, key_len) || aes_cipher(&ctx, input, output)) lua_pushnil(L); else lua_pushlstring(L,(const char*)output,sizeof(output)); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_aes_gcm(lua_State *L) { // aes_gcm(bEncrypt, key, iv, in, [additional_data]) returns out, atag lua_check_argc_range(L,"aes_gcm",4,5); LUA_STACK_GUARD_ENTER(L) int argc = lua_gettop(L); bool bEncrypt = lua_toboolean(L,1); size_t key_len; const uint8_t *key = (uint8_t*)lua_reqlstring(L,2,&key_len); if (key_len!=16 && key_len!=24 && key_len!=32) luaL_error(L, "aes_gcm: wrong key length %u. should be 16,24,32.", (unsigned)key_len); size_t iv_len; const uint8_t *iv = (uint8_t*)lua_reqlstring(L,3,&iv_len); if (!iv_len) luaL_error(L, "aes_gcm: zero iv length"); size_t input_len; const uint8_t *input = (uint8_t*)lua_reqlstring(L,4,&input_len); size_t add_len=0; const uint8_t *add = lua_isnoneornil(L,5) ? NULL : (uint8_t*)lua_reqlstring(L,5,&add_len); uint8_t atag[16]; uint8_t *output = lua_newuserdata(L, input_len); if (aes_gcm_crypt(bEncrypt, output, input, input_len, key, key_len, iv, iv_len, add, add_len, atag, sizeof(atag))) { lua_pushnil(L); lua_pushnil(L); } else { lua_pushlstring(L,(const char*)output,input_len); lua_pushlstring(L,(const char*)atag,sizeof(atag)); } lua_remove(L,-3); LUA_STACK_GUARD_RETURN(L,2) } static int luacall_aes_ctr(lua_State *L) { // aes_ctr(key, iv, in) returns out lua_check_argc(L,"aes_ctr",3); LUA_STACK_GUARD_ENTER(L) size_t key_len; const uint8_t *key = (uint8_t*)lua_reqlstring(L,1,&key_len); if (key_len!=16 && key_len!=24 && key_len!=32) luaL_error(L, "aes_ctr: wrong key length %u. should be 16,24,32.", (unsigned)key_len); size_t iv_len; const uint8_t *iv = (uint8_t*)lua_reqlstring(L,2,&iv_len); if (iv_len!=16) luaL_error(L, "aes_ctr: wrong iv length %u. should be 16.", (unsigned)iv_len); size_t input_len; const uint8_t *input = (uint8_t*)luaL_checklstring(L,3,&input_len); uint8_t *output = lua_newuserdata(L, input_len); if (aes_ctr_crypt(key, key_len, iv, input, input_len, output)) lua_pushnil(L); else lua_pushlstring(L,(const char*)output,input_len); lua_remove(L,-2); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_hkdf(lua_State *L) { // hkdf(hash_type, salt, ikm, info, okm_len) returns okm // hash_type - string "sha224" or "sha256" lua_check_argc(L,"hkdf",5); LUA_STACK_GUARD_ENTER(L) const char *s_hash_type = luaL_checkstring(L,1); SHAversion sha_ver = lua_hash_type(L, s_hash_type); size_t salt_len=0; const uint8_t *salt = lua_type(L,2) == LUA_TNIL ? NULL : (uint8_t*)luaL_checklstring(L,2,&salt_len); size_t ikm_len=0; const uint8_t *ikm = lua_type(L,3) == LUA_TNIL ? NULL : (uint8_t*)luaL_checklstring(L,3,&ikm_len); size_t info_len=0; const uint8_t *info = lua_type(L,4) == LUA_TNIL ? NULL : (uint8_t*)luaL_checklstring(L,4,&info_len); lua_Integer okm_len = luaL_checkinteger(L,5); if (okm_len<0) luaL_error(L, "hkdf: invalid arg"); uint8_t *okm = lua_newuserdata(L, okm_len); if (hkdf(sha_ver, salt, salt_len, ikm, ikm_len, info, info_len, okm, okm_len)) lua_pushnil(L); else lua_pushlstring(L,(const char*)okm, okm_len); lua_remove(L,-2); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_getpid(lua_State *L) { lua_check_argc(L,"getpid", 0); lua_pushinteger(L, getpid()); return 1; } static int luacall_gettid(lua_State *L) { lua_check_argc(L,"gettid", 0); #ifdef __OpenBSD__ lua_pushinteger(L, getthrid()); #elif defined(__FreeBSD__) long tid; if (thr_self(&tid)) lua_pushnil(L); else lua_pushinteger(L, tid); #elif defined(__linux__) lua_pushinteger(L, syscall(SYS_gettid)); #elif defined(__CYGWIN__) lua_pushinteger(L, GetCurrentThreadId()); #else // unsupported OS ? lua_pushnil(L); #endif return 1; } static int luacall_uname(lua_State *L) { lua_check_argc(L,"uname", 0); LUA_STACK_GUARD_ENTER(L) struct utsname udata; if (uname(&udata)) lua_pushnil(L); else { lua_createtable(L, 0, 5); lua_pushf_str(L,"sysname", udata.sysname); lua_pushf_str(L,"nodename", udata.nodename); lua_pushf_str(L,"release", udata.release); lua_pushf_str(L,"version", udata.version); lua_pushf_str(L,"machine", udata.machine); } LUA_STACK_GUARD_RETURN(L,1) } static int luacall_clock_gettime(lua_State *L) { lua_check_argc(L,"clock_gettime", 0); LUA_STACK_GUARD_ENTER(L) struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts)) { lua_pushnil(L); lua_pushnil(L); } else { lua_pushlint(L, ts.tv_sec); lua_pushinteger(L, ts.tv_nsec); } LUA_STACK_GUARD_RETURN(L,2) } static int luacall_clock_getfloattime(lua_State *L) { lua_check_argc(L,"clock_getfloattime", 0); LUA_STACK_GUARD_ENTER(L) struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts)) lua_pushnil(L); else lua_pushnumber(L, ts.tv_sec + ts.tv_nsec/1000000000.); LUA_STACK_GUARD_RETURN(L,1) } static void lua_mt_init_desync_ctx(lua_State *L) { luaL_newmetatable(L, "desync_ctx"); lua_pop(L, 1); } static t_lua_desync_context *lua_desync_ctx(lua_State *L) { if (lua_isnil(L,1)) luaL_error(L, "missing ctx"); t_lua_desync_context *ctx = (t_lua_desync_context *)luaL_checkudata(L, 1, "desync_ctx"); if (!ctx->valid) luaL_error(L, "ctx is invalid"); return ctx; } static void lua_desync_ctx_create(lua_State *L) { if (!params.ref_desync_ctx) { LUA_STACK_GUARD_ENTER(L) t_lua_desync_context *ctx = (t_lua_desync_context *)lua_newuserdata(L, sizeof(t_lua_desync_context)); memset(ctx, 0, sizeof(*ctx)); luaL_getmetatable(L, "desync_ctx"); lua_setmetatable(L, -2); params.ref_desync_ctx = luaL_ref(params.L, LUA_REGISTRYINDEX); LUA_STACK_GUARD_LEAVE(L,0) } } static void lua_desync_ctx_destroy(lua_State *L) { if (params.ref_desync_ctx) { luaL_unref(L, LUA_REGISTRYINDEX, params.ref_desync_ctx); params.ref_desync_ctx = 0; } } static int luacall_instance_cutoff(lua_State *L) { // out : instance_name.profile_number[0] // in : instance_name.profile_number[1] lua_check_argc_range(L,"instance_cutoff",1,2); LUA_STACK_GUARD_ENTER(L) if (lua_isnil(L,1)) // this can happen in orchestrated function. they do not have their own ctx and they cant cutoff DLOG("instance cutoff not possible because missing ctx\n"); else { const t_lua_desync_context *ctx = lua_desync_ctx(L); int argc=lua_gettop(L); bool bIn,bOut; if (argc>=2 && lua_type(L,2)!=LUA_TNIL) { luaL_checktype(L,2,LUA_TBOOLEAN); bOut = lua_toboolean(L,2); bIn = !bOut; } else bIn = bOut = true; if (ctx->ctrack) { DLOG("instance cutoff for '%s' in=%u out=%u\n",ctx->instance,bIn,bOut); lua_rawgeti(L,LUA_REGISTRYINDEX,ctx->ctrack->lua_instance_cutoff); lua_getfield(L,-1,ctx->instance); if (!lua_istable(L,-1)) { lua_pop(L,1); lua_pushf_table(L,ctx->instance); lua_getfield(L,-1,ctx->instance); } lua_rawgeti(L,-1,ctx->dp->n); if (!lua_istable(L,-1)) { lua_pop(L,1); lua_pushi_table(L,ctx->dp->n); lua_rawgeti(L,-1,ctx->dp->n); } if (bOut) lua_pushi_bool(L,0,true); if (bIn) lua_pushi_bool(L,1,true); lua_pop(L,3); } else DLOG("instance cutoff requested for '%s' in=%u out=%u but not possible without conntrack\n",ctx->instance,bIn,bOut); } LUA_STACK_GUARD_RETURN(L,0) } bool lua_instance_cutoff_check(lua_State *L, const t_lua_desync_context *ctx, bool bIn) { bool b=false; // out : func_name.profile_number[0] // in : func_name.profile_number[1] if (ctx->ctrack) { lua_rawgeti(L,LUA_REGISTRYINDEX,ctx->ctrack->lua_instance_cutoff); lua_getfield(L,-1,ctx->instance); if (!lua_istable(L,-1)) { lua_pop(L,2); return false; } lua_rawgeti(L,-1,ctx->dp->n); if (!lua_istable(L,-1)) { lua_pop(L,3); return false; } lua_rawgeti(L,-1,bIn); b = lua_toboolean(L,-1); lua_pop(L,4); } return b; } static int luacall_lua_cutoff(lua_State *L) { lua_check_argc_range(L,"lua_cutoff",1,2); LUA_STACK_GUARD_ENTER(L) t_lua_desync_context *ctx = lua_desync_ctx(L); int argc=lua_gettop(L); bool bIn,bOut; if (argc>=2 && lua_type(L,2)!=LUA_TNIL) { luaL_checktype(L,2,LUA_TBOOLEAN); bOut = lua_toboolean(L,2); bIn = !bOut; } else bIn = bOut = true; if (ctx->ctrack) { DLOG("lua cutoff from '%s' in=%u out=%u\n",ctx->instance,bIn,bOut); // lua cutoff is one way transition if (bIn) ctx->ctrack->b_lua_in_cutoff = true; if (bOut) ctx->ctrack->b_lua_out_cutoff = true; } else DLOG("lua cutoff requested from '%s' in=%u out=%u but not possible without conntrack\n",ctx->instance,bIn,bOut); LUA_STACK_GUARD_RETURN(L,0) } static int luacall_execution_plan(lua_State *L) { lua_check_argc(L,"execution_plan",1); LUA_STACK_GUARD_ENTER(L) t_lua_desync_context *ctx = lua_desync_ctx(L); lua_newtable(L); struct func_list *func; char instance[256], plsl[2048]; struct packet_range *range; unsigned int n=1; t_l7payload pl; const char *pls; LIST_FOREACH(func, &ctx->dp->lua_desync, next) { if (n > ctx->func_n) { desync_instance(func->func, ctx->dp->n, n, instance, sizeof(instance)); range = ctx->incoming ? &func->range_in : &func->range_out; lua_pushinteger(L, n - ctx->func_n); lua_createtable(L, 0, 7); lua_pushf_args(L,&func->args, -1, false); lua_pushf_str(L,"func", func->func); lua_pushf_int(L,"func_n", n); lua_pushf_str(L,"func_instance", instance); lua_pushf_range(L,"range", range); lua_pushstring(L, "payload"); lua_newtable(L); if (func->payload_type==L7P_ALL) { lua_pushliteral(L,"all"); lua_pushboolean(L,true); lua_rawset(L,-3); } else { for (pl=0 ; plpayload_type & (1ULL<payload_type, plsl, sizeof(plsl))) lua_pushf_str(L,"payload_filter", plsl); else lua_pushf_nil(L,"payload_filter"); lua_rawset(L,-3); } n++; } LUA_STACK_GUARD_RETURN(L,1) } static int luacall_execution_plan_cancel(lua_State *L) { lua_check_argc(L,"execution_plan_cancel",1); t_lua_desync_context *ctx = lua_desync_ctx(L); DLOG("execution plan cancel from '%s'\n",ctx->instance); ctx->cancel = true; return 0; } static int luacall_raw_packet(lua_State *L) { lua_check_argc(L,"raw_packet",1); LUA_STACK_GUARD_ENTER(L) const t_lua_desync_context *ctx = lua_desync_ctx(L); lua_pushlstring(L, (const char*)ctx->dis->data_pkt, ctx->dis->len_pkt); LUA_STACK_GUARD_RETURN(L,1) } void lua_pushf_nil(lua_State *L, const char *field) { lua_pushstring(L, field); lua_pushnil(L); lua_rawset(L,-3); } void lua_pushi_nil(lua_State *L, lua_Integer idx) { lua_pushinteger(L, idx); lua_pushnil(L); lua_rawset(L,-3); } void lua_pushf_int(lua_State *L, const char *field, lua_Integer v) { lua_pushstring(L, field); lua_pushlint(L, v); lua_rawset(L,-3); } void lua_pushi_int(lua_State *L, lua_Integer idx, lua_Integer v) { lua_pushinteger(L, idx); lua_pushlint(L, v); lua_rawset(L,-3); } void lua_pushf_lint(lua_State *L, const char *field, int64_t v) { lua_pushstring(L, field); lua_pushlint(L, v); lua_rawset(L,-3); } void lua_pushi_lint(lua_State *L, lua_Integer idx, int64_t v) { lua_pushinteger(L, idx); lua_pushlint(L, v); lua_rawset(L,-3); } void lua_pushf_number(lua_State *L, const char *field, lua_Number v) { lua_pushstring(L, field); lua_pushnumber(L, v); lua_rawset(L,-3); } void lua_pushi_number(lua_State *L, lua_Integer idx, lua_Number v) { lua_pushinteger(L, idx); lua_pushnumber(L, v); lua_rawset(L,-3); } void lua_pushf_bool(lua_State *L, const char *field, bool b) { lua_pushstring(L, field); lua_pushboolean(L, b); lua_rawset(L,-3); } void lua_pushi_bool(lua_State *L, lua_Integer idx, bool b) { lua_pushinteger(L, idx); lua_pushboolean(L, b); lua_rawset(L,-3); } void lua_pushf_str(lua_State *L, const char *field, const char *str) { lua_pushstring(L, field); lua_pushstring(L, str); // pushes nil if str==NULL lua_rawset(L,-3); } void lua_pushi_str(lua_State *L, lua_Integer idx, const char *str) { lua_pushinteger(L, idx); lua_pushstring(L, str); // pushes nil if str==NULL lua_rawset(L,-3); } void lua_pushf_lstr(lua_State *L, const char *field, const char *str, size_t size) { lua_pushstring(L, field); lua_pushlstring(L, str, size); lua_rawset(L,-3); } void lua_pushi_lstr(lua_State *L, lua_Integer idx, const char *str, size_t size) { lua_pushinteger(L, idx); lua_pushlstring(L, str, size); lua_rawset(L,-3); } void lua_push_raw(lua_State *L, const void *v, size_t l) { if (v) lua_pushlstring(L, (char*)v, l); else lua_pushnil(L); } void lua_pushf_raw(lua_State *L, const char *field, const void *v, size_t l) { lua_pushstring(L, field); lua_push_raw(L, v,l); lua_rawset(L,-3); } void lua_pushi_raw(lua_State *L, lua_Integer idx, const void *v, size_t l) { lua_pushinteger(L, idx); lua_push_raw(L,v,l); lua_rawset(L,-3); } void lua_pushf_reg(lua_State *L, const char *field, int ref) { lua_pushstring(L, field); lua_rawgeti(L, LUA_REGISTRYINDEX, ref); lua_rawset(L, -3); } void lua_pushf_lud(lua_State *L, const char *field, void *p) { lua_pushstring(L, field); lua_pushlightuserdata(L, p); lua_rawset(L,-3); } void lua_pushf_table(lua_State *L, const char *field) { lua_pushstring(L, field); lua_newtable(L); lua_rawset(L,-3); } void lua_pushi_table(lua_State *L, lua_Integer idx) { lua_pushinteger(L, idx); lua_newtable(L); lua_rawset(L,-3); } void lua_pushf_global(lua_State *L, const char *field, const char *global) { lua_pushstring(L, field); lua_getglobal(L, global); lua_rawset(L,-3); } void lua_push_blob(lua_State *L, int idx_desync, const char *blob) { lua_getfield(L, idx_desync, blob); if (lua_type(L,-1)==LUA_TNIL) { lua_pop(L,1); lua_getglobal(L, blob); } lua_tostring(L,-1); } void lua_pushf_blob(lua_State *L, int idx_desync, const char *field, const char *blob) { lua_pushstring(L, field); lua_push_blob(L, idx_desync, blob); lua_rawset(L,-3); } void lua_push_ipaddr(lua_State *L, const struct sockaddr *sa) { switch(sa ? sa->sa_family : 0) { case AF_INET: lua_pushlstring(L, (const char*)&((struct sockaddr_in*)sa)->sin_addr, sizeof(struct in_addr)); break; case AF_INET6: lua_pushlstring(L, (const char*)&((struct sockaddr_in6*)sa)->sin6_addr, sizeof(struct in6_addr)); break; default: lua_pushnil(L); } } void lua_pushf_ipaddr(lua_State *L, const char *field, const struct sockaddr *sa) { lua_pushstring(L, field); lua_push_ipaddr(L,sa); lua_rawset(L,-3); } void lua_pushi_ipaddr(lua_State *L, lua_Integer idx, const struct sockaddr *sa) { lua_pushinteger(L, idx); lua_push_ipaddr(L,sa); lua_rawset(L,-3); } void lua_pushf_tcphdr_options(lua_State *L, const struct tcphdr *tcp, size_t len) { LUA_STACK_GUARD_ENTER(L) lua_pushliteral(L,"options"); lua_newtable(L); uint8_t *t = (uint8_t*)(tcp+1); uint8_t *end = (uint8_t*)tcp + (tcp->th_off<<2); uint8_t opt; if ((end-(uint8_t*)tcp) > len) end=(uint8_t*)tcp + len; lua_Integer idx=1; while(t=end || t[1]<2 || (t+t[1])>end) break; lua_pushinteger(L,idx); lua_newtable(L); lua_pushf_int(L,"kind",opt); lua_pushf_raw(L,"data",t+2,t[1]-2); t+=t[1]; } lua_rawset(L,-3); if (opt==TCP_KIND_END) break; idx++; } lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } void lua_push_tcphdr(lua_State *L, const struct tcphdr *tcp, size_t len) { LUA_STACK_GUARD_ENTER(L) if (tcp && len>=sizeof(struct tcphdr)) { lua_createtable(L, 0, 11); lua_pushf_int(L,"th_sport",ntohs(tcp->th_sport)); lua_pushf_int(L,"th_dport",ntohs(tcp->th_dport)); lua_pushf_lint(L,"th_seq",ntohl(tcp->th_seq)); lua_pushf_lint(L,"th_ack",ntohl(tcp->th_ack)); lua_pushf_int(L,"th_x2",tcp->th_x2); lua_pushf_int(L,"th_off",tcp->th_off); lua_pushf_int(L,"th_flags",tcp->th_flags); lua_pushf_int(L,"th_win",ntohs(tcp->th_win)); lua_pushf_int(L,"th_sum",ntohs(tcp->th_sum)); lua_pushf_int(L,"th_urp",ntohs(tcp->th_urp)); lua_pushf_tcphdr_options(L,tcp,len); } else lua_pushnil(L); LUA_STACK_GUARD_LEAVE(L, 1) } void lua_pushf_tcphdr(lua_State *L, const struct tcphdr *tcp, size_t len) { LUA_STACK_GUARD_ENTER(L) lua_pushliteral(L, "tcp"); lua_push_tcphdr(L,tcp,len); lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } static int luacall_dissect_tcphdr(lua_State *L) { // dissect_tcphdr(tcphdr_data) lua_check_argc(L,"dissect_tcphdr",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); lua_push_tcphdr(L, (struct tcphdr*)data, len); LUA_STACK_GUARD_RETURN(L,1) } void lua_push_udphdr(lua_State *L, const struct udphdr *udp, size_t len) { LUA_STACK_GUARD_ENTER(L) if (udp && len>=sizeof(struct udphdr)) { lua_createtable(L, 0, 4); lua_pushf_int(L,"uh_sport",ntohs(udp->uh_sport)); lua_pushf_int(L,"uh_dport",ntohs(udp->uh_dport)); lua_pushf_int(L,"uh_ulen",ntohs(udp->uh_ulen)); lua_pushf_int(L,"uh_sum",ntohs(udp->uh_sum)); } else lua_pushnil(L); LUA_STACK_GUARD_LEAVE(L, 1) } void lua_pushf_udphdr(lua_State *L, const struct udphdr *udp, size_t len) { LUA_STACK_GUARD_ENTER(L) lua_pushliteral(L, "udp"); lua_push_udphdr(L,udp,len); lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } static int luacall_dissect_udphdr(lua_State *L) { // dissect_udphdr(udphdr_data) lua_check_argc(L,"dissect_udphdr",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); lua_push_udphdr(L, (struct udphdr*)data, len); LUA_STACK_GUARD_RETURN(L,1) } void lua_push_icmphdr(lua_State *L, const struct icmp46 *icmp, size_t len) { LUA_STACK_GUARD_ENTER(L) if (icmp && len>=sizeof(struct icmp46)) { lua_createtable(L, 0, 4); lua_pushf_int(L,"icmp_type",icmp->icmp_type); lua_pushf_int(L,"icmp_code",icmp->icmp_code); lua_pushf_int(L,"icmp_cksum",ntohs(icmp->icmp_cksum)); lua_pushf_lint(L,"icmp_data",ntohl(icmp->data.data32)); } else lua_pushnil(L); LUA_STACK_GUARD_LEAVE(L, 1) } void lua_pushf_icmphdr(lua_State *L, const struct icmp46 *icmp, size_t len) { LUA_STACK_GUARD_ENTER(L) lua_pushliteral(L, "icmp"); lua_push_icmphdr(L,icmp,len); lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } static int luacall_dissect_icmphdr(lua_State *L) { // dissect_icmphdr(icmphdr_data) lua_check_argc(L,"dissect_icmphdr",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); lua_push_icmphdr(L, (struct icmp46*)data, len); LUA_STACK_GUARD_RETURN(L,1) } void lua_push_iphdr(lua_State *L, const struct ip *ip, size_t len) { LUA_STACK_GUARD_ENTER(L) if (ip && len>=sizeof(struct ip)) { uint16_t hl = ip->ip_hl<<2; bool b_has_opt = hl>sizeof(struct ip) && hl<=len; lua_createtable(L, 0, 11+b_has_opt); lua_pushf_int(L,"ip_v",ip->ip_v); lua_pushf_int(L,"ip_hl",ip->ip_hl); lua_pushf_int(L,"ip_tos",ip->ip_tos); lua_pushf_int(L,"ip_len",ntohs(ip->ip_len)); lua_pushf_int(L,"ip_id",ntohs(ip->ip_id)); lua_pushf_int(L,"ip_off",ntohs(ip->ip_off)); lua_pushf_int(L,"ip_ttl",ip->ip_ttl); lua_pushf_int(L,"ip_p",ip->ip_p); lua_pushf_int(L,"ip_sum",ntohs(ip->ip_sum)); lua_pushf_raw(L,"ip_src",&ip->ip_src,sizeof(struct in_addr)); lua_pushf_raw(L,"ip_dst",&ip->ip_dst,sizeof(struct in_addr)); if (b_has_opt) lua_pushf_raw(L,"options",(uint8_t*)(ip+1),hl-sizeof(struct ip)); } else lua_pushnil(L); LUA_STACK_GUARD_LEAVE(L, 1) } void lua_pushf_iphdr(lua_State *L, const struct ip *ip, size_t len) { LUA_STACK_GUARD_ENTER(L) lua_pushliteral(L, "ip"); lua_push_iphdr(L,ip,len); lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } static int luacall_dissect_iphdr(lua_State *L) { // dissect_iphdr(iphdr_data) lua_check_argc(L,"dissect_iphdr",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); lua_push_iphdr(L, (struct ip*)data, len); LUA_STACK_GUARD_RETURN(L,1) } void lua_pushf_ip6exthdr(lua_State *L, const struct ip6_hdr *ip6, size_t len) { LUA_STACK_GUARD_ENTER(L); // assume ipv6 packet structure was already checked for validity size_t hdrlen; lua_Integer idx = 1; uint8_t HeaderType, *data; uint16_t plen; uint16_t fr_off=0; bool fr=false; lua_pushliteral(L, "exthdr"); lua_newtable(L); if (len>=sizeof(struct ip6_hdr)) { HeaderType = ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt; data=(uint8_t*)(ip6+1); len-=sizeof(struct ip6_hdr); plen = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); if (plen < len) len = plen; while (len && !(fr && fr_off)) // need at least one byte for NextHeader field. stop after fragment header if not first fragment { switch (HeaderType) { case IPPROTO_HOPOPTS: case IPPROTO_ROUTING: case IPPROTO_DSTOPTS: case IPPROTO_MH: // mobility header case IPPROTO_HIP: // Host Identity Protocol Version v2 case IPPROTO_SHIM6: if (len < 2) goto end; // error hdrlen = 8 + (data[1] << 3); break; case IPPROTO_FRAGMENT: // fragment. length fixed to 8, hdrlen field defined as reserved hdrlen = 8; if (len < hdrlen) goto end; fr_off = ntohs(((struct ip6_frag*)data)->ip6f_offlg & IP6F_OFF_MASK); fr = ((struct ip6_frag*)data)->ip6f_offlg & (IP6F_OFF_MASK|IP6F_MORE_FRAG); break; case IPPROTO_AH: // special case. length in ah header is in 32-bit words minus 2 if (len < 2) goto end; // error hdrlen = 8 + (data[1] << 2); break; case IPPROTO_NONE: // no next header default: // we found some meaningful payload. it can be tcp, udp, icmp or some another exotic shit goto end; } if (len < hdrlen) goto end; // error lua_pushinteger(L, idx++); lua_createtable(L, 0, 3); lua_pushf_int(L,"type", HeaderType); HeaderType = *data; lua_pushf_int(L,"next", HeaderType); lua_pushf_raw(L,"data",data+2,hdrlen-2); lua_rawset(L,-3); // advance to the next header location len -= hdrlen; data += hdrlen; } } end: lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } void lua_push_ip6hdr(lua_State *L, const struct ip6_hdr *ip6, size_t len) { LUA_STACK_GUARD_ENTER(L) if (ip6 && len>=sizeof(struct ip6_hdr)) { lua_createtable(L, 0, 7); lua_pushf_lint(L,"ip6_flow",ntohl(ip6->ip6_ctlun.ip6_un1.ip6_un1_flow)); lua_pushf_lint(L,"ip6_plen",ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen)); lua_pushf_int(L,"ip6_nxt",ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt); lua_pushf_int(L,"ip6_hlim",ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim); lua_pushf_raw(L,"ip6_src",&ip6->ip6_src,sizeof(struct in6_addr)); lua_pushf_raw(L,"ip6_dst",&ip6->ip6_dst,sizeof(struct in6_addr)); lua_pushf_ip6exthdr(L,ip6,len); } else lua_pushnil(L); LUA_STACK_GUARD_LEAVE(L, 1) } void lua_pushf_ip6hdr(lua_State *L, const struct ip6_hdr *ip6, size_t len) { LUA_STACK_GUARD_ENTER(L) lua_pushliteral(L, "ip6"); lua_push_ip6hdr(L,ip6,len); lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } static int luacall_dissect_ip6hdr(lua_State *L) { // dissect_iphdr(ip6hdr_data) lua_check_argc(L,"dissect_ip6hdr",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); lua_push_ip6hdr(L, (struct ip6_hdr*)data, len); LUA_STACK_GUARD_RETURN(L,1) } void lua_push_dissect(lua_State *L, const struct dissect *dis) { LUA_STACK_GUARD_ENTER(L) if (dis) { lua_createtable(L, 0, 10+dis->frag); lua_pushf_int(L,"l4proto",dis->proto); lua_pushf_int(L,"transport_len",dis->transport_len); lua_pushf_int(L,"l3_len",dis->len_l3); lua_pushf_int(L,"l4_len",dis->len_l4); lua_pushf_raw(L,"payload",dis->data_payload,dis->len_payload); if (dis->frag) lua_pushf_int(L,"frag_off",dis->frag_off); lua_pushf_iphdr(L,dis->ip, dis->len_l3); lua_pushf_ip6hdr(L,dis->ip6, dis->len_l3); lua_pushf_tcphdr(L,dis->tcp, dis->len_l4); lua_pushf_udphdr(L,dis->udp, dis->len_l4); lua_pushf_icmphdr(L,dis->icmp, dis->len_l4); } else lua_pushnil(L); LUA_STACK_GUARD_LEAVE(L, 1) } void lua_pushf_dissect(lua_State *L, const struct dissect *dis) { lua_pushliteral(L, "dis"); lua_push_dissect(L, dis); lua_rawset(L,-3); } void lua_pushf_ctrack_pos(lua_State *L, const t_ctrack *ctrack, const t_ctrack_position *pos) { LUA_STACK_GUARD_ENTER(L) lua_pushf_lint(L,"pcounter", pos->pcounter); lua_pushf_lint(L,"pdcounter", pos->pdcounter); lua_pushf_lint(L,"pbcounter", pos->pbcounter); if (pos->ip6flow) lua_pushf_int(L,"ip6_flow", pos->ip6flow); if (ctrack->pos.ipproto == IPPROTO_TCP) { lua_pushliteral(L, "tcp"); lua_createtable(L, 0, 11); lua_pushf_lint(L,"seq0", pos->seq0); lua_pushf_lint(L,"seq", pos->seq_last); lua_pushf_lint(L,"rseq", pos->seq_last - pos->seq0); lua_pushf_bool(L,"rseq_over_2G", pos->rseq_over_2G); lua_pushf_int(L,"pos", pos->pos - pos->seq0); lua_pushf_int(L,"uppos", pos->uppos - pos->seq0); lua_pushf_int(L,"uppos_prev", pos->uppos_prev - pos->seq0); lua_pushf_int(L,"winsize", pos->winsize); lua_pushf_int(L,"winsize_calc", pos->winsize_calc); lua_pushf_int(L,"scale", pos->scale); lua_pushf_int(L,"mss", pos->mss); lua_rawset(L,-3); } LUA_STACK_GUARD_LEAVE(L, 0) } void lua_push_ctrack(lua_State *L, const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming) { LUA_STACK_GUARD_ENTER(L) if (ctrack) { if (!tpos) tpos = &ctrack->pos; lua_createtable(L, 0, 9); if (ctrack->incoming_ttl) lua_pushf_int(L, "incoming_ttl", ctrack->incoming_ttl); lua_pushf_str(L, "l7proto", l7proto_str(ctrack->l7proto)); lua_pushf_str(L, "hostname", ctrack->hostname); if (ctrack->hostname) lua_pushf_bool(L, "hostname_is_ip", ctrack->hostname_is_ip); lua_pushf_reg(L, "lua_state", ctrack->lua_state); lua_pushf_bool(L, "lua_in_cutoff", ctrack->b_lua_in_cutoff); lua_pushf_bool(L, "lua_out_cutoff", ctrack->b_lua_out_cutoff); lua_pushf_number(L, "t_start", (lua_Number)ctrack->t_start.tv_sec + ctrack->t_start.tv_nsec/1000000000.); lua_pushliteral(L, "pos"); lua_createtable(L, 0, 5); // orig, reply related to connection logical direction // for tcp orig is client (who connects), reply is server (who listens). // for orig is the first seen party, reply is another party lua_pushf_number(L, "dt", (lua_Number)tpos->t_last.tv_sec - (lua_Number)ctrack->t_start.tv_sec + (tpos->t_last.tv_nsec - ctrack->t_start.tv_nsec)/1000000000.); lua_pushliteral(L, "client"); lua_newtable(L); lua_pushf_ctrack_pos(L, ctrack, &tpos->client); lua_rawset(L,-3); lua_pushliteral(L, "server"); lua_newtable(L); lua_pushf_ctrack_pos(L, ctrack, &tpos->server); lua_rawset(L,-3); // direct and reverse are adjusted for server mode. in server mode orig and reply are exchanged. lua_pushliteral(L, "direct"); lua_getfield(L, -2, (params.server ^ bIncoming) ? "server" : "client"); lua_rawset(L,-3); lua_pushliteral(L, "reverse"); lua_getfield(L, -2, (params.server ^ bIncoming) ? "client" : "server"); lua_rawset(L,-3); lua_rawset(L,-3); } else lua_pushnil(L); LUA_STACK_GUARD_LEAVE(L, 1) } void lua_pushf_ctrack(lua_State *L, const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming) { LUA_STACK_GUARD_ENTER(L) lua_pushliteral(L, "track"); lua_push_ctrack(L, ctrack, tpos, bIncoming); lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } void lua_pushf_args(lua_State *L, const struct str2_list_head *args, int idx_desync, bool subst_prefix) { // var=val - pass val string // var=%val - subst 'val' blob // var=#val - subst 'val' blob length // var=\#val - no subst, skip '\' // var=\%val - no subst, skip '\' LUA_STACK_GUARD_ENTER(L) struct str2_list *arg; const char *var, *val; idx_desync = lua_absindex(L, idx_desync); lua_pushliteral(L,"arg"); lua_newtable(L); LIST_FOREACH(arg, args, next) { var = arg->str1; val = arg->str2 ? arg->str2 : ""; if (subst_prefix) { if (val[0]=='\\' && (val[1]=='%' || val[1]=='#')) // escape char lua_pushf_str(L, var, val+1); else if (val[0]=='%') lua_pushf_blob(L, idx_desync, var, val+1); else if (val[0]=='#') { lua_push_blob(L, idx_desync, val+1); lua_Integer len = lua_rawlen(L, -1); lua_pop(L,1); lua_pushstring(L, var); lua_pushinteger(L, len); lua_tostring(L,-1); // force string type in arg lua_rawset(L,-3); } else lua_pushf_str(L, var, val); } else lua_pushf_str(L, var, val); } lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } void lua_pushf_pos(lua_State *L, const char *name, const struct packet_pos *pos) { LUA_STACK_GUARD_ENTER(L) char smode[2]="?"; lua_pushf_table(L,name); lua_getfield(L, -1, name); *smode=pos->mode; lua_pushf_str(L, "mode",smode); lua_pushf_lint(L, "pos",pos->pos); lua_pop(L,1); LUA_STACK_GUARD_LEAVE(L, 0) } void lua_pushf_range(lua_State *L, const char *name, const struct packet_range *range) { LUA_STACK_GUARD_ENTER(L) lua_pushf_table(L, name); lua_getfield(L, -1, name); lua_pushf_bool(L, "upper_cutoff",range->upper_cutoff); lua_pushf_pos(L, "from", &range->from); lua_pushf_pos(L, "to", &range->to); lua_pop(L,1); LUA_STACK_GUARD_LEAVE(L, 0) } static void lua_reconstruct_extract_options(lua_State *L, int idx, bool *keepsum, bool *badsum, bool *ip6_preserve_next, uint8_t *ip6_last_proto) { if (lua_isnoneornil(L,idx)) { if (keepsum) *keepsum = false; if (badsum) *badsum = false; if (ip6_preserve_next) *ip6_preserve_next = false; if (ip6_last_proto) *ip6_last_proto = IPPROTO_NONE; } else { luaL_checktype(L, idx, LUA_TTABLE); if (keepsum) { lua_getfield(L, idx,"keepsum"); *keepsum = lua_type(L,-1)!=LUA_TNIL && (lua_type(L,-1)!=LUA_TBOOLEAN || lua_toboolean(L,-1)); lua_pop(L,1); } if (badsum) { lua_getfield(L, idx,"badsum"); *badsum = lua_type(L,-1)!=LUA_TNIL && (lua_type(L,-1)!=LUA_TBOOLEAN || lua_toboolean(L,-1)); lua_pop(L,1); } if (ip6_preserve_next) { lua_getfield(L, idx,"ip6_preserve_next"); *ip6_preserve_next = lua_type(L,-1)!=LUA_TNIL && (lua_type(L,-1)!=LUA_TBOOLEAN || lua_toboolean(L,-1)); lua_pop(L,1); } if (ip6_last_proto) { lua_getfield(L, idx,"ip6_last_proto"); *ip6_last_proto = lua_type(L,-1)==LUA_TNIL ? IPPROTO_NONE : (uint8_t)lua_tointeger(L,-1); lua_pop(L,1); } } } static bool lua_reconstruct_ip6exthdr(lua_State *L, int idx, struct ip6_hdr *ip6, size_t *len, uint8_t proto, bool preserve_next) { LUA_STACK_GUARD_ENTER(L) // proto = last header type if (*lenip6_ctlun.ip6_un1.ip6_un1_nxt; size_t filled = sizeof(struct ip6_hdr); lua_getfield(L,idx,"exthdr"); if (lua_type(L,-1)==LUA_TTABLE) { lua_Integer idx=0; uint8_t next, type, *p, *data = (uint8_t*)(ip6+1); size_t l, left; left = *len - filled; for(;;) { lua_rawgeti(L,-1,++idx); if (lua_type(L,-1)==LUA_TNIL) { lua_pop(L, 1); break; } else { if (lua_type(L,-1)!=LUA_TTABLE) goto err; lua_getfield(L,-1, "type"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; type = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); lua_getfield(L,-1, "next"); next = lua_type(L,-1)==LUA_TNUMBER ? (uint8_t)lua_tointeger(L,-1) : IPPROTO_NONE; lua_pop(L, 1); lua_getfield(L,-1, "data"); if (lua_type(L,-1)!=LUA_TSTRING) goto err; if (!(p=(uint8_t*)lua_tolstring(L,-1,&l))) l=0; if (l<6 || (l+2)>left) goto err; if (type==IPPROTO_AH) { if (l>=1024 || ((l+2) & 3)) goto err; memcpy(data+2,p,l); l+=2; data[1] = (l>>2)-2; } else { if (l>=2048 || ((l+2) & 7)) goto err; memcpy(data+2,p,l); l+=2; data[1] = (l>>3)-1; } data[0] = next; // may be overwritten later if (!preserve_next) *last_proto = type; last_proto = data; // first byte of header holds type left -= l; data += l; filled += l; lua_pop(L, 2); } } } // set last header proto if (!preserve_next) *last_proto = proto; *len = filled; lua_pop(L, 1); LUA_STACK_GUARD_LEAVE(L, 0) return true; err: LUA_STACK_GUARD_UNWIND(L) return false; } bool lua_reconstruct_ip6hdr(lua_State *L, int idx, struct ip6_hdr *ip6, size_t *len, uint8_t last_proto, bool preserve_next) { LUA_STACK_GUARD_ENTER(L) const char *p; size_t l; if (*lenip6_ctlun.ip6_un1.ip6_un1_flow = htonl(lua_type(L,-1)==LUA_TNUMBER ? (uint32_t)lua_tolint(L,-1) : 0x60000000); lua_pop(L, 1); lua_getfield(L,idx,"ip6_nxt"); ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); lua_getfield(L,idx,"ip6_hlim"); ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); lua_getfield(L,idx,"ip6_src"); if (lua_type(L,-1)!=LUA_TSTRING) goto err; p = lua_tolstring(L,-1,&l); if (!p || l!=sizeof(struct in6_addr)) goto err; ip6->ip6_src = *(struct in6_addr*)p; lua_pop(L, 1); lua_getfield(L,idx,"ip6_dst"); if (lua_type(L,-1)!=LUA_TSTRING) goto err; p = lua_tolstring(L,-1,&l); if (!p || l!=sizeof(struct in6_addr)) goto err; ip6->ip6_dst = *(struct in6_addr*)p; lua_pop(L, 1); bool have_plen = false; lua_getfield(L,idx,"ip6_plen"); switch (lua_type(L,-1)) { case LUA_TNIL: break; case LUA_TNUMBER: ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons((uint16_t)luaL_checkinteger(L,-1)); have_plen = true; break; default: luaL_error(L,"reconstruct_ip6hdr: ip6_plen wrong type"); } lua_pop(L, 1); bool b = lua_reconstruct_ip6exthdr(L, idx, ip6, len, last_proto, preserve_next); if (b && !have_plen) ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons((uint16_t)(*len-sizeof(struct ip6_hdr))); LUA_STACK_GUARD_LEAVE(L, 0) return b; err: lua_pop(L, 1); LUA_STACK_GUARD_LEAVE(L, 0) return false; } static int luacall_reconstruct_ip6hdr(lua_State *L) { lua_check_argc_range(L,"reconstruct_ip6hdr",1,2); LUA_STACK_GUARD_ENTER(L) char data[512]; size_t len=sizeof(data); uint8_t last_proto; bool preserve_next; lua_reconstruct_extract_options(L, 2, NULL, NULL, &preserve_next, &last_proto); if (!lua_reconstruct_ip6hdr(L, 1,(struct ip6_hdr*)data, &len, last_proto, preserve_next)) luaL_error(L, "invalid data for ip6hdr"); lua_pushlstring(L,data,len); LUA_STACK_GUARD_RETURN(L,1) } bool lua_reconstruct_iphdr(lua_State *L, int idx, struct ip *ip, size_t *len) { const char *p; size_t l, lopt=0; LUA_STACK_GUARD_ENTER(L) if (*lenip_v = IPVERSION; lua_getfield(L,idx,"ip_tos"); ip->ip_tos = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); lua_getfield(L,idx,"ip_len"); ip->ip_len = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"ip_id"); ip->ip_id = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"ip_off"); ip->ip_off = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"ip_ttl"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; ip->ip_ttl = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); lua_getfield(L,idx,"ip_p"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; ip->ip_p = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); lua_getfield(L,idx,"ip_src"); if (lua_type(L,-1)!=LUA_TSTRING) goto err; p = lua_tolstring(L,-1,&l); if (!p || l!=sizeof(struct in_addr)) goto err; ip->ip_src = *(struct in_addr*)p; lua_pop(L, 1); lua_getfield(L,idx,"ip_dst"); if (lua_type(L,-1)!=LUA_TSTRING) goto err; p = lua_tolstring(L,-1,&l); if (!p || l!=sizeof(struct in_addr)) goto err; ip->ip_dst = *(struct in_addr*)p; lua_pop(L, 1); lua_getfield(L,idx,"options"); if (lua_type(L,-1)==LUA_TSTRING) { p = lua_tolstring(L,-1,&lopt); if (p && lopt) { if (lopt>40 || ((sizeof(struct ip) + ((lopt+3)&~3)) > *len)) goto err; memcpy(ip+1,p,lopt); memset(((uint8_t*)ip) + sizeof(struct ip) + lopt, 0, (4-lopt&3)&3); lopt = (lopt+3) & ~3; } } lua_pop(L, 1); *len = sizeof(struct ip) + lopt; ip->ip_hl = *len >> 2; ip4_fix_checksum(ip); LUA_STACK_GUARD_LEAVE(L, 0) return true; err: lua_pop(L, 1); LUA_STACK_GUARD_LEAVE(L, 0) return false; } static int luacall_reconstruct_iphdr(lua_State *L) { lua_check_argc(L,"reconstruct_iphdr",1); LUA_STACK_GUARD_ENTER(L) char data[60]; size_t l = sizeof(data); if (!lua_reconstruct_iphdr(L,1,(struct ip*)&data,&l)) luaL_error(L, "invalid data for iphdr"); lua_pushlstring(L,data,l); LUA_STACK_GUARD_RETURN(L,1) } static bool lua_reconstruct_tcphdr_options(lua_State *L, int idx, struct tcphdr *tcp, size_t *len) { if (*len40) left=40; // max size of tcp options for (;;) { lua_rawgeti(L,-1,++idx); if (lua_type(L,-1)==LUA_TNIL) { lua_pop(L, 1); break; } else { // uses 'key' (at index -2) and 'value' (at index -1) if (!left || lua_type(L,-1)!=LUA_TTABLE) goto err; lua_getfield(L,-1, "kind"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; kind = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); switch(kind) { case TCP_KIND_END: *data = kind; data++; left--; filled++; lua_pop(L, 1); goto end; case TCP_KIND_NOOP: *data = kind; data++; left--; filled++; break; default: lua_getfield(L,-1, "data"); l = 0; p = lua_type(L,-1)==LUA_TSTRING ? (uint8_t*)lua_tolstring(L,-1,&l) : NULL; if ((2+l)>left) goto err; if (p) memcpy(data+2,p,l); l+=2; data[0] = kind; data[1] = (uint8_t)l; left -= l; data += l; filled += l; lua_pop(L, 1); } lua_pop(L, 1); } } end: while(filled & 3) { if (!left) goto err; *data = TCP_KIND_NOOP; data++; left--; filled++; } } tcp->th_off = filled>>2; *len = filled; lua_pop(L, 1); LUA_STACK_GUARD_LEAVE(L, 0) return true; err: LUA_STACK_GUARD_UNWIND(L) return false; } bool lua_reconstruct_tcphdr(lua_State *L, int idx, struct tcphdr *tcp, size_t *len) { if (*lenth_sport = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"th_dport"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; tcp->th_dport = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"th_seq"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; tcp->th_seq = htonl((uint32_t)lua_tolint(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"th_ack"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; tcp->th_ack = htonl((uint32_t)lua_tolint(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"th_x2"); tcp->th_x2 = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); lua_getfield(L,idx,"th_flags"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; tcp->th_flags = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); lua_getfield(L,idx,"th_win"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; tcp->th_win = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"th_sum"); tcp->th_sum = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"th_urp"); tcp->th_urp = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); tcp->th_off = 5; bool b = lua_reconstruct_tcphdr_options(L, idx, tcp, len); LUA_STACK_GUARD_LEAVE(L, 0) return b; err: lua_pop(L, 1); LUA_STACK_GUARD_LEAVE(L, 0) return false; } static int luacall_reconstruct_tcphdr(lua_State *L) { lua_check_argc(L,"reconstruct_tcphdr",1); LUA_STACK_GUARD_ENTER(L) char data[60]; size_t len=sizeof(data); if (!lua_reconstruct_tcphdr(L,1,(struct tcphdr*)data,&len)) luaL_error(L, "invalid data for tcphdr"); lua_pushlstring(L,data,len); LUA_STACK_GUARD_RETURN(L,1) } bool lua_reconstruct_udphdr(lua_State *L, int idx, struct udphdr *udp) { if (lua_type(L,-1)!=LUA_TTABLE) return false; LUA_STACK_GUARD_ENTER(L) lua_getfield(L,idx,"uh_sport"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; udp->uh_sport = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"uh_dport"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; udp->uh_dport = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"uh_ulen"); udp->uh_ulen = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"uh_sum"); udp->uh_sum = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); LUA_STACK_GUARD_LEAVE(L, 0) return true; err: lua_pop(L, 1); LUA_STACK_GUARD_LEAVE(L, 0) return false; } static int luacall_reconstruct_udphdr(lua_State *L) { LUA_STACK_GUARD_ENTER(L) lua_check_argc(L,"reconstruct_udphdr",1); struct udphdr udp; if (!lua_reconstruct_udphdr(L,1,&udp)) luaL_error(L, "invalid data for udphdr"); lua_pushlstring(L,(char*)&udp,sizeof(udp)); LUA_STACK_GUARD_RETURN(L,1) } bool lua_reconstruct_icmphdr(lua_State *L, int idx, struct icmp46 *icmp) { if (lua_type(L,-1)!=LUA_TTABLE) return false; LUA_STACK_GUARD_ENTER(L) lua_getfield(L,idx,"icmp_type"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; icmp->icmp_type = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); lua_getfield(L,idx,"icmp_code"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; icmp->icmp_code = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); lua_getfield(L,idx,"icmp_data"); if (lua_type(L,-1)!=LUA_TNUMBER) goto err; icmp->data.data32 = htonl((uint32_t)lua_tolint(L,-1)); lua_pop(L, 1); lua_getfield(L,idx,"icmp_cksum"); icmp->icmp_cksum = htons((uint16_t)lua_tointeger(L,-1)); lua_pop(L, 1); LUA_STACK_GUARD_LEAVE(L, 0) return true; err: lua_pop(L, 1); LUA_STACK_GUARD_LEAVE(L, 0) return false; } static int luacall_reconstruct_icmphdr(lua_State *L) { LUA_STACK_GUARD_ENTER(L) lua_check_argc(L,"reconstruct_icmphdr",1); struct icmp46 icmp; if (!lua_reconstruct_icmphdr(L,1,&icmp)) luaL_error(L, "invalid data for icmphdr"); lua_pushlstring(L,(char*)&icmp,sizeof(icmp)); LUA_STACK_GUARD_RETURN(L,1) } uint8_t lua_ip6_l4proto_from_dissect(lua_State *L, int idx) { int type; lua_getfield(L,idx,"tcp"); type=lua_type(L,-1); lua_pop(L,1); if (type==LUA_TTABLE) return IPPROTO_TCP; lua_getfield(L,idx,"udp"); type=lua_type(L,-1); lua_pop(L,1); if (type==LUA_TTABLE) return IPPROTO_UDP; lua_getfield(L,idx,"icmp"); type=lua_type(L,-1); lua_pop(L,1); if (type==LUA_TTABLE) { lua_getfield(L,idx,"ip"); type=lua_type(L,-1); lua_pop(L,1); if (type==LUA_TTABLE) return IPPROTO_ICMP; lua_getfield(L,idx,"ip6"); type=lua_type(L,-1); lua_pop(L,1); if (type==LUA_TTABLE) return IPPROTO_ICMPV6; } return IPPROTO_NONE; } // last_proto = IPPROTO_NONE means auto detect bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, bool keepsum, bool badsum, uint8_t last_proto, bool ip6_preserve_next) { uint8_t *data = buf; size_t sz,l,lpayload,l3,left = *len; struct ip *ip=NULL; struct ip6_hdr *ip6=NULL; struct tcphdr *tcp=NULL; struct udphdr *udp=NULL; struct icmp46 *icmp=NULL; const char *p; bool frag; LUA_STACK_GUARD_ENTER(L) idx = lua_absindex(L, idx); lua_getfield(L,idx,"frag_off"); if (lua_type(L,-1)!=LUA_TNIL) { luaL_checkinteger(L,-1); // verify type frag = true; } else frag = false; lua_pop(L, 1); if (frag) ip6_preserve_next = true; // there's no other source of next. no tcp, no udp, no icmp headers. just raw ip payload lua_getfield(L,idx,"ip"); l = left; if (lua_type(L,-1)==LUA_TTABLE) { ip = (struct ip*)data; if (!lua_reconstruct_iphdr(L,-1, ip, &l)) { DLOG_ERR("reconstruct_dissect: bad ip\n"); goto err; } ip4_fix_checksum(ip); } else { lua_pop(L, 1); lua_getfield(L,idx,"ip6"); if (lua_type(L,-1)!=LUA_TTABLE) goto err; ip6 = (struct ip6_hdr*)data; if (!lua_reconstruct_ip6hdr(L,-1, ip6, &l, last_proto==IPPROTO_NONE ? lua_ip6_l4proto_from_dissect(L,idx) : last_proto, ip6_preserve_next)) { DLOG_ERR("reconstruct_dissect: bad ip6\n"); goto err; } } l3=l; data+=l; left-=l; lua_pop(L, 1); if (frag) { lua_getfield(L,idx,"payload"); p = lua_tolstring(L,-1,&lpayload); if (p) { if (lpayload>0xFFFF) { DLOG_ERR("reconstruct_dissect: payload too large : %zu\n",lpayload); goto err; } if (left0xFFFF) { DLOG_ERR("reconstruct_dissect: payload too large : %zu\n",lpayload); goto err; } if (leftth_sum ^= 1 + (random() % 0xFFFF); } else if (udp) { sz = lpayload+sizeof(struct udphdr); if (sz>0xFFFF) { DLOG_ERR("reconstruct_dissect: invalid payload length\n"); goto err; } udp->uh_ulen = htons((uint16_t)sz); udp_fix_checksum(udp,l-l3,ip,ip6); if (badsum) udp->uh_sum ^= 1 + (random() % 0xFFFF); } else if (icmp) { icmp_fix_checksum(icmp,l-l3,ip6); if (badsum) icmp->icmp_cksum ^= 1 + (random() % 0xFFFF); } } if (ip) { if (ntohs(ip->ip_off) & (IP_OFFMASK|IP_MF)) { // fragmentation. caller should set ip_len, ip_off and IP_MF correctly. C code moves and shrinks constructed ip payload uint16_t iplen = ntohs(ip->ip_len); uint16_t off = (ntohs(ip->ip_off) & IP_OFFMASK)<<3; size_t frag_start = l3 + off; if (iplenl) { DLOG_ERR("ipv4 frag : invalid ip_len\n"); goto err; } size_t frag_len = iplen-l3; if ((frag_start+frag_len)>l) { DLOG_ERR("ipv4 frag : fragment end is outside of the packet\n"); goto err; } if (off) memmove(buf+l3,buf+frag_start,frag_len); l = iplen; // shrink packet to iplen } else ip->ip_len = htons((uint16_t)l); ip4_fix_checksum(ip); } else if (ip6) { // data points to reconstructed packet's end uint8_t *frag = proto_find_ip6_exthdr(ip6, l, IPPROTO_FRAGMENT); if (frag) { uint16_t plen = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); // without ipv6 base header uint16_t off = ntohs(((struct ip6_frag *)frag)->ip6f_offlg) & 0xFFF8; uint8_t *endfrag = frag + 8; size_t size_unfragmentable = endfrag - (uint8_t*)ip6 - sizeof(struct ip6_hdr); if (size_unfragmentable > plen) { DLOG_ERR("ipv6 frag : invalid ip6_plen\n"); goto err; } size_t size_fragmentable = plen - size_unfragmentable; if ((endfrag + off + size_fragmentable) > data) { DLOG_ERR("ipv6 frag : fragmentable part is outside of the packet\n"); goto err; } if (off) memmove(endfrag, endfrag + off, size_fragmentable); l = sizeof(struct ip6_hdr) + plen; } else ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons((uint16_t)(l-sizeof(struct ip6_hdr))); } } *len = l; LUA_STACK_GUARD_LEAVE(L, 0) return true; err: LUA_STACK_GUARD_UNWIND(L) return false; } static int luacall_reconstruct_dissect(lua_State *L) { // reconstruct_dissect(data, reconstruct_opts) lua_check_argc_range(L,"reconstruct_dissect",1,2); LUA_STACK_GUARD_ENTER(L) size_t l; uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16))); uint8_t last_proto; l = sizeof(buf); bool ip6_preserve_next, badsum, keepsum; lua_reconstruct_extract_options(L, 2, &keepsum, &badsum, &ip6_preserve_next, &last_proto); if (!lua_reconstruct_dissect(L, 1, buf, &l, keepsum, badsum, last_proto, ip6_preserve_next)) luaL_error(L, "invalid dissect data"); lua_pushlstring(L,(char*)buf,l); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_dissect(lua_State *L) { // dissect(packet_data) lua_check_argc_range(L,"dissect",1,2); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); int argc = lua_gettop(L); bool no_payload_check = argc>=2 ? lua_toboolean(L, 2) : false; struct dissect dis; proto_dissect_l3l4(data, len, &dis, no_payload_check); lua_push_dissect(L, &dis); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_csum_ip4_fix(lua_State *L) { // csum_ip4_fix(ip_header) returns ip_header lua_check_argc(L,"csum_ip4_fix",1); LUA_STACK_GUARD_ENTER(L) size_t l; const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &l); if (l>60 || !proto_check_ipv4(data, l)) luaL_error(L, "invalid ip header"); uint8_t data2[60]; memcpy(data2, data, l); ip4_fix_checksum((struct ip*)data2); lua_pushlstring(L,(char*)data2,l); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_csum_tcp_fix(lua_State *L) { // csum_tcp_fix(ip_header, tcp_header, payload) returns tcp_header lua_check_argc(L,"csum_tcp_fix",3); LUA_STACK_GUARD_ENTER(L) size_t l_ip; const uint8_t *b_ip = (const uint8_t*)lua_reqlstring(L, 1, &l_ip); const struct ip *ip=NULL; const struct ip6_hdr *ip6=NULL; if (proto_check_ipv4(b_ip, l_ip)) ip = (struct ip*)b_ip; else if (proto_check_ipv6(b_ip, l_ip)) ip6 = (struct ip6_hdr*)b_ip; else luaL_error(L, "invalid ip header"); size_t l_tcp; const uint8_t *b_tcp = (const uint8_t*)lua_reqlstring(L, 2, &l_tcp); if (!proto_check_tcp(b_tcp, l_tcp)) luaL_error(L, "invalid tcp header"); size_t l_pl; const uint8_t *b_pl = (const uint8_t*)lua_reqlstring(L, 3, &l_pl); if (l_pl>0xFFFF) luaL_error(L, "invalid payload length"); size_t l_tpl = l_tcp + l_pl; uint8_t *tpl = lua_newuserdata(L, l_tpl); memcpy(tpl, b_tcp, l_tcp); memcpy(tpl+l_tcp, b_pl, l_pl); struct tcphdr *tcp = (struct tcphdr*)tpl; tcp_fix_checksum(tcp, l_tpl, ip, ip6); lua_pushlstring(L,(char*)tpl,l_tcp); lua_remove(L,-2); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_csum_udp_fix(lua_State *L) { // csum_udp_fix(ip_header, udp_header, payload) returns udp_header lua_check_argc(L,"csum_udp_fix",3); LUA_STACK_GUARD_ENTER(L) size_t l_ip; const uint8_t *b_ip = (const uint8_t*)lua_reqlstring(L, 1, &l_ip); const struct ip *ip=NULL; const struct ip6_hdr *ip6=NULL; if (proto_check_ipv4(b_ip, l_ip)) ip = (struct ip*)b_ip; else if (proto_check_ipv6(b_ip, l_ip)) ip6 = (struct ip6_hdr*)b_ip; else luaL_error(L, "invalid ip header"); size_t l_udp; const uint8_t *b_udp = (const uint8_t*)lua_reqlstring(L, 2, &l_udp); if (!proto_check_udp(b_udp, l_udp)) luaL_error(L, "invalid udp header"); size_t l_pl; const uint8_t *b_pl = (const uint8_t*)lua_reqlstring(L, 3, &l_pl); if (l_pl>0xFFFF) luaL_error(L, "invalid payload length"); size_t l_tpl = l_udp + l_pl; uint8_t *tpl = lua_newuserdata(L, l_tpl); memcpy(tpl, b_udp, l_udp); memcpy(tpl+l_udp, b_pl, l_pl); struct udphdr *udp = (struct udphdr*)tpl; udp_fix_checksum(udp, l_tpl, ip, ip6); lua_pushlstring(L,(char*)tpl,l_udp); lua_remove(L,-2); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_csum_icmp_fix(lua_State *L) { // csum_icmp_fix(ip_header, icmp_header, payload) returns icmp_header lua_check_argc(L,"csum_icmp_fix",3); LUA_STACK_GUARD_ENTER(L) size_t l_ip; const uint8_t *b_ip = (const uint8_t*)lua_reqlstring(L, 1, &l_ip); const struct ip *ip=NULL; const struct ip6_hdr *ip6=NULL; if (proto_check_ipv4(b_ip, l_ip)) ip = (struct ip*)b_ip; else if (proto_check_ipv6(b_ip, l_ip)) ip6 = (struct ip6_hdr*)b_ip; else luaL_error(L, "invalid ip header"); size_t l_icmp; const uint8_t *b_icmp = (const uint8_t*)lua_reqlstring(L, 2, &l_icmp); if (!proto_check_icmp(b_icmp, l_icmp)) luaL_error(L, "invalid icmp header"); size_t l_pl; const uint8_t *b_pl = (const uint8_t*)lua_reqlstring(L, 3, &l_pl); if (l_pl>0xFFFF) luaL_error(L, "invalid payload length"); size_t l_tpl = l_icmp + l_pl; uint8_t *tpl = lua_newuserdata(L, l_tpl); memcpy(tpl, b_icmp, l_icmp); memcpy(tpl+l_icmp, b_pl, l_pl); struct icmp46 *icmp = (struct icmp46*)tpl; icmp_fix_checksum(icmp, l_tpl, ip6); lua_pushlstring(L,(char*)tpl,l_icmp); lua_remove(L,-2); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_ntop(lua_State *L) { size_t l; const char *p; char s[INET6_ADDRSTRLEN]; int af=0; lua_check_argc(L,"ntop",1); LUA_STACK_GUARD_ENTER(L) p=lua_reqlstring(L,1,&l); switch(l) { case sizeof(struct in_addr): af=AF_INET; break; case sizeof(struct in6_addr): af=AF_INET6; break; default: lua_pushnil(L); return 1; } if (inet_ntop(af,p,s,sizeof(s))) lua_pushstring(L,s); else lua_pushnil(L); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_pton(lua_State *L) { const char *p; char s[sizeof(struct in6_addr)]; lua_check_argc(L,"pton",1); LUA_STACK_GUARD_ENTER(L) p=lua_reqstring(L,1); if (inet_pton(AF_INET,p,s)) lua_pushlstring(L,s,sizeof(struct in_addr)); else if (inet_pton(AF_INET6,p,s)) lua_pushlstring(L,s,sizeof(struct in6_addr)); else lua_pushnil(L); LUA_STACK_GUARD_RETURN(L,1) } static void lua_rawsend_extract_options(lua_State *L, int idx, int *repeats, uint32_t *fwmark, const char **ifout) { if (lua_isnoneornil(L,idx)) { if (repeats) *repeats = 1; if (fwmark) *fwmark = params.desync_fwmark; if (ifout) *ifout = NULL; } else { luaL_checktype(L, idx, LUA_TTABLE); if (repeats) { lua_getfield(L,idx,"repeats"); *repeats=(int)lua_tointeger(L,-1); if (*repeats<0) luaL_error(L, "rawsend: negative repeats"); if (!*repeats) *repeats=1; lua_pop(L,1); } if (fwmark) { lua_getfield(L,idx,"fwmark"); *fwmark=(uint32_t)lua_tolint(L,-1) | params.desync_fwmark; lua_pop(L,1); } if (ifout) { lua_getfield(L,idx,"ifout"); *ifout = lua_type(L,-1)==LUA_TSTRING ? lua_tostring(L,-1) : NULL; lua_pop(L,1); } } } static int luacall_rawsend(lua_State *L) { // bool rawsend(raw_data, {repeats, fwmark, ifout}) lua_check_argc_range(L,"rawsend",1,2); LUA_STACK_GUARD_ENTER(L) uint8_t *data; const char *ifout; size_t len; int repeats; uint32_t fwmark; sockaddr_in46 sa; bool b; data=(uint8_t*)lua_reqlstring(L,1,&len); lua_rawsend_extract_options(L,2,&repeats,&fwmark,&ifout); if (!extract_dst(data, len, (struct sockaddr*)&sa)) luaL_error(L, "bad ip4/ip6 header"); DLOG("rawsend repeats=%d size=%zu ifout=%s fwmark=%08X\n", repeats,len,ifout ? ifout : "",fwmark); b = rawsend_rep(repeats, (struct sockaddr*)&sa, fwmark, ifout, data, len); lua_pushboolean(L, b); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_rawsend_dissect(lua_State *L) { // rawsend_dissect(data, rawsend_opts, reconstruct_opts) lua_check_argc_range(L,"rawsend_dissect",1,3); LUA_STACK_GUARD_ENTER(L) size_t len; const char *ifout; int repeats; uint32_t fwmark; sockaddr_in46 sa; bool b, badsum, keepsum, ip6_preserve_next; uint8_t last_proto; uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16))); luaL_checktype(L,1,LUA_TTABLE); lua_rawsend_extract_options(L,2, &repeats, &fwmark, &ifout); lua_reconstruct_extract_options(L, 3, &keepsum, &badsum, &ip6_preserve_next, &last_proto); len = sizeof(buf); if (!lua_reconstruct_dissect(L, 1, buf, &len, keepsum, badsum, last_proto, ip6_preserve_next)) luaL_error(L, "invalid dissect data"); if (!extract_dst(buf, len, (struct sockaddr*)&sa)) luaL_error(L, "bad ip4/ip6 header"); DLOG("rawsend_dissect repeats=%d size=%zu badsum=%u ifout=%s fwmark=%08X\n", repeats,len,badsum,ifout ? ifout : "",fwmark); b = rawsend_rep(repeats, (struct sockaddr*)&sa, fwmark, ifout, buf, len); lua_pushboolean(L, b); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_conntrack_feed(lua_State *L) { // conntrack_feed(dissect/raw_packet[, reconstruct_opts]) return track,bOutgoing lua_check_argc_range(L,"conntrack_feed",1,3); LUA_STACK_GUARD_ENTER(L) if (params.ctrack_disable) goto err; else { size_t len; bool badsum, keepsum, ip6_preserve_next, bReverse; uint8_t last_proto; struct dissect dis; t_ctrack *ctrack; const uint8_t *pbuf; uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16))); switch(lua_type(L,1)) { case LUA_TTABLE: lua_reconstruct_extract_options(L, 2, &keepsum, &badsum, &ip6_preserve_next, &last_proto); len = sizeof(buf); if (!lua_reconstruct_dissect(L, 1, buf, &len, keepsum, badsum, last_proto, ip6_preserve_next)) luaL_error(L, "invalid dissect data"); pbuf = buf; break; case LUA_TSTRING: pbuf = (const uint8_t*)lua_tolstring(L,1,&len); break; default: luaL_error(L, "invalid packet data type"); } proto_dissect_l3l4(pbuf, len, &dis, false); ConntrackPoolPurge(¶ms.conntrack); if (ConntrackPoolFeed(¶ms.conntrack, &dis, &ctrack, &bReverse)) { lua_push_ctrack(L, ctrack, NULL, bReverse); lua_pushboolean(L, !bReverse); // outgoing } else goto err; } ex: LUA_STACK_GUARD_RETURN(L,2) err: lua_pushnil(L); lua_pushnil(L); goto ex; } static int luacall_get_source_ip(lua_State *L) { // get_source_ip(target_ip) lua_check_argc(L,"get_source_ip",1); LUA_STACK_GUARD_ENTER(L) union { struct in_addr a4; struct in6_addr a6; } a; size_t len; const uint8_t *data = (uint8_t*)lua_reqlstring(L,1,&len); switch(len) { case sizeof(struct in_addr) : if (get_source_ip4((struct in_addr*)data, &a.a4)) lua_pushlstring(L,(char*)&a.a4,sizeof(a.a4)); else lua_pushnil(L); break; case sizeof(struct in6_addr) : if (get_source_ip6((struct in6_addr*)data, &a.a6)) lua_pushlstring(L,(char*)&a.a6,sizeof(a.a6)); else lua_pushnil(L); break; default: luaL_error(L, "invalid IP length %u", (unsigned int)len); } LUA_STACK_GUARD_RETURN(L,1) } #ifdef __CYGWIN__ #define GAA_FLAGS (GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST) static int lua_get_ifaddrs(lua_State *L) { LUA_STACK_GUARD_ENTER(L) ULONG Size=0; if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAGS, NULL, NULL, &Size)==ERROR_BUFFER_OVERFLOW) { PIP_ADAPTER_ADDRESSES pip, pips = (PIP_ADAPTER_ADDRESSES)lua_newuserdata(L, Size); if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAGS, NULL, pips, &Size)==ERROR_SUCCESS) { lua_newtable(L); for(pip=pips; pip ; pip=pip->Next) { if (!pip->FirstUnicastAddress || pip->OperStatus!=IfOperStatusUp) continue; // disconnected ? char ifname[16]; snprintf(ifname,sizeof(ifname),"%u.0",pip->IfIndex); lua_pushf_table(L,ifname); lua_getfield(L,-1,ifname); lua_pushf_str(L, "guid", pip->AdapterName); if (pip->PhysicalAddressLength) lua_pushf_lstr(L, "phys", pip->PhysicalAddress, pip->PhysicalAddressLength); lua_pushf_int(L, "index", pip->IfIndex); lua_pushf_int(L, "index6", pip->Ipv6IfIndex); lua_pushf_int(L, "flags", pip->Flags); lua_pushf_lint(L, "mtu", pip->Mtu); lua_pushf_int(L, "iftype", pip->IfType); lua_pushf_lint(L, "speed_xmit", pip->TransmitLinkSpeed); lua_pushf_lint(L, "speed_recv", pip->ReceiveLinkSpeed); lua_pushf_lint(L, "metric4", pip->Ipv4Metric); lua_pushf_lint(L, "metric6", pip->Ipv6Metric); lua_pushf_lint(L, "conntype", pip->ConnectionType); lua_pushf_lint(L, "tunneltype", pip->TunnelType); lua_pushf_table(L,"addr"); lua_getfield(L,-1,"addr"); int n; uint32_t a4,a44; PIP_ADAPTER_UNICAST_ADDRESS_LH pa; for(pa=pip->FirstUnicastAddress, n=1; pa ; pa=pa->Next, n++) { lua_pushi_table(L, n); lua_rawgeti(L, -1, n); lua_pushf_ipaddr(L, "addr", pa->Address.lpSockaddr); switch(pa->Address.lpSockaddr->sa_family) { case AF_INET: if (pa->OnLinkPrefixLength<=32) { a44 = mask_from_bitcount(pa->OnLinkPrefixLength); a4 = ~a44; lua_pushf_lstr(L, "netmask", (const char*)&a4, 4); a4 &= ((struct sockaddr_in*)pa->Address.lpSockaddr)->sin_addr.s_addr; a4 |= a44; lua_pushf_lstr(L, "broadcast", (const char*)&a4, 4); } break; case AF_INET6: if (pa->OnLinkPrefixLength<=128) { lua_pushf_lstr(L, "netmask", (const char*)mask_from_bitcount6(128 - pa->OnLinkPrefixLength), 16); } break; } lua_pushf_ipaddr(L, "addr", pa->Address.lpSockaddr); lua_pop(L,1); } lua_pop(L,2); } lua_remove(L,-2); goto ok; } lua_remove(L,-1); } lua_pushnil(L); ok: LUA_STACK_GUARD_RETURN(L,1) } #else // in cygwin this does not work with low intergity level because of cygwin objects in NT directory tree static int lua_get_ifaddrs(lua_State *L) { LUA_STACK_GUARD_ENTER(L) struct ifaddrs *addrs,*a; unsigned int index; lua_Integer li; struct ifreq ifr; const char *ifname; #ifdef __CYGWIN__ char ifname_buf[IFNAMSIZ]; #endif memset(&ifr,0,sizeof(ifr)); if (getifaddrs(&addrs)<0) lua_pushnil(L); else { int sock = socket(AF_INET,SOCK_DGRAM,0); lua_newtable(L); a = addrs; for(a=addrs ; a ; a=a->ifa_next) { if (a->ifa_addr && (a->ifa_addr->sa_family==AF_INET || a->ifa_addr->sa_family==AF_INET6) && a->ifa_name && *a->ifa_name) { #ifdef __CYGWIN__ // cygwin returns GUID interface names. windivert needs ifindex.subindex if (index = if_nametoindex(a->ifa_name)) { snprintf(ifname_buf,sizeof(ifname_buf),"%u.0",index); ifname = ifname_buf; } #else ifname = a->ifa_name; #endif lua_getfield(L,-1,ifname); if (lua_isnil(L,-1)) { lua_pop(L,1); lua_pushf_table(L,ifname); lua_getfield(L,-1,ifname); #ifdef __CYGWIN__ lua_pushf_str(L, "guid", a->ifa_name); #else index = if_nametoindex(ifname); #endif if (index) lua_pushf_int(L, "index", index); lua_pushf_int(L, "flags", a->ifa_flags); #ifdef HAS_FILTER_SSID lua_pushf_str(L, "ssid", wlan_ssid_search_ifname(ifname)); #endif memset(ifr.ifr_name,0,sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (sock>=0 && !ioctl(sock, SIOCGIFMTU, &ifr)) lua_pushf_int(L, "mtu", ifr.ifr_mtu); lua_pushf_table(L,"addr"); } lua_getfield(L,-1,"addr"); li = lua_rawlen(L,-1)+1; lua_pushi_table(L, li); lua_rawgeti(L,-1,li); lua_pushf_ipaddr(L, "addr", a->ifa_addr); lua_pushf_ipaddr(L, "netmask", a->ifa_netmask); lua_pushf_ipaddr(L, "broadcast", a->ifa_broadaddr); lua_pushf_ipaddr(L, "dst", a->ifa_dstaddr); lua_pop(L,3); } } freeifaddrs(addrs); if (sock>=0) close(sock); } LUA_STACK_GUARD_RETURN(L,1) } #endif // CYGWIN static int luacall_get_ifaddrs(lua_State *L) { lua_check_argc(L,"get_ifaddrs",0); lua_get_ifaddrs(L); return 1; } static int luacall_resolve_pos(lua_State *L) { // resolve_pos(blob,l7payload_type,marker[,zero_based_pos]) lua_check_argc_range(L,"resolve_pos",3,4); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t len; const uint8_t *data = (uint8_t*)lua_reqlstring(L,1,&len); const char *sl7payload = lua_reqstring(L,2); const char *smarker = lua_reqstring(L,3); bool bZeroBased = argc>=4 && lua_toboolean(L,4); t_l7payload l7payload = l7payload_from_name(sl7payload); if (l7payload==L7P_INVALID) luaL_error(L, "bad payload type : '%s'", sl7payload); struct proto_pos marker; if (!posmarker_parse(smarker,&marker)) luaL_error(L, "bad marker : '%s'", smarker); ssize_t pos=ResolvePos(data, len, l7payload, &marker); if (pos==POS_NOT_FOUND) lua_pushnil(L); else lua_pushinteger(L,pos+!bZeroBased); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_resolve_multi_pos(lua_State *L) { // resolve_multi_pos(blob,l7payload_type,marker_list[,zero_based_pos]) lua_check_argc_range(L,"resolve_multi_pos",3,4); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t len; const uint8_t *data = (uint8_t*)lua_reqlstring(L,1,&len); const char *sl7payload = lua_reqstring(L,2); const char *smarkers = lua_reqstring(L,3); bool bZeroBased = argc>=4 && lua_toboolean(L,4); t_l7payload l7payload = l7payload_from_name(sl7payload); if (l7payload==L7P_INVALID) luaL_error(L, "bad payload type : '%s'", sl7payload); struct proto_pos markers[128]; ssize_t pos[sizeof(markers)/sizeof(*markers)]; int i, ctpos, ctm = sizeof(markers)/sizeof(*markers); if (!posmarker_list_parse(smarkers,markers,&ctm)) luaL_error(L, "bad marker list"); ResolveMultiPos(data, len, l7payload, markers, ctm, pos, &ctpos); lua_newtable(L); for(i=0;i=4 && lua_toboolean(L,4); bool bZeroBased = argc>=5 && lua_toboolean(L,5); t_l7payload l7payload = l7payload_from_name(sl7payload); if (l7payload==L7P_INVALID) luaL_error(L, "bad payload type : '%s'", sl7payload); struct proto_pos markers[2]; ssize_t pos[sizeof(markers)/sizeof(*markers)]; int ctm = sizeof(markers)/sizeof(*markers); if (!posmarker_list_parse(smarkers,markers,&ctm)) luaL_error(L, "bad marker list"); if (ctm!=2) luaL_error(L, "resolve_range require 2 markers"); pos[0] = ResolvePos(data, len, l7payload, markers); pos[1] = ResolvePos(data, len, l7payload, markers+1); if (pos[0]==POS_NOT_FOUND && pos[1]==POS_NOT_FOUND || bStrict && (pos[0]==POS_NOT_FOUND || pos[1]==POS_NOT_FOUND)) { lua_pushnil(L); return 1; } if (pos[0]==POS_NOT_FOUND) pos[0] = 0; if (pos[1]==POS_NOT_FOUND) pos[1] = len-1; if (pos[0]>pos[1]) { lua_pushnil(L); return 1; } lua_newtable(L); lua_pushi_int(L,1,pos[0]+!bZeroBased); lua_pushi_int(L,2,pos[1]+!bZeroBased); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_mod(lua_State *L) { // (blob, modlist, payload) lua_check_argc_range(L,"tls_mod",2,3); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t fake_tls_len; bool bRes; const uint8_t *fake_tls = (uint8_t*)lua_reqlstring(L,1,&fake_tls_len); const char *modlist = lua_reqstring(L,2); size_t payload_len = 0; const uint8_t *payload = NULL; if (argc>=3 && lua_type(L,3)!=LUA_TNIL) payload = (uint8_t*)lua_reqlstring(L,3,&payload_len); struct fake_tls_mod mod; if (!TLSMod_parse_list(modlist, &mod)) luaL_error(L, "invalid tls mod list : '%s'", modlist); if (mod.mod) { size_t newlen = fake_tls_len, maxlen = fake_tls_len + sizeof(mod.sni) + 4; uint8_t *newtls = lua_newuserdata(L, maxlen); memcpy(newtls, fake_tls, newlen); bRes = TLSMod(&mod, payload, payload_len, newtls, &newlen, maxlen); lua_pushlstring(L,(char*)newtls,newlen); lua_remove(L,-2); } else { // no mod. push it back lua_pushlstring(L,(char*)fake_tls,fake_tls_len); bRes = true; } lua_pushboolean(L, bRes); LUA_STACK_GUARD_RETURN(L,2) } struct userdata_zs { bool valid, inflate; z_stream zs; }; static int lua_cfunc_zstream_gc(lua_State *L) { struct userdata_zs *uzs = (struct userdata_zs *)luaL_checkudata(L, 1, "userdata_zstream"); if (uzs->valid) { if (uzs->inflate) inflateEnd(&uzs->zs); else deflateEnd(&uzs->zs); uzs->valid = false; } return 0; } static void lua_mt_init_zstream(lua_State *L) { LUA_STACK_GUARD_ENTER(L) luaL_newmetatable(L, "userdata_zstream"); lua_pushcfunction(L, lua_cfunc_zstream_gc); lua_setfield(L, -2, "__gc"); // Lua 5.5+ to-be-closed var lua_pushcfunction(L, lua_cfunc_zstream_gc); lua_setfield(L, -2, "__close"); lua_pop(L,1); LUA_STACK_GUARD_LEAVE(L, 0) } static struct userdata_zs *lua_uzs(lua_State *L, int idx, bool bInflate) { struct userdata_zs *uzs = (struct userdata_zs *)luaL_checkudata(L, idx, "userdata_zstream"); if (!uzs->valid) luaL_error(L, "gzip stream is not valid"); if (bInflate!=uzs->inflate) luaL_error(L, "gzip stream role mismatch"); return uzs; } static int luacall_gunzip_init(lua_State *L) { // gunzip_init(windowBits) return zstream lua_check_argc_range(L,"gunzip_init",0,1); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); int windowBits = (argc>=1 && !lua_isnil(L,1)) ? luaL_checkinteger(L, 1) : 47; struct userdata_zs *uzs = (struct userdata_zs *)lua_newuserdata(L, sizeof(struct userdata_zs)); memset(&uzs->zs, 0, sizeof(uzs->zs)); int r = inflateInit2(&uzs->zs, windowBits); if (r == Z_OK) { uzs->inflate = true; uzs->valid = true; luaL_getmetatable(L, "userdata_zstream"); lua_setmetatable(L, -2); } else { lua_pop(L,1); lua_pushnil(L); } LUA_STACK_GUARD_RETURN(L,1) } static int luacall_gunzip_end(lua_State *L) { lua_check_argc(L,"gunzip_end",1); LUA_STACK_GUARD_ENTER(L) struct userdata_zs *uzs = lua_uzs(L, 1, true); inflateEnd(&uzs->zs); uzs->valid = false; LUA_STACK_GUARD_RETURN(L,0) } #define BUFMIN 64 #define Z_INFL_BUF_INCREMENT 16384 #define Z_DEFL_BUF_INCREMENT 8192 static int luacall_gunzip_inflate(lua_State *L) { // gunzip_inflate(zstream, compressed_data, expected_uncompressed_chunk_size) return decompressed_data lua_check_argc_range(L,"gunzip_inflate",2,3); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t l; int r; size_t bufsize=0, size=0; uint8_t *buf=NULL, *newbuf; struct userdata_zs *uzs = lua_uzs(L, 1, true); uzs->zs.next_in = (z_const Bytef*)luaL_checklstring(L,2,&l); uzs->zs.avail_in = (uInt)l; size_t bufchunk = argc>=3 ? luaL_checkinteger(L,3) : l*4; size_t increment = bufchunk / 2; if (increment < Z_INFL_BUF_INCREMENT) increment = Z_INFL_BUF_INCREMENT; for(;;) { if ((bufsize - size) < BUFMIN) { if (buf) { bufsize += increment; newbuf = realloc(buf, bufsize); } else { bufsize += bufchunk; newbuf = malloc(bufsize); } if (!newbuf) { r = Z_MEM_ERROR; goto zerr; } buf = newbuf; } uzs->zs.avail_out = bufsize - size; uzs->zs.next_out = buf + size; r = inflate(&uzs->zs, Z_NO_FLUSH); size = bufsize - uzs->zs.avail_out; if (r==Z_STREAM_END) break; if (r==Z_BUF_ERROR) { if (uzs->zs.avail_in) goto zerr; else break; // OK } if (r!=Z_OK) goto zerr; } lua_pushlstring(L, (const char*)buf, size); lua_pushboolean(L, r==Z_STREAM_END); end: free(buf); LUA_STACK_GUARD_RETURN(L,2) zerr: lua_pushnil(L); lua_pushnil(L); goto end; } static void *z_alloc(voidpf opaque, uInt items, uInt size) { return malloc((size_t)items*size); } static void z_free(voidpf opaque, voidpf address) { free(address); } static int luacall_gzip_init(lua_State *L) { // gzip_init(windowBits, level, memlevel) return zstream lua_check_argc_range(L,"gzip_init",0,3); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); int windowBits = (argc>=1 && !lua_isnil(L,1)) ? luaL_checkinteger(L, 1) : 31; int level = (argc>=2 && !lua_isnil(L,2)) ? luaL_checkinteger(L, 2) : 9; int memlevel = (argc>=3 && !lua_isnil(L,3)) ? luaL_checkinteger(L, 3) : 8; struct userdata_zs *uzs = (struct userdata_zs *)lua_newuserdata(L, sizeof(struct userdata_zs)); memset(&uzs->zs, 0, sizeof(uzs->zs)); uzs->zs.zalloc = z_alloc; uzs->zs.zfree = z_free; int r = deflateInit2(&uzs->zs, level, Z_DEFLATED, windowBits, memlevel, Z_DEFAULT_STRATEGY); if (r == Z_OK) { uzs->inflate = false; uzs->valid = true; luaL_newmetatable(L, "userdata_zstream"); lua_setmetatable(L, -2); } else { lua_pop(L,1); lua_pushnil(L); } LUA_STACK_GUARD_RETURN(L,1) } static int luacall_gzip_end(lua_State *L) { lua_check_argc(L,"gzip_end",1); LUA_STACK_GUARD_ENTER(L) struct userdata_zs *uzs = lua_uzs(L, 1, false); deflateEnd(&uzs->zs); uzs->valid = false; LUA_STACK_GUARD_RETURN(L,0) } static int luacall_gzip_deflate(lua_State *L) { // gzip_deflate(zstream, decompressed_data, expected_compressed_chunk_size) return compressed_data lua_check_argc_range(L,"gzip_deflate",1,3); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t l=0; int r, flush; size_t bufsize=0, size=0; uint8_t *buf=NULL, *newbuf; struct userdata_zs *uzs = lua_uzs(L, 1, false); if (argc>=2 && !lua_isnil(L,2)) { uzs->zs.next_in = (z_const Bytef*)luaL_checklstring(L,2,&l); uzs->zs.avail_in = (uInt)l; } size_t bufchunk = BUFMIN + (argc>=3 ? luaL_checkinteger(L,3) : l/2); size_t increment = bufchunk / 2; if (increment < Z_DEFL_BUF_INCREMENT) increment = Z_DEFL_BUF_INCREMENT; flush = l ? Z_NO_FLUSH : Z_FINISH; for(;;) { if ((bufsize - size) < BUFMIN) { if (buf) { bufsize += increment; newbuf = realloc(buf, bufsize); } else { bufsize += bufchunk; newbuf = malloc(bufsize); } if (!newbuf) { r = Z_MEM_ERROR; goto zerr; } buf = newbuf; } uzs->zs.avail_out = bufsize - size; uzs->zs.next_out = buf + size; r = deflate(&uzs->zs, flush); size = bufsize - uzs->zs.avail_out; if (r==Z_STREAM_END) break; if (r==Z_OK) { if (uzs->zs.avail_out && !uzs->zs.avail_in && flush != Z_FINISH) break; } else goto zerr; } lua_pushlstring(L, (const char*)buf, size); lua_pushboolean(L, r==Z_STREAM_END); end: free(buf); LUA_STACK_GUARD_RETURN(L,2) zerr: lua_pushnil(L); lua_pushnil(L); goto end; } static int luacall_stat(lua_State *L) { // stat(filename) return stat_table or nil,strerror,errno lua_check_argc(L,"stat",1); int n=1; struct stat st; if (stat(luaL_checkstring(L,1), &st)) { lua_pushnil(L); const char *err = strerror(errno); if (err) { lua_pushstring(L,err); lua_pushinteger(L,errno); return 3; } } else { lua_createtable(L, 0, 5); lua_pushf_lint(L,"dev", st.st_dev); lua_pushf_lint(L,"inode", st.st_ino); lua_pushf_lint(L,"size", st.st_size); lua_pushf_number(L,"mtime", st.st_mtim.tv_sec + st.st_mtim.tv_nsec/1000000000.); const char *ftype; switch(st.st_mode & S_IFMT) { case S_IFREG: ftype="file"; break; case S_IFDIR: ftype="dir"; break; case S_IFLNK: ftype="symlink"; break; case S_IFSOCK: ftype="socket"; break; case S_IFBLK: ftype="blockdev"; break; case S_IFCHR: ftype="chardev"; break; case S_IFIFO: ftype="fifo"; break; default: ftype="unknown"; break; } lua_pushf_str(L, "type", ftype); } return 1; } static void lua_xtime(lua_State *L, struct tm *(*timefunc)(const time_t *,struct tm *)) { struct tm t; time_t unixtime = (time_t)luaL_checklint(L,1); if (!timefunc(&unixtime, &t)) { lua_pushnil(L); } else { lua_createtable(L, 0, 11); lua_pushf_int(L,"sec", t.tm_sec); lua_pushf_int(L,"min", t.tm_min); lua_pushf_int(L,"hour", t.tm_hour); lua_pushf_int(L,"mday", t.tm_mday); lua_pushf_int(L,"mon", t.tm_mon); lua_pushf_int(L,"year", t.tm_year+1900); lua_pushf_int(L,"wday", t.tm_wday); lua_pushf_int(L,"yday", t.tm_yday); lua_pushf_int(L,"isdst", t.tm_isdst); lua_pushf_str(L,"zone", t.tm_zone); char s[24]; snprintf(s,sizeof(s),"%02d.%02d.%04d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec); lua_pushf_str(L,"str", s); } } static int luacall_localtime(lua_State *L) { // localtime(unixtime) lua_check_argc(L,"localtime",1); lua_xtime(L, localtime_r); return 1; } static int luacall_gmtime(lua_State *L) { // gmtime(unixtime) lua_check_argc(L,"gmtime",1); lua_xtime(L, gmtime_r); return 1; } #define TIMEX_VAL(v) \ lua_getfield(L,1,#v); \ if (lua_type(L,-1)!=LUA_TNUMBER) luaL_error(L,"invalid tm." #v); \ t.tm_##v = lua_tointeger(L,-1); \ lua_pop(L,1); static void lua_timex(lua_State *L, time_t (*timefunc)(struct tm *)) { if (lua_type(L,1)!=LUA_TTABLE) luaL_error(L,"invalid tm structure"); struct tm t; TIMEX_VAL(sec) TIMEX_VAL(min) TIMEX_VAL(hour) TIMEX_VAL(mday) TIMEX_VAL(mon) TIMEX_VAL(year) t.tm_year-=1900; TIMEX_VAL(isdst) time_t unixtime = timefunc(&t); if (unixtime==(time_t)-1) { lua_pushnil(L); } else lua_pushlint(L,unixtime); } static int luacall_timelocal(lua_State *L) { // timelocal(tm) lua_check_argc(L,"timelocal",1); lua_timex(L, mktime); return 1; } static int luacall_timegm(lua_State *L) { // timegm(tm) lua_check_argc(L,"timegm",1); lua_timex(L, timegm); return 1; } // ---------------------------------------- void lua_cleanup(lua_State *L) { lua_desync_ctx_destroy(L); // conntrack holds lua state. must clear it before lua shoudown ConntrackPoolDestroy(¶ms.conntrack); } void lua_shutdown() { if (params.L) { DLOG("LUA SHUTDOWN\n"); lua_cleanup(params.L); lua_close(params.L); params.L=NULL; } } #if LUA_VERSION_NUM >= 504 static void lua_warn(void *ud, const char *msg, int tocont) { DLOG_CONDUP("LUA WARNING: %s\n",msg); } #endif static void lua_perror(lua_State *L) { if (lua_isstring(L, -1)) { const char *error_message = lua_tostring(L, -1); DLOG_ERR("LUA ERROR: %s\n", error_message); } lua_pop(L, 1); } static int lua_panic(lua_State *L) { lua_perror(L); DLOG_ERR("LUA PANIC: THIS IS FATAL. DYING.\n"); exit(100); return 0; } static bool lua_basic_init() { lua_shutdown(); if (!(params.L = luaL_newstate())) { DLOG_ERR("LUA INIT ERROR\n"); return false; } unsigned int ver; #if LUA_VERSION_NUM >= 504 ver = (unsigned int)lua_version(params.L); #elif LUA_VERSION_NUM >= 502 ver = (unsigned int)*lua_version(params.L); #else ver = LUA_VERSION_NUM; #endif #ifdef LUAJIT_VERSION #ifdef OPENRESTY_LUAJIT #define LJSUBVER " OpenResty" #else #define LJSUBVER "" #endif DLOG_CONDUP("LUA v%u.%u %s%s\n",ver/100,ver%100, LUAJIT_VERSION, LJSUBVER); #else DLOG_CONDUP("LUA v%u.%u\n",ver/100,ver%100); #endif #if LUA_VERSION_NUM >= 504 lua_setwarnf(params.L,lua_warn,NULL); #endif lua_atpanic(params.L,lua_panic); luaL_openlibs(params.L); /* Load Lua libraries */ lua_getfield(params.L, LUA_REGISTRYINDEX, "_LOADED"); if (lua_type(params.L, -1)==LUA_TTABLE) { lua_getfield(params.L, -1, "jit"); if (lua_type(params.L, -1)==LUA_TTABLE) { lua_getfield(params.L, -1, "status"); if (lua_type(params.L, -1)==LUA_TFUNCTION) { const char *s; int n = lua_gettop(params.L); lua_call(params.L, 0, LUA_MULTRET); DLOG_CONDUP(lua_toboolean(params.L, n) ? "JIT: ON" : "JIT: OFF"); for (n++; (s = lua_tostring(params.L, n)); n++) DLOG_CONDUP(" %s", s); DLOG_CONDUP("\n"); } } } lua_settop(params.L, 0); return true; } static bool lua_desync_functions_exist() { struct desync_profile_list *dpl; struct func_list *func; LIST_FOREACH(dpl, ¶ms.desync_profiles, next) { LIST_FOREACH(func, &dpl->dp.lua_desync, next) { lua_getglobal(params.L, func->func); if (!lua_isfunction(params.L,-1)) { lua_pop(params.L,1); DLOG_ERR("desync function '%s' does not exist\n",func->func); return false; } lua_pop(params.L,1); } } return true; } static bool lua_file_open_test(const char *filename, bool *b_gzip, char *fname) { FILE *F = fopen(filename,"rb"); if (F) { if (fname) snprintf(fname,PATH_MAX,"%s",filename); } else { size_t l = strlen(filename); char *fngz = malloc(l+4); if (!fngz) return false; memcpy(fngz, filename, l); memcpy(fngz+l,".gz",4); if (fname) snprintf(fname,PATH_MAX,"%s",fngz); F = fopen(fngz,"rb"); free(fngz); } if (F) { if (b_gzip) *b_gzip = is_gzip(F); fclose(F); } return F; } bool lua_test_init_script_files(void) { struct str_list *str; LIST_FOREACH(str, ¶ms.lua_init_scripts, next) { if (str->str[0]=='@' && !lua_file_open_test(str->str+1, NULL, NULL)) { #ifndef __CYGWIN__ int e = errno; #endif DLOG_ERR("LUA file '%s' or '%s.gz' not accessible\n", str->str+1, str->str+1); #ifndef __CYGWIN__ if (e==EACCES) DLOG_ERR("I drop my privileges and do not run Lua as root\ncheck file permissions and +x rights on all directories in the path\n"); #endif return false; } } return true; } static int luaL_doZfile(lua_State *L, const char *filename) { bool b_gzip; char fname[PATH_MAX]; if (!lua_file_open_test(filename, &b_gzip, fname)) luaL_error(L, "could not open lua file '%s' or '%s.gz'", filename, filename); if (b_gzip) { size_t size; char *buf; int r; FILE *F = fopen(fname, "rb"); if (!F) luaL_error(L, "could not open lua file '%s'", fname); r = z_readfile(F, &buf, &size, 0); fclose(F); if (r != Z_STREAM_END) luaL_error(L, "could not unzip lua file '%s'", fname); r = luaL_loadbuffer(L, buf, size, fname); free(buf); if (!r) r=lua_pcall(L, 0, LUA_MULTRET, 0); return r; } else return luaL_dofile(L, fname); } static bool lua_init_scripts(void) { struct str_list *str; int status; LIST_FOREACH(str, ¶ms.lua_init_scripts, next) { if (bQuit) return false; if (params.debug) { if (str->str[0]=='@') DLOG("LUA RUN FILE: %s\n",str->str+1); else { char s[128]; snprintf(s,sizeof(s),"%s",str->str); DLOG("LUA RUN STR: %s\n",s); } } if ((status = str->str[0]=='@' ? luaL_doZfile(params.L, str->str+1) : luaL_dostring(params.L, str->str))) { lua_perror(params.L); return false; } } return true; } static void lua_sec_harden(void) { LUA_STACK_GUARD_ENTER(params.L) // remove unwanted functions. lua scripts are not intended to execute files const struct { const char *global, *field, *field2; } bad[] = { {"os","execute",NULL}, {"io","popen",NULL}, {"package","loadlib",NULL}, {"debug", NULL, NULL}, {"package", "loaded", "debug"} }; DLOG("LUA REMOVE:"); for (int i=0;iname, blob->size); lua_pushlstring(params.L, (char*)blob->data, blob->size); lua_setglobal(params.L, blob->name); blob_destroy(blob); } LUA_STACK_GUARD_LEAVE(params.L, 0) } static void lua_init_const(void) { LUA_STACK_GUARD_ENTER(params.L) const struct { const char *name, *v; } cstr[] = { {"NFQWS2_VER",params.verstr} }; DLOG("LUA STR:"); for (int i=0;i= params.lua_gc) { int kb1 = lua_gc(params.L, LUA_GCCOUNT, 0); lua_gc(params.L, LUA_GCCOLLECT, 0); int kb2 = lua_gc(params.L, LUA_GCCOUNT, 0); DLOG("\nLUA GARBAGE COLLECT: %dK => %dK\n",kb1,kb2); gc_time = now; } } }