linux-old/net/ipv4/fib_rules.c
<<
>>
Prefs
   1/*
   2 * INET         An implementation of the TCP/IP protocol suite for the LINUX
   3 *              operating system.  INET is implemented using the  BSD Socket
   4 *              interface as the means of communication with the user level.
   5 *
   6 *              IPv4 Forwarding Information Base: policy rules.
   7 *
   8 * Version:     $Id: fib_rules.c,v 1.9 1999/03/25 10:04:23 davem Exp $
   9 *
  10 * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  11 *
  12 *              This program is free software; you can redistribute it and/or
  13 *              modify it under the terms of the GNU General Public License
  14 *              as published by the Free Software Foundation; either version
  15 *              2 of the License, or (at your option) any later version.
  16 *
  17 * Fixes:
  18 *              Rani Assaf      :       local_rule cannot be deleted
  19 *              Marc Boucher    :       routing by fwmark
  20 */
  21
  22#include <linux/config.h>
  23#include <asm/uaccess.h>
  24#include <asm/system.h>
  25#include <asm/bitops.h>
  26#include <linux/types.h>
  27#include <linux/kernel.h>
  28#include <linux/sched.h>
  29#include <linux/mm.h>
  30#include <linux/string.h>
  31#include <linux/socket.h>
  32#include <linux/sockios.h>
  33#include <linux/errno.h>
  34#include <linux/in.h>
  35#include <linux/inet.h>
  36#include <linux/netdevice.h>
  37#include <linux/if_arp.h>
  38#include <linux/proc_fs.h>
  39#include <linux/skbuff.h>
  40#include <linux/netlink.h>
  41#include <linux/init.h>
  42
  43#include <net/ip.h>
  44#include <net/protocol.h>
  45#include <net/route.h>
  46#include <net/tcp.h>
  47#include <net/sock.h>
  48#include <net/ip_fib.h>
  49
  50#define FRprintk(a...)
  51
  52struct fib_rule
  53{
  54        struct fib_rule *r_next;
  55        u32             r_preference;
  56        unsigned char   r_table;
  57        unsigned char   r_action;
  58        unsigned char   r_dst_len;
  59        unsigned char   r_src_len;
  60        u32             r_src;
  61        u32             r_srcmask;
  62        u32             r_dst;
  63        u32             r_dstmask;
  64        u32             r_srcmap;
  65        u8              r_flags;
  66        u8              r_tos;
  67#ifdef CONFIG_IP_ROUTE_FWMARK
  68        u32             r_fwmark;
  69#endif
  70        int             r_ifindex;
  71#ifdef CONFIG_NET_CLS_ROUTE
  72        __u32           r_tclassid;
  73#endif
  74        char            r_ifname[IFNAMSIZ];
  75};
  76
  77static struct fib_rule default_rule = { NULL, 0x7FFF, RT_TABLE_DEFAULT, RTN_UNICAST, };
  78static struct fib_rule main_rule = { &default_rule, 0x7FFE, RT_TABLE_MAIN, RTN_UNICAST, };
  79static struct fib_rule local_rule = { &main_rule, 0, RT_TABLE_LOCAL, RTN_UNICAST, };
  80
  81static struct fib_rule *fib_rules = &local_rule;
  82
  83int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
  84{
  85        struct rtattr **rta = arg;
  86        struct rtmsg *rtm = NLMSG_DATA(nlh);
  87        struct fib_rule *r, **rp;
  88
  89        for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) {
  90                if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) &&
  91                    rtm->rtm_src_len == r->r_src_len &&
  92                    rtm->rtm_dst_len == r->r_dst_len &&
  93                    (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 4) == 0) &&
  94                    rtm->rtm_tos == r->r_tos &&
  95#ifdef CONFIG_IP_ROUTE_FWMARK
  96                    (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) &&
  97#endif
  98                    (!rtm->rtm_type || rtm->rtm_type == r->r_action) &&
  99                    (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
 100                    (!rta[RTA_IIF-1] || strcmp(RTA_DATA(rta[RTA_IIF-1]), r->r_ifname) == 0) &&
 101                    (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
 102                        if (r == &local_rule)
 103                                return -EPERM;
 104
 105                        *rp = r->r_next;
 106                        synchronize_bh();
 107
 108                        if (r != &default_rule && r != &main_rule)
 109                                kfree(r);
 110                        return 0;
 111                }
 112        }
 113        return -ESRCH;
 114}
 115
 116/* Allocate new unique table id */
 117
 118static struct fib_table *fib_empty_table(void)
 119{
 120        int id;
 121
 122        for (id = 1; id <= RT_TABLE_MAX; id++)
 123                if (fib_tables[id] == NULL)
 124                        return __fib_new_table(id);
 125        return NULL;
 126}
 127
 128
 129int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 130{
 131        struct rtattr **rta = arg;
 132        struct rtmsg *rtm = NLMSG_DATA(nlh);
 133        struct fib_rule *r, *new_r, **rp;
 134        unsigned char table_id;
 135
 136        if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 ||
 137            (rtm->rtm_tos & ~IPTOS_TOS_MASK))
 138                return -EINVAL;
 139
 140        if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ)
 141                return -EINVAL;
 142
 143        table_id = rtm->rtm_table;
 144        if (table_id == RT_TABLE_UNSPEC) {
 145                struct fib_table *table;
 146                if (rtm->rtm_type == RTN_UNICAST || rtm->rtm_type == RTN_NAT) {
 147                        if ((table = fib_empty_table()) == NULL)
 148                                return -ENOBUFS;
 149                        table_id = table->tb_id;
 150                }
 151        }
 152
 153        new_r = kmalloc(sizeof(*new_r), GFP_KERNEL);
 154        if (!new_r)
 155                return -ENOMEM;
 156        memset(new_r, 0, sizeof(*new_r));
 157        if (rta[RTA_SRC-1])
 158                memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4);
 159        if (rta[RTA_DST-1])
 160                memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 4);
 161        if (rta[RTA_GATEWAY-1])
 162                memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 4);
 163        new_r->r_src_len = rtm->rtm_src_len;
 164        new_r->r_dst_len = rtm->rtm_dst_len;
 165        new_r->r_srcmask = inet_make_mask(rtm->rtm_src_len);
 166        new_r->r_dstmask = inet_make_mask(rtm->rtm_dst_len);
 167        new_r->r_tos = rtm->rtm_tos;
 168#ifdef CONFIG_IP_ROUTE_FWMARK
 169        if (rta[RTA_PROTOINFO-1])
 170                memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4);
 171#endif
 172        new_r->r_action = rtm->rtm_type;
 173        new_r->r_flags = rtm->rtm_flags;
 174        if (rta[RTA_PRIORITY-1])
 175                memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
 176        new_r->r_table = table_id;
 177        if (rta[RTA_IIF-1]) {
 178                struct device *dev;
 179                memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ);
 180                new_r->r_ifname[IFNAMSIZ-1] = 0;
 181                new_r->r_ifindex = -1;
 182                dev = dev_get(new_r->r_ifname);
 183                if (dev)
 184                        new_r->r_ifindex = dev->ifindex;
 185        }
 186#ifdef CONFIG_NET_CLS_ROUTE
 187        if (rta[RTA_FLOW-1])
 188                memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
 189#endif
 190
 191        rp = &fib_rules;
 192        if (!new_r->r_preference) {
 193                r = fib_rules;
 194                if (r && (r = r->r_next) != NULL) {
 195                        rp = &fib_rules->r_next;
 196                        if (r->r_preference)
 197                                new_r->r_preference = r->r_preference - 1;
 198                }
 199        }
 200
 201        while ( (r = *rp) != NULL ) {
 202                if (r->r_preference > new_r->r_preference)
 203                        break;
 204                rp = &r->r_next;
 205        }
 206
 207        new_r->r_next = r;
 208        *rp = new_r;
 209        return 0;
 210}
 211
 212u32 fib_rules_map_destination(u32 daddr, struct fib_result *res)
 213{
 214        u32 mask = inet_make_mask(res->prefixlen);
 215        return (daddr&~mask)|res->fi->fib_nh->nh_gw;
 216}
 217
 218u32 fib_rules_policy(u32 saddr, struct fib_result *res, unsigned *flags)
 219{
 220        struct fib_rule *r = res->r;
 221
 222        if (r->r_action == RTN_NAT) {
 223                int addrtype = inet_addr_type(r->r_srcmap);
 224
 225                if (addrtype == RTN_NAT) {
 226                        /* Packet is from  translated source; remember it */
 227                        saddr = (saddr&~r->r_srcmask)|r->r_srcmap;
 228                        *flags |= RTCF_SNAT;
 229                } else if (addrtype == RTN_LOCAL || r->r_srcmap == 0) {
 230                        /* Packet is from masqueraded source; remember it */
 231                        saddr = r->r_srcmap;
 232                        *flags |= RTCF_MASQ;
 233                }
 234        }
 235        return saddr;
 236}
 237
 238#ifdef CONFIG_NET_CLS_ROUTE
 239u32 fib_rules_tclass(struct fib_result *res)
 240{
 241        if (res->r)
 242                return res->r->r_tclassid;
 243        return 0;
 244}
 245#endif
 246
 247
 248static void fib_rules_detach(struct device *dev)
 249{
 250        struct fib_rule *r;
 251
 252        for (r=fib_rules; r; r=r->r_next) {
 253                if (r->r_ifindex == dev->ifindex)
 254                        r->r_ifindex = -1;
 255        }
 256}
 257
 258static void fib_rules_attach(struct device *dev)
 259{
 260        struct fib_rule *r;
 261
 262        for (r=fib_rules; r; r=r->r_next) {
 263                if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
 264                        r->r_ifindex = dev->ifindex;
 265        }
 266}
 267
 268int fib_lookup(const struct rt_key *key, struct fib_result *res)
 269{
 270        int err;
 271        struct fib_rule *r, *policy;
 272        struct fib_table *tb;
 273
 274        u32 daddr = key->dst;
 275        u32 saddr = key->src;
 276
 277FRprintk("Lookup: %08x <- %08x ", key->dst, key->src);
 278        for (r = fib_rules; r; r=r->r_next) {
 279                if (((saddr^r->r_src) & r->r_srcmask) ||
 280                    ((daddr^r->r_dst) & r->r_dstmask) ||
 281#ifdef CONFIG_IP_ROUTE_TOS
 282                    (r->r_tos && r->r_tos != key->tos) ||
 283#endif
 284#ifdef CONFIG_IP_ROUTE_FWMARK
 285                    (r->r_fwmark && r->r_fwmark != key->fwmark) ||
 286#endif
 287                    (r->r_ifindex && r->r_ifindex != key->iif))
 288                        continue;
 289
 290FRprintk("tb %d r %d ", r->r_table, r->r_action);
 291                switch (r->r_action) {
 292                case RTN_UNICAST:
 293                case RTN_NAT:
 294                        policy = r;
 295                        break;
 296                case RTN_UNREACHABLE:
 297                        return -ENETUNREACH;
 298                default:
 299                case RTN_BLACKHOLE:
 300                        return -EINVAL;
 301                case RTN_PROHIBIT:
 302                        return -EACCES;
 303                }
 304
 305                if ((tb = fib_get_table(r->r_table)) == NULL)
 306                        continue;
 307                err = tb->tb_lookup(tb, key, res);
 308                if (err == 0) {
 309FRprintk("ok\n");
 310                        res->r = policy;
 311                        return 0;
 312                }
 313                if (err < 0 && err != -EAGAIN)
 314                        return err;
 315        }
 316FRprintk("FAILURE\n");
 317        return -ENETUNREACH;
 318}
 319
 320void fib_select_default(const struct rt_key *key, struct fib_result *res)
 321{
 322        if (res->r && res->r->r_action == RTN_UNICAST &&
 323            FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
 324                struct fib_table *tb;
 325                if ((tb = fib_get_table(res->r->r_table)) != NULL)
 326                        tb->tb_select_default(tb, key, res);
 327        }
 328}
 329
 330static int fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr)
 331{
 332        struct device *dev = ptr;
 333
 334        if (event == NETDEV_UNREGISTER)
 335                fib_rules_detach(dev);
 336        else if (event == NETDEV_REGISTER)
 337                fib_rules_attach(dev);
 338        return NOTIFY_DONE;
 339}
 340
 341
 342struct notifier_block fib_rules_notifier = {
 343        fib_rules_event,
 344        NULL,
 345        0
 346};
 347
 348#ifdef CONFIG_RTNETLINK
 349
 350extern __inline__ int inet_fill_rule(struct sk_buff *skb,
 351                                     struct fib_rule *r,
 352                                     struct netlink_callback *cb)
 353{
 354        struct rtmsg *rtm;
 355        struct nlmsghdr  *nlh;
 356        unsigned char    *b = skb->tail;
 357
 358        nlh = NLMSG_PUT(skb, NETLINK_CREDS(cb->skb)->pid, cb->nlh->nlmsg_seq, RTM_NEWRULE, sizeof(*rtm));
 359        rtm = NLMSG_DATA(nlh);
 360        rtm->rtm_family = AF_INET;
 361        rtm->rtm_dst_len = r->r_dst_len;
 362        rtm->rtm_src_len = r->r_src_len;
 363        rtm->rtm_tos = r->r_tos;
 364#ifdef CONFIG_IP_ROUTE_FWMARK
 365        if (r->r_fwmark)
 366                RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark);
 367#endif
 368        rtm->rtm_table = r->r_table;
 369        rtm->rtm_protocol = 0;
 370        rtm->rtm_scope = 0;
 371        rtm->rtm_type = r->r_action;
 372        rtm->rtm_flags = r->r_flags;
 373
 374        if (r->r_dst_len)
 375                RTA_PUT(skb, RTA_DST, 4, &r->r_dst);
 376        if (r->r_src_len)
 377                RTA_PUT(skb, RTA_SRC, 4, &r->r_src);
 378        if (r->r_ifname[0])
 379                RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname);
 380        if (r->r_preference)
 381                RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference);
 382        if (r->r_srcmap)
 383                RTA_PUT(skb, RTA_GATEWAY, 4, &r->r_srcmap);
 384#ifdef CONFIG_NET_CLS_ROUTE
 385        if (r->r_tclassid)
 386                RTA_PUT(skb, RTA_FLOW, 4, &r->r_tclassid);
 387#endif
 388        nlh->nlmsg_len = skb->tail - b;
 389        return skb->len;
 390
 391nlmsg_failure:
 392rtattr_failure:
 393        skb_put(skb, b - skb->tail);
 394        return -1;
 395}
 396
 397int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
 398{
 399        int idx;
 400        int s_idx = cb->args[0];
 401        struct fib_rule *r;
 402
 403        for (r=fib_rules, idx=0; r; r = r->r_next, idx++) {
 404                if (idx < s_idx)
 405                        continue;
 406                if (inet_fill_rule(skb, r, cb) < 0)
 407                        break;
 408        }
 409        cb->args[0] = idx;
 410
 411        return skb->len;
 412}
 413
 414#endif /* CONFIG_RTNETLINK */
 415
 416__initfunc(void fib_rules_init(void))
 417{
 418        register_netdevice_notifier(&fib_rules_notifier);
 419}
 420
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.