0001
0002
0003
0004
0005
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
0031 const u_int8_t *op;
0032 u8 _opt[15 * 4 - sizeof(_tcph)];
0033 unsigned int i, optlen;
0034
0035
0036 th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
0037 if (th == NULL)
0038 goto dropit;
0039
0040
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
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);