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 #ifdef HAVE_LUA
50 
51 #include <lua.h>
52 #include <lualib.h>
53 #include <lauxlib.h>
54 
55 #include "util-lua.h"
56 #include "util-lua-common.h"
57 #include "util-lua-http.h"
58 
59 static int HttpGetRequestHost(lua_State *luastate)
60 {
61  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
62  return LuaCallbackError(luastate, "error: protocol not http");
63 
64  htp_tx_t *tx = LuaStateGetTX(luastate);
65  if (tx == NULL)
66  return LuaCallbackError(luastate, "internal error: no tx");
67 
68  if (tx->request_hostname == NULL)
69  return LuaCallbackError(luastate, "no request hostname");
70 
71  return LuaPushStringBuffer(luastate,
72  bstr_ptr(tx->request_hostname), bstr_len(tx->request_hostname));
73 }
74 
75 static int HttpGetRequestUriRaw(lua_State *luastate)
76 {
77  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
78  return LuaCallbackError(luastate, "error: protocol not http");
79 
80  htp_tx_t *tx = LuaStateGetTX(luastate);
81  if (tx == NULL)
82  return LuaCallbackError(luastate, "internal error: no tx");
83 
84  if (tx->request_uri == NULL)
85  return LuaCallbackError(luastate, "no request uri");
86 
87  return LuaPushStringBuffer(luastate,
88  bstr_ptr(tx->request_uri), bstr_len(tx->request_uri));
89 }
90 
91 static int HttpGetRequestUriNormalized(lua_State *luastate)
92 {
93  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
94  return LuaCallbackError(luastate, "error: protocol not http");
95 
96  htp_tx_t *tx = LuaStateGetTX(luastate);
97  if (tx == NULL)
98  return LuaCallbackError(luastate, "internal error: no tx");
99 
100  HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
101  if (htud == NULL)
102  return LuaCallbackError(luastate, "no htud in tx");
103 
104  if (htud->request_uri_normalized == NULL ||
105  bstr_ptr(htud->request_uri_normalized) == NULL ||
106  bstr_len(htud->request_uri_normalized) == 0)
107  return LuaCallbackError(luastate, "no normalized uri");
108 
109  return LuaPushStringBuffer(luastate,
110  bstr_ptr(htud->request_uri_normalized),
111  bstr_len(htud->request_uri_normalized));
112 }
113 
114 static int HttpGetRequestLine(lua_State *luastate)
115 {
116  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
117  return LuaCallbackError(luastate, "error: protocol not http");
118 
119  htp_tx_t *tx = LuaStateGetTX(luastate);
120  if (tx == NULL)
121  return LuaCallbackError(luastate, "internal error: no tx");
122 
123  if (tx->request_line == NULL)
124  return LuaCallbackError(luastate, "no request_line");
125 
126  return LuaPushStringBuffer(luastate,
127  bstr_ptr(tx->request_line), bstr_len(tx->request_line));
128 }
129 
130 static int HttpGetResponseLine(lua_State *luastate)
131 {
132  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
133  return LuaCallbackError(luastate, "error: protocol not http");
134 
135  htp_tx_t *tx = LuaStateGetTX(luastate);
136  if (tx == NULL)
137  return LuaCallbackError(luastate, "internal error: no tx");
138 
139  if (tx->response_line == NULL)
140  return LuaCallbackError(luastate, "no response_line");
141 
142  return LuaPushStringBuffer(luastate,
143  bstr_ptr(tx->response_line), bstr_len(tx->response_line));
144 }
145 
146 static int HttpGetHeader(lua_State *luastate, int dir)
147 {
148  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
149  return LuaCallbackError(luastate, "error: protocol not http");
150 
151  htp_tx_t *tx = LuaStateGetTX(luastate);
152  if (tx == NULL)
153  return LuaCallbackError(luastate, "internal error: no tx");
154 
155  const char *name = LuaGetStringArgument(luastate, 1);
156  if (name == NULL)
157  return LuaCallbackError(luastate, "1st argument missing, empty or wrong type");
158 
159  htp_table_t *headers = tx->request_headers;
160  if (dir == 1)
161  headers = tx->response_headers;
162  if (headers == NULL)
163  return LuaCallbackError(luastate, "tx has no headers");
164 
165  htp_header_t *h = (htp_header_t *)htp_table_get_c(headers, name);
166  if (h == NULL || bstr_len(h->value) == 0)
167  return LuaCallbackError(luastate, "header not found");
168 
169  return LuaPushStringBuffer(luastate,
170  bstr_ptr(h->value), bstr_len(h->value));
171 }
172 
173 static int HttpGetRequestHeader(lua_State *luastate)
174 {
175  return HttpGetHeader(luastate, 0 /* request */);
176 }
177 
178 static int HttpGetResponseHeader(lua_State *luastate)
179 {
180  return HttpGetHeader(luastate, 1 /* response */);
181 }
182 
183 static int HttpGetRawHeaders(lua_State *luastate, int dir)
184 {
185  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
186  return LuaCallbackError(luastate, "error: protocol not http");
187 
188  htp_tx_t *tx = LuaStateGetTX(luastate);
189  if (tx == NULL)
190  return LuaCallbackError(luastate, "internal error: no tx");
191 
192  HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
193  if (htud == NULL)
194  return LuaCallbackError(luastate, "no htud in tx");
195 
196  uint8_t *raw = htud->request_headers_raw;
197  uint32_t raw_len = htud->request_headers_raw_len;
198  if (dir == 1) {
199  raw = htud->response_headers_raw;
200  raw_len = htud->response_headers_raw_len;
201  }
202 
203  if (raw == NULL || raw_len == 0)
204  return LuaCallbackError(luastate, "no raw headers");
205 
206  return LuaPushStringBuffer(luastate, raw, raw_len);
207 }
208 
209 static int HttpGetRawRequestHeaders(lua_State *luastate)
210 {
211  return HttpGetRawHeaders(luastate, 0);
212 }
213 
214 static int HttpGetRawResponseHeaders(lua_State *luastate)
215 {
216  return HttpGetRawHeaders(luastate, 1);
217 }
218 
219 
220 static int HttpGetHeaders(lua_State *luastate, int dir)
221 {
222  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
223  return LuaCallbackError(luastate, "error: protocol not http");
224 
225  htp_tx_t *tx = LuaStateGetTX(luastate);
226  if (tx == NULL)
227  return LuaCallbackError(luastate, "internal error: no tx");
228 
229  htp_table_t *table = tx->request_headers;
230  if (dir == 1)
231  table = tx->response_headers;
232  if (tx->request_headers == NULL)
233  return LuaCallbackError(luastate, "no headers");
234 
235  lua_newtable(luastate);
236  htp_header_t *h = NULL;
237  size_t i = 0;
238  size_t no_of_headers = htp_table_size(table);
239  for (; i < no_of_headers; i++) {
240  h = htp_table_get_index(table, i, NULL);
241  LuaPushStringBuffer(luastate, bstr_ptr(h->name), bstr_len(h->name));
242  LuaPushStringBuffer(luastate, bstr_ptr(h->value), bstr_len(h->value));
243  lua_settable(luastate, -3);
244  }
245  return 1;
246 }
247 
248 /** \brief return request headers as lua table */
249 static int HttpGetRequestHeaders(lua_State *luastate)
250 {
251  return HttpGetHeaders(luastate, 0);
252 }
253 
254 /** \brief return response headers as lua table */
255 static int HttpGetResponseHeaders(lua_State *luastate)
256 {
257  return HttpGetHeaders(luastate, 1);
258 }
259 
260 static int HttpGetBody(lua_State *luastate, int dir)
261 {
262  HtpBody *body = NULL;
263 
264  if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1)))
265  return LuaCallbackError(luastate, "error: protocol not http");
266 
267  htp_tx_t *tx = LuaStateGetTX(luastate);
268  if (tx == NULL)
269  return LuaCallbackError(luastate, "internal error: no tx");
270 
271  HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
272  if (htud == NULL)
273  return LuaCallbackError(luastate, "no htud in tx");
274 
275  if (dir == 0)
276  body = &htud->request_body;
277  else
278  body = &htud->response_body;
279 
280  if (body->first == NULL)
281  return LuaCallbackError(luastate, "no body");
282 
283  int index = 1;
284  HtpBodyChunk *chunk = body->first;
285  lua_newtable(luastate);
286  while (chunk != NULL) {
287  lua_pushinteger(luastate, index);
288 
289  const uint8_t *data = NULL;
290  uint32_t data_len = 0;
291  StreamingBufferSegmentGetData(body->sb, &chunk->sbseg, &data, &data_len);
292  LuaPushStringBuffer(luastate, data, data_len);
293 
294  lua_settable(luastate, -3);
295 
296  chunk = chunk->next;
297  index++;
298  }
299 
300  if (body->first && body->last) {
301  lua_pushinteger(luastate, body->first->sbseg.stream_offset);
302  lua_pushinteger(luastate, body->last->sbseg.stream_offset + body->last->sbseg.segment_len);
303  return 3;
304  } else {
305  return 1;
306  }
307 }
308 
309 static int HttpGetRequestBody(lua_State *luastate)
310 {
311  return HttpGetBody(luastate, 0);
312 }
313 
314 static int HttpGetResponseBody(lua_State *luastate)
315 {
316  return HttpGetBody(luastate, 1);
317 }
318 
319 /** \brief register http lua extensions in a luastate */
320 int LuaRegisterHttpFunctions(lua_State *luastate)
321 {
322  /* registration of the callbacks */
323  lua_pushcfunction(luastate, HttpGetRequestHeader);
324  lua_setglobal(luastate, "HttpGetRequestHeader");
325  lua_pushcfunction(luastate, HttpGetResponseHeader);
326  lua_setglobal(luastate, "HttpGetResponseHeader");
327  lua_pushcfunction(luastate, HttpGetRequestLine);
328  lua_setglobal(luastate, "HttpGetRequestLine");
329  lua_pushcfunction(luastate, HttpGetResponseLine);
330  lua_setglobal(luastate, "HttpGetResponseLine");
331  lua_pushcfunction(luastate, HttpGetRawRequestHeaders);
332  lua_setglobal(luastate, "HttpGetRawRequestHeaders");
333  lua_pushcfunction(luastate, HttpGetRawResponseHeaders);
334  lua_setglobal(luastate, "HttpGetRawResponseHeaders");
335  lua_pushcfunction(luastate, HttpGetRequestUriRaw);
336  lua_setglobal(luastate, "HttpGetRequestUriRaw");
337  lua_pushcfunction(luastate, HttpGetRequestUriNormalized);
338  lua_setglobal(luastate, "HttpGetRequestUriNormalized");
339  lua_pushcfunction(luastate, HttpGetRequestHeaders);
340  lua_setglobal(luastate, "HttpGetRequestHeaders");
341  lua_pushcfunction(luastate, HttpGetResponseHeaders);
342  lua_setglobal(luastate, "HttpGetResponseHeaders");
343  lua_pushcfunction(luastate, HttpGetRequestHost);
344  lua_setglobal(luastate, "HttpGetRequestHost");
345 
346  lua_pushcfunction(luastate, HttpGetRequestBody);
347  lua_setglobal(luastate, "HttpGetRequestBody");
348  lua_pushcfunction(luastate, HttpGetResponseBody);
349  lua_setglobal(luastate, "HttpGetResponseBody");
350  return 0;
351 }
352 
353 #endif /* HAVE_LUA */
tm-threads.h
util-lua-common.h
HtpTxUserData_::request_headers_raw_len
uint32_t request_headers_raw_len
Definition: app-layer-htp.h:229
HtpBody_::sb
StreamingBuffer * sb
Definition: app-layer-htp.h:190
util-lua.h
threads.h
HtpBody_::last
HtpBodyChunk * last
Definition: app-layer-htp.h:188
HtpTxUserData_::request_body
HtpBody request_body
Definition: app-layer-htp.h:222
util-privs.h
HtpTxUserData_::request_uri_normalized
bstr * request_uri_normalized
Definition: app-layer-htp.h:225
util-unittest.h
HtpBody_::first
HtpBodyChunk * first
Definition: app-layer-htp.h:187
app-layer-htp.h
util-debug.h
util-print.h
detect.h
HtpTxUserData_::request_headers_raw
uint8_t * request_headers_raw
Definition: app-layer-htp.h:227
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:223
HtpBody_
Definition: app-layer-htp.h:186
suricata-common.h
HtpTxUserData_::response_headers_raw
uint8_t * response_headers_raw
Definition: app-layer-htp.h:228
HtpBodyChunk_
Definition: app-layer-htp.h:178
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:30
lua_State
void lua_State
Definition: suricata-common.h:500
HtpTxUserData_
Definition: app-layer-htp.h:207
threadvars.h
HtpBodyChunk_::next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:179
util-logopenfile.h
util-buffer.h
util-lua-http.h
HtpTxUserData_::response_headers_raw_len
uint32_t response_headers_raw_len
Definition: app-layer-htp.h:230
StreamingBufferSegmentGetData
void StreamingBufferSegmentGetData(const StreamingBuffer *sb, const StreamingBufferSegment *seg, const uint8_t **data, uint32_t *data_len)
Definition: util-streaming-buffer.c:1734
HtpBodyChunk_::sbseg
StreamingBufferSegment sbseg
Definition: app-layer-htp.h:181
output.h
app-layer.h