1*31e6f1a8Ssthen /* $OpenBSD: sync.c,v 1.25 2024/08/24 08:35:24 sthen Exp $ */ 25f515bebSbeck 35f515bebSbeck /* 45f515bebSbeck * Copyright (c) 2008 Bob Beck <beck@openbsd.org> 55f515bebSbeck * Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org> 65f515bebSbeck * 75f515bebSbeck * Permission to use, copy, modify, and distribute this software for any 85f515bebSbeck * purpose with or without fee is hereby granted, provided that the above 95f515bebSbeck * copyright notice and this permission notice appear in all copies. 105f515bebSbeck * 115f515bebSbeck * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 125f515bebSbeck * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 135f515bebSbeck * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 145f515bebSbeck * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 155f515bebSbeck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 165f515bebSbeck * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 175f515bebSbeck * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 185f515bebSbeck */ 195f515bebSbeck 20837cddffSkrw #include <sys/types.h> 215f515bebSbeck #include <sys/ioctl.h> 225f515bebSbeck #include <sys/queue.h> 23837cddffSkrw #include <sys/socket.h> 245f515bebSbeck 255f515bebSbeck #include <net/if.h> 26837cddffSkrw 275f515bebSbeck #include <arpa/inet.h> 285f515bebSbeck 29837cddffSkrw #include <netinet/in.h> 305f515bebSbeck 315f515bebSbeck #include <openssl/hmac.h> 325f515bebSbeck 33837cddffSkrw #include <errno.h> 34837cddffSkrw #include <netdb.h> 35837cddffSkrw #include <sha1.h> 36837cddffSkrw #include <string.h> 37837cddffSkrw #include <syslog.h> 38837cddffSkrw #include <unistd.h> 39837cddffSkrw 40837cddffSkrw #include "dhcp.h" 41837cddffSkrw #include "tree.h" 425f515bebSbeck #include "dhcpd.h" 43c525a185Skrw #include "log.h" 445f515bebSbeck #include "sync.h" 455f515bebSbeck 465f515bebSbeck int sync_debug; 475f515bebSbeck 485f515bebSbeck u_int32_t sync_counter; 49a84ef30bSbeck int syncfd = -1; 505f515bebSbeck int sendmcast; 515f515bebSbeck 525f515bebSbeck struct sockaddr_in sync_in; 535f515bebSbeck struct sockaddr_in sync_out; 545f515bebSbeck static char *sync_key; 555f515bebSbeck 565f515bebSbeck struct sync_host { 575f515bebSbeck LIST_ENTRY(sync_host) h_entry; 585f515bebSbeck 595f515bebSbeck char *h_name; 605f515bebSbeck struct sockaddr_in sh_addr; 615f515bebSbeck }; 625f515bebSbeck LIST_HEAD(synchosts, sync_host) sync_hosts = LIST_HEAD_INITIALIZER(sync_hosts); 635f515bebSbeck 645f515bebSbeck void sync_send(struct iovec *, int); 655f515bebSbeck 665f515bebSbeck int 675f515bebSbeck sync_addhost(const char *name, u_short port) 685f515bebSbeck { 695f515bebSbeck struct addrinfo hints, *res, *res0; 705f515bebSbeck struct sync_host *shost; 715f515bebSbeck struct sockaddr_in *addr = NULL; 725f515bebSbeck 7387fe6823Smestre memset(&hints, 0, sizeof(hints)); 745f515bebSbeck hints.ai_family = PF_UNSPEC; 755f515bebSbeck hints.ai_socktype = SOCK_STREAM; 765f515bebSbeck if (getaddrinfo(name, NULL, &hints, &res0) != 0) 775f515bebSbeck return (EINVAL); 785f515bebSbeck for (res = res0; res != NULL; res = res->ai_next) { 795f515bebSbeck if (addr == NULL && res->ai_family == AF_INET) { 805f515bebSbeck addr = (struct sockaddr_in *)res->ai_addr; 815f515bebSbeck break; 825f515bebSbeck } 835f515bebSbeck } 845f515bebSbeck if (addr == NULL) { 855f515bebSbeck freeaddrinfo(res0); 865f515bebSbeck return (EINVAL); 875f515bebSbeck } 885f515bebSbeck if ((shost = (struct sync_host *) 895f515bebSbeck calloc(1, sizeof(struct sync_host))) == NULL) { 905f515bebSbeck freeaddrinfo(res0); 915f515bebSbeck return (ENOMEM); 925f515bebSbeck } 937a904ddaSkrw shost->h_name = strdup(name); 947a904ddaSkrw if (shost->h_name == NULL) { 955f515bebSbeck free(shost); 965f515bebSbeck freeaddrinfo(res0); 975f515bebSbeck return (ENOMEM); 985f515bebSbeck } 995f515bebSbeck 1005f515bebSbeck shost->sh_addr.sin_family = AF_INET; 1015f515bebSbeck shost->sh_addr.sin_port = htons(port); 1025f515bebSbeck shost->sh_addr.sin_addr.s_addr = addr->sin_addr.s_addr; 1035f515bebSbeck freeaddrinfo(res0); 1045f515bebSbeck 1055f515bebSbeck LIST_INSERT_HEAD(&sync_hosts, shost, h_entry); 1065f515bebSbeck 1075f515bebSbeck if (sync_debug) 108c525a185Skrw log_info("added dhcp sync host %s (address %s, port %d)\n", 1093af700feSclaudio shost->h_name, inet_ntoa(shost->sh_addr.sin_addr), port); 1105f515bebSbeck 1115f515bebSbeck return (0); 1125f515bebSbeck } 1135f515bebSbeck 1145f515bebSbeck int 1155f515bebSbeck sync_init(const char *iface, const char *baddr, u_short port) 1165f515bebSbeck { 1175f515bebSbeck int one = 1; 1185f515bebSbeck u_int8_t ttl; 1195f515bebSbeck struct ifreq ifr; 1205f515bebSbeck struct ip_mreq mreq; 1215f515bebSbeck struct sockaddr_in *addr; 1225f515bebSbeck char ifnam[IFNAMSIZ], *ttlstr; 1235f515bebSbeck const char *errstr; 1245f515bebSbeck struct in_addr ina; 1255f515bebSbeck 1265f515bebSbeck if (iface != NULL) 1275f515bebSbeck sendmcast++; 1285f515bebSbeck 12987fe6823Smestre memset(&ina, 0, sizeof(ina)); 1305f515bebSbeck if (baddr != NULL) { 1315f515bebSbeck if (inet_pton(AF_INET, baddr, &ina) != 1) { 1325f515bebSbeck ina.s_addr = htonl(INADDR_ANY); 1335f515bebSbeck if (iface == NULL) 1345f515bebSbeck iface = baddr; 1355f515bebSbeck else if (iface != NULL && strcmp(baddr, iface) != 0) { 1365f515bebSbeck fprintf(stderr, "multicast interface does " 1375f515bebSbeck "not match"); 1385f515bebSbeck return (-1); 1395f515bebSbeck } 1405f515bebSbeck } 1415f515bebSbeck } 1425f515bebSbeck 1435f515bebSbeck sync_key = SHA1File(DHCP_SYNC_KEY, NULL); 1445f515bebSbeck if (sync_key == NULL) { 1455f515bebSbeck if (errno != ENOENT) { 146a76b277aSkrw log_warn("failed to open sync key"); 1475f515bebSbeck return (-1); 1485f515bebSbeck } 1495f515bebSbeck /* Use empty key by default */ 1505f515bebSbeck sync_key = ""; 1515f515bebSbeck } 1525f515bebSbeck 1535f515bebSbeck syncfd = socket(AF_INET, SOCK_DGRAM, 0); 1545f515bebSbeck if (syncfd == -1) 1555f515bebSbeck return (-1); 1565f515bebSbeck 1575f515bebSbeck if (setsockopt(syncfd, SOL_SOCKET, SO_REUSEADDR, &one, 1585f515bebSbeck sizeof(one)) == -1) 1595f515bebSbeck goto fail; 1605f515bebSbeck 16187fe6823Smestre memset(&sync_out, 0, sizeof(sync_out)); 1625f515bebSbeck sync_out.sin_family = AF_INET; 1635f515bebSbeck sync_out.sin_len = sizeof(sync_out); 1645f515bebSbeck sync_out.sin_addr.s_addr = ina.s_addr; 1655f515bebSbeck if (baddr == NULL && iface == NULL) 1665f515bebSbeck sync_out.sin_port = 0; 1675f515bebSbeck else 1685f515bebSbeck sync_out.sin_port = htons(port); 1695f515bebSbeck 1705f515bebSbeck if (bind(syncfd, (struct sockaddr *)&sync_out, sizeof(sync_out)) == -1) 1715f515bebSbeck goto fail; 1725f515bebSbeck 1735f515bebSbeck /* Don't use multicast messages */ 1745f515bebSbeck if (iface == NULL) 1755f515bebSbeck return (syncfd); 1765f515bebSbeck 1775f515bebSbeck strlcpy(ifnam, iface, sizeof(ifnam)); 1785f515bebSbeck ttl = DHCP_SYNC_MCASTTTL; 1795f515bebSbeck if ((ttlstr = strchr(ifnam, ':')) != NULL) { 1805f515bebSbeck *ttlstr++ = '\0'; 1815f515bebSbeck ttl = (u_int8_t)strtonum(ttlstr, 1, UINT8_MAX, &errstr); 1825f515bebSbeck if (errstr) { 1835f515bebSbeck fprintf(stderr, "invalid multicast ttl %s: %s", 1845f515bebSbeck ttlstr, errstr); 1855f515bebSbeck goto fail; 1865f515bebSbeck } 1875f515bebSbeck } 1885f515bebSbeck 18987fe6823Smestre memset(&ifr, 0, sizeof(ifr)); 1905f515bebSbeck strlcpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); 1915f515bebSbeck if (ioctl(syncfd, SIOCGIFADDR, &ifr) == -1) 1925f515bebSbeck goto fail; 1935f515bebSbeck 19487fe6823Smestre memset(&sync_in, 0, sizeof(sync_in)); 1955f515bebSbeck addr = (struct sockaddr_in *)&ifr.ifr_addr; 1965f515bebSbeck sync_in.sin_family = AF_INET; 1975f515bebSbeck sync_in.sin_len = sizeof(sync_in); 1985f515bebSbeck sync_in.sin_addr.s_addr = addr->sin_addr.s_addr; 1995f515bebSbeck sync_in.sin_port = htons(port); 2005f515bebSbeck 20187fe6823Smestre memset(&mreq, 0, sizeof(mreq)); 2025f515bebSbeck sync_out.sin_addr.s_addr = inet_addr(DHCP_SYNC_MCASTADDR); 2035f515bebSbeck mreq.imr_multiaddr.s_addr = inet_addr(DHCP_SYNC_MCASTADDR); 2045f515bebSbeck mreq.imr_interface.s_addr = sync_in.sin_addr.s_addr; 2055f515bebSbeck 2065f515bebSbeck if (setsockopt(syncfd, IPPROTO_IP, 2075f515bebSbeck IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { 208a76b277aSkrw log_warn("failed to add multicast membership to %s", 209a76b277aSkrw DHCP_SYNC_MCASTADDR); 2105f515bebSbeck goto fail; 2115f515bebSbeck } 2125f515bebSbeck if (setsockopt(syncfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 2139bb003e4Sclaudio sizeof(ttl)) == -1) { 214a76b277aSkrw log_warn("failed to set multicast ttl to %u", ttl); 2155f515bebSbeck setsockopt(syncfd, IPPROTO_IP, 2165f515bebSbeck IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); 2175f515bebSbeck goto fail; 2185f515bebSbeck } 2195f515bebSbeck 2205f515bebSbeck if (sync_debug) 221c525a185Skrw log_debug("using multicast dhcp sync %smode " 2225f515bebSbeck "(ttl %u, group %s, port %d)\n", 2235f515bebSbeck sendmcast ? "" : "receive ", 2245f515bebSbeck ttl, inet_ntoa(sync_out.sin_addr), port); 2255f515bebSbeck 2265f515bebSbeck return (syncfd); 2275f515bebSbeck 2285f515bebSbeck fail: 2295f515bebSbeck close(syncfd); 2305f515bebSbeck return (-1); 2315f515bebSbeck } 2325f515bebSbeck 2335f515bebSbeck void 2345f515bebSbeck sync_recv(void) 2355f515bebSbeck { 2365f515bebSbeck struct dhcp_synchdr *hdr; 2375f515bebSbeck struct sockaddr_in addr; 2385f515bebSbeck struct dhcp_synctlv_hdr *tlv; 2395f515bebSbeck struct dhcp_synctlv_lease *lv; 2405f515bebSbeck struct lease *lease; 2415f515bebSbeck u_int8_t buf[DHCP_SYNC_MAXSIZE]; 2425f515bebSbeck u_int8_t hmac[2][DHCP_SYNC_HMAC_LEN]; 2435f515bebSbeck struct lease l, *lp; 2445f515bebSbeck u_int8_t *p; 2455f515bebSbeck socklen_t addr_len; 2465f515bebSbeck ssize_t len; 2475f515bebSbeck u_int hmac_len; 2485f515bebSbeck 24987fe6823Smestre memset(&addr, 0, sizeof(addr)); 25087fe6823Smestre memset(buf, 0, sizeof(buf)); 2515f515bebSbeck 2525f515bebSbeck addr_len = sizeof(addr); 2535f515bebSbeck if ((len = recvfrom(syncfd, buf, sizeof(buf), 0, 2545f515bebSbeck (struct sockaddr *)&addr, &addr_len)) < 1) 2555f515bebSbeck return; 2565f515bebSbeck if (addr.sin_addr.s_addr != htonl(INADDR_ANY) && 2575f515bebSbeck bcmp(&sync_in.sin_addr, &addr.sin_addr, 2585f515bebSbeck sizeof(addr.sin_addr)) == 0) 2595f515bebSbeck return; 2605f515bebSbeck 2615f515bebSbeck /* Ignore invalid or truncated packets */ 2625f515bebSbeck hdr = (struct dhcp_synchdr *)buf; 2635f515bebSbeck if (len < sizeof(struct dhcp_synchdr) || 2645f515bebSbeck hdr->sh_version != DHCP_SYNC_VERSION || 2655f515bebSbeck hdr->sh_af != AF_INET || 2665f515bebSbeck len < ntohs(hdr->sh_length)) 2675f515bebSbeck goto trunc; 2685f515bebSbeck len = ntohs(hdr->sh_length); 2695f515bebSbeck 2705f515bebSbeck /* Compute and validate HMAC */ 2711674d7d2Skrw memcpy(hmac[0], hdr->sh_hmac, DHCP_SYNC_HMAC_LEN); 27287fe6823Smestre explicit_bzero(hdr->sh_hmac, DHCP_SYNC_HMAC_LEN); 2735f515bebSbeck HMAC(EVP_sha1(), sync_key, strlen(sync_key), buf, len, 2745f515bebSbeck hmac[1], &hmac_len); 2755f515bebSbeck if (bcmp(hmac[0], hmac[1], DHCP_SYNC_HMAC_LEN) != 0) 2765f515bebSbeck goto trunc; 2775f515bebSbeck 2785f515bebSbeck if (sync_debug) 279c525a185Skrw log_info("%s(sync): received packet of %d bytes\n", 2805f515bebSbeck inet_ntoa(addr.sin_addr), (int)len); 2815f515bebSbeck 2825f515bebSbeck p = (u_int8_t *)(hdr + 1); 2835f515bebSbeck while (len) { 2845f515bebSbeck tlv = (struct dhcp_synctlv_hdr *)p; 2855f515bebSbeck 2865f515bebSbeck if (len < sizeof(struct dhcp_synctlv_hdr) || 2875f515bebSbeck len < ntohs(tlv->st_length)) 2885f515bebSbeck goto trunc; 2895f515bebSbeck 2905f515bebSbeck switch (ntohs(tlv->st_type)) { 2915f515bebSbeck case DHCP_SYNC_LEASE: 2925f515bebSbeck lv = (struct dhcp_synctlv_lease *)tlv; 2935f515bebSbeck if (sizeof(*lv) > ntohs(tlv->st_length)) 2945f515bebSbeck goto trunc; 295dc53f43cSkrw lease = find_lease_by_hw_addr( 296aa92cf00Skrw lv->lv_hardware_addr.haddr, 297dc53f43cSkrw lv->lv_hardware_addr.hlen); 298dc53f43cSkrw if (lease == NULL) 299dc53f43cSkrw lease = find_lease_by_ip_addr(lv->lv_ip_addr); 3005f515bebSbeck 3015f515bebSbeck lp = &l; 3025f515bebSbeck memset(lp, 0, sizeof(*lp)); 303aa92cf00Skrw lp->timestamp = ntohl(lv->lv_timestamp); 304aa92cf00Skrw lp->starts = ntohl(lv->lv_starts); 305aa92cf00Skrw lp->ends = ntohl(lv->lv_ends); 306aa92cf00Skrw memcpy(&lp->ip_addr, &lv->lv_ip_addr, 3075f515bebSbeck sizeof(lp->ip_addr)); 308aa92cf00Skrw memcpy(&lp->hardware_addr, &lv->lv_hardware_addr, 3095f515bebSbeck sizeof(lp->hardware_addr)); 310*31e6f1a8Ssthen log_debug("DHCP_SYNC_LEASE from %s for hw %s -> ip %s, " 31196bc3eceSkrw "start %lld, end %lld", 3125f515bebSbeck inet_ntoa(addr.sin_addr), 3135f515bebSbeck print_hw_addr(lp->hardware_addr.htype, 3143af700feSclaudio lp->hardware_addr.hlen, lp->hardware_addr.haddr), 31596bc3eceSkrw piaddr(lp->ip_addr), 31696bc3eceSkrw (long long)lp->starts, (long long)lp->ends); 3175f515bebSbeck /* now whack the lease in there */ 3185f515bebSbeck if (lease == NULL) { 3195f515bebSbeck enter_lease(lp); 3205f515bebSbeck write_leases(); 3215f515bebSbeck } 3225f515bebSbeck else if (lease->ends < lp->ends) 3235f515bebSbeck supersede_lease(lease, lp, 1); 3245f515bebSbeck else if (lease->ends > lp->ends) 3255f515bebSbeck /* 3265f515bebSbeck * our partner sent us a lease 3275f515bebSbeck * that is older than what we have, 3285f515bebSbeck * so re-educate them with what we 3295f515bebSbeck * know is newer. 3305f515bebSbeck */ 3315f515bebSbeck sync_lease(lease); 3325f515bebSbeck break; 3335f515bebSbeck case DHCP_SYNC_END: 3345f515bebSbeck goto done; 3355f515bebSbeck default: 3365f515bebSbeck printf("invalid type: %d\n", ntohs(tlv->st_type)); 3375f515bebSbeck goto trunc; 3385f515bebSbeck } 3395f515bebSbeck len -= ntohs(tlv->st_length); 3405f515bebSbeck p = ((u_int8_t *)tlv) + ntohs(tlv->st_length); 3415f515bebSbeck } 3425f515bebSbeck 3435f515bebSbeck done: 3445f515bebSbeck return; 3455f515bebSbeck 3465f515bebSbeck trunc: 3475f515bebSbeck if (sync_debug) 348c525a185Skrw log_info("%s(sync): truncated or invalid packet\n", 3495f515bebSbeck inet_ntoa(addr.sin_addr)); 3505f515bebSbeck } 3515f515bebSbeck 3525f515bebSbeck void 3535f515bebSbeck sync_send(struct iovec *iov, int iovlen) 3545f515bebSbeck { 3555f515bebSbeck struct sync_host *shost; 3565f515bebSbeck struct msghdr msg; 3575f515bebSbeck 3587eab935eSbeck if (syncfd == -1) 3597eab935eSbeck return; 3607eab935eSbeck 3615f515bebSbeck /* setup buffer */ 36287fe6823Smestre memset(&msg, 0, sizeof(msg)); 3635f515bebSbeck msg.msg_iov = iov; 3645f515bebSbeck msg.msg_iovlen = iovlen; 3655f515bebSbeck 3665f515bebSbeck if (sendmcast) { 3675f515bebSbeck if (sync_debug) 368c525a185Skrw log_info("sending multicast sync message\n"); 3695f515bebSbeck msg.msg_name = &sync_out; 3705f515bebSbeck msg.msg_namelen = sizeof(sync_out); 3713af700feSclaudio if (sendmsg(syncfd, &msg, 0) == -1) 3720438cf0aSkrw log_warn("sending multicast sync message failed"); 3735f515bebSbeck } 3745f515bebSbeck 3755f515bebSbeck LIST_FOREACH(shost, &sync_hosts, h_entry) { 3765f515bebSbeck if (sync_debug) 377c525a185Skrw log_info("sending sync message to %s (%s)\n", 3785f515bebSbeck shost->h_name, inet_ntoa(shost->sh_addr.sin_addr)); 3795f515bebSbeck msg.msg_name = &shost->sh_addr; 3805f515bebSbeck msg.msg_namelen = sizeof(shost->sh_addr); 3813af700feSclaudio if (sendmsg(syncfd, &msg, 0) == -1) 3820438cf0aSkrw log_warn("sending sync message failed"); 3835f515bebSbeck } 3845f515bebSbeck } 3855f515bebSbeck 3865f515bebSbeck void 3875f515bebSbeck sync_lease(struct lease *lease) 3885f515bebSbeck { 389ed4ccfd6Sderaadt struct iovec iov[4]; 3905f515bebSbeck struct dhcp_synchdr hdr; 391aa92cf00Skrw struct dhcp_synctlv_lease lv; 3925f515bebSbeck struct dhcp_synctlv_hdr end; 3933aa44215Sderaadt char pad[DHCP_ALIGNBYTES]; 3943aa44215Sderaadt u_int16_t leaselen, padlen; 3955f515bebSbeck int i = 0; 3968f4b0a11Stb HMAC_CTX *ctx; 3975f515bebSbeck u_int hmac_len; 3985f515bebSbeck 399a07ad480Sbeck if (sync_key == NULL) 400a07ad480Sbeck return; 401a07ad480Sbeck 40287fe6823Smestre memset(&hdr, 0, sizeof(hdr)); 40387fe6823Smestre memset(&lv, 0, sizeof(lv)); 40487fe6823Smestre memset(&pad, 0, sizeof(pad)); 4055f515bebSbeck 4068f4b0a11Stb if ((ctx = HMAC_CTX_new()) == NULL) 4078f4b0a11Stb goto bad; 4088f4b0a11Stb if (!HMAC_Init_ex(ctx, sync_key, strlen(sync_key), EVP_sha1(), NULL)) 4098f4b0a11Stb goto bad; 4105f515bebSbeck 411aa92cf00Skrw leaselen = sizeof(lv); 4123aa44215Sderaadt padlen = DHCP_ALIGN(leaselen) - leaselen; 4133aa44215Sderaadt 4145f515bebSbeck /* Add DHCP sync packet header */ 4155f515bebSbeck hdr.sh_version = DHCP_SYNC_VERSION; 4165f515bebSbeck hdr.sh_af = AF_INET; 4175f515bebSbeck hdr.sh_counter = sync_counter++; 418aa92cf00Skrw hdr.sh_length = htons(sizeof(hdr) + sizeof(lv) + padlen + sizeof(end)); 4195f515bebSbeck iov[i].iov_base = &hdr; 4205f515bebSbeck iov[i].iov_len = sizeof(hdr); 4218f4b0a11Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len)) 4228f4b0a11Stb goto bad; 4235f515bebSbeck i++; 4245f515bebSbeck 4255f515bebSbeck /* Add single DHCP sync address entry */ 426aa92cf00Skrw lv.lv_type = htons(DHCP_SYNC_LEASE); 427aa92cf00Skrw lv.lv_length = htons(leaselen + padlen); 428aa92cf00Skrw lv.lv_timestamp = htonl(lease->timestamp); 429aa92cf00Skrw lv.lv_starts = htonl(lease->starts); 430aa92cf00Skrw lv.lv_ends = htonl(lease->ends); 431aa92cf00Skrw memcpy(&lv.lv_ip_addr, &lease->ip_addr, sizeof(lv.lv_ip_addr)); 432aa92cf00Skrw memcpy(&lv.lv_hardware_addr, &lease->hardware_addr, 433aa92cf00Skrw sizeof(lv.lv_hardware_addr)); 434*31e6f1a8Ssthen log_debug("sending DHCP_SYNC_LEASE for hw %s -> ip %s, start %d, " 43535318e8fSkrw "end %d", print_hw_addr(lv.lv_hardware_addr.htype, 43635318e8fSkrw lv.lv_hardware_addr.hlen, lv.lv_hardware_addr.haddr), 43735318e8fSkrw piaddr(lease->ip_addr), ntohl(lv.lv_starts), ntohl(lv.lv_ends)); 438aa92cf00Skrw iov[i].iov_base = &lv; 439aa92cf00Skrw iov[i].iov_len = sizeof(lv); 4408f4b0a11Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len)) 4418f4b0a11Stb goto bad; 4425f515bebSbeck i++; 4435f515bebSbeck 4443aa44215Sderaadt iov[i].iov_base = pad; 4453aa44215Sderaadt iov[i].iov_len = padlen; 4468f4b0a11Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len)) 4478f4b0a11Stb goto bad; 4483aa44215Sderaadt i++; 4493aa44215Sderaadt 4505f515bebSbeck /* Add end marker */ 4515f515bebSbeck end.st_type = htons(DHCP_SYNC_END); 4525f515bebSbeck end.st_length = htons(sizeof(end)); 4535f515bebSbeck iov[i].iov_base = &end; 4545f515bebSbeck iov[i].iov_len = sizeof(end); 4558f4b0a11Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len)) 4568f4b0a11Stb goto bad; 4575f515bebSbeck i++; 4585f515bebSbeck 4598f4b0a11Stb if (!HMAC_Final(ctx, hdr.sh_hmac, &hmac_len)) 4608f4b0a11Stb goto bad; 4615f515bebSbeck 4625f515bebSbeck /* Send message to the target hosts */ 4635f515bebSbeck sync_send(iov, i); 4648f4b0a11Stb 4658f4b0a11Stb bad: 4668f4b0a11Stb HMAC_CTX_free(ctx); 4675f515bebSbeck } 468