From: Eric Leblond Date: Wed, 18 Sep 2013 11:27:49 +0000 (+0200) Subject: Add reject for IPv6 X-Git-Tag: suricata-2.0beta2~254 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f05efeb46f1286c0cb05830c3e85fffab1ea2075;p=thirdparty%2Fsuricata.git Add reject for IPv6 With this patch reject is now available in IPv6. --- diff --git a/src/respond-reject-libnet11.c b/src/respond-reject-libnet11.c index f91a3173c6..f00f7ec49b 100644 --- a/src/respond-reject-libnet11.c +++ b/src/respond-reject-libnet11.c @@ -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 */ diff --git a/src/respond-reject-libnet11.h b/src/respond-reject-libnet11.h index 7a676551ba..f2e605b916 100644 --- a/src/respond-reject-libnet11.h +++ b/src/respond-reject-libnet11.h @@ -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__ */ diff --git a/src/respond-reject.c b/src/respond-reject.c index 742ace8d74..e087f1d24d 100644 --- a/src/respond-reject.c +++ b/src/respond-reject.c @@ -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); }