diff options
author | Renato Westphal <renato@cvs.openbsd.org> | 2016-05-23 18:58:49 +0000 |
---|---|---|
committer | Renato Westphal <renato@cvs.openbsd.org> | 2016-05-23 18:58:49 +0000 |
commit | cf7a670d9f872a58664dbcb1068aa3f90ee3a358 (patch) | |
tree | 5c5ac205ed68e30352e11e2307ed38d7076646cc /usr.sbin/ldpd | |
parent | 2a70268000d85df755837c9e48ee7423c839ee75 (diff) |
Add support for IPv6 (RFC 7552).
This includes:
* Full compliance to RFC 7552;
* Support for MD5 on LDPov6 sessions;
* Support for pseudowires over IPv6 LSPs (we're probably the world's
first implementation doing this);
* Support for the IPv6 explicit-null label;
* Knob to specify the prefered address-family for TCP transport
connections;
* Knob to use cisco non-compliant format to send and interpret the
Dual-Stack capability TLV.
Diffstat (limited to 'usr.sbin/ldpd')
-rw-r--r-- | usr.sbin/ldpd/address.c | 130 | ||||
-rw-r--r-- | usr.sbin/ldpd/adjacency.c | 78 | ||||
-rw-r--r-- | usr.sbin/ldpd/hello.c | 343 | ||||
-rw-r--r-- | usr.sbin/ldpd/init.c | 6 | ||||
-rw-r--r-- | usr.sbin/ldpd/interface.c | 354 | ||||
-rw-r--r-- | usr.sbin/ldpd/kroute.c | 731 | ||||
-rw-r--r-- | usr.sbin/ldpd/l2vpn.c | 40 | ||||
-rw-r--r-- | usr.sbin/ldpd/labelmapping.c | 76 | ||||
-rw-r--r-- | usr.sbin/ldpd/lde.c | 257 | ||||
-rw-r--r-- | usr.sbin/ldpd/lde.h | 54 | ||||
-rw-r--r-- | usr.sbin/ldpd/lde_lib.c | 93 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldp.h | 25 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.8 | 13 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.c | 166 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.conf.5 | 83 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.h | 178 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.c | 178 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.h | 98 | ||||
-rw-r--r-- | usr.sbin/ldpd/log.c | 126 | ||||
-rw-r--r-- | usr.sbin/ldpd/log.h | 11 | ||||
-rw-r--r-- | usr.sbin/ldpd/neighbor.c | 113 | ||||
-rw-r--r-- | usr.sbin/ldpd/packet.c | 163 | ||||
-rw-r--r-- | usr.sbin/ldpd/parse.y | 300 | ||||
-rw-r--r-- | usr.sbin/ldpd/pfkey.c | 72 | ||||
-rw-r--r-- | usr.sbin/ldpd/printconf.c | 88 | ||||
-rw-r--r-- | usr.sbin/ldpd/socket.c | 131 | ||||
-rw-r--r-- | usr.sbin/ldpd/util.c | 303 |
27 files changed, 3060 insertions, 1150 deletions
diff --git a/usr.sbin/ldpd/address.c b/usr.sbin/ldpd/address.c index 139393e928a..45e85e99b8f 100644 --- a/usr.sbin/ldpd/address.c +++ b/usr.sbin/ldpd/address.c @@ -1,4 +1,4 @@ -/* $OpenBSD: address.c,v 1.22 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: address.c,v 1.23 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -32,16 +32,16 @@ #include <string.h> #include "ldpd.h" -#include "ldp.h" -#include "log.h" #include "ldpe.h" +#include "lde.h" +#include "log.h" extern struct ldpd_conf *leconf; -void gen_address_list_tlv(struct ibuf *, struct if_addr *, uint16_t); +void gen_address_list_tlv(struct ibuf *, uint16_t, int, struct if_addr *); void -send_address(struct nbr *nbr, struct if_addr *if_addr, int withdraw) +send_address(struct nbr *nbr, int af, struct if_addr *if_addr, int withdraw) { struct ibuf *buf; uint32_t msg_type; @@ -55,12 +55,22 @@ send_address(struct nbr *nbr, struct if_addr *if_addr, int withdraw) if (if_addr == NULL) { LIST_FOREACH(if_addr, &global.addr_list, entry) - iface_count++; + if (if_addr->af == af) + iface_count++; } else iface_count = 1; - size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct address_list_tlv) + - iface_count * sizeof(struct in_addr); + size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct address_list_tlv); + switch (af) { + case AF_INET: + size += iface_count * sizeof(struct in_addr); + break; + case AF_INET6: + size += iface_count * sizeof(struct in6_addr); + break; + default: + fatalx("send_address: unknown af"); + } if ((buf = ibuf_open(size)) == NULL) fatal(__func__); @@ -69,7 +79,7 @@ send_address(struct nbr *nbr, struct if_addr *if_addr, int withdraw) size -= LDP_HDR_SIZE; gen_msg_hdr(buf, msg_type, size); size -= LDP_MSG_SIZE; - gen_address_list_tlv(buf, if_addr, size); + gen_address_list_tlv(buf, size, af, if_addr); evbuf_enqueue(&nbr->tcp->wbuf, buf); @@ -82,13 +92,9 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) struct ldp_msg addr; struct address_list_tlv alt; enum imsg_type type; + struct lde_addr lde_addr; memcpy(&addr, buf, sizeof(addr)); - if (ntohs(addr.type) == MSG_TYPE_ADDR) - type = IMSG_ADDRESS_ADD; - else - type = IMSG_ADDRESS_DEL; - buf += LDP_MSG_SIZE; len -= LDP_MSG_SIZE; @@ -107,48 +113,104 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) session_shutdown(nbr, S_UNKNOWN_TLV, addr.msgid, addr.type); return (-1); } - - /* For now we only support IPv4 */ - if (alt.family != htons(AF_IPV4)) { + switch (ntohs(alt.family)) { + case AF_IPV4: + if (!nbr->v4_enabled) + /* just ignore the message */ + return (0); + break; + case AF_IPV6: + if (!nbr->v6_enabled) + /* just ignore the message */ + return (0); + break; + default: send_notification_nbr(nbr, S_UNSUP_ADDR, addr.msgid, addr.type); return (-1); } buf += sizeof(alt); len -= sizeof(alt); - while (len >= sizeof(struct in_addr)) { - ldpe_imsg_compose_lde(type, nbr->peerid, 0, - buf, sizeof(struct in_addr)); - - buf += sizeof(struct in_addr); - len -= sizeof(struct in_addr); - } + if (ntohs(addr.type) == MSG_TYPE_ADDR) + type = IMSG_ADDRESS_ADD; + else + type = IMSG_ADDRESS_DEL; - if (len != 0) { - session_shutdown(nbr, S_BAD_TLV_LEN, addr.msgid, addr.type); - return (-1); + while (len > 0) { + switch (ntohs(alt.family)) { + case AF_IPV4: + if (len < sizeof(struct in_addr)) { + session_shutdown(nbr, S_BAD_TLV_LEN, addr.msgid, + addr.type); + return (-1); + } + + memset(&lde_addr, 0, sizeof(lde_addr)); + lde_addr.af = AF_INET; + memcpy(&lde_addr.addr, buf, sizeof(struct in_addr)); + + buf += sizeof(struct in_addr); + len -= sizeof(struct in_addr); + break; + case AF_IPV6: + if (len < sizeof(struct in6_addr)) { + session_shutdown(nbr, S_BAD_TLV_LEN, addr.msgid, + addr.type); + return (-1); + } + + memset(&lde_addr, 0, sizeof(lde_addr)); + lde_addr.af = AF_INET6; + memcpy(&lde_addr.addr, buf, sizeof(struct in6_addr)); + + buf += sizeof(struct in6_addr); + len -= sizeof(struct in6_addr); + break; + default: + fatalx("recv_address: unknown af"); + } + + log_debug("%s: neighbor ID %s address %s%s", __func__, + inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr), + ntohs(addr.type) == MSG_TYPE_ADDR ? "" : " (withdraw)"); + + ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr, + sizeof(lde_addr)); } return (0); } void -gen_address_list_tlv(struct ibuf *buf, struct if_addr *if_addr, uint16_t size) +gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af, + struct if_addr *if_addr) { struct address_list_tlv alt; - + uint16_t addr_size; memset(&alt, 0, sizeof(alt)); alt.type = TLV_TYPE_ADDRLIST; alt.length = htons(size - TLV_HDR_LEN); - /* XXX: just ipv4 for now */ - alt.family = htons(AF_IPV4); + switch (af) { + case AF_INET: + alt.family = htons(AF_IPV4); + addr_size = sizeof(struct in_addr); + break; + case AF_INET6: + alt.family = htons(AF_IPV6); + addr_size = sizeof(struct in6_addr); + break; + default: + fatalx("gen_address_list_tlv: unknown af"); + } ibuf_add(buf, &alt, sizeof(alt)); if (if_addr == NULL) { - LIST_FOREACH(if_addr, &global.addr_list, entry) - ibuf_add(buf, &if_addr->addr, sizeof(if_addr->addr)); + LIST_FOREACH(if_addr, &global.addr_list, entry) { + if (if_addr->af == af) + ibuf_add(buf, &if_addr->addr, addr_size); + } } else - ibuf_add(buf, &if_addr->addr, sizeof(if_addr->addr)); + ibuf_add(buf, &if_addr->addr, addr_size); } diff --git a/usr.sbin/ldpd/adjacency.c b/usr.sbin/ldpd/adjacency.c index 68066ff81bb..a116b4592b1 100644 --- a/usr.sbin/ldpd/adjacency.c +++ b/usr.sbin/ldpd/adjacency.c @@ -1,4 +1,4 @@ -/* $OpenBSD: adjacency.c,v 1.18 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: adjacency.c,v 1.19 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -39,28 +39,29 @@ void tnbr_start_hello_timer(struct tnbr *); void tnbr_stop_hello_timer(struct tnbr *); struct adj * -adj_new(struct nbr *nbr, struct hello_source *source, struct in_addr addr) +adj_new(struct in_addr lsr_id, struct hello_source *source, + union ldpd_addr *addr) { struct adj *adj; - log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(nbr->id), + log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(lsr_id), log_hello_src(source)); if ((adj = calloc(1, sizeof(*adj))) == NULL) fatal(__func__); - adj->nbr = nbr; + adj->lsr_id = lsr_id; + adj->nbr = NULL; adj->source = *source; - adj->addr = addr; + adj->trans_addr = *addr; evtimer_set(&adj->inactivity_timer, adj_itimer, adj); - LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry); + LIST_INSERT_HEAD(&global.adj_list, adj, global_entry); switch (source->type) { case HELLO_LINK: - LIST_INSERT_HEAD(&source->link.iface->adj_list, adj, - iface_entry); + LIST_INSERT_HEAD(&source->link.ia->adj_list, adj, ia_entry); break; case HELLO_TARGETED: source->target->adj = adj; @@ -73,35 +74,38 @@ adj_new(struct nbr *nbr, struct hello_source *source, struct in_addr addr) void adj_del(struct adj *adj) { - log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(adj->nbr->id), + log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(adj->lsr_id), log_hello_src(&adj->source)); adj_stop_itimer(adj); - LIST_REMOVE(adj, nbr_entry); + LIST_REMOVE(adj, global_entry); + if (adj->nbr) + LIST_REMOVE(adj, nbr_entry); if (adj->source.type == HELLO_LINK) - LIST_REMOVE(adj, iface_entry); + LIST_REMOVE(adj, ia_entry); /* last adjacency deleted */ - if (LIST_EMPTY(&adj->nbr->adj_list)) + if (adj->nbr && LIST_EMPTY(&adj->nbr->adj_list)) nbr_del(adj->nbr); free(adj); } struct adj * -adj_find(struct nbr *nbr, struct hello_source *source) +adj_find(struct hello_source *source) { struct adj *adj; - LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) { + LIST_FOREACH(adj, &global.adj_list, global_entry) { if (adj->source.type != source->type) continue; switch (source->type) { case HELLO_LINK: - if (adj->source.link.src_addr.s_addr == - source->link.src_addr.s_addr) + if (ldp_addrcmp(source->link.ia->af, + &adj->source.link.src_addr, + &source->link.src_addr) == 0) return (adj); break; case HELLO_TARGETED: @@ -114,6 +118,19 @@ adj_find(struct nbr *nbr, struct hello_source *source) return (NULL); } +int +adj_get_af(struct adj *adj) +{ + switch (adj->source.type) { + case HELLO_LINK: + return (adj->source.link.ia->af); + case HELLO_TARGETED: + return (adj->source.target->af); + default: + fatalx("adj_get_af: unknown hello type"); + } +} + /* adjacency timers */ /* ARGSUSED */ @@ -122,7 +139,7 @@ adj_itimer(int fd, short event, void *arg) { struct adj *adj = arg; - log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->nbr->id)); + log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id)); if (adj->source.type == HELLO_TARGETED) { if (!(adj->source.target->flags & F_TNBR_CONFIGURED) && @@ -159,17 +176,18 @@ adj_stop_itimer(struct adj *adj) /* targeted neighbors */ struct tnbr * -tnbr_new(struct ldpd_conf *xconf, struct in_addr addr) +tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) { struct tnbr *tnbr; if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL) fatal(__func__); - tnbr->addr = addr; + tnbr->af = af; + tnbr->addr = *addr; tnbr->state = TNBR_STA_DOWN; - tnbr->hello_holdtime = xconf->thello_holdtime; - tnbr->hello_interval = xconf->thello_interval; + tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime; + tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval; return (tnbr); } @@ -185,12 +203,13 @@ tnbr_del(struct tnbr *tnbr) } struct tnbr * -tnbr_find(struct ldpd_conf *xconf, struct in_addr addr) +tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) { struct tnbr *tnbr; LIST_FOREACH(tnbr, &xconf->tnbr_list, entry) - if (addr.s_addr == tnbr->addr.s_addr) + if (af == tnbr->af && + ldp_addrcmp(af, addr, &tnbr->addr) == 0) return (tnbr); return (NULL); @@ -213,7 +232,7 @@ tnbr_update(struct tnbr *tnbr) { int socket_ok, rtr_id_ok; - if (global.ldp_edisc_socket != -1) + if ((ldp_af_global_get(&global, tnbr->af))->ldp_edisc_socket != -1) socket_ok = 1; else socket_ok = 0; @@ -242,13 +261,14 @@ tnbr_update(struct tnbr *tnbr) } void -tnbr_update_all(void) +tnbr_update_all(int af) { struct tnbr *tnbr; /* update targeted neighbors */ LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) - tnbr_update(tnbr); + if (tnbr->af == af || af == AF_UNSPEC) + tnbr_update(tnbr); } /* target neighbors timers */ @@ -287,11 +307,12 @@ adj_to_ctl(struct adj *adj) { static struct ctl_adj actl; - actl.id = adj->nbr->id; + actl.af = adj_get_af(adj); + actl.id = adj->lsr_id; actl.type = adj->source.type; switch (adj->source.type) { case HELLO_LINK: - memcpy(actl.ifname, adj->source.link.iface->name, + memcpy(actl.ifname, adj->source.link.ia->iface->name, sizeof(actl.ifname)); break; case HELLO_TARGETED: @@ -299,6 +320,7 @@ adj_to_ctl(struct adj *adj) break; } actl.holdtime = adj->holdtime; + actl.trans_addr = adj->trans_addr; return (&actl); } diff --git a/usr.sbin/ldpd/hello.c b/usr.sbin/ldpd/hello.c index be195e393ba..043eac8b7da 100644 --- a/usr.sbin/ldpd/hello.c +++ b/usr.sbin/ldpd/hello.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hello.c,v 1.39 2016/05/23 18:33:56 renato Exp $ */ +/* $OpenBSD: hello.c,v 1.40 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -38,42 +38,70 @@ extern struct ldpd_conf *leconf; int tlv_decode_hello_prms(char *, uint16_t, uint16_t *, uint16_t *); -int tlv_decode_opt_hello_prms(char *, uint16_t, struct in_addr *, - uint32_t *); +int tlv_decode_opt_hello_prms(char *, uint16_t, int *, int, + union ldpd_addr *, uint32_t *, uint16_t *); int gen_hello_prms_tlv(struct ibuf *buf, uint16_t, uint16_t); int gen_opt4_hello_prms_tlv(struct ibuf *, uint16_t, uint32_t); +int gen_opt16_hello_prms_tlv(struct ibuf *, uint16_t, uint8_t *); +int gen_ds_hello_prms_tlv(struct ibuf *, uint32_t); int -send_hello(enum hello_type type, struct iface *iface, struct tnbr *tnbr) +send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr) { - struct sockaddr_in dst; - struct ibuf *buf; + int af; + union ldpd_addr dst; uint16_t size, holdtime = 0, flags = 0; int fd = 0; - - dst.sin_port = htons(LDP_PORT); - dst.sin_family = AF_INET; - dst.sin_len = sizeof(struct sockaddr_in); + struct ibuf *buf; switch (type) { case HELLO_LINK: - inet_aton(AllRouters, &dst.sin_addr); - holdtime = iface->hello_holdtime; + af = ia->af; + holdtime = ia->hello_holdtime; flags = 0; - fd = global.ldp_disc_socket; + fd = (ldp_af_global_get(&global, af))->ldp_disc_socket; + + /* multicast destination address */ + switch (af) { + case AF_INET: + dst.v4 = global.mcast_addr_v4; + break; + case AF_INET6: + dst.v6 = global.mcast_addr_v6; + break; + default: + fatalx("send_hello: unknown af"); + } break; case HELLO_TARGETED: - dst.sin_addr = tnbr->addr; + af = tnbr->af; holdtime = tnbr->hello_holdtime; flags = TARGETED_HELLO; if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count) flags |= REQUEST_TARG_HELLO; - fd = global.ldp_edisc_socket; + fd = (ldp_af_global_get(&global, af))->ldp_edisc_socket; + + /* unicast destination address */ + dst = tnbr->addr; break; + default: + fatalx("send_hello: unknown hello type"); } - size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct hello_prms_tlv) + - sizeof(struct hello_prms_opt4_tlv); + /* calculate message size */ + size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct hello_prms_tlv); + switch (af) { + case AF_INET: + size += sizeof(struct hello_prms_opt4_tlv); + break; + case AF_INET6: + size += sizeof(struct hello_prms_opt16_tlv); + break; + default: + fatalx("send_hello: unknown af"); + } + if (ldp_is_dual_stack(leconf)) + size += sizeof(struct hello_prms_opt4_tlv); /* generate message */ if ((buf = ibuf_open(size)) == NULL) @@ -83,26 +111,57 @@ send_hello(enum hello_type type, struct iface *iface, struct tnbr *tnbr) size -= LDP_HDR_SIZE; gen_msg_hdr(buf, MSG_TYPE_HELLO, size); gen_hello_prms_tlv(buf, holdtime, flags); - gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR, - leconf->trans_addr.s_addr); - send_packet(fd, iface, buf->buf, buf->wpos, &dst); + /* + * RFC 7552 - Section 6.1: + * "An LSR MUST include only the transport address whose address + * family is the same as that of the IP packet carrying the Hello + * message". + */ + switch (af) { + case AF_INET: + gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR, + leconf->ipv4.trans_addr.v4.s_addr); + break; + case AF_INET6: + gen_opt16_hello_prms_tlv(buf, TLV_TYPE_IPV6TRANSADDR, + leconf->ipv6.trans_addr.v6.s6_addr); + break; + default: + fatalx("send_hello: unknown af"); + } + + /* + * RFC 7552 - Section 6.1.1: + * "A Dual-stack LSR (i.e., an LSR supporting Dual-stack LDP for a peer) + * MUST include the Dual-Stack capability TLV in all of its LDP Hellos". + */ + if (ldp_is_dual_stack(leconf)) + gen_ds_hello_prms_tlv(buf, leconf->trans_pref); + + send_packet(fd, af, &dst, ia, buf->buf, buf->wpos); ibuf_free(buf); return (0); } void -recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src, - struct iface *iface, int multicast, char *buf, uint16_t len) +recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, int af, + union ldpd_addr *src, struct iface *iface, int multicast, char *buf, + uint16_t len) { - struct adj *adj; + struct adj *adj = NULL; struct nbr *nbr; uint16_t holdtime, flags; - struct in_addr transport_addr; + int tlvs_rcvd; + int ds_tlv; + union ldpd_addr trans_addr; + uint32_t scope_id = 0; uint32_t conf_number; + uint16_t trans_pref; int r; struct hello_source source; + struct iface_af *ia = NULL; struct tnbr *tnbr = NULL; r = tlv_decode_hello_prms(buf, len, &holdtime, &flags); @@ -133,7 +192,19 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src, memset(&source, 0, sizeof(source)); if (flags & TARGETED_HELLO) { - tnbr = tnbr_find(leconf, src); + /* + * RFC 7552 - Section 5.2: + * "The link-local IPv6 addresses MUST NOT be used as the + * targeted LDP Hello packet's source or destination addresses. + */ + if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&src->v6)) { + log_debug("%s: lsr-id %s: targeted hello with " + "link-local source address", __func__, + inet_ntoa(lsr_id)); + return; + } + + tnbr = tnbr_find(leconf, af, src); /* remove the dynamic tnbr if the 'R' bit was cleared */ if (tnbr && (tnbr->flags & F_TNBR_DYNAMIC) && @@ -144,10 +215,11 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src, if (!tnbr) { if (!((flags & REQUEST_TARG_HELLO) && - leconf->flags & F_LDPD_TH_ACCEPT)) + ((ldp_af_conf_get(leconf, af))->flags & + F_LDPD_AF_THELLO_ACCEPT))) return; - tnbr = tnbr_new(leconf, src); + tnbr = tnbr_new(leconf, af, src); tnbr->flags |= F_TNBR_DYNAMIC; tnbr_update(tnbr); LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry); @@ -156,13 +228,14 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src, source.type = HELLO_TARGETED; source.target = tnbr; } else { + ia = iface_af_get(iface, af); source.type = HELLO_LINK; - source.link.iface = iface; - source.link.src_addr = src; + source.link.ia = ia; + source.link.src_addr = *src; } - r = tlv_decode_opt_hello_prms(buf, len, &transport_addr, - &conf_number); + r = tlv_decode_opt_hello_prms(buf, len, &tlvs_rcvd, af, &trans_addr, + &conf_number, &trans_pref); if (r == -1) { log_debug("%s: lsr-id %s: failed to decode optional params", __func__, inet_ntoa(lsr_id)); @@ -175,30 +248,118 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src, } /* implicit transport address */ - if (transport_addr.s_addr == INADDR_ANY) - transport_addr = src; - if (bad_ip_addr(transport_addr)) { + if (!(tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR)) + trans_addr = *src; + if (bad_addr(af, &trans_addr)) { log_debug("%s: lsr-id %s: invalid transport address %s", - __func__, inet_ntoa(lsr_id), inet_ntoa(transport_addr)); + __func__, inet_ntoa(lsr_id), log_addr(af, &trans_addr)); return; } + if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&trans_addr.v6)) { + /* + * RFC 7552 - Section 6.1: + * An LSR MUST use a global unicast IPv6 address in an IPv6 + * Transport Address optional object of outgoing targeted + * Hellos and check for the same in incoming targeted Hellos + * (i.e., MUST discard the targeted Hello if it failed the + * check)". + */ + if (source.type == HELLO_TARGETED) + return; + scope_id = iface->ifindex; + } + adj = adj_find(&source); nbr = nbr_find_ldpid(lsr_id.s_addr); - if (!nbr) { + + /* check dual-stack tlv */ + ds_tlv = (tlvs_rcvd & F_HELLO_TLV_RCVD_DS) ? 1 : 0; + if (ds_tlv && trans_pref != leconf->trans_pref) { + /* + * RFC 7552 - Section 6.1.1: + * "If the Dual-Stack capability TLV is present and the remote + * preference does not match the local preference (or does not + * get recognized), then the LSR MUST discard the Hello message + * and log an error. + * If an LDP session was already in place, then the LSR MUST + * send a fatal Notification message with status code of + * 'Transport Connection Mismatch' and reset the session". + */ + log_debug("%s: lsr-id %s: remote transport preference does not " + "match the local preference", __func__, inet_ntoa(lsr_id)); + if (nbr) + session_shutdown(nbr, S_TRANS_MISMTCH, lm->msgid, + lm->type); + if (adj) + adj_del(adj); + return; + } + + if (adj == NULL) { + adj = adj_new(lsr_id, &source, &trans_addr); + if (nbr) { + adj->nbr = nbr; + LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry); + } + } + + if (nbr == NULL) { + /* + * The hello adjacency's address-family doesn't match the local + * preference. + */ + if (ds_tlv && + ((trans_pref == DUAL_STACK_LDPOV4 && af != AF_INET) || + (trans_pref == DUAL_STACK_LDPOV6 && af != AF_INET6))) + return; + + nbr = nbr_find_addr(af, &trans_addr); + if (nbr) { + log_debug("%s: transport address %s is already being " + "used by lsr-id %s", __func__, log_addr(af, + &trans_addr), inet_ntoa(nbr->id)); + return; + } + /* create new adjacency and new neighbor */ - nbr = nbr_new(lsr_id, transport_addr); - adj = adj_new(nbr, &source, transport_addr); + nbr = nbr_new(lsr_id, af, ds_tlv, &trans_addr, scope_id); } else { - adj = adj_find(nbr, &source); - if (!adj) { - /* create new adjacency for existing neighbor */ - adj = adj_new(nbr, &source, transport_addr); - - if (nbr->raddr.s_addr != transport_addr.s_addr) - log_warnx("%s: lsr-id %s: multiple " - "adjacencies advertising different " - "transport addresses", __func__, - inet_ntoa(lsr_id)); + /* + * Check for noncompliant dual-stack neighbor according to + * RFC 7552 section 6.1.1. + */ + if (!ds_tlv) { + switch (af) { + case AF_INET: + if (nbr_adj_count(nbr, AF_INET6) > 0) { + session_shutdown(nbr, S_DS_NONCMPLNCE, + lm->msgid, lm->type); + return; + } + break; + case AF_INET6: + if (nbr_adj_count(nbr, AF_INET) > 0) { + session_shutdown(nbr, S_DS_NONCMPLNCE, + lm->msgid, lm->type); + return; + } + break; + default: + fatalx("recv_hello: unknown af"); + } + } + + /* + * Protection against misconfigured networks and buggy + * implementations. + */ + if (af == nbr->af && + (ldp_addrcmp(af, &nbr->raddr, &trans_addr) || + nbr->raddr_scope != scope_id)) { + log_warnx("%s: lsr-id %s: ignoring hello packet " + "advertising different transport address", __func__, + inet_ntoa(lsr_id)); + return; } } @@ -208,7 +369,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *lm, struct in_addr src, if (holdtime == 0) holdtime = LINK_DFLT_HOLDTIME; - adj->holdtime = min(iface->hello_holdtime, holdtime); + adj->holdtime = min(ia->hello_holdtime, holdtime); break; case HELLO_TARGETED: if (holdtime == 0) @@ -247,13 +408,37 @@ gen_opt4_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint32_t value) memset(&parms, 0, sizeof(parms)); parms.type = htons(type); - parms.length = htons(4); + parms.length = htons(sizeof(parms.value)); parms.value = value; return (ibuf_add(buf, &parms, sizeof(parms))); } int +gen_opt16_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint8_t *value) +{ + struct hello_prms_opt16_tlv parms; + + memset(&parms, 0, sizeof(parms)); + parms.type = htons(type); + parms.length = htons(sizeof(parms.value)); + memcpy(&parms.value, value, sizeof(parms.value)); + + return (ibuf_add(buf, &parms, sizeof(parms))); +} + +int +gen_ds_hello_prms_tlv(struct ibuf *buf, uint32_t value) +{ + if (leconf->flags & F_LDPD_DS_CISCO_INTEROP) + value = htonl(value); + else + value = htonl(value << 28); + + return (gen_opt4_hello_prms_tlv(buf, TLV_TYPE_DUALSTACK, value)); +} + +int tlv_decode_hello_prms(char *buf, uint16_t len, uint16_t *holdtime, uint16_t *flags) { @@ -275,30 +460,78 @@ tlv_decode_hello_prms(char *buf, uint16_t len, uint16_t *holdtime, } int -tlv_decode_opt_hello_prms(char *buf, uint16_t len, struct in_addr *addr, - uint32_t *conf_number) +tlv_decode_opt_hello_prms(char *buf, uint16_t len, int *tlvs_rcvd, int af, + union ldpd_addr *addr, uint32_t *conf_number, uint16_t *trans_pref) { struct tlv tlv; uint16_t tlv_len; int total = 0; + *tlvs_rcvd = 0; memset(addr, 0, sizeof(*addr)); *conf_number = 0; - + *trans_pref = 0; + + /* + * RFC 7552 - Section 6.1: + * "An LSR SHOULD accept the Hello message that contains both IPv4 and + * IPv6 Transport Address optional objects but MUST use only the + * transport address whose address family is the same as that of the + * IP packet carrying the Hello message. An LSR SHOULD accept only + * the first Transport Address optional object for a given address + * family in the received Hello message and ignore the rest if the + * LSR receives more than one Transport Address optional object for a + * given address family". + */ while (len >= sizeof(tlv)) { memcpy(&tlv, buf, sizeof(tlv)); tlv_len = ntohs(tlv.length); switch (ntohs(tlv.type)) { case TLV_TYPE_IPV4TRANSADDR: - if (tlv_len != sizeof(uint32_t)) + if (tlv_len != sizeof(addr->v4)) + return (-1); + if (af != AF_INET || ldp_addrisset(AF_INET, addr)) + break; + memcpy(&addr->v4, buf + TLV_HDR_LEN, sizeof(addr->v4)); + *tlvs_rcvd |= F_HELLO_TLV_RCVD_ADDR; + break; + case TLV_TYPE_IPV6TRANSADDR: + if (tlv_len != sizeof(addr->v6)) return (-1); - memcpy(addr, buf + TLV_HDR_LEN, sizeof(uint32_t)); + if (af != AF_INET6 || ldp_addrisset(AF_INET6, addr)) + break; + memcpy(&addr->v6, buf + TLV_HDR_LEN, sizeof(addr->v6)); + *tlvs_rcvd |= F_HELLO_TLV_RCVD_ADDR; break; case TLV_TYPE_CONFIG: if (tlv_len != sizeof(uint32_t)) return (-1); memcpy(conf_number, buf + TLV_HDR_LEN, sizeof(uint32_t)); + *tlvs_rcvd |= F_HELLO_TLV_RCVD_CONF; + break; + case TLV_TYPE_DUALSTACK: + if (tlv_len != sizeof(uint32_t)) + return (-1); + /* + * RFC 7552 - Section 6.1: + * "A Single-stack LSR does not need to use the + * Dual-Stack capability in Hello messages and SHOULD + * ignore this capability if received". + */ + if (!ldp_is_dual_stack(leconf)) + break; + /* Shame on you, Cisco! */ + if (leconf->flags & F_LDPD_DS_CISCO_INTEROP) { + memcpy(trans_pref, buf + TLV_HDR_LEN + + sizeof(uint16_t), sizeof(uint16_t)); + *trans_pref = ntohs(*trans_pref); + } else { + memcpy(trans_pref, buf + TLV_HDR_LEN, + sizeof(uint16_t)); + *trans_pref = ntohs(*trans_pref) >> 12; + } + *tlvs_rcvd |= F_HELLO_TLV_RCVD_DS; break; default: /* if unknown flag set, ignore TLV */ diff --git a/usr.sbin/ldpd/init.c b/usr.sbin/ldpd/init.c index cad15769b03..4e162bc8788 100644 --- a/usr.sbin/ldpd/init.c +++ b/usr.sbin/ldpd/init.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init.c,v 1.24 2016/05/23 17:43:42 renato Exp $ */ +/* $OpenBSD: init.c,v 1.25 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -104,7 +104,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) return (-1); } - nbr->keepalive = min(nbr_get_keepalive(nbr->raddr), + nbr->keepalive = min(nbr_get_keepalive(nbr->af, nbr->id), ntohs(sess.keepalive_time)); max_pdu_len = ntohs(sess.max_pdu_len); @@ -131,7 +131,7 @@ gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr, uint16_t size) parms.type = htons(TLV_TYPE_COMMONSESSION); parms.length = htons(size - TLV_HDR_LEN); parms.proto_version = htons(LDP_VERSION); - parms.keepalive_time = htons(nbr_get_keepalive(nbr->raddr)); + parms.keepalive_time = htons(nbr_get_keepalive(nbr->af, nbr->id)); parms.reserved = 0; parms.pvlim = 0; parms.max_pdu_len = 0; diff --git a/usr.sbin/ldpd/interface.c b/usr.sbin/ldpd/interface.c index 22a5ea17f84..fcaefed8c15 100644 --- a/usr.sbin/ldpd/interface.c +++ b/usr.sbin/ldpd/interface.c @@ -1,4 +1,4 @@ -/* $OpenBSD: interface.c,v 1.40 2016/05/23 18:41:59 renato Exp $ */ +/* $OpenBSD: interface.c,v 1.41 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -42,8 +42,8 @@ extern struct ldpd_conf *leconf; void if_hello_timer(int, short, void *); -void if_start_hello_timer(struct iface *); -void if_stop_hello_timer(struct iface *); +void if_start_hello_timer(struct iface_af *); +void if_stop_hello_timer(struct iface_af *); struct iface * if_new(struct kif *kif) @@ -53,11 +53,6 @@ if_new(struct kif *kif) if ((iface = calloc(1, sizeof(*iface))) == NULL) fatal("if_new: calloc"); - iface->state = IF_STA_DOWN; - - LIST_INIT(&iface->addr_list); - LIST_INIT(&iface->adj_list); - strlcpy(iface->name, kif->ifname, sizeof(iface->name)); /* get type */ @@ -68,11 +63,26 @@ if_new(struct kif *kif) iface->type = IF_TYPE_BROADCAST; /* get index and flags */ + LIST_INIT(&iface->addr_list); iface->ifindex = kif->ifindex; iface->flags = kif->flags; iface->linkstate = kif->link_state; iface->if_type = kif->if_type; + /* ipv4 */ + iface->ipv4.af = AF_INET; + iface->ipv4.iface = iface; + iface->ipv4.enabled = 0; + iface->ipv4.state = IF_STA_DOWN; + LIST_INIT(&iface->ipv4.adj_list); + + /* ipv6 */ + iface->ipv6.af = AF_INET6; + iface->ipv6.iface = iface; + iface->ipv6.enabled = 0; + iface->ipv6.state = IF_STA_DOWN; + LIST_INIT(&iface->ipv6.adj_list); + return (iface); } @@ -81,11 +91,13 @@ if_del(struct iface *iface) { struct if_addr *if_addr; - if (iface->state == IF_STA_ACTIVE) - if_reset(iface); - log_debug("%s: interface %s", __func__, iface->name); + if (iface->ipv4.state == IF_STA_ACTIVE) + if_reset(iface, AF_INET); + if (iface->ipv6.state == IF_STA_ACTIVE) + if_reset(iface, AF_INET6); + while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) { LIST_REMOVE(if_addr, entry); free(if_addr); @@ -106,6 +118,19 @@ if_lookup(struct ldpd_conf *xconf, unsigned short ifindex) return (NULL); } +struct iface_af * +iface_af_get(struct iface *iface, int af) +{ + switch (af) { + case AF_INET: + return (&iface->ipv4); + case AF_INET6: + return (&iface->ipv6); + default: + fatalx("iface_af_get: unknown af"); + } +} + struct if_addr * if_addr_new(struct kaddr *ka) { @@ -114,8 +139,9 @@ if_addr_new(struct kaddr *ka) if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL) fatal(__func__); + if_addr->af = ka->af; if_addr->addr = ka->addr; - if_addr->mask = ka->mask; + if_addr->prefixlen = ka->prefixlen; if_addr->dstbrd = ka->dstbrd; return (if_addr); @@ -124,12 +150,13 @@ if_addr_new(struct kaddr *ka) struct if_addr * if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka) { - struct if_addr *if_addr; + struct if_addr *if_addr; + int af = ka->af; LIST_FOREACH(if_addr, addr_list, entry) - if (if_addr->addr.s_addr == ka->addr.s_addr && - if_addr->mask.s_addr == ka->mask.s_addr && - if_addr->dstbrd.s_addr == ka->dstbrd.s_addr) + if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) && + if_addr->prefixlen == ka->prefixlen && + !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd)) return (if_addr); return (NULL); @@ -149,17 +176,25 @@ if_addr_add(struct kaddr *ka) RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { if (nbr->state != NBR_STA_OPER) continue; + if (if_addr->af == AF_INET && !nbr->v4_enabled) + continue; + if (if_addr->af == AF_INET6 && !nbr->v6_enabled) + continue; - send_address(nbr, if_addr, 0); + send_address(nbr, if_addr->af, if_addr, 0); } } iface = if_lookup(leconf, ka->ifindex); - if (iface && - if_addr_lookup(&iface->addr_list, ka) == NULL) { - if_addr = if_addr_new(ka); - LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry); - if_update(iface); + if (iface) { + if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6)) + iface->linklocal = ka->addr.v6; + + if (if_addr_lookup(&iface->addr_list, ka) == NULL) { + if_addr = if_addr_new(ka); + LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry); + if_update(iface, if_addr->af); + } } } @@ -172,11 +207,15 @@ if_addr_del(struct kaddr *ka) iface = if_lookup(leconf, ka->ifindex); if (iface) { + if (ka->af == AF_INET6 && + IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6)) + memset(&iface->linklocal, 0, sizeof(iface->linklocal)); + if_addr = if_addr_lookup(&iface->addr_list, ka); if (if_addr) { LIST_REMOVE(if_addr, entry); + if_update(iface, if_addr->af); free(if_addr); - if_update(iface); } } @@ -185,7 +224,11 @@ if_addr_del(struct kaddr *ka) RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { if (nbr->state != NBR_STA_OPER) continue; - send_address(nbr, if_addr, 1); + if (if_addr->af == AF_INET && !nbr->v4_enabled) + continue; + if (if_addr->af == AF_INET6 && !nbr->v6_enabled) + continue; + send_address(nbr, if_addr->af, if_addr, 1); } LIST_REMOVE(if_addr, entry); free(if_addr); @@ -193,61 +236,100 @@ if_addr_del(struct kaddr *ka) } int -if_start(struct iface *iface) +if_start(struct iface *iface, int af) { - struct in_addr addr; + struct iface_af *ia; struct timeval now; - log_debug("%s: %s", __func__, iface->name); + log_debug("%s: %s address-family %s", __func__, iface->name, + af_name(af)); - gettimeofday(&now, NULL); - iface->uptime = now.tv_sec; + ia = iface_af_get(iface, af); - inet_aton(AllRouters, &addr); - if (if_join_group(iface, &addr)) - return (-1); + gettimeofday(&now, NULL); + ia->uptime = now.tv_sec; + + switch (af) { + case AF_INET: + if (if_join_ipv4_group(iface, &global.mcast_addr_v4)) + return (-1); + break; + case AF_INET6: + if (if_join_ipv6_group(iface, &global.mcast_addr_v6)) + return (-1); + break; + default: + fatalx("if_start: unknown af"); + } - send_hello(HELLO_LINK, iface, NULL); + send_hello(HELLO_LINK, ia, NULL); - evtimer_set(&iface->hello_timer, if_hello_timer, iface); - if_start_hello_timer(iface); + evtimer_set(&ia->hello_timer, if_hello_timer, ia); + if_start_hello_timer(ia); return (0); } int -if_reset(struct iface *iface) +if_reset(struct iface *iface, int af) { - struct in_addr addr; + struct iface_af *ia; struct adj *adj; - log_debug("%s: %s", __func__, iface->name); + log_debug("%s: %s address-family %s", __func__, iface->name, + af_name(af)); - while ((adj = LIST_FIRST(&iface->adj_list)) != NULL) - adj_del(adj); + ia = iface_af_get(iface, af); + if_stop_hello_timer(ia); - if_stop_hello_timer(iface); + while ((adj = LIST_FIRST(&ia->adj_list)) != NULL) + adj_del(adj); /* try to cleanup */ - if (global.ldp_disc_socket != -1) { - inet_aton(AllRouters, &addr); - if_leave_group(iface, &addr); + switch (af) { + case AF_INET: + if (global.ipv4.ldp_disc_socket != -1) + if_leave_ipv4_group(iface, &global.mcast_addr_v4); + break; + case AF_INET6: + if (global.ipv6.ldp_disc_socket != -1) + if_leave_ipv6_group(iface, &global.mcast_addr_v6); + break; + default: + fatalx("if_start: unknown af"); } return (0); } -int -if_update(struct iface *iface) +void +if_update_af(struct iface_af *ia, int link_ok) { - int link_ok, addr_ok = 0, socket_ok, rtr_id_ok; - int ret; - - link_ok = (iface->flags & IFF_UP) && - LINK_STATE_IS_UP(iface->linkstate); + int addr_ok = 0, socket_ok, rtr_id_ok; + struct if_addr *if_addr; - addr_ok = !LIST_EMPTY(&iface->addr_list); + switch (ia->af) { + case AF_INET: + /* + * NOTE: for LDPv4, each interface should have at least one + * valid IP address otherwise they can not be enabled. + */ + LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) { + if (if_addr->af == AF_INET) { + addr_ok = 1; + break; + } + } + break; + case AF_INET6: + /* for IPv6 the link-local address is enough. */ + if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal)) + addr_ok = 1; + break; + default: + fatalx("if_update_af: unknown af"); + } - if (global.ldp_disc_socket != -1) + if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1) socket_ok = 1; else socket_ok = 0; @@ -257,31 +339,43 @@ if_update(struct iface *iface) else rtr_id_ok = 0; - if (iface->state == IF_STA_DOWN) { - if (!link_ok || !addr_ok || !socket_ok || !rtr_id_ok) - return (0); - + if (ia->state == IF_STA_DOWN) { + if (!ia->enabled || !link_ok || !addr_ok || !socket_ok || + !rtr_id_ok) + return; - iface->state = IF_STA_ACTIVE; - ret = if_start(iface); - } else { - if (link_ok && addr_ok && socket_ok && rtr_id_ok) - return (0); + ia->state = IF_STA_ACTIVE; + if_start(ia->iface, ia->af); + } else if (ia->state == IF_STA_ACTIVE) { + if (ia->enabled && link_ok && addr_ok && socket_ok && rtr_id_ok) + return; - iface->state = IF_STA_DOWN; - ret = if_reset(iface); + ia->state = IF_STA_DOWN; + if_reset(ia->iface, ia->af); } +} - return (ret); +void +if_update(struct iface *iface, int af) +{ + int link_ok; + + link_ok = (iface->flags & IFF_UP) && + LINK_STATE_IS_UP(iface->linkstate); + + if (af == AF_INET || af == AF_UNSPEC) + if_update_af(&iface->ipv4, link_ok); + if (af == AF_INET6 || af == AF_UNSPEC) + if_update_af(&iface->ipv6, link_ok); } void -if_update_all(void) +if_update_all(int af) { struct iface *iface; LIST_FOREACH(iface, &leconf->iface_list, entry) - if_update(iface); + if_update(iface, af); } /* timers */ @@ -289,78 +383,89 @@ if_update_all(void) void if_hello_timer(int fd, short event, void *arg) { - struct iface *iface = arg; + struct iface_af *ia = arg; - send_hello(HELLO_LINK, iface, NULL); - if_start_hello_timer(iface); + send_hello(HELLO_LINK, ia, NULL); + if_start_hello_timer(ia); } void -if_start_hello_timer(struct iface *iface) +if_start_hello_timer(struct iface_af *ia) { struct timeval tv; timerclear(&tv); - tv.tv_sec = iface->hello_interval; - if (evtimer_add(&iface->hello_timer, &tv) == -1) + tv.tv_sec = ia->hello_interval; + if (evtimer_add(&ia->hello_timer, &tv) == -1) fatal(__func__); } void -if_stop_hello_timer(struct iface *iface) +if_stop_hello_timer(struct iface_af *ia) { - if (evtimer_pending(&iface->hello_timer, NULL) && - evtimer_del(&iface->hello_timer) == -1) + if (evtimer_pending(&ia->hello_timer, NULL) && + evtimer_del(&ia->hello_timer) == -1) fatal(__func__); } struct ctl_iface * -if_to_ctl(struct iface *iface) +if_to_ctl(struct iface_af *ia) { static struct ctl_iface ictl; struct timeval now; struct adj *adj; - memcpy(ictl.name, iface->name, sizeof(ictl.name)); - ictl.ifindex = iface->ifindex; - ictl.state = iface->state; - ictl.hello_holdtime = iface->hello_holdtime; - ictl.hello_interval = iface->hello_interval; - ictl.flags = iface->flags; - ictl.type = iface->type; - ictl.linkstate = iface->linkstate; - ictl.if_type = iface->if_type; + ictl.af = ia->af; + memcpy(ictl.name, ia->iface->name, sizeof(ictl.name)); + ictl.ifindex = ia->iface->ifindex; + ictl.state = ia->state; + ictl.flags = ia->iface->flags; + ictl.linkstate = ia->iface->linkstate; + ictl.type = ia->iface->type; + ictl.if_type = ia->iface->if_type; + ictl.hello_holdtime = ia->hello_holdtime; + ictl.hello_interval = ia->hello_interval; gettimeofday(&now, NULL); - if (iface->state != IF_STA_DOWN && - iface->uptime != 0) { - ictl.uptime = now.tv_sec - iface->uptime; + if (ia->state != IF_STA_DOWN && + ia->uptime != 0) { + ictl.uptime = now.tv_sec - ia->uptime; } else ictl.uptime = 0; ictl.adj_cnt = 0; - LIST_FOREACH(adj, &iface->adj_list, iface_entry) + LIST_FOREACH(adj, &ia->adj_list, ia_entry) ictl.adj_cnt++; return (&ictl); } -/* misc */ +/* multicast membership sockopts */ +in_addr_t +if_get_ipv4_addr(struct iface *iface) +{ + struct if_addr *if_addr; + + LIST_FOREACH(if_addr, &iface->addr_list, entry) + if (if_addr->af == AF_INET) + return (if_addr->addr.v4.s_addr); + + return (INADDR_ANY); +} + int -if_join_group(struct iface *iface, struct in_addr *addr) +if_join_ipv4_group(struct iface *iface, struct in_addr *addr) { struct ip_mreq mreq; - struct if_addr *if_addr; log_debug("%s: interface %s addr %s", __func__, iface->name, inet_ntoa(*addr)); - if_addr = LIST_FIRST(&iface->addr_list); mreq.imr_multiaddr = *addr; - mreq.imr_interface = if_addr->addr; + mreq.imr_interface.s_addr = if_get_ipv4_addr(iface); - if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (void *)&mreq, sizeof(mreq)) < 0) { + if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, + IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s", __func__, iface->name, inet_ntoa(*addr)); return (-1); @@ -369,23 +474,18 @@ if_join_group(struct iface *iface, struct in_addr *addr) } int -if_leave_group(struct iface *iface, struct in_addr *addr) +if_leave_ipv4_group(struct iface *iface, struct in_addr *addr) { struct ip_mreq mreq; - struct if_addr *if_addr; log_debug("%s: interface %s addr %s", __func__, iface->name, inet_ntoa(*addr)); - if_addr = LIST_FIRST(&iface->addr_list); - if (!if_addr) - return (0); - mreq.imr_multiaddr = *addr; - mreq.imr_interface = if_addr->addr; + mreq.imr_interface.s_addr = if_get_ipv4_addr(iface); - if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, - (void *)&mreq, sizeof(mreq)) < 0) { + if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, + IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s " "address %s", __func__, iface->name, inet_ntoa(*addr)); return (-1); @@ -393,3 +493,45 @@ if_leave_group(struct iface *iface, struct in_addr *addr) return (0); } + +int +if_join_ipv6_group(struct iface *iface, struct in6_addr *addr) +{ + struct ipv6_mreq mreq; + + log_debug("%s: interface %s addr %s", __func__, iface->name, + log_in6addr(addr)); + + mreq.ipv6mr_multiaddr = *addr; + mreq.ipv6mr_interface = iface->ifindex; + + if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6, + IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { + log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s", + __func__, iface->name, log_in6addr(addr)); + return (-1); + } + + return (0); +} + +int +if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr) +{ + struct ipv6_mreq mreq; + + log_debug("%s: interface %s addr %s", __func__, iface->name, + log_in6addr(addr)); + + mreq.ipv6mr_multiaddr = *addr; + mreq.ipv6mr_interface = iface->ifindex; + + if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6, + IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) { + log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s", + __func__, iface->name, log_in6addr(addr)); + return (-1); + } + + return (0); +} diff --git a/usr.sbin/ldpd/kroute.c b/usr.sbin/ldpd/kroute.c index e765ea0be14..bf4adb43415 100644 --- a/usr.sbin/ldpd/kroute.c +++ b/usr.sbin/ldpd/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.56 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: kroute.c,v 1.57 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -67,7 +67,8 @@ struct kroute_priority { struct kroute_prefix { RB_ENTRY(kroute_prefix) entry; - struct in_addr prefix; + int af; + union ldpd_addr prefix; uint8_t prefixlen; TAILQ_HEAD(plist, kroute_priority) priorities; }; @@ -84,15 +85,17 @@ struct kif_node { struct kpw *kpw; }; -void kr_redist_remove(struct kroute *); -int kr_redist_eval(struct kroute *); -void kr_redistribute(struct kroute_prefix *); -int kroute_compare(struct kroute_prefix *, struct kroute_prefix *); +void kr_redist_remove(struct kroute *); +int kr_redist_eval(struct kroute *); +void kr_redistribute(struct kroute_prefix *); +int kroute_compare(struct kroute_prefix *, + struct kroute_prefix *); + +struct kroute_prefix *kroute_find_prefix(int, union ldpd_addr *, uint8_t); +struct kroute_priority *kroute_find_prio(struct kroute_prefix *, uint8_t); +struct kroute_node *kroute_find_gw(struct kroute_priority *, + union ldpd_addr *); -struct kroute_prefix *kroute_find(in_addr_t, uint8_t); -struct kroute_priority *kroute_find_prio(in_addr_t, uint8_t, uint8_t); -struct kroute_node *kroute_find_gw(in_addr_t, uint8_t, uint8_t, - struct in_addr); int kroute_insert(struct kroute *); int kroute_uninstall(struct kroute_node *); int kroute_remove(struct kroute *); @@ -105,23 +108,27 @@ int kif_remove(struct kif_node *); struct kif_node *kif_update(unsigned short, int, struct if_data *, struct sockaddr_dl *, int *); -struct kroute_priority *kroute_match(in_addr_t); +struct kroute_priority *kroute_match(int, union ldpd_addr *); uint8_t prefixlen_classful(in_addr_t); void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); void if_change(unsigned short, int, struct if_data *, struct sockaddr_dl *); -void if_newaddr(unsigned short, struct sockaddr_in *, - struct sockaddr_in *, struct sockaddr_in *); -void if_deladdr(unsigned short, struct sockaddr_in *, - struct sockaddr_in *, struct sockaddr_in *); +void if_newaddr(unsigned short, struct sockaddr *, struct sockaddr *, + struct sockaddr *); +void if_deladdr(unsigned short, struct sockaddr *, struct sockaddr *, + struct sockaddr *); void if_announce(void *); -int send_rtmsg(int, int, struct kroute *, uint32_t); +int send_rtmsg(int, int, struct kroute *, int); +int send_rtmsg_v4(int, int, struct kroute *, int); +int send_rtmsg_v6(int, int, struct kroute *, int); int dispatch_rtmsg(void); int fetchtable(void); int fetchifs(void); int rtmsg_process(char *, size_t); +int rtmsg_process_route(struct rt_msghdr *, + struct sockaddr *[RTAX_MAX]); RB_HEAD(kroute_tree, kroute_prefix) krt = RB_INITIALIZER(&krt); RB_PROTOTYPE(kroute_tree, kroute_prefix, entry, kroute_compare) @@ -219,55 +226,72 @@ kif_redistribute(const char *ifname) } int -kr_change(struct kroute *kroute) +kr_change(struct kroute *kr) { + struct kroute_prefix *kp; + struct kroute_priority *kprio; struct kroute_node *kn; int action = RTM_ADD; - char buf[16]; - kn = kroute_find_gw(kroute->prefix.s_addr, kroute->prefixlen, - RTP_ANY, kroute->nexthop); - if (kn == NULL) { - log_warnx("%s: lost FEC %s/%d nexthop %s", __func__, - inet_ntoa(kroute->prefix), kroute->prefixlen, - inet_ntop(AF_INET, &kroute->nexthop, buf, sizeof(buf))); - return (-1); - } + kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen); + if (kp == NULL) + goto miss; + + kprio = kroute_find_prio(kp, RTP_ANY); + if (kprio == NULL) + goto miss; + + kn = kroute_find_gw(kprio, &kr->nexthop); + if (kn == NULL) + goto miss; if (kn->r.flags & F_LDPD_INSERTED) action = RTM_CHANGE; - kn->r.local_label = kroute->local_label; - kn->r.remote_label = kroute->remote_label; + kn->r.local_label = kr->local_label; + kn->r.remote_label = kr->remote_label; kn->r.flags = kn->r.flags | F_LDPD_INSERTED; /* send update */ if (send_rtmsg(kr_state.fd, action, &kn->r, AF_MPLS) == -1) return (-1); - if (kn->r.nexthop.s_addr != INADDR_ANY && + if (ldp_addrisset(kn->r.af, &kn->r.nexthop) && kn->r.remote_label != NO_LABEL) { if (send_rtmsg(kr_state.fd, RTM_CHANGE, &kn->r, AF_INET) == -1) return (-1); } return (0); + +miss: + log_warnx("%s: lost FEC %s/%d nexthop %s", __func__, + log_addr(kr->af, &kr->prefix), kr->prefixlen, + log_addr(kr->af, &kr->nexthop)); + return (-1); } int -kr_delete(struct kroute *kroute) +kr_delete(struct kroute *kr) { + struct kroute_prefix *kp; + struct kroute_priority *kprio; struct kroute_node *kn; int update = 0; - kn = kroute_find_gw(kroute->prefix.s_addr, kroute->prefixlen, - RTP_ANY, kroute->nexthop); + kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen); + if (kp == NULL) + return (0); + kprio = kroute_find_prio(kp, RTP_ANY); + if (kprio == NULL) + return (0); + kn = kroute_find_gw(kprio, &kr->nexthop); if (kn == NULL) return (0); if (!(kn->r.flags & F_LDPD_INSERTED)) return (0); - if (kn->r.nexthop.s_addr != INADDR_ANY && + if (ldp_addrisset(kn->r.af, &kn->r.nexthop) && kn->r.remote_label != NO_LABEL) update = 1; @@ -318,7 +342,7 @@ kr_fib_couple(void) send_rtmsg(kr_state.fd, RTM_ADD, &kn->r, AF_MPLS); - if (kn->r.nexthop.s_addr != INADDR_ANY && + if (ldp_addrisset(kn->r.af, &kn->r.nexthop) && kn->r.remote_label != NO_LABEL) { send_rtmsg(kr_state.fd, RTM_CHANGE, &kn->r, AF_INET); @@ -357,7 +381,7 @@ kr_fib_decouple(void) send_rtmsg(kr_state.fd, RTM_DELETE, &kn->r, AF_MPLS); - if (kn->r.nexthop.s_addr != INADDR_ANY && + if (ldp_addrisset(kn->r.af, &kn->r.nexthop) && kn->r.remote_label != NO_LABEL) { rl = kn->r.remote_label; kn->r.remote_label = NO_LABEL; @@ -377,22 +401,36 @@ kr_fib_decouple(void) } void -kr_change_egress_label(int was_implicit) +kr_change_egress_label(int af, int was_implicit) { struct kroute_prefix *kp; struct kroute_priority *kprio; struct kroute_node *kn; RB_FOREACH(kp, kroute_tree, &krt) { + if (kp->af != af) + continue; + TAILQ_FOREACH(kprio, &kp->priorities, entry) { TAILQ_FOREACH(kn, &kprio->nexthops, entry) { if (kn->r.local_label > MPLS_LABEL_RESERVED_MAX) continue; - if (!was_implicit) + if (!was_implicit) { kn->r.local_label = MPLS_LABEL_IMPLNULL; - else + continue; + } + + switch (kn->r.af) { + case AF_INET: kn->r.local_label = MPLS_LABEL_IPV4NULL; + break; + case AF_INET6: + kn->r.local_label = MPLS_LABEL_IPV6NULL; + break; + default: + break; + } } } } @@ -413,7 +451,7 @@ kr_show_route(struct imsg *imsg) struct kroute_priority *kprio; struct kroute_node *kn; int flags; - struct in_addr addr; + struct kroute kr; switch (imsg->hdr.type) { case IMSG_CTL_KROUTE: @@ -426,22 +464,25 @@ kr_show_route(struct imsg *imsg) RB_FOREACH(kp, kroute_tree, &krt) TAILQ_FOREACH(kprio, &kp->priorities, entry) TAILQ_FOREACH(kn, &kprio->nexthops, entry) { - if (!flags || kn->r.flags & flags) - main_imsg_compose_ldpe( - IMSG_CTL_KROUTE, - imsg->hdr.pid, - &kn->r, sizeof(kn->r)); + if (flags && !(kn->r.flags & flags)) + continue; + + main_imsg_compose_ldpe(IMSG_CTL_KROUTE, + imsg->hdr.pid, &kn->r, + sizeof(kn->r)); } break; case IMSG_CTL_KROUTE_ADDR: - if (imsg->hdr.len != IMSG_HEADER_SIZE + - sizeof(struct in_addr)) { + if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) { log_warnx("%s: wrong imsg len", __func__); return; } - memcpy(&addr, imsg->data, sizeof(addr)); + memcpy(&kr, imsg->data, sizeof(kr)); + + kprio = kroute_match(kr.af, &kr.prefix); + if (kprio == NULL) + break; - kprio = kroute_match(addr.s_addr); TAILQ_FOREACH(kn, &kprio->nexthops, entry) main_imsg_compose_ldpe(IMSG_CTL_KROUTE, imsg->hdr.pid, &kn->r, sizeof(kn->r)); @@ -482,8 +523,6 @@ kr_redist_remove(struct kroute *kr) int kr_redist_eval(struct kroute *kr) { - uint32_t a; - /* was the route redistributed? */ if (kr->flags & F_REDISTRIBUTED) goto dont_redistribute; @@ -492,22 +531,34 @@ kr_redist_eval(struct kroute *kr) if (kr->flags & F_DYNAMIC) goto dont_redistribute; - /* - * We consider the loopback net, default route, multicast and - * experimental addresses as not redistributable. - */ - a = ntohl(kr->prefix.s_addr); - if (IN_MULTICAST(a) || IN_BADCLASS(a) || - (kr->prefixlen == 0) || - (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) + /* filter-out non-redistributable addresses */ + if (bad_addr(kr->af, &kr->prefix) || + (kr->af == AF_INET6 && IN6_IS_SCOPE_EMBED(&kr->prefix.v6))) + goto dont_redistribute; + + /* do not redistribute the default route */ + if (kr->prefixlen == 0) goto dont_redistribute; + /* * Consider networks with nexthop loopback as not redistributable * unless it is a reject or blackhole route. */ - if (kr->nexthop.s_addr == htonl(INADDR_LOOPBACK) && - !(kr->flags & (F_BLACKHOLE|F_REJECT))) - goto dont_redistribute; + switch (kr->af) { + case AF_INET: + if (kr->nexthop.v4.s_addr == htonl(INADDR_LOOPBACK) && + !(kr->flags & (F_BLACKHOLE|F_REJECT))) + goto dont_redistribute; + break; + case AF_INET6: + if (IN6_IS_ADDR_LOOPBACK(&kr->nexthop.v6) && + !(kr->flags & (F_BLACKHOLE|F_REJECT))) + goto dont_redistribute; + break; + default: + log_debug("%s: unexpected address-family", __func__); + break; + } /* prefix should be redistributed */ kr->flags |= F_REDISTRIBUTED; @@ -539,10 +590,17 @@ kr_redistribute(struct kroute_prefix *kp) int kroute_compare(struct kroute_prefix *a, struct kroute_prefix *b) { - if (ntohl(a->prefix.s_addr) < ntohl(b->prefix.s_addr)) + int addrcmp; + + if (a->af < b->af) return (-1); - if (ntohl(a->prefix.s_addr) > ntohl(b->prefix.s_addr)) + if (a->af > b->af) return (1); + + addrcmp = ldp_addrcmp(a->af, &a->prefix, &b->prefix); + if (addrcmp != 0) + return (addrcmp); + if (a->prefixlen < b->prefixlen) return (-1); if (a->prefixlen > b->prefixlen) @@ -553,25 +611,22 @@ kroute_compare(struct kroute_prefix *a, struct kroute_prefix *b) /* tree management */ struct kroute_prefix * -kroute_find(in_addr_t prefix, uint8_t prefixlen) +kroute_find_prefix(int af, union ldpd_addr *prefix, uint8_t prefixlen) { struct kroute_prefix s; - s.prefix.s_addr = prefix; + s.af = af; + s.prefix = *prefix; s.prefixlen = prefixlen; return (RB_FIND(kroute_tree, &krt, &s)); } struct kroute_priority * -kroute_find_prio(in_addr_t prefix, uint8_t prefixlen, uint8_t prio) +kroute_find_prio(struct kroute_prefix *kp, uint8_t prio) { - struct kroute_prefix *kp; struct kroute_priority *kprio; - if ((kp = kroute_find(prefix, prefixlen)) == NULL) - return (NULL); - /* RTP_ANY here picks the lowest priority node */ if (prio == RTP_ANY) return (TAILQ_FIRST(&kp->priorities)); @@ -584,17 +639,12 @@ kroute_find_prio(in_addr_t prefix, uint8_t prefixlen, uint8_t prio) } struct kroute_node * -kroute_find_gw(in_addr_t prefix, uint8_t prefixlen, uint8_t prio, - struct in_addr nh) +kroute_find_gw(struct kroute_priority *kprio, union ldpd_addr *nh) { - struct kroute_priority *kprio; struct kroute_node *kn; - if ((kprio = kroute_find_prio(prefix, prefixlen, prio)) == NULL) - return (NULL); - TAILQ_FOREACH(kn, &kprio->nexthops, entry) - if (kn->r.nexthop.s_addr == nh.s_addr) + if (ldp_addrcmp(kprio->kp->af, &kn->r.nexthop, nh) == 0) return (kn); return (NULL); @@ -604,24 +654,24 @@ int kroute_insert(struct kroute *kr) { struct kroute_prefix *kp; - struct kroute_priority *kprio, *tmp = NULL; + struct kroute_priority *kprio, *tmp; struct kroute_node *kn; - kp = kroute_find(kr->prefix.s_addr, kr->prefixlen); + kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen); if (kp == NULL) { - kp = calloc(1, sizeof(struct kroute_prefix)); + kp = calloc(1, sizeof((*kp))); if (kp == NULL) fatal(__func__); + kp->af = kr->af; kp->prefix = kr->prefix; kp->prefixlen = kr->prefixlen; TAILQ_INIT(&kp->priorities); RB_INSERT(kroute_tree, &krt, kp); } - kprio = kroute_find_prio(kr->prefix.s_addr, kr->prefixlen, - kr->priority); + kprio = kroute_find_prio(kp, kr->priority); if (kprio == NULL) { - kprio = calloc(1, sizeof(struct kroute_priority)); + kprio = calloc(1, sizeof(*kprio)); if (kprio == NULL) fatal(__func__); kprio->kp = kp; @@ -629,20 +679,18 @@ kroute_insert(struct kroute *kr) TAILQ_INIT(&kprio->nexthops); /* lower priorities first */ - TAILQ_FOREACH(tmp, &kp->priorities, entry) { - if (tmp->priority > kr->priority) { - TAILQ_INSERT_BEFORE(tmp, kprio, entry); - goto done; - } - } - TAILQ_INSERT_TAIL(&kp->priorities, kprio, entry); + TAILQ_FOREACH(tmp, &kp->priorities, entry) + if (tmp->priority > kprio->priority) + break; + if (tmp) + TAILQ_INSERT_BEFORE(tmp, kprio, entry); + else + TAILQ_INSERT_TAIL(&kp->priorities, kprio, entry); } -done: - kn = kroute_find_gw(kr->prefix.s_addr, kr->prefixlen, kr->priority, - kr->nexthop); + kn = kroute_find_gw(kprio, &kr->nexthop); if (kn == NULL) { - kn = calloc(1, sizeof(struct kroute_node)); + kn = calloc(1, sizeof(*kn)); if (kn == NULL) fatal(__func__); kn->kprio = kprio; @@ -673,15 +721,15 @@ kroute_remove(struct kroute *kr) struct kroute_priority *kprio; struct kroute_node *kn; - kn = kroute_find_gw(kr->prefix.s_addr, kr->prefixlen, kr->priority, - kr->nexthop); - if (kn == NULL) { - log_warnx("%s failed to find %s/%u", __func__, - inet_ntoa(kr->prefix), kr->prefixlen); - return (-1); - } - kprio = kn->kprio; - kp = kprio->kp; + kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen); + if (kp == NULL) + goto notfound; + kprio = kroute_find_prio(kp, kr->priority); + if (kprio == NULL) + goto notfound; + kn = kroute_find_gw(kprio, &kr->nexthop); + if (kn == NULL) + goto notfound; kr_redist_remove(&kn->r); kroute_uninstall(kn); @@ -697,7 +745,7 @@ kroute_remove(struct kroute *kr) if (TAILQ_EMPTY(&kp->priorities)) { if (RB_REMOVE(kroute_tree, &krt, kp) == NULL) { log_warnx("%s failed for %s/%u", __func__, - inet_ntoa(kp->prefix), kp->prefixlen); + log_addr(kr->af, &kr->prefix), kp->prefixlen); return (-1); } free(kp); @@ -705,6 +753,11 @@ kroute_remove(struct kroute *kr) kr_redistribute(kp); return (0); + +notfound: + log_warnx("%s failed to find %s/%u", __func__, + log_addr(kr->af, &kr->prefix), kr->prefixlen); + return (-1); } void @@ -838,20 +891,36 @@ kif_update(unsigned short ifindex, int flags, struct if_data *ifd, } struct kroute_priority * -kroute_match(in_addr_t key) +kroute_match(int af, union ldpd_addr *key) { - int i; + int i, maxprefixlen; + struct kroute_prefix *kp; struct kroute_priority *kprio; + union ldpd_addr addr; - /* we will never match the default route */ - for (i = 32; i > 0; i--) - if ((kprio = kroute_find_prio(key & prefixlen2mask(i), i, - RTP_ANY)) != NULL) - return (kprio); + switch (af) { + case AF_INET: + maxprefixlen = 32; + break; + case AF_INET6: + maxprefixlen = 128; + break; + default: + log_warnx("%s: unknown af", __func__); + return (NULL); + } + + for (i = maxprefixlen; i >= 0; i--) { + ldp_applymask(af, &addr, key, i); + + kp = kroute_find_prefix(af, &addr, i); + if (kp == NULL) + continue; - /* if we don't have a match yet, try to find a default route */ - if ((kprio = kroute_find_prio(0, 0, RTP_ANY)) != NULL) - return (kprio); + kprio = kroute_find_prio(kp, RTP_ANY); + if (kprio != NULL) + return (kprio); + } return (NULL); } @@ -924,38 +993,66 @@ if_change(unsigned short ifindex, int flags, struct if_data *ifd, } void -if_newaddr(unsigned short ifindex, struct sockaddr_in *ifa, - struct sockaddr_in *mask, struct sockaddr_in *brd) +if_newaddr(unsigned short ifindex, struct sockaddr *ifa, struct sockaddr *mask, + struct sockaddr *brd) { - struct kif_node *kif; - struct kif_addr *ka; - uint32_t a; + struct kif_node *kif; + struct sockaddr_in *ifa4, *mask4, *brd4; + struct sockaddr_in6 *ifa6, *mask6, *brd6; + struct kif_addr *ka; - if (ifa == NULL || ifa->sin_family != AF_INET) + if (ifa == NULL) return; if ((kif = kif_find(ifindex)) == NULL) { log_warnx("%s: corresponding if %d not found", __func__, ifindex); return; } - a = ntohl(ifa->sin_addr.s_addr); - if (IN_MULTICAST(a) || IN_BADCLASS(a) || - (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) + + switch (ifa->sa_family) { + case AF_INET: + ifa4 = (struct sockaddr_in *) ifa; + mask4 = (struct sockaddr_in *) mask; + brd4 = (struct sockaddr_in *) brd; + + /* filter out unwanted addresses */ + if (bad_addr_v4(ifa4->sin_addr)) + return; + + if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL) + fatal("if_newaddr"); + ka->a.addr.v4 = ifa4->sin_addr; + if (mask4) + ka->a.prefixlen = + mask2prefixlen(mask4->sin_addr.s_addr); + if (brd4) + ka->a.dstbrd.v4 = brd4->sin_addr; + break; + case AF_INET6: + ifa6 = (struct sockaddr_in6 *) ifa; + mask6 = (struct sockaddr_in6 *) mask; + brd6 = (struct sockaddr_in6 *) brd; + + /* We only care about link-local and global-scope. */ + if (bad_addr_v6(&ifa6->sin6_addr)) + return; + + clearscope(&ifa6->sin6_addr); + + if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL) + fatal("if_newaddr"); + ka->a.addr.v6 = ifa6->sin6_addr; + if (mask6) + ka->a.prefixlen = mask2prefixlen6(mask6); + if (brd6) + ka->a.dstbrd.v6 = brd6->sin6_addr; + break; + default: return; + } - if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL) - fatal(__func__); ka->a.ifindex = ifindex; - ka->a.addr = ifa->sin_addr; - if (mask) - ka->a.mask = mask->sin_addr; - else - ka->a.mask.s_addr = INADDR_NONE; - if (brd) - ka->a.dstbrd = brd->sin_addr; - else - ka->a.dstbrd.s_addr = INADDR_NONE; - + ka->a.af = ifa->sa_family; TAILQ_INSERT_TAIL(&kif->addrs, ka, entry); /* notify ldpe about new address */ @@ -963,13 +1060,16 @@ if_newaddr(unsigned short ifindex, struct sockaddr_in *ifa, } void -if_deladdr(unsigned short ifindex, struct sockaddr_in *ifa, - struct sockaddr_in *mask, struct sockaddr_in *brd) +if_deladdr(unsigned short ifindex, struct sockaddr *ifa, struct sockaddr *mask, + struct sockaddr *brd) { - struct kif_node *kif; - struct kif_addr *ka, *nka; + struct kif_node *kif; + struct sockaddr_in *ifa4, *mask4, *brd4; + struct sockaddr_in6 *ifa6, *mask6, *brd6; + struct kaddr k; + struct kif_addr *ka, *nka; - if (ifa == NULL || ifa->sin_family != AF_INET) + if (ifa == NULL) return; if ((kif = kif_find(ifindex)) == NULL) { log_warnx("%s: corresponding if %d not found", __func__, @@ -977,10 +1077,51 @@ if_deladdr(unsigned short ifindex, struct sockaddr_in *ifa, return; } + memset(&k, 0, sizeof(k)); + k.af = ifa->sa_family; + switch (ifa->sa_family) { + case AF_INET: + ifa4 = (struct sockaddr_in *) ifa; + mask4 = (struct sockaddr_in *) mask; + brd4 = (struct sockaddr_in *) brd; + + /* filter out unwanted addresses */ + if (bad_addr_v4(ifa4->sin_addr)) + return; + + k.addr.v4 = ifa4->sin_addr; + if (mask4) + k.prefixlen = mask2prefixlen(mask4->sin_addr.s_addr); + if (brd4) + k.dstbrd.v4 = brd4->sin_addr; + break; + case AF_INET6: + ifa6 = (struct sockaddr_in6 *) ifa; + mask6 = (struct sockaddr_in6 *) mask; + brd6 = (struct sockaddr_in6 *) brd; + + /* We only care about link-local and global-scope. */ + if (bad_addr_v6(&ifa6->sin6_addr)) + return; + + clearscope(&ifa6->sin6_addr); + + k.addr.v6 = ifa6->sin6_addr; + if (mask6) + k.prefixlen = mask2prefixlen6(mask6); + if (brd6) + k.dstbrd.v6 = brd6->sin6_addr; + break; + default: + return; + } + for (ka = TAILQ_FIRST(&kif->addrs); ka != NULL; ka = nka) { nka = TAILQ_NEXT(ka, entry); - if (ka->a.addr.s_addr != ifa->sin_addr.s_addr) + if (ka->a.af != k.af || + ka->a.prefixlen != k.prefixlen || + ldp_addrcmp(ka->a.af, &ka->a.addr, &k.addr)) continue; /* notify ldpe about removed address */ @@ -1016,7 +1157,20 @@ if_announce(void *msg) /* rtsock */ int -send_rtmsg(int fd, int action, struct kroute *kr, uint32_t family) +send_rtmsg(int fd, int action, struct kroute *kr, int family) +{ + switch (kr->af) { + case AF_INET: + return (send_rtmsg_v4(fd, action, kr, family)); + case AF_INET6: + return (send_rtmsg_v6(fd, action, kr, family)); + default: + fatalx("send_rtmsg: unknown af"); + } +} + +int +send_rtmsg_v4(int fd, int action, struct kroute *kr, int family) { struct iovec iov[5]; struct rt_msghdr hdr; @@ -1066,7 +1220,7 @@ send_rtmsg(int fd, int action, struct kroute *kr, uint32_t family) memset(&dst, 0, sizeof(dst)); dst.sin_len = sizeof(dst); dst.sin_family = AF_INET; - dst.sin_addr = kr->prefix; + dst.sin_addr = kr->prefix.v4; /* adjust header */ hdr.rtm_addrs |= RTA_DST; hdr.rtm_msglen += sizeof(dst); @@ -1078,7 +1232,7 @@ send_rtmsg(int fd, int action, struct kroute *kr, uint32_t family) memset(&nexthop, 0, sizeof(nexthop)); nexthop.sin_len = sizeof(nexthop); nexthop.sin_family = AF_INET; - nexthop.sin_addr = kr->nexthop; + nexthop.sin_addr = kr->nexthop.v4; /* adjust header */ hdr.rtm_flags |= RTF_GATEWAY; hdr.rtm_addrs |= RTA_GATEWAY; @@ -1136,12 +1290,13 @@ retry: goto retry; } else if (hdr.rtm_type == RTM_DELETE) { log_info("route %s/%u vanished before delete", - inet_ntoa(kr->prefix), kr->prefixlen); + inet_ntoa(kr->prefix.v4), kr->prefixlen); return (-1); } } - log_warn("%s action %u, AF %d, prefix %s/%u", __func__, - hdr.rtm_type, family, inet_ntoa(kr->prefix), kr->prefixlen); + log_warn("%s action %u, af %s, prefix %s/%u", __func__, + hdr.rtm_type, af_name(family), inet_ntoa(kr->prefix.v4), + kr->prefixlen); return (-1); } @@ -1149,6 +1304,12 @@ retry: } int +send_rtmsg_v6(int fd, int action, struct kroute *kr, int family) +{ + return (0); +} + +int fetchtable(void) { size_t len; @@ -1159,7 +1320,7 @@ fetchtable(void) mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; - mib[3] = AF_INET; + mib[3] = 0; mib[4] = NET_RT_DUMP; mib[5] = 0; mib[6] = 0; /* rtableid */ @@ -1195,7 +1356,7 @@ fetchifs(void) mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; - mib[3] = AF_INET; + mib[3] = 0; /* wildcard */ mib[4] = NET_RT_IFLIST; mib[5] = 0; @@ -1247,14 +1408,6 @@ rtmsg_process(char *buf, size_t len) struct if_msghdr ifm; struct ifa_msghdr *ifam; struct sockaddr *sa, *rti_info[RTAX_MAX]; - struct sockaddr_in *sa_in; - struct kroute_priority *kprio; - struct kroute_node *kn; - struct kroute kr; - struct in_addr prefix, nexthop; - uint8_t prefixlen, prio; - int flags; - unsigned short ifindex = 0; size_t offset; char *next; @@ -1268,12 +1421,6 @@ rtmsg_process(char *buf, size_t len) continue; log_rtmsg(rtm->rtm_type); - prefix.s_addr = 0; - prefixlen = 0; - nexthop.s_addr = 0; - prio = 0; - flags = 0; - sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); @@ -1292,9 +1439,6 @@ rtmsg_process(char *buf, size_t len) rtm->rtm_pid != kr_state.pid) continue; - if ((sa = rti_info[RTAX_DST]) == NULL) - continue; - /* Skip ARP/ND cache and broadcast routes. */ if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST)) continue; @@ -1302,118 +1446,12 @@ rtmsg_process(char *buf, size_t len) /* LDP should follow the IGP and ignore BGP routes */ if (rtm->rtm_priority == RTP_BGP) continue; - prio = rtm->rtm_priority; - - switch (sa->sa_family) { - case AF_INET: - prefix = ((struct sockaddr_in *)sa)->sin_addr; - sa_in = (struct sockaddr_in *) - rti_info[RTAX_NETMASK]; - if (sa_in != NULL) { - if (sa_in->sin_len != 0) - prefixlen = mask2prefixlen( - sa_in->sin_addr.s_addr); - } else if (rtm->rtm_flags & RTF_HOST) - prefixlen = 32; - else - prefixlen = - prefixlen_classful(prefix.s_addr); - if (rtm->rtm_flags & RTF_STATIC) - flags |= F_STATIC; - if (rtm->rtm_flags & RTF_BLACKHOLE) - flags |= F_BLACKHOLE; - if (rtm->rtm_flags & RTF_REJECT) - flags |= F_REJECT; - if (rtm->rtm_flags & RTF_DYNAMIC) - flags |= F_DYNAMIC; - break; - default: - continue; - } - - ifindex = rtm->rtm_index; - if ((sa = rti_info[RTAX_GATEWAY]) != NULL) { - switch (sa->sa_family) { - case AF_INET: - if (rtm->rtm_flags & RTF_CONNECTED) { - flags |= F_CONNECTED; - break; - } - nexthop = ((struct - sockaddr_in *)sa)->sin_addr; - break; - case AF_LINK: - /* - * Traditional BSD connected routes have - * a gateway of type AF_LINK. - */ - flags |= F_CONNECTED; - break; - } - } - } - switch (rtm->rtm_type) { - case RTM_CHANGE: - /* - * The kernel doesn't allow RTM_CHANGE for multipath - * routes. If we got this message we know that the - * route has only one nexthop and we should remove - * it before installing the same route with a new - * nexthop. - */ - if ((kprio = kroute_find_prio(prefix.s_addr, - prefixlen, prio)) == NULL) { - log_warnx("%s: route not found", __func__); - return (-1); - } - kn = TAILQ_FIRST(&kprio->nexthops); - if (kn && kroute_remove(&kn->r) == -1) + if (rtmsg_process_route(rtm, rti_info) == -1) return (-1); - break; - default: - break; } switch (rtm->rtm_type) { - case RTM_ADD: - case RTM_GET: - case RTM_CHANGE: - if (nexthop.s_addr == 0 && !(flags & F_CONNECTED)) { - log_warnx("no nexthop for %s/%u", - inet_ntoa(prefix), prefixlen); - continue; - } - - /* routes attached to loopback interfaces */ - if (prefix.s_addr == nexthop.s_addr) - flags |= F_CONNECTED; - - if (kroute_find_gw(prefix.s_addr, prefixlen, prio, - nexthop) != NULL) - break; - - memset(&kr, 0, sizeof(kr)); - kr.prefix = prefix; - kr.prefixlen = prefixlen; - kr.nexthop = nexthop; - kr.flags = flags; - kr.ifindex = ifindex; - kr.priority = prio; - kr.local_label = NO_LABEL; - kr.remote_label = NO_LABEL; - kroute_insert(&kr); - break; - case RTM_DELETE: - /* get the correct route */ - if ((kn = kroute_find_gw(prefix.s_addr, prefixlen, - prio, nexthop)) == NULL) { - log_warnx("%s: route not found", __func__); - return (-1); - } - if (kroute_remove(&kn->r) == -1) - return (-1); - break; case RTM_IFINFO: memcpy(&ifm, next, sizeof(ifm)); if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data, @@ -1426,9 +1464,9 @@ rtmsg_process(char *buf, size_t len) break; if_newaddr(ifam->ifam_index, - (struct sockaddr_in *)rti_info[RTAX_IFA], - (struct sockaddr_in *)rti_info[RTAX_NETMASK], - (struct sockaddr_in *)rti_info[RTAX_BRD]); + (struct sockaddr *)rti_info[RTAX_IFA], + (struct sockaddr *)rti_info[RTAX_NETMASK], + (struct sockaddr *)rti_info[RTAX_BRD]); break; case RTM_DELADDR: ifam = (struct ifa_msghdr *)rtm; @@ -1437,9 +1475,9 @@ rtmsg_process(char *buf, size_t len) break; if_deladdr(ifam->ifam_index, - (struct sockaddr_in *)rti_info[RTAX_IFA], - (struct sockaddr_in *)rti_info[RTAX_NETMASK], - (struct sockaddr_in *)rti_info[RTAX_BRD]); + (struct sockaddr *)rti_info[RTAX_IFA], + (struct sockaddr *)rti_info[RTAX_NETMASK], + (struct sockaddr *)rti_info[RTAX_BRD]); break; case RTM_IFANNOUNCE: if_announce(next); @@ -1454,6 +1492,134 @@ rtmsg_process(char *buf, size_t len) } int +rtmsg_process_route(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX]) +{ + struct sockaddr *sa; + struct sockaddr_in *sa_in; + struct sockaddr_in6 *sa_in6; + struct kroute kr; + struct kroute_prefix *kp; + struct kroute_priority *kprio; + struct kroute_node *kn; + + if ((sa = rti_info[RTAX_DST]) == NULL) + return (-1); + + memset(&kr, 0, sizeof(kr)); + kr.af = sa->sa_family; + switch (kr.af) { + case AF_INET: + kr.prefix.v4 = ((struct sockaddr_in *)sa)->sin_addr; + sa_in = (struct sockaddr_in *) rti_info[RTAX_NETMASK]; + if (sa_in != NULL && sa_in->sin_len != 0) + kr.prefixlen = mask2prefixlen(sa_in->sin_addr.s_addr); + else if (rtm->rtm_flags & RTF_HOST) + kr.prefixlen = 32; + else if (kr.prefix.v4.s_addr == INADDR_ANY) + kr.prefixlen = 0; + else + kr.prefixlen = prefixlen_classful(kr.prefix.v4.s_addr); + break; + case AF_INET6: + kr.prefix.v6 = ((struct sockaddr_in6 *)sa)->sin6_addr; + sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK]; + if (sa_in6 != NULL && sa_in6->sin6_len != 0) + kr.prefixlen = mask2prefixlen6(sa_in6); + else if (rtm->rtm_flags & RTF_HOST) + kr.prefixlen = 128; + else if (IN6_IS_ADDR_UNSPECIFIED(&kr.prefix.v6)) + kr.prefixlen = 0; + else + fatalx("in6 net addr without netmask"); + break; + default: + return (0); + } + kr.ifindex = rtm->rtm_index; + if ((sa = rti_info[RTAX_GATEWAY]) != NULL) { + switch (sa->sa_family) { + case AF_INET: + kr.nexthop.v4 = ((struct sockaddr_in *)sa)->sin_addr; + break; + case AF_INET6: + sa_in6 = (struct sockaddr_in6 *)sa; + recoverscope(sa_in6); + kr.nexthop.v6 = sa_in6->sin6_addr; + if (sa_in6->sin6_scope_id) + kr.ifindex = sa_in6->sin6_scope_id; + break; + case AF_LINK: + kr.flags |= F_CONNECTED; + break; + } + } + + if (rtm->rtm_flags & RTF_STATIC) + kr.flags |= F_STATIC; + if (rtm->rtm_flags & RTF_BLACKHOLE) + kr.flags |= F_BLACKHOLE; + if (rtm->rtm_flags & RTF_REJECT) + kr.flags |= F_REJECT; + if (rtm->rtm_flags & RTF_DYNAMIC) + kr.flags |= F_DYNAMIC; + /* routes attached to connected or loopback interfaces */ + if (rtm->rtm_flags & RTF_CONNECTED || + ldp_addrcmp(kr.af, &kr.prefix, &kr.nexthop) == 0) + kr.flags |= F_CONNECTED; + kr.priority = rtm->rtm_priority; + + if (rtm->rtm_type == RTM_CHANGE) { + /* + * The kernel doesn't allow RTM_CHANGE for multipath routes. + * If we got this message we know that the route has only one + * nexthop and we should remove it before installing the same + * route with the new nexthop. + */ + kp = kroute_find_prefix(kr.af, &kr.prefix, kr.prefixlen); + if (kp) { + kprio = kroute_find_prio(kp, kr.priority); + if (kprio) { + kn = TAILQ_FIRST(&kprio->nexthops); + if (kn) + kroute_remove(&kn->r); + } + } + } + + kn = NULL; + kp = kroute_find_prefix(kr.af, &kr.prefix, kr.prefixlen); + if (kp) { + kprio = kroute_find_prio(kp, kr.priority); + if (kprio) + kn = kroute_find_gw(kprio, &kr.nexthop); + } + + if (rtm->rtm_type == RTM_DELETE) { + if (kn == NULL) + return (0); + return (kroute_remove(&kr)); + } + + if (!ldp_addrisset(kr.af, &kr.nexthop) && !(kr.flags & F_CONNECTED)) { + log_warnx("%s: no nexthop for %s/%u", __func__, + log_addr(kr.af, &kr.prefix), kr.prefixlen); + return (-1); + } + + if (kn != NULL) { + /* update route */ + kn->r = kr; + kr_redistribute(kp); + } else { + kr.local_label = NO_LABEL; + kr.remote_label = NO_LABEL; + kroute_insert(&kr); + } + + return (0); +} + +int kmpw_set(struct kpw *kpw) { struct kif_node *kif; @@ -1497,7 +1663,6 @@ kmpw_unset(struct kpw *kpw) int kmpw_install(const char *ifname, struct kpw *kpw) { - struct sockaddr_in *sin; struct ifreq ifr; struct ifmpwreq imr; @@ -1518,10 +1683,8 @@ kmpw_install(const char *ifname, struct kpw *kpw) if (kpw->flags & F_PW_CWORD) imr.imr_flags |= IMR_FLAG_CONTROLWORD; - sin = (struct sockaddr_in *) &imr.imr_nexthop; - sin->sin_family = AF_INET; - sin->sin_addr = kpw->nexthop; - sin->sin_len = sizeof(struct sockaddr_in); + memcpy(&imr.imr_nexthop, addr2sa(kpw->af, &kpw->nexthop, 0), + sizeof(imr.imr_nexthop)); imr.imr_lshim.shim_label = kpw->local_label; imr.imr_rshim.shim_label = kpw->remote_label; diff --git a/usr.sbin/ldpd/l2vpn.c b/usr.sbin/ldpd/l2vpn.c index 91e60207be8..a1328f4cb4b 100644 --- a/usr.sbin/ldpd/l2vpn.c +++ b/usr.sbin/ldpd/l2vpn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: l2vpn.c,v 1.13 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: l2vpn.c,v 1.14 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> @@ -164,7 +164,8 @@ l2vpn_pw_init(struct l2vpn_pw *pw) l2vpn_pw_reset(pw); l2vpn_pw_fec(pw, &fec); - lde_kernel_insert(&fec, pw->lsr_id, 0, (void *)pw); + lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, + 0, (void *)pw); } void @@ -173,7 +174,7 @@ l2vpn_pw_exit(struct l2vpn_pw *pw) struct fec fec; l2vpn_pw_fec(pw, &fec); - lde_kernel_remove(&fec, pw->lsr_id); + lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id); } void @@ -225,9 +226,21 @@ l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh) /* check for a working lsp to the nexthop */ memset(&fec, 0, sizeof(fec)); - fec.type = FEC_TYPE_IPV4; - fec.u.ipv4.prefix = pw->lsr_id; - fec.u.ipv4.prefixlen = 32; + switch (pw->af) { + case AF_INET: + fec.type = FEC_TYPE_IPV4; + fec.u.ipv4.prefix = pw->addr.v4; + fec.u.ipv4.prefixlen = 32; + break; + case AF_INET6: + fec.type = FEC_TYPE_IPV6; + fec.u.ipv6.prefix = pw->addr.v6; + fec.u.ipv6.prefixlen = 128; + break; + default: + fatalx("l2vpn_pw_ok: unknown af"); + } + fn = (struct fec_node *)fec_find(&ft, &fec); if (fn == NULL || fn->local_label == NO_LABEL) return (0); @@ -328,7 +341,7 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) if (pw == NULL) return; - fnh = fec_nh_find(fn, ln->id); + fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id); if (fnh == NULL) return; @@ -345,7 +358,7 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) } void -l2vpn_sync_pws(struct in_addr addr) +l2vpn_sync_pws(int af, union ldpd_addr *addr) { struct l2vpn *l2vpn; struct l2vpn_pw *pw; @@ -355,14 +368,15 @@ l2vpn_sync_pws(struct in_addr addr) LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) { LIST_FOREACH(pw, &l2vpn->pw_list, entry) { - if (pw->lsr_id.s_addr != addr.s_addr) + if (af != pw->af || ldp_addrcmp(af, &pw->addr, addr)) continue; l2vpn_pw_fec(pw, &fec); fn = (struct fec_node *)fec_find(&ft, &fec); if (fn == NULL) continue; - fnh = fec_nh_find(fn, pw->lsr_id); + fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *) + &pw->lsr_id); if (fnh == NULL) continue; @@ -472,9 +486,9 @@ ldpe_l2vpn_pw_init(struct l2vpn_pw *pw) { struct tnbr *tnbr; - tnbr = tnbr_find(leconf, pw->lsr_id); + tnbr = tnbr_find(leconf, pw->af, &pw->addr); if (tnbr == NULL) { - tnbr = tnbr_new(leconf, pw->lsr_id); + tnbr = tnbr_new(leconf, pw->af, &pw->addr); tnbr_update(tnbr); LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry); } @@ -487,7 +501,7 @@ ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw) { struct tnbr *tnbr; - tnbr = tnbr_find(leconf, pw->lsr_id); + tnbr = tnbr_find(leconf, pw->af, &pw->addr); if (tnbr) { tnbr->pw_count--; tnbr_check(tnbr); diff --git a/usr.sbin/ldpd/labelmapping.c b/usr.sbin/ldpd/labelmapping.c index 6706b4f4c0b..ed98c95c4bf 100644 --- a/usr.sbin/ldpd/labelmapping.c +++ b/usr.sbin/ldpd/labelmapping.c @@ -1,4 +1,4 @@ -/* $OpenBSD: labelmapping.c,v 1.42 2016/05/23 18:51:52 renato Exp $ */ +/* $OpenBSD: labelmapping.c,v 1.43 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -90,7 +90,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) break; case MAP_TYPE_PREFIX: msg_size += FEC_ELM_PREFIX_MIN_LEN + - PREFIX_SIZE(me->map.fec.ipv4.prefixlen); + PREFIX_SIZE(me->map.fec.prefix.prefixlen); break; case MAP_TYPE_PWID: msg_size += FEC_PWID_ELM_MIN_LEN; @@ -350,7 +350,32 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) int imsg_type = IMSG_NONE; me->map.flags |= flags; - if (me->map.type == MAP_TYPE_PWID) { + switch (me->map.type) { + case MAP_TYPE_PREFIX: + switch (me->map.fec.prefix.af) { + case AF_IPV4: + if (label == MPLS_LABEL_IPV6NULL) { + session_shutdown(nbr, S_BAD_TLV_VAL, + lm.msgid, lm.type); + goto err; + } + if (!nbr->v4_enabled) + goto next; + break; + case AF_IPV6: + if (label == MPLS_LABEL_IPV4NULL) { + session_shutdown(nbr, S_BAD_TLV_VAL, + lm.msgid, lm.type); + goto err; + } + if (!nbr->v6_enabled) + goto next; + break; + default: + fatalx("recv_labelmessage: unknown af"); + } + break; + case MAP_TYPE_PWID: if (label <= MPLS_LABEL_RESERVED_MAX) { session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, lm.type); @@ -358,6 +383,9 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) } if (me->map.flags & F_MAP_PW_STATUS) me->map.pw_status = pw_status; + break; + default: + break; } me->map.label = label; if (me->map.flags & F_MAP_REQ_ID) @@ -397,6 +425,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map, sizeof(struct map)); +next: TAILQ_REMOVE(&mh, me, entry); free(me); } @@ -451,6 +480,7 @@ tlv_decode_label(struct nbr *nbr, struct ldp_msg *lm, char *buf, if (*label > MPLS_LABEL_MAX || (*label <= MPLS_LABEL_RESERVED_MAX && *label != MPLS_LABEL_IPV4NULL && + *label != MPLS_LABEL_IPV6NULL && *label != MPLS_LABEL_IMPLNULL)) { session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, lm->type); @@ -509,18 +539,18 @@ gen_fec_tlv(struct ibuf *buf, struct map *map) ibuf_add(buf, &map->type, sizeof(map->type)); break; case MAP_TYPE_PREFIX: - len = PREFIX_SIZE(map->fec.ipv4.prefixlen); + len = PREFIX_SIZE(map->fec.prefix.prefixlen); ft.length = htons(sizeof(map->type) + sizeof(family) + - sizeof(map->fec.ipv4.prefixlen) + len); + sizeof(map->fec.prefix.prefixlen) + len); ibuf_add(buf, &ft, sizeof(ft)); ibuf_add(buf, &map->type, sizeof(map->type)); - family = htons(AF_IPV4); + family = htons(map->fec.prefix.af); ibuf_add(buf, &family, sizeof(family)); - ibuf_add(buf, &map->fec.ipv4.prefixlen, - sizeof(map->fec.ipv4.prefixlen)); + ibuf_add(buf, &map->fec.prefix.prefixlen, + sizeof(map->fec.prefix.prefixlen)); if (len) - ibuf_add(buf, &map->fec.ipv4.prefix, len); + ibuf_add(buf, &map->fec.prefix.prefix, len); break; case MAP_TYPE_PWID: if (map->flags & F_MAP_PW_ID) @@ -566,7 +596,7 @@ int tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf, uint16_t len, struct map *map) { - uint16_t family, off = 0; + uint16_t off = 0; uint8_t pw_len; map->type = *buf; @@ -590,31 +620,33 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf, } /* Address Family */ - memcpy(&family, buf + off, sizeof(family)); - off += sizeof(family); - - if (family != htons(AF_IPV4)) { + memcpy(&map->fec.prefix.af, buf + off, + sizeof(map->fec.prefix.af)); + map->fec.prefix.af = ntohs(map->fec.prefix.af); + off += sizeof(map->fec.prefix.af); + if (map->fec.prefix.af != AF_IPV4 && + map->fec.prefix.af != AF_IPV6) { send_notification_nbr(nbr, S_UNSUP_ADDR, lm->msgid, lm->type); return (-1); } - /* PreLen */ - map->fec.ipv4.prefixlen = buf[off]; + /* Prefix Length */ + map->fec.prefix.prefixlen = buf[off]; off += sizeof(uint8_t); - - if (len < off + PREFIX_SIZE(map->fec.ipv4.prefixlen)) { + if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) { session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); return (-1); } /* Prefix */ - map->fec.ipv4.prefix.s_addr = 0; - memcpy(&map->fec.ipv4.prefix, buf + off, - PREFIX_SIZE(map->fec.ipv4.prefixlen)); + memset(&map->fec.prefix.prefix, 0, + sizeof(map->fec.prefix.prefix)); + memcpy(&map->fec.prefix.prefix, buf + off, + PREFIX_SIZE(map->fec.prefix.prefixlen)); - return (off + PREFIX_SIZE(map->fec.ipv4.prefixlen)); + return (off + PREFIX_SIZE(map->fec.prefix.prefixlen)); case MAP_TYPE_PWID: if (len < FEC_PWID_ELM_MIN_LEN) { session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, diff --git a/usr.sbin/ldpd/lde.c b/usr.sbin/ldpd/lde.c index 28eb38420cd..3e7afac9d89 100644 --- a/usr.sbin/ldpd/lde.c +++ b/usr.sbin/ldpd/lde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lde.c,v 1.53 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: lde.c,v 1.54 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org> @@ -45,7 +45,7 @@ void lde_dispatch_imsg(int, short, void *); void lde_dispatch_parent(int, short, void *); struct lde_nbr *lde_nbr_find(uint32_t); -struct lde_nbr *lde_nbr_new(uint32_t, struct in_addr *); +struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *); void lde_nbr_del(struct lde_nbr *); void lde_nbr_clear(void); @@ -220,7 +220,7 @@ lde_dispatch_imsg(int fd, short event, void *bula) struct imsg imsg; struct lde_nbr *ln; struct map map; - struct in_addr addr; + struct lde_addr lde_addr; struct notify_msg nm; ssize_t n; int shut = 0, verbose; @@ -296,9 +296,9 @@ lde_dispatch_imsg(int fd, short event, void *bula) } break; case IMSG_ADDRESS_ADD: - if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(addr)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr)) fatalx("lde_dispatch_imsg: wrong imsg len"); - memcpy(&addr, imsg.data, sizeof(addr)); + memcpy(&lde_addr, imsg.data, sizeof(lde_addr)); ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { @@ -306,16 +306,16 @@ lde_dispatch_imsg(int fd, short event, void *bula) __func__); break; } - if (lde_address_add(ln, &addr) < 0) { + if (lde_address_add(ln, &lde_addr) < 0) { log_debug("%s: cannot add address %s, it " "already exists", __func__, - inet_ntoa(addr)); + log_addr(lde_addr.af, &lde_addr.addr)); } break; case IMSG_ADDRESS_DEL: - if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(addr)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr)) fatalx("lde_dispatch_imsg: wrong imsg len"); - memcpy(&addr, imsg.data, sizeof(addr)); + memcpy(&lde_addr, imsg.data, sizeof(lde_addr)); ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { @@ -323,10 +323,10 @@ lde_dispatch_imsg(int fd, short event, void *bula) __func__); break; } - if (lde_address_del(ln, &addr) < 0) { + if (lde_address_del(ln, &lde_addr) < 0) { log_debug("%s: cannot delete address %s, it " "does not exist", __func__, - inet_ntoa(addr)); + log_addr(lde_addr.af, &lde_addr.addr)); } break; case IMSG_NOTIFICATION: @@ -350,7 +350,8 @@ lde_dispatch_imsg(int fd, short event, void *bula) } break; case IMSG_NEIGHBOR_UP: - if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(addr)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(struct lde_nbr)) fatalx("lde_dispatch_imsg: wrong imsg len"); if (lde_nbr_find(imsg.hdr.peerid)) @@ -439,29 +440,37 @@ lde_dispatch_parent(int fd, short event, void *bula) switch (imsg.hdr.type) { case IMSG_NETWORK_ADD: + case IMSG_NETWORK_DEL: if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) { log_warnx("%s: wrong imsg len", __func__); break; } memcpy(&kr, imsg.data, sizeof(kr)); - fec.type = FEC_TYPE_IPV4; - fec.u.ipv4.prefix = kr.prefix; - fec.u.ipv4.prefixlen = kr.prefixlen; - lde_kernel_insert(&fec, kr.nexthop, - kr.flags & F_CONNECTED, NULL); - break; - case IMSG_NETWORK_DEL: - if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) { - log_warnx("%s: wrong imsg len", __func__); + switch (kr.af) { + case AF_INET: + fec.type = FEC_TYPE_IPV4; + fec.u.ipv4.prefix = kr.prefix.v4; + fec.u.ipv4.prefixlen = kr.prefixlen; break; + case AF_INET6: + fec.type = FEC_TYPE_IPV6; + fec.u.ipv6.prefix = kr.prefix.v6; + fec.u.ipv6.prefixlen = kr.prefixlen; + break; + default: + fatalx("lde_dispatch_parent: unknown af"); } - memcpy(&kr, imsg.data, sizeof(kr)); - fec.type = FEC_TYPE_IPV4; - fec.u.ipv4.prefix = kr.prefix; - fec.u.ipv4.prefixlen = kr.prefixlen; - lde_kernel_remove(&fec, kr.nexthop); + switch (imsg.hdr.type) { + case IMSG_NETWORK_ADD: + lde_kernel_insert(&fec, kr.af, &kr.nexthop, + kr.flags & F_CONNECTED, NULL); + break; + case IMSG_NETWORK_DEL: + lde_kernel_remove(&fec, kr.af, &kr.nexthop); + break; + } break; case IMSG_RECONF_CONF: if ((nconf = malloc(sizeof(struct ldpd_conf))) == @@ -480,7 +489,10 @@ lde_dispatch_parent(int fd, short event, void *bula) memcpy(niface, imsg.data, sizeof(struct iface)); LIST_INIT(&niface->addr_list); - LIST_INIT(&niface->adj_list); + LIST_INIT(&niface->ipv4.adj_list); + LIST_INIT(&niface->ipv6.adj_list); + niface->ipv4.iface = niface; + niface->ipv6.iface = niface; LIST_INSERT_HEAD(&nconf->iface_list, niface, entry); break; @@ -564,18 +576,35 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) switch (fn->fec.type) { case FEC_TYPE_IPV4: memset(&kr, 0, sizeof(kr)); - kr.prefix = fn->fec.u.ipv4.prefix; + kr.af = AF_INET; + kr.prefix.v4 = fn->fec.u.ipv4.prefix; kr.prefixlen = fn->fec.u.ipv4.prefixlen; + kr.nexthop.v4 = fnh->nexthop.v4; kr.local_label = fn->local_label; - kr.nexthop = fnh->nexthop; kr.remote_label = fnh->remote_label; lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, sizeof(kr)); - if (fnh->remote_label != NO_LABEL && - fn->fec.u.ipv4.prefixlen == 32) - l2vpn_sync_pws(fn->fec.u.ipv4.prefix); + if (fn->fec.u.ipv4.prefixlen == 32) + l2vpn_sync_pws(AF_INET, (union ldpd_addr *) + &fn->fec.u.ipv4.prefix); + break; + case FEC_TYPE_IPV6: + memset(&kr, 0, sizeof(kr)); + kr.af = AF_INET6; + kr.prefix.v6 = fn->fec.u.ipv6.prefix; + kr.prefixlen = fn->fec.u.ipv6.prefixlen; + kr.nexthop.v6 = fnh->nexthop.v6; + kr.local_label = fn->local_label; + kr.remote_label = fnh->remote_label; + + lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, + sizeof(kr)); + + if (fn->fec.u.ipv6.prefixlen == 128) + l2vpn_sync_pws(AF_INET6, (union ldpd_addr *) + &fn->fec.u.ipv6.prefix); break; case FEC_TYPE_PWID: if (fn->local_label == NO_LABEL || @@ -588,7 +617,8 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) memset(&kpw, 0, sizeof(kpw)); kpw.ifindex = pw->ifindex; kpw.pw_type = fn->fec.u.pwid.type; - kpw.nexthop = fnh->nexthop; + kpw.af = pw->af; + kpw.nexthop = pw->addr; kpw.local_label = fn->local_label; kpw.remote_label = fnh->remote_label; kpw.flags = pw->flags; @@ -609,17 +639,35 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) switch (fn->fec.type) { case FEC_TYPE_IPV4: memset(&kr, 0, sizeof(kr)); - kr.prefix = fn->fec.u.ipv4.prefix; + kr.af = AF_INET; + kr.prefix.v4 = fn->fec.u.ipv4.prefix; kr.prefixlen = fn->fec.u.ipv4.prefixlen; + kr.nexthop.v4 = fnh->nexthop.v4; kr.local_label = fn->local_label; - kr.nexthop = fnh->nexthop; kr.remote_label = fnh->remote_label; lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, sizeof(kr)); if (fn->fec.u.ipv4.prefixlen == 32) - l2vpn_sync_pws(fn->fec.u.ipv4.prefix); + l2vpn_sync_pws(AF_INET, (union ldpd_addr *) + &fn->fec.u.ipv4.prefix); + break; + case FEC_TYPE_IPV6: + memset(&kr, 0, sizeof(kr)); + kr.af = AF_INET6; + kr.prefix.v6 = fn->fec.u.ipv6.prefix; + kr.prefixlen = fn->fec.u.ipv6.prefixlen; + kr.nexthop.v6 = fnh->nexthop.v6; + kr.local_label = fn->local_label; + kr.remote_label = fnh->remote_label; + + lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, + sizeof(kr)); + + if (fn->fec.u.ipv6.prefixlen == 128) + l2vpn_sync_pws(AF_INET6, (union ldpd_addr *) + &fn->fec.u.ipv6.prefix); break; case FEC_TYPE_PWID: pw = (struct l2vpn_pw *) fn->data; @@ -630,7 +678,8 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) memset(&kpw, 0, sizeof(kpw)); kpw.ifindex = pw->ifindex; kpw.pw_type = fn->fec.u.pwid.type; - kpw.nexthop = fnh->nexthop; + kpw.af = pw->af; + kpw.nexthop = pw->addr; kpw.local_label = fn->local_label; kpw.remote_label = fnh->remote_label; kpw.flags = pw->flags; @@ -649,8 +698,15 @@ lde_fec2map(struct fec *fec, struct map *map) switch (fec->type) { case FEC_TYPE_IPV4: map->type = MAP_TYPE_PREFIX; - map->fec.ipv4.prefix = fec->u.ipv4.prefix; - map->fec.ipv4.prefixlen = fec->u.ipv4.prefixlen; + map->fec.prefix.af = AF_IPV4; + map->fec.prefix.prefix.v4 = fec->u.ipv4.prefix; + map->fec.prefix.prefixlen = fec->u.ipv4.prefixlen; + break; + case FEC_TYPE_IPV6: + map->type = MAP_TYPE_PREFIX; + map->fec.prefix.af = AF_IPV6; + map->fec.prefix.prefix.v6 = fec->u.ipv6.prefix; + map->fec.prefix.prefixlen = fec->u.ipv6.prefixlen; break; case FEC_TYPE_PWID: map->type = MAP_TYPE_PWID; @@ -669,9 +725,21 @@ lde_map2fec(struct map *map, struct in_addr lsr_id, struct fec *fec) switch (map->type) { case MAP_TYPE_PREFIX: - fec->type = FEC_TYPE_IPV4; - fec->u.ipv4.prefix = map->fec.ipv4.prefix; - fec->u.ipv4.prefixlen = map->fec.ipv4.prefixlen; + switch (map->fec.prefix.af) { + case AF_IPV4: + fec->type = FEC_TYPE_IPV4; + fec->u.ipv4.prefix = map->fec.prefix.prefix.v4; + fec->u.ipv4.prefixlen = map->fec.prefix.prefixlen; + break; + case AF_IPV6: + fec->type = FEC_TYPE_IPV6; + fec->u.ipv6.prefix = map->fec.prefix.prefix.v6; + fec->u.ipv6.prefixlen = map->fec.prefix.prefixlen; + break; + default: + fatalx("lde_map2fec: unknown af"); + break; + } break; case MAP_TYPE_PWID: fec->type = FEC_TYPE_PWID; @@ -697,7 +765,16 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) */ lde_fec2map(&fn->fec, &map); - if (fn->fec.type == FEC_TYPE_PWID) { + switch (fn->fec.type) { + case FEC_TYPE_IPV4: + if (!ln->v4_enabled) + return; + break; + case FEC_TYPE_IPV6: + if (!ln->v6_enabled) + return; + break; + case FEC_TYPE_PWID: pw = (struct l2vpn_pw *) fn->data; if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr) /* not the remote end of the pseudowire */ @@ -712,6 +789,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) /* VPLS are always up */ map.pw_status = PW_FORWARDING; } + break; } map.label = fn->local_label; @@ -750,8 +828,16 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) if (fn) { lde_fec2map(&fn->fec, &map); - map.label = fn->local_label; - if (fn->fec.type == FEC_TYPE_PWID) { + switch (fn->fec.type) { + case FEC_TYPE_IPV4: + if (!ln->v4_enabled) + return; + break; + case FEC_TYPE_IPV6: + if (!ln->v6_enabled) + return; + break; + case FEC_TYPE_PWID: pw = (struct l2vpn_pw *) fn->data; if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr) /* not the remote end of the pseudowire */ @@ -759,7 +845,9 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) if (pw->flags & F_PW_CWORD) map.flags |= F_MAP_PW_CWORD; + break; } + map.label = fn->local_label; } else { memset(&map, 0, sizeof(map)); map.type = MAP_TYPE_WILDCARD; @@ -807,7 +895,16 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) if (fn) { lde_fec2map(&fn->fec, &map); - if (fn->fec.type == FEC_TYPE_PWID) { + switch (fn->fec.type) { + case FEC_TYPE_IPV4: + if (!ln->v4_enabled) + return; + break; + case FEC_TYPE_IPV6: + if (!ln->v6_enabled) + return; + break; + case FEC_TYPE_PWID: pw = (struct l2vpn_pw *) fn->data; if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr) /* not the remote end of the pseudowire */ @@ -815,6 +912,7 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) if (pw->flags & F_PW_CWORD) map.flags |= F_MAP_PW_CWORD; + break; } } else { memset(&map, 0, sizeof(map)); @@ -850,14 +948,16 @@ lde_nbr_compare(struct lde_nbr *a, struct lde_nbr *b) } struct lde_nbr * -lde_nbr_new(uint32_t peerid, struct in_addr *id) +lde_nbr_new(uint32_t peerid, struct lde_nbr *new) { struct lde_nbr *ln; if ((ln = calloc(1, sizeof(*ln))) == NULL) fatal(__func__); - ln->id = *id; + ln->id = new->id; + ln->v4_enabled = new->v4_enabled; + ln->v6_enabled = new->v6_enabled; ln->peerid = peerid; fec_init(&ln->recv_map); fec_init(&ln->sent_map); @@ -891,7 +991,9 @@ lde_nbr_del(struct lde_nbr *ln) LIST_FOREACH(fnh, &fn->nexthops, entry) { switch (f->type) { case FEC_TYPE_IPV4: - if (!lde_address_find(ln, &fnh->nexthop)) + case FEC_TYPE_IPV6: + if (!lde_address_find(ln, fnh->af, + &fnh->nexthop)) continue; break; case FEC_TYPE_PWID: @@ -946,12 +1048,12 @@ lde_nbr_find_by_lsrid(struct in_addr addr) } struct lde_nbr * -lde_nbr_find_by_addr(struct in_addr addr) +lde_nbr_find_by_addr(int af, union ldpd_addr *addr) { struct lde_nbr *ln; RB_FOREACH(ln, nbr_tree, &lde_nbrs) - if (lde_address_find(ln, &addr) != NULL) + if (lde_address_find(ln, af, addr) != NULL) return (ln); return (NULL); @@ -1074,25 +1176,44 @@ lde_wdraw_del(struct lde_nbr *ln, struct lde_wdraw *lw) } void -lde_change_egress_label(int was_implicit) +lde_change_egress_label(int af, int was_implicit) { struct lde_nbr *ln; struct fec *f; struct fec_node *fn; - /* explicit withdraw */ - if (was_implicit) - lde_send_labelwithdraw_all(NULL, MPLS_LABEL_IMPLNULL); - else - lde_send_labelwithdraw_all(NULL, MPLS_LABEL_IPV4NULL); - - /* update label of connected prefixes */ RB_FOREACH(ln, nbr_tree, &lde_nbrs) { + /* explicit withdraw */ + if (was_implicit) + lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL); + else { + if (ln->v4_enabled) + lde_send_labelwithdraw(ln, NULL, + MPLS_LABEL_IPV4NULL); + if (ln->v6_enabled) + lde_send_labelwithdraw(ln, NULL, + MPLS_LABEL_IPV6NULL); + } + + /* advertise new label of connected prefixes */ RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; if (fn->local_label > MPLS_LABEL_RESERVED_MAX) continue; + switch (af) { + case AF_INET: + if (fn->fec.type != FEC_TYPE_IPV4) + continue; + break; + case AF_INET6: + if (fn->fec.type != FEC_TYPE_IPV6) + continue; + break; + default: + fatalx("lde_change_egress_label: unknown af"); + } + fn->local_label = egress_label(fn->fec.type); lde_send_labelmapping(ln, fn, 0); } @@ -1103,28 +1224,27 @@ lde_change_egress_label(int was_implicit) } int -lde_address_add(struct lde_nbr *ln, struct in_addr *addr) +lde_address_add(struct lde_nbr *ln, struct lde_addr *lde_addr) { struct lde_addr *new; - if (lde_address_find(ln, addr) != NULL) + if (lde_address_find(ln, lde_addr->af, &lde_addr->addr) != NULL) return (-1); if ((new = calloc(1, sizeof(*new))) == NULL) fatal(__func__); - new->addr = *addr; + new->af = lde_addr->af; + new->addr = lde_addr->addr; TAILQ_INSERT_TAIL(&ln->addr_list, new, entry); return (0); } int -lde_address_del(struct lde_nbr *ln, struct in_addr *addr) +lde_address_del(struct lde_nbr *ln, struct lde_addr *lde_addr) { - struct lde_addr *lde_addr; - - lde_addr = lde_address_find(ln, addr); + lde_addr = lde_address_find(ln, lde_addr->af, &lde_addr->addr); if (lde_addr == NULL) return (-1); @@ -1135,12 +1255,13 @@ lde_address_del(struct lde_nbr *ln, struct in_addr *addr) } struct lde_addr * -lde_address_find(struct lde_nbr *ln, struct in_addr *addr) +lde_address_find(struct lde_nbr *ln, int af, union ldpd_addr *addr) { struct lde_addr *lde_addr; TAILQ_FOREACH(lde_addr, &ln->addr_list, entry) - if (lde_addr->addr.s_addr == addr->s_addr) + if (lde_addr->af == af && + ldp_addrcmp(af, &lde_addr->addr, addr) == 0) return (lde_addr); return (NULL); diff --git a/usr.sbin/ldpd/lde.h b/usr.sbin/ldpd/lde.h index 9097715ebf7..92d9ab936c8 100644 --- a/usr.sbin/ldpd/lde.h +++ b/usr.sbin/ldpd/lde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lde.h,v 1.34 2016/05/23 18:46:13 renato Exp $ */ +/* $OpenBSD: lde.h,v 1.35 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> @@ -30,6 +30,7 @@ RB_HEAD(fec_tree, fec); enum fec_type { FEC_TYPE_IPV4, + FEC_TYPE_IPV6, FEC_TYPE_PWID }; @@ -42,6 +43,10 @@ struct fec { uint8_t prefixlen; } ipv4; struct { + struct in6_addr prefix; + uint8_t prefixlen; + } ipv6; + struct { uint16_t type; uint32_t pwid; struct in_addr lsr_id; @@ -74,27 +79,29 @@ struct lde_wdraw { /* Addresses belonging to neighbor */ struct lde_addr { TAILQ_ENTRY(lde_addr) entry; - struct in_addr addr; + int af; + union ldpd_addr addr; }; /* just the info LDE needs */ struct lde_nbr { - RB_ENTRY(lde_nbr) entry; - struct in_addr id; - - struct fec_tree recv_req; - struct fec_tree sent_req; - struct fec_tree recv_map; - struct fec_tree sent_map; - struct fec_tree sent_wdraw; - TAILQ_HEAD(, lde_addr) addr_list; - - uint32_t peerid; + RB_ENTRY(lde_nbr) entry; + uint32_t peerid; + struct in_addr id; + int v4_enabled; /* announce/process v4 msgs */ + int v6_enabled; /* announce/process v6 msgs */ + struct fec_tree recv_req; + struct fec_tree sent_req; + struct fec_tree recv_map; + struct fec_tree sent_map; + struct fec_tree sent_wdraw; + TAILQ_HEAD(, lde_addr) addr_list; }; struct fec_nh { LIST_ENTRY(fec_nh) entry; - struct in_addr nexthop; + int af; + union ldpd_addr nexthop; uint32_t remote_label; }; @@ -125,18 +132,19 @@ void lde_send_labelwithdraw_all(struct fec_node *, uint32_t); void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, uint32_t); void lde_send_notification(uint32_t, uint32_t, uint32_t, uint16_t); struct lde_nbr *lde_nbr_find_by_lsrid(struct in_addr); -struct lde_nbr *lde_nbr_find_by_addr(struct in_addr); +struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_addr *); struct lde_map *lde_map_add(struct lde_nbr *, struct fec_node *, int); void lde_map_del(struct lde_nbr *, struct lde_map *, int); struct lde_req *lde_req_add(struct lde_nbr *, struct fec *, int); void lde_req_del(struct lde_nbr *, struct lde_req *, int); struct lde_wdraw *lde_wdraw_add(struct lde_nbr *, struct fec_node *); void lde_wdraw_del(struct lde_nbr *, struct lde_wdraw *); -void lde_change_egress_label(int); +void lde_change_egress_label(int, int); -int lde_address_add(struct lde_nbr *, struct in_addr *); -struct lde_addr *lde_address_find(struct lde_nbr *, struct in_addr *); -int lde_address_del(struct lde_nbr *, struct in_addr *); +int lde_address_add(struct lde_nbr *, struct lde_addr *); +struct lde_addr *lde_address_find(struct lde_nbr *, int, + union ldpd_addr *); +int lde_address_del(struct lde_nbr *, struct lde_addr *); /* lde_lib.c */ void fec_init(struct fec_tree *); @@ -149,10 +157,10 @@ void rt_dump(pid_t); void fec_snap(struct lde_nbr *); void fec_tree_clear(void); -struct fec_nh *fec_nh_find(struct fec_node *, struct in_addr); +struct fec_nh *fec_nh_find(struct fec_node *, int, union ldpd_addr *); uint32_t egress_label(enum fec_type); -void lde_kernel_insert(struct fec *, struct in_addr, int, void *); -void lde_kernel_remove(struct fec *, struct in_addr); +void lde_kernel_insert(struct fec *, int, union ldpd_addr *, int, void *); +void lde_kernel_remove(struct fec *, int, union ldpd_addr *); void lde_check_mapping(struct map *, struct lde_nbr *); void lde_check_request(struct map *, struct lde_nbr *); void lde_check_release(struct map *, struct lde_nbr *); @@ -185,7 +193,7 @@ int l2vpn_pw_negotiate(struct lde_nbr *, struct fec_node *, struct map *); void l2vpn_send_pw_status(uint32_t, uint32_t, struct fec *); void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *); -void l2vpn_sync_pws(struct in_addr); +void l2vpn_sync_pws(int, union ldpd_addr *); void l2vpn_pw_ctl(pid_t); void l2vpn_binding_ctl(pid_t); diff --git a/usr.sbin/ldpd/lde_lib.c b/usr.sbin/ldpd/lde_lib.c index e549c4086eb..f8099d086b9 100644 --- a/usr.sbin/ldpd/lde_lib.c +++ b/usr.sbin/ldpd/lde_lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lde_lib.c,v 1.54 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: lde_lib.c,v 1.55 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -42,7 +42,7 @@ static int fec_compare(struct fec *, struct fec *); void fec_free(void *); struct fec_node *fec_add(struct fec *fec); -struct fec_nh *fec_nh_add(struct fec_node *, struct in_addr); +struct fec_nh *fec_nh_add(struct fec_node *, int, union ldpd_addr *); void fec_nh_del(struct fec_nh *); int lde_nbr_is_nexthop(struct fec_node *, struct lde_nbr *); @@ -84,6 +84,18 @@ fec_compare(struct fec *a, struct fec *b) if (a->u.ipv4.prefixlen > b->u.ipv4.prefixlen) return (1); return (0); + case FEC_TYPE_IPV6: + if (memcmp(&a->u.ipv6.prefix, &b->u.ipv6.prefix, + sizeof(struct in6_addr)) < 0) + return (-1); + if (memcmp(&a->u.ipv6.prefix, &b->u.ipv6.prefix, + sizeof(struct in6_addr)) > 0) + return (1); + if (a->u.ipv6.prefixlen < b->u.ipv6.prefixlen) + return (-1); + if (a->u.ipv6.prefixlen > b->u.ipv6.prefixlen) + return (1); + return (0); case FEC_TYPE_PWID: if (a->u.pwid.type < b->u.pwid.type) return (-1); @@ -147,7 +159,7 @@ lde_nbr_is_nexthop(struct fec_node *fn, struct lde_nbr *ln) struct fec_nh *fnh; LIST_FOREACH(fnh, &fn->nexthops, entry) - if (lde_address_find(ln, &fnh->nexthop)) + if (lde_address_find(ln, fnh->af, &fnh->nexthop)) return (1); return (0); @@ -163,17 +175,26 @@ rt_dump(pid_t pid) RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; - if (fn->fec.type != FEC_TYPE_IPV4) - continue; - if (fn->local_label == NO_LABEL && LIST_EMPTY(&fn->downstream)) continue; - rtctl.prefix = fn->fec.u.ipv4.prefix; - rtctl.prefixlen = fn->fec.u.ipv4.prefixlen; - rtctl.local_label = fn->local_label; + switch (fn->fec.type) { + case FEC_TYPE_IPV4: + rtctl.af = AF_INET; + rtctl.prefix.v4 = fn->fec.u.ipv4.prefix; + rtctl.prefixlen = fn->fec.u.ipv4.prefixlen; + break; + case FEC_TYPE_IPV6: + rtctl.af = AF_INET6; + rtctl.prefix.v6 = fn->fec.u.ipv6.prefix; + rtctl.prefixlen = fn->fec.u.ipv6.prefixlen; + break; + default: + continue; + } + rtctl.local_label = fn->local_label; LIST_FOREACH(me, &fn->downstream, entry) { rtctl.in_use = lde_nbr_is_nexthop(fn, me->nexthop); rtctl.nexthop = me->nexthop->id; @@ -257,19 +278,20 @@ fec_add(struct fec *fec) } struct fec_nh * -fec_nh_find(struct fec_node *fn, struct in_addr nexthop) +fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop) { struct fec_nh *fnh; LIST_FOREACH(fnh, &fn->nexthops, entry) - if (fnh->nexthop.s_addr == nexthop.s_addr) + if (fnh->af == af && + ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0) return (fnh); return (NULL); } struct fec_nh * -fec_nh_add(struct fec_node *fn, struct in_addr nexthop) +fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop) { struct fec_nh *fnh; @@ -277,7 +299,8 @@ fec_nh_add(struct fec_node *fn, struct in_addr nexthop) if (fnh == NULL) fatal(__func__); - fnh->nexthop = nexthop; + fnh->af = af; + fnh->nexthop = *nexthop; fnh->remote_label = NO_LABEL; LIST_INSERT_HEAD(&fn->nexthops, fnh, entry); @@ -294,12 +317,15 @@ fec_nh_del(struct fec_nh *fnh) uint32_t egress_label(enum fec_type fec_type) { - if (!(ldeconf->flags & F_LDPD_EXPNULL)) - return (MPLS_LABEL_IMPLNULL); - switch (fec_type) { case FEC_TYPE_IPV4: + if (!(ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL)) + return (MPLS_LABEL_IMPLNULL); return (MPLS_LABEL_IPV4NULL); + case FEC_TYPE_IPV6: + if (!(ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL)) + return (MPLS_LABEL_IMPLNULL); + return (MPLS_LABEL_IPV6NULL); default: log_warnx("%s: unexpected fec type", __func__); } @@ -308,8 +334,8 @@ egress_label(enum fec_type fec_type) } void -lde_kernel_insert(struct fec *fec, struct in_addr nexthop, int connected, - void *data) +lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, + int connected, void *data) { struct fec_node *fn; struct fec_nh *fnh; @@ -319,11 +345,11 @@ lde_kernel_insert(struct fec *fec, struct in_addr nexthop, int connected, fn = (struct fec_node *)fec_find(&ft, fec); if (fn == NULL) fn = fec_add(fec); - if (fec_nh_find(fn, nexthop) != NULL) + if (fec_nh_find(fn, af, nexthop) != NULL) return; log_debug("lde add fec %s nexthop %s", - log_fec(&fn->fec), inet_ntoa(nexthop)); + log_fec(&fn->fec), log_addr(af, nexthop)); if (fn->fec.type == FEC_TYPE_PWID) fn->data = data; @@ -339,12 +365,13 @@ lde_kernel_insert(struct fec *fec, struct in_addr nexthop, int connected, lde_send_labelmapping(ln, fn, 1); } - fnh = fec_nh_add(fn, nexthop); + fnh = fec_nh_add(fn, af, nexthop); lde_send_change_klabel(fn, fnh); switch (fn->fec.type) { case FEC_TYPE_IPV4: - ln = lde_nbr_find_by_addr(fnh->nexthop); + case FEC_TYPE_IPV6: + ln = lde_nbr_find_by_addr(af, &fnh->nexthop); break; case FEC_TYPE_PWID: ln = lde_nbr_find_by_lsrid(fn->fec.u.pwid.lsr_id); @@ -364,7 +391,7 @@ lde_kernel_insert(struct fec *fec, struct in_addr nexthop, int connected, } void -lde_kernel_remove(struct fec *fec, struct in_addr nexthop) +lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop) { struct fec_node *fn; struct fec_nh *fnh; @@ -373,13 +400,13 @@ lde_kernel_remove(struct fec *fec, struct in_addr nexthop) if (fn == NULL) /* route lost */ return; - fnh = fec_nh_find(fn, nexthop); + fnh = fec_nh_find(fn, af, nexthop); if (fnh == NULL) /* route lost */ return; log_debug("lde remove fec %s nexthop %s", - log_fec(&fn->fec), inet_ntoa(nexthop)); + log_fec(&fn->fec), log_addr(af, nexthop)); lde_send_delete_klabel(fn, fnh); fec_nh_del(fnh); @@ -435,7 +462,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) * the possibility of multipath. */ LIST_FOREACH(fnh, &fn->nexthops, entry) { - if (lde_address_find(ln, &fnh->nexthop) == NULL) + if (lde_address_find(ln, fnh->af, + &fnh->nexthop) == NULL) continue; lde_send_delete_klabel(fn, fnh); @@ -452,7 +480,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) /* LMp.15: install FEC in FIB */ switch (fec.type) { case FEC_TYPE_IPV4: - if (!lde_address_find(ln, &fnh->nexthop)) + case FEC_TYPE_IPV6: + if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) continue; fnh->remote_label = map->label; @@ -517,7 +546,8 @@ lde_check_request(struct map *map, struct lde_nbr *ln) LIST_FOREACH(fnh, &fn->nexthops, entry) { switch (fec.type) { case FEC_TYPE_IPV4: - if (!lde_address_find(ln, &fnh->nexthop)) + case FEC_TYPE_IPV6: + if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) continue; lde_send_notification(ln->peerid, S_LOOP_DETECTED, @@ -640,7 +670,8 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) LIST_FOREACH(fnh, &fn->nexthops, entry) { switch (fec.type) { case FEC_TYPE_IPV4: - if (!lde_address_find(ln, &fnh->nexthop)) + case FEC_TYPE_IPV6: + if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) continue; break; case FEC_TYPE_PWID: @@ -683,7 +714,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) LIST_FOREACH(fnh, &fn->nexthops, entry) { switch (f->type) { case FEC_TYPE_IPV4: - if (!lde_address_find(ln, &fnh->nexthop)) + case FEC_TYPE_IPV6: + if (!lde_address_find(ln, fnh->af, + &fnh->nexthop)) continue; break; case FEC_TYPE_PWID: diff --git a/usr.sbin/ldpd/ldp.h b/usr.sbin/ldpd/ldp.h index 505e6952989..bbf12ca89ff 100644 --- a/usr.sbin/ldpd/ldp.h +++ b/usr.sbin/ldpd/ldp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldp.h,v 1.26 2016/05/23 17:43:42 renato Exp $ */ +/* $OpenBSD: ldp.h,v 1.27 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -27,10 +27,12 @@ /* misc */ #define LDP_VERSION 1 #define LDP_PORT 646 -#define AllRouters "224.0.0.2" - #define LDP_MAX_LEN 4096 +/* All Routers on this Subnet group multicast addresses */ +#define AllRouters_v4 "224.0.0.2" +#define AllRouters_v6 "ff02::2" + #define LINK_DFLT_HOLDTIME 15 #define TARGETED_DFLT_HOLDTIME 45 #define MIN_HOLDTIME 3 @@ -93,6 +95,8 @@ #define TLV_TYPE_PW_STATUS 0x096A #define TLV_TYPE_PW_IF_PARAM 0x096B #define TLV_TYPE_PW_GROUP_ID 0x096C +/* RFC 7552 */ +#define TLV_TYPE_DUALSTACK 0x8701 /* LDP header */ struct ldp_hdr { @@ -144,6 +148,18 @@ struct hello_prms_opt4_tlv { uint32_t value; }; +struct hello_prms_opt16_tlv { + uint16_t type; + uint16_t length; + uint8_t value[16]; +}; + +#define DUAL_STACK_LDPOV4 4 +#define DUAL_STACK_LDPOV6 6 + +#define F_HELLO_TLV_RCVD_ADDR 0x01 +#define F_HELLO_TLV_RCVD_CONF 0x02 +#define F_HELLO_TLV_RCVD_DS 0x04 #define S_SUCCESS 0x00000000 #define S_BAD_LDP_ID 0x80000001 @@ -180,6 +196,9 @@ struct hello_prms_opt4_tlv { #define S_UNASSIGN_TAI 0x00000029 #define S_MISCONF_ERR 0x0000002A #define S_WITHDRAW_MTHD 0x0000002B +/* RFC 7552 */ +#define S_TRANS_MISMTCH 0x80000032 +#define S_DS_NONCMPLNCE 0x80000033 struct sess_prms_tlv { uint16_t type; diff --git a/usr.sbin/ldpd/ldpd.8 b/usr.sbin/ldpd/ldpd.8 index 501b933f955..c91d3753d6d 100644 --- a/usr.sbin/ldpd/ldpd.8 +++ b/usr.sbin/ldpd/ldpd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ldpd.8,v 1.13 2016/05/23 17:43:42 renato Exp $ +.\" $OpenBSD: ldpd.8,v 1.14 2016/05/23 18:58:48 renato Exp $ .\" .\" Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> .\" Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org> @@ -126,6 +126,17 @@ socket used for communication with .%R RFC 5036 .%T LDP Specification .Re +.Pp +.Rs +.%A R. Asati +.%A C. Pignataro +.%A K. Raza +.%A V. Manral +.%A R. Papneja +.%D June 2015 +.%R RFC 7552 +.%T Updates to LDP for IPv6 +.Re .Sh HISTORY The .Nm diff --git a/usr.sbin/ldpd/ldpd.c b/usr.sbin/ldpd/ldpd.c index 1cb72f02528..8d464b17c87 100644 --- a/usr.sbin/ldpd/ldpd.c +++ b/usr.sbin/ldpd/ldpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpd.c,v 1.43 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: ldpd.c,v 1.44 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -54,11 +54,13 @@ int check_child(pid_t, const char *); void main_dispatch_ldpe(int, short, void *); void main_dispatch_lde(int, short, void *); int main_imsg_compose_both(enum imsg_type, void *, uint16_t); -void main_imsg_send_net_sockets(void); -void main_imsg_send_net_socket(enum socket_type); +void main_imsg_send_net_sockets(int); +void main_imsg_send_net_socket(int, enum socket_type); int ldp_reload(void); void merge_global(struct ldpd_conf *, struct ldpd_conf *); +void merge_af(int, struct ldpd_af_conf *, struct ldpd_af_conf *); void merge_ifaces(struct ldpd_conf *, struct ldpd_conf *); +void merge_iface_af(struct iface_af *, struct iface_af *); void merge_tnbrs(struct ldpd_conf *, struct ldpd_conf *); void merge_nbrps(struct ldpd_conf *, struct ldpd_conf *); void merge_l2vpns(struct ldpd_conf *, struct ldpd_conf *); @@ -263,7 +265,8 @@ main(int argc, char *argv[]) if (kr_init(!(ldpd_conf->flags & F_LDPD_NO_FIB_UPDATE)) == -1) fatalx("kr_init failed"); - main_imsg_send_net_sockets(); + main_imsg_send_net_sockets(AF_INET); + main_imsg_send_net_sockets(AF_INET6); /* remove unneded stuff from config */ /* ... */ @@ -333,6 +336,7 @@ main_dispatch_ldpe(int fd, short event, void *bula) struct imsgev *iev = bula; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; + int af; ssize_t n; int shut = 0, verbose; @@ -358,7 +362,8 @@ main_dispatch_ldpe(int fd, short event, void *bula) switch (imsg.hdr.type) { case IMSG_REQUEST_SOCKETS: - main_imsg_send_net_sockets(); + af = imsg.hdr.peerid; + main_imsg_send_net_sockets(af); break; case IMSG_CTL_RELOAD: if (ldp_reload() == -1) @@ -562,30 +567,63 @@ evbuf_clear(struct evbuf *eb) } void -main_imsg_send_net_sockets(void) +main_imsg_send_net_sockets(int af) { - main_imsg_send_net_socket(LDP_SOCKET_DISC); - main_imsg_send_net_socket(LDP_SOCKET_EDISC); - main_imsg_send_net_socket(LDP_SOCKET_SESSION); - main_imsg_compose_ldpe(IMSG_SETUP_SOCKETS, 0, NULL, 0); + main_imsg_send_net_socket(af, LDP_SOCKET_DISC); + main_imsg_send_net_socket(af, LDP_SOCKET_EDISC); + main_imsg_send_net_socket(af, LDP_SOCKET_SESSION); + imsg_compose_event(iev_ldpe, IMSG_SETUP_SOCKETS, af, 0, -1, NULL, 0); } void -main_imsg_send_net_socket(enum socket_type type) +main_imsg_send_net_socket(int af, enum socket_type type) { int fd; - fd = ldp_create_socket(type); + fd = ldp_create_socket(af, type); if (fd == -1) { - log_warnx("%s: failed to create %s socket", __func__, - socket_name(type)); + log_warnx("%s: failed to create %s socket for address-family " + "%s", __func__, socket_name(type), af_name(af)); return; } - imsg_compose_event(iev_ldpe, IMSG_SOCKET_NET, 0, 0, fd, &type, + imsg_compose_event(iev_ldpe, IMSG_SOCKET_NET, af, 0, fd, &type, sizeof(type)); } +struct ldpd_af_conf * +ldp_af_conf_get(struct ldpd_conf *xconf, int af) +{ + switch (af) { + case AF_INET: + return (&xconf->ipv4); + case AF_INET6: + return (&xconf->ipv6); + default: + fatalx("ldp_af_conf_get: unknown af"); + } +} + +struct ldpd_af_global * +ldp_af_global_get(struct ldpd_global *xglobal, int af) +{ + switch (af) { + case AF_INET: + return (&xglobal->ipv4); + case AF_INET6: + return (&xglobal->ipv6); + default: + fatalx("ldp_af_global_get: unknown af"); + } +} + +int +ldp_is_dual_stack(struct ldpd_conf *xconf) +{ + return ((xconf->ipv4.flags & F_LDPD_AF_ENABLED) && + (xconf->ipv6.flags & F_LDPD_AF_ENABLED)); +} + int ldp_reload(void) { @@ -651,6 +689,8 @@ void merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf) { merge_global(conf, xconf); + merge_af(AF_INET, &conf->ipv4, &xconf->ipv4); + merge_af(AF_INET6, &conf->ipv6, &xconf->ipv6); merge_ifaces(conf, xconf); merge_tnbrs(conf, xconf); merge_nbrps(conf, xconf); @@ -661,68 +701,91 @@ merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf) void merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf) { - struct nbr *nbr; - struct nbr_params *nbrp; - int egress_label_changed = 0; - /* change of router-id requires resetting all neighborships */ if (conf->rtr_id.s_addr != xconf->rtr_id.s_addr) { if (ldpd_process == PROC_LDP_ENGINE) { - ldpe_reset_nbrs(); + ldpe_reset_nbrs(AF_INET); + ldpe_reset_nbrs(AF_INET6); if (conf->rtr_id.s_addr == INADDR_ANY || xconf->rtr_id.s_addr == INADDR_ANY) { - if_update_all(); - tnbr_update_all(); + if_update_all(AF_UNSPEC); + tnbr_update_all(AF_UNSPEC); } } conf->rtr_id = xconf->rtr_id; } - if (conf->keepalive != xconf->keepalive) { - conf->keepalive = xconf->keepalive; + if (conf->trans_pref != xconf->trans_pref) { + if (ldpd_process == PROC_LDP_ENGINE) + ldpe_reset_ds_nbrs(); + conf->trans_pref = xconf->trans_pref; + } + + if ((conf->flags & F_LDPD_DS_CISCO_INTEROP) != + (xconf->flags & F_LDPD_DS_CISCO_INTEROP)) { if (ldpd_process == PROC_LDP_ENGINE) - ldpe_stop_init_backoff(); + ldpe_reset_ds_nbrs(); } - conf->thello_holdtime = xconf->thello_holdtime; - conf->thello_interval = xconf->thello_interval; + conf->flags = xconf->flags; +} + +void +merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa) +{ + struct nbr *nbr; + struct nbr_params *nbrp; + int egress_label_changed = 0; + + if (af_conf->keepalive != xa->keepalive) { + af_conf->keepalive = xa->keepalive; + if (ldpd_process == PROC_LDP_ENGINE) + ldpe_stop_init_backoff(af); + } + af_conf->thello_holdtime = xa->thello_holdtime; + af_conf->thello_interval = xa->thello_interval; /* update flags */ if (ldpd_process == PROC_LDP_ENGINE && - (conf->flags & F_LDPD_TH_ACCEPT) && - !(xconf->flags & F_LDPD_TH_ACCEPT)) - ldpe_remove_dynamic_tnbrs(); + (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) && + !(xa->flags & F_LDPD_AF_THELLO_ACCEPT)) + ldpe_remove_dynamic_tnbrs(af); - if ((conf->flags & F_LDPD_EXPNULL) != - (xconf->flags & F_LDPD_EXPNULL)) + if ((af_conf->flags & F_LDPD_AF_EXPNULL) != + (xa->flags & F_LDPD_AF_EXPNULL)) egress_label_changed = 1; - conf->flags = xconf->flags; + af_conf->flags = xa->flags; if (egress_label_changed) { switch (ldpd_process) { case PROC_LDE_ENGINE: - lde_change_egress_label(conf->flags & F_LDPD_EXPNULL); + lde_change_egress_label(af, af_conf->flags & + F_LDPD_AF_EXPNULL); break; case PROC_MAIN: - kr_change_egress_label(conf->flags & F_LDPD_EXPNULL); + kr_change_egress_label(af, af_conf->flags & + F_LDPD_AF_EXPNULL); break; default: break; } } - if (conf->trans_addr.s_addr != xconf->trans_addr.s_addr) { - conf->trans_addr = xconf->trans_addr; + if (ldp_addrcmp(af, &af_conf->trans_addr, &xa->trans_addr)) { + af_conf->trans_addr = xa->trans_addr; if (ldpd_process == PROC_MAIN) - imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, 0, + imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, af, 0, -1, NULL, 0); if (ldpd_process == PROC_LDP_ENGINE) { RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { + if (nbr->af != af) + continue; + session_shutdown(nbr, S_SHUTDOWN, 0, 0); pfkey_remove(nbr); - nbr->laddr = conf->trans_addr; + nbr->laddr = af_conf->trans_addr; nbrp = nbr_params_find(leconf, nbr->id); if (nbrp && pfkey_establish(nbr, nbrp) == -1) fatalx("pfkey setup failed"); @@ -759,14 +822,26 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf) } /* update existing interfaces */ - iface->hello_holdtime = xi->hello_holdtime; - iface->hello_interval = xi->hello_interval; + merge_iface_af(&iface->ipv4, &xi->ipv4); + merge_iface_af(&iface->ipv6, &xi->ipv6); LIST_REMOVE(xi, entry); free(xi); } } void +merge_iface_af(struct iface_af *ia, struct iface_af *xi) +{ + if (ia->enabled != xi->enabled) { + ia->enabled = xi->enabled; + if (ldpd_process == PROC_LDP_ENGINE) + if_update(ia->iface, ia->af); + } + ia->hello_holdtime = xi->hello_holdtime; + ia->hello_interval = xi->hello_interval; +} + +void merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf) { struct tnbr *tnbr, *ttmp, *xt; @@ -776,7 +851,7 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf) continue; /* find deleted tnbrs */ - if ((xt = tnbr_find(xconf, tnbr->addr)) == NULL) { + if ((xt = tnbr_find(xconf, tnbr->af, &tnbr->addr)) == NULL) { if (ldpd_process == PROC_LDP_ENGINE) { tnbr->flags &= ~F_TNBR_CONFIGURED; tnbr_check(tnbr); @@ -788,7 +863,7 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf) } LIST_FOREACH_SAFE(xt, &xconf->tnbr_list, entry, ttmp) { /* find new tnbrs */ - if ((tnbr = tnbr_find(conf, xt->addr)) == NULL) { + if ((tnbr = tnbr_find(conf, xt->af, &xt->addr)) == NULL) { LIST_REMOVE(xt, entry); LIST_INSERT_HEAD(&conf->tnbr_list, xt, entry); @@ -997,7 +1072,8 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) } /* update existing pseudowire */ - if (pw->lsr_id.s_addr != xp->lsr_id.s_addr) + if (pw->af != xp->af || + ldp_addrcmp(pw->af, &pw->addr, &xp->addr)) reinstall_tnbr = 1; else reinstall_tnbr = 0; @@ -1029,6 +1105,8 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) !reset_nbr && reinstall_pwfec) l2vpn_pw_exit(pw); pw->lsr_id = xp->lsr_id; + pw->af = xp->af; + pw->addr = xp->addr; pw->pwid = xp->pwid; strlcpy(pw->ifname, xp->ifname, sizeof(pw->ifname)); pw->ifindex = xp->ifindex; diff --git a/usr.sbin/ldpd/ldpd.conf.5 b/usr.sbin/ldpd/ldpd.conf.5 index 49de2c22dc6..050a2a9ff6e 100644 --- a/usr.sbin/ldpd/ldpd.conf.5 +++ b/usr.sbin/ldpd/ldpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ldpd.conf.5,v 1.26 2016/05/23 18:49:22 renato Exp $ +.\" $OpenBSD: ldpd.conf.5,v 1.27 2016/05/23 18:58:48 renato Exp $ .\" .\" Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> .\" Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org> @@ -31,7 +31,7 @@ daemon implements the Label Distribution Protocol as described in RFC 5036. .Sh SECTIONS The .Nm -config file is divided into six main sections. +config file is divided into seven main sections. .Bl -tag -width xxxx .It Sy Macros User-defined variables may be defined and used later, simplifying the @@ -39,6 +39,8 @@ configuration file. .It Sy Global Configuration Global settings for .Xr ldpd 8 . +.It Sy Address-Family Configuration +Address-family specific parameters. .It Sy Interfaces Configuration Interface-specific parameters. .It Sy Targeted Neighbors Configuration @@ -78,18 +80,19 @@ neighbor 10.0.1.5 { } .Ed .Sh GLOBAL CONFIGURATION -All interface related settings can be configured globally and per interface. +Several settings can be configured globally or within a more restricted scope, +like per address-family or per interface. The only settings that can be set globally and not overruled are listed below. .Pp .Bl -tag -width Ds -compact .It Xo -.Ic explicit-null +.Ic ds-cisco-interop .Pq Ic yes Ns | Ns Ic no .Xc If set to .Ic yes , -advertise explicit-null labels in place of implicit-null labels for directly -connected prefixes. +Cisco non-compliant format will be used to send and interpret the Dual-Stack +capability TLV. The default is .Ic no . .Pp @@ -104,15 +107,48 @@ table. The default is .Ic yes . .Pp -.It Ic keepalive Ar seconds -Set the keepalive timeout in seconds. -The default value is 180; valid range is 1\-65535. -.Pp .It Ic router-id Ar address Set the router ID; in combination with labelspace it forms the LSR-ID. If not specified, the numerically lowest IP address of the router will be used. .Pp .It Xo +.Ic transport-preference +.Pq Ic ipv4 Ns | Ns Ic ipv6 +.Xc +Specify the prefered address-family for TCP transport connections. +If two dual-stack LSRs preferences does not match, no LDP session will +be established. +The default is +.Ic ipv6 . +.El +.Sh ADDRESS-FAMILY CONFIGURATION +Each address-family can have several parameters configured +individually, otherwise they are inherited. +.Bd -literal -offset indent +address-family ipv6 { + explicit-null yes + transport-address 2001:db8::50 + interface em0 +} +.Ed +.Pp +.Bl -tag -width Ds -compact +.It Xo +.Ic explicit-null +.Pq Ic yes Ns | Ns Ic no +.Xc +If set to +.Ic yes , +advertise explicit-null labels in place of implicit-null labels for directly +connected prefixes. +The default is +.Ic no . +.Pp +.It Ic keepalive Ar seconds +Set the keepalive timeout in seconds. +The default value is 180; valid range is 3\-65535. +.Pp +.It Xo .Ic targeted-hello-accept .Pq Ic yes Ns | Ns Ic no .Xc @@ -125,13 +161,18 @@ The default is .Pp .It Ic transport-address Ar address Set the local address to be used in the TCP sessions. -If not specified, the router-id will be used. +For the IPv4 address-family, the router-id will be used if this option is not specified. +For the IPv6 address-family, this option must be specified. .El .Sh INTERFACES Each interface can have several parameters configured individually, otherwise they are inherited. .Bd -literal -offset indent -interface em0 { +address-family ipv4 { + interface em0 { + link-hello-holdtime 9 + link-hello-interval 3 + } } .Ed .Pp @@ -152,7 +193,14 @@ The default value is 5; valid range is 1\-65535. Each targeted neighbor can have several parameters configured individually, otherwise they are inherited. .Bd -literal -offset indent -targeted-neighbor A.B.C.D { +address-family ipv4 { + targeted-neighbor A.B.C.D { + targeted-hello-holdtime 90 + targeted-hello-interval 10 + } +} +address-family ipv6 { + targeted-neighbor 2001:db8::1 } .Ed .Pp @@ -178,6 +226,7 @@ Note, however, that uses the hello discovery mechanism to discover its neighbors. Without an underlying adjacency these commands have no effect. A neighbor is identified by its LSR-ID, not by its remote address. +The neighbor-specific parameters apply for both LDPoIPv4 and LDPoIPv6 sessions. .Bd -literal -offset indent neighbor A.B.C.D { } @@ -264,9 +313,13 @@ preferred. The default is .Ic yes . .Pp -.It Ic neighbor Ar address -Specify the endpoint of the pseudowire on the remote PE router. +.It Ic neighbor-addr Ar address +Specify the IPv4 or IPv6 address of the remote endpoint of the pseudowire. A targeted neighbor will automatically be created for this address. +By default, the LSR-ID of the remote endpoint of the pseudowire will be used. +.Pp +.It Ic neighbor-id Ar address +Specify the LSR-ID of the remote endpoint of the pseudowire. .Pp .It Ic pw-id Ar number Set the PW ID used to identify the pseudowire. diff --git a/usr.sbin/ldpd/ldpd.h b/usr.sbin/ldpd/ldpd.h index 4962a09e678..ddd1ddcbd0c 100644 --- a/usr.sbin/ldpd/ldpd.h +++ b/usr.sbin/ldpd/ldpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpd.h,v 1.70 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: ldpd.h,v 1.71 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -127,6 +127,16 @@ enum imsg_type { IMSG_RECONF_END }; +union ldpd_addr { + struct in_addr v4; + struct in6_addr v6; +}; + +#define IN6_IS_SCOPE_EMBED(a) \ + ((IN6_IS_ADDR_LINKLOCAL(a)) || \ + (IN6_IS_ADDR_MC_LINKLOCAL(a)) || \ + (IN6_IS_ADDR_MC_INTFACELOCAL(a))) + /* interface states */ #define IF_STA_DOWN 0x01 #define IF_STA_ACTIVE 0x02 @@ -180,11 +190,12 @@ TAILQ_HEAD(mapping_head, mapping_entry); struct map { uint8_t type; uint32_t messageid; - union map_fec { + union { struct { - struct in_addr prefix; + uint16_t af; + union ldpd_addr prefix; uint8_t prefixlen; - } ipv4; + } prefix; struct { uint16_t type; uint32_t pwid; @@ -216,29 +227,37 @@ struct notify_msg { struct if_addr { LIST_ENTRY(if_addr) entry; - struct in_addr addr; - struct in_addr mask; - struct in_addr dstbrd; + int af; + union ldpd_addr addr; + uint8_t prefixlen; + union ldpd_addr dstbrd; }; LIST_HEAD(if_addr_head, if_addr); -struct iface { - LIST_ENTRY(iface) entry; - struct event hello_timer; - - char name[IF_NAMESIZE]; - struct if_addr_head addr_list; +struct iface_af { + struct iface *iface; + int af; + int enabled; + int state; LIST_HEAD(, adj) adj_list; - time_t uptime; - unsigned int ifindex; - int state; + struct event hello_timer; uint16_t hello_holdtime; uint16_t hello_interval; - uint16_t flags; +}; + +struct iface { + LIST_ENTRY(iface) entry; + char name[IF_NAMESIZE]; + unsigned int ifindex; + struct if_addr_head addr_list; + struct in6_addr linklocal; enum iface_type type; uint8_t if_type; + uint16_t flags; uint8_t linkstate; + struct iface_af ipv4; + struct iface_af ipv6; }; /* source of targeted hellos */ @@ -246,8 +265,8 @@ struct tnbr { LIST_ENTRY(tnbr) entry; struct event hello_timer; struct adj *adj; - struct in_addr addr; - + int af; + union ldpd_addr addr; int state; uint16_t hello_holdtime; uint16_t hello_interval; @@ -289,6 +308,8 @@ struct l2vpn_pw { LIST_ENTRY(l2vpn_pw) entry; struct l2vpn *l2vpn; struct in_addr lsr_id; + int af; + union ldpd_addr addr; uint32_t pwid; char ifname[IF_NAMESIZE]; unsigned int ifindex; @@ -335,30 +356,49 @@ enum hello_type { HELLO_TARGETED }; +struct ldpd_af_conf { + uint16_t keepalive; + uint16_t thello_holdtime; + uint16_t thello_interval; + union ldpd_addr trans_addr; + int flags; +}; +#define F_LDPD_AF_ENABLED 0x0001 +#define F_LDPD_AF_THELLO_ACCEPT 0x0002 +#define F_LDPD_AF_EXPNULL 0x0004 + struct ldpd_conf { struct in_addr rtr_id; - struct in_addr trans_addr; + struct ldpd_af_conf ipv4; + struct ldpd_af_conf ipv6; LIST_HEAD(, iface) iface_list; LIST_HEAD(, tnbr) tnbr_list; LIST_HEAD(, nbr_params) nbrp_list; LIST_HEAD(, l2vpn) l2vpn_list; - uint16_t keepalive; - uint16_t thello_holdtime; - uint16_t thello_interval; + uint16_t trans_pref; int flags; }; #define F_LDPD_NO_FIB_UPDATE 0x0001 -#define F_LDPD_TH_ACCEPT 0x0002 -#define F_LDPD_EXPNULL 0x0004 +#define F_LDPD_DS_CISCO_INTEROP 0x0002 + +struct ldpd_af_global { + struct event disc_ev; + struct event edisc_ev; + int ldp_disc_socket; + int ldp_edisc_socket; + int ldp_session_socket; +}; struct ldpd_global { int cmd_opts; time_t uptime; + struct ldpd_af_global ipv4; + struct ldpd_af_global ipv6; int pfkeysock; - int ldp_disc_socket; - int ldp_edisc_socket; - int ldp_session_socket; struct if_addr_head addr_list; + LIST_HEAD(, adj) adj_list; + struct in_addr mcast_addr_v4; + struct in6_addr mcast_addr_v6; TAILQ_HEAD(, pending_conn) pending_conns; }; @@ -366,20 +406,22 @@ extern struct ldpd_global global; /* kroute */ struct kroute { - struct in_addr prefix; - struct in_addr nexthop; + int af; + union ldpd_addr prefix; + uint8_t prefixlen; + union ldpd_addr nexthop; uint32_t local_label; uint32_t remote_label; - uint16_t flags; unsigned short ifindex; - uint8_t prefixlen; uint8_t priority; + uint16_t flags; }; struct kpw { unsigned short ifindex; int pw_type; - struct in_addr nexthop; + int af; + union ldpd_addr nexthop; uint32_t local_label; uint32_t remote_label; uint8_t flags; @@ -387,55 +429,62 @@ struct kpw { struct kaddr { unsigned short ifindex; - struct in_addr addr; - struct in_addr mask; - struct in_addr dstbrd; + int af; + union ldpd_addr addr; + uint8_t prefixlen; + union ldpd_addr dstbrd; }; struct kif { char ifname[IF_NAMESIZE]; - uint64_t baudrate; + unsigned short ifindex; int flags; + uint8_t link_state; int mtu; - unsigned short ifindex; uint8_t if_type; - uint8_t link_state; + uint64_t baudrate; }; /* control data structures */ struct ctl_iface { + int af; char name[IF_NAMESIZE]; - time_t uptime; unsigned int ifindex; int state; - uint16_t adj_cnt; uint16_t flags; - uint16_t hello_holdtime; - uint16_t hello_interval; - enum iface_type type; uint8_t linkstate; + enum iface_type type; uint8_t if_type; + uint16_t hello_holdtime; + uint16_t hello_interval; + time_t uptime; + uint16_t adj_cnt; }; struct ctl_adj { + int af; struct in_addr id; enum hello_type type; char ifname[IF_NAMESIZE]; - struct in_addr src_addr; + union ldpd_addr src_addr; uint16_t holdtime; + union ldpd_addr trans_addr; }; struct ctl_nbr { + int af; struct in_addr id; - struct in_addr addr; + union ldpd_addr laddr; + union ldpd_addr raddr; time_t uptime; int nbr_state; }; struct ctl_rt { - struct in_addr prefix; + int af; + union ldpd_addr prefix; uint8_t prefixlen; - struct in_addr nexthop; + struct in_addr nexthop; /* lsr-id */ uint32_t local_label; uint32_t remote_label; uint8_t flags; @@ -470,13 +519,11 @@ void kif_clear(void); void kr_shutdown(void); void kr_fib_couple(void); void kr_fib_decouple(void); -void kr_change_egress_label(int); +void kr_change_egress_label(int, int); void kr_dispatch_msg(int, short, void *); void kr_show_route(struct imsg *); void kr_ifinfo(char *, pid_t); struct kif *kif_findname(char *); -uint8_t mask2prefixlen(in_addr_t); -in_addr_t prefixlen2mask(uint8_t); int kmpw_set(struct kpw *); int kmpw_unset(struct kpw *); int kmpw_install(const char *, struct kpw *); @@ -490,8 +537,25 @@ const char *notification_name(uint32_t); /* util.c */ uint8_t mask2prefixlen(in_addr_t); +uint8_t mask2prefixlen6(struct sockaddr_in6 *); in_addr_t prefixlen2mask(uint8_t); -int bad_ip_addr(struct in_addr); +struct in6_addr *prefixlen2mask6(uint8_t); +void ldp_applymask(int, union ldpd_addr *, + const union ldpd_addr *, int); +int ldp_addrcmp(int, const union ldpd_addr *, + const union ldpd_addr *); +int ldp_addrisset(int, const union ldpd_addr *); +int ldp_prefixcmp(int, const union ldpd_addr *, + const union ldpd_addr *, uint8_t); +int bad_addr_v4(struct in_addr); +int bad_addr_v6(struct in6_addr *); +int bad_addr(int, union ldpd_addr *); +void embedscope(struct sockaddr_in6 *); +void recoverscope(struct sockaddr_in6 *); +void addscope(struct sockaddr_in6 *, uint32_t); +void clearscope(struct in6_addr *); +struct sockaddr *addr2sa(int af, union ldpd_addr *, uint16_t); +void sa2addr(struct sockaddr *, int *, union ldpd_addr *); /* ldpd.c */ void main_imsg_compose_ldpe(int, pid_t, void *, uint16_t); @@ -506,8 +570,12 @@ void evbuf_event_add(struct evbuf *); void evbuf_init(struct evbuf *, int, void (*)(int, short, void *), void *); void evbuf_clear(struct evbuf *); +struct ldpd_af_conf *ldp_af_conf_get(struct ldpd_conf *, int); +struct ldpd_af_global *ldp_af_global_get(struct ldpd_global *, int); +int ldp_is_dual_stack(struct ldpd_conf *); + /* socket.c */ -int ldp_create_socket(enum socket_type); +int ldp_create_socket(int, enum socket_type); void sock_set_recvbuf(int); int sock_set_reuse(int, int); int sock_set_bindany(int, int); @@ -516,6 +584,10 @@ int sock_set_ipv4_tos(int, int); int sock_set_ipv4_recvif(int, int); int sock_set_ipv4_mcast(struct iface *); int sock_set_ipv4_mcast_loop(int); +int sock_set_ipv6_dscp(int, int); +int sock_set_ipv6_pktinfo(int, int); +int sock_set_ipv6_mcast(struct iface *); +int sock_set_ipv6_mcast_loop(int); /* printconf.c */ void print_config(struct ldpd_conf *); diff --git a/usr.sbin/ldpd/ldpe.c b/usr.sbin/ldpd/ldpe.c index 228e1f9bc5e..a269298d55d 100644 --- a/usr.sbin/ldpd/ldpe.c +++ b/usr.sbin/ldpd/ldpe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpe.c,v 1.56 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: ldpe.c,v 1.57 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -32,6 +32,7 @@ #include <pwd.h> #include <unistd.h> #include <event.h> +#include <arpa/inet.h> #include <err.h> #include <errno.h> #include <stdio.h> @@ -49,9 +50,7 @@ void ldpe_shutdown(void); struct ldpd_conf *leconf = NULL, *nconf; struct imsgev *iev_main; struct imsgev *iev_lde; -struct event disc_ev; -struct event edisc_ev; -struct event pfkey_ev; +struct event pfkey_ev; struct ldpd_sysdep sysdep; /* ARGSUSED */ @@ -97,7 +96,12 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2], fatalx("control socket setup failed"); LIST_INIT(&global.addr_list); + LIST_INIT(&global.adj_list); TAILQ_INIT(&global.pending_conns); + if (inet_pton(AF_INET, AllRouters_v4, &global.mcast_addr_v4) != 1) + fatal("inet_pton"); + if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1) + fatal("inet_pton"); global.pfkeysock = pfkey_init(&sysdep); if ((pw = getpwnam(LDPD_USER)) == NULL) @@ -159,9 +163,12 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2], } /* mark sockets as closed */ - global.ldp_disc_socket = -1; - global.ldp_edisc_socket = -1; - global.ldp_session_socket = -1; + global.ipv4.ldp_disc_socket = -1; + global.ipv4.ldp_edisc_socket = -1; + global.ipv4.ldp_session_socket = -1; + global.ipv6.ldp_disc_socket = -1; + global.ipv6.ldp_edisc_socket = -1; + global.ipv6.ldp_session_socket = -1; /* listen on ldpd control socket */ TAILQ_INIT(&ctl_conns); @@ -185,6 +192,7 @@ void ldpe_shutdown(void) { struct if_addr *if_addr; + struct adj *adj; control_cleanup(); config_clear(leconf); @@ -193,13 +201,16 @@ ldpe_shutdown(void) event_del(&pfkey_ev); close(global.pfkeysock); } - ldpe_close_sockets(); + ldpe_close_sockets(AF_INET); + ldpe_close_sockets(AF_INET6); /* remove addresses from global list */ while ((if_addr = LIST_FIRST(&global.addr_list)) != NULL) { LIST_REMOVE(if_addr, entry); free(if_addr); } + while ((adj = LIST_FIRST(&global.adj_list)) != NULL) + adj_del(adj); /* clean up */ msgbuf_write(&iev_lde->ibuf.w); @@ -244,6 +255,7 @@ ldpe_dispatch_main(int fd, short event, void *bula) struct imsgbuf *ibuf = &iev->ibuf; struct iface *iface = NULL; struct kif *kif; + int af; enum socket_type *socket_type; static int disc_socket = -1; static int edisc_socket = -1; @@ -282,7 +294,7 @@ ldpe_dispatch_main(int fd, short event, void *bula) iface->flags = kif->flags; iface->linkstate = kif->link_state; - if_update(iface); + if_update(iface, AF_UNSPEC); break; case IMSG_NEWADDR: if (imsg.hdr.len != IMSG_HEADER_SIZE + @@ -299,9 +311,11 @@ ldpe_dispatch_main(int fd, short event, void *bula) if_addr_del(imsg.data); break; case IMSG_CLOSE_SOCKETS: - ldpe_close_sockets(); - if_update_all(); - tnbr_update_all(); + af = imsg.hdr.peerid; + + ldpe_close_sockets(af); + if_update_all(af); + tnbr_update_all(af); disc_socket = -1; edisc_socket = -1; @@ -328,6 +342,7 @@ ldpe_dispatch_main(int fd, short event, void *bula) } break; case IMSG_SETUP_SOCKETS: + af = imsg.hdr.peerid; if (disc_socket == -1 || edisc_socket == -1 || session_socket == -1) { if (disc_socket != -1) @@ -339,10 +354,10 @@ ldpe_dispatch_main(int fd, short event, void *bula) break; } - ldpe_setup_sockets(disc_socket, edisc_socket, + ldpe_setup_sockets(af, disc_socket, edisc_socket, session_socket); - if_update_all(); - tnbr_update_all(); + if_update_all(af); + tnbr_update_all(af); break; case IMSG_RECONF_CONF: if ((nconf = malloc(sizeof(struct ldpd_conf))) == @@ -361,7 +376,10 @@ ldpe_dispatch_main(int fd, short event, void *bula) memcpy(niface, imsg.data, sizeof(struct iface)); LIST_INIT(&niface->addr_list); - LIST_INIT(&niface->adj_list); + LIST_INIT(&niface->ipv4.adj_list); + LIST_INIT(&niface->ipv6.adj_list); + niface->ipv4.iface = niface; + niface->ipv6.iface = niface; LIST_INSERT_HEAD(&nconf->iface_list, niface, entry); break; @@ -577,79 +595,103 @@ ldpe_dispatch_pfkey(int fd, short event, void *bula) } void -ldpe_setup_sockets(int disc_socket, int edisc_socket, int session_socket) +ldpe_setup_sockets(int af, int disc_socket, int edisc_socket, int session_socket) { + struct ldpd_af_global *af_global; + + af_global = ldp_af_global_get(&global, af); + /* discovery socket */ - global.ldp_disc_socket = disc_socket; - event_set(&disc_ev, global.ldp_disc_socket, + af_global->ldp_disc_socket = disc_socket; + event_set(&af_global->disc_ev, af_global->ldp_disc_socket, EV_READ|EV_PERSIST, disc_recv_packet, NULL); - event_add(&disc_ev, NULL); + event_add(&af_global->disc_ev, NULL); /* extended discovery socket */ - global.ldp_edisc_socket = edisc_socket; - event_set(&edisc_ev, global.ldp_edisc_socket, + af_global->ldp_edisc_socket = edisc_socket; + event_set(&af_global->edisc_ev, af_global->ldp_edisc_socket, EV_READ|EV_PERSIST, disc_recv_packet, NULL); - event_add(&edisc_ev, NULL); + event_add(&af_global->edisc_ev, NULL); /* session socket */ - global.ldp_session_socket = session_socket; - accept_add(global.ldp_session_socket, session_accept, NULL); + af_global->ldp_session_socket = session_socket; + accept_add(af_global->ldp_session_socket, session_accept, NULL); } void -ldpe_close_sockets(void) +ldpe_close_sockets(int af) { + struct ldpd_af_global *af_global; + + af_global = ldp_af_global_get(&global, af); + /* discovery socket */ - if (event_initialized(&disc_ev)) - event_del(&disc_ev); - if (global.ldp_disc_socket != -1) { - close(global.ldp_disc_socket); - global.ldp_disc_socket = -1; + if (event_initialized(&af_global->disc_ev)) + event_del(&af_global->disc_ev); + if (af_global->ldp_disc_socket != -1) { + close(af_global->ldp_disc_socket); + af_global->ldp_disc_socket = -1; } /* extended discovery socket */ - if (event_initialized(&edisc_ev)) - event_del(&edisc_ev); - if (global.ldp_edisc_socket != -1) { - close(global.ldp_edisc_socket); - global.ldp_edisc_socket = -1; + if (event_initialized(&af_global->edisc_ev)) + event_del(&af_global->edisc_ev); + if (af_global->ldp_edisc_socket != -1) { + close(af_global->ldp_edisc_socket); + af_global->ldp_edisc_socket = -1; } /* session socket */ - if (global.ldp_session_socket != -1) { - accept_del(global.ldp_session_socket); - close(global.ldp_session_socket); - global.ldp_session_socket = -1; + if (af_global->ldp_session_socket != -1) { + accept_del(af_global->ldp_session_socket); + close(af_global->ldp_session_socket); + af_global->ldp_session_socket = -1; + } +} + +void +ldpe_reset_nbrs(int af) +{ + struct nbr *nbr; + + RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { + if (nbr->af == af) + session_shutdown(nbr, S_SHUTDOWN, 0, 0); } } void -ldpe_reset_nbrs(void) +ldpe_reset_ds_nbrs(void) { struct nbr *nbr; - RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) - session_shutdown(nbr, S_SHUTDOWN, 0, 0); + RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { + if (nbr->ds_tlv) + session_shutdown(nbr, S_SHUTDOWN, 0, 0); + } } void -ldpe_remove_dynamic_tnbrs(void) +ldpe_remove_dynamic_tnbrs(int af) { struct tnbr *tnbr, *safe; LIST_FOREACH_SAFE(tnbr, &leconf->tnbr_list, entry, safe) { + if (tnbr->af != af) + continue; + tnbr->flags &= ~F_TNBR_DYNAMIC; tnbr_check(tnbr); } } void -ldpe_stop_init_backoff(void) +ldpe_stop_init_backoff(int af) { struct nbr *nbr; RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { - if (nbr_pending_idtimer(nbr)) { + if (nbr->af == af && nbr_pending_idtimer(nbr)) { nbr_stop_idtimer(nbr); nbr_establish_connection(nbr); } @@ -657,14 +699,19 @@ ldpe_stop_init_backoff(void) } void -ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx) +ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx) { struct iface *iface; + struct iface_af *ia; struct ctl_iface *ictl; LIST_FOREACH(iface, &leconf->iface_list, entry) { if (idx == 0 || idx == iface->ifindex) { - ictl = if_to_ctl(iface); + ia = iface_af_get(iface, af); + if (!ia->enabled) + continue; + + ictl = if_to_ctl(ia); imsg_compose_event(&c->iev, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, ictl, sizeof(struct ctl_iface)); @@ -673,28 +720,35 @@ ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx) } void +ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx) +{ + ldpe_iface_af_ctl(c, AF_INET, idx); + ldpe_iface_af_ctl(c, AF_INET6, idx); +} + +void ldpe_adj_ctl(struct ctl_conn *c) { + struct nbr *nbr; struct adj *adj; - struct iface *iface; - struct tnbr *tnbr; struct ctl_adj *actl; - /* basic discovery mechanism */ - LIST_FOREACH(iface, &leconf->iface_list, entry) - LIST_FOREACH(adj, &iface->adj_list, iface_entry) { + RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) { + LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) { actl = adj_to_ctl(adj); imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, actl, sizeof(struct ctl_adj)); } - - /* extended discovery mechanism */ - LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) - if (tnbr->adj) { - actl = adj_to_ctl(tnbr->adj); - imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, - 0, 0, -1, actl, sizeof(struct ctl_adj)); - } + } + /* show adjacencies not associated with any neighbor */ + LIST_FOREACH(adj, &global.adj_list, global_entry) { + if (adj->nbr != NULL) + continue; + + actl = adj_to_ctl(adj); + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, + -1, actl, sizeof(struct ctl_adj)); + } imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); } @@ -705,7 +759,7 @@ ldpe_nbr_ctl(struct ctl_conn *c) struct nbr *nbr; struct ctl_nbr *nctl; - RB_FOREACH(nbr, nbr_pid_head, &nbrs_by_pid) { + RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) { nctl = nbr_to_ctl(nbr); imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl, sizeof(struct ctl_nbr)); diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h index 77cc98dff40..8caea614685 100644 --- a/usr.sbin/ldpd/ldpe.h +++ b/usr.sbin/ldpd/ldpe.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpe.h,v 1.51 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: ldpe.h,v 1.52 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> @@ -31,23 +31,25 @@ struct hello_source { enum hello_type type; struct { - struct iface *iface; - struct in_addr src_addr; - } link; + struct iface_af *ia; + union ldpd_addr src_addr; + } link; struct tnbr *target; }; struct adj { + LIST_ENTRY(adj) global_entry; LIST_ENTRY(adj) nbr_entry; - LIST_ENTRY(adj) iface_entry; + LIST_ENTRY(adj) ia_entry; + struct in_addr lsr_id; struct nbr *nbr; + int ds_tlv; struct hello_source source; struct event inactivity_timer; uint16_t holdtime; - struct in_addr addr; + union ldpd_addr trans_addr; }; -struct nbr; struct tcp_conn { struct nbr *nbr; int fd; @@ -71,13 +73,16 @@ struct nbr { struct mapping_head release_list; struct mapping_head abortreq_list; - struct in_addr laddr; /* local address */ - struct in_addr raddr; /* remote address */ + uint32_t peerid; /* unique ID in DB */ + int af; + int ds_tlv; + int v4_enabled; /* announce/process v4 msgs */ + int v6_enabled; /* announce/process v6 msgs */ struct in_addr id; /* lsr id */ - + union ldpd_addr laddr; /* local address */ + union ldpd_addr raddr; /* remote address */ + uint32_t raddr_scope; /* remote address scope (v6) */ time_t uptime; - uint32_t peerid; /* unique ID in DB */ - int fd; int state; int idtimer_cnt; @@ -96,7 +101,8 @@ struct nbr { struct pending_conn { TAILQ_ENTRY(pending_conn) entry; int fd; - struct in_addr addr; + int af; + union ldpd_addr addr; struct event ev_timeout; }; #define PENDING_CONN_TIMEOUT 5 @@ -119,8 +125,8 @@ void accept_pause(void); void accept_unpause(void); /* hello.c */ -int send_hello(enum hello_type, struct iface *, struct tnbr *); -void recv_hello(struct in_addr, struct ldp_msg *, struct in_addr, +int send_hello(enum hello_type, struct iface_af *, struct tnbr *); +void recv_hello(struct in_addr, struct ldp_msg *, int, union ldpd_addr *, struct iface *, int, char *, uint16_t); /* init.c */ @@ -139,7 +145,7 @@ void send_notification_full(struct tcp_conn *, struct notify_msg *); int recv_notification(struct nbr *, char *, uint16_t); /* address.c */ -void send_address(struct nbr *, struct if_addr *, int); +void send_address(struct nbr *, int, struct if_addr *, int); int recv_address(struct nbr *, char *, uint16_t); /* labelmapping.c */ @@ -153,18 +159,21 @@ int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *, /* ldpe.c */ pid_t ldpe(struct ldpd_conf *, int[2], int[2], int[2]); -int ldpe_imsg_compose_parent(int, pid_t, void *, uint16_t); +int ldpe_imsg_compose_parent(int, pid_t, void *, + uint16_t); int ldpe_imsg_compose_lde(int, uint32_t, pid_t, void *, uint16_t); void ldpe_dispatch_main(int, short, void *); void ldpe_dispatch_lde(int, short, void *); void ldpe_dispatch_pfkey(int, short, void *); -void ldpe_setup_sockets(int, int, int); -void ldpe_close_sockets(void); -void ldpe_reset_nbrs(void); -void ldpe_remove_dynamic_tnbrs(void); -void ldpe_stop_init_backoff(void); +void ldpe_setup_sockets(int, int, int, int); +void ldpe_close_sockets(int); +void ldpe_reset_nbrs(int); +void ldpe_reset_ds_nbrs(void); +void ldpe_remove_dynamic_tnbrs(int); +void ldpe_stop_init_backoff(int); struct ctl_conn; +void ldpe_iface_af_ctl(struct ctl_conn *, int, unsigned int); void ldpe_iface_ctl(struct ctl_conn *, unsigned int); void ldpe_adj_ctl(struct ctl_conn *); void ldpe_nbr_ctl(struct ctl_conn *); @@ -172,47 +181,55 @@ void mapping_list_add(struct mapping_head *, struct map *); void mapping_list_clr(struct mapping_head *); /* interface.c */ -int if_start(struct iface *); -int if_reset(struct iface *); -int if_update(struct iface *); -void if_update_all(void); +int if_start(struct iface *, int); +int if_reset(struct iface *, int); +void if_update_af(struct iface_af *, int); +void if_update(struct iface *, int); +void if_update_all(int); struct iface *if_new(struct kif *); void if_del(struct iface *); struct iface *if_lookup(struct ldpd_conf *, unsigned short); +struct iface_af *iface_af_get(struct iface *, int); struct if_addr *if_addr_new(struct kaddr *); struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *); void if_addr_add(struct kaddr *); void if_addr_del(struct kaddr *); -struct ctl_iface *if_to_ctl(struct iface *); +struct ctl_iface *if_to_ctl(struct iface_af *); -int if_join_group(struct iface *, struct in_addr *); -int if_leave_group(struct iface *, struct in_addr *); +in_addr_t if_get_ipv4_addr(struct iface *); +int if_join_ipv4_group(struct iface *, struct in_addr *); +int if_leave_ipv4_group(struct iface *, struct in_addr *); +int if_join_ipv6_group(struct iface *, struct in6_addr *); +int if_leave_ipv6_group(struct iface *, struct in6_addr *); /* adjacency.c */ -struct adj *adj_new(struct nbr *, struct hello_source *, struct in_addr); +struct adj *adj_new(struct in_addr, struct hello_source *, + union ldpd_addr *); void adj_del(struct adj *); -struct adj *adj_find(struct nbr *, struct hello_source *); +struct adj *adj_find(struct hello_source *); +int adj_get_af(struct adj *adj); void adj_start_itimer(struct adj *); void adj_stop_itimer(struct adj *); -struct tnbr *tnbr_new(struct ldpd_conf *, struct in_addr); +struct tnbr *tnbr_new(struct ldpd_conf *, int, union ldpd_addr *); void tnbr_del(struct tnbr *); -struct tnbr *tnbr_find(struct ldpd_conf *, struct in_addr); +struct tnbr *tnbr_find(struct ldpd_conf *, int, union ldpd_addr *); struct tnbr *tnbr_check(struct tnbr *); void tnbr_update(struct tnbr *); -void tnbr_update_all(void); +void tnbr_update_all(int); struct ctl_adj *adj_to_ctl(struct adj *); /* neighbor.c */ -struct nbr *nbr_new(struct in_addr, struct in_addr); +struct nbr *nbr_new(struct in_addr, int, int, union ldpd_addr *, uint32_t); void nbr_del(struct nbr *); void nbr_update_peerid(struct nbr *); struct nbr *nbr_find_ldpid(uint32_t); -struct nbr *nbr_find_addr(struct in_addr); +struct nbr *nbr_find_addr(int, union ldpd_addr *); struct nbr *nbr_find_peerid(uint32_t); +int nbr_adj_count(struct nbr *, int); int nbr_fsm(struct nbr *, enum nbr_event); int nbr_session_active_role(struct nbr *); @@ -230,7 +247,7 @@ int nbr_pending_idtimer(struct nbr *); int nbr_pending_connect(struct nbr *); int nbr_establish_connection(struct nbr *); -uint16_t nbr_get_keepalive(struct in_addr); +uint16_t nbr_get_keepalive(int, struct in_addr); struct nbr_params *nbr_params_new(struct in_addr); struct nbr_params *nbr_params_find(struct ldpd_conf *, struct in_addr); @@ -246,7 +263,8 @@ RB_PROTOTYPE(nbr_pid_head, nbr, pid_tree, nbr_pid_compare) /* packet.c */ int gen_ldp_hdr(struct ibuf *, uint16_t); int gen_msg_hdr(struct ibuf *, uint32_t, uint16_t); -int send_packet(int, struct iface *, void *, size_t, struct sockaddr_in *); +int send_packet(int, int, union ldpd_addr *, struct iface_af *, void *, + size_t); void disc_recv_packet(int, short, void *); void session_accept(int, short, void *); void session_accept_nbr(struct nbr *, int); @@ -257,9 +275,9 @@ void session_shutdown(struct nbr *, uint32_t, uint32_t, uint32_t); struct tcp_conn *tcp_new(int, struct nbr *); void tcp_close(struct tcp_conn *); -struct pending_conn *pending_conn_new(int, struct in_addr); +struct pending_conn *pending_conn_new(int, int, union ldpd_addr *); void pending_conn_del(struct pending_conn *); -struct pending_conn *pending_conn_find(struct in_addr); +struct pending_conn *pending_conn_find(int, union ldpd_addr *); void pending_conn_timeout(int, short, void *); char *pkt_ptr; /* packet buffer */ diff --git a/usr.sbin/ldpd/log.c b/usr.sbin/ldpd/log.c index 5f5374dea46..077189a8c17 100644 --- a/usr.sbin/ldpd/log.c +++ b/usr.sbin/ldpd/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.24 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: log.c,v 1.25 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -28,6 +28,7 @@ #include <string.h> #include <syslog.h> #include <unistd.h> +#include <netdb.h> #include "ldpd.h" #include "ldpe.h" @@ -174,8 +175,92 @@ fatalx(const char *emsg) fatal(emsg); } +#define NUM_LOGS 4 +const char * +log_sockaddr(void *vp) +{ + static char buf[NUM_LOGS][NI_MAXHOST]; + static int round = 0; + struct sockaddr *sa = vp; + + round = (round + 1) % NUM_LOGS; + + if (getnameinfo(sa, sa->sa_len, buf[round], NI_MAXHOST, NULL, 0, + NI_NUMERICHOST)) + return ("(unknown)"); + else + return (buf[round]); +} + +const char * +log_in6addr(const struct in6_addr *addr) +{ + struct sockaddr_in6 sa_in6; + + memset(&sa_in6, 0, sizeof(sa_in6)); + sa_in6.sin6_len = sizeof(sa_in6); + sa_in6.sin6_family = AF_INET6; + sa_in6.sin6_addr = *addr; + + recoverscope(&sa_in6); + + return (log_sockaddr(&sa_in6)); +} + +const char * +log_in6addr_scope(const struct in6_addr *addr, unsigned int ifindex) +{ + struct sockaddr_in6 sa_in6; + + memset(&sa_in6, 0, sizeof(sa_in6)); + sa_in6.sin6_len = sizeof(sa_in6); + sa_in6.sin6_family = AF_INET6; + sa_in6.sin6_addr = *addr; + + addscope(&sa_in6, ifindex); + + return (log_sockaddr(&sa_in6)); +} + +const char * +log_addr(int af, const union ldpd_addr *addr) +{ + static char buf[NUM_LOGS][INET6_ADDRSTRLEN]; + static int round = 0; + + switch (af) { + case AF_INET: + round = (round + 1) % NUM_LOGS; + if (inet_ntop(AF_INET, &addr->v4, buf[round], + sizeof(buf[round])) == NULL) + return ("???"); + return (buf[round]); + case AF_INET6: + return (log_in6addr(&addr->v6)); + default: + break; + } + + return ("???"); +} + /* names */ const char * +af_name(int af) +{ + switch (af) { + case AF_INET: + return ("ipv4"); + case AF_INET6: + return ("ipv6"); + case AF_MPLS: + return ("mpls"); + default: + return ("UNKNOWN"); + } +} + +const char * socket_name(int type) { switch (type) { @@ -309,6 +394,10 @@ notification_name(uint32_t status) return ("Generic Misconfiguration Error"); case S_WITHDRAW_MTHD: return ("Label Withdraw PW Status Method"); + case S_TRANS_MISMTCH: + return ("Transport Connection Mismatch"); + case S_DS_NONCMPLNCE: + return ("Dual-Stack Noncompliance"); default: snprintf(buf, sizeof(buf), "[%08x]", status); return (buf); @@ -339,11 +428,11 @@ log_hello_src(const struct hello_source *src) switch (src->type) { case HELLO_LINK: snprintf(buffer, sizeof(buffer), "iface %s", - src->link.iface->name); + src->link.ia->iface->name); break; case HELLO_TARGETED: snprintf(buffer, sizeof(buffer), "source %s", - inet_ntoa(src->target->addr)); + log_addr(src->target->af, &src->target->addr)); break; } @@ -354,7 +443,7 @@ const char * log_map(const struct map *map) { static char buf[64]; - char pstr[64]; + int af; switch (map->type) { case MAP_TYPE_WILDCARD: @@ -362,9 +451,20 @@ log_map(const struct map *map) return ("???"); break; case MAP_TYPE_PREFIX: + switch (map->fec.prefix.af) { + case AF_IPV4: + af = AF_INET; + break; + case AF_IPV6: + af = AF_INET6; + break; + default: + return ("???"); + } + if (snprintf(buf, sizeof(buf), "%s/%u", - inet_ntop(AF_INET, &map->fec.ipv4.prefix, pstr, - sizeof(pstr)), map->fec.ipv4.prefixlen) == -1) + log_addr(af, &map->fec.prefix.prefix), + map->fec.prefix.prefixlen) == -1) return ("???"); break; case MAP_TYPE_PWID: @@ -384,13 +484,19 @@ const char * log_fec(const struct fec *fec) { static char buf[64]; - char pstr[32]; + union ldpd_addr addr; switch (fec->type) { case FEC_TYPE_IPV4: - if (snprintf(buf, sizeof(buf), "%s/%u", - inet_ntop(AF_INET, &fec->u.ipv4.prefix, pstr, - sizeof(pstr)), fec->u.ipv4.prefixlen) == -1) + addr.v4 = fec->u.ipv4.prefix; + if (snprintf(buf, sizeof(buf), "ipv4 %s/%u", + log_addr(AF_INET, &addr), fec->u.ipv4.prefixlen) == -1) + return ("???"); + break; + case FEC_TYPE_IPV6: + addr.v6 = fec->u.ipv6.prefix; + if (snprintf(buf, sizeof(buf), "ipv6 %s/%u", + log_addr(AF_INET6, &addr), fec->u.ipv6.prefixlen) == -1) return ("???"); break; case FEC_TYPE_PWID: diff --git a/usr.sbin/ldpd/log.h b/usr.sbin/ldpd/log.h index 043cc2ffc2f..aedc26dccc1 100644 --- a/usr.sbin/ldpd/log.h +++ b/usr.sbin/ldpd/log.h @@ -1,4 +1,4 @@ -/* $OpenBSD: log.h,v 1.9 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: log.h,v 1.10 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -21,6 +21,9 @@ #include <stdarg.h> +struct in6_addr; +union ldpd_addr; + void log_init(int); void log_verbose(int); void logit(int, const char *, ...); @@ -31,6 +34,7 @@ void log_info(const char *, ...); void log_debug(const char *, ...); void fatal(const char *) __dead; void fatalx(const char *) __dead; +const char *af_name(int); const char *socket_name(int); const char *pw_type_name(uint16_t); const char *log_map(const struct map *); @@ -40,4 +44,9 @@ void log_rtmsg(unsigned char); struct hello_source; char *log_hello_src(const struct hello_source *); +const char *log_in6addr(const struct in6_addr *); +const char *log_in6addr_scope(const struct in6_addr *, unsigned int); +const char *log_sockaddr(void *); +const char *log_addr(int, const union ldpd_addr *); + #endif /* _LOG_H_ */ diff --git a/usr.sbin/ldpd/neighbor.c b/usr.sbin/ldpd/neighbor.c index bee64588bb8..2d1c3dab295 100644 --- a/usr.sbin/ldpd/neighbor.c +++ b/usr.sbin/ldpd/neighbor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: neighbor.c,v 1.67 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: neighbor.c,v 1.68 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -66,12 +66,12 @@ nbr_id_compare(struct nbr *a, struct nbr *b) static __inline int nbr_addr_compare(struct nbr *a, struct nbr *b) { - if (ntohl(a->raddr.s_addr) < ntohl(b->raddr.s_addr)) + if (a->af < b->af) return (-1); - if (ntohl(a->raddr.s_addr) > ntohl(b->raddr.s_addr)) + if (a->af > b->af) return (1); - return (0); + return (ldp_addrcmp(a->af, &a->raddr, &b->raddr)); } static __inline int @@ -188,7 +188,10 @@ nbr_fsm(struct nbr *nbr, enum nbr_event event) nbr_act_session_operational(nbr); nbr_start_ktimer(nbr); nbr_start_ktimeout(nbr); - send_address(nbr, NULL, 0); + if (nbr->v4_enabled) + send_address(nbr, AF_INET, NULL, 0); + if (nbr->v6_enabled) + send_address(nbr, AF_INET6, NULL, 0); nbr_send_labelmappings(nbr); break; case NBR_ACT_CONNECT_SETUP: @@ -220,23 +223,40 @@ nbr_fsm(struct nbr *nbr, enum nbr_event event) } struct nbr * -nbr_new(struct in_addr id, struct in_addr addr) +nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr, + uint32_t scope_id) { struct nbr *nbr; struct nbr_params *nbrp; + struct adj *adj; struct pending_conn *pconn; - log_debug("%s: lsr-id %s", __func__, inet_ntoa(id)); + log_debug("%s: lsr-id %s transport-address %s", __func__, + inet_ntoa(id), log_addr(af, addr)); if ((nbr = calloc(1, sizeof(*nbr))) == NULL) fatal(__func__); LIST_INIT(&nbr->adj_list); nbr->state = NBR_STA_PRESENT; - nbr->id = id; - nbr->laddr = leconf->trans_addr; - nbr->raddr = addr; nbr->peerid = 0; + nbr->af = af; + nbr->ds_tlv = ds_tlv; + if (af == AF_INET || ds_tlv) + nbr->v4_enabled = 1; + if (af == AF_INET6 || ds_tlv) + nbr->v6_enabled = 1; + nbr->id = id; + nbr->laddr = (ldp_af_conf_get(leconf, af))->trans_addr; + nbr->raddr = *addr; + nbr->raddr_scope = scope_id; + + LIST_FOREACH(adj, &global.adj_list, global_entry) { + if (adj->lsr_id.s_addr == nbr->id.s_addr) { + adj->nbr = nbr; + LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry); + } + } if (RB_INSERT(nbr_id_head, &nbrs_by_id, nbr) != NULL) fatalx("nbr_new: RB_INSERT(nbrs_by_id) failed"); @@ -258,7 +278,7 @@ nbr_new(struct in_addr id, struct in_addr addr) if (nbrp && pfkey_establish(nbr, nbrp) == -1) fatalx("pfkey setup failed"); - pconn = pending_conn_find(nbr->raddr); + pconn = pending_conn_find(nbr->af, &nbr->raddr); if (pconn) { session_accept_nbr(nbr, pconn->fd); pending_conn_del(pconn); @@ -319,10 +339,11 @@ nbr_find_ldpid(uint32_t lsr_id) } struct nbr * -nbr_find_addr(struct in_addr addr) +nbr_find_addr(int af, union ldpd_addr *addr) { struct nbr n; - n.raddr = addr; + n.af = af; + n.raddr = *addr; return (RB_FIND(nbr_addr_head, &nbrs_by_addr, &n)); } @@ -335,9 +356,22 @@ nbr_find_peerid(uint32_t peerid) } int +nbr_adj_count(struct nbr *nbr, int af) +{ + struct adj *adj; + int total = 0; + + LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) + if (adj_get_af(adj) == af) + total++; + + return (total); +} + +int nbr_session_active_role(struct nbr *nbr) { - if (ntohl(nbr->laddr.s_addr) > ntohl(nbr->raddr.s_addr)) + if (ldp_addrcmp(nbr->af, &nbr->laddr, &nbr->raddr) > 0) return (1); return (0); @@ -492,7 +526,7 @@ nbr_connect_cb(int fd, short event, void *arg) close(nbr->fd); errno = error; log_debug("%s: error while connecting to %s: %s", __func__, - inet_ntoa(nbr->raddr), strerror(errno)); + log_addr(nbr->af, &nbr->raddr), strerror(errno)); return; } @@ -502,13 +536,14 @@ nbr_connect_cb(int fd, short event, void *arg) int nbr_establish_connection(struct nbr *nbr) { - struct sockaddr_in local_sa; - struct sockaddr_in remote_sa; + struct sockaddr_storage local_sa; + struct sockaddr_storage remote_sa; struct adj *adj; struct nbr_params *nbrp; int opt = 1; - nbr->fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); + nbr->fd = socket(nbr->af, + SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); if (nbr->fd == -1) { log_warn("%s: error while creating socket", __func__); return (-1); @@ -529,34 +564,30 @@ nbr_establish_connection(struct nbr *nbr) } } - memset(&local_sa, 0, sizeof(local_sa)); - local_sa.sin_family = AF_INET; - local_sa.sin_port = htons(0); - local_sa.sin_addr = nbr->laddr; + memcpy(&local_sa, addr2sa(nbr->af, &nbr->laddr, 0), sizeof(local_sa)); + memcpy(&remote_sa, addr2sa(nbr->af, &nbr->raddr, LDP_PORT), + sizeof(local_sa)); + if (nbr->af == AF_INET6 && nbr->raddr_scope) + addscope((struct sockaddr_in6 *)&remote_sa, nbr->raddr_scope); - if (bind(nbr->fd, (struct sockaddr *) &local_sa, - sizeof(struct sockaddr_in)) == -1) { + if (bind(nbr->fd, (struct sockaddr *)&local_sa, + local_sa.ss_len) == -1) { log_warn("%s: error while binding socket to %s", __func__, - inet_ntoa(local_sa.sin_addr)); + log_sockaddr((struct sockaddr *)&local_sa)); close(nbr->fd); return (-1); } - memset(&remote_sa, 0, sizeof(remote_sa)); - remote_sa.sin_family = AF_INET; - remote_sa.sin_port = htons(LDP_PORT); - remote_sa.sin_addr = nbr->raddr; - /* * Send an extra hello to guarantee that the remote peer has formed * an adjacency as well. */ LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) - send_hello(adj->source.type, adj->source.link.iface, + send_hello(adj->source.type, adj->source.link.ia, adj->source.target); if (connect(nbr->fd, (struct sockaddr *)&remote_sa, - sizeof(remote_sa)) == -1) { + remote_sa.ss_len) == -1) { if (errno == EINPROGRESS) { event_set(&nbr->ev_connect, nbr->fd, EV_WRITE, nbr_connect_cb, nbr); @@ -564,7 +595,7 @@ nbr_establish_connection(struct nbr *nbr) return (0); } log_warn("%s: error while connecting to %s", __func__, - inet_ntoa(nbr->raddr)); + log_sockaddr((struct sockaddr *)&remote_sa)); close(nbr->fd); return (-1); } @@ -578,13 +609,19 @@ nbr_establish_connection(struct nbr *nbr) int nbr_act_session_operational(struct nbr *nbr) { + struct lde_nbr lde_nbr; + nbr->idtimer_cnt = 0; /* this is necessary to avoid ipc synchronization issues */ nbr_update_peerid(nbr); + memset(&lde_nbr, 0, sizeof(lde_nbr)); + lde_nbr.id = nbr->id; + lde_nbr.v4_enabled = nbr->v4_enabled; + lde_nbr.v6_enabled = nbr->v6_enabled; return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, - &nbr->id, sizeof(nbr->id))); + &lde_nbr, sizeof(lde_nbr))); } void @@ -621,7 +658,7 @@ nbr_params_find(struct ldpd_conf *xconf, struct in_addr lsr_id) } uint16_t -nbr_get_keepalive(struct in_addr lsr_id) +nbr_get_keepalive(int af, struct in_addr lsr_id) { struct nbr_params *nbrp; @@ -629,7 +666,7 @@ nbr_get_keepalive(struct in_addr lsr_id) if (nbrp && (nbrp->flags & F_NBRP_KEEPALIVE)) return (nbrp->keepalive); - return (leconf->keepalive); + return ((ldp_af_conf_get(leconf, af))->keepalive); } struct ctl_nbr * @@ -638,8 +675,10 @@ nbr_to_ctl(struct nbr *nbr) static struct ctl_nbr nctl; struct timeval now; + nctl.af = nbr->af; nctl.id = nbr->id; - nctl.addr = nbr->raddr; + nctl.laddr = nbr->laddr; + nctl.raddr = nbr->raddr; nctl.nbr_state = nbr->state; gettimeofday(&now, NULL); diff --git a/usr.sbin/ldpd/packet.c b/usr.sbin/ldpd/packet.c index 878c59d4cd0..60e84b9bac9 100644 --- a/usr.sbin/ldpd/packet.c +++ b/usr.sbin/ldpd/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.54 2016/05/23 17:43:42 renato Exp $ */ +/* $OpenBSD: packet.c,v 1.55 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -42,7 +42,7 @@ extern struct ldpd_conf *leconf; extern struct ldpd_sysdep sysdep; -struct iface *disc_find_iface(unsigned int, struct in_addr, int); +struct iface *disc_find_iface(unsigned int, int, union ldpd_addr *, int); ssize_t session_get_pdu(struct ibuf_read *, char **); static int msgcnt = 0; @@ -79,21 +79,40 @@ gen_msg_hdr(struct ibuf *buf, uint32_t type, uint16_t size) /* send packets */ int -send_packet(int fd, struct iface *iface, void *pkt, size_t len, - struct sockaddr_in *dst) +send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia, + void *pkt, size_t len) { - /* set outgoing interface for multicast traffic */ - if (iface && IN_MULTICAST(ntohl(dst->sin_addr.s_addr))) - if (sock_set_ipv4_mcast(iface) == -1) { - log_warn("%s: error setting multicast interface, %s", - __func__, iface->name); - return (-1); + struct sockaddr *sa; + + switch (af) { + case AF_INET: + if (ia && IN_MULTICAST(ntohl(dst->v4.s_addr))) { + /* set outgoing interface for multicast traffic */ + if (sock_set_ipv4_mcast(ia->iface) == -1) { + log_debug("%s: error setting multicast " + "interface, %s", __func__, ia->iface->name); + return (-1); + } + } + break; + case AF_INET6: + if (ia && IN6_IS_ADDR_MULTICAST(&dst->v6)) { + /* set outgoing interface for multicast traffic */ + if (sock_set_ipv6_mcast(ia->iface) == -1) { + log_debug("%s: error setting multicast " + "interface, %s", __func__, ia->iface->name); + return (-1); + } } + break; + default: + fatalx("send_packet: unknown af"); + } - if (sendto(fd, pkt, len, 0, (struct sockaddr *)dst, - sizeof(*dst)) == -1) { + sa = addr2sa(af, dst, LDP_PORT); + if (sendto(fd, pkt, len, 0, sa, sa->sa_len) == -1) { log_warn("%s: error sending packet to %s", __func__, - inet_ntoa(dst->sin_addr)); + log_sockaddr(sa)); return (-1); } @@ -101,20 +120,23 @@ send_packet(int fd, struct iface *iface, void *pkt, size_t len, } /* Discovery functions */ +#define CMSG_MAXLEN max(sizeof(struct sockaddr_dl), sizeof(struct in6_pktinfo)) void disc_recv_packet(int fd, short event, void *bula) { union { struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(struct sockaddr_dl))]; + char buf[CMSG_SPACE(CMSG_MAXLEN)]; } cmsgbuf; - struct sockaddr_in src; struct msghdr msg; + struct sockaddr_storage from; struct iovec iov; char *buf; struct cmsghdr *cmsg; ssize_t r; int multicast; + int af; + union ldpd_addr src; unsigned int ifindex = 0; struct iface *iface; uint16_t len; @@ -131,8 +153,8 @@ disc_recv_packet(int fd, short event, void *bula) memset(&msg, 0, sizeof(msg)); iov.iov_base = buf = pkt_ptr; iov.iov_len = IBUF_READ_SIZE; - msg.msg_name = &src; - msg.msg_namelen = sizeof(src); + msg.msg_name = &from; + msg.msg_namelen = sizeof(from); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsgbuf.buf; @@ -146,24 +168,31 @@ disc_recv_packet(int fd, short event, void *bula) } multicast = (msg.msg_flags & MSG_MCAST) ? 1 : 0; - if (bad_ip_addr(src.sin_addr)) { + sa2addr((struct sockaddr *)&from, &af, &src); + if (bad_addr(af, &src)) { log_debug("%s: invalid source address: %s", __func__, - inet_ntoa(src.sin_addr)); + log_addr(af, &src)); return; } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == IPPROTO_IP && + if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVIF) { ifindex = ((struct sockaddr_dl *) CMSG_DATA(cmsg))->sdl_index; break; } + if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 && + cmsg->cmsg_type == IPV6_PKTINFO) { + ifindex = ((struct in6_pktinfo *) + CMSG_DATA(cmsg))->ipi6_ifindex; + break; + } } /* find a matching interface */ - iface = disc_find_iface(ifindex, src.sin_addr, multicast); + iface = disc_find_iface(ifindex, af, &src, multicast); if (iface == NULL) return; @@ -171,7 +200,7 @@ disc_recv_packet(int fd, short event, void *bula) len = (uint16_t)r; if (len < (LDP_HDR_SIZE + LDP_MSG_SIZE) || len > LDP_MAX_LEN) { log_debug("%s: bad packet size, source %s", __func__, - inet_ntoa(src.sin_addr)); + log_addr(af, &src)); return; } @@ -179,12 +208,12 @@ disc_recv_packet(int fd, short event, void *bula) memcpy(&ldp_hdr, buf, sizeof(ldp_hdr)); if (ntohs(ldp_hdr.version) != LDP_VERSION) { log_debug("%s: invalid LDP version %d, source %s", __func__, - ntohs(ldp_hdr.version), inet_ntoa(src.sin_addr)); + ntohs(ldp_hdr.version), log_addr(af, &src)); return; } if (ntohs(ldp_hdr.lspace_id) != 0) { log_debug("%s: invalid label space %u, source %s", __func__, - ntohs(ldp_hdr.lspace_id), inet_ntoa(src.sin_addr)); + ntohs(ldp_hdr.lspace_id), log_addr(af, &src)); return; } /* check "PDU Length" field */ @@ -192,7 +221,7 @@ disc_recv_packet(int fd, short event, void *bula) if ((pdu_len < (LDP_HDR_PDU_LEN + LDP_MSG_SIZE)) || (pdu_len > (len - LDP_HDR_DEAD_LEN))) { log_debug("%s: invalid LDP packet length %u, source %s", - __func__, ntohs(ldp_hdr.length), inet_ntoa(src.sin_addr)); + __func__, ntohs(ldp_hdr.length), log_addr(af, &src)); return; } buf += LDP_HDR_SIZE; @@ -211,7 +240,7 @@ disc_recv_packet(int fd, short event, void *bula) msg_len = ntohs(ldp_msg.length); if (msg_len < LDP_MSG_LEN || ((msg_len + LDP_MSG_DEAD_LEN) > pdu_len)) { log_debug("%s: invalid LDP message length %u, source %s", - __func__, ntohs(ldp_msg.length), inet_ntoa(src.sin_addr)); + __func__, ntohs(ldp_msg.length), log_addr(af, &src)); return; } buf += LDP_MSG_SIZE; @@ -220,43 +249,65 @@ disc_recv_packet(int fd, short event, void *bula) /* switch LDP packet type */ switch (ntohs(ldp_msg.type)) { case MSG_TYPE_HELLO: - recv_hello(lsr_id, &ldp_msg, src.sin_addr, iface, multicast, + recv_hello(lsr_id, &ldp_msg, af, &src, iface, multicast, buf, len); break; default: log_debug("%s: unknown LDP packet type, source %s", __func__, - inet_ntoa(src.sin_addr)); + log_addr(af, &src)); } } struct iface * -disc_find_iface(unsigned int ifindex, struct in_addr src, +disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src, int multicast) { struct iface *iface; + struct iface_af *ia; struct if_addr *if_addr; + in_addr_t mask; iface = if_lookup(leconf, ifindex); if (iface == NULL) return (NULL); - if (!multicast) - return (iface); + /* + * For unicast packets, we just need to make sure that the interface + * is enabled for the given address-family. + */ + if (!multicast) { + ia = iface_af_get(iface, af); + if (ia->enabled) + return (iface); + return (NULL); + } + + switch (af) { + case AF_INET: + LIST_FOREACH(if_addr, &iface->addr_list, entry) { + if (if_addr->af != AF_INET) + continue; - LIST_FOREACH(if_addr, &iface->addr_list, entry) { - switch (iface->type) { - case IF_TYPE_POINTOPOINT: - if (ifindex == iface->ifindex && - if_addr->dstbrd.s_addr == src.s_addr) - return (iface); - break; - default: - if (ifindex == iface->ifindex && - (if_addr->addr.s_addr & if_addr->mask.s_addr) == - (src.s_addr & if_addr->mask.s_addr)) - return (iface); - break; + switch (iface->type) { + case IF_TYPE_POINTOPOINT: + if (if_addr->dstbrd.v4.s_addr == src->v4.s_addr) + return (iface); + break; + default: + mask = prefixlen2mask(if_addr->prefixlen); + if ((if_addr->addr.v4.s_addr & mask) == + (src->v4.s_addr & mask)) + return (iface); + break; + } } + break; + case AF_INET6: + if (IN6_IS_ADDR_LINKLOCAL(&src->v6)) + return (iface); + break; + default: + fatalx("disc_find_iface: unknown af"); } return (NULL); @@ -265,9 +316,11 @@ disc_find_iface(unsigned int ifindex, struct in_addr src, void session_accept(int fd, short event, void *bula) { - struct sockaddr_in src; + struct sockaddr_storage src; socklen_t len = sizeof(src); int newfd; + int af; + union ldpd_addr addr; struct nbr *nbr; struct pending_conn *pconn; @@ -290,12 +343,14 @@ session_accept(int fd, short event, void *bula) return; } + sa2addr((struct sockaddr *)&src, &af, &addr); + /* * Since we don't support label spaces, we can identify this neighbor * just by its source address. This way we don't need to wait for its * Initialization message to know who we are talking to. */ - nbr = nbr_find_addr(src.sin_addr); + nbr = nbr_find_addr(af, &addr); if (nbr == NULL) { /* * According to RFC 5036, we would need to send a No Hello @@ -308,11 +363,11 @@ session_accept(int fd, short event, void *bula) * message within this interval, so it's worth waiting before * taking a more drastic measure. */ - pconn = pending_conn_find(src.sin_addr); + pconn = pending_conn_find(af, &addr); if (pconn) close(newfd); else - pending_conn_new(newfd, src.sin_addr); + pending_conn_new(newfd, af, &addr); return; } /* protection against buggy implementations */ @@ -663,7 +718,7 @@ tcp_close(struct tcp_conn *tcp) } struct pending_conn * -pending_conn_new(int fd, struct in_addr addr) +pending_conn_new(int fd, int af, union ldpd_addr *addr) { struct pending_conn *pconn; struct timeval tv; @@ -672,7 +727,8 @@ pending_conn_new(int fd, struct in_addr addr) fatal(__func__); pconn->fd = fd; - pconn->addr = addr; + pconn->af = af; + pconn->addr = *addr; evtimer_set(&pconn->ev_timeout, pending_conn_timeout, pconn); TAILQ_INSERT_TAIL(&global.pending_conns, pconn, entry); @@ -696,12 +752,13 @@ pending_conn_del(struct pending_conn *pconn) } struct pending_conn * -pending_conn_find(struct in_addr addr) +pending_conn_find(int af, union ldpd_addr *addr) { struct pending_conn *pconn; TAILQ_FOREACH(pconn, &global.pending_conns, entry) - if (addr.s_addr == pconn->addr.s_addr) + if (af == pconn->af && + ldp_addrcmp(af, addr, &pconn->addr) == 0) return (pconn); return (NULL); @@ -714,7 +771,7 @@ pending_conn_timeout(int fd, short event, void *arg) struct tcp_conn *tcp; log_debug("%s: no adjacency with remote end: %s", __func__, - inet_ntoa(pconn->addr)); + log_addr(pconn->af, &pconn->addr)); /* * Create a write buffer detached from any neighbor to send a diff --git a/usr.sbin/ldpd/parse.y b/usr.sbin/ldpd/parse.y index 193b1cb1f79..174bdd303fe 100644 --- a/usr.sbin/ldpd/parse.y +++ b/usr.sbin/ldpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.49 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: parse.y,v 1.50 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> @@ -81,33 +81,41 @@ char *symget(const char *); void clear_config(struct ldpd_conf *xconf); uint32_t get_rtr_id(void); -int host(const char *, struct in_addr *, struct in_addr *); +int get_address(const char *, union ldpd_addr *); +int get_af_address(const char *, int *, union ldpd_addr *); static struct ldpd_conf *conf; static int errors = 0; +int af = AF_UNSPEC; +struct ldpd_af_conf *af_conf = NULL; struct iface *iface = NULL; +struct iface_af *ia = NULL; struct tnbr *tnbr = NULL; struct nbr_params *nbrp = NULL; struct l2vpn *l2vpn = NULL; struct l2vpn_pw *pw = NULL; struct config_defaults { + uint16_t keepalive; uint16_t lhello_holdtime; uint16_t lhello_interval; uint16_t thello_holdtime; uint16_t thello_interval; + union ldpd_addr trans_addr; + int afflags; uint8_t pwflags; }; struct config_defaults globaldefs; +struct config_defaults afdefs; struct config_defaults ifacedefs; struct config_defaults tnbrdefs; struct config_defaults pwdefs; struct config_defaults *defs; struct iface *conf_get_if(struct kif *); -struct tnbr *conf_get_tnbr(struct in_addr); +struct tnbr *conf_get_tnbr(union ldpd_addr *); struct nbr_params *conf_get_nbrp(struct in_addr); struct l2vpn *conf_get_l2vpn(char *); struct l2vpn_if *conf_get_l2vpn_if(struct l2vpn *, struct kif *); @@ -126,19 +134,19 @@ typedef struct { %token INTERFACE TNEIGHBOR ROUTERID FIBUPDATE EXPNULL %token LHELLOHOLDTIME LHELLOINTERVAL %token THELLOHOLDTIME THELLOINTERVAL -%token THELLOACCEPT -%token KEEPALIVE TRANSADDRESS +%token THELLOACCEPT AF IPV4 IPV6 +%token KEEPALIVE TRANSADDRESS TRANSPREFERENCE DSCISCOINTEROP %token NEIGHBOR PASSWORD %token L2VPN TYPE VPLS PWTYPE MTU BRIDGE %token ETHERNET ETHERNETTAGGED STATUSTLV CONTROLWORD -%token PSEUDOWIRE NEIGHBOR PWID +%token PSEUDOWIRE NEIGHBORID NEIGHBORADDR PWID %token EXTTAG %token YES NO %token INCLUDE %token ERROR %token <v.string> STRING %token <v.number> NUMBER -%type <v.number> yesno l2vpn_type pw_type +%type <v.number> yesno ldp_af l2vpn_type pw_type %type <v.string> string %% @@ -148,8 +156,7 @@ grammar : /* empty */ | grammar '\n' | grammar conf_main '\n' | grammar varset '\n' - | grammar interface '\n' - | grammar tneighbor '\n' + | grammar af '\n' | grammar neighbor '\n' | grammar l2vpn '\n' | grammar error '\n' { file->errors++; } @@ -187,6 +194,10 @@ yesno : YES { $$ = 1; } | NO { $$ = 0; } ; +ldp_af : IPV4 { $$ = AF_INET; } + | IPV6 { $$ = AF_INET6; } + ; + l2vpn_type : VPLS { $$ = L2VPN_TYPE_VPLS; } ; @@ -211,7 +222,7 @@ conf_main : ROUTERID STRING { YYERROR; } free($2); - if (bad_ip_addr(conf->rtr_id)) { + if (bad_addr_v4(conf->rtr_id)) { yyerror("invalid router-id"); YYERROR; } @@ -222,40 +233,114 @@ conf_main : ROUTERID STRING { else conf->flags &= ~F_LDPD_NO_FIB_UPDATE; } - | THELLOACCEPT yesno { - if ($2 == 0) - conf->flags &= ~F_LDPD_TH_ACCEPT; - else - conf->flags |= F_LDPD_TH_ACCEPT; + | TRANSPREFERENCE ldp_af { + conf->trans_pref = $2; + + switch (conf->trans_pref) { + case AF_INET: + conf->trans_pref = DUAL_STACK_LDPOV4; + break; + case AF_INET6: + conf->trans_pref = DUAL_STACK_LDPOV6; + break; + default: + yyerror("invalid address-family"); + YYERROR; + } } - | EXPNULL yesno { - if ($2 == 0) - conf->flags &= ~F_LDPD_EXPNULL; + | DSCISCOINTEROP yesno { + if ($2 == 1) + conf->flags |= F_LDPD_DS_CISCO_INTEROP; else - conf->flags |= F_LDPD_EXPNULL; + conf->flags &= ~F_LDPD_DS_CISCO_INTEROP; } - | KEEPALIVE NUMBER { - if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) { - yyerror("keepalive out of range (%d-%d)", - MIN_KEEPALIVE, MAX_KEEPALIVE); + | af_defaults + | iface_defaults + | tnbr_defaults + ; + +af : AF ldp_af { + af = $2; + switch (af) { + case AF_INET: + af_conf = &conf->ipv4; + break; + case AF_INET6: + af_conf = &conf->ipv6; + break; + default: + yyerror("invalid address-family"); YYERROR; } - conf->keepalive = $2; + + afdefs = *defs; + defs = &afdefs; + } af_block { + af_conf->keepalive = defs->keepalive; + af_conf->thello_holdtime = defs->thello_holdtime; + af_conf->thello_interval = defs->thello_interval; + af_conf->flags = defs->afflags; + af_conf->flags |= F_LDPD_AF_ENABLED; + af_conf = NULL; + af = AF_UNSPEC; + defs = &globaldefs; } - | TRANSADDRESS STRING { - if (!inet_aton($2, &conf->trans_addr)) { + ; + +af_block : '{' optnl afopts_l '}' + | '{' optnl '}' + | + ; + +afopts_l : afopts_l afoptsl nl + | afoptsl optnl + ; + +afoptsl : TRANSADDRESS STRING { + if (get_address($2, &af_conf->trans_addr) == -1) { yyerror("error parsing transport-address"); free($2); YYERROR; } free($2); - if (bad_ip_addr(conf->trans_addr)) { + if (bad_addr(af, &af_conf->trans_addr)) { yyerror("invalid transport-address"); YYERROR; } + if (af == AF_INET6 && + IN6_IS_SCOPE_EMBED(&af_conf->trans_addr.v6)) { + yyerror("ipv6 transport-address can not be " + "link-local"); + YYERROR; + } } + | af_defaults | iface_defaults | tnbr_defaults + | interface + | tneighbor + ; + +af_defaults : THELLOACCEPT yesno { + if ($2 == 0) + defs->afflags &= ~F_LDPD_AF_THELLO_ACCEPT; + else + defs->afflags |= F_LDPD_AF_THELLO_ACCEPT; + } + | EXPNULL yesno { + if ($2 == 0) + defs->afflags &= ~F_LDPD_AF_EXPNULL; + else + defs->afflags |= F_LDPD_AF_EXPNULL; + } + | KEEPALIVE NUMBER { + if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) { + yyerror("keepalive out of range (%d-%d)", + MIN_KEEPALIVE, MAX_KEEPALIVE); + YYERROR; + } + defs->keepalive = $2; + } ; iface_defaults : LHELLOHOLDTIME NUMBER { @@ -344,22 +429,46 @@ pwopts : PWID NUMBER { pw->pwid = $2; } - | NEIGHBOR STRING { + | NEIGHBORID STRING { struct in_addr addr; - if (inet_aton($2, &addr) == 0) { - yyerror("error parsing neighbor address"); + if (!inet_aton($2, &addr)) { + yyerror("error parsing neighbor-id"); free($2); YYERROR; } free($2); - if (bad_ip_addr(addr)) { + if (bad_addr_v4(addr)) { yyerror("invalid neighbor-id"); YYERROR; } pw->lsr_id = addr; } + | NEIGHBORADDR STRING { + int family; + union ldpd_addr addr; + + if (get_af_address($2, &family, &addr) == -1) { + yyerror("error parsing neighbor address"); + free($2); + YYERROR; + } + free($2); + if (bad_addr(family, &addr)) { + yyerror("invalid neighbor address"); + YYERROR; + } + if (family == AF_INET6 && + IN6_IS_SCOPE_EMBED(&addr.v6)) { + yyerror("neighbor address can not be " + "link-local"); + YYERROR; + } + + pw->af = family; + pw->addr = addr; + } | pw_defaults ; @@ -395,14 +504,16 @@ pseudowire : PSEUDOWIRE STRING { YYERROR; } if (pw->lsr_id.s_addr == INADDR_ANY) { - yyerror("missing pseudowire neighbor"); + yyerror("missing pseudowire neighbor-id"); YYERROR; } LIST_FOREACH(l, &conf->l2vpn_list, entry) { LIST_FOREACH(p, &l->pw_list, entry) { if (pw != p && pw->pwid == p->pwid && - pw->lsr_id.s_addr == p->lsr_id.s_addr) { + pw->af == p->af && + pw->lsr_id.s_addr == + p->lsr_id.s_addr) { yyerror("pseudowire already " "configured"); YYERROR; @@ -410,6 +521,15 @@ pseudowire : PSEUDOWIRE STRING { } } + /* + * If the neighbor address is not specified, use the + * neighbor id. + */ + if (pw->af == AF_UNSPEC) { + pw->af = AF_INET; + pw->addr.v4 = pw->lsr_id; + } + pw->flags = defs->pwflags; pw = NULL; defs = &globaldefs; @@ -521,13 +641,22 @@ interface : INTERFACE STRING { if (iface == NULL) YYERROR; + ia = iface_af_get(iface, af); + if (ia->enabled) { + yyerror("interface %s already configured for " + "address-family %s", kif->ifname, + af_name(af)); + YYERROR; + } + ia->enabled = 1; + ifacedefs = *defs; defs = &ifacedefs; } interface_block { - iface->hello_holdtime = defs->lhello_holdtime; - iface->hello_interval = defs->lhello_interval; + ia->hello_holdtime = defs->lhello_holdtime; + ia->hello_interval = defs->lhello_interval; iface = NULL; - defs = &globaldefs; + defs = &afdefs; } ; @@ -541,21 +670,27 @@ interfaceopts_l : interfaceopts_l iface_defaults nl ; tneighbor : TNEIGHBOR STRING { - struct in_addr addr; + union ldpd_addr addr; - if (inet_aton($2, &addr) == 0) { + if (get_address($2, &addr) == -1) { yyerror("error parsing targeted-neighbor " "address"); free($2); YYERROR; } free($2); - if (bad_ip_addr(addr)) { + if (bad_addr(af, &addr)) { yyerror("invalid targeted-neighbor address"); YYERROR; } + if (af == AF_INET6 && + IN6_IS_SCOPE_EMBED(&addr.v6)) { + yyerror("targeted-neighbor address can not be " + "link-local"); + YYERROR; + } - tnbr = conf_get_tnbr(addr); + tnbr = conf_get_tnbr(&addr); if (tnbr == NULL) YYERROR; @@ -565,7 +700,7 @@ tneighbor : TNEIGHBOR STRING { tnbr->hello_holdtime = defs->thello_holdtime; tnbr->hello_interval = defs->thello_interval; tnbr = NULL; - defs = &globaldefs; + defs = &afdefs; } ; @@ -582,13 +717,13 @@ neighbor : NEIGHBOR STRING { struct in_addr addr; if (inet_aton($2, &addr) == 0) { - yyerror("error parsing neighbor address"); + yyerror("error parsing neighbor-id"); free($2); YYERROR; } free($2); - if (bad_ip_addr(addr)) { - yyerror("invalid neighbor address"); + if (bad_addr_v4(addr)) { + yyerror("invalid neighbor-id"); YYERROR; } @@ -662,20 +797,26 @@ lookup(char *s) { /* this has to be sorted always */ static const struct keywords keywords[] = { + {"address-family", AF}, {"bridge", BRIDGE}, {"control-word", CONTROLWORD}, + {"ds-cisco-interop", DSCISCOINTEROP}, {"ethernet", ETHERNET}, {"ethernet-tagged", ETHERNETTAGGED}, {"explicit-null", EXPNULL}, {"fib-update", FIBUPDATE}, {"include", INCLUDE}, {"interface", INTERFACE}, + {"ipv4", IPV4}, + {"ipv6", IPV6}, {"keepalive", KEEPALIVE}, {"l2vpn", L2VPN}, {"link-hello-holdtime", LHELLOHOLDTIME}, {"link-hello-interval", LHELLOINTERVAL}, {"mtu", MTU}, {"neighbor", NEIGHBOR}, + {"neighbor-addr", NEIGHBORADDR}, + {"neighbor-id", NEIGHBORID}, {"no", NO}, {"password", PASSWORD}, {"pseudowire", PSEUDOWIRE}, @@ -688,6 +829,7 @@ lookup(char *s) {"targeted-hello-interval", THELLOINTERVAL}, {"targeted-neighbor", TNEIGHBOR}, {"transport-address", TRANSADDRESS}, + {"transport-preference", TRANSPREFERENCE}, {"type", TYPE}, {"vpls", VPLS}, {"yes", YES} @@ -1020,15 +1162,14 @@ parse_config(char *filename) if ((conf = calloc(1, sizeof(struct ldpd_conf))) == NULL) fatal(__func__); - conf->keepalive = DEFAULT_KEEPALIVE; + conf->trans_pref = DUAL_STACK_LDPOV6; defs = &globaldefs; + defs->keepalive = DEFAULT_KEEPALIVE; defs->lhello_holdtime = LINK_DFLT_HOLDTIME; defs->lhello_interval = DEFAULT_HELLO_INTERVAL; defs->thello_holdtime = TARGETED_DFLT_HOLDTIME; defs->thello_interval = DEFAULT_HELLO_INTERVAL; - conf->thello_holdtime = TARGETED_DFLT_HOLDTIME; - conf->thello_interval = DEFAULT_HELLO_INTERVAL; defs->pwflags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF; if ((file = pushfile(filename, @@ -1069,8 +1210,11 @@ parse_config(char *filename) if (conf->rtr_id.s_addr == INADDR_ANY) conf->rtr_id.s_addr = get_rtr_id(); - if (conf->trans_addr.s_addr == 0) - conf->trans_addr = conf->rtr_id; + + /* if the ipv4 transport-address is not set, use the router-id */ + if ((conf->ipv4.flags & F_LDPD_AF_ENABLED) && + conf->ipv4.trans_addr.v4.s_addr == INADDR_ANY) + conf->ipv4.trans_addr.v4 = conf->rtr_id; return (conf); } @@ -1154,13 +1298,9 @@ conf_get_if(struct kif *kif) { struct iface *i; - LIST_FOREACH(i, &conf->iface_list, entry) { - if (i->ifindex == kif->ifindex) { - yyerror("interface %s already configured", - kif->ifname); - return (NULL); - } - } + LIST_FOREACH(i, &conf->iface_list, entry) + if (i->ifindex == kif->ifindex) + return (i); if (kif->if_type == IFT_LOOP || kif->if_type == IFT_CARP || @@ -1176,18 +1316,18 @@ conf_get_if(struct kif *kif) } struct tnbr * -conf_get_tnbr(struct in_addr addr) +conf_get_tnbr(union ldpd_addr *addr) { struct tnbr *t; - t = tnbr_find(conf, addr); + t = tnbr_find(conf, af, addr); if (t) { yyerror("targeted neighbor %s already configured", - inet_ntoa(addr)); + log_addr(af, addr)); return (NULL); } - t = tnbr_new(conf, addr); + t = tnbr_new(conf, af, addr); t->flags |= F_TNBR_CONFIGURED; LIST_INSERT_HEAD(&conf->tnbr_list, t, entry); return (t); @@ -1343,22 +1483,36 @@ get_rtr_id(void) } int -host(const char *s, struct in_addr *addr, struct in_addr *mask) +get_address(const char *s, union ldpd_addr *addr) { - struct in_addr ina; - int bits = 32; + switch (af) { + case AF_INET: + if (inet_pton(AF_INET, s, &addr->v4) != 1) + return (-1); + break; + case AF_INET6: + if (inet_pton(AF_INET6, s, &addr->v6) != 1) + return (-1); + break; + default: + return (-1); + } - memset(&ina, 0, sizeof(struct in_addr)); - if (strrchr(s, '/') != NULL) { - if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) - return (0); - } else { - if (inet_pton(AF_INET, s, &ina) != 1) - return (0); + return (0); +} + +int +get_af_address(const char *s, int *family, union ldpd_addr *addr) +{ + if (inet_pton(AF_INET, s, &addr->v4) == 1) { + *family = AF_INET; + return (0); } - *addr = ina; - mask->s_addr = prefixlen2mask(bits); + if (inet_pton(AF_INET6, s, &addr->v6) == 1) { + *family = AF_INET6; + return (0); + } - return (1); + return (-1); } diff --git a/usr.sbin/ldpd/pfkey.c b/usr.sbin/ldpd/pfkey.c index e1d470b6afa..c1a412fb137 100644 --- a/usr.sbin/ldpd/pfkey.c +++ b/usr.sbin/ldpd/pfkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.7 2016/05/23 18:28:22 renato Exp $ */ +/* $OpenBSD: pfkey.c,v 1.8 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -43,34 +43,19 @@ static int fd; int pfkey_reply(int, uint32_t *); int pfkey_send(int, uint8_t, uint8_t, uint8_t, - struct in_addr *, struct in_addr *, + int, union ldpd_addr *, union ldpd_addr *, uint32_t, uint8_t, int, char *, uint8_t, int, char *, uint16_t, uint16_t); -int pfkey_sa_add(struct in_addr *, struct in_addr *, uint8_t, char *, +int pfkey_sa_add(int, union ldpd_addr *, union ldpd_addr *, uint8_t, char *, uint32_t *); -int pfkey_sa_remove(struct in_addr *, struct in_addr *, uint32_t *); +int pfkey_sa_remove(int, union ldpd_addr *, union ldpd_addr *, uint32_t *); int pfkey_md5sig_establish(struct nbr *, struct nbr_params *nbrp); int pfkey_md5sig_remove(struct nbr *); -static struct sockaddr * -addr2sa(struct in_addr *addr) -{ - static struct sockaddr_storage ss; - struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; - - memset(&ss, 0, sizeof(ss)); - sa_in->sin_family = AF_INET; - sa_in->sin_len = sizeof(struct sockaddr_in); - sa_in->sin_addr = *addr; - sa_in->sin_port = htons(0); - - return ((struct sockaddr *)&ss); -} - int pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir, - struct in_addr *src, struct in_addr *dst, uint32_t spi, + int af, union ldpd_addr *src, union ldpd_addr *dst, uint32_t spi, uint8_t aalg, int alen, char *akey, uint8_t ealg, int elen, char *ekey, uint16_t sport, uint16_t dport) { @@ -92,17 +77,37 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir, /* we need clean sockaddr... no ports set */ memset(&ssrc, 0, sizeof(ssrc)); memset(&smask, 0, sizeof(smask)); - if ((saptr = addr2sa(src))) + if ((saptr = addr2sa(af, src, 0))) memcpy(&ssrc, saptr, sizeof(ssrc)); - memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8); + switch (af) { + case AF_INET: + memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8); + break; + case AF_INET6: + memset(&((struct sockaddr_in6 *)&smask)->sin6_addr, 0xff, + 128/8); + break; + default: + return (-1); + } smask.ss_family = ssrc.ss_family; smask.ss_len = ssrc.ss_len; memset(&sdst, 0, sizeof(sdst)); memset(&dmask, 0, sizeof(dmask)); - if ((saptr = addr2sa(dst))) + if ((saptr = addr2sa(af, dst, 0))) memcpy(&sdst, saptr, sizeof(sdst)); - memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8); + switch (af) { + case AF_INET: + memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8); + break; + case AF_INET6: + memset(&((struct sockaddr_in6 *)&dmask)->sin6_addr, 0xff, + 128/8); + break; + default: + return (-1); + } dmask.ss_family = sdst.ss_family; dmask.ss_len = sdst.ss_len; @@ -341,16 +346,16 @@ pfkey_reply(int sd, uint32_t *spip) } int -pfkey_sa_add(struct in_addr *src, struct in_addr *dst, uint8_t keylen, +pfkey_sa_add(int af, union ldpd_addr *src, union ldpd_addr *dst, uint8_t keylen, char *key, uint32_t *spi) { if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_GETSPI, 0, - src, dst, 0, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0) + af, src, dst, 0, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0) return (-1); if (pfkey_reply(fd, spi) < 0) return (-1); if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_UPDATE, 0, - src, dst, *spi, 0, keylen, key, 0, 0, NULL, 0, 0) < 0) + af, src, dst, *spi, 0, keylen, key, 0, 0, NULL, 0, 0) < 0) return (-1); if (pfkey_reply(fd, NULL) < 0) return (-1); @@ -358,10 +363,11 @@ pfkey_sa_add(struct in_addr *src, struct in_addr *dst, uint8_t keylen, } int -pfkey_sa_remove(struct in_addr *src, struct in_addr *dst, uint32_t *spi) +pfkey_sa_remove(int af, union ldpd_addr *src, union ldpd_addr *dst, + uint32_t *spi) { if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_DELETE, 0, - src, dst, *spi, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0) + af, src, dst, *spi, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0) return (-1); if (pfkey_reply(fd, NULL) < 0) return (-1); @@ -375,12 +381,12 @@ pfkey_md5sig_establish(struct nbr *nbr, struct nbr_params *nbrp) sleep(1); if (!nbr->auth.spi_out) - if (pfkey_sa_add(&nbr->laddr, &nbr->raddr, + if (pfkey_sa_add(nbr->af, &nbr->laddr, &nbr->raddr, nbrp->auth.md5key_len, nbrp->auth.md5key, &nbr->auth.spi_out) == -1) return (-1); if (!nbr->auth.spi_in) - if (pfkey_sa_add(&nbr->raddr, &nbr->laddr, + if (pfkey_sa_add(nbr->af, &nbr->raddr, &nbr->laddr, nbrp->auth.md5key_len, nbrp->auth.md5key, &nbr->auth.spi_in) == -1) return (-1); @@ -393,11 +399,11 @@ int pfkey_md5sig_remove(struct nbr *nbr) { if (nbr->auth.spi_out) - if (pfkey_sa_remove(&nbr->laddr, &nbr->raddr, + if (pfkey_sa_remove(nbr->af, &nbr->laddr, &nbr->raddr, &nbr->auth.spi_out) == -1) return (-1); if (nbr->auth.spi_in) - if (pfkey_sa_remove(&nbr->raddr, &nbr->laddr, + if (pfkey_sa_remove(nbr->af, &nbr->raddr, &nbr->laddr, &nbr->auth.spi_in) == -1) return (-1); diff --git a/usr.sbin/ldpd/printconf.c b/usr.sbin/ldpd/printconf.c index 383fb1c8813..f1adc0ec9e1 100644 --- a/usr.sbin/ldpd/printconf.c +++ b/usr.sbin/ldpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.21 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: printconf.c,v 1.22 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> @@ -27,9 +27,11 @@ #include "ldp.h" #include "ldpd.h" #include "ldpe.h" +#include "log.h" void print_mainconf(struct ldpd_conf *); -void print_iface(struct iface *); +void print_af(int, struct ldpd_conf *, struct ldpd_af_conf *); +void print_iface(struct iface *, struct iface_af *); void print_tnbr(struct tnbr *); void print_nbrp(struct nbr_params *); void print_l2vpn(struct l2vpn *); @@ -45,36 +47,68 @@ print_mainconf(struct ldpd_conf *conf) else printf("fib-update yes\n"); - if (conf->flags & F_LDPD_TH_ACCEPT) - printf("targeted-hello-accept yes\n"); + if (conf->trans_pref == DUAL_STACK_LDPOV4) + printf("transport-preference ipv4\n"); + else if (conf->trans_pref == DUAL_STACK_LDPOV6) + printf("transport-preference ipv6\n"); + + if (conf->flags & F_LDPD_DS_CISCO_INTEROP) + printf("ds-cisco-interop yes\n"); else - printf("targeted-hello-accept no\n"); + printf("ds-cisco-interop no\n"); +} + +void +print_af(int af, struct ldpd_conf *conf, struct ldpd_af_conf *af_conf) +{ + struct iface *iface; + struct iface_af *ia; + struct tnbr *tnbr; - if (conf->flags & F_LDPD_EXPNULL) - printf("explicit-null yes\n"); + printf("\naddress-family %s {\n", af_name(af)); + + if (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) + printf("\ttargeted-hello-accept yes\n"); + else + printf("\ttargeted-hello-accept no\n"); + + if (af_conf->flags & F_LDPD_AF_EXPNULL) + printf("\texplicit-null yes\n"); else - printf("explicit-null no\n"); + printf("\texplicit-null no\n"); + + printf("\tkeepalive %u\n", af_conf->keepalive); + printf("\ttransport-address %s\n", log_addr(af, &af_conf->trans_addr)); + + LIST_FOREACH(iface, &conf->iface_list, entry) { + ia = iface_af_get(iface, af); + if (ia->enabled) + print_iface(iface, ia); + } + + LIST_FOREACH(tnbr, &conf->tnbr_list, entry) + if (tnbr->af == af && tnbr->flags & F_TNBR_CONFIGURED) + print_tnbr(tnbr); - printf("keepalive %u\n", conf->keepalive); - printf("transport-address %s\n", inet_ntoa(conf->trans_addr)); + printf("}\n"); } void -print_iface(struct iface *iface) +print_iface(struct iface *iface, struct iface_af *ia) { - printf("\ninterface %s {\n", iface->name); - printf("\tlink-hello-holdtime %u\n", iface->hello_holdtime); - printf("\tlink-hello-interval %u\n", iface->hello_interval); - printf("}\n"); + printf("\tinterface %s {\n", iface->name); + printf("\t\tlink-hello-holdtime %u\n", ia->hello_holdtime); + printf("\t\tlink-hello-interval %u\n", ia->hello_interval); + printf("\t}\n"); } void print_tnbr(struct tnbr *tnbr) { - printf("\ntargeted-neighbor %s {\n", inet_ntoa(tnbr->addr)); - printf("\ttargeted-hello-holdtime %u\n", tnbr->hello_holdtime); - printf("\ttargeted-hello-interval %u\n", tnbr->hello_interval); - printf("}\n"); + printf("\n\ttargeted-neighbor %s {\n", log_addr(tnbr->af, &tnbr->addr)); + printf("\t\ttargeted-hello-holdtime %u\n", tnbr->hello_holdtime); + printf("\t\ttargeted-hello-interval %u\n", tnbr->hello_interval); + printf("\t}\n"); } void @@ -119,7 +153,9 @@ void print_pw(struct l2vpn_pw *pw) { printf("\tpseudowire %s {\n", pw->ifname); - printf("\t\tneighbor %s\n", inet_ntoa(pw->lsr_id)); + + printf("\t\tneighbor-id %s\n", inet_ntoa(pw->lsr_id)); + printf("\t\tneighbor-addr %s\n", log_addr(pw->af, &pw->addr)); printf("\t\tpw-id %u\n", pw->pwid); if (pw->flags & F_PW_STATUSTLV_CONF) @@ -138,19 +174,15 @@ print_pw(struct l2vpn_pw *pw) void print_config(struct ldpd_conf *conf) { - struct iface *iface; - struct tnbr *tnbr; struct nbr_params *nbrp; struct l2vpn *l2vpn; print_mainconf(conf); - LIST_FOREACH(iface, &conf->iface_list, entry) - print_iface(iface); - - LIST_FOREACH(tnbr, &conf->tnbr_list, entry) - if (tnbr->flags & F_TNBR_CONFIGURED) - print_tnbr(tnbr); + if (conf->ipv4.flags & F_LDPD_AF_ENABLED) + print_af(AF_INET, conf, &conf->ipv4); + if (conf->ipv6.flags & F_LDPD_AF_ENABLED) + print_af(AF_INET6, conf, &conf->ipv6); LIST_FOREACH(nbrp, &conf->nbrp_list, entry) print_nbrp(nbrp); diff --git a/usr.sbin/ldpd/socket.c b/usr.sbin/ldpd/socket.c index f4e1120faab..89b94fd7b72 100644 --- a/usr.sbin/ldpd/socket.c +++ b/usr.sbin/ldpd/socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: socket.c,v 1.5 2016/05/23 18:43:28 renato Exp $ */ +/* $OpenBSD: socket.c,v 1.6 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2016 Renato Westphal <renato@openbsd.org> @@ -35,10 +35,11 @@ extern struct ldpd_conf *ldpd_conf; extern struct ldpd_sysdep sysdep; int -ldp_create_socket(enum socket_type type) +ldp_create_socket(int af, enum socket_type type) { int fd, domain, proto; - struct sockaddr_in local_sa; + union ldpd_addr addr; + struct sockaddr_storage local_sa; int opt; /* create socket */ @@ -55,24 +56,25 @@ ldp_create_socket(enum socket_type type) default: fatalx("ldp_create_socket: unknown socket type"); } - fd = socket(AF_INET, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto); + fd = socket(af, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto); if (fd == -1) { log_warn("%s: error creating socket", __func__); return (-1); } /* bind to a local address/port */ - memset(&local_sa, 0, sizeof(local_sa)); - local_sa.sin_family = AF_INET; - local_sa.sin_len = sizeof(struct sockaddr_in); - local_sa.sin_port = htons(LDP_PORT); switch (type) { case LDP_SOCKET_DISC: /* listen on all addresses */ + memset(&addr, 0, sizeof(addr)); + memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT), + sizeof(local_sa)); break; case LDP_SOCKET_EDISC: case LDP_SOCKET_SESSION: - local_sa.sin_addr = ldpd_conf->trans_addr; + addr = (ldp_af_conf_get(ldpd_conf, af))->trans_addr; + memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT), + sizeof(local_sa)); if (sock_set_bindany(fd, 1) == -1) { close(fd); return (-1); @@ -83,33 +85,55 @@ ldp_create_socket(enum socket_type type) close(fd); return (-1); } - if (bind(fd, (struct sockaddr *)&local_sa, local_sa.sin_len) == -1) { + if (bind(fd, (struct sockaddr *)&local_sa, local_sa.ss_len) == -1) { log_warn("%s: error binding socket", __func__); close(fd); return (-1); } /* set options */ - if (sock_set_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) == -1) { - close(fd); - return (-1); - } - if (type == LDP_SOCKET_DISC) { - if (sock_set_ipv4_mcast_ttl(fd, - IP_DEFAULT_MULTICAST_TTL) == -1) { + switch (af) { + case AF_INET: + if (sock_set_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) == -1) { close(fd); return (-1); } - if (sock_set_ipv4_mcast_loop(fd) == -1) { - close(fd); - return (-1); + if (type == LDP_SOCKET_DISC) { + if (sock_set_ipv4_mcast_ttl(fd, + IP_DEFAULT_MULTICAST_TTL) == -1) { + close(fd); + return (-1); + } + if (sock_set_ipv4_mcast_loop(fd) == -1) { + close(fd); + return (-1); + } } - } - if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) { - if (sock_set_ipv4_recvif(fd, 1) == -1) { + if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) { + if (sock_set_ipv4_recvif(fd, 1) == -1) { + close(fd); + return (-1); + } + } + break; + case AF_INET6: + if (sock_set_ipv6_dscp(fd, IPTOS_PREC_INTERNETCONTROL) == -1) { close(fd); return (-1); } + if (type == LDP_SOCKET_DISC) { + if (sock_set_ipv6_mcast_loop(fd) == -1) { + close(fd); + return (-1); + } + } + if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) { + if (sock_set_ipv6_pktinfo(fd, 1) == -1) { + close(fd); + return (-1); + } + } + break; } switch (type) { case LDP_SOCKET_DISC: @@ -210,14 +234,12 @@ sock_set_ipv4_recvif(int fd, int enable) int sock_set_ipv4_mcast(struct iface *iface) { - struct if_addr *if_addr; + in_addr_t addr; - if_addr = LIST_FIRST(&iface->addr_list); - if (!if_addr) - return (0); + addr = if_get_ipv4_addr(iface); - if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF, - &if_addr->addr.s_addr, sizeof(if_addr->addr.s_addr)) < 0) { + if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF, + &addr, sizeof(addr)) < 0) { log_warn("%s: error setting IP_MULTICAST_IF, interface %s", __func__, iface->name); return (-1); @@ -239,3 +261,54 @@ sock_set_ipv4_mcast_loop(int fd) return (0); } + +int +sock_set_ipv6_dscp(int fd, int dscp) +{ + if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp, + sizeof(dscp)) < 0) { + log_warn("%s: error setting IPV6_TCLASS", __func__); + return (-1); + } + + return (0); +} + +int +sock_set_ipv6_pktinfo(int fd, int enable) +{ + if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable, + sizeof(enable)) < 0) { + log_warn("%s: error setting IPV6_RECVPKTINFO", __func__); + return (-1); + } + + return (0); +} + +int +sock_set_ipv6_mcast(struct iface *iface) +{ + if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6, + IPV6_MULTICAST_IF, &iface->ifindex, sizeof(iface->ifindex)) < 0) { + log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s", + __func__, iface->name); + return (-1); + } + + return (0); +} + +int +sock_set_ipv6_mcast_loop(int fd) +{ + unsigned int loop = 0; + + if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + (unsigned int *)&loop, sizeof(loop)) < 0) { + log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__); + return (-1); + } + + return (0); +} diff --git a/usr.sbin/ldpd/util.c b/usr.sbin/ldpd/util.c index 92d51624ead..ba0cfa0a2f4 100644 --- a/usr.sbin/ldpd/util.c +++ b/usr.sbin/ldpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.3 2016/05/23 18:55:21 renato Exp $ */ +/* $OpenBSD: util.c,v 1.4 2016/05/23 18:58:48 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> @@ -34,6 +34,54 @@ mask2prefixlen(in_addr_t ina) return (33 - ffs(ntohl(ina))); } +uint8_t +mask2prefixlen6(struct sockaddr_in6 *sa_in6) +{ + uint8_t l = 0, *ap, *ep; + + /* + * sin6_len is the size of the sockaddr so substract the offset of + * the possibly truncated sin6_addr struct. + */ + ap = (uint8_t *)&sa_in6->sin6_addr; + ep = (uint8_t *)sa_in6 + sa_in6->sin6_len; + for (; ap < ep; ap++) { + /* this "beauty" is adopted from sbin/route/show.c ... */ + switch (*ap) { + case 0xff: + l += 8; + break; + case 0xfe: + l += 7; + return (l); + case 0xfc: + l += 6; + return (l); + case 0xf8: + l += 5; + return (l); + case 0xf0: + l += 4; + return (l); + case 0xe0: + l += 3; + return (l); + case 0xc0: + l += 2; + return (l); + case 0x80: + l += 1; + return (l); + case 0x00: + return (l); + default: + fatalx("non contiguous inet6 netmask"); + } + } + + return (l); +} + in_addr_t prefixlen2mask(uint8_t prefixlen) { @@ -43,8 +91,129 @@ prefixlen2mask(uint8_t prefixlen) return (htonl(0xffffffff << (32 - prefixlen))); } +struct in6_addr * +prefixlen2mask6(uint8_t prefixlen) +{ + static struct in6_addr mask; + int i; + + memset(&mask, 0, sizeof(mask)); + for (i = 0; i < prefixlen / 8; i++) + mask.s6_addr[i] = 0xff; + i = prefixlen % 8; + if (i) + mask.s6_addr[prefixlen / 8] = 0xff00 >> i; + + return (&mask); +} + +void +ldp_applymask(int af, union ldpd_addr *dest, const union ldpd_addr *src, + int prefixlen) +{ + struct in6_addr mask; + int i; + + switch (af) { + case AF_INET: + dest->v4.s_addr = src->v4.s_addr & prefixlen2mask(prefixlen); + break; + case AF_INET6: + memset(&mask, 0, sizeof(mask)); + for (i = 0; i < prefixlen / 8; i++) + mask.s6_addr[i] = 0xff; + i = prefixlen % 8; + if (i) + mask.s6_addr[prefixlen / 8] = 0xff00 >> i; + + for (i = 0; i < 16; i++) + dest->v6.s6_addr[i] = src->v6.s6_addr[i] & + mask.s6_addr[i]; + break; + default: + fatalx("ldp_applymask: unknown af"); + } +} + int -bad_ip_addr(struct in_addr addr) +ldp_addrcmp(int af, const union ldpd_addr *a, const union ldpd_addr *b) +{ + switch (af) { + case AF_INET: + if (a->v4.s_addr == b->v4.s_addr) + return (0); + return ((ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr)) ? 1 : -1); + case AF_INET6: + return (memcmp(&a->v6, &b->v6, sizeof(struct in6_addr))); + default: + fatalx("ldp_addrcmp: unknown af"); + } +} + +int +ldp_addrisset(int af, const union ldpd_addr *addr) +{ + switch (af) { + case AF_UNSPEC: + return (0); + case AF_INET: + if (addr->v4.s_addr != INADDR_ANY) + return (1); + break; + case AF_INET6: + if (!IN6_IS_ADDR_UNSPECIFIED(&addr->v6)) + return (1); + break; + default: + fatalx("ldp_addrisset: unknown af"); + } + + return (0); +} + +int +ldp_prefixcmp(int af, const union ldpd_addr *a, const union ldpd_addr *b, + uint8_t prefixlen) +{ + in_addr_t mask, aa, ba; + int i; + uint8_t m; + + switch (af) { + case AF_INET: + if (prefixlen == 0) + return (0); + if (prefixlen > 32) + fatalx("ldp_prefixcmp: bad IPv4 prefixlen"); + mask = htonl(prefixlen2mask(prefixlen)); + aa = htonl(a->v4.s_addr) & mask; + ba = htonl(b->v4.s_addr) & mask; + return (aa - ba); + case AF_INET6: + if (prefixlen == 0) + return (0); + if (prefixlen > 128) + fatalx("ldp_prefixcmp: bad IPv6 prefixlen"); + for (i = 0; i < prefixlen / 8; i++) + if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) + return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); + i = prefixlen % 8; + if (i) { + m = 0xff00 >> i; + if ((a->v6.s6_addr[prefixlen / 8] & m) != + (b->v6.s6_addr[prefixlen / 8] & m)) + return ((a->v6.s6_addr[prefixlen / 8] & m) - + (b->v6.s6_addr[prefixlen / 8] & m)); + } + return (0); + default: + fatalx("ldp_prefixcmp: unknown af"); + } + return (-1); +} + +int +bad_addr_v4(struct in_addr addr) { uint32_t a = ntohl(addr.s_addr); @@ -55,3 +224,133 @@ bad_ip_addr(struct in_addr addr) return (0); } + +int +bad_addr_v6(struct in6_addr *addr) +{ + if (IN6_IS_ADDR_UNSPECIFIED(addr) || + IN6_IS_ADDR_LOOPBACK(addr) || + IN6_IS_ADDR_MULTICAST(addr) || + IN6_IS_ADDR_SITELOCAL(addr) || + IN6_IS_ADDR_V4MAPPED(addr) || + IN6_IS_ADDR_V4COMPAT(addr)) + return (1); + + return (0); +} + +int +bad_addr(int af, union ldpd_addr *addr) +{ + switch (af) { + case AF_INET: + return (bad_addr_v4(addr->v4)); + case AF_INET6: + return (bad_addr_v6(&addr->v6)); + default: + fatalx("bad_addr: unknown af"); + } +} + +void +embedscope(struct sockaddr_in6 *sin6) +{ + uint16_t tmp16; + + if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { + memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); + if (tmp16 != 0) { + log_warnx("%s: address %s already has embeded scope %u", + __func__, log_sockaddr(sin6), ntohs(tmp16)); + } + tmp16 = htons(sin6->sin6_scope_id); + memcpy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16)); + sin6->sin6_scope_id = 0; + } +} + +void +recoverscope(struct sockaddr_in6 *sin6) +{ + uint16_t tmp16; + + if (sin6->sin6_scope_id != 0) + log_warnx("%s: address %s already has scope id %u", + __func__, log_sockaddr(sin6), sin6->sin6_scope_id); + + if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { + memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); + sin6->sin6_scope_id = ntohs(tmp16); + sin6->sin6_addr.s6_addr[2] = 0; + sin6->sin6_addr.s6_addr[3] = 0; + } +} + +void +addscope(struct sockaddr_in6 *sin6, uint32_t id) +{ + if (sin6->sin6_scope_id != 0) + log_warnx("%s: address %s already has scope id %u", __func__, + log_sockaddr(sin6), sin6->sin6_scope_id); + + if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) + sin6->sin6_scope_id = id; +} + +void +clearscope(struct in6_addr *in6) +{ + if (IN6_IS_SCOPE_EMBED(in6)) { + in6->s6_addr[2] = 0; + in6->s6_addr[3] = 0; + } +} + +struct sockaddr * +addr2sa(int af, union ldpd_addr *addr, uint16_t port) +{ + static struct sockaddr_storage ss; + struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; + struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; + + memset(&ss, 0, sizeof(ss)); + switch (af) { + case AF_INET: + sa_in->sin_family = AF_INET; + sa_in->sin_len = sizeof(struct sockaddr_in); + sa_in->sin_addr = addr->v4; + sa_in->sin_port = htons(port); + break; + case AF_INET6: + sa_in6->sin6_family = AF_INET6; + sa_in6->sin6_len = sizeof(struct sockaddr_in6); + sa_in6->sin6_addr = addr->v6; + sa_in6->sin6_port = htons(port); + break; + default: + fatalx("addr2sa: unknown af"); + } + + return ((struct sockaddr *)&ss); +} + +void +sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr) +{ + struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; + struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; + + memset(addr, 0, sizeof(*addr)); + switch (sa->sa_family) { + case AF_INET: + *af = AF_INET; + addr->v4 = sa_in->sin_addr; + break; + case AF_INET6: + *af = AF_INET6; + addr->v6 = sa_in6->sin6_addr; + break; + default: + fatalx("sa2addr: unknown af"); + } +} |