#include <stddef.h>
#include <resolv.h>
#include <sys/timerfd.h>
+#include <arpa/inet.h>
#include "odhcpd.h"
#include "dhcpv6.h"
struct interface *iface, void *dest_addr);
-
// Create socket and register events
-int init_dhcpv6(void)
+int dhcpv6_init(void)
{
dhcpv6_ia_init();
return 0;
}
-
-int setup_dhcpv6_interface(struct interface *iface, bool enable)
+int dhcpv6_setup_interface(struct interface *iface, bool enable)
{
if (iface->dhcpv6_event.uloop.fd > 0) {
uloop_fd_delete(&iface->dhcpv6_event.uloop);
}
// Configure multicast settings
- if (enable && iface->dhcpv6 && !iface->master) {
+ if (enable && iface->dhcpv6) {
int sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
if (sock < 0) {
syslog(LOG_ERR, "Failed to create DHCPv6 server socket: %s",
struct ipv6_mreq server = {ALL_DHCPV6_SERVERS, iface->ifindex};
setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &relay, sizeof(relay));
- if (iface->dhcpv6 == RELAYD_SERVER)
+ if (iface->dhcpv6 == MODE_SERVER)
setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &server, sizeof(server));
iface->dhcpv6_event.uloop.fd = sock;
odhcpd_register(&iface->dhcpv6_event);
}
- return setup_dhcpv6_ia_interface(iface, enable);
+ return dhcpv6_setup_ia_interface(iface, enable);
}
enum {
size_t dns_cnt = iface->dns_cnt;
if ((dns_cnt == 0) &&
- odhcpd_get_preferred_interface_address(iface->ifindex, &dns_addr)) {
+ !odhcpd_get_interface_dns_addr(iface, &dns_addr)) {
dns_addr_ptr = &dns_addr;
dns_cnt = 1;
}
iov[IOV_CERID].iov_len = sizeof(cerid);
if (IN6_IS_ADDR_UNSPECIFIED(&cerid.addr)) {
- struct odhcpd_ipaddr addrs[32];
- ssize_t len = odhcpd_get_interface_addresses(0, addrs,
- ARRAY_SIZE(addrs));
+ struct odhcpd_ipaddr *addrs;
+ ssize_t len = netlink_get_interface_addrs(0, true, &addrs);
for (ssize_t i = 0; i < len; ++i)
if (IN6_IS_ADDR_UNSPECIFIED(&cerid.addr)
|| memcmp(&addrs[i].addr, &cerid.addr, sizeof(cerid.addr)) < 0)
- cerid.addr = addrs[i].addr;
+ cerid.addr = addrs[i].addr.in6;
+
+ free(addrs);
}
#endif
}
static void handle_dhcpv6(void *addr, void *data, size_t len,
struct interface *iface, void *dest_addr)
{
- if (iface->dhcpv6 == RELAYD_SERVER) {
+ if (iface->dhcpv6 == MODE_SERVER) {
handle_client_request(addr, data, len, iface, dest_addr);
- } else if (iface->dhcpv6 == RELAYD_RELAY) {
+ } else if (iface->dhcpv6 == MODE_RELAY) {
if (iface->master)
relay_server_response(data, len);
else
size_t rewrite_cnt = iface->dns_cnt;
if (rewrite_cnt == 0) {
- if (odhcpd_get_preferred_interface_address(iface->ifindex, &addr) < 1)
+ if (odhcpd_get_interface_dns_addr(iface, &addr))
return; // Unable to get interface address
rewrite = &addr;
odhcpd_send(iface->dhcpv6_event.uloop.fd, &target, &iov, 1, iface);
}
+static struct odhcpd_ipaddr *relay_link_address(struct interface *iface)
+{
+ struct odhcpd_ipaddr *addr = NULL;
+ time_t now = odhcpd_time();
+
+ for (size_t i = 0; i < iface->addr6_len; i++) {
+ if (iface->addr6[i].valid <= (uint32_t)now)
+ continue;
+
+ if (iface->addr6[i].preferred > (uint32_t)now) {
+ addr = &iface->addr6[i];
+ break;
+ }
+
+ if (!addr || (iface->addr6[i].valid > addr->valid))
+ addr = &iface->addr6[i];
+ }
+
+ return addr;
+}
// Relay client request (regular DHCPv6-relay)
static void relay_client_request(struct sockaddr_in6 *source,
{
struct interface *master = odhcpd_get_master_interface();
const struct dhcpv6_relay_header *h = data;
- if (!master || master->dhcpv6 != RELAYD_RELAY ||
+ 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 ||
memcpy(&hdr.interface_id_data, &ifindex, sizeof(ifindex));
// Detect public IP of slave interface to use as link-address
- struct odhcpd_ipaddr ip;
- if (odhcpd_get_interface_addresses(iface->ifindex, &ip, 1) < 1) {
+ 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.
- if (odhcpd_get_interface_addresses(master->ifindex, &ip, 1) < 1)
+ ip = relay_link_address(master);
+ if (!ip)
return; // Could not obtain a suitable address
}
- memcpy(&hdr.link_address, &ip.addr, sizeof(hdr.link_address));
+
+ memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address));
struct sockaddr_in6 dhcpv6_servers = {AF_INET6,
htons(DHCPV6_SERVER_PORT), 0, ALL_DHCPV6_SERVERS, 0};
struct iovec iov[2] = {{&hdr, sizeof(hdr)}, {(void*)data, len}};
- odhcpd_send(iface->dhcpv6_event.uloop.fd, &dhcpv6_servers, iov, 2, master);
+ odhcpd_send(master->dhcpv6_event.uloop.fd, &dhcpv6_servers, iov, 2, master);
}