/*
Copyright (c) 1999 Rafal Wojtczuk <nergal@avet.com.pl>. All rights reserved.
See the file COPYING for license details.
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include "checksum.h"
#include "scan.h"
#include "tcp.h"
#include "util.h"
#include "nids.h"
#include "hash.h"
#if ! HAVE_TCP_STATES
//定义TCP连接状态
enum {
TCP_ESTABLISHED = 1,//tcp 建立,开始传输数据
TCP_SYN_SENT,//标示syn_send状态,主动打开
TCP_SYN_RECV,//syn_recv状态,接收syn
TCP_FIN_WAIT1,
TCP_FIN_WAIT2,
TCP_TIME_WAIT,
TCP_CLOSE,
TCP_CLOSE_WAIT,
TCP_LAST_ACK,
TCP_LISTEN,
TCP_CLOSING /* now a valid state */
};
#endif
#define FIN_SENT 120
#define FIN_CONFIRMED 121
#define COLLECT_cc 1 //客户端有数据
#define COLLECT_sc 2 //服务器端有数据
#define COLLECT_ccu 4 //客户端有紧急数据
#define COLLECT_scu 8 //服务器端有紧急数据
#define EXP_SEQ (snd->first_data_seq + rcv->count + rcv->urg_count) //渴望得到的序列号
extern struct proc_node *tcp_procs;
static struct tcp_stream **tcp_stream_table;
static struct tcp_stream *streams_pool;
static int tcp_num = 0;
static int tcp_stream_table_size;
static int max_stream;
static struct tcp_stream *tcp_latest = 0, *tcp_oldest = 0;
static struct tcp_stream *free_streams;//上一个已经释放的TCP连接
static struct ip *ugly_iphdr;
//free the mem of struct half_stream *h
//释放TCP连接中的一端
static void purge_queue(struct half_stream * h)
{
struct skbuff *tmp, *p = h->list;
while (p) {
free(p->data);
tmp = p->next;
free(p);
p = tmp;
}
h->list = h->listtail = 0;
h->rmem_alloc = 0;
}
//释放一个tcp 连接
static void
free_tcp(struct tcp_stream * a_tcp)
{
int hash_index = a_tcp->hash_index;//传输哈希值,将由该值在tcp_stream_table 中找到该节点
struct lurker_node *i, *j;
//释放客户端机服务器端所占的内存
purge_queue(&a_tcp->server);
purge_queue(&a_tcp->client);
if (a_tcp->next_node)
a_tcp->next_node->prev_node = a_tcp->prev_node;
if (a_tcp->prev_node)
a_tcp->prev_node->next_node = a_tcp->next_node;
//free link of a_tcp
else
tcp_stream_table[hash_index] = a_tcp->next_node;//如果链表的前指针为空则哈希表指向其后指针指向的结构
//释放客户端和服务器端的数据部分
if (a_tcp->client.data)
free(a_tcp->client.data);
if (a_tcp->server.data)
free(a_tcp->server.data);
//next_time,prev_time双向链表中删除该TCP节点
if (a_tcp->next_time)
a_tcp->next_time->prev_time = a_tcp->prev_time;
if (a_tcp->prev_time)
a_tcp->prev_time->next_time = a_tcp->next_time;
//调整两个公共指针的值
if (a_tcp == tcp_oldest)//
tcp_oldest = a_tcp->prev_time;
if (a_tcp == tcp_latest)
tcp_latest = a_tcp->next_time;
i = a_tcp->listeners;//struct lurker_node *listeners
while (i) {
j = i->next;
free(i);
i = j;
}
a_tcp->next_free = free_streams;
free_streams = a_tcp;
tcp_num--;//表示现有的TCP连接总数
}
//产生哈希索引值
static int
mk_hash_index(struct tuple4 addr)
{
int hash=mkhash(addr.saddr, addr.source, addr.daddr, addr.dest);
return hash % tcp_stream_table_size;
}
//获得时间截
static int get_ts(struct tcphdr * this_tcphdr, unsigned int * ts)
{
int len = 4 * this_tcphdr->th_off;//获得总长度
unsigned int tmp_ts;
unsigned char * options = (char*)(this_tcphdr + 1);//指向选项的指针
int ind = 0, ret = 0;
while (ind <= len - (int)sizeof (struct tcphdr) - 10 )//获得kind字段的值
switch (options[ind]) {
//TCPOPT_NOP表示无操作,作填充用;TCPOPT_EOL表示选项表结束 TCPOPT_TIMESTAMP表示时间戳选项
case 0: /* TCPOPT_EOL */
return ret;
case 1: /* TCPOPT_NOP */
ind++;
continue;
case 8: /* TCPOPT_TIMESTAMP */
memcpy((char*)&tmp_ts, options + ind + 2, 4);//获得时间截
*ts=ntohl(tmp_ts);//得到时间戳 *ts !!
ret = 1;
/* no break, intentionally 程序将在这里继续向下执行default语句*/
default:
if (options[ind+1] < 2 ) /* "silly option" */
return ret;
ind += options[ind+1];
}
return ret;
}
// 从选项字段中 得到窗口扩大因子
static int get_wscale(struct tcphdr * this_tcphdr, unsigned int * ws)
{
int len = 4 * this_tcphdr->th_off;
unsigned int tmp_ws;
unsigned char * options = (char*)(this_tcphdr + 1);
int ind = 0, ret = 0;
*ws=1;
while (ind <= len - (int)sizeof (struct tcphdr) - 3 )
switch (options[ind]) {//判断kind的值,如果为三,对应窗口扩大因子
case 0: /* TCPOPT_EOL */
return ret;
case 1: /* TCPOPT_NOP */
ind++;
continue;
case 3: /* TCPOPT_WSCALE */
tmp_ws=options[ind+2];//得到窗口扩大因子
if (tmp_ws>14)
tmp_ws=14;
*ws=1<<tmp_ws;
ret = 1;
/* no break, intentionally */
default:
if (options[ind+1] < 2 ) /* "silly option" */
return ret;
ind += options[ind+1];
}
return ret;
}
//添加一个新的TCP连接到链表中
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连接已经超出了连接允许的最大值
//释放监听时间最长的TCP连接
if (tcp_num > max_stream) {
struct lurker_node *i;
tcp_oldest->nids_state = NIDS_TIMED_OUT;//等词最长的TCP连接做超时处理
for (i = tcp_oldest->listeners; i; i = i->next)
(i->item) (tcp_oldest, &i->data);//void (*item)()
free_tcp(tcp_oldest);
nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_TOOMUCH, ugly_iphdr, this_tcphdr);
}//若缓冲池满则释放tcp_oldest指向的tcp链表
a_tcp = free_streams;//给a_tcp分配空闲空间以便填充
if (!a_tcp) {
fprintf(stderr, "gdb me ...\n");
pause();
}
free_streams = a_tcp->next_free;
tcp_num++;
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;
}
//接收到新数据,重新分配空间,要根据收到的数据的大小
//和buffersize进行重分配
static void
add2buf(struct half_stream * rcv, char *data, int datalen)//根据rcv_data增加buffsize
{
int toalloc;
if (datalen + rcv->count - rcv->offset > rcv->bufsize) {//如果加入新数据后大于能接受的范围
if (!rcv->data) {//数据区是空的
if (datalen < 2048)
toalloc = 4096;
else
toalloc = datalen * 2;
//为数据区分配空间
rcv->data = malloc(toalloc);
rcv->bufsize = toalloc;
}
//如果数据区不为空
else {//new tcp segment coming
if (datalen < rcv->bufsize)
toalloc = 2 * rcv->bufsize;
else
toalloc = rcv->bufsize + 2*datalen;
rcv->data = realloc(rcv->data, toalloc);
rcv->bufsize = toalloc;
}
if (!rcv->data)
nids_params.no_mem("add2buf");
}
memcpy(rcv->data + rcv->count - rcv->offset, data, datalen);
rcv->count_new = datalen;
rcv->count += datalen;
}
static void
ride_lurkers(struct tcp_stream * a_tcp, char mask)
{
struct lurker_node *i;
char cc, sc, ccu, scu;
for (i = a_tcp->listeners; i; i = i->next)
if (i->whatto & mask) { /
评论0