Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NETFILTER]: Add SANE connection tracking helper

This is nf_conntrack_sane, a netfilter connection tracking helper module
for the SANE protocol used by the 'saned' daemon to make scanners available
via network. The SANE protocol uses separate control & data connections,
similar to passive FTP. The helper module is needed to recognize the data
connection as RELATED to the control one.

Signed-off-by: Michal Schmidt <mschmidt@redhat.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Michal Schmidt and committed by
David S. Miller
6fecd198 719647e2

+279
+21
include/linux/netfilter/nf_conntrack_sane.h
··· 1 + #ifndef _NF_CONNTRACK_SANE_H 2 + #define _NF_CONNTRACK_SANE_H 3 + /* SANE tracking. */ 4 + 5 + #ifdef __KERNEL__ 6 + 7 + #define SANE_PORT 6566 8 + 9 + enum sane_state { 10 + SANE_STATE_NORMAL, 11 + SANE_STATE_START_REQUESTED, 12 + }; 13 + 14 + /* This structure exists only once per master */ 15 + struct nf_ct_sane_master { 16 + enum sane_state state; 17 + }; 18 + 19 + #endif /* __KERNEL__ */ 20 + 21 + #endif /* _NF_CONNTRACK_SANE_H */
+2
include/net/netfilter/nf_conntrack.h
··· 45 45 #include <linux/netfilter/nf_conntrack_ftp.h> 46 46 #include <linux/netfilter/nf_conntrack_pptp.h> 47 47 #include <linux/netfilter/nf_conntrack_h323.h> 48 + #include <linux/netfilter/nf_conntrack_sane.h> 48 49 49 50 /* per conntrack: application helper private data */ 50 51 union nf_conntrack_help { ··· 53 52 struct nf_ct_ftp_master ct_ftp_info; 54 53 struct nf_ct_pptp_master ct_pptp_info; 55 54 struct nf_ct_h323_master ct_h323_info; 55 + struct nf_ct_sane_master ct_sane_info; 56 56 }; 57 57 58 58 #include <linux/types.h>
+13
net/netfilter/Kconfig
··· 235 235 236 236 To compile it as a module, choose M here. If unsure, say N. 237 237 238 + config NF_CONNTRACK_SANE 239 + tristate "SANE protocol support (EXPERIMENTAL)" 240 + depends on EXPERIMENTAL && NF_CONNTRACK 241 + help 242 + SANE is a protocol for remote access to scanners as implemented 243 + by the 'saned' daemon. Like FTP, it uses separate control and 244 + data connections. 245 + 246 + With this module you can support SANE on a connection tracking 247 + firewall. 248 + 249 + To compile it as a module, choose M here. If unsure, say N. 250 + 238 251 config NF_CONNTRACK_SIP 239 252 tristate "SIP protocol support (EXPERIMENTAL)" 240 253 depends on EXPERIMENTAL && NF_CONNTRACK
+1
net/netfilter/Makefile
··· 29 29 obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o 30 30 obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o 31 31 obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o 32 + obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o 32 33 obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o 33 34 obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o 34 35
+242
net/netfilter/nf_conntrack_sane.c
··· 1 + /* SANE connection tracking helper 2 + * (SANE = Scanner Access Now Easy) 3 + * For documentation about the SANE network protocol see 4 + * http://www.sane-project.org/html/doc015.html 5 + */ 6 + 7 + /* Copyright (C) 2007 Red Hat, Inc. 8 + * Author: Michal Schmidt <mschmidt@redhat.com> 9 + * Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c): 10 + * (C) 1999-2001 Paul `Rusty' Russell 11 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> 12 + * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> 13 + * (C) 2003 Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> 14 + * 15 + * This program is free software; you can redistribute it and/or modify 16 + * it under the terms of the GNU General Public License version 2 as 17 + * published by the Free Software Foundation. 18 + */ 19 + 20 + #include <linux/module.h> 21 + #include <linux/moduleparam.h> 22 + #include <linux/netfilter.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 + MODULE_LICENSE("GPL"); 31 + MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>"); 32 + MODULE_DESCRIPTION("SANE connection tracking helper"); 33 + 34 + static char *sane_buffer; 35 + 36 + static DEFINE_SPINLOCK(nf_sane_lock); 37 + 38 + #define MAX_PORTS 8 39 + static u_int16_t ports[MAX_PORTS]; 40 + static unsigned int ports_c; 41 + module_param_array(ports, ushort, &ports_c, 0400); 42 + 43 + #if 0 44 + #define DEBUGP printk 45 + #else 46 + #define DEBUGP(format, args...) 47 + #endif 48 + 49 + struct sane_request { 50 + __be32 RPC_code; 51 + #define SANE_NET_START 7 /* RPC code */ 52 + 53 + __be32 handle; 54 + }; 55 + 56 + struct sane_reply_net_start { 57 + __be32 status; 58 + #define SANE_STATUS_SUCCESS 0 59 + 60 + __be16 zero; 61 + __be16 port; 62 + /* other fields aren't interesting for conntrack */ 63 + }; 64 + 65 + static int help(struct sk_buff **pskb, 66 + unsigned int protoff, 67 + struct nf_conn *ct, 68 + enum ip_conntrack_info ctinfo) 69 + { 70 + unsigned int dataoff, datalen; 71 + struct tcphdr _tcph, *th; 72 + char *sb_ptr; 73 + int ret = NF_ACCEPT; 74 + int dir = CTINFO2DIR(ctinfo); 75 + struct nf_ct_sane_master *ct_sane_info; 76 + struct nf_conntrack_expect *exp; 77 + struct nf_conntrack_tuple *tuple; 78 + struct sane_request *req; 79 + struct sane_reply_net_start *reply; 80 + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; 81 + 82 + ct_sane_info = &nfct_help(ct)->help.ct_sane_info; 83 + /* Until there's been traffic both ways, don't look in packets. */ 84 + if (ctinfo != IP_CT_ESTABLISHED && 85 + ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) 86 + return NF_ACCEPT; 87 + 88 + /* Not a full tcp header? */ 89 + th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph); 90 + if (th == NULL) 91 + return NF_ACCEPT; 92 + 93 + /* No data? */ 94 + dataoff = protoff + th->doff * 4; 95 + if (dataoff >= (*pskb)->len) 96 + return NF_ACCEPT; 97 + 98 + datalen = (*pskb)->len - dataoff; 99 + 100 + spin_lock_bh(&nf_sane_lock); 101 + sb_ptr = skb_header_pointer(*pskb, dataoff, datalen, sane_buffer); 102 + BUG_ON(sb_ptr == NULL); 103 + 104 + if (dir == IP_CT_DIR_ORIGINAL) { 105 + if (datalen != sizeof(struct sane_request)) 106 + goto out; 107 + 108 + req = (struct sane_request *)sb_ptr; 109 + if (req->RPC_code != htonl(SANE_NET_START)) { 110 + /* Not an interesting command */ 111 + ct_sane_info->state = SANE_STATE_NORMAL; 112 + goto out; 113 + } 114 + 115 + /* We're interested in the next reply */ 116 + ct_sane_info->state = SANE_STATE_START_REQUESTED; 117 + goto out; 118 + } 119 + 120 + /* Is it a reply to an uninteresting command? */ 121 + if (ct_sane_info->state != SANE_STATE_START_REQUESTED) 122 + goto out; 123 + 124 + /* It's a reply to SANE_NET_START. */ 125 + ct_sane_info->state = SANE_STATE_NORMAL; 126 + 127 + if (datalen < sizeof(struct sane_reply_net_start)) { 128 + DEBUGP("nf_ct_sane: NET_START reply too short\n"); 129 + goto out; 130 + } 131 + 132 + reply = (struct sane_reply_net_start *)sb_ptr; 133 + if (reply->status != htonl(SANE_STATUS_SUCCESS)) { 134 + /* saned refused the command */ 135 + DEBUGP("nf_ct_sane: unsuccessful SANE_STATUS = %u\n", 136 + ntohl(reply->status)); 137 + goto out; 138 + } 139 + 140 + /* Invalid saned reply? Ignore it. */ 141 + if (reply->zero != 0) 142 + goto out; 143 + 144 + exp = nf_conntrack_expect_alloc(ct); 145 + if (exp == NULL) { 146 + ret = NF_DROP; 147 + goto out; 148 + } 149 + 150 + tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; 151 + nf_conntrack_expect_init(exp, family, 152 + &tuple->src.u3, &tuple->dst.u3, 153 + IPPROTO_TCP, 154 + NULL, &reply->port); 155 + 156 + DEBUGP("nf_ct_sane: expect: "); 157 + NF_CT_DUMP_TUPLE(&exp->tuple); 158 + NF_CT_DUMP_TUPLE(&exp->mask); 159 + 160 + /* Can't expect this? Best to drop packet now. */ 161 + if (nf_conntrack_expect_related(exp) != 0) 162 + ret = NF_DROP; 163 + 164 + nf_conntrack_expect_put(exp); 165 + 166 + out: 167 + spin_unlock_bh(&nf_sane_lock); 168 + return ret; 169 + } 170 + 171 + static struct nf_conntrack_helper sane[MAX_PORTS][2]; 172 + static char sane_names[MAX_PORTS][2][sizeof("sane-65535")]; 173 + 174 + /* don't make this __exit, since it's called from __init ! */ 175 + static void nf_conntrack_sane_fini(void) 176 + { 177 + int i, j; 178 + 179 + for (i = 0; i < ports_c; i++) { 180 + for (j = 0; j < 2; j++) { 181 + DEBUGP("nf_ct_sane: unregistering helper for pf: %d " 182 + "port: %d\n", 183 + sane[i][j].tuple.src.l3num, ports[i]); 184 + nf_conntrack_helper_unregister(&sane[i][j]); 185 + } 186 + } 187 + 188 + kfree(sane_buffer); 189 + } 190 + 191 + static int __init nf_conntrack_sane_init(void) 192 + { 193 + int i, j = -1, ret = 0; 194 + char *tmpname; 195 + 196 + sane_buffer = kmalloc(65536, GFP_KERNEL); 197 + if (!sane_buffer) 198 + return -ENOMEM; 199 + 200 + if (ports_c == 0) 201 + ports[ports_c++] = SANE_PORT; 202 + 203 + /* FIXME should be configurable whether IPv4 and IPv6 connections 204 + are tracked or not - YK */ 205 + for (i = 0; i < ports_c; i++) { 206 + sane[i][0].tuple.src.l3num = PF_INET; 207 + sane[i][1].tuple.src.l3num = PF_INET6; 208 + for (j = 0; j < 2; j++) { 209 + sane[i][j].tuple.src.u.tcp.port = htons(ports[i]); 210 + sane[i][j].tuple.dst.protonum = IPPROTO_TCP; 211 + sane[i][j].mask.src.u.tcp.port = 0xFFFF; 212 + sane[i][j].mask.dst.protonum = 0xFF; 213 + sane[i][j].max_expected = 1; 214 + sane[i][j].timeout = 5 * 60; /* 5 Minutes */ 215 + sane[i][j].me = THIS_MODULE; 216 + sane[i][j].help = help; 217 + tmpname = &sane_names[i][j][0]; 218 + if (ports[i] == SANE_PORT) 219 + sprintf(tmpname, "sane"); 220 + else 221 + sprintf(tmpname, "sane-%d", ports[i]); 222 + sane[i][j].name = tmpname; 223 + 224 + DEBUGP("nf_ct_sane: registering helper for pf: %d " 225 + "port: %d\n", 226 + sane[i][j].tuple.src.l3num, ports[i]); 227 + ret = nf_conntrack_helper_register(&sane[i][j]); 228 + if (ret) { 229 + printk(KERN_ERR "nf_ct_sane: failed to " 230 + "register helper for pf: %d port: %d\n", 231 + sane[i][j].tuple.src.l3num, ports[i]); 232 + nf_conntrack_sane_fini(); 233 + return ret; 234 + } 235 + } 236 + } 237 + 238 + return 0; 239 + } 240 + 241 + module_init(nf_conntrack_sane_init); 242 + module_exit(nf_conntrack_sane_fini);