1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Add zlib binding for NSE. Fixes #532

This commit is contained in:
dmiller
2017-09-13 01:54:19 +00:00
parent 30de1639eb
commit b57d23f005
8 changed files with 1123 additions and 0 deletions

View File

@@ -1,5 +1,8 @@
#s wa Nmap Changelog ($Id$); -*-text-*- #s wa Nmap Changelog ($Id$); -*-text-*-
o [NSE][GH#532] Added zlib library for NSE. This was a leftover project from
GSOC 2014, and will be very useful. [Claudiu Perta, Daniel Miller]
o [NSE][GH#1004] Fixed handling of brute.retries variable. It was being treated o [NSE][GH#1004] Fixed handling of brute.retries variable. It was being treated
as the number of tries, not retries, and a value of 0 would result in as the number of tries, not retries, and a value of 0 would result in
infinite retries. Instead, it is now the number of retries, defaulting to 2 infinite retries. Instead, it is now the number of retries, defaulting to 2

View File

@@ -105,6 +105,11 @@ NSE_SRC+=nse_libssh2.cc
NSE_HDRS+=nse_libssh2.h NSE_HDRS+=nse_libssh2.h
NSE_OBJS+=nse_libssh2.o NSE_OBJS+=nse_libssh2.o
endif endif
ifneq (@LIBZLIB_LIBS@,)
NSE_SRC+=nse_zlib.cc
NSE_HDRS+=nse_zlib.h
NSE_OBJS+=nse_zlib.o
endif
endif endif
export SRCS = charpool.cc FingerPrintResults.cc FPEngine.cc FPModel.cc idle_scan.cc MACLookup.cc main.cc nmap.cc nmap_dns.cc nmap_error.cc nmap_ftp.cc NmapOps.cc NmapOutputTable.cc nmap_tty.cc osscan2.cc osscan.cc output.cc payload.cc portlist.cc portreasons.cc protocols.cc scan_engine.cc scan_engine_connect.cc scan_engine_raw.cc scan_lists.cc service_scan.cc services.cc Target.cc NewTargets.cc TargetGroup.cc targets.cc tcpip.cc timing.cc traceroute.cc utils.cc xml.cc $(NSE_SRC) export SRCS = charpool.cc FingerPrintResults.cc FPEngine.cc FPModel.cc idle_scan.cc MACLookup.cc main.cc nmap.cc nmap_dns.cc nmap_error.cc nmap_ftp.cc NmapOps.cc NmapOutputTable.cc nmap_tty.cc osscan2.cc osscan.cc output.cc payload.cc portlist.cc portreasons.cc protocols.cc scan_engine.cc scan_engine_connect.cc scan_engine_raw.cc scan_lists.cc service_scan.cc services.cc Target.cc NewTargets.cc TargetGroup.cc targets.cc tcpip.cc timing.cc traceroute.cc utils.cc xml.cc $(NSE_SRC)

View File

@@ -166,6 +166,7 @@ xcopy /y /d "$(ProjectDir)..\libssh2\win32\$(Configuration)_dll\*.dll" "$(Proje
<ClCompile Include="..\nse_openssl.cc" /> <ClCompile Include="..\nse_openssl.cc" />
<ClCompile Include="..\nse_pcrelib.cc" /> <ClCompile Include="..\nse_pcrelib.cc" />
<ClCompile Include="..\nse_ssl_cert.cc" /> <ClCompile Include="..\nse_ssl_cert.cc" />
<ClCompile Include="..\nse_zlib.cc" />
<ClCompile Include="..\osscan.cc" /> <ClCompile Include="..\osscan.cc" />
<ClCompile Include="..\osscan2.cc" /> <ClCompile Include="..\osscan2.cc" />
<ClCompile Include="..\output.cc" /> <ClCompile Include="..\output.cc" />
@@ -221,6 +222,7 @@ xcopy /y /d "$(ProjectDir)..\libssh2\win32\$(Configuration)_dll\*.dll" "$(Proje
<ClInclude Include="..\nse_openssl.h" /> <ClInclude Include="..\nse_openssl.h" />
<ClInclude Include="..\nse_pcrelib.h" /> <ClInclude Include="..\nse_pcrelib.h" />
<ClInclude Include="..\nse_ssl_cert.h" /> <ClInclude Include="..\nse_ssl_cert.h" />
<ClInclude Include="..\nse_zlib.h" />
<ClInclude Include="..\osscan.h" /> <ClInclude Include="..\osscan.h" />
<ClInclude Include="..\osscan2.h" /> <ClInclude Include="..\osscan2.h" />
<ClInclude Include="..\output.h" /> <ClInclude Include="..\output.h" />

View File

@@ -19,6 +19,7 @@
#include "nse_debug.h" #include "nse_debug.h"
#include "nse_lpeg.h" #include "nse_lpeg.h"
#include "nse_libssh2.h" #include "nse_libssh2.h"
#include "nse_zlib.h"
#include <math.h> #include <math.h>
@@ -551,6 +552,9 @@ static void set_nmap_libraries (lua_State *L)
#endif #endif
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
{OPENSSLLIBNAME, luaopen_openssl}, {OPENSSLLIBNAME, luaopen_openssl},
#endif
#ifdef HAVE_LIBZ
{NSE_ZLIBNAME, luaopen_zlib},
#endif #endif
{NULL, NULL} {NULL, NULL}
}; };

988
nse_zlib.cc Normal file
View File

@@ -0,0 +1,988 @@
/************************************************************************
* Author : Tiago Dionizio <tiago.dionizio@gmail.com> *
* Library : lzlib - Lua 5 interface to access zlib library functions *
* *
* Permission is hereby granted, free of charge, to any person obtaining *
* a copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to *
* the following conditions: *
* *
* The above copyright notice and this permission notice shall be *
* included in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY *
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
************************************************************************/
#include <stdlib.h>
#include <string.h>
extern "C" {
#include "lua.h"
#include "lauxlib.h"
}
#include <zlib.h>
/*
** =========================================================================
** compile time options wich determine available functionality
** =========================================================================
*/
/* TODO
- also call flush on table/userdata when flush function is detected
- remove io_cb check inflate_block if condition
- only set eos when ZSTREAM_END is reached
- check for stream errors to close stream when really needed
*/
/*
** =========================================================================
** zlib stream metamethods
** =========================================================================
*/
#define ZSTREAMMETA "zlib:zstream"
#define LZ_ANY -1
#define LZ_NONE 0
#define LZ_DEFLATE 1
#define LZ_INFLATE 2
#if 0
#define LZ_BUFFER_SIZE LUAL_BUFFERSIZE
#else
#define LZ_BUFFER_SIZE 8192
#endif
typedef struct {
/* zlib structures */
z_stream zstream;
/* stream state. LZ_DEFLATE | LZ_INFLATE */
int state;
int error;
int peek;
int eos;
/* user callback source for reading/writing */
int io_cb;
/* input buffer */
int i_buffer_ref;
size_t i_buffer_pos;
size_t i_buffer_len;
const char *i_buffer;
/* output buffer */
size_t o_buffer_len;
size_t o_buffer_max;
char o_buffer[LZ_BUFFER_SIZE];
/* dictionary */
const Bytef *dictionary;
size_t dictionary_len;
} lz_stream;
/* forward declarations */
static int lzstream_docompress(lua_State *L, lz_stream *s, int from, int to, int flush);
static lz_stream *lzstream_new(lua_State *L, int src) {
lz_stream *s = (lz_stream*)lua_newuserdata(L, sizeof(lz_stream));
luaL_getmetatable(L, ZSTREAMMETA);
lua_setmetatable(L, -2); /* set metatable */
s->state = LZ_NONE;
s->error = Z_OK;
s->eos = 0;
s->io_cb = LUA_REFNIL;
s->i_buffer = NULL;
s->i_buffer_ref = LUA_REFNIL;
s->i_buffer_pos = 0;
s->i_buffer_len = 0;
s->peek = 0;
s->o_buffer_len = 0;
s->o_buffer_max = sizeof(s->o_buffer) / sizeof(s->o_buffer[0]);
s->zstream.zalloc = Z_NULL;
s->zstream.zfree = Z_NULL;
/* prepare source */
if (lua_isstring(L, src)) {
lua_pushvalue(L, src);
s->i_buffer_ref = luaL_ref(L, LUA_REGISTRYINDEX);
s->i_buffer = lua_tolstring(L, src, &s->i_buffer_len);
} else {
/* table | function | userdata */
lua_pushvalue(L, src);
s->io_cb = luaL_ref(L, LUA_REGISTRYINDEX);
}
return s;
}
static void lzstream_cleanup(lua_State *L, lz_stream *s) {
if (s && s->state != LZ_NONE) {
if (s->state == LZ_INFLATE) {
inflateEnd(&s->zstream);
}
if (s->state == LZ_DEFLATE) {
deflateEnd(&s->zstream);
}
luaL_unref(L, LUA_REGISTRYINDEX, s->io_cb);
luaL_unref(L, LUA_REGISTRYINDEX, s->i_buffer_ref);
s->state = LZ_NONE;
}
}
/* ====================================================================== */
static lz_stream *lzstream_get(lua_State *L, int index) {
lz_stream *s = (lz_stream*)luaL_checkudata(L, index, ZSTREAMMETA);
if (s == NULL) luaL_argerror(L, index, "bad zlib stream");
return s;
}
static lz_stream *lzstream_check(lua_State *L, int index, int state) {
lz_stream *s = lzstream_get(L, index);
if ((state != LZ_ANY && s->state != state) || s->state == LZ_NONE) {
luaL_argerror(L, index, "attempt to use invalid zlib stream");
}
return s;
}
/* ====================================================================== */
static int lzstream_tostring(lua_State *L) {
lz_stream *s = (lz_stream*)luaL_checkudata(L, 1, ZSTREAMMETA);
if (s == NULL) luaL_argerror(L, 1, "bad zlib stream");
if (s->state == LZ_NONE) {
lua_pushstring(L, "zlib stream (closed)");
} else if (s->state == LZ_DEFLATE) {
lua_pushfstring(L, "zlib deflate stream (%p)", (void*)s);
} else if (s->state == LZ_INFLATE) {
lua_pushfstring(L, "zlib inflate stream (%p)", (void*)s);
} else {
lua_pushfstring(L, "%p", (void*)s);
}
return 1;
}
/* ====================================================================== */
static int lzstream_gc(lua_State *L) {
lz_stream *s = lzstream_get(L, 1);
lzstream_cleanup(L, s);
return 0;
}
/* ====================================================================== */
static int lzstream_close(lua_State *L) {
lz_stream *s = lzstream_get(L, 1);
if (s->state == LZ_DEFLATE) {
lua_settop(L, 0);
lua_pushliteral(L, "");
return lzstream_docompress(L, s, 1, 1, Z_FINISH);
}
lzstream_cleanup(L, s);
lua_pushboolean(L, 1);
return 1;
}
/* ====================================================================== */
static int lzstream_adler(lua_State *L) {
lz_stream *s = lzstream_check(L, 1, LZ_ANY);
lua_pushnumber(L, s->zstream.adler);
return 1;
}
/* ====================================================================== */
/*
zlib.deflate(
sink: function | { write: function [, close: function, flush: function] },
compression level, [Z_DEFAILT_COMPRESSION]
method, [Z_DEFLATED]
windowBits, [15]
memLevel, [8]
strategy, [Z_DEFAULT_STRATEGY]
dictionary: [""]
)
*/
static int lzlib_deflate(lua_State *L) {
int level, method, windowBits, memLevel, strategy;
lz_stream *s;
const char *dictionary;
size_t dictionary_len;
if (lua_istable(L, 1) || lua_isuserdata(L, 1)) {
/* is there a :write function? */
lua_getfield(L, 1, "write");
if (!lua_isfunction(L, -1)) {
luaL_argerror(L, 1, "output parameter does not provide :write function");
}
lua_pop(L, 1);
}
else if (!lua_isfunction(L, 1)) {
luaL_argerror(L, 1, "output parameter must be a function, table or userdata value");
}
level = (int) luaL_optinteger(L, 2, Z_DEFAULT_COMPRESSION);
method = (int) luaL_optinteger(L, 3, Z_DEFLATED);
windowBits = (int) luaL_optinteger(L, 4, 15);
memLevel = (int) luaL_optinteger(L, 5, 8);
strategy = (int) luaL_optinteger(L, 6, Z_DEFAULT_STRATEGY);
dictionary = luaL_optlstring(L, 7, NULL, &dictionary_len);
s = lzstream_new(L, 1);
if (deflateInit2(&s->zstream, level, method, windowBits, memLevel, strategy) != Z_OK) {
lua_pushliteral(L, "call to deflateInit2 failed");
lua_error(L);
}
if (dictionary) {
if (deflateSetDictionary(&s->zstream, (const Bytef *) dictionary, dictionary_len) != Z_OK) {
lua_pushliteral(L, "call to deflateSetDictionnary failed");
lua_error(L);
}
}
s->state = LZ_DEFLATE;
return 1;
}
/*
zlib.inflate(
source: string | function | { read: function, close: function },
windowBits: number, [15]
dictionary: [""]
)
*/
static int lzlib_inflate(lua_State *L)
{
int windowBits;
lz_stream *s;
int have_peek = 0;
const char *dictionary;
size_t dictionary_len;
if (lua_istable(L, 1) || lua_isuserdata(L, 1)) {
/* is there a :read function? */
lua_getfield(L, 1, "read");
if (!lua_isfunction(L, -1)) {
luaL_argerror(L, 1, "input parameter does not provide :read function");
}
lua_pop(L, 1);
/* check for peek function */
lua_getfield(L, 1, "peek");
have_peek = lua_isfunction(L, -1);
lua_pop(L, 1);
}
else if (!lua_isstring(L, 1) && !lua_isfunction(L, 1)) {
luaL_argerror(L, 1, "input parameter must be a string, function, table or userdata value");
}
windowBits = (int) luaL_optinteger(L, 2, 15);
dictionary = luaL_optlstring(L, 3, NULL, &dictionary_len);
s = lzstream_new(L, 1);
if (windowBits > 0 && windowBits < 16) {
windowBits |= 32;
}
if (inflateInit2(&s->zstream, windowBits) != Z_OK) {
lua_pushliteral(L, "call to inflateInit2 failed");
lua_error(L);
}
if (dictionary) {
s->dictionary = (const Bytef *) dictionary;
s->dictionary_len = dictionary_len;
}
s->peek = have_peek;
s->state = LZ_INFLATE;
return 1;
}
/* ====================================================================== */
static int lz_pushresult (lua_State *L, lz_stream *s) {
if (s->error == Z_OK) {
lua_pushboolean(L, 1);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, zError(s->error));
lua_pushinteger(L, s->error);
return 3;
}
}
/*
Get block to process:
- top of stack gets
*/
static const char* lzstream_fetch_block(lua_State *L, lz_stream *s, int hint) {
if (s->i_buffer_pos >= s->i_buffer_len) {
luaL_unref(L, LUA_REGISTRYINDEX, s->i_buffer_ref);
s->i_buffer_ref = LUA_NOREF;
s->i_buffer = NULL;
lua_rawgeti(L, LUA_REGISTRYINDEX, s->io_cb);
if (!lua_isnil(L, -1)) {
if (lua_isfunction(L, -1)) {
lua_pushinteger(L, hint);
lua_call(L, 1, 1);
} else {
lua_getfield(L, -1, (s->peek ? "peek" : "read"));
lua_insert(L, -2);
lua_pushinteger(L, hint);
lua_call(L, 2, 1);
}
if (lua_isstring(L, -1)) {
s->i_buffer_pos = 0;
s->i_buffer = lua_tolstring(L, -1, &s->i_buffer_len);
if (s->i_buffer_len > 0) {
s->i_buffer_ref = luaL_ref(L, LUA_REGISTRYINDEX);
} else {
lua_pop(L, 1);
}
} else if (lua_isnil(L, -1)) {
lua_pop(L, 1);
} else {
lua_pushliteral(L, "deflate callback must return string or nil");
lua_error(L);
}
} else {
lua_pop(L, 1);
}
}
return s->i_buffer;
}
static int lzstream_inflate_block(lua_State *L, lz_stream *s) {
if (lzstream_fetch_block(L, s, LZ_BUFFER_SIZE) || !s->eos) {
int r;
if (s->i_buffer_len == s->i_buffer_pos) {
s->zstream.next_in = NULL;
s->zstream.avail_in = 0;
} else {
s->zstream.next_in = (unsigned char*)(s->i_buffer + s->i_buffer_pos);
s->zstream.avail_in = s->i_buffer_len - s->i_buffer_pos;
}
s->zstream.next_out = (unsigned char*)s->o_buffer + s->o_buffer_len;
s->zstream.avail_out = s->o_buffer_max - s->o_buffer_len;
/* munch some more */
r = inflate(&s->zstream, Z_SYNC_FLUSH);
if (r == Z_NEED_DICT) {
if (s->dictionary == NULL) {
lua_pushliteral(L, "no inflate dictionary provided");
lua_error(L);
}
if (inflateSetDictionary(&s->zstream, s->dictionary, s->dictionary_len) != Z_OK) {
lua_pushliteral(L, "call to inflateSetDictionnary failed");
lua_error(L);
}
r = inflate(&s->zstream, Z_SYNC_FLUSH);
}
if (r != Z_OK && r != Z_STREAM_END && r != Z_BUF_ERROR) {
lzstream_cleanup(L, s);
s->error = r;
#if 1
lua_pushfstring(L, "failed to decompress [%d]", r);
lua_error(L);
#endif
}
if (r == Z_STREAM_END) {
luaL_unref(L, LUA_REGISTRYINDEX, s->i_buffer_ref);
s->i_buffer_ref = LUA_NOREF;
s->i_buffer = NULL;
s->eos = 1;
}
/* number of processed bytes */
if (s->peek) {
size_t processed = s->i_buffer_len - s->i_buffer_pos - s->zstream.avail_in;
lua_rawgeti(L, LUA_REGISTRYINDEX, s->io_cb);
lua_getfield(L, -1, "read");
lua_insert(L, -2);
lua_pushinteger(L, processed);
lua_call(L, 2, 0);
}
s->i_buffer_pos = s->i_buffer_len - s->zstream.avail_in;
s->o_buffer_len = s->o_buffer_max - s->zstream.avail_out;
}
return s->o_buffer_len;
}
/*
** Remove n bytes from the output buffer.
*/
static void lzstream_remove(lz_stream *s, size_t n) {
memmove(s->o_buffer, s->o_buffer + n, s->o_buffer_len - n);
s->o_buffer_len -= n;
}
/*
** Copy at most n bytes to buffer b and remove them from the
** output stream buffer.
*/
static int lzstream_flush_buffer(lua_State *L, lz_stream *s, size_t n, luaL_Buffer *b) {
/* check output */
if (n > s->o_buffer_len) {
n = s->o_buffer_len;
}
if (n > 0) {
lua_pushlstring(L, s->o_buffer, n);
luaL_addvalue(b);
lzstream_remove(s, n);
}
return n;
}
/*
z:read(
{number | '*l' | '*a'}*
)
*/
static int lz_test_eof(lua_State *L, lz_stream *s) {
lua_pushlstring(L, NULL, 0);
if (s->o_buffer_len > 0) {
return 1;
} else if (s->eos) {
return 0;
} else {
return lzstream_inflate_block(L, s);
}
}
static int lz_read_line(lua_State *L, lz_stream *s) {
luaL_Buffer b;
size_t l = 0, n;
luaL_buffinit(L, &b);
if (s->o_buffer_len > 0 || !s->eos) do {
char *p = s->o_buffer;
size_t len = s->o_buffer_len;
/* find newline in output buffer */
for (n = 0; n < len; ++n, ++p) {
if (*p == '\n' || *p == '\r') {
int eat_nl = *p == '\r';
luaL_addlstring(&b, s->o_buffer, n);
lzstream_remove(s, n+1);
l += n;
if (eat_nl && lzstream_inflate_block(L, s)) {
if (s->o_buffer_len > 0 && *s->o_buffer == '\n') {
lzstream_remove(s, 1);
}
}
luaL_pushresult(&b);
return 1;
}
}
if (len > 0) {
luaL_addlstring(&b, s->o_buffer, len);
lzstream_remove(s, len);
l += len;
}
} while (lzstream_inflate_block(L, s));
luaL_pushresult(&b);
return l > 0 || !s->eos || s->o_buffer_len > 0;
}
static int lz_read_chars(lua_State *L, lz_stream *s, size_t n) {
size_t len;
luaL_Buffer b;
luaL_buffinit(L, &b);
if (s->o_buffer_len > 0 || !s->eos) do {
size_t rlen = lzstream_flush_buffer(L, s, n, &b);
n -= rlen;
} while (n > 0 && lzstream_inflate_block(L, s));
luaL_pushresult(&b);
lua_tolstring(L, -1, &len);
return n == 0 || len > 0;
}
static int lzstream_decompress(lua_State *L) {
lz_stream *s = lzstream_check(L, 1, LZ_INFLATE);
int nargs = lua_gettop(L) - 1;
int success;
int n;
if (nargs == 0) { /* no arguments? */
success = lz_read_line(L, s);
n = 3; /* to return 1 result */
}
else { /* ensure stack space for all results and for auxlib's buffer */
luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
success = 1;
for (n = 2; nargs-- && success; n++) {
if (lua_type(L, n) == LUA_TNUMBER) {
size_t l = (size_t)lua_tointeger(L, n);
success = (l == 0) ? lz_test_eof(L, s) : lz_read_chars(L, s, l);
}
else {
const char *p = lua_tostring(L, n);
luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
switch (p[1]) {
case 'l': /* line */
success = lz_read_line(L, s);
break;
case 'a': /* file */
lz_read_chars(L, s, ~((size_t)0)); /* read MAX_SIZE_T chars */
success = 1; /* always success */
break;
default:
return luaL_argerror(L, n, "invalid format");
}
}
}
}
if (s->error != Z_OK) {
return lz_pushresult(L, s);
}
if (!success) {
lua_pop(L, 1); /* remove last result */
lua_pushnil(L); /* push nil instead */
}
return n - 2;
}
static int lzstream_readline(lua_State *L) {
lz_stream *s;
int sucess;
s = lzstream_check(L, lua_upvalueindex(1), LZ_INFLATE);
sucess = lz_read_line(L, s);
if (s->error != Z_OK) {
return lz_pushresult(L, s);
}
if (sucess) {
return 1;
} else {
/* EOF */
return 0;
}
}
static int lzstream_lines(lua_State *L) {
lzstream_check(L, 1, LZ_INFLATE);
lua_settop(L, 1);
lua_pushcclosure(L, lzstream_readline, 1);
return 1;
}
/* ====================================================================== */
static int lzstream_docompress(lua_State *L, lz_stream *s, int from, int to, int flush) {
int r, arg;
int self = 0;
size_t b_size = s->o_buffer_max;
unsigned char *b = (unsigned char *)s->o_buffer;
/* number of processed bytes */
lua_rawgeti(L, LUA_REGISTRYINDEX, s->io_cb);
if (!lua_isfunction(L, -1)) {
self = 1;
lua_getfield(L, -1, "write");
}
for (arg = from; arg <= to; arg++) {
s->zstream.next_in = (unsigned char*)luaL_checklstring(L, arg, (size_t*)&s->zstream.avail_in);
do {
s->zstream.next_out = b;
s->zstream.avail_out = b_size;
/* bake some more */
r = deflate(&s->zstream, flush);
if (r != Z_OK && r != Z_STREAM_END && r != Z_BUF_ERROR) {
lzstream_cleanup(L, s);
lua_pushboolean(L, 0);
lua_pushfstring(L, "failed to compress [%d]", r);
return 2;
}
if (s->zstream.avail_out != b_size) {
/* write output */
lua_pushvalue(L, -1); /* function */
if (self) lua_pushvalue(L, -3); /* self */
lua_pushlstring(L, (char*)b, b_size - s->zstream.avail_out); /* data */
lua_call(L, (self ? 2 : 1), 0);
}
if (r == Z_STREAM_END) {
lzstream_cleanup(L, s);
break;
}
/* process all input */
} while (s->zstream.avail_in > 0 || s->zstream.avail_out == 0);
}
lua_pushboolean(L, 1);
return 1;
}
static int lzstream_compress(lua_State *L) {
lz_stream *s = lzstream_check(L, 1, LZ_DEFLATE);
return lzstream_docompress(L, s, 2, lua_gettop(L), Z_NO_FLUSH);
}
/* ====================================================================== */
static int lzstream_flush(lua_State *L) {
static int flush_values[] = { Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH };
static const char *const flush_opts[] = { "sync", "full", "finish" };
lz_stream *s = lzstream_check(L, 1, LZ_DEFLATE);
int flush = luaL_checkoption(L, 2, flush_opts[0], flush_opts);
lua_settop(L, 0);
lua_pushliteral(L, "");
return lzstream_docompress(L, s, 1, 1, flush_values[flush]);
}
/*
** =========================================================================
** zlib functions
** =========================================================================
*/
static int lzlib_version(lua_State *L)
{
lua_pushstring(L, zlibVersion());
return 1;
}
/* ====================================================================== */
static int lzlib_adler32(lua_State *L)
{
if (lua_gettop(L) == 0)
{
/* adler32 initial value */
lua_pushnumber(L, adler32(0L, Z_NULL, 0));
}
else
{
/* update adler32 checksum */
size_t len;
int adler = (int) luaL_checkinteger(L, 1);
const unsigned char* buf = (unsigned char*)luaL_checklstring(L, 2, &len);
lua_pushnumber(L, adler32(adler, buf, len));
}
return 1;
}
/* ====================================================================== */
static int lzlib_crc32(lua_State *L)
{
if (lua_gettop(L) == 0)
{
/* crc32 initial value */
lua_pushnumber(L, crc32(0L, Z_NULL, 0));
}
else
{
/* update crc32 checksum */
size_t len;
int crc = (int) luaL_checkinteger(L, 1);
const unsigned char* buf = (unsigned char*)luaL_checklstring(L, 2, &len);
lua_pushnumber(L, crc32(crc, buf, len));
}
return 1;
}
/* ====================================================================== */
static int lzlib_compress(lua_State *L) {
size_t avail_in;
const char *next_in = luaL_checklstring(L, 1, &avail_in);
int level = (int) luaL_optinteger(L, 2, Z_DEFAULT_COMPRESSION);
int method = (int) luaL_optinteger(L, 3, Z_DEFLATED);
int windowBits = (int) luaL_optinteger(L, 4, 15);
int memLevel = (int) luaL_optinteger(L, 5, 8);
int strategy = (int) luaL_optinteger(L, 6, Z_DEFAULT_STRATEGY);
int ret;
luaL_Buffer b;
z_stream zs;
luaL_buffinit(L, &b);
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.next_out = Z_NULL;
zs.avail_out = 0;
zs.next_in = Z_NULL;
zs.avail_in = 0;
ret = deflateInit2(&zs, level, method, windowBits, memLevel, strategy);
if (ret != Z_OK)
{
lua_pushnil(L);
lua_pushnumber(L, ret);
return 2;
}
zs.next_in = (unsigned char*)next_in;
zs.avail_in = avail_in;
for(;;)
{
zs.next_out = (unsigned char*)luaL_prepbuffer(&b);
zs.avail_out = LUAL_BUFFERSIZE;
/* munch some more */
ret = deflate(&zs, Z_FINISH);
/* push gathered data */
luaL_addsize(&b, LUAL_BUFFERSIZE - zs.avail_out);
/* done processing? */
if (ret == Z_STREAM_END)
break;
/* error condition? */
if (ret != Z_OK)
break;
}
/* cleanup */
deflateEnd(&zs);
luaL_pushresult(&b);
lua_pushnumber(L, ret);
return 2;
}
/* ====================================================================== */
static int lzlib_decompress(lua_State *L)
{
size_t avail_in;
const char *next_in = luaL_checklstring(L, 1, &avail_in);
int windowBits = (int) luaL_optinteger(L, 2, 15);
int ret;
luaL_Buffer b;
z_stream zs;
luaL_buffinit(L, &b);
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.next_out = Z_NULL;
zs.avail_out = 0;
zs.next_in = Z_NULL;
zs.avail_in = 0;
ret = inflateInit2(&zs, windowBits);
if (ret != Z_OK) {
lua_pushliteral(L, "failed to initialize zstream structures");
lua_error(L);
}
zs.next_in = (unsigned char*)next_in;
zs.avail_in = avail_in;
for (;;) {
zs.next_out = (unsigned char*)luaL_prepbuffer(&b);
zs.avail_out = LUAL_BUFFERSIZE;
/* bake some more */
ret = inflate(&zs, Z_FINISH);
/* push gathered data */
luaL_addsize(&b, LUAL_BUFFERSIZE - zs.avail_out);
/* done processing? */
if (ret == Z_STREAM_END)
break;
if (ret != Z_OK && ret != Z_BUF_ERROR) {
/* cleanup */
inflateEnd(&zs);
lua_pushliteral(L, "failed to process zlib stream");
lua_error(L);
}
}
/* cleanup */
inflateEnd(&zs);
luaL_pushresult(&b);
return 1;
}
/*
** =========================================================================
** Register functions
** =========================================================================
*/
#if (LUA_VERSION_NUM >= 502)
#define luaL_register(L,n,f) luaL_setfuncs(L,f,0)
#endif
LUALIB_API int luaopen_zlib(lua_State *L)
{
const luaL_Reg lzstream_meta[] =
{
{"write", lzstream_compress },
{"read", lzstream_decompress },
{"lines", lzstream_lines },
{"flush", lzstream_flush },
{"close", lzstream_close },
{"adler", lzstream_adler },
{"__tostring", lzstream_tostring },
{"__gc", lzstream_gc },
{NULL, NULL}
};
const luaL_Reg zlib[] =
{
{"version", lzlib_version },
{"adler32", lzlib_adler32 },
{"crc32", lzlib_crc32 },
{"deflate", lzlib_deflate },
{"inflate", lzlib_inflate },
{"compress", lzlib_compress },
{"decompress", lzlib_decompress },
{NULL, NULL}
};
/* ====================================================================== */
/* create new metatable for zlib compression structures */
luaL_newmetatable(L, ZSTREAMMETA);
lua_pushliteral(L, "__index");
lua_pushvalue(L, -2); /* push metatable */
lua_rawset(L, -3); /* metatable.__index = metatable */
/*
** Stack: metatable
*/
luaL_register(L, NULL, lzstream_meta);
lua_pop(L, 1); /* remove metatable from stack */
/*
** Stack:
*/
lua_newtable(L);
lua_pushliteral (L, "_COPYRIGHT");
lua_pushliteral (L, "Copyright (C) 2003-2010 Tiago Dionizio");
lua_settable (L, -3);
lua_pushliteral (L, "_DESCRIPTION");
lua_pushliteral (L, "Lua 5 interface to access zlib library functions");
lua_settable (L, -3);
lua_pushliteral (L, "_VERSION");
lua_pushliteral (L, "lzlib 0.4-work3");
lua_settable (L, -3);
#define PUSH_LITERAL(name) \
lua_pushliteral (L, #name); \
lua_pushinteger (L, Z_##name); \
lua_settable (L, -3);
#define PUSH_NUMBER(name, value) \
lua_pushliteral (L, #name); \
lua_pushinteger (L, value); \
lua_settable (L, -3);
PUSH_LITERAL(NO_COMPRESSION)
PUSH_LITERAL(BEST_SPEED)
PUSH_LITERAL(BEST_COMPRESSION)
PUSH_LITERAL(DEFAULT_COMPRESSION)
PUSH_LITERAL(FILTERED)
PUSH_LITERAL(HUFFMAN_ONLY)
PUSH_LITERAL(RLE)
PUSH_LITERAL(FIXED)
PUSH_LITERAL(DEFAULT_STRATEGY)
PUSH_NUMBER(MINIMUM_MEMLEVEL, 1)
PUSH_NUMBER(MAXIMUM_MEMLEVEL, 9)
PUSH_NUMBER(DEFAULT_MEMLEVEL, 8)
PUSH_NUMBER(DEFAULT_WINDOWBITS, 15)
PUSH_NUMBER(MINIMUM_WINDOWBITS, 8)
PUSH_NUMBER(MAXIMUM_WINDOWBITS, 15)
PUSH_NUMBER(GZIP_WINDOWBITS, 16)
PUSH_NUMBER(RAW_WINDOWBITS, -1)
luaL_register(L, NULL, zlib);
/*
** Stack: zlib table
*/
return 1;
}

9
nse_zlib.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef ZLIB
#define ZLIB
#define NSE_ZLIBNAME "zlib"
LUALIB_API int luaopen_zlib(lua_State *L);
#endif

View File

@@ -153,6 +153,7 @@ local libs = {
"wsdd", "wsdd",
"xdmcp", "xdmcp",
"xmpp", "xmpp",
"zlib",
} }
-- This script-arg is documented in the unittest script to avoid cluttering -- This script-arg is documented in the unittest script to avoid cluttering

111
nselib/zlib.luadoc Normal file
View File

@@ -0,0 +1,111 @@
---
-- Zlib compression and decompression library
--
-- From https://github.com/LuaDist/lzlib
-- @author Tiago Dionizio <tiago.dionizio@gmail.com>
-- @copyright The MIT License (MIT); Copyright Tiago Dionizio (tiago.dionizio@gmail.com)
module "zlib"
-- NSEdoc derived from lzlib's README
--- returns zlib version
-- @return the zlib version
function version()
--- Compute an adler32 checksum
--
-- Without any parameters, returns the initial adler32 value.
--
-- Call to update the adler32 value, adler is the current value, buffer is passed
-- to adler32 zlib function and the updated value is returned.
-- @param adler An integer, the result of a previous call to <code>adler32</code>
-- @param buffer A string, over which to compute the adler32 checksum.
-- @return The adler32 checksum result.
function adler32(adler, buffer)
--- Compute a crc32 checksum
--
-- Without any parameters, returns the initial crc32 value.
--
-- Call to update the crc32 value, crc is the current value, buffer is passed
-- to crc32 zlib function and the updated value is returned.
-- @param crc An integer, the result of a previous call to <code>crc32</code>
-- @param buffer A string, over which to compute the crc32 checksum.
-- @return The crc32 checksum result.
function crc32(crc, buffer)
--- Return a string containing the compressed buffer according to the given parameters.
--
-- All of the parameters besides buffer are optional. The zlib library sets the
-- default values, which are usually equivalent to
-- <code>compress(buffer, 6, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY)</code>
-- @param buffer String to compress
-- @param level Optional integer corresponding to compression level, 0-9
-- @param method Optional integer corresponding to compression method
-- @param windowBits Optional integer, the base-2 logarithm of the maximum window size. Default: 15
-- @param memLevel Optional integer corresponding to memory use and therefore speed
-- @param strategy Optional integer corresponding to compression strategy
function compress(buffer, level, method, windowBits, memLevel, strategy)
--- Return the decompressed stream after processing the given buffer.
--
-- If windowBits is negative, this function decompresses raw deflate data without header.
-- @param buffer String containing DEFLATE-compressed data
-- @param windowBits Optional integer, the base-2 logarithm of the maximum window size. Default: 15
function decompress(buffer, windowBits)
--- Return a deflate stream.
--
-- This stream is a file-like object that can be used to write compressed
-- (deflated) data to some sink stream. If the sink stream is a table or
-- object, it must have a <code>write</code> method. Otherwise, it must be a
-- function that will be called with data to write (e.g.
-- <code>socket.send</code>).
-- @param sink The location where compressed data will be written
-- @param level Optional integer corresponding to compression level, 0-9
-- @param method Optional integer corresponding to compression method
-- @param windowBits Optional integer, the base-2 logarithm of the maximum window size. Default: 15
-- @param memLevel Optional integer corresponding to memory use and therefore speed
-- @param strategy Optional integer corresponding to compression strategy
-- @param dictionary Optional string corresponding to initial compression dictionary
function deflate(sink, level, method, windowBits, memLevel, strategy, dictionary)
--- Read from an inflate stream
--
-- @param how A number of bytes to read, or "*l" (read until newline), or "*a" (read the whole stream). Default: "*l"
-- @return The bytes read, or nil on EOF.
function inflate_stream:read(how)
--- Return iterator that returns a line each time it is called, or nil on end
-- of file.
-- @return An iterator suitable for use with <code>for</code>
function inflate_stream:lines()
--- Close the stream.
--@return True, or false on error
--@return An error string
function stream:close()
--- Return an inflate stream.
--
-- This stream is a file-like object that can be used to read decompressed
-- (inflated) data from some source stream. If the source stream is a table or
-- object, it must have a <code>read</code> method. Otherwise, it must be a
-- function that will be called to get more compressed data.
-- @param source The location where compressed data will be read from
-- @param windowBits Optional integer, the base-2 logarithm of the maximum window size. Default: 15
-- @param dictionary Optional string corresponding to initial compression dictionary
-- @return an inflate stream.
function inflate(source, windowBits, dictionary)
--- Write each parameter into the stream
-- @param ... any number of strings to write
-- @return True, or false on error
-- @return Error string on error
function deflate_stream:write(...)
--- Flush output for deflate streams.
-- @param value One of 'sync', 'full', or 'finish'
-- @return True, or false on error
-- @return Error string on error
function deflate_stream:flush(value)