LCOV - code coverage report
Current view: top level - net/ipv4 - fib_rules.c (source / functions) Hit Total Coverage
Test: Real Lines: 27 137 19.7 %
Date: 2020-10-17 15:46:16 Functions: 0 17 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 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                 :            : static bool fib4_rule_matchall(const struct fib_rule *rule)
      48                 :            : {
      49                 :            :         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                 :            :                 return false;
      61                 :          0 :         if (rule->table != RT_TABLE_LOCAL && rule->table != RT_TABLE_MAIN &&
      62                 :            :             rule->table != RT_TABLE_DEFAULT)
      63                 :            :                 return false;
      64                 :          0 :         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                 :            : {
      70                 :          0 :         return fib_rules_dump(net, nb, AF_INET);
      71                 :            : }
      72                 :            : 
      73                 :          0 : unsigned int fib4_rules_seq_read(struct net *net)
      74                 :            : {
      75                 :          0 :         return fib_rules_seq_read(net, AF_INET);
      76                 :            : }
      77                 :            : 
      78                 :          0 : int __fib_lookup(struct net *net, struct flowi4 *flp,
      79                 :            :                  struct fib_result *res, unsigned int flags)
      80                 :            : {
      81                 :          0 :         struct fib_lookup_arg arg = {
      82                 :            :                 .result = res,
      83                 :            :                 .flags = flags,
      84                 :            :         };
      85                 :            :         int err;
      86                 :            : 
      87                 :            :         /* update flow if oif or iif point to device enslaved to l3mdev */
      88                 :          0 :         l3mdev_update_flow(net, flowi4_to_flowi(flp));
      89                 :            : 
      90                 :          0 :         err = fib_rules_lookup(net->ipv4.rules_ops, flowi4_to_flowi(flp), 0, &arg);
      91                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
      92                 :          0 :         if (arg.rule)
      93                 :          0 :                 res->tclassid = ((struct fib4_rule *)arg.rule)->tclassid;
      94                 :            :         else
      95                 :          0 :                 res->tclassid = 0;
      96                 :            : #endif
      97                 :            : 
      98                 :          0 :         if (err == -ESRCH)
      99                 :            :                 err = -ENETUNREACH;
     100                 :            : 
     101                 :          0 :         return err;
     102                 :            : }
     103                 :            : EXPORT_SYMBOL_GPL(__fib_lookup);
     104                 :            : 
     105                 :          0 : static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
     106                 :            :                             int flags, struct fib_lookup_arg *arg)
     107                 :            : {
     108                 :            :         int err = -EAGAIN;
     109                 :            :         struct fib_table *tbl;
     110                 :            :         u32 tb_id;
     111                 :            : 
     112                 :          0 :         switch (rule->action) {
     113                 :            :         case FR_ACT_TO_TBL:
     114                 :            :                 break;
     115                 :            : 
     116                 :            :         case FR_ACT_UNREACHABLE:
     117                 :            :                 return -ENETUNREACH;
     118                 :            : 
     119                 :            :         case FR_ACT_PROHIBIT:
     120                 :          0 :                 return -EACCES;
     121                 :            : 
     122                 :            :         case FR_ACT_BLACKHOLE:
     123                 :            :         default:
     124                 :          0 :                 return -EINVAL;
     125                 :            :         }
     126                 :            : 
     127                 :            :         rcu_read_lock();
     128                 :            : 
     129                 :            :         tb_id = fib_rule_get_table(rule, arg);
     130                 :          0 :         tbl = fib_get_table(rule->fr_net, tb_id);
     131                 :          0 :         if (tbl)
     132                 :          0 :                 err = fib_table_lookup(tbl, &flp->u.ip4,
     133                 :          0 :                                        (struct fib_result *)arg->result,
     134                 :            :                                        arg->flags);
     135                 :            : 
     136                 :            :         rcu_read_unlock();
     137                 :          0 :         return err;
     138                 :            : }
     139                 :            : 
     140                 :          0 : static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
     141                 :            : {
     142                 :          0 :         struct fib_result *result = (struct fib_result *) arg->result;
     143                 :            :         struct net_device *dev = NULL;
     144                 :            : 
     145                 :          0 :         if (result->fi) {
     146                 :          0 :                 struct fib_nh_common *nhc = fib_info_nhc(result->fi, 0);
     147                 :            : 
     148                 :          0 :                 dev = nhc->nhc_dev;
     149                 :            :         }
     150                 :            : 
     151                 :            :         /* do not accept result if the route does
     152                 :            :          * not meet the required prefix length
     153                 :            :          */
     154                 :          0 :         if (result->prefixlen <= rule->suppress_prefixlen)
     155                 :            :                 goto suppress_route;
     156                 :            : 
     157                 :            :         /* do not accept result if the route uses a device
     158                 :            :          * belonging to a forbidden interface group
     159                 :            :          */
     160                 :          0 :         if (rule->suppress_ifgroup != -1 && dev && dev->group == rule->suppress_ifgroup)
     161                 :            :                 goto suppress_route;
     162                 :            : 
     163                 :            :         return false;
     164                 :            : 
     165                 :            : suppress_route:
     166                 :          0 :         if (!(arg->flags & FIB_LOOKUP_NOREF))
     167                 :          0 :                 fib_info_put(result->fi);
     168                 :            :         return true;
     169                 :            : }
     170                 :            : 
     171                 :          0 : static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
     172                 :            : {
     173                 :            :         struct fib4_rule *r = (struct fib4_rule *) rule;
     174                 :            :         struct flowi4 *fl4 = &fl->u.ip4;
     175                 :          0 :         __be32 daddr = fl4->daddr;
     176                 :          0 :         __be32 saddr = fl4->saddr;
     177                 :            : 
     178                 :          0 :         if (((saddr ^ r->src) & r->srcmask) ||
     179                 :          0 :             ((daddr ^ r->dst) & r->dstmask))
     180                 :            :                 return 0;
     181                 :            : 
     182                 :          0 :         if (r->tos && (r->tos != fl4->flowi4_tos))
     183                 :            :                 return 0;
     184                 :            : 
     185                 :          0 :         if (rule->ip_proto && (rule->ip_proto != fl4->flowi4_proto))
     186                 :            :                 return 0;
     187                 :            : 
     188                 :          0 :         if (fib_rule_port_range_set(&rule->sport_range) &&
     189                 :          0 :             !fib_rule_port_inrange(&rule->sport_range, fl4->fl4_sport))
     190                 :            :                 return 0;
     191                 :            : 
     192                 :          0 :         if (fib_rule_port_range_set(&rule->dport_range) &&
     193                 :          0 :             !fib_rule_port_inrange(&rule->dport_range, fl4->fl4_dport))
     194                 :            :                 return 0;
     195                 :            : 
     196                 :          0 :         return 1;
     197                 :            : }
     198                 :            : 
     199                 :          0 : static struct fib_table *fib_empty_table(struct net *net)
     200                 :            : {
     201                 :            :         u32 id = 1;
     202                 :            : 
     203                 :            :         while (1) {
     204                 :          0 :                 if (!fib_get_table(net, id))
     205                 :          0 :                         return fib_new_table(net, id);
     206                 :            : 
     207                 :          0 :                 if (id++ == RT_TABLE_MAX)
     208                 :            :                         break;
     209                 :            :         }
     210                 :            :         return NULL;
     211                 :            : }
     212                 :            : 
     213                 :            : static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = {
     214                 :            :         FRA_GENERIC_POLICY,
     215                 :            :         [FRA_FLOW]      = { .type = NLA_U32 },
     216                 :            : };
     217                 :            : 
     218                 :          0 : static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
     219                 :            :                                struct fib_rule_hdr *frh,
     220                 :            :                                struct nlattr **tb,
     221                 :            :                                struct netlink_ext_ack *extack)
     222                 :            : {
     223                 :          0 :         struct net *net = sock_net(skb->sk);
     224                 :            :         int err = -EINVAL;
     225                 :            :         struct fib4_rule *rule4 = (struct fib4_rule *) rule;
     226                 :            : 
     227                 :          0 :         if (frh->tos & ~IPTOS_TOS_MASK) {
     228                 :          0 :                 NL_SET_ERR_MSG(extack, "Invalid tos");
     229                 :            :                 goto errout;
     230                 :            :         }
     231                 :            : 
     232                 :            :         /* split local/main if they are not already split */
     233                 :          0 :         err = fib_unmerge(net);
     234                 :          0 :         if (err)
     235                 :            :                 goto errout;
     236                 :            : 
     237                 :          0 :         if (rule->table == RT_TABLE_UNSPEC && !rule->l3mdev) {
     238                 :          0 :                 if (rule->action == FR_ACT_TO_TBL) {
     239                 :            :                         struct fib_table *table;
     240                 :            : 
     241                 :          0 :                         table = fib_empty_table(net);
     242                 :          0 :                         if (!table) {
     243                 :            :                                 err = -ENOBUFS;
     244                 :            :                                 goto errout;
     245                 :            :                         }
     246                 :            : 
     247                 :          0 :                         rule->table = table->tb_id;
     248                 :            :                 }
     249                 :            :         }
     250                 :            : 
     251                 :          0 :         if (frh->src_len)
     252                 :          0 :                 rule4->src = nla_get_in_addr(tb[FRA_SRC]);
     253                 :            : 
     254                 :          0 :         if (frh->dst_len)
     255                 :          0 :                 rule4->dst = nla_get_in_addr(tb[FRA_DST]);
     256                 :            : 
     257                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
     258                 :          0 :         if (tb[FRA_FLOW]) {
     259                 :          0 :                 rule4->tclassid = nla_get_u32(tb[FRA_FLOW]);
     260                 :          0 :                 if (rule4->tclassid)
     261                 :          0 :                         net->ipv4.fib_num_tclassid_users++;
     262                 :            :         }
     263                 :            : #endif
     264                 :            : 
     265                 :          0 :         if (fib_rule_requires_fldissect(rule))
     266                 :          0 :                 net->ipv4.fib_rules_require_fldissect++;
     267                 :            : 
     268                 :          0 :         rule4->src_len = frh->src_len;
     269                 :          0 :         rule4->srcmask = inet_make_mask(rule4->src_len);
     270                 :          0 :         rule4->dst_len = frh->dst_len;
     271                 :          0 :         rule4->dstmask = inet_make_mask(rule4->dst_len);
     272                 :          0 :         rule4->tos = frh->tos;
     273                 :            : 
     274                 :          0 :         net->ipv4.fib_has_custom_rules = true;
     275                 :            : 
     276                 :            :         err = 0;
     277                 :            : errout:
     278                 :          0 :         return err;
     279                 :            : }
     280                 :            : 
     281                 :          1 : static int fib4_rule_delete(struct fib_rule *rule)
     282                 :            : {
     283                 :          1 :         struct net *net = rule->fr_net;
     284                 :            :         int err;
     285                 :            : 
     286                 :            :         /* split local/main if they are not already split */
     287                 :          1 :         err = fib_unmerge(net);
     288                 :          1 :         if (err)
     289                 :            :                 goto errout;
     290                 :            : 
     291                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
     292                 :          1 :         if (((struct fib4_rule *)rule)->tclassid)
     293                 :          0 :                 net->ipv4.fib_num_tclassid_users--;
     294                 :            : #endif
     295                 :          1 :         net->ipv4.fib_has_custom_rules = true;
     296                 :            : 
     297                 :          1 :         if (net->ipv4.fib_rules_require_fldissect &&
     298                 :          0 :             fib_rule_requires_fldissect(rule))
     299                 :          0 :                 net->ipv4.fib_rules_require_fldissect--;
     300                 :            : errout:
     301                 :          1 :         return err;
     302                 :            : }
     303                 :            : 
     304                 :          0 : static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
     305                 :            :                              struct nlattr **tb)
     306                 :            : {
     307                 :            :         struct fib4_rule *rule4 = (struct fib4_rule *) rule;
     308                 :            : 
     309                 :          0 :         if (frh->src_len && (rule4->src_len != frh->src_len))
     310                 :            :                 return 0;
     311                 :            : 
     312                 :          0 :         if (frh->dst_len && (rule4->dst_len != frh->dst_len))
     313                 :            :                 return 0;
     314                 :            : 
     315                 :          0 :         if (frh->tos && (rule4->tos != frh->tos))
     316                 :            :                 return 0;
     317                 :            : 
     318                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
     319                 :          0 :         if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW])))
     320                 :            :                 return 0;
     321                 :            : #endif
     322                 :            : 
     323                 :          0 :         if (frh->src_len && (rule4->src != nla_get_in_addr(tb[FRA_SRC])))
     324                 :            :                 return 0;
     325                 :            : 
     326                 :          0 :         if (frh->dst_len && (rule4->dst != nla_get_in_addr(tb[FRA_DST])))
     327                 :            :                 return 0;
     328                 :            : 
     329                 :          0 :         return 1;
     330                 :            : }
     331                 :            : 
     332                 :          0 : static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
     333                 :            :                           struct fib_rule_hdr *frh)
     334                 :            : {
     335                 :            :         struct fib4_rule *rule4 = (struct fib4_rule *) rule;
     336                 :            : 
     337                 :          0 :         frh->dst_len = rule4->dst_len;
     338                 :          0 :         frh->src_len = rule4->src_len;
     339                 :          0 :         frh->tos = rule4->tos;
     340                 :            : 
     341                 :          0 :         if ((rule4->dst_len &&
     342                 :          0 :              nla_put_in_addr(skb, FRA_DST, rule4->dst)) ||
     343                 :          0 :             (rule4->src_len &&
     344                 :          0 :              nla_put_in_addr(skb, FRA_SRC, rule4->src)))
     345                 :            :                 goto nla_put_failure;
     346                 :            : #ifdef CONFIG_IP_ROUTE_CLASSID
     347                 :          0 :         if (rule4->tclassid &&
     348                 :            :             nla_put_u32(skb, FRA_FLOW, rule4->tclassid))
     349                 :            :                 goto nla_put_failure;
     350                 :            : #endif
     351                 :            :         return 0;
     352                 :            : 
     353                 :            : nla_put_failure:
     354                 :            :         return -ENOBUFS;
     355                 :            : }
     356                 :            : 
     357                 :          0 : static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule)
     358                 :            : {
     359                 :          0 :         return nla_total_size(4) /* dst */
     360                 :            :                + nla_total_size(4) /* src */
     361                 :            :                + nla_total_size(4); /* flow */
     362                 :            : }
     363                 :            : 
     364                 :          0 : static void fib4_rule_flush_cache(struct fib_rules_ops *ops)
     365                 :            : {
     366                 :          0 :         rt_cache_flush(ops->fro_net);
     367                 :          0 : }
     368                 :            : 
     369                 :            : static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = {
     370                 :            :         .family         = AF_INET,
     371                 :            :         .rule_size      = sizeof(struct fib4_rule),
     372                 :            :         .addr_size      = sizeof(u32),
     373                 :            :         .action         = fib4_rule_action,
     374                 :            :         .suppress       = fib4_rule_suppress,
     375                 :            :         .match          = fib4_rule_match,
     376                 :            :         .configure      = fib4_rule_configure,
     377                 :            :         .delete         = fib4_rule_delete,
     378                 :            :         .compare        = fib4_rule_compare,
     379                 :            :         .fill           = fib4_rule_fill,
     380                 :            :         .nlmsg_payload  = fib4_rule_nlmsg_payload,
     381                 :            :         .flush_cache    = fib4_rule_flush_cache,
     382                 :            :         .nlgroup        = RTNLGRP_IPV4_RULE,
     383                 :            :         .policy         = fib4_rule_policy,
     384                 :            :         .owner          = THIS_MODULE,
     385                 :            : };
     386                 :            : 
     387                 :          3 : static int fib_default_rules_init(struct fib_rules_ops *ops)
     388                 :            : {
     389                 :            :         int err;
     390                 :            : 
     391                 :          3 :         err = fib_default_rule_add(ops, 0, RT_TABLE_LOCAL, 0);
     392                 :          3 :         if (err < 0)
     393                 :            :                 return err;
     394                 :          3 :         err = fib_default_rule_add(ops, 0x7FFE, RT_TABLE_MAIN, 0);
     395                 :          3 :         if (err < 0)
     396                 :            :                 return err;
     397                 :          3 :         err = fib_default_rule_add(ops, 0x7FFF, RT_TABLE_DEFAULT, 0);
     398                 :          3 :         if (err < 0)
     399                 :          0 :                 return err;
     400                 :            :         return 0;
     401                 :            : }
     402                 :            : 
     403                 :          3 : int __net_init fib4_rules_init(struct net *net)
     404                 :            : {
     405                 :            :         int err;
     406                 :            :         struct fib_rules_ops *ops;
     407                 :            : 
     408                 :          3 :         ops = fib_rules_register(&fib4_rules_ops_template, net);
     409                 :          3 :         if (IS_ERR(ops))
     410                 :          0 :                 return PTR_ERR(ops);
     411                 :            : 
     412                 :          3 :         err = fib_default_rules_init(ops);
     413                 :          3 :         if (err < 0)
     414                 :            :                 goto fail;
     415                 :          3 :         net->ipv4.rules_ops = ops;
     416                 :          3 :         net->ipv4.fib_has_custom_rules = false;
     417                 :          3 :         net->ipv4.fib_rules_require_fldissect = 0;
     418                 :          3 :         return 0;
     419                 :            : 
     420                 :            : fail:
     421                 :            :         /* also cleans all rules already added */
     422                 :          0 :         fib_rules_unregister(ops);
     423                 :          0 :         return err;
     424                 :            : }
     425                 :            : 
     426                 :          1 : void __net_exit fib4_rules_exit(struct net *net)
     427                 :            : {
     428                 :          1 :         fib_rules_unregister(net->ipv4.rules_ops);
     429                 :          1 : }
    

Generated by: LCOV version 1.14