1 /* $NetBSD: mpls_routes.c,v 1.25 2022/04/07 19:33:38 andvar Exp $ */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Mihai Chelaru <kefren@NetBSD.org>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/param.h>
35 #include <sys/sysctl.h>
36 #include <net/if.h>
37 #include <net/route.h>
38 #include <netinet/in.h>
39 #include <netmpls/mpls.h>
40
41 #include <arpa/inet.h>
42
43 #include <assert.h>
44 #include <stdlib.h>
45 #include <errno.h>
46 #include <poll.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <unistd.h>
50
51 #include "ldp.h"
52 #include "ldp_errors.h"
53 #include "ldp_peer.h"
54 #include "mpls_interface.h"
55 #include "tlv_stack.h"
56 #include "label.h"
57 #include "mpls_routes.h"
58 #include "socketops.h"
59
60 extern int route_socket;
61 int rt_seq = 200;
62 int dont_catch = 0;
63 extern int no_default_route;
64 extern int debug_f, warn_f;
65 static int my_pid = 0;
66
67 struct rt_msg replay_rt[REPLAY_MAX];
68 int replay_index = 0;
69
70 #if 0
71 static int read_route_socket(char *, int);
72 #endif
73 void mask_addr(union sockunion *);
74 int compare_sockunion(const union sockunion *, const union sockunion *);
75 static int check_if_addr_updown(struct rt_msg *, uint);
76
77 extern struct sockaddr mplssockaddr;
78
79 /* Many lines inspired or shamelessly stolen from sbin/route/route.c */
80
81 #define NEXTADDR(u) \
82 do { l = RT_ROUNDUP(u->sa.sa_len); memcpy(cp, u, l); cp += l;} while(0);
83 #define NEXTADDR2(u) \
84 do { l = RT_ROUNDUP(u.sa_len); memcpy(cp, &u, l); cp += l; } while(0);
85
86 #define CHECK_LEN(sunion) \
87 if (size_cp + sunion->sa.sa_len > rlen) \
88 return LDP_E_ROUTE_ERROR; \
89 else \
90 size_cp += sunion->sa.sa_len;
91
92 #define CHECK_MINSA \
93 if (size_cp + sizeof(sa_family_t) + sizeof(uint8_t) > rlen) \
94 return LDP_E_ROUTE_ERROR;
95
96 #define GETNEXT(dstunion, origunion) \
97 do { \
98 CHECK_MINSA \
99 dstunion = (union sockunion *) ((char *) (origunion) + \
100 RT_ROUNDUP((origunion)->sa.sa_len)); \
101 CHECK_LEN(dstunion) \
102 } while (0);
103
104 #if 0
105 static int
106 read_route_socket(char *s, int max)
107 {
108 int rv, to_read;
109 struct rt_msghdr *rhdr;
110 struct pollfd pfd;
111
112 pfd.fd = route_socket;
113 pfd.events = POLLRDNORM;
114 pfd.revents = 0;
115
116 errno = 0;
117
118 do {
119 rv = poll(&pfd, 1, 100);
120 } while (rv == -1 && errno == EINTR);
121
122 if (rv < 1) {
123 if (rv == 0) {
124 fatalp("read_route_socket: poll timeout\n");
125 } else
126 fatalp("read_route_socket: poll: %s",
127 strerror(errno));
128 return 0;
129 }
130
131 do {
132 rv = recv(route_socket, s, max, MSG_PEEK);
133 } while(rv == -1 && errno == EINTR);
134
135 if (rv < 1) {
136 debugp("read_route_socket: recv error\n");
137 return 0;
138 }
139 if (rv > max) {
140 rv = max;
141 debugp("read_route_socket: rv > max\n");
142 }
143
144 rhdr = (struct rt_msghdr *)s;
145 to_read = rhdr->rtm_msglen > max ? max : rhdr->rtm_msglen;
146 rv = 0;
147
148 do {
149 rv += recv(route_socket, s, to_read - rv, 0);
150 } while (rv != to_read);
151
152 return rv;
153 }
154 #endif /* 0 */
155
156 /* Recalculate length */
157 void
mask_addr(union sockunion * su)158 mask_addr(union sockunion * su)
159 {
160 /*
161 int olen = su->sa.sa_len;
162 char *cp1 = olen + (char *) su;
163
164 for (su->sa.sa_len = 0; cp1 > (char *) su;)
165 if (*--cp1 != 0) {
166 su->sa.sa_len = 1 + cp1 - (char *) su;
167 break;
168 }
169 */
170 /* Let's use INET only version for the moment */
171 su->sa.sa_len = 4 + from_union_to_cidr(su) / 8 +
172 ( from_union_to_cidr(su) % 8 ? 1 : 0 );
173 }
174
175 /* creates a sockunion from an IP address */
176 union sockunion *
make_inet_union(const char * s)177 make_inet_union(const char *s)
178 {
179 union sockunion *so_inet;
180
181 so_inet = calloc(1, sizeof(*so_inet));
182
183 if (!so_inet) {
184 fatalp("make_inet_union: malloc problem\n");
185 return NULL;
186 }
187
188 so_inet->sin.sin_len = sizeof(struct sockaddr_in);
189 so_inet->sin.sin_family = AF_INET;
190 inet_aton(s, &so_inet->sin.sin_addr);
191
192 return so_inet;
193 }
194
195 /* creates a sockunion from a label */
196 union sockunion *
make_mpls_union(uint32_t label)197 make_mpls_union(uint32_t label)
198 {
199 union sockunion *so_mpls;
200
201 so_mpls = calloc(1, sizeof(*so_mpls));
202
203 if (!so_mpls) {
204 fatalp("make_mpls_union: malloc problem\n");
205 return NULL;
206 }
207
208 so_mpls->smpls.smpls_len = sizeof(struct sockaddr_mpls);
209 so_mpls->smpls.smpls_family = AF_MPLS;
210 so_mpls->smpls.smpls_addr.shim.label = label;
211
212 so_mpls->smpls.smpls_addr.s_addr =
213 htonl(so_mpls->smpls.smpls_addr.s_addr);
214
215 return so_mpls;
216 }
217
218 int
compare_sockunion(const union sockunion * __restrict a,const union sockunion * __restrict b)219 compare_sockunion(const union sockunion * __restrict a,
220 const union sockunion * __restrict b)
221 {
222 if (a->sa.sa_len != b->sa.sa_len)
223 return 1;
224 return memcmp(a, b, a->sa.sa_len);
225 }
226
227 union sockunion *
from_cidr_to_union(uint8_t prefixlen)228 from_cidr_to_union(uint8_t prefixlen)
229 {
230 union sockunion *u;
231 uint32_t m = 0xFFFFFFFF;
232
233 u = calloc(1, sizeof(*u));
234
235 if (!u) {
236 fatalp("from_cidr_to_union: malloc problem\n");
237 return NULL;
238 }
239 u->sin.sin_len = sizeof(struct sockaddr_in);
240 u->sin.sin_family = AF_INET;
241 if (prefixlen != 0) {
242 m = (m >> (32 - prefixlen) ) << (32 - prefixlen);
243 m = ntohl(m);
244 u->sin.sin_addr.s_addr = m;
245 }
246 return u;
247 }
248
249 uint8_t
from_mask_to_cidr(const char * mask)250 from_mask_to_cidr(const char *mask)
251 {
252 struct in_addr addr;
253 uint8_t plen = 0;
254
255 if (inet_aton(mask, &addr) != 0)
256 for (; addr.s_addr; plen++)
257 addr.s_addr &= addr.s_addr - 1;
258 return plen;
259 }
260
261 uint8_t
from_union_to_cidr(const union sockunion * so_pref)262 from_union_to_cidr(const union sockunion *so_pref)
263 {
264 const struct sockaddr_in *sin = (const struct sockaddr_in*) so_pref;
265 uint32_t a;
266 uint8_t r;
267
268 a = ntohl(sin->sin_addr.s_addr);
269 for (r=0; a ; a = a << 1, r++);
270
271 return r;
272 }
273
274 /* returns in mask the netmask created from CIDR prefixlen */
275 void
from_cidr_to_mask(uint8_t prefixlen,char * mask)276 from_cidr_to_mask(uint8_t prefixlen, char *mask)
277 {
278 uint32_t a = 0;
279 uint8_t plen = prefixlen < 32 ? prefixlen : 32;
280
281 if (plen != 0)
282 a = (0xffffffff >> (32 - plen)) << (32 - plen);
283 snprintf(mask, 16, "%d.%d.%d.%d", a >> 24, (a << 8) >> 24,
284 (a << 16) >> 24, (a << 24) >> 24);
285 }
286
287 /* From src/sbin/route/route.c */
288 static const char *
route_strerror(int error)289 route_strerror(int error)
290 {
291
292 switch (error) {
293 case ESRCH:
294 return "not in table";
295 case EBUSY:
296 return "entry in use";
297 case ENOBUFS:
298 return "routing table overflow";
299 default:
300 return strerror(error);
301 }
302 }
303
304
305 /* Adds a route. Or changes it. */
306 int
add_route(union sockunion * so_dest,union sockunion * so_prefix,union sockunion * so_gate,union sockunion * so_ifa,union sockunion * so_tag,int fr,int optype)307 add_route(union sockunion *so_dest, union sockunion *so_prefix,
308 union sockunion *so_gate, union sockunion *so_ifa,
309 union sockunion *so_tag, int fr, int optype)
310 {
311 int l, rlen, rv = LDP_E_OK;
312 struct rt_msg rm;
313 char *cp;
314
315 if(dont_catch)
316 return LDP_E_OK;
317
318 memset(&rm, 0, sizeof(rm));
319 cp = rm.m_space;
320
321 rm.m_rtm.rtm_type = (optype == RTM_READD) ? RTM_ADD : optype;
322 rm.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
323
324 rm.m_rtm.rtm_version = RTM_VERSION;
325 rm.m_rtm.rtm_seq = ++rt_seq;
326 rm.m_rtm.rtm_addrs = RTA_DST;
327 if (so_gate)
328 rm.m_rtm.rtm_addrs |= RTA_GATEWAY;
329
330 assert(so_dest);
331
332 /* Order is: destination, gateway, netmask, genmask, ifp, ifa, tag */
333 NEXTADDR(so_dest);
334 if (so_gate)
335 NEXTADDR(so_gate);
336
337 if (so_prefix) {
338 union sockunion *so_prefix_temp = so_prefix;
339
340 if (fr != FREESO) {
341 /* don't modify so_prefix */
342 so_prefix_temp = calloc(1, so_prefix->sa.sa_len);
343 if (so_prefix_temp == NULL)
344 return LDP_E_MEMORY;
345 memcpy(so_prefix_temp, so_prefix, so_prefix->sa.sa_len);
346 }
347 mask_addr(so_prefix_temp);
348 NEXTADDR(so_prefix_temp);
349 if (fr != FREESO)
350 free(so_prefix_temp);
351 /* XXX: looks like nobody cares about this */
352 rm.m_rtm.rtm_flags |= RTF_MASK;
353 rm.m_rtm.rtm_addrs |= RTA_NETMASK;
354 } else
355 rm.m_rtm.rtm_flags |= RTF_HOST;
356
357 /* route to mpls interface */
358 if (optype != RTM_READD && so_dest->sa.sa_family != AF_MPLS) {
359 NEXTADDR2(mplssockaddr);
360 rm.m_rtm.rtm_addrs |= RTA_IFP;
361 }
362
363 if (so_ifa != NULL) {
364 NEXTADDR(so_ifa);
365 rm.m_rtm.rtm_addrs |= RTA_IFA;
366 }
367
368 if (so_tag) {
369 NEXTADDR(so_tag);
370 rm.m_rtm.rtm_addrs |= RTA_TAG;
371 }
372
373 rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
374
375 if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
376 warnp("Error adding a route: %s\n", route_strerror(errno));
377 warnp("Destination was: %s\n", satos(&so_dest->sa));
378 if (so_prefix)
379 warnp("Prefix was: %s\n", satos(&so_prefix->sa));
380 if (so_gate)
381 warnp("Gateway was: %s\n", satos(&so_gate->sa));
382 rv = LDP_E_ROUTE_ERROR;
383 }
384 if (fr == FREESO) {
385 free(so_dest);
386 if (so_prefix)
387 free(so_prefix);
388 if (so_gate)
389 free(so_gate);
390 if (so_ifa)
391 free(so_ifa);
392 if (so_tag)
393 free(so_tag);
394 }
395
396 return rv;
397 }
398
399 /* Deletes a route */
400 int
delete_route(union sockunion * so_dest,union sockunion * so_pref,int freeso)401 delete_route(union sockunion * so_dest, union sockunion * so_pref, int freeso)
402 {
403 int l, rlen;
404 struct rt_msg rm;
405 char *cp;
406
407 if(dont_catch)
408 return LDP_E_OK;
409
410 memset(&rm, 0, sizeof(struct rt_msg));
411 cp = rm.m_space;
412
413 rm.m_rtm.rtm_type = RTM_DELETE;
414 rm.m_rtm.rtm_version = RTM_VERSION;
415 rm.m_rtm.rtm_seq = ++rt_seq;
416 if (so_pref)
417 rm.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
418 else {
419 rm.m_rtm.rtm_addrs = RTA_DST;
420 rm.m_rtm.rtm_flags |= RTF_HOST;
421 }
422
423 /* destination, gateway, netmask, genmask, ifp, ifa */
424
425 NEXTADDR(so_dest);
426
427 if (so_pref) {
428 union sockunion *so_pref_temp = so_pref;
429 if (freeso != FREESO) {
430 /* don't modify the original prefix */
431 so_pref_temp = calloc(1, so_pref->sa.sa_len);
432 if (so_pref_temp == NULL)
433 return LDP_E_MEMORY;
434 memcpy(so_pref_temp, so_pref, so_pref->sa.sa_len);
435 }
436 mask_addr(so_pref_temp);
437 NEXTADDR(so_pref_temp);
438 if (freeso != FREESO)
439 free(so_pref_temp);
440 }
441 rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
442
443 if (freeso == FREESO) {
444 free(so_dest);
445 if (so_pref)
446 free(so_pref);
447 }
448 if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
449 if(so_pref) {
450 char spreftmp[INET_ADDRSTRLEN];
451 strlcpy(spreftmp, inet_ntoa(so_pref->sin.sin_addr),
452 INET_ADDRSTRLEN);
453 warnp("Error deleting route(%s): %s/%s",
454 route_strerror(errno), satos(&so_dest->sa),
455 spreftmp);
456 } else
457 warnp("Error deleting route(%s) : %s",
458 route_strerror(errno), satos(&so_dest->sa));
459 return LDP_E_NO_SUCH_ROUTE;
460 }
461 return LDP_E_OK;
462 }
463
464 #if 0
465 /*
466 * Check for a route and returns it in rg
467 * If exact_match is set it compares also the so_dest and so_pref
468 * with the returned result
469 */
470 int
471 get_route(struct rt_msg * rg, const union sockunion * so_dest,
472 const union sockunion * so_pref, int exact_match)
473 {
474 int l, rlen, myseq;
475 struct rt_msg rm;
476 char *cp;
477 union sockunion *su;
478
479 memset(&rm, 0, sizeof(struct rt_msg));
480 cp = rm.m_space;
481
482 myseq = ++rt_seq;
483
484 rm.m_rtm.rtm_type = RTM_GET;
485 rm.m_rtm.rtm_version = RTM_VERSION;
486 rm.m_rtm.rtm_seq = myseq;
487
488 /*
489 * rtm_addrs should contain what we provide into this message but
490 * RTA_DST | RTA_IFP trick is allowed in order to find out the
491 * interface.
492 */
493
494 rm.m_rtm.rtm_addrs = RTA_DST | RTA_IFP;
495
496 /*
497 * ORDER of fields is: destination, gateway, netmask, genmask, ifp,
498 * ifa
499 */
500
501 NEXTADDR(so_dest);
502 if (so_pref) {
503 union sockunion *so_pref_temp = calloc(1, so_pref->sa.sa_len);
504
505 if (so_pref_temp == NULL)
506 return LDP_E_MEMORY;
507 rm.m_rtm.rtm_addrs |= RTA_NETMASK;
508 memcpy(so_pref_temp, so_pref, so_pref->sa.sa_len);
509 mask_addr(so_pref_temp);
510 NEXTADDR(so_pref_temp);
511 free(so_pref_temp);
512 }
513 rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
514
515 setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){1},
516 sizeof(int));
517 rlen = write(route_socket, (char *) &rm, l);
518 setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){0},
519 sizeof(int));
520
521 if (rlen < l) {
522 debugp("Cannot get a route !(rlen=%d instead of %d) - %s\n",
523 rlen, l, strerror(errno));
524 return LDP_E_NO_SUCH_ROUTE;
525 } else
526 for ( ; ; ) {
527 rlen = read_route_socket((char *) rg,
528 sizeof(struct rt_msg));
529 if (rlen < 1)
530 break;
531 /*
532 * We might lose important messages here. WORKAROUND:
533 * For now I just try to save this messages and replay
534 * them later
535 */
536 if (rg->m_rtm.rtm_pid == getpid() &&
537 rg->m_rtm.rtm_seq == myseq)
538 break;
539 /* Fast skip */
540 if (rg->m_rtm.rtm_type != RTM_ADD &&
541 rg->m_rtm.rtm_type != RTM_DELETE &&
542 rg->m_rtm.rtm_type != RTM_CHANGE &&
543 rg->m_rtm.rtm_type != RTM_NEWADDR &&
544 rg->m_rtm.rtm_type != RTM_DELADDR)
545 continue;
546 warnp("Added to replay PID: %d, SEQ: %d\n",
547 rg->m_rtm.rtm_pid, rg->m_rtm.rtm_seq);
548 memcpy(&replay_rt[replay_index], rg,
549 sizeof(struct rt_msg));
550 if (replay_index < REPLAY_MAX - 1)
551 replay_index++;
552 else
553 fatalp("Replay index is full\n");
554 }
555
556 if (rlen <= (int)sizeof(struct rt_msghdr)) {
557 debugp("Got only %d bytes, expecting at least %zu\n", rlen,
558 sizeof(struct rt_msghdr));
559 return LDP_E_ROUTE_ERROR;
560 }
561
562 /* Check if we don't have a less specific route */
563 if (exact_match) {
564 su = (union sockunion*)(rg->m_space);
565 if (compare_sockunion(so_dest, su)) {
566 debugp("Dest %s ", satos(&so_dest->sa));
567 debugp("not like %s\n", satos(&su->sa));
568 return LDP_E_NO_SUCH_ROUTE;
569 }
570 }
571
572 return LDP_E_OK;
573 }
574
575 #endif /* 0 */
576
577 /* triggered when a route event occurs */
578 int
check_route(struct rt_msg * rg,uint rlen)579 check_route(struct rt_msg * rg, uint rlen)
580 {
581 union sockunion *so_dest = NULL, *so_gate = NULL, *so_pref = NULL;
582 int so_pref_allocated = 0;
583 int prefixlen;
584 size_t size_cp;
585 struct peer_map *pm;
586 struct label *lab;
587 char dest[50], gate[50], pref[50], oper[50];
588 dest[0] = 0;
589 gate[0] = 0;
590 pref[0] = 0;
591
592 if (rlen <= offsetof(struct rt_msghdr, rtm_type) ||
593 rg->m_rtm.rtm_version != RTM_VERSION)
594 return LDP_E_ROUTE_ERROR;
595
596 if (rg->m_rtm.rtm_type == RTM_NEWADDR ||
597 rg->m_rtm.rtm_type == RTM_DELADDR)
598 return check_if_addr_updown(rg, rlen);
599
600 size_cp = sizeof(struct rt_msghdr);
601 CHECK_MINSA;
602
603 if (my_pid == 0)
604 my_pid = getpid();
605 assert(my_pid != 0);
606
607 if (rg->m_rtm.rtm_pid == my_pid ||
608 (rg->m_rtm.rtm_pid != 0 && (rg->m_rtm.rtm_flags & RTF_DONE) == 0) ||
609 (rg->m_rtm.rtm_type != RTM_ADD &&
610 rg->m_rtm.rtm_type != RTM_DELETE &&
611 rg->m_rtm.rtm_type != RTM_CHANGE))
612 return LDP_E_OK;
613
614 debugp("Check route triggered by PID: %d\n", rg->m_rtm.rtm_pid);
615
616 if (rg->m_rtm.rtm_addrs & RTA_DST)
617 so_dest = (union sockunion *) rg->m_space;
618 else
619 return LDP_E_ROUTE_ERROR;
620
621 if (so_dest->sa.sa_family != AF_INET)
622 return LDP_E_OK;/* We don't care about non-IP changes */
623
624 CHECK_LEN(so_dest);
625
626 if (rg->m_rtm.rtm_addrs & RTA_GATEWAY) {
627 GETNEXT(so_gate, so_dest);
628 if ((rg->m_rtm.rtm_flags & RTF_CONNECTED) == 0 &&
629 so_gate->sa.sa_family != AF_INET &&
630 so_gate->sa.sa_family != AF_MPLS)
631 return LDP_E_OK;
632 }
633 if (rg->m_rtm.rtm_addrs & RTA_NETMASK) {
634 if (so_gate != NULL) {
635 GETNEXT(so_pref, so_gate);
636 } else
637 GETNEXT(so_pref, so_dest);
638 }
639 /* Calculate prefixlen */
640 if (so_pref)
641 prefixlen = from_union_to_cidr(so_pref);
642 else {
643 prefixlen = 32;
644 if ((so_pref = from_cidr_to_union(32)) == NULL)
645 return LDP_E_MEMORY;
646 so_pref_allocated = 1;
647 }
648
649 so_pref->sa.sa_family = AF_INET;
650 so_pref->sa.sa_len = sizeof(struct sockaddr_in);
651 so_pref->sin.sin_port = 0;
652 memset(&so_pref->sin.sin_zero, 0, sizeof(so_pref->sin.sin_zero));
653
654 if (rg->m_rtm.rtm_flags & RTF_CONNECTED)
655 so_gate = NULL;
656
657 switch (rg->m_rtm.rtm_type) {
658 case RTM_CHANGE:
659 lab = label_get(so_dest, so_pref);
660 if (lab) {
661 send_withdraw_tlv_to_all(&so_dest->sa,
662 prefixlen);
663 label_reattach_route(lab, REATT_INET_DEL);
664 label_del(lab);
665 }
666 /* Fallthrough */
667 case RTM_ADD:
668 /*
669 * Check if the route is connected. If so, bind it to
670 * POP_LABEL and send announce. If not, check if the prefix
671 * was announced by a LDP neighbour and route it there
672 */
673
674 /* First of all check if we already know this one */
675 if (label_get(so_dest, so_pref) == NULL) {
676 /* Just add an IMPLNULL label */
677 if (so_gate == NULL)
678 label_add(so_dest, so_pref, NULL,
679 MPLS_LABEL_IMPLNULL, NULL, 0,
680 rg->m_rtm.rtm_flags & RTF_HOST);
681 else {
682 pm = ldp_test_mapping(&so_dest->sa,
683 prefixlen, &so_gate->sa);
684 if (pm) {
685 /* create an implnull label as it
686 * gets rewritten in mpls_add_label */
687 lab = label_add(so_dest, so_pref,
688 so_gate, MPLS_LABEL_IMPLNULL,
689 pm->peer, pm->lm->label,
690 rg->m_rtm.rtm_flags & RTF_HOST);
691 if (lab != NULL)
692 mpls_add_label(lab);
693 free(pm);
694 } else
695 label_add(so_dest, so_pref, so_gate,
696 MPLS_LABEL_IMPLNULL, NULL, 0,
697 rg->m_rtm.rtm_flags & RTF_HOST);
698 }
699 } else /* We already know about this prefix */
700 fatalp("Binding already there for prefix %s/%d !\n",
701 satos(&so_dest->sa), prefixlen);
702 break;
703 case RTM_DELETE:
704 /*
705 * Send withdraw check the binding, delete the route, delete
706 * the binding
707 */
708 lab = label_get(so_dest, so_pref);
709 if (!lab)
710 break;
711 send_withdraw_tlv_to_all(&so_dest->sa, prefixlen);
712 /* No readd or delete IP route. Just delete the MPLS route */
713 label_reattach_route(lab, REATT_INET_NODEL);
714 label_del(lab);
715 break;
716 }
717
718 if (!debug_f && !warn_f) {
719 if(so_pref_allocated)
720 free(so_pref);
721 return LDP_E_OK;
722 }
723
724 /* Rest is just for debug */
725
726 if (so_dest)
727 strlcpy(dest, satos(&so_dest->sa), sizeof(dest));
728 if (so_pref)
729 snprintf(pref, sizeof(pref), "%d", prefixlen);
730 if (so_gate)
731 strlcpy(gate, satos(&so_gate->sa), sizeof(gate));
732
733 switch (rg->m_rtm.rtm_type) {
734 case RTM_ADD:
735 strlcpy(oper, "added", 20);
736 break;
737 case RTM_DELETE:
738 strlcpy(oper, "delete", 20);
739 break;
740 case RTM_GET:
741 strlcpy(oper, "get", 20);
742 break;
743 case RTM_CHANGE:
744 strlcpy(oper, "change", 20);
745 break;
746 case RTM_LOSING:
747 strlcpy(oper, "losing", 20);
748 break;
749 case RTM_REDIRECT:
750 strlcpy(oper, "redirect", 20);
751 break;
752 case RTM_NEWADDR:
753 strlcpy(oper, "new address", 20);
754 break;
755 case RTM_DELADDR:
756 strlcpy(oper, "del address", 20);
757 break;
758 default:
759 snprintf(oper, sizeof(oper), "unknown 0x%X operation",
760 rg->m_rtm.rtm_type);
761 }
762
763 debugp("[check_route] Route %s: %s / %s -> %s by PID:%d\n", oper, dest,
764 pref, gate, rg->m_rtm.rtm_pid);
765
766 if(so_pref_allocated)
767 free(so_pref);
768 return LDP_E_OK;
769 }
770
771 /*
772 * Checks NEWADDR and DELADDR messages and sends announcements accordingly
773 */
774 static int
check_if_addr_updown(struct rt_msg * rg,uint rlen)775 check_if_addr_updown(struct rt_msg * rg, uint rlen)
776 {
777 union sockunion *ifa, *netmask;
778 struct ldp_peer *p;
779 struct address_list_tlv al_tlv;
780 struct ifa_msghdr *msghdr = (struct ifa_msghdr *)&rg->m_rtm;
781 size_t size_cp = sizeof(struct ifa_msghdr);
782
783 if (rlen < sizeof(struct ifa_msghdr) ||
784 (msghdr->ifam_addrs & RTA_NETMASK) == 0 ||
785 (msghdr->ifam_addrs & RTA_IFA) == 0)
786 return LDP_E_ROUTE_ERROR;
787
788 CHECK_MINSA;
789
790 /* we should have RTA_NETMASK, RTA_IFP, RTA_IFA and RTA_BRD */
791 ifa = netmask = (union sockunion *)(msghdr + 1);
792 if (netmask->sa.sa_family != AF_INET)
793 return LDP_E_OK;
794 CHECK_LEN(netmask);
795
796 if (msghdr->ifam_addrs & RTA_IFP)
797 GETNEXT(ifa, ifa);
798
799 GETNEXT(ifa, ifa);
800
801 if (ifa->sa.sa_family != AF_INET ||
802 ntohl(ifa->sin.sin_addr.s_addr) >> 24 == IN_LOOPBACKNET)
803 return LDP_E_OK;
804
805 memset(&al_tlv, 0, sizeof(al_tlv));
806 al_tlv.type = rg->m_rtm.rtm_type == RTM_NEWADDR ? htons(LDP_ADDRESS) :
807 htons(LDP_ADDRESS_WITHDRAW);
808 al_tlv.length = htons(sizeof(al_tlv) - TLV_TYPE_LENGTH);
809 al_tlv.messageid = htonl(get_message_id());
810 al_tlv.a_type = htons(TLV_ADDRESS_LIST);
811 al_tlv.a_length = htons(sizeof(al_tlv.a_af) + sizeof(al_tlv.a_address));
812 al_tlv.a_af = htons(LDP_AF_INET);
813 memcpy(&al_tlv.a_address, &ifa->sin.sin_addr, sizeof(al_tlv.a_address));
814
815 SLIST_FOREACH(p, &ldp_peer_head, peers)
816 if (p->state == LDP_PEER_ESTABLISHED)
817 send_tlv(p, (struct tlv *)&al_tlv);
818
819 return LDP_E_OK;
820 }
821
822 int
bind_current_routes()823 bind_current_routes()
824 {
825 size_t needed, size_cp;
826 int mib[6];
827 char *buf, *next, *lim;
828 struct rt_msghdr *rtmes;
829 union sockunion *so_dst, *so_pref, *so_gate;
830 uint rlen;
831
832 mib[0] = CTL_NET;
833 mib[1] = PF_ROUTE;
834 mib[2] = 0;
835 mib[3] = 0;
836 mib[4] = NET_RT_DUMP;
837 mib[5] = 0;
838 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
839 fatalp("route-sysctl-estimate: %s",
840 strerror(errno));
841 return LDP_E_ROUTE_ERROR;
842 }
843 if ((buf = malloc(needed)) == 0)
844 return LDP_E_ROUTE_ERROR;
845 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
846 free(buf);
847 return LDP_E_ROUTE_ERROR;
848 }
849 lim = buf + needed;
850
851 for (next = buf; next < lim; next += rlen) {
852 rtmes = (struct rt_msghdr *) next;
853 rlen = rtmes->rtm_msglen;
854 size_cp = sizeof(struct rt_msghdr);
855 so_gate = so_pref = NULL;
856 if (!(rtmes->rtm_addrs & RTA_DST)) {
857 debugp("No dst\n");
858 continue;
859 }
860
861 CHECK_MINSA;
862 so_dst = (union sockunion *) & rtmes[1];
863 CHECK_LEN(so_dst);
864
865 /*
866 * This function is called only at startup, so use
867 * this occasion to delete all MPLS routes
868 */
869 if (so_dst->sa.sa_family == AF_MPLS) {
870 delete_route(so_dst, NULL, NO_FREESO);
871 debugp("MPLS route deleted.\n");
872 continue;
873 }
874
875 if (so_dst->sa.sa_family != AF_INET) {
876 /*debugp("sa_dst is not AF_INET\n");*/
877 continue;
878 }
879
880 /* Check if it's the default gateway */
881 if (so_dst->sin.sin_addr.s_addr == 0 && no_default_route != 0)
882 continue;
883
884 /* Check if it's loopback */
885 if ((ntohl(so_dst->sin.sin_addr.s_addr) >> 24)==IN_LOOPBACKNET)
886 continue;
887
888 /* Get Gateway */
889 if (rtmes->rtm_addrs & RTA_GATEWAY)
890 GETNEXT(so_gate, so_dst);
891
892 /* Get prefix */
893 if (rtmes->rtm_flags & RTF_HOST) {
894 if ((so_pref = from_cidr_to_union(32)) == NULL)
895 return LDP_E_MEMORY;
896 } else if (rtmes->rtm_addrs & RTA_GATEWAY) {
897 GETNEXT(so_pref, so_gate);
898 } else
899 GETNEXT(so_pref, so_dst);
900
901 so_pref->sa.sa_family = AF_INET;
902 so_pref->sa.sa_len = sizeof(struct sockaddr_in);
903 so_pref->sin.sin_port = 0;
904 memset(&so_pref->sin.sin_zero, 0, 8);
905
906 /* Also deletes when dest is IPv4 and gateway MPLS */
907 if ((rtmes->rtm_addrs & RTA_GATEWAY) &&
908 (so_gate->sa.sa_family == AF_MPLS)) {
909 debugp("MPLS route to %s deleted.\n",
910 inet_ntoa(so_dst->sin.sin_addr));
911 delete_route(so_dst,
912 rtmes->rtm_flags & RTF_HOST ? NULL : so_pref,
913 NO_FREESO);
914 if (rtmes->rtm_flags & RTF_HOST)
915 free(so_pref);
916 continue;
917 }
918
919 if (so_gate != NULL && so_gate->sa.sa_family == AF_LINK)
920 so_gate = NULL; /* connected route */
921
922 if (so_gate == NULL || so_gate->sa.sa_family == AF_INET)
923 label_add(so_dst, so_pref, so_gate,
924 MPLS_LABEL_IMPLNULL, NULL, 0,
925 rtmes->rtm_flags & RTF_HOST);
926
927 if (rtmes->rtm_flags & RTF_HOST)
928 free(so_pref);
929 }
930 free(buf);
931 return LDP_E_OK;
932 }
933
934 int
flush_mpls_routes()935 flush_mpls_routes()
936 {
937 size_t needed, size_cp;
938 int mib[6];
939 uint rlen;
940 char *buf, *next, *lim;
941 struct rt_msghdr *rtm;
942 union sockunion *so_dst, *so_pref, *so_gate;
943
944 mib[0] = CTL_NET;
945 mib[1] = PF_ROUTE;
946 mib[2] = 0;
947 mib[3] = 0;
948 mib[4] = NET_RT_DUMP;
949 mib[5] = 0;
950 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
951 fatalp("route-sysctl-estimate: %s", strerror(errno));
952 return LDP_E_ROUTE_ERROR;
953 }
954 if ((buf = malloc(needed)) == NULL) {
955 fatalp("route-sysctl-estimate: %s", strerror(errno));
956 return LDP_E_MEMORY;
957 }
958 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
959 free(buf);
960 return LDP_E_ROUTE_ERROR;
961 }
962 lim = buf + needed;
963
964 for (next = buf; next < lim; next += rlen) {
965 rtm = (struct rt_msghdr *) next;
966 size_cp = sizeof(struct rt_msghdr);
967 rlen = rtm->rtm_msglen;
968 so_pref = NULL;
969 so_gate = NULL;
970 if (!(rtm->rtm_addrs & RTA_DST)) {
971 debugp("No dst\n");
972 continue;
973 }
974 so_dst = (union sockunion *) & rtm[1];
975
976 if (so_dst->sa.sa_family == AF_MPLS) {
977 delete_route(so_dst, NULL, NO_FREESO);
978 debugp("MPLS route deleted.\n");
979 continue;
980 }
981
982 if ((rtm->rtm_addrs & RTA_GATEWAY) == 0)
983 continue;
984 GETNEXT(so_gate, so_dst);
985
986 if ((rtm->rtm_flags & RTF_HOST) == 0)
987 GETNEXT(so_pref, so_gate);
988
989 if (so_gate->sa.sa_family == AF_MPLS) {
990 if (so_dst->sa.sa_family == AF_INET)
991 debugp("MPLS route to %s deleted.\n",
992 inet_ntoa(so_dst->sin.sin_addr));
993 delete_route(so_dst, so_pref, NO_FREESO);
994 continue;
995 }
996
997 }
998 free(buf);
999 return LDP_E_OK;
1000 }
1001