Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / sysdep / bsd / krt-sock.c @ 6b3f1a54

History | View | Annotate | Download (25 KB)

1
/*
2
 *        BIRD -- BSD Routing Table Syncing
3
 *
4
 *        (c) 2004 Ondrej Filip <feela@network.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <ctype.h>
12
#include <fcntl.h>
13
#include <unistd.h>
14
#include <sys/param.h>
15
#include <sys/types.h>
16
#include <sys/socket.h>
17
#include <sys/sysctl.h>
18
#include <sys/ioctl.h>
19
#include <netinet/in.h>
20
#include <net/route.h>
21
#include <net/if.h>
22
#include <net/if_dl.h>
23

    
24
#undef LOCAL_DEBUG
25

    
26
#include "nest/bird.h"
27
#include "nest/iface.h"
28
#include "nest/route.h"
29
#include "nest/protocol.h"
30
#include "nest/iface.h"
31
#include "sysdep/unix/unix.h"
32
#include "sysdep/unix/krt.h"
33
#include "lib/string.h"
34
#include "lib/socket.h"
35

    
36
const int rt_default_ecmp = 0;
37

    
38
/*
39
 * There are significant differences in multiple tables support between BSD variants.
40
 *
41
 * OpenBSD has table_id field for routes in route socket protocol, therefore all
42
 * tables could be managed by one kernel socket. FreeBSD lacks such field,
43
 * therefore multiple sockets (locked to specific table using SO_SETFIB socket
44
 * option) must be used.
45
 *
46
 * Both FreeBSD and OpenBSD uses separate scans for each table. In OpenBSD,
47
 * table_id is specified explicitly as sysctl scan argument, while in FreeBSD it
48
 * is handled implicitly by changing default table using setfib() syscall.
49
 *
50
 * KRT_SHARED_SOCKET        - use shared kernel socked instead of one for each krt_proto
51
 * KRT_USE_SETFIB_SCAN        - use setfib() for sysctl() route scan
52
 * KRT_USE_SETFIB_SOCK        - use SO_SETFIB socket option for kernel sockets
53
 * KRT_USE_SYSCTL_7        - use 7-th arg of sysctl() as table id for route scans
54
 * KRT_USE_SYSCTL_NET_FIBS - use net.fibs sysctl() for dynamic max number of fibs
55
 */
56

    
57
#ifdef __FreeBSD__
58
#define KRT_MAX_TABLES 256
59
#define KRT_USE_SETFIB_SCAN
60
#define KRT_USE_SETFIB_SOCK
61
#define KRT_USE_SYSCTL_NET_FIBS
62
#endif
63

    
64
#ifdef __OpenBSD__
65
#define KRT_MAX_TABLES (RT_TABLEID_MAX+1)
66
#define KRT_SHARED_SOCKET
67
#define KRT_USE_SYSCTL_7
68
#endif
69

    
70
#ifndef KRT_MAX_TABLES
71
#define KRT_MAX_TABLES 1
72
#endif
73

    
74

    
75
/* Dynamic max number of tables */
76

    
77
uint krt_max_tables;
78

    
79
#ifdef KRT_USE_SYSCTL_NET_FIBS
80

    
81
static uint
82
krt_get_max_tables(void)
83
{
84
  int fibs;
85
  size_t fibs_len = sizeof(fibs);
86

    
87
  if (sysctlbyname("net.fibs", &fibs, &fibs_len, NULL, 0) < 0)
88
  {
89
    log(L_WARN "KRT: unable to get max number of fib tables: %m");
90
    return 1;
91
  }
92

    
93
  /* Should not happen */
94
  if (fibs < 1)
95
    return 1;
96

    
97
  return (uint) MIN(fibs, KRT_MAX_TABLES);
98
}
99

    
100
#else
101

    
102
static int
103
krt_get_max_tables(void)
104
{
105
  return KRT_MAX_TABLES;
106
}
107

    
108
#endif /* KRT_USE_SYSCTL_NET_FIBS */
109

    
110

    
111
/* setfib() syscall for FreeBSD scans */
112

    
113
#ifdef KRT_USE_SETFIB_SCAN
114

    
115
/*
116
static int krt_default_fib;
117

118
static int
119
krt_get_active_fib(void)
120
{
121
  int fib;
122
  size_t fib_len = sizeof(fib);
123

124
  if (sysctlbyname("net.my_fibnum", &fib, &fib_len, NULL, 0) < 0)
125
  {
126
    log(L_WARN "KRT: unable to get active fib number: %m");
127
    return 0;
128
  }
129

130
  return fib;
131
}
132
*/
133

    
134
extern int setfib(int fib);
135

    
136
#endif /* KRT_USE_SETFIB_SCAN */
137

    
138

    
139
/* table_id -> krt_proto map */
140

    
141
#ifdef KRT_SHARED_SOCKET
142
static struct krt_proto *krt_table_map[KRT_MAX_TABLES][2];
143
#endif
144

    
145

    
146
/* Route socket message processing */
147

    
148
int
149
krt_capable(rte *e)
150
{
151
  rta *a = e->attrs;
152

    
153
  return
154
    ((a->dest == RTD_UNICAST && !a->nh.next) /* No multipath support */
155
#ifdef RTF_REJECT
156
     || a->dest == RTD_UNREACHABLE
157
#endif
158
#ifdef RTF_BLACKHOLE
159
     || a->dest == RTD_BLACKHOLE
160
#endif
161
     );
162
}
163

    
164
#ifndef RTAX_MAX
165
#define RTAX_MAX 8
166
#endif
167

    
168
struct ks_msg
169
{
170
  struct rt_msghdr rtm;
171
  struct sockaddr_storage buf[RTAX_MAX];
172
} PACKED;
173

    
174
#define ROUNDUP(a) \
175
        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
176

    
177
#define NEXTADDR(w, u) \
178
        if (msg.rtm.rtm_addrs & (w)) {\
179
          l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\
180
          memmove(body, &(u), l); body += l;}
181

    
182
#define GETADDR(p, F) \
183
  bzero(p, sizeof(*p));\
184
  if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\
185
    uint l = ROUNDUP(((struct sockaddr *)body)->sa_len);\
186
    memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
187
    body += l;}
188

    
189
static inline void
190
sockaddr_fill_dl(struct sockaddr_dl *sa, struct iface *ifa)
191
{
192
  uint len = OFFSETOF(struct sockaddr_dl, sdl_data);
193
  memset(sa, 0, len);
194
  sa->sdl_len = len;
195
  sa->sdl_family = AF_LINK;
196
  sa->sdl_index = ifa->index;
197
}
198

    
199
static int
200
krt_send_route(struct krt_proto *p, int cmd, rte *e)
201
{
202
  net *net = e->net;
203
  rta *a = e->attrs;
204
  static int msg_seq;
205
  struct iface *j, *i = a->nh.iface;
206
  int l;
207
  struct ks_msg msg;
208
  char *body = (char *)msg.buf;
209
  sockaddr gate, mask, dst;
210

    
211
  DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
212

    
213
  bzero(&msg,sizeof (struct rt_msghdr));
214
  msg.rtm.rtm_version = RTM_VERSION;
215
  msg.rtm.rtm_type = cmd;
216
  msg.rtm.rtm_seq = msg_seq++;
217
  msg.rtm.rtm_addrs = RTA_DST;
218
  msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
219

    
220
  /* XXXX */
221
  if (net_pxlen(net->n.addr) == net_max_prefix_length[net->n.addr->type])
222
    msg.rtm.rtm_flags |= RTF_HOST;
223
  else
224
    msg.rtm.rtm_addrs |= RTA_NETMASK;
225

    
226
#ifdef KRT_SHARED_SOCKET
227
  msg.rtm.rtm_tableid = KRT_CF->sys.table_id;
228
#endif
229

    
230
#ifdef RTF_REJECT
231
  if(a->dest == RTD_UNREACHABLE)
232
    msg.rtm.rtm_flags |= RTF_REJECT;
233
#endif
234
#ifdef RTF_BLACKHOLE
235
  if(a->dest == RTD_BLACKHOLE)
236
    msg.rtm.rtm_flags |= RTF_BLACKHOLE;
237
#endif
238

    
239
  /*
240
   * This is really very nasty, but I'm not able to add reject/blackhole route
241
   * without gateway address.
242
   */
243
  if (!i)
244
  {
245
    WALK_LIST(j, iface_list)
246
    {
247
      if (j->flags & IF_LOOPBACK)
248
      {
249
        i = j;
250
        break;
251
      }
252
    }
253

    
254
    if (!i)
255
    {
256
      log(L_ERR "KRT: Cannot find loopback iface");
257
      return -1;
258
    }
259
  }
260

    
261
  int af = AF_UNSPEC;
262

    
263
  switch (net->n.addr->type) {
264
    case NET_IP4:
265
      af = AF_INET;
266
      break;
267
    case NET_IP6:
268
      af = AF_INET6;
269
      break;
270
    default:
271
      log(L_ERR "KRT: Not sending route %N to kernel", net->n.addr);
272
      return -1;
273
  }
274

    
275
  sockaddr_fill(&dst,  af, net_prefix(net->n.addr), NULL, 0);
276
  sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0);
277

    
278
  switch (a->dest)
279
  {
280
  case RTD_UNICAST:
281
    if (ipa_nonzero(a->nh.gw))
282
    {
283
      ip_addr gw = a->nh.gw;
284

    
285
      /* Embed interface ID to link-local address */
286
      if (ipa_is_link_local(gw))
287
        _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
288

    
289
      sockaddr_fill(&gate, af, gw, NULL, 0);
290
      msg.rtm.rtm_flags |= RTF_GATEWAY;
291
      msg.rtm.rtm_addrs |= RTA_GATEWAY;
292
      break;
293
    }
294

    
295
#ifdef RTF_REJECT
296
  case RTD_UNREACHABLE:
297
#endif
298
#ifdef RTF_BLACKHOLE
299
  case RTD_BLACKHOLE:
300
#endif
301
  {
302
    /* Fallback for all other valid cases */
303

    
304
#if __OpenBSD__
305
    /* Keeping temporarily old code for OpenBSD */
306
    struct ifa *addr = (net->n.addr->type == NET_IP4) ? i->addr4 : (i->addr6 ?: i->llv6);
307

    
308
    if (!addr)
309
    {
310
      log(L_ERR "KRT: interface %s has no IP addess", i->name);
311
      return -1;
312
    }
313

    
314
    /* Embed interface ID to link-local address */
315
    ip_addr gw = addr->ip;
316
    if (ipa_is_link_local(gw))
317
      _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
318

    
319
    sockaddr_fill(&gate, af, gw, i, 0);
320
#else
321
    sockaddr_fill_dl(&gate, i);
322
#endif
323

    
324
    msg.rtm.rtm_addrs |= RTA_GATEWAY;
325
    break;
326
  }
327

    
328
  default:
329
    bug("krt-sock: unknown flags, but not filtered");
330
  }
331

    
332
  msg.rtm.rtm_index = i->index;
333

    
334
  NEXTADDR(RTA_DST, dst);
335
  NEXTADDR(RTA_GATEWAY, gate);
336
  NEXTADDR(RTA_NETMASK, mask);
337

    
338
  l = body - (char *)&msg;
339
  msg.rtm.rtm_msglen = l;
340

    
341
  if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
342
    log(L_ERR "KRT: Error sending route %N to kernel: %m", net->n.addr);
343
    return -1;
344
  }
345

    
346
  return 0;
347
}
348

    
349
void
350
krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old,
351
                struct ea_list *eattrs UNUSED)
352
{
353
  int err = 0;
354

    
355
  if (old)
356
    krt_send_route(p, RTM_DELETE, old);
357

    
358
  if (new)
359
    err = krt_send_route(p, RTM_ADD, new);
360

    
361
  if (err < 0)
362
    n->n.flags |= KRF_SYNC_ERROR;
363
  else
364
    n->n.flags &= ~KRF_SYNC_ERROR;
365
}
366

    
367
#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
368

    
369
static void
370
krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
371
{
372
  /* p is NULL iff KRT_SHARED_SOCKET and !scan */
373

    
374
  int ipv6;
375
  rte *e;
376
  net *net;
377
  sockaddr dst, gate, mask;
378
  ip_addr idst, igate, imask;
379
  net_addr ndst;
380
  void *body = (char *)msg->buf;
381
  int new = (msg->rtm.rtm_type != RTM_DELETE);
382
  char *errmsg = "KRT: Invalid route received";
383
  int flags = msg->rtm.rtm_flags;
384
  int addrs = msg->rtm.rtm_addrs;
385
  int src;
386
  byte src2;
387

    
388
  if (!(flags & RTF_UP) && scan)
389
    SKIP("not up in scan\n");
390

    
391
  if (!(flags & RTF_DONE) && !scan)
392
    SKIP("not done in async\n");
393

    
394
  if (flags & RTF_LLINFO)
395
    SKIP("link-local\n");
396

    
397
  GETADDR(&dst, RTA_DST);
398
  GETADDR(&gate, RTA_GATEWAY);
399
  GETADDR(&mask, RTA_NETMASK);
400

    
401
  switch (dst.sa.sa_family) {
402
    case AF_INET:
403
      ipv6 = 0;
404
      break;
405
    case AF_INET6:
406
      ipv6 = 1;
407
      break;
408
    default:
409
      SKIP("invalid DST");
410
  }
411

    
412
  /* We do not test family for RTA_NETMASK, because BSD sends us
413
     some strange values, but interpreting them as IPv4/IPv6 works */
414
  mask.sa.sa_family = dst.sa.sa_family;
415

    
416
  idst  = ipa_from_sa(&dst);
417
  imask = ipa_from_sa(&mask);
418
  igate = (gate.sa.sa_family == dst.sa.sa_family) ? ipa_from_sa(&gate) : IPA_NONE;
419

    
420
#ifdef KRT_SHARED_SOCKET
421
  if (!scan)
422
  {
423
    int table_id = msg->rtm.rtm_tableid;
424
    p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id][ipv6] : NULL;
425

    
426
    if (!p)
427
      SKIP("unknown table id %d\n", table_id);
428
  }
429
#endif
430
  if ((!ipv6) && (p->p.main_channel->table->addr_type != NET_IP4))
431
    SKIP("reading only IPv4 routes");
432
  if (  ipv6  && (p->p.main_channel->table->addr_type != NET_IP6))
433
    SKIP("reading only IPv6 routes");
434

    
435
  int c = ipa_classify_net(idst);
436
  if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
437
    SKIP("strange class/scope\n");
438

    
439
  int pxlen;
440
  if (ipv6)
441
    pxlen = (flags & RTF_HOST) ? IP6_MAX_PREFIX_LENGTH : ip6_masklen(&ipa_to_ip6(imask));
442
  else
443
    pxlen = (flags & RTF_HOST) ? IP4_MAX_PREFIX_LENGTH : ip4_masklen(ipa_to_ip4(imask));
444

    
445
  if (pxlen < 0)
446
    { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
447

    
448
  if (ipv6)
449
    net_fill_ip6(&ndst, ipa_to_ip6(idst), pxlen);
450
  else
451
    net_fill_ip4(&ndst, ipa_to_ip4(idst), pxlen);
452

    
453
  if ((flags & RTF_GATEWAY) && ipa_zero(igate))
454
    { log(L_ERR "%s (%N) - missing gateway", errmsg, ndst); return; }
455

    
456
  u32 self_mask = RTF_PROTO1;
457
  u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
458

    
459
  src2 = (flags & RTF_STATIC) ? 1 : 0;
460
  src2 |= (flags & RTF_PROTO1) ? 2 : 0;
461

    
462
#ifdef RTF_PROTO2
463
  alien_mask |= RTF_PROTO2;
464
  src2 |= (flags & RTF_PROTO2) ? 4 : 0;
465
#endif
466

    
467
#ifdef RTF_PROTO3
468
  alien_mask |= RTF_PROTO3;
469
  src2 |= (flags & RTF_PROTO3) ? 8 : 0;
470
#endif
471

    
472
#ifdef RTF_REJECT
473
  alien_mask |= RTF_REJECT;
474
#endif
475

    
476
#ifdef RTF_BLACKHOLE
477
  alien_mask |= RTF_BLACKHOLE;
478
#endif
479

    
480
  if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
481
    src = KRT_SRC_REDIRECT;
482
  else if (flags & self_mask)
483
    {
484
      if (!scan)
485
        SKIP("echo\n");
486
      src = KRT_SRC_BIRD;
487
    }
488
  else if (flags & alien_mask)
489
    src = KRT_SRC_ALIEN;
490
  else
491
    src = KRT_SRC_KERNEL;
492

    
493
  net = net_get(p->p.main_channel->table, &ndst);
494

    
495
  rta a = {
496
    .src = p->p.main_source,
497
    .source = RTS_INHERIT,
498
    .scope = SCOPE_UNIVERSE,
499
  };
500

    
501
  /* reject/blackhole routes have also set RTF_GATEWAY,
502
     we wil check them first. */
503

    
504
#ifdef RTF_REJECT
505
  if(flags & RTF_REJECT) {
506
    a.dest = RTD_UNREACHABLE;
507
    goto done;
508
  }
509
#endif
510

    
511
#ifdef RTF_BLACKHOLE
512
  if(flags & RTF_BLACKHOLE) {
513
    a.dest = RTD_BLACKHOLE;
514
    goto done;
515
  }
516
#endif
517

    
518
  a.nh.iface = if_find_by_index(msg->rtm.rtm_index);
519
  if (!a.nh.iface)
520
    {
521
      log(L_ERR "KRT: Received route %N with unknown ifindex %u",
522
          net->n.addr, msg->rtm.rtm_index);
523
      return;
524
    }
525

    
526
  a.dest = RTD_UNICAST;
527
  if (flags & RTF_GATEWAY)
528
  {
529
    neighbor *ng;
530
    a.nh.gw = igate;
531

    
532
    /* Clean up embedded interface ID returned in link-local address */
533
    if (ipa_is_link_local(a.nh.gw))
534
      _I0(a.nh.gw) = 0xfe800000;
535

    
536
    ng = neigh_find2(&p->p, &a.nh.gw, a.nh.iface, 0);
537
    if (!ng || (ng->scope == SCOPE_HOST))
538
      {
539
        /* Ignore routes with next-hop 127.0.0.1, host routes with such
540
           next-hop appear on OpenBSD for address aliases. */
541
        if (ipa_classify(a.nh.gw) == (IADDR_HOST | SCOPE_HOST))
542
          return;
543

    
544
        log(L_ERR "KRT: Received route %N with strange next-hop %I",
545
            net->n.addr, a.nh.gw);
546
        return;
547
      }
548
  }
549

    
550
 done:
551
  e = rte_get_temp(&a);
552
  e->net = net;
553
  e->u.krt.src = src;
554
  e->u.krt.proto = src2;
555
  e->u.krt.seen = 0;
556
  e->u.krt.best = 0;
557
  e->u.krt.metric = 0;
558

    
559
  if (scan)
560
    krt_got_route(p, e);
561
  else
562
    krt_got_route_async(p, e, new);
563
}
564

    
565
static void
566
krt_read_ifannounce(struct ks_msg *msg)
567
{
568
  struct if_announcemsghdr *ifam = (struct if_announcemsghdr *)&msg->rtm;
569

    
570
  if (ifam->ifan_what == IFAN_ARRIVAL)
571
  {
572
    /* Not enough info to create the iface, so we just trigger iface scan */
573
    kif_request_scan();
574
  }
575
  else if (ifam->ifan_what == IFAN_DEPARTURE)
576
  {
577
    struct iface *iface = if_find_by_index(ifam->ifan_index);
578

    
579
    /* Interface is destroyed */
580
    if (!iface)
581
    {
582
      DBG("KRT: unknown interface (%s, #%d) going down. Ignoring\n", ifam->ifan_name, ifam->ifan_index);
583
      return;
584
    }
585

    
586
    if_delete(iface);
587
  }
588

    
589
  DBG("KRT: IFANNOUNCE what: %d index %d name %s\n", ifam->ifan_what, ifam->ifan_index, ifam->ifan_name);
590
}
591

    
592
static void
593
krt_read_ifinfo(struct ks_msg *msg, int scan)
594
{
595
  struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm;
596
  void *body = (void *)(ifm + 1);
597
  struct sockaddr_dl *dl = NULL;
598
  uint i;
599
  struct iface *iface = NULL, f = {};
600
  int fl = ifm->ifm_flags;
601
  int nlen = 0;
602

    
603
  for (i = 1; i<=RTA_IFP; i <<= 1)
604
  {
605
    if (i & ifm->ifm_addrs)
606
    {
607
      if (i == RTA_IFP)
608
      {
609
        dl = (struct sockaddr_dl *)body;
610
        break;
611
      }
612
      body += ROUNDUP(((struct sockaddr *)&(body))->sa_len);
613
    }
614
  }
615

    
616
  if (dl && (dl->sdl_family != AF_LINK))
617
  {
618
    log(L_WARN "Ignoring strange IFINFO");
619
    return;
620
  }
621

    
622
  if (dl)
623
    nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen);
624

    
625
  /* Note that asynchronous IFINFO messages do not contain iface
626
     name, so we have to found an existing iface by iface index */
627

    
628
  iface = if_find_by_index(ifm->ifm_index);
629
  if (!iface)
630
  {
631
    /* New interface */
632
    if (!dl)
633
      return;        /* No interface name, ignoring */
634

    
635
    memcpy(f.name, dl->sdl_data, nlen);
636
    DBG("New interface '%s' found\n", f.name);
637
  }
638
  else if (dl && memcmp(iface->name, dl->sdl_data, nlen))
639
  {
640
    /* Interface renamed */
641
    if_delete(iface);
642
    memcpy(f.name, dl->sdl_data, nlen);
643
  }
644
  else
645
  {
646
    /* Old interface */
647
    memcpy(f.name, iface->name, sizeof(f.name));
648
  }
649

    
650
  f.index = ifm->ifm_index;
651
  f.mtu = ifm->ifm_data.ifi_mtu;
652

    
653
  if (fl & IFF_UP)
654
    f.flags |= IF_ADMIN_UP;
655
  if (ifm->ifm_data.ifi_link_state != LINK_STATE_DOWN)
656
    f.flags |= IF_LINK_UP;          /* up or unknown */
657
  if (fl & IFF_LOOPBACK)            /* Loopback */
658
    f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
659
  else if (fl & IFF_POINTOPOINT)    /* PtP */
660
    f.flags |= IF_MULTICAST;
661
  else if (fl & IFF_BROADCAST)      /* Broadcast */
662
    f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
663
  else
664
    f.flags |= IF_MULTIACCESS;      /* NBMA */
665

    
666
  iface = if_update(&f);
667

    
668
  if (!scan)
669
    if_end_partial_update(iface);
670
}
671

    
672
static void
673
krt_read_addr(struct ks_msg *msg, int scan)
674
{
675
  struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm;
676
  void *body = (void *)(ifam + 1);
677
  sockaddr addr, mask, brd;
678
  struct iface *iface = NULL;
679
  struct ifa ifa;
680
  struct sockaddr null;
681
  ip_addr iaddr, imask, ibrd;
682
  int addrs = ifam->ifam_addrs;
683
  int scope, masklen = -1;
684
  int new = (ifam->ifam_type == RTM_NEWADDR);
685

    
686
  /* Strange messages with zero (invalid) ifindex appear on OpenBSD */
687
  if (ifam->ifam_index == 0)
688
    return;
689

    
690
  if(!(iface = if_find_by_index(ifam->ifam_index)))
691
  {
692
    log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index);
693
    return;
694
  }
695

    
696
  GETADDR (&null, RTA_DST);
697
  GETADDR (&null, RTA_GATEWAY);
698
  GETADDR (&mask, RTA_NETMASK);
699
  GETADDR (&null, RTA_GENMASK);
700
  GETADDR (&null, RTA_IFP);
701
  GETADDR (&addr, RTA_IFA);
702
  GETADDR (&null, RTA_AUTHOR);
703
  GETADDR (&brd, RTA_BRD);
704

    
705
  /* Is addr family IP4 or IP6? */
706
  int ipv6;
707
  switch (addr.sa.sa_family) {
708
    case AF_INET: ipv6 = 0; break;
709
    case AF_INET6: ipv6 = 1; break;
710
    default: return;
711
  }
712

    
713
  /* We do not test family for RTA_NETMASK, because BSD sends us
714
     some strange values, but interpreting them as IPv4/IPv6 works */
715
  mask.sa.sa_family = addr.sa.sa_family;
716

    
717
  iaddr = ipa_from_sa(&addr);
718
  imask = ipa_from_sa(&mask);
719
  ibrd  = ipa_from_sa(&brd);
720

    
721
  if ((ipv6 ? (masklen = ip6_masklen(&ipa_to_ip6(imask))) : (masklen = ip4_masklen(ipa_to_ip4(imask)))) < 0)
722
  {
723
    log(L_ERR "KIF: Invalid mask %I for %s", imask, iface->name);
724
    return;
725
  }
726

    
727
  /* Clean up embedded interface ID returned in link-local address */
728

    
729
  if (ipa_is_link_local(iaddr))
730
    _I0(iaddr) = 0xfe800000;
731

    
732
  if (ipa_is_link_local(ibrd))
733
    _I0(ibrd) = 0xfe800000;
734

    
735

    
736
  bzero(&ifa, sizeof(ifa));
737
  ifa.iface = iface;
738
  ifa.ip = iaddr;
739

    
740
  scope = ipa_classify(ifa.ip);
741
  if (scope < 0)
742
  {
743
    log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name);
744
    return;
745
  }
746
  ifa.scope = scope & IADDR_SCOPE_MASK;
747

    
748
  if (masklen < (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH))
749
  {
750
    net_fill_ipa(&ifa.prefix, ifa.ip, masklen);
751
    net_normalize(&ifa.prefix);
752

    
753
    if (masklen == ((ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH) - 1))
754
      ifa.opposite = ipa_opposite_m1(ifa.ip);
755

    
756
    if ((!ipv6) && (masklen == IP4_MAX_PREFIX_LENGTH - 2))
757
      ifa.opposite = ipa_opposite_m2(ifa.ip);
758

    
759
    if (iface->flags & IF_BROADCAST)
760
      ifa.brd = ibrd;
761

    
762
    if (!(iface->flags & IF_MULTIACCESS))
763
      ifa.opposite = ibrd;
764
  }
765
  else if (!(iface->flags & IF_MULTIACCESS) && ipa_nonzero(ibrd))
766
  {
767
    net_fill_ipa(&ifa.prefix, ibrd, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH));
768
    ifa.opposite = ibrd;
769
    ifa.flags |= IA_PEER;
770
  }
771
  else
772
  {
773
    net_fill_ipa(&ifa.prefix, ifa.ip, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH));
774
    ifa.flags |= IA_HOST;
775
  }
776

    
777
  if (new)
778
    ifa_update(&ifa);
779
  else
780
    ifa_delete(&ifa);
781

    
782
  if (!scan)
783
    if_end_partial_update(iface);
784
}
785

    
786
static void
787
krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
788
{
789
  /* p is NULL iff KRT_SHARED_SOCKET and !scan */
790

    
791
  switch (msg->rtm.rtm_type)
792
  {
793
    case RTM_GET:
794
      if(!scan) return;
795
    case RTM_ADD:
796
    case RTM_DELETE:
797
    case RTM_CHANGE:
798
      krt_read_route(msg, (struct krt_proto *)p, scan);
799
      break;
800
    case RTM_IFANNOUNCE:
801
      krt_read_ifannounce(msg);
802
      break;
803
    case RTM_IFINFO:
804
      krt_read_ifinfo(msg, scan);
805
      break;
806
    case RTM_NEWADDR:
807
    case RTM_DELADDR:
808
      krt_read_addr(msg, scan);
809
      break;
810
    default:
811
      break;
812
  }
813
}
814

    
815

    
816
/* Sysctl based scans */
817

    
818
static byte *krt_buffer;
819
static size_t krt_buflen, krt_bufmin;
820
static struct proto *krt_buffer_owner;
821

    
822
static byte *
823
krt_buffer_update(struct proto *p, size_t *needed)
824
{
825
  size_t req = *needed;
826

    
827
  if ((req > krt_buflen) ||
828
      ((p == krt_buffer_owner) && (req < krt_bufmin)))
829
  {
830
    /* min buflen is 32 kB, step is 8 kB, or 128 kB if > 1 MB */
831
    size_t step = (req < 0x100000) ? 0x2000 : 0x20000;
832
    krt_buflen = (req < 0x6000) ? 0x8000 : (req + step);
833
    krt_bufmin = (req < 0x8000) ? 0 : (req - 2*step);
834

    
835
    if (krt_buffer) 
836
      mb_free(krt_buffer);
837
    krt_buffer = mb_alloc(krt_pool, krt_buflen);
838
    krt_buffer_owner = p;
839
  }
840

    
841
  *needed = krt_buflen;
842
  return krt_buffer;
843
}
844

    
845
static void
846
krt_buffer_release(struct proto *p)
847
{
848
  if (p == krt_buffer_owner)
849
  {
850
    mb_free(krt_buffer);
851
    krt_buffer = NULL;
852
    krt_buflen = 0;
853
    krt_buffer_owner = 0;
854
  }
855
}
856

    
857
static void
858
krt_sysctl_scan(struct proto *p, int cmd, int table_id)
859
{
860
  byte *buf, *next;
861
  int mib[7], mcnt;
862
  size_t needed;
863
  struct ks_msg *m;
864
  int retries = 3;
865
  int rv;
866

    
867
  mib[0] = CTL_NET;
868
  mib[1] = PF_ROUTE;
869
  mib[2] = 0;
870
  mib[3] = 0; // Set AF to 0 for all available families
871
  mib[4] = cmd;
872
  mib[5] = 0;
873
  mcnt = 6;
874

    
875
#ifdef KRT_USE_SYSCTL_7
876
  if (table_id >= 0)
877
  {
878
    mib[6] = table_id;
879
    mcnt = 7;
880
  }
881
#endif
882

    
883
#ifdef KRT_USE_SETFIB_SCAN
884
  if (table_id > 0)
885
    if (setfib(table_id) < 0)
886
    {
887
      log(L_ERR "KRT: setfib(%d) failed: %m", table_id);
888
      return;
889
    }
890
#endif
891

    
892
 try:
893
  rv = sysctl(mib, mcnt, NULL, &needed, NULL, 0);
894
  if (rv < 0)
895
  {
896
    /* OpenBSD returns EINVAL for not yet used tables */
897
    if ((errno == EINVAL) && (table_id > 0))
898
      goto exit;
899

    
900
    log(L_ERR "KRT: Route scan estimate failed: %m");
901
    goto exit;
902
  }
903

    
904
  /* The table is empty */
905
  if (needed == 0)
906
    goto exit;
907

    
908
  buf = krt_buffer_update(p, &needed);
909

    
910
  rv = sysctl(mib, mcnt, buf, &needed, NULL, 0);
911
  if (rv < 0)
912
  {
913
    /* The buffer size changed since last sysctl ('needed' is not changed) */
914
    if ((errno == ENOMEM) && retries--)
915
      goto try;
916

    
917
    log(L_ERR "KRT: Route scan failed: %m");
918
    goto exit;
919
  }
920

    
921
#ifdef KRT_USE_SETFIB_SCAN
922
  if (table_id > 0)
923
    if (setfib(0) < 0)
924
      die("KRT: setfib(%d) failed: %m", 0);
925
#endif
926

    
927
  /* Process received messages */
928
  for (next = buf; next < (buf + needed); next += m->rtm.rtm_msglen)
929
  {
930
    m = (struct ks_msg *)next;
931
    krt_read_msg(p, m, 1);
932
  }
933

    
934
  return;
935

    
936
 exit:
937
  krt_buffer_release(p);
938

    
939
#ifdef KRT_USE_SETFIB_SCAN
940
  if (table_id > 0)
941
    if (setfib(0) < 0)
942
      die("KRT: setfib(%d) failed: %m", 0);
943
#endif
944
}
945

    
946
void
947
krt_do_scan(struct krt_proto *p)
948
{
949
  krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id);
950
}
951

    
952
void
953
kif_do_scan(struct kif_proto *p)
954
{
955
  if_start_update();
956
  krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1);
957
  if_end_update();
958
}
959

    
960

    
961
/* Kernel sockets */
962

    
963
static int
964
krt_sock_hook(sock *sk, uint size UNUSED)
965
{
966
  struct ks_msg msg;
967
  int l = read(sk->fd, (char *)&msg, sizeof(msg));
968

    
969
  if (l <= 0)
970
    log(L_ERR "krt-sock: read failed");
971
  else
972
    krt_read_msg((struct proto *) sk->data, &msg, 0);
973

    
974
  return 0;
975
}
976

    
977
static void
978
krt_sock_err_hook(sock *sk, int e UNUSED)
979
{
980
  krt_sock_hook(sk, 0);
981
}
982

    
983
static sock *
984
krt_sock_open(pool *pool, void *data, int table_id UNUSED)
985
{
986
  sock *sk;
987
  int fd;
988

    
989
  fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
990
  if (fd < 0)
991
    die("Cannot open kernel socket for routes");
992

    
993
#ifdef KRT_USE_SETFIB_SOCK
994
  if (table_id > 0)
995
  {
996
    if (setsockopt(fd, SOL_SOCKET, SO_SETFIB, &table_id, sizeof(table_id)) < 0)
997
      die("Cannot set FIB %d for kernel socket: %m", table_id);
998
  }
999
#endif
1000

    
1001
  sk = sk_new(pool);
1002
  sk->type = SK_MAGIC;
1003
  sk->rx_hook = krt_sock_hook;
1004
  sk->err_hook = krt_sock_err_hook;
1005
  sk->fd = fd;
1006
  sk->data = data;
1007

    
1008
  if (sk_open(sk) < 0)
1009
    bug("krt-sock: sk_open failed");
1010

    
1011
  return sk;
1012
}
1013

    
1014
static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32][2];
1015

    
1016
#ifdef KRT_SHARED_SOCKET
1017

    
1018
static sock *krt_sock;
1019
static int krt_sock_count;
1020

    
1021

    
1022
static void
1023
krt_sock_open_shared(void)
1024
{
1025
  if (!krt_sock_count)
1026
    krt_sock = krt_sock_open(krt_pool, NULL, -1);
1027
  
1028
  krt_sock_count++;
1029
}
1030

    
1031
static void
1032
krt_sock_close_shared(void)
1033
{
1034
  krt_sock_count--;
1035

    
1036
  if (!krt_sock_count)
1037
  {
1038
    rfree(krt_sock);
1039
    krt_sock = NULL;
1040
  }
1041
}
1042

    
1043
int
1044
krt_sys_start(struct krt_proto *p)
1045
{
1046
  int id = KRT_CF->sys.table_id;
1047

    
1048
  if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32)))
1049
    {
1050
      log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id);
1051
      return 0;
1052
    }
1053

    
1054
  krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32));
1055

    
1056
  krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = p;
1057

    
1058
  krt_sock_open_shared();
1059
  p->sys.sk = krt_sock;
1060

    
1061
  return 1;
1062
}
1063

    
1064
void
1065
krt_sys_shutdown(struct krt_proto *p)
1066
{
1067
  krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32));
1068

    
1069
  krt_sock_close_shared();
1070
  p->sys.sk = NULL;
1071

    
1072
  krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = NULL;
1073

    
1074
  krt_buffer_release(&p->p);
1075
}
1076

    
1077
#else
1078

    
1079
int
1080
krt_sys_start(struct krt_proto *p)
1081
{
1082
  int id = KRT_CF->sys.table_id;
1083

    
1084
  if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32)))
1085
    {
1086
      log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id);
1087
      return 0;
1088
    }
1089

    
1090
  krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32));
1091

    
1092
  p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id);
1093
  return 1;
1094
}
1095

    
1096
void
1097
krt_sys_shutdown(struct krt_proto *p)
1098
{
1099
  krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32));
1100

    
1101
  rfree(p->sys.sk);
1102
  p->sys.sk = NULL;
1103

    
1104
  krt_buffer_release(&p->p);
1105
}
1106

    
1107
#endif /* KRT_SHARED_SOCKET */
1108

    
1109

    
1110
/* KRT configuration callbacks */
1111

    
1112
int
1113
krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1114
{
1115
  return n->sys.table_id == o->sys.table_id;
1116
}
1117

    
1118
void
1119
krt_sys_preconfig(struct config *c UNUSED)
1120
{
1121
  krt_max_tables = krt_get_max_tables();
1122
  bzero(&krt_table_cf, sizeof(krt_table_cf));
1123
}
1124

    
1125
void krt_sys_init_config(struct krt_config *c)
1126
{
1127
  c->sys.table_id = 0; /* Default table */
1128
}
1129

    
1130
void krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1131
{
1132
  d->sys.table_id = s->sys.table_id;
1133
}
1134

    
1135

    
1136
/* KIF misc code */
1137

    
1138
void
1139
kif_sys_start(struct kif_proto *p UNUSED)
1140
{
1141
}
1142

    
1143
void
1144
kif_sys_shutdown(struct kif_proto *p)
1145
{
1146
  krt_buffer_release(&p->p);
1147
}
1148

    
1149
int
1150
kif_update_sysdep_addr(struct iface *i)
1151
{
1152
  static int fd = -1;
1153

    
1154
  if (fd < 0)
1155
    fd = socket(AF_INET, SOCK_DGRAM, 0);
1156

    
1157
  struct ifreq ifr;
1158
  memset(&ifr, 0, sizeof(ifr));
1159
  strncpy(ifr.ifr_name, i->name, IFNAMSIZ);
1160

    
1161
  int rv = ioctl(fd, SIOCGIFADDR, (char *) &ifr);
1162
  if (rv < 0)
1163
    return 0;
1164

    
1165
  ip4_addr old = i->sysdep;
1166
  i->sysdep = ipa_to_ip4(ipa_from_sa4(&ifr.ifr_addr));
1167

    
1168
  return !ip4_equal(i->sysdep, old);
1169
}