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        BUG_ON(sb_ptr == NULL);
  99
 100        if (dir == IP_CT_DIR_ORIGINAL) {
 101                if (datalen != sizeof(struct sane_request))
 102                        goto out;
 103
 104                req = sb_ptr;
 105                if (req->RPC_code != htonl(SANE_NET_START)) {
 106                        /* Not an interesting command */
 107                        ct_sane_info->state = SANE_STATE_NORMAL;
 108                        goto out;
 109                }
 110
 111                /* We're interested in the next reply */
 112                ct_sane_info->state = SANE_STATE_START_REQUESTED;
 113                goto out;
 114        }
 115
 116        /* Is it a reply to an uninteresting command? */
 117        if (ct_sane_info->state != SANE_STATE_START_REQUESTED)
 118                goto out;
 119
 120        /* It's a reply to SANE_NET_START. */
 121        ct_sane_info->state = SANE_STATE_NORMAL;
 122
 123        if (datalen < sizeof(struct sane_reply_net_start)) {
 124                pr_debug("NET_START reply too short\n");
 125                goto out;
 126        }
 127
 128        reply = sb_ptr;
 129        if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
 130                /* saned refused the command */
 131                pr_debug("unsuccessful SANE_STATUS = %u\n",
 132                         ntohl(reply->status));
 133                goto out;
 134        }
 135
 136        /* Invalid saned reply? Ignore it. */
 137        if (reply->zero != 0)
 138                goto out;
 139
 140        exp = nf_ct_expect_alloc(ct);
 141        if (exp == NULL) {
 142                nf_ct_helper_log(skb, ct, "cannot alloc expectation");
 143                ret = NF_DROP;
 144                goto out;
 145        }
 146
 147        tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
 148        nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
 149                          &tuple->src.u3, &tuple->dst.u3,
 150                          IPPROTO_TCP, NULL, &reply->port);
 151
 152        pr_debug("expect: ");
 153        nf_ct_dump_tuple(&exp->tuple);
 154
 155        /* Can't expect this?  Best to drop packet now. */
 156        if (nf_ct_expect_related(exp, 0) != 0) {
 157                nf_ct_helper_log(skb, ct, "cannot add expectation");
 158                ret = NF_DROP;
 159        }
 160
 161        nf_ct_expect_put(exp);
 162
 163out:
 164        spin_unlock_bh(&nf_sane_lock);
 165        return ret;
 166}
 167
 168static struct nf_conntrack_helper sane[MAX_PORTS * 2] __read_mostly;
 169
 170static const struct nf_conntrack_expect_policy sane_exp_policy = {
 171        .max_expected   = 1,
 172        .timeout        = 5 * 60,
 173};
 174
 175static void __exit nf_conntrack_sane_fini(void)
 176{
 177        nf_conntrack_helpers_unregister(sane, ports_c * 2);
 178        kfree(sane_buffer);
 179}
 180
 181static int __init nf_conntrack_sane_init(void)
 182{
 183        int i, ret = 0;
 184
 185        NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_sane_master));
 186
 187        sane_buffer = kmalloc(65536, GFP_KERNEL);
 188        if (!sane_buffer)
 189                return -ENOMEM;
 190
 191        if (ports_c == 0)
 192                ports[ports_c++] = SANE_PORT;
 193
 194        /* FIXME should be configurable whether IPv4 and IPv6 connections
 195                 are tracked or not - YK */
 196        for (i = 0; i < ports_c; i++) {
 197                nf_ct_helper_init(&sane[2 * i], AF_INET, IPPROTO_TCP,
 198                                  HELPER_NAME, SANE_PORT, ports[i], ports[i],
 199                                  &sane_exp_policy, 0, help, NULL,
 200                                  THIS_MODULE);
 201                nf_ct_helper_init(&sane[2 * i + 1], AF_INET6, IPPROTO_TCP,
 202                                  HELPER_NAME, SANE_PORT, ports[i], ports[i],
 203                                  &sane_exp_policy, 0, help, NULL,
 204                                  THIS_MODULE);
 205        }
 206
 207        ret = nf_conntrack_helpers_register(sane, ports_c * 2);
 208        if (ret < 0) {
 209                pr_err("failed to register helpers\n");
 210                kfree(sane_buffer);
 211                return ret;
 212        }
 213
 214        return 0;
 215}
 216
 217module_init(nf_conntrack_sane_init);
 218module_exit(nf_conntrack_sane_fini);
 219