LCOV - code coverage report
Current view: top level - net/ipv4 - fib_rules.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 19 168 11.3 %
Date: 2022-03-28 16:04:14 Functions: 2 17 11.8 %
Branches: 4 132 3.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * INET         An implementation of the TCP/IP protocol suite for the LINUX
       4                 :            :  *              operating system.  INET is implemented using the  BSD Socket
       5                 :            :  *              interface as the means of communication with the user level.
       6                 :            :  *
       7                 :            :  *              IPv4 Forwarding Information Base: policy rules.
       8                 :            :  *
       9                 :            :  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
      10                 :            :  *              Thomas Graf <tgraf@suug.ch>
      11                 :            :  *
      12                 :            :  * Fixes:
      13                 :            :  *              Rani Assaf      :       local_rule cannot be deleted
      14                 :            :  *              Marc Boucher    :       routing by fwmark
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <linux/types.h>
      18                 :            : #include <linux/kernel.h>
      19                 :            : #include <linux/netdevice.h>
      20                 :            : #include <linux/netlink.h>
      21                 :            : #include <linux/inetdevice.h>
      22                 :            : #include <linux/init.h>
      23                 :            : #include <linux/list.h>
      24                 :            : #include <linux/rcupdate.h>
      25                 :            : #include <linux/export.h>
      26                 :            : #include <net/ip.h>
      27                 :            : #include <net/route.h>
      28                 :            : #include <net/tcp.h>
      29                 :            : #include <net/ip_fib.h>
      30                 :            : #include <net/nexthop.h>
      31                 :            : #include <net/fib_rules.h>
      32                 :            : 
      33                 :            : struct fib4_rule {
      34                 :            :         struct fib_rule         common;
      35                 :            :         u8                      dst_len;
      36                 :            :         u8                      src_len;
      37                 :            :         u8                      tos;
      38                 :            :         __be32                  src;
      39                 :            :         __be32                  srcmask;
      40                 :            :         __be32                  dst;
      41                 :            :         __be32                  dstmask;
      42                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
      43                 :            :         u32                     tclassid;
      44                 :            : #endif
      45                 :            : };
      46                 :            : 
      47                 :          0 : static bool fib4_rule_matchall(const struct fib_rule *rule)
      48                 :            : {
      49                 :          0 :         struct fib4_rule *r = container_of(rule, struct fib4_rule, common);
      50                 :            : 
      51         [ #  # ]:          0 :         if (r->dst_len || r->src_len || r->tos)
      52                 :            :                 return false;
      53                 :          0 :         return fib_rule_matchall(rule);
      54                 :            : }
      55                 :            : 
      56                 :          0 : bool fib4_rule_default(const struct fib_rule *rule)
      57                 :            : {
      58   [ #  #  #  #  :          0 :         if (!fib4_rule_matchall(rule) || rule->action != FR_ACT_TO_TBL ||
                   #  # ]
      59                 :            :             rule->l3mdev)
      60                 :          0 :                 return false;
      61         [ #  # ]:          0 :         if (rule->table != RT_TABLE_LOCAL && rule->table != RT_TABLE_MAIN &&
      62                 :            :             rule->table != RT_TABLE_DEFAULT)
      63                 :          0 :                 return false;
      64                 :            :         return true;
      65                 :            : }
      66                 :            : EXPORT_SYMBOL_GPL(fib4_rule_default);
      67                 :            : 
      68                 :          0 : int fib4_rules_dump(struct net *net, struct notifier_block *nb,
      69                 :            :                     struct netlink_ext_ack *extack)
      70                 :            : {
      71                 :          0 :         return fib_rules_dump(net, nb, AF_INET, extack);
      72                 :            : }
      73                 :            : 
      74                 :          0 : unsigned int fib4_rules_seq_read(struct net *net)
      75                 :            : {
      76                 :          0 :         return fib_rules_seq_read(net, AF_INET);
      77                 :            : }
      78                 :            : 
      79                 :          0 : int __fib_lookup(struct net *net, struct flowi4 *flp,
      80                 :            :                  struct fib_result *res, unsigned int flags)
      81                 :            : {
      82                 :          0 :         struct fib_lookup_arg arg = {
      83                 :            :                 .result = res,
      84                 :            :                 .flags = flags,
      85                 :            :         };
      86                 :          0 :         int err;
      87                 :            : 
      88                 :            :         /* update flow if oif or iif point to device enslaved to l3mdev */
      89                 :          0 :         l3mdev_update_flow(net, flowi4_to_flowi(flp));
      90                 :            : 
      91                 :          0 :         err = fib_rules_lookup(net->ipv4.rules_ops, flowi4_to_flowi(flp), 0, &arg);
      92                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
      93                 :            :         if (arg.rule)
      94                 :            :                 res->tclassid = ((struct fib4_rule *)arg.rule)->tclassid;
      95                 :            :         else
      96                 :            :                 res->tclassid = 0;
      97                 :            : #endif
      98                 :            : 
      99         [ #  # ]:          0 :         if (err == -ESRCH)
     100                 :          0 :                 err = -ENETUNREACH;
     101                 :            : 
     102                 :          0 :         return err;
     103                 :            : }
     104                 :            : EXPORT_SYMBOL_GPL(__fib_lookup);
     105                 :            : 
     106                 :          0 : static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
     107                 :            :                             int flags, struct fib_lookup_arg *arg)
     108                 :            : {
     109                 :          0 :         int err = -EAGAIN;
     110                 :          0 :         struct fib_table *tbl;
     111                 :          0 :         u32 tb_id;
     112                 :            : 
     113   [ #  #  #  # ]:          0 :         switch (rule->action) {
     114                 :            :         case FR_ACT_TO_TBL:
     115                 :          0 :                 break;
     116                 :            : 
     117                 :            :         case FR_ACT_UNREACHABLE:
     118                 :            :                 return -ENETUNREACH;
     119                 :            : 
     120                 :          0 :         case FR_ACT_PROHIBIT:
     121                 :          0 :                 return -EACCES;
     122                 :            : 
     123                 :          0 :         case FR_ACT_BLACKHOLE:
     124                 :            :         default:
     125                 :          0 :                 return -EINVAL;
     126                 :            :         }
     127                 :            : 
     128                 :          0 :         rcu_read_lock();
     129                 :            : 
     130                 :          0 :         tb_id = fib_rule_get_table(rule, arg);
     131                 :          0 :         tbl = fib_get_table(rule->fr_net, tb_id);
     132         [ #  # ]:          0 :         if (tbl)
     133                 :          0 :                 err = fib_table_lookup(tbl, &flp->u.ip4,
     134                 :          0 :                                        (struct fib_result *)arg->result,
     135                 :            :                                        arg->flags);
     136                 :            : 
     137                 :          0 :         rcu_read_unlock();
     138                 :          0 :         return err;
     139                 :            : }
     140                 :            : 
     141                 :          0 : static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
     142                 :            : {
     143                 :          0 :         struct fib_result *result = (struct fib_result *) arg->result;
     144                 :          0 :         struct net_device *dev = NULL;
     145                 :            : 
     146         [ #  # ]:          0 :         if (result->fi) {
     147         [ #  # ]:          0 :                 struct fib_nh_common *nhc = fib_info_nhc(result->fi, 0);
     148                 :            : 
     149                 :          0 :                 dev = nhc->nhc_dev;
     150                 :            :         }
     151                 :            : 
     152                 :            :         /* do not accept result if the route does
     153                 :            :          * not meet the required prefix length
     154                 :            :          */
     155         [ #  # ]:          0 :         if (result->prefixlen <= rule->suppress_prefixlen)
     156                 :          0 :                 goto suppress_route;
     157                 :            : 
     158                 :            :         /* do not accept result if the route uses a device
     159                 :            :          * belonging to a forbidden interface group
     160                 :            :          */
     161   [ #  #  #  #  :          0 :         if (rule->suppress_ifgroup != -1 && dev && dev->group == rule->suppress_ifgroup)
                   #  # ]
     162                 :          0 :                 goto suppress_route;
     163                 :            : 
     164                 :            :         return false;
     165                 :            : 
     166                 :          0 : suppress_route:
     167         [ #  # ]:          0 :         if (!(arg->flags & FIB_LOOKUP_NOREF))
     168                 :          0 :                 fib_info_put(result->fi);
     169                 :            :         return true;
     170                 :            : }
     171                 :            : 
     172                 :          0 : static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
     173                 :            : {
     174                 :          0 :         struct fib4_rule *r = (struct fib4_rule *) rule;
     175                 :          0 :         struct flowi4 *fl4 = &fl->u.ip4;
     176                 :          0 :         __be32 daddr = fl4->daddr;
     177                 :          0 :         __be32 saddr = fl4->saddr;
     178                 :            : 
     179         [ #  # ]:          0 :         if (((saddr ^ r->src) & r->srcmask) ||
     180         [ #  # ]:          0 :             ((daddr ^ r->dst) & r->dstmask))
     181                 :            :                 return 0;
     182                 :            : 
     183   [ #  #  #  # ]:          0 :         if (r->tos && (r->tos != fl4->flowi4_tos))
     184                 :            :                 return 0;
     185                 :            : 
     186   [ #  #  #  # ]:          0 :         if (rule->ip_proto && (rule->ip_proto != fl4->flowi4_proto))
     187                 :            :                 return 0;
     188                 :            : 
     189   [ #  #  #  #  :          0 :         if (fib_rule_port_range_set(&rule->sport_range) &&
                   #  # ]
     190         [ #  # ]:          0 :             !fib_rule_port_inrange(&rule->sport_range, fl4->fl4_sport))
     191                 :            :                 return 0;
     192                 :            : 
     193   [ #  #  #  #  :          0 :         if (fib_rule_port_range_set(&rule->dport_range) &&
                   #  # ]
     194         [ #  # ]:          0 :             !fib_rule_port_inrange(&rule->dport_range, fl4->fl4_dport))
     195                 :          0 :                 return 0;
     196                 :            : 
     197                 :            :         return 1;
     198                 :            : }
     199                 :            : 
     200                 :          0 : static struct fib_table *fib_empty_table(struct net *net)
     201                 :            : {
     202                 :          0 :         u32 id = 1;
     203                 :            : 
     204                 :          0 :         while (1) {
     205         [ #  # ]:          0 :                 if (!fib_get_table(net, id))
     206                 :          0 :                         return fib_new_table(net, id);
     207                 :            : 
     208         [ #  # ]:          0 :                 if (id++ == RT_TABLE_MAX)
     209                 :            :                         break;
     210                 :            :         }
     211                 :            :         return NULL;
     212                 :            : }
     213                 :            : 
     214                 :            : static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = {
     215                 :            :         FRA_GENERIC_POLICY,
     216                 :            :         [FRA_FLOW]      = { .type = NLA_U32 },
     217                 :            : };
     218                 :            : 
     219                 :          0 : static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
     220                 :            :                                struct fib_rule_hdr *frh,
     221                 :            :                                struct nlattr **tb,
     222                 :            :                                struct netlink_ext_ack *extack)
     223                 :            : {
     224         [ #  # ]:          0 :         struct net *net = sock_net(skb->sk);
     225                 :          0 :         int err = -EINVAL;
     226                 :          0 :         struct fib4_rule *rule4 = (struct fib4_rule *) rule;
     227                 :            : 
     228         [ #  # ]:          0 :         if (frh->tos & ~IPTOS_TOS_MASK) {
     229         [ #  # ]:          0 :                 NL_SET_ERR_MSG(extack, "Invalid tos");
     230                 :          0 :                 goto errout;
     231                 :            :         }
     232                 :            : 
     233                 :            :         /* split local/main if they are not already split */
     234                 :          0 :         err = fib_unmerge(net);
     235         [ #  # ]:          0 :         if (err)
     236                 :          0 :                 goto errout;
     237                 :            : 
     238   [ #  #  #  # ]:          0 :         if (rule->table == RT_TABLE_UNSPEC && !rule->l3mdev) {
     239         [ #  # ]:          0 :                 if (rule->action == FR_ACT_TO_TBL) {
     240                 :          0 :                         struct fib_table *table;
     241                 :            : 
     242                 :          0 :                         table = fib_empty_table(net);
     243         [ #  # ]:          0 :                         if (!table) {
     244                 :          0 :                                 err = -ENOBUFS;
     245                 :          0 :                                 goto errout;
     246                 :            :                         }
     247                 :            : 
     248                 :          0 :                         rule->table = table->tb_id;
     249                 :            :                 }
     250                 :            :         }
     251                 :            : 
     252         [ #  # ]:          0 :         if (frh->src_len)
     253                 :          0 :                 rule4->src = nla_get_in_addr(tb[FRA_SRC]);
     254                 :            : 
     255         [ #  # ]:          0 :         if (frh->dst_len)
     256                 :          0 :                 rule4->dst = nla_get_in_addr(tb[FRA_DST]);
     257                 :            : 
     258                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
     259                 :            :         if (tb[FRA_FLOW]) {
     260                 :            :                 rule4->tclassid = nla_get_u32(tb[FRA_FLOW]);
     261                 :            :                 if (rule4->tclassid)
     262                 :            :                         net->ipv4.fib_num_tclassid_users++;
     263                 :            :         }
     264                 :            : #endif
     265                 :            : 
     266         [ #  # ]:          0 :         if (fib_rule_requires_fldissect(rule))
     267                 :          0 :                 net->ipv4.fib_rules_require_fldissect++;
     268                 :            : 
     269                 :          0 :         rule4->src_len = frh->src_len;
     270         [ #  # ]:          0 :         rule4->srcmask = inet_make_mask(rule4->src_len);
     271                 :          0 :         rule4->dst_len = frh->dst_len;
     272         [ #  # ]:          0 :         rule4->dstmask = inet_make_mask(rule4->dst_len);
     273                 :          0 :         rule4->tos = frh->tos;
     274                 :            : 
     275                 :          0 :         net->ipv4.fib_has_custom_rules = true;
     276                 :            : 
     277                 :          0 :         err = 0;
     278                 :          0 : errout:
     279                 :          0 :         return err;
     280                 :            : }
     281                 :            : 
     282                 :          0 : static int fib4_rule_delete(struct fib_rule *rule)
     283                 :            : {
     284                 :          0 :         struct net *net = rule->fr_net;
     285                 :          0 :         int err;
     286                 :            : 
     287                 :            :         /* split local/main if they are not already split */
     288                 :          0 :         err = fib_unmerge(net);
     289         [ #  # ]:          0 :         if (err)
     290                 :          0 :                 goto errout;
     291                 :            : 
     292                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
     293                 :            :         if (((struct fib4_rule *)rule)->tclassid)
     294                 :            :                 net->ipv4.fib_num_tclassid_users--;
     295                 :            : #endif
     296                 :          0 :         net->ipv4.fib_has_custom_rules = true;
     297                 :            : 
     298         [ #  # ]:          0 :         if (net->ipv4.fib_rules_require_fldissect &&
     299         [ #  # ]:          0 :             fib_rule_requires_fldissect(rule))
     300                 :          0 :                 net->ipv4.fib_rules_require_fldissect--;
     301                 :          0 : errout:
     302                 :          0 :         return err;
     303                 :            : }
     304                 :            : 
     305                 :          0 : static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
     306                 :            :                              struct nlattr **tb)
     307                 :            : {
     308                 :          0 :         struct fib4_rule *rule4 = (struct fib4_rule *) rule;
     309                 :            : 
     310   [ #  #  #  # ]:          0 :         if (frh->src_len && (rule4->src_len != frh->src_len))
     311                 :            :                 return 0;
     312                 :            : 
     313   [ #  #  #  # ]:          0 :         if (frh->dst_len && (rule4->dst_len != frh->dst_len))
     314                 :            :                 return 0;
     315                 :            : 
     316   [ #  #  #  # ]:          0 :         if (frh->tos && (rule4->tos != frh->tos))
     317                 :            :                 return 0;
     318                 :            : 
     319                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
     320                 :            :         if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW])))
     321                 :            :                 return 0;
     322                 :            : #endif
     323                 :            : 
     324   [ #  #  #  # ]:          0 :         if (frh->src_len && (rule4->src != nla_get_in_addr(tb[FRA_SRC])))
     325                 :            :                 return 0;
     326                 :            : 
     327   [ #  #  #  # ]:          0 :         if (frh->dst_len && (rule4->dst != nla_get_in_addr(tb[FRA_DST])))
     328                 :          0 :                 return 0;
     329                 :            : 
     330                 :            :         return 1;
     331                 :            : }
     332                 :            : 
     333                 :          0 : static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
     334                 :            :                           struct fib_rule_hdr *frh)
     335                 :            : {
     336                 :          0 :         struct fib4_rule *rule4 = (struct fib4_rule *) rule;
     337                 :            : 
     338                 :          0 :         frh->dst_len = rule4->dst_len;
     339                 :          0 :         frh->src_len = rule4->src_len;
     340                 :          0 :         frh->tos = rule4->tos;
     341                 :            : 
     342   [ #  #  #  # ]:          0 :         if ((rule4->dst_len &&
     343                 :          0 :              nla_put_in_addr(skb, FRA_DST, rule4->dst)) ||
     344   [ #  #  #  # ]:          0 :             (rule4->src_len &&
     345                 :          0 :              nla_put_in_addr(skb, FRA_SRC, rule4->src)))
     346                 :          0 :                 goto nla_put_failure;
     347                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
     348                 :            :         if (rule4->tclassid &&
     349                 :            :             nla_put_u32(skb, FRA_FLOW, rule4->tclassid))
     350                 :            :                 goto nla_put_failure;
     351                 :            : #endif
     352                 :            :         return 0;
     353                 :            : 
     354                 :            : nla_put_failure:
     355                 :          0 :         return -ENOBUFS;
     356                 :            : }
     357                 :            : 
     358                 :          0 : static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule)
     359                 :            : {
     360                 :          0 :         return nla_total_size(4) /* dst */
     361                 :            :                + nla_total_size(4) /* src */
     362                 :          0 :                + nla_total_size(4); /* flow */
     363                 :            : }
     364                 :            : 
     365                 :          0 : static void fib4_rule_flush_cache(struct fib_rules_ops *ops)
     366                 :            : {
     367                 :          0 :         rt_cache_flush(ops->fro_net);
     368                 :          0 : }
     369                 :            : 
     370                 :            : static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = {
     371                 :            :         .family         = AF_INET,
     372                 :            :         .rule_size      = sizeof(struct fib4_rule),
     373                 :            :         .addr_size      = sizeof(u32),
     374                 :            :         .action         = fib4_rule_action,
     375                 :            :         .suppress       = fib4_rule_suppress,
     376                 :            :         .match          = fib4_rule_match,
     377                 :            :         .configure      = fib4_rule_configure,
     378                 :            :         .delete         = fib4_rule_delete,
     379                 :            :         .compare        = fib4_rule_compare,
     380                 :            :         .fill           = fib4_rule_fill,
     381                 :            :         .nlmsg_payload  = fib4_rule_nlmsg_payload,
     382                 :            :         .flush_cache    = fib4_rule_flush_cache,
     383                 :            :         .nlgroup        = RTNLGRP_IPV4_RULE,
     384                 :            :         .policy         = fib4_rule_policy,
     385                 :            :         .owner          = THIS_MODULE,
     386                 :            : };
     387                 :            : 
     388                 :         13 : static int fib_default_rules_init(struct fib_rules_ops *ops)
     389                 :            : {
     390                 :         13 :         int err;
     391                 :            : 
     392                 :         13 :         err = fib_default_rule_add(ops, 0, RT_TABLE_LOCAL, 0);
     393         [ +  - ]:         13 :         if (err < 0)
     394                 :            :                 return err;
     395                 :         13 :         err = fib_default_rule_add(ops, 0x7FFE, RT_TABLE_MAIN, 0);
     396         [ +  - ]:         13 :         if (err < 0)
     397                 :            :                 return err;
     398                 :         13 :         err = fib_default_rule_add(ops, 0x7FFF, RT_TABLE_DEFAULT, 0);
     399                 :         13 :         if (err < 0)
     400                 :            :                 return err;
     401                 :            :         return 0;
     402                 :            : }
     403                 :            : 
     404                 :         13 : int __net_init fib4_rules_init(struct net *net)
     405                 :            : {
     406                 :         13 :         int err;
     407                 :         13 :         struct fib_rules_ops *ops;
     408                 :            : 
     409                 :         13 :         ops = fib_rules_register(&fib4_rules_ops_template, net);
     410         [ -  + ]:         13 :         if (IS_ERR(ops))
     411                 :          0 :                 return PTR_ERR(ops);
     412                 :            : 
     413                 :         13 :         err = fib_default_rules_init(ops);
     414         [ -  + ]:         13 :         if (err < 0)
     415                 :          0 :                 goto fail;
     416                 :         13 :         net->ipv4.rules_ops = ops;
     417                 :         13 :         net->ipv4.fib_has_custom_rules = false;
     418                 :         13 :         net->ipv4.fib_rules_require_fldissect = 0;
     419                 :         13 :         return 0;
     420                 :            : 
     421                 :            : fail:
     422                 :            :         /* also cleans all rules already added */
     423                 :          0 :         fib_rules_unregister(ops);
     424                 :          0 :         return err;
     425                 :            : }
     426                 :            : 
     427                 :          0 : void __net_exit fib4_rules_exit(struct net *net)
     428                 :            : {
     429                 :          0 :         fib_rules_unregister(net->ipv4.rules_ops);
     430                 :          0 : }

Generated by: LCOV version 1.14