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_afinfo *afinfo;
  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        rcu_read_lock();
  51
  52        afinfo = nf_get_afinfo(NFPROTO_IPV6);
  53        if (afinfo != NULL) {
  54                const struct nf_ipv6_ops *v6ops;
  55
  56                if (dev && (mask & XT_ADDRTYPE_LOCAL)) {
  57                        v6ops = nf_get_ipv6_ops();
  58                        if (v6ops && v6ops->chk_addr(net, addr, dev, true))
  59                                ret = XT_ADDRTYPE_LOCAL;
  60                }
  61                route_err = afinfo->route(net, (struct dst_entry **)&rt,
  62                                          flowi6_to_flowi(&flow), false);
  63        } else {
  64                route_err = 1;
  65        }
  66        rcu_read_unlock();
  67
  68        if (route_err)
  69                return XT_ADDRTYPE_UNREACHABLE;
  70
  71        if (rt->rt6i_flags & RTF_REJECT)
  72                ret = XT_ADDRTYPE_UNREACHABLE;
  73
  74        if (dev == NULL && rt->rt6i_flags & RTF_LOCAL)
  75                ret |= XT_ADDRTYPE_LOCAL;
  76        if (rt->rt6i_flags & RTF_ANYCAST)
  77                ret |= XT_ADDRTYPE_ANYCAST;
  78
  79        dst_release(&rt->dst);
  80        return ret;
  81}
  82
  83static bool match_type6(struct net *net, const struct net_device *dev,
  84                                const struct in6_addr *addr, u16 mask)
  85{
  86        int addr_type = ipv6_addr_type(addr);
  87
  88        if ((mask & XT_ADDRTYPE_MULTICAST) &&
  89            !(addr_type & IPV6_ADDR_MULTICAST))
  90                return false;
  91        if ((mask & XT_ADDRTYPE_UNICAST) && !(addr_type & IPV6_ADDR_UNICAST))
  92                return false;
  93        if ((mask & XT_ADDRTYPE_UNSPEC) && addr_type != IPV6_ADDR_ANY)
  94                return false;
  95
  96        if ((XT_ADDRTYPE_LOCAL | XT_ADDRTYPE_ANYCAST |
  97             XT_ADDRTYPE_UNREACHABLE) & mask)
  98                return !!(mask & match_lookup_rt6(net, dev, addr, mask));
  99        return true;
 100}
 101
 102static bool
 103addrtype_mt6(struct net *net, const struct net_device *dev,
 104        const struct sk_buff *skb, const struct xt_addrtype_info_v1 *info)
 105{
 106        const struct ipv6hdr *iph = ipv6_hdr(skb);
 107        bool ret = true;
 108
 109        if (info->source)
 110                ret &= match_type6(net, dev, &iph->saddr, info->source) ^
 111                       (info->flags & XT_ADDRTYPE_INVERT_SOURCE);
 112        if (ret && info->dest)
 113                ret &= match_type6(net, dev, &iph->daddr, info->dest) ^
 114                       !!(info->flags & XT_ADDRTYPE_INVERT_DEST);
 115        return ret;
 116}
 117#endif
 118
 119static inline bool match_type(struct net *net, const struct net_device *dev,
 120                              __be32 addr, u_int16_t mask)
 121{
 122        return !!(mask & (1 << inet_dev_addr_type(net, dev, addr)));
 123}
 124
 125static bool
 126addrtype_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
 127{
 128        struct net *net = dev_net(par->in ? par->in : par->out);
 129        const struct xt_addrtype_info *info = par->matchinfo;
 130        const struct iphdr *iph = ip_hdr(skb);
 131        bool ret = true;
 132
 133        if (info->source)
 134                ret &= match_type(net, NULL, iph->saddr, info->source) ^
 135                       info->invert_source;
 136        if (info->dest)
 137                ret &= match_type(net, NULL, iph->daddr, info->dest) ^
 138                       info->invert_dest;
 139
 140        return ret;
 141}
 142
 143static bool
 144addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
 145{
 146        struct net *net = dev_net(par->in ? par->in : par->out);
 147        const struct xt_addrtype_info_v1 *info = par->matchinfo;
 148        const struct iphdr *iph;
 149        const struct net_device *dev = NULL;
 150        bool ret = true;
 151
 152        if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
 153                dev = par->in;
 154        else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
 155                dev = par->out;
 156
 157#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 158        if (par->family == NFPROTO_IPV6)
 159                return addrtype_mt6(net, dev, skb, info);
 160#endif
 161        iph = ip_hdr(skb);
 162        if (info->source)
 163                ret &= match_type(net, dev, iph->saddr, info->source) ^
 164                       (info->flags & XT_ADDRTYPE_INVERT_SOURCE);
 165        if (ret && info->dest)
 166                ret &= match_type(net, dev, iph->daddr, info->dest) ^
 167                       !!(info->flags & XT_ADDRTYPE_INVERT_DEST);
 168        return ret;
 169}
 170
 171static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)
 172{
 173        struct xt_addrtype_info_v1 *info = par->matchinfo;
 174
 175        if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN &&
 176            info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) {
 177                pr_info("both incoming and outgoing "
 178                        "interface limitation cannot be selected\n");
 179                return -EINVAL;
 180        }
 181
 182        if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
 183            (1 << NF_INET_LOCAL_IN)) &&
 184            info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) {
 185                pr_info("output interface limitation "
 186                        "not valid in PREROUTING and INPUT\n");
 187                return -EINVAL;
 188        }
 189
 190        if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
 191            (1 << NF_INET_LOCAL_OUT)) &&
 192            info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) {
 193                pr_info("input interface limitation "
 194                        "not valid in POSTROUTING and OUTPUT\n");
 195                return -EINVAL;
 196        }
 197
 198#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 199        if (par->family == NFPROTO_IPV6) {
 200                if ((info->source | info->dest) & XT_ADDRTYPE_BLACKHOLE) {
 201                        pr_err("ipv6 BLACKHOLE matching not supported\n");
 202                        return -EINVAL;
 203                }
 204                if ((info->source | info->dest) >= XT_ADDRTYPE_PROHIBIT) {
 205                        pr_err("ipv6 PROHIBT (THROW, NAT ..) matching not supported\n");
 206                        return -EINVAL;
 207                }
 208                if ((info->source | info->dest) & XT_ADDRTYPE_BROADCAST) {
 209                        pr_err("ipv6 does not support BROADCAST matching\n");
 210                        return -EINVAL;
 211                }
 212        }
 213#endif
 214        return 0;
 215}
 216
 217static struct xt_match addrtype_mt_reg[] __read_mostly = {
 218        {
 219                .name           = "addrtype",
 220                .family         = NFPROTO_IPV4,
 221                .match          = addrtype_mt_v0,
 222                .matchsize      = sizeof(struct xt_addrtype_info),
 223                .me             = THIS_MODULE
 224        },
 225        {
 226                .name           = "addrtype",
 227                .family         = NFPROTO_UNSPEC,
 228                .revision       = 1,
 229                .match          = addrtype_mt_v1,
 230                .checkentry     = addrtype_mt_checkentry_v1,
 231                .matchsize      = sizeof(struct xt_addrtype_info_v1),
 232                .me             = THIS_MODULE
 233        }
 234};
 235
 236static int __init addrtype_mt_init(void)
 237{
 238        return xt_register_matches(addrtype_mt_reg,
 239                                   ARRAY_SIZE(addrtype_mt_reg));
 240}
 241
 242static void __exit addrtype_mt_exit(void)
 243{
 244        xt_unregister_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
 245}
 246
 247module_init(addrtype_mt_init);
 248module_exit(addrtype_mt_exit);
 249
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.