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
60extern int      route_socket;
61int             rt_seq = 200;
62int		dont_catch = 0;
63extern int	no_default_route;
64extern int	debug_f, warn_f;
65static int	my_pid = 0;
66
67struct rt_msg   replay_rt[REPLAY_MAX];
68int             replay_index = 0;
69
70#if 0
71static int read_route_socket(char *, int);
72#endif
73void	mask_addr(union sockunion *);
74int	compare_sockunion(const union sockunion *, const union sockunion *);
75static int check_if_addr_updown(struct rt_msg *, uint);
76
77extern 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
105static int
106read_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 */
157void
158mask_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 */
171su->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 */
176union sockunion *
177make_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 */
196union sockunion *
197make_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
218int
219compare_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
227union sockunion *
228from_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
249uint8_t
250from_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
261uint8_t
262from_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 */
275void
276from_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 */
288static const char *
289route_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. */
306int
307add_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 */
400int
401delete_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 */
470int
471get_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 */
578int
579check_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 */
774static int
775check_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
822int
823bind_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
934int
935flush_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