void process_tcp(u_char * data, int skblen) { struct ip *this_iphdr = (struct ip *)data; /*tcphdr 的头*/ struct tcphdr *this_tcphdr = (struct tcphdr *)(data + 4 * this_iphdr->ip_hl); int datalen, iplen; int from_client = 1; /*客户发送数据*/ unsigned int tmp_ts; /*流分为客户端服务端*/ struct tcp_stream *a_tcp; struct half_stream *snd, *rcv; 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 /*tcp 数据长度*/ datalen = iplen - 4 * this_iphdr->ip_hl - 4 * this_tcphdr->th_off; if (datalen < 0) { nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr, this_tcphdr); return; } // ktos sie bawi /*源和目的地址都存在*/ 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; } /*如果没有th_ack 包,则进行扫描是否有攻击包*/ if (!(this_tcphdr->th_flags & TH_ACK)) detect_scan(this_iphdr); /* /* 表示有扫描攻击发生 */ if (!nids_params.n_tcp_streams) return; /*tcp 头的长度,iplen -4*this_iphdr->ip_hl, 进行包头的校验*/ 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 /*查找添加流*/ /* ************* 三次握手的第一次握手***************************************** */ 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; } /* 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); { 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; } } /* ************************************************************ 挥手过程 ************************************************************* */ /*数据结束的包的判断*/ if ((this_tcphdr->th_flags & TH_ACK)) { /* 从数据传输过程不断更新服务器客户端的ack_seq 一直到接收到fin 包,数据传输结束 */ 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); nids_free_tcp_stream(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) nids_free_tcp_stream(a_tcp); } //判断 该TCP 数据包是添加到数据区还是添加到list双向链表中 static void tcp_queue(struct tcp_stream * a_tcp, struct tcphdr * this_tcphdr, struct half_stream * snd, struct half_stream* rcv, char *data, int datalen, int skblen ) { u_int this_seq = ntohl(this_tcphdr->th_seq); struct skbuff *pakiet, *tmp; /* #define EXP_SEQ (snd->first_data_seq + rcv->count + rcv->urg_count) EXP_SEQ > this_seq */ /* 如果EXP_SEQ > = this_seq */ /* EXP_SEQ 期望到达的数据 this_seq 实际到达的数据 */ if ( !after(this_seq, EXP_SEQ) ) { /*this_seq + datalen + (this_tcphdr->th_flags & TH_FIN)> EXP_SEQ*/ /*有重叠数据存在(重叠数据怎么处理呢) 也可能没有重叠数据 */ if ( after(this_seq + datalen + (this_tcphdr->th_flags & TH_FIN), EXP_SEQ) ) { /* the packet straddles our window end */ get_ts(this_tcphdr, &snd->curr_ts); add_from_skb(a_tcp, rcv, snd, data, datalen, this_seq, (this_tcphdr->th_flags & TH_FIN), (this_tcphdr->th_flags & TH_URG), ntohs(this_tcphdr->th_urp) + this_seq - 1); /* * Do we have any old packets to ack that the above * made visible? (Go forward from skb) */ /*从头节点释放节点*/ pakiet = rcv->list; while (pakiet) { /* 期望的序列号小于该包的序列号则直接返回 */ if (after(pakiet->seq, EXP_SEQ)) break; /* 对失序队列数据包的处理 如果包序列号加上长度还小于期望序列号 则把该包添加到数据区,并在失序队列中删除该包 */ if (after(pakiet->seq + pakiet->len + pakiet->fin, EXP_SEQ)) { add_from_skb(a_tcp, rcv, snd, pakiet->data, pakiet->len, pakiet->seq, pakiet->fin, pakiet->urg, pakiet->urg_ptr + pakiet->seq - 1); } rcv->rmem_alloc -= pakiet->truesize; /*从头节点释放链表*/ if (pakiet->prev) pakiet->prev->next = pakiet->next; else rcv->list = pakiet->next; if (pakiet->next) pakiet->next->prev = pakiet->prev; else rcv->listtail = pakiet->prev; tmp = pakiet->next; free(pakiet->data); free(pakiet); pakiet = tmp; } } else return; } /*提前到达数据的加入失去顺序队列中链表*/ //序列号大于我们期望的序列号,则把该包添加到list双向链表中 /*链表加入节点 */ else { /*初始化*/ struct skbuff *p = rcv->listtail; /* pakiet 加入rcv->listtal 链表中 */ /* pakiet 节点的初始化 */ pakiet = mknew(struct skbuff); pakiet->truesize = skblen; rcv->rmem_alloc += pakiet->truesize; /*数据包填充pakiet->data 中*/ pakiet->len = datalen; pakiet->data = malloc(datalen); if (!pakiet->data) nids_params.no_mem("tcp_queue"); memcpy(pakiet->data, data, datalen); /*是否是结束包*/ pakiet->fin = (this_tcphdr->th_flags & TH_FIN); /* Some Cisco - at least - hardware accept to close a TCP connection * even though packets were lost before the first TCP FIN packet and * never retransmitted; this violates RFC 793, but since it really * happens, it has to be dealt with... The idea is to introduce a 10s * timeout after TCP FIN packets were sent by both sides so that * corresponding libnids resources can be released instead of waiting * for retransmissions which will never happen. -- Sebastien Raveau */ /* 硬件接收一个tcp 终止的链接, 即使包在一个结束包的时候丢失,并且不再重传, 处理这种方法就是引入时间机制处理 */ if (pakiet->fin) { snd->state = TCP_CLOSING; if (rcv->state == FIN_SENT || rcv->state == FIN_CONFIRMED) add_tcp_closing_timeout(a_tcp); } /* seq,urg ,urg_ptr 赋值 */ pakiet->seq = this_seq; pakiet->urg = (this_tcphdr->th_flags & TH_URG); pakiet->urg_ptr = ntohs(this_tcphdr->th_urp); for (;;) { if (!p || !after(p->seq, this_seq)) break; p = p->prev; } if (!p) { /*建立首节点*/ pakiet->prev = 0; pakiet->next = rcv->list; if (rcv->list) rcv->list->prev = pakiet; rcv->list = pakiet; if (!rcv->listtail) rcv->listtail = pakiet; } /*链表后插入*/ else { pakiet->next = p->next; p->next = pakiet; pakiet->prev = p; if (pakiet->next) pakiet->next->prev = pakiet; else rcv->listtail = pakiet; } } } /* 分配空间,数据保存rcv->data 中 长度为:rcv->count 新数据为date 长度为datalen 接收到新数据,重新分配空间,要根据收到的数据的大小 buffersize重分配的空间 */ static void add2buf(struct half_stream * rcv, char *data, int datalen) { int toalloc; /*datalen + rcv->count - rcv->offset 如果大于buffersize 需要重新分配空间*/ if (datalen + rcv->count - rcv->offset > rcv->bufsize) { /*如果rcv->data 不存在*/ if (!rcv->data) { if (datalen < 2048) toalloc = 4096; else toalloc = datalen * 2; /*数据分配空间,bufsize 为分配空间的大小*/ rcv->data = malloc(toalloc); rcv->bufsize = toalloc; } /*第一次分配空间,如果空间不够重新分配*/ else { 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; /*count 累加为收到的数据之和,从流开始建立*/ } /* 通知服务器或者客户端接受数据 */ static void notify(struct tcp_stream * a_tcp, struct half_stream * rcv) { /* 监听节点 */ struct lurker_node *i, **prev_addr; char mask; /* 紧急数据 */ if (rcv->count_new_urg) { if (!rcv->collect_urg) return; if (rcv == &a_tcp->client) mask = COLLECT_ccu; else mask = COLLECT_scu; ride_lurkers(a_tcp, mask); goto prune_listeners; } /* 常规数据 */ if (rcv->collect) { if (rcv == &a_tcp->client) mask = COLLECT_cc; else mask = COLLECT_sc; /* 不断读取数据,一直到 读取到数据结束 */ do { int total; /* a_tcp 为为收到的datalen total = dalalen; */ a_tcp->read = rcv->count - rcv->offset; total = a_tcp->read; /*处理监听节点上报信息*/ ride_lurkers(a_tcp, mask); if (a_tcp->read > total-rcv->count_new) rcv->count_new = total-a_tcp->read; if (a_tcp->read > 0) { /* 已经读过的数据部再读,把没有读的数据放在rcv->data 中, 继续循环,hlf->data 指向新数据 rcv->count_new 为新数据的长度 */ memmove(rcv->data, rcv->data + a_tcp->read, rcv->count - rcv->offset - a_tcp->read); /*rcv->ofset 最终== rcv->count */ rcv->offset += a_tcp->read; } }while (nids_params.one_loop_less && a_tcp->read>0 && rcv->count_new); // we know that if one_loop_less!=0, we have only one callback to notify /* rcv->count_new 初始化为0 */ rcv->count_new=0; } prune_listeners: prev_addr = &a_tcp->listeners; i = a_tcp->listeners; while (i) if (!i->whatto) { *prev_addr = i->next; free(i); i = *prev_addr; } else { prev_addr = &i->next; i = i->next; } }