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

📄 ip_conntrack_proto_tcp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir];	struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir];#endif	end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, iph, tcph);		write_lock_bh(&tcp_lock);	/*	 * We have to worry for the ack in the reply packet only...	 */	if (after(end, conntrack->proto.tcp.seen[dir].td_end))		conntrack->proto.tcp.seen[dir].td_end = end;	conntrack->proto.tcp.last_end = end;	write_unlock_bh(&tcp_lock);	DEBUGP("tcp_update: 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);} #endif#define	TH_FIN	0x01#define	TH_SYN	0x02#define	TH_RST	0x04#define	TH_PUSH	0x08#define	TH_ACK	0x10#define	TH_URG	0x20#define	TH_ECE	0x40#define	TH_CWR	0x80/* table of valid flag combinations - ECE and CWR are always valid */static const u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] ={	[TH_SYN]			= 1,	[TH_SYN|TH_ACK]			= 1,	[TH_SYN|TH_PUSH]		= 1,	[TH_SYN|TH_ACK|TH_PUSH]		= 1,	[TH_RST]			= 1,	[TH_RST|TH_ACK]			= 1,	[TH_RST|TH_ACK|TH_PUSH]		= 1,	[TH_FIN|TH_ACK]			= 1,	[TH_ACK]			= 1,	[TH_ACK|TH_PUSH]		= 1,	[TH_ACK|TH_URG]			= 1,	[TH_ACK|TH_URG|TH_PUSH]		= 1,	[TH_FIN|TH_ACK|TH_PUSH]		= 1,	[TH_FIN|TH_ACK|TH_URG]		= 1,	[TH_FIN|TH_ACK|TH_URG|TH_PUSH]	= 1,};/* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c.  */static int tcp_error(struct sk_buff *skb,		     enum ip_conntrack_info *ctinfo,		     unsigned int hooknum){	struct iphdr *iph = skb->nh.iph;	struct tcphdr _tcph, *th;	unsigned int tcplen = skb->len - iph->ihl * 4;	u_int8_t tcpflags;	/* Smaller that minimal TCP header? */	th = skb_header_pointer(skb, iph->ihl * 4,				sizeof(_tcph), &_tcph);	if (th == NULL) {		if (LOG_INVALID(IPPROTO_TCP))			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,				"ip_ct_tcp: short packet ");		return -NF_ACCEPT;  	}  	/* Not whole TCP header or malformed packet */	if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {		if (LOG_INVALID(IPPROTO_TCP))			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,				"ip_ct_tcp: truncated/malformed packet ");		return -NF_ACCEPT;	}  	/* Checksum invalid? Ignore.	 * We skip checking packets on the outgoing path	 * because the semantic of CHECKSUM_HW is different there 	 * and moreover root might send raw packets.	 */	/* FIXME: Source route IP option packets --RR */	if (hooknum == NF_IP_PRE_ROUTING	    && skb->ip_summed != CHECKSUM_UNNECESSARY	    && csum_tcpudp_magic(iph->saddr, iph->daddr, tcplen, IPPROTO_TCP,			         skb->ip_summed == CHECKSUM_HW ? skb->csum			      	 : skb_checksum(skb, iph->ihl*4, tcplen, 0))) {		if (LOG_INVALID(IPPROTO_TCP))			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,				  "ip_ct_tcp: bad TCP checksum ");		return -NF_ACCEPT;	}	/* Check TCP flags. */	tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR));	if (!tcp_valid_flags[tcpflags]) {		if (LOG_INVALID(IPPROTO_TCP))			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,				  "ip_ct_tcp: invalid TCP flag combination ");		return -NF_ACCEPT;	}	return NF_ACCEPT;}/* Returns verdict for packet, or -1 for invalid. */static int tcp_packet(struct ip_conntrack *conntrack,		      const struct sk_buff *skb,		      enum ip_conntrack_info ctinfo){	enum tcp_conntrack new_state, old_state;	enum ip_conntrack_dir dir;	struct iphdr *iph = skb->nh.iph;	struct tcphdr *th, _tcph;	unsigned long timeout;	unsigned int index;		th = skb_header_pointer(skb, iph->ihl * 4,				sizeof(_tcph), &_tcph);	BUG_ON(th == NULL);		write_lock_bh(&tcp_lock);	old_state = conntrack->proto.tcp.state;	dir = CTINFO2DIR(ctinfo);	index = get_conntrack_index(th);	new_state = tcp_conntracks[dir][index][old_state];	switch (new_state) {	case TCP_CONNTRACK_IGNORE:		/* Ignored packets:		 * 		 * a) SYN in ORIGINAL		 * b) SYN/ACK in REPLY		 * c) ACK in reply direction after initial SYN in original.		 */		if (index == TCP_SYNACK_SET		    && conntrack->proto.tcp.last_index == TCP_SYN_SET		    && conntrack->proto.tcp.last_dir != dir		    && ntohl(th->ack_seq) ==		    	     conntrack->proto.tcp.last_end) {			/* This SYN/ACK acknowledges a SYN that we earlier 			 * ignored as invalid. This means that the client and			 * the server are both in sync, while the firewall is			 * not. We kill this session and block the SYN/ACK so			 * that the client cannot but retransmit its SYN and 			 * thus initiate a clean new session.			 */		    	write_unlock_bh(&tcp_lock);			if (LOG_INVALID(IPPROTO_TCP))				nf_log_packet(PF_INET, 0, skb, NULL, NULL,					      NULL, "ip_ct_tcp: "					      "killing out of sync session ");		    	if (del_timer(&conntrack->timeout))		    		conntrack->timeout.function((unsigned long)		    					    conntrack);		    	return -NF_DROP;		}		conntrack->proto.tcp.last_index = index;		conntrack->proto.tcp.last_dir = dir;		conntrack->proto.tcp.last_seq = ntohl(th->seq);		conntrack->proto.tcp.last_end = 		    segment_seq_plus_len(ntohl(th->seq), skb->len, iph, th);				write_unlock_bh(&tcp_lock);		if (LOG_INVALID(IPPROTO_TCP))			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,				  "ip_ct_tcp: invalid packet ignored ");		return NF_ACCEPT;	case TCP_CONNTRACK_MAX:		/* Invalid packet */		DEBUGP("ip_ct_tcp: Invalid dir=%i index=%u ostate=%u\n",		       dir, get_conntrack_index(th),		       old_state);		write_unlock_bh(&tcp_lock);		if (LOG_INVALID(IPPROTO_TCP))			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,				  "ip_ct_tcp: invalid state ");		return -NF_ACCEPT;	case TCP_CONNTRACK_SYN_SENT:		if (old_state < TCP_CONNTRACK_TIME_WAIT)			break;		if ((conntrack->proto.tcp.seen[dir].flags &		         IP_CT_TCP_FLAG_CLOSE_INIT)		    || after(ntohl(th->seq),		    	     conntrack->proto.tcp.seen[dir].td_end)) {			    	/* Attempt to reopen a closed connection.		    	* Delete this connection and look up again. */		    	write_unlock_bh(&tcp_lock);		    	if (del_timer(&conntrack->timeout))		    		conntrack->timeout.function((unsigned long)		    					    conntrack);		    	return -NF_REPEAT;		} else {			write_unlock_bh(&tcp_lock);			if (LOG_INVALID(IPPROTO_TCP))				nf_log_packet(PF_INET, 0, skb, NULL, NULL,					      NULL, "ip_ct_tcp: invalid SYN");			return -NF_ACCEPT;		}	case TCP_CONNTRACK_CLOSE:		if (index == TCP_RST_SET		    && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)		         && conntrack->proto.tcp.last_index == TCP_SYN_SET)		        || (!test_bit(IPS_ASSURED_BIT, &conntrack->status)		            && conntrack->proto.tcp.last_index == TCP_ACK_SET))		    && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) {			/* RST sent to invalid SYN or ACK we had let trough			 * at a) and c) above:			 *			 * a) SYN was in window then			 * c) we hold a half-open connection.			 *			 * Delete our connection entry.			 * We skip window checking, because packet might ACK			 * segments we ignored. */			goto in_window;		}		/* Just fall trough */	default:		/* Keep compilers happy. */		break;	}	if (!tcp_in_window(&conntrack->proto.tcp, dir, index, 			   skb, iph, th)) {		write_unlock_bh(&tcp_lock);		return -NF_ACCEPT;	}    in_window:	/* From now on we have got in-window packets */		conntrack->proto.tcp.last_index = index;	DEBUGP("tcp_conntracks: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "	       "syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n",		NIPQUAD(iph->saddr), ntohs(th->source),		NIPQUAD(iph->daddr), ntohs(th->dest),		(th->syn ? 1 : 0), (th->ack ? 1 : 0),		(th->fin ? 1 : 0), (th->rst ? 1 : 0),		old_state, new_state);	conntrack->proto.tcp.state = new_state;	if (old_state != new_state 	    && (new_state == TCP_CONNTRACK_FIN_WAIT	    	|| new_state == TCP_CONNTRACK_CLOSE))		conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;	timeout = conntrack->proto.tcp.retrans >= ip_ct_tcp_max_retrans		  && *tcp_timeouts[new_state] > ip_ct_tcp_timeout_max_retrans		  ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];	write_unlock_bh(&tcp_lock);	ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);	if (new_state != old_state)		ip_conntrack_event_cache(IPCT_PROTOINFO, skb);	if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {		/* If only reply is a RST, we can consider ourselves not to		   have an established connection: this is a fairly common		   problem case, so we can delete the conntrack		   immediately.  --RR */		if (th->rst) {			if (del_timer(&conntrack->timeout))				conntrack->timeout.function((unsigned long)							    conntrack);			return NF_ACCEPT;		}	} else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)		   && (old_state == TCP_CONNTRACK_SYN_RECV		       || old_state == TCP_CONNTRACK_ESTABLISHED)		   && new_state == TCP_CONNTRACK_ESTABLISHED) {		/* Set ASSURED if we see see valid ack in ESTABLISHED 		   after SYN_RECV or a valid answer for a picked up 		   connection. */		set_bit(IPS_ASSURED_BIT, &conntrack->status);		ip_conntrack_event_cache(IPCT_STATUS, skb);	}	ip_ct_refresh_acct(conntrack, ctinfo, skb, timeout);	return NF_ACCEPT;} /* Called when a new connection for this protocol found. */static int tcp_new(struct ip_conntrack *conntrack,		   const struct sk_buff *skb){	enum tcp_conntrack new_state;	struct iphdr *iph = skb->nh.iph;	struct tcphdr *th, _tcph;#ifdef DEBUGP_VARS	struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0];	struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1];#endif	th = skb_header_pointer(skb, iph->ihl * 4,				sizeof(_tcph), &_tcph);	BUG_ON(th == NULL);		/* Don't need lock here: this conntrack not in circulation yet */	new_state		= tcp_conntracks[0][get_conntrack_index(th)]		[TCP_CONNTRACK_NONE];	/* Invalid: delete conntrack */	if (new_state >= TCP_CONNTRACK_MAX) {		DEBUGP("ip_ct_tcp: invalid new deleting.\n");		return 0;	}	if (new_state == TCP_CONNTRACK_SYN_SENT) {		/* SYN packet */		conntrack->proto.tcp.seen[0].td_end =			segment_seq_plus_len(ntohl(th->seq), skb->len,					     iph, th);		conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);		if (conntrack->proto.tcp.seen[0].td_maxwin == 0)			conntrack->proto.tcp.seen[0].td_maxwin = 1;		conntrack->proto.tcp.seen[0].td_maxend =			conntrack->proto.tcp.seen[0].td_end;		tcp_options(skb, iph, th, &conntrack->proto.tcp.seen[0]);		conntrack->proto.tcp.seen[1].flags = 0;		conntrack->proto.tcp.seen[0].loose = 		conntrack->proto.tcp.seen[1].loose = 0;	} else if (ip_ct_tcp_loose == 0) {		/* Don't try to pick up connections. */		return 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.		 */		conntrack->proto.tcp.seen[0].td_end =			segment_seq_plus_len(ntohl(th->seq), skb->len,					     iph, th);		conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);		if (conntrack->proto.tcp.seen[0].td_maxwin == 0)			conntrack->proto.tcp.seen[0].td_maxwin = 1;		conntrack->proto.tcp.seen[0].td_maxend =			conntrack->proto.tcp.seen[0].td_end + 			conntrack->proto.tcp.seen[0].td_maxwin;		conntrack->proto.tcp.seen[0].td_scale = 0;		/* We assume SACK. Should we assume window scaling too? */		conntrack->proto.tcp.seen[0].flags =		conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM;		conntrack->proto.tcp.seen[0].loose = 		conntrack->proto.tcp.seen[1].loose = ip_ct_tcp_loose;	}    	conntrack->proto.tcp.seen[1].td_end = 0;	conntrack->proto.tcp.seen[1].td_maxend = 0;	conntrack->proto.tcp.seen[1].td_maxwin = 1;	conntrack->proto.tcp.seen[1].td_scale = 0;      	/* tcp_packet will set them */	conntrack->proto.tcp.state = TCP_CONNTRACK_NONE;	conntrack->proto.tcp.last_index = TCP_NONE_SET;	 	DEBUGP("tcp_new: 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);	return 1;}  struct ip_conntrack_protocol ip_conntrack_protocol_tcp ={	.proto 			= IPPROTO_TCP,	.name 			= "tcp",	.pkt_to_tuple 		= tcp_pkt_to_tuple,	.invert_tuple 		= tcp_invert_tuple,	.print_tuple 		= tcp_print_tuple,	.print_conntrack 	= tcp_print_conntrack,	.packet 		= tcp_packet,	.new 			= tcp_new,	.error			= tcp_error,#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)	.to_nfattr		= tcp_to_nfattr,	.from_nfattr		= nfattr_to_tcp,	.tuple_to_nfattr	= ip_ct_port_tuple_to_nfattr,	.nfattr_to_tuple	= ip_ct_port_nfattr_to_tuple,#endif};

⌨️ 快捷键说明

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