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

📄 ip_vs_core.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	unsigned short   len;	unsigned short	clen, csize;	struct ip_vs_conn *cp;	struct rtable *rt;			/* Route to the other host */	int    mtu;	if (skb_is_nonlinear(skb)) {		if (skb_linearize(skb, GFP_ATOMIC) != 0)			return NF_DROP;	}	iph = skb->nh.iph;	ip_send_check(iph);	icmph = (struct icmphdr *)((char *)iph + (iph->ihl << 2));	len = ntohs(iph->tot_len) - (iph->ihl<<2);	if (len < sizeof(struct icmphdr))		return NF_DROP;	IP_VS_DBG(12, "icmp in (%d,%d) %u.%u.%u.%u -> %u.%u.%u.%u\n",		  icmph->type, ntohs(icmp_id(icmph)),		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));	if ((icmph->type != ICMP_DEST_UNREACH) &&	    (icmph->type != ICMP_SOURCE_QUENCH) &&	    (icmph->type != ICMP_TIME_EXCEEDED))		return NF_ACCEPT;	/*	 * If we get here we have an ICMP error of one of the above 3 types	 * Now find the contained IP header	 */	clen = len - sizeof(struct icmphdr);	if (clen < sizeof(struct iphdr))		return NF_DROP;	ciph = (struct iphdr *) (icmph + 1);	csize = ciph->ihl << 2;	if (clen < csize)		return NF_DROP;	/* We are only interested ICMPs generated from TCP or UDP packets */	if (ciph->protocol != IPPROTO_UDP && ciph->protocol != IPPROTO_TCP)		return NF_ACCEPT;	/* Skip non-first embedded TCP/UDP fragments */	if (ciph->frag_off & __constant_htons(IP_OFFSET))		return NF_ACCEPT;	/* We need at least TCP/UDP ports here */	if (clen < csize + sizeof(struct udphdr))		return NF_DROP;	/* Ensure the checksum is correct */	if (ip_compute_csum((unsigned char *) icmph, len)) {		/* Failed checksum! */		IP_VS_ERR_RL("incoming ICMP: failed checksum from "			     "%d.%d.%d.%d!\n", NIPQUAD(iph->saddr));		return NF_DROP;	}	pptr = (__u16 *)&(((char *)ciph)[csize]);	IP_VS_DBG(11, "Handling incoming ICMP for "		  "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n",		  NIPQUAD(ciph->saddr), ntohs(pptr[0]),		  NIPQUAD(ciph->daddr), ntohs(pptr[1]));	/* This is pretty much what ip_vs_conn_in_get() does,	   except parameters are in the reverse order */	cp = ip_vs_conn_in_get(ciph->protocol,			       ciph->daddr, pptr[1],			       ciph->saddr, pptr[0]);	if (cp == NULL)		return NF_ACCEPT;	ip_vs_in_stats(cp, skb);	/* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be	   forwarded directly here, because there is no need to	   translate address/port back */	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {		int ret;		if (cp->packet_xmit)			ret = cp->packet_xmit(skb, cp);		else			ret = NF_ACCEPT;		atomic_inc(&cp->in_pkts);		ip_vs_conn_put(cp);		return ret;	}	/*	 * mangle and send the packet here	 */	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))		goto tx_error_icmp;	/* MTU checking */	mtu = rt->u.dst.pmtu;	if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) {		ip_rt_put(rt);		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));		IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n");		goto tx_error;	}	/* drop old route */	dst_release(skb->dst);	skb->dst = &rt->u.dst;	/* copy-on-write the packet before mangling it */	if (ip_vs_skb_cow(skb, rt->u.dst.dev->hard_header_len,			  &iph, (unsigned char**)&icmph)) {		ip_vs_conn_put(cp);		return NF_DROP;	}	ciph = (struct iphdr *) (icmph + 1);	pptr = (__u16 *)&(((char *)ciph)[csize]);	/* The ICMP packet for VS/NAT must be written to correct addresses	   before being forwarded to the right server */	/* First change the dest IP address, and recalc checksum */	iph->daddr = cp->daddr;	ip_send_check(iph);	/* Now change the *source* address in the contained IP */	ciph->saddr = cp->daddr;	ip_send_check(ciph);	/* the TCP/UDP source port - cannot redo check */	pptr[0] = cp->dport;	/* And finally the ICMP checksum */	icmph->checksum = 0;	icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);	skb->ip_summed = CHECKSUM_UNNECESSARY;	IP_VS_DBG(11, "Forwarding incoming ICMP to "		  "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n",		  NIPQUAD(ciph->saddr), ntohs(pptr[0]),		  NIPQUAD(ciph->daddr), ntohs(pptr[1]));#ifdef CONFIG_NETFILTER_DEBUG	skb->nf_debug = 1 << NF_IP_LOCAL_OUT;#endif /* CONFIG_NETFILTER_DEBUG */	ip_send(skb);	ip_vs_conn_put(cp);	return NF_STOLEN;  tx_error_icmp:	dst_link_failure(skb);  tx_error:	dev_kfree_skb(skb);	ip_vs_conn_put(cp);	return NF_STOLEN;}/* *	Check if it's for virtual services, look it up, *	and send it on its way... */static unsigned int ip_vs_in(unsigned int hooknum,			     struct sk_buff **skb_p,			     const struct net_device *in,			     const struct net_device *out,			     int (*okfn)(struct sk_buff *)){	struct sk_buff	*skb = *skb_p;	struct iphdr	*iph = skb->nh.iph;	union ip_vs_tphdr h;	struct ip_vs_conn *cp;	struct ip_vs_service *svc;	int ihl;	int ret;	/*	 *	Big tappo: only PACKET_HOST (nor loopback neither mcasts)	 *	... don't know why 1st test DOES NOT include 2nd (?)	 */	if (skb->pkt_type != PACKET_HOST || skb->dev == &loopback_dev) {		IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n",			  skb->pkt_type,			  iph->protocol,			  NIPQUAD(iph->daddr));		return NF_ACCEPT;	}	if (iph->protocol == IPPROTO_ICMP)		return ip_vs_in_icmp(skb_p);	/* let it go if other IP protocols */	if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)		return NF_ACCEPT;	/* make sure that protocol header available in skb data area,	   note that skb data area may be reallocated. */	ihl = iph->ihl << 2;	if (ip_vs_header_check(skb, iph->protocol, ihl) == -1)		return NF_DROP;	iph = skb->nh.iph;	h.raw = (char*) iph + ihl;	/*	 * Check if the packet belongs to an existing connection entry	 */	cp = ip_vs_conn_in_get(iph->protocol, iph->saddr, h.portp[0],			       iph->daddr, h.portp[1]);	if (!cp &&	    (h.th->syn || (iph->protocol!=IPPROTO_TCP)) &&	    (svc = ip_vs_service_get(skb->nfmark, iph->protocol,				     iph->daddr, h.portp[1]))) {		if (ip_vs_todrop()) {			/*			 * It seems that we are very loaded.			 * We have to drop this packet :(			 */			ip_vs_service_put(svc);			return NF_DROP;		}		/*		 * Let the virtual server select a real server for the		 * incoming connection, and create a connection entry.		 */		cp = ip_vs_schedule(svc, iph);		if (!cp)			return ip_vs_leave(svc, skb);		ip_vs_conn_stats(cp, svc);		ip_vs_service_put(svc);	}	if (!cp) {		/* sorry, all this trouble for a no-hit :) */		IP_VS_DBG(12, "packet for %s %d.%d.%d.%d:%d continue "			  "traversal as normal.\n",			  ip_vs_proto_name(iph->protocol),			  NIPQUAD(iph->daddr),			  ntohs(h.portp[1]));		return NF_ACCEPT;	}	IP_VS_DBG(11, "Incoming %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d\n",		  ip_vs_proto_name(iph->protocol),		  NIPQUAD(iph->saddr), ntohs(h.portp[0]),		  NIPQUAD(iph->daddr), ntohs(h.portp[1]));	/* Check the server status */	if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {		/* the destination server is not availabe */		if (sysctl_ip_vs_expire_nodest_conn) {			/* try to expire the connection immediately */			ip_vs_conn_expire_now(cp);		} else {			/* don't restart its timer, and silently			   drop the packet. */			__ip_vs_conn_put(cp);		}		return NF_DROP;	}	ip_vs_in_stats(cp, skb);	ip_vs_set_state(cp, VS_STATE_INPUT, iph, h.portp);	if (cp->packet_xmit)		ret = cp->packet_xmit(skb, cp);	else {		IP_VS_DBG_RL("warning: packet_xmit is null");		ret = NF_ACCEPT;	}	/* increase its packet counter and check if it is needed	   to be synchronized */	atomic_inc(&cp->in_pkts);	if (ip_vs_sync_state & IP_VS_STATE_MASTER &&	    (cp->protocol != IPPROTO_TCP ||	     cp->state == IP_VS_S_ESTABLISHED) &&	    (atomic_read(&cp->in_pkts) % 50 == sysctl_ip_vs_sync_threshold))		ip_vs_sync_conn(cp);	ip_vs_conn_put(cp);	return ret;}/* *	It is hooked at the NF_IP_FORWARD chain, in order to catch ICMP *      packets destined for 0.0.0.0/0. *      When fwmark-based virtual service is used, such as transparent *      cache cluster, TCP packets can be marked and routed to ip_vs_in, *      but ICMP destined for 0.0.0.0/0 cannot not be easily marked and *      sent to ip_vs_in_icmp. So, catch them at the NF_IP_FORWARD chain *      and send them to ip_vs_in_icmp. */static unsigned int ip_vs_forward_icmp(unsigned int hooknum,				       struct sk_buff **skb_p,				       const struct net_device *in,				       const struct net_device *out,				       int (*okfn)(struct sk_buff *)){	struct sk_buff	*skb = *skb_p;	struct iphdr	*iph = skb->nh.iph;	if (iph->protocol != IPPROTO_ICMP)		return NF_ACCEPT;	if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {		skb = ip_defrag(skb);		if (!skb)			return NF_STOLEN;		*skb_p = skb;	}	return ip_vs_in_icmp(skb_p);}/* After packet filtering, forward packet through VS/DR, VS/TUN,   or VS/NAT(change destination), so that filtering rules can be   applied to IPVS. */static struct nf_hook_ops ip_vs_in_ops = {	{ NULL, NULL },	ip_vs_in, PF_INET, NF_IP_LOCAL_IN, 100};/* After packet filtering, change source only for VS/NAT */static struct nf_hook_ops ip_vs_out_ops = {	{ NULL, NULL },	ip_vs_out, PF_INET, NF_IP_FORWARD, 100};/* After packet filtering (but before ip_vs_out_icmp), catch icmp   destined for 0.0.0.0/0, which is for incoming IPVS connections */static struct nf_hook_ops ip_vs_forward_icmp_ops = {	{ NULL, NULL },	ip_vs_forward_icmp, PF_INET, NF_IP_FORWARD, 99};/* Before the netfilter connection tracking, exit from POST_ROUTING */static struct nf_hook_ops ip_vs_post_routing_ops = {	{ NULL, NULL },	ip_vs_post_routing, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC-1};/* *	Initialize IP Virtual Server */static int __init ip_vs_init(void){	int ret;	ret = ip_vs_control_init();	if (ret < 0) {		IP_VS_ERR("can't setup control.\n");		goto cleanup_nothing;	}	ret = ip_vs_conn_init();	if (ret < 0) {		IP_VS_ERR("can't setup connection table.\n");		goto cleanup_control;	}	ret = ip_vs_app_init();	if (ret < 0) {		IP_VS_ERR("can't setup application helper.\n");		goto cleanup_conn;	}	ret = nf_register_hook(&ip_vs_in_ops);	if (ret < 0) {		IP_VS_ERR("can't register in hook.\n");		goto cleanup_app;	}	ret = nf_register_hook(&ip_vs_out_ops);	if (ret < 0) {		IP_VS_ERR("can't register out hook.\n");		goto cleanup_inops;	}	ret = nf_register_hook(&ip_vs_post_routing_ops);	if (ret < 0) {		IP_VS_ERR("can't register post_routing hook.\n");		goto cleanup_outops;	}	ret = nf_register_hook(&ip_vs_forward_icmp_ops);	if (ret < 0) {		IP_VS_ERR("can't register forward_icmp hook.\n");		goto cleanup_postroutingops;	}	IP_VS_INFO("ipvs loaded.\n");	return ret;  cleanup_postroutingops:	nf_unregister_hook(&ip_vs_post_routing_ops);  cleanup_outops:	nf_unregister_hook(&ip_vs_out_ops);  cleanup_inops:	nf_unregister_hook(&ip_vs_in_ops);  cleanup_app:	ip_vs_app_cleanup();  cleanup_conn:	ip_vs_conn_cleanup();  cleanup_control:	ip_vs_control_cleanup();  cleanup_nothing:	return ret;}static void __exit ip_vs_cleanup(void){	nf_unregister_hook(&ip_vs_forward_icmp_ops);	nf_unregister_hook(&ip_vs_post_routing_ops);	nf_unregister_hook(&ip_vs_out_ops);	nf_unregister_hook(&ip_vs_in_ops);	ip_vs_app_cleanup();	ip_vs_conn_cleanup();	ip_vs_control_cleanup();	IP_VS_INFO("ipvs unloaded.\n");}module_init(ip_vs_init);module_exit(ip_vs_cleanup);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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