From: Ian Pilcher <arequipeno@gmail.com>
To: netfilter-devel@vger.kernel.org
Subject: Re: [RFC] SSDP (UPnP) conntrack helper
Date: Sat, 18 Feb 2012 11:09:43 -0600 [thread overview]
Message-ID: <jhom0o$548$1@dough.gmane.org> (raw)
In-Reply-To: <jhkpju$dsp$1@dough.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1325 bytes --]
On 02/16/2012 11:46 PM, Ian Pilcher wrote:
> 6. In the vast majority of cases, any responses should come from media
> servers on the same subnet as the interface through which the query
> is sent, so it seems like it might make sense to only accept
> responses from the local subnet, unless overridden with a module
> parameter. The source address is easily accessible, but I'll need
> to access its associated subnet mask. What is the proper way to
> access this information through the skb? (That __rcu in struct
> net_device makes me think I should be careful.)
Attached is a new version of the module, which enforces the subnet match
that I described (modulo a parameter to turn off the restriction). I'm
using in_dev_get()/in_dev_put() to access the IP address information via
skb->dev.
Is this approach correct, or do I need to do additional RCU-related
stuff to safely iterate through the IP addresses?
Still hoping for some help with the other questions in my previous note.
Thanks!
--
========================================================================
Ian Pilcher arequipeno@gmail.com
"If you're going to shift my paradigm ... at least buy me dinner first."
========================================================================
[-- Attachment #2: nf_conntrack_ssdp.c --]
[-- Type: text/x-csrc, Size: 4234 bytes --]
/*
* nf_conntrack_ssdp.c - netfilter connection tracking helper for UPnP SSDP
*
* Copyright 2012 Ian Pilcher <arequipeno@gmail.com>
*
* This program is free software. You can redistribute it or modify it
* under the terms of version 2 of the GNU General Public License, as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/udp.h>
#include <linux/inetdevice.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#define SSDP_MCAST_ADDR 0xeffffffa /* 239.255.255.250 - host byte order */
#define SSDP_UDP_PORT 1900
#define SSDP_M_SEARCH "M-SEARCH"
#define SSDP_M_SEARCH_SIZE (sizeof SSDP_M_SEARCH - 1)
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ian Pilcher <arequipeno@gmail.com>");
MODULE_DESCRIPTION("SSDP connection tracking helper");
MODULE_ALIAS("ip_conntrack_ssdp");
MODULE_ALIAS_NFCT_HELPER("ssdp");
static __be32 ssdp_src_netmask(const struct sk_buff *skb,
const struct nf_conntrack_tuple *orig)
{
struct in_device *dev;
const struct in_ifaddr *addr;
__be32 ret = 0; /* indicates failure (0.0.0.0 is not a valid netmask) */
if ((dev = in_dev_get(skb->dev)) == NULL) {
pr_warn("Device %s has no IPv4 addresses assigned\n", skb->dev->name);
return ret; /* 0 */
}
for (addr = dev->ifa_list; addr != NULL; addr = addr->ifa_next) {
if (addr->ifa_local == orig->src.u3.ip) {
pr_debug("ssdp_netmask: found netmask %pI4 for address %pI4 on device %s\n",
&addr->ifa_mask, &orig->src.u3.ip, addr->ifa_label);
ret = addr->ifa_mask;
break;
}
}
if (ret == 0) {
pr_warn("M-SEARCH source address %pI4 not assigned to device %s\n",
&orig->src.u3.ip, skb->dev->name);
}
in_dev_put(dev);
return ret;
}
static int ssdp_help(struct sk_buff *skb,
unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
struct nf_conntrack_expect *expect;
struct nf_conntrack_tuple *tuple;
char udpdata_buffer[SSDP_M_SEARCH_SIZE];
char *udpdata;
__be32 netmask;
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
pr_debug("ssdp_help: %pI4:%hu --> %pI4:%hu\n",
&tuple->src.u3.ip, be16_to_cpu(tuple->src.u.udp.port),
&tuple->dst.u3.ip, be16_to_cpu(tuple->dst.u.udp.port));
if (tuple->dst.u3.ip != cpu_to_be32(SSDP_MCAST_ADDR)) {
pr_debug("ssdp_help: destination address != 239.255.255.250; ignoring\n");
return NF_ACCEPT;
}
udpdata = skb_header_pointer(skb, protoff + sizeof(struct udphdr),
sizeof udpdata_buffer, &udpdata_buffer);
if (udpdata == NULL) {
pr_debug("ssdp_help: UDP payload too small for M-SEARCH; ignoring\n");
return NF_ACCEPT;
}
if (memcmp(udpdata, SSDP_M_SEARCH, SSDP_M_SEARCH_SIZE) != 0) {
pr_debug("ssdp_help: UDP payload does not begin with 'M-SEARCH'; ignoring\n");
return NF_ACCEPT;
}
if ((netmask = ssdp_src_netmask(skb, tuple)) == 0)
return NF_DROP; /* ssdp_src_netmask prints warning on failure */
if ((expect = nf_ct_expect_alloc(ct)) == NULL) {
pr_warn("Memory allocation failure\n");
return NF_DROP;
}
expect->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
expect->tuple.src.u3.ip = expect->tuple.dst.u3.ip;
memset(&expect->mask, 0, sizeof expect->mask);
expect->mask.src.u3.ip = netmask;
expect->mask.src.u.udp.port = 0xffff; /* byte order doesn't matter */
expect->expectfn = NULL;
expect->flags = 0;
expect->class = NF_CT_EXPECT_CLASS_DEFAULT;
expect->helper = NULL;
nf_ct_expect_related(expect);
nf_ct_expect_put(expect);
return NF_ACCEPT;
}
static const struct nf_conntrack_expect_policy ssdp_policy = {
.max_expected = 1,
.timeout = 1,
.name = "ssdp",
};
static struct nf_conntrack_helper __read_mostly ssdp_helper = {
.name = "ssdp",
.tuple.src.l3num = NFPROTO_IPV4,
.tuple.src.u.udp.port = cpu_to_be16(SSDP_UDP_PORT),
.tuple.dst.protonum = IPPROTO_UDP,
.me = THIS_MODULE,
.help = ssdp_help,
.expect_policy = &ssdp_policy,
};
static int __init nf_conntrack_ssdp_init(void)
{
return nf_conntrack_helper_register(&ssdp_helper);
}
static void __exit nf_conntrack_ssdp_exit(void)
{
nf_conntrack_helper_unregister(&ssdp_helper);
}
module_init(nf_conntrack_ssdp_init);
module_exit(nf_conntrack_ssdp_exit);
next prev parent reply other threads:[~2012-02-18 17:10 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-02-17 5:46 [RFC] SSDP (UPnP) conntrack helper Ian Pilcher
2012-02-18 17:09 ` Ian Pilcher [this message]
2012-02-24 2:32 ` Ian Pilcher
2012-02-24 16:53 ` Pablo Neira Ayuso
2012-02-24 20:13 ` Ian Pilcher
2012-02-25 13:32 ` Pablo Neira Ayuso
2012-02-25 19:07 ` Ian Pilcher
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='jhom0o$548$1@dough.gmane.org' \
--to=arequipeno@gmail.com \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).