0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
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
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
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
0078 if (ctinfo != IP_CT_ESTABLISHED &&
0079 ctinfo != IP_CT_ESTABLISHED_REPLY)
0080 return NF_ACCEPT;
0081
0082
0083 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
0084 if (th == NULL)
0085 return NF_ACCEPT;
0086
0087
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
0105 WRITE_ONCE(ct_sane_info->state, SANE_STATE_NORMAL);
0106 return NF_ACCEPT;
0107 }
0108
0109
0110 WRITE_ONCE(ct_sane_info->state, SANE_STATE_START_REQUESTED);
0111 return NF_ACCEPT;
0112 }
0113
0114
0115
0116
0117 if (READ_ONCE(ct_sane_info->state) != SANE_STATE_START_REQUESTED)
0118 return NF_ACCEPT;
0119
0120
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
0136 pr_debug("unsuccessful SANE_STATUS = %u\n",
0137 ntohl(reply->status));
0138 return NF_ACCEPT;
0139 }
0140
0141
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
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
0191
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);