// $Id: inline.c,v 1.3 2003/02/15 21:46:14 redmaze Exp $
#ifdef GIDS
#include "inline.h"
#include "rules.h"
#include <pcap.h>
#include <string.h>
#include <stdlib.h>
#include <libnet.h>
#define PKT_BUFSIZE 65536
/* Most of the code related to libnet (resets and icmp unreach) was
* taken from sp_respond.c */
/* vars */
int libnet_nd; /* libnet descriptor */
char errbuf[LIBNET_ERRBUF_SIZE];
Packet *tmpP;
char *l_tcp, *l_icmp;
/* predeclarations */
#ifndef IPFW
void HandlePacket(ipq_packet_msg_t *);
void TranslateToPcap(ipq_packet_msg_t *, struct pcap_pkthdr *);
#else
void HandlePacket();
void TranslateToPcap(struct pcap_pkthdr *phdr, ssize_t len);
#endif /* IPFW */
void ResetIV(void);
/**
* InlineMode - determine if we are in inline mode
*
* @returns 1 if we are in inline mode, 0 otherwise
*/
int InlineMode()
{
if (pv.inline_flag) /*设置了inline模试flag就等于1*/
return 1;
return 0;
}
#ifndef IPFW
void TranslateToPcap(ipq_packet_msg_t *m, struct pcap_pkthdr *phdr)
{
static struct timeval t;
if (!m->timestamp_sec)
{
memset (&t, 0, sizeof(struct timeval));
gettimeofday(&t, NULL);
phdr->ts.tv_sec = t.tv_sec;
phdr->ts.tv_usec = t.tv_usec;
}
else
{
phdr->ts.tv_sec = m->timestamp_sec;
phdr->ts.tv_usec = m->timestamp_usec;
}
phdr->caplen = m->data_len;
phdr->len = m->data_len;
/* copy the mark to the iv struct, so we can reach it inside stream4 */
iv.mark = m->mark;
}
#else
#endif
void ResetIV()
{
iv.drop = 0;
iv.reject = 0;
iv.replace = 0;
iv.mark = 0;
}
/*
* Function: void InitInlinePostConfig
*
* Purpose: perform initialization tasks that depend on the configfile
*
* Args: none
*
* Returns: nothing void function
*/
void InitInlinePostConfig(void)
{
int tcp_size = 0;
int icmp_size = 0;
//printf("InitInline stage 2: InitInlinePostConfig starting...\n");
/* Let's initialize Libnet, but not if we are in
* layer 2 resets mode, because we use the link
* layer then... */
#ifndef IPFW
if(pv.layer2_resets)
{
tcp_size = ETH_H + IP_H + TCP_H;
icmp_size = 128 + ETH_H;
}
else
#endif
{
//printf("opening raw socket in IP-mode\n");
if((libnet_nd = libnet_open_raw_sock(IPPROTO_RAW)) < 0)
{
fprintf(stdout, "InitInline: Could not open raw socket for libnet\n");
exit(-1);
}
tcp_size = IP_H + TCP_H;
icmp_size = 128;
}
/* init */
l_tcp = calloc(tcp_size, sizeof(char));
if (l_tcp == NULL)
{
perror("InitInline: Could not allocate l_tcp\n");
exit(-1);
}
l_icmp = calloc(icmp_size, sizeof(char));
if (l_icmp == NULL)
{
perror("InitInline: Could not allocate l_icmp\n");
exit(-1);
}
#ifndef IPFW
if(pv.layer2_resets)
{
/* Building Layer 2 Reset Packets */
printf("building cached link layer reset packets\n");
libnet_build_ip(TCP_H, 0, libnet_get_prand(PRu16), 0, 255,
IPPROTO_TCP, 0, 0, NULL, 0, l_tcp + ETH_H);
libnet_build_tcp(0, 0, 0, 0, TH_RST|TH_ACK, 0, 0, NULL, 0,
l_tcp + ETH_H + IP_H);
/* create icmp cached packet */
libnet_build_ip(ICMP_UNREACH_H, 0, libnet_get_prand(PRu16), 0,
255, IPPROTO_ICMP, 0, 0, NULL, 0, l_icmp + ETH_H);
libnet_build_icmp_unreach(3, 3, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0,
l_icmp + ETH_H + IP_H);
}
else
#endif
{
/* Building Socket Reset Packets */
printf("building cached socket reset packets\n");
libnet_build_ip(TCP_H, 0, libnet_get_prand(PRu16), 0, 255,
IPPROTO_TCP, 0, 0, NULL, 0, l_tcp);
libnet_build_tcp(0, 0, 0, 0, TH_RST|TH_ACK, 0, 0, NULL, 0,
l_tcp + IP_H);
/* create icmp cached packet */
libnet_build_ip(ICMP_UNREACH_H, 0, libnet_get_prand(PRu16), 0,
255, IPPROTO_ICMP, 0, 0, NULL, 0, l_icmp);
libnet_build_icmp_unreach(3, 3, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0,
l_icmp + IP_H);
}
}
/* InitInline is called before the Snort_inline configuration file is read. */
int InitInline()//初始化
{
int status;
#ifdef DEBUG_GIDS
printf("Initializing Inline mode \n");
#endif
printf("Initializing Inline mode \n");
#ifndef IPFW
ipqh = ipq_create_handle(0, PF_INET);
if (!ipqh)
{
ipq_perror("InlineInit: ");
ipq_destroy_handle(ipqh);
exit(1);
}
status = ipq_set_mode(ipqh, IPQ_COPY_PACKET, PKT_BUFSIZE);
if (status < 0)
{
ipq_perror("InitInline: ");
ipq_destroy_handle(ipqh);
exit(1);
}
#endif /* IPFW */
ResetIV();//重设iv结构
/* Just in case someone wants to write to a pcap file
* using DLT_RAW because iptables does not give us datalink layer.
*/
pd = pcap_open_dead(DLT_RAW, SNAPLEN);
return 0;
}
#ifndef IPFW
void IpqLoop() //对捕获的包进行的操作
{
int status;
struct pcap_pkthdr PHdr;
unsigned char buf[PKT_BUFSIZE];
static ipq_packet_msg_t *m;
#ifdef DEBUG_GIDS
printf("Reading Packets from ipq handle \n");
#endif
while(1)
{
ResetIV();
status = ipq_read(ipqh, buf, PKT_BUFSIZE, 0);
if (status < 0)
{
ipq_perror("IpqLoop: ");
}
else
{
switch(ipq_message_type(buf))
{
case NLMSG_ERROR:
fprintf(stderr, "Received error message %d\n",
ipq_get_msgerr(buf));
break;
case IPQM_PACKET:
m = ipq_get_packet(buf);
#ifdef DEBUG_INLINE
printf("%02X:%02X:%02X:%02X:%02X:%02X\n", m->hw_addr[0], m->hw_addr[1],
m->hw_addr[2], m->hw_addr[3], m->hw_addr[4], m->hw_addr[5]);
#endif
TranslateToPcap(m, &PHdr);
ProcessPacket(NULL, &PHdr, (u_char *)m->payload);
HandlePacket(m);//以上两个函数是对包处理,处理结果有这函数决定
break;
} /* switch */
} /* if - else */
} /* while() */
}
#else
/* Loop reading packets from IPFW
- borrowed mostly from the TCP-MSSD daemon in FreeBSD ports tree
Questions, comments send to: nick@rogness.net
*/
#endif
/*
* Function: static void RejectSocket
*
* Purpose: send a reject packet (tcp-reset or icmp-unreachable
*
* Args: none
*
* Returns: nothing void function
*/
/*
* Function: static void RejectLayer2(ipq_packet_msg_t *m)
*
* Purpose: send a reject packet (tcp-reset or icmp-unreachable
*
* Args: the ipq_packet_msg_t m for determining the output interface
* and the source mac for our packet.
*
* Returns: nothing void function
*
* TODO: make it also work on *BSD.
*/
#ifndef IPFW
#ifndef IPFW
void HandlePacket(ipq_packet_msg_t *m)
#else
void HandlePacket()
#endif
{
int status;
if (iv.drop)
{
#ifndef IPFW
status = ipq_set_verdict(ipqh, m->packet_id, NF_DROP, 0, NULL);
if (status < 0)
{
ipq_perror("NF_DROP: ");
}
#endif
if (iv.reject)
{
#ifndef IPFW
if(pv.layer2_resets)
{
RejectLayer2(m);
}
else
#endif
{
RejectSocket();
}
}
}
#ifndef IPFW
else if (!iv.replace)
{
status = ipq_set_verdict(ipqh, m->packet_id, NF_ACCEPT, 0, NULL);
if (status < 0)
{
ipq_perror("NF_ACCEPT: ");
}
}
else
{
status = ipq_set_verdict(ipqh, m->packet_id, NF_ACCEPT,
m->data_len, m->payload);
if (status < 0)
{
ipq_perror("NF_ACCEPT: ");
}
}
#endif
}
int InlineDrop()
{
//printf("InlineDrop(): dropping\n");
iv.drop = 1;
return 0;
}
int InlineReject(Packet *p)
{
//printf("InlineReject(): rejecting\n");
iv.reject = 1;
iv.drop = 1;
tmpP = p;
return 0;
}
int InlineAccept()
{
iv.drop = 0;
return 0;
}
int InlineReplace()
{
iv.replace = 1;
return 0;
}
#endif /* GIDS */
|