📄 tcp.c
字号:
/* 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_STATESenum { TCP_ESTABLISHED = 1, TCP_SYN_SENT, TCP_SYN_RECV, 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;static struct ip *ugly_iphdr;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;}static voidfree_tcp(struct tcp_stream * a_tcp){ int hash_index = a_tcp->hash_index; 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; 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); 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; while (i) { j = i->next; free(i); i = j; } a_tcp->next_free = free_streams; free_streams = a_tcp; tcp_num--;}static intmk_hash_index(struct tuple4 addr){ int hash=mkhash(addr.saddr, addr.source, addr.daddr, addr.dest); return hash % tcp_stream_table_size;}static voidadd_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); if (tcp_num > max_stream) { 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++; 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->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;}static voidadd2buf(struct half_stream * rcv, char *data, int datalen){ if (datalen + rcv->count - rcv->offset > rcv->bufsize) { if (!rcv->data) { int toalloc; if (datalen < 2048) toalloc = 4096; else toalloc = datalen * 2; rcv->data = malloc(toalloc); rcv->bufsize = toalloc; } else { rcv->data = realloc(rcv->data, 2 * rcv->bufsize); rcv->bufsize *= 2; } 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 voidride_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) { cc = a_tcp->client.collect; sc = a_tcp->server.collect; ccu = a_tcp->client.collect_urg; scu = a_tcp->server.collect_urg; (i->item) (a_tcp, &i->data); if (cc < a_tcp->client.collect) i->whatto |= COLLECT_cc; if (ccu < a_tcp->client.collect_urg) i->whatto |= COLLECT_ccu; if (sc < a_tcp->server.collect) i->whatto |= COLLECT_sc; if (scu < a_tcp->server.collect_urg) i->whatto |= COLLECT_scu; if (cc > a_tcp->client.collect) i->whatto &= ~COLLECT_cc; if (ccu > a_tcp->client.collect_urg) i->whatto &= ~COLLECT_ccu; if (sc > a_tcp->server.collect) i->whatto &= ~COLLECT_sc; if (scu > a_tcp->server.collect_urg) i->whatto &= ~COLLECT_scu; }}static voidnotify(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->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) { memmove(rcv->data, rcv->data + a_tcp->read, rcv->count - rcv->offset - a_tcp->read); 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; } 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; }}static voidadd_from_skb(struct tcp_stream * a_tcp, struct half_stream * rcv, struct half_stream * snd, u_char *data, int datalen, u_int this_seq, char fin, char urg, u_int urg_ptr){ u_int lost = EXP_SEQ - this_seq; int to_copy, to_copy2; if (urg && after(urg_ptr, EXP_SEQ - 1) && (!rcv->urg_seen || after(urg_ptr, rcv->urg_ptr))) { rcv->urg_ptr = urg_ptr; rcv->urg_seen = 1; } if (after(rcv->urg_ptr + 1, this_seq + lost) && before(rcv->urg_ptr, this_seq + datalen)) { to_copy = rcv->urg_ptr - (this_seq + lost); if (to_copy > 0) { if (rcv->collect) { add2buf(rcv, data + lost, to_copy); notify(a_tcp, rcv); } else { rcv->count += to_copy; } } rcv->urgdata = data[rcv->urg_ptr - this_seq]; rcv->count_new_urg = 1; notify(a_tcp, rcv); rcv->count_new_urg = 0; rcv->urg_count++; to_copy2 = this_seq + datalen - rcv->urg_ptr - 1; if (to_copy2 > 0) { if (rcv->collect) { add2buf(rcv, data + lost + to_copy + 1, to_copy2); notify(a_tcp, rcv); } else { rcv->count += to_copy2; } } } else { if (datalen - lost > 0) { if (rcv->collect) { add2buf(rcv, data + lost, datalen - lost); notify(a_tcp, rcv); } else { rcv->count += datalen - lost; } } } if (fin) snd->state = FIN_SENT;}static voidtcp_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; /* * Did we get anything new to ack? */ if (!after(this_seq, EXP_SEQ)) { if (after(this_seq + datalen + (this_tcphdr->th_flags & TH_FIN), EXP_SEQ)) { /* the packet straddles our window end */ 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, EXP_SEQ)) { struct skbuff *tmp; 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 pakiet = pakiet->next; } } else return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -