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

📄 tcp_ipv4.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
 *	Send an ACK for a socket less packet (needed for time wait)  * *  FIXME: Does not echo timestamps yet. * *  Assumes that the caller did basic address and flag checks. */static void tcp_v4_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack, __u16 window){	struct tcphdr *th = skb->h.th;	struct tcphdr rth;	struct ip_reply_arg arg;	/* Swap the send and the receive. */	memset(&rth, 0, sizeof(struct tcphdr)); 	rth.dest = th->source;	rth.source = th->dest; 	rth.doff = sizeof(struct tcphdr)/4;	rth.seq = seq;	rth.ack_seq = ack; 	rth.ack = 1;	rth.window = htons(window);	memset(&arg, 0, sizeof arg); 	arg.iov[0].iov_base = (unsigned char *)&rth; 	arg.iov[0].iov_len  = sizeof rth;	arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, 				      skb->nh.iph->saddr, /*XXX*/				      sizeof(struct tcphdr),				      IPPROTO_TCP,				      0); 	arg.n_iov = 1;	arg.csumoffset = offsetof(struct tcphdr, check) / 2; 	ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth);	tcp_statistics.TcpOutSegs++;}#ifdef CONFIG_IP_TRANSPARENT_PROXY/*   Seems, I never wrote nothing more stupid.   I hope Gods will forgive me, but I cannot forgive myself 8)                                                --ANK (981001) */static struct sock *tcp_v4_search_proxy_openreq(struct sk_buff *skb){	struct iphdr *iph = skb->nh.iph;	struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4);	struct sock *sk;	int i;	for (i=0; i<TCP_LHTABLE_SIZE; i++) {		for(sk = tcp_listening_hash[i]; sk; sk = sk->next) {			struct open_request *dummy;			if (tcp_v4_search_req(&sk->tp_pinfo.af_tcp, iph,					      th, &dummy) &&			    (!sk->bound_dev_if ||			     sk->bound_dev_if == skb->dev->ifindex))				return sk;		}	}	return NULL;}/* *	Check whether a received TCP packet might be for one of our *	connections. */int tcp_chkaddr(struct sk_buff *skb){	struct iphdr *iph = skb->nh.iph;	struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4);	struct sock *sk;	sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr,			   th->dest, skb->dev->ifindex);	if (!sk)		return tcp_v4_search_proxy_openreq(skb) != NULL;	if (sk->state == TCP_LISTEN) {		struct open_request *dummy;		if (tcp_v4_search_req(&sk->tp_pinfo.af_tcp, skb->nh.iph,				      th, &dummy) &&		    (!sk->bound_dev_if ||		     sk->bound_dev_if == skb->dev->ifindex))			return 1;	}	/* 0 means accept all LOCAL addresses here, not all the world... */	if (sk->rcv_saddr == 0)		return 0;	return 1;}#endif/* *	Send a SYN-ACK after having received an ACK.  *	This still operates on a open_request only, not on a big *	socket. */ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req){	struct rtable *rt;	struct ip_options *opt;	struct sk_buff * skb;	int mss;	/* First, grab a route. */	opt = req->af.v4_req.opt;	if(ip_route_output(&rt, ((opt && opt->srr) ?				 opt->faddr :				 req->af.v4_req.rmt_addr),			   req->af.v4_req.loc_addr,			   RT_TOS(sk->ip_tos) | RTO_CONN | sk->localroute,			   sk->bound_dev_if)) {		ip_statistics.IpOutNoRoutes++;		return;	}	if(opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) {		ip_rt_put(rt);		ip_statistics.IpOutNoRoutes++;		return;	}	mss = rt->u.dst.pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr);	skb = tcp_make_synack(sk, &rt->u.dst, req, mss);	if (skb) {		struct tcphdr *th = skb->h.th;#ifdef CONFIG_IP_TRANSPARENT_PROXY		th->source = req->lcl_port; /* LVE */#endif		th->check = tcp_v4_check(th, skb->len,					 req->af.v4_req.loc_addr, req->af.v4_req.rmt_addr,					 csum_partial((char *)th, skb->len, skb->csum));		ip_build_and_send_pkt(skb, sk, req->af.v4_req.loc_addr,				      req->af.v4_req.rmt_addr, req->af.v4_req.opt);	}	ip_rt_put(rt);}/* *	IPv4 open_request destructor. */ static void tcp_v4_or_free(struct open_request *req){	if(!req->sk && req->af.v4_req.opt)		kfree_s(req->af.v4_req.opt, optlength(req->af.v4_req.opt));}static inline void syn_flood_warning(struct sk_buff *skb){	static unsigned long warntime;		if (jiffies - warntime > HZ*60) {		warntime = jiffies;		printk(KERN_INFO 		       "possible SYN flooding on port %d. Sending cookies.\n",  		       ntohs(skb->h.th->dest));	}}/*  * Save and compile IPv4 options into the open_request if needed.  */static inline struct ip_options * tcp_v4_save_options(struct sock *sk, struct sk_buff *skb){	struct ip_options *opt = &(IPCB(skb)->opt);	struct ip_options *dopt = NULL; 	if (opt && opt->optlen) {		int opt_size = optlength(opt); 		dopt = kmalloc(opt_size, GFP_ATOMIC);		if (dopt) {			if (ip_options_echo(dopt, skb)) {				kfree_s(dopt, opt_size);				dopt = NULL;			}		}	}	return dopt;}/*  * Maximum number of SYN_RECV sockets in queue per LISTEN socket. * One SYN_RECV socket costs about 80bytes on a 32bit machine. * It would be better to replace it with a global counter for all sockets * but then some measure against one socket starving all other sockets * would be needed. */int sysctl_max_syn_backlog = 128; struct or_calltable or_ipv4 = {	tcp_v4_send_synack,	tcp_v4_or_free,	tcp_v4_send_reset};#define BACKLOG(sk) ((sk)->tp_pinfo.af_tcp.syn_backlog) /* lvalue! */#define BACKLOGMAX(sk) sysctl_max_syn_backlogint tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, __u32 isn){	struct tcp_opt tp;	struct open_request *req;	struct tcphdr *th = skb->h.th;	__u32 saddr = skb->nh.iph->saddr;	__u32 daddr = skb->nh.iph->daddr;#ifdef CONFIG_SYN_COOKIES	int want_cookie = 0;#else#define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */#endif	/* If the socket is dead, don't accept the connection.	*/	if (sk->dead) 		goto dead; 	/* Never answer to SYNs send to broadcast or multicast */	if (((struct rtable *)skb->dst)->rt_flags & 	    (RTCF_BROADCAST|RTCF_MULTICAST))		goto drop; 	/* XXX: Check against a global syn pool counter. */	if (BACKLOG(sk) > BACKLOGMAX(sk)) {#ifdef CONFIG_SYN_COOKIES		if (sysctl_tcp_syncookies) {			syn_flood_warning(skb);			want_cookie = 1; 		} else#endif		goto drop;	} else { 		if (isn == 0)			isn = tcp_v4_init_sequence(sk, skb);		BACKLOG(sk)++;	}	req = tcp_openreq_alloc();	if (req == NULL) {		goto dropbacklog;	}	req->rcv_wnd = 0;		/* So that tcp_send_synack() knows! */	req->rcv_isn = TCP_SKB_CB(skb)->seq; 	tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;	tp.mss_clamp = 65535;	tcp_parse_options(NULL, th, &tp, want_cookie);	if (tp.mss_clamp == 65535)		tp.mss_clamp = 576 - sizeof(struct iphdr) - sizeof(struct iphdr);	if (sk->tp_pinfo.af_tcp.user_mss && sk->tp_pinfo.af_tcp.user_mss < tp.mss_clamp)		tp.mss_clamp = sk->tp_pinfo.af_tcp.user_mss;	req->mss = tp.mss_clamp;	if (tp.saw_tstamp)		req->ts_recent = tp.rcv_tsval;	req->tstamp_ok = tp.tstamp_ok;	req->sack_ok = tp.sack_ok;	req->snd_wscale = tp.snd_wscale;	req->wscale_ok = tp.wscale_ok;	req->rmt_port = th->source;#ifdef CONFIG_IP_TRANSPARENT_PROXY	req->lcl_port = th->dest ; /* LVE */#endif	req->af.v4_req.loc_addr = daddr;	req->af.v4_req.rmt_addr = saddr;	/* Note that we ignore the isn passed from the TIME_WAIT	 * state here. That's the price we pay for cookies.	 */	if (want_cookie)		isn = cookie_v4_init_sequence(sk, skb, &req->mss);	req->snt_isn = isn;	req->af.v4_req.opt = tcp_v4_save_options(sk, skb);	req->class = &or_ipv4;	req->retrans = 0;	req->sk = NULL;	tcp_v4_send_synack(sk, req);	if (want_cookie) {		if (req->af.v4_req.opt)			kfree(req->af.v4_req.opt);		tcp_v4_or_free(req); 	   	tcp_openreq_free(req); 	} else {		req->expires = jiffies + TCP_TIMEOUT_INIT;		tcp_inc_slow_timer(TCP_SLT_SYNACK);		tcp_synq_queue(&sk->tp_pinfo.af_tcp, req);	}	return 0;dead:	SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n",sk);	tcp_statistics.TcpAttemptFails++;	return -ENOTCONN; /* send reset */dropbacklog:	if (!want_cookie) 		BACKLOG(sk)--;drop:	tcp_statistics.TcpAttemptFails++;	return 0;}/* This is not only more efficient than what we used to do, it eliminates * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM * * This function wants to be moved to a common for IPv[46] file. --ANK */struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, struct sk_buff *skb){	struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0);	if(newsk != NULL) {		struct tcp_opt *newtp;#ifdef CONFIG_FILTER		struct sk_filter *filter;#endif		memcpy(newsk, sk, sizeof(*newsk));		newsk->sklist_next = NULL;		newsk->state = TCP_SYN_RECV;		/* Clone the TCP header template */		newsk->dport = req->rmt_port;		atomic_set(&newsk->sock_readers, 0);		atomic_set(&newsk->rmem_alloc, 0);		skb_queue_head_init(&newsk->receive_queue);		atomic_set(&newsk->wmem_alloc, 0);		skb_queue_head_init(&newsk->write_queue);		atomic_set(&newsk->omem_alloc, 0);		newsk->done = 0;		newsk->proc = 0;		skb_queue_head_init(&newsk->back_log);		skb_queue_head_init(&newsk->error_queue);#ifdef CONFIG_FILTER		if ((filter = newsk->filter) != NULL)			sk_filter_charge(newsk, filter);#endif		/* Now setup tcp_opt */		newtp = &(newsk->tp_pinfo.af_tcp);		newtp->pred_flags = 0;		newtp->rcv_nxt = req->rcv_isn + 1;		newtp->snd_nxt = req->snt_isn + 1;		newtp->snd_una = req->snt_isn + 1;		newtp->srtt = 0;		newtp->ato = 0;		newtp->snd_wl1 = req->rcv_isn;		newtp->snd_wl2 = req->snt_isn;		/* RFC1323: The window in SYN & SYN/ACK segments		 * is never scaled.		 */		newtp->snd_wnd = ntohs(skb->h.th->window);		newtp->max_window = newtp->snd_wnd;		newtp->pending = 0;		newtp->retransmits = 0;		newtp->last_ack_sent = req->rcv_isn + 1;		newtp->backoff = 0;		newtp->mdev = TCP_TIMEOUT_INIT;		/* So many TCP implementations out there (incorrectly) count the		 * initial SYN frame in their delayed-ACK and congestion control		 * algorithms that we must have the following bandaid to talk		 * efficiently to them.  -DaveM		 */		newtp->snd_cwnd = 2;		newtp->rto = TCP_TIMEOUT_INIT;		newtp->packets_out = 0;		newtp->fackets_out = 0;		newtp->retrans_out = 0;		newtp->high_seq = 0;		newtp->snd_ssthresh = 0x7fffffff;		newtp->snd_cwnd_cnt = 0;		newtp->dup_acks = 0;		newtp->delayed_acks = 0;		init_timer(&newtp->retransmit_timer);		newtp->retransmit_timer.function = &tcp_retransmit_timer;		newtp->retransmit_timer.data = (unsigned long) newsk;		init_timer(&newtp->delack_timer);		newtp->delack_timer.function = &tcp_delack_timer;		newtp->delack_timer.data = (unsigned long) newsk;		skb_queue_head_init(&newtp->out_of_order_queue);		newtp->send_head = newtp->retrans_head = NULL;		newtp->rcv_wup = req->rcv_isn + 1;		newtp->write_seq = req->snt_isn + 1;		newtp->copied_seq = req->rcv_isn + 1;		newtp->saw_tstamp = 0;		newtp->mss_clamp = req->mss;		init_timer(&newtp->probe_timer);		newtp->probe_timer.function = &tcp_probe_timer;		newtp->probe_timer.data = (unsigned long) newsk;		newtp->probes_out = 0;		newtp->syn_seq = req->rcv_isn;		newtp->fin_seq = req->rcv_isn;		newtp->urg_data = 0;		tcp_synq_init(newtp);		newtp->syn_backlog = 0;		if (skb->len >= 536)			newtp->last_seg_size = skb->len; 		/* Back to base struct sock members. */		newsk->err = 0;		newsk->ack_backlog = 0;		newsk->max_ack_backlog = SOMAXCONN;		newsk->priority = 0;		/* IP layer stuff */		newsk->timeout = 0;		init_timer(&newsk->timer);		newsk->timer.function = &net_timer;		newsk->timer.data = (unsigned long) newsk;		newsk->socket = NULL;		newtp->tstamp_ok = req->tstamp_ok;		if((newtp->sack_ok = req->sack_ok) != 0)			newtp->num_sacks = 0;		newtp->window_clamp = req->window_clamp;		newtp->rcv_wnd = req->rcv_wnd;		newtp->wscale_ok = req->wscale_ok;		if (newtp->wscale_ok) {			newtp->snd_wscale = req->snd_wscale;			newtp->rcv_wscale = req->rcv_wscale;		} else {			newtp->snd_wscale = newtp->rcv_wscale = 0;			newtp->window_clamp = min(newtp->window_clamp,65535);		}		if (newtp->tstamp_ok) {			newtp->ts_recent = req->ts_recent;			newtp->ts_recent_stamp = tcp_time_stamp;			newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;		} else {			newtp->tcp_header_len = sizeof(struct tcphdr);		}	}	return newsk;}/*  * The three way handshake has completed - we got a valid synack -  * now create the new socket.  */struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,				   struct open_request *req,				   struct dst_entry *dst){	struct ip_options *opt = req->af.v4_req.opt;	struct tcp_opt *newtp;	struct sock *newsk;	if (sk->ack_backlog > sk->max_ack_backlog)		goto exit; /* head drop */	if (dst == NULL) { 		struct rtable *rt;				if (ip_route_output(&rt,			opt && opt->srr ? opt->faddr : req->af.v4_req.rmt_addr,			req->af.v4_req.loc_addr, sk->ip_tos|RTO_CONN, 0))			return NULL;	        dst = &rt->u.dst;	}#ifdef CONFIG_IP_TRANSPARENT_PROXY	/* The new socket created for transparent proxy may fall	 * into a non-existed bind bucket because sk->num != newsk->num.	 * Ensure existance of the bucket now. The placement of the check	 * later will require to destroy just created newsk in the case of fail.	 * 1998/04/22 Andrey V. Savochkin <saw@msu.ru>	 */	if (__tcp_bucket_check(ntohs(skb->h.th->dest)))		goto exit;#endif	newsk = tcp_create_openreq_child(sk, req, skb);	if (!newsk) 		goto exit;	sk->tp_pinfo.af_tcp.syn_backlog--;	sk->ack_backlog++;	newsk->dst_cache = dst;	newtp = &(newsk->tp_pinfo.af_tcp);	newsk->daddr = req->af.v4_req.rmt_addr;	newsk->saddr = req->af.v4_req.loc_addr;	newsk->rcv_saddr = req->af.v4_req.loc_addr;

⌨️ 快捷键说明

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