static unsigned int tcpoptstrip_mangle_packet(struct sk_buff *skb, const struct xt_tcpoptstrip_target_info *info, unsigned int tcphoff, unsigned int minlen) { unsigned int optl, i, j; struct tcphdr *tcph; u_int16_t n, o; u_int8_t *opt; if (!skb_make_writable(skb, skb->len)) return NF_DROP; tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); opt = (u_int8_t *)tcph; /* * Walk through all TCP options - if we find some option to remove, * set all octets to %TCPOPT_NOP and adjust checksum. */ for (i = sizeof(struct tcphdr); i < tcp_hdrlen(skb); i += optl) { optl = optlen(opt, i); if (i + optl > tcp_hdrlen(skb)) break; if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i])) continue; for (j = 0; j < optl; ++j) { o = opt[i+j]; n = TCPOPT_NOP; if ((i + j) % 2 == 0) { o <<= 8; n <<= 8; } inet_proto_csum_replace2(&tcph->check, skb, htons(o), htons(n), 0); } memset(opt + i, TCPOPT_NOP, optl); } return XT_CONTINUE; }
static int tcpmss_mangle_packet(struct sk_buff *skb, const struct xt_tcpmss_info *info, unsigned int in_mtu, unsigned int tcphoff, unsigned int minlen) { struct tcphdr *tcph; unsigned int tcplen, i; __be16 oldval; u16 newmss; u8 *opt; if (!skb_make_writable(skb, skb->len)) return -1; tcplen = skb->len - tcphoff; tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); /* Header cannot be larger than the packet */ if (tcplen < tcph->doff*4) return -1; if (info->mss == XT_TCPMSS_CLAMP_PMTU) { if (dst_mtu(skb_dst(skb)) <= minlen) { if (net_ratelimit()) pr_err("unknown or invalid path-MTU (%u)\n", dst_mtu(skb_dst(skb))); return -1; } if (in_mtu <= minlen) { if (net_ratelimit()) pr_err("unknown or invalid path-MTU (%u)\n", in_mtu); return -1; } newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen; } else newmss = info->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]; /* Never increase MSS, even when setting it, as * doing so results in problems for hosts that rely * on MSS being set correctly. */ if (oldmss <= newmss) return 0; opt[i+2] = (newmss & 0xff00) >> 8; opt[i+3] = newmss & 0x00ff; inet_proto_csum_replace2(&tcph->check, skb, htons(oldmss), htons(newmss), 0); return 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 int tcpmss_mangle_packet(struct sk_buff **pskb, const struct xt_tcpmss_info *info, unsigned int tcphoff, unsigned int minlen) { struct tcphdr *tcph; unsigned int tcplen, i; __be16 oldval; u16 newmss; u8 *opt; if (!skb_make_writable(pskb, (*pskb)->len)) return -1; tcplen = (*pskb)->len - tcphoff; tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff); /* 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 "xt_TCPMSS: bad length (%u bytes)\n", (*pskb)->len); return -1; } if (info->mss == XT_TCPMSS_CLAMP_PMTU) { if (dst_mtu((*pskb)->dst) <= minlen) { if (net_ratelimit()) printk(KERN_ERR "xt_TCPMSS: " "unknown or invalid path-MTU (%u)\n", dst_mtu((*pskb)->dst)); return -1; } newmss = dst_mtu((*pskb)->dst) - minlen; } else newmss = info->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 (info->mss == XT_TCPMSS_CLAMP_PMTU && oldmss <= newmss) return 0; opt[i+2] = (newmss & 0xff00) >> 8; opt[i+3] = newmss & 0x00ff; nf_proto_csum_replace2(&tcph->check, *pskb, htons(oldmss), htons(newmss), 0); return 0; } }
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; } }
static unsigned int ipt_tcpmss_target(struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, unsigned int hooknum, const struct xt_target *target, const void *targinfo) { const struct ipt_tcpmss_info *tcpmssinfo = targinfo; struct tcphdr *tcph; struct iphdr *iph; u_int16_t tcplen, newmss; __be16 newtotlen, oldval; unsigned int i; u_int8_t *opt; if (!skb_make_writable(pskb, (*pskb)->len)) 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 IPT_CONTINUE; } if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) { 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 = nf_proto_csum_update(*pskb, htons(oldmss)^htons(0xFFFF), htons(newmss), tcph->check, 0); return IPT_CONTINUE; } }
static int tcpmss_mangle_packet(struct sk_buff *skb, const struct xt_action_param *par, unsigned int family, unsigned int tcphoff, unsigned int minlen) { const struct xt_tcpmss_info *info = par->targinfo; struct tcphdr *tcph; int len, tcp_hdrlen; unsigned int i; __be16 oldval; u16 newmss; u8 *opt; /* This is a fragment, no TCP header is available */ if (par->fragoff != 0) return 0; if (!skb_make_writable(skb, skb->len)) return -1; len = skb->len - tcphoff; if (len < (int)sizeof(struct tcphdr)) return -1; tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); tcp_hdrlen = tcph->doff * 4; if (len < tcp_hdrlen) return -1; if (info->mss == XT_TCPMSS_CLAMP_PMTU) { struct net *net = dev_net(par->in ? par->in : par->out); unsigned int in_mtu = tcpmss_reverse_mtu(net, skb, family); if (dst_mtu(skb_dst(skb)) <= minlen) { net_err_ratelimited("unknown or invalid path-MTU (%u)\n", dst_mtu(skb_dst(skb))); return -1; } if (in_mtu <= minlen) { net_err_ratelimited("unknown or invalid path-MTU (%u)\n", in_mtu); return -1; } newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen; } else newmss = info->mss; opt = (u_int8_t *)tcph; for (i = sizeof(struct tcphdr); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen(opt, i)) { if (opt[i] == TCPOPT_MSS && opt[i+1] == TCPOLEN_MSS) { u_int16_t oldmss; oldmss = (opt[i+2] << 8) | opt[i+3]; /* Never increase MSS, even when setting it, as * doing so results in problems for hosts that rely * on MSS being set correctly. */ if (oldmss <= newmss) return 0; opt[i+2] = (newmss & 0xff00) >> 8; opt[i+3] = newmss & 0x00ff; inet_proto_csum_replace2(&tcph->check, skb, htons(oldmss), htons(newmss), false); return 0; } }