From b0769168ccdc25a94e691540737b72914fef7784 Mon Sep 17 00:00:00 2001 From: Hans Dedecker Date: Thu, 21 Mar 2019 14:43:52 +0100 Subject: [PATCH] dhcpv6/router: add support for mutiple master interfaces Support multiple master interfaces for dhcpv6 and ra; it allows to forward dhcpv6 mesaages and RS on multiple upstream links Signed-off-by: Hans Dedecker --- src/dhcpv6.c | 73 +++++++++++++++++++++++++++++----------------------- src/odhcpd.h | 1 - src/router.c | 13 +++++++--- 3 files changed, 51 insertions(+), 36 deletions(-) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index f2080c8..b0049bd 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -582,19 +582,7 @@ static struct odhcpd_ipaddr *relay_link_address(struct interface *iface) static void relay_client_request(struct sockaddr_in6 *source, const void *data, size_t len, struct interface *iface) { - struct interface *master = odhcpd_get_master_interface(); const struct dhcpv6_relay_header *h = data; - struct sockaddr_in6 s; - - if (!master || master->dhcpv6 != MODE_RELAY || - h->msg_type == DHCPV6_MSG_RELAY_REPL || - h->msg_type == DHCPV6_MSG_RECONFIGURE || - h->msg_type == DHCPV6_MSG_REPLY || - h->msg_type == DHCPV6_MSG_ADVERTISE) - return; /* Invalid message types for client */ - - syslog(LOG_NOTICE, "Got a DHCPv6-request"); - /* Construct our forwarding envelope */ struct dhcpv6_relay_forward_envelope hdr = { .msg_type = DHCPV6_MSG_RELAY_FORW, @@ -604,39 +592,60 @@ static void relay_client_request(struct sockaddr_in6 *source, .relay_message_type = htons(DHCPV6_OPT_RELAY_MSG), .relay_message_len = htons(len), }; + struct iovec iov[2] = {{&hdr, sizeof(hdr)}, {(void *)data, len}}; + struct interface *c; + struct odhcpd_ipaddr *ip; + struct sockaddr_in6 s; + + if (h->msg_type == DHCPV6_MSG_RELAY_REPL || + h->msg_type == DHCPV6_MSG_RECONFIGURE || + h->msg_type == DHCPV6_MSG_REPLY || + h->msg_type == DHCPV6_MSG_ADVERTISE) + return; /* Invalid message types for client */ + + syslog(LOG_NOTICE, "Got a DHCPv6-request on %s", iface->name); if (h->msg_type == DHCPV6_MSG_RELAY_FORW) { /* handle relay-forward */ if (h->hop_count >= DHCPV6_HOP_COUNT_LIMIT) - return; // Invalid hop count - else - hdr.hop_count = h->hop_count + 1; + return; /* Invalid hop count */ + + hdr.hop_count = h->hop_count + 1; } /* use memcpy here as the destination fields are unaligned */ - uint32_t ifindex = iface->ifindex; memcpy(&hdr.peer_address, &source->sin6_addr, sizeof(struct in6_addr)); - memcpy(&hdr.interface_id_data, &ifindex, sizeof(ifindex)); + memcpy(&hdr.interface_id_data, &iface->ifindex, sizeof(iface->ifindex)); /* Detect public IP of slave interface to use as link-address */ - struct odhcpd_ipaddr *ip = relay_link_address(iface); - if (!ip) { - /* No suitable address! Is the slave not configured yet? - * Detect public IP of master interface and use it instead - * This is WRONG and probably violates the RFC. However - * otherwise we have a hen and egg problem because the - * slave-interface cannot be auto-configured. */ - ip = relay_link_address(master); - if (!ip) - return; /* Could not obtain a suitable address */ - } - - memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address)); + ip = relay_link_address(iface); + if (ip) + memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address)); memset(&s, 0, sizeof(s)); s.sin6_family = AF_INET6; s.sin6_port = htons(DHCPV6_SERVER_PORT); inet_pton(AF_INET6, ALL_DHCPV6_SERVERS, &s.sin6_addr); - struct iovec iov[2] = {{&hdr, sizeof(hdr)}, {(void*)data, len}}; - odhcpd_send(master->dhcpv6_event.uloop.fd, &s, iov, 2, master); + avl_for_each_element(&interfaces, c, avl) { + if (!c->master || c->dhcpv6 != MODE_RELAY) + continue; + + if (!ip) { + /* No suitable address! Is the slave not configured yet? + * Detect public IP of master interface and use it instead + * This is WRONG and probably violates the RFC. However + * otherwise we have a hen and egg problem because the + * slave-interface cannot be auto-configured. */ + ip = relay_link_address(c); + if (!ip) + continue; /* Could not obtain a suitable address */ + + memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address)); + ip = NULL; + } + + syslog(LOG_NOTICE, "Sending a DHCPv6-relay-forward on %s", c->name); + + odhcpd_send(c->dhcpv6_event.uloop.fd, &s, iov, 2, c); + } } diff --git a/src/odhcpd.h b/src/odhcpd.h index 38ee020..80f416d 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -332,7 +332,6 @@ int odhcpd_get_interface_dns_addr(const struct interface *iface, int odhcpd_get_interface_config(const char *ifname, const char *what); int odhcpd_get_mac(const struct interface *iface, uint8_t mac[6]); struct interface* odhcpd_get_interface_by_index(int ifindex); -struct interface* odhcpd_get_master_interface(void); int odhcpd_urandom(void *data, size_t len); void odhcpd_run(void); diff --git a/src/router.c b/src/router.c index ec0bee0..976e28a 100644 --- a/src/router.c +++ b/src/router.c @@ -712,10 +712,17 @@ static void handle_icmpv6(void *addr, void *data, size_t len, if (hdr->icmp6_type == ND_ROUTER_SOLICIT) send_router_advert(iface, &from->sin6_addr); } else if (iface->ra == MODE_RELAY) { /* Relay mode */ - if (hdr->icmp6_type == ND_ROUTER_ADVERT && iface->master) + if (hdr->icmp6_type == ND_ROUTER_SOLICIT && !iface->master) { + struct interface *c; + + avl_for_each_element(&interfaces, c, avl) { + if (!c->master || c->ra != MODE_RELAY) + continue; + + forward_router_solicitation(c); + } + } else if (hdr->icmp6_type == ND_ROUTER_ADVERT && iface->master) forward_router_advertisement(iface, data, len); - else if (hdr->icmp6_type == ND_ROUTER_SOLICIT && !iface->master) - forward_router_solicitation(odhcpd_get_master_interface()); } } -- 2.30.2