xref: /openbsd/usr.sbin/eigrpd/kroute.c (revision e2a2cc33)
1*e2a2cc33Srenato /*	$OpenBSD: kroute.c,v 1.8 2016/02/21 18:36:11 renato Exp $ */
243509a12Srenato 
343509a12Srenato /*
443509a12Srenato  * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
543509a12Srenato  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
643509a12Srenato  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
743509a12Srenato  *
843509a12Srenato  * Permission to use, copy, modify, and distribute this software for any
943509a12Srenato  * purpose with or without fee is hereby granted, provided that the above
1043509a12Srenato  * copyright notice and this permission notice appear in all copies.
1143509a12Srenato  *
1243509a12Srenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1343509a12Srenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1443509a12Srenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1543509a12Srenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1643509a12Srenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1743509a12Srenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1843509a12Srenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1943509a12Srenato  */
2043509a12Srenato 
2143509a12Srenato #include <sys/types.h>
2243509a12Srenato #include <sys/socket.h>
2343509a12Srenato #include <sys/sysctl.h>
2443509a12Srenato #include <sys/tree.h>
2543509a12Srenato #include <sys/uio.h>
2643509a12Srenato #include <netinet/in.h>
2743509a12Srenato #include <arpa/inet.h>
2843509a12Srenato #include <net/if.h>
2943509a12Srenato #include <net/if_dl.h>
3043509a12Srenato #include <net/if_types.h>
3143509a12Srenato #include <net/route.h>
3243509a12Srenato #include <err.h>
3343509a12Srenato #include <errno.h>
3443509a12Srenato #include <fcntl.h>
3543509a12Srenato #include <stdio.h>
3643509a12Srenato #include <stdlib.h>
3743509a12Srenato #include <string.h>
3843509a12Srenato #include <unistd.h>
3943509a12Srenato #include <limits.h>
4043509a12Srenato 
4143509a12Srenato #include "eigrpd.h"
4243509a12Srenato #include "log.h"
4343509a12Srenato 
4443509a12Srenato extern struct eigrpd_conf	*eigrpd_conf;
4543509a12Srenato 
4643509a12Srenato struct {
4743509a12Srenato 	uint32_t		rtseq;
4843509a12Srenato 	pid_t			pid;
4943509a12Srenato 	int			fib_sync;
5043509a12Srenato 	int			fd;
5143509a12Srenato 	struct event		ev;
5243509a12Srenato 	unsigned int		rdomain;
5343509a12Srenato } kr_state;
5443509a12Srenato 
5543509a12Srenato struct kroute_node {
5643509a12Srenato 	TAILQ_ENTRY(kroute_node)	 entry;
5743509a12Srenato 	struct kroute_priority		*kprio;		/* back pointer */
5843509a12Srenato 	struct kroute			 r;
5943509a12Srenato };
6043509a12Srenato 
6143509a12Srenato struct kroute_priority {
6243509a12Srenato 	TAILQ_ENTRY(kroute_priority)	 entry;
6343509a12Srenato 	struct kroute_prefix		*kp;		/* back pointer */
6443509a12Srenato 	uint8_t				 priority;
6543509a12Srenato 	TAILQ_HEAD(, kroute_node)	 nexthops;
6643509a12Srenato };
6743509a12Srenato 
6843509a12Srenato struct kroute_prefix {
6943509a12Srenato 	RB_ENTRY(kroute_prefix)		 entry;
7043509a12Srenato 	int				 af;
7143509a12Srenato 	union eigrpd_addr		 prefix;
7243509a12Srenato 	uint8_t				 prefixlen;
7343509a12Srenato 	TAILQ_HEAD(plist, kroute_priority) priorities;
7443509a12Srenato };
7543509a12Srenato 
7643509a12Srenato struct kif_addr {
7743509a12Srenato 	TAILQ_ENTRY(kif_addr)	 entry;
7843509a12Srenato 	struct kaddr		 a;
7943509a12Srenato };
8043509a12Srenato 
8143509a12Srenato struct kif_node {
8243509a12Srenato 	RB_ENTRY(kif_node)	 entry;
8343509a12Srenato 	TAILQ_HEAD(, kif_addr)	 addrs;
8443509a12Srenato 	struct kif		 k;
8543509a12Srenato };
8643509a12Srenato 
8743509a12Srenato void			 kr_redist_remove(struct kroute *);
8843509a12Srenato int			 kr_redist_eval(struct kroute *);
8943509a12Srenato void			 kr_redistribute(struct kroute_prefix *);
9043509a12Srenato int			 kroute_compare(struct kroute_prefix *,
9143509a12Srenato     struct kroute_prefix *);
9243509a12Srenato struct kroute_prefix	*kroute_find_prefix(int, union eigrpd_addr *, uint8_t);
9343509a12Srenato struct kroute_priority	*kroute_find_prio(struct kroute_prefix *, uint8_t);
9443509a12Srenato struct kroute_node	*kroute_find_gw(struct kroute_priority *,
9543509a12Srenato     union eigrpd_addr *);
9643509a12Srenato struct kroute_node	*kroute_insert(struct kroute *);
9743509a12Srenato int			 kroute_remove(struct kroute *);
9843509a12Srenato void			 kroute_clear(void);
9943509a12Srenato 
10043509a12Srenato int			 kif_compare(struct kif_node *, struct kif_node *);
10143509a12Srenato struct kif_node		*kif_find(unsigned short);
10243509a12Srenato struct kif_node		*kif_insert(unsigned short);
10343509a12Srenato int			 kif_remove(struct kif_node *);
10443509a12Srenato struct kif		*kif_update(unsigned short, int, struct if_data *,
10543509a12Srenato     struct sockaddr_dl *);
10643509a12Srenato int			 kif_validate(unsigned short);
10743509a12Srenato 
10843509a12Srenato void		protect_lo(void);
10943509a12Srenato uint8_t		prefixlen_classful(in_addr_t);
11043509a12Srenato void		get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
11143509a12Srenato void		if_change(unsigned short, int, struct if_data *,
11243509a12Srenato     struct sockaddr_dl *);
11343509a12Srenato void		if_newaddr(unsigned short, struct sockaddr *, struct sockaddr *,
11443509a12Srenato     struct sockaddr *);
11543509a12Srenato void		if_deladdr(unsigned short, struct sockaddr *, struct sockaddr *,
11643509a12Srenato     struct sockaddr *);
11743509a12Srenato void		if_announce(void *);
11843509a12Srenato 
11943509a12Srenato int		send_rtmsg(int, int, struct kroute *);
12043509a12Srenato int		dispatch_rtmsg(void);
12143509a12Srenato int		fetchtable(void);
12243509a12Srenato int		fetchifs(void);
12343509a12Srenato int		rtmsg_process(char *, size_t);
12443509a12Srenato int		rtmsg_process_route(struct rt_msghdr *,
12543509a12Srenato     struct sockaddr *[RTAX_MAX]);
12643509a12Srenato 
12743509a12Srenato RB_HEAD(kroute_tree, kroute_prefix)	krt;
12843509a12Srenato RB_PROTOTYPE(kroute_tree, kroute_prefix, entry, kroute_compare)
12943509a12Srenato RB_GENERATE(kroute_tree, kroute_prefix, entry, kroute_compare)
13043509a12Srenato 
13143509a12Srenato RB_HEAD(kif_tree, kif_node)		kit;
13243509a12Srenato RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)
13343509a12Srenato RB_GENERATE(kif_tree, kif_node, entry, kif_compare)
13443509a12Srenato 
13543509a12Srenato int
13643509a12Srenato kif_init(void)
13743509a12Srenato {
13843509a12Srenato 	RB_INIT(&kit);
13943509a12Srenato 	kr_state.fib_sync = 0;	/* decoupled */
14043509a12Srenato 
14143509a12Srenato 	if (fetchifs() == -1)
14243509a12Srenato 		return (-1);
14343509a12Srenato 
14443509a12Srenato 	return (0);
14543509a12Srenato }
14643509a12Srenato 
14743509a12Srenato int
14843509a12Srenato kr_init(int fs, unsigned int rdomain)
14943509a12Srenato {
15043509a12Srenato 	int		opt = 0, rcvbuf, default_rcvbuf;
15143509a12Srenato 	socklen_t	optlen;
15243509a12Srenato 
15343509a12Srenato 	kr_state.fib_sync = fs;
15443509a12Srenato 	kr_state.rdomain = rdomain;
15543509a12Srenato 
15643509a12Srenato 	if ((kr_state.fd = socket(AF_ROUTE,
15743509a12Srenato 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) {
15843509a12Srenato 		log_warn("%s: socket", __func__);
15943509a12Srenato 		return (-1);
16043509a12Srenato 	}
16143509a12Srenato 
16243509a12Srenato 	/* not interested in my own messages */
16343509a12Srenato 	if (setsockopt(kr_state.fd, SOL_SOCKET, SO_USELOOPBACK,
16443509a12Srenato 	    &opt, sizeof(opt)) == -1)
16543509a12Srenato 		log_warn("%s: setsockopt", __func__);	/* not fatal */
16643509a12Srenato 
16743509a12Srenato 	/* grow receive buffer, don't wanna miss messages */
16843509a12Srenato 	optlen = sizeof(default_rcvbuf);
16943509a12Srenato 	if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
17043509a12Srenato 	    &default_rcvbuf, &optlen) == -1)
17143509a12Srenato 		log_warn("%s: getsockopt SOL_SOCKET SO_RCVBUF", __func__);
17243509a12Srenato 	else
17343509a12Srenato 		for (rcvbuf = MAX_RTSOCK_BUF;
17443509a12Srenato 		    rcvbuf > default_rcvbuf &&
17543509a12Srenato 		    setsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
17643509a12Srenato 		    &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS;
17743509a12Srenato 		    rcvbuf /= 2)
17843509a12Srenato 			;	/* nothing */
17943509a12Srenato 
18043509a12Srenato 	kr_state.pid = getpid();
18143509a12Srenato 	kr_state.rtseq = 1;
18243509a12Srenato 
18343509a12Srenato 	if (fetchtable() == -1)
18443509a12Srenato 		return (-1);
18543509a12Srenato 
18643509a12Srenato 	protect_lo();
18743509a12Srenato 
18843509a12Srenato 	event_set(&kr_state.ev, kr_state.fd, EV_READ | EV_PERSIST,
18943509a12Srenato 	    kr_dispatch_msg, NULL);
19043509a12Srenato 	event_add(&kr_state.ev, NULL);
19143509a12Srenato 
19243509a12Srenato 	return (0);
19343509a12Srenato }
19443509a12Srenato 
19543509a12Srenato void
19643509a12Srenato kif_redistribute(void)
19743509a12Srenato {
19843509a12Srenato 	struct kif_node		*kif;
19943509a12Srenato 	struct kif_addr		*ka;
20043509a12Srenato 
201d6040158Srenato 	RB_FOREACH(kif, kif_tree, &kit) {
202d6040158Srenato 		main_imsg_compose_eigrpe(IMSG_IFINFO, 0, &kif->k,
203d6040158Srenato 		    sizeof(struct kif));
204d6040158Srenato 		TAILQ_FOREACH(ka, &kif->addrs, entry) {
20543509a12Srenato 			main_imsg_compose_eigrpe(IMSG_NEWADDR, 0, &ka->a,
20643509a12Srenato 			    sizeof(struct kaddr));
20743509a12Srenato 		}
208d6040158Srenato 	}
209d6040158Srenato }
21043509a12Srenato 
21143509a12Srenato int
21243509a12Srenato kr_change(struct kroute *kr)
21343509a12Srenato {
21443509a12Srenato 	struct kroute_prefix	*kp;
21543509a12Srenato 	struct kroute_priority	*kprio;
21643509a12Srenato 	struct kroute_node	*kn;
21743509a12Srenato 	int			 action = RTM_ADD;
21843509a12Srenato 
21943509a12Srenato 	kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen);
22043509a12Srenato 	if (kp == NULL)
22143509a12Srenato 		kn = kroute_insert(kr);
22243509a12Srenato 	else {
22343509a12Srenato 		kprio = kroute_find_prio(kp, kr->priority);
22443509a12Srenato 		if (kprio == NULL)
22543509a12Srenato 			kn = kroute_insert(kr);
22643509a12Srenato 		else {
22743509a12Srenato 			kn = kroute_find_gw(kprio, &kr->nexthop);
22843509a12Srenato 			if (kn == NULL)
22943509a12Srenato 				kn = kroute_insert(kr);
23043509a12Srenato 			else
23143509a12Srenato 				action = RTM_CHANGE;
23243509a12Srenato 		}
23343509a12Srenato 	}
23443509a12Srenato 
23543509a12Srenato 	/* send update */
23643509a12Srenato 	if (send_rtmsg(kr_state.fd, action, kr) == -1)
23743509a12Srenato 		return (-1);
23843509a12Srenato 
23943509a12Srenato 	kn->r.flags |= F_EIGRPD_INSERTED;
24043509a12Srenato 
24143509a12Srenato 	return (0);
24243509a12Srenato }
24343509a12Srenato 
24443509a12Srenato int
24543509a12Srenato kr_delete(struct kroute *kr)
24643509a12Srenato {
24743509a12Srenato 	struct kroute_prefix	*kp;
24843509a12Srenato 	struct kroute_priority	*kprio;
24943509a12Srenato 	struct kroute_node	*kn;
25043509a12Srenato 
25143509a12Srenato 	kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen);
25243509a12Srenato 	if (kp == NULL)
25343509a12Srenato 		return (0);
25443509a12Srenato 	kprio = kroute_find_prio(kp, kr->priority);
25543509a12Srenato 	if (kprio == NULL)
25643509a12Srenato 		return (0);
25743509a12Srenato 	kn = kroute_find_gw(kprio, &kr->nexthop);
25843509a12Srenato 	if (kn == NULL)
25943509a12Srenato 		return (0);
26043509a12Srenato 
26143509a12Srenato 	if (!(kn->r.flags & F_EIGRPD_INSERTED))
26243509a12Srenato 		return (0);
26343509a12Srenato 
26443509a12Srenato 	if (send_rtmsg(kr_state.fd, RTM_DELETE, &kn->r) == -1)
26543509a12Srenato 		return (-1);
26643509a12Srenato 
26743509a12Srenato 	if (kroute_remove(kr) == -1)
26843509a12Srenato 		return (-1);
26943509a12Srenato 
27043509a12Srenato 	return (0);
27143509a12Srenato }
27243509a12Srenato 
27343509a12Srenato void
27443509a12Srenato kr_shutdown(void)
27543509a12Srenato {
27643509a12Srenato 	kr_fib_decouple();
27743509a12Srenato 	kroute_clear();
27843509a12Srenato 	kif_clear();
27943509a12Srenato }
28043509a12Srenato 
28143509a12Srenato void
28243509a12Srenato kr_fib_couple(void)
28343509a12Srenato {
28443509a12Srenato 	struct kroute_prefix	*kp;
28543509a12Srenato 	struct kroute_priority	*kprio;
28643509a12Srenato 	struct kroute_node	*kn;
28743509a12Srenato 
28843509a12Srenato 	if (kr_state.fib_sync == 1)	/* already coupled */
28943509a12Srenato 		return;
29043509a12Srenato 
29143509a12Srenato 	kr_state.fib_sync = 1;
29243509a12Srenato 
29343509a12Srenato 	RB_FOREACH(kp, kroute_tree, &krt)
29443509a12Srenato 		TAILQ_FOREACH(kprio, &kp->priorities, entry)
29543509a12Srenato 			TAILQ_FOREACH(kn, &kprio->nexthops, entry) {
29643509a12Srenato 				if (!(kn->r.flags & F_EIGRPD_INSERTED))
29743509a12Srenato 					continue;
29843509a12Srenato 				send_rtmsg(kr_state.fd, RTM_ADD, &kn->r);
29943509a12Srenato 			}
30043509a12Srenato 
30143509a12Srenato 	log_info("kernel routing table coupled");
30243509a12Srenato }
30343509a12Srenato 
30443509a12Srenato void
30543509a12Srenato kr_fib_decouple(void)
30643509a12Srenato {
30743509a12Srenato 	struct kroute_prefix	*kp;
30843509a12Srenato 	struct kroute_priority	*kprio;
30943509a12Srenato 	struct kroute_node	*kn;
31043509a12Srenato 
31143509a12Srenato 	if (kr_state.fib_sync == 0)	/* already decoupled */
31243509a12Srenato 		return;
31343509a12Srenato 
31443509a12Srenato 	RB_FOREACH(kp, kroute_tree, &krt)
31543509a12Srenato 		TAILQ_FOREACH(kprio, &kp->priorities, entry)
31643509a12Srenato 			TAILQ_FOREACH(kn, &kprio->nexthops, entry) {
31743509a12Srenato 				if (!(kn->r.flags & F_EIGRPD_INSERTED))
31843509a12Srenato 					continue;
31943509a12Srenato 
32043509a12Srenato 				send_rtmsg(kr_state.fd, RTM_DELETE, &kn->r);
32143509a12Srenato 			}
32243509a12Srenato 
32343509a12Srenato 	kr_state.fib_sync = 0;
32443509a12Srenato 
32543509a12Srenato 	log_info("kernel routing table decoupled");
32643509a12Srenato }
32743509a12Srenato 
32843509a12Srenato /* ARGSUSED */
32943509a12Srenato void
33043509a12Srenato kr_dispatch_msg(int fd, short event, void *bula)
33143509a12Srenato {
33243509a12Srenato 	if (dispatch_rtmsg() == -1)
33343509a12Srenato 		event_loopexit(NULL);
33443509a12Srenato }
33543509a12Srenato 
33643509a12Srenato void
33743509a12Srenato kr_show_route(struct imsg *imsg)
33843509a12Srenato {
33943509a12Srenato 	struct kroute_prefix	*kp;
34043509a12Srenato 	struct kroute_priority	*kprio;
34143509a12Srenato 	struct kroute_node	*kn;
34243509a12Srenato 	struct kroute		 kr;
34343509a12Srenato 	int			 flags;
34443509a12Srenato 
34543509a12Srenato 	if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(flags)) {
34643509a12Srenato 		log_warnx("%s: wrong imsg len", __func__);
34743509a12Srenato 		return;
34843509a12Srenato 	}
34943509a12Srenato 	memcpy(&flags, imsg->data, sizeof(flags));
35043509a12Srenato 	RB_FOREACH(kp, kroute_tree, &krt)
35143509a12Srenato 		TAILQ_FOREACH(kprio, &kp->priorities, entry)
35243509a12Srenato 			TAILQ_FOREACH(kn, &kprio->nexthops, entry) {
35343509a12Srenato 				if (flags && !(kn->r.flags & flags))
35443509a12Srenato 					continue;
35543509a12Srenato 
35643509a12Srenato 				memcpy(&kr, &kn->r, sizeof(kr));
35743509a12Srenato 				if (kr.priority ==
35843509a12Srenato 				    eigrpd_conf->fib_priority_external)
35943509a12Srenato 					kr.flags |= F_CTL_EXTERNAL;
36043509a12Srenato 				main_imsg_compose_eigrpe(IMSG_CTL_KROUTE,
36143509a12Srenato 				    imsg->hdr.pid, &kr, sizeof(kr));
36243509a12Srenato 			}
36343509a12Srenato 
36443509a12Srenato 	main_imsg_compose_eigrpe(IMSG_CTL_END, imsg->hdr.pid, NULL, 0);
36543509a12Srenato }
36643509a12Srenato 
36743509a12Srenato void
36843509a12Srenato kr_ifinfo(char *ifname, pid_t pid)
36943509a12Srenato {
37043509a12Srenato 	struct kif_node	*kif;
37143509a12Srenato 
37243509a12Srenato 	RB_FOREACH(kif, kif_tree, &kit)
37343509a12Srenato 		if (ifname == NULL || !strcmp(ifname, kif->k.ifname)) {
37443509a12Srenato 			main_imsg_compose_eigrpe(IMSG_CTL_IFINFO,
37543509a12Srenato 			    pid, &kif->k, sizeof(kif->k));
37643509a12Srenato 		}
37743509a12Srenato 
37843509a12Srenato 	main_imsg_compose_eigrpe(IMSG_CTL_END, pid, NULL, 0);
37943509a12Srenato }
38043509a12Srenato 
38143509a12Srenato void
38243509a12Srenato kr_redist_remove(struct kroute *kr)
38343509a12Srenato {
38443509a12Srenato 	/* was the route redistributed? */
38543509a12Srenato 	if (!(kr->flags & F_REDISTRIBUTED))
38643509a12Srenato 		return;
38743509a12Srenato 
38843509a12Srenato 	/* remove redistributed flag */
38943509a12Srenato 	kr->flags &= ~F_REDISTRIBUTED;
39043509a12Srenato 	main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, kr, sizeof(*kr));
39143509a12Srenato }
39243509a12Srenato 
39343509a12Srenato int
39443509a12Srenato kr_redist_eval(struct kroute *kr)
39543509a12Srenato {
39643509a12Srenato 	in_addr_t	 a;
39743509a12Srenato 
39843509a12Srenato 	/* Only non-eigrpd routes are considered for redistribution. */
39943509a12Srenato 	if (!(kr->flags & F_KERNEL))
40043509a12Srenato 		goto dont_redistribute;
40143509a12Srenato 
40243509a12Srenato 	/* Dynamic routes are not redistributable. */
40343509a12Srenato 	if (kr->flags & F_DYNAMIC)
40443509a12Srenato 		goto dont_redistribute;
40543509a12Srenato 
40643509a12Srenato 	/* interface is not up and running so don't announce */
40743509a12Srenato 	if (kr->flags & F_DOWN)
40843509a12Srenato 		goto dont_redistribute;
40943509a12Srenato 
41043509a12Srenato 	/* filter-out non redistributable addresses */
41143509a12Srenato 	switch (kr->af) {
41243509a12Srenato 	case AF_INET:
41343509a12Srenato 		a = ntohl(kr->prefix.v4.s_addr);
41443509a12Srenato 		if (IN_MULTICAST(a) || IN_BADCLASS(a) ||
41543509a12Srenato 		    (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
41643509a12Srenato 			goto dont_redistribute;
41743509a12Srenato 
41843509a12Srenato 		if (kr->nexthop.v4.s_addr == htonl(INADDR_LOOPBACK) &&
41943509a12Srenato 		    !(kr->flags & (F_BLACKHOLE|F_REJECT)))
42043509a12Srenato 			goto dont_redistribute;
42143509a12Srenato 		break;
42243509a12Srenato 	case AF_INET6:
42343509a12Srenato 		if (IN6_IS_ADDR_LOOPBACK(&kr->prefix.v6) ||
42443509a12Srenato 		    IN6_IS_ADDR_MULTICAST(&kr->prefix.v6) ||
42543509a12Srenato 		    IN6_IS_ADDR_LINKLOCAL(&kr->prefix.v6) ||
42643509a12Srenato 		    IN6_IS_ADDR_SITELOCAL(&kr->prefix.v6) ||
42743509a12Srenato 		    IN6_IS_ADDR_V4MAPPED(&kr->prefix.v6) ||
42843509a12Srenato 		    IN6_IS_ADDR_V4COMPAT(&kr->prefix.v6))
42943509a12Srenato 			goto dont_redistribute;
43043509a12Srenato 
43143509a12Srenato 		if (IN6_IS_ADDR_LOOPBACK(&kr->nexthop.v6) &&
43243509a12Srenato 		    !(kr->flags & (F_BLACKHOLE|F_REJECT)))
43343509a12Srenato 			goto dont_redistribute;
43443509a12Srenato 		break;
43543509a12Srenato 	default:
43643509a12Srenato 		log_debug("%s: unexpected address-family", __func__);
43743509a12Srenato 		break;
43843509a12Srenato 	}
43943509a12Srenato 
44043509a12Srenato 	/* prefix should be redistributed */
44143509a12Srenato 	kr->flags |= F_REDISTRIBUTED;
44243509a12Srenato 	main_imsg_compose_rde(IMSG_NETWORK_ADD, 0, kr, sizeof(*kr));
44343509a12Srenato 	return (1);
44443509a12Srenato 
44543509a12Srenato dont_redistribute:
44643509a12Srenato 	kr_redist_remove(kr);
44743509a12Srenato 	return (0);
44843509a12Srenato }
44943509a12Srenato 
45043509a12Srenato void
45143509a12Srenato kr_redistribute(struct kroute_prefix *kp)
45243509a12Srenato {
45343509a12Srenato 	struct kroute_priority	*kprio;
45443509a12Srenato 	struct kroute_node	*kn;
45543509a12Srenato 
45643509a12Srenato 	/* only the highest prio route can be redistributed */
45743509a12Srenato 	TAILQ_FOREACH_REVERSE(kprio, &kp->priorities, plist, entry) {
45843509a12Srenato 		if (kprio == TAILQ_FIRST(&kp->priorities)) {
45943509a12Srenato 			TAILQ_FOREACH(kn, &kprio->nexthops, entry)
46043509a12Srenato 				/* pick just one entry in case of multipath */
46143509a12Srenato 				if (kr_redist_eval(&kn->r))
46243509a12Srenato 					break;
46343509a12Srenato 		} else {
46443509a12Srenato 			TAILQ_FOREACH(kn, &kprio->nexthops, entry)
46543509a12Srenato 				kr_redist_remove(&kn->r);
46643509a12Srenato 		}
46743509a12Srenato 	}
46843509a12Srenato }
46943509a12Srenato 
47043509a12Srenato int
47143509a12Srenato kroute_compare(struct kroute_prefix *a, struct kroute_prefix *b)
47243509a12Srenato {
47343509a12Srenato 	if (a->af < b->af)
47443509a12Srenato 		return (-1);
47543509a12Srenato 	if (a->af > b->af)
47643509a12Srenato 		return (1);
47743509a12Srenato 
47843509a12Srenato 	switch (a->af) {
47943509a12Srenato 	case AF_INET:
48043509a12Srenato 		if (ntohl(a->prefix.v4.s_addr) <
48143509a12Srenato 		    ntohl(b->prefix.v4.s_addr))
48243509a12Srenato 			return (-1);
48343509a12Srenato 		if (ntohl(a->prefix.v4.s_addr) >
48443509a12Srenato 		    ntohl(b->prefix.v4.s_addr))
48543509a12Srenato 			return (1);
48643509a12Srenato 		break;
48743509a12Srenato 	case AF_INET6:
48843509a12Srenato 		if (memcmp(a->prefix.v6.s6_addr,
48943509a12Srenato 		    b->prefix.v6.s6_addr, 16) < 0)
49043509a12Srenato 			return (-1);
49143509a12Srenato 		if (memcmp(a->prefix.v6.s6_addr,
49243509a12Srenato 		    b->prefix.v6.s6_addr, 16) > 0)
49343509a12Srenato 			return (1);
49443509a12Srenato 		break;
49543509a12Srenato 	default:
49643509a12Srenato 		log_debug("%s: unexpected address-family", __func__);
49743509a12Srenato 		break;
49843509a12Srenato 	}
49943509a12Srenato 
50043509a12Srenato 	if (a->prefixlen < b->prefixlen)
50143509a12Srenato 		return (-1);
50243509a12Srenato 	if (a->prefixlen > b->prefixlen)
50343509a12Srenato 		return (1);
50443509a12Srenato 
50543509a12Srenato 	return (0);
50643509a12Srenato }
50743509a12Srenato 
50843509a12Srenato /* tree management */
50943509a12Srenato struct kroute_prefix *
51043509a12Srenato kroute_find_prefix(int af, union eigrpd_addr *prefix, uint8_t prefixlen)
51143509a12Srenato {
51243509a12Srenato 	struct kroute_prefix	 s;
51343509a12Srenato 
51443509a12Srenato 	s.af = af;
51543509a12Srenato 	memcpy(&s.prefix, prefix, sizeof(s.prefix));
51643509a12Srenato 	s.prefixlen = prefixlen;
51743509a12Srenato 
51843509a12Srenato 	return (RB_FIND(kroute_tree, &krt, &s));
51943509a12Srenato }
52043509a12Srenato 
52143509a12Srenato struct kroute_priority *
52243509a12Srenato kroute_find_prio(struct kroute_prefix *kp, uint8_t prio)
52343509a12Srenato {
52443509a12Srenato 	struct kroute_priority	*kprio;
52543509a12Srenato 
52643509a12Srenato 	/* RTP_ANY here picks the lowest priority node */
52743509a12Srenato 	if (prio == RTP_ANY)
52843509a12Srenato 		return (TAILQ_FIRST(&kp->priorities));
52943509a12Srenato 
53043509a12Srenato 	TAILQ_FOREACH(kprio, &kp->priorities, entry)
53143509a12Srenato 		if (kprio->priority == prio)
53243509a12Srenato 			return (kprio);
53343509a12Srenato 
53443509a12Srenato 	return (NULL);
53543509a12Srenato }
53643509a12Srenato 
53743509a12Srenato struct kroute_node *
53843509a12Srenato kroute_find_gw(struct kroute_priority *kprio, union eigrpd_addr *nh)
53943509a12Srenato {
54043509a12Srenato 	struct kroute_node	*kn;
54143509a12Srenato 
54243509a12Srenato 	TAILQ_FOREACH(kn, &kprio->nexthops, entry)
54343509a12Srenato 		if (eigrp_addrcmp(kprio->kp->af, &kn->r.nexthop, nh) == 0)
54443509a12Srenato 			return (kn);
54543509a12Srenato 
54643509a12Srenato 	return (NULL);
54743509a12Srenato }
54843509a12Srenato 
54943509a12Srenato struct kroute_node *
55043509a12Srenato kroute_insert(struct kroute *kr)
55143509a12Srenato {
55243509a12Srenato 	struct kroute_prefix	*kp;
55337212791Srenato 	struct kroute_priority	*kprio, *tmp;
55443509a12Srenato 	struct kroute_node	*kn;
55543509a12Srenato 
55643509a12Srenato 	kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen);
55743509a12Srenato 	if (kp == NULL) {
55843509a12Srenato 		kp = calloc(1, sizeof((*kp)));
55943509a12Srenato 		if (kp == NULL)
56043509a12Srenato 			fatal("kroute_insert");
56143509a12Srenato 		kp->af = kr->af;
56243509a12Srenato 		memcpy(&kp->prefix, &kr->prefix, sizeof(kp->prefix));
56343509a12Srenato 		kp->prefixlen = kr->prefixlen;
56443509a12Srenato 		TAILQ_INIT(&kp->priorities);
56543509a12Srenato 		RB_INSERT(kroute_tree, &krt, kp);
56643509a12Srenato 	}
56743509a12Srenato 
56843509a12Srenato 	kprio = kroute_find_prio(kp, kr->priority);
56943509a12Srenato 	if (kprio == NULL) {
57043509a12Srenato 		kprio = calloc(1, sizeof(*kprio));
57143509a12Srenato 		if (kprio == NULL)
57243509a12Srenato 			fatal("kroute_insert");
57343509a12Srenato 		kprio->kp = kp;
57443509a12Srenato 		kprio->priority = kr->priority;
57543509a12Srenato 		TAILQ_INIT(&kprio->nexthops);
57643509a12Srenato 
57743509a12Srenato 		/* lower priorities first */
57843509a12Srenato 		TAILQ_FOREACH(tmp, &kp->priorities, entry)
57943509a12Srenato 			if (tmp->priority > kprio->priority)
58043509a12Srenato 				break;
58143509a12Srenato 		if (tmp)
58243509a12Srenato 			TAILQ_INSERT_BEFORE(tmp, kprio, entry);
58343509a12Srenato 		else
58443509a12Srenato 			TAILQ_INSERT_TAIL(&kp->priorities, kprio, entry);
58543509a12Srenato 	}
58643509a12Srenato 
58743509a12Srenato 	kn = kroute_find_gw(kprio, &kr->nexthop);
58843509a12Srenato 	if (kn == NULL) {
58943509a12Srenato 		kn = calloc(1, sizeof(*kn));
59043509a12Srenato 		if (kn == NULL)
59143509a12Srenato 			fatal("kroute_insert");
59243509a12Srenato 		kn->kprio = kprio;
59343509a12Srenato 		memcpy(&kn->r, kr, sizeof(kn->r));
59443509a12Srenato 		TAILQ_INSERT_TAIL(&kprio->nexthops, kn, entry);
59543509a12Srenato 	}
59643509a12Srenato 
59743509a12Srenato 	if (!(kr->flags & F_KERNEL)) {
59843509a12Srenato 		/* don't validate or redistribute eigrp route */
59943509a12Srenato 		kr->flags &= ~F_DOWN;
60043509a12Srenato 		return (kn);
60143509a12Srenato 	}
60243509a12Srenato 
60343509a12Srenato 	if (kif_validate(kr->ifindex))
60443509a12Srenato 		kr->flags &= ~F_DOWN;
60543509a12Srenato 	else
60643509a12Srenato 		kr->flags |= F_DOWN;
60743509a12Srenato 
60843509a12Srenato 	kr_redistribute(kp);
60943509a12Srenato 	return (kn);
61043509a12Srenato }
61143509a12Srenato 
61243509a12Srenato int
61343509a12Srenato kroute_remove(struct kroute *kr)
61443509a12Srenato {
61543509a12Srenato 	struct kroute_prefix	*kp;
61643509a12Srenato 	struct kroute_priority	*kprio;
61743509a12Srenato 	struct kroute_node	*kn;
61843509a12Srenato 
61943509a12Srenato 	kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen);
62043509a12Srenato 	if (kp == NULL)
62143509a12Srenato 		goto notfound;
62243509a12Srenato 	kprio = kroute_find_prio(kp, kr->priority);
62343509a12Srenato 	if (kprio == NULL)
62443509a12Srenato 		goto notfound;
62543509a12Srenato 	kn = kroute_find_gw(kprio, &kr->nexthop);
62643509a12Srenato 	if (kn == NULL)
62743509a12Srenato 		goto notfound;
62843509a12Srenato 
62943509a12Srenato 	kr_redist_remove(&kn->r);
63043509a12Srenato 
63143509a12Srenato 	TAILQ_REMOVE(&kprio->nexthops, kn, entry);
63243509a12Srenato 	free(kn);
63343509a12Srenato 
63443509a12Srenato 	if (TAILQ_EMPTY(&kprio->nexthops)) {
63543509a12Srenato 		TAILQ_REMOVE(&kp->priorities, kprio, entry);
63643509a12Srenato 		free(kprio);
63743509a12Srenato 	}
63843509a12Srenato 
63943509a12Srenato 	if (TAILQ_EMPTY(&kp->priorities)) {
64043509a12Srenato 		if (RB_REMOVE(kroute_tree, &krt, kp) == NULL)
64143509a12Srenato 			log_warnx("%s failed for %s/%u", __func__,
64243509a12Srenato 			    log_addr(kr->af, &kr->prefix), kp->prefixlen);
64343509a12Srenato 		free(kp);
64443509a12Srenato 	} else
64543509a12Srenato 		kr_redistribute(kp);
64643509a12Srenato 
64743509a12Srenato 	return (0);
64843509a12Srenato 
64943509a12Srenato notfound:
65043509a12Srenato 	log_warnx("%s failed to find %s/%u", __func__,
65143509a12Srenato 	    log_addr(kr->af, &kr->prefix), kr->prefixlen);
65243509a12Srenato 	return (-1);
65343509a12Srenato }
65443509a12Srenato 
65543509a12Srenato void
65643509a12Srenato kroute_clear(void)
65743509a12Srenato {
65843509a12Srenato 	struct kroute_prefix	*kp;
65943509a12Srenato 	struct kroute_priority	*kprio;
66043509a12Srenato 	struct kroute_node	*kn;
66143509a12Srenato 
66243509a12Srenato 	while ((kp = RB_MIN(kroute_tree, &krt)) != NULL) {
66343509a12Srenato 		while ((kprio = TAILQ_FIRST(&kp->priorities)) != NULL) {
66443509a12Srenato 			while ((kn = TAILQ_FIRST(&kprio->nexthops)) != NULL) {
66543509a12Srenato 				TAILQ_REMOVE(&kprio->nexthops, kn, entry);
66643509a12Srenato 				free(kn);
66743509a12Srenato 			}
66843509a12Srenato 			TAILQ_REMOVE(&kp->priorities, kprio, entry);
66943509a12Srenato 			free(kprio);
67043509a12Srenato 		}
67143509a12Srenato 		RB_REMOVE(kroute_tree, &krt, kp);
67243509a12Srenato 		free(kp);
67343509a12Srenato 	}
67443509a12Srenato }
67543509a12Srenato 
67643509a12Srenato int
67743509a12Srenato kif_compare(struct kif_node *a, struct kif_node *b)
67843509a12Srenato {
67943509a12Srenato 	return (b->k.ifindex - a->k.ifindex);
68043509a12Srenato }
68143509a12Srenato 
68243509a12Srenato /* tree management */
68343509a12Srenato struct kif_node *
68443509a12Srenato kif_find(unsigned short ifindex)
68543509a12Srenato {
68643509a12Srenato 	struct kif_node	s;
68743509a12Srenato 
68843509a12Srenato 	memset(&s, 0, sizeof(s));
68943509a12Srenato 	s.k.ifindex = ifindex;
69043509a12Srenato 
69143509a12Srenato 	return (RB_FIND(kif_tree, &kit, &s));
69243509a12Srenato }
69343509a12Srenato 
69443509a12Srenato struct kif *
69543509a12Srenato kif_findname(char *ifname)
69643509a12Srenato {
69743509a12Srenato 	struct kif_node	*kif;
69843509a12Srenato 
69943509a12Srenato 	RB_FOREACH(kif, kif_tree, &kit)
70043509a12Srenato 		if (!strcmp(ifname, kif->k.ifname))
70143509a12Srenato 			return (&kif->k);
70243509a12Srenato 
70343509a12Srenato 	return (NULL);
70443509a12Srenato }
70543509a12Srenato 
70643509a12Srenato struct kif_node *
70743509a12Srenato kif_insert(unsigned short ifindex)
70843509a12Srenato {
70943509a12Srenato 	struct kif_node	*kif;
71043509a12Srenato 
71143509a12Srenato 	if ((kif = calloc(1, sizeof(struct kif_node))) == NULL)
71243509a12Srenato 		return (NULL);
71343509a12Srenato 
71443509a12Srenato 	kif->k.ifindex = ifindex;
71543509a12Srenato 	TAILQ_INIT(&kif->addrs);
71643509a12Srenato 
71743509a12Srenato 	if (RB_INSERT(kif_tree, &kit, kif) != NULL)
71843509a12Srenato 		fatalx("kif_insert: RB_INSERT");
71943509a12Srenato 
72043509a12Srenato 	return (kif);
72143509a12Srenato }
72243509a12Srenato 
72343509a12Srenato int
72443509a12Srenato kif_remove(struct kif_node *kif)
72543509a12Srenato {
72643509a12Srenato 	struct kif_addr	*ka;
72743509a12Srenato 
72843509a12Srenato 	if (RB_REMOVE(kif_tree, &kit, kif) == NULL) {
72943509a12Srenato 		log_warnx("%s failed for inteface %s", __func__, kif->k.ifname);
73043509a12Srenato 		return (-1);
73143509a12Srenato 	}
73243509a12Srenato 
73343509a12Srenato 	while ((ka = TAILQ_FIRST(&kif->addrs)) != NULL) {
73443509a12Srenato 		TAILQ_REMOVE(&kif->addrs, ka, entry);
73543509a12Srenato 		free(ka);
73643509a12Srenato 	}
73743509a12Srenato 	free(kif);
73843509a12Srenato 	return (0);
73943509a12Srenato }
74043509a12Srenato 
74143509a12Srenato void
74243509a12Srenato kif_clear(void)
74343509a12Srenato {
74443509a12Srenato 	struct kif_node	*kif;
74543509a12Srenato 
74643509a12Srenato 	while ((kif = RB_MIN(kif_tree, &kit)) != NULL)
74743509a12Srenato 		kif_remove(kif);
74843509a12Srenato }
74943509a12Srenato 
75043509a12Srenato struct kif *
75143509a12Srenato kif_update(unsigned short ifindex, int flags, struct if_data *ifd,
75243509a12Srenato     struct sockaddr_dl *sdl)
75343509a12Srenato {
75443509a12Srenato 	struct kif_node		*kif;
75543509a12Srenato 
75643509a12Srenato 	if ((kif = kif_find(ifindex)) == NULL) {
75743509a12Srenato 		if ((kif = kif_insert(ifindex)) == NULL)
75843509a12Srenato 			return (NULL);
75943509a12Srenato 		kif->k.nh_reachable = (flags & IFF_UP) &&
76043509a12Srenato 		    LINK_STATE_IS_UP(ifd->ifi_link_state);
76143509a12Srenato 	}
76243509a12Srenato 
76343509a12Srenato 	kif->k.flags = flags;
76443509a12Srenato 	kif->k.link_state = ifd->ifi_link_state;
76543509a12Srenato 	kif->k.if_type = ifd->ifi_type;
76643509a12Srenato 	kif->k.baudrate = ifd->ifi_baudrate;
76743509a12Srenato 	kif->k.mtu = ifd->ifi_mtu;
76843509a12Srenato 
76943509a12Srenato 	if (sdl && sdl->sdl_family == AF_LINK) {
77043509a12Srenato 		if (sdl->sdl_nlen >= sizeof(kif->k.ifname))
77143509a12Srenato 			memcpy(kif->k.ifname, sdl->sdl_data,
77243509a12Srenato 			    sizeof(kif->k.ifname) - 1);
77343509a12Srenato 		else if (sdl->sdl_nlen > 0)
77443509a12Srenato 			memcpy(kif->k.ifname, sdl->sdl_data,
77543509a12Srenato 			    sdl->sdl_nlen);
77643509a12Srenato 		/* string already terminated via calloc() */
77743509a12Srenato 	}
77843509a12Srenato 
77943509a12Srenato 	return (&kif->k);
78043509a12Srenato }
78143509a12Srenato 
78243509a12Srenato int
78343509a12Srenato kif_validate(unsigned short ifindex)
78443509a12Srenato {
78543509a12Srenato 	struct kif_node		*kif;
78643509a12Srenato 
78743509a12Srenato 	if ((kif = kif_find(ifindex)) == NULL)
78843509a12Srenato 		return (0);
78943509a12Srenato 
79043509a12Srenato 	return (kif->k.nh_reachable);
79143509a12Srenato }
79243509a12Srenato 
79343509a12Srenato /* misc */
79443509a12Srenato void
79543509a12Srenato protect_lo(void)
79643509a12Srenato {
79743509a12Srenato 	struct kroute	 kr4, kr6;
79843509a12Srenato 
79943509a12Srenato 	/* special protection for 127/8 */
80043509a12Srenato 	memset(&kr4, 0, sizeof(kr4));
80143509a12Srenato 	kr4.af = AF_INET;
80243509a12Srenato 	kr4.prefix.v4.s_addr = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
80343509a12Srenato 	kr4.prefixlen = 8;
80443509a12Srenato 	kr4.flags = F_KERNEL|F_CONNECTED;
80543509a12Srenato 	kroute_insert(&kr4);
80643509a12Srenato 
80743509a12Srenato 	/* special protection for ::1 */
80843509a12Srenato 	memset(&kr6, 0, sizeof(kr6));
80943509a12Srenato 	kr6.af = AF_INET6;
81043509a12Srenato 	memcpy(&kr6.prefix.v6, &in6addr_loopback, sizeof(kr6.prefix.v6));
81143509a12Srenato 	kr6.prefixlen = 128;
81243509a12Srenato 	kr6.flags = F_KERNEL|F_CONNECTED;
81343509a12Srenato 	kroute_insert(&kr6);
81443509a12Srenato }
81543509a12Srenato 
81643509a12Srenato uint8_t
81743509a12Srenato prefixlen_classful(in_addr_t ina)
81843509a12Srenato {
81943509a12Srenato 	/* it hurt to write this. */
82043509a12Srenato 
82143509a12Srenato 	if (ina >= 0xf0000000U)		/* class E */
82243509a12Srenato 		return (32);
82343509a12Srenato 	else if (ina >= 0xe0000000U)	/* class D */
82443509a12Srenato 		return (4);
82543509a12Srenato 	else if (ina >= 0xc0000000U)	/* class C */
82643509a12Srenato 		return (24);
82743509a12Srenato 	else if (ina >= 0x80000000U)	/* class B */
82843509a12Srenato 		return (16);
82943509a12Srenato 	else				/* class A */
83043509a12Srenato 		return (8);
83143509a12Srenato }
83243509a12Srenato 
83343509a12Srenato #define	ROUNDUP(a)	\
83443509a12Srenato     (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
83543509a12Srenato 
83643509a12Srenato void
83743509a12Srenato get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
83843509a12Srenato {
83943509a12Srenato 	int	i;
84043509a12Srenato 
84143509a12Srenato 	for (i = 0; i < RTAX_MAX; i++) {
84243509a12Srenato 		if (addrs & (1 << i)) {
84343509a12Srenato 			rti_info[i] = sa;
84443509a12Srenato 			sa = (struct sockaddr *)((char *)(sa) +
84543509a12Srenato 			    ROUNDUP(sa->sa_len));
84643509a12Srenato 		} else
84743509a12Srenato 			rti_info[i] = NULL;
84843509a12Srenato 	}
84943509a12Srenato }
85043509a12Srenato 
85143509a12Srenato void
85243509a12Srenato if_change(unsigned short ifindex, int flags, struct if_data *ifd,
85343509a12Srenato     struct sockaddr_dl *sdl)
85443509a12Srenato {
85543509a12Srenato 	struct kroute_prefix	*kp;
85643509a12Srenato 	struct kroute_priority	*kprio;
85743509a12Srenato 	struct kroute_node	*kn;
85843509a12Srenato 	struct kif		*kif;
85943509a12Srenato 	uint8_t			 reachable;
86043509a12Srenato 
86143509a12Srenato 	if ((kif = kif_update(ifindex, flags, ifd, sdl)) == NULL) {
86243509a12Srenato 		log_warn("%s: kif_update(%u)", __func__, ifindex);
86343509a12Srenato 		return;
86443509a12Srenato 	}
86543509a12Srenato 
86643509a12Srenato 	reachable = (kif->flags & IFF_UP) &&
86743509a12Srenato 	    LINK_STATE_IS_UP(kif->link_state);
86843509a12Srenato 
86943509a12Srenato 	if (reachable == kif->nh_reachable)
87043509a12Srenato 		return;		/* nothing changed wrt nexthop validity */
87143509a12Srenato 
87243509a12Srenato 	kif->nh_reachable = reachable;
87343509a12Srenato 
87443509a12Srenato 	/* notify eigrpe about link state */
87543509a12Srenato 	main_imsg_compose_eigrpe(IMSG_IFINFO, 0, kif, sizeof(struct kif));
87643509a12Srenato 
87743509a12Srenato 	/* notify rde about link going down */
87843509a12Srenato 	if (!kif->nh_reachable)
87943509a12Srenato 		main_imsg_compose_rde(IMSG_IFDOWN, 0, kif, sizeof(struct kif));
88043509a12Srenato 
88143509a12Srenato 	/* update redistribute list */
88243509a12Srenato 	RB_FOREACH(kp, kroute_tree, &krt) {
88343509a12Srenato 		TAILQ_FOREACH(kprio, &kp->priorities, entry) {
88443509a12Srenato 			TAILQ_FOREACH(kn, &kprio->nexthops, entry) {
88543509a12Srenato 				if (kn->r.ifindex != ifindex)
88643509a12Srenato 					continue;
88743509a12Srenato 
88843509a12Srenato 				if (reachable)
88943509a12Srenato 					kn->r.flags &= ~F_DOWN;
89043509a12Srenato 				else
89143509a12Srenato 					kn->r.flags |= F_DOWN;
89243509a12Srenato 			}
89343509a12Srenato 		}
89443509a12Srenato 		kr_redistribute(kp);
89543509a12Srenato 	}
89643509a12Srenato }
89743509a12Srenato 
89843509a12Srenato void
89943509a12Srenato if_newaddr(unsigned short ifindex, struct sockaddr *ifa, struct sockaddr *mask,
90043509a12Srenato     struct sockaddr *brd)
90143509a12Srenato {
90243509a12Srenato 	struct kif_node		*kif;
90343509a12Srenato 	struct sockaddr_in	*ifa4, *mask4, *brd4;
90443509a12Srenato 	struct sockaddr_in6	*ifa6, *mask6, *brd6;
90543509a12Srenato 	struct kif_addr		*ka;
90643509a12Srenato 	uint32_t		 a;
90743509a12Srenato 
90843509a12Srenato 	if (ifa == NULL)
90943509a12Srenato 		return;
91043509a12Srenato 	if ((kif = kif_find(ifindex)) == NULL) {
91143509a12Srenato 		log_warnx("%s: corresponding if %d not found", __func__,
91243509a12Srenato 		    ifindex);
91343509a12Srenato 		return;
91443509a12Srenato 	}
91543509a12Srenato 
91643509a12Srenato 	switch (ifa->sa_family) {
91743509a12Srenato 	case AF_INET:
91843509a12Srenato 		ifa4 = (struct sockaddr_in *) ifa;
91943509a12Srenato 		mask4 = (struct sockaddr_in *) mask;
92043509a12Srenato 		brd4 = (struct sockaddr_in *) brd;
92143509a12Srenato 
92243509a12Srenato 		/* filter out unwanted addresses */
92343509a12Srenato 		a = ntohl(ifa4->sin_addr.s_addr);
92443509a12Srenato 		if (IN_MULTICAST(a) || IN_BADCLASS(a) ||
92543509a12Srenato 		    (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
92643509a12Srenato 			return;
92743509a12Srenato 
92843509a12Srenato 		if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL)
92943509a12Srenato 			fatal("if_newaddr");
93043509a12Srenato 		ka->a.addr.v4.s_addr = ifa4->sin_addr.s_addr;
93143509a12Srenato 		if (mask4)
93243509a12Srenato 			ka->a.prefixlen =
93343509a12Srenato 			    mask2prefixlen(mask4->sin_addr.s_addr);
93443509a12Srenato 		if (brd4)
93543509a12Srenato 			ka->a.dstbrd.v4.s_addr = brd4->sin_addr.s_addr;
93643509a12Srenato 		break;
93743509a12Srenato 	case AF_INET6:
93843509a12Srenato 		ifa6 = (struct sockaddr_in6 *) ifa;
93943509a12Srenato 		mask6 = (struct sockaddr_in6 *) mask;
94043509a12Srenato 		brd6 = (struct sockaddr_in6 *) brd;
94143509a12Srenato 
94243509a12Srenato 		/* We only care about link-local and global-scope. */
94343509a12Srenato 		if (IN6_IS_ADDR_UNSPECIFIED(&ifa6->sin6_addr) ||
94443509a12Srenato 		    IN6_IS_ADDR_LOOPBACK(&ifa6->sin6_addr) ||
94543509a12Srenato 		    IN6_IS_ADDR_MULTICAST(&ifa6->sin6_addr) ||
94643509a12Srenato 		    IN6_IS_ADDR_SITELOCAL(&ifa6->sin6_addr) ||
94743509a12Srenato 		    IN6_IS_ADDR_V4MAPPED(&ifa6->sin6_addr) ||
94843509a12Srenato 		    IN6_IS_ADDR_V4COMPAT(&ifa6->sin6_addr))
94943509a12Srenato 			return;
95043509a12Srenato 
95143509a12Srenato 		clearscope(&ifa6->sin6_addr);
95243509a12Srenato 
95343509a12Srenato 		if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL)
95443509a12Srenato 			fatal("if_newaddr");
95543509a12Srenato 		ka->a.addr.v6 = ifa6->sin6_addr;
95643509a12Srenato 		if (mask6)
95743509a12Srenato 			ka->a.prefixlen = mask2prefixlen6(mask6);
95843509a12Srenato 		if (brd6)
95943509a12Srenato 			ka->a.dstbrd.v6 = brd6->sin6_addr;
96043509a12Srenato 		break;
96143509a12Srenato 	default:
96243509a12Srenato 		return;
96343509a12Srenato 	}
96443509a12Srenato 
96543509a12Srenato 	ka->a.ifindex = ifindex;
96643509a12Srenato 	ka->a.af = ifa->sa_family;
96743509a12Srenato 	TAILQ_INSERT_TAIL(&kif->addrs, ka, entry);
96843509a12Srenato 
96943509a12Srenato 	/* notify eigrpe about new address */
97043509a12Srenato 	main_imsg_compose_eigrpe(IMSG_NEWADDR, 0, &ka->a,
97143509a12Srenato 	    sizeof(struct kaddr));
97243509a12Srenato }
97343509a12Srenato 
97443509a12Srenato void
97543509a12Srenato if_deladdr(unsigned short ifindex, struct sockaddr *ifa, struct sockaddr *mask,
97643509a12Srenato     struct sockaddr *brd)
97743509a12Srenato {
97843509a12Srenato 	struct kif_node		*kif;
97943509a12Srenato 	struct sockaddr_in	*ifa4, *mask4, *brd4;
98043509a12Srenato 	struct sockaddr_in6	*ifa6, *mask6, *brd6;
98143509a12Srenato 	struct kaddr		 k;
98243509a12Srenato 	struct kif_addr		*ka, *nka;
98343509a12Srenato 
98443509a12Srenato 	if (ifa == NULL)
98543509a12Srenato 		return;
98643509a12Srenato 	if ((kif = kif_find(ifindex)) == NULL) {
98743509a12Srenato 		log_warnx("%s: corresponding if %d not found", __func__,
98843509a12Srenato 		    ifindex);
98943509a12Srenato 		return;
99043509a12Srenato 	}
99143509a12Srenato 
99243509a12Srenato 	memset(&k, 0, sizeof(k));
99343509a12Srenato 	k.af = ifa->sa_family;
99443509a12Srenato 	switch (ifa->sa_family) {
99543509a12Srenato 	case AF_INET:
99643509a12Srenato 		ifa4 = (struct sockaddr_in *) ifa;
99743509a12Srenato 		mask4 = (struct sockaddr_in *) mask;
99843509a12Srenato 		brd4 = (struct sockaddr_in *) brd;
99943509a12Srenato 
100043509a12Srenato 		k.addr.v4.s_addr = ifa4->sin_addr.s_addr;
100143509a12Srenato 		if (mask4)
100243509a12Srenato 			k.prefixlen = mask2prefixlen(mask4->sin_addr.s_addr);
100343509a12Srenato 		if (brd4)
100443509a12Srenato 			k.dstbrd.v4.s_addr = brd4->sin_addr.s_addr;
100543509a12Srenato 		break;
100643509a12Srenato 	case AF_INET6:
100743509a12Srenato 		ifa6 = (struct sockaddr_in6 *) ifa;
100843509a12Srenato 		mask6 = (struct sockaddr_in6 *) mask;
100943509a12Srenato 		brd6 = (struct sockaddr_in6 *) brd;
101043509a12Srenato 
101143509a12Srenato 		/* We only care about link-local and global-scope. */
101243509a12Srenato 		if (IN6_IS_ADDR_UNSPECIFIED(&ifa6->sin6_addr) ||
101343509a12Srenato 		    IN6_IS_ADDR_LOOPBACK(&ifa6->sin6_addr) ||
101443509a12Srenato 		    IN6_IS_ADDR_MULTICAST(&ifa6->sin6_addr) ||
101543509a12Srenato 		    IN6_IS_ADDR_SITELOCAL(&ifa6->sin6_addr) ||
101643509a12Srenato 		    IN6_IS_ADDR_V4MAPPED(&ifa6->sin6_addr) ||
101743509a12Srenato 		    IN6_IS_ADDR_V4COMPAT(&ifa6->sin6_addr))
101843509a12Srenato 			return;
101943509a12Srenato 
102043509a12Srenato 		clearscope(&ifa6->sin6_addr);
102143509a12Srenato 
102243509a12Srenato 		k.addr.v6 = ifa6->sin6_addr;
102343509a12Srenato 		if (mask6)
102443509a12Srenato 			k.prefixlen = mask2prefixlen6(mask6);
102543509a12Srenato 		if (brd6)
102643509a12Srenato 			k.dstbrd.v6 = brd6->sin6_addr;
102743509a12Srenato 		break;
102843509a12Srenato 	default:
102943509a12Srenato 		return;
103043509a12Srenato 	}
103143509a12Srenato 
103243509a12Srenato 	for (ka = TAILQ_FIRST(&kif->addrs); ka != NULL; ka = nka) {
103343509a12Srenato 		nka = TAILQ_NEXT(ka, entry);
103443509a12Srenato 
103543509a12Srenato 		if (ka->a.af != k.af ||
103643509a12Srenato 		    ka->a.prefixlen != k.prefixlen)
103743509a12Srenato 			continue;
103843509a12Srenato 
103943509a12Srenato 		switch (ifa->sa_family) {
104043509a12Srenato 		case AF_INET:
104143509a12Srenato 			if (ka->a.addr.v4.s_addr != k.addr.v4.s_addr ||
104243509a12Srenato 			    ka->a.dstbrd.v4.s_addr != k.dstbrd.v4.s_addr)
104343509a12Srenato 				continue;
104443509a12Srenato 			break;
104543509a12Srenato 		case AF_INET6:
104643509a12Srenato 			if (!IN6_ARE_ADDR_EQUAL(&ka->a.addr.v6, &k.addr.v6) ||
104743509a12Srenato 			    !IN6_ARE_ADDR_EQUAL(&ka->a.dstbrd.v6, &k.dstbrd.v6))
104843509a12Srenato 				continue;
104943509a12Srenato 			break;
105043509a12Srenato 		default:
105143509a12Srenato 			break;
105243509a12Srenato 		}
105343509a12Srenato 
105443509a12Srenato 		/* notify eigrpe about removed address */
105543509a12Srenato 		main_imsg_compose_eigrpe(IMSG_DELADDR, 0, &ka->a,
105643509a12Srenato 		    sizeof(struct kaddr));
105743509a12Srenato 		TAILQ_REMOVE(&kif->addrs, ka, entry);
105843509a12Srenato 		free(ka);
105943509a12Srenato 		return;
106043509a12Srenato 	}
106143509a12Srenato }
106243509a12Srenato 
106343509a12Srenato void
106443509a12Srenato if_announce(void *msg)
106543509a12Srenato {
106643509a12Srenato 	struct if_announcemsghdr	*ifan;
106743509a12Srenato 	struct kif_node			*kif;
106843509a12Srenato 
106943509a12Srenato 	ifan = msg;
107043509a12Srenato 
107143509a12Srenato 	switch (ifan->ifan_what) {
107243509a12Srenato 	case IFAN_ARRIVAL:
107343509a12Srenato 		kif = kif_insert(ifan->ifan_index);
107443509a12Srenato 		if (kif)
107543509a12Srenato 			strlcpy(kif->k.ifname, ifan->ifan_name,
107643509a12Srenato 			    sizeof(kif->k.ifname));
107743509a12Srenato 		break;
107843509a12Srenato 	case IFAN_DEPARTURE:
107943509a12Srenato 		kif = kif_find(ifan->ifan_index);
108043509a12Srenato 		if (kif)
108143509a12Srenato 			kif_remove(kif);
108243509a12Srenato 		break;
108343509a12Srenato 	}
108443509a12Srenato }
108543509a12Srenato 
108643509a12Srenato /* rtsock */
108743509a12Srenato static int
108843509a12Srenato send_rtmsg_v4(int fd, int action, struct kroute *kr)
108943509a12Srenato {
109043509a12Srenato 	struct iovec		iov[5];
109143509a12Srenato 	struct rt_msghdr	hdr;
109243509a12Srenato 	struct sockaddr_in	prefix;
109343509a12Srenato 	struct sockaddr_in	nexthop;
109443509a12Srenato 	struct sockaddr_in	mask;
109543509a12Srenato 	int			iovcnt = 0;
109643509a12Srenato 
109743509a12Srenato 	if (kr_state.fib_sync == 0)
109843509a12Srenato 		return (0);
109943509a12Srenato 
110043509a12Srenato 	/* initialize header */
110143509a12Srenato 	memset(&hdr, 0, sizeof(hdr));
110243509a12Srenato 	hdr.rtm_version = RTM_VERSION;
110343509a12Srenato 	hdr.rtm_type = action;
110443509a12Srenato 	hdr.rtm_priority = kr->priority;
110543509a12Srenato 	hdr.rtm_tableid = kr_state.rdomain;	/* rtableid */
110643509a12Srenato 	if (action == RTM_CHANGE)
110743509a12Srenato 		hdr.rtm_fmask = RTF_REJECT|RTF_BLACKHOLE;
110843509a12Srenato 	else
110943509a12Srenato 		hdr.rtm_flags = RTF_MPATH;
11107c245af9Srenato 	if (kr->flags & F_BLACKHOLE)
11117c245af9Srenato 		hdr.rtm_flags |= RTF_BLACKHOLE;
111243509a12Srenato 	hdr.rtm_seq = kr_state.rtseq++;	/* overflow doesn't matter */
111343509a12Srenato 	hdr.rtm_msglen = sizeof(hdr);
111443509a12Srenato 	/* adjust iovec */
111543509a12Srenato 	iov[iovcnt].iov_base = &hdr;
111643509a12Srenato 	iov[iovcnt++].iov_len = sizeof(hdr);
111743509a12Srenato 
111843509a12Srenato 	memset(&prefix, 0, sizeof(prefix));
111943509a12Srenato 	prefix.sin_len = sizeof(prefix);
112043509a12Srenato 	prefix.sin_family = AF_INET;
112143509a12Srenato 	prefix.sin_addr.s_addr = kr->prefix.v4.s_addr;
112243509a12Srenato 	/* adjust header */
112343509a12Srenato 	hdr.rtm_addrs |= RTA_DST;
112443509a12Srenato 	hdr.rtm_msglen += sizeof(prefix);
112543509a12Srenato 	/* adjust iovec */
112643509a12Srenato 	iov[iovcnt].iov_base = &prefix;
112743509a12Srenato 	iov[iovcnt++].iov_len = sizeof(prefix);
112843509a12Srenato 
112943509a12Srenato 	if (kr->nexthop.v4.s_addr != 0) {
113043509a12Srenato 		memset(&nexthop, 0, sizeof(nexthop));
113143509a12Srenato 		nexthop.sin_len = sizeof(nexthop);
113243509a12Srenato 		nexthop.sin_family = AF_INET;
113343509a12Srenato 		nexthop.sin_addr.s_addr = kr->nexthop.v4.s_addr;
113443509a12Srenato 		/* adjust header */
113543509a12Srenato 		hdr.rtm_flags |= RTF_GATEWAY;
113643509a12Srenato 		hdr.rtm_addrs |= RTA_GATEWAY;
113743509a12Srenato 		hdr.rtm_msglen += sizeof(nexthop);
113843509a12Srenato 		/* adjust iovec */
113943509a12Srenato 		iov[iovcnt].iov_base = &nexthop;
114043509a12Srenato 		iov[iovcnt++].iov_len = sizeof(nexthop);
114143509a12Srenato 	}
114243509a12Srenato 
114343509a12Srenato 	memset(&mask, 0, sizeof(mask));
114443509a12Srenato 	mask.sin_len = sizeof(mask);
114543509a12Srenato 	mask.sin_family = AF_INET;
114643509a12Srenato 	mask.sin_addr.s_addr = prefixlen2mask(kr->prefixlen);
114743509a12Srenato 	/* adjust header */
114843509a12Srenato 	hdr.rtm_addrs |= RTA_NETMASK;
114943509a12Srenato 	hdr.rtm_msglen += sizeof(mask);
115043509a12Srenato 	/* adjust iovec */
115143509a12Srenato 	iov[iovcnt].iov_base = &mask;
115243509a12Srenato 	iov[iovcnt++].iov_len = sizeof(mask);
115343509a12Srenato 
115443509a12Srenato retry:
115543509a12Srenato 	if (writev(fd, iov, iovcnt) == -1) {
115643509a12Srenato 		if (errno == ESRCH) {
115743509a12Srenato 			if (hdr.rtm_type == RTM_CHANGE) {
115843509a12Srenato 				hdr.rtm_type = RTM_ADD;
115943509a12Srenato 				goto retry;
116043509a12Srenato 			} else if (hdr.rtm_type == RTM_DELETE) {
116143509a12Srenato 				log_info("route %s/%u vanished before delete",
116243509a12Srenato 				    inet_ntoa(kr->prefix.v4),
116343509a12Srenato 				    kr->prefixlen);
116443509a12Srenato 				return (0);
116543509a12Srenato 			}
116643509a12Srenato 		}
116743509a12Srenato 		log_warn("%s: action %u, prefix %s/%u", __func__, hdr.rtm_type,
116843509a12Srenato 		    inet_ntoa(kr->prefix.v4), kr->prefixlen);
116943509a12Srenato 		return (0);
117043509a12Srenato 	}
117143509a12Srenato 
117243509a12Srenato 	return (0);
117343509a12Srenato }
117443509a12Srenato 
117543509a12Srenato static int
117643509a12Srenato send_rtmsg_v6(int fd, int action, struct kroute *kr)
117743509a12Srenato {
117843509a12Srenato 	struct iovec		iov[5];
117943509a12Srenato 	struct rt_msghdr	hdr;
118043509a12Srenato 	struct pad {
118143509a12Srenato 		struct sockaddr_in6	addr;
118243509a12Srenato 		char			pad[sizeof(long)]; /* thank you IPv6 */
118343509a12Srenato 	} prefix, nexthop, mask;
118443509a12Srenato 	int			iovcnt = 0;
118543509a12Srenato 
118643509a12Srenato 	if (kr_state.fib_sync == 0)
118743509a12Srenato 		return (0);
118843509a12Srenato 
118943509a12Srenato 	/* initialize header */
119043509a12Srenato 	memset(&hdr, 0, sizeof(hdr));
119143509a12Srenato 	hdr.rtm_version = RTM_VERSION;
119243509a12Srenato 	hdr.rtm_type = action;
119343509a12Srenato 	hdr.rtm_priority = kr->priority;
119443509a12Srenato 	hdr.rtm_tableid = kr_state.rdomain;	/* rtableid */
119543509a12Srenato 	if (action == RTM_CHANGE)
119643509a12Srenato 		hdr.rtm_fmask = RTF_REJECT|RTF_BLACKHOLE;
119743509a12Srenato 	else
119843509a12Srenato 		hdr.rtm_flags = RTF_MPATH;
119943509a12Srenato 	hdr.rtm_seq = kr_state.rtseq++;	/* overflow doesn't matter */
120043509a12Srenato 	hdr.rtm_msglen = sizeof(hdr);
120143509a12Srenato 	/* adjust iovec */
120243509a12Srenato 	iov[iovcnt].iov_base = &hdr;
120343509a12Srenato 	iov[iovcnt++].iov_len = sizeof(hdr);
120443509a12Srenato 
120543509a12Srenato 	memset(&prefix, 0, sizeof(prefix));
120643509a12Srenato 	prefix.addr.sin6_len = sizeof(struct sockaddr_in6);
120743509a12Srenato 	prefix.addr.sin6_family = AF_INET6;
120843509a12Srenato 	prefix.addr.sin6_addr = kr->prefix.v6;
120943509a12Srenato 	/* adjust header */
121043509a12Srenato 	hdr.rtm_addrs |= RTA_DST;
121143509a12Srenato 	hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6));
121243509a12Srenato 	/* adjust iovec */
121343509a12Srenato 	iov[iovcnt].iov_base = &prefix;
121443509a12Srenato 	iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
121543509a12Srenato 
121643509a12Srenato 	if (!IN6_IS_ADDR_UNSPECIFIED(&kr->nexthop.v6)) {
121743509a12Srenato 		memset(&nexthop, 0, sizeof(nexthop));
121843509a12Srenato 		nexthop.addr.sin6_len = sizeof(struct sockaddr_in6);
121943509a12Srenato 		nexthop.addr.sin6_family = AF_INET6;
122043509a12Srenato 		nexthop.addr.sin6_addr = kr->nexthop.v6;
122143509a12Srenato 		nexthop.addr.sin6_scope_id = kr->ifindex;
122243509a12Srenato 		embedscope(&nexthop.addr);
122343509a12Srenato 
122443509a12Srenato 		/* adjust header */
122543509a12Srenato 		hdr.rtm_flags |= RTF_GATEWAY;
122643509a12Srenato 		hdr.rtm_addrs |= RTA_GATEWAY;
122743509a12Srenato 		hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6));
122843509a12Srenato 		/* adjust iovec */
122943509a12Srenato 		iov[iovcnt].iov_base = &nexthop;
123043509a12Srenato 		iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
123143509a12Srenato 	}
123243509a12Srenato 
123343509a12Srenato 	memset(&mask, 0, sizeof(mask));
123443509a12Srenato 	mask.addr.sin6_len = sizeof(struct sockaddr_in6);
123543509a12Srenato 	mask.addr.sin6_family = AF_INET6;
123643509a12Srenato 	mask.addr.sin6_addr = *prefixlen2mask6(kr->prefixlen);
123743509a12Srenato 	/* adjust header */
123843509a12Srenato 	if (kr->prefixlen == 128)
123943509a12Srenato 		hdr.rtm_flags |= RTF_HOST;
124043509a12Srenato 	hdr.rtm_addrs |= RTA_NETMASK;
124143509a12Srenato 	hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6));
124243509a12Srenato 	/* adjust iovec */
124343509a12Srenato 	iov[iovcnt].iov_base = &mask;
124443509a12Srenato 	iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
124543509a12Srenato 
124643509a12Srenato retry:
124743509a12Srenato 	if (writev(fd, iov, iovcnt) == -1) {
124843509a12Srenato 		if (errno == ESRCH) {
124943509a12Srenato 			if (hdr.rtm_type == RTM_CHANGE) {
125043509a12Srenato 				hdr.rtm_type = RTM_ADD;
125143509a12Srenato 				goto retry;
125243509a12Srenato 			} else if (hdr.rtm_type == RTM_DELETE) {
125343509a12Srenato 				log_info("route %s/%u vanished before delete",
125443509a12Srenato 				    log_in6addr(&kr->prefix.v6),
125543509a12Srenato 				    kr->prefixlen);
125643509a12Srenato 				return (0);
125743509a12Srenato 			}
125843509a12Srenato 		}
125943509a12Srenato 		log_warn("%s: action %u, prefix %s/%u", __func__, hdr.rtm_type,
126043509a12Srenato 		    log_in6addr(&kr->prefix.v6), kr->prefixlen);
126143509a12Srenato 		return (0);
126243509a12Srenato 	}
126343509a12Srenato 
126443509a12Srenato 	return (0);
126543509a12Srenato }
126643509a12Srenato 
126743509a12Srenato int
126843509a12Srenato send_rtmsg(int fd, int action, struct kroute *kr)
126943509a12Srenato {
127043509a12Srenato 	switch (kr->af) {
127143509a12Srenato 	case AF_INET:
127243509a12Srenato 		return (send_rtmsg_v4(fd, action, kr));
127343509a12Srenato 	case AF_INET6:
127443509a12Srenato 		return (send_rtmsg_v6(fd, action, kr));
127543509a12Srenato 	default:
127643509a12Srenato 		break;
127743509a12Srenato 	}
127843509a12Srenato 
127943509a12Srenato 	return (-1);
128043509a12Srenato }
128143509a12Srenato 
128243509a12Srenato int
128343509a12Srenato fetchtable(void)
128443509a12Srenato {
128543509a12Srenato 	size_t			 len;
128643509a12Srenato 	int			 mib[7];
128743509a12Srenato 	char			*buf;
128843509a12Srenato 	int			 rv;
128943509a12Srenato 
129043509a12Srenato 	mib[0] = CTL_NET;
129143509a12Srenato 	mib[1] = PF_ROUTE;
129243509a12Srenato 	mib[2] = 0;
129343509a12Srenato 	mib[3] = 0;
129443509a12Srenato 	mib[4] = NET_RT_DUMP;
129543509a12Srenato 	mib[5] = 0;
129643509a12Srenato 	mib[6] = kr_state.rdomain;	/* rtableid */
129743509a12Srenato 
129843509a12Srenato 	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
129943509a12Srenato 		log_warn("sysctl");
130043509a12Srenato 		return (-1);
130143509a12Srenato 	}
130243509a12Srenato 	if ((buf = malloc(len)) == NULL) {
130343509a12Srenato 		log_warn("fetchtable");
130443509a12Srenato 		return (-1);
130543509a12Srenato 	}
130643509a12Srenato 	if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
130743509a12Srenato 		log_warn("sysctl");
130843509a12Srenato 		free(buf);
130943509a12Srenato 		return (-1);
131043509a12Srenato 	}
131143509a12Srenato 
131243509a12Srenato 	rv = rtmsg_process(buf, len);
131343509a12Srenato 	free(buf);
131443509a12Srenato 
131543509a12Srenato 	return (rv);
131643509a12Srenato }
131743509a12Srenato 
131843509a12Srenato int
131943509a12Srenato fetchifs(void)
132043509a12Srenato {
132143509a12Srenato 	size_t			 len;
132243509a12Srenato 	int			 mib[6];
132343509a12Srenato 	char			*buf;
132443509a12Srenato 	int			 rv;
132543509a12Srenato 
132643509a12Srenato 	mib[0] = CTL_NET;
132743509a12Srenato 	mib[1] = PF_ROUTE;
132843509a12Srenato 	mib[2] = 0;
132943509a12Srenato 	mib[3] = 0;	/* wildcard */
133043509a12Srenato 	mib[4] = NET_RT_IFLIST;
133143509a12Srenato 	mib[5] = 0;
133243509a12Srenato 
133343509a12Srenato 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
133443509a12Srenato 		log_warn("sysctl");
133543509a12Srenato 		return (-1);
133643509a12Srenato 	}
133743509a12Srenato 	if ((buf = malloc(len)) == NULL) {
133843509a12Srenato 		log_warn("fetchifs");
133943509a12Srenato 		return (-1);
134043509a12Srenato 	}
134143509a12Srenato 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
134243509a12Srenato 		log_warn("sysctl");
134343509a12Srenato 		free(buf);
134443509a12Srenato 		return (-1);
134543509a12Srenato 	}
134643509a12Srenato 
134743509a12Srenato 	rv = rtmsg_process(buf, len);
134843509a12Srenato 	free(buf);
134943509a12Srenato 
135043509a12Srenato 	return (rv);
135143509a12Srenato }
135243509a12Srenato 
135343509a12Srenato int
135443509a12Srenato dispatch_rtmsg(void)
135543509a12Srenato {
135643509a12Srenato 	char			 buf[RT_BUF_SIZE];
135743509a12Srenato 	ssize_t			 n;
135843509a12Srenato 
135943509a12Srenato 	if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) {
136043509a12Srenato 		if (errno == EAGAIN || errno == EINTR)
136143509a12Srenato 			return (0);
136243509a12Srenato 		log_warn("%s: read error", __func__);
136343509a12Srenato 		return (-1);
136443509a12Srenato 	}
136543509a12Srenato 
136643509a12Srenato 	if (n == 0) {
136743509a12Srenato 		log_warnx("routing socket closed");
136843509a12Srenato 		return (-1);
136943509a12Srenato 	}
137043509a12Srenato 
137143509a12Srenato 	return (rtmsg_process(buf, n));
137243509a12Srenato }
137343509a12Srenato 
137443509a12Srenato int
137543509a12Srenato rtmsg_process(char *buf, size_t len)
137643509a12Srenato {
137743509a12Srenato 	struct rt_msghdr	*rtm;
137843509a12Srenato 	struct if_msghdr	 ifm;
137943509a12Srenato 	struct ifa_msghdr	*ifam;
138043509a12Srenato 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
138143509a12Srenato 	size_t			 offset;
138243509a12Srenato 	char			*next;
138343509a12Srenato 
138443509a12Srenato 	for (offset = 0; offset < len; offset += rtm->rtm_msglen) {
138543509a12Srenato 		next = buf + offset;
138643509a12Srenato 		rtm = (struct rt_msghdr *)next;
138743509a12Srenato 		if (len < offset + sizeof(unsigned short) ||
138843509a12Srenato 		    len < offset + rtm->rtm_msglen)
138943509a12Srenato 			fatalx("rtmsg_process: partial rtm in buffer");
139043509a12Srenato 		if (rtm->rtm_version != RTM_VERSION)
139143509a12Srenato 			continue;
139243509a12Srenato 
139343509a12Srenato 		sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
139443509a12Srenato 		get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
139543509a12Srenato 
139643509a12Srenato 		switch (rtm->rtm_type) {
139743509a12Srenato 		case RTM_ADD:
139843509a12Srenato 		case RTM_GET:
139943509a12Srenato 		case RTM_CHANGE:
140043509a12Srenato 		case RTM_DELETE:
140143509a12Srenato 			if (rtm->rtm_errno)		/* failed attempts... */
140243509a12Srenato 				continue;
140343509a12Srenato 
140443509a12Srenato 			if (rtm->rtm_tableid != kr_state.rdomain)
140543509a12Srenato 				continue;
140643509a12Srenato 
1407*e2a2cc33Srenato 			if (rtm->rtm_type == RTM_GET &&
1408*e2a2cc33Srenato 			    rtm->rtm_pid != kr_state.pid)
1409*e2a2cc33Srenato 				continue;
1410*e2a2cc33Srenato 
141143509a12Srenato 			/* Skip ARP/ND cache and broadcast routes. */
141243509a12Srenato 			if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST))
141343509a12Srenato 				continue;
141443509a12Srenato 
141543509a12Srenato 			if (rtmsg_process_route(rtm, rti_info) == -1)
141643509a12Srenato 				return (-1);
141743509a12Srenato 		}
141843509a12Srenato 
141943509a12Srenato 		switch (rtm->rtm_type) {
142043509a12Srenato 		case RTM_IFINFO:
142143509a12Srenato 			memcpy(&ifm, next, sizeof(ifm));
142243509a12Srenato 			if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data,
142343509a12Srenato 			    (struct sockaddr_dl *)rti_info[RTAX_IFP]);
142443509a12Srenato 			break;
142543509a12Srenato 		case RTM_NEWADDR:
142643509a12Srenato 			ifam = (struct ifa_msghdr *)rtm;
142743509a12Srenato 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
142843509a12Srenato 			    RTA_BRD)) == 0)
142943509a12Srenato 				break;
143043509a12Srenato 
143143509a12Srenato 			if_newaddr(ifam->ifam_index,
143243509a12Srenato 			    (struct sockaddr *)rti_info[RTAX_IFA],
143343509a12Srenato 			    (struct sockaddr *)rti_info[RTAX_NETMASK],
143443509a12Srenato 			    (struct sockaddr *)rti_info[RTAX_BRD]);
143543509a12Srenato 			break;
143643509a12Srenato 		case RTM_DELADDR:
143743509a12Srenato 			ifam = (struct ifa_msghdr *)rtm;
143843509a12Srenato 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
143943509a12Srenato 			    RTA_BRD)) == 0)
144043509a12Srenato 				break;
144143509a12Srenato 
144243509a12Srenato 			if_deladdr(ifam->ifam_index,
144343509a12Srenato 			    (struct sockaddr *)rti_info[RTAX_IFA],
144443509a12Srenato 			    (struct sockaddr *)rti_info[RTAX_NETMASK],
144543509a12Srenato 			    (struct sockaddr *)rti_info[RTAX_BRD]);
144643509a12Srenato 			break;
144743509a12Srenato 		case RTM_IFANNOUNCE:
144843509a12Srenato 			if_announce(next);
144943509a12Srenato 			break;
145043509a12Srenato 		default:
145143509a12Srenato 			/* ignore for now */
145243509a12Srenato 			break;
145343509a12Srenato 		}
145443509a12Srenato 	}
145543509a12Srenato 
145643509a12Srenato 	return (offset);
145743509a12Srenato }
145843509a12Srenato 
145943509a12Srenato int
146043509a12Srenato rtmsg_process_route(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX])
146143509a12Srenato {
146243509a12Srenato 	struct sockaddr		*sa;
146343509a12Srenato 	struct sockaddr_in	*sa_in;
146443509a12Srenato 	struct sockaddr_in6	*sa_in6;
146543509a12Srenato 	struct kroute		 kr;
146643509a12Srenato 	struct kroute_prefix	*kp;
146743509a12Srenato 	struct kroute_priority	*kprio;
146843509a12Srenato 	struct kroute_node	*kn;
146943509a12Srenato 
147043509a12Srenato 	if ((sa = rti_info[RTAX_DST]) == NULL)
147143509a12Srenato 		return (-1);
147243509a12Srenato 
147343509a12Srenato 	memset(&kr, 0, sizeof(kr));
147443509a12Srenato 	kr.af = sa->sa_family;
147543509a12Srenato 	switch (kr.af) {
147643509a12Srenato 	case AF_INET:
147743509a12Srenato 		kr.prefix.v4.s_addr =
147843509a12Srenato 		    ((struct sockaddr_in *)sa)->sin_addr.s_addr;
147943509a12Srenato 		sa_in = (struct sockaddr_in *) rti_info[RTAX_NETMASK];
148043509a12Srenato 		if (sa_in != NULL && sa_in->sin_len != 0)
148143509a12Srenato 			kr.prefixlen = mask2prefixlen(sa_in->sin_addr.s_addr);
148243509a12Srenato 		else if (rtm->rtm_flags & RTF_HOST)
148343509a12Srenato 			kr.prefixlen = 32;
148443509a12Srenato 		else if (kr.prefix.v4.s_addr == INADDR_ANY)
148543509a12Srenato 			kr.prefixlen = 0;
148643509a12Srenato 		else
148743509a12Srenato 			kr.prefixlen = prefixlen_classful(kr.prefix.v4.s_addr);
148843509a12Srenato 		break;
148943509a12Srenato 	case AF_INET6:
149043509a12Srenato 		memcpy(&kr.prefix.v6, &((struct sockaddr_in6 *)sa)->sin6_addr,
149143509a12Srenato 		    sizeof(kr.prefix.v6));
149243509a12Srenato 		sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
149343509a12Srenato 		if (sa_in6 != NULL && sa_in6->sin6_len != 0)
149443509a12Srenato 			kr.prefixlen = mask2prefixlen6(sa_in6);
149543509a12Srenato 		else if (rtm->rtm_flags & RTF_HOST)
149643509a12Srenato 			kr.prefixlen = 128;
149743509a12Srenato 		else if (IN6_IS_ADDR_UNSPECIFIED(&kr.prefix.v6))
149843509a12Srenato 			kr.prefixlen = 0;
149943509a12Srenato 		else
150043509a12Srenato 			fatalx("in6 net addr without netmask");
150143509a12Srenato 		break;
150243509a12Srenato 	default:
150343509a12Srenato 		return (0);
150443509a12Srenato 	}
150543509a12Srenato 	kr.ifindex = rtm->rtm_index;
150643509a12Srenato 	if ((sa = rti_info[RTAX_GATEWAY]) != NULL) {
150743509a12Srenato 		switch (sa->sa_family) {
150843509a12Srenato 		case AF_INET:
150943509a12Srenato 			kr.nexthop.v4.s_addr =
151043509a12Srenato 			    ((struct sockaddr_in *)sa)->sin_addr.s_addr;
151143509a12Srenato 			break;
151243509a12Srenato 		case AF_INET6:
151343509a12Srenato 			sa_in6 = (struct sockaddr_in6 *)sa;
151443509a12Srenato 			recoverscope(sa_in6);
151543509a12Srenato 			kr.nexthop.v6 = sa_in6->sin6_addr;
151643509a12Srenato 			if (sa_in6->sin6_scope_id)
151743509a12Srenato 				kr.ifindex = sa_in6->sin6_scope_id;
151843509a12Srenato 			break;
151943509a12Srenato 		case AF_LINK:
152043509a12Srenato 			kr.flags |= F_CONNECTED;
152143509a12Srenato 			break;
152243509a12Srenato 		}
152343509a12Srenato 	}
152443509a12Srenato 	kr.flags |= F_KERNEL;
152543509a12Srenato 	if (rtm->rtm_flags & RTF_STATIC)
152643509a12Srenato 		kr.flags |= F_STATIC;
152743509a12Srenato 	if (rtm->rtm_flags & RTF_BLACKHOLE)
152843509a12Srenato 		kr.flags |= F_BLACKHOLE;
152943509a12Srenato 	if (rtm->rtm_flags & RTF_REJECT)
153043509a12Srenato 		kr.flags |= F_REJECT;
153143509a12Srenato 	if (rtm->rtm_flags & RTF_DYNAMIC)
153243509a12Srenato 		kr.flags |= F_DYNAMIC;
153343509a12Srenato 	kr.priority = rtm->rtm_priority;
153443509a12Srenato 
153543509a12Srenato 	if (rtm->rtm_type == RTM_CHANGE) {
153643509a12Srenato 		/*
153743509a12Srenato 		 * The kernel doesn't allow RTM_CHANGE for multipath routes.
153843509a12Srenato 		 * If we got this message we know that the route has only one
153943509a12Srenato 		 * nexthop and we should remove it before installing the same
154043509a12Srenato 		 * route with the new nexthop.
154143509a12Srenato 		 */
154243509a12Srenato 		kp = kroute_find_prefix(kr.af, &kr.prefix, kr.prefixlen);
154343509a12Srenato 		if (kp) {
154443509a12Srenato 			kprio = kroute_find_prio(kp, kr.priority);
154543509a12Srenato 			if (kprio) {
154643509a12Srenato 				kn = TAILQ_FIRST(&kprio->nexthops);
15474f0b2092Srenato 				if (kn)
15484f0b2092Srenato 					kroute_remove(&kn->r);
154943509a12Srenato 			}
155043509a12Srenato 		}
155143509a12Srenato 	}
155243509a12Srenato 
155343509a12Srenato 	kn = NULL;
155443509a12Srenato 	kp = kroute_find_prefix(kr.af, &kr.prefix, kr.prefixlen);
155543509a12Srenato 	if (kp) {
155643509a12Srenato 		kprio = kroute_find_prio(kp, kr.priority);
155743509a12Srenato 		if (kprio)
155843509a12Srenato 			kn = kroute_find_gw(kprio, &kr.nexthop);
155943509a12Srenato 	}
156043509a12Srenato 
156143509a12Srenato 	if (rtm->rtm_type == RTM_DELETE) {
156243509a12Srenato 		if (kn == NULL || !(kn->r.flags & F_KERNEL))
156343509a12Srenato 			return (0);
156443509a12Srenato 		return (kroute_remove(&kr));
156543509a12Srenato 	}
156643509a12Srenato 
156743509a12Srenato 	if (!eigrp_addrisset(kr.af, &kr.nexthop) && !(kr.flags & F_CONNECTED)) {
156843509a12Srenato 		log_warnx("%s: no nexthop for %s/%u", __func__,
156943509a12Srenato 		    log_addr(kr.af, &kr.prefix), kr.prefixlen);
157043509a12Srenato 		return (-1);
157143509a12Srenato 	}
157243509a12Srenato 
157343509a12Srenato 	if (kn != NULL) {
157443509a12Srenato 		/* update route */
157543509a12Srenato 		memcpy(&kn->r, &kr, sizeof(kn->r));
157643509a12Srenato 
157743509a12Srenato 		if (kif_validate(kn->r.ifindex))
157843509a12Srenato 			kn->r.flags &= ~F_DOWN;
157943509a12Srenato 		else
158043509a12Srenato 			kn->r.flags |= F_DOWN;
158143509a12Srenato 
158243509a12Srenato 		kr_redistribute(kp);
15834f0b2092Srenato 	} else {
15844f0b2092Srenato 		if ((rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_GET) &&
15854f0b2092Srenato 		    (kr.priority == eigrpd_conf->fib_priority_internal ||
15864f0b2092Srenato 		    kr.priority == eigrpd_conf->fib_priority_external ||
15874f0b2092Srenato 		    kr.priority == eigrpd_conf->fib_priority_summary)) {
15884f0b2092Srenato 			log_warnx("alien EIGRP route %s/%d", log_addr(kr.af,
15894f0b2092Srenato 			    &kr.prefix), kr.prefixlen);
15904f0b2092Srenato 			return (send_rtmsg(kr_state.fd, RTM_DELETE, &kr));
15914f0b2092Srenato 		}
15924f0b2092Srenato 
159343509a12Srenato 		kroute_insert(&kr);
15944f0b2092Srenato 	}
159543509a12Srenato 
159643509a12Srenato 	return (0);
159743509a12Srenato }
1598