1 |
|
|
/* $OpenBSD: sync.c,v 1.23 2017/02/13 23:04:05 krw Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2008 Bob Beck <beck@openbsd.org> |
5 |
|
|
* Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org> |
6 |
|
|
* |
7 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
8 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
9 |
|
|
* copyright notice and this permission notice appear in all copies. |
10 |
|
|
* |
11 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 |
|
|
*/ |
19 |
|
|
|
20 |
|
|
#include <sys/types.h> |
21 |
|
|
#include <sys/ioctl.h> |
22 |
|
|
#include <sys/queue.h> |
23 |
|
|
#include <sys/socket.h> |
24 |
|
|
|
25 |
|
|
#include <net/if.h> |
26 |
|
|
|
27 |
|
|
#include <arpa/inet.h> |
28 |
|
|
|
29 |
|
|
#include <netinet/in.h> |
30 |
|
|
|
31 |
|
|
#include <openssl/hmac.h> |
32 |
|
|
|
33 |
|
|
#include <errno.h> |
34 |
|
|
#include <netdb.h> |
35 |
|
|
#include <sha1.h> |
36 |
|
|
#include <string.h> |
37 |
|
|
#include <syslog.h> |
38 |
|
|
#include <unistd.h> |
39 |
|
|
|
40 |
|
|
#include "dhcp.h" |
41 |
|
|
#include "tree.h" |
42 |
|
|
#include "dhcpd.h" |
43 |
|
|
#include "log.h" |
44 |
|
|
#include "sync.h" |
45 |
|
|
|
46 |
|
|
int sync_debug; |
47 |
|
|
|
48 |
|
|
u_int32_t sync_counter; |
49 |
|
|
int syncfd = -1; |
50 |
|
|
int sendmcast; |
51 |
|
|
|
52 |
|
|
struct sockaddr_in sync_in; |
53 |
|
|
struct sockaddr_in sync_out; |
54 |
|
|
static char *sync_key; |
55 |
|
|
|
56 |
|
|
struct sync_host { |
57 |
|
|
LIST_ENTRY(sync_host) h_entry; |
58 |
|
|
|
59 |
|
|
char *h_name; |
60 |
|
|
struct sockaddr_in sh_addr; |
61 |
|
|
}; |
62 |
|
|
LIST_HEAD(synchosts, sync_host) sync_hosts = LIST_HEAD_INITIALIZER(sync_hosts); |
63 |
|
|
|
64 |
|
|
void sync_send(struct iovec *, int); |
65 |
|
|
|
66 |
|
|
int |
67 |
|
|
sync_addhost(const char *name, u_short port) |
68 |
|
|
{ |
69 |
|
|
struct addrinfo hints, *res, *res0; |
70 |
|
|
struct sync_host *shost; |
71 |
|
|
struct sockaddr_in *addr = NULL; |
72 |
|
|
|
73 |
|
|
memset(&hints, 0, sizeof(hints)); |
74 |
|
|
hints.ai_family = PF_UNSPEC; |
75 |
|
|
hints.ai_socktype = SOCK_STREAM; |
76 |
|
|
if (getaddrinfo(name, NULL, &hints, &res0) != 0) |
77 |
|
|
return (EINVAL); |
78 |
|
|
for (res = res0; res != NULL; res = res->ai_next) { |
79 |
|
|
if (addr == NULL && res->ai_family == AF_INET) { |
80 |
|
|
addr = (struct sockaddr_in *)res->ai_addr; |
81 |
|
|
break; |
82 |
|
|
} |
83 |
|
|
} |
84 |
|
|
if (addr == NULL) { |
85 |
|
|
freeaddrinfo(res0); |
86 |
|
|
return (EINVAL); |
87 |
|
|
} |
88 |
|
|
if ((shost = (struct sync_host *) |
89 |
|
|
calloc(1, sizeof(struct sync_host))) == NULL) { |
90 |
|
|
freeaddrinfo(res0); |
91 |
|
|
return (ENOMEM); |
92 |
|
|
} |
93 |
|
|
shost->h_name = strdup(name); |
94 |
|
|
if (shost->h_name == NULL) { |
95 |
|
|
free(shost); |
96 |
|
|
freeaddrinfo(res0); |
97 |
|
|
return (ENOMEM); |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
shost->sh_addr.sin_family = AF_INET; |
101 |
|
|
shost->sh_addr.sin_port = htons(port); |
102 |
|
|
shost->sh_addr.sin_addr.s_addr = addr->sin_addr.s_addr; |
103 |
|
|
freeaddrinfo(res0); |
104 |
|
|
|
105 |
|
|
LIST_INSERT_HEAD(&sync_hosts, shost, h_entry); |
106 |
|
|
|
107 |
|
|
if (sync_debug) |
108 |
|
|
log_info("added dhcp sync host %s (address %s, port %d)\n", |
109 |
|
|
shost->h_name, inet_ntoa(shost->sh_addr.sin_addr), port); |
110 |
|
|
|
111 |
|
|
return (0); |
112 |
|
|
} |
113 |
|
|
|
114 |
|
|
int |
115 |
|
|
sync_init(const char *iface, const char *baddr, u_short port) |
116 |
|
|
{ |
117 |
|
|
int one = 1; |
118 |
|
|
u_int8_t ttl; |
119 |
|
|
struct ifreq ifr; |
120 |
|
|
struct ip_mreq mreq; |
121 |
|
|
struct sockaddr_in *addr; |
122 |
|
|
char ifnam[IFNAMSIZ], *ttlstr; |
123 |
|
|
const char *errstr; |
124 |
|
|
struct in_addr ina; |
125 |
|
|
|
126 |
|
|
if (iface != NULL) |
127 |
|
|
sendmcast++; |
128 |
|
|
|
129 |
|
|
memset(&ina, 0, sizeof(ina)); |
130 |
|
|
if (baddr != NULL) { |
131 |
|
|
if (inet_pton(AF_INET, baddr, &ina) != 1) { |
132 |
|
|
ina.s_addr = htonl(INADDR_ANY); |
133 |
|
|
if (iface == NULL) |
134 |
|
|
iface = baddr; |
135 |
|
|
else if (iface != NULL && strcmp(baddr, iface) != 0) { |
136 |
|
|
fprintf(stderr, "multicast interface does " |
137 |
|
|
"not match"); |
138 |
|
|
return (-1); |
139 |
|
|
} |
140 |
|
|
} |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
sync_key = SHA1File(DHCP_SYNC_KEY, NULL); |
144 |
|
|
if (sync_key == NULL) { |
145 |
|
|
if (errno != ENOENT) { |
146 |
|
|
log_warn("failed to open sync key"); |
147 |
|
|
return (-1); |
148 |
|
|
} |
149 |
|
|
/* Use empty key by default */ |
150 |
|
|
sync_key = ""; |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
syncfd = socket(AF_INET, SOCK_DGRAM, 0); |
154 |
|
|
if (syncfd == -1) |
155 |
|
|
return (-1); |
156 |
|
|
|
157 |
|
|
if (setsockopt(syncfd, SOL_SOCKET, SO_REUSEADDR, &one, |
158 |
|
|
sizeof(one)) == -1) |
159 |
|
|
goto fail; |
160 |
|
|
|
161 |
|
|
memset(&sync_out, 0, sizeof(sync_out)); |
162 |
|
|
sync_out.sin_family = AF_INET; |
163 |
|
|
sync_out.sin_len = sizeof(sync_out); |
164 |
|
|
sync_out.sin_addr.s_addr = ina.s_addr; |
165 |
|
|
if (baddr == NULL && iface == NULL) |
166 |
|
|
sync_out.sin_port = 0; |
167 |
|
|
else |
168 |
|
|
sync_out.sin_port = htons(port); |
169 |
|
|
|
170 |
|
|
if (bind(syncfd, (struct sockaddr *)&sync_out, sizeof(sync_out)) == -1) |
171 |
|
|
goto fail; |
172 |
|
|
|
173 |
|
|
/* Don't use multicast messages */ |
174 |
|
|
if (iface == NULL) |
175 |
|
|
return (syncfd); |
176 |
|
|
|
177 |
|
|
strlcpy(ifnam, iface, sizeof(ifnam)); |
178 |
|
|
ttl = DHCP_SYNC_MCASTTTL; |
179 |
|
|
if ((ttlstr = strchr(ifnam, ':')) != NULL) { |
180 |
|
|
*ttlstr++ = '\0'; |
181 |
|
|
ttl = (u_int8_t)strtonum(ttlstr, 1, UINT8_MAX, &errstr); |
182 |
|
|
if (errstr) { |
183 |
|
|
fprintf(stderr, "invalid multicast ttl %s: %s", |
184 |
|
|
ttlstr, errstr); |
185 |
|
|
goto fail; |
186 |
|
|
} |
187 |
|
|
} |
188 |
|
|
|
189 |
|
|
memset(&ifr, 0, sizeof(ifr)); |
190 |
|
|
strlcpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); |
191 |
|
|
if (ioctl(syncfd, SIOCGIFADDR, &ifr) == -1) |
192 |
|
|
goto fail; |
193 |
|
|
|
194 |
|
|
memset(&sync_in, 0, sizeof(sync_in)); |
195 |
|
|
addr = (struct sockaddr_in *)&ifr.ifr_addr; |
196 |
|
|
sync_in.sin_family = AF_INET; |
197 |
|
|
sync_in.sin_len = sizeof(sync_in); |
198 |
|
|
sync_in.sin_addr.s_addr = addr->sin_addr.s_addr; |
199 |
|
|
sync_in.sin_port = htons(port); |
200 |
|
|
|
201 |
|
|
memset(&mreq, 0, sizeof(mreq)); |
202 |
|
|
sync_out.sin_addr.s_addr = inet_addr(DHCP_SYNC_MCASTADDR); |
203 |
|
|
mreq.imr_multiaddr.s_addr = inet_addr(DHCP_SYNC_MCASTADDR); |
204 |
|
|
mreq.imr_interface.s_addr = sync_in.sin_addr.s_addr; |
205 |
|
|
|
206 |
|
|
if (setsockopt(syncfd, IPPROTO_IP, |
207 |
|
|
IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { |
208 |
|
|
log_warn("failed to add multicast membership to %s", |
209 |
|
|
DHCP_SYNC_MCASTADDR); |
210 |
|
|
goto fail; |
211 |
|
|
} |
212 |
|
|
if (setsockopt(syncfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, |
213 |
|
|
sizeof(ttl)) == -1) { |
214 |
|
|
log_warn("failed to set multicast ttl to %u", ttl); |
215 |
|
|
setsockopt(syncfd, IPPROTO_IP, |
216 |
|
|
IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); |
217 |
|
|
goto fail; |
218 |
|
|
} |
219 |
|
|
|
220 |
|
|
if (sync_debug) |
221 |
|
|
log_debug("using multicast dhcp sync %smode " |
222 |
|
|
"(ttl %u, group %s, port %d)\n", |
223 |
|
|
sendmcast ? "" : "receive ", |
224 |
|
|
ttl, inet_ntoa(sync_out.sin_addr), port); |
225 |
|
|
|
226 |
|
|
return (syncfd); |
227 |
|
|
|
228 |
|
|
fail: |
229 |
|
|
close(syncfd); |
230 |
|
|
return (-1); |
231 |
|
|
} |
232 |
|
|
|
233 |
|
|
void |
234 |
|
|
sync_recv(void) |
235 |
|
|
{ |
236 |
|
|
struct dhcp_synchdr *hdr; |
237 |
|
|
struct sockaddr_in addr; |
238 |
|
|
struct dhcp_synctlv_hdr *tlv; |
239 |
|
|
struct dhcp_synctlv_lease *lv; |
240 |
|
|
struct lease *lease; |
241 |
|
|
u_int8_t buf[DHCP_SYNC_MAXSIZE]; |
242 |
|
|
u_int8_t hmac[2][DHCP_SYNC_HMAC_LEN]; |
243 |
|
|
struct lease l, *lp; |
244 |
|
|
u_int8_t *p; |
245 |
|
|
socklen_t addr_len; |
246 |
|
|
ssize_t len; |
247 |
|
|
u_int hmac_len; |
248 |
|
|
|
249 |
|
|
memset(&addr, 0, sizeof(addr)); |
250 |
|
|
memset(buf, 0, sizeof(buf)); |
251 |
|
|
|
252 |
|
|
addr_len = sizeof(addr); |
253 |
|
|
if ((len = recvfrom(syncfd, buf, sizeof(buf), 0, |
254 |
|
|
(struct sockaddr *)&addr, &addr_len)) < 1) |
255 |
|
|
return; |
256 |
|
|
if (addr.sin_addr.s_addr != htonl(INADDR_ANY) && |
257 |
|
|
bcmp(&sync_in.sin_addr, &addr.sin_addr, |
258 |
|
|
sizeof(addr.sin_addr)) == 0) |
259 |
|
|
return; |
260 |
|
|
|
261 |
|
|
/* Ignore invalid or truncated packets */ |
262 |
|
|
hdr = (struct dhcp_synchdr *)buf; |
263 |
|
|
if (len < sizeof(struct dhcp_synchdr) || |
264 |
|
|
hdr->sh_version != DHCP_SYNC_VERSION || |
265 |
|
|
hdr->sh_af != AF_INET || |
266 |
|
|
len < ntohs(hdr->sh_length)) |
267 |
|
|
goto trunc; |
268 |
|
|
len = ntohs(hdr->sh_length); |
269 |
|
|
|
270 |
|
|
/* Compute and validate HMAC */ |
271 |
|
|
memcpy(hmac[0], hdr->sh_hmac, DHCP_SYNC_HMAC_LEN); |
272 |
|
|
explicit_bzero(hdr->sh_hmac, DHCP_SYNC_HMAC_LEN); |
273 |
|
|
HMAC(EVP_sha1(), sync_key, strlen(sync_key), buf, len, |
274 |
|
|
hmac[1], &hmac_len); |
275 |
|
|
if (bcmp(hmac[0], hmac[1], DHCP_SYNC_HMAC_LEN) != 0) |
276 |
|
|
goto trunc; |
277 |
|
|
|
278 |
|
|
if (sync_debug) |
279 |
|
|
log_info("%s(sync): received packet of %d bytes\n", |
280 |
|
|
inet_ntoa(addr.sin_addr), (int)len); |
281 |
|
|
|
282 |
|
|
p = (u_int8_t *)(hdr + 1); |
283 |
|
|
while (len) { |
284 |
|
|
tlv = (struct dhcp_synctlv_hdr *)p; |
285 |
|
|
|
286 |
|
|
if (len < sizeof(struct dhcp_synctlv_hdr) || |
287 |
|
|
len < ntohs(tlv->st_length)) |
288 |
|
|
goto trunc; |
289 |
|
|
|
290 |
|
|
switch (ntohs(tlv->st_type)) { |
291 |
|
|
case DHCP_SYNC_LEASE: |
292 |
|
|
lv = (struct dhcp_synctlv_lease *)tlv; |
293 |
|
|
if (sizeof(*lv) > ntohs(tlv->st_length)) |
294 |
|
|
goto trunc; |
295 |
|
|
lease = find_lease_by_hw_addr( |
296 |
|
|
lv->lv_hardware_addr.haddr, |
297 |
|
|
lv->lv_hardware_addr.hlen); |
298 |
|
|
if (lease == NULL) |
299 |
|
|
lease = find_lease_by_ip_addr(lv->lv_ip_addr); |
300 |
|
|
|
301 |
|
|
lp = &l; |
302 |
|
|
memset(lp, 0, sizeof(*lp)); |
303 |
|
|
lp->timestamp = ntohl(lv->lv_timestamp); |
304 |
|
|
lp->starts = ntohl(lv->lv_starts); |
305 |
|
|
lp->ends = ntohl(lv->lv_ends); |
306 |
|
|
memcpy(&lp->ip_addr, &lv->lv_ip_addr, |
307 |
|
|
sizeof(lp->ip_addr)); |
308 |
|
|
memcpy(&lp->hardware_addr, &lv->lv_hardware_addr, |
309 |
|
|
sizeof(lp->hardware_addr)); |
310 |
|
|
log_info("DHCP_SYNC_LEASE from %s for hw %s -> ip %s, " |
311 |
|
|
"start %lld, end %lld", |
312 |
|
|
inet_ntoa(addr.sin_addr), |
313 |
|
|
print_hw_addr(lp->hardware_addr.htype, |
314 |
|
|
lp->hardware_addr.hlen, lp->hardware_addr.haddr), |
315 |
|
|
piaddr(lp->ip_addr), |
316 |
|
|
(long long)lp->starts, (long long)lp->ends); |
317 |
|
|
/* now whack the lease in there */ |
318 |
|
|
if (lease == NULL) { |
319 |
|
|
enter_lease(lp); |
320 |
|
|
write_leases(); |
321 |
|
|
} |
322 |
|
|
else if (lease->ends < lp->ends) |
323 |
|
|
supersede_lease(lease, lp, 1); |
324 |
|
|
else if (lease->ends > lp->ends) |
325 |
|
|
/* |
326 |
|
|
* our partner sent us a lease |
327 |
|
|
* that is older than what we have, |
328 |
|
|
* so re-educate them with what we |
329 |
|
|
* know is newer. |
330 |
|
|
*/ |
331 |
|
|
sync_lease(lease); |
332 |
|
|
break; |
333 |
|
|
case DHCP_SYNC_END: |
334 |
|
|
goto done; |
335 |
|
|
default: |
336 |
|
|
printf("invalid type: %d\n", ntohs(tlv->st_type)); |
337 |
|
|
goto trunc; |
338 |
|
|
} |
339 |
|
|
len -= ntohs(tlv->st_length); |
340 |
|
|
p = ((u_int8_t *)tlv) + ntohs(tlv->st_length); |
341 |
|
|
} |
342 |
|
|
|
343 |
|
|
done: |
344 |
|
|
return; |
345 |
|
|
|
346 |
|
|
trunc: |
347 |
|
|
if (sync_debug) |
348 |
|
|
log_info("%s(sync): truncated or invalid packet\n", |
349 |
|
|
inet_ntoa(addr.sin_addr)); |
350 |
|
|
} |
351 |
|
|
|
352 |
|
|
void |
353 |
|
|
sync_send(struct iovec *iov, int iovlen) |
354 |
|
|
{ |
355 |
|
|
struct sync_host *shost; |
356 |
|
|
struct msghdr msg; |
357 |
|
|
|
358 |
|
|
if (syncfd == -1) |
359 |
|
|
return; |
360 |
|
|
|
361 |
|
|
/* setup buffer */ |
362 |
|
|
memset(&msg, 0, sizeof(msg)); |
363 |
|
|
msg.msg_iov = iov; |
364 |
|
|
msg.msg_iovlen = iovlen; |
365 |
|
|
|
366 |
|
|
if (sendmcast) { |
367 |
|
|
if (sync_debug) |
368 |
|
|
log_info("sending multicast sync message\n"); |
369 |
|
|
msg.msg_name = &sync_out; |
370 |
|
|
msg.msg_namelen = sizeof(sync_out); |
371 |
|
|
if (sendmsg(syncfd, &msg, 0) == -1) |
372 |
|
|
log_warn("sending multicast sync message failed"); |
373 |
|
|
} |
374 |
|
|
|
375 |
|
|
LIST_FOREACH(shost, &sync_hosts, h_entry) { |
376 |
|
|
if (sync_debug) |
377 |
|
|
log_info("sending sync message to %s (%s)\n", |
378 |
|
|
shost->h_name, inet_ntoa(shost->sh_addr.sin_addr)); |
379 |
|
|
msg.msg_name = &shost->sh_addr; |
380 |
|
|
msg.msg_namelen = sizeof(shost->sh_addr); |
381 |
|
|
if (sendmsg(syncfd, &msg, 0) == -1) |
382 |
|
|
log_warn("sending sync message failed"); |
383 |
|
|
} |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
void |
387 |
|
|
sync_lease(struct lease *lease) |
388 |
|
|
{ |
389 |
|
|
struct iovec iov[4]; |
390 |
|
|
struct dhcp_synchdr hdr; |
391 |
|
|
struct dhcp_synctlv_lease lv; |
392 |
|
|
struct dhcp_synctlv_hdr end; |
393 |
|
|
char pad[DHCP_ALIGNBYTES]; |
394 |
|
|
u_int16_t leaselen, padlen; |
395 |
|
|
int i = 0; |
396 |
|
|
HMAC_CTX ctx; |
397 |
|
|
u_int hmac_len; |
398 |
|
|
|
399 |
|
|
if (sync_key == NULL) |
400 |
|
|
return; |
401 |
|
|
|
402 |
|
|
memset(&hdr, 0, sizeof(hdr)); |
403 |
|
|
memset(&lv, 0, sizeof(lv)); |
404 |
|
|
memset(&pad, 0, sizeof(pad)); |
405 |
|
|
|
406 |
|
|
HMAC_CTX_init(&ctx); |
407 |
|
|
HMAC_Init(&ctx, sync_key, strlen(sync_key), EVP_sha1()); |
408 |
|
|
|
409 |
|
|
leaselen = sizeof(lv); |
410 |
|
|
padlen = DHCP_ALIGN(leaselen) - leaselen; |
411 |
|
|
|
412 |
|
|
/* Add DHCP sync packet header */ |
413 |
|
|
hdr.sh_version = DHCP_SYNC_VERSION; |
414 |
|
|
hdr.sh_af = AF_INET; |
415 |
|
|
hdr.sh_counter = sync_counter++; |
416 |
|
|
hdr.sh_length = htons(sizeof(hdr) + sizeof(lv) + padlen + sizeof(end)); |
417 |
|
|
iov[i].iov_base = &hdr; |
418 |
|
|
iov[i].iov_len = sizeof(hdr); |
419 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
420 |
|
|
i++; |
421 |
|
|
|
422 |
|
|
/* Add single DHCP sync address entry */ |
423 |
|
|
lv.lv_type = htons(DHCP_SYNC_LEASE); |
424 |
|
|
lv.lv_length = htons(leaselen + padlen); |
425 |
|
|
lv.lv_timestamp = htonl(lease->timestamp); |
426 |
|
|
lv.lv_starts = htonl(lease->starts); |
427 |
|
|
lv.lv_ends = htonl(lease->ends); |
428 |
|
|
memcpy(&lv.lv_ip_addr, &lease->ip_addr, sizeof(lv.lv_ip_addr)); |
429 |
|
|
memcpy(&lv.lv_hardware_addr, &lease->hardware_addr, |
430 |
|
|
sizeof(lv.lv_hardware_addr)); |
431 |
|
|
log_info("sending DHCP_SYNC_LEASE for hw %s -> ip %s, start %d, " |
432 |
|
|
"end %d", print_hw_addr(lv.lv_hardware_addr.htype, |
433 |
|
|
lv.lv_hardware_addr.hlen, lv.lv_hardware_addr.haddr), |
434 |
|
|
piaddr(lease->ip_addr), ntohl(lv.lv_starts), ntohl(lv.lv_ends)); |
435 |
|
|
iov[i].iov_base = &lv; |
436 |
|
|
iov[i].iov_len = sizeof(lv); |
437 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
438 |
|
|
i++; |
439 |
|
|
|
440 |
|
|
iov[i].iov_base = pad; |
441 |
|
|
iov[i].iov_len = padlen; |
442 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
443 |
|
|
i++; |
444 |
|
|
|
445 |
|
|
/* Add end marker */ |
446 |
|
|
end.st_type = htons(DHCP_SYNC_END); |
447 |
|
|
end.st_length = htons(sizeof(end)); |
448 |
|
|
iov[i].iov_base = &end; |
449 |
|
|
iov[i].iov_len = sizeof(end); |
450 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
451 |
|
|
i++; |
452 |
|
|
|
453 |
|
|
HMAC_Final(&ctx, hdr.sh_hmac, &hmac_len); |
454 |
|
|
|
455 |
|
|
/* Send message to the target hosts */ |
456 |
|
|
sync_send(iov, i); |
457 |
|
|
HMAC_CTX_cleanup(&ctx); |
458 |
|
|
} |