All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] SSDP (UPnP) conntrack helper
@ 2012-02-17  5:46 Ian Pilcher
  2012-02-18 17:09 ` Ian Pilcher
  2012-02-24 16:53 ` Pablo Neira Ayuso
  0 siblings, 2 replies; 7+ messages in thread
From: Ian Pilcher @ 2012-02-17  5:46 UTC (permalink / raw)
  To: netfilter-devel

[-- Attachment #1: Type: text/plain, Size: 2511 bytes --]

Attached is my first crack at a conntrack helper for SSDP, which is used
by DLNA/UPnP clients to discover media servers.

This is the first time I've ever tried to write a kernel module, let
alone a netfilter conntrack helper, so I have a number of questions:

1.  Most obviously, have I done anything egregiously wrong?

    I have tried to follow the general framework of nf_conntrack_tftp.c
    and the DHCPv6 helper that Darren Willis has been working on, along
    with the (very limited) documentation that I could find.

2.  What is the significance of nf_conntrack_expect_policy.max_expected?

    I have set this to 1, but VLC is able to discover both of the media
    servers on my network, which seems to indicate that the expectation
    is not being removed when the first response is received.

3.  Does nf_conntrack_expect_policy.timeout have the same meaning as the
    old ip_conntrack_helper.timeout field (as described in the Hacking
    HOWTO)?

4.  Am I using the appropriate values for expect->flags and
    expect->class?  (Are the possible values and their meanings
    documented anywhere?)

5.  What is the effect of the return value of the helper function?

    I've followed the example of the TFTP helper and returned NF_DROP if
    nf_ct_allow() fails.  Does this mean that the outgoing packet will
    dropped?  (I guess this makes sense, if the response won't make it
    through.)

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.)

7.  I intend to add IPv6 support, which means I won't be able to get
    away with bitwise operations on 32-bit ints.  Are there any helper
    functions available to assist with manipulating/comparing IPv6
    addresses?

Thanks in advance for your feedback!

-- 
========================================================================
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: 3133 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 and/or modify
 * it under the terms of the GNU General Public License, version 2, as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/udp.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 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;
	
	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 ((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;
	memset(&expect->mask, 0, sizeof expect->mask);
	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);

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] SSDP (UPnP) conntrack helper
  2012-02-17  5:46 [RFC] SSDP (UPnP) conntrack helper Ian Pilcher
@ 2012-02-18 17:09 ` Ian Pilcher
  2012-02-24  2:32   ` Ian Pilcher
  2012-02-24 16:53 ` Pablo Neira Ayuso
  1 sibling, 1 reply; 7+ messages in thread
From: Ian Pilcher @ 2012-02-18 17:09 UTC (permalink / raw)
  To: netfilter-devel

[-- 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);

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] SSDP (UPnP) conntrack helper
  2012-02-18 17:09 ` Ian Pilcher
@ 2012-02-24  2:32   ` Ian Pilcher
  0 siblings, 0 replies; 7+ messages in thread
From: Ian Pilcher @ 2012-02-24  2:32 UTC (permalink / raw)
  To: netfilter-devel

Bump?

-- 
========================================================================
Ian Pilcher                                         arequipeno@gmail.com
"If you're going to shift my paradigm ... at least buy me dinner first."
========================================================================


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] SSDP (UPnP) conntrack helper
  2012-02-17  5:46 [RFC] SSDP (UPnP) conntrack helper Ian Pilcher
  2012-02-18 17:09 ` Ian Pilcher
@ 2012-02-24 16:53 ` Pablo Neira Ayuso
  2012-02-24 20:13   ` Ian Pilcher
  1 sibling, 1 reply; 7+ messages in thread
From: Pablo Neira Ayuso @ 2012-02-24 16:53 UTC (permalink / raw)
  To: Ian Pilcher; +Cc: netfilter-devel

On Thu, Feb 16, 2012 at 11:46:38PM -0600, Ian Pilcher wrote:
> Attached is my first crack at a conntrack helper for SSDP, which is used
> by DLNA/UPnP clients to discover media servers.

We're targeting to have this helper and others in user-space in the
short tun.

I have a patch to add user-space helper infrastructure. I expect to
have it done soon.

I think it's time to think about having helpers in user-space.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] SSDP (UPnP) conntrack helper
  2012-02-24 16:53 ` Pablo Neira Ayuso
@ 2012-02-24 20:13   ` Ian Pilcher
  2012-02-25 13:32     ` Pablo Neira Ayuso
  0 siblings, 1 reply; 7+ messages in thread
From: Ian Pilcher @ 2012-02-24 20:13 UTC (permalink / raw)
  To: netfilter-devel

On 02/24/2012 10:53 AM, Pablo Neira Ayuso wrote:
> We're targeting to have this helper and others in user-space in the
> short tun.
> 
> I have a patch to add user-space helper infrastructure. I expect to
> have it done soon.
> 
> I think it's time to think about having helpers in user-space.

Thanks for the response.

Assuming the user-space connection tracking thing pans out, it sounds
like there isn't much possibility of this making it upstream.

I'd still like to get it the module finished up.  It's a useful learning
exercise, and I think it could be useful for anyone who stays on an
older kernel, "enterprise" distribution users for example.

I would *really* appreciate some feedback on the various questions that
I've posed in this thread.

Thanks!

-- 
========================================================================
Ian Pilcher                                         arequipeno@gmail.com
"If you're going to shift my paradigm ... at least buy me dinner first."
========================================================================


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] SSDP (UPnP) conntrack helper
  2012-02-24 20:13   ` Ian Pilcher
@ 2012-02-25 13:32     ` Pablo Neira Ayuso
  2012-02-25 19:07       ` Ian Pilcher
  0 siblings, 1 reply; 7+ messages in thread
From: Pablo Neira Ayuso @ 2012-02-25 13:32 UTC (permalink / raw)
  To: Ian Pilcher; +Cc: netfilter-devel

On Fri, Feb 24, 2012 at 02:13:54PM -0600, Ian Pilcher wrote:
> On 02/24/2012 10:53 AM, Pablo Neira Ayuso wrote:
> > We're targeting to have this helper and others in user-space in the
> > short tun.
> > 
> > I have a patch to add user-space helper infrastructure. I expect to
> > have it done soon.
> > 
> > I think it's time to think about having helpers in user-space.
> 
> Thanks for the response.
> 
> Assuming the user-space connection tracking thing pans out, it sounds
> like there isn't much possibility of this making it upstream.
> 
> I'd still like to get it the module finished up.  It's a useful learning
> exercise, and I think it could be useful for anyone who stays on an
> older kernel, "enterprise" distribution users for example.

I'll be very happy if you work on the user-space version. The
user-space cthelper infrastructure will be ready in two months
or so.

> I would *really* appreciate some feedback on the various questions that
> I've posed in this thread.

I think most of the questions can be replied by looking and
nf_conntrack_expect.c. I'll try to find some spare time to reply some
of those questions, but I don't promise anything.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] SSDP (UPnP) conntrack helper
  2012-02-25 13:32     ` Pablo Neira Ayuso
@ 2012-02-25 19:07       ` Ian Pilcher
  0 siblings, 0 replies; 7+ messages in thread
From: Ian Pilcher @ 2012-02-25 19:07 UTC (permalink / raw)
  To: netfilter-devel

On 02/25/2012 07:32 AM, Pablo Neira Ayuso wrote:
> I'll be very happy if you work on the user-space version. The
> user-space cthelper infrastructure will be ready in two months
> or so.

I fully intend to, although I'll probably wait until the required
infrastructure makes it into Fedora.

> I think most of the questions can be replied by looking and
> nf_conntrack_expect.c. I'll try to find some spare time to reply some
> of those questions, but I don't promise anything.

I'll take another look at that file.  Many of my questions are of the
"why" variety, however, so looking at other files doesn't always help
that much.

I'm sure, BTW, that you're not the only person subscribed to this list
that has the knowledge to help out.  ;-)

Thanks!

-- 
========================================================================
Ian Pilcher                                         arequipeno@gmail.com
"If you're going to shift my paradigm ... at least buy me dinner first."
========================================================================


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-02-25 19:07 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-17  5:46 [RFC] SSDP (UPnP) conntrack helper Ian Pilcher
2012-02-18 17:09 ` Ian Pilcher
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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.