linux/net/netfilter/xt_tcpmss.c
<<
>>
Prefs
   1/* Kernel module to match TCP MSS values. */
   2
   3/* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
   4 * Portions (C) 2005 by Harald Welte <laforge@netfilter.org>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/skbuff.h>
  13#include <net/tcp.h>
  14
  15#include <linux/netfilter/xt_tcpmss.h>
  16#include <linux/netfilter/x_tables.h>
  17
  18#include <linux/netfilter_ipv4/ip_tables.h>
  19#include <linux/netfilter_ipv6/ip6_tables.h>
  20
  21MODULE_LICENSE("GPL");
  22MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
  23MODULE_DESCRIPTION("Xtables: TCP MSS match");
  24MODULE_ALIAS("ipt_tcpmss");
  25MODULE_ALIAS("ip6t_tcpmss");
  26
  27static bool
  28tcpmss_mt(const struct sk_buff *skb, const struct xt_match_param *par)
  29{
  30        const struct xt_tcpmss_match_info *info = par->matchinfo;
  31        const struct tcphdr *th;
  32        struct tcphdr _tcph;
  33        /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
  34        const u_int8_t *op;
  35        u8 _opt[15 * 4 - sizeof(_tcph)];
  36        unsigned int i, optlen;
  37
  38        /* If we don't have the whole header, drop packet. */
  39        th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
  40        if (th == NULL)
  41                goto dropit;
  42
  43        /* Malformed. */
  44        if (th->doff*4 < sizeof(*th))
  45                goto dropit;
  46
  47        optlen = th->doff*4 - sizeof(*th);
  48        if (!optlen)
  49                goto out;
  50
  51        /* Truncated options. */
  52        op = skb_header_pointer(skb, par->thoff + sizeof(*th), optlen, _opt);
  53        if (op == NULL)
  54                goto dropit;
  55
  56        for (i = 0; i < optlen; ) {
  57                if (op[i] == TCPOPT_MSS
  58                    && (optlen - i) >= TCPOLEN_MSS
  59                    && op[i+1] == TCPOLEN_MSS) {
  60                        u_int16_t mssval;
  61
  62                        mssval = (op[i+2] << 8) | op[i+3];
  63
  64                        return (mssval >= info->mss_min &&
  65                                mssval <= info->mss_max) ^ info->invert;
  66                }
  67                if (op[i] < 2)
  68                        i++;
  69                else
  70                        i += op[i+1] ? : 1;
  71        }
  72out:
  73        return info->invert;
  74
  75dropit:
  76        *par->hotdrop = true;
  77        return false;
  78}
  79
  80static struct xt_match tcpmss_mt_reg[] __read_mostly = {
  81        {
  82                .name           = "tcpmss",
  83                .family         = NFPROTO_IPV4,
  84                .match          = tcpmss_mt,
  85                .matchsize      = sizeof(struct xt_tcpmss_match_info),
  86                .proto          = IPPROTO_TCP,
  87                .me             = THIS_MODULE,
  88        },
  89        {
  90                .name           = "tcpmss",
  91                .family         = NFPROTO_IPV6,
  92                .match          = tcpmss_mt,
  93                .matchsize      = sizeof(struct xt_tcpmss_match_info),
  94                .proto          = IPPROTO_TCP,
  95                .me             = THIS_MODULE,
  96        },
  97};
  98
  99static int __init tcpmss_mt_init(void)
 100{
 101        return xt_register_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
 102}
 103
 104static void __exit tcpmss_mt_exit(void)
 105{
 106        xt_unregister_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
 107}
 108
 109module_init(tcpmss_mt_init);
 110module_exit(tcpmss_mt_exit);
 111