]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/bsd/krt-sock.c
BSD: Explicitly dropping routes with mismatched AF's.
[thirdparty/bird.git] / sysdep / bsd / krt-sock.c
CommitLineData
b1a1faba 1/*
c01a9466 2 * BIRD -- BSD Routing Table Syncing
b1a1faba
OF
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>
c01a9466 10#include <stdlib.h>
b1a1faba
OF
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 "lib/timer.h"
32#include "lib/unix.h"
33#include "lib/krt.h"
34#include "lib/string.h"
35#include "lib/socket.h"
36
396dfa90 37
c01a9466
OZ
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
396dfa90
OZ
62#endif
63
c01a9466
OZ
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
c01a9466
OZ
74
75/* Dynamic max number of tables */
76
77int krt_max_tables;
78
79#ifdef KRT_USE_SYSCTL_NET_FIBS
80
81static int
82krt_get_max_tables(void)
396dfa90 83{
c01a9466
OZ
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 return MIN(fibs, KRT_MAX_TABLES);
94}
95
96#else
97
98static int
99krt_get_max_tables(void)
100{
101 return KRT_MAX_TABLES;
102}
103
104#endif /* KRT_USE_SYSCTL_NET_FIBS */
105
106
107/* setfib() syscall for FreeBSD scans */
108
109#ifdef KRT_USE_SETFIB_SCAN
110
111/*
112static int krt_default_fib;
113
114static int
115krt_get_active_fib(void)
116{
117 int fib;
118 size_t fib_len = sizeof(fib);
119
120 if (sysctlbyname("net.my_fibnum", &fib, &fib_len, NULL, 0) < 0)
121 {
122 log(L_WARN "KRT: unable to get active fib number: %m");
123 return 0;
124 }
125
126 return fib;
127}
128*/
129
130extern int setfib(int fib);
396dfa90 131
c01a9466 132#endif /* KRT_USE_SETFIB_SCAN */
396dfa90 133
c01a9466
OZ
134
135/* table_id -> krt_proto map */
136
137#ifdef KRT_SHARED_SOCKET
8109eb76 138static struct krt_proto *krt_table_map[KRT_MAX_TABLES][2];
c01a9466 139#endif
396dfa90
OZ
140
141
c01a9466 142/* Route socket message processing */
b1a1faba 143
b1a1faba
OF
144int
145krt_capable(rte *e)
146{
147 rta *a = e->attrs;
148
b1a1faba
OF
149 return
150 a->cast == RTC_UNICAST &&
151 (a->dest == RTD_ROUTER
152 || a->dest == RTD_DEVICE
153#ifdef RTF_REJECT
154 || a->dest == RTD_UNREACHABLE
155#endif
156#ifdef RTF_BLACKHOLE
ff2857b0 157 || a->dest == RTD_BLACKHOLE
b1a1faba
OF
158#endif
159 );
160}
161
c01a9466
OZ
162#ifndef RTAX_MAX
163#define RTAX_MAX 8
164#endif
165
166struct ks_msg
167{
168 struct rt_msghdr rtm;
169 struct sockaddr_storage buf[RTAX_MAX];
170};
171
b1a1faba
OF
172#define ROUNDUP(a) \
173 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
174
175#define NEXTADDR(w, u) \
176 if (msg.rtm.rtm_addrs & (w)) {\
177 l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\
178 memmove(body, &(u), l); body += l;}
179
ff2857b0
OZ
180#define GETADDR(p, F) \
181 bzero(p, sizeof(*p));\
182 if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\
ae80a2de 183 uint l = ROUNDUP(((struct sockaddr *)body)->sa_len);\
ff2857b0
OZ
184 memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
185 body += l;}
186
32f95476 187static int
c01a9466 188krt_send_route(struct krt_proto *p, int cmd, rte *e)
b1a1faba
OF
189{
190 net *net = e->net;
191 rta *a = e->attrs;
192 static int msg_seq;
193 struct iface *j, *i = a->iface;
194 int l;
195 struct ks_msg msg;
196 char *body = (char *)msg.buf;
197 sockaddr gate, mask, dst;
44aa101c 198 ip_addr gw;
b1a1faba 199
ff2857b0 200 DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
b1a1faba 201
b88a1d40 202 bzero(&msg,sizeof (struct rt_msghdr));
b1a1faba
OF
203 msg.rtm.rtm_version = RTM_VERSION;
204 msg.rtm.rtm_type = cmd;
205 msg.rtm.rtm_seq = msg_seq++;
206 msg.rtm.rtm_addrs = RTA_DST;
ff2857b0 207 msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
b1a1faba 208
d7661fbe
MM
209 /* XXXX */
210 if (net_pxlen(net->n.addr) == net_max_prefix_length[net->n.addr->type])
b1a1faba 211 msg.rtm.rtm_flags |= RTF_HOST;
b1a1faba 212 else
b1a1faba 213 msg.rtm.rtm_addrs |= RTA_NETMASK;
c01a9466
OZ
214
215#ifdef KRT_SHARED_SOCKET
216 msg.rtm.rtm_tableid = KRT_CF->sys.table_id;
217#endif
b1a1faba
OF
218
219#ifdef RTF_REJECT
220 if(a->dest == RTD_UNREACHABLE)
221 msg.rtm.rtm_flags |= RTF_REJECT;
222#endif
223#ifdef RTF_BLACKHOLE
224 if(a->dest == RTD_BLACKHOLE)
225 msg.rtm.rtm_flags |= RTF_BLACKHOLE;
226#endif
227
228 /* This is really very nasty, but I'm not able
229 * to add "(reject|blackhole)" route without
230 * gateway set
231 */
232 if(!i)
233 {
8281ff20 234 i = HEAD(iface_list);
77772dbc 235
8281ff20
OF
236 WALK_LIST(j, iface_list)
237 {
238 if (j->flags & IF_LOOPBACK)
b1a1faba 239 {
8281ff20
OF
240 i = j;
241 break;
b1a1faba
OF
242 }
243 }
244 }
245
44aa101c
OZ
246 gw = a->gw;
247
44aa101c 248 /* Embed interface ID to link-local address */
304ac2e8 249 if (ipa_is_link_local(gw))
44aa101c 250 _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
44aa101c 251
9b136840
MM
252 int af = AF_UNSPEC;
253
254 switch (net->n.addr->type) {
255 case NET_IP4:
256 af = AF_INET;
257 break;
258 case NET_IP6:
259 af = AF_INET6;
260 break;
261 default:
262 log(L_ERR "KRT: Not sending VPN route %N to kernel", net->n.addr);
263 return -1;
264 }
265
266
267 sockaddr_fill(&dst, af, net_prefix(net->n.addr), NULL, 0);
268 sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0);
269 sockaddr_fill(&gate, af, gw, NULL, 0);
44aa101c 270
b1a1faba
OF
271 switch (a->dest)
272 {
273 case RTD_ROUTER:
274 msg.rtm.rtm_flags |= RTF_GATEWAY;
275 msg.rtm.rtm_addrs |= RTA_GATEWAY;
276 break;
029ec22d 277
b1a1faba
OF
278#ifdef RTF_REJECT
279 case RTD_UNREACHABLE:
280#endif
281#ifdef RTF_BLACKHOLE
282 case RTD_BLACKHOLE:
283#endif
284 case RTD_DEVICE:
285 if(i)
286 {
7d196668 287#ifdef RTF_CLONING
b1a1faba
OF
288 if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */
289 msg.rtm.rtm_flags |= RTF_CLONING;
7d196668 290#endif
b1a1faba
OF
291
292 if(!i->addr) {
c429d4a4 293 log(L_ERR "KRT: interface %s has no IP addess", i->name);
32f95476 294 return -1;
b1a1faba
OF
295 }
296
d7661fbe 297 sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0);
b1a1faba
OF
298 msg.rtm.rtm_addrs |= RTA_GATEWAY;
299 }
b1a1faba
OF
300 break;
301 default:
302 bug("krt-sock: unknown flags, but not filtered");
303 }
304
1554cc02 305 msg.rtm.rtm_index = i->index;
b1a1faba
OF
306
307 NEXTADDR(RTA_DST, dst);
308 NEXTADDR(RTA_GATEWAY, gate);
309 NEXTADDR(RTA_NETMASK, mask);
310
311 l = body - (char *)&msg;
312 msg.rtm.rtm_msglen = l;
313
c01a9466 314 if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
9b136840 315 log(L_ERR "KRT: Error sending route %N to kernel: %m", net->n.addr);
32f95476 316 return -1;
b1a1faba 317 }
32f95476
OZ
318
319 return 0;
b1a1faba
OF
320}
321
322void
c01a9466 323krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old,
7a2c48da 324 struct ea_list *eattrs UNUSED)
b1a1faba 325{
32f95476
OZ
326 int err = 0;
327
b1a1faba 328 if (old)
c01a9466 329 krt_send_route(p, RTM_DELETE, old);
32f95476 330
b1a1faba 331 if (new)
c01a9466 332 err = krt_send_route(p, RTM_ADD, new);
32f95476
OZ
333
334 if (err < 0)
335 n->n.flags |= KRF_SYNC_ERROR;
336 else
337 n->n.flags &= ~KRF_SYNC_ERROR;
b1a1faba
OF
338}
339
ff2857b0
OZ
340#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
341
282997f2 342static void
c01a9466 343krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
b1a1faba 344{
c01a9466
OZ
345 /* p is NULL iff KRT_SHARED_SOCKET and !scan */
346
3f358161 347 int ipv6;
b1a1faba
OF
348 rte *e;
349 net *net;
ff2857b0 350 sockaddr dst, gate, mask;
b1a1faba 351 ip_addr idst, igate, imask;
9b136840 352 net_addr ndst;
b1a1faba 353 void *body = (char *)msg->buf;
90097f4f 354 int new = (msg->rtm.rtm_type != RTM_DELETE);
ff2857b0 355 char *errmsg = "KRT: Invalid route received";
b1a1faba
OF
356 int flags = msg->rtm.rtm_flags;
357 int addrs = msg->rtm.rtm_addrs;
72aed1a0
OZ
358 int src;
359 byte src2;
b1a1faba 360
ff2857b0
OZ
361 if (!(flags & RTF_UP) && scan)
362 SKIP("not up in scan\n");
b1a1faba 363
ff2857b0
OZ
364 if (!(flags & RTF_DONE) && !scan)
365 SKIP("not done in async\n");
b1a1faba 366
ff2857b0
OZ
367 if (flags & RTF_LLINFO)
368 SKIP("link-local\n");
b1a1faba 369
ff2857b0
OZ
370 GETADDR(&dst, RTA_DST);
371 GETADDR(&gate, RTA_GATEWAY);
372 GETADDR(&mask, RTA_NETMASK);
b1a1faba 373
d7661fbe
MM
374 switch (dst.sa.sa_family) {
375 case AF_INET:
3f358161
MM
376 ipv6 = 0;
377 break;
8109eb76 378 case AF_INET6:
3f358161 379 ipv6 = 1;
8109eb76 380 break;
d7661fbe
MM
381 default:
382 SKIP("invalid DST");
383 }
b1a1faba 384
3f358161
MM
385 /* We do not test family for RTA_NETMASK, because BSD sends us
386 some strange values, but interpreting them as IPv4/IPv6 works */
387 mask.sa.sa_family = dst.sa.sa_family;
388
05476c4d 389 idst = ipa_from_sa(&dst);
8109eb76 390 imask = ipa_from_sa(&mask);
d7661fbe 391 igate = (gate.sa.sa_family == dst.sa.sa_family) ? ipa_from_sa(&gate) : IPA_NONE;
b1a1faba 392
8109eb76
MM
393#ifdef KRT_SHARED_SOCKET
394 if (!scan)
395 {
396 int table_id = msg->rtm.rtm_tableid;
3f358161 397 p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id][ipv6] : NULL;
05476c4d 398
8109eb76
MM
399 if (!p)
400 SKIP("unknown table id %d\n", table_id);
401 }
402#endif
3f358161
MM
403 if ((!ipv6) && (p->p.table->addr_type != NET_IP4))
404 SKIP("reading only IPv4 routes");
405 if ( ipv6 && (p->p.table->addr_type != NET_IP6))
406 SKIP("reading only IPv6 routes");
b1a1faba 407
ff2857b0
OZ
408 int c = ipa_classify_net(idst);
409 if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
410 SKIP("strange class/scope\n");
b1a1faba 411
8109eb76 412 int pxlen;
3f358161 413 if (ipv6)
8109eb76 414 pxlen = (flags & RTF_HOST) ? IP6_MAX_PREFIX_LENGTH : ip6_masklen(&ipa_to_ip6(imask));
3f358161
MM
415 else
416 pxlen = (flags & RTF_HOST) ? IP4_MAX_PREFIX_LENGTH : ip4_masklen(ipa_to_ip4(imask));
8109eb76 417
ff2857b0
OZ
418 if (pxlen < 0)
419 { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
b1a1faba 420
3f358161
MM
421 if (ipv6)
422 net_fill_ip6(&ndst, ipa_to_ip6(idst), pxlen);
423 else
424 net_fill_ip4(&ndst, ipa_to_ip4(idst), pxlen);
9b136840 425
ff2857b0 426 if ((flags & RTF_GATEWAY) && ipa_zero(igate))
9b136840 427 { log(L_ERR "%s (%N) - missing gateway", errmsg, ndst); return; }
ff2857b0
OZ
428
429 u32 self_mask = RTF_PROTO1;
a9f380fe 430 u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
ff2857b0 431
72aed1a0
OZ
432 src2 = (flags & RTF_STATIC) ? 1 : 0;
433 src2 |= (flags & RTF_PROTO1) ? 2 : 0;
434
ff2857b0
OZ
435#ifdef RTF_PROTO2
436 alien_mask |= RTF_PROTO2;
72aed1a0 437 src2 |= (flags & RTF_PROTO2) ? 4 : 0;
ff2857b0 438#endif
b1a1faba 439
ff2857b0
OZ
440#ifdef RTF_PROTO3
441 alien_mask |= RTF_PROTO3;
72aed1a0 442 src2 |= (flags & RTF_PROTO3) ? 8 : 0;
ff2857b0
OZ
443#endif
444
a9f380fe
OZ
445#ifdef RTF_REJECT
446 alien_mask |= RTF_REJECT;
447#endif
448
449#ifdef RTF_BLACKHOLE
450 alien_mask |= RTF_BLACKHOLE;
451#endif
452
ff2857b0
OZ
453 if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
454 src = KRT_SRC_REDIRECT;
455 else if (flags & self_mask)
456 {
457 if (!scan)
458 SKIP("echo\n");
459 src = KRT_SRC_BIRD;
460 }
461 else if (flags & alien_mask)
462 src = KRT_SRC_ALIEN;
463 else
464 src = KRT_SRC_KERNEL;
465
9b136840 466 net = net_get(p->p.table, &ndst);
b1a1faba 467
cfe34a31 468 rta a = {
094d2bdb 469 .src = p->p.main_source,
cfe34a31
OZ
470 .source = RTS_INHERIT,
471 .scope = SCOPE_UNIVERSE,
472 .cast = RTC_UNICAST
473 };
b1a1faba 474
ff2857b0
OZ
475 /* reject/blackhole routes have also set RTF_GATEWAY,
476 we wil check them first. */
b1a1faba
OF
477
478#ifdef RTF_REJECT
479 if(flags & RTF_REJECT) {
480 a.dest = RTD_UNREACHABLE;
ff2857b0 481 goto done;
b1a1faba
OF
482 }
483#endif
484
485#ifdef RTF_BLACKHOLE
486 if(flags & RTF_BLACKHOLE) {
487 a.dest = RTD_BLACKHOLE;
ff2857b0 488 goto done;
b1a1faba
OF
489 }
490#endif
491
ff2857b0
OZ
492 a.iface = if_find_by_index(msg->rtm.rtm_index);
493 if (!a.iface)
494 {
9b136840
MM
495 log(L_ERR "KRT: Received route %N with unknown ifindex %u",
496 net->n.addr, msg->rtm.rtm_index);
ff2857b0
OZ
497 return;
498 }
499
500 if (flags & RTF_GATEWAY)
b1a1faba 501 {
ff2857b0
OZ
502 neighbor *ng;
503 a.dest = RTD_ROUTER;
504 a.gw = igate;
b1a1faba 505
44aa101c 506 /* Clean up embedded interface ID returned in link-local address */
304ac2e8 507 if (ipa_is_link_local(a.gw))
44aa101c 508 _I0(a.gw) = 0xfe800000;
44aa101c 509
ff2857b0
OZ
510 ng = neigh_find2(&p->p, &a.gw, a.iface, 0);
511 if (!ng || (ng->scope == SCOPE_HOST))
512 {
de14a7c7
OZ
513 /* Ignore routes with next-hop 127.0.0.1, host routes with such
514 next-hop appear on OpenBSD for address aliases. */
515 if (ipa_classify(a.gw) == (IADDR_HOST | SCOPE_HOST))
516 return;
517
9b136840
MM
518 log(L_ERR "KRT: Received route %N with strange next-hop %I",
519 net->n.addr, a.gw);
ff2857b0
OZ
520 return;
521 }
522 }
523 else
524 a.dest = RTD_DEVICE;
b1a1faba 525
ff2857b0 526 done:
b1a1faba
OF
527 e = rte_get_temp(&a);
528 e->net = net;
529 e->u.krt.src = src;
72aed1a0 530 e->u.krt.proto = src2;
ff2857b0
OZ
531
532 /* These are probably too Linux-specific */
ff2857b0 533 e->u.krt.type = 0;
b1a1faba
OF
534 e->u.krt.metric = 0;
535
536 if (scan)
537 krt_got_route(p, e);
538 else
539 krt_got_route_async(p, e, new);
540}
541
09686693
OZ
542static void
543krt_read_ifannounce(struct ks_msg *msg)
544{
545 struct if_announcemsghdr *ifam = (struct if_announcemsghdr *)&msg->rtm;
546
547 if (ifam->ifan_what == IFAN_ARRIVAL)
548 {
549 /* Not enough info to create the iface, so we just trigger iface scan */
550 kif_request_scan();
551 }
552 else if (ifam->ifan_what == IFAN_DEPARTURE)
553 {
554 struct iface *iface = if_find_by_index(ifam->ifan_index);
555
556 /* Interface is destroyed */
557 if (!iface)
558 {
559 DBG("KRT: unknown interface (%s, #%d) going down. Ignoring\n", ifam->ifan_name, ifam->ifan_index);
560 return;
561 }
562
563 if_delete(iface);
564 }
565
566 DBG("KRT: IFANNOUNCE what: %d index %d name %s\n", ifam->ifan_what, ifam->ifan_index, ifam->ifan_name);
567}
568
282997f2 569static void
3216eb03 570krt_read_ifinfo(struct ks_msg *msg, int scan)
b1a1faba
OF
571{
572 struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm;
573 void *body = (void *)(ifm + 1);
574 struct sockaddr_dl *dl = NULL;
ae80a2de 575 uint i;
732a0a25 576 struct iface *iface = NULL, f = {};
b1a1faba 577 int fl = ifm->ifm_flags;
732a0a25 578 int nlen = 0;
b1a1faba 579
d32a071d 580 for (i = 1; i<=RTA_IFP; i <<= 1)
b1a1faba 581 {
d32a071d 582 if (i & ifm->ifm_addrs)
b1a1faba 583 {
d32a071d 584 if (i == RTA_IFP)
b1a1faba
OF
585 {
586 dl = (struct sockaddr_dl *)body;
587 break;
588 }
d32a071d 589 body += ROUNDUP(((struct sockaddr *)&(body))->sa_len);
b1a1faba
OF
590 }
591 }
592
732a0a25 593 if (dl && (dl->sdl_family != AF_LINK))
b1a1faba 594 {
09686693 595 log(L_WARN "Ignoring strange IFINFO");
b1a1faba
OF
596 return;
597 }
598
732a0a25
OZ
599 if (dl)
600 nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen);
601
602 /* Note that asynchronous IFINFO messages do not contain iface
603 name, so we have to found an existing iface by iface index */
b1a1faba 604
732a0a25
OZ
605 iface = if_find_by_index(ifm->ifm_index);
606 if (!iface)
b1a1faba
OF
607 {
608 /* New interface */
732a0a25
OZ
609 if (!dl)
610 return; /* No interface name, ignoring */
dad7ee70 611
732a0a25
OZ
612 memcpy(f.name, dl->sdl_data, nlen);
613 DBG("New interface '%s' found\n", f.name);
614 }
615 else if (dl && memcmp(iface->name, dl->sdl_data, nlen))
616 {
617 /* Interface renamed */
618 if_delete(iface);
619 memcpy(f.name, dl->sdl_data, nlen);
b1a1faba
OF
620 }
621 else
622 {
732a0a25
OZ
623 /* Old interface */
624 memcpy(f.name, iface->name, sizeof(f.name));
b1a1faba
OF
625 }
626
732a0a25 627 f.index = ifm->ifm_index;
b1a1faba 628 f.mtu = ifm->ifm_data.ifi_mtu;
b1a1faba
OF
629
630 if (fl & IFF_UP)
f25cb0ef
OZ
631 f.flags |= IF_ADMIN_UP;
632 if (ifm->ifm_data.ifi_link_state != LINK_STATE_DOWN)
633 f.flags |= IF_LINK_UP; /* up or unknown */
b1a1faba
OF
634 if (fl & IFF_LOOPBACK) /* Loopback */
635 f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
636 else if (fl & IFF_POINTOPOINT) /* PtP */
637 f.flags |= IF_MULTICAST;
638 else if (fl & IFF_BROADCAST) /* Broadcast */
639 f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
640 else
641 f.flags |= IF_MULTIACCESS; /* NBMA */
642
3216eb03
OZ
643 iface = if_update(&f);
644
645 if (!scan)
646 if_end_partial_update(iface);
b1a1faba
OF
647}
648
282997f2 649static void
3216eb03 650krt_read_addr(struct ks_msg *msg, int scan)
b1a1faba
OF
651{
652 struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm;
653 void *body = (void *)(ifam + 1);
654 sockaddr addr, mask, brd;
b1a1faba
OF
655 struct iface *iface = NULL;
656 struct ifa ifa;
657 struct sockaddr null;
658 ip_addr iaddr, imask, ibrd;
659 int addrs = ifam->ifam_addrs;
660 int scope, masklen = -1;
661 int new = (ifam->ifam_type == RTM_NEWADDR);
b1a1faba 662
ff2857b0
OZ
663 /* Strange messages with zero (invalid) ifindex appear on OpenBSD */
664 if (ifam->ifam_index == 0)
665 return;
666
b1a1faba
OF
667 if(!(iface = if_find_by_index(ifam->ifam_index)))
668 {
669 log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index);
670 return;
671 }
672
673 GETADDR (&null, RTA_DST);
674 GETADDR (&null, RTA_GATEWAY);
675 GETADDR (&mask, RTA_NETMASK);
676 GETADDR (&null, RTA_GENMASK);
677 GETADDR (&null, RTA_IFP);
678 GETADDR (&addr, RTA_IFA);
679 GETADDR (&null, RTA_AUTHOR);
680 GETADDR (&brd, RTA_BRD);
681
d7661fbe
MM
682 /* Is addr family IP4 or IP6? */
683 int ipv6;
684 switch (addr.sa.sa_family) {
685 case AF_INET: ipv6 = 0; break;
686 case AF_INET6: ipv6 = 1; break;
687 default: return;
688 }
b1a1faba 689
05476c4d
OZ
690 iaddr = ipa_from_sa(&addr);
691 imask = ipa_from_sa(&mask);
692 ibrd = ipa_from_sa(&brd);
693
8109eb76 694 if ((ipv6 ? (masklen = ip6_masklen(&ipa_to_ip6(imask))) : (masklen = ip4_masklen(ipa_to_ip4(imask)))) < 0)
b1a1faba 695 {
8109eb76 696 log(L_ERR "KIF: Invalid mask %I for %s", imask, iface->name);
b1a1faba
OF
697 return;
698 }
699
64534ea2 700 /* Clean up embedded interface ID returned in link-local address */
b1a1faba 701
304ac2e8 702 if (ipa_is_link_local(iaddr))
64534ea2 703 _I0(iaddr) = 0xfe800000;
b1a1faba 704
304ac2e8 705 if (ipa_is_link_local(ibrd))
64534ea2 706 _I0(ibrd) = 0xfe800000;
b1a1faba 707
b1a1faba 708
64534ea2
OZ
709 bzero(&ifa, sizeof(ifa));
710 ifa.iface = iface;
711 ifa.ip = iaddr;
b1a1faba
OF
712
713 scope = ipa_classify(ifa.ip);
b1a1faba
OF
714 if (scope < 0)
715 {
716 log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name);
717 return;
718 }
719 ifa.scope = scope & IADDR_SCOPE_MASK;
720
d7661fbe 721 if (masklen < (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH))
ba321706 722 {
9b136840
MM
723 net_fill_ipa(&ifa.prefix, ifa.ip, masklen);
724 net_normalize(&ifa.prefix);
ba321706 725
d7661fbe 726 if (masklen == ((ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH) - 1))
ba321706
OZ
727 ifa.opposite = ipa_opposite_m1(ifa.ip);
728
8109eb76 729 if ((!ipv6) && (masklen == IP4_MAX_PREFIX_LENGTH - 2))
ba321706 730 ifa.opposite = ipa_opposite_m2(ifa.ip);
f515e229 731
64534ea2
OZ
732 if (iface->flags & IF_BROADCAST)
733 ifa.brd = ibrd;
734
f515e229 735 if (!(iface->flags & IF_MULTIACCESS))
64534ea2 736 ifa.opposite = ibrd;
ba321706 737 }
64534ea2 738 else if (!(iface->flags & IF_MULTIACCESS) && ipa_nonzero(ibrd))
afa9f66c 739 {
d7661fbe 740 net_fill_ipa(&ifa.prefix, ibrd, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH));
9b136840 741 ifa.opposite = ibrd;
52a43ae3 742 ifa.flags |= IA_PEER;
f515e229
OZ
743 }
744 else
745 {
d7661fbe 746 net_fill_ipa(&ifa.prefix, ifa.ip, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH));
f515e229 747 ifa.flags |= IA_HOST;
afa9f66c
OZ
748 }
749
b1a1faba
OF
750 if (new)
751 ifa_update(&ifa);
752 else
753 ifa_delete(&ifa);
3216eb03
OZ
754
755 if (!scan)
756 if_end_partial_update(iface);
b1a1faba
OF
757}
758
c01a9466 759static void
b1a1faba
OF
760krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
761{
c01a9466
OZ
762 /* p is NULL iff KRT_SHARED_SOCKET and !scan */
763
b1a1faba
OF
764 switch (msg->rtm.rtm_type)
765 {
766 case RTM_GET:
767 if(!scan) return;
768 case RTM_ADD:
769 case RTM_DELETE:
90097f4f 770 case RTM_CHANGE:
c01a9466 771 krt_read_route(msg, (struct krt_proto *)p, scan);
b1a1faba 772 break;
09686693
OZ
773 case RTM_IFANNOUNCE:
774 krt_read_ifannounce(msg);
775 break;
b1a1faba 776 case RTM_IFINFO:
3216eb03 777 krt_read_ifinfo(msg, scan);
b1a1faba
OF
778 break;
779 case RTM_NEWADDR:
780 case RTM_DELADDR:
3216eb03 781 krt_read_addr(msg, scan);
b1a1faba 782 break;
b1a1faba 783 default:
b1a1faba
OF
784 break;
785 }
786}
787
c01a9466
OZ
788
789/* Sysctl based scans */
790
791static byte *krt_buffer;
792static size_t krt_buflen, krt_bufmin;
793static struct proto *krt_buffer_owner;
794
795static byte *
796krt_buffer_update(struct proto *p, size_t *needed)
797{
798 size_t req = *needed;
799
800 if ((req > krt_buflen) ||
801 ((p == krt_buffer_owner) && (req < krt_bufmin)))
802 {
803 /* min buflen is 32 kB, step is 8 kB, or 128 kB if > 1 MB */
804 size_t step = (req < 0x100000) ? 0x2000 : 0x20000;
805 krt_buflen = (req < 0x6000) ? 0x8000 : (req + step);
806 krt_bufmin = (req < 0x8000) ? 0 : (req - 2*step);
807
808 if (krt_buffer)
809 mb_free(krt_buffer);
810 krt_buffer = mb_alloc(krt_pool, krt_buflen);
811 krt_buffer_owner = p;
812 }
813
814 *needed = krt_buflen;
815 return krt_buffer;
816}
817
282997f2 818static void
c01a9466 819krt_buffer_release(struct proto *p)
b1a1faba 820{
c01a9466
OZ
821 if (p == krt_buffer_owner)
822 {
823 mb_free(krt_buffer);
824 krt_buffer = NULL;
825 krt_buflen = 0;
826 krt_buffer_owner = 0;
827 }
828}
829
282997f2 830static void
c01a9466 831krt_sysctl_scan(struct proto *p, int cmd, int table_id)
b1a1faba 832{
c01a9466
OZ
833 byte *buf, *next;
834 int mib[7], mcnt;
835 size_t needed;
b1a1faba 836 struct ks_msg *m;
4aef102b 837 int retries = 3;
c01a9466 838 int rv;
b1a1faba
OF
839
840 mib[0] = CTL_NET;
841 mib[1] = PF_ROUTE;
842 mib[2] = 0;
8109eb76 843 mib[3] = 0; // Set AF to 0 for all available families
b1a1faba
OF
844 mib[4] = cmd;
845 mib[5] = 0;
c01a9466 846 mcnt = 6;
b1a1faba 847
c01a9466
OZ
848#ifdef KRT_USE_SYSCTL_7
849 if (table_id >= 0)
850 {
851 mib[6] = table_id;
852 mcnt = 7;
853 }
854#endif
b1a1faba 855
c01a9466
OZ
856#ifdef KRT_USE_SETFIB_SCAN
857 if (table_id > 0)
858 if (setfib(table_id) < 0)
859 {
860 log(L_ERR "KRT: setfib(%d) failed: %m", table_id);
861 return;
862 }
863#endif
b1a1faba 864
c01a9466
OZ
865 try:
866 rv = sysctl(mib, mcnt, NULL, &needed, NULL, 0);
867 if (rv < 0)
b1a1faba 868 {
c01a9466
OZ
869 /* OpenBSD returns EINVAL for not yet used tables */
870 if ((errno == EINVAL) && (table_id > 0))
871 goto exit;
872
873 log(L_ERR "KRT: Route scan estimate failed: %m");
874 goto exit;
b1a1faba
OF
875 }
876
c01a9466
OZ
877 /* The table is empty */
878 if (needed == 0)
879 goto exit;
880
881 buf = krt_buffer_update(p, &needed);
882
883 rv = sysctl(mib, mcnt, buf, &needed, NULL, 0);
884 if (rv < 0)
b1a1faba 885 {
c01a9466
OZ
886 /* The buffer size changed since last sysctl ('needed' is not changed) */
887 if ((errno == ENOMEM) && retries--)
888 goto try;
4aef102b 889
c01a9466
OZ
890 log(L_ERR "KRT: Route scan failed: %m");
891 goto exit;
b1a1faba
OF
892 }
893
c01a9466
OZ
894#ifdef KRT_USE_SETFIB_SCAN
895 if (table_id > 0)
896 if (setfib(0) < 0)
897 die("KRT: setfib(%d) failed: %m", 0);
898#endif
899
900 /* Process received messages */
901 for (next = buf; next < (buf + needed); next += m->rtm.rtm_msglen)
b1a1faba
OF
902 {
903 m = (struct ks_msg *)next;
904 krt_read_msg(p, m, 1);
905 }
b1a1faba 906
c01a9466
OZ
907 return;
908
909 exit:
910 krt_buffer_release(p);
911
912#ifdef KRT_USE_SETFIB_SCAN
913 if (table_id > 0)
914 if (setfib(0) < 0)
915 die("KRT: setfib(%d) failed: %m", 0);
916#endif
917}
ff2857b0 918
b1a1faba 919void
396dfa90 920krt_do_scan(struct krt_proto *p)
b1a1faba 921{
c01a9466 922 krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id);
b1a1faba
OF
923}
924
925void
396dfa90 926kif_do_scan(struct kif_proto *p)
b1a1faba 927{
b1a1faba 928 if_start_update();
c01a9466 929 krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1);
b1a1faba
OF
930 if_end_update();
931}
932
c01a9466
OZ
933
934/* Kernel sockets */
935
396dfa90
OZ
936static int
937krt_sock_hook(sock *sk, int size UNUSED)
938{
939 struct ks_msg msg;
940 int l = read(sk->fd, (char *)&msg, sizeof(msg));
941
c01a9466 942 if (l <= 0)
396dfa90
OZ
943 log(L_ERR "krt-sock: read failed");
944 else
c01a9466 945 krt_read_msg((struct proto *) sk->data, &msg, 0);
396dfa90
OZ
946
947 return 0;
948}
b1a1faba 949
c01a9466
OZ
950static sock *
951krt_sock_open(pool *pool, void *data, int table_id)
952{
953 sock *sk;
954 int fd;
955
956 fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
957 if (fd < 0)
958 die("Cannot open kernel socket for routes");
959
960#ifdef KRT_USE_SETFIB_SOCK
961 if (table_id > 0)
962 {
963 if (setsockopt(fd, SOL_SOCKET, SO_SETFIB, &table_id, sizeof(table_id)) < 0)
964 die("Cannot set FIB %d for kernel socket: %m", table_id);
965 }
966#endif
967
968 sk = sk_new(pool);
969 sk->type = SK_MAGIC;
970 sk->rx_hook = krt_sock_hook;
971 sk->fd = fd;
972 sk->data = data;
973
974 if (sk_open(sk) < 0)
975 bug("krt-sock: sk_open failed");
976
977 return sk;
978}
979
8109eb76 980static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32][2];
c01a9466
OZ
981
982#ifdef KRT_SHARED_SOCKET
983
984static sock *krt_sock;
985static int krt_sock_count;
986
987
988static void
989krt_sock_open_shared(void)
990{
991 if (!krt_sock_count)
992 krt_sock = krt_sock_open(krt_pool, NULL, -1);
993
994 krt_sock_count++;
995}
996
997static void
998krt_sock_close_shared(void)
999{
1000 krt_sock_count--;
1001
1002 if (!krt_sock_count)
1003 {
1004 rfree(krt_sock);
1005 krt_sock = NULL;
1006 }
1007}
1008
9ddbfbdd 1009int
c01a9466 1010krt_sys_start(struct krt_proto *p)
b1a1faba 1011{
8109eb76
MM
1012 int id = KRT_CF->sys.table_id;
1013
1014 if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32)))
1015 {
1016 log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id);
1017 return 0;
1018 }
1019
1020 krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32));
1021
1022 krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = p;
396dfa90 1023
c01a9466
OZ
1024 krt_sock_open_shared();
1025 p->sys.sk = krt_sock;
9ddbfbdd
MM
1026
1027 return 1;
c01a9466 1028}
396dfa90 1029
c01a9466
OZ
1030void
1031krt_sys_shutdown(struct krt_proto *p)
1032{
8109eb76
MM
1033 krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32));
1034
c01a9466
OZ
1035 krt_sock_close_shared();
1036 p->sys.sk = NULL;
396dfa90 1037
8109eb76 1038 krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = NULL;
396dfa90 1039
c01a9466
OZ
1040 krt_buffer_release(&p->p);
1041}
396dfa90 1042
c01a9466
OZ
1043#else
1044
9ddbfbdd 1045int
c01a9466
OZ
1046krt_sys_start(struct krt_proto *p)
1047{
8109eb76
MM
1048 int id = KRT_CF->sys.table_id;
1049
1050 if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32)))
1051 {
1052 log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id);
1053 return 0;
1054 }
1055
1056 krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32));
1057
c01a9466 1058 p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id);
9ddbfbdd 1059 return 1;
b1a1faba
OF
1060}
1061
1062void
c01a9466 1063krt_sys_shutdown(struct krt_proto *p)
b1a1faba 1064{
8109eb76
MM
1065 krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32));
1066
c01a9466
OZ
1067 rfree(p->sys.sk);
1068 p->sys.sk = NULL;
a209d5d8 1069
c01a9466 1070 krt_buffer_release(&p->p);
ff2857b0 1071}
b1a1faba 1072
c01a9466
OZ
1073#endif /* KRT_SHARED_SOCKET */
1074
a209d5d8 1075
c01a9466
OZ
1076/* KRT configuration callbacks */
1077
c01a9466
OZ
1078int
1079krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1080{
1081 return n->sys.table_id == o->sys.table_id;
ff2857b0 1082}
b1a1faba
OF
1083
1084void
c01a9466 1085krt_sys_preconfig(struct config *c UNUSED)
b1a1faba 1086{
c01a9466
OZ
1087 krt_max_tables = krt_get_max_tables();
1088 bzero(&krt_table_cf, sizeof(krt_table_cf));
b1a1faba
OF
1089}
1090
c01a9466
OZ
1091void krt_sys_init_config(struct krt_config *c)
1092{
1093 c->sys.table_id = 0; /* Default table */
1094}
a209d5d8 1095
c01a9466
OZ
1096void krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1097{
1098 d->sys.table_id = s->sys.table_id;
1099}
1100
1101
1102/* KIF misc code */
1103
b1a1faba 1104void
c01a9466 1105kif_sys_start(struct kif_proto *p UNUSED)
b1a1faba 1106{
c01a9466 1107}
a209d5d8 1108
c01a9466
OZ
1109void
1110kif_sys_shutdown(struct kif_proto *p)
1111{
1112 krt_buffer_release(&p->p);
b1a1faba
OF
1113}
1114
e237b28a
OZ
1115
1116struct ifa *
1117kif_get_primary_ip(struct iface *i)
1118{
8109eb76 1119#if 0
e237b28a
OZ
1120 static int fd = -1;
1121
1122 if (fd < 0)
1123 fd = socket(AF_INET, SOCK_DGRAM, 0);
1124
1125 struct ifreq ifr;
1126 memset(&ifr, 0, sizeof(ifr));
1127 strncpy(ifr.ifr_name, i->name, IFNAMSIZ);
1128
1129 int rv = ioctl(fd, SIOCGIFADDR, (char *) &ifr);
1130 if (rv < 0)
1131 return NULL;
1132
1133 ip_addr addr;
1134 struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
1135 memcpy(&addr, &sin->sin_addr.s_addr, sizeof(ip_addr));
1136 ipa_ntoh(addr);
1137
1138 struct ifa *a;
1139 WALK_LIST(a, i->addrs)
1140 {
1141 if (ipa_equal(a->ip, addr))
1142 return a;
1143 }
1144#endif
1145
1146 return NULL;
1147}