@ -57,13 +57,17 @@
# define LIBNET_INIT_CAST
# endif
/* Globally configured device to use for sending resets in IDS mode. */
const char * g_reject_dev = NULL ;
/** 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>
extern uint8_t host_mode ;
thread_local libnet_t * t_c = NULL ;
thread_local int t_inject_mode = - 1 ;
typedef struct Libnet11Packet_ {
uint32_t ack , seq ;
@ -76,38 +80,59 @@ typedef struct Libnet11Packet_ {
uint32_t src4 , dst4 ;
uint16_t sp , dp ;
size_t len ;
uint8_t * smac , * dmac ;
} Libnet11Packet ;
int RejectSendLibnet11L3IPv4TCP ( ThreadVars * tv , Packet * p , void * data , int dir )
static inline libnet_t * GetCtx ( const Packet * p , int injection_type )
{
Libnet11Packet lpacket ;
libnet_t * c ; /* libnet context */
char ebuf [ LIBNET_ERRBUF_SIZE ] ;
int result ;
const char * devname = NULL ;
/* fill in struct defaults */
lpacket . ttl = 0 ;
lpacket . id = 0 ;
lpacket . flow = 0 ;
lpacket . class = 0 ;
/* fast path: use cache ctx */
if ( t_c )
return t_c ;
if ( IS_SURI_HOST_MODE_SNIFFER_ONLY ( host_mode ) & & ( p - > livedev ) ) {
devname = p - > livedev - > dev ;
SCLogDebug ( " Will emit reject packet on dev %s " , devname ) ;
/* 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 ;
}
}
if ( p - > tcph = = NULL )
return 1 ;
if ( ( c = libnet_init ( LIBNET_RAW4 , LIBNET_INIT_CAST devname , ebuf ) ) = = NULL ) {
char ebuf [ LIBNET_ERRBUF_SIZE ] ;
libnet_t * c = libnet_init ( injection_type , LIBNET_INIT_CAST devname , ebuf ) ;
if ( c = = NULL ) {
SCLogError ( SC_ERR_LIBNET_INIT , " libnet_init failed: %s " , ebuf ) ;
return 1 ;
}
if ( store_ctx ) {
t_c = c ;
}
return c ;
}
/* save payload len */
lpacket . dsize = p - > payload_len ;
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 , int dir )
{
switch ( dir ) {
case REJECT_DIR_SRC :
SCLogDebug ( " sending a tcp reset to src " ) ;
@ -117,50 +142,41 @@ int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir)
* 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 ;
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 - > 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 ) ;
lpacket . src4 = GET_IPV4_DST_ADDR_U32 ( p ) ;
lpacket . dst4 = GET_IPV4_SRC_ADDR_U32 ( p ) ;
lpacket - > sp = TCP_GET_DST_PORT ( p ) ;
lpacket - > dp = TCP_GET_SRC_PORT ( p ) ;
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 ) ;
lpacket - > seq = TCP_GET_SEQ ( p ) ;
lpacket - > ack = TCP_GET_ACK ( p ) ;
lpacket . src4 = GET_IPV4_SRC_ADDR_U32 ( p ) ;
lpacket . dst4 = GET_IPV4_DST_ADDR_U32 ( p ) ;
lpacket - > sp = TCP_GET_SRC_PORT ( p ) ;
lpacket - > dp = TCP_GET_DST_PORT ( p ) ;
break ;
default :
SCLogError ( SC_ERR_LIBNET_INVALID_DIR ,
" reset not src or dst returning " ) ;
return 1 ;
abort ( ) ;
}
lpacket . window = TCP_GET_WINDOW ( p ) ;
lpacket - > window = TCP_GET_WINDOW ( p ) ;
//lpacket.seq += lpacket.dsize;
}
/* TODO come up with ttl calc function */
lpacket . ttl = 64 ;
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 */
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 */
lpacket - > window , /* window size */
0 , /* checksum */
0 , /* urgent flag */
LIBNET_TCP_H , /* header length */
@ -170,26 +186,129 @@ int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir)
0 ) ) < 0 ) /* libnet ptag */
{
SCLogError ( SC_ERR_LIBNET_BUILD_FAILED , " libnet_build_tcp %s " , libnet_geterror ( c ) ) ;
goto cleanup ;
return - 1 ;
}
return 0 ;
}
static inline int BuildIPv4 ( libnet_t * c , Libnet11Packet * lpacket , const uint8_t proto )
{
const int len = LIBNET_IPV4_H + lpacket - > len +
( ( proto = = IPPROTO_TCP ) ? LIBNET_TCP_H : LIBNET_ICMPV4_H ) ;
if ( ( libnet_build_ipv4 (
LIBNET_TCP_H + LIBNET_IPV4_H , /* entire packet length */
len, /* entire packet length */
0 , /* tos */
lpacket . id , /* ID */
lpacket - > id , /* ID */
0 , /* fragmentation flags and offset */
lpacket . ttl , /* TTL */
IPPROTO_TCP, /* protocol */
lpacket - > ttl , /* TTL */
proto, /* protocol */
0 , /* checksum */
lpacket . src4 , /* source address */
lpacket . dst4 , /* destination address */
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 )
{
const int len = lpacket - > len +
( ( proto = = IPPROTO_TCP ) ? LIBNET_TCP_H : LIBNET_ICMPV6_H ) ;
if ( ( libnet_build_ipv6 (
lpacket - > class , /* traffic class */
lpacket - > flow , /* Flow label */
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 , int dir )
{
switch ( dir ) {
case REJECT_DIR_SRC :
lpacket - > smac = p - > ethh - > eth_dst ;
lpacket - > dmac = p - > ethh - > eth_src ;
break ;
case REJECT_DIR_DST :
lpacket - > smac = p - > ethh - > eth_src ;
lpacket - > dmac = p - > ethh - > eth_dst ;
break ;
default :
abort ( ) ;
}
}
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 ;
}
int RejectSendLibnet11L3IPv4TCP ( ThreadVars * tv , Packet * p , void * data , int 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 ;
/* save payload len */
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 :
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 ( BuildEthernet ( c , & lpacket , ETHERNET_TYPE_IP ) < 0 )
goto cleanup ;
}
result = libnet_write ( c ) ;
@ -199,17 +318,14 @@ int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir)
}
cleanup :
libnet_destroy ( c ) ;
ClearCtx ( c ) ;
return 0 ;
}
int RejectSendLibnet11L3IPv4ICMP ( ThreadVars * tv , Packet * p , void * data , int dir )
{
Libnet11Packet lpacket ;
libnet_t * c ; /* libnet context */
char ebuf [ LIBNET_ERRBUF_SIZE ] ;
int result ;
const char * devname = NULL ;
/* fill in struct defaults */
lpacket . ttl = 0 ;
@ -218,13 +334,9 @@ int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
lpacket . class = 0 ;
lpacket . len = ( IPV4_GET_HLEN ( p ) + p - > payload_len ) ;
if ( IS_SURI_HOST_MODE_SNIFFER_ONLY ( host_mode ) & & ( p - > livedev ) ) {
devname = p - > livedev - > dev ;
}
if ( ( c = libnet_init ( LIBNET_RAW4 , LIBNET_INIT_CAST devname , ebuf ) ) = = NULL ) {
SCLogError ( SC_ERR_LIBNET_INIT , " libnet_inint failed: %s " , ebuf ) ;
libnet_t * c = GetCtx ( p , LIBNET_RAW4 ) ;
if ( c = = NULL )
return 1 ;
}
switch ( dir ) {
case REJECT_DIR_SRC :
@ -258,24 +370,13 @@ int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
goto cleanup ;
}
if ( ( libnet_build_ipv4 (
LIBNET_ICMPV4_H + LIBNET_IPV4_H +
lpacket . len , /* entire packet length */
0 , /* tos */
lpacket . id , /* ID */
0 , /* fragmentation flags and offset */
lpacket . ttl , /* TTL */
IPPROTO_ICMP , /* 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 ) ) ;
if ( BuildIPv4 ( c , & lpacket , IPPROTO_ICMP ) < 0 )
goto cleanup ;
if ( t_inject_mode = = LIBNET_LINK ) {
SetupEthernet ( p , & lpacket , dir ) ;
if ( BuildEthernet ( c , & lpacket , ETHERNET_TYPE_IP ) < 0 )
goto cleanup ;
}
result = libnet_write ( c ) ;
@ -285,17 +386,14 @@ int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
}
cleanup :
libnet_destroy ( c ) ;
ClearCtx ( c ) ;
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 ;
const char * devname = NULL ;
/* fill in struct defaults */
lpacket . ttl = 0 ;
@ -303,102 +401,40 @@ int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir)
lpacket . flow = 0 ;
lpacket . class = 0 ;
if ( IS_SURI_HOST_MODE_SNIFFER_ONLY ( host_mode ) & & ( p - > livedev ) ) {
devname = p - > livedev - > dev ;
}
if ( p - > tcph = = NULL )
return 1 ;
if ( ( c = libnet_init ( LIBNET_RAW6 , LIBNET_INIT_CAST devname , ebuf ) ) = = NULL ) {
SCLogError ( SC_ERR_LIBNET_INIT , " libnet_init failed: %s " , ebuf ) ;
libnet_t * c = GetCtx ( p , LIBNET_RAW6 ) ;
if ( c = = 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 ;
}
SetupTCP ( p , & lpacket , dir ) ;
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 ) ) ;
BuildTCP ( c , & lpacket ) ;
if ( BuildIPv6 ( c , & lpacket , IPPROTO_ICMP ) < 0 )
goto cleanup ;
if ( t_inject_mode = = LIBNET_LINK ) {
SetupEthernet ( p , & lpacket , dir ) ;
if ( BuildEthernet ( c , & lpacket , ETHERNET_TYPE_IPV6 ) < 0 )
goto cleanup ;
}
result = libnet_write ( c ) ;
@ -408,7 +444,7 @@ int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir)
}
cleanup :
libnet_destroy ( c ) ;
ClearCtx ( c ) ;
return 0 ;
}
@ -416,10 +452,7 @@ cleanup:
int RejectSendLibnet11L3IPv6ICMP ( ThreadVars * tv , Packet * p , void * data , int dir )
{
Libnet11Packet lpacket ;
libnet_t * c ; /* libnet context */
char ebuf [ LIBNET_ERRBUF_SIZE ] ;
int result ;
const char * devname = NULL ;
/* fill in struct defaults */
lpacket . ttl = 0 ;
@ -428,13 +461,9 @@ int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
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 , LIBNET_INIT_CAST devname , ebuf ) ) = = NULL ) {
SCLogError ( SC_ERR_LIBNET_INIT , " libnet_inint failed: %s " , ebuf ) ;
libnet_t * c = GetCtx ( p , LIBNET_RAW6 ) ;
if ( c = = NULL )
return 1 ;
}
switch ( dir ) {
case REJECT_DIR_SRC :
@ -468,21 +497,13 @@ int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
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 ) ) ;
if ( BuildIPv6 ( c , & lpacket , IPPROTO_ICMP ) < 0 )
goto cleanup ;
if ( t_inject_mode = = LIBNET_LINK ) {
SetupEthernet ( p , & lpacket , dir ) ;
if ( BuildEthernet ( c , & lpacket , ETHERNET_TYPE_IPV6 ) < 0 )
goto cleanup ;
}
result = libnet_write ( c ) ;
@ -492,9 +513,10 @@ int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
}
cleanup :
libnet_destroy ( c ) ;
ClearCtx ( c ) ;
return 0 ;
}
# else /* HAVE_LIBNET_ICMPV6_UNREACH */
int RejectSendLibnet11L3IPv6ICMP ( ThreadVars * tv , Packet * p , void * data , int dir )
@ -541,4 +563,9 @@ int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir)
return 0 ;
}
void FreeCachedCtx ( void )
{
SCLogDebug ( " no libhnet support " ) ;
}
# endif /* HAVE_LIBNET11 */