⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpstream.c

📁 Firestorm NIDS是一个性能非常高的网络入侵检测系统 (NIDS)。目前
💻 C
📖 第 1 页 / 共 2 页
字号:
		/* TODO: Always need to re-order any out of order		 * transmissions. Not sure what kind of mem policy		 * we are going to need here...		 */		dmesg(M_DEBUG, "tcpstream: Out of order: %u->%u %u->%u",			tp->seq-rcv->isn,			tp->seq_end-rcv->isn,			tp->seq, rcv->rcv_nxt);	}}/* Process incoming TCP segments here */static int tcpstream_tcpseg(struct packet *p, unsigned int i){	struct pkt_iphdr *iph=p->layer[i].h.ip;	struct pkt_tcphdr *tcph=p->layer[i+1].h.tcp;	struct tcp_session *s;	struct tcp_stream *snd, *rcv;	int to_server;	int ret=0;	struct tcpseg tp;	/* Host order header values */	tp.ack=ntohl(tcph->ack);	tp.seq=ntohl(tcph->seq);	tp.win=ntohs(tcph->win);	tp.len=ntohs(iph->tot_len) - (iph->ihl<<2) - (tcph->doff<<2);	tp.seq_end=tp.seq+tp.len+tcph->flags.bits.syn+tcph->flags.bits.fin;	tp.tsval=0;	tp.saw_tstamp=0;	/* Find the session this packet comes from */	if ( !(s=tcp_find(iph, tcph, &to_server)) ) {		if ( (tcph->flags.bits.syn) &&			!(tcph->flags.bits.ack) &&			!(tcph->flags.bits.rst)) {			/* SYN: part 1 of connection handshake */			p->layer[i+1].session=tcp_new(iph, tcph, p);			p->layer[i+1].flags|=FLAG_TCP_STATE|FLAG_TCP_2SVR;			return ret;		}		dmesg(M_DEBUG,"tcpstream: never heard of you");		return ret;	}else p->layer[i+1].session=s;	/* figure out who is sender and who is reciever */	if ( to_server ) {		snd=&s->client;		rcv=&s->server;		p->layer[i+1].flags|=FLAG_TCP_2SVR;	}else{		snd=&s->server;		rcv=&s->client;		p->layer[i+1].flags&=(~FLAG_TCP_2SVR);	}	/* LRU: Move to front of LRU and hash collision chain */	tcp_lru_mtf(&lru, s);	tcp_hash_mtf(s);	/* Deal with a SYN/ACK */	if ( rcv->state==TCP_SYN_SENT ) {		/* fist check the ack field */		if ( tcph->flags.bits.ack ) {		 	/* if SND.UNA =< SEG.ACK =< SND.NXT			 * then ACK is acceptable */			if ( !(between(tp.ack, rcv->snd_una, rcv->snd_nxt)) ) {				return ret;			}			p->layer[i+1].flags|=FLAG_TCP_STATE|FLAG_TCP_SURE;		}		/* then check the rst flag */		if ( tcph->flags.bits.rst ) {			return 1;		}		if ( tcph->flags.bits.syn ) {			/* update the advertised window */			snd->rcv_wnd=tp.win;			/* update sequencing information */			snd->snd_una=tp.seq+1;			snd->snd_nxt=snd->snd_una+1;			rcv->isn=tp.seq;			rcv->rcv_nxt=tp.seq_end;			rcv->rcv_wup=tp.seq_end;			if ( tcph->flags.bits.ack )				rcv->snd_una=tp.ack;			/* client now sees servers initial options */			tcp_syn_options(&s->client, tcph, p->time.tv_sec);			/* Check whether to use window scaling */			if (!(rcv->flags&TF_WSCALE_OK && snd->flags&TF_WSCALE_OK)) {				rcv->scale=0;				snd->scale=0;			}			/* SYN|ACK: part 2 of connection handshake */			rcv->state=TCP_SYN_RECV;			snd->state=TCP_SYN_SENT;			transition(s, s->client.state, s->server.state);			tcp_tmo_del(s);			return ret;		}else goto no_checks;	}	/* First check the sequence number */	if ( !tcp_sequence(rcv, tp.seq, tp.seq_end) ) {		/* XXX: Don't alert here retransmits hit this */		return ret;	}no_checks:	/* rfc1323: H1. Apply PAWS checks first */	if ( rcv->flags&TF_TSTAMP_OK &&		(tp.saw_tstamp=tcp_fast_options(tcph, &tp.tsval)) ) {		/* TODO: Fix PAWS check, its buggy as fuck */		if ( (int32_t)(rcv->ts_recent - tp.tsval) > TCP_PAWS_WINDOW &&			p->time.tv_sec<rcv->ts_recent_stamp + TCP_PAWS_24DAYS ) {			alert(&tcpstream_gen, p, &alert_tcp3);			return ret;		}	}	/* Second, check the RST bit */	if ( tcph->flags.bits.rst ) {		p->layer[i+1].flags|=FLAG_TCP_STATE|FLAG_TCP_SURE;		dmesg(M_DEBUG,"TCP stream was reset");		return 1;	}	/* rfc1323: PAWS: update ts_recent */	if ( tp.saw_tstamp && !after(tp.seq,rcv->rcv_wup) ) {		if((int32_t)(tp.tsval - rcv->ts_recent) >= 0 ||		   p->time.tv_sec >= rcv->ts_recent_stamp + TCP_PAWS_24DAYS) {			rcv->ts_recent=tp.tsval;			rcv->ts_recent_stamp=p->time.tv_sec;		}	}	/* Third, check security and precendece (pfft) */	/* Fourth, check the SYN bit */	if ( tcph->flags.bits.syn && !before(tp.seq,rcv->rcv_nxt) ) {		alert(&tcpstream_gen, p, &alert_tcp1);		return 1;	}	/* we now know that this packet is in-state */	p->layer[i+1].flags|=FLAG_TCP_STATE|FLAG_TCP_SURE;	/* Scale the window */	tp.win<<=snd->scale;	/* Fifth, check the ack field */	if ( !tcph->flags.bits.ack ) goto no_ack;	switch(rcv->state) {	case TCP_SYN_SENT:		/* ACK: part 3 of connection handshake */		if ( rcv->snd_una <= tp.ack && tp.ack <= rcv->snd_nxt ) {			p->layer[i+1].flags|=FLAG_TCP_CT_EST;			tcp_established(snd,rcv,tp.seq,tp.ack,tp.win);			transition(s, TCP_ESTABLISHED, TCP_ESTABLISHED);		}		break;	case TCP_ESTABLISHED:		tcp_established(snd,rcv,tp.seq,tp.ack,tp.win);		rcv->rcv_nxt=tp.seq;		break;	case TCP_FIN_WAIT1:		tcp_established(snd,rcv,tp.seq,tp.ack,tp.win);		rcv->state=TCP_FIN_WAIT2;		snd->state=TCP_LAST_ACK;		transition(s, s->client.state, s->server.state);	case TCP_FIN_WAIT2:		break;	case TCP_CLOSE_WAIT:		tcp_established(snd,rcv,tp.seq,tp.ack,tp.win);		break;	case TCP_CLOSING:		tcp_established(snd,rcv,tp.seq,tp.ack,tp.win);		rcv->state=TCP_TIME_WAIT;		transition(s, s->client.state, s->server.state);		break;	case TCP_LAST_ACK:		rcv->state=0;		transition(s, s->client.state, s->server.state);		break;	default:		break;	}no_ack:	/* sixth check URG bit */	if ( !tcph->flags.bits.urg ) goto no_urg;	/* XXX: What does processing urgent/OOB data	 * actually buy us in terms of intrusion detection	 * capability? Need to look in to this... */no_urg:	/* seventh process the segment text */	/* We might not actually need to bother... */	if ( !tcp_reassemble ) goto no_data;	if ( !tp.len || !s->proto ) goto no_data;	/* There is data in the segment */	switch(rcv->state) {	case TCP_CLOSE_WAIT:	case TCP_CLOSING:	case TCP_LAST_ACK:	case TCP_TIME_WAIT:		alert(&tcpstream_gen, p, &alert_tcp2);		goto no_data;	}	tcpstream_data(s, rcv, tcph, &tp);no_data:	/* eighth, check the FIN bit */	if ( !tcph->flags.bits.fin ) goto no_fin;	/* XXX: Fin implies PSH */	rcv->rcv_nxt++;	switch(rcv->state) {	case TCP_SYN_RECV:	case TCP_ESTABLISHED:		rcv->state=TCP_CLOSE_WAIT;		snd->state=TCP_FIN_WAIT1;		transition(s, s->client.state, s->server.state);		break;	case TCP_FIN_WAIT1:		/* if fin has been acked do time_wait else closing */		rcv->state=TCP_TIME_WAIT;		transition(s, s->client.state, s->server.state);		break;	case TCP_FIN_WAIT2:		rcv->state=TCP_TIME_WAIT;		transition(s, s->client.state, s->server.state);		break;	case TCP_CLOSE_WAIT:	case TCP_CLOSING:	case TCP_LAST_ACK:	case TCP_TIME_WAIT:		/* Remain in the same state */		break;	default:		break;	}no_fin:	/* XXX: need to implement time_wait timer */	if ( (snd->state==TCP_TIME_WAIT && rcv->state==0) ||		(rcv->state==TCP_TIME_WAIT && snd->state==0) ) {		ret=1;	}else if ( rcv->state==0 && snd->state==TCP_SYN_SENT ) {		/* XXX: we reset the timeout on retransmissions */		if ( (tcph->flags.bits.syn) &&			!(tcph->flags.bits.ack) &&			!(tcph->flags.bits.rst)) {			tcp_tmo_del(s);			s->expire=tcp_jiffies(p)+TCP_TMO_SYN1;			tcp_tmo_add(&syn1, s);		}	}	return ret;}/* Process an ICMP error message during connection */void icmperr_process(struct packet *p, unsigned int l){	struct pkt_iphdr *outer_iph;	struct pkt_icmphdr *icmph;	struct pkt_iphdr *iph;	struct pkt_tcphdr *tcph;	struct tcp_session *s;	struct tcp_stream *snd,*rcv;	int to_server;	/* Get all the headers we need */	if ( l+2 >= p->llen ) return;	outer_iph=p->layer[l-1].h.ip;	icmph=p->layer[l].h.icmp;	iph=p->layer[l+1].h.ip;	tcph=p->layer[l+2].h.tcp;	/* Make sure the packet is cool */	if ( iph->protocol!=6 ) return;	if ( icmph->type != ICMP_DEST_UNREACH ) return;	if ( icmph->code == ICMP_FRAG_NEEDED ) return;	if ( icmph->code > NR_ICMP_UNREACH ) return;	/* Check the IP packet came from the endpoint	 * ( if necessary ) */	if ( icmph->code==ICMP_PROT_UNREACH ||		icmph->code==ICMP_PORT_UNREACH ) {		if ( iph->saddr!=outer_iph->daddr ) {			alert(&icmperr_gen, p, &alert_icmp1);			return;		}	}	/* Lookup our session */	if ( !(s=tcp_find(iph, tcph, &to_server)) ) {		/* XXX: Alert here? Seems to happen a lot... */		return;	}	/* Find out which side sent the offending packet */	if ( iph->daddr==s->c_addr ) {		snd=&s->server;		rcv=&s->client;	}else{		snd=&s->client;		rcv=&s->server;	}	/* Only reset opening connections */	if ( snd->state!=TCP_SYN_SENT && snd->state!=TCP_SYN_RECV ) {		alert(&icmperr_gen, p, &alert_icmp2);		return;	}	/* TODO: Check seq/ack numbers */	dmesg(M_DEBUG,"TCP reset by ICMP from %.8x", outer_iph->saddr);	tcp_free(s);}/* Do some basic sanity checks to decide whether to even * bother processing a given segment or not. */void tcpstream_process(struct packet *pkt, unsigned int i){	struct pkt_iphdr *iph=pkt->layer[i].h.ip;	struct layer *l=&pkt->layer[i+1];	struct tcp_session *s;	int ret=0;	l->flags|=FLAG_TCP_TRACK;	/* Ignore fragments */	if ( iph->frag_off & ipfmask )		goto nodecode;	/* Ignore bad IP checksums - ooh naughty! */	if ( !(pkt->layer[i].flags&FLAG_IP_CSUM) )		goto nodecode;	/* Ignore bad TCP checksums - bad boy! */	if ( !(l->flags&FLAG_TCP_CSUM) )		goto nodecode;	/* Ignore broadcast and multicast packets */	if ( (pkt->flags & (FP_MULTICAST|FP_BROADCAST)) ) {		tcp_broadcast++;		goto nodecode;	}	/* Ignore packets with TTLs lower than minttl */	if ( iph->ttl < tcp_minttl ) {		tcp_lowttl++;		goto nodecode;	}	/* Check we aren't in a icmp error message */	if ( i>0 && pkt->layer[i-1].proto==&icmp_p )		goto nodecode;	/* Actually do the state tracking */	ret=tcpstream_tcpseg(pkt, i);	/* Statistics counters */	if ( !(l->flags & FLAG_TCP_STATE) )		tcp_state_errs++;	tcp_packets++;	/* Have we actually been decoded? */	if ( !(s=l->session) || !s->proto )		goto nodecode;	/* Dispatch to protocol handler */	pkt->layer[pkt->llen].flags=0;	pkt->layer[pkt->llen].session=NULL;	pkt->layer[pkt->llen].proto=s->proto;	if ( s->proto->sdecode(pkt)<0 && !ret ) {		/* TODO: queue this packet for reassembly */		mesg(M_DEBUG, "queue");	}	goto done;nodecode:	if ( pkt->layer[pkt->llen].h.raw<pkt->end )		pkt->layer[pkt->llen++].proto=NULL;	dispatch(pkt);done:	if (ret) tcp_free(l->session);	tcp_tmo_check(pkt);	return;}/* Called before firestorm shuts down */void tcpstream_free(void){	mesg(M_INFO,"tcpstream: max_concurrent=%u num_active=%u",		max_concurrent, num_active);	if ( tcp_reassemble ) {		mesg(M_INFO,"tcpstream: max_flows=%u num_flows=%u",			max_flows, num_flows);	}	mesg(M_INFO,"tcpstream: %u state errors out of %u packets",	       tcp_state_errs, tcp_packets);	mesg(M_INFO,"tcpstream: %u broadcasts, %u ttl evasions, %u timeouts",		tcp_broadcast, tcp_lowttl, tcp_timeouts);	if ( tcp_hash )		free(tcp_hash);	if ( all_sessions )		free(all_sessions);}/* Initialise flow cache */int tcpstream_flow_init(void){	void *p,*n=NULL;	int i;	/* Pointless if not reassembling, or have	 * no application layer protocols with flow	 * capabilities... */	if ( !tcp_reassemble || !flow_len )		return 0;	/* not likely */	if ( flow_len < sizeof(void *) ) {		flow_len=sizeof(void *);	}	/* flows are 1 to 1 with streams, even in worst case */	if ( tcp_numflows > tcp_numstreams ) {		tcp_numflows=tcp_numstreams;		mesg(M_WARN, "tcpstream: num_flows>num_streams, duh");	}	if ( tcp_numflows < 256 ) {		mesg(M_WARN, "tcpstream: you may be at risk with "			"such a low num_flows value");	}	/* Allocate it */	if ( !(flow_cache=calloc(tcp_numflows, flow_len)) ) {		return -1;	}	/* Initialise it */	for(i=0; i<(tcp_numflows-1); ) {		p=(char *)flow_cache + (i*flow_len);		n=(char *)flow_cache + (++i*flow_len);		*(void **)p = n;	}	*(void **)n=NULL;	flow_next=flow_cache;	return 0;}/* Initialise based on user parameters */int tcpstream_init(char *args){	int i;	if ( tcp_stateful ) {		mesg(M_ERR,"tcpstream: Can't add tcpstream twice!");		return 0;	}	if ( args && args_parse(tcpstream_args, args, NULL)<=0 ) {		mesg(M_ERR,"tcpstream: parse error: %s", args);		return 0;	}	if ( tcp_minttl > 255 ) {		mesg(M_ERR,"tcpstream: minttl must be < 256");		return 0;	}	if ( tcp_numstreams < 32 ) {		mesg(M_WARN,"tcpstream: num_streams is stupidly "			"low, setting to 512");		tcp_numstreams=512;	}else if ( tcp_numstreams < 512 ) {		mesg(M_WARN,"tcpstream: num_streams is VERY low! "			"are you sure?!");	}	/* Select a size for the hash table such that	 * num_streams/hash_size is no larger than 128	 * and such that the minimum size is 512 */	for(tcp_hashsz=512;		tcp_numstreams/tcp_hashsz>128;		tcp_hashsz<<=1);	/* Make sure its always odd */	tcp_hashsz|=1;	/* Initialise data structures */	if ( !(all_sessions=calloc(tcp_numstreams,		sizeof(struct tcp_session))) ) {		goto oom;	}	if ( !(tcp_hash=calloc(tcp_hashsz,		sizeof(*tcp_hash))) ) {		free(all_sessions);		goto oom;	}	/* Initialise the slab-style allocator */	for(i=0; i<(tcp_numstreams-1); i++) {		all_sessions[i].next=&all_sessions[i+1];	}	all_sessions[i].next=NULL;	tcp_next=all_sessions;	/* Initialise state info */	if ( tcp_reassemble ) {		struct proto_child *pc;		for(pc=tcp_p.children; pc; pc=pc->next)		{			if ( pc->proto->state_len > flow_len )				flow_len = (size_t)pc->proto->state_len;		}	}	/* Initialise flow cache */	if ( tcpstream_flow_init() )		goto oom;	/* Print out some statistics */	mesg(M_INFO,"tcpstream: %u streams in %u buckets (%u KB)",		tcp_numstreams, tcp_hashsz,		(tcp_numstreams*sizeof(struct tcp_session))/1024);	mesg(M_INFO,"tcpstream: TCP stream reassembly is %s: %u flows",		tcp_reassemble ? "ENABLED" : "DISABLED",		tcp_reassemble ? tcp_numflows : 0);	tcp_stateful=1;	return 1;oom:	mesg(M_ERR,"tcpstream: calloc(): %s", get_err());	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -