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

📄 ip_vs_core.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		ret = cp->packet_xmit(skb, cp);		atomic_inc(&cp->in_pkts);		ip_vs_conn_put(cp);		return ret;	}	/*	 * When the virtual ftp service is presented, packets destined	 * for other services on the VIP may get here (except services	 * listed in the ipvs table), pass the packets, because it is	 * not ipvs job to decide to drop the packets.	 */	if ((svc->port == FTPPORT) && (portp[1] != FTPPORT)) {		ip_vs_service_put(svc);		return NF_ACCEPT;	}	ip_vs_service_put(svc);	/*	 * Notify the client that the destination is unreachable, and	 * release the socket buffer.	 * Since it is in IP layer, the TCP socket is not actually	 * created, the TCP RST packet cannot be sent, instead that	 * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ	 */	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);	kfree_skb(skb);	return NF_STOLEN;}/* *      It is hooked before NF_IP_PRI_NAT_SRC at the NF_IP_POST_ROUTING *      chain, and is used for VS/NAT. *      It detects packets for VS/NAT connections and sends the packets *      immediately. This can avoid that iptable_nat mangles the packets *      for VS/NAT. */static unsigned int ip_vs_post_routing(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;	if (!(skb->nfcache & NFC_IPVS_PROPERTY))		return NF_ACCEPT;	/* The packet was sent from IPVS, exit this chain */	(*okfn)(skb);	return NF_STOLEN;}/* *	Handle ICMP messages in the inside-to-outside direction (outgoing). *	Find any that might be relevant, check against existing connections, *	forward to the right destination host if relevant. *	Currently handles error types - unreachable, quench, ttl exceeded. *      (Only used in VS/NAT) */static int ip_vs_out_icmp(struct sk_buff **skb_p){	struct sk_buff	*skb   = *skb_p;	struct iphdr	*iph;	struct icmphdr	*icmph;	struct iphdr	*ciph;	/* The ip header contained within the ICMP */	__u16		*pptr;	/* port numbers from TCP/UDP contained header */	unsigned short	ihl;	unsigned short	len;	unsigned short	clen, csize;	struct ip_vs_conn *cp;	/* reassemble IP fragments, but will it happen in ICMP packets?? */	if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {		skb = ip_defrag(skb);		if (!skb)			return NF_STOLEN;		*skb_p = skb;	}	if (skb_is_nonlinear(skb)) {		if (skb_linearize(skb, GFP_ATOMIC) != 0)			return NF_DROP;		ip_send_check(skb->nh.iph);	}	iph = skb->nh.iph;	ihl = iph->ihl << 2;	icmph = (struct icmphdr *)((char *)iph + ihl);	len   = ntohs(iph->tot_len) - ihl;	if (len < sizeof(struct icmphdr))		return NF_DROP;	IP_VS_DBG(12, "outgoing ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",		  icmph->type, ntohs(icmp_id(icmph)),		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));	/*	 * Work through seeing if this is for us.	 * These checks are supposed to be in an order that means easy	 * things are checked first to speed up processing.... however	 * this means that some packets will manage to get a long way	 * down this stack and then be rejected, but that's life.	 */	if ((icmph->type != ICMP_DEST_UNREACH) &&	    (icmph->type != ICMP_SOURCE_QUENCH) &&	    (icmph->type != ICMP_TIME_EXCEEDED))		return NF_ACCEPT;	/* 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;	/*	 * Find the ports involved - this packet was	 * incoming so the ports are right way round	 * (but reversed relative to outer IP header!)	 */	pptr = (__u16 *)&(((char *)ciph)[csize]);	/* Ensure the checksum is correct */	if (ip_compute_csum((unsigned char *) icmph, len)) {		/* Failed checksum! */		IP_VS_DBG(1, "forward ICMP: failed checksum from %d.%d.%d.%d!\n",			  NIPQUAD(iph->saddr));		return NF_DROP;	}	IP_VS_DBG(11, "Handling outgoing 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]));	/* ciph content is actually <protocol, caddr, cport, daddr, dport> */	cp = ip_vs_conn_out_get(ciph->protocol, ciph->daddr, pptr[1],				ciph->saddr, pptr[0]);	if (!cp)		return NF_ACCEPT;	if (IP_VS_FWD_METHOD(cp) != 0) {		IP_VS_ERR("shouldn't reach here, because the box is on the"			  "half connection in the tun/dr module.\n");	}	/* Now we do real damage to this packet...! */	/* First change the source IP address, and recalc checksum */	iph->saddr = cp->vaddr;	ip_send_check(iph);	/* Now change the *dest* address in the contained IP */	ciph->daddr = cp->vaddr;	ip_send_check(ciph);	/* the TCP/UDP dest port - cannot redo check */	pptr[1] = cp->vport;	/* And finally the ICMP checksum */	icmph->checksum = 0;	icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);	skb->ip_summed = CHECKSUM_UNNECESSARY;	/* do the statistics and put it back */	ip_vs_out_stats(cp, skb);	ip_vs_conn_put(cp);	IP_VS_DBG(11, "Forwarding correct outgoing 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]));	skb->nfcache |= NFC_IPVS_PROPERTY;	return NF_ACCEPT;}/* *	It is hooked at the NF_IP_FORWARD chain, used only for VS/NAT. *	Check if outgoing packet belongs to the established ip_vs_conn, *      rewrite addresses of the packet and send it on its way... */static unsigned int ip_vs_out(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;	union ip_vs_tphdr h;	struct ip_vs_conn *cp;	int size;	int ihl;	EnterFunction(11);	if (skb->nfcache & NFC_IPVS_PROPERTY)		return NF_ACCEPT;	iph = skb->nh.iph;	if (iph->protocol == IPPROTO_ICMP)		return ip_vs_out_icmp(skb_p);	/* let it go if other IP protocols */	if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)		return NF_ACCEPT;	/* reassemble IP fragments */	if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {		skb = ip_defrag(skb);		if (!skb)			return NF_STOLEN;		iph = skb->nh.iph;		*skb_p = skb;	}	/* 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 old entry	 */	cp = ip_vs_conn_out_get(iph->protocol, iph->saddr, h.portp[0],				iph->daddr, h.portp[1]);	if (!cp) {		if (sysctl_ip_vs_nat_icmp_send &&		    ip_vs_lookup_real_service(iph->protocol,					      iph->saddr, h.portp[0])) {			/*			 * Notify the real server: there is no existing			 * entry if it is not RST packet or not TCP packet.			 */			if (!h.th->rst || iph->protocol != IPPROTO_TCP) {				icmp_send(skb, ICMP_DEST_UNREACH,					  ICMP_PORT_UNREACH, 0);				kfree_skb(skb);				return NF_STOLEN;			}		}		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]));		if (skb_is_nonlinear(skb))			ip_send_check(iph);		return NF_ACCEPT;	}	/*	 * If it has ip_vs_app helper, the helper may change the payload,	 * so it needs full checksum checking and checksum calculation.	 * If not, only the header (addr/port) is changed, so it is fast	 * to do incremental checksum update, and let the destination host	 * do final checksum checking.	 */	if (cp->app && skb_is_nonlinear(skb)) {		if (skb_linearize(skb, GFP_ATOMIC) != 0) {			ip_vs_conn_put(cp);			return NF_DROP;		}		iph = skb->nh.iph;		h.raw = (char*) iph + ihl;	}	size = skb->len - ihl;	IP_VS_DBG(11, "O-pkt: %s size=%d\n",		  ip_vs_proto_name(iph->protocol), size);	/* do TCP/UDP checksum checking if it has application helper */	if (cp->app && (iph->protocol != IPPROTO_UDP || h.uh->check != 0)) {		switch (skb->ip_summed) {		case CHECKSUM_NONE:			skb->csum = csum_partial(h.raw, size, 0);		case CHECKSUM_HW:			if (csum_tcpudp_magic(iph->saddr, iph->daddr, size,					      iph->protocol, skb->csum)) {				ip_vs_conn_put(cp);				IP_VS_DBG_RL("Outgoing failed %s checksum "					     "from %d.%d.%d.%d (size=%d)!\n",					     ip_vs_proto_name(iph->protocol),					     NIPQUAD(iph->saddr),					     size);				return NF_DROP;			}			break;		default:			/* CHECKSUM_UNNECESSARY */			break;		}	}	IP_VS_DBG(11, "Outgoing %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]));	/* mangle the packet */	iph->saddr = cp->vaddr;	h.portp[0] = cp->vport;	/*	 *	Call application helper if needed	 */	if (ip_vs_app_pkt_out(cp, skb) != 0) {		/* skb data has probably changed, update pointers */		iph = skb->nh.iph;		h.raw = (char*)iph + ihl;		size = skb->len - ihl;	}	/*	 *	Adjust TCP/UDP checksums	 */	if (!cp->app && (iph->protocol != IPPROTO_UDP || h.uh->check != 0)) {		/* Only port and addr are changed, do fast csum update */		ip_vs_fast_check_update(&h, cp->daddr, cp->vaddr,					cp->dport, cp->vport, iph->protocol);		if (skb->ip_summed == CHECKSUM_HW)			skb->ip_summed = CHECKSUM_NONE;	} else {		/* full checksum calculation */		switch (iph->protocol) {		case IPPROTO_TCP:			h.th->check = 0;			skb->csum = csum_partial(h.raw, size, 0);			h.th->check = csum_tcpudp_magic(iph->saddr, iph->daddr,							size, iph->protocol,							skb->csum);			IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%d)\n",				  ip_vs_proto_name(iph->protocol), h.th->check,				  (char*)&(h.th->check) - (char*)h.raw);			break;		case IPPROTO_UDP:			h.uh->check = 0;			skb->csum = csum_partial(h.raw, size, 0);			h.uh->check = csum_tcpudp_magic(iph->saddr, iph->daddr,							size, iph->protocol,							skb->csum);			if (h.uh->check == 0)				h.uh->check = 0xFFFF;			IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%d)\n",				  ip_vs_proto_name(iph->protocol), h.uh->check,				  (char*)&(h.uh->check) - (char*)h.raw);			break;		}	}	ip_send_check(iph);	ip_vs_out_stats(cp, skb);	ip_vs_set_state(cp, VS_STATE_OUTPUT, iph, h.portp);	ip_vs_conn_put(cp);	skb->nfcache |= NFC_IPVS_PROPERTY;	LeaveFunction(11);	return NF_ACCEPT;}/* *      Check if the packet is for VS/NAT connections, then send it *      immediately. *      Called by ip_fw_compact to detect packets for VS/NAT before *      they are changed by ipchains masquerading code. */unsigned int check_for_ip_vs_out(struct sk_buff **skb_p,				 int (*okfn)(struct sk_buff *)){	unsigned int ret;	ret = ip_vs_out(NF_IP_FORWARD, skb_p, NULL, NULL, NULL);	if (ret != NF_ACCEPT) {		return ret;	} else {		/* send the packet immediately if it is already mangled		   by ip_vs_out */		if ((*skb_p)->nfcache & NFC_IPVS_PROPERTY) {			(*okfn)(*skb_p);			return NF_STOLEN;		}	}	return NF_ACCEPT;}/* *	Handle ICMP messages in the outside-to-inside direction (incoming) *	and sometimes in outgoing direction from ip_vs_forward_icmp. *	Find any that might be relevant, check against existing connections, *	forward to the right destination host if relevant. *	Currently handles error types - unreachable, quench, ttl exceeded. */static int ip_vs_in_icmp(struct sk_buff **skb_p){	struct sk_buff	*skb   = *skb_p;	struct iphdr    *iph;	struct icmphdr  *icmph;	struct iphdr    *ciph;	/* The ip header contained within the ICMP */	__u16	        *pptr;	/* port numbers from TCP/UDP contained header */

⌨️ 快捷键说明

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