]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
Add reject for IPv6
authorEric Leblond <eric@regit.org>
Wed, 18 Sep 2013 11:27:49 +0000 (13:27 +0200)
committerVictor Julien <victor@inliniac.net>
Thu, 3 Oct 2013 05:02:04 +0000 (07:02 +0200)
With this patch reject is now available in IPv6.

src/respond-reject-libnet11.c
src/respond-reject-libnet11.h
src/respond-reject.c

index f91a3173c6cbf0ad248a8921052f3aa34d46dffd..f00f7ec49b52831f44bd6e08ee344d164dd85342 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2010 Open Information Security Foundation
+/* Copyright (C) 2007-2013 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -66,7 +66,7 @@ typedef struct Libnet11Packet_ {
     uint16_t id;
     uint32_t flow;
     uint8_t class;
-    struct in6_addr src6, dst6;
+    struct libnet_in6_addr src6, dst6;
     uint32_t src4, dst4;
     uint16_t sp, dp;
     size_t len;
@@ -285,6 +285,225 @@ cleanup:
     return 0;
 }
 
+int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir)
+{
+
+    Libnet11Packet lpacket;
+    libnet_t *c; /* libnet context */
+    char ebuf[LIBNET_ERRBUF_SIZE];
+    int result;
+    char *devname = NULL;
+
+    /* fill in struct defaults */
+    lpacket.ttl = 0;
+    lpacket.id = 0;
+    lpacket.flow = 0;
+    lpacket.class = 0;
+
+    if (IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode) && (p->livedev)) {
+        devname = p->livedev->dev;
+    }
+    if ((c = libnet_init(LIBNET_RAW6, devname, ebuf)) == NULL) {
+        SCLogError(SC_ERR_LIBNET_INIT,"libnet_init failed: %s", ebuf);
+        return 1;
+    }
+
+    if (p->tcph == NULL)
+       return 1;
+
+    /* save payload len */
+    lpacket.dsize = p->payload_len;
+
+    switch (dir) {
+        case REJECT_DIR_SRC:
+            SCLogDebug("sending a tcp reset to src");
+            /* We follow http://tools.ietf.org/html/rfc793#section-3.4 :
+             *  If packet has no ACK, the seq number is 0 and the ACK is built
+             *  the normal way. If packet has a ACK, the seq of the RST packet
+             *  is equal to the ACK of incoming packet and the ACK is build
+             *  using packet sequence number and size of the data. */
+            if (TCP_GET_ACK(p) == 0) {
+                lpacket.seq = 0;
+                lpacket.ack = TCP_GET_SEQ(p) + lpacket.dsize + 1;
+            } else {
+                lpacket.seq = TCP_GET_ACK(p);
+                lpacket.ack = TCP_GET_SEQ(p) + lpacket.dsize;
+            }
+
+            lpacket.sp = TCP_GET_DST_PORT(p);
+            lpacket.dp = TCP_GET_SRC_PORT(p);
+
+            memcpy(lpacket.src6.libnet_s6_addr, GET_IPV6_DST_ADDR(p), 16);
+            memcpy(lpacket.dst6.libnet_s6_addr, GET_IPV6_SRC_ADDR(p), 16);
+
+            break;
+        case REJECT_DIR_DST:
+            SCLogDebug("sending a tcp reset to dst");
+            lpacket.seq = TCP_GET_SEQ(p);
+            lpacket.ack = TCP_GET_ACK(p);
+
+            lpacket.sp = TCP_GET_SRC_PORT(p);
+            lpacket.dp = TCP_GET_DST_PORT(p);
+
+            memcpy(lpacket.src6.libnet_s6_addr, GET_IPV6_SRC_ADDR(p), 16);
+            memcpy(lpacket.dst6.libnet_s6_addr, GET_IPV6_DST_ADDR(p), 16);
+            break;
+        default:
+            SCLogError(SC_ERR_LIBNET_INVALID_DIR,
+                       "reset not src or dst returning");
+            return 1;
+    }
+
+    lpacket.window = TCP_GET_WINDOW(p);
+    //lpacket.seq += lpacket.dsize;
+
+    /* TODO come up with ttl calc function */
+    lpacket.ttl = 64;
+
+    /* build the package */
+    if ((libnet_build_tcp(
+                    lpacket.sp,            /* source port */
+                    lpacket.dp,            /* dst port */
+                    lpacket.seq,           /* seq number */
+                    lpacket.ack,           /* ack number */
+                    TH_RST|TH_ACK,         /* flags */
+                    lpacket.window,        /* window size */
+                    0,                     /* checksum */
+                    0,                     /* urgent flag */
+                    LIBNET_TCP_H,          /* header length */
+                    NULL,                  /* payload */
+                    0,                     /* payload length */
+                    c,                     /* libnet context */
+                    0)) < 0)               /* libnet ptag */
+    {
+        SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_tcp %s", libnet_geterror(c));
+        goto cleanup;
+    }
+
+    if ((libnet_build_ipv6(
+                    lpacket.class,                /* traffic class */
+                    lpacket.flow,                 /* Flow label */
+                    LIBNET_TCP_H,                 /* payload length */
+                    IPPROTO_TCP,                  /* next header */
+                    lpacket.ttl,                  /* TTL */
+                    lpacket.src6,                 /* source address */
+                    lpacket.dst6,                 /* destination address */
+                    NULL,                         /* pointer to packet data (or NULL) */
+                    0,                            /* payload length */
+                    c,                            /* libnet context pointer */
+                    0)) < 0)                      /* packet id */
+    {
+        SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_ipv6 %s", libnet_geterror(c));
+        goto cleanup;
+    }
+
+    result = libnet_write(c);
+    if (result == -1) {
+        SCLogError(SC_ERR_LIBNET_WRITE_FAILED,"libnet_write failed: %s", libnet_geterror(c));
+        goto cleanup;
+    }
+
+cleanup:
+    libnet_destroy (c);
+    return 0;
+}
+
+#ifdef HAVE_LIBNET_ICMPV6_UNREACH
+int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
+{
+    Libnet11Packet lpacket;
+    libnet_t *c; /* libnet context */
+    char ebuf[LIBNET_ERRBUF_SIZE];
+    int result;
+    char *devname = NULL;
+
+    /* fill in struct defaults */
+    lpacket.ttl = 0;
+    lpacket.id = 0;
+    lpacket.flow = 0;
+    lpacket.class = 0;
+
+
+    lpacket.len = IPV6_GET_PLEN(p) + IPV6_HEADER_LEN;
+
+    if (IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode) && (p->livedev)) {
+        devname = p->livedev->dev;
+    }
+    if ((c = libnet_init(LIBNET_RAW6, devname, ebuf)) == NULL) {
+        SCLogError(SC_ERR_LIBNET_INIT,"libnet_inint failed: %s", ebuf);
+        return 1;
+    }
+
+    switch (dir) {
+        case REJECT_DIR_SRC:
+            memcpy(lpacket.src6.libnet_s6_addr, GET_IPV6_DST_ADDR(p), 16);
+            memcpy(lpacket.dst6.libnet_s6_addr, GET_IPV6_SRC_ADDR(p), 16);
+            break;
+        case REJECT_DIR_DST:
+            memcpy(lpacket.src6.libnet_s6_addr, GET_IPV6_SRC_ADDR(p), 16);
+            memcpy(lpacket.dst6.libnet_s6_addr, GET_IPV6_DST_ADDR(p), 16);
+            break;
+        default:
+            SCLogError(SC_ERR_LIBNET_INVALID_DIR,
+                       "reset not src or dst returning");
+            return 1;
+    }
+
+    /* TODO come up with ttl calc function */
+    lpacket.ttl = 64;
+
+    /* build the package */
+    if ((libnet_build_icmpv6_unreach(
+                    ICMP6_DST_UNREACH,        /* type */
+                    ICMP6_DST_UNREACH_ADMIN,  /* code */
+                    0,                        /* checksum */
+                    (uint8_t *)p->ip6h,       /* payload */
+                    lpacket.len,              /* payload length */
+                    c,                        /* libnet context */
+                    0)) < 0)                  /* libnet ptag */
+    {
+        SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_icmpv6_unreach %s", libnet_geterror(c));
+        goto cleanup;
+    }
+
+    if ((libnet_build_ipv6(
+                    lpacket.class,                            /* traffic class */
+                    lpacket.flow,                            /* Flow label */
+                    LIBNET_ICMPV6_H + lpacket.len, /* IPv6 payload length */
+                    IPPROTO_ICMPV6,               /* next header */
+                    lpacket.ttl,                  /* TTL */
+                    lpacket.src6,                 /* source address */
+                    lpacket.dst6,                 /* destination address */
+                    NULL,                         /* pointer to packet data (or NULL) */
+                    0,                            /* payload length */
+                    c,                            /* libnet context pointer */
+                    0)) < 0)                      /* packet id */
+    {
+        SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_ipv6 %s", libnet_geterror(c));
+        goto cleanup;
+    }
+
+    result = libnet_write(c);
+    if (result == -1) {
+        SCLogError(SC_ERR_LIBNET_WRITE_FAILED,"libnet_write_raw_ipv6 failed: %s", libnet_geterror(c));
+        goto cleanup;
+    }
+
+cleanup:
+    libnet_destroy (c);
+    return 0;
+}
+#else /* HAVE_LIBNET_ICMPV6_UNREACH */
+
+int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
+{
+    SCLogError(SC_ERR_LIBNET_NOT_ENABLED, "Libnet ICMPv6 based rejects are disabled."
+                "Usually this means that you don't have a patched libnet installed,"
+                " or configure couldn't find it.");
+}
+#endif /* HAVE_LIBNET_ICMPV6_UNREACH */
+
+
 #else
 
 int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir)
@@ -303,4 +522,20 @@ int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
     return 0;
 }
 
+int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir)
+{
+    SCLogError(SC_ERR_LIBNET_NOT_ENABLED, "Libnet based rejects are disabled."
+                "Usually this means that you don't have libnet installed,"
+                " or configure couldn't find it.");
+    return 0;
+}
+
+int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
+{
+    SCLogError(SC_ERR_LIBNET_NOT_ENABLED, "Libnet based rejects are disabled."
+                "Usually this means that you don't have libnet installed,"
+                " or configure couldn't find it.");
+    return 0;
+}
+
 #endif /* HAVE_LIBNET11 */
index 7a676551ba00db4794f2ff6e3d5972dd74827fd4..f2e605b916fe932fab64951c2e3ffe9be2eee15e 100644 (file)
@@ -27,4 +27,7 @@
 
 int RejectSendLibnet11L3IPv4TCP(ThreadVars *, Packet *, void *,int);
 int RejectSendLibnet11L3IPv4ICMP(ThreadVars *, Packet *, void *,int);
+
+int RejectSendLibnet11L3IPv6TCP(ThreadVars *, Packet *, void *,int);
+int RejectSendLibnet11L3IPv6ICMP(ThreadVars *, Packet *, void *,int);
 #endif /* __RESPOND_REJECT_LIBNET11_H__ */
index 742ace8d74a21cef593987c762752c5f86abb2a4..e087f1d24d23a8e45c7083eb8e1669cb1c609d15 100644 (file)
@@ -125,17 +125,37 @@ int RejectSendIPv4ICMP(ThreadVars *tv, Packet *p, void *data) {
     return 0;
 }
 
-/** \todo implement */
 int RejectSendIPv6TCP(ThreadVars *tv, Packet *p, void *data) {
     SCEnter();
-    SCLogDebug("we would send a ipv6 tcp reset here");
+    if (PACKET_TEST_ACTION(p, ACTION_REJECT)) {
+        return RejectSendLibnet11L3IPv6TCP(tv, p, data, REJECT_DIR_SRC);
+    } else if (PACKET_TEST_ACTION(p, ACTION_REJECT_DST)) {
+        return RejectSendLibnet11L3IPv6TCP(tv, p, data, REJECT_DIR_DST);
+    } else if(PACKET_TEST_ACTION(p, ACTION_REJECT_BOTH)) {
+        if (RejectSendLibnet11L3IPv6TCP(tv, p, data, REJECT_DIR_SRC) == 0 &&
+            RejectSendLibnet11L3IPv6TCP(tv, p, data, REJECT_DIR_DST) == 0) {
+            return 0;
+        } else {
+            return 1;
+        }
+    }
     SCReturnInt(0);
 }
 
-/** \todo implement */
 int RejectSendIPv6ICMP(ThreadVars *tv, Packet *p, void *data) {
     SCEnter();
-    SCLogDebug("we would send a ipv6 icmp reset here");
+    if (PACKET_TEST_ACTION(p, ACTION_REJECT)) {
+        return RejectSendLibnet11L3IPv6ICMP(tv, p, data, REJECT_DIR_SRC);
+    } else if (PACKET_TEST_ACTION(p, ACTION_REJECT_DST)) {
+        return RejectSendLibnet11L3IPv6ICMP(tv, p, data, REJECT_DIR_DST);
+    } else if(PACKET_TEST_ACTION(p, ACTION_REJECT_BOTH)) {
+        if (RejectSendLibnet11L3IPv6ICMP(tv, p, data, REJECT_DIR_SRC) == 0 &&
+            RejectSendLibnet11L3IPv6ICMP(tv, p, data, REJECT_DIR_DST) == 0) {
+            return 0;
+        } else {
+            return 1;
+        }
+    }
     SCReturnInt(0);
 }