All of lore.kernel.org
 help / color / mirror / Atom feed
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);

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