You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/respond-reject-libnet11.c

614 lines
19 KiB
C

/* Copyright (C) 2007-2020 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
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Victor Julien <victor@inliniac.net>
* \author William Metcalf <william.metcalf@gmail.com>
*
* RespondRejectLibnet11 used to send out libnet based
* TCP resets and ICMP unreachables.
*
* \todo calculate TTL base on average from stream tracking
* \todo come up with a way for users to specify icmp unreachable type
* \todo Possibly default to port unreachable for UDP traffic this seems
* to be the default in flexresp and iptables
* \todo implement ipv6 resets
* \todo implement pre-alloc resets for speed
*/
#include "suricata-common.h"
#include "decode.h"
#include "decode-ipv4.h"
#include "decode-tcp.h"
#include "decode-sctp.h"
#include "decode-udp.h"
#include "packet-queue.h"
#include "threads.h"
#include "threadvars.h"
#include "tm-queuehandlers.h"
Add per packet profiling. Per packet profiling uses tick based accounting. It has 2 outputs, a summary and a csv file that contains per packet stats. Stats per packet include: 1) total ticks spent 2) ticks spent per individual thread module 3) "threading overhead" which is simply calculated by subtracting (2) of (1). A number of changes were made to integrate the new code in a clean way: a number of generic enums are now placed in tm-threads-common.h so we can include them from any part of the engine. Code depends on --enable-profiling just like the rule profiling code. New yaml parameters: profiling: # packet profiling packets: # Profiling can be disabled here, but it will still have a # performance impact if compiled in. enabled: yes filename: packet_stats.log append: yes # per packet csv output csv: # Output can be disabled here, but it will still have a # performance impact if compiled in. enabled: no filename: packet_stats.csv Example output of summary stats: IP ver Proto cnt min max avg ------ ----- ------ ------ ---------- ------- IPv4 6 19436 11448 5404365 32993 IPv4 256 4 11511 49968 30575 Per Thread module stats: Thread Module IP ver Proto cnt min max avg ------------------------ ------ ----- ------ ------ ---------- ------- TMM_DECODEPCAPFILE IPv4 6 19434 1242 47889 1770 TMM_DETECT IPv4 6 19436 1107 137241 1504 TMM_ALERTFASTLOG IPv4 6 19436 90 1323 155 TMM_ALERTUNIFIED2ALERT IPv4 6 19436 108 1359 138 TMM_ALERTDEBUGLOG IPv4 6 19436 90 1134 154 TMM_LOGHTTPLOG IPv4 6 19436 414 5392089 7944 TMM_STREAMTCP IPv4 6 19434 828 1299159 19438 The proto 256 is a counter for handling of pseudo/tunnel packets. Example output of csv: pcap_cnt,ipver,ipproto,total,TMM_DECODENFQ,TMM_VERDICTNFQ,TMM_RECEIVENFQ,TMM_RECEIVEPCAP,TMM_RECEIVEPCAPFILE,TMM_DECODEPCAP,TMM_DECODEPCAPFILE,TMM_RECEIVEPFRING,TMM_DECODEPFRING,TMM_DETECT,TMM_ALERTFASTLOG,TMM_ALERTFASTLOG4,TMM_ALERTFASTLOG6,TMM_ALERTUNIFIEDLOG,TMM_ALERTUNIFIEDALERT,TMM_ALERTUNIFIED2ALERT,TMM_ALERTPRELUDE,TMM_ALERTDEBUGLOG,TMM_ALERTSYSLOG,TMM_LOGDROPLOG,TMM_ALERTSYSLOG4,TMM_ALERTSYSLOG6,TMM_RESPONDREJECT,TMM_LOGHTTPLOG,TMM_LOGHTTPLOG4,TMM_LOGHTTPLOG6,TMM_PCAPLOG,TMM_STREAMTCP,TMM_DECODEIPFW,TMM_VERDICTIPFW,TMM_RECEIVEIPFW,TMM_RECEIVEERFFILE,TMM_DECODEERFFILE,TMM_RECEIVEERFDAG,TMM_DECODEERFDAG,threading 1,4,6,172008,0,0,0,0,0,0,47889,0,0,48582,1323,0,0,0,0,1359,0,1134,0,0,0,0,0,8028,0,0,0,49356,0,0,0,0,0,0,0,14337 First line of the file contains labels. 2 example gnuplot scripts added to plot the data.
14 years ago
#include "tm-threads.h"
#include "action-globals.h"
#include "respond-reject.h"
#include "respond-reject-libnet11.h"
#include "util-device.h"
#ifdef HAVE_LIBNET11
#ifndef HAVE_LIBNET_INIT_CONST
#define LIBNET_INIT_CAST (char *)
#else
#define LIBNET_INIT_CAST
#endif
/* Globally configured device to use for sending resets in IDS mode. */
const char *g_reject_dev = NULL;
uint16_t g_reject_dev_mtu = 0;
/** set to true in main if we're setting caps. We need it here if we're using
* reject rules as libnet 1.1 is not compatible with caps. */
extern int sc_set_caps;
#include <libnet.h>
thread_local libnet_t *t_c = NULL;
thread_local int t_inject_mode = -1;
typedef struct Libnet11Packet_ {
uint32_t ack, seq;
uint16_t window, dsize;
uint8_t ttl;
uint16_t id;
uint32_t flow;
uint8_t class;
struct libnet_in6_addr src6, dst6;
uint32_t src4, dst4;
uint16_t sp, dp;
size_t len;
uint8_t *smac, *dmac;
} Libnet11Packet;
static inline libnet_t *GetCtx(const Packet *p, int injection_type)
{
/* fast path: use cache ctx */
if (t_c)
return t_c;
/* slow path: setup a new ctx */
bool store_ctx = false;
const char *devname = NULL;
extern uint8_t host_mode;
if (IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode)) {
if (g_reject_dev != NULL) {
if (p->datalink == LINKTYPE_ETHERNET)
injection_type = t_inject_mode = LIBNET_LINK;
devname = g_reject_dev;
store_ctx = true;
} else {
devname = p->livedev ? p->livedev->dev : NULL;
}
}
char ebuf[LIBNET_ERRBUF_SIZE];
libnet_t *c = libnet_init(injection_type, LIBNET_INIT_CAST devname, ebuf);
if (c == NULL) {
12 years ago
SCLogError(SC_ERR_LIBNET_INIT,"libnet_init failed: %s", ebuf);
}
if (store_ctx) {
t_c = c;
}
return c;
}
static inline void ClearCtx(libnet_t *c)
{
if (t_c == c)
libnet_clear_packet(c);
else
libnet_destroy(c);
}
void FreeCachedCtx(void)
{
if (t_c) {
libnet_destroy(t_c);
t_c = NULL;
}
}
static inline void SetupTCP(Packet *p, Libnet11Packet *lpacket, enum RejectDirection dir)
{
switch (dir) {
case REJECT_DIR_SRC:
SCLogDebug("sending a tcp reset to src");
reject: update computation of seq and ack We have follow TCP RFC (http://tools.ietf.org/html/rfc793#section-3.4). There is two cases depending on wether the original packet contains a ACK. If packet has no ACK, the RST seq number is 0 and the ACK is built the standard 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. Regarding standard Ack number, it is computed using seq number of captured packet added to packet length. Finally 1 is added so we respect the RFC: If the ACK control bit is set this field contains the value of the next sequence number the sender of the segment is expecting to receive. Once a connection is established this is always sent. With this patch we have some correct results. With the following rule: reject ssh any any -> 192.168.56.3 any (msg:"no SSH way"; sid:3; rev:1;) ssh connection to 192.168.56.3 is correctly resetted on client side. But this is not perfect. If we have the following rule: reject tcp any any -> 192.168.56.3 22 (msg:"no way"; sid:2; rev:1;) then the connection is not resetted on a standard ethernet network. But if we introduce 20ms delay on packets, then it is correctly resetted. This is explained when looking at the network trace. The reset is sent as answer to the SYN packet and it is emitted after the SYN ACK from server because the exchange is really fast. So this is discarded by the client OS which has already seen a ACK for the same sequence number. This should fix #895.
12 years ago
/* 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;
reject: update computation of seq and ack We have follow TCP RFC (http://tools.ietf.org/html/rfc793#section-3.4). There is two cases depending on wether the original packet contains a ACK. If packet has no ACK, the RST seq number is 0 and the ACK is built the standard 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. Regarding standard Ack number, it is computed using seq number of captured packet added to packet length. Finally 1 is added so we respect the RFC: If the ACK control bit is set this field contains the value of the next sequence number the sender of the segment is expecting to receive. Once a connection is established this is always sent. With this patch we have some correct results. With the following rule: reject ssh any any -> 192.168.56.3 any (msg:"no SSH way"; sid:3; rev:1;) ssh connection to 192.168.56.3 is correctly resetted on client side. But this is not perfect. If we have the following rule: reject tcp any any -> 192.168.56.3 22 (msg:"no way"; sid:2; rev:1;) then the connection is not resetted on a standard ethernet network. But if we introduce 20ms delay on packets, then it is correctly resetted. This is explained when looking at the network trace. The reset is sent as answer to the SYN packet and it is emitted after the SYN ACK from server because the exchange is really fast. So this is discarded by the client OS which has already seen a ACK for the same sequence number. This should fix #895.
12 years ago
} else {
lpacket->seq = TCP_GET_ACK(p);
lpacket->ack = TCP_GET_SEQ(p) + lpacket->dsize;
reject: update computation of seq and ack We have follow TCP RFC (http://tools.ietf.org/html/rfc793#section-3.4). There is two cases depending on wether the original packet contains a ACK. If packet has no ACK, the RST seq number is 0 and the ACK is built the standard 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. Regarding standard Ack number, it is computed using seq number of captured packet added to packet length. Finally 1 is added so we respect the RFC: If the ACK control bit is set this field contains the value of the next sequence number the sender of the segment is expecting to receive. Once a connection is established this is always sent. With this patch we have some correct results. With the following rule: reject ssh any any -> 192.168.56.3 any (msg:"no SSH way"; sid:3; rev:1;) ssh connection to 192.168.56.3 is correctly resetted on client side. But this is not perfect. If we have the following rule: reject tcp any any -> 192.168.56.3 22 (msg:"no way"; sid:2; rev:1;) then the connection is not resetted on a standard ethernet network. But if we introduce 20ms delay on packets, then it is correctly resetted. This is explained when looking at the network trace. The reset is sent as answer to the SYN packet and it is emitted after the SYN ACK from server because the exchange is really fast. So this is discarded by the client OS which has already seen a ACK for the same sequence number. This should fix #895.
12 years ago
}
lpacket->sp = TCP_GET_DST_PORT(p);
lpacket->dp = TCP_GET_SRC_PORT(p);
break;
case REJECT_DIR_DST:
default:
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);
break;
}
lpacket->window = TCP_GET_WINDOW(p);
//lpacket.seq += lpacket.dsize;
}
static inline int BuildTCP(libnet_t *c, Libnet11Packet *lpacket)
{
/* 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));
return -1;
}
return 0;
}
static inline int BuildIPv4(libnet_t *c, Libnet11Packet *lpacket, const uint8_t proto)
{
if ((libnet_build_ipv4(
lpacket->len, /* entire packet length */
0, /* tos */
lpacket->id, /* ID */
0, /* fragmentation flags and offset */
lpacket->ttl, /* TTL */
proto, /* protocol */
0, /* checksum */
lpacket->src4, /* source address */
lpacket->dst4, /* 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_ipv4 %s", libnet_geterror(c));
return -1;
}
return 0;
}
static inline int BuildIPv6(libnet_t *c, Libnet11Packet *lpacket, const uint8_t proto)
{
if ((libnet_build_ipv6(
lpacket->class, /* traffic class */
lpacket->flow, /* Flow label */
lpacket->len, /* payload length */
proto, /* 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));
return -1;
}
return 0;
}
static inline void SetupEthernet(Packet *p, Libnet11Packet *lpacket, enum RejectDirection dir)
{
switch (dir) {
case REJECT_DIR_SRC:
lpacket->smac = p->ethh->eth_dst;
lpacket->dmac = p->ethh->eth_src;
break;
case REJECT_DIR_DST:
default:
lpacket->smac = p->ethh->eth_src;
lpacket->dmac = p->ethh->eth_dst;
break;
}
}
static inline int BuildEthernet(libnet_t *c, Libnet11Packet *lpacket, uint16_t proto)
{
if ((libnet_build_ethernet(lpacket->dmac,lpacket->smac, proto , NULL, 0, c, 0)) < 0) {
SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_ethernet %s", libnet_geterror(c));
return -1;
}
return 0;
}
static inline int BuildEthernetVLAN(libnet_t *c, Libnet11Packet *lpacket, uint16_t proto, uint16_t vlan_id)
{
if (libnet_build_802_1q(
lpacket->dmac, lpacket->smac, ETHERTYPE_VLAN,
0x000, 0x000, vlan_id, proto,
NULL, /* payload */
0, /* payload size */
c, /* libnet handle */
0) < 0)
{
SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_802_1q %s", libnet_geterror(c));
return -1;
}
return 0;
}
int RejectSendLibnet11IPv4TCP(ThreadVars *tv, Packet *p, void *data, enum RejectDirection dir)
{
Libnet11Packet lpacket;
int result;
/* fill in struct defaults */
lpacket.ttl = 0;
lpacket.id = 0;
lpacket.flow = 0;
lpacket.class = 0;
if (p->tcph == NULL)
return 1;
libnet_t *c = GetCtx(p, LIBNET_RAW4);
if (c == NULL)
return 1;
lpacket.len = LIBNET_IPV4_H + LIBNET_TCP_H;
lpacket.dsize = p->payload_len;
switch (dir) {
case REJECT_DIR_SRC:
lpacket.src4 = GET_IPV4_DST_ADDR_U32(p);
lpacket.dst4 = GET_IPV4_SRC_ADDR_U32(p);
break;
case REJECT_DIR_DST:
default:
lpacket.src4 = GET_IPV4_SRC_ADDR_U32(p);
lpacket.dst4 = GET_IPV4_DST_ADDR_U32(p);
break;
}
/* TODO come up with ttl calc function */
lpacket.ttl = 64;
SetupTCP(p, &lpacket, dir);
if (BuildTCP(c, &lpacket) < 0)
goto cleanup;
if (BuildIPv4(c, &lpacket, IPPROTO_TCP) < 0)
goto cleanup;
if (t_inject_mode == LIBNET_LINK) {
SetupEthernet(p, &lpacket, dir);
if (p->vlan_idx == 1) {
if (BuildEthernetVLAN(c, &lpacket, ETHERNET_TYPE_IP, p->vlan_id[0]) < 0)
goto cleanup;
} else {
if (BuildEthernet(c, &lpacket, ETHERNET_TYPE_IP) < 0)
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:
ClearCtx(c);
return 0;
}
int RejectSendLibnet11IPv4ICMP(ThreadVars *tv, Packet *p, void *data, enum RejectDirection dir)
{
Libnet11Packet lpacket;
int result;
/* fill in struct defaults */
lpacket.ttl = 0;
lpacket.id = 0;
lpacket.flow = 0;
lpacket.class = 0;
const int iplen = IPV4_GET_IPLEN(p);
if (g_reject_dev_mtu >= ETHERNET_HEADER_LEN + LIBNET_IPV4_H + 8) {
lpacket.len = MIN(g_reject_dev_mtu - ETHERNET_HEADER_LEN, (LIBNET_IPV4_H + iplen));
} else {
lpacket.len = LIBNET_IPV4_H + MIN(8,iplen); // 8 bytes is the minimum we have to attach
}
lpacket.dsize = lpacket.len - (LIBNET_IPV4_H + LIBNET_ICMPV4_H);
libnet_t *c = GetCtx(p, LIBNET_RAW4);
if (c == NULL)
return 1;
switch (dir) {
case REJECT_DIR_SRC:
lpacket.src4 = GET_IPV4_DST_ADDR_U32(p);
lpacket.dst4 = GET_IPV4_SRC_ADDR_U32(p);
break;
case REJECT_DIR_DST:
default:
lpacket.src4 = GET_IPV4_SRC_ADDR_U32(p);
lpacket.dst4 = GET_IPV4_DST_ADDR_U32(p);
break;
}
/* TODO come up with ttl calc function */
lpacket.ttl = 64;
/* build the package */
if ((libnet_build_icmpv4_unreach(
ICMP_DEST_UNREACH, /* type */
ICMP_HOST_ANO, /* code */
0, /* checksum */
(uint8_t *)p->ip4h, /* payload */
lpacket.dsize, /* payload length */
c, /* libnet context */
0)) < 0) /* libnet ptag */
{
SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_icmpv4_unreach %s", libnet_geterror(c));
goto cleanup;
}
if (BuildIPv4(c, &lpacket, IPPROTO_ICMP) < 0)
goto cleanup;
if (t_inject_mode == LIBNET_LINK) {
SetupEthernet(p, &lpacket, dir);
if (p->vlan_idx == 1) {
if (BuildEthernetVLAN(c, &lpacket, ETHERNET_TYPE_IP, p->vlan_id[0]) < 0)
goto cleanup;
} else {
if (BuildEthernet(c, &lpacket, ETHERNET_TYPE_IP) < 0)
goto cleanup;
}
}
result = libnet_write(c);
if (result == -1) {
SCLogError(SC_ERR_LIBNET_WRITE_FAILED,"libnet_write_raw_ipv4 failed: %s", libnet_geterror(c));
goto cleanup;
}
cleanup:
ClearCtx(c);
return 0;
}
int RejectSendLibnet11IPv6TCP(ThreadVars *tv, Packet *p, void *data, enum RejectDirection dir)
{
Libnet11Packet lpacket;
int result;
/* fill in struct defaults */
lpacket.ttl = 0;
lpacket.id = 0;
lpacket.flow = 0;
lpacket.class = 0;
if (p->tcph == NULL)
return 1;
libnet_t *c = GetCtx(p, LIBNET_RAW6);
if (c == NULL)
return 1;
lpacket.len = LIBNET_IPV6_H + LIBNET_TCP_H;
lpacket.dsize = p->payload_len;
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:
default:
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;
}
/* TODO come up with ttl calc function */
lpacket.ttl = 64;
SetupTCP(p, &lpacket, dir);
BuildTCP(c, &lpacket);
if (BuildIPv6(c, &lpacket, IPPROTO_ICMP) < 0)
goto cleanup;
if (t_inject_mode == LIBNET_LINK) {
SetupEthernet(p, &lpacket, dir);
if (p->vlan_idx == 1) {
if (BuildEthernetVLAN(c, &lpacket, ETHERNET_TYPE_IPV6, p->vlan_id[0]) < 0)
goto cleanup;
} else {
if (BuildEthernet(c, &lpacket, ETHERNET_TYPE_IPV6) < 0)
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:
ClearCtx(c);
return 0;
}
#ifdef HAVE_LIBNET_ICMPV6_UNREACH
int RejectSendLibnet11IPv6ICMP(ThreadVars *tv, Packet *p, void *data, enum RejectDirection dir)
{
Libnet11Packet lpacket;
int result;
/* fill in struct defaults */
lpacket.ttl = 0;
lpacket.id = 0;
lpacket.flow = 0;
lpacket.class = 0;
const int iplen = IPV6_GET_PLEN(p);
if (g_reject_dev_mtu >= ETHERNET_HEADER_LEN + IPV6_HEADER_LEN + 8) {
lpacket.len = IPV6_HEADER_LEN + MIN(g_reject_dev_mtu - ETHERNET_HEADER_LEN, iplen);
} else {
lpacket.len = IPV6_HEADER_LEN + MIN(8, iplen);
}
lpacket.dsize = lpacket.len - LIBNET_ICMPV6_H;
libnet_t *c = GetCtx(p, LIBNET_RAW6);
if (c == NULL)
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:
default:
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;
}
/* 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.dsize, /* 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 (BuildIPv6(c, &lpacket, IPPROTO_ICMPV6) < 0)
goto cleanup;
if (t_inject_mode == LIBNET_LINK) {
SetupEthernet(p, &lpacket, dir);
if (p->vlan_idx == 1) {
if (BuildEthernetVLAN(c, &lpacket, ETHERNET_TYPE_IPV6, p->vlan_id[0]) < 0)
goto cleanup;
} else {
if (BuildEthernet(c, &lpacket, ETHERNET_TYPE_IPV6) < 0)
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:
ClearCtx(c);
return 0;
}
#else /* HAVE_LIBNET_ICMPV6_UNREACH */
int RejectSendLibnet11IPv6ICMP(ThreadVars *tv, Packet *p, void *data, enum RejectDirection 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.");
return 0;
}
#endif /* HAVE_LIBNET_ICMPV6_UNREACH */
#else
int RejectSendLibnet11IPv4TCP(ThreadVars *tv, Packet *p, void *data, enum RejectDirection 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 RejectSendLibnet11IPv4ICMP(ThreadVars *tv, Packet *p, void *data, enum RejectDirection 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 RejectSendLibnet11IPv6TCP(ThreadVars *tv, Packet *p, void *data, enum RejectDirection 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 RejectSendLibnet11IPv6ICMP(ThreadVars *tv, Packet *p, void *data, enum RejectDirection 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;
}
void FreeCachedCtx(void)
{
SCLogDebug("no libhnet support");
}
#endif /* HAVE_LIBNET11 */