X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Fdhcpv6-ia.c;h=35c6ae33076e69ddfce1475ed0b21649d93cebbc;hp=9b8c47927b32b6a7ab733d0392073325a60a8708;hb=1d55edbf1c90568ad37ff394b548e7143c4e0e7b;hpb=cb1842c117030e6779f9556cd5d86b1a0ef145d7 diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 9b8c479..35c6ae3 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -1,5 +1,6 @@ /** * Copyright (C) 2013 Steven Barth + * Copyright (C) 2016 Hans Dedecker * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License v2 as published by @@ -33,36 +34,18 @@ #include #include - +static void free_dhcpv6_assignment(struct dhcpv6_assignment *c); static void reconf_timer(struct uloop_timeout *event); static struct uloop_timeout reconf_event = {.cb = reconf_timer}; static uint32_t serial = 0; static uint8_t statemd5[16]; - int dhcpv6_ia_init(void) { uloop_timeout_set(&reconf_event, 2000); return 0; } - -void free_dhcpv6_assignment(struct dhcpv6_assignment *c) -{ - if (c->managed_sock.fd.registered) { - ustream_free(&c->managed_sock.stream); - close(c->managed_sock.fd.fd); - } - - if (c->head.next) - list_del(&c->head); - - free(c->managed); - free(c->hostname); - free(c); -} - - int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) { if (!enable && iface->ia_assignments.next) { @@ -83,7 +66,7 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) syslog(LOG_ERR, "Calloc failed for border on interface %s", iface->ifname); return -1; } - + border->length = 64; list_add(&border->head, &iface->ia_assignments); } @@ -100,6 +83,9 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) return -1; } + if (lease->dhcpv4_leasetime > 0) + a->leasetime = lease->dhcpv4_leasetime; + a->clid_len = duid_len; a->length = 128; if (lease->hostid) { @@ -111,6 +97,10 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) odhcpd_urandom(a->key, sizeof(a->key)); memcpy(a->clid_data, lease->duid, lease->duid_len); memcpy(a->mac, lease->mac.ether_addr_octet, sizeof(a->mac)); + /* Static assignment */ + a->flags |= OAF_STATIC; + /* Infinite valid */ + a->valid_until = 0; // Assign to all interfaces struct dhcpv6_assignment *c; @@ -138,6 +128,20 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) return 0; } +static void free_dhcpv6_assignment(struct dhcpv6_assignment *c) +{ + if (c->managed_sock.fd.registered) { + ustream_free(&c->managed_sock.stream); + close(c->managed_sock.fd.fd); + } + + if (c->head.next) + list_del(&c->head); + + free(c->managed); + free(c->hostname); + free(c); +} static int send_reconf(struct interface *iface, struct dhcpv6_assignment *assign) { @@ -202,7 +206,6 @@ static int send_reconf(struct interface *iface, struct dhcpv6_assignment *assign return odhcpd_send(iface->dhcpv6_event.uloop.fd, &assign->peer, &iov, 1, iface); } - void dhcpv6_write_statefile(void) { md5_ctx_t md5; @@ -231,7 +234,7 @@ void dhcpv6_write_statefile(void) if (iface->dhcpv6 == RELAYD_SERVER && iface->ia_assignments.next) { struct dhcpv6_assignment *c; list_for_each_entry(c, &iface->ia_assignments, head) { - if (c->clid_len == 0 || c->managed_size < 0) + if (!(c->flags & OAF_BOUND) || c->managed_size < 0) continue; char ipbuf[INET6_ADDRSTRLEN]; @@ -240,11 +243,12 @@ void dhcpv6_write_statefile(void) odhcpd_hexlify(duidbuf, c->clid_data, c->clid_len); // iface DUID iaid hostname lifetime assigned length [addrs...] - int l = snprintf(leasebuf, sizeof(leasebuf), "# %s %s %x %s %u %x %u ", + int l = snprintf(leasebuf, sizeof(leasebuf), "# %s %s %x %s %ld %x %u ", iface->ifname, duidbuf, ntohl(c->iaid), (c->hostname ? c->hostname : "-"), - (unsigned)(c->valid_until > now ? - (c->valid_until - now + wall_time) : 0), + (c->valid_until > now ? + (c->valid_until - now + wall_time) : + (INFINITE_VALID(c->valid_until) ? -1 : 0)), c->assigned, (unsigned)c->length); struct in6_addr addr; @@ -259,7 +263,7 @@ void dhcpv6_write_statefile(void) m = i; for (size_t i = 0; i < addrlen; ++i) { - if (addrs[i].prefix > 96 || c->valid_until <= now || + if (addrs[i].prefix > 96 || (!INFINITE_VALID(c->valid_until) && c->valid_until <= now) || (iface->managed < RELAYD_MANAGED_NO_AFLAG && i != m && addrs[i].prefix == 64)) continue; @@ -276,9 +280,9 @@ void dhcpv6_write_statefile(void) fputs(ipbuf, fp); char b[256]; - if (dn_expand(iface->search, iface->search + iface->search_len, - iface->search, b, sizeof(b)) > 0) - fprintf(fp, "\t%s.%s", c->hostname, b); + if (dn_expand(iface->search, iface->search + iface->search_len, + iface->search, b, sizeof(b)) > 0) + fprintf(fp, "\t%s.%s", c->hostname, b); fprintf(fp, "\t%s\n", c->hostname); md5_hash(ipbuf, strlen(ipbuf), &md5); @@ -296,29 +300,33 @@ void dhcpv6_write_statefile(void) if (iface->dhcpv4 == RELAYD_SERVER && iface->dhcpv4_assignments.next) { struct dhcpv4_assignment *c; list_for_each_entry(c, &iface->dhcpv4_assignments, head) { + if (!(c->flags & OAF_BOUND)) + continue; + char ipbuf[INET6_ADDRSTRLEN]; char leasebuf[512]; char duidbuf[16]; odhcpd_hexlify(duidbuf, c->hwaddr, sizeof(c->hwaddr)); // iface DUID iaid hostname lifetime assigned length [addrs...] - int l = snprintf(leasebuf, sizeof(leasebuf), "# %s %s ipv4 %s %u %x 32 ", + int l = snprintf(leasebuf, sizeof(leasebuf), "# %s %s ipv4 %s %ld %x 32 ", iface->ifname, duidbuf, (c->hostname ? c->hostname : "-"), - (unsigned)(c->valid_until > now ? - (c->valid_until - now + wall_time) : 0), + (c->valid_until > now ? + (c->valid_until - now + wall_time) : + (INFINITE_VALID(c->valid_until) ? -1 : 0)), c->addr); struct in_addr addr = {htonl(c->addr)}; inet_ntop(AF_INET, &addr, ipbuf, sizeof(ipbuf) - 1); - if (c->hostname[0]) { + if (c->hostname) { fputs(ipbuf, fp); char b[256]; - if (dn_expand(iface->search, iface->search + iface->search_len, - iface->search, b, sizeof(b)) > 0) - fprintf(fp, "\t%s.%s", c->hostname, b); + if (dn_expand(iface->search, iface->search + iface->search_len, + iface->search, b, sizeof(b)) > 0) + fprintf(fp, "\t%s.%s", c->hostname, b); fprintf(fp, "\t%s\n", c->hostname); md5_hash(ipbuf, strlen(ipbuf), &md5); @@ -365,7 +373,6 @@ static void apply_lease(struct interface *iface, struct dhcpv6_assignment *a, bo } } - // More data was received from TCP connection static void managed_handle_pd_data(struct ustream *s, _unused int bytes_new) { @@ -447,8 +454,6 @@ static void managed_handle_pd_done(struct ustream *s) c->reconf_cnt = 1; } - - static bool assign_pd(struct interface *iface, struct dhcpv6_assignment *assign) { struct dhcpv6_assignment *c; @@ -522,7 +527,6 @@ static bool assign_pd(struct interface *iface, struct dhcpv6_assignment *assign) return false; } - static bool assign_na(struct interface *iface, struct dhcpv6_assignment *assign) { // Seed RNG with checksum of DUID @@ -589,7 +593,8 @@ void dhcpv6_ia_postupdate(struct interface *iface, time_t now) struct list_head reassign = LIST_HEAD_INIT(reassign); struct dhcpv6_assignment *c, *d; list_for_each_entry_safe(c, d, &iface->ia_assignments, head) { - if (c->clid_len == 0 || c->valid_until < now || c->managed_size) + if (c->clid_len == 0 || (!INFINITE_VALID(c->valid_until) && c->valid_until < now) || + c->managed_size) continue; if (c->length < 128 && c->assigned >= border->assigned && c != border) @@ -623,7 +628,6 @@ void dhcpv6_ia_postupdate(struct interface *iface, time_t now) dhcpv6_write_statefile(); } - static void reconf_timer(struct uloop_timeout *event) { time_t now = odhcpd_time(); @@ -634,7 +638,7 @@ static void reconf_timer(struct uloop_timeout *event) struct dhcpv6_assignment *a, *n; list_for_each_entry_safe(a, n, &iface->ia_assignments, head) { - if (a->valid_until < now) { + if (!INFINITE_VALID(a->valid_until) && a->valid_until < now) { if ((a->length < 128 && a->clid_len > 0) || (a->length == 128 && a->clid_len == 0)) { list_del(&a->head); @@ -651,7 +655,6 @@ static void reconf_timer(struct uloop_timeout *event) uloop_timeout_set(event, 2000); } - static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, const struct dhcpv6_ia_hdr *ia, struct dhcpv6_assignment *a, struct interface *iface, bool request) @@ -675,7 +678,12 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, datalen += sizeof(stat); } else { if (a) { - uint32_t leasetime = iface->dhcpv4_leasetime; + uint32_t leasetime; + if (a->leasetime > 0) { + leasetime = a->leasetime; + } else { + leasetime = iface->dhcpv4_leasetime; + } if (leasetime == 0) leasetime = 3600; else if (leasetime < 60) @@ -760,9 +768,12 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, } } - a->valid_until = valid + now; - out.t1 = htonl(pref * 5 / 10); - out.t2 = htonl(pref * 8 / 10); + if (!INFINITE_VALID(a->valid_until)) + /* UINT32_MAX is considered as infinite leasetime */ + a->valid_until = (valid == UINT32_MAX) ? 0 : valid + now; + + out.t1 = htonl((pref == UINT32_MAX) ? pref : pref * 5 / 10); + out.t2 = htonl((pref == UINT32_MAX) ? pref : pref * 8 / 10); if (!out.t1) out.t1 = htonl(1); @@ -848,7 +859,6 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, return datalen; } - static void dhcpv6_log(uint8_t msgtype, struct interface *iface, time_t now, const char *duidbuf, bool is_pd, struct dhcpv6_assignment *a, int code) { @@ -928,8 +938,6 @@ static void dhcpv6_log(uint8_t msgtype, struct interface *iface, time_t now, duidbuf, iface->ifname, status, leasebuf); } - - ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, const struct sockaddr_in6 *addr, const void *data, const uint8_t *end) { @@ -1023,7 +1031,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, if (((c->clid_len == clid_len && !memcmp(c->clid_data, clid_data, clid_len)) || (c->clid_len >= clid_len && !c->clid_data[0] && !c->clid_data[1] && !memcmp(c->mac, mac, sizeof(mac)))) && - (c->iaid == ia->iaid || c->valid_until < now) && + (c->iaid == ia->iaid || INFINITE_VALID(c->valid_until) || now < c->valid_until) && ((is_pd && c->length <= 64) || (is_na && c->length == 128))) { a = c; @@ -1054,6 +1062,9 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, a->length = reqlen; a->peer = *addr; a->assigned = reqhint; + // Set valid time to current time indicating + // assignment is not having infinite lifetime + a->valid_until = now; if (first) memcpy(a->key, first->key, sizeof(a->key)); @@ -1106,7 +1117,10 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, // Was only a solicitation: mark binding for removal if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT) { - a->valid_until = 0; + a->flags &= ~OAF_BOUND; + + if (!(a->flags & OAF_STATIC)) + a->valid_until = now; } else if (assigned && hdr->msg_type == DHCPV6_MSG_REQUEST) { if (hostname_len > 0) { a->hostname = realloc(a->hostname, hostname_len + 1); @@ -1116,6 +1130,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, } } a->accept_reconf = accept_reconf; + a->flags |= OAF_BOUND; apply_lease(iface, a, true); } else if (!assigned && a && a->managed_size == 0) { // Cleanup failed assignment free_dhcpv6_assignment(a); @@ -1130,14 +1145,23 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, } else if (hdr->msg_type == DHCPV6_MSG_RENEW || hdr->msg_type == DHCPV6_MSG_REBIND) { ia_response_len = append_reply(buf, buflen, status, ia, a, iface, false); - if (a) + if (a) { + a->flags |= OAF_BOUND; apply_lease(iface, a, true); + } } else if (hdr->msg_type == DHCPV6_MSG_RELEASE) { - a->valid_until = 0; + if (!(a->flags & OAF_STATIC)) + a->valid_until = now - 1; + + a->flags &= ~OAF_BOUND; apply_lease(iface, a, false); } else if (hdr->msg_type == DHCPV6_MSG_DECLINE && a->length == 128) { - a->clid_len = 0; - a->valid_until = now + 3600; // Block address for 1h + a->flags &= ~OAF_BOUND; + + if (!(a->flags & OAF_STATIC)) { + a->clid_len = 0; + a->valid_until = now + 3600; // Block address for 1h + } } } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM && ia_addr_present) { // Send NOTONLINK for CONFIRM with addr present so that clients restart connection