X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Fdhcpv6-ia.c;h=de445816116693d0aa70343a2a9fc75fcfcfa7e8;hp=610bca3162a1aab8b5041a6199d8b1d69352708f;hb=9bdbc5a4be1ab75145431bc728159a55c723e2ca;hpb=ac448deb59fc9ed2f19a3549d521ab796ae6ca47 diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 610bca3..de44581 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -219,7 +219,7 @@ void dhcpv6_write_statefile(void) return; lockf(fd, F_LOCK, 0); - ftruncate(fd, 0); + if (ftruncate(fd, 0) < 0) {} FILE *fp = fdopen(fd, "w"); if (!fp) { @@ -254,11 +254,18 @@ void dhcpv6_write_statefile(void) struct in6_addr addr; struct odhcpd_ipaddr *addrs = (c->managed) ? c->managed : iface->ia_addr; size_t addrlen = (c->managed) ? (size_t)c->managed_size : iface->ia_addr_len; + size_t m = 0; + + for (size_t i = 0; i < addrlen; ++i) + if (addrs[i].preferred > addrs[m].preferred || + (addrs[i].preferred == addrs[m].preferred && + memcmp(&addrs[i].addr, &addrs[m].addr, 16) > 0)) + m = i; for (size_t i = 0; i < addrlen; ++i) { - if (addrs[i].prefix > 96) - continue; - if (c->valid_until <= now) + if (addrs[i].prefix > 96 || c->valid_until <= now || + (iface->managed < RELAYD_MANAGED_NO_AFLAG && i != m && + addrs[i].prefix == 64)) continue; addr = addrs[i].addr; @@ -269,7 +276,7 @@ void dhcpv6_write_statefile(void) inet_ntop(AF_INET6, &addr, ipbuf, sizeof(ipbuf) - 1); - if (c->length == 128 && c->hostname && i == 0) { + if (c->length == 128 && c->hostname) { fputs(ipbuf, fp); char b[256]; @@ -419,8 +426,6 @@ static void managed_handle_pd_data(struct ustream *s, _unused int bytes_new) else n->valid += now; - n->has_class = false; - n->class = 0; n->dprefix = 0; ++c->managed_size; @@ -524,23 +529,6 @@ static bool assign_pd(struct interface *iface, struct dhcpv6_assignment *assign) static bool assign_na(struct interface *iface, struct dhcpv6_assignment *assign) { - bool match = false; - for (size_t i = 0; i < iface->ia_addr_len; ++i) { - if (!iface->ia_addr[i].has_class) { - match = true; - continue; - } else if (assign->classes_cnt) { - for (size_t j = 0; j < assign->classes_cnt; ++j) - if (assign->classes[j] == iface->ia_addr[i].class) - match = true; - } else if (assign->all_class) { - match = true; - } - } - - if (!match) - return false; - // Seed RNG with checksum of DUID uint32_t seed = 0; for (size_t i = 0; i < assign->clid_len; ++i) @@ -595,7 +583,7 @@ static void update(struct interface *iface) int minprefix = -1; for (int i = 0; i < len; ++i) { - if (addr[i].prefix > minprefix) + if (addr[i].preferred > 0 && addr[i].prefix > minprefix) minprefix = addr[i].prefix; addr[i].addr.s6_addr32[3] = 0; @@ -731,44 +719,27 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->ia_addr; size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len; + size_t m = 0; - for (size_t i = 0; i < addrlen; ++i) { - bool match = true; - if (addrs[i].has_class) { - match = false; - if (a->classes_cnt) { - for (size_t j = 0; j < a->classes_cnt; ++j) - if (a->classes[j] == addrs[i].class) - match = true; - } else if (a->all_class) { - match = true; - } - } + for (size_t i = 0; i < addrlen; ++i) + if (addrs[i].preferred > addrs[m].preferred || + (addrs[i].preferred == addrs[m].preferred && + memcmp(&addrs[i].addr, &addrs[m].addr, 16) > 0)) + m = i; - if (!match) - continue; - - uint32_t prefix_pref = addrs[i].preferred - now; - uint32_t prefix_valid = addrs[i].valid - now; + for (size_t i = 0; i < addrlen; ++i) { + uint32_t prefix_pref = addrs[i].preferred; + uint32_t prefix_valid = addrs[i].valid; if (addrs[i].prefix > 96 || addrs[i].preferred <= (uint32_t)now) continue; - if (prefix_pref > 86400) - prefix_pref = 86400; + if (prefix_pref != UINT32_MAX) + prefix_pref -= now; - if (prefix_valid > 86400) - prefix_valid = 86400; - -#ifdef DHCPV6_OPT_PREFIX_CLASS - struct { - uint16_t code; - uint16_t length; - uint16_t class; - } pclass = {htons(DHCPV6_OPT_PREFIX_CLASS), - htons(2), htons(iface->ia_addr[i].class)}; -#endif + if (prefix_valid != UINT32_MAX) + prefix_valid -= now; if (a->length < 128) { struct dhcpv6_ia_prefix p = { @@ -783,21 +754,11 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, size_t entrlen = sizeof(p) - 4; -#ifdef DHCPV6_OPT_PREFIX_CLASS - if (iface->ia_addr[i].has_class) { - entrlen += sizeof(pclass); - p.len = htons(entrlen); - } -#endif - if (datalen + entrlen + 4 > buflen || (a->assigned == 0 && a->managed_size == 0)) continue; memcpy(buf + datalen, &p, sizeof(p)); -#ifdef DHCPV6_OPT_PREFIX_CLASS - memcpy(buf + datalen + sizeof(p), &pclass, sizeof(pclass)); -#endif datalen += entrlen + 4; } else { struct dhcpv6_ia_addr n = { @@ -810,20 +771,14 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, n.addr.s6_addr32[3] = htonl(a->assigned); size_t entrlen = sizeof(n) - 4; -#ifdef DHCPV6_OPT_PREFIX_CLASS - if (iface->ia_addr[i].has_class) { - entrlen += sizeof(pclass); - n.len = htons(entrlen); - } -#endif + if (iface->managed < RELAYD_MANAGED_NO_AFLAG && i != m && + addrs[i].prefix == 64) + continue; if (datalen + entrlen + 4 > buflen || a->assigned == 0) continue; memcpy(buf + datalen, &n, sizeof(n)); -#ifdef DHCPV6_OPT_PREFIX_CLASS - memcpy(buf + datalen + sizeof(n), &pclass, sizeof(pclass)); -#endif datalen += entrlen + 4; } @@ -873,7 +828,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, addr.s6_addr32[1] |= htonl(a->assigned); if (!memcmp(&p->addr, &addr, sizeof(addr)) && - p->prefix == a->length) + p->prefix == ((a->managed) ? addrs[i].prefix : a->length)) found = true; } else { addr.s6_addr32[3] = htonl(a->assigned); @@ -926,6 +881,87 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, } +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) +{ + const char *type = "UNKNOWN"; + const char *status = "UNKNOWN"; + + if (msgtype == DHCPV6_MSG_RENEW) + return; + + switch (msgtype) { + case DHCPV6_MSG_SOLICIT: + type = "SOLICIT"; + break; + case DHCPV6_MSG_REQUEST: + type = "REQUEST"; + break; + case DHCPV6_MSG_CONFIRM: + type = "CONFIRM"; + break; + case DHCPV6_MSG_RENEW: + type = "RENEW"; + break; + case DHCPV6_MSG_REBIND: + type = "REBIND"; + break; + case DHCPV6_MSG_RELEASE: + type = "RELEASE"; + break; + case DHCPV6_MSG_DECLINE: + type = "DECLINE"; + break; + } + + switch (code) { + case DHCPV6_STATUS_OK: + status = "ok"; + break; + case DHCPV6_STATUS_NOADDRSAVAIL: + status = "no addresses available"; + break; + case DHCPV6_STATUS_NOBINDING: + status = "no binding"; + break; + case DHCPV6_STATUS_NOTONLINK: + status = "not on-link"; + break; + case DHCPV6_STATUS_NOPREFIXAVAIL: + status = "no prefix available"; + break; + } + + char leasebuf[256] = ""; + + if (a) { + struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->ia_addr; + size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len; + size_t lbsize = 0; + char addrbuf[INET6_ADDRSTRLEN]; + + for (size_t i = 0; i < addrlen; ++i) { + if (addrs[i].prefix > 96 || addrs[i].preferred <= (uint32_t)now) + continue; + + struct in6_addr addr = addrs[i].addr; + int prefix = a->managed ? addrs[i].prefix : a->length; + if (prefix == 128) + addr.s6_addr32[3] = htonl(a->assigned); + else + addr.s6_addr32[1] |= htonl(a->assigned); + + inet_ntop(AF_INET6, &addr, addrbuf, sizeof(addrbuf)); + lbsize += snprintf(leasebuf + lbsize, sizeof(leasebuf) - lbsize, "%s/%d ", addrbuf, prefix); + } + } + + syslog(LOG_WARNING, "DHCPV6 %s %s from %s on %s: %s %s", type, (is_pd) ? "IA_PD" : "IA_NA", + 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) { @@ -940,8 +976,8 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, uint8_t *clid_data = NULL, clid_len = 0, mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; char hostname[256]; size_t hostname_len = 0; - bool class_oro = false; bool notonlink = false; + char duidbuf[261]; dhcpv6_for_each_option(start, end, otype, olen, odata) { if (otype == DHCPV6_OPT_CLIENTID) { @@ -952,6 +988,9 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, memcpy(mac, &odata[8], sizeof(mac)); else if (olen == 10 && odata[0] == 0 && odata[1] == 3) memcpy(mac, &odata[4], sizeof(mac)); + + if (olen <= 130) + odhcpd_hexlify(duidbuf, odata, olen); } else if (otype == DHCPV6_OPT_FQDN && olen >= 2 && olen <= 255) { uint8_t fqdn_buf[256]; memcpy(fqdn_buf, odata, olen); @@ -959,14 +998,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, if (dn_expand(&fqdn_buf[1], &fqdn_buf[olen], &fqdn_buf[1], hostname, sizeof(hostname)) > 0) hostname_len = strcspn(hostname, "."); - } else if (otype == DHCPV6_OPT_ORO) { -#ifdef DHCPV6_OPT_PREFIX_CLASS - for (size_t i = 0; i + 1 < olen; i += 2) { - if (odata[i] == (DHCPV6_OPT_PREFIX_CLASS >> 8) && - odata[i + 1] == (DHCPV6_OPT_PREFIX_CLASS & 0xff)) - class_oro = true; - } -#endif } else if (otype == DHCPV6_OPT_RECONF_ACCEPT) { accept_reconf = true; } @@ -976,7 +1007,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, goto out; update(iface); - bool update_state = false; struct dhcpv6_assignment *first = NULL; dhcpv6_for_each_option(start, end, otype, olen, odata) { @@ -991,10 +1021,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, uint8_t reqlen = (is_pd) ? 62 : 128; uint32_t reqhint = 0; - const uint8_t classes_max = 32; - uint8_t classes_cnt = 0; - uint16_t classes[classes_max]; - // Parse request hint for IA-PD if (is_pd) { uint8_t *sdata; @@ -1010,20 +1036,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, if (reqlen > 32 && reqlen <= 64) reqhint &= (1U << (64 - reqlen)) - 1; } - -#ifdef DHCPV6_OPT_PREFIX_CLASS - uint8_t *xdata; - uint16_t xtype, xlen; - dhcpv6_for_each_option(&p[1], sdata + slen, xtype, xlen, xdata) { - if (xtype != DHCPV6_OPT_PREFIX_CLASS || xlen != 2) - continue; - - if (classes_cnt >= classes_max) - continue; - - classes[classes_cnt++] = (uint16_t)xdata[0] << 8 | (uint16_t)xdata[1]; - } -#endif } if (reqlen > 64) @@ -1036,20 +1048,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, continue; ia_addr_present = true; -#ifdef DHCPV6_OPT_PREFIX_CLASS - uint8_t *xdata; - uint16_t xtype, xlen; - struct dhcpv6_ia_addr *p = (struct dhcpv6_ia_addr*)&sdata[-4]; - dhcpv6_for_each_option(&p[1], sdata + slen, xtype, xlen, xdata) { - if (xtype != DHCPV6_OPT_PREFIX_CLASS || xlen != 2) - continue; - - if (classes_cnt >= classes_max) - continue; - - classes[classes_cnt++] = (uint16_t)xdata[0] << 8 | (uint16_t)xdata[1]; - } -#endif } } @@ -1071,11 +1069,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, a->peer = *addr; a->reconf_cnt = 0; a->reconf_sent = 0; - a->all_class = class_oro; - a->classes_cnt = classes_cnt; - a->classes = realloc(a->classes, classes_cnt * sizeof(uint16_t)); - if (a->classes) - memcpy(a->classes, classes, classes_cnt * sizeof(uint16_t)); break; } } @@ -1095,13 +1088,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, a->length = reqlen; a->peer = *addr; a->assigned = reqhint; - a->all_class = class_oro; - a->classes_cnt = classes_cnt; - if (classes_cnt) { - a->classes = malloc(classes_cnt * sizeof(uint16_t)); - if (a->classes) - memcpy(a->classes, classes, classes_cnt * sizeof(uint16_t)); - } if (first) memcpy(a->key, first->key, sizeof(a->key)); @@ -1165,7 +1151,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, } a->accept_reconf = accept_reconf; apply_lease(iface, a, true); - update_state = true; } else if (!assigned && a && a->managed_size == 0) { // Cleanup failed assignment free_dhcpv6_assignment(a); } @@ -1184,11 +1169,9 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, } else if (hdr->msg_type == DHCPV6_MSG_RELEASE) { a->valid_until = 0; apply_lease(iface, a, false); - update_state = true; } else if (hdr->msg_type == DHCPV6_MSG_DECLINE && a->length == 128) { a->clid_len = 0; a->valid_until = now + 3600; // Block address for 1h - update_state = true; } } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM && ia_addr_present) { // Send NOTONLINK for CONFIRM with addr present so that clients restart connection @@ -1200,6 +1183,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, buf += ia_response_len; buflen -= ia_response_len; response_len += ia_response_len; + dhcpv6_log(hdr->msg_type, iface, now, duidbuf, is_pd, a, status); } if ((hdr->msg_type == DHCPV6_MSG_RELEASE || hdr->msg_type == DHCPV6_MSG_DECLINE || notonlink) && @@ -1213,8 +1197,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, response_len += 6; } - if (update_state) - dhcpv6_write_statefile(); + dhcpv6_write_statefile(); out: return response_len;