linux/net/netfilter/xt_addrtype.c
<<
>>
Prefs
   1/*
   2 *  iptables module to match inet_addr_type() of an ip.
   3 *
   4 *  Copyright (c) 2004 Patrick McHardy <kaber@trash.net>
   5 *  (C) 2007 Laszlo Attila Toth <panther@balabit.hu>
   6 *
   7 *  This program is free software; you can redistribute it and/or modify
   8 *  it under the terms of the GNU General Public License version 2 as
   9 *  published by the Free Software Foundation.
  10 */
  11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/skbuff.h>
  15#include <linux/netdevice.h>
  16#include <linux/ip.h>
  17#include <net/route.h>
  18
  19#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
  20#include <net/ipv6.h>
  21#include <net/ip6_route.h>
  22#include <net/ip6_fib.h>
  23#endif
  24
  25#include <linux/netfilter_ipv6.h>
  26#include <linux/netfilter/xt_addrtype.h>
  27#include <linux/netfilter/x_tables.h>
  28
  29MODULE_LICENSE("GPL");
  30MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
  31MODULE_DESCRIPTION("Xtables: address type match");
  32MODULE_ALIAS("ipt_addrtype");
  33MODULE_ALIAS("ip6t_addrtype");
  34
  35#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
  36static u32 match_lookup_rt6(struct net *net, const struct net_device *dev,
  37                            const struct in6_addr *addr, u16 mask)
  38{
  39        const struct nf_ipv6_ops *v6ops;
  40        struct flowi6 flow;
  41        struct rt6_info *rt;
  42        u32 ret = 0;
  43        int route_err;
  44
  45        memset(&flow, 0, sizeof(flow));
  46        flow.daddr = *addr;
  47        if (dev)
  48                flow.flowi6_oif = dev->ifindex;
  49
  50        v6ops = nf_get_ipv6_ops();
  51        if (v6ops) {
  52                if (dev && (mask & XT_ADDRTYPE_LOCAL)) {
  53                        if (v6ops->chk_addr(net, addr, dev, true))
  54                                ret = XT_ADDRTYPE_LOCAL;
  55                }
  56                route_err = v6ops->route(net, (struct dst_entry **)&rt,
  57                                         flowi6_to_flowi(&flow), false);
  58        } else {
  59                route_err = 1;
  60        }
  61
  62        if (route_err)
  63                return XT_ADDRTYPE_UNREACHABLE;
  64
  65        if (rt->rt6i_flags & RTF_REJECT)
  66                ret = XT_ADDRTYPE_UNREACHABLE;
  67
  68        if (dev == NULL && rt->rt6i_flags & RTF_LOCAL)
  69                ret |= XT_ADDRTYPE_LOCAL;
  70        if (ipv6_anycast_destination((struct dst_entry *)rt, addr))
  71                ret |= XT_ADDRTYPE_ANYCAST;
  72
  73        dst_release(&rt->dst);
  74        return ret;
  75}
  76
  77static bool match_type6(struct net *net, const struct net_device *dev,
  78                                const struct in6_addr *addr, u16 mask)
  79{
  80        int addr_type = ipv6_addr_type(addr);
  81
  82        if ((mask & XT_ADDRTYPE_MULTICAST) &&
  83            !(addr_type & IPV6_ADDR_MULTICAST))
  84                return false;
  85        if ((mask & XT_ADDRTYPE_UNICAST) && !(addr_type & IPV6_ADDR_UNICAST))
  86                return false;
  87        if ((mask & XT_ADDRTYPE_UNSPEC) && addr_type != IPV6_ADDR_ANY)
  88                return false;
  89
  90        if ((XT_ADDRTYPE_LOCAL | XT_ADDRTYPE_ANYCAST |
  91             XT_ADDRTYPE_UNREACHABLE) & mask)
  92                return !!(mask & match_lookup_rt6(net, dev, addr, mask));
  93        return true;
  94}
  95
  96static bool
  97addrtype_mt6(struct net *net, const struct net_device *dev,
  98        const struct sk_buff *skb, const struct xt_addrtype_info_v1 *info)
  99{
 100        const struct ipv6hdr *iph = ipv6_hdr(skb);
 101        bool ret = true;
 102
 103        if (info->source)
 104                ret &= match_type6(net, dev, &iph->saddr, info->source) ^
 105                       (info->flags & XT_ADDRTYPE_INVERT_SOURCE);
 106        if (ret && info->dest)
 107                ret &= match_type6(net, dev, &iph->daddr, info->dest) ^
 108                       !!(info->flags & XT_ADDRTYPE_INVERT_DEST);
 109        return ret;
 110}
 111#endif
 112
 113static inline bool match_type(struct net *net, const struct net_device *dev,
 114                              __be32 addr, u_int16_t mask)
 115{
 116        return !!(mask & (1 << inet_dev_addr_type(net, dev, addr)));
 117}
 118
 119static bool
 120addrtype_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
 121{
 122        struct net *net = xt_net(par);
 123        const struct xt_addrtype_info *info = par->matchinfo;
 124        const struct iphdr *iph = ip_hdr(skb);
 125        bool ret = true;
 126
 127        if (info->source)
 128                ret &= match_type(net, NULL, iph->saddr, info->source) ^
 129                       info->invert_source;
 130        if (info->dest)
 131                ret &= match_type(net, NULL, iph->daddr, info->dest) ^
 132                       info->invert_dest;
 133
 134        return ret;
 135}
 136
 137static bool
 138addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
 139{
 140        struct net *net = xt_net(par);
 141        const struct xt_addrtype_info_v1 *info = par->matchinfo;
 142        const struct iphdr *iph;
 143        const struct net_device *dev = NULL;
 144        bool ret = true;
 145
 146        if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
 147                dev = xt_in(par);
 148        else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
 149                dev = xt_out(par);
 150
 151#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 152        if (xt_family(par) == NFPROTO_IPV6)
 153                return addrtype_mt6(net, dev, skb, info);
 154#endif
 155        iph = ip_hdr(skb);
 156        if (info->source)
 157                ret &= match_type(net, dev, iph->saddr, info->source) ^
 158                       (info->flags & XT_ADDRTYPE_INVERT_SOURCE);
 159        if (ret && info->dest)
 160                ret &= match_type(net, dev, iph->daddr, info->dest) ^
 161                       !!(info->flags & XT_ADDRTYPE_INVERT_DEST);
 162        return ret;
 163}
 164
 165static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)
 166{
 167        const char *errmsg = "both incoming and outgoing interface limitation cannot be selected";
 168        struct xt_addrtype_info_v1 *info = par->matchinfo;
 169
 170        if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN &&
 171            info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
 172                goto err;
 173
 174        if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
 175            (1 << NF_INET_LOCAL_IN)) &&
 176            info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) {
 177                errmsg = "output interface limitation not valid in PREROUTING and INPUT";
 178                goto err;
 179        }
 180
 181        if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
 182            (1 << NF_INET_LOCAL_OUT)) &&
 183            info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) {
 184                errmsg = "input interface limitation not valid in POSTROUTING and OUTPUT";
 185                goto err;
 186        }
 187
 188#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 189        if (par->family == NFPROTO_IPV6) {
 190                if ((info->source | info->dest) & XT_ADDRTYPE_BLACKHOLE) {
 191                        errmsg = "ipv6 BLACKHOLE matching not supported";
 192                        goto err;
 193                }
 194                if ((info->source | info->dest) >= XT_ADDRTYPE_PROHIBIT) {
 195                        errmsg = "ipv6 PROHIBIT (THROW, NAT ..) matching not supported";
 196                        goto err;
 197                }
 198                if ((info->source | info->dest) & XT_ADDRTYPE_BROADCAST) {
 199                        errmsg = "ipv6 does not support BROADCAST matching";
 200                        goto err;
 201                }
 202        }
 203#endif
 204        return 0;
 205err:
 206        pr_info_ratelimited("%s\n", errmsg);
 207        return -EINVAL;
 208}
 209
 210static struct xt_match addrtype_mt_reg[] __read_mostly = {
 211        {
 212                .name           = "addrtype",
 213                .family         = NFPROTO_IPV4,
 214                .match          = addrtype_mt_v0,
 215                .matchsize      = sizeof(struct xt_addrtype_info),
 216                .me             = THIS_MODULE
 217        },
 218        {
 219                .name           = "addrtype",
 220                .family         = NFPROTO_UNSPEC,
 221                .revision       = 1,
 222                .match          = addrtype_mt_v1,
 223                .checkentry     = addrtype_mt_checkentry_v1,
 224                .matchsize      = sizeof(struct xt_addrtype_info_v1),
 225                .me             = THIS_MODULE
 226        }
 227};
 228
 229static int __init addrtype_mt_init(void)
 230{
 231        return xt_register_matches(addrtype_mt_reg,
 232                                   ARRAY_SIZE(addrtype_mt_reg));
 233}
 234
 235static void __exit addrtype_mt_exit(void)
 236{
 237        xt_unregister_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
 238}
 239
 240module_init(addrtype_mt_init);
 241module_exit(addrtype_mt_exit);
 242