mirror of
https://github.com/bol-van/zapret2.git
synced 2026-03-13 22:03:09 +00:00
4520 lines
111 KiB
C
4520 lines
111 KiB
C
#include <time.h>
|
|
#include <fcntl.h>
|
|
#include <sys/utsname.h>
|
|
#include <netinet/in.h>
|
|
#include <unistd.h>
|
|
#include <net/if.h>
|
|
#include <errno.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#ifdef __ANDROID__
|
|
#include "andr/ifaddrs.h"
|
|
#else
|
|
#include <ifaddrs.h>
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
#include <sys/thr.h>
|
|
|
|
#elif defined(__linux__)
|
|
|
|
#include <sys/syscall.h>
|
|
|
|
#elif defined(__CYGWIN__)
|
|
|
|
#include <processthreadsapi.h>
|
|
|
|
// 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 <iphlpapi.h>
|
|
|
|
#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 ; pl<L7P_LAST ; pl++)
|
|
{
|
|
if (func->payload_type & (1ULL<<pl))
|
|
{
|
|
if ((pls = l7payload_str(pl)))
|
|
{
|
|
lua_pushstring(L,pls);
|
|
lua_pushboolean(L,true);
|
|
lua_rawset(L,-3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
lua_rawset(L,-3);
|
|
|
|
if (l7_payload_str_list(func->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)
|
|
{
|
|
opt = *t;
|
|
if (opt==TCP_KIND_NOOP || opt==TCP_KIND_END)
|
|
{
|
|
lua_pushinteger(L,idx);
|
|
lua_newtable(L);
|
|
lua_pushf_int(L,"kind",opt);
|
|
t++;
|
|
}
|
|
else
|
|
{
|
|
if ((t+1)>=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 (*len<sizeof(struct tcphdr)) return false;
|
|
|
|
uint8_t *last_proto = &ip6->ip6_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 (*len<sizeof(struct ip6_hdr) || lua_type(L,idx)!=LUA_TTABLE) return false;
|
|
|
|
idx = lua_absindex(L, idx);
|
|
|
|
lua_getfield(L,idx,"ip6_flow");
|
|
ip6->ip6_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 (*len<sizeof(struct ip) || lua_type(L,-1)!=LUA_TTABLE) return false;
|
|
|
|
ip->ip_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 (*len<sizeof(struct tcphdr)) return false;
|
|
|
|
LUA_STACK_GUARD_ENTER(L)
|
|
|
|
uint8_t filled = sizeof(struct tcphdr);
|
|
|
|
lua_getfield(L,idx,"options");
|
|
if (lua_type(L,-1)==LUA_TTABLE)
|
|
{
|
|
lua_Integer idx=0;
|
|
uint8_t *p, *data = (uint8_t*)(tcp+1);
|
|
size_t l, left;
|
|
uint8_t kind;
|
|
|
|
left = *len - filled;
|
|
if (left>40) 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 (*len<sizeof(struct tcphdr) || lua_type(L,-1)!=LUA_TTABLE) return false;
|
|
|
|
LUA_STACK_GUARD_ENTER(L)
|
|
|
|
idx = lua_absindex(L, idx);
|
|
|
|
lua_getfield(L,idx,"th_sport");
|
|
if (lua_type(L,-1)!=LUA_TNUMBER) goto err;
|
|
tcp->th_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 (left<lpayload)
|
|
{
|
|
DLOG_ERR("reconstruct_dissect: payload does not fit into the buffer : payload %zu buffer_left %zu\n",lpayload,left);
|
|
goto err;
|
|
}
|
|
memcpy(data,p,lpayload);
|
|
data+=lpayload; left-=lpayload;
|
|
}
|
|
else
|
|
lpayload = 0;
|
|
lua_pop(L, 1);
|
|
l = data-buf;
|
|
}
|
|
else
|
|
{
|
|
lua_getfield(L,idx,"tcp");
|
|
l=0;
|
|
if (lua_type(L,-1)==LUA_TTABLE)
|
|
{
|
|
l = left;
|
|
tcp = (struct tcphdr*)data;
|
|
if (!lua_reconstruct_tcphdr(L, -1, tcp, &l))
|
|
{
|
|
DLOG_ERR("reconstruct_dissect: bad tcp\n");
|
|
goto err;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lua_pop(L, 1);
|
|
lua_getfield(L,idx,"udp");
|
|
if (lua_type(L,-1)==LUA_TTABLE)
|
|
{
|
|
l = sizeof(struct udphdr);
|
|
udp = (struct udphdr*)data;
|
|
if (!lua_reconstruct_udphdr(L, -1, udp))
|
|
{
|
|
DLOG_ERR("reconstruct_dissect: bad udp\n");
|
|
goto err;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lua_pop(L, 1);
|
|
lua_getfield(L,idx,"icmp");
|
|
if (lua_type(L,-1)==LUA_TTABLE)
|
|
{
|
|
l = sizeof(struct icmp46);
|
|
icmp = (struct icmp46*)data;
|
|
if (!lua_reconstruct_icmphdr(L, -1, icmp))
|
|
{
|
|
DLOG_ERR("reconstruct_dissect: bad icmp\n");
|
|
goto err;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
data+=l; left-=l;
|
|
lua_pop(L, 1);
|
|
|
|
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 (left<lpayload)
|
|
{
|
|
DLOG_ERR("reconstruct_dissect: payload does not fit into the buffer : payload %zu buffer_left %zu\n",lpayload,left);
|
|
goto err;
|
|
}
|
|
memcpy(data,p,lpayload);
|
|
data+=lpayload; left-=lpayload;
|
|
}
|
|
else
|
|
lpayload = 0;
|
|
lua_pop(L, 1);
|
|
|
|
l = data-buf;
|
|
|
|
if (!keepsum)
|
|
{
|
|
if (tcp)
|
|
{
|
|
tcp_fix_checksum(tcp,l-l3,ip,ip6);
|
|
if (badsum) tcp->th_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 (iplen<l3 || iplen>l)
|
|
{
|
|
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<ctpos;i++) lua_pushi_int(L,i+1,pos[i]+!bZeroBased);
|
|
|
|
LUA_STACK_GUARD_RETURN(L,1)
|
|
}
|
|
static int luacall_resolve_range(lua_State *L)
|
|
{
|
|
// resolve_range(blob,l7payload_type,marker_list[,strict][,zero_based_pos])
|
|
// "strict" means do not expand range to the beginning/end if only one pos is resolved
|
|
lua_check_argc_range(L,"resolve_range",3,5);
|
|
|
|
LUA_STACK_GUARD_ENTER(L)
|
|
|
|
int argc=lua_gettop(L);
|
|
size_t i,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 bStrict = argc>=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;i<sizeof(bad)/sizeof(*bad);i++)
|
|
{
|
|
if (bad[i].field)
|
|
{
|
|
lua_getglobal(params.L, bad[i].global);
|
|
if (bad[i].field2)
|
|
{
|
|
lua_getfield(params.L, -1, bad[i].field);
|
|
lua_pushstring(params.L, bad[i].field2);
|
|
DLOG(" %s.%s.%s", bad[i].global, bad[i].field, bad[i].field2);
|
|
}
|
|
else
|
|
{
|
|
lua_pushstring(params.L, bad[i].field);
|
|
DLOG(" %s.%s", bad[i].global, bad[i].field);
|
|
}
|
|
lua_pushnil(params.L);
|
|
lua_rawset(params.L, -3);
|
|
lua_pop(params.L,1 + !!bad[i].field2);
|
|
}
|
|
else
|
|
{
|
|
lua_pushnil(params.L);
|
|
lua_setglobal(params.L, bad[i].global);
|
|
DLOG(" %s", bad[i].global);
|
|
}
|
|
}
|
|
DLOG("\n");
|
|
|
|
LUA_STACK_GUARD_LEAVE(params.L,0)
|
|
}
|
|
|
|
static void lua_init_blobs(void)
|
|
{
|
|
LUA_STACK_GUARD_ENTER(params.L)
|
|
|
|
struct blob_item *blob;
|
|
// save some memory - destroy C blobs as they are not needed anymore
|
|
while ((blob = LIST_FIRST(¶ms.blobs)))
|
|
{
|
|
LIST_REMOVE(blob, next);
|
|
DLOG("LUA BLOB: %s (size=%zu)\n",blob->name, 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<sizeof(cstr)/sizeof(*cstr);i++)
|
|
{
|
|
lua_pushstring(params.L, cstr[i].v);
|
|
lua_setglobal(params.L, cstr[i].name);
|
|
DLOG(" %s", cstr[i].name);
|
|
}
|
|
|
|
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},
|
|
{"NFQWS2_COMPAT_VER",LUA_COMPAT_VER},
|
|
|
|
{"VERDICT_PASS",VERDICT_PASS},
|
|
{"VERDICT_MODIFY",VERDICT_MODIFY},
|
|
{"VERDICT_DROP",VERDICT_DROP},
|
|
{"VERDICT_MASK",VERDICT_MASK},
|
|
{"VERDICT_PRESERVE_NEXT",VERDICT_PRESERVE_NEXT},
|
|
|
|
{"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)},
|
|
{"ICMP_BASE_LEN",sizeof(struct icmp46)},
|
|
|
|
{"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_NOT_ECT",0},
|
|
{"IPTOS_ECN_ECT1",IPTOS_ECN_ECT1},
|
|
{"IPTOS_ECN_ECT0",IPTOS_ECN_ECT0},
|
|
{"IPTOS_ECN_CE",IPTOS_ECN_CE},
|
|
{"IPTOS_DSCP_MASK",0xFC},
|
|
{"IP6F_MORE_FRAG",0x0001}, // in ip6.h it's defined depending of machine byte order
|
|
{"IPV6_FLOWLABEL_MASK",0x000FFFFF},
|
|
{"IPV6_FLOWINFO_MASK",0x0FFFFFFF},
|
|
|
|
{"IPPROTO_IP",IPPROTO_IP},
|
|
{"IPPROTO_IPIP",IPPROTO_IPIP},
|
|
{"IPPROTO_IPV6",IPPROTO_IPV6},
|
|
{"IPPROTO_ICMP",IPPROTO_ICMP},
|
|
{"IPPROTO_TCP",IPPROTO_TCP},
|
|
{"IPPROTO_UDP",IPPROTO_UDP},
|
|
{"IPPROTO_ICMPV6",IPPROTO_ICMPV6},
|
|
{"IPPROTO_SCTP",IPPROTO_SCTP},
|
|
{"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},
|
|
|
|
// icmp types
|
|
{"ICMP_ECHOREPLY",ICMP_ECHOREPLY},
|
|
{"ICMP_DEST_UNREACH",ICMP_DEST_UNREACH},
|
|
{"ICMP_REDIRECT",ICMP_REDIRECT},
|
|
{"ICMP_ECHO",ICMP_ECHO},
|
|
{"ICMP_TIME_EXCEEDED",ICMP_TIME_EXCEEDED},
|
|
{"ICMP_PARAMETERPROB",ICMP_PARAMETERPROB},
|
|
{"ICMP_TIMESTAMP",ICMP_TIMESTAMP},
|
|
{"ICMP_TIMESTAMPREPLY",ICMP_TIMESTAMPREPLY},
|
|
{"ICMP_INFO_REQUEST",ICMP_INFO_REQUEST},
|
|
{"ICMP_INFO_REPLY",ICMP_INFO_REPLY},
|
|
|
|
// icmp codes for UNREACH
|
|
{"ICMP_UNREACH_NET",ICMP_UNREACH_NET},
|
|
{"ICMP_UNREACH_HOST",ICMP_UNREACH_HOST},
|
|
{"ICMP_UNREACH_PROTOCOL",ICMP_UNREACH_PROTOCOL},
|
|
{"ICMP_UNREACH_PORT",ICMP_UNREACH_PORT},
|
|
{"ICMP_UNREACH_NEEDFRAG",ICMP_UNREACH_NEEDFRAG},
|
|
{"ICMP_UNREACH_SRCFAIL",ICMP_UNREACH_SRCFAIL},
|
|
{"ICMP_UNREACH_NET_UNKNOWN",ICMP_UNREACH_NET_UNKNOWN},
|
|
{"ICMP_UNREACH_HOST_UNKNOWN",ICMP_UNREACH_HOST_UNKNOWN},
|
|
{"ICMP_UNREACH_NET_PROHIB",ICMP_UNREACH_NET_PROHIB},
|
|
{"ICMP_UNREACH_HOST_PROHIB",ICMP_UNREACH_HOST_PROHIB},
|
|
{"ICMP_UNREACH_TOSNET",ICMP_UNREACH_TOSNET},
|
|
{"ICMP_UNREACH_TOSHOST",ICMP_UNREACH_TOSHOST},
|
|
{"ICMP_UNREACH_FILTER_PROHIB",ICMP_UNREACH_FILTER_PROHIB},
|
|
{"ICMP_UNREACH_HOST_PRECEDENCE",ICMP_UNREACH_HOST_PRECEDENCE},
|
|
{"ICMP_UNREACH_PRECEDENCE_CUTOFF",ICMP_UNREACH_PRECEDENCE_CUTOFF},
|
|
|
|
// icmp codes for REDIRECT
|
|
{"ICMP_REDIRECT_NET",ICMP_REDIRECT_NET},
|
|
{"ICMP_REDIRECT_HOST",ICMP_REDIRECT_HOST},
|
|
{"ICMP_REDIRECT_TOSNET",ICMP_REDIRECT_TOSNET},
|
|
{"ICMP_REDIRECT_TOSHOST",ICMP_REDIRECT_TOSHOST},
|
|
|
|
// icmp codes for TIME_EXCEEDED
|
|
{"ICMP_TIMXCEED_INTRANS",ICMP_TIMXCEED_INTRANS},
|
|
{"ICMP_TIMXCEED_REASS",ICMP_TIMXCEED_REASS},
|
|
|
|
// icmp6 types
|
|
{"ICMP6_ECHO_REQUEST",ICMP6_ECHO_REQUEST},
|
|
{"ICMP6_ECHO_REPLY",ICMP6_ECHO_REPLY},
|
|
{"ICMP6_DST_UNREACH",ICMP6_DST_UNREACH},
|
|
{"ICMP6_PACKET_TOO_BIG",ICMP6_PACKET_TOO_BIG},
|
|
{"ICMP6_TIME_EXCEEDED",ICMP6_TIME_EXCEEDED},
|
|
{"ICMP6_PARAM_PROB",ICMP6_PARAM_PROB},
|
|
{"MLD_LISTENER_QUERY",MLD_LISTENER_QUERY},
|
|
{"MLD_LISTENER_REPORT",MLD_LISTENER_REPORT},
|
|
{"MLD_LISTENER_REDUCTION",MLD_LISTENER_REDUCTION},
|
|
{"ND_ROUTER_SOLICIT",ND_ROUTER_SOLICIT},
|
|
{"ND_ROUTER_ADVERT",ND_ROUTER_ADVERT},
|
|
{"ND_NEIGHBOR_SOLICIT",ND_NEIGHBOR_SOLICIT},
|
|
{"ND_NEIGHBOR_ADVERT",ND_NEIGHBOR_ADVERT},
|
|
{"ND_REDIRECT",ND_REDIRECT},
|
|
|
|
// icmp codes for ICMP6_DST_UNREACH
|
|
{"ICMP6_DST_UNREACH_NOROUTE",ICMP6_DST_UNREACH_NOROUTE},
|
|
{"ICMP6_DST_UNREACH_ADMIN",ICMP6_DST_UNREACH_ADMIN},
|
|
{"ICMP6_DST_UNREACH_BEYONDSCOPE",ICMP6_DST_UNREACH_BEYONDSCOPE},
|
|
{"ICMP6_DST_UNREACH_ADDR",ICMP6_DST_UNREACH_ADDR},
|
|
{"ICMP6_DST_UNREACH_NOPORT",ICMP6_DST_UNREACH_NOPORT},
|
|
|
|
// icmp codes for ICMP6_TIME_EXCEEDED
|
|
{"ICMP6_TIME_EXCEED_TRANSIT",ICMP6_TIME_EXCEED_TRANSIT},
|
|
{"ICMP6_TIME_EXCEED_REASSEMBLY",ICMP6_TIME_EXCEED_REASSEMBLY},
|
|
|
|
// icmp codes for ICMP6_PARAM_PROB
|
|
{"ICMP6_PARAMPROB_HEADER",ICMP6_PARAMPROB_HEADER},
|
|
{"ICMP6_PARAMPROB_NEXTHEADER",ICMP6_PARAMPROB_NEXTHEADER},
|
|
{"ICMP6_PARAMPROB_OPTION",ICMP6_PARAMPROB_OPTION}
|
|
};
|
|
DLOG("\nLUA NUMERIC:");
|
|
for (int i=0;i<sizeof(cuint)/sizeof(*cuint);i++)
|
|
{
|
|
lua_pushinteger(params.L, (lua_Integer)cuint[i].v);
|
|
lua_setglobal(params.L, cuint[i].name);
|
|
DLOG(" %s", cuint[i].name);
|
|
}
|
|
|
|
DLOG("\nLUA BOOL:");
|
|
const struct
|
|
{
|
|
const char *name;
|
|
bool v;
|
|
} cbool[] = {
|
|
{"b_debug",params.debug},
|
|
{"b_daemon",params.daemon},
|
|
{"b_server",params.server},
|
|
{"b_ipcache_hostname",params.cache_hostname},
|
|
{"b_ctrack_disable",params.ctrack_disable}
|
|
};
|
|
for (int i=0;i<sizeof(cbool)/sizeof(*cbool);i++)
|
|
{
|
|
lua_pushboolean(params.L, cbool[i].v);
|
|
lua_setglobal(params.L, cbool[i].name);
|
|
DLOG(" %s", cbool[i].name);
|
|
}
|
|
|
|
DLOG("\n");
|
|
|
|
LUA_STACK_GUARD_LEAVE(params.L, 0)
|
|
}
|
|
|
|
static void lua_init_functions(void)
|
|
{
|
|
LUA_STACK_GUARD_ENTER(params.L)
|
|
|
|
const struct
|
|
{
|
|
const char *name;
|
|
lua_CFunction f;
|
|
} lfunc[] = {
|
|
// logging
|
|
{"DLOG",luacall_DLOG},
|
|
{"DLOG_ERR",luacall_DLOG_ERR},
|
|
{"DLOG_CONDUP",luacall_DLOG_CONDUP},
|
|
|
|
// ip blob to string with ip version autodetect
|
|
{"ntop",luacall_ntop},
|
|
// string to ip blob with ip version autodetect
|
|
{"pton",luacall_pton},
|
|
|
|
// bit manipulation
|
|
{"bitlshift",luacall_bitlshift},
|
|
{"bitrshift",luacall_bitrshift},
|
|
{"bitand",luacall_bitand},
|
|
{"bitor",luacall_bitor},
|
|
{"bitxor",luacall_bitxor},
|
|
{"bitget",luacall_bitget},
|
|
{"bitset",luacall_bitset},
|
|
{"bitnot",luacall_bitnot48},
|
|
{"bitnot8",luacall_bitnot8},
|
|
{"bitnot16",luacall_bitnot16},
|
|
{"bitnot24",luacall_bitnot24},
|
|
{"bitnot32",luacall_bitnot32},
|
|
{"bitnot48",luacall_bitnot48},
|
|
|
|
// WARNING : lua 5.1 and luajit does not correctly implement integers. they seem to be stored as float which can't hold 64-bit.
|
|
// convert part of the blob (string) to number
|
|
{"u8",luacall_u8},
|
|
{"u16",luacall_u16},
|
|
{"u24",luacall_u24},
|
|
{"u32",luacall_u32},
|
|
{"u48",luacall_u48},
|
|
// add any number of arguments as they would be unsigned int of specific size
|
|
{"u8add",luacall_u8add},
|
|
{"u16add",luacall_u16add},
|
|
{"u24add",luacall_u24add},
|
|
{"u32add",luacall_u32add},
|
|
{"u48add",luacall_u48add},
|
|
// convert number to blob (string) - big endian
|
|
{"bu8",luacall_bu8},
|
|
{"bu16",luacall_bu16},
|
|
{"bu24",luacall_bu24},
|
|
{"bu32",luacall_bu32},
|
|
{"bu48",luacall_bu48},
|
|
// swap byte order
|
|
{"swap16",luacall_swap16},
|
|
{"swap24",luacall_swap24},
|
|
{"swap32",luacall_swap32},
|
|
{"swap48",luacall_swap48},
|
|
|
|
// integer division
|
|
{"divint",luacall_divint},
|
|
|
|
// hacky function, write to immutable strings
|
|
//{"memcpy",luacall_memcpy},
|
|
|
|
// random blob generation
|
|
{"brandom",luacall_brandom},
|
|
{"brandom_az",luacall_brandom_az},
|
|
{"brandom_az09",luacall_brandom_az09},
|
|
|
|
// crypto
|
|
{"bcryptorandom",luacall_bcryptorandom},
|
|
{"bxor",luacall_bxor},
|
|
{"bor",luacall_bor},
|
|
{"band",luacall_band},
|
|
{"hash",luacall_hash},
|
|
{"aes",luacall_aes},
|
|
{"aes_gcm",luacall_aes_gcm},
|
|
{"aes_ctr",luacall_aes_ctr},
|
|
{"hkdf",luacall_hkdf},
|
|
|
|
// parsing
|
|
{"parse_hex",luacall_parse_hex},
|
|
|
|
// voluntarily stop receiving packets
|
|
{"instance_cutoff",luacall_instance_cutoff},
|
|
// voluntarily stop receiving packets of the current connection for all instances
|
|
{"lua_cutoff",luacall_lua_cutoff},
|
|
// get info about upcoming desync instances and their arguments
|
|
{"execution_plan",luacall_execution_plan},
|
|
// cancel execution of upcoming desync instances and their arguments
|
|
{"execution_plan_cancel",luacall_execution_plan_cancel},
|
|
// get raw packet data
|
|
{"raw_packet",luacall_raw_packet},
|
|
|
|
// system functions
|
|
{"uname",luacall_uname},
|
|
{"clock_gettime",luacall_clock_gettime},
|
|
{"clock_getfloattime",luacall_clock_getfloattime},
|
|
{"getpid",luacall_getpid},
|
|
{"gettid",luacall_gettid},
|
|
|
|
// convert table representation to blob or vise versa
|
|
{"reconstruct_tcphdr",luacall_reconstruct_tcphdr},
|
|
{"reconstruct_udphdr",luacall_reconstruct_udphdr},
|
|
{"reconstruct_icmphdr",luacall_reconstruct_icmphdr},
|
|
{"reconstruct_ip6hdr",luacall_reconstruct_ip6hdr},
|
|
{"reconstruct_iphdr",luacall_reconstruct_iphdr},
|
|
{"reconstruct_dissect",luacall_reconstruct_dissect},
|
|
{"dissect_tcphdr",luacall_dissect_tcphdr},
|
|
{"dissect_udphdr",luacall_dissect_udphdr},
|
|
{"dissect_icmphdr",luacall_dissect_icmphdr},
|
|
{"dissect_ip6hdr",luacall_dissect_ip6hdr},
|
|
{"dissect_iphdr",luacall_dissect_iphdr},
|
|
{"dissect",luacall_dissect},
|
|
{"csum_ip4_fix",luacall_csum_ip4_fix},
|
|
{"csum_tcp_fix",luacall_csum_tcp_fix},
|
|
{"csum_udp_fix",luacall_csum_udp_fix},
|
|
{"csum_icmp_fix",luacall_csum_icmp_fix},
|
|
|
|
// send packets
|
|
{"rawsend",luacall_rawsend},
|
|
{"rawsend_dissect",luacall_rawsend_dissect},
|
|
|
|
// conntrack inject packet
|
|
{"conntrack_feed",luacall_conntrack_feed},
|
|
|
|
// get source addr when connecting to specified target addr
|
|
{"get_source_ip",luacall_get_source_ip},
|
|
// get os interface intformation
|
|
{"get_ifaddrs",luacall_get_ifaddrs},
|
|
|
|
// resolve position markers in any supported payload
|
|
{"resolve_pos",luacall_resolve_pos},
|
|
{"resolve_multi_pos",luacall_resolve_multi_pos},
|
|
{"resolve_range",luacall_resolve_range},
|
|
|
|
// tls
|
|
{"tls_mod",luacall_tls_mod},
|
|
|
|
// gzip decompress
|
|
{"gunzip_init",luacall_gunzip_init},
|
|
{"gunzip_end",luacall_gunzip_end},
|
|
{"gunzip_inflate",luacall_gunzip_inflate},
|
|
// gzip compress
|
|
{"gzip_init",luacall_gzip_init},
|
|
{"gzip_end",luacall_gzip_end},
|
|
{"gzip_deflate",luacall_gzip_deflate},
|
|
|
|
// stat() - file size, mod time
|
|
{"stat",luacall_stat},
|
|
|
|
// time
|
|
{"localtime",luacall_localtime},
|
|
{"gmtime",luacall_gmtime},
|
|
{"timelocal",luacall_timelocal},
|
|
{"timegm",luacall_timegm}
|
|
};
|
|
for(int i=0;i<(sizeof(lfunc)/sizeof(*lfunc));i++)
|
|
lua_register(params.L,lfunc[i].name,lfunc[i].f);
|
|
|
|
LUA_STACK_GUARD_LEAVE(params.L, 0)
|
|
}
|
|
|
|
static void lua_init_mt()
|
|
{
|
|
lua_mt_init_zstream(params.L);
|
|
lua_mt_init_desync_ctx(params.L);
|
|
lua_desync_ctx_create(params.L);
|
|
}
|
|
|
|
static void lua_interrupt_hook(lua_State *L, lua_Debug *ar)
|
|
{
|
|
// avoid infinite loops
|
|
lua_sethook(L, NULL, 0, 0);
|
|
luaL_error(L, "INTERRUPT");
|
|
}
|
|
void lua_req_quit(void)
|
|
{
|
|
if (params.L) lua_sethook(params.L, lua_interrupt_hook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT | LUA_MASKLINE, 1);
|
|
}
|
|
|
|
bool lua_init(void)
|
|
{
|
|
DLOG("\nLUA INIT\n");
|
|
|
|
if (!lua_basic_init()) return false;
|
|
|
|
LUA_STACK_GUARD_ENTER(params.L)
|
|
|
|
lua_sec_harden();
|
|
lua_init_blobs();
|
|
lua_init_const();
|
|
lua_init_functions();
|
|
lua_init_mt();
|
|
if (!lua_init_scripts()) goto err;
|
|
if (!lua_desync_functions_exist()) goto err;
|
|
|
|
LUA_STACK_GUARD_LEAVE(params.L,0)
|
|
DLOG("LUA INIT DONE\n\n");
|
|
return true;
|
|
err:
|
|
LUA_STACK_GUARD_LEAVE(params.L,0)
|
|
lua_shutdown();
|
|
return false;
|
|
}
|
|
|
|
void lua_dlog_error(void)
|
|
{
|
|
if (lua_isstring(params.L, -1))
|
|
{
|
|
const char *error_message = lua_tostring(params.L, -1);
|
|
DLOG_ERR("LUA ERROR: %s\n", error_message);
|
|
}
|
|
lua_pop(params.L, 1);
|
|
}
|
|
|
|
|
|
static time_t gc_time=0;
|
|
void lua_do_gc(void)
|
|
{
|
|
if (params.lua_gc)
|
|
{
|
|
time_t now = time(NULL);
|
|
if ((now - gc_time) >= 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;
|
|
}
|
|
}
|
|
}
|