root/net/ipv6/fib6_rules.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fib6_rule_matchall
  2. fib6_rule_default
  3. fib6_rules_dump
  4. fib6_rules_seq_read
  5. fib6_lookup
  6. fib6_rule_lookup
  7. fib6_rule_saddr
  8. fib6_rule_action_alt
  9. __fib6_rule_action
  10. fib6_rule_action
  11. fib6_rule_suppress
  12. fib6_rule_match
  13. fib6_rule_configure
  14. fib6_rule_delete
  15. fib6_rule_compare
  16. fib6_rule_fill
  17. fib6_rule_nlmsg_payload
  18. fib6_rules_net_init
  19. fib6_rules_net_exit
  20. fib6_rules_init
  21. fib6_rules_cleanup

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * net/ipv6/fib6_rules.c        IPv6 Routing Policy Rules
   4  *
   5  * Copyright (C)2003-2006 Helsinki University of Technology
   6  * Copyright (C)2003-2006 USAGI/WIDE Project
   7  *
   8  * Authors
   9  *      Thomas Graf             <tgraf@suug.ch>
  10  *      Ville Nuorvala          <vnuorval@tcs.hut.fi>
  11  */
  12 
  13 #include <linux/netdevice.h>
  14 #include <linux/notifier.h>
  15 #include <linux/export.h>
  16 
  17 #include <net/fib_rules.h>
  18 #include <net/ipv6.h>
  19 #include <net/addrconf.h>
  20 #include <net/ip6_route.h>
  21 #include <net/netlink.h>
  22 
  23 struct fib6_rule {
  24         struct fib_rule         common;
  25         struct rt6key           src;
  26         struct rt6key           dst;
  27         u8                      tclass;
  28 };
  29 
  30 static bool fib6_rule_matchall(const struct fib_rule *rule)
  31 {
  32         struct fib6_rule *r = container_of(rule, struct fib6_rule, common);
  33 
  34         if (r->dst.plen || r->src.plen || r->tclass)
  35                 return false;
  36         return fib_rule_matchall(rule);
  37 }
  38 
  39 bool fib6_rule_default(const struct fib_rule *rule)
  40 {
  41         if (!fib6_rule_matchall(rule) || rule->action != FR_ACT_TO_TBL ||
  42             rule->l3mdev)
  43                 return false;
  44         if (rule->table != RT6_TABLE_LOCAL && rule->table != RT6_TABLE_MAIN)
  45                 return false;
  46         return true;
  47 }
  48 EXPORT_SYMBOL_GPL(fib6_rule_default);
  49 
  50 int fib6_rules_dump(struct net *net, struct notifier_block *nb)
  51 {
  52         return fib_rules_dump(net, nb, AF_INET6);
  53 }
  54 
  55 unsigned int fib6_rules_seq_read(struct net *net)
  56 {
  57         return fib_rules_seq_read(net, AF_INET6);
  58 }
  59 
  60 /* called with rcu lock held; no reference taken on fib6_info */
  61 int fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
  62                 struct fib6_result *res, int flags)
  63 {
  64         int err;
  65 
  66         if (net->ipv6.fib6_has_custom_rules) {
  67                 struct fib_lookup_arg arg = {
  68                         .lookup_ptr = fib6_table_lookup,
  69                         .lookup_data = &oif,
  70                         .result = res,
  71                         .flags = FIB_LOOKUP_NOREF,
  72                 };
  73 
  74                 l3mdev_update_flow(net, flowi6_to_flowi(fl6));
  75 
  76                 err = fib_rules_lookup(net->ipv6.fib6_rules_ops,
  77                                        flowi6_to_flowi(fl6), flags, &arg);
  78         } else {
  79                 err = fib6_table_lookup(net, net->ipv6.fib6_local_tbl, oif,
  80                                         fl6, res, flags);
  81                 if (err || res->f6i == net->ipv6.fib6_null_entry)
  82                         err = fib6_table_lookup(net, net->ipv6.fib6_main_tbl,
  83                                                 oif, fl6, res, flags);
  84         }
  85 
  86         return err;
  87 }
  88 
  89 struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
  90                                    const struct sk_buff *skb,
  91                                    int flags, pol_lookup_t lookup)
  92 {
  93         if (net->ipv6.fib6_has_custom_rules) {
  94                 struct fib6_result res = {};
  95                 struct fib_lookup_arg arg = {
  96                         .lookup_ptr = lookup,
  97                         .lookup_data = skb,
  98                         .result = &res,
  99                         .flags = FIB_LOOKUP_NOREF,
 100                 };
 101 
 102                 /* update flow if oif or iif point to device enslaved to l3mdev */
 103                 l3mdev_update_flow(net, flowi6_to_flowi(fl6));
 104 
 105                 fib_rules_lookup(net->ipv6.fib6_rules_ops,
 106                                  flowi6_to_flowi(fl6), flags, &arg);
 107 
 108                 if (res.rt6)
 109                         return &res.rt6->dst;
 110         } else {
 111                 struct rt6_info *rt;
 112 
 113                 rt = lookup(net, net->ipv6.fib6_local_tbl, fl6, skb, flags);
 114                 if (rt != net->ipv6.ip6_null_entry && rt->dst.error != -EAGAIN)
 115                         return &rt->dst;
 116                 ip6_rt_put_flags(rt, flags);
 117                 rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, skb, flags);
 118                 if (rt->dst.error != -EAGAIN)
 119                         return &rt->dst;
 120                 ip6_rt_put_flags(rt, flags);
 121         }
 122 
 123         if (!(flags & RT6_LOOKUP_F_DST_NOREF))
 124                 dst_hold(&net->ipv6.ip6_null_entry->dst);
 125         return &net->ipv6.ip6_null_entry->dst;
 126 }
 127 
 128 static int fib6_rule_saddr(struct net *net, struct fib_rule *rule, int flags,
 129                            struct flowi6 *flp6, const struct net_device *dev)
 130 {
 131         struct fib6_rule *r = (struct fib6_rule *)rule;
 132 
 133         /* If we need to find a source address for this traffic,
 134          * we check the result if it meets requirement of the rule.
 135          */
 136         if ((rule->flags & FIB_RULE_FIND_SADDR) &&
 137             r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) {
 138                 struct in6_addr saddr;
 139 
 140                 if (ipv6_dev_get_saddr(net, dev, &flp6->daddr,
 141                                        rt6_flags2srcprefs(flags), &saddr))
 142                         return -EAGAIN;
 143 
 144                 if (!ipv6_prefix_equal(&saddr, &r->src.addr, r->src.plen))
 145                         return -EAGAIN;
 146 
 147                 flp6->saddr = saddr;
 148         }
 149 
 150         return 0;
 151 }
 152 
 153 static int fib6_rule_action_alt(struct fib_rule *rule, struct flowi *flp,
 154                                 int flags, struct fib_lookup_arg *arg)
 155 {
 156         struct fib6_result *res = arg->result;
 157         struct flowi6 *flp6 = &flp->u.ip6;
 158         struct net *net = rule->fr_net;
 159         struct fib6_table *table;
 160         int err, *oif;
 161         u32 tb_id;
 162 
 163         switch (rule->action) {
 164         case FR_ACT_TO_TBL:
 165                 break;
 166         case FR_ACT_UNREACHABLE:
 167                 return -ENETUNREACH;
 168         case FR_ACT_PROHIBIT:
 169                 return -EACCES;
 170         case FR_ACT_BLACKHOLE:
 171         default:
 172                 return -EINVAL;
 173         }
 174 
 175         tb_id = fib_rule_get_table(rule, arg);
 176         table = fib6_get_table(net, tb_id);
 177         if (!table)
 178                 return -EAGAIN;
 179 
 180         oif = (int *)arg->lookup_data;
 181         err = fib6_table_lookup(net, table, *oif, flp6, res, flags);
 182         if (!err && res->f6i != net->ipv6.fib6_null_entry)
 183                 err = fib6_rule_saddr(net, rule, flags, flp6,
 184                                       res->nh->fib_nh_dev);
 185         else
 186                 err = -EAGAIN;
 187 
 188         return err;
 189 }
 190 
 191 static int __fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
 192                               int flags, struct fib_lookup_arg *arg)
 193 {
 194         struct fib6_result *res = arg->result;
 195         struct flowi6 *flp6 = &flp->u.ip6;
 196         struct rt6_info *rt = NULL;
 197         struct fib6_table *table;
 198         struct net *net = rule->fr_net;
 199         pol_lookup_t lookup = arg->lookup_ptr;
 200         int err = 0;
 201         u32 tb_id;
 202 
 203         switch (rule->action) {
 204         case FR_ACT_TO_TBL:
 205                 break;
 206         case FR_ACT_UNREACHABLE:
 207                 err = -ENETUNREACH;
 208                 rt = net->ipv6.ip6_null_entry;
 209                 goto discard_pkt;
 210         default:
 211         case FR_ACT_BLACKHOLE:
 212                 err = -EINVAL;
 213                 rt = net->ipv6.ip6_blk_hole_entry;
 214                 goto discard_pkt;
 215         case FR_ACT_PROHIBIT:
 216                 err = -EACCES;
 217                 rt = net->ipv6.ip6_prohibit_entry;
 218                 goto discard_pkt;
 219         }
 220 
 221         tb_id = fib_rule_get_table(rule, arg);
 222         table = fib6_get_table(net, tb_id);
 223         if (!table) {
 224                 err = -EAGAIN;
 225                 goto out;
 226         }
 227 
 228         rt = lookup(net, table, flp6, arg->lookup_data, flags);
 229         if (rt != net->ipv6.ip6_null_entry) {
 230                 err = fib6_rule_saddr(net, rule, flags, flp6,
 231                                       ip6_dst_idev(&rt->dst)->dev);
 232 
 233                 if (err == -EAGAIN)
 234                         goto again;
 235 
 236                 err = rt->dst.error;
 237                 if (err != -EAGAIN)
 238                         goto out;
 239         }
 240 again:
 241         ip6_rt_put_flags(rt, flags);
 242         err = -EAGAIN;
 243         rt = NULL;
 244         goto out;
 245 
 246 discard_pkt:
 247         if (!(flags & RT6_LOOKUP_F_DST_NOREF))
 248                 dst_hold(&rt->dst);
 249 out:
 250         res->rt6 = rt;
 251         return err;
 252 }
 253 
 254 static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
 255                             int flags, struct fib_lookup_arg *arg)
 256 {
 257         if (arg->lookup_ptr == fib6_table_lookup)
 258                 return fib6_rule_action_alt(rule, flp, flags, arg);
 259 
 260         return __fib6_rule_action(rule, flp, flags, arg);
 261 }
 262 
 263 static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
 264 {
 265         struct fib6_result *res = arg->result;
 266         struct rt6_info *rt = res->rt6;
 267         struct net_device *dev = NULL;
 268 
 269         if (!rt)
 270                 return false;
 271 
 272         if (rt->rt6i_idev)
 273                 dev = rt->rt6i_idev->dev;
 274 
 275         /* do not accept result if the route does
 276          * not meet the required prefix length
 277          */
 278         if (rt->rt6i_dst.plen <= rule->suppress_prefixlen)
 279                 goto suppress_route;
 280 
 281         /* do not accept result if the route uses a device
 282          * belonging to a forbidden interface group
 283          */
 284         if (rule->suppress_ifgroup != -1 && dev && dev->group == rule->suppress_ifgroup)
 285                 goto suppress_route;
 286 
 287         return false;
 288 
 289 suppress_route:
 290         if (!(arg->flags & FIB_LOOKUP_NOREF))
 291                 ip6_rt_put(rt);
 292         return true;
 293 }
 294 
 295 static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
 296 {
 297         struct fib6_rule *r = (struct fib6_rule *) rule;
 298         struct flowi6 *fl6 = &fl->u.ip6;
 299 
 300         if (r->dst.plen &&
 301             !ipv6_prefix_equal(&fl6->daddr, &r->dst.addr, r->dst.plen))
 302                 return 0;
 303 
 304         /*
 305          * If FIB_RULE_FIND_SADDR is set and we do not have a
 306          * source address for the traffic, we defer check for
 307          * source address.
 308          */
 309         if (r->src.plen) {
 310                 if (flags & RT6_LOOKUP_F_HAS_SADDR) {
 311                         if (!ipv6_prefix_equal(&fl6->saddr, &r->src.addr,
 312                                                r->src.plen))
 313                                 return 0;
 314                 } else if (!(r->common.flags & FIB_RULE_FIND_SADDR))
 315                         return 0;
 316         }
 317 
 318         if (r->tclass && r->tclass != ip6_tclass(fl6->flowlabel))
 319                 return 0;
 320 
 321         if (rule->ip_proto && (rule->ip_proto != fl6->flowi6_proto))
 322                 return 0;
 323 
 324         if (fib_rule_port_range_set(&rule->sport_range) &&
 325             !fib_rule_port_inrange(&rule->sport_range, fl6->fl6_sport))
 326                 return 0;
 327 
 328         if (fib_rule_port_range_set(&rule->dport_range) &&
 329             !fib_rule_port_inrange(&rule->dport_range, fl6->fl6_dport))
 330                 return 0;
 331 
 332         return 1;
 333 }
 334 
 335 static const struct nla_policy fib6_rule_policy[FRA_MAX+1] = {
 336         FRA_GENERIC_POLICY,
 337 };
 338 
 339 static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
 340                                struct fib_rule_hdr *frh,
 341                                struct nlattr **tb,
 342                                struct netlink_ext_ack *extack)
 343 {
 344         int err = -EINVAL;
 345         struct net *net = sock_net(skb->sk);
 346         struct fib6_rule *rule6 = (struct fib6_rule *) rule;
 347 
 348         if (rule->action == FR_ACT_TO_TBL && !rule->l3mdev) {
 349                 if (rule->table == RT6_TABLE_UNSPEC) {
 350                         NL_SET_ERR_MSG(extack, "Invalid table");
 351                         goto errout;
 352                 }
 353 
 354                 if (fib6_new_table(net, rule->table) == NULL) {
 355                         err = -ENOBUFS;
 356                         goto errout;
 357                 }
 358         }
 359 
 360         if (frh->src_len)
 361                 rule6->src.addr = nla_get_in6_addr(tb[FRA_SRC]);
 362 
 363         if (frh->dst_len)
 364                 rule6->dst.addr = nla_get_in6_addr(tb[FRA_DST]);
 365 
 366         rule6->src.plen = frh->src_len;
 367         rule6->dst.plen = frh->dst_len;
 368         rule6->tclass = frh->tos;
 369 
 370         if (fib_rule_requires_fldissect(rule))
 371                 net->ipv6.fib6_rules_require_fldissect++;
 372 
 373         net->ipv6.fib6_has_custom_rules = true;
 374         err = 0;
 375 errout:
 376         return err;
 377 }
 378 
 379 static int fib6_rule_delete(struct fib_rule *rule)
 380 {
 381         struct net *net = rule->fr_net;
 382 
 383         if (net->ipv6.fib6_rules_require_fldissect &&
 384             fib_rule_requires_fldissect(rule))
 385                 net->ipv6.fib6_rules_require_fldissect--;
 386 
 387         return 0;
 388 }
 389 
 390 static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
 391                              struct nlattr **tb)
 392 {
 393         struct fib6_rule *rule6 = (struct fib6_rule *) rule;
 394 
 395         if (frh->src_len && (rule6->src.plen != frh->src_len))
 396                 return 0;
 397 
 398         if (frh->dst_len && (rule6->dst.plen != frh->dst_len))
 399                 return 0;
 400 
 401         if (frh->tos && (rule6->tclass != frh->tos))
 402                 return 0;
 403 
 404         if (frh->src_len &&
 405             nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr)))
 406                 return 0;
 407 
 408         if (frh->dst_len &&
 409             nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr)))
 410                 return 0;
 411 
 412         return 1;
 413 }
 414 
 415 static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
 416                           struct fib_rule_hdr *frh)
 417 {
 418         struct fib6_rule *rule6 = (struct fib6_rule *) rule;
 419 
 420         frh->dst_len = rule6->dst.plen;
 421         frh->src_len = rule6->src.plen;
 422         frh->tos = rule6->tclass;
 423 
 424         if ((rule6->dst.plen &&
 425              nla_put_in6_addr(skb, FRA_DST, &rule6->dst.addr)) ||
 426             (rule6->src.plen &&
 427              nla_put_in6_addr(skb, FRA_SRC, &rule6->src.addr)))
 428                 goto nla_put_failure;
 429         return 0;
 430 
 431 nla_put_failure:
 432         return -ENOBUFS;
 433 }
 434 
 435 static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
 436 {
 437         return nla_total_size(16) /* dst */
 438                + nla_total_size(16); /* src */
 439 }
 440 
 441 static const struct fib_rules_ops __net_initconst fib6_rules_ops_template = {
 442         .family                 = AF_INET6,
 443         .rule_size              = sizeof(struct fib6_rule),
 444         .addr_size              = sizeof(struct in6_addr),
 445         .action                 = fib6_rule_action,
 446         .match                  = fib6_rule_match,
 447         .suppress               = fib6_rule_suppress,
 448         .configure              = fib6_rule_configure,
 449         .delete                 = fib6_rule_delete,
 450         .compare                = fib6_rule_compare,
 451         .fill                   = fib6_rule_fill,
 452         .nlmsg_payload          = fib6_rule_nlmsg_payload,
 453         .nlgroup                = RTNLGRP_IPV6_RULE,
 454         .policy                 = fib6_rule_policy,
 455         .owner                  = THIS_MODULE,
 456         .fro_net                = &init_net,
 457 };
 458 
 459 static int __net_init fib6_rules_net_init(struct net *net)
 460 {
 461         struct fib_rules_ops *ops;
 462         int err = -ENOMEM;
 463 
 464         ops = fib_rules_register(&fib6_rules_ops_template, net);
 465         if (IS_ERR(ops))
 466                 return PTR_ERR(ops);
 467 
 468         err = fib_default_rule_add(ops, 0, RT6_TABLE_LOCAL, 0);
 469         if (err)
 470                 goto out_fib6_rules_ops;
 471 
 472         err = fib_default_rule_add(ops, 0x7FFE, RT6_TABLE_MAIN, 0);
 473         if (err)
 474                 goto out_fib6_rules_ops;
 475 
 476         net->ipv6.fib6_rules_ops = ops;
 477         net->ipv6.fib6_rules_require_fldissect = 0;
 478 out:
 479         return err;
 480 
 481 out_fib6_rules_ops:
 482         fib_rules_unregister(ops);
 483         goto out;
 484 }
 485 
 486 static void __net_exit fib6_rules_net_exit(struct net *net)
 487 {
 488         rtnl_lock();
 489         fib_rules_unregister(net->ipv6.fib6_rules_ops);
 490         rtnl_unlock();
 491 }
 492 
 493 static struct pernet_operations fib6_rules_net_ops = {
 494         .init = fib6_rules_net_init,
 495         .exit = fib6_rules_net_exit,
 496 };
 497 
 498 int __init fib6_rules_init(void)
 499 {
 500         return register_pernet_subsys(&fib6_rules_net_ops);
 501 }
 502 
 503 
 504 void fib6_rules_cleanup(void)
 505 {
 506         unregister_pernet_subsys(&fib6_rules_net_ops);
 507 }

/* [<][>][^][v][top][bottom][index][help] */