Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * This is a module which is used for setting the MSS option in TCP packets.
0004  *
0005  * Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
0006  * Copyright (C) 2007 Patrick McHardy <kaber@trash.net>
0007  */
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009 #include <linux/module.h>
0010 #include <linux/skbuff.h>
0011 #include <linux/ip.h>
0012 #include <linux/gfp.h>
0013 #include <linux/ipv6.h>
0014 #include <linux/tcp.h>
0015 #include <net/dst.h>
0016 #include <net/flow.h>
0017 #include <net/ipv6.h>
0018 #include <net/route.h>
0019 #include <net/tcp.h>
0020 
0021 #include <linux/netfilter_ipv4/ip_tables.h>
0022 #include <linux/netfilter_ipv6/ip6_tables.h>
0023 #include <linux/netfilter/x_tables.h>
0024 #include <linux/netfilter/xt_tcpudp.h>
0025 #include <linux/netfilter/xt_TCPMSS.h>
0026 
0027 MODULE_LICENSE("GPL");
0028 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
0029 MODULE_DESCRIPTION("Xtables: TCP Maximum Segment Size (MSS) adjustment");
0030 MODULE_ALIAS("ipt_TCPMSS");
0031 MODULE_ALIAS("ip6t_TCPMSS");
0032 
0033 static inline unsigned int
0034 optlen(const u_int8_t *opt, unsigned int offset)
0035 {
0036     /* Beware zero-length options: make finite progress */
0037     if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
0038         return 1;
0039     else
0040         return opt[offset+1];
0041 }
0042 
0043 static u_int32_t tcpmss_reverse_mtu(struct net *net,
0044                     const struct sk_buff *skb,
0045                     unsigned int family)
0046 {
0047     struct flowi fl;
0048     struct rtable *rt = NULL;
0049     u_int32_t mtu     = ~0U;
0050 
0051     if (family == PF_INET) {
0052         struct flowi4 *fl4 = &fl.u.ip4;
0053         memset(fl4, 0, sizeof(*fl4));
0054         fl4->daddr = ip_hdr(skb)->saddr;
0055     } else {
0056         struct flowi6 *fl6 = &fl.u.ip6;
0057 
0058         memset(fl6, 0, sizeof(*fl6));
0059         fl6->daddr = ipv6_hdr(skb)->saddr;
0060     }
0061 
0062     nf_route(net, (struct dst_entry **)&rt, &fl, false, family);
0063     if (rt != NULL) {
0064         mtu = dst_mtu(&rt->dst);
0065         dst_release(&rt->dst);
0066     }
0067     return mtu;
0068 }
0069 
0070 static int
0071 tcpmss_mangle_packet(struct sk_buff *skb,
0072              const struct xt_action_param *par,
0073              unsigned int family,
0074              unsigned int tcphoff,
0075              unsigned int minlen)
0076 {
0077     const struct xt_tcpmss_info *info = par->targinfo;
0078     struct tcphdr *tcph;
0079     int len, tcp_hdrlen;
0080     unsigned int i;
0081     __be16 oldval;
0082     u16 newmss;
0083     u8 *opt;
0084 
0085     /* This is a fragment, no TCP header is available */
0086     if (par->fragoff != 0)
0087         return 0;
0088 
0089     if (skb_ensure_writable(skb, skb->len))
0090         return -1;
0091 
0092     len = skb->len - tcphoff;
0093     if (len < (int)sizeof(struct tcphdr))
0094         return -1;
0095 
0096     tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
0097     tcp_hdrlen = tcph->doff * 4;
0098 
0099     if (len < tcp_hdrlen || tcp_hdrlen < sizeof(struct tcphdr))
0100         return -1;
0101 
0102     if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
0103         struct net *net = xt_net(par);
0104         unsigned int in_mtu = tcpmss_reverse_mtu(net, skb, family);
0105         unsigned int min_mtu = min(dst_mtu(skb_dst(skb)), in_mtu);
0106 
0107         if (min_mtu <= minlen) {
0108             net_err_ratelimited("unknown or invalid path-MTU (%u)\n",
0109                         min_mtu);
0110             return -1;
0111         }
0112         newmss = min_mtu - minlen;
0113     } else
0114         newmss = info->mss;
0115 
0116     opt = (u_int8_t *)tcph;
0117     for (i = sizeof(struct tcphdr); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen(opt, i)) {
0118         if (opt[i] == TCPOPT_MSS && opt[i+1] == TCPOLEN_MSS) {
0119             u_int16_t oldmss;
0120 
0121             oldmss = (opt[i+2] << 8) | opt[i+3];
0122 
0123             /* Never increase MSS, even when setting it, as
0124              * doing so results in problems for hosts that rely
0125              * on MSS being set correctly.
0126              */
0127             if (oldmss <= newmss)
0128                 return 0;
0129 
0130             opt[i+2] = (newmss & 0xff00) >> 8;
0131             opt[i+3] = newmss & 0x00ff;
0132 
0133             inet_proto_csum_replace2(&tcph->check, skb,
0134                          htons(oldmss), htons(newmss),
0135                          false);
0136             return 0;
0137         }
0138     }
0139 
0140     /* There is data after the header so the option can't be added
0141      * without moving it, and doing so may make the SYN packet
0142      * itself too large. Accept the packet unmodified instead.
0143      */
0144     if (len > tcp_hdrlen)
0145         return 0;
0146 
0147     /* tcph->doff has 4 bits, do not wrap it to 0 */
0148     if (tcp_hdrlen >= 15 * 4)
0149         return 0;
0150 
0151     /*
0152      * MSS Option not found ?! add it..
0153      */
0154     if (skb_tailroom(skb) < TCPOLEN_MSS) {
0155         if (pskb_expand_head(skb, 0,
0156                      TCPOLEN_MSS - skb_tailroom(skb),
0157                      GFP_ATOMIC))
0158             return -1;
0159         tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
0160     }
0161 
0162     skb_put(skb, TCPOLEN_MSS);
0163 
0164     /*
0165      * IPv4: RFC 1122 states "If an MSS option is not received at
0166      * connection setup, TCP MUST assume a default send MSS of 536".
0167      * IPv6: RFC 2460 states IPv6 has a minimum MTU of 1280 and a minimum
0168      * length IPv6 header of 60, ergo the default MSS value is 1220
0169      * Since no MSS was provided, we must use the default values
0170      */
0171     if (xt_family(par) == NFPROTO_IPV4)
0172         newmss = min(newmss, (u16)536);
0173     else
0174         newmss = min(newmss, (u16)1220);
0175 
0176     opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
0177     memmove(opt + TCPOLEN_MSS, opt, len - sizeof(struct tcphdr));
0178 
0179     inet_proto_csum_replace2(&tcph->check, skb,
0180                  htons(len), htons(len + TCPOLEN_MSS), true);
0181     opt[0] = TCPOPT_MSS;
0182     opt[1] = TCPOLEN_MSS;
0183     opt[2] = (newmss & 0xff00) >> 8;
0184     opt[3] = newmss & 0x00ff;
0185 
0186     inet_proto_csum_replace4(&tcph->check, skb, 0, *((__be32 *)opt), false);
0187 
0188     oldval = ((__be16 *)tcph)[6];
0189     tcph->doff += TCPOLEN_MSS/4;
0190     inet_proto_csum_replace2(&tcph->check, skb,
0191                  oldval, ((__be16 *)tcph)[6], false);
0192     return TCPOLEN_MSS;
0193 }
0194 
0195 static unsigned int
0196 tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
0197 {
0198     struct iphdr *iph = ip_hdr(skb);
0199     __be16 newlen;
0200     int ret;
0201 
0202     ret = tcpmss_mangle_packet(skb, par,
0203                    PF_INET,
0204                    iph->ihl * 4,
0205                    sizeof(*iph) + sizeof(struct tcphdr));
0206     if (ret < 0)
0207         return NF_DROP;
0208     if (ret > 0) {
0209         iph = ip_hdr(skb);
0210         newlen = htons(ntohs(iph->tot_len) + ret);
0211         csum_replace2(&iph->check, iph->tot_len, newlen);
0212         iph->tot_len = newlen;
0213     }
0214     return XT_CONTINUE;
0215 }
0216 
0217 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
0218 static unsigned int
0219 tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
0220 {
0221     struct ipv6hdr *ipv6h = ipv6_hdr(skb);
0222     u8 nexthdr;
0223     __be16 frag_off, oldlen, newlen;
0224     int tcphoff;
0225     int ret;
0226 
0227     nexthdr = ipv6h->nexthdr;
0228     tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off);
0229     if (tcphoff < 0)
0230         return NF_DROP;
0231     ret = tcpmss_mangle_packet(skb, par,
0232                    PF_INET6,
0233                    tcphoff,
0234                    sizeof(*ipv6h) + sizeof(struct tcphdr));
0235     if (ret < 0)
0236         return NF_DROP;
0237     if (ret > 0) {
0238         ipv6h = ipv6_hdr(skb);
0239         oldlen = ipv6h->payload_len;
0240         newlen = htons(ntohs(oldlen) + ret);
0241         if (skb->ip_summed == CHECKSUM_COMPLETE)
0242             skb->csum = csum_add(csum_sub(skb->csum, (__force __wsum)oldlen),
0243                          (__force __wsum)newlen);
0244         ipv6h->payload_len = newlen;
0245     }
0246     return XT_CONTINUE;
0247 }
0248 #endif
0249 
0250 /* Must specify -p tcp --syn */
0251 static inline bool find_syn_match(const struct xt_entry_match *m)
0252 {
0253     const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
0254 
0255     if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
0256         tcpinfo->flg_cmp & TCPHDR_SYN &&
0257         !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
0258         return true;
0259 
0260     return false;
0261 }
0262 
0263 static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
0264 {
0265     const struct xt_tcpmss_info *info = par->targinfo;
0266     const struct ipt_entry *e = par->entryinfo;
0267     const struct xt_entry_match *ematch;
0268 
0269     if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
0270         (par->hook_mask & ~((1 << NF_INET_FORWARD) |
0271                (1 << NF_INET_LOCAL_OUT) |
0272                (1 << NF_INET_POST_ROUTING))) != 0) {
0273         pr_info_ratelimited("path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
0274         return -EINVAL;
0275     }
0276     if (par->nft_compat)
0277         return 0;
0278 
0279     xt_ematch_foreach(ematch, e)
0280         if (find_syn_match(ematch))
0281             return 0;
0282     pr_info_ratelimited("Only works on TCP SYN packets\n");
0283     return -EINVAL;
0284 }
0285 
0286 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
0287 static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
0288 {
0289     const struct xt_tcpmss_info *info = par->targinfo;
0290     const struct ip6t_entry *e = par->entryinfo;
0291     const struct xt_entry_match *ematch;
0292 
0293     if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
0294         (par->hook_mask & ~((1 << NF_INET_FORWARD) |
0295                (1 << NF_INET_LOCAL_OUT) |
0296                (1 << NF_INET_POST_ROUTING))) != 0) {
0297         pr_info_ratelimited("path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
0298         return -EINVAL;
0299     }
0300     if (par->nft_compat)
0301         return 0;
0302 
0303     xt_ematch_foreach(ematch, e)
0304         if (find_syn_match(ematch))
0305             return 0;
0306     pr_info_ratelimited("Only works on TCP SYN packets\n");
0307     return -EINVAL;
0308 }
0309 #endif
0310 
0311 static struct xt_target tcpmss_tg_reg[] __read_mostly = {
0312     {
0313         .family     = NFPROTO_IPV4,
0314         .name       = "TCPMSS",
0315         .checkentry = tcpmss_tg4_check,
0316         .target     = tcpmss_tg4,
0317         .targetsize = sizeof(struct xt_tcpmss_info),
0318         .proto      = IPPROTO_TCP,
0319         .me     = THIS_MODULE,
0320     },
0321 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
0322     {
0323         .family     = NFPROTO_IPV6,
0324         .name       = "TCPMSS",
0325         .checkentry = tcpmss_tg6_check,
0326         .target     = tcpmss_tg6,
0327         .targetsize = sizeof(struct xt_tcpmss_info),
0328         .proto      = IPPROTO_TCP,
0329         .me     = THIS_MODULE,
0330     },
0331 #endif
0332 };
0333 
0334 static int __init tcpmss_tg_init(void)
0335 {
0336     return xt_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
0337 }
0338 
0339 static void __exit tcpmss_tg_exit(void)
0340 {
0341     xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
0342 }
0343 
0344 module_init(tcpmss_tg_init);
0345 module_exit(tcpmss_tg_exit);