Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* SANE connection tracking helper
0003  * (SANE = Scanner Access Now Easy)
0004  * For documentation about the SANE network protocol see
0005  * http://www.sane-project.org/html/doc015.html
0006  */
0007 
0008 /* Copyright (C) 2007 Red Hat, Inc.
0009  * Author: Michal Schmidt <mschmidt@redhat.com>
0010  * Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c):
0011  *  (C) 1999-2001 Paul `Rusty' Russell
0012  *  (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
0013  *  (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
0014  *  (C) 2003 Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
0015  */
0016 
0017 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0018 
0019 #include <linux/module.h>
0020 #include <linux/moduleparam.h>
0021 #include <linux/netfilter.h>
0022 #include <linux/slab.h>
0023 #include <linux/in.h>
0024 #include <linux/tcp.h>
0025 #include <net/netfilter/nf_conntrack.h>
0026 #include <net/netfilter/nf_conntrack_helper.h>
0027 #include <net/netfilter/nf_conntrack_expect.h>
0028 #include <linux/netfilter/nf_conntrack_sane.h>
0029 
0030 #define HELPER_NAME "sane"
0031 
0032 MODULE_LICENSE("GPL");
0033 MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
0034 MODULE_DESCRIPTION("SANE connection tracking helper");
0035 MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
0036 
0037 #define MAX_PORTS 8
0038 static u_int16_t ports[MAX_PORTS];
0039 static unsigned int ports_c;
0040 module_param_array(ports, ushort, &ports_c, 0400);
0041 
0042 struct sane_request {
0043     __be32 RPC_code;
0044 #define SANE_NET_START      7   /* RPC code */
0045 
0046     __be32 handle;
0047 };
0048 
0049 struct sane_reply_net_start {
0050     __be32 status;
0051 #define SANE_STATUS_SUCCESS 0
0052 
0053     __be16 zero;
0054     __be16 port;
0055     /* other fields aren't interesting for conntrack */
0056 };
0057 
0058 static int help(struct sk_buff *skb,
0059         unsigned int protoff,
0060         struct nf_conn *ct,
0061         enum ip_conntrack_info ctinfo)
0062 {
0063     unsigned int dataoff, datalen;
0064     const struct tcphdr *th;
0065     struct tcphdr _tcph;
0066     int ret = NF_ACCEPT;
0067     int dir = CTINFO2DIR(ctinfo);
0068     struct nf_ct_sane_master *ct_sane_info = nfct_help_data(ct);
0069     struct nf_conntrack_expect *exp;
0070     struct nf_conntrack_tuple *tuple;
0071     struct sane_reply_net_start *reply;
0072     union {
0073         struct sane_request req;
0074         struct sane_reply_net_start repl;
0075     } buf;
0076 
0077     /* Until there's been traffic both ways, don't look in packets. */
0078     if (ctinfo != IP_CT_ESTABLISHED &&
0079         ctinfo != IP_CT_ESTABLISHED_REPLY)
0080         return NF_ACCEPT;
0081 
0082     /* Not a full tcp header? */
0083     th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
0084     if (th == NULL)
0085         return NF_ACCEPT;
0086 
0087     /* No data? */
0088     dataoff = protoff + th->doff * 4;
0089     if (dataoff >= skb->len)
0090         return NF_ACCEPT;
0091 
0092     datalen = skb->len - dataoff;
0093     if (dir == IP_CT_DIR_ORIGINAL) {
0094         const struct sane_request *req;
0095 
0096         if (datalen != sizeof(struct sane_request))
0097             return NF_ACCEPT;
0098 
0099         req = skb_header_pointer(skb, dataoff, datalen, &buf.req);
0100         if (!req)
0101             return NF_ACCEPT;
0102 
0103         if (req->RPC_code != htonl(SANE_NET_START)) {
0104             /* Not an interesting command */
0105             WRITE_ONCE(ct_sane_info->state, SANE_STATE_NORMAL);
0106             return NF_ACCEPT;
0107         }
0108 
0109         /* We're interested in the next reply */
0110         WRITE_ONCE(ct_sane_info->state, SANE_STATE_START_REQUESTED);
0111         return NF_ACCEPT;
0112     }
0113 
0114     /* IP_CT_DIR_REPLY */
0115 
0116     /* Is it a reply to an uninteresting command? */
0117     if (READ_ONCE(ct_sane_info->state) != SANE_STATE_START_REQUESTED)
0118         return NF_ACCEPT;
0119 
0120     /* It's a reply to SANE_NET_START. */
0121     WRITE_ONCE(ct_sane_info->state, SANE_STATE_NORMAL);
0122 
0123     if (datalen < sizeof(struct sane_reply_net_start)) {
0124         pr_debug("NET_START reply too short\n");
0125         return NF_ACCEPT;
0126     }
0127 
0128     datalen = sizeof(struct sane_reply_net_start);
0129 
0130     reply = skb_header_pointer(skb, dataoff, datalen, &buf.repl);
0131     if (!reply)
0132         return NF_ACCEPT;
0133 
0134     if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
0135         /* saned refused the command */
0136         pr_debug("unsuccessful SANE_STATUS = %u\n",
0137              ntohl(reply->status));
0138         return NF_ACCEPT;
0139     }
0140 
0141     /* Invalid saned reply? Ignore it. */
0142     if (reply->zero != 0)
0143         return NF_ACCEPT;
0144 
0145     exp = nf_ct_expect_alloc(ct);
0146     if (exp == NULL) {
0147         nf_ct_helper_log(skb, ct, "cannot alloc expectation");
0148         return NF_DROP;
0149     }
0150 
0151     tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
0152     nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
0153               &tuple->src.u3, &tuple->dst.u3,
0154               IPPROTO_TCP, NULL, &reply->port);
0155 
0156     pr_debug("expect: ");
0157     nf_ct_dump_tuple(&exp->tuple);
0158 
0159     /* Can't expect this?  Best to drop packet now. */
0160     if (nf_ct_expect_related(exp, 0) != 0) {
0161         nf_ct_helper_log(skb, ct, "cannot add expectation");
0162         ret = NF_DROP;
0163     }
0164 
0165     nf_ct_expect_put(exp);
0166     return ret;
0167 }
0168 
0169 static struct nf_conntrack_helper sane[MAX_PORTS * 2] __read_mostly;
0170 
0171 static const struct nf_conntrack_expect_policy sane_exp_policy = {
0172     .max_expected   = 1,
0173     .timeout    = 5 * 60,
0174 };
0175 
0176 static void __exit nf_conntrack_sane_fini(void)
0177 {
0178     nf_conntrack_helpers_unregister(sane, ports_c * 2);
0179 }
0180 
0181 static int __init nf_conntrack_sane_init(void)
0182 {
0183     int i, ret = 0;
0184 
0185     NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_sane_master));
0186 
0187     if (ports_c == 0)
0188         ports[ports_c++] = SANE_PORT;
0189 
0190     /* FIXME should be configurable whether IPv4 and IPv6 connections
0191          are tracked or not - YK */
0192     for (i = 0; i < ports_c; i++) {
0193         nf_ct_helper_init(&sane[2 * i], AF_INET, IPPROTO_TCP,
0194                   HELPER_NAME, SANE_PORT, ports[i], ports[i],
0195                   &sane_exp_policy, 0, help, NULL,
0196                   THIS_MODULE);
0197         nf_ct_helper_init(&sane[2 * i + 1], AF_INET6, IPPROTO_TCP,
0198                   HELPER_NAME, SANE_PORT, ports[i], ports[i],
0199                   &sane_exp_policy, 0, help, NULL,
0200                   THIS_MODULE);
0201     }
0202 
0203     ret = nf_conntrack_helpers_register(sane, ports_c * 2);
0204     if (ret < 0) {
0205         pr_err("failed to register helpers\n");
0206         return ret;
0207     }
0208 
0209     return 0;
0210 }
0211 
0212 module_init(nf_conntrack_sane_init);
0213 module_exit(nf_conntrack_sane_fini);