Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 279060
b: refs/heads/master
c: 8f97339
h: refs/heads/master
v: v3
  • Loading branch information
Florian Westphal authored and Pablo Neira Ayuso committed Dec 4, 2011
1 parent 662024e commit 201f50b
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6fc01438a94702bd160cb1b89203d9b97ae68ced
refs/heads/master: 8f97339d3feb662037b86a925e692017c0b32323
23 changes: 23 additions & 0 deletions trunk/include/linux/netfilter/xt_rpfilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef _XT_RPATH_H
#define _XT_RPATH_H

#include <linux/types.h>

enum {
XT_RPFILTER_LOOSE = 1 << 0,
XT_RPFILTER_VALID_MARK = 1 << 1,
XT_RPFILTER_ACCEPT_LOCAL = 1 << 2,
XT_RPFILTER_INVERT = 1 << 3,
#ifdef __KERNEL__
XT_RPFILTER_OPTION_MASK = XT_RPFILTER_LOOSE |
XT_RPFILTER_VALID_MARK |
XT_RPFILTER_ACCEPT_LOCAL |
XT_RPFILTER_INVERT,
#endif
};

struct xt_rpfilter_info {
__u8 flags;
};

#endif
10 changes: 10 additions & 0 deletions trunk/net/ipv4/netfilter/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ config IP_NF_MATCH_ECN

To compile it as a module, choose M here. If unsure, say N.

config IP_NF_MATCH_RPFILTER
tristate '"rpfilter" reverse path filter match support'
depends on NETFILTER_ADVANCED
---help---
This option allows you to match packets whose replies would
go out via the interface the packet came in.

To compile it as a module, choose M here. If unsure, say N.
The module will be called ipt_rpfilter.

config IP_NF_MATCH_TTL
tristate '"ttl" match support'
depends on NETFILTER_ADVANCED
Expand Down
1 change: 1 addition & 0 deletions trunk/net/ipv4/netfilter/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
# matches
obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o

# targets
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
Expand Down
141 changes: 141 additions & 0 deletions trunk/net/ipv4/netfilter/ipt_rpfilter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2011 Florian Westphal <fw@strlen.de>
*
* 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.
*
* based on fib_frontend.c; Author: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <net/ip_fib.h>
#include <net/route.h>

#include <linux/netfilter/xt_rpfilter.h>
#include <linux/netfilter/x_tables.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
MODULE_DESCRIPTION("iptables: ipv4 reverse path filter match");

/* don't try to find route from mcast/bcast/zeronet */
static __be32 rpfilter_get_saddr(__be32 addr)
{
if (ipv4_is_multicast(addr) || ipv4_is_lbcast(addr) ||
ipv4_is_zeronet(addr))
return 0;
return addr;
}

static bool rpfilter_lookup_reverse(struct flowi4 *fl4,
const struct net_device *dev, u8 flags)
{
struct fib_result res;
bool dev_match;
struct net *net = dev_net(dev);
int ret __maybe_unused;

if (fib_lookup(net, fl4, &res))
return false;

if (res.type != RTN_UNICAST) {
if (res.type != RTN_LOCAL || !(flags & XT_RPFILTER_ACCEPT_LOCAL))
return false;
}
dev_match = false;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
for (ret = 0; ret < res.fi->fib_nhs; ret++) {
struct fib_nh *nh = &res.fi->fib_nh[ret];

if (nh->nh_dev == dev) {
dev_match = true;
break;
}
}
#else
if (FIB_RES_DEV(res) == dev)
dev_match = true;
#endif
if (dev_match || flags & XT_RPFILTER_LOOSE)
return FIB_RES_NH(res).nh_scope <= RT_SCOPE_HOST;
return dev_match;
}

static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_rpfilter_info *info;
const struct iphdr *iph;
struct flowi4 flow;
bool invert;

info = par->matchinfo;
invert = info->flags & XT_RPFILTER_INVERT;

if (par->in->flags & IFF_LOOPBACK)
return true ^ invert;

iph = ip_hdr(skb);
if (ipv4_is_multicast(iph->daddr)) {
if (ipv4_is_zeronet(iph->saddr))
return ipv4_is_local_multicast(iph->daddr) ^ invert;
flow.flowi4_iif = 0;
} else {
flow.flowi4_iif = dev_net(par->in)->loopback_dev->ifindex;
}

flow.daddr = iph->saddr;
flow.saddr = rpfilter_get_saddr(iph->daddr);
flow.flowi4_oif = 0;
flow.flowi4_mark = info->flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
flow.flowi4_tos = RT_TOS(iph->tos);
flow.flowi4_scope = RT_SCOPE_UNIVERSE;

return rpfilter_lookup_reverse(&flow, par->in, info->flags) ^ invert;
}

static int rpfilter_check(const struct xt_mtchk_param *par)
{
const struct xt_rpfilter_info *info = par->matchinfo;
unsigned int options = ~XT_RPFILTER_OPTION_MASK;
if (info->flags & options) {
pr_info("unknown options encountered");
return -EINVAL;
}

if (strcmp(par->table, "mangle") != 0 &&
strcmp(par->table, "raw") != 0) {
pr_info("match only valid in the \'raw\' "
"or \'mangle\' tables, not \'%s\'.\n", par->table);
return -EINVAL;
}

return 0;
}

static struct xt_match rpfilter_mt_reg __read_mostly = {
.name = "rpfilter",
.family = NFPROTO_IPV4,
.checkentry = rpfilter_check,
.match = rpfilter_mt,
.matchsize = sizeof(struct xt_rpfilter_info),
.hooks = (1 << NF_INET_PRE_ROUTING),
.me = THIS_MODULE
};

static int __init rpfilter_mt_init(void)
{
return xt_register_match(&rpfilter_mt_reg);
}

static void __exit rpfilter_mt_exit(void)
{
xt_unregister_match(&rpfilter_mt_reg);
}

module_init(rpfilter_mt_init);
module_exit(rpfilter_mt_exit);

0 comments on commit 201f50b

Please sign in to comment.