suricata
respond-reject-libnet11.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2013 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  * \author William Metcalf <william.metcalf@gmail.com>
23  *
24  * RespondRejectLibnet11 used to send out libnet based
25  * TCP resets and ICMP unreachables.
26  *
27  * \todo calculate TTL base on average from stream tracking
28  * \todo come up with a way for users to specify icmp unreachable type
29  * \todo Possibly default to port unreachable for UDP traffic this seems
30  * to be the default in flexresp and iptables
31  * \todo implement ipv6 resets
32  * \todo implement pre-alloc resets for speed
33  */
34 
35 #include "suricata-common.h"
36 
37 #include "decode.h"
38 #include "decode-ipv4.h"
39 #include "decode-tcp.h"
40 #include "decode-sctp.h"
41 #include "decode-udp.h"
42 #include "packet-queue.h"
43 #include "threads.h"
44 #include "threadvars.h"
45 #include "tm-queuehandlers.h"
46 #include "tm-threads.h"
47 #include "action-globals.h"
48 #include "respond-reject.h"
50 #include "util-device.h"
51 
52 #ifdef HAVE_LIBNET11
53 
54 #ifndef HAVE_LIBNET_INIT_CONST
55 #define LIBNET_INIT_CAST (char *)
56 #else
57 #define LIBNET_INIT_CAST
58 #endif
59 
60 /** set to true in main if we're setting caps. We need it here if we're using
61  * reject rules as libnet 1.1 is not compatible with caps. */
62 extern int sc_set_caps;
63 
64 #include <libnet.h>
65 
66 extern uint8_t host_mode;
67 
68 typedef struct Libnet11Packet_ {
69  uint32_t ack, seq;
70  uint16_t window, dsize;
71  uint8_t ttl;
72  uint16_t id;
73  uint32_t flow;
74  uint8_t class;
75  struct libnet_in6_addr src6, dst6;
76  uint32_t src4, dst4;
77  uint16_t sp, dp;
78  size_t len;
79 } Libnet11Packet;
80 
81 int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir)
82 {
83 
84  Libnet11Packet lpacket;
85  libnet_t *c; /* libnet context */
86  char ebuf[LIBNET_ERRBUF_SIZE];
87  int result;
88  const char *devname = NULL;
89 
90  /* fill in struct defaults */
91  lpacket.ttl = 0;
92  lpacket.id = 0;
93  lpacket.flow = 0;
94  lpacket.class = 0;
95 
97  devname = p->livedev->dev;
98  SCLogDebug("Will emit reject packet on dev %s", devname);
99  }
100  if ((c = libnet_init(LIBNET_RAW4, LIBNET_INIT_CAST devname, ebuf)) == NULL) {
101  SCLogError(SC_ERR_LIBNET_INIT,"libnet_init failed: %s", ebuf);
102  return 1;
103  }
104 
105  if (p->tcph == NULL)
106  return 1;
107 
108  /* save payload len */
109  lpacket.dsize = p->payload_len;
110 
111  switch (dir) {
112  case REJECT_DIR_SRC:
113  SCLogDebug("sending a tcp reset to src");
114  /* We follow http://tools.ietf.org/html/rfc793#section-3.4 :
115  * If packet has no ACK, the seq number is 0 and the ACK is built
116  * the normal way. If packet has a ACK, the seq of the RST packet
117  * is equal to the ACK of incoming packet and the ACK is build
118  * using packet sequence number and size of the data. */
119  if (TCP_GET_ACK(p) == 0) {
120  lpacket.seq = 0;
121  lpacket.ack = TCP_GET_SEQ(p) + lpacket.dsize + 1;
122  } else {
123  lpacket.seq = TCP_GET_ACK(p);
124  lpacket.ack = TCP_GET_SEQ(p) + lpacket.dsize;
125  }
126 
127  lpacket.sp = TCP_GET_DST_PORT(p);
128  lpacket.dp = TCP_GET_SRC_PORT(p);
129 
130  lpacket.src4 = GET_IPV4_DST_ADDR_U32(p);
131  lpacket.dst4 = GET_IPV4_SRC_ADDR_U32(p);
132  break;
133  case REJECT_DIR_DST:
134  SCLogDebug("sending a tcp reset to dst");
135  lpacket.seq = TCP_GET_SEQ(p);
136  lpacket.ack = TCP_GET_ACK(p);
137 
138  lpacket.sp = TCP_GET_SRC_PORT(p);
139  lpacket.dp = TCP_GET_DST_PORT(p);
140 
141  lpacket.src4 = GET_IPV4_SRC_ADDR_U32(p);
142  lpacket.dst4 = GET_IPV4_DST_ADDR_U32(p);
143  break;
144  default:
146  "reset not src or dst returning");
147  return 1;
148  }
149 
150  lpacket.window = TCP_GET_WINDOW(p);
151  //lpacket.seq += lpacket.dsize;
152 
153  /* TODO come up with ttl calc function */
154  lpacket.ttl = 64;
155 
156  /* build the package */
157  if ((libnet_build_tcp(
158  lpacket.sp, /* source port */
159  lpacket.dp, /* dst port */
160  lpacket.seq, /* seq number */
161  lpacket.ack, /* ack number */
162  TH_RST|TH_ACK, /* flags */
163  lpacket.window, /* window size */
164  0, /* checksum */
165  0, /* urgent flag */
166  LIBNET_TCP_H, /* header length */
167  NULL, /* payload */
168  0, /* payload length */
169  c, /* libnet context */
170  0)) < 0) /* libnet ptag */
171  {
172  SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_tcp %s", libnet_geterror(c));
173  goto cleanup;
174  }
175 
176  if ((libnet_build_ipv4(
177  LIBNET_TCP_H + LIBNET_IPV4_H, /* entire packet length */
178  0, /* tos */
179  lpacket.id, /* ID */
180  0, /* fragmentation flags and offset */
181  lpacket.ttl, /* TTL */
182  IPPROTO_TCP, /* protocol */
183  0, /* checksum */
184  lpacket.src4, /* source address */
185  lpacket.dst4, /* destination address */
186  NULL, /* pointer to packet data (or NULL) */
187  0, /* payload length */
188  c, /* libnet context pointer */
189  0)) < 0) /* packet id */
190  {
191  SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_ipv4 %s", libnet_geterror(c));
192  goto cleanup;
193  }
194 
195  result = libnet_write(c);
196  if (result == -1) {
197  SCLogError(SC_ERR_LIBNET_WRITE_FAILED,"libnet_write failed: %s", libnet_geterror(c));
198  goto cleanup;
199  }
200 
201 cleanup:
202  libnet_destroy (c);
203  return 0;
204 }
205 
206 int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
207 {
208  Libnet11Packet lpacket;
209  libnet_t *c; /* libnet context */
210  char ebuf[LIBNET_ERRBUF_SIZE];
211  int result;
212  const char *devname = NULL;
213 
214  /* fill in struct defaults */
215  lpacket.ttl = 0;
216  lpacket.id = 0;
217  lpacket.flow = 0;
218  lpacket.class = 0;
219 
220  lpacket.len = (IPV4_GET_HLEN(p) + p->payload_len);
221 
223  devname = p->livedev->dev;
224  }
225  if ((c = libnet_init(LIBNET_RAW4, LIBNET_INIT_CAST devname, ebuf)) == NULL) {
226  SCLogError(SC_ERR_LIBNET_INIT,"libnet_inint failed: %s", ebuf);
227  return 1;
228  }
229 
230  switch (dir) {
231  case REJECT_DIR_SRC:
232  lpacket.src4 = GET_IPV4_DST_ADDR_U32(p);
233  lpacket.dst4 = GET_IPV4_SRC_ADDR_U32(p);
234  break;
235  case REJECT_DIR_DST:
236  lpacket.src4 = GET_IPV4_SRC_ADDR_U32(p);
237  lpacket.dst4 = GET_IPV4_DST_ADDR_U32(p);
238  break;
239  default:
241  "reset not src or dst returning");
242  return 1;
243  }
244 
245  /* TODO come up with ttl calc function */
246  lpacket.ttl = 64;
247 
248  /* build the package */
249  if ((libnet_build_icmpv4_unreach(
250  ICMP_DEST_UNREACH, /* type */
251  ICMP_HOST_ANO, /* code */
252  0, /* checksum */
253  (uint8_t *)p->ip4h, /* payload */
254  lpacket.len, /* payload length */
255  c, /* libnet context */
256  0)) < 0) /* libnet ptag */
257  {
258  SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_icmpv4_unreach %s", libnet_geterror(c));
259  goto cleanup;
260  }
261 
262  if ((libnet_build_ipv4(
263  LIBNET_ICMPV4_H + LIBNET_IPV4_H +
264  lpacket.len, /* entire packet length */
265  0, /* tos */
266  lpacket.id, /* ID */
267  0, /* fragmentation flags and offset */
268  lpacket.ttl, /* TTL */
269  IPPROTO_ICMP, /* protocol */
270  0, /* checksum */
271  lpacket.src4, /* source address */
272  lpacket.dst4, /* destination address */
273  NULL, /* pointer to packet data (or NULL) */
274  0, /* payload length */
275  c, /* libnet context pointer */
276  0)) < 0) /* packet id */
277  {
278  SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_ipv4 %s", libnet_geterror(c));
279  goto cleanup;
280  }
281 
282  result = libnet_write(c);
283  if (result == -1) {
284  SCLogError(SC_ERR_LIBNET_WRITE_FAILED,"libnet_write_raw_ipv4 failed: %s", libnet_geterror(c));
285  goto cleanup;
286  }
287 
288 cleanup:
289  libnet_destroy (c);
290  return 0;
291 }
292 
293 int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir)
294 {
295 
296  Libnet11Packet lpacket;
297  libnet_t *c; /* libnet context */
298  char ebuf[LIBNET_ERRBUF_SIZE];
299  int result;
300  const char *devname = NULL;
301 
302  /* fill in struct defaults */
303  lpacket.ttl = 0;
304  lpacket.id = 0;
305  lpacket.flow = 0;
306  lpacket.class = 0;
307 
309  devname = p->livedev->dev;
310  }
311  if ((c = libnet_init(LIBNET_RAW6, LIBNET_INIT_CAST devname, ebuf)) == NULL) {
312  SCLogError(SC_ERR_LIBNET_INIT,"libnet_init failed: %s", ebuf);
313  return 1;
314  }
315 
316  if (p->tcph == NULL)
317  return 1;
318 
319  /* save payload len */
320  lpacket.dsize = p->payload_len;
321 
322  switch (dir) {
323  case REJECT_DIR_SRC:
324  SCLogDebug("sending a tcp reset to src");
325  /* We follow http://tools.ietf.org/html/rfc793#section-3.4 :
326  * If packet has no ACK, the seq number is 0 and the ACK is built
327  * the normal way. If packet has a ACK, the seq of the RST packet
328  * is equal to the ACK of incoming packet and the ACK is build
329  * using packet sequence number and size of the data. */
330  if (TCP_GET_ACK(p) == 0) {
331  lpacket.seq = 0;
332  lpacket.ack = TCP_GET_SEQ(p) + lpacket.dsize + 1;
333  } else {
334  lpacket.seq = TCP_GET_ACK(p);
335  lpacket.ack = TCP_GET_SEQ(p) + lpacket.dsize;
336  }
337 
338  lpacket.sp = TCP_GET_DST_PORT(p);
339  lpacket.dp = TCP_GET_SRC_PORT(p);
340 
341  memcpy(lpacket.src6.libnet_s6_addr, GET_IPV6_DST_ADDR(p), 16);
342  memcpy(lpacket.dst6.libnet_s6_addr, GET_IPV6_SRC_ADDR(p), 16);
343 
344  break;
345  case REJECT_DIR_DST:
346  SCLogDebug("sending a tcp reset to dst");
347  lpacket.seq = TCP_GET_SEQ(p);
348  lpacket.ack = TCP_GET_ACK(p);
349 
350  lpacket.sp = TCP_GET_SRC_PORT(p);
351  lpacket.dp = TCP_GET_DST_PORT(p);
352 
353  memcpy(lpacket.src6.libnet_s6_addr, GET_IPV6_SRC_ADDR(p), 16);
354  memcpy(lpacket.dst6.libnet_s6_addr, GET_IPV6_DST_ADDR(p), 16);
355  break;
356  default:
358  "reset not src or dst returning");
359  return 1;
360  }
361 
362  lpacket.window = TCP_GET_WINDOW(p);
363  //lpacket.seq += lpacket.dsize;
364 
365  /* TODO come up with ttl calc function */
366  lpacket.ttl = 64;
367 
368  /* build the package */
369  if ((libnet_build_tcp(
370  lpacket.sp, /* source port */
371  lpacket.dp, /* dst port */
372  lpacket.seq, /* seq number */
373  lpacket.ack, /* ack number */
374  TH_RST|TH_ACK, /* flags */
375  lpacket.window, /* window size */
376  0, /* checksum */
377  0, /* urgent flag */
378  LIBNET_TCP_H, /* header length */
379  NULL, /* payload */
380  0, /* payload length */
381  c, /* libnet context */
382  0)) < 0) /* libnet ptag */
383  {
384  SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_tcp %s", libnet_geterror(c));
385  goto cleanup;
386  }
387 
388  if ((libnet_build_ipv6(
389  lpacket.class, /* traffic class */
390  lpacket.flow, /* Flow label */
391  LIBNET_TCP_H, /* payload length */
392  IPPROTO_TCP, /* next header */
393  lpacket.ttl, /* TTL */
394  lpacket.src6, /* source address */
395  lpacket.dst6, /* destination address */
396  NULL, /* pointer to packet data (or NULL) */
397  0, /* payload length */
398  c, /* libnet context pointer */
399  0)) < 0) /* packet id */
400  {
401  SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_ipv6 %s", libnet_geterror(c));
402  goto cleanup;
403  }
404 
405  result = libnet_write(c);
406  if (result == -1) {
407  SCLogError(SC_ERR_LIBNET_WRITE_FAILED,"libnet_write failed: %s", libnet_geterror(c));
408  goto cleanup;
409  }
410 
411 cleanup:
412  libnet_destroy (c);
413  return 0;
414 }
415 
416 #ifdef HAVE_LIBNET_ICMPV6_UNREACH
417 int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
418 {
419  Libnet11Packet lpacket;
420  libnet_t *c; /* libnet context */
421  char ebuf[LIBNET_ERRBUF_SIZE];
422  int result;
423  const char *devname = NULL;
424 
425  /* fill in struct defaults */
426  lpacket.ttl = 0;
427  lpacket.id = 0;
428  lpacket.flow = 0;
429  lpacket.class = 0;
430 
431 
432  lpacket.len = IPV6_GET_PLEN(p) + IPV6_HEADER_LEN;
433 
435  devname = p->livedev->dev;
436  }
437  if ((c = libnet_init(LIBNET_RAW6, LIBNET_INIT_CAST devname, ebuf)) == NULL) {
438  SCLogError(SC_ERR_LIBNET_INIT,"libnet_inint failed: %s", ebuf);
439  return 1;
440  }
441 
442  switch (dir) {
443  case REJECT_DIR_SRC:
444  memcpy(lpacket.src6.libnet_s6_addr, GET_IPV6_DST_ADDR(p), 16);
445  memcpy(lpacket.dst6.libnet_s6_addr, GET_IPV6_SRC_ADDR(p), 16);
446  break;
447  case REJECT_DIR_DST:
448  memcpy(lpacket.src6.libnet_s6_addr, GET_IPV6_SRC_ADDR(p), 16);
449  memcpy(lpacket.dst6.libnet_s6_addr, GET_IPV6_DST_ADDR(p), 16);
450  break;
451  default:
453  "reset not src or dst returning");
454  return 1;
455  }
456 
457  /* TODO come up with ttl calc function */
458  lpacket.ttl = 64;
459 
460  /* build the package */
461  if ((libnet_build_icmpv6_unreach(
462  ICMP6_DST_UNREACH, /* type */
463  ICMP6_DST_UNREACH_ADMIN, /* code */
464  0, /* checksum */
465  (uint8_t *)p->ip6h, /* payload */
466  lpacket.len, /* payload length */
467  c, /* libnet context */
468  0)) < 0) /* libnet ptag */
469  {
470  SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_icmpv6_unreach %s", libnet_geterror(c));
471  goto cleanup;
472  }
473 
474  if ((libnet_build_ipv6(
475  lpacket.class, /* traffic class */
476  lpacket.flow, /* Flow label */
477  LIBNET_ICMPV6_H + lpacket.len, /* IPv6 payload length */
478  IPPROTO_ICMPV6, /* next header */
479  lpacket.ttl, /* TTL */
480  lpacket.src6, /* source address */
481  lpacket.dst6, /* destination address */
482  NULL, /* pointer to packet data (or NULL) */
483  0, /* payload length */
484  c, /* libnet context pointer */
485  0)) < 0) /* packet id */
486  {
487  SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_ipv6 %s", libnet_geterror(c));
488  goto cleanup;
489  }
490 
491  result = libnet_write(c);
492  if (result == -1) {
493  SCLogError(SC_ERR_LIBNET_WRITE_FAILED,"libnet_write_raw_ipv6 failed: %s", libnet_geterror(c));
494  goto cleanup;
495  }
496 
497 cleanup:
498  libnet_destroy (c);
499  return 0;
500 }
501 #else /* HAVE_LIBNET_ICMPV6_UNREACH */
502 
503 int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
504 {
505  SCLogError(SC_ERR_LIBNET_NOT_ENABLED, "Libnet ICMPv6 based rejects are disabled."
506  "Usually this means that you don't have a patched libnet installed,"
507  " or configure couldn't find it.");
508  return 0;
509 }
510 #endif /* HAVE_LIBNET_ICMPV6_UNREACH */
511 
512 
513 #else
514 
515 int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir)
516 {
517  SCLogError(SC_ERR_LIBNET_NOT_ENABLED, "Libnet based rejects are disabled."
518  "Usually this means that you don't have libnet installed,"
519  " or configure couldn't find it.");
520  return 0;
521 }
522 
523 int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
524 {
525  SCLogError(SC_ERR_LIBNET_NOT_ENABLED, "Libnet based rejects are disabled."
526  "Usually this means that you don't have libnet installed,"
527  " or configure couldn't find it.");
528  return 0;
529 }
530 
531 int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir)
532 {
533  SCLogError(SC_ERR_LIBNET_NOT_ENABLED, "Libnet based rejects are disabled."
534  "Usually this means that you don't have libnet installed,"
535  " or configure couldn't find it.");
536  return 0;
537 }
538 
539 int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
540 {
541  SCLogError(SC_ERR_LIBNET_NOT_ENABLED, "Libnet based rejects are disabled."
542  "Usually this means that you don't have libnet installed,"
543  " or configure couldn't find it.");
544  return 0;
545 }
546 
547 #endif /* HAVE_LIBNET11 */
#define GET_IPV4_SRC_ADDR_U32(p)
Definition: decode.h:213
#define SCLogDebug(...)
Definition: util-debug.h:335
#define REJECT_DIR_DST
#define GET_IPV4_DST_ADDR_U32(p)
Definition: decode.h:214
#define TH_RST
Definition: decode-tcp.h:37
#define TCP_GET_WINDOW(p)
Definition: decode-tcp.h:115
#define TCP_GET_DST_PORT(p)
Definition: decode-tcp.h:112
TCPHdr * tcph
Definition: decode.h:523
int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
char * dev
Definition: util-device.h:41
#define TCP_GET_SEQ(p)
Definition: decode-tcp.h:113
IPV6Hdr * ip6h
Definition: decode.h:503
#define IPV6_GET_PLEN(p)
Definition: decode-ipv6.h:88
uint32_t seq
#define GET_IPV6_DST_ADDR(p)
Definition: decode.h:221
#define TCP_GET_SRC_PORT(p)
Definition: decode-tcp.h:111
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define ICMP6_DST_UNREACH
Definition: decode-icmpv6.h:37
#define TH_ACK
Definition: decode-tcp.h:39
uint8_t host_mode
Definition: suricata.c:212
#define IPV4_GET_HLEN(p)
Definition: decode-ipv4.h:123
IPV4Hdr * ip4h
Definition: decode.h:501
#define REJECT_DIR_SRC
#define GET_IPV6_SRC_ADDR(p)
Definition: decode.h:220
#define IPV6_HEADER_LEN
Definition: decode-ipv6.h:27
#define IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode)
Definition: suricata.h:124
#define ICMP6_DST_UNREACH_ADMIN
Definition: decode-icmpv6.h:82
int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir)
int sc_set_caps
Definition: suricata.c:221
struct LiveDevice_ * livedev
Definition: decode.h:554
uint8_t len
Per thread variable structure.
Definition: threadvars.h:57
#define TCP_GET_ACK(p)
Definition: decode-tcp.h:114
uint16_t payload_len
Definition: decode.h:542
int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir)