|
|
|
Re: [RFC] SSDP (UPnP) conntrack helper | |
| [Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] |
|
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@xxxxxxxxx "If you're going to shift my paradigm ... at least buy me dinner first." ========================================================================
/*
* nf_conntrack_ssdp.c - netfilter connection tracking helper for UPnP SSDP
*
* Copyright 2012 Ian Pilcher <arequipeno@xxxxxxxxx>
*
* 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@xxxxxxxxx>");
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);
[Netfitler Users] [LARTC] [Bugtraq] [Yosemite Forum] [Photo]