linux/net/netfilter/nf_conntrack_sane.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* SANE connection tracking helper
   3 * (SANE = Scanner Access Now Easy)
   4 * For documentation about the SANE network protocol see
   5 * http://www.sane-project.org/html/doc015.html
   6 */
   7
   8/* Copyright (C) 2007 Red Hat, Inc.
   9 * Author: Michal Schmidt <mschmidt@redhat.com>
  10 * Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c):
  11 *  (C) 1999-2001 Paul `Rusty' Russell
  12 *  (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
  13 *  (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
  14 *  (C) 2003 Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
  15 */
  16
  17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  18
  19#include <linux/module.h>
  20#include <linux/moduleparam.h>
  21#include <linux/netfilter.h>
  22#include <linux/slab.h>
  23#include <linux/in.h>
  24#include <linux/tcp.h>
  25#include <net/netfilter/nf_conntrack.h>
  26#include <net/netfilter/nf_conntrack_helper.h>
  27#include <net/netfilter/nf_conntrack_expect.h>
  28#include <linux/netfilter/nf_conntrack_sane.h>
  29
  30#define HELPER_NAME "sane"
  31
  32MODULE_LICENSE("GPL");
  33MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
  34MODULE_DESCRIPTION("SANE connection tracking helper");
  35MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
  36
  37static char *sane_buffer;
  38
  39static DEFINE_SPINLOCK(nf_sane_lock);
  40
  41#define MAX_PORTS 8
  42static u_int16_t ports[MAX_PORTS];
  43static unsigned int ports_c;
  44module_param_array(ports, ushort, &ports_c, 0400);
  45
  46struct sane_request {
  47        __be32 RPC_code;
  48#define SANE_NET_START      7   /* RPC code */
  49
  50        __be32 handle;
  51};
  52
  53struct sane_reply_net_start {
  54        __be32 status;
  55#define SANE_STATUS_SUCCESS 0
  56
  57        __be16 zero;
  58        __be16 port;
  59        /* other fields aren't interesting for conntrack */
  60};
  61
  62static int help(struct sk_buff *skb,
  63                unsigned int protoff,
  64                struct nf_conn *ct,
  65                enum ip_conntrack_info ctinfo)
  66{
  67        unsigned int dataoff, datalen;
  68        const struct tcphdr *th;
  69        struct tcphdr _tcph;
  70        void *sb_ptr;
  71        int ret = NF_ACCEPT;
  72        int dir = CTINFO2DIR(ctinfo);
  73        struct nf_ct_sane_master *ct_sane_info = nfct_help_data(ct);
  74        struct nf_conntrack_expect *exp;
  75        struct nf_conntrack_tuple *tuple;
  76        struct sane_request *req;
  77        struct sane_reply_net_start *reply;
  78
  79        /* Until there's been traffic both ways, don't look in packets. */
  80        if (ctinfo != IP_CT_ESTABLISHED &&
  81            ctinfo != IP_CT_ESTABLISHED_REPLY)
  82                return NF_ACCEPT;
  83
  84        /* Not a full tcp header? */
  85        th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
  86        if (th == NULL)
  87                return NF_ACCEPT;
  88
  89        /* No data? */
  90        dataoff = protoff + th->doff * 4;
  91        if (dataoff >= skb->len)
  92                return NF_ACCEPT;
  93
  94        datalen = skb->len - dataoff;
  95
  96        spin_lock_bh(&nf_sane_lock);
  97        sb_ptr = skb_header_pointer(skb, dataoff, datalen, sane_buffer);
  98        if (!sb_ptr) {
  99                spin_unlock_bh(&nf_sane_lock);
 100                return NF_ACCEPT;
 101        }
 102
 103        if (dir == IP_CT_DIR_ORIGINAL) {
 104                if (datalen != sizeof(struct sane_request))
 105                        goto out;
 106
 107                req = sb_ptr;
 108                if (req->RPC_code != htonl(SANE_NET_START)) {
 109                        /* Not an interesting command */
 110                        ct_sane_info->state = SANE_STATE_NORMAL;
 111                        goto out;
 112                }
 113
 114                /* We're interested in the next reply */
 115                ct_sane_info->state = SANE_STATE_START_REQUESTED;
 116                goto out;
 117        }
 118
 119        /* Is it a reply to an uninteresting command? */
 120        if (ct_sane_info->state != SANE_STATE_START_REQUESTED)
 121                goto out;
 122
 123        /* It's a reply to SANE_NET_START. */
 124        ct_sane_info->state = SANE_STATE_NORMAL;
 125
 126        if (datalen < sizeof(struct sane_reply_net_start)) {
 127                pr_debug("NET_START reply too short\n");
 128                goto out;
 129        }
 130
 131        reply = sb_ptr;
 132        if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
 133                /* saned refused the command */
 134                pr_debug("unsuccessful SANE_STATUS = %u\n",
 135                         ntohl(reply->status));
 136                goto out;
 137        }
 138
 139        /* Invalid saned reply? Ignore it. */
 140        if (reply->zero != 0)
 141                goto out;
 142
 143        exp = nf_ct_expect_alloc(ct);
 144        if (exp == NULL) {
 145                nf_ct_helper_log(skb, ct, "cannot alloc expectation");
 146                ret = NF_DROP;
 147                goto out;
 148        }
 149
 150        tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
 151        nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
 152                          &tuple->src.u3, &tuple->dst.u3,
 153                          IPPROTO_TCP, NULL, &reply->port);
 154
 155        pr_debug("expect: ");
 156        nf_ct_dump_tuple(&exp->tuple);
 157
 158        /* Can't expect this?  Best to drop packet now. */
 159        if (nf_ct_expect_related(exp, 0) != 0) {
 160                nf_ct_helper_log(skb, ct, "cannot add expectation");
 161                ret = NF_DROP;
 162        }
 163
 164        nf_ct_expect_put(exp);
 165
 166out:
 167        spin_unlock_bh(&nf_sane_lock);
 168        return ret;
 169}
 170
 171static struct nf_conntrack_helper sane[MAX_PORTS * 2] __read_mostly;
 172
 173static const struct nf_conntrack_expect_policy sane_exp_policy = {
 174        .max_expected   = 1,
 175        .timeout        = 5 * 60,
 176};
 177
 178static void __exit nf_conntrack_sane_fini(void)
 179{
 180        nf_conntrack_helpers_unregister(sane, ports_c * 2);
 181        kfree(sane_buffer);
 182}
 183
 184static int __init nf_conntrack_sane_init(void)
 185{
 186        int i, ret = 0;
 187
 188        NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_sane_master));
 189
 190        sane_buffer = kmalloc(65536, GFP_KERNEL);
 191        if (!sane_buffer)
 192                return -ENOMEM;
 193
 194        if (ports_c == 0)
 195                ports[ports_c++] = SANE_PORT;
 196
 197        /* FIXME should be configurable whether IPv4 and IPv6 connections
 198                 are tracked or not - YK */
 199        for (i = 0; i < ports_c; i++) {
 200                nf_ct_helper_init(&sane[2 * i], AF_INET, IPPROTO_TCP,
 201                                  HELPER_NAME, SANE_PORT, ports[i], ports[i],
 202                                  &sane_exp_policy, 0, help, NULL,
 203                                  THIS_MODULE);
 204                nf_ct_helper_init(&sane[2 * i + 1], AF_INET6, IPPROTO_TCP,
 205                                  HELPER_NAME, SANE_PORT, ports[i], ports[i],
 206                                  &sane_exp_policy, 0, help, NULL,
 207                                  THIS_MODULE);
 208        }
 209
 210        ret = nf_conntrack_helpers_register(sane, ports_c * 2);
 211        if (ret < 0) {
 212                pr_err("failed to register helpers\n");
 213                kfree(sane_buffer);
 214                return ret;
 215        }
 216
 217        return 0;
 218}
 219
 220module_init(nf_conntrack_sane_init);
 221module_exit(nf_conntrack_sane_fini);
 222