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

📄 ip_conntrack_proto_tcp.c

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 C
📖 第 1 页 / 共 3 页
字号:
      I. 	Upper bound for valid data:	seq + len <= sender.td_maxend   II. 	Lower bound for valid data:	seq >= sender.td_end - receiver.td_maxwin   III.	Upper bound for valid ack:      sack <= receiver.td_end   IV.	Lower bound for valid ack:	ack >= receiver.td_end - MAXACKWINDOW   	   where sack is the highest right edge of sack block found in the packet.   	   The upper bound limit for a valid ack is not ignored -    we doesn't have to deal with fragments. */static inline __u32 segment_seq_plus_len(__u32 seq,					 size_t len,					 struct iphdr *iph,					 struct tcphdr *tcph)  {	return (seq + len - (iph->ihl + tcph->doff)*4		+ (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0));}  /* Fixme: what about big packets? */#define MAXACKWINCONST			66000#define MAXACKWINDOW(sender)						\	((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin	\					      : MAXACKWINCONST)  /* * Simplified tcp_parse_options routine from tcp_input.c */static void tcp_options(const struct sk_buff *skb,			struct iphdr *iph,			struct tcphdr *tcph, 			struct ip_ct_tcp_state *state){	unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];	unsigned char *ptr;	int length = (tcph->doff*4) - sizeof(struct tcphdr);		if (!length)		return;	ptr = skb_header_pointer(skb,				 (iph->ihl * 4) + sizeof(struct tcphdr),				 length, buff);	BUG_ON(ptr == NULL);	state->td_scale = 	state->flags = 0;		while (length > 0) {		int opcode=*ptr++;		int opsize;				switch (opcode) {		case TCPOPT_EOL:			return;		case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */			length--;			continue;		default:			opsize=*ptr++;			if (opsize < 2) /* "silly options" */				return;			if (opsize > length)				break;	/* don't parse partial options */			if (opcode == TCPOPT_SACK_PERM 			    && opsize == TCPOLEN_SACK_PERM)				state->flags |= IP_CT_TCP_FLAG_SACK_PERM;			else if (opcode == TCPOPT_WINDOW				 && opsize == TCPOLEN_WINDOW) {				state->td_scale = *(u_int8_t *)ptr;								if (state->td_scale > 14) {					/* See RFC1323 */					state->td_scale = 14;				}				state->flags |=					IP_CT_TCP_FLAG_WINDOW_SCALE;			}			ptr += opsize - 2;			length -= opsize;		}	}}static void tcp_sack(struct tcphdr *tcph, __u32 *sack){	__u32 tmp;	unsigned char *ptr;	int length = (tcph->doff*4) - sizeof(struct tcphdr);		/* Fast path for timestamp-only option */	if (length == TCPOLEN_TSTAMP_ALIGNED*4	    && *(__u32 *)(tcph + 1) ==	        __constant_ntohl((TCPOPT_NOP << 24) 	        		 | (TCPOPT_NOP << 16)	        		 | (TCPOPT_TIMESTAMP << 8)	        		 | TCPOLEN_TIMESTAMP))		return;			ptr = (unsigned char *)(tcph + 1);	while (length > 0) {		int opcode=*ptr++;		int opsize, i;				switch (opcode) {		case TCPOPT_EOL:			return;		case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */			length--;			continue;		default:			opsize=*ptr++;			if (opsize < 2) /* "silly options" */				return;			if (opsize > length)				break;	/* don't parse partial options */			if (opcode == TCPOPT_SACK 			    && opsize >= (TCPOLEN_SACK_BASE 			    		  + TCPOLEN_SACK_PERBLOCK)			    && !((opsize - TCPOLEN_SACK_BASE) 			    	 % TCPOLEN_SACK_PERBLOCK)) {			    	for (i = 0;			    	     i < (opsize - TCPOLEN_SACK_BASE);			    	     i += TCPOLEN_SACK_PERBLOCK) {					tmp = ntohl(*((u_int32_t *)(ptr+i)+1));										if (after(tmp, *sack))						*sack = tmp;				}				return;			}			ptr += opsize - 2;			length -= opsize;		}	}}static int tcp_in_window(struct ip_ct_tcp *state,                          enum ip_conntrack_dir dir,                         unsigned int *index,                         const struct sk_buff *skb,                         struct iphdr *iph,                         struct tcphdr *tcph){	struct ip_ct_tcp_state *sender = &state->seen[dir];	struct ip_ct_tcp_state *receiver = &state->seen[!dir];	__u32 seq, ack, sack, end, win, swin;	int res;		/*	 * Get the required data from the packet.	 */	seq = ntohl(tcph->seq);	ack = sack = ntohl(tcph->ack_seq);	win = ntohs(tcph->window);	end = segment_seq_plus_len(seq, skb->len, iph, tcph);		if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM)		tcp_sack(tcph, &sack);			DEBUGP("tcp_in_window: START\n");	DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "	       "seq=%u ack=%u sack=%u win=%u end=%u\n",		NIPQUAD(iph->saddr), ntohs(tcph->source), 		NIPQUAD(iph->daddr), ntohs(tcph->dest),		seq, ack, sack, win, end);	DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",		sender->td_end, sender->td_maxend, sender->td_maxwin,		sender->td_scale, 		receiver->td_end, receiver->td_maxend, receiver->td_maxwin, 		receiver->td_scale);			if (sender->td_end == 0) {		/*		 * Initialize sender data.		 */		if (tcph->syn && tcph->ack) {			/*			 * Outgoing SYN-ACK in reply to a SYN.			 */			sender->td_end = 			sender->td_maxend = end;			sender->td_maxwin = (win == 0 ? 1 : win);			tcp_options(skb, iph, tcph, sender);			/* 			 * RFC 1323:			 * Both sides must send the Window Scale option			 * to enable window scaling in either direction.			 */			if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE			      && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE))				sender->td_scale = 				receiver->td_scale = 0;		} else {			/*			 * We are in the middle of a connection,			 * its history is lost for us.			 * Let's try to use the data from the packet.		 	 */			sender->td_end = end;			sender->td_maxwin = (win == 0 ? 1 : win);			sender->td_maxend = end + sender->td_maxwin;		}	} else if (((state->state == TCP_CONNTRACK_SYN_SENT		     && dir == IP_CT_DIR_ORIGINAL)		    || (state->state == TCP_CONNTRACK_SYN_RECV		        && dir == IP_CT_DIR_REPLY))		    && after(end, sender->td_end)) {		/*		 * RFC 793: "if a TCP is reinitialized ... then it need		 * not wait at all; it must only be sure to use sequence 		 * numbers larger than those recently used."		 */		sender->td_end =		sender->td_maxend = end;		sender->td_maxwin = (win == 0 ? 1 : win);		tcp_options(skb, iph, tcph, sender);	}		if (!(tcph->ack)) {		/*		 * If there is no ACK, just pretend it was set and OK.		 */		ack = sack = receiver->td_end;	} else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) == 		    (TCP_FLAG_ACK|TCP_FLAG_RST)) 		   && (ack == 0)) {		/*		 * Broken TCP stacks, that set ACK in RST packets as well		 * with zero ack value.		 */		ack = sack = receiver->td_end;	}	if (seq == end)		/*		 * Packets contains no data: we assume it is valid		 * and check the ack value only.		 */		seq = end = sender->td_end;			DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "	       "seq=%u ack=%u sack =%u win=%u end=%u trim=%u\n",		NIPQUAD(iph->saddr), ntohs(tcph->source),		NIPQUAD(iph->daddr), ntohs(tcph->dest),		seq, ack, sack, win, end, 		after(end, sender->td_maxend) && before(seq, sender->td_maxend)		? sender->td_maxend : end);	DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",		sender->td_end, sender->td_maxend, sender->td_maxwin,		sender->td_scale, 		receiver->td_end, receiver->td_maxend, receiver->td_maxwin,		receiver->td_scale);		/* Ignore data over the right edge of the receiver's window. */	if (after(end, sender->td_maxend) &&	    before(seq, sender->td_maxend)) {		end = sender->td_maxend;		if (*index == TCP_FIN_SET)			*index = TCP_ACK_SET;	}	DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n",		before(end, sender->td_maxend + 1) 		    || before(seq, sender->td_maxend + 1),	    	after(seq, sender->td_end - receiver->td_maxwin - 1) 	    	    || after(end, sender->td_end - receiver->td_maxwin - 1),	    	before(sack, receiver->td_end + 1),	    	after(ack, receiver->td_end - MAXACKWINDOW(sender)));		if (sender->loose || receiver->loose ||	    (before(end, sender->td_maxend + 1) &&	     after(seq, sender->td_end - receiver->td_maxwin - 1) &&	     before(sack, receiver->td_end + 1) &&	     after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {	    	/*		 * Take into account window scaling (RFC 1323).		 */		if (!tcph->syn)			win <<= sender->td_scale;				/*		 * Update sender data.		 */		swin = win + (sack - ack);		if (sender->td_maxwin < swin)			sender->td_maxwin = swin;		if (after(end, sender->td_end))			sender->td_end = end;		if (after(sack + win, receiver->td_maxend - 1)) {			receiver->td_maxend = sack + win;			if (win == 0)				receiver->td_maxend++;		}		/* 		 * Check retransmissions.		 */		if (*index == TCP_ACK_SET) {			if (state->last_dir == dir			    && state->last_seq == seq			    && state->last_ack == ack			    && state->last_end == end)				state->retrans++;			else {				state->last_dir = dir;				state->last_seq = seq;				state->last_ack = ack;				state->last_end = end;				state->retrans = 0;			}		}		/*		 * Close the window of disabled window tracking :-)		 */		if (sender->loose)			sender->loose--;				res = 1;	} else {		if (LOG_INVALID(IPPROTO_TCP))			nf_log_packet(PF_INET, 0, skb, NULL, NULL,			"ip_ct_tcp: %s ",			before(end, sender->td_maxend + 1) ?			after(seq, sender->td_end - receiver->td_maxwin - 1) ?			before(sack, receiver->td_end + 1) ?			after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG"			: "ACK is under the lower bound (possibly overly delayed ACK)"			: "ACK is over the upper bound (ACKed data has never seen yet)"			: "SEQ is under the lower bound (retransmitted already ACKed data)"			: "SEQ is over the upper bound (over the window of the receiver)");		res = ip_ct_tcp_be_liberal && !tcph->rst;  	}  	DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "	       "receiver end=%u maxend=%u maxwin=%u\n",		res, sender->td_end, sender->td_maxend, sender->td_maxwin, 		receiver->td_end, receiver->td_maxend, receiver->td_maxwin);	return res;}#ifdef CONFIG_IP_NF_NAT_NEEDED/* Update sender->td_end after NAT successfully mangled the packet */void ip_conntrack_tcp_update(struct sk_buff *skb,			     struct ip_conntrack *conntrack, 			     enum ip_conntrack_dir dir){	struct iphdr *iph = skb->nh.iph;	struct tcphdr *tcph = (void *)skb->nh.iph + skb->nh.iph->ihl*4;	__u32 end;

⌨️ 快捷键说明

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