~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/netfilter/ip6t_rpfilter.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (c) 2011 Florian Westphal <fw@strlen.de>
  4  */
  5 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  6 #include <linux/module.h>
  7 #include <linux/skbuff.h>
  8 #include <linux/netdevice.h>
  9 #include <linux/route.h>
 10 #include <net/ip6_fib.h>
 11 #include <net/ip6_route.h>
 12 
 13 #include <linux/netfilter/xt_rpfilter.h>
 14 #include <linux/netfilter/x_tables.h>
 15 
 16 MODULE_LICENSE("GPL");
 17 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
 18 MODULE_DESCRIPTION("Xtables: IPv6 reverse path filter match");
 19 
 20 static bool rpfilter_addr_unicast(const struct in6_addr *addr)
 21 {
 22         int addr_type = ipv6_addr_type(addr);
 23         return addr_type & IPV6_ADDR_UNICAST;
 24 }
 25 
 26 static bool rpfilter_addr_linklocal(const struct in6_addr *addr)
 27 {
 28         int addr_type = ipv6_addr_type(addr);
 29         return addr_type & IPV6_ADDR_LINKLOCAL;
 30 }
 31 
 32 static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb,
 33                                      const struct net_device *dev, u8 flags)
 34 {
 35         struct rt6_info *rt;
 36         struct ipv6hdr *iph = ipv6_hdr(skb);
 37         bool ret = false;
 38         struct flowi6 fl6 = {
 39                 .flowi6_iif = LOOPBACK_IFINDEX,
 40                 .flowi6_l3mdev = l3mdev_master_ifindex_rcu(dev),
 41                 .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK,
 42                 .flowi6_proto = iph->nexthdr,
 43                 .flowi6_uid = sock_net_uid(net, NULL),
 44                 .daddr = iph->saddr,
 45         };
 46         int lookup_flags;
 47 
 48         if (rpfilter_addr_unicast(&iph->daddr)) {
 49                 memcpy(&fl6.saddr, &iph->daddr, sizeof(struct in6_addr));
 50                 lookup_flags = RT6_LOOKUP_F_HAS_SADDR;
 51         } else {
 52                 lookup_flags = 0;
 53         }
 54 
 55         fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
 56 
 57         if (rpfilter_addr_linklocal(&iph->saddr)) {
 58                 lookup_flags |= RT6_LOOKUP_F_IFACE;
 59                 fl6.flowi6_oif = dev->ifindex;
 60         } else if ((flags & XT_RPFILTER_LOOSE) == 0)
 61                 fl6.flowi6_oif = dev->ifindex;
 62 
 63         rt = (void *)ip6_route_lookup(net, &fl6, skb, lookup_flags);
 64         if (rt->dst.error)
 65                 goto out;
 66 
 67         if (rt->rt6i_flags & (RTF_REJECT|RTF_ANYCAST))
 68                 goto out;
 69 
 70         if (rt->rt6i_flags & RTF_LOCAL) {
 71                 ret = flags & XT_RPFILTER_ACCEPT_LOCAL;
 72                 goto out;
 73         }
 74 
 75         if (rt->rt6i_idev->dev == dev ||
 76             l3mdev_master_ifindex_rcu(rt->rt6i_idev->dev) == dev->ifindex ||
 77             (flags & XT_RPFILTER_LOOSE))
 78                 ret = true;
 79  out:
 80         ip6_rt_put(rt);
 81         return ret;
 82 }
 83 
 84 static bool
 85 rpfilter_is_loopback(const struct sk_buff *skb, const struct net_device *in)
 86 {
 87         return skb->pkt_type == PACKET_LOOPBACK || in->flags & IFF_LOOPBACK;
 88 }
 89 
 90 static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
 91 {
 92         const struct xt_rpfilter_info *info = par->matchinfo;
 93         int saddrtype;
 94         struct ipv6hdr *iph;
 95         bool invert = info->flags & XT_RPFILTER_INVERT;
 96 
 97         if (rpfilter_is_loopback(skb, xt_in(par)))
 98                 return true ^ invert;
 99 
100         iph = ipv6_hdr(skb);
101         saddrtype = ipv6_addr_type(&iph->saddr);
102         if (unlikely(saddrtype == IPV6_ADDR_ANY))
103                 return true ^ invert; /* not routable: forward path will drop it */
104 
105         return rpfilter_lookup_reverse6(xt_net(par), skb, xt_in(par),
106                                         info->flags) ^ invert;
107 }
108 
109 static int rpfilter_check(const struct xt_mtchk_param *par)
110 {
111         const struct xt_rpfilter_info *info = par->matchinfo;
112         unsigned int options = ~XT_RPFILTER_OPTION_MASK;
113 
114         if (info->flags & options) {
115                 pr_info_ratelimited("unknown options\n");
116                 return -EINVAL;
117         }
118 
119         if (strcmp(par->table, "mangle") != 0 &&
120             strcmp(par->table, "raw") != 0) {
121                 pr_info_ratelimited("only valid in \'raw\' or \'mangle\' table, not \'%s\'\n",
122                                     par->table);
123                 return -EINVAL;
124         }
125 
126         return 0;
127 }
128 
129 static struct xt_match rpfilter_mt_reg __read_mostly = {
130         .name           = "rpfilter",
131         .family         = NFPROTO_IPV6,
132         .checkentry     = rpfilter_check,
133         .match          = rpfilter_mt,
134         .matchsize      = sizeof(struct xt_rpfilter_info),
135         .hooks          = (1 << NF_INET_PRE_ROUTING),
136         .me             = THIS_MODULE
137 };
138 
139 static int __init rpfilter_mt_init(void)
140 {
141         return xt_register_match(&rpfilter_mt_reg);
142 }
143 
144 static void __exit rpfilter_mt_exit(void)
145 {
146         xt_unregister_match(&rpfilter_mt_reg);
147 }
148 
149 module_init(rpfilter_mt_init);
150 module_exit(rpfilter_mt_exit);
151 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php