root/net/netfilter/nf_conntrack_sane.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. help
  2. nf_conntrack_sane_fini
  3. nf_conntrack_sane_init

   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 
  32 MODULE_LICENSE("GPL");
  33 MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
  34 MODULE_DESCRIPTION("SANE connection tracking helper");
  35 MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
  36 
  37 static char *sane_buffer;
  38 
  39 static DEFINE_SPINLOCK(nf_sane_lock);
  40 
  41 #define MAX_PORTS 8
  42 static u_int16_t ports[MAX_PORTS];
  43 static unsigned int ports_c;
  44 module_param_array(ports, ushort, &ports_c, 0400);
  45 
  46 struct sane_request {
  47         __be32 RPC_code;
  48 #define SANE_NET_START      7   /* RPC code */
  49 
  50         __be32 handle;
  51 };
  52 
  53 struct 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 
  62 static 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 
 163 out:
 164         spin_unlock_bh(&nf_sane_lock);
 165         return ret;
 166 }
 167 
 168 static struct nf_conntrack_helper sane[MAX_PORTS * 2] __read_mostly;
 169 
 170 static const struct nf_conntrack_expect_policy sane_exp_policy = {
 171         .max_expected   = 1,
 172         .timeout        = 5 * 60,
 173 };
 174 
 175 static void __exit nf_conntrack_sane_fini(void)
 176 {
 177         nf_conntrack_helpers_unregister(sane, ports_c * 2);
 178         kfree(sane_buffer);
 179 }
 180 
 181 static 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 
 217 module_init(nf_conntrack_sane_init);
 218 module_exit(nf_conntrack_sane_fini);

/* [<][>][^][v][top][bottom][index][help] */