suricata
util-lua-http.c
Go to the documentation of this file.
1 /* Copyright (C) 2014 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  */
24 
25 #include "suricata-common.h"
26 #include "detect.h"
27 #include "pkt-var.h"
28 #include "conf.h"
29 
30 #include "threads.h"
31 #include "threadvars.h"
32 #include "tm-threads.h"
33 
34 #include "util-print.h"
35 #include "util-unittest.h"
36 
37 #include "util-debug.h"
38 
39 #include "output.h"
40 #include "app-layer-htp.h"
41 #include "app-layer.h"
42 #include "app-layer-parser.h"
43 #include "util-privs.h"
44 #include "util-buffer.h"
45 #include "util-proto-name.h"
46 #include "util-logopenfile.h"
47 #include "util-time.h"
48 
49 #include "lua.h"
50 #include "lualib.h"
51 #include "lauxlib.h"
52 
53 #include "util-lua.h"
54 #include "util-lua-common.h"
55 #include "util-lua-http.h"
56 
57 static int HttpGetRequestHost(lua_State *luastate)
58 {
59  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
60  return LuaCallbackError(luastate, "error: protocol not http");
61 
62  htp_tx_t *tx = LuaStateGetTX(luastate);
63  if (tx == NULL)
64  return LuaCallbackError(luastate, "internal error: no tx");
65 
66  if (tx->request_hostname == NULL)
67  return LuaCallbackError(luastate, "no request hostname");
68 
69  return LuaPushStringBuffer(luastate,
70  bstr_ptr(tx->request_hostname), bstr_len(tx->request_hostname));
71 }
72 
73 static int HttpGetRequestUriRaw(lua_State *luastate)
74 {
75  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
76  return LuaCallbackError(luastate, "error: protocol not http");
77 
78  htp_tx_t *tx = LuaStateGetTX(luastate);
79  if (tx == NULL)
80  return LuaCallbackError(luastate, "internal error: no tx");
81 
82  if (tx->request_uri == NULL)
83  return LuaCallbackError(luastate, "no request uri");
84 
85  return LuaPushStringBuffer(luastate,
86  bstr_ptr(tx->request_uri), bstr_len(tx->request_uri));
87 }
88 
89 static int HttpGetRequestUriNormalized(lua_State *luastate)
90 {
91  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
92  return LuaCallbackError(luastate, "error: protocol not http");
93 
94  htp_tx_t *tx = LuaStateGetTX(luastate);
95  if (tx == NULL)
96  return LuaCallbackError(luastate, "internal error: no tx");
97 
98  HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
99  if (htud == NULL)
100  return LuaCallbackError(luastate, "no htud in tx");
101 
102  if (htud->request_uri_normalized == NULL ||
103  bstr_ptr(htud->request_uri_normalized) == NULL ||
104  bstr_len(htud->request_uri_normalized) == 0)
105  return LuaCallbackError(luastate, "no normalized uri");
106 
107  return LuaPushStringBuffer(luastate,
108  bstr_ptr(htud->request_uri_normalized),
109  bstr_len(htud->request_uri_normalized));
110 }
111 
112 static int HttpGetRequestLine(lua_State *luastate)
113 {
114  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
115  return LuaCallbackError(luastate, "error: protocol not http");
116 
117  htp_tx_t *tx = LuaStateGetTX(luastate);
118  if (tx == NULL)
119  return LuaCallbackError(luastate, "internal error: no tx");
120 
121  if (tx->request_line == NULL)
122  return LuaCallbackError(luastate, "no request_line");
123 
124  return LuaPushStringBuffer(luastate,
125  bstr_ptr(tx->request_line), bstr_len(tx->request_line));
126 }
127 
128 static int HttpGetResponseLine(lua_State *luastate)
129 {
130  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
131  return LuaCallbackError(luastate, "error: protocol not http");
132 
133  htp_tx_t *tx = LuaStateGetTX(luastate);
134  if (tx == NULL)
135  return LuaCallbackError(luastate, "internal error: no tx");
136 
137  if (tx->response_line == NULL)
138  return LuaCallbackError(luastate, "no response_line");
139 
140  return LuaPushStringBuffer(luastate,
141  bstr_ptr(tx->response_line), bstr_len(tx->response_line));
142 }
143 
144 static int HttpGetHeader(lua_State *luastate, int dir)
145 {
146  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
147  return LuaCallbackError(luastate, "error: protocol not http");
148 
149  htp_tx_t *tx = LuaStateGetTX(luastate);
150  if (tx == NULL)
151  return LuaCallbackError(luastate, "internal error: no tx");
152 
153  const char *name = LuaGetStringArgument(luastate, 1);
154  if (name == NULL)
155  return LuaCallbackError(luastate, "1st argument missing, empty or wrong type");
156 
157  htp_table_t *headers = tx->request_headers;
158  if (dir == 1)
159  headers = tx->response_headers;
160  if (headers == NULL)
161  return LuaCallbackError(luastate, "tx has no headers");
162 
163  htp_header_t *h = (htp_header_t *)htp_table_get_c(headers, name);
164  if (h == NULL || bstr_len(h->value) == 0)
165  return LuaCallbackError(luastate, "header not found");
166 
167  return LuaPushStringBuffer(luastate,
168  bstr_ptr(h->value), bstr_len(h->value));
169 }
170 
171 static int HttpGetRequestHeader(lua_State *luastate)
172 {
173  return HttpGetHeader(luastate, 0 /* request */);
174 }
175 
176 static int HttpGetResponseHeader(lua_State *luastate)
177 {
178  return HttpGetHeader(luastate, 1 /* response */);
179 }
180 
181 static int HttpGetRawHeaders(lua_State *luastate, int dir)
182 {
183  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
184  return LuaCallbackError(luastate, "error: protocol not http");
185 
186  htp_tx_t *tx = LuaStateGetTX(luastate);
187  if (tx == NULL)
188  return LuaCallbackError(luastate, "internal error: no tx");
189 
190  HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
191  if (htud == NULL)
192  return LuaCallbackError(luastate, "no htud in tx");
193 
194  uint8_t *raw = htud->request_headers_raw;
195  uint32_t raw_len = htud->request_headers_raw_len;
196  if (dir == 1) {
197  raw = htud->response_headers_raw;
198  raw_len = htud->response_headers_raw_len;
199  }
200 
201  if (raw == NULL || raw_len == 0)
202  return LuaCallbackError(luastate, "no raw headers");
203 
204  return LuaPushStringBuffer(luastate, raw, raw_len);
205 }
206 
207 static int HttpGetRawRequestHeaders(lua_State *luastate)
208 {
209  return HttpGetRawHeaders(luastate, 0);
210 }
211 
212 static int HttpGetRawResponseHeaders(lua_State *luastate)
213 {
214  return HttpGetRawHeaders(luastate, 1);
215 }
216 
217 
218 static int HttpGetHeaders(lua_State *luastate, int dir)
219 {
220  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
221  return LuaCallbackError(luastate, "error: protocol not http");
222 
223  htp_tx_t *tx = LuaStateGetTX(luastate);
224  if (tx == NULL)
225  return LuaCallbackError(luastate, "internal error: no tx");
226 
227  htp_table_t *table = tx->request_headers;
228  if (dir == 1)
229  table = tx->response_headers;
230  if (tx->request_headers == NULL)
231  return LuaCallbackError(luastate, "no headers");
232 
233  lua_newtable(luastate);
234  htp_header_t *h = NULL;
235  size_t i = 0;
236  size_t no_of_headers = htp_table_size(table);
237  for (; i < no_of_headers; i++) {
238  h = htp_table_get_index(table, i, NULL);
239  LuaPushStringBuffer(luastate, bstr_ptr(h->name), bstr_len(h->name));
240  LuaPushStringBuffer(luastate, bstr_ptr(h->value), bstr_len(h->value));
241  lua_settable(luastate, -3);
242  }
243  return 1;
244 }
245 
246 /** \brief return request headers as lua table */
247 static int HttpGetRequestHeaders(lua_State *luastate)
248 {
249  return HttpGetHeaders(luastate, 0);
250 }
251 
252 /** \brief return response headers as lua table */
253 static int HttpGetResponseHeaders(lua_State *luastate)
254 {
255  return HttpGetHeaders(luastate, 1);
256 }
257 
258 static int HttpGetBody(lua_State *luastate, int dir)
259 {
260  HtpBody *body = NULL;
261 
262  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
263  return LuaCallbackError(luastate, "error: protocol not http");
264 
265  htp_tx_t *tx = LuaStateGetTX(luastate);
266  if (tx == NULL)
267  return LuaCallbackError(luastate, "internal error: no tx");
268 
269  HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
270  if (htud == NULL)
271  return LuaCallbackError(luastate, "no htud in tx");
272 
273  if (dir == 0)
274  body = &htud->request_body;
275  else
276  body = &htud->response_body;
277 
278  if (body->first == NULL)
279  return LuaCallbackError(luastate, "no body");
280 
281  int index = 1;
282  HtpBodyChunk *chunk = body->first;
283  lua_newtable(luastate);
284  while (chunk != NULL) {
285  lua_pushinteger(luastate, index);
286 
287  const uint8_t *data = NULL;
288  uint32_t data_len = 0;
289  StreamingBufferSegmentGetData(body->sb, &chunk->sbseg, &data, &data_len);
290  LuaPushStringBuffer(luastate, data, data_len);
291 
292  lua_settable(luastate, -3);
293 
294  chunk = chunk->next;
295  index++;
296  }
297 
298  if (body->first && body->last) {
299  lua_pushinteger(luastate, body->first->sbseg.stream_offset);
300  lua_pushinteger(luastate, body->last->sbseg.stream_offset + body->last->sbseg.segment_len);
301  return 3;
302  } else {
303  return 1;
304  }
305 }
306 
307 static int HttpGetRequestBody(lua_State *luastate)
308 {
309  return HttpGetBody(luastate, 0);
310 }
311 
312 static int HttpGetResponseBody(lua_State *luastate)
313 {
314  return HttpGetBody(luastate, 1);
315 }
316 
317 /** \brief register http lua extensions in a luastate */
319 {
320  /* registration of the callbacks */
321  lua_pushcfunction(luastate, HttpGetRequestHeader);
322  lua_setglobal(luastate, "HttpGetRequestHeader");
323  lua_pushcfunction(luastate, HttpGetResponseHeader);
324  lua_setglobal(luastate, "HttpGetResponseHeader");
325  lua_pushcfunction(luastate, HttpGetRequestLine);
326  lua_setglobal(luastate, "HttpGetRequestLine");
327  lua_pushcfunction(luastate, HttpGetResponseLine);
328  lua_setglobal(luastate, "HttpGetResponseLine");
329  lua_pushcfunction(luastate, HttpGetRawRequestHeaders);
330  lua_setglobal(luastate, "HttpGetRawRequestHeaders");
331  lua_pushcfunction(luastate, HttpGetRawResponseHeaders);
332  lua_setglobal(luastate, "HttpGetRawResponseHeaders");
333  lua_pushcfunction(luastate, HttpGetRequestUriRaw);
334  lua_setglobal(luastate, "HttpGetRequestUriRaw");
335  lua_pushcfunction(luastate, HttpGetRequestUriNormalized);
336  lua_setglobal(luastate, "HttpGetRequestUriNormalized");
337  lua_pushcfunction(luastate, HttpGetRequestHeaders);
338  lua_setglobal(luastate, "HttpGetRequestHeaders");
339  lua_pushcfunction(luastate, HttpGetResponseHeaders);
340  lua_setglobal(luastate, "HttpGetResponseHeaders");
341  lua_pushcfunction(luastate, HttpGetRequestHost);
342  lua_setglobal(luastate, "HttpGetRequestHost");
343 
344  lua_pushcfunction(luastate, HttpGetRequestBody);
345  lua_setglobal(luastate, "HttpGetRequestBody");
346  lua_pushcfunction(luastate, HttpGetResponseBody);
347  lua_setglobal(luastate, "HttpGetResponseBody");
348  return 0;
349 }
tm-threads.h
util-lua-common.h
HtpTxUserData_::request_headers_raw_len
uint32_t request_headers_raw_len
Definition: app-layer-htp.h:226
HtpBody_::sb
StreamingBuffer * sb
Definition: app-layer-htp.h:189
util-lua.h
LuaCallbackError
int LuaCallbackError(lua_State *luastate, const char *msg)
Definition: util-lua-common.c:59
threads.h
HtpBody_::last
HtpBodyChunk * last
Definition: app-layer-htp.h:187
HtpTxUserData_::request_body
HtpBody request_body
Definition: app-layer-htp.h:219
util-privs.h
HtpTxUserData_::request_uri_normalized
bstr * request_uri_normalized
Definition: app-layer-htp.h:222
util-unittest.h
HtpBody_::first
HtpBodyChunk * first
Definition: app-layer-htp.h:186
lua_State
struct lua_State lua_State
Definition: suricata-common.h:506
app-layer-htp.h
LuaRegisterHttpFunctions
int LuaRegisterHttpFunctions(lua_State *luastate)
register http lua extensions in a luastate
Definition: util-lua-http.c:318
util-debug.h
util-print.h
detect.h
HtpTxUserData_::request_headers_raw
uint8_t * request_headers_raw
Definition: app-layer-htp.h:224
pkt-var.h
util-time.h
app-layer-parser.h
conf.h
util-proto-name.h
HtpTxUserData_::response_body
HtpBody response_body
Definition: app-layer-htp.h:220
LuaStateGetTX
void * LuaStateGetTX(lua_State *luastate)
get tx pointer from the lua state
Definition: util-lua.c:134
HtpBody_
Definition: app-layer-htp.h:185
suricata-common.h
HtpTxUserData_::response_headers_raw
uint8_t * response_headers_raw
Definition: app-layer-htp.h:225
HtpBodyChunk_
Definition: app-layer-htp.h:177
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:30
HtpTxUserData_
Definition: app-layer-htp.h:206
threadvars.h
HtpBodyChunk_::next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:178
util-logopenfile.h
util-buffer.h
LuaGetStringArgument
const char * LuaGetStringArgument(lua_State *luastate, int argc)
Definition: util-lua-common.c:66
util-lua-http.h
HtpTxUserData_::response_headers_raw_len
uint32_t response_headers_raw_len
Definition: app-layer-htp.h:227
StreamingBufferSegmentGetData
void StreamingBufferSegmentGetData(const StreamingBuffer *sb, const StreamingBufferSegment *seg, const uint8_t **data, uint32_t *data_len)
Definition: util-streaming-buffer.c:1737
HtpBodyChunk_::sbseg
StreamingBufferSegment sbseg
Definition: app-layer-htp.h:180
LuaStateNeedProto
int LuaStateNeedProto(lua_State *luastate, AppProto alproto)
Definition: util-lua-common.c:995
output.h
LuaPushStringBuffer
int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len)
Definition: util-lua.c:319
app-layer.h