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

📄 ipfrag.c

📁 Firestorm NIDS是一个性能非常高的网络入侵检测系统 (NIDS)。目前
💻 C
字号:
/* * Copyright (c) Gianni Tedesco 2002. * Released under the terms of the GNU GPL v2 */#include "tcpip.h"/* * IP Defragmentation for firestorm * ================================ * * This code is a reworking of ip_fragment.c from Linux 2.4.18, * it should be relatively straight forward to understand. Its * pretty well tested. * * Should CORRECTLY cope with: *  Overlapping fragments *  Oversized fragments *  Out of order fragments *  Timed out packets * * TODO: *  Use more efficient search to insert fragments *  Detect ICMP_TIME_EXCEEDED/ICMP_EXC_FRAGTIME (?) *  Coalesce fragments in incomplete packets (??) */#if 1#define dmesg(x...)#define __INLINE__ static inline#else#define dmesg mesg#define __INLINE__ static#endifunsigned int use_ipfrag=0;/* Statistics */unsigned int ipfrag_err_reasm=0;unsigned int ipfrag_err_mem=0;unsigned int ipfrag_err_timeout=0;unsigned int ipfrag_reassembled=0;/* Generator */struct generator ipfrag_gen=init_generator("ipfrag", &ip_tb);/* Don't decode fragments inside fragments */serial_t last_frag;unsigned int first_frag=0;/* Memory usage, high and low water marks */unsigned int ipfrag_mem=0;unsigned int ipfrag_mem_hi=1024*1024;unsigned int ipfrag_mem_lo=768*1024;/* Timeout (in seconds) */unsigned int ipfrag_timeout=60;/* Don't decode fragments with too low ttl */unsigned int ipfrag_minttl=0;struct arg ipfrag_args[]={	{"minttl", ARGTYPE_PUINT,  NULL, {vp_uint:&ipfrag_minttl}},	{"timeout", ARGTYPE_PUINT, NULL, {vp_uint:&ipfrag_timeout}},	{"mem_hi", ARGTYPE_PBYTES, NULL, {vp_bytes:&ipfrag_mem_hi}},	{"mem_lo", ARGTYPE_PBYTES, NULL, {vp_bytes:&ipfrag_mem_lo}},	{NULL,ARGTYPE_NOP,NULL}};/* Reassembly */struct packet ipfr;char *reasm_buf=NULL;unsigned int reasm_len=0;struct ipq *ipq_latest=NULL;struct ipq *ipq_oldest=NULL;#define IPHASH 128 /* Must be a power of two */struct ipq *ipq_hash[IPHASH]; /* IP fragment hash table *//* Hash function for ipq_hash lookup */__INLINE__ unsigned int ipq_hashfn(u_int16_t id,	u_int32_t saddr,	u_int32_t daddr,	u_int8_t proto){	unsigned int h=saddr^daddr;	h ^= (h>>16)^id;	h ^= (h>>8)^proto;	return h & (IPHASH-1);}/* * Report ip fragmentation violations. */static void ipfrag_teardrop(struct packet *p){	static struct alert ta=init_alert("Teardrop", 1, 0, 5);	alert(&ipfrag_gen, p, &ta);}static void ipfrag_oversize(struct packet *p){	static struct alert ta=init_alert("Oversized fragments", 2, 0, 5);	alert(&ipfrag_gen, p, &ta);}static void ipfrag_attack(struct packet *p){	static struct alert ta=init_alert("Fragmentation attack", 3, 0, 5);	alert(&ipfrag_gen, p, &ta);}static void ipfrag_boink(struct packet *p){	static struct alert ta=init_alert("Boink", 4, 0, 5);	alert(&ipfrag_gen, p, &ta);}static void ipfrag_truncated(struct packet *p){	static struct alert ta=init_alert("Truncated fragment", 5, 0, 5);	alert(&ipfrag_gen, p, &ta);}static void ipfrag_fraginfrag(struct packet *p){	static struct alert ta=init_alert("Fragment in fragment", 6, 0, 5);	alert(&ipfrag_gen, p, &ta);}static void ipfrag_oom(struct packet *p){	static struct alert ta=init_alert("Too many fragments", 7, 0, 5);	alert(&ipfrag_gen, p, &ta);}static void ipfrag_timedout(struct packet *p){	static struct alert ta=init_alert("Fragment arrived after timeout", 8, 0, 5);	alert(&ipfrag_gen, p, &ta);}void ipq_kill(struct ipq *qp){	struct ipfrag *foo, *bar;	/* Unlink from the list */	if ( qp->next )		qp->next->pprev=qp->pprev;	*qp->pprev=qp->next;	/* Free the fragments and descriptors */	for(foo=qp->fragments; foo;) {		bar=foo;		foo=foo->next;		if ( bar->free ) {			free(bar->fdata);			ipfrag_mem-=bar->flen;		}		free(bar);		ipfrag_mem-=sizeof(struct ipfrag);	}	/* Remove from LRU queue */	if ( qp->next_time) qp->next_time->prev_time=qp->prev_time;	if ( qp->prev_time) qp->prev_time->next_time=qp->next_time;	if ( qp == ipq_oldest ) ipq_oldest=qp->prev_time;	if ( qp == ipq_latest ) ipq_latest=qp->next_time;	/* Free the ipq itself */	free(qp);	ipfrag_mem-=sizeof(struct ipq);}/* Create a checksum for the ip header. I don't know * why we bother really... */static void ipfrag_csum(struct pkt_iphdr *iph){	u_int16_t *tmp=(u_int16_t *)iph;	u_int32_t sum=0;	int i;	for(i=0; i<iph->ihl<<1; i++) {		/* ignore field 5, its the checksum ;) */		if ( i!=5 ) sum+=tmp[i];		if(sum & 0x80000000) {			sum = (sum & 0xffff) + (sum >> 16);		}	}	while(sum >> 16)		sum = (sum & 0xffff) + (sum >> 16);	iph->csum=(~sum) & 0xffff;}/* Reassemble a complete set of fragments, decode the * new packet, and send it back through the preprocessor * list, we won't touch it next time round */__INLINE__ void ipfrag_reassemble(struct ipq *qp){	struct ipfrag *f;	struct pkt_iphdr *iph;	unsigned int olen=qp->len;	unsigned int len=0;	char *buf;	/* Kill oversize packets */	if ( olen > 0xffff ) {		ipfrag_err_reasm++;		return;	}	if ( !qp->fragments ) {		ipfrag_err_reasm++;		return;	}	iph=qp->fragments->fdata;	olen+=iph->ihl<<2;	/* Allocate the frankenpacket buffer */	if ( reasm_buf ) {		char *tmp;		/* Expand the buffer if it's too small */		if ( olen > reasm_len ) {			if ( !(tmp=realloc(reasm_buf, olen)) ) {				olen=reasm_len;			}else{				reasm_buf=tmp;				reasm_len=qp->len;			}		}	}else{		if ( !(reasm_buf=malloc(olen)) ) {			dmesg(M_DEBUG,"ipfrag: reassemble error!");			ipfrag_err_reasm++;			return;		}		reasm_len=olen;	}	/* Copy all the fragments in to the new buffer */	dmesg(M_DEBUG,"Reassemble: %u bytes", olen);	buf=reasm_buf;	/* Do the header */	dmesg(M_DEBUG," * %u byte header", iph->ihl<<2);	memcpy(buf, qp->fragments->fdata, iph->ihl<<2);	buf+=iph->ihl<<2;	len+=iph->ihl<<2;	for(f=qp->fragments; f; f=f->next) {		dmesg(M_DEBUG," * %u bytes @ %u", f->len, f->offset);		memcpy(buf, f->data, f->len);		buf+=f->len;		len+=f->len;		if ( len >= olen ) break;	}	dmesg(M_DEBUG,"");	/* Build the packet */	ipfr.len=len;	ipfr.caplen=len;	ipfr.llen=0;	ipfr.layer[0].proto=&ipv4_p;	ipfr.layer[0].h.raw=reasm_buf;	ipfr.layer[0].flags=FLAG_IP_REASM|FLAG_IP_CSUM;	ipfr.layer[0].session=NULL;	ipfr.base=reasm_buf;	ipfr.end=ipfr.base+olen;	ipfr.capture=qp->cap;	ipfr.flags=(qp->flags & ~FP_LIVE) | FP_CLONE;	/* Fill in the timestamp	 * (time of last packet seen for this frag) */	ipfr.time.tv_sec=qp->time.tv_sec;	ipfr.time.tv_usec=qp->time.tv_usec;	/* Fixup the IP header */	ipfr.layer[0].h.ip->frag_off=0;	ipfr.layer[0].h.ip->tot_len=ntohs(len);	ipfrag_csum(ipfr.layer[0].h.ip);	/* Inject the packet back in to the flow */	ipfrag_reassembled++;	serial_number(&ipfr.serial);	ipfr.layer[0].proto->decode(&ipfr);	return;}__INLINE__ struct ipq *ip_frag_create(unsigned int hash, struct pkt_iphdr *iph){	struct ipq *q;	if ( !(q=calloc(1, sizeof(struct ipq))) ){		ipfrag_err_mem++;		return NULL;	}	ipfrag_mem+=sizeof(struct ipq);	q->id=iph->id;	q->saddr=iph->saddr;	q->daddr=iph->daddr;	q->protocol=iph->protocol;	if ( (q->next=ipq_hash[hash]) ) {		q->next->pprev=&q->next;	}	ipq_hash[hash]=q;	q->pprev=&ipq_hash[hash];	return q;}/* Find (or create) the ipq for this IP fragment */__INLINE__ struct ipq *ip_find(struct pkt_iphdr *iph,			       unsigned int *hash,			       struct packet *pkt){	struct ipq *qp;	*hash=ipq_hashfn(iph->id, iph->saddr,		iph->daddr, iph->protocol);	for(qp=ipq_hash[*hash]; qp; qp=qp->next) {		if ( qp->id == iph->id &&			qp->saddr == iph->saddr &&			qp->daddr == iph->daddr &&			qp->protocol == iph->protocol ) {			return qp;		}	}	qp=ip_frag_create(*hash, iph);	qp->time.tv_sec=pkt->time.tv_sec;	qp->time.tv_usec=pkt->time.tv_usec;	return qp;}/* If a fragment is too old then zap it */__INLINE__ int ipfrag_expire(struct packet *pkt, struct ipq *qp){	struct timeval diff;	diff.tv_sec=(pkt->time.tv_sec - qp->time.tv_sec);	diff.tv_usec=(1000000+pkt->time.tv_usec)-qp->time.tv_usec;	while(diff.tv_usec > 1000000) {		diff.tv_usec-=1000000;		diff.tv_sec++;	}	if ( diff.tv_sec >= ipfrag_timeout ) {		ipfrag_err_timeout++;		return 0;	}	return 1;}/* Trim down to low memory watermark */__INLINE__ void ip_evictor(struct packet *pkt, struct ipq *cq){	dmesg(M_DEBUG,"Running the ipfrag evictor!");	ipfrag_oom(pkt);	while ( (ipfrag_mem > ipfrag_mem_lo) ) {		if ( !ipq_oldest || ipq_oldest==cq) return;		ipfrag_err_mem++;		ipq_kill(ipq_oldest);	}}__INLINE__ int ipfrag_queue(	unsigned int hash,	struct ipq *qp,	struct packet *pkt,	struct pkt_iphdr *iph){	struct ipfrag *prev, *next, *me;	int flags, offset;	int ihl, end, len;	int chop=0;	/* Move to head of LRU list */	if ( qp->next_time) qp->next_time->prev_time=qp->prev_time;	if ( qp->prev_time) qp->prev_time->next_time=qp->next_time;	if ( qp == ipq_oldest ) ipq_oldest=qp->prev_time;	if ( qp == ipq_latest ) ipq_latest=qp->next_time;	qp->next_time=ipq_latest;	qp->prev_time=NULL;	if ( !ipq_oldest ) ipq_oldest=qp;	if ( ipq_latest ) ipq_latest->prev_time=qp;	ipq_latest=qp;	/* Check our timeout */	if ( !ipfrag_expire(pkt, qp) ) {		/* We alert if we actually see a fragment		 * arrive after the timeout because that		 * is suspicious (read: evasive) */		ipfrag_timedout(pkt);		ipq_kill(qp);		return 0;	}	/* Check other timeouts */	while ( ipq_oldest ){	       	if ( ipfrag_expire(pkt, ipq_oldest) ) break;		/* this can't kill qp from under us because		 * we already know we haven't timed out */		ipq_kill(ipq_oldest);	}	/* Move to front heuristic */	if ( qp->next )		qp->next->pprev=qp->pprev;	*qp->pprev=qp->next;	if ( (qp->next=ipq_hash[hash]) )		qp->next->pprev=&qp->next;	ipq_hash[hash]=qp;	qp->pprev=&ipq_hash[hash];	/* The time for the reassembled packet is equal	 * to the time of the last packet recieved. This	 * makes things sane in the sense that time won't	 * be seen to be going backwards by the higher layers!	 */	qp->time.tv_sec=pkt->time.tv_sec;	qp->time.tv_usec=pkt->time.tv_usec;	/* Kill off LRU ipqs, we are OOM */	if ( ipfrag_mem > ipfrag_mem_hi )		ip_evictor(pkt, qp);	/* Now we can get on with queueing the packet.. */	ihl=iph->ihl<<2;	len=ntohs(iph->tot_len);	if ( ((void *)iph)+len > pkt->end ) {		ipfrag_truncated(pkt);		return 1;	}	offset=ntohs(iph->frag_off);	flags=offset & ~IP_OFFMASK;	offset&=IP_OFFMASK;	offset<<=3; /* 8 byte granularity */	end = offset + len - ihl;	if ( (flags&IP_MF)==0 ) {		if ( end < qp->len ||			((qp->last_in & LAST_IN) && end!=qp->len)) {			ipfrag_teardrop(pkt);			return 1;		}		qp->last_in |= LAST_IN;		qp->len = end;	}else{		if ( end&7 ) {			/* Don't drop the packet stupid! Modern			 * stacks mask off 0x7 so if we ditch the			 * frag as invalid we could be evaded. */			ipfrag_boink(pkt);		}		/* Non-terminal fragments must be multiples of		 * 8 bytes so mask off low-order bits */		end &=~7;		if ( end > qp->len ) {			if (qp->last_in & LAST_IN) {				ipfrag_attack(pkt);				return 1;			}			qp->len=end;		}	}	if ( end==offset ) {		ipfrag_attack(pkt);		return 1;	}	/* Don't bother wasting any more resources	 * when we know the packet is oversize (invalid) */	if ( qp->len > 0xffff ) {		ipfrag_oversize(pkt);		return 1;	}	/* Insert data into fragment chain */	if ( !(me=calloc(1, sizeof(struct ipfrag))) ) return 1;	ipfrag_mem+=sizeof(struct ipfrag);	/* Find out where to insert this fragment in the list */	prev=NULL;	for(next=qp->fragments; next; next=next->next) {		if ( next->offset >= offset ) break;		prev=next;	}	/* Check we don't overlap the previous fragment */	if ( prev ) {		int i=(prev->offset + prev->len) - offset;		if ( i>0 ) {			offset += i;			chop=i;			len-=i;			if ( end <= offset ) {				ipfrag_attack(pkt);				return 1;			}		}	}	/* Make sure we don't overlap next packets */	while(next && next->offset < end) {		int i = end - next->offset;		if ( i < next->len ) {			/* Eat head of the next overlapped fragment			 * and leave the loop. The next ones cannot			 * overlap. */			next->offset+=i;			next->len-=i;			next->data+=i;			break;		}else{			struct ipfrag *free_it=next;			/* Old fragment is completely overriden			 * with new one. Drop it */			next=next->next;			if ( prev ){				prev->next=next;			}else{				qp->fragments=next;			}			qp->meat -= free_it->len;			free(free_it);			ipfrag_mem-=sizeof(struct ipfrag);		}	}	/* Make the fragment */	me->len=len-(chop);	me->offset=offset;	me->len-=ihl;	if ( offset ) {		chop=ihl;	}	/* IP defragmentation can be zerocopy */	if ( pkt->flags & FP_CLONE ) {		unsigned int alen=me->len;		if ( !offset ) alen+=ihl;		if ( !(me->fdata=malloc(alen)) ) {			free(me);			return 1;		}		ipfrag_mem+=alen;		memcpy(me->fdata, ((void *)iph)+chop, alen);		me->free=1;		me->flen=alen;	}else {		me->fdata=((void *)iph)+chop;		me->free=0;	}	me->data=me->fdata;	if ( !offset ) me->data+=ihl;	/* Insert the fragment */	me->next=next;	if ( prev ) {		prev->next=me;	}else{		qp->fragments=me;	}	/* Finish up */	qp->cap=pkt->capture;	qp->flags=pkt->flags;	qp->meat+=me->len;	if ( !offset ) qp->last_in |= FIRST_IN;	dmesg(M_DEBUG,"0x%x: got a fragment (%u/%u)",		(unsigned int)qp,		qp->meat, qp->len);	return 1;}void ipfrag_free(void){	mesg(M_INFO,"ipfrag: %u reassembled packets, "	       "%u reasm errors, %u timeouts",	       ipfrag_reassembled,	       ipfrag_err_reasm,	       ipfrag_err_timeout);	mesg(M_INFO,"ipfrag: %u times out of memory, %uKB still used",	       ipfrag_err_mem,	       ipfrag_mem/1024);}/* Preprocessor entry point */int ipfrag_process(struct packet *pkt, unsigned int i){	struct pkt_iphdr *iph;	unsigned int hash;	struct ipq *q;	iph=pkt->layer[i].h.ip;	/* Don't track fragments inside fragments	 * wait till they are reassembled. This also	 * catches the case where an ip fragment caused	 * an icmp error that also gets fragmented	 */	if ( first_frag && (pkt->serial==last_frag) ) {		ipfrag_fraginfrag(pkt);		return 0;	}	first_frag=1;	last_frag=pkt->serial;	/* Ignore badly checksummed packets */	if ( !(pkt->layer[i].flags&FLAG_IP_CSUM) )		return 0;	/* Ignore packets with ttl < min_ttl */	if ( iph->ttl < ipfrag_minttl )		return 0;	if ( (q=ip_find(iph, &hash, pkt)) ) {		pkt->layer[i].session=q;		if ( !ipfrag_queue(hash, q, pkt, iph) )			return 1;		if ( q->last_in == (FIRST_IN|LAST_IN) &&			q->meat == q->len ) {			ipfrag_reassemble(q);			return 1;		}	}	return 0;}int ipfrag_init(char *args){	if ( use_ipfrag ) {		mesg(M_ERR,"ipfrag: can't add ipfrag twice!");		return 0;	}	if ( args && args_parse(ipfrag_args, args, NULL)<=0 ) {		mesg(M_ERR,"ipfrag: parse error: %s", args);		return 0;	}	if ( ipfrag_mem_hi<=ipfrag_mem_lo ) {		mesg(M_ERR,"ipfrag: mem_hi must be bigger than mem_lo");		return 0;	}	if ( ipfrag_minttl>255 ) {		mesg(M_ERR,"ipfrag: minttl must be < 256");		return 0;	}	if ( ipfrag_timeout<10 || ipfrag_timeout>120 ) {		mesg(M_WARN,"ipfrag: timeout is unreasonable - "			"you will be vulnerable to attack!");	}	mesg(M_INFO,"ipfrag: mem_hi=%u mem_lo=%u "		"minttl=%u timeout=%us",		ipfrag_mem_hi, ipfrag_mem_lo,		ipfrag_minttl, ipfrag_timeout);	use_ipfrag=1;	return 1;}

⌨️ 快捷键说明

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