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