-
void nids_run()
-
{
-
if (!desc) {
-
strcpy(nids_errbuf, "Libnids not initialized");
-
return;
-
}
-
pcap_loop(desc, -1, (pcap_handler) pcap_hand, 0);
-
clear_stream_buffers();
-
strcpy(nids_errbuf, "loop: ");
-
strncat(nids_errbuf, pcap_geterr(desc), sizeof(nids_errbuf) - 7);
-
pcap_close(desc);
-
}
run函数调用pcap_loop()函数。此函数为libpcap中的函数,无限循环抓包,抓到的包交给回调函数处理。
回调函数处理流程如下:
点击(此处)折叠或打开
-
static void pcap_hand(u_char * par, struct pcap_pkthdr *hdr, u_char * data)
-
{
-
struct proc_node *i;
-
u_char *data_aligned;
-
#ifdef DLT_IEEE802_11
-
unsigned short fc;
-
int linkoffset_tweaked_by_prism_code = 0;
-
#endif
-
nids_last_pcap_header = hdr;
-
(void)par; /* warnings... */
-
switch (linktype) {
-
case DLT_EN10MB:
-
if (hdr->caplen < 14)
-
return;
-
/* Only handle IP packets and 802.1Q VLAN tagged packets below. */
-
if (data[12] == 8 && data[13] == 0) {
-
/* Regular ethernet */
-
linkoffset = 14;
-
} else if (data[12] == 0x81 && data[13] == 0) {
-
/* Skip 802.1Q VLAN and priority information */
-
linkoffset = 18;
-
} else
-
/* non-ip frame */
-
return;
-
break;
-
#ifdef DLT_PRISM_HEADER
-
#ifndef DLT_IEEE802_11
-
#error DLT_PRISM_HEADER is defined, but DLT_IEEE802_11 is not ???
-
#endif
-
case DLT_PRISM_HEADER:
-
linkoffset = 144; //sizeof(prism2_hdr);
-
linkoffset_tweaked_by_prism_code = 1;
-
//now let DLT_IEEE802_11 do the rest
-
#endif
-
#ifdef DLT_IEEE802_11
-
case DLT_IEEE802_11:
-
/* I don't know why frame control is always little endian, but it
-
* works for tcpdump, so who am I to complain? (wam)
-
*/
-
if (!linkoffset_tweaked_by_prism_code)
-
linkoffset = 0;
-
fc = EXTRACT_LE_16BITS(data + linkoffset);
-
if (FC_TYPE(fc) != T_DATA || FC_WEP(fc)) {
-
return;
-
}
-
if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
-
/* a wireless distribution system packet will have another
-
* MAC addr in the frame
-
*/
-
linkoffset += 30;
-
} else {
-
linkoffset += 24;
-
}
-
if (hdr->len < linkoffset + LLC_FRAME_SIZE)
-
return;
-
if (ETHERTYPE_IP !=
-
EXTRACT_16BITS(data + linkoffset + LLC_OFFSET_TO_TYPE_FIELD)) {
-
/* EAP, LEAP, and other 802.11 enhancements can be
-
* encapsulated within a data packet too. Look only at
-
* encapsulated IP packets (Type field of the LLC frame).
-
*/
-
return;
-
}
-
linkoffset += LLC_FRAME_SIZE;
-
break;
-
#endif
-
default:;
-
}
-
if (hdr->caplen < linkoffset)
-
return;
-
-
/*
-
* sure, memcpy costs. But many EXTRACT_{SHORT, LONG} macros cost, too.
-
* Anyway, libpcap tries to ensure proper layer 3 alignment (look for
-
* handle->offset in pcap sources), so memcpy should not be called.
-
*/
-
#ifdef LBL_ALIGN
-
if ((unsigned long) (data + linkoffset) & 0x3) {
-
data_aligned = alloca(hdr->caplen - linkoffset + 4);
-
data_aligned -= (unsigned long) data_aligned % 4;
-
memcpy(data_aligned, data + linkoffset, hdr->caplen - linkoffset);
-
} else
-
#endif
-
data_aligned = data + linkoffset;
-
for (i = ip_frag_procs; i; i = i->next)
-
(i->item) (data_aligned, hdr->caplen - linkoffset);
-
}
对于每一个包,都调用函数gen_ip_proc()进行处理,判断其类型,以便进行重组。
-
static void gen_ip_proc(u_char * data, int skblen)
-
{
-
switch (((struct ip *) data)->ip_p) {
-
case IPPROTO_TCP:
-
process_tcp(data, skblen);
-
break;
-
case IPPROTO_UDP:
-
process_udp(data);
-
break;
-
case IPPROTO_ICMP:
-
if (nids_params.n_tcp_streams)
-
process_icmp(data);
-
break;
-
default:
-
break;
-
}
-
}
首先分析一下抓包函数和回调函数之间的关系
函数名称:int pcap_loop(pcap_t * p,int cnt, pcap_handler callback, uchar * user);
函数功能:捕获数据包,不会响应pcap_open_live()函数设置的超时时间
参数说明:p 是由pcap_open_live()返回的所打的网卡的指针;
cnt用于设置所捕获数据包的个数;
pcap_handler 是与void packet_handler()使用的一个参数,即回调函数的名称;
user值一般为NULL
pcap_loop原型是pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user)
其中第一个参数是winpcap的句柄,第二个是指定捕获的数据包个数,如果为-1则无限循环捕获。第四个参数user是留给用户使用的。
第三个是回调函数其原型如下: pcap_callback(u_char* argument,const struct pcap_pkthdr* packet_header,const u_char* packet_content)
其中参数pcap_content表示的捕获到的数据包的内容
参数argument是从函数pcap_loop()传递过来的。注意:这里的参数就是指 pcap_loop中的 *user 参数
参数pcap_pkthdr 表示捕获到的数据包基本信息,包括时间,长度等信息. 另
外:回调函数必须是全局函数或静态函数,其参数默认,比如pcap_loop()可以写成
pcap_loop(pcap_handle,10,pcap_callback,NULL)不能往里面传递实参.
-----------------------------------------------------------------------------------------------------------------
pcap_loop和callback之间参数存在联系:
pcap_loop的最后一个参数user是留给用户使用的,当callback被调用的时候这个值会传递给callback的第一个参数(也叫user),
callback的最后一个参数p指向一块内存空间,这个空间中存放的就是pcap_loop抓到的数据包。
callback的第二个参数是一个结构体指针,该结构体定义如下:
-
struct pcap_pkthdr
-
-
{ struct timeval ts; /* 时间戳 */
-
-
bpf_u_int32 caplen; /* 已捕获部分的长度 */
-
-
bpf_u_int32 len; /* 该包的脱机长度 */
-
-
};
这个结构体是由pcap_loop自己填充的,用来取得一些关于数据包的信息
所以,在callback函数当中只有第一个user指针是可以留给用户使用的,
如果你想给callback传递自己参数,那就只能通过pcap_loop的最后一个参数user来实现了
无限循环的抓包函数的回调函数调用了gen_ip_proc()函数,该函数通过判断类型进入到对应的重组阶段。下面开始分析TCP重组部分。
函数名:process_tcp(data, skblen)
代码很长,如下:
-
void process_tcp(u_char * data, int skblen)//传入数据与其长度
-
{
-
struct ip *this_iphdr = (struct ip *)data;//ip与tcp结构体见后面说明
-
struct tcphdr *this_tcphdr = (struct tcphdr *)(data + 4 * this_iphdr->ip_hl);
-
//计算ip部分偏移指到TCP头部
-
int datalen, iplen;//数据部分长度,以及ip长度
-
int from_client = 1;
-
unsigned int tmp_ts;//时间戳
-
struct tcp_stream *a_tcp;//一个TCP流的全部信息
-
struct half_stream *snd, *rcv;
-
//一个方向上的TCP流,TCP分为两个方向上的,一个是客户到服务端,一个是服务端到客户
-
-
ugly_iphdr = this_iphdr;
-
iplen = ntohs(this_iphdr->ip_len);
-
if ((unsigned)iplen < 4 * this_iphdr->ip_hl + sizeof(struct tcphdr)) {
-
nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr,
-
this_tcphdr);//指示的长度与实际的不相符,指出错误
-
return;
-
} // ktos sie bawi
-
-
datalen = iplen - 4 * this_iphdr->ip_hl - 4 * this_tcphdr->th_off;
-
//tcp数据部分长度,去掉了TCP的头部
-
//ip_hl表示ip头部长度,th_off表示tcp头部长度,datalen表示tcp数据部分长度
-
if (datalen < 0) {
-
nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr,
-
this_tcphdr);
-
return;
-
} // ktos sie bawi,数据部分小于0,发生错误,返回
-
-
if ((this_iphdr->ip_src.s_addr | this_iphdr->ip_dst.s_addr) == 0) {
-
nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr,
-
this_tcphdr);
-
return;
-
}
-
if (!(this_tcphdr->th_flags & TH_ACK))//确认信息有效
-
detect_scan(this_iphdr);//如果是TCP中的ACK信息,检测是否出现攻击
-
if (!nids_params.n_tcp_streams) return;
-
if (my_tcp_check(this_tcphdr, iplen - 4 * this_iphdr->ip_hl,
-
this_iphdr->ip_src.s_addr, this_iphdr->ip_dst.s_addr)) {
-
nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr,
-
this_tcphdr);
-
return;
-
}//检测数据包的有效性
-
#if 0
-
check_flags(this_iphdr, this_tcphdr);
-
//ECN
-
#endif
-
-
//经过以上处,初步判断tcp包正常,进行入队操作,插入队列前,先进行此包的状态判断,判断此数据包处于何种状态
-
if (!(a_tcp = find_stream(this_tcphdr, this_iphdr, &from_client))) {
-
/*是三次握手的第一个包*/
-
/*tcp里流不存在时:且tcp数据包里的(syn=1 && ack==0 && rst==0)时,添加一条tcp流*/
-
/*tcp第一次握手*/
-
if ((this_tcphdr->th_flags & TH_SYN) &&
-
!(this_tcphdr->th_flags & TH_ACK) &&
-
!(this_tcphdr->th_flags & TH_RST))
-
add_new_tcp(this_tcphdr, this_iphdr);//发现新的TCP流,进行添加。
-
/*第一次握手完毕返回*/
-
-
//在此处添加TCP流,但此处有隐患,对数据进行保存操作后,有可能数据没释放,实际应用中碰到中
-
return;
-
}
-
if (from_client) {
-
snd = &a_tcp->client;
-
rcv = &a_tcp->server;
-
}
-
else {
-
rcv = &a_tcp->client;
-
snd = &a_tcp->server;
-
}
-
/**********************************************************************
-
-
三次握手的第二次握手
-
-
************************************************************************/
-
-
/*tcp 三次握手, SYN ==1,ACK==1,tcp第二次握手(server -> client的同步响应)*/
-
-
//来了一个SYN包
-
if ((this_tcphdr->th_flags & TH_SYN)) {
-
//syn包是用来建立新连接的,所以,要么来自客户端且没标志(前面处理了),要么来自服务端且加ACK标志
-
//所以这里只能来自服务器,检查服务器状态是否正常,不正常的话果断忽略这个包
-
if (from_client || a_tcp->client.state != TCP_SYN_SENT ||
-
a_tcp->server.state != TCP_CLOSE || !(this_tcphdr->th_flags & TH_ACK))
-
return;
-
/*第二次回应包的ACK 值为第一个包的序列号+1,在初始化的时候已经加一*/
-
//忽略流水号错误的包
-
if (a_tcp->client.seq != ntohl(this_tcphdr->th_ack))
-
return;
-
-
/*第二个包服务端赋值*/
-
/*a_tcp 中服务端赋值,*/
-
//tcp流中有2个方向上的数据,此事可以给一个方向上的一些数据赋值
-
a_tcp->server.state = TCP_SYN_RECV;
-
a_tcp->server.seq = ntohl(this_tcphdr->th_seq) + 1;
-
a_tcp->server.first_data_seq = a_tcp->server.seq;
-
a_tcp->server.ack_seq = ntohl(this_tcphdr->th_ack);
-
a_tcp->server.window = ntohs(this_tcphdr->th_win);
-
-
/*对于tcp 选项的赋值*/
-
//初始化客户端和服务器的时间截
-
-
-
if (a_tcp->client.ts_on)
-
{
-
a_tcp->server.ts_on = get_ts(this_tcphdr, &a_tcp->server.curr_ts);
-
if (!a_tcp->server.ts_on)
-
a_tcp->client.ts_on = 0;
-
} else
-
a_tcp->server.ts_on = 0;//初始化窗口大小
-
if (a_tcp->client.wscale_on)
-
{
-
a_tcp->server.wscale_on = get_wscale(this_tcphdr, &a_tcp->server.wscale);
-
if (!a_tcp->server.wscale_on)
-
{
-
a_tcp->client.wscale_on = 0;
-
a_tcp->client.wscale = 1;
-
a_tcp->server.wscale = 1;
-
}
-
}
-
else
-
{
-
a_tcp->server.wscale_on = 0;
-
a_tcp->server.wscale = 1;
-
}
-
/*第二次握手完毕,返回*/ return; }
-
/*
-
(如果有数据存在或者序列号不等于确认号的)并且
-
-
序列号在窗口之外
-
已经确认过的序号
-
-
*/
-
if ( ! ( !datalen && ntohl(this_tcphdr->th_seq) == rcv->ack_seq ) &&
-
( !before(ntohl(this_tcphdr->th_seq), rcv->ack_seq + rcv->window*rcv->wscale) ||
-
before(ntohl(this_tcphdr->th_seq) + datalen, rcv->ack_seq) ) )
-
return;/*发送th_rst 重新开启一个连接*/
-
//如果是rst包,ok,关闭连接
-
//将现有数据推给注册的回调方,然后销毁这个会话。 if ((this_tcphdr->th_flags & TH_RST)) {
-
/*是tcp 数据*/
-
if (a_tcp->nids_state == NIDS_DATA) { struct lurker_node *i; a_tcp->nids_state = NIDS_RESET;
-
//下面回调所有的钩子
-
for (i = a_tcp->listeners; i; i = i->next)
-
(i->item) (a_tcp, &i->data);
-
}
-
free_tcp(a_tcp);
-
return;
-
}
-
/* PAWS check */
-
/* PAWS(防止重复报文)check 检查时间戳*/
-
if (rcv->ts_on && get_ts(this_tcphdr, &tmp_ts) && before(tmp_ts, snd->curr_ts))
-
return;
-
/**********************************************************************
-
第三次握手包
-
-
**********************************************************************
-
*/
-
-
/*
-
-
-
从client --> server的包
-
-
是从三次握手的第三个包分析开始的,进行一部分数据分析,和初始化
-
连接状态
-
-
*/
-
if ((this_tcphdr->th_flags & TH_ACK)) { //如果是从客户端来的,且两边都在第二次握手的状态上
-
if (from_client && a_tcp->client.state == TCP_SYN_SENT &&a_tcp->server.state == TCP_SYN_RECV)
-
{//在此情况下,流水号又对得上,好的,这个包是第三次握手包,连接建立成功
-
if (ntohl(this_tcphdr->th_ack) == a_tcp->server.seq)
-
{a_tcp->client.state = TCP_ESTABLISHED;
-
//更新客户端状态
-
a_tcp->client.ack_seq = ntohl(this_tcphdr->th_ack);
-
//更新ack序号
-
{
-
struct proc_node *i;
-
struct lurker_node *j;
-
void *data;
-
a_tcp->server.state = TCP_ESTABLISHED;
-
a_tcp->nids_state = NIDS_JUST_EST;
-
/*开始全双工传输,client server 连接已经建立起来了*/
-
-
/*三次握手tcp ip 连接建立*/
-
for (i = tcp_procs; i; i = i->next)
-
{ //此处根据调用者的设定来判断哪些数据需要在回调时返回
-
-
char whatto = 0;
-
char cc = a_tcp->client.collect;
-
char sc = a_tcp->server.collect;
-
char ccu = a_tcp->client.collect_urg;
-
char scu = a_tcp->server.collect_urg; /*进入回调函数处理*/
-
-
/*
-
-
如果在相应端口出现
-
-
client.collect ++ ;
-
-
测审计次数据
-
对应用来说tcp 连接已经建立
-
-
*/
-
(i->item) (a_tcp, &data);
-
if (cc < a_tcp->client.collect)
-
whatto |= COLLECT_cc;
-
if (ccu < a_tcp->client.collect_urg)
-
whatto |= COLLECT_ccu;
-
if (sc < a_tcp->server.collect)
-
whatto |= COLLECT_sc;
-
if (scu < a_tcp->server.collect_urg)
-
whatto |= COLLECT_scu;
-
if (nids_params.one_loop_less)
-
{ if (a_tcp->client.collect >=2)
-
{
-
a_tcp->client.collect=cc;
-
whatto&=~COLLECT_cc;
-
}
-
if (a_tcp->server.collect >=2 )
-
{
-
a_tcp->server.collect=sc;
-
whatto&=~COLLECT_sc;
-
}
-
}
-
/*加入监听队列,开始数据接收*/
-
if (whatto)
-
{
-
j = mknew(struct lurker_node);
-
j->item = i->item;
-
j->data = data;
-
j->whatto = whatto;
-
j->next = a_tcp->listeners;
-
a_tcp->listeners = j;
-
}
-
}
-
if (!a_tcp->listeners)
-
{/*不存在监听着*/
-
free_tcp(a_tcp);
-
return;
-
}
-
a_tcp->nids_state = NIDS_DATA;
-
}
-
}
-
//
-
return;
-
}
-
}
-
/*
-
************************************************************
-
-
挥手过程
-
-
*************************************************************
-
-
*/
-
-
/*数据结束的包的判断*/
-
if ((this_tcphdr->th_flags & TH_ACK)) {
-
/* 从数据传输过程不断更新服务器客户端的ack_seq
-
一直到接收到fin 包,数据传输结束
-
-
*/
-
//先调用handle_ack更新ack序号
-
handle_ack(snd, ntohl(this_tcphdr->th_ack));
-
//更新状态,回调告知连接关闭,然后释放连接
-
if (rcv->state == FIN_SENT)
-
rcv->state = FIN_CONFIRMED;
-
if (rcv->state == FIN_CONFIRMED && snd->state == FIN_CONFIRMED
-
{
-
struct lurker_node *i;
-
a_tcp->nids_state = NIDS_CLOSE;
-
for (i = a_tcp->listeners; i; i = i->next)
-
(i->item) (a_tcp, &i->data);
-
free_tcp(a_tcp);
-
return;
-
}
-
}
-
/*
-
-
*************************************************************
-
数据处理过程
-
*************************************************************
-
-
*/
-
-
if (datalen + (this_tcphdr->th_flags & TH_FIN) > 0) /*
-
-
a_tcp -----a_tcp 客户端连接包
-
this_tcphdr tcp 包头
-
snd-----发送包
-
rcv -----接收包
-
-
(char *) (this_tcphdr) + 4 * this_tcphdr->th_off -----数据包内容
-
datalen---------数据包长度
-
-
-
*/
-
//就将数据更新到接收方缓冲区
-
tcp_queue(a_tcp, this_tcphdr, snd, rcv, (char *) (this_tcphdr) + 4 * this_tcphdr->th_off, datalen, skblen);
-
//更新窗口大小
-
snd->window = ntohs(this_tcphdr->th_win);
-
//如果缓存溢出(说明出了问题),果断释放连接
-
if (rcv->rmem_alloc > 65535) prune_queue(rcv, this_tcphdr); if (!a_tcp->listeners) free_tcp(a_tcp);}
相关结构体说明
-
struct timestamp
-
{
-
u_int8_t len;
-
u_int8_t ptr;
-
#if __BYTE_ORDER == __LITTLE_ENDIAN
-
unsigned int flags:4;
-
unsigned int overflow:4;
-
#elif __BYTE_ORDER == __BIG_ENDIAN
-
unsigned int overflow:4;
-
unsigned int flags:4;
-
#else
-
# error "Please fix "
-
#endif
-
u_int32_t data[9];
-
};
-
-
struct iphdr
-
{
-
#if __BYTE_ORDER == __LITTLE_ENDIAN
-
unsigned int ihl:4;
-
unsigned int version:4;
-
#elif __BYTE_ORDER == __BIG_ENDIAN
-
unsigned int version:4;
-
unsigned int ihl:4;
-
#else
-
# error "Please fix "
-
#endif
-
u_int8_t tos;
-
u_int16_t tot_len;
-
u_int16_t id;
-
u_int16_t frag_off;
-
u_int8_t ttl;
-
u_int8_t protocol;
-
u_int16_t check;
-
u_int32_t saddr;
-
u_int32_t daddr;
-
/*The options start here. */
-
};
-
<pre name="code" class="cpp"><pre></pre>
-
<p></p>
-
<pre></pre>
-
tcp结构
-
<p></p>
-
<p></p>
-
<pre name="code" class="cpp">struct tcphdr {
-
__be16 source;
-
__be16 dest;
-
__be32 seq;
-
__be32 ack_seq;
-
#if defined(__LITTLE_ENDIAN_BITFIELD)
-
__u16 res1:4,
-
doff:4,
-
fin:1,
-
syn:1,
-
rst:1,
-
psh:1,
-
ack:1,
-
urg:1,
-
ece:1,
-
cwr:1;
-
#elif defined(__BIG_ENDIAN_BITFIELD)
-
__u16 doff:4,
-
res1:4,
-
cwr:1,
-
ece:1,
-
urg:1,
-
ack:1,
-
psh:1,
-
rst:1,
-
syn:1,
-
fin:1;
-
#else
-
#error "Adjust your defines"
-
#endif
-
__be16 window;
-
__be16 check;
-
__be16 urg_ptr;
-
};
查找是否存在tcp流
-
struct tcp_stream *
-
find_stream(struct tcphdr * this_tcphdr, struct ip * this_iphdr,
-
int *from_client)
-
{
-
struct tuple4 this_addr, reversed;
-
int hash_index;
-
struct tcp_stream *a_tcp;
-
-
this_addr.source = ntohs(this_tcphdr->th_sport);
-
this_addr.dest = ntohs(this_tcphdr->th_dport);
-
this_addr.saddr = this_iphdr->ip_src.s_addr;
-
this_addr.daddr = this_iphdr->ip_dst.s_addr;
-
hash_index = mk_hash_index(this_addr);//找到传入数据的哈希地址
-
for (a_tcp = tcp_stream_table[hash_index];
-
a_tcp && !b_comp(a_tcp->addr, this_addr);
-
a_tcp = a_tcp->next_node);//如果此地址开始即为空,则表明没有与此包对应的TCP流,如果该地址不为空,则看地址值是否一样,如果
-
//找到,设定from_client = 1,否则,一直找到最后。看是否为同一个TCP流主要看其地址是否一样
-
if (a_tcp) {
-
*from_client = 1;
-
return a_tcp;
-
}
-
reversed.source = ntohs(this_tcphdr->th_dport);
-
reversed.dest = ntohs(this_tcphdr->th_sport);
-
reversed.saddr = this_iphdr->ip_dst.s_addr;
-
reversed.daddr = this_iphdr->ip_src.s_addr;
-
hash_index = mk_hash_index(reversed);
-
for (a_tcp = tcp_stream_table[hash_index];
-
a_tcp && !b_comp(a_tcp->addr, reversed);
-
a_tcp = a_tcp->next_node);
-
if (a_tcp) {
-
*from_client = 0;
-
return a_tcp;
-
}
-
else
-
return 0;
-
}
-
struct tcp_stream *
-
find_stream(struct tcphdr * this_tcphdr, struct ip * this_iphdr,
-
int *from_client)
-
{
-
struct tuple4 this_addr, reversed;
-
int hash_index;
-
struct tcp_stream *a_tcp;
-
-
this_addr.source = ntohs(this_tcphdr->th_sport);
-
this_addr.dest = ntohs(this_tcphdr->th_dport);
-
this_addr.saddr = this_iphdr->ip_src.s_addr;
-
this_addr.daddr = this_iphdr->ip_dst.s_addr;
-
hash_index = mk_hash_index(this_addr);//找到传入数据的哈希地址
-
for (a_tcp = tcp_stream_table[hash_index];
-
a_tcp && !b_comp(a_tcp->addr, this_addr);
-
a_tcp = a_tcp->next_node);//如果此地址开始即为空,则表明没有与此包对应的TCP流,如果该地址不为空,则看地址值是否一样,如果
-
//找到,设定from_client = 1,否则,一直找到最后。看是否为同一个TCP流主要看其地址是否一样
-
if (a_tcp) {
-
*from_client = 1;
-
return a_tcp;
-
}
-
reversed.source = ntohs(this_tcphdr->th_dport);
-
reversed.dest = ntohs(this_tcphdr->th_sport);
-
reversed.saddr = this_iphdr->ip_dst.s_addr;
-
reversed.daddr = this_iphdr->ip_src.s_addr;
-
hash_index = mk_hash_index(reversed);
-
for (a_tcp = tcp_stream_table[hash_index];
-
a_tcp && !b_comp(a_tcp->addr, reversed);
-
a_tcp = a_tcp->next_node);
-
if (a_tcp) {
-
*from_client = 0;
-
return a_tcp;
-
}
-
else
-
return 0;
-
}
当没有找到一个与之对应已存在的TCP流是,添加一个新的TCP流。调用函数:add_new_tcp(this_tcphdr, this_iphdr);
-
static void
-
add_new_tcp(struct tcphdr * this_tcphdr, struct ip * this_iphdr)
-
{
-
struct tcp_stream *tolink;
-
struct tcp_stream *a_tcp;
-
int hash_index;
-
struct tuple4 addr;
-
-
addr.source = ntohs(this_tcphdr->th_sport);
-
addr.dest = ntohs(this_tcphdr->th_dport);
-
addr.saddr = this_iphdr->ip_src.s_addr;
-
addr.daddr = this_iphdr->ip_dst.s_addr;
-
hash_index = mk_hash_index(addr);//计算新的TCP流的哈希地址
-
-
if (tcp_num > max_stream) {//tcp流的大小超过了阈值,需要先释放空间
-
struct lurker_node *i;
-
-
tcp_oldest->nids_state = NIDS_TIMED_OUT;
-
for (i = tcp_oldest->listeners; i; i = i->next)
-
(i->item) (tcp_oldest, &i->data);
-
free_tcp(tcp_oldest);
-
nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_TOOMUCH, ugly_iphdr, this_tcphdr);
-
}
-
a_tcp = free_streams;加入流的地址
-
if (!a_tcp) {
-
fprintf(stderr, "gdb me ...\n");
-
pause();
-
}
-
free_streams = a_tcp->next_free;
-
-
tcp_num++;//流的总数加1
-
tolink = tcp_stream_table[hash_index];
-
memset(a_tcp, 0, sizeof(struct tcp_stream));
-
a_tcp->hash_index = hash_index;
-
a_tcp->addr = addr;
-
a_tcp->client.state = TCP_SYN_SENT;
-
a_tcp->client.seq = ntohl(this_tcphdr->th_seq) + 1;
-
a_tcp->client.first_data_seq = a_tcp->client.seq;
-
a_tcp->client.window = ntohs(this_tcphdr->th_win);
-
a_tcp->client.ts_on = get_ts(this_tcphdr, &a_tcp->client.curr_ts);
-
a_tcp->client.wscale_on = get_wscale(this_tcphdr, &a_tcp->client.wscale);
-
a_tcp->server.state = TCP_CLOSE;
-
a_tcp->next_node = tolink;
-
a_tcp->prev_node = 0;
-
if (tolink)
-
tolink->prev_node = a_tcp;
-
tcp_stream_table[hash_index] = a_tcp;
-
a_tcp->next_time = tcp_latest;
-
a_tcp->prev_time = 0;
-
if (!tcp_oldest)
-
tcp_oldest = a_tcp;
-
if (tcp_latest)
-
tcp_latest->prev_time = a_tcp;
-
tcp_latest = a_tcp;
-
}
下面来看TCP重组过程当中的三次握手:
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
完成三次握手后,开始传送数据。
/*******************************************************************************************************************
第一次握手
*******************************************************************************************************************/
-
if (!(a_tcp = find_stream(this_tcphdr, this_iphdr, &from_client))) {
-
-
/*是三次握手的第一个包*/
-
/*tcp里流不存在时:且tcp数据包里的(syn=1 && ack==0 && rst==0)时,添加一条tcp流*/
-
/*tcp第一次握手*/
-
if ((this_tcphdr->th_flags & TH_SYN) &&
-
!(this_tcphdr->th_flags & TH_ACK) &&
-
!(this_tcphdr->th_flags & TH_RST))
-
/*并且没有收到th_rest 包*/
-
add_new_tcp(this_tcphdr, this_iphdr);/*节点加入链表中*/
-
-
/*第一次握手完毕返回*/
-
return;
-
}
-
-
-
if (from_client) { /*从client --> server的包*/
-
snd = &a_tcp->client;
-
rcv = &a_tcp->server;
-
}
-
else {/* server --> client的包 */
-
rcv = &a_tcp->client;
-
snd = &a_tcp->server;
-
}
/*******************************************************************************************************************
第二次握手
*******************************************************************************************************************/
-
/*tcp 三次握手, SYN ==1,ACK==1,tcp第二次握手(server -> client的同步响应)*/
-
if ((this_tcphdr->th_flags & TH_SYN)) {
-
if (from_client || a_tcp->client.state != TCP_SYN_SENT ||
-
a_tcp->server.state != TCP_CLOSE || !(this_tcphdr->th_flags & TH_ACK))
-
return;
-
-
-
/*第二次回应包的ACK 值为第一个包的序列号+1,在初始化的时候已经加一*/
-
if (a_tcp->client.seq != ntohl(this_tcphdr->th_ack))
-
return;
-
-
-
/*第二个包服务端赋值*/
-
/*a_tcp 中服务端赋值,*/
-
-
a_tcp->server.state = TCP_SYN_RECV;
-
a_tcp->server.seq = ntohl(this_tcphdr->th_seq) + 1;
-
a_tcp->server.first_data_seq = a_tcp->server.seq;
-
a_tcp->server.ack_seq = ntohl(this_tcphdr->th_ack);
-
a_tcp->server.window = ntohs(this_tcphdr->th_win);
-
-
-
/*对于tcp 选项的赋值*/
-
//初始化客户端和服务器的时间截
-
-
if (a_tcp->client.ts_on) {
-
a_tcp->server.ts_on = get_ts(this_tcphdr, &a_tcp->server.curr_ts);
-
if (!a_tcp->server.ts_on)
-
a_tcp->client.ts_on = 0;
-
} else a_tcp->server.ts_on = 0;
-
-
-
//初始化窗口大小
-
-
if (a_tcp->client.wscale_on) {
-
a_tcp->server.wscale_on = get_wscale(this_tcphdr, &a_tcp->server.wscale);
-
if (!a_tcp->server.wscale_on) {
-
a_tcp->client.wscale_on = 0;
-
a_tcp->client.wscale = 1;
-
a_tcp->server.wscale = 1;
-
}
-
} else {
-
a_tcp->server.wscale_on = 0;
-
a_tcp->server.wscale = 1;
-
}
-
/*第二次握手完毕,返回*/
-
-
return;
-
}
完成第二次握手后,需要对一些数据进行处理,代码如下:
-
/*
-
(如果有数据存在或者修列号不等于确认号的)并且
-
-
序列号在窗口之外
-
已经确认过的序号
-
-
*/
-
-
if (
-
! (!datalen &&ntohl(this_tcphdr->th_seq)== rcv->ack_seq)
-
&&
-
-
/*th_seq - (ack_seq+ wscale) > 0 或者th_seq+datalen - ack_sql < 0*/
-
( !before(ntohl(this_tcphdr->th_seq), rcv->ack_seq+ rcv->window*rcv->wscale)||
-
before(ntohl(this_tcphdr->th_seq)+ datalen, rcv->ack_seq)
-
)
-
)
-
return;
-
-
-
-
/*发送th_rst 重新开启一个连接*/
-
if ((this_tcphdr->th_flags& TH_RST)){
-
/*是tcp 数据*/
-
if (a_tcp->nids_state== NIDS_DATA){
-
struct lurker_node *i;
-
a_tcp->nids_state= NIDS_RESET;
-
for (i= a_tcp->listeners; i; i= i->next)
-
(i->item)(a_tcp, &i->data);
-
}
-
nids_free_tcp_stream(a_tcp);
-
return;
-
}
然后开始第三次握手
/*******************************************************************************
第三次握手
******************************************************************************/
-
/*从client --> server的包
-
-
是从三次握手的第三个包分析开始的,进行一部分数据分析,和初始化
-
连接状态
-
-
*/
-
-
if ((this_tcphdr->th_flags& TH_ACK)){
-
if (from_client&& a_tcp->client.state== TCP_SYN_SENT&&
-
a_tcp->server.state== TCP_SYN_RECV){
-
if (ntohl(this_tcphdr->th_ack)== a_tcp->server.seq){
-
a_tcp->client.state= TCP_ESTABLISHED;
-
a_tcp->client.ack_seq= ntohl(this_tcphdr->th_ack);
-
{
-
struct proc_node *i;
-
struct lurker_node *j;
-
void *data;
-
-
a_tcp->server.state= TCP_ESTABLISHED;
-
a_tcp->nids_state= NIDS_JUST_EST;
-
/*开始全双工传输,client server 连接已经建立起来了*/
-
-
/*三次握手tcp ip 连接建立*/
-
for (i= tcp_procs; i; i= i->next){
-
char whatto = 0;
-
-
char cc = a_tcp->client.collect;
-
char sc = a_tcp->server.collect;
-
char ccu = a_tcp->client.collect_urg;
-
char scu = a_tcp->server.collect_urg;
-
-
/*进入回调函数处理*/
-
-
/*
-
-
如果在相应端口出现
-
-
client.collect ++ ;
-
-
测审计次数据
-
对应用来说tcp 连接已经建立
-
-
*/
-
-
-
(i->item)(a_tcp, &data);
-
-
/**/
-
if (cc< a_tcp->client.collect)
-
whatto |= COLLECT_cc;
-
if (ccu< a_tcp->client.collect_urg)
-
whatto |= COLLECT_ccu;
-
if (sc< a_tcp->server.collect)
-
whatto |= COLLECT_sc;
-
if (scu< a_tcp->server.collect_urg)
-
whatto |= COLLECT_scu;
-
if (nids_params.one_loop_less){
-
if (a_tcp->client.collect>=2){
-
a_tcp->client.collect=cc;
-
whatto&=~COLLECT_cc;
-
}
-
if (a_tcp->server.collect>=2 ) {
-
a_tcp->server.collect=sc;
-
whatto&=~COLLECT_sc;
-
}
-
}
-
-
/*加入监听队列,开始数据接收*/
-
if (whatto){
-
j = mknew(struct lurker_node);
-
j->item= i->item;/*放入监听队列*/
-
j->data= data;
-
j->whatto= whatto;
-
-
j->next= a_tcp->listeners;
-
a_tcp->listeners= j;
-
}
-
-
}
-
-
-
/*不存在监听着*/{
-
nids_free_tcp_stream(a_tcp);
-
return;
-
}
-
if (!a_tcp->listeners)
-
-
a_tcp->nids_state= NIDS_DATA;
-
}
-
}
-
// return;
-
-
}
-
}
nids头文件定义
-
从client --> server的包
-
-
是从三次握手的第三个包分析开始的,进行一部分数据分析,和初始化
-
连接状态
-
-
*/
-
-
if ((this_tcphdr->th_flags& TH_ACK)){
-
if (from_client&& a_tcp->client.state== TCP_SYN_SENT&&
-
a_tcp->server.state== TCP_SYN_RECV){
-
if (ntohl(this_tcphdr->th_ack)== a_tcp->server.seq){
-
a_tcp->client.state= TCP_ESTABLISHED;
-
a_tcp->client.ack_seq= ntohl(this_tcphdr->th_ack);
-
{
-
struct proc_node *i;
-
struct lurker_node *j;
-
void *data;
-
-
a_tcp->server.state= TCP_ESTABLISHED;
-
a_tcp->nids_state= NIDS_JUST_EST;
-
/*开始全双工传输,client server 连接已经建立起来了*/
-
-
/*三次握手tcp ip 连接建立*/
-
for (i= tcp_procs; i; i= i->next){
-
char whatto = 0;
-
-
char cc = a_tcp->client.collect;
-
char sc = a_tcp->server.collect;
-
char ccu = a_tcp->client.collect_urg;
-
char scu = a_tcp->server.collect_urg;
-
-
/*进入回调函数处理*/
-
-
/*
-
-
如果在相应端口出现
-
-
client.collect ++ ;
-
-
测审计次数据
-
对应用来说tcp 连接已经建立
-
-
*/
-
-
-
(i->item)(a_tcp, &data);
-
-
/**/
-
if (cc< a_tcp->client.collect)
-
whatto |= COLLECT_cc;
-
if (ccu< a_tcp->client.collect_urg)
-
whatto |= COLLECT_ccu;
-
if (sc< a_tcp->server.collect)
-
whatto |= COLLECT_sc;
-
if (scu< a_tcp->server.collect_urg)
-
whatto |= COLLECT_scu;
-
if (nids_params.one_loop_less){
-
if (a_tcp->client.collect>=2){
-
a_tcp->client.collect=cc;
-
whatto&=~COLLECT_cc;
-
}
-
if (a_tcp->server.collect>=2 ) {
-
a_tcp->server.collect=sc;
-
whatto&=~COLLECT_sc;
-
}
-
}
-
-
/*加入监听队列,开始数据接收*/
-
if (whatto){
-
j = mknew(struct lurker_node);
-
j->item= i->item;/*放入监听队列*/
-
j->data= data;
-
j->whatto= whatto;
-
-
j->next= a_tcp->listeners;
-
a_tcp->listeners= j;
-
}
-
-
}
-
-
-
/*不存在监听着*/{
-
nids_free_tcp_stream(a_tcp);
-
return;
-
}
-
if (!a_tcp->listeners)
-
-
a_tcp->nids_state= NIDS_DATA;
-
}
-
}
-
// return;
-
-
}
-
}