示例#1
0
static unsigned int
ipt_tcpmss_target(struct sk_buff **pskb,
		  unsigned int hooknum,
		  const struct net_device *in,
		  const struct net_device *out,
		  const void *targinfo,
		  void *userinfo)
{
	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
	struct tcphdr *tcph;
	struct iphdr *iph;
	u_int16_t tcplen, newtotlen, oldval, newmss, mtu;
	unsigned int i;
	u_int8_t *opt;

	/* raw socket (tcpdump) may have clone of incoming skb: don't
	   disturb it --RR */
	if (skb_cloned(*pskb) && !(*pskb)->sk) {
		struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
		if (!nskb)
			return IPT_CONTINUE;
		kfree_skb(*pskb);
		*pskb = nskb;
	}

	iph = (*pskb)->nh.iph;
	tcplen = (*pskb)->len - iph->ihl*4;

	tcph = (void *)iph + iph->ihl*4;

	/* Since it passed flags test in tcp match, we know it is is
	   not a fragment, and has data >= tcp header length.  SYN
	   packets should not contain data: if they did, then we risk
	   running over MTU, sending Frag Needed and breaking things
	   badly. --RR */
	if (tcplen != tcph->doff*4) {
		if (net_ratelimit())
			printk(KERN_ERR
			       "ipt_tcpmss_target: bad length (%d bytes)\n",
			       (*pskb)->len);
		return IPT_CONTINUE;
	}

	if(tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
		if(!(*pskb)->dst) {
			if (net_ratelimit())
				printk(KERN_ERR
			       		"ipt_tcpmss_target: no dst?! can't determine path-MTU\n");
			return IPT_CONTINUE;
		}

		if((*pskb)->dst->pmtu <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
			if (net_ratelimit())
				printk(KERN_ERR
		       			"ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", (*pskb)->dst->pmtu);
			return IPT_CONTINUE;
		}
		mtu = (*pskb)->dst->pmtu;

		if (in) {
			if (in->mtu <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
				if (net_ratelimit())
					printk(KERN_ERR
		       				"ipt_tcpmss_target: invalid interface MTU (%d)\n", in->mtu);
				return IPT_CONTINUE;
			}
			if (in->mtu < mtu)
				mtu = in->mtu;
		}

		newmss = mtu - sizeof(struct iphdr) - sizeof(struct tcphdr);
	} else
		newmss = tcpmssinfo->mss;

 	opt = (u_int8_t *)tcph;
	for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)){
		if ((opt[i] == TCPOPT_MSS) &&
		    ((tcph->doff*4 - i) >= TCPOLEN_MSS) &&
		    (opt[i+1] == TCPOLEN_MSS)) {
			u_int16_t oldmss;

			oldmss = (opt[i+2] << 8) | opt[i+3];

			if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) &&
				(oldmss <= newmss))
					return IPT_CONTINUE;

			opt[i+2] = (newmss & 0xff00) >> 8;
			opt[i+3] = (newmss & 0x00ff);

			tcph->check = cheat_check(htons(oldmss)^0xFFFF,
						  htons(newmss),
						  tcph->check);

			DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu"
			       "->%u.%u.%u.%u:%hu changed TCP MSS option"
			       " (from %u to %u)\n", 
			       NIPQUAD((*pskb)->nh.iph->saddr),
			       ntohs(tcph->source),
			       NIPQUAD((*pskb)->nh.iph->daddr),
			       ntohs(tcph->dest),
			       oldmss, newmss);
			goto retmodified;
		}
	}
static unsigned int
ipt_tcpmss_target(struct sk_buff **pskb,
		  const struct net_device *in,
		  const struct net_device *out,
		  unsigned int hooknum,
		  const void *targinfo,
		  void *userinfo)
{
	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
	struct tcphdr *tcph;
	struct iphdr *iph;
	u_int16_t tcplen, newtotlen, oldval, newmss;
	unsigned int i;
	u_int8_t *opt;

	if (!skb_make_writable(pskb, (*pskb)->len))
		return NF_DROP;

	if ((*pskb)->ip_summed == CHECKSUM_HW &&
	    skb_checksum_help(*pskb, out == NULL))
		return NF_DROP;

	iph = (*pskb)->nh.iph;
	tcplen = (*pskb)->len - iph->ihl*4;

	tcph = (void *)iph + iph->ihl*4;

	/* Since it passed flags test in tcp match, we know it is is
	   not a fragment, and has data >= tcp header length.  SYN
	   packets should not contain data: if they did, then we risk
	   running over MTU, sending Frag Needed and breaking things
	   badly. --RR */
	if (tcplen != tcph->doff*4) {
		if (net_ratelimit())
			printk(KERN_ERR
			       "ipt_tcpmss_target: bad length (%d bytes)\n",
			       (*pskb)->len);
		return NF_DROP;
	}

	if(tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
		if(!(*pskb)->dst) {
			if (net_ratelimit())
				printk(KERN_ERR
			       		"ipt_tcpmss_target: no dst?! can't determine path-MTU\n");
			return NF_DROP; /* or IPT_CONTINUE ?? */
		}

		if(dst_mtu((*pskb)->dst) <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
			if (net_ratelimit())
				printk(KERN_ERR
		       			"ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", dst_mtu((*pskb)->dst));
			return NF_DROP; /* or IPT_CONTINUE ?? */
		}

		newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) - sizeof(struct tcphdr);
	} else
		newmss = tcpmssinfo->mss;

 	opt = (u_int8_t *)tcph;
	for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)){
		if ((opt[i] == TCPOPT_MSS) &&
		    ((tcph->doff*4 - i) >= TCPOLEN_MSS) &&
		    (opt[i+1] == TCPOLEN_MSS)) {
			u_int16_t oldmss;

			oldmss = (opt[i+2] << 8) | opt[i+3];

			if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) &&
				(oldmss <= newmss))
					return IPT_CONTINUE;

			opt[i+2] = (newmss & 0xff00) >> 8;
			opt[i+3] = (newmss & 0x00ff);

			tcph->check = cheat_check(htons(oldmss)^0xFFFF,
						  htons(newmss),
						  tcph->check);

			DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu"
			       "->%u.%u.%u.%u:%hu changed TCP MSS option"
			       " (from %u to %u)\n", 
			       NIPQUAD((*pskb)->nh.iph->saddr),
			       ntohs(tcph->source),
			       NIPQUAD((*pskb)->nh.iph->daddr),
			       ntohs(tcph->dest),
			       oldmss, newmss);
			goto retmodified;
		}
	}