summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2019-03-21 14:43:52 +0100
committerHans Dedecker <dedeckeh@gmail.com>2019-03-21 15:41:39 +0100
commitb0769168ccdc25a94e691540737b72914fef7784 (patch)
treefd1652f3659a9f3c6c8187016cceb98804e92d1f
parente4a24dcb5aa48fdace3d6482db262bde9969b5bb (diff)
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 <dedeckeh@gmail.com>
-rw-r--r--src/dhcpv6.c73
-rw-r--r--src/odhcpd.h1
-rw-r--r--src/router.c13
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());
}
}