2 * Copyright (c) 2011 Florian Westphal <fw@strlen.de>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * based on fib_frontend.c; Author: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 #include <linux/module.h>
12 #include <linux/skbuff.h>
13 #include <linux/netdevice.h>
16 #include <net/ip_fib.h>
17 #include <net/route.h>
19 #include <linux/netfilter/xt_rpfilter.h>
20 #include <linux/netfilter/x_tables.h>
22 MODULE_LICENSE("GPL");
23 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
24 MODULE_DESCRIPTION("iptables: ipv4 reverse path filter match");
26 /* don't try to find route from mcast/bcast/zeronet */
27 static __be32
rpfilter_get_saddr(__be32 addr
)
29 if (ipv4_is_multicast(addr
) || ipv4_is_lbcast(addr
) ||
30 ipv4_is_zeronet(addr
))
35 static bool rpfilter_lookup_reverse(struct net
*net
, struct flowi4
*fl4
,
36 const struct net_device
*dev
, u8 flags
)
38 struct fib_result res
;
39 int ret __maybe_unused
;
41 if (fib_lookup(net
, fl4
, &res
, FIB_LOOKUP_IGNORE_LINKSTATE
))
44 if (res
.type
!= RTN_UNICAST
) {
45 if (res
.type
!= RTN_LOCAL
|| !(flags
& XT_RPFILTER_ACCEPT_LOCAL
))
48 return fib_info_nh_uses_dev(res
.fi
, dev
) || flags
& XT_RPFILTER_LOOSE
;
52 rpfilter_is_loopback(const struct sk_buff
*skb
, const struct net_device
*in
)
54 return skb
->pkt_type
== PACKET_LOOPBACK
|| in
->flags
& IFF_LOOPBACK
;
57 static bool rpfilter_mt(const struct sk_buff
*skb
, struct xt_action_param
*par
)
59 const struct xt_rpfilter_info
*info
;
60 const struct iphdr
*iph
;
64 info
= par
->matchinfo
;
65 invert
= info
->flags
& XT_RPFILTER_INVERT
;
67 if (rpfilter_is_loopback(skb
, xt_in(par
)))
71 if (ipv4_is_zeronet(iph
->saddr
)) {
72 if (ipv4_is_lbcast(iph
->daddr
) ||
73 ipv4_is_local_multicast(iph
->daddr
))
77 memset(&flow
, 0, sizeof(flow
));
78 flow
.flowi4_iif
= LOOPBACK_IFINDEX
;
79 flow
.daddr
= iph
->saddr
;
80 flow
.saddr
= rpfilter_get_saddr(iph
->daddr
);
81 flow
.flowi4_mark
= info
->flags
& XT_RPFILTER_VALID_MARK
? skb
->mark
: 0;
82 flow
.flowi4_tos
= RT_TOS(iph
->tos
);
83 flow
.flowi4_scope
= RT_SCOPE_UNIVERSE
;
85 return rpfilter_lookup_reverse(xt_net(par
), &flow
, xt_in(par
), info
->flags
) ^ invert
;
88 static int rpfilter_check(const struct xt_mtchk_param
*par
)
90 const struct xt_rpfilter_info
*info
= par
->matchinfo
;
91 unsigned int options
= ~XT_RPFILTER_OPTION_MASK
;
92 if (info
->flags
& options
) {
93 pr_info_ratelimited("unknown options\n");
97 if (strcmp(par
->table
, "mangle") != 0 &&
98 strcmp(par
->table
, "raw") != 0) {
99 pr_info_ratelimited("only valid in \'raw\' or \'mangle\' table, not \'%s\'\n",
107 static struct xt_match rpfilter_mt_reg __read_mostly
= {
109 .family
= NFPROTO_IPV4
,
110 .checkentry
= rpfilter_check
,
111 .match
= rpfilter_mt
,
112 .matchsize
= sizeof(struct xt_rpfilter_info
),
113 .hooks
= (1 << NF_INET_PRE_ROUTING
),
117 static int __init
rpfilter_mt_init(void)
119 return xt_register_match(&rpfilter_mt_reg
);
122 static void __exit
rpfilter_mt_exit(void)
124 xt_unregister_match(&rpfilter_mt_reg
);
127 module_init(rpfilter_mt_init
);
128 module_exit(rpfilter_mt_exit
);