11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * INET An implementation of the TCP/IP protocol suite for the LINUX 31da177e4SLinus Torvalds * operating system. INET is implemented using the BSD Socket 41da177e4SLinus Torvalds * interface as the means of communication with the user level. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * IPv4 Forwarding Information Base: policy rules. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 9e1ef4bf2SThomas Graf * Thomas Graf <tgraf@suug.ch> 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 121da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 131da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 141da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * Fixes: 171da177e4SLinus Torvalds * Rani Assaf : local_rule cannot be deleted 181da177e4SLinus Torvalds * Marc Boucher : routing by fwmark 191da177e4SLinus Torvalds */ 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #include <linux/types.h> 221da177e4SLinus Torvalds #include <linux/kernel.h> 231da177e4SLinus Torvalds #include <linux/netdevice.h> 241da177e4SLinus Torvalds #include <linux/netlink.h> 25e1ef4bf2SThomas Graf #include <linux/inetdevice.h> 261da177e4SLinus Torvalds #include <linux/init.h> 277b204afdSRobert Olsson #include <linux/list.h> 287b204afdSRobert Olsson #include <linux/rcupdate.h> 291da177e4SLinus Torvalds #include <net/ip.h> 301da177e4SLinus Torvalds #include <net/route.h> 311da177e4SLinus Torvalds #include <net/tcp.h> 321da177e4SLinus Torvalds #include <net/ip_fib.h> 33e1ef4bf2SThomas Graf #include <net/fib_rules.h> 341da177e4SLinus Torvalds 35e1ef4bf2SThomas Graf struct fib4_rule 361da177e4SLinus Torvalds { 37e1ef4bf2SThomas Graf struct fib_rule common; 38e1ef4bf2SThomas Graf u8 dst_len; 39e1ef4bf2SThomas Graf u8 src_len; 40e1ef4bf2SThomas Graf u8 tos; 4181f7bf6cSAl Viro __be32 src; 4281f7bf6cSAl Viro __be32 srcmask; 4381f7bf6cSAl Viro __be32 dst; 4481f7bf6cSAl Viro __be32 dstmask; 451da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE 46e1ef4bf2SThomas Graf u32 tclassid; 471da177e4SLinus Torvalds #endif 481da177e4SLinus Torvalds }; 491da177e4SLinus Torvalds 50e1ef4bf2SThomas Graf #ifdef CONFIG_NET_CLS_ROUTE 51e1ef4bf2SThomas Graf u32 fib_rules_tclass(struct fib_result *res) 521da177e4SLinus Torvalds { 53e1ef4bf2SThomas Graf return res->r ? ((struct fib4_rule *) res->r)->tclassid : 0; 54e1ef4bf2SThomas Graf } 551da177e4SLinus Torvalds #endif 561da177e4SLinus Torvalds 57e1ef4bf2SThomas Graf int fib_lookup(struct flowi *flp, struct fib_result *res) 58e1ef4bf2SThomas Graf { 59e1ef4bf2SThomas Graf struct fib_lookup_arg arg = { 60e1ef4bf2SThomas Graf .result = res, 61e1ef4bf2SThomas Graf }; 62e1ef4bf2SThomas Graf int err; 63e1ef4bf2SThomas Graf 64e4e4971cSDenis V. Lunev err = fib_rules_lookup(init_net.ipv4.rules_ops, flp, 0, &arg); 65e1ef4bf2SThomas Graf res->r = arg.rule; 66e1ef4bf2SThomas Graf 671da177e4SLinus Torvalds return err; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 708ce11e6aSAdrian Bunk static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp, 718ce11e6aSAdrian Bunk int flags, struct fib_lookup_arg *arg) 72e1ef4bf2SThomas Graf { 73e1ef4bf2SThomas Graf int err = -EAGAIN; 74e1ef4bf2SThomas Graf struct fib_table *tbl; 75e1ef4bf2SThomas Graf 76e1ef4bf2SThomas Graf switch (rule->action) { 77e1ef4bf2SThomas Graf case FR_ACT_TO_TBL: 78e1ef4bf2SThomas Graf break; 79e1ef4bf2SThomas Graf 80e1ef4bf2SThomas Graf case FR_ACT_UNREACHABLE: 81e1ef4bf2SThomas Graf err = -ENETUNREACH; 82e1ef4bf2SThomas Graf goto errout; 83e1ef4bf2SThomas Graf 84e1ef4bf2SThomas Graf case FR_ACT_PROHIBIT: 85e1ef4bf2SThomas Graf err = -EACCES; 86e1ef4bf2SThomas Graf goto errout; 87e1ef4bf2SThomas Graf 88e1ef4bf2SThomas Graf case FR_ACT_BLACKHOLE: 89e1ef4bf2SThomas Graf default: 90e1ef4bf2SThomas Graf err = -EINVAL; 91e1ef4bf2SThomas Graf goto errout; 92e1ef4bf2SThomas Graf } 93e1ef4bf2SThomas Graf 948ad4942cSDenis V. Lunev if ((tbl = fib_get_table(&init_net, rule->table)) == NULL) 95e1ef4bf2SThomas Graf goto errout; 96e1ef4bf2SThomas Graf 97e1ef4bf2SThomas Graf err = tbl->tb_lookup(tbl, flp, (struct fib_result *) arg->result); 98e1ef4bf2SThomas Graf if (err > 0) 99e1ef4bf2SThomas Graf err = -EAGAIN; 100e1ef4bf2SThomas Graf errout: 101e1ef4bf2SThomas Graf return err; 102e1ef4bf2SThomas Graf } 103e1ef4bf2SThomas Graf 104e1ef4bf2SThomas Graf 105e1ef4bf2SThomas Graf void fib_select_default(const struct flowi *flp, struct fib_result *res) 106e1ef4bf2SThomas Graf { 107e1ef4bf2SThomas Graf if (res->r && res->r->action == FR_ACT_TO_TBL && 108e1ef4bf2SThomas Graf FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) { 109e1ef4bf2SThomas Graf struct fib_table *tb; 1108ad4942cSDenis V. Lunev if ((tb = fib_get_table(&init_net, res->r->table)) != NULL) 111e1ef4bf2SThomas Graf tb->tb_select_default(tb, flp, res); 112e1ef4bf2SThomas Graf } 113e1ef4bf2SThomas Graf } 114e1ef4bf2SThomas Graf 115e1ef4bf2SThomas Graf static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) 116e1ef4bf2SThomas Graf { 117e1ef4bf2SThomas Graf struct fib4_rule *r = (struct fib4_rule *) rule; 11881f7bf6cSAl Viro __be32 daddr = fl->fl4_dst; 11981f7bf6cSAl Viro __be32 saddr = fl->fl4_src; 120e1ef4bf2SThomas Graf 121e1ef4bf2SThomas Graf if (((saddr ^ r->src) & r->srcmask) || 122e1ef4bf2SThomas Graf ((daddr ^ r->dst) & r->dstmask)) 123e1ef4bf2SThomas Graf return 0; 124e1ef4bf2SThomas Graf 125e1ef4bf2SThomas Graf if (r->tos && (r->tos != fl->fl4_tos)) 126e1ef4bf2SThomas Graf return 0; 127e1ef4bf2SThomas Graf 128e1ef4bf2SThomas Graf return 1; 129e1ef4bf2SThomas Graf } 1301da177e4SLinus Torvalds 1318ad4942cSDenis V. Lunev static struct fib_table *fib_empty_table(struct net *net) 1321da177e4SLinus Torvalds { 1332dfe55b4SPatrick McHardy u32 id; 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds for (id = 1; id <= RT_TABLE_MAX; id++) 1368ad4942cSDenis V. Lunev if (fib_get_table(net, id) == NULL) 1378ad4942cSDenis V. Lunev return fib_new_table(net, id); 1381da177e4SLinus Torvalds return NULL; 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds 141ef7c79edSPatrick McHardy static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = { 1421f6c9557SThomas Graf FRA_GENERIC_POLICY, 143e1ef4bf2SThomas Graf [FRA_FLOW] = { .type = NLA_U32 }, 1441da177e4SLinus Torvalds }; 1451da177e4SLinus Torvalds 146e1ef4bf2SThomas Graf static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, 147e1ef4bf2SThomas Graf struct nlmsghdr *nlh, struct fib_rule_hdr *frh, 148e1ef4bf2SThomas Graf struct nlattr **tb) 1491da177e4SLinus Torvalds { 150e4e4971cSDenis V. Lunev struct net *net = skb->sk->sk_net; 151e1ef4bf2SThomas Graf int err = -EINVAL; 152e1ef4bf2SThomas Graf struct fib4_rule *rule4 = (struct fib4_rule *) rule; 1531da177e4SLinus Torvalds 154e1701c68SThomas Graf if (frh->tos & ~IPTOS_TOS_MASK) 155e1ef4bf2SThomas Graf goto errout; 156e1ef4bf2SThomas Graf 157e1ef4bf2SThomas Graf if (rule->table == RT_TABLE_UNSPEC) { 158e1ef4bf2SThomas Graf if (rule->action == FR_ACT_TO_TBL) { 159e1ef4bf2SThomas Graf struct fib_table *table; 160e1ef4bf2SThomas Graf 161e4e4971cSDenis V. Lunev table = fib_empty_table(net); 162e1ef4bf2SThomas Graf if (table == NULL) { 163e1ef4bf2SThomas Graf err = -ENOBUFS; 164e1ef4bf2SThomas Graf goto errout; 165e1ef4bf2SThomas Graf } 166e1ef4bf2SThomas Graf 167e1ef4bf2SThomas Graf rule->table = table->tb_id; 168e1ef4bf2SThomas Graf } 169e1ef4bf2SThomas Graf } 170e1ef4bf2SThomas Graf 171e1701c68SThomas Graf if (frh->src_len) 17245d60b9eSAl Viro rule4->src = nla_get_be32(tb[FRA_SRC]); 173e1ef4bf2SThomas Graf 174e1701c68SThomas Graf if (frh->dst_len) 17545d60b9eSAl Viro rule4->dst = nla_get_be32(tb[FRA_DST]); 176e1ef4bf2SThomas Graf 1771da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE 178e1ef4bf2SThomas Graf if (tb[FRA_FLOW]) 179e1ef4bf2SThomas Graf rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); 1801da177e4SLinus Torvalds #endif 1811da177e4SLinus Torvalds 182e1ef4bf2SThomas Graf rule4->src_len = frh->src_len; 183e1ef4bf2SThomas Graf rule4->srcmask = inet_make_mask(rule4->src_len); 184e1ef4bf2SThomas Graf rule4->dst_len = frh->dst_len; 185e1ef4bf2SThomas Graf rule4->dstmask = inet_make_mask(rule4->dst_len); 186e1ef4bf2SThomas Graf rule4->tos = frh->tos; 187e1ef4bf2SThomas Graf 188e1ef4bf2SThomas Graf err = 0; 189e1ef4bf2SThomas Graf errout: 190e1ef4bf2SThomas Graf return err; 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 193e1ef4bf2SThomas Graf static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, 194e1ef4bf2SThomas Graf struct nlattr **tb) 195a5cdc030SPatrick McHardy { 196e1ef4bf2SThomas Graf struct fib4_rule *rule4 = (struct fib4_rule *) rule; 197a5cdc030SPatrick McHardy 198e1ef4bf2SThomas Graf if (frh->src_len && (rule4->src_len != frh->src_len)) 199e1ef4bf2SThomas Graf return 0; 200e1ef4bf2SThomas Graf 201e1ef4bf2SThomas Graf if (frh->dst_len && (rule4->dst_len != frh->dst_len)) 202e1ef4bf2SThomas Graf return 0; 203e1ef4bf2SThomas Graf 204e1ef4bf2SThomas Graf if (frh->tos && (rule4->tos != frh->tos)) 205e1ef4bf2SThomas Graf return 0; 206e1ef4bf2SThomas Graf 207e1ef4bf2SThomas Graf #ifdef CONFIG_NET_CLS_ROUTE 208e1ef4bf2SThomas Graf if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW]))) 209e1ef4bf2SThomas Graf return 0; 210e1ef4bf2SThomas Graf #endif 211e1ef4bf2SThomas Graf 212e1701c68SThomas Graf if (frh->src_len && (rule4->src != nla_get_be32(tb[FRA_SRC]))) 213e1ef4bf2SThomas Graf return 0; 214e1ef4bf2SThomas Graf 215e1701c68SThomas Graf if (frh->dst_len && (rule4->dst != nla_get_be32(tb[FRA_DST]))) 216e1ef4bf2SThomas Graf return 0; 217e1ef4bf2SThomas Graf 218e1ef4bf2SThomas Graf return 1; 219a5cdc030SPatrick McHardy } 220a5cdc030SPatrick McHardy 221e1ef4bf2SThomas Graf static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, 222e1ef4bf2SThomas Graf struct nlmsghdr *nlh, struct fib_rule_hdr *frh) 2231da177e4SLinus Torvalds { 224e1ef4bf2SThomas Graf struct fib4_rule *rule4 = (struct fib4_rule *) rule; 2251da177e4SLinus Torvalds 226e1ef4bf2SThomas Graf frh->family = AF_INET; 227e1ef4bf2SThomas Graf frh->dst_len = rule4->dst_len; 228e1ef4bf2SThomas Graf frh->src_len = rule4->src_len; 229e1ef4bf2SThomas Graf frh->tos = rule4->tos; 2301da177e4SLinus Torvalds 231e1ef4bf2SThomas Graf if (rule4->dst_len) 23245d60b9eSAl Viro NLA_PUT_BE32(skb, FRA_DST, rule4->dst); 233e1ef4bf2SThomas Graf 234e1ef4bf2SThomas Graf if (rule4->src_len) 23545d60b9eSAl Viro NLA_PUT_BE32(skb, FRA_SRC, rule4->src); 236e1ef4bf2SThomas Graf 237e1ef4bf2SThomas Graf #ifdef CONFIG_NET_CLS_ROUTE 238e1ef4bf2SThomas Graf if (rule4->tclassid) 239e1ef4bf2SThomas Graf NLA_PUT_U32(skb, FRA_FLOW, rule4->tclassid); 240e1ef4bf2SThomas Graf #endif 241e1ef4bf2SThomas Graf return 0; 242e1ef4bf2SThomas Graf 243e1ef4bf2SThomas Graf nla_put_failure: 244e1ef4bf2SThomas Graf return -ENOBUFS; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 247868d13acSDenis V. Lunev static u32 fib4_rule_default_pref(struct fib_rules_ops *ops) 248e1ef4bf2SThomas Graf { 249e1ef4bf2SThomas Graf struct list_head *pos; 250e1ef4bf2SThomas Graf struct fib_rule *rule; 251e1ef4bf2SThomas Graf 252e4e4971cSDenis V. Lunev if (!list_empty(&ops->rules_list)) { 253e4e4971cSDenis V. Lunev pos = ops->rules_list.next; 254e4e4971cSDenis V. Lunev if (pos->next != &ops->rules_list) { 255e1ef4bf2SThomas Graf rule = list_entry(pos->next, struct fib_rule, list); 256e1ef4bf2SThomas Graf if (rule->pref) 257e1ef4bf2SThomas Graf return rule->pref - 1; 258e1ef4bf2SThomas Graf } 259e1ef4bf2SThomas Graf } 260e1ef4bf2SThomas Graf 261e1ef4bf2SThomas Graf return 0; 262e1ef4bf2SThomas Graf } 263e1ef4bf2SThomas Graf 264339bf98fSThomas Graf static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule) 265339bf98fSThomas Graf { 266339bf98fSThomas Graf return nla_total_size(4) /* dst */ 267339bf98fSThomas Graf + nla_total_size(4) /* src */ 268339bf98fSThomas Graf + nla_total_size(4); /* flow */ 269339bf98fSThomas Graf } 270339bf98fSThomas Graf 27173417f61SThomas Graf static void fib4_rule_flush_cache(void) 27273417f61SThomas Graf { 2734b19ca44SThomas Graf rt_cache_flush(-1); 27473417f61SThomas Graf } 27573417f61SThomas Graf 276e4e4971cSDenis V. Lunev static struct fib_rules_ops fib4_rules_ops_template = { 277e1ef4bf2SThomas Graf .family = AF_INET, 278e1ef4bf2SThomas Graf .rule_size = sizeof(struct fib4_rule), 279e1701c68SThomas Graf .addr_size = sizeof(u32), 280e1ef4bf2SThomas Graf .action = fib4_rule_action, 281e1ef4bf2SThomas Graf .match = fib4_rule_match, 282e1ef4bf2SThomas Graf .configure = fib4_rule_configure, 283e1ef4bf2SThomas Graf .compare = fib4_rule_compare, 284e1ef4bf2SThomas Graf .fill = fib4_rule_fill, 285e1ef4bf2SThomas Graf .default_pref = fib4_rule_default_pref, 286339bf98fSThomas Graf .nlmsg_payload = fib4_rule_nlmsg_payload, 28773417f61SThomas Graf .flush_cache = fib4_rule_flush_cache, 288e1ef4bf2SThomas Graf .nlgroup = RTNLGRP_IPV4_RULE, 289e1ef4bf2SThomas Graf .policy = fib4_rule_policy, 290e1ef4bf2SThomas Graf .owner = THIS_MODULE, 291e1ef4bf2SThomas Graf }; 292e1ef4bf2SThomas Graf 293e4e4971cSDenis V. Lunev static int fib_default_rules_init(struct fib_rules_ops *ops) 2942994c638SDenis V. Lunev { 2952994c638SDenis V. Lunev int err; 2962994c638SDenis V. Lunev 297e4e4971cSDenis V. Lunev err = fib_default_rule_add(ops, 0, RT_TABLE_LOCAL, FIB_RULE_PERMANENT); 2982994c638SDenis V. Lunev if (err < 0) 2992994c638SDenis V. Lunev return err; 300e4e4971cSDenis V. Lunev err = fib_default_rule_add(ops, 0x7FFE, RT_TABLE_MAIN, 0); 3012994c638SDenis V. Lunev if (err < 0) 3022994c638SDenis V. Lunev return err; 303e4e4971cSDenis V. Lunev err = fib_default_rule_add(ops, 0x7FFF, RT_TABLE_DEFAULT, 0); 3042994c638SDenis V. Lunev if (err < 0) 3052994c638SDenis V. Lunev return err; 3062994c638SDenis V. Lunev return 0; 3072994c638SDenis V. Lunev } 3082994c638SDenis V. Lunev 3097b1a74fdSDenis V. Lunev int __net_init fib4_rules_init(struct net *net) 310e1ef4bf2SThomas Graf { 311dbb50165SDenis V. Lunev int err; 312e4e4971cSDenis V. Lunev struct fib_rules_ops *ops; 313dbb50165SDenis V. Lunev 314e4e4971cSDenis V. Lunev ops = kmemdup(&fib4_rules_ops_template, sizeof(*ops), GFP_KERNEL); 315e4e4971cSDenis V. Lunev if (ops == NULL) 316e4e4971cSDenis V. Lunev return -ENOMEM; 317e4e4971cSDenis V. Lunev INIT_LIST_HEAD(&ops->rules_list); 31803592383SDenis V. Lunev ops->fro_net = net; 31903592383SDenis V. Lunev 320*9e3a5487SDenis V. Lunev fib_rules_register(ops); 321e4e4971cSDenis V. Lunev 322e4e4971cSDenis V. Lunev err = fib_default_rules_init(ops); 323dbb50165SDenis V. Lunev if (err < 0) 324dbb50165SDenis V. Lunev goto fail; 325e4e4971cSDenis V. Lunev net->ipv4.rules_ops = ops; 326dbb50165SDenis V. Lunev return 0; 327dbb50165SDenis V. Lunev 328dbb50165SDenis V. Lunev fail: 329dbb50165SDenis V. Lunev /* also cleans all rules already added */ 330*9e3a5487SDenis V. Lunev fib_rules_unregister(ops); 331e4e4971cSDenis V. Lunev kfree(ops); 332dbb50165SDenis V. Lunev return err; 333e1ef4bf2SThomas Graf } 3347b1a74fdSDenis V. Lunev 3357b1a74fdSDenis V. Lunev void __net_exit fib4_rules_exit(struct net *net) 3367b1a74fdSDenis V. Lunev { 337*9e3a5487SDenis V. Lunev fib_rules_unregister(net->ipv4.rules_ops); 338e4e4971cSDenis V. Lunev kfree(net->ipv4.rules_ops); 3397b1a74fdSDenis V. Lunev } 340