xref: /netbsd/usr.sbin/ldpd/mpls_routes.c (revision 2c3eb313)
1 /* $NetBSD: mpls_routes.c,v 1.24 2016/04/04 07:37:08 ozaki-r 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
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 *
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 *
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
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 *
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
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
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
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 *
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
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
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
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
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
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 ocassion 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
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