Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Kernel module to match TCP MSS values. */
0003 
0004 /* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
0005  * Portions (C) 2005 by Harald Welte <laforge@netfilter.org>
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/skbuff.h>
0010 #include <net/tcp.h>
0011 
0012 #include <linux/netfilter/xt_tcpmss.h>
0013 #include <linux/netfilter/x_tables.h>
0014 
0015 #include <linux/netfilter_ipv4/ip_tables.h>
0016 #include <linux/netfilter_ipv6/ip6_tables.h>
0017 
0018 MODULE_LICENSE("GPL");
0019 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
0020 MODULE_DESCRIPTION("Xtables: TCP MSS match");
0021 MODULE_ALIAS("ipt_tcpmss");
0022 MODULE_ALIAS("ip6t_tcpmss");
0023 
0024 static bool
0025 tcpmss_mt(const struct sk_buff *skb, struct xt_action_param *par)
0026 {
0027     const struct xt_tcpmss_match_info *info = par->matchinfo;
0028     const struct tcphdr *th;
0029     struct tcphdr _tcph;
0030     /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
0031     const u_int8_t *op;
0032     u8 _opt[15 * 4 - sizeof(_tcph)];
0033     unsigned int i, optlen;
0034 
0035     /* If we don't have the whole header, drop packet. */
0036     th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
0037     if (th == NULL)
0038         goto dropit;
0039 
0040     /* Malformed. */
0041     if (th->doff*4 < sizeof(*th))
0042         goto dropit;
0043 
0044     optlen = th->doff*4 - sizeof(*th);
0045     if (!optlen)
0046         goto out;
0047 
0048     /* Truncated options. */
0049     op = skb_header_pointer(skb, par->thoff + sizeof(*th), optlen, _opt);
0050     if (op == NULL)
0051         goto dropit;
0052 
0053     for (i = 0; i < optlen; ) {
0054         if (op[i] == TCPOPT_MSS
0055             && (optlen - i) >= TCPOLEN_MSS
0056             && op[i+1] == TCPOLEN_MSS) {
0057             u_int16_t mssval;
0058 
0059             mssval = (op[i+2] << 8) | op[i+3];
0060 
0061             return (mssval >= info->mss_min &&
0062                 mssval <= info->mss_max) ^ info->invert;
0063         }
0064         if (op[i] < 2)
0065             i++;
0066         else
0067             i += op[i+1] ? : 1;
0068     }
0069 out:
0070     return info->invert;
0071 
0072 dropit:
0073     par->hotdrop = true;
0074     return false;
0075 }
0076 
0077 static struct xt_match tcpmss_mt_reg[] __read_mostly = {
0078     {
0079         .name       = "tcpmss",
0080         .family     = NFPROTO_IPV4,
0081         .match      = tcpmss_mt,
0082         .matchsize  = sizeof(struct xt_tcpmss_match_info),
0083         .proto      = IPPROTO_TCP,
0084         .me     = THIS_MODULE,
0085     },
0086     {
0087         .name       = "tcpmss",
0088         .family     = NFPROTO_IPV6,
0089         .match      = tcpmss_mt,
0090         .matchsize  = sizeof(struct xt_tcpmss_match_info),
0091         .proto      = IPPROTO_TCP,
0092         .me     = THIS_MODULE,
0093     },
0094 };
0095 
0096 static int __init tcpmss_mt_init(void)
0097 {
0098     return xt_register_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
0099 }
0100 
0101 static void __exit tcpmss_mt_exit(void)
0102 {
0103     xt_unregister_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
0104 }
0105 
0106 module_init(tcpmss_mt_init);
0107 module_exit(tcpmss_mt_exit);