#include #include "lua.h" #include "params.h" #include "helpers.h" 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(params.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; } static int luacall_bitlshift(lua_State *L) { lua_check_argc(L,"bitlshift",2); lua_pushinteger(L,luaL_checkinteger(L,1) << luaL_checkinteger(L,2)); return 1; } static int luacall_bitrshift(lua_State *L) { lua_check_argc(L,"bitrshift",2); lua_pushinteger(L,((LUA_UNSIGNED)luaL_checkinteger(L,1)) >> luaL_checkinteger(L,2)); return 1; } static int luacall_bitand(lua_State *L) { lua_check_argc_range(L,"bitand",2,100); int argc = lua_gettop(L); lua_Integer v=luaL_checkinteger(L,1); for(int i=2;i<=argc;i++) v&=luaL_checkinteger(L,i); lua_pushinteger(L,v); return 1; } static int luacall_bitor(lua_State *L) { lua_check_argc_range(L,"bitor",2,100); int argc = lua_gettop(L); lua_Integer v=0; for(int i=1;i<=argc;i++) v|=luaL_checkinteger(L,i); lua_pushinteger(L,v); return 1; } static int luacall_bitnot(lua_State *L) { lua_check_argc(L,"bitnot",1); lua_pushinteger(L,~luaL_checkinteger(L,1)); return 1; } static int luacall_bitxor(lua_State *L) { lua_check_argc_range(L,"bitxor",2,100); int argc = lua_gettop(L); lua_Integer v=0; for(int i=1;i<=argc;i++) v^=luaL_checkinteger(L,i); lua_pushinteger(L,v); return 1; } static int luacall_bitget(lua_State *L) { lua_check_argc(L,"bitget",3); LUA_UNSIGNED what = (LUA_UNSIGNED)luaL_checkinteger(L,1); lua_Integer from = luaL_checkinteger(L,2); lua_Integer to = luaL_checkinteger(L,3); if (from>to || from>63 || to>63) luaL_error(L, "bit range invalid"); what = (what >> from) & ~((lua_Integer)-1 << (to-from+1)); lua_pushinteger(L,what); return 1; } static int luacall_bitset(lua_State *L) { lua_check_argc(L,"bitset",4); LUA_UNSIGNED what = (LUA_UNSIGNED)luaL_checkinteger(L,1); lua_Integer from = luaL_checkinteger(L,2); lua_Integer to = luaL_checkinteger(L,3); LUA_UNSIGNED set = (LUA_UNSIGNED)luaL_checkinteger(L,4); if (from>to || from>63 || to>63) luaL_error(L, "bit range invalid"); lua_Integer mask = ~((lua_Integer)-1 << (to-from+1)); set = (set & mask) << from; mask <<= from; what = what & ~mask | set; lua_pushinteger(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*)luaL_checklstring(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*)luaL_checklstring(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*)luaL_checklstring(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*)luaL_checklstring(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_pushinteger(L,pntoh32(p+offset)); return 1; } static int luacall_bu8(lua_State *L) { lua_check_argc(L,"bu8",1); lua_Integer i = luaL_checkinteger(L,1); if (i & ~(uint64_t)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); lua_Integer i = luaL_checkinteger(L,1); if (i & ~(uint64_t)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); lua_Integer i = luaL_checkinteger(L,1); if (i & ~(uint64_t)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); lua_Integer i = luaL_checkinteger(L,1); if (i & ~(uint64_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_divint(lua_State *L) { lua_check_argc(L,"divint",2); lua_Integer v1=luaL_checkinteger(L,1); lua_Integer v2=luaL_checkinteger(L,2); if (v2) lua_pushinteger(L,v1/v2); else lua_pushnil(L); return 1; } static int luacall_brandom(lua_State *L) { lua_check_argc(L,"brandom",1); lua_Integer len = luaL_checkinteger(L,1); uint8_t *p = malloc(len); if (!p) luaL_error(L, "out of memory"); fill_random_bytes(p,len); // in out of memory condition this will leave p unfreed lua_pushlstring(L,(char*)p,len); free(p); return 1; } static int luacall_brandom_az(lua_State *L) { lua_check_argc(L,"brandom_az",1); lua_Integer len = luaL_checkinteger(L,1); uint8_t *p = malloc(len); if (!p) luaL_error(L, "out of memory"); fill_random_az(p,len); // in out of memory condition this will leave p unfreed lua_pushlstring(L,(char*)p,len); free(p); return 1; } static int luacall_brandom_az09(lua_State *L) { lua_check_argc(L,"brandom_az09",1); lua_Integer len = luaL_checkinteger(L,1); uint8_t *p = malloc(len); if (!p) luaL_error(L, "out of memory"); fill_random_az09(p,len); // in out of memory condition this will leave p unfreed lua_pushlstring(L,(char*)p,len); free(p); return 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_tolstring(L,1,&l); if ((l&1)) goto err; l>>=1; uint8_t *p = malloc(l); if (!p) goto err; if (!parse_hex_str(hex,p,&l)) { free(p); goto err; } // in out of memory condition this will leave p unfreed lua_pushlstring(L,(char*)p,l); free(p); ex: LUA_STACK_GUARD_RETURN(L,1) err: lua_pushnil(L); goto ex; } static SHAversion lua_hash_type(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(params.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); uint8_t *p = malloc(len); if (!p) luaL_error(L, "out of memory"); if (!fill_crypto_random_bytes(p,len)) { free(p); // this is fatal. they expect us to give them crypto secure random blob luaL_error(L, "could not read random data from /dev/random"); } lua_pushlstring(L,(char*)p,len); free(p); LUA_STACK_GUARD_RETURN(L,1) } 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(s_hash_type); size_t data_len; const uint8_t *data = (uint8_t*)luaL_checklstring(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_gcm(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*)luaL_checklstring(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*)luaL_checklstring(L,3,&input_len); if (input_len!=16) luaL_error(L, "aes: wrong data length %u. should be 16.", (unsigned)input_len); aes_init_keygen_tables(); 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*)luaL_checklstring(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*)luaL_checklstring(L,3,&iv_len); if (iv_len!=12) luaL_error(L, "aes_gcm: wrong iv length %u. should be 12.", (unsigned)iv_len); size_t input_len; const uint8_t *input = (uint8_t*)luaL_checklstring(L,4,&input_len); size_t add_len=0; const uint8_t *add = lua_isnoneornil(L,5) ? NULL : (uint8_t*)luaL_checklstring(L,5,&add_len); uint8_t atag[16]; uint8_t *output = malloc(input_len); if (!output) luaL_error(L, "out of memory"); gcm_initialize(); 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)); } free(output); LUA_STACK_GUARD_RETURN(L,2) } 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(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); size_t okm_len = (size_t)luaL_checkinteger(L,5); uint8_t *okm = malloc(okm_len); if (!okm) luaL_error(L, "out of memory"); 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); free(okm); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_instance_cutoff(lua_State *L) { // out : func_name.profile_number[0] // in : func_name.profile_number[1] lua_check_argc_range(L,"instance_cutoff",1,2); LUA_STACK_GUARD_ENTER(L) const t_lua_desync_context *ctx; if (!lua_islightuserdata(L,1)) luaL_error(L, "instance_cutoff expect desync context in the first argument"); ctx = lua_touserdata(L,1); int argc=lua_gettop(L); bool bIn,bOut; if (argc>=2) { 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(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(ctx->dp->n); lua_rawgeti(L,-1,ctx->dp->n); } if (bOut) lua_pushi_bool(0,true); if (bIn) lua_pushi_bool(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(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(params.L,LUA_REGISTRYINDEX,ctx->ctrack->lua_instance_cutoff); lua_getfield(params.L,-1,ctx->instance); if (!lua_istable(params.L,-1)) { lua_pop(params.L,2); return false; } lua_rawgeti(params.L,-1,ctx->dp->n); if (!lua_istable(params.L,-1)) { lua_pop(params.L,3); return false; } lua_rawgeti(params.L,-1,bIn); b = lua_toboolean(params.L,-1); lua_pop(params.L,4); } return b; } void lua_pushf_nil(const char *field) { lua_pushstring(params.L, field); lua_pushnil(params.L); lua_rawset(params.L,-3); } void lua_pushi_nil(lua_Integer idx) { lua_pushinteger(params.L, idx); lua_pushnil(params.L); lua_rawset(params.L,-3); } void lua_pushf_int(const char *field, lua_Integer v) { lua_pushstring(params.L, field); lua_pushinteger(params.L, v); lua_rawset(params.L,-3); } void lua_pushi_int(lua_Integer idx, lua_Integer v) { lua_pushinteger(params.L, idx); lua_pushinteger(params.L, v); lua_rawset(params.L,-3); } void lua_pushf_bool(const char *field, bool b) { lua_pushstring(params.L, field); lua_pushboolean(params.L, b); lua_rawset(params.L,-3); } void lua_pushi_bool(lua_Integer idx, bool b) { lua_pushinteger(params.L, idx); lua_pushboolean(params.L, b); lua_rawset(params.L,-3); } void lua_pushf_str(const char *field, const char *str) { lua_pushstring(params.L, field); lua_pushstring(params.L, str); // pushes nil if str==NULL lua_rawset(params.L,-3); } void lua_pushi_str(lua_Integer idx, const char *str) { lua_pushinteger(params.L, idx); lua_pushstring(params.L, str); // pushes nil if str==NULL lua_rawset(params.L,-3); } void lua_push_raw(const void *v, size_t l) { if (v) lua_pushlstring(params.L, (char*)v, l); else lua_pushnil(params.L); } void lua_pushf_raw(const char *field, const void *v, size_t l) { lua_pushstring(params.L, field); lua_push_raw(v,l); lua_rawset(params.L,-3); } void lua_pushi_raw(lua_Integer idx, const void *v, size_t l) { lua_pushinteger(params.L, idx); lua_push_raw(v,l); lua_rawset(params.L,-3); } void lua_pushf_reg(const char *field, int ref) { lua_pushstring(params.L, field); lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref); lua_rawset(params.L, -3); } void lua_pushf_lud(const char *field, void *p) { lua_pushstring(params.L, field); lua_pushlightuserdata(params.L, p); lua_rawset(params.L,-3); } void lua_pushf_table(const char *field) { lua_pushstring(params.L, field); lua_newtable(params.L); lua_rawset(params.L,-3); } void lua_pushi_table(lua_Integer idx) { lua_pushinteger(params.L, idx); lua_newtable(params.L); lua_rawset(params.L,-3); } void lua_pushf_global(const char *field, const char *global) { lua_pushstring(params.L, field); lua_getglobal(params.L, global); lua_rawset(params.L,-3); } void lua_pushf_tcphdr_options(const struct tcphdr *tcp, size_t len) { lua_pushliteral(params.L,"options"); lua_newtable(params.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(params.L,idx); lua_newtable(params.L); lua_pushf_int("kind",opt); lua_pushf_raw("data",t+2,t[1]-2); t+=t[1]; } lua_rawset(params.L,-3); if (opt==TCP_KIND_END) break; idx++; } lua_rawset(params.L,-3); } void lua_pushf_tcphdr(const struct tcphdr *tcp, size_t len) { lua_pushliteral(params.L, "tcp"); if (tcp && len>=sizeof(struct tcphdr)) { lua_createtable(params.L, 0, 11); lua_pushf_int("th_sport",ntohs(tcp->th_sport)); lua_pushf_int("th_dport",ntohs(tcp->th_dport)); lua_pushf_int("th_seq",ntohl(tcp->th_seq)); lua_pushf_int("th_ack",ntohl(tcp->th_ack)); lua_pushf_int("th_x2",tcp->th_x2); lua_pushf_int("th_off",tcp->th_off); lua_pushf_int("th_flags",tcp->th_flags); lua_pushf_int("th_win",ntohs(tcp->th_win)); lua_pushf_int("th_sum",ntohs(tcp->th_sum)); lua_pushf_int("th_urp",ntohs(tcp->th_urp)); lua_pushf_tcphdr_options(tcp,len); } else lua_pushnil(params.L); lua_rawset(params.L,-3); } void lua_pushf_udphdr(const struct udphdr *udp, size_t len) { lua_pushliteral(params.L, "udp"); if (udp && len>=sizeof(struct udphdr)) { lua_createtable(params.L, 0, 4); lua_pushf_int("uh_sport",ntohs(udp->uh_sport)); lua_pushf_int("uh_dport",ntohs(udp->uh_dport)); lua_pushf_int("uh_ulen",ntohs(udp->uh_ulen)); lua_pushf_int("uh_sum",ntohs(udp->uh_sum)); } else lua_pushnil(params.L); lua_rawset(params.L,-3); } void lua_pushf_iphdr(const struct ip *ip, size_t len) { lua_pushliteral(params.L, "ip"); if (ip && len>=sizeof(struct ip)) { uint16_t hl = ip->ip_hl<<2; bool b_has_opt = hl>sizeof(struct tcphdr) && hl<=len; lua_createtable(params.L, 0, 11+b_has_opt); lua_pushf_int("ip_v",ip->ip_v); lua_pushf_int("ip_hl",ip->ip_hl); lua_pushf_int("ip_tos",ip->ip_tos); lua_pushf_int("ip_len",ntohs(ip->ip_len)); lua_pushf_int("ip_id",ntohs(ip->ip_id)); lua_pushf_int("ip_off",ntohs(ip->ip_off)); lua_pushf_int("ip_ttl",ip->ip_ttl); lua_pushf_int("ip_p",ip->ip_p); lua_pushf_int("ip_sum",ip->ip_sum); lua_pushf_raw("ip_src",&ip->ip_src,sizeof(struct in_addr)); lua_pushf_raw("ip_dst",&ip->ip_dst,sizeof(struct in_addr)); if (b_has_opt) lua_pushf_raw("options",(uint8_t*)(ip+1),hl-sizeof(struct tcphdr)); } else lua_pushnil(params.L); lua_rawset(params.L,-3); } void lua_pushf_ip6exthdr(const struct ip6_hdr *ip6, size_t len) { // assume ipv6 packet structure was already checked for validity size_t hdrlen; uint8_t HeaderType, *data; lua_Integer idx = 1; lua_pushliteral(params.L, "exthdr"); lua_newtable(params.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); while (len > 0) // need at least one byte for NextHeader field { 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) return; // error hdrlen = 8 + (data[1] << 3); break; case IPPROTO_FRAGMENT: // fragment. length fixed to 8, hdrlen field defined as reserved hdrlen = 8; break; case IPPROTO_AH: // special case. length in ah header is in 32-bit words minus 2 if (len < 2) return; // 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(params.L, idx++); lua_createtable(params.L, 0, 3); lua_pushf_int("type", HeaderType); HeaderType = *data; lua_pushf_int("next", HeaderType); lua_pushf_raw("data",data+2,hdrlen-2); lua_rawset(params.L,-3); // advance to the next header location len -= hdrlen; data += hdrlen; } } end: lua_rawset(params.L,-3); } void lua_pushf_ip6hdr(const struct ip6_hdr *ip6, size_t len) { lua_pushliteral(params.L, "ip6"); if (ip6) { lua_createtable(params.L, 0, 7); lua_pushf_int("ip6_flow",ntohl(ip6->ip6_ctlun.ip6_un1.ip6_un1_flow)); lua_pushf_int("ip6_plen",ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen)); lua_pushf_int("ip6_nxt",ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt); lua_pushf_int("ip6_hlim",ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim); lua_pushf_raw("ip6_src",&ip6->ip6_src,sizeof(struct in6_addr)); lua_pushf_raw("ip6_dst",&ip6->ip6_dst,sizeof(struct in6_addr)); lua_pushf_ip6exthdr(ip6,len); } else lua_pushnil(params.L); lua_rawset(params.L,-3); } void lua_push_dissect(const struct dissect *dis) { if (dis) { lua_createtable(params.L, 0, 7); lua_pushf_iphdr(dis->ip, dis->len_l3); lua_pushf_ip6hdr(dis->ip6, dis->len_l3); lua_pushf_tcphdr(dis->tcp, dis->len_l4); lua_pushf_udphdr(dis->udp, dis->len_l4); lua_pushf_int("l4proto",dis->proto); lua_pushf_int("transport_len",dis->transport_len); lua_pushf_raw("payload",dis->data_payload,dis->len_payload); } else lua_pushnil(params.L); } void lua_pushf_dissect(const struct dissect *dis) { lua_pushliteral(params.L, "dis"); lua_push_dissect(dis); lua_rawset(params.L,-3); } void lua_pushf_ctrack(const t_ctrack *ctrack) { lua_pushliteral(params.L, "track"); if (ctrack) { lua_createtable(params.L, 0, 13 + (ctrack->ipproto == IPPROTO_TCP)); lua_pushf_int("pcounter_orig", ctrack->pcounter_orig); lua_pushf_int("pdcounter_orig", ctrack->pdcounter_orig); lua_pushf_int("pbcounter_orig", ctrack->pbcounter_orig); lua_pushf_int("pcounter_reply", ctrack->pcounter_reply); lua_pushf_int("pdcounter_reply", ctrack->pdcounter_reply); lua_pushf_int("pbcounter_reply", ctrack->pbcounter_reply); if (ctrack->incoming_ttl) lua_pushf_int("incoming_ttl", ctrack->incoming_ttl); else lua_pushf_nil("incoming_ttl"); lua_pushf_str("l7proto", l7proto_str(ctrack->l7proto)); lua_pushf_str("hostname", ctrack->hostname); lua_pushf_bool("hostname_is_ip", ctrack->hostname_is_ip); lua_pushf_reg("lua_state", ctrack->lua_state); lua_pushf_bool("lua_in_cutoff", ctrack->b_lua_in_cutoff); lua_pushf_bool("lua_out_cutoff", ctrack->b_lua_out_cutoff); if (ctrack->ipproto == IPPROTO_TCP) { lua_pushliteral(params.L, "tcp"); lua_createtable(params.L, 0, 14); lua_pushf_int("seq0", ctrack->seq0); lua_pushf_int("seq", ctrack->seq_last); lua_pushf_int("ack0", ctrack->ack0); lua_pushf_int("ack", ctrack->ack_last); lua_pushf_int("pos_orig", ctrack->pos_orig - ctrack->seq0); lua_pushf_int("winsize_orig", ctrack->winsize_orig); lua_pushf_int("winsize_orig_calc", ctrack->winsize_orig_calc); lua_pushf_int("scale_orig", ctrack->scale_orig); lua_pushf_int("mss_orig", ctrack->mss_orig); lua_pushf_int("pos_reply", ctrack->pos_reply - ctrack->ack0); lua_pushf_int("winsize_reply", ctrack->winsize_reply); lua_pushf_int("winsize_reply_calc", ctrack->winsize_reply_calc); lua_pushf_int("scale_reply", ctrack->scale_reply); lua_pushf_int("mss_reply", ctrack->mss_reply); lua_rawset(params.L,-3); } } else lua_pushnil(params.L); lua_rawset(params.L,-3); } void lua_pushf_args(const struct ptr_list_head *args) { struct ptr_list *arg; lua_pushliteral(params.L,"arg"); lua_newtable(params.L); LIST_FOREACH(arg, args, next) { lua_pushf_str((char*)arg->ptr1,arg->ptr2 ? (char*)arg->ptr2 : ""); } lua_rawset(params.L,-3); } static void lua_reconstruct_extract_options(lua_State *L, int idx, bool *badsum, bool *ip6_preserve_next, uint8_t *ip6_last_proto) { if (lua_isnoneornil(L,idx)) { 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 (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(int idx, struct ip6_hdr *ip6, size_t *len, uint8_t proto, bool preserve_next) { // proto = last header type if (*lenip6_ctlun.ip6_un1.ip6_un1_nxt; uint8_t filled = sizeof(struct ip6_hdr); lua_getfield(params.L,idx,"exthdr"); if (lua_type(params.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(params.L,-1,++idx); if (lua_type(params.L,-1)==LUA_TNIL) { lua_pop(params.L, 1); break; } else { if (lua_type(params.L,-1)!=LUA_TTABLE) goto err2; lua_getfield(params.L,-1, "type"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err3; type = (uint8_t)lua_tointeger(params.L,-1); lua_pop(params.L, 1); lua_getfield(params.L,-1, "next"); next = lua_type(params.L,-1)==LUA_TNUMBER ? (uint8_t)lua_tointeger(params.L,-1) : IPPROTO_NONE; lua_pop(params.L, 1); lua_getfield(params.L,-1, "data"); if (lua_type(params.L,-1)!=LUA_TSTRING) goto err3; p=(uint8_t*)lua_tolstring(params.L,-1,&l); if (!l || (l+2)>left || ((type==IPPROTO_AH) ? (l<6 || ((l+2) & 3)) : ((l+2) & 7))) goto err3; memcpy(data+2,p,l); l+=2; data[0] = next; // may be overwritten later data[1] = (type==IPPROTO_AH) ? (l>>2)-2 : (l>>3)-1; if (!preserve_next) *last_proto = type; last_proto = data; // first byte of header holds type left -= l; data += l; filled += l; lua_pop(params.L, 2); } } } // set last header proto if (!preserve_next) *last_proto = proto; *len = filled; lua_pop(params.L, 1); return true; err2: lua_pop(params.L, 2); return false; err3: lua_pop(params.L, 3); return false; } bool lua_reconstruct_ip6hdr(int idx, struct ip6_hdr *ip6, size_t *len, uint8_t last_proto, bool preserve_next) { const char *p; size_t l; if (*lenip6_ctlun.ip6_un1.ip6_un1_flow = htonl(lua_type(params.L,-1)==LUA_TNUMBER ? (uint32_t)lua_tointeger(params.L,-1) : 0x60000000); lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip6_plen"); ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip6_nxt"); ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt = (uint8_t)lua_tointeger(params.L,-1); lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip6_hlim"); ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = (uint8_t)lua_tointeger(params.L,-1); lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip6_src"); if (lua_type(params.L,-1)!=LUA_TSTRING) goto err; p = lua_tolstring(params.L,-1,&l); if (l!=sizeof(struct in6_addr)) goto err; ip6->ip6_src = *(struct in6_addr*)p; lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip6_dst"); if (lua_type(params.L,-1)!=LUA_TSTRING) goto err; p = lua_tolstring(params.L,-1,&l); if (l!=sizeof(struct in6_addr)) goto err; ip6->ip6_dst = *(struct in6_addr*)p; lua_pop(params.L, 1); return lua_reconstruct_ip6exthdr(idx, ip6, len, last_proto, preserve_next); err: lua_pop(params.L, 1); 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, &preserve_next, &last_proto); if (!lua_reconstruct_ip6hdr(1,(struct ip6_hdr*)data, &len, last_proto, preserve_next)) luaL_error(L, "invalid data for ip6hdr"); lua_pushlstring(params.L,data,len); LUA_STACK_GUARD_RETURN(L,1) } bool lua_reconstruct_iphdr(int idx, struct ip *ip, size_t *len) { const char *p; size_t l, lopt=0; if (*lenip_v = IPVERSION; lua_getfield(params.L,idx,"ip_tos"); ip->ip_tos = (uint8_t)lua_tointeger(params.L,-1); lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip_len"); ip->ip_len = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip_id"); ip->ip_id = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip_off"); ip->ip_off = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip_ttl"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err; ip->ip_ttl = (uint8_t)lua_tointeger(params.L,-1); lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip_p"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err; ip->ip_p = (uint8_t)lua_tointeger(params.L,-1); lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip_src"); if (lua_type(params.L,-1)!=LUA_TSTRING) goto err; p = lua_tolstring(params.L,-1,&l); if (l!=sizeof(struct in_addr)) goto err; ip->ip_src = *(struct in_addr*)p; lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip_dst"); if (lua_type(params.L,-1)!=LUA_TSTRING) goto err; p = lua_tolstring(params.L,-1,&l); if (l!=sizeof(struct in_addr)) goto err; ip->ip_dst = *(struct in_addr*)p; lua_pop(params.L, 1); lua_getfield(params.L,idx,"options"); if (lua_type(params.L,-1)==LUA_TSTRING) { p = lua_tolstring(params.L,-1,&lopt); if (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(params.L, 1); *len = sizeof(struct ip) + lopt; ip->ip_hl = *len >> 2; ip4_fix_checksum(ip); return true; err: lua_pop(params.L, 1); 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(1,(struct ip*)&data,&l)) luaL_error(L, "invalid data for iphdr"); lua_pushlstring(params.L,data,l); LUA_STACK_GUARD_RETURN(L,1) } static bool lua_reconstruct_tcphdr_options(int idx, struct tcphdr *tcp, size_t *len) { if (*len40) left=40; // max size of tcp options for (;;) { lua_rawgeti(params.L,-1,++idx); if (lua_type(params.L,-1)==LUA_TNIL) { lua_pop(params.L, 1); break; } else { // uses 'key' (at index -2) and 'value' (at index -1) if (!left || lua_type(params.L,-1)!=LUA_TTABLE) goto err2; lua_getfield(params.L,-1, "kind"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err3; kind = (uint8_t)lua_tointeger(params.L,-1); lua_pop(params.L, 1); switch(kind) { case TCP_KIND_END: *data = kind; data++; left--; filled++; lua_pop(params.L, 1); goto end; case TCP_KIND_NOOP: *data = kind; data++; left--; filled++; break; default: lua_getfield(params.L,-1, "data"); l = 0; p = lua_type(params.L,-1)==LUA_TSTRING ? (uint8_t*)lua_tolstring(params.L,-1,&l) : NULL; if ((2+l)>left) goto err3; 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(params.L, 1); } lua_pop(params.L, 1); } } end: while(filled & 3) { if (!left) goto err1; *data = TCP_KIND_NOOP; data++; left--; filled++; } } tcp->th_off = filled>>2; *len = filled; lua_pop(params.L, 1); return true; err1: lua_pop(params.L, 1); return false; err2: lua_pop(params.L, 2); return false; err3: lua_pop(params.L, 3); return false; } bool lua_reconstruct_tcphdr(int idx, struct tcphdr *tcp, size_t *len) { if (*lenth_sport = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"th_dport"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err; tcp->th_dport = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"th_seq"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err; tcp->th_seq = htonl((uint32_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"th_ack"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err; tcp->th_ack = htonl((uint32_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"th_x2"); tcp->th_x2 = (uint8_t)lua_tointeger(params.L,-1); lua_pop(params.L, 1); lua_getfield(params.L,idx,"th_flags"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err; tcp->th_flags = (uint8_t)lua_tointeger(params.L,-1); lua_pop(params.L, 1); lua_getfield(params.L,idx,"th_win"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err; tcp->th_win = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"th_sum"); tcp->th_sum = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"th_urp"); tcp->th_urp = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); tcp->th_off = 5; return lua_reconstruct_tcphdr_options(idx, tcp, len); err: lua_pop(params.L, 1); 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(1,(struct tcphdr*)data,&len)) luaL_error(L, "invalid data for tcphdr"); lua_pushlstring(params.L,data,len); LUA_STACK_GUARD_RETURN(L,1) } bool lua_reconstruct_udphdr(int idx, struct udphdr *udp) { if (lua_type(params.L,-1)!=LUA_TTABLE) return false; lua_getfield(params.L,idx,"uh_sport"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err; udp->uh_sport = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"uh_dport"); if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err; udp->uh_dport = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"uh_ulen"); udp->uh_ulen = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); lua_getfield(params.L,idx,"uh_sum"); udp->uh_sum = htons((uint16_t)lua_tointeger(params.L,-1)); lua_pop(params.L, 1); return true; err: lua_pop(params.L, 1); 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(1,&udp)) luaL_error(L, "invalid data for udphdr"); lua_pushlstring(params.L,(char*)&udp,sizeof(udp)); LUA_STACK_GUARD_RETURN(L,1) } uint8_t lua_ip6_l4proto_from_dissect(int idx) { int type; lua_getfield(params.L,idx,"tcp"); type=lua_type(params.L,-1); lua_pop(params.L,1); if (type==LUA_TTABLE) return IPPROTO_TCP; lua_getfield(params.L,idx,"udp"); type=lua_type(params.L,-1); lua_pop(params.L,1); return type==LUA_TTABLE ? IPPROTO_UDP : IPPROTO_NONE; } bool lua_reconstruct_dissect(int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next) { uint8_t *data = buf; size_t l,lpayload,l3,left = *len; struct ip *ip=NULL; struct ip6_hdr *ip6=NULL; struct tcphdr *tcp=NULL; struct udphdr *udp=NULL; const char *p; idx = lua_absindex(params.L, idx); lua_getfield(params.L,idx,"ip"); l = left; if (lua_type(params.L,-1)==LUA_TTABLE) { ip = (struct ip*)data; if (!lua_reconstruct_iphdr(-1, ip, &l)) { DLOG_ERR("reconstruct_dissect: bad ip\n"); goto err; } ip4_fix_checksum(ip); } else { lua_pop(params.L, 1); lua_getfield(params.L,idx,"ip6"); if (lua_type(params.L,-1)!=LUA_TTABLE) goto err; ip6 = (struct ip6_hdr*)data; if (!lua_reconstruct_ip6hdr(-1, ip6, &l, lua_ip6_l4proto_from_dissect(idx), ip6_preserve_next)) { DLOG_ERR("reconstruct_dissect: bad ip6\n"); goto err; } } l3=l; data+=l; left-=l; lua_pop(params.L, 1); lua_getfield(params.L,idx,"tcp"); l = left; if (lua_type(params.L,-1)==LUA_TTABLE) { tcp = (struct tcphdr*)data; if (!lua_reconstruct_tcphdr(-1, tcp, &l)) { DLOG_ERR("reconstruct_dissect: bad tcp\n"); goto err; } } else { lua_pop(params.L, 1); lua_getfield(params.L,idx,"udp"); l = sizeof(struct udphdr); if (lua_type(params.L,-1)!=LUA_TTABLE || leftuh_ulen = htons((uint16_t)(lpayload+sizeof(struct udphdr))); udp_fix_checksum(udp,l-l3,ip,ip6); if (badsum) udp->uh_sum ^= 1 + (random() % 0xFFFF); } if (tcp) { tcp_fix_checksum(tcp,l-l3,ip,ip6); if (badsum) tcp->th_sum ^= 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; } if (frag_start>l) { DLOG_ERR("ipv4 frag : fragment offset is outside of the packet\n"); goto err; } if (off) memmove(buf+l3,buf+l3+off,iplen-l3); 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; return true; err: lua_pop(params.L, 1); 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) uint8_t buf[RECONSTRUCT_MAX_SIZE]; size_t l = sizeof(buf); bool ip6_preserve_next, badsum; lua_reconstruct_extract_options(params.L, 2, &badsum, &ip6_preserve_next, NULL); if (!lua_reconstruct_dissect(1, buf, &l, badsum, ip6_preserve_next)) luaL_error(L, "invalid dissect data"); lua_pushlstring(params.L,(char*)buf,l); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_dissect(lua_State *L) { // dissect(packet_data) lua_check_argc(L,"dissect",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (const uint8_t*)luaL_checklstring(L, 1, &len); struct dissect dis; proto_dissect_l3l4(data, len, &dis); lua_push_dissect(&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*)luaL_checklstring(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(params.L,(char*)data2,l); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_csum_tcp_fix(lua_State *L) { // csum_ip4_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*)luaL_checklstring(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, sizeof(struct ip6_hdr) + ntohs(((struct ip6_hdr*)b_ip)->ip6_ctlun.ip6_un1.ip6_un1_plen))) 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*)luaL_checklstring(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*)luaL_checklstring(L, 3, &l_pl); size_t l_tpl = l_tcp + l_pl; uint8_t *tpl = malloc(l_tpl); if (!tpl) luaL_error(L, "out of memory"); 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); free(tpl); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_csum_udp_fix(lua_State *L) { // csum_ip4_fix(ip_header, tcp_header, payload) returns tcp_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*)luaL_checklstring(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, sizeof(struct ip6_hdr) + ntohs(((struct ip6_hdr*)b_ip)->ip6_ctlun.ip6_un1.ip6_un1_plen))) 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*)luaL_checklstring(L, 2, &l_udp); if (!proto_check_udp(b_udp, ntohs(((struct udphdr*)b_udp)->uh_ulen))) luaL_error(L, "invalid udp header"); size_t l_pl; const uint8_t *b_pl = (const uint8_t*)luaL_checklstring(L, 3, &l_pl); size_t l_tpl = l_udp + l_pl; uint8_t *tpl = malloc(l_tpl); if (!tpl) luaL_error(L, "out of memory"); 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); free(tpl); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_ntop(lua_State *L) { size_t l; const char *p; char s[40]; int af=0; lua_check_argc(L,"ntop",1); LUA_STACK_GUARD_ENTER(L) p=luaL_checklstring(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))) luaL_error(L, "inet_ntop error"); lua_pushstring(L,s); 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=luaL_checkstring(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) *repeats=1; lua_pop(L,1); } if (fwmark) { lua_getfield(L,idx,"fwmark"); *fwmark=(uint32_t)lua_tointeger(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*)luaL_checklstring(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(data, rawsend_opts, reconstruct_opts) lua_check_argc_range(L,"rawsend_dissect",1,3); LUA_STACK_GUARD_ENTER(L) uint8_t buf[RECONSTRUCT_MAX_SIZE]; size_t len=sizeof(buf); const char *ifout; int repeats; uint32_t fwmark; sockaddr_in46 sa; bool b, badsum, ip6_preserve_next; luaL_checktype(L,1,LUA_TTABLE); lua_rawsend_extract_options(L,2, &repeats, &fwmark, &ifout); lua_reconstruct_extract_options(params.L, 3, &badsum, &ip6_preserve_next, NULL); if (!lua_reconstruct_dissect(1, buf, &len, badsum, 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_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*)luaL_checklstring(L,1,&len); const char *sl7payload = luaL_checkstring(L,2); const char *smarker = luaL_checkstring(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*)luaL_checklstring(L,1,&len); const char *sl7payload = luaL_checkstring(L,2); const char *smarkers = luaL_checkstring(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(1,pos[0]+!bZeroBased); lua_pushi_int(2,pos[1]+!bZeroBased); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_record_is_tls_client_hello(lua_State *L) { // (blob,partialOK) lua_check_argc_range(L,"tls_record_is_tls_client_hello",1,2); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t len; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); bool bPartialOK = argc>=2 && lua_toboolean(L,2); lua_pushboolean(L,IsTLSClientHello(data,len,bPartialOK)); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_record_is_tls_server_hello(lua_State *L) { // (blob,partialOK) lua_check_argc_range(L,"tls_record_is_tls_server_hello",1,2); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t len; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); bool bPartialOK = argc>=2 && lua_toboolean(L,2); lua_pushboolean(L,IsTLSServerHello(data,len,bPartialOK)); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_handshake_is_tls_client_hello(lua_State *L) { // (blob,partialOK) lua_check_argc_range(L,"tls_handshake_is_tls_client_hello",1,2); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t len; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); bool bPartialOK = argc>=2 && lua_toboolean(L,2); lua_pushboolean(L,IsTLSHandshakeClientHello(data,len,bPartialOK)); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_handshake_is_tls_server_hello(lua_State *L) { // (blob,partialOK) lua_check_argc_range(L,"tls_handshake_is_tls_server_hello",1,2); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t len; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); bool bPartialOK = argc>=2 && lua_toboolean(L,2); lua_pushboolean(L,IsTLSHandshakeServerHello(data,len,bPartialOK)); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_record_find_ext(lua_State *L) { // (blob,type,partialOK) lua_check_argc_range(L,"tls_record_find_ext",2,3); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t len, len_ext; const uint8_t *ext, *data = (uint8_t*)luaL_checklstring(L,1,&len); luaL_checktype(L,2,LUA_TNUMBER); uint16_t type = (uint16_t)lua_tointeger(L,2); bool bPartialOK = argc>=3 && lua_toboolean(L,3); bool b = TLSFindExt(data, len, type, &ext, &len_ext, bPartialOK); lua_pushinteger(L,b ? ext-data+1 : 0); lua_pushinteger(L,b ? len_ext : 0); LUA_STACK_GUARD_RETURN(L,2) } static int luacall_tls_handshake_find_ext(lua_State *L) { // (blob,type,partialOK) lua_check_argc_range(L,"tls_handshake_find_ext",2,3); LUA_STACK_GUARD_ENTER(L) int argc=lua_gettop(L); size_t len, len_ext; const uint8_t *ext, *data = (uint8_t*)luaL_checklstring(L,1,&len); luaL_checktype(L,2,LUA_TNUMBER); uint16_t type = (uint16_t)lua_tointeger(L,2); bool bPartialOK = argc>=3 && lua_toboolean(L,3); bool b = TLSFindExtInHandshake(data, len, type, &ext, &len_ext, bPartialOK); lua_pushinteger(L,b ? ext-data+1 : 0); lua_pushinteger(L,b ? len_ext : 0); LUA_STACK_GUARD_RETURN(L,2) } static int luacall_tls_record_find_extlen(lua_State *L) { // (blob) lua_check_argc(L,"tls_record_find_extlen",1); LUA_STACK_GUARD_ENTER(L) size_t len, offset; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); bool b = TLSFindExtLen(data, len, &offset); lua_pushinteger(L,b ? offset+1 : 0); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_handshake_find_extlen(lua_State *L) { // (blob) lua_check_argc(L,"tls_handshake_find_extlen",1); LUA_STACK_GUARD_ENTER(L) size_t len, offset; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); bool b = TLSFindExtLenOffsetInHandshake(data, len, &offset); lua_pushinteger(L,b ? offset+1 : 0); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_record_len(lua_State *L) { // (blob) lua_check_argc(L,"tls_record_len",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); lua_pushinteger(L,IsTLSHello(data,len,0,true) ? TLSRecordLen(data) : 0); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_record_data_len(lua_State *L) { // (blob) lua_check_argc(L,"tls_record_data_len",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); lua_pushinteger(L,IsTLSHello(data,len,0,true) ? TLSRecordDataLen(data) : 0); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_record_is_full(lua_State *L) { // (blob) lua_check_argc(L,"tls_record_is_full",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); lua_pushboolean(L,IsTLSHello(data,len,0,true) && IsTLSRecordFull(data,len) ); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_handshake_len(lua_State *L) { // (blob) lua_check_argc(L,"tls_handshake_len",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); lua_pushinteger(L,IsTLSHandshakeHello(data,len,0,true) ? TLSHandshakeLen(data) : 0); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_handshake_data_len(lua_State *L) { // (blob) lua_check_argc(L,"tls_handshake_data_len",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); lua_pushinteger(L,IsTLSHandshakeHello(data,len,0,true) ? TLSHandshakeDataLen(data) : 0); LUA_STACK_GUARD_RETURN(L,1) } static int luacall_tls_handshake_is_full(lua_State *L) { // (blob) lua_check_argc(L,"tls_handshake_is_full",1); LUA_STACK_GUARD_ENTER(L) size_t len; const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); lua_pushboolean(L,IsTLSHandshakeFull(data,len)); 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*)luaL_checklstring(L,1,&fake_tls_len); const char *modlist = luaL_checkstring(L,2); size_t payload_len = 0; const uint8_t *payload = NULL; if (argc>=3 && lua_type(L,3)!=LUA_TNIL) payload = (uint8_t*)luaL_checklstring(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 = malloc(maxlen); if (!newtls) luaL_error(L, "out of memory"); memcpy(newtls, fake_tls, newlen); bRes = TLSMod(&mod, payload, payload_len, newtls, &newlen, maxlen); lua_pushlstring(L,(char*)newtls,newlen); free(newtls); } 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) } // ---------------------------------------- void lua_shutdown() { if (params.L) { DLOG("LUA SHUTDOWN\n"); 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 */ 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_init_scripts(void) { struct str_list *str; int status; LIST_FOREACH(str, ¶ms.lua_init_scripts, next) { 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_dofile(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) { // remove unwanted functions. lua scripts are not intended to execute files const struct { const char *global, *func; } bad[] = { {"os","execute"}, {"io","popen"}, {"package","loadlib"}, {"debug", NULL} }; 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); } } static void lua_init_const(void) { const struct { const char *name; unsigned int v; } cuint[] = { #ifdef __linux__ {"qnum",params.qnum}, #elif defined(BSD) {"divert_port",params.port}, #endif {"desync_fwmark",params.desync_fwmark}, {"VERDICT_PASS",VERDICT_PASS}, {"VERDICT_MODIFY",VERDICT_MODIFY}, {"VERDICT_DROP",VERDICT_DROP}, {"DEFAULT_MSS",DEFAULT_MSS}, {"IP_BASE_LEN",sizeof(struct ip)}, {"IP6_BASE_LEN",sizeof(struct ip6_hdr)}, {"TCP_BASE_LEN",sizeof(struct tcphdr)}, {"UDP_BASE_LEN",sizeof(struct udphdr)}, {"TCP_KIND_END",TCP_KIND_END}, {"TCP_KIND_NOOP",TCP_KIND_NOOP}, {"TCP_KIND_MSS",TCP_KIND_MSS}, {"TCP_KIND_SCALE",TCP_KIND_SCALE}, {"TCP_KIND_SACK_PERM",TCP_KIND_SACK_PERM}, {"TCP_KIND_SACK",TCP_KIND_SACK}, {"TCP_KIND_TS",TCP_KIND_TS}, {"TCP_KIND_MD5",TCP_KIND_MD5}, {"TCP_KIND_AO",TCP_KIND_AO}, {"TCP_KIND_FASTOPEN",TCP_KIND_FASTOPEN}, {"TH_FIN",TH_FIN}, {"TH_SYN",TH_SYN}, {"TH_RST",TH_RST}, {"TH_PUSH",TH_PUSH}, {"TH_ACK",TH_ACK}, {"TH_FIN",TH_FIN}, {"TH_URG",TH_URG}, {"TH_ECE",0x40}, {"TH_CWR",0x80}, {"IP_RF",IP_RF}, {"IP_DF",IP_DF}, {"IP_MF",IP_MF}, {"IP_OFFMASK",IP_OFFMASK}, {"IP_FLAGMASK",IP_RF|IP_DF|IP_MF}, {"IPTOS_ECN_MASK",IPTOS_ECN_MASK}, {"IPTOS_ECN_ECT1",IPTOS_ECN_ECT1}, {"IPTOS_ECN_ECT0",IPTOS_ECN_ECT0}, {"IPTOS_ECN_CE",IPTOS_ECN_CE}, {"IP6F_MORE_FRAG",0x0001}, // in ip6.h it's defined depending of machine byte order {"IPPROTO_IP",IPPROTO_IP}, {"IPPROTO_IPV6",IPPROTO_IPV6}, {"IPPROTO_ICMP",IPPROTO_ICMP}, {"IPPROTO_TCP",IPPROTO_TCP}, {"IPPROTO_UDP",IPPROTO_UDP}, {"IPPROTO_ICMPV6",IPPROTO_ICMPV6}, {"IPPROTO_HOPOPTS",IPPROTO_HOPOPTS}, {"IPPROTO_ROUTING",IPPROTO_ROUTING}, {"IPPROTO_FRAGMENT",IPPROTO_FRAGMENT}, {"IPPROTO_AH",IPPROTO_AH}, {"IPPROTO_ESP",IPPROTO_ESP}, {"IPPROTO_DSTOPTS",IPPROTO_DSTOPTS}, {"IPPROTO_MH",IPPROTO_MH}, {"IPPROTO_HIP",IPPROTO_HIP}, {"IPPROTO_SHIM6",IPPROTO_SHIM6}, {"IPPROTO_NONE",IPPROTO_NONE} }; DLOG("LUA NUMERIC:"); 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; } } }