]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/bsd/krt-sock.c
Updated the distribution script.
[thirdparty/bird.git] / sysdep / bsd / krt-sock.c
CommitLineData
b1a1faba
OF
1/*
2 * BIRD -- Unix 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 <ctype.h>
11#include <fcntl.h>
12#include <unistd.h>
13#include <sys/param.h>
14#include <sys/types.h>
15#include <sys/socket.h>
16#include <sys/sysctl.h>
17#include <sys/ioctl.h>
18#include <netinet/in.h>
19#include <net/route.h>
20#include <net/if.h>
21#include <net/if_dl.h>
22
23#undef LOCAL_DEBUG
24
25#include "nest/bird.h"
26#include "nest/iface.h"
27#include "nest/route.h"
28#include "nest/protocol.h"
29#include "nest/iface.h"
30#include "lib/timer.h"
31#include "lib/unix.h"
32#include "lib/krt.h"
33#include "lib/string.h"
34#include "lib/socket.h"
35
36#ifdef IPV6
37#define HOST_MASK 128
38#else
39#define HOST_MASK 32
40#endif
41
42int rt_sock = 0;
43
44#define CHECK_FAMILY(sa) \
45 ((((struct sockaddr *)sa)->sa_family) == BIRD_AF)
46
47struct iface *
48krt_temp_iface_index(struct krt_proto *p, unsigned index)
49{
50 struct iface *i, *j;
51
52 WALK_LIST(i, p->scan.temp_ifs)
53 if (i->index == index)
54 return i;
55 i = mb_allocz(p->p.pool, sizeof(struct iface));
56 if (j = if_find_by_index(index))
57 {
58 strcpy(i->name, j->name);
59 i->addr = j->addr;
60 }
61 else
62 strcpy(i->name, "?");
63 i->index = index;
64 add_tail(&p->scan.temp_ifs, &i->n);
65 return i;
66}
67
68
69int
70krt_capable(rte *e)
71{
72 rta *a = e->attrs;
73
74#ifdef CONFIG_AUTO_ROUTES
75 if (a->source == RTS_DEVICE)
76 return 0;
77#endif
78 return
79 a->cast == RTC_UNICAST &&
80 (a->dest == RTD_ROUTER
81 || a->dest == RTD_DEVICE
82#ifdef RTF_REJECT
83 || a->dest == RTD_UNREACHABLE
84#endif
85#ifdef RTF_BLACKHOLE
86 || a->dest == RTD_BLACKHOLE /* FIXME Prohibited? */
87#endif
88 );
89}
90
91#define ROUNDUP(a) \
92 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
93
94#define NEXTADDR(w, u) \
95 if (msg.rtm.rtm_addrs & (w)) {\
96 l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\
97 memmove(body, &(u), l); body += l;}
98
99static void
100krt_sock_send(int cmd, rte *e, char *name)
101{
102 net *net = e->net;
103 rta *a = e->attrs;
104 static int msg_seq;
105 struct iface *j, *i = a->iface;
106 int l;
107 struct ks_msg msg;
108 char *body = (char *)msg.buf;
109 sockaddr gate, mask, dst;
110
111 log("KRT sock send: %I/%d via %I", net->n.prefix, net->n.pxlen, a->gw);
112
113 fill_in_sockaddr(&dst, net->n.prefix, 0);
114 fill_in_sockaddr(&mask, ipa_mkmask(net->n.pxlen), 0);
115 fill_in_sockaddr(&gate, a->gw, 0);
116
117 memset (&msg, 0, sizeof (struct rt_msghdr));
118 msg.rtm.rtm_version = RTM_VERSION;
119 msg.rtm.rtm_type = cmd;
120 msg.rtm.rtm_seq = msg_seq++;
121 msg.rtm.rtm_addrs = RTA_DST;
122 msg.rtm.rtm_flags = RTF_UP;
123
124 if (net->n.pxlen == HOST_MASK)
125 {
126 msg.rtm.rtm_flags |= RTF_HOST;
127 }
128 else
129 {
130 msg.rtm.rtm_addrs |= RTA_NETMASK;
131 }
132
133#ifdef RTF_REJECT
134 if(a->dest == RTD_UNREACHABLE)
135 msg.rtm.rtm_flags |= RTF_REJECT;
136#endif
137#ifdef RTF_BLACKHOLE
138 if(a->dest == RTD_BLACKHOLE)
139 msg.rtm.rtm_flags |= RTF_BLACKHOLE;
140#endif
141
142 /* This is really very nasty, but I'm not able
143 * to add "(reject|blackhole)" route without
144 * gateway set
145 */
146 if(!i)
147 {
148 i = HEAD(iface_list);
149
150 WALK_LIST(j, iface_list)
151 {
152 if (j->flags & IF_LOOPBACK)
153 {
154 i = j;
155 break;
156 }
157 }
158 }
159
160 switch (a->dest)
161 {
162 case RTD_ROUTER:
163 msg.rtm.rtm_flags |= RTF_GATEWAY;
164 msg.rtm.rtm_addrs |= RTA_GATEWAY;
165 break;
166#ifdef RTF_REJECT
167 case RTD_UNREACHABLE:
168#endif
169#ifdef RTF_BLACKHOLE
170 case RTD_BLACKHOLE:
171#endif
172 case RTD_DEVICE:
173 if(i)
174 {
175 if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */
176 msg.rtm.rtm_flags |= RTF_CLONING;
177
178 if(!i->addr) {
179 log(L_ERR "KIF: interface \"%s\" has no IP addess", i->name);
180 return;
181 }
182
183 fill_in_sockaddr(&gate, i->addr->ip, 0);
184 msg.rtm.rtm_addrs |= RTA_GATEWAY;
185 }
186 else
187 {
188 bug("krt-sock: interface route %I/%d without interface", net->n.prefix, net->n.pxlen);
189 }
190 break;
191 default:
192 bug("krt-sock: unknown flags, but not filtered");
193 }
194
195 if(i) msg.rtm.rtm_index = i->index;
196
197 NEXTADDR(RTA_DST, dst);
198 NEXTADDR(RTA_GATEWAY, gate);
199 NEXTADDR(RTA_NETMASK, mask);
200
201 l = body - (char *)&msg;
202 msg.rtm.rtm_msglen = l;
203
204 if ((l = write(rt_sock, (char *)&msg, l)) < 0) {
205 log(L_ERR "KIF: error writting route to socket (%I/%d)", net->n.prefix, net->n.pxlen);
206 }
207}
208
209void
210krt_set_notify(struct krt_proto *p, net *net, rte *new, rte *old)
211{
212 if (old)
213 {
214 DBG("krt_remove_route(%I/%d)\n", net->n.prefix, net->n.pxlen);
215 krt_sock_send(RTM_DELETE, old, "RTM_DELETE");
216
217 }
218 if (new)
219 {
220 DBG("krt_add_route(%I/%d)\n", net->n.prefix, net->n.pxlen);
221 krt_sock_send(RTM_ADD, new, "RTM_ADD");
222 }
223}
224
225void
226krt_set_start(struct krt_proto *x, int first)
227{
228 sock *sk_rt;
229 static int ks_open_tried = 0;
230
231 if (ks_open_tried)
232 return;
233
234 ks_open_tried = 1;
235
236 DBG("KRT: Opening kernel socket\n");
237
238 if( (rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0)
239 die("Cannot open kernel socket for routes");
240
241 sk_rt = sk_new(krt_pool);
242 sk_rt->type = SK_MAGIC;
243 sk_rt->rx_hook = krt_set_hook;
244 sk_rt->fd = rt_sock;
245 sk_rt->data = x;
246 if (sk_open(sk_rt))
247 bug("Krt_sock: sk_rt_open failed");
248}
249
250static int
251krt_set_hook(sock *sk, int size)
252{
253 int l;
254 struct ks_msg msg;
255
256 l = read(sk->fd, (char *)&msg, sizeof(msg));
257
258 krt_read_msg((struct proto *)sk->data, &msg, 0);
259 return 0;
260}
261
262void
263krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan)
264{
265 sockaddr gate, mask, dst;
266 rta a;
267 rte *e;
268 net *net;
269 u32 oif;
270 ip_addr idst, igate, imask;
271 void *body = (char *)msg->buf;
272 int new = (msg->rtm.rtm_type == RTM_ADD);
273 int src;
274 int flags = msg->rtm.rtm_flags;
275 int addrs = msg->rtm.rtm_addrs;
276 int masklen = -1;
277
278 if (!(flags & RTF_UP))
279 {
280 DBG("Down.\n");
281 return;
282 }
283
284 if (flags & RTF_HOST)
285 masklen = HOST_MASK;
286
287 if(!CHECK_FAMILY(body)) return;
288
289 if(msg->rtm.rtm_flags & RTF_LLINFO) return; /* ARPs etc. */
290
291#define GETADDR(p, F) \
292 memset(p, 0, sizeof(*p));\
293 if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\
294 unsigned int l = ROUNDUP(((struct sockaddr *)body)->sa_len);\
295 memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
296 body += l;}
297
298 GETADDR (&dst, RTA_DST);
299 GETADDR (&gate, RTA_GATEWAY);
300 GETADDR (&mask, RTA_NETMASK);
301
302 idst = IPA_NONE;
303 igate = IPA_NONE;
304 imask = IPA_NONE;
305
306 get_sockaddr(&dst, &idst, NULL, 0);
307 if(CHECK_FAMILY(&gate)) get_sockaddr(&gate, &igate, NULL, 0);
308 get_sockaddr(&mask, &imask, NULL, 0);
309
310 if (masklen < 0) masklen = ipa_mklen(imask);
311
312 if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
313 {
314 log(L_WARN "krt: Ignoring redirect to %I/%d via %I", idst, masklen, igate);
315 return;
316 }
317
318 if (masklen < 0)
319 {
320 log(L_WARN "krt: Got invalid route from kernel!");
321 return;
322 }
323
324 net = net_get(p->p.table, idst, masklen);
325
326 memset(&a, 0, sizeof(a));
327
328 a.proto = &p->p;
329 a.source = RTS_INHERIT;
330 a.scope = SCOPE_UNIVERSE;
331 a.cast = RTC_UNICAST;
332 a.flags = a.aflags = 0;
333 a.from = IPA_NONE;
334 a.gw = IPA_NONE;
335 a.iface = NULL;
336 a.eattrs = NULL;
337
338 a.dest = RTD_NONE;
339
340
341 if (flags & RTF_GATEWAY)
342 {
343 neighbor *ng = neigh_find(&p->p, &igate, 0);
344 if (ng && ng->scope)
345 a.iface = ng->iface;
346 else
347 log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", igate, net->n.prefix, net->n.pxlen);
348
349 a.dest = RTD_ROUTER;
350 a.gw = igate;
351 }
352 else
353 {
354 a.dest = RTD_DEVICE;
355 a.gw = IPA_NONE;
356 a.iface = krt_temp_iface_index(p, msg->rtm.rtm_index);
357 }
358
359#ifdef RTF_REJECT
360 if(flags & RTF_REJECT) {
361 a.dest = RTD_UNREACHABLE;
362 a.gw = IPA_NONE;
363 }
364#endif
365
366#ifdef RTF_BLACKHOLE
367 if(flags & RTF_BLACKHOLE) {
368 a.dest = RTD_BLACKHOLE;
369 a.gw = IPA_NONE;
370 }
371#endif
372
373 if (a.dest == RTD_NONE)
374 {
375 log(L_WARN "Kernel reporting unknown route type to %I/%d", net->n.prefix, net->n.pxlen);
376 return;
377 }
378
379 src = KRT_SRC_UNKNOWN; /* FIXME */
380
381
382
383 e = rte_get_temp(&a);
384 e->net = net;
385 e->u.krt.src = src;
386 //e->u.krt.proto = i->rtm_protocol;
387 //e->u.krt.type = i->rtm_type;
388 e->u.krt.metric = 0;
389
390 if (scan)
391 krt_got_route(p, e);
392 else
393 krt_got_route_async(p, e, new);
394}
395
396void
397krt_read_ifinfo(struct ks_msg *msg)
398{
399 struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm;
400 void *body = (void *)(ifm + 1);
401 struct sockaddr_dl *dl = NULL;
402 unsigned int i;
403 struct iface *iface = NULL, f;
404 char *ifname = "(none)";
405 int fl = ifm->ifm_flags;
406
407 for(i = 1; i!=0; i <<= 1)
408 {
409 if((i & ifm->ifm_addrs) && (i == RTA_IFP))
410 {
411 if( i == RTA_IFP)
412 {
413 dl = (struct sockaddr_dl *)body;
414 break;
415 }
416 body += ROUNDUP(((struct sockaddr *)&(body))->sa_len);\
417 }
418 }
419
420 if(dl && (dl->sdl_family != AF_LINK))
421 {
422 log("Ignoring strange IFINFO");
423 return;
424 }
425
426 if(dl) ifname = dl->sdl_data;
427
428 iface = if_find_by_index(ifm->ifm_index);
429
430 if(!iface)
431 {
432 /* New interface */
433 if(!dl) return; /* No interface name, ignoring */
434 DBG("New interface \"%s\" found", ifname);
435 bzero(&f, sizeof(f));
436 f.index = ifm->ifm_index;
437 strncpy(f.name, ifname, sizeof(f.name) -1);
438 }
439 else
440 {
441 memcpy(&f, iface, sizeof(struct iface));
442 }
443
444 f.mtu = ifm->ifm_data.ifi_mtu;
445 f.flags = 0;
446
447 if (fl & IFF_UP)
448 {
449 //f.flags |= IF_UP; /* FIXME */
450 f.flags |= IF_LINK_UP;
451 }
452 if (fl & IFF_LOOPBACK) /* Loopback */
453 f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
454 else if (fl & IFF_POINTOPOINT) /* PtP */
455 f.flags |= IF_MULTICAST;
456 else if (fl & IFF_BROADCAST) /* Broadcast */
457 f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
458 else
459 f.flags |= IF_MULTIACCESS; /* NBMA */
460
461 if((!iface) || memcmp(&f, iface, sizeof(struct iface)))
462 if_update(&f); /* Just if something happens */
463}
464
465void
466krt_read_addr(struct ks_msg *msg)
467{
468 struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm;
469 void *body = (void *)(ifam + 1);
470 sockaddr addr, mask, brd;
471 unsigned int i;
472 struct iface *iface = NULL;
473 struct ifa ifa;
474 struct sockaddr null;
475 ip_addr iaddr, imask, ibrd;
476 int addrs = ifam->ifam_addrs;
477 int scope, masklen = -1;
478 int new = (ifam->ifam_type == RTM_NEWADDR);
479 int fl = ifam->ifam_flags;
480
481 if(!(iface = if_find_by_index(ifam->ifam_index)))
482 {
483 log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index);
484 return;
485 }
486
487 GETADDR (&null, RTA_DST);
488 GETADDR (&null, RTA_GATEWAY);
489 GETADDR (&mask, RTA_NETMASK);
490 GETADDR (&null, RTA_GENMASK);
491 GETADDR (&null, RTA_IFP);
492 GETADDR (&addr, RTA_IFA);
493 GETADDR (&null, RTA_AUTHOR);
494 GETADDR (&brd, RTA_BRD);
495
496 if(!CHECK_FAMILY(&addr)) return; /* Some other family address */
497
498 get_sockaddr(&addr, &iaddr, NULL, 0);
499 get_sockaddr(&mask, &imask, NULL, 0);
500 get_sockaddr(&brd, &ibrd, NULL, 0);
501
502 if ((masklen = ipa_mklen(imask)) < 0)
503 {
504 log("Invalid masklen");
505 return;
506 }
507
508 memset(&ifa, 0, sizeof(ifa));
509
510 ifa.iface = iface;
511
512 memcpy(&ifa.ip, &iaddr, sizeof(ip_addr));
513 ifa.pxlen = masklen;
514 memcpy(&ifa.brd, &ibrd, sizeof(ip_addr));
515
516 scope = ipa_classify(ifa.ip);
517
518 ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen));
519
520 if (scope < 0)
521 {
522 log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name);
523 return;
524 }
525 ifa.scope = scope & IADDR_SCOPE_MASK;
526
527 if (new)
528 ifa_update(&ifa);
529 else
530 ifa_delete(&ifa);
531}
532
533
534void
535krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
536{
537 switch (msg->rtm.rtm_type)
538 {
539 case RTM_GET:
540 if(!scan) return;
541 case RTM_ADD:
542 case RTM_DELETE:
543 //log("KRT_ADD/DELETE");
544 krt_read_rt(msg, (struct krt_proto *)p, scan);
545 break;
546 case RTM_IFINFO:
547 //log("KRT_IFINFO");
548 krt_read_ifinfo(msg);
549 break;
550 case RTM_NEWADDR:
551 case RTM_DELADDR:
552 //log("KRT_NEWADDR/DELADDR");
553 krt_read_addr(msg);
554 break;
555#ifdef RTM_IFANNOUNCE
556 case RTM_IFANNOUNCE:
557 log("KRT_IFANNOUNCE");
558 //ifan_read (&buf.ian.ifan);
559 break;
560#endif /* RTM_IFANNOUNCE */
561 default:
562 log("Unprocessed RTM_type: %d", msg->rtm.rtm_type);
563 break;
564 }
565}
566
567
568struct iface *
569krt_temp_iface(struct krt_proto *p, char *name)
570{
571 struct iface *i;
572
573 WALK_LIST(i, p->scan.temp_ifs)
574 if (!strcmp(i->name, name))
575 return i;
576 i = mb_allocz(p->p.pool, sizeof(struct iface));
577 strcpy(i->name, name);
578 add_tail(&p->scan.temp_ifs, &i->n);
579 return i;
580}
581
582
583void
584krt_scan_construct(struct krt_config *c)
585{
586}
587
588void
589krt_scan_preconfig(struct config *c)
590{
591}
592
593void
594krt_scan_postconfig(struct krt_config *c)
595{
596}
597
598void
599krt_scan_start(struct krt_proto *x, int first)
600{
601 init_list(&x->scan.temp_ifs);
602}
603
604void
605krt_scan_shutdown(struct krt_proto *x, int last)
606{
607}
608
609void
610krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, int *bl, int cmd)
611{
612 byte *next;
613 int obl, needed, mib[6], on;
614 struct ks_msg *m;
615
616 mib[0] = CTL_NET;
617 mib[1] = PF_ROUTE;
618 mib[2] = 0;
619 mib[3] = BIRD_PF;
620 mib[4] = cmd;
621 mib[5] = 0;
622
623 if( sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0)
624 {
625 die("RT scan...");
626 }
627
628 obl = *bl;
629
630 while(needed > *bl) *bl *= 2;
631 while(needed < (*bl/2)) *bl /= 2;
632
633 if( (obl!=*bl) || !*buf)
634 {
635 if(*buf) mb_free(*buf);
636 if( (*buf = mb_alloc(pool, *bl)) == NULL ) die("RT scan buf alloc");
637 }
638
639 on = needed;
640
641 if( sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0)
642 {
643 if(on != needed) return; /* The buffer size changed since last sysctl */
644 die("RT scan 2");
645 }
646
647 for (next = *buf; next < (*buf + needed); next += m->rtm.rtm_msglen)
648 {
649 m = (struct ks_msg *)next;
650 krt_read_msg(p, m, 1);
651 }
652}
653
654void
655krt_scan_fire(struct krt_proto *p)
656{
657 static byte *buf = NULL;
658 static int bl = 32768;
659 krt_sysctl_scan((struct proto *)p , p->krt_pool, &buf, &bl, NET_RT_DUMP);
660}
661
662void
663krt_if_scan(struct kif_proto *p)
664{
665 static byte *buf = NULL;
666 static int bl = 4096;
667 struct proto *P = (struct proto *)p;
668 if_start_update();
669 krt_sysctl_scan(P, P->pool, &buf, &bl, NET_RT_IFLIST);
670 if_end_update();
671}
672
673
674void
675krt_set_construct(struct krt_config *c)
676{
677}
678
679void
680krt_set_shutdown(struct krt_proto *x, int last)
681{
682}
683
684void
685krt_if_io_init(void)
686{
687}
688
689void
690krt_if_construct(struct kif_config *c)
691{
692}
693
694void
695krt_if_start(struct kif_proto *p)
696{
697}
698
699void
700krt_if_shutdown(struct kif_proto *p)
701{
702}
703