linux/net/netfilter/nf_conntrack_amanda.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* Amanda extension for IP connection tracking
   3 *
   4 * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
   5 * based on HW's ip_conntrack_irc.c as well as other modules
   6 * (C) 2006 Patrick McHardy <kaber@trash.net>
   7 */
   8#include <linux/kernel.h>
   9#include <linux/module.h>
  10#include <linux/moduleparam.h>
  11#include <linux/textsearch.h>
  12#include <linux/skbuff.h>
  13#include <linux/in.h>
  14#include <linux/udp.h>
  15#include <linux/netfilter.h>
  16#include <linux/gfp.h>
  17
  18#include <net/netfilter/nf_conntrack.h>
  19#include <net/netfilter/nf_conntrack_expect.h>
  20#include <net/netfilter/nf_conntrack_ecache.h>
  21#include <net/netfilter/nf_conntrack_helper.h>
  22#include <linux/netfilter/nf_conntrack_amanda.h>
  23
  24static unsigned int master_timeout __read_mostly = 300;
  25static char *ts_algo = "kmp";
  26
  27#define HELPER_NAME "amanda"
  28
  29MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
  30MODULE_DESCRIPTION("Amanda connection tracking module");
  31MODULE_LICENSE("GPL");
  32MODULE_ALIAS("ip_conntrack_amanda");
  33MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
  34
  35module_param(master_timeout, uint, 0600);
  36MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
  37module_param(ts_algo, charp, 0400);
  38MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)");
  39
  40unsigned int (*nf_nat_amanda_hook)(struct sk_buff *skb,
  41                                   enum ip_conntrack_info ctinfo,
  42                                   unsigned int protoff,
  43                                   unsigned int matchoff,
  44                                   unsigned int matchlen,
  45                                   struct nf_conntrack_expect *exp)
  46                                   __read_mostly;
  47EXPORT_SYMBOL_GPL(nf_nat_amanda_hook);
  48
  49enum amanda_strings {
  50        SEARCH_CONNECT,
  51        SEARCH_NEWLINE,
  52        SEARCH_DATA,
  53        SEARCH_MESG,
  54        SEARCH_INDEX,
  55        SEARCH_STATE,
  56};
  57
  58static struct {
  59        const char              *string;
  60        size_t                  len;
  61        struct ts_config        *ts;
  62} search[] __read_mostly = {
  63        [SEARCH_CONNECT] = {
  64                .string = "CONNECT ",
  65                .len    = 8,
  66        },
  67        [SEARCH_NEWLINE] = {
  68                .string = "\n",
  69                .len    = 1,
  70        },
  71        [SEARCH_DATA] = {
  72                .string = "DATA ",
  73                .len    = 5,
  74        },
  75        [SEARCH_MESG] = {
  76                .string = "MESG ",
  77                .len    = 5,
  78        },
  79        [SEARCH_INDEX] = {
  80                .string = "INDEX ",
  81                .len    = 6,
  82        },
  83        [SEARCH_STATE] = {
  84                .string = "STATE ",
  85                .len    = 6,
  86        },
  87};
  88
  89static int amanda_help(struct sk_buff *skb,
  90                       unsigned int protoff,
  91                       struct nf_conn *ct,
  92                       enum ip_conntrack_info ctinfo)
  93{
  94        struct nf_conntrack_expect *exp;
  95        struct nf_conntrack_tuple *tuple;
  96        unsigned int dataoff, start, stop, off, i;
  97        char pbuf[sizeof("65535")], *tmp;
  98        u_int16_t len;
  99        __be16 port;
 100        int ret = NF_ACCEPT;
 101        typeof(nf_nat_amanda_hook) nf_nat_amanda;
 102
 103        /* Only look at packets from the Amanda server */
 104        if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
 105                return NF_ACCEPT;
 106
 107        /* increase the UDP timeout of the master connection as replies from
 108         * Amanda clients to the server can be quite delayed */
 109        nf_ct_refresh(ct, skb, master_timeout * HZ);
 110
 111        /* No data? */
 112        dataoff = protoff + sizeof(struct udphdr);
 113        if (dataoff >= skb->len) {
 114                net_err_ratelimited("amanda_help: skblen = %u\n", skb->len);
 115                return NF_ACCEPT;
 116        }
 117
 118        start = skb_find_text(skb, dataoff, skb->len,
 119                              search[SEARCH_CONNECT].ts);
 120        if (start == UINT_MAX)
 121                goto out;
 122        start += dataoff + search[SEARCH_CONNECT].len;
 123
 124        stop = skb_find_text(skb, start, skb->len,
 125                             search[SEARCH_NEWLINE].ts);
 126        if (stop == UINT_MAX)
 127                goto out;
 128        stop += start;
 129
 130        for (i = SEARCH_DATA; i <= SEARCH_STATE; i++) {
 131                off = skb_find_text(skb, start, stop, search[i].ts);
 132                if (off == UINT_MAX)
 133                        continue;
 134                off += start + search[i].len;
 135
 136                len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off);
 137                if (skb_copy_bits(skb, off, pbuf, len))
 138                        break;
 139                pbuf[len] = '\0';
 140
 141                port = htons(simple_strtoul(pbuf, &tmp, 10));
 142                len = tmp - pbuf;
 143                if (port == 0 || len > 5)
 144                        break;
 145
 146                exp = nf_ct_expect_alloc(ct);
 147                if (exp == NULL) {
 148                        nf_ct_helper_log(skb, ct, "cannot alloc expectation");
 149                        ret = NF_DROP;
 150                        goto out;
 151                }
 152                tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
 153                nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
 154                                  nf_ct_l3num(ct),
 155                                  &tuple->src.u3, &tuple->dst.u3,
 156                                  IPPROTO_TCP, NULL, &port);
 157
 158                nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook);
 159                if (nf_nat_amanda && ct->status & IPS_NAT_MASK)
 160                        ret = nf_nat_amanda(skb, ctinfo, protoff,
 161                                            off - dataoff, len, exp);
 162                else if (nf_ct_expect_related(exp, 0) != 0) {
 163                        nf_ct_helper_log(skb, ct, "cannot add expectation");
 164                        ret = NF_DROP;
 165                }
 166                nf_ct_expect_put(exp);
 167        }
 168
 169out:
 170        return ret;
 171}
 172
 173static const struct nf_conntrack_expect_policy amanda_exp_policy = {
 174        .max_expected           = 4,
 175        .timeout                = 180,
 176};
 177
 178static struct nf_conntrack_helper amanda_helper[2] __read_mostly = {
 179        {
 180                .name                   = HELPER_NAME,
 181                .me                     = THIS_MODULE,
 182                .help                   = amanda_help,
 183                .tuple.src.l3num        = AF_INET,
 184                .tuple.src.u.udp.port   = cpu_to_be16(10080),
 185                .tuple.dst.protonum     = IPPROTO_UDP,
 186                .expect_policy          = &amanda_exp_policy,
 187                .nat_mod_name           = NF_NAT_HELPER_NAME(HELPER_NAME),
 188        },
 189        {
 190                .name                   = "amanda",
 191                .me                     = THIS_MODULE,
 192                .help                   = amanda_help,
 193                .tuple.src.l3num        = AF_INET6,
 194                .tuple.src.u.udp.port   = cpu_to_be16(10080),
 195                .tuple.dst.protonum     = IPPROTO_UDP,
 196                .expect_policy          = &amanda_exp_policy,
 197                .nat_mod_name           = NF_NAT_HELPER_NAME(HELPER_NAME),
 198        },
 199};
 200
 201static void __exit nf_conntrack_amanda_fini(void)
 202{
 203        int i;
 204
 205        nf_conntrack_helpers_unregister(amanda_helper,
 206                                        ARRAY_SIZE(amanda_helper));
 207        for (i = 0; i < ARRAY_SIZE(search); i++)
 208                textsearch_destroy(search[i].ts);
 209}
 210
 211static int __init nf_conntrack_amanda_init(void)
 212{
 213        int ret, i;
 214
 215        NF_CT_HELPER_BUILD_BUG_ON(0);
 216
 217        for (i = 0; i < ARRAY_SIZE(search); i++) {
 218                search[i].ts = textsearch_prepare(ts_algo, search[i].string,
 219                                                  search[i].len,
 220                                                  GFP_KERNEL, TS_AUTOLOAD);
 221                if (IS_ERR(search[i].ts)) {
 222                        ret = PTR_ERR(search[i].ts);
 223                        goto err1;
 224                }
 225        }
 226        ret = nf_conntrack_helpers_register(amanda_helper,
 227                                            ARRAY_SIZE(amanda_helper));
 228        if (ret < 0)
 229                goto err1;
 230        return 0;
 231
 232err1:
 233        while (--i >= 0)
 234                textsearch_destroy(search[i].ts);
 235
 236        return ret;
 237}
 238
 239module_init(nf_conntrack_amanda_init);
 240module_exit(nf_conntrack_amanda_fini);
 241