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

📄 ip_vs_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	/*	 *    Non-persistent service	 */	if (!svc->fwmark && pptr[1] != svc->port) {		if (!svc->port)			IP_VS_ERR("Schedule: port zero only supported "				  "in persistent services, "				  "check your ipvs configuration\n");		return NULL;	}	dest = svc->scheduler->schedule(svc, skb);	if (dest == NULL) {		IP_VS_DBG(1, "Schedule: no dest found.\n");		return NULL;	}	/*	 *    Create a connection entry.	 */	cp = ip_vs_conn_new(iph->protocol,			    iph->saddr, pptr[0],			    iph->daddr, pptr[1],			    dest->addr, dest->port?dest->port:pptr[1],			    0,			    dest);	if (cp == NULL)		return NULL;	IP_VS_DBG(6, "Schedule fwd:%c c:%u.%u.%u.%u:%u v:%u.%u.%u.%u:%u "		  "d:%u.%u.%u.%u:%u flg:%X cnt:%d\n",		  ip_vs_fwd_tag(cp),		  NIPQUAD(cp->caddr), ntohs(cp->cport),		  NIPQUAD(cp->vaddr), ntohs(cp->vport),		  NIPQUAD(cp->daddr), ntohs(cp->dport),		  cp->flags, atomic_read(&cp->refcnt));	ip_vs_conn_stats(cp, svc);	return cp;}/* *  Pass or drop the packet. *  Called by ip_vs_in, when the virtual service is available but *  no destination is available for a new connection. */int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,		struct ip_vs_protocol *pp){	__u16 _ports[2], *pptr;	struct iphdr *iph = skb->nh.iph;	pptr = skb_header_pointer(skb, iph->ihl*4,				  sizeof(_ports), _ports);	if (pptr == NULL) {		ip_vs_service_put(svc);		return NF_DROP;	}	/* if it is fwmark-based service, the cache_bypass sysctl is up	   and the destination is RTN_UNICAST (and not local), then create	   a cache_bypass connection entry */	if (sysctl_ip_vs_cache_bypass && svc->fwmark	    && (inet_addr_type(iph->daddr) == RTN_UNICAST)) {		int ret, cs;		struct ip_vs_conn *cp;		ip_vs_service_put(svc);		/* create a new connection entry */		IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n");		cp = ip_vs_conn_new(iph->protocol,				    iph->saddr, pptr[0],				    iph->daddr, pptr[1],				    0, 0,				    IP_VS_CONN_F_BYPASS,				    NULL);		if (cp == NULL)			return NF_DROP;		/* statistics */		ip_vs_in_stats(cp, skb);		/* set state */		cs = ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pp);		/* transmit the first SYN packet */		ret = cp->packet_xmit(skb, cp, pp);		/* do not touch skb anymore */		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) && (pptr[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);	return NF_DROP;}/* *      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 **pskb,				       const struct net_device *in,				       const struct net_device *out,				       int (*okfn)(struct sk_buff *)){	if (!((*pskb)->ipvs_property))		return NF_ACCEPT;	/* The packet was sent from IPVS, exit this chain */	(*okfn)(*pskb);	return NF_STOLEN;}u16 ip_vs_checksum_complete(struct sk_buff *skb, int offset){	return (u16) csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));}static inline struct sk_buff *ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user){	skb = ip_defrag(skb, user);	if (skb)		ip_send_check(skb->nh.iph);	return skb;}/* * Packet has been made sufficiently writable in caller * - inout: 1=in->out, 0=out->in */void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,		    struct ip_vs_conn *cp, int inout){	struct iphdr *iph	 = skb->nh.iph;	unsigned int icmp_offset = iph->ihl*4;	struct icmphdr *icmph	 = (struct icmphdr *)(skb->nh.raw + icmp_offset);	struct iphdr *ciph	 = (struct iphdr *)(icmph + 1);	if (inout) {		iph->saddr = cp->vaddr;		ip_send_check(iph);		ciph->daddr = cp->vaddr;		ip_send_check(ciph);	} else {		iph->daddr = cp->daddr;		ip_send_check(iph);		ciph->saddr = cp->daddr;		ip_send_check(ciph);	}	/* the TCP/UDP port */	if (IPPROTO_TCP == ciph->protocol || IPPROTO_UDP == ciph->protocol) {		__u16 *ports = (void *)ciph + ciph->ihl*4;		if (inout)			ports[1] = cp->vport;		else			ports[0] = cp->dport;	}	/* And finally the ICMP checksum */	icmph->checksum = 0;	icmph->checksum = ip_vs_checksum_complete(skb, icmp_offset);	skb->ip_summed = CHECKSUM_UNNECESSARY;	if (inout)		IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,			"Forwarding altered outgoing ICMP");	else		IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,			"Forwarding altered incoming ICMP");}/* *	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 **pskb, int *related){	struct sk_buff *skb = *pskb;	struct iphdr *iph;	struct icmphdr	_icmph, *ic;	struct iphdr	_ciph, *cih;	/* The ip header contained within the ICMP */	struct ip_vs_conn *cp;	struct ip_vs_protocol *pp;	unsigned int offset, ihl, verdict;	*related = 1;	/* reassemble IP fragments */	if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {		skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT);		if (!skb)			return NF_STOLEN;		*pskb = skb;	}	iph = skb->nh.iph;	offset = ihl = iph->ihl * 4;	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);	if (ic == NULL)		return NF_DROP;	IP_VS_DBG(12, "Outgoing ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",		  ic->type, ntohs(icmp_id(ic)),		  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 ((ic->type != ICMP_DEST_UNREACH) &&	    (ic->type != ICMP_SOURCE_QUENCH) &&	    (ic->type != ICMP_TIME_EXCEEDED)) {		*related = 0;		return NF_ACCEPT;	}	/* Now find the contained IP header */	offset += sizeof(_icmph);	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);	if (cih == NULL)		return NF_ACCEPT; /* The packet looks wrong, ignore */	pp = ip_vs_proto_get(cih->protocol);	if (!pp)		return NF_ACCEPT;	/* Is the embedded protocol header present? */	if (unlikely(cih->frag_off & __constant_htons(IP_OFFSET) &&		     pp->dont_defrag))		return NF_ACCEPT;	IP_VS_DBG_PKT(11, pp, skb, offset, "Checking outgoing ICMP for");	offset += cih->ihl * 4;	/* The embedded headers contain source and dest in reverse order */	cp = pp->conn_out_get(skb, pp, cih, offset, 1);	if (!cp)		return NF_ACCEPT;	verdict = NF_DROP;	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");	}	/* Ensure the checksum is correct */	if (skb->ip_summed != CHECKSUM_UNNECESSARY &&	    ip_vs_checksum_complete(skb, ihl)) {		/* Failed checksum! */		IP_VS_DBG(1, "Forward ICMP: failed checksum from %d.%d.%d.%d!\n",			  NIPQUAD(iph->saddr));		goto out;	}	if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol)		offset += 2 * sizeof(__u16);	if (!ip_vs_make_skb_writable(pskb, offset))		goto out;	skb = *pskb;	ip_vs_nat_icmp(skb, pp, cp, 1);	/* do the statistics and put it back */	ip_vs_out_stats(cp, skb);	skb->ipvs_property = 1;	verdict = NF_ACCEPT;  out:	__ip_vs_conn_put(cp);	return verdict;}static inline int is_tcp_reset(const struct sk_buff *skb){	struct tcphdr _tcph, *th;	th = skb_header_pointer(skb, skb->nh.iph->ihl * 4,				sizeof(_tcph), &_tcph);	if (th == NULL)		return 0;	return th->rst;}/* *	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 intip_vs_out(unsigned int hooknum, struct sk_buff **pskb,	  const struct net_device *in, const struct net_device *out,	  int (*okfn)(struct sk_buff *)){	struct sk_buff  *skb = *pskb;	struct iphdr	*iph;	struct ip_vs_protocol *pp;	struct ip_vs_conn *cp;	int ihl;	EnterFunction(11);	if (skb->ipvs_property)		return NF_ACCEPT;	iph = skb->nh.iph;	if (unlikely(iph->protocol == IPPROTO_ICMP)) {		int related, verdict = ip_vs_out_icmp(pskb, &related);		if (related)			return verdict;		skb = *pskb;		iph = skb->nh.iph;	}	pp = ip_vs_proto_get(iph->protocol);	if (unlikely(!pp))		return NF_ACCEPT;	/* reassemble IP fragments */	if (unlikely(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET) &&		     !pp->dont_defrag)) {		skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT);		if (!skb)			return NF_STOLEN;		iph = skb->nh.iph;		*pskb = skb;	}	ihl = iph->ihl << 2;	/*	 * Check if the packet belongs to an existing entry	 */	cp = pp->conn_out_get(skb, pp, iph, ihl, 0);	if (unlikely(!cp)) {		if (sysctl_ip_vs_nat_icmp_send &&		    (pp->protocol == IPPROTO_TCP ||		     pp->protocol == IPPROTO_UDP)) {			__u16 _ports[2], *pptr;			pptr = skb_header_pointer(skb, ihl,						  sizeof(_ports), _ports);			if (pptr == NULL)				return NF_ACCEPT;	/* Not for me */			if (ip_vs_lookup_real_service(iph->protocol,						      iph->saddr, pptr[0])) {				/*				 * Notify the real server: there is no				 * existing entry if it is not RST				 * packet or not TCP packet.				 */				if (iph->protocol != IPPROTO_TCP				    || !is_tcp_reset(skb)) {					icmp_send(skb,ICMP_DEST_UNREACH,

⌨️ 快捷键说明

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