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