-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 46958 b: refs/heads/master c: 6fecd19 h: refs/heads/master v: v3
- Loading branch information
Michal Schmidt
authored and
David S. Miller
committed
Feb 8, 2007
1 parent
8ab6630
commit 2b3ce39
Showing
6 changed files
with
280 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 719647e2131585ea0a82b05d3745b36be32975d8 | ||
refs/heads/master: 6fecd1985116fb08bdee3b9db6719e159fe5e43d |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#ifndef _NF_CONNTRACK_SANE_H | ||
#define _NF_CONNTRACK_SANE_H | ||
/* SANE tracking. */ | ||
|
||
#ifdef __KERNEL__ | ||
|
||
#define SANE_PORT 6566 | ||
|
||
enum sane_state { | ||
SANE_STATE_NORMAL, | ||
SANE_STATE_START_REQUESTED, | ||
}; | ||
|
||
/* This structure exists only once per master */ | ||
struct nf_ct_sane_master { | ||
enum sane_state state; | ||
}; | ||
|
||
#endif /* __KERNEL__ */ | ||
|
||
#endif /* _NF_CONNTRACK_SANE_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
/* SANE connection tracking helper | ||
* (SANE = Scanner Access Now Easy) | ||
* For documentation about the SANE network protocol see | ||
* http://www.sane-project.org/html/doc015.html | ||
*/ | ||
|
||
/* Copyright (C) 2007 Red Hat, Inc. | ||
* Author: Michal Schmidt <mschmidt@redhat.com> | ||
* Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c): | ||
* (C) 1999-2001 Paul `Rusty' Russell | ||
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
* (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> | ||
* (C) 2003 Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/moduleparam.h> | ||
#include <linux/netfilter.h> | ||
#include <linux/in.h> | ||
#include <linux/tcp.h> | ||
#include <net/netfilter/nf_conntrack.h> | ||
#include <net/netfilter/nf_conntrack_helper.h> | ||
#include <net/netfilter/nf_conntrack_expect.h> | ||
#include <linux/netfilter/nf_conntrack_sane.h> | ||
|
||
MODULE_LICENSE("GPL"); | ||
MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>"); | ||
MODULE_DESCRIPTION("SANE connection tracking helper"); | ||
|
||
static char *sane_buffer; | ||
|
||
static DEFINE_SPINLOCK(nf_sane_lock); | ||
|
||
#define MAX_PORTS 8 | ||
static u_int16_t ports[MAX_PORTS]; | ||
static unsigned int ports_c; | ||
module_param_array(ports, ushort, &ports_c, 0400); | ||
|
||
#if 0 | ||
#define DEBUGP printk | ||
#else | ||
#define DEBUGP(format, args...) | ||
#endif | ||
|
||
struct sane_request { | ||
__be32 RPC_code; | ||
#define SANE_NET_START 7 /* RPC code */ | ||
|
||
__be32 handle; | ||
}; | ||
|
||
struct sane_reply_net_start { | ||
__be32 status; | ||
#define SANE_STATUS_SUCCESS 0 | ||
|
||
__be16 zero; | ||
__be16 port; | ||
/* other fields aren't interesting for conntrack */ | ||
}; | ||
|
||
static int help(struct sk_buff **pskb, | ||
unsigned int protoff, | ||
struct nf_conn *ct, | ||
enum ip_conntrack_info ctinfo) | ||
{ | ||
unsigned int dataoff, datalen; | ||
struct tcphdr _tcph, *th; | ||
char *sb_ptr; | ||
int ret = NF_ACCEPT; | ||
int dir = CTINFO2DIR(ctinfo); | ||
struct nf_ct_sane_master *ct_sane_info; | ||
struct nf_conntrack_expect *exp; | ||
struct nf_conntrack_tuple *tuple; | ||
struct sane_request *req; | ||
struct sane_reply_net_start *reply; | ||
int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | ||
|
||
ct_sane_info = &nfct_help(ct)->help.ct_sane_info; | ||
/* Until there's been traffic both ways, don't look in packets. */ | ||
if (ctinfo != IP_CT_ESTABLISHED && | ||
ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) | ||
return NF_ACCEPT; | ||
|
||
/* Not a full tcp header? */ | ||
th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph); | ||
if (th == NULL) | ||
return NF_ACCEPT; | ||
|
||
/* No data? */ | ||
dataoff = protoff + th->doff * 4; | ||
if (dataoff >= (*pskb)->len) | ||
return NF_ACCEPT; | ||
|
||
datalen = (*pskb)->len - dataoff; | ||
|
||
spin_lock_bh(&nf_sane_lock); | ||
sb_ptr = skb_header_pointer(*pskb, dataoff, datalen, sane_buffer); | ||
BUG_ON(sb_ptr == NULL); | ||
|
||
if (dir == IP_CT_DIR_ORIGINAL) { | ||
if (datalen != sizeof(struct sane_request)) | ||
goto out; | ||
|
||
req = (struct sane_request *)sb_ptr; | ||
if (req->RPC_code != htonl(SANE_NET_START)) { | ||
/* Not an interesting command */ | ||
ct_sane_info->state = SANE_STATE_NORMAL; | ||
goto out; | ||
} | ||
|
||
/* We're interested in the next reply */ | ||
ct_sane_info->state = SANE_STATE_START_REQUESTED; | ||
goto out; | ||
} | ||
|
||
/* Is it a reply to an uninteresting command? */ | ||
if (ct_sane_info->state != SANE_STATE_START_REQUESTED) | ||
goto out; | ||
|
||
/* It's a reply to SANE_NET_START. */ | ||
ct_sane_info->state = SANE_STATE_NORMAL; | ||
|
||
if (datalen < sizeof(struct sane_reply_net_start)) { | ||
DEBUGP("nf_ct_sane: NET_START reply too short\n"); | ||
goto out; | ||
} | ||
|
||
reply = (struct sane_reply_net_start *)sb_ptr; | ||
if (reply->status != htonl(SANE_STATUS_SUCCESS)) { | ||
/* saned refused the command */ | ||
DEBUGP("nf_ct_sane: unsuccessful SANE_STATUS = %u\n", | ||
ntohl(reply->status)); | ||
goto out; | ||
} | ||
|
||
/* Invalid saned reply? Ignore it. */ | ||
if (reply->zero != 0) | ||
goto out; | ||
|
||
exp = nf_conntrack_expect_alloc(ct); | ||
if (exp == NULL) { | ||
ret = NF_DROP; | ||
goto out; | ||
} | ||
|
||
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | ||
nf_conntrack_expect_init(exp, family, | ||
&tuple->src.u3, &tuple->dst.u3, | ||
IPPROTO_TCP, | ||
NULL, &reply->port); | ||
|
||
DEBUGP("nf_ct_sane: expect: "); | ||
NF_CT_DUMP_TUPLE(&exp->tuple); | ||
NF_CT_DUMP_TUPLE(&exp->mask); | ||
|
||
/* Can't expect this? Best to drop packet now. */ | ||
if (nf_conntrack_expect_related(exp) != 0) | ||
ret = NF_DROP; | ||
|
||
nf_conntrack_expect_put(exp); | ||
|
||
out: | ||
spin_unlock_bh(&nf_sane_lock); | ||
return ret; | ||
} | ||
|
||
static struct nf_conntrack_helper sane[MAX_PORTS][2]; | ||
static char sane_names[MAX_PORTS][2][sizeof("sane-65535")]; | ||
|
||
/* don't make this __exit, since it's called from __init ! */ | ||
static void nf_conntrack_sane_fini(void) | ||
{ | ||
int i, j; | ||
|
||
for (i = 0; i < ports_c; i++) { | ||
for (j = 0; j < 2; j++) { | ||
DEBUGP("nf_ct_sane: unregistering helper for pf: %d " | ||
"port: %d\n", | ||
sane[i][j].tuple.src.l3num, ports[i]); | ||
nf_conntrack_helper_unregister(&sane[i][j]); | ||
} | ||
} | ||
|
||
kfree(sane_buffer); | ||
} | ||
|
||
static int __init nf_conntrack_sane_init(void) | ||
{ | ||
int i, j = -1, ret = 0; | ||
char *tmpname; | ||
|
||
sane_buffer = kmalloc(65536, GFP_KERNEL); | ||
if (!sane_buffer) | ||
return -ENOMEM; | ||
|
||
if (ports_c == 0) | ||
ports[ports_c++] = SANE_PORT; | ||
|
||
/* FIXME should be configurable whether IPv4 and IPv6 connections | ||
are tracked or not - YK */ | ||
for (i = 0; i < ports_c; i++) { | ||
sane[i][0].tuple.src.l3num = PF_INET; | ||
sane[i][1].tuple.src.l3num = PF_INET6; | ||
for (j = 0; j < 2; j++) { | ||
sane[i][j].tuple.src.u.tcp.port = htons(ports[i]); | ||
sane[i][j].tuple.dst.protonum = IPPROTO_TCP; | ||
sane[i][j].mask.src.u.tcp.port = 0xFFFF; | ||
sane[i][j].mask.dst.protonum = 0xFF; | ||
sane[i][j].max_expected = 1; | ||
sane[i][j].timeout = 5 * 60; /* 5 Minutes */ | ||
sane[i][j].me = THIS_MODULE; | ||
sane[i][j].help = help; | ||
tmpname = &sane_names[i][j][0]; | ||
if (ports[i] == SANE_PORT) | ||
sprintf(tmpname, "sane"); | ||
else | ||
sprintf(tmpname, "sane-%d", ports[i]); | ||
sane[i][j].name = tmpname; | ||
|
||
DEBUGP("nf_ct_sane: registering helper for pf: %d " | ||
"port: %d\n", | ||
sane[i][j].tuple.src.l3num, ports[i]); | ||
ret = nf_conntrack_helper_register(&sane[i][j]); | ||
if (ret) { | ||
printk(KERN_ERR "nf_ct_sane: failed to " | ||
"register helper for pf: %d port: %d\n", | ||
sane[i][j].tuple.src.l3num, ports[i]); | ||
nf_conntrack_sane_fini(); | ||
return ret; | ||
} | ||
} | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
module_init(nf_conntrack_sane_init); | ||
module_exit(nf_conntrack_sane_fini); |