1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2013 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <net/if_arp.h>
7 #include <sys/ioctl.h>
8
9 #include "sd-dhcp-server.h"
10 #include "sd-id128.h"
11
12 #include "alloc-util.h"
13 #include "dhcp-internal.h"
14 #include "dhcp-server-internal.h"
15 #include "dns-domain.h"
16 #include "fd-util.h"
17 #include "in-addr-util.h"
18 #include "io-util.h"
19 #include "memory-util.h"
20 #include "network-common.h"
21 #include "ordered-set.h"
22 #include "siphash24.h"
23 #include "string-util.h"
24 #include "unaligned.h"
25 #include "utf8.h"
26
27 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
28 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
29
dhcp_lease_free(DHCPLease * lease)30 static DHCPLease *dhcp_lease_free(DHCPLease *lease) {
31 if (!lease)
32 return NULL;
33
34 if (lease->server) {
35 hashmap_remove_value(lease->server->bound_leases_by_address, UINT32_TO_PTR(lease->address), lease);
36 hashmap_remove_value(lease->server->bound_leases_by_client_id, &lease->client_id, lease);
37 hashmap_remove_value(lease->server->static_leases_by_address, UINT32_TO_PTR(lease->address), lease);
38 hashmap_remove_value(lease->server->static_leases_by_client_id, &lease->client_id, lease);
39 }
40
41 free(lease->client_id.data);
42 return mfree(lease);
43 }
44
45 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease*, dhcp_lease_free);
46
47 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
48 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
49 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
50 * accidentally hand it out */
sd_dhcp_server_configure_pool(sd_dhcp_server * server,const struct in_addr * address,unsigned char prefixlen,uint32_t offset,uint32_t size)51 int sd_dhcp_server_configure_pool(
52 sd_dhcp_server *server,
53 const struct in_addr *address,
54 unsigned char prefixlen,
55 uint32_t offset,
56 uint32_t size) {
57
58 struct in_addr netmask_addr;
59 be32_t netmask;
60 uint32_t server_off, broadcast_off, size_max;
61
62 assert_return(server, -EINVAL);
63 assert_return(address, -EINVAL);
64 assert_return(address->s_addr != INADDR_ANY, -EINVAL);
65 assert_return(prefixlen <= 32, -ERANGE);
66
67 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
68 netmask = netmask_addr.s_addr;
69
70 server_off = be32toh(address->s_addr & ~netmask);
71 broadcast_off = be32toh(~netmask);
72
73 /* the server address cannot be the subnet address */
74 assert_return(server_off != 0, -ERANGE);
75
76 /* nor the broadcast address */
77 assert_return(server_off != broadcast_off, -ERANGE);
78
79 /* 0 offset means we should set a default, we skip the first (subnet) address
80 and take the next one */
81 if (offset == 0)
82 offset = 1;
83
84 size_max = (broadcast_off + 1) /* the number of addresses in the subnet */
85 - offset /* exclude the addresses before the offset */
86 - 1; /* exclude the last (broadcast) address */
87
88 /* The pool must contain at least one address */
89 assert_return(size_max >= 1, -ERANGE);
90
91 if (size != 0)
92 assert_return(size <= size_max, -ERANGE);
93 else
94 size = size_max;
95
96 if (server->address != address->s_addr || server->netmask != netmask || server->pool_size != size || server->pool_offset != offset) {
97
98 server->pool_offset = offset;
99 server->pool_size = size;
100
101 server->address = address->s_addr;
102 server->netmask = netmask;
103 server->subnet = address->s_addr & netmask;
104
105 /* Drop any leases associated with the old address range */
106 hashmap_clear(server->bound_leases_by_address);
107 hashmap_clear(server->bound_leases_by_client_id);
108
109 if (server->callback)
110 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
111 }
112
113 return 0;
114 }
115
sd_dhcp_server_is_running(sd_dhcp_server * server)116 int sd_dhcp_server_is_running(sd_dhcp_server *server) {
117 assert_return(server, false);
118
119 return !!server->receive_message;
120 }
121
sd_dhcp_server_is_in_relay_mode(sd_dhcp_server * server)122 int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server) {
123 assert_return(server, -EINVAL);
124
125 return in4_addr_is_set(&server->relay_target);
126 }
127
client_id_hash_func(const DHCPClientId * id,struct siphash * state)128 void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
129 assert(id);
130 assert(id->length > 0);
131 assert(id->data);
132
133 siphash24_compress(&id->length, sizeof(id->length), state);
134 siphash24_compress(id->data, id->length, state);
135 }
136
client_id_compare_func(const DHCPClientId * a,const DHCPClientId * b)137 int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
138 int r;
139
140 assert(a->length > 0);
141 assert(a->data);
142 assert(b->length > 0);
143 assert(b->data);
144
145 r = CMP(a->length, b->length);
146 if (r != 0)
147 return r;
148
149 return memcmp(a->data, b->data, a->length);
150 }
151
152 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
153 dhcp_lease_hash_ops,
154 DHCPClientId,
155 client_id_hash_func,
156 client_id_compare_func,
157 DHCPLease,
158 dhcp_lease_free);
159
dhcp_server_free(sd_dhcp_server * server)160 static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
161 assert(server);
162
163 sd_dhcp_server_stop(server);
164
165 sd_event_unref(server->event);
166
167 free(server->boot_server_name);
168 free(server->boot_filename);
169 free(server->timezone);
170
171 for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++)
172 free(server->servers[i].addr);
173
174 server->bound_leases_by_address = hashmap_free(server->bound_leases_by_address);
175 server->bound_leases_by_client_id = hashmap_free(server->bound_leases_by_client_id);
176 server->static_leases_by_address = hashmap_free(server->static_leases_by_address);
177 server->static_leases_by_client_id = hashmap_free(server->static_leases_by_client_id);
178
179 ordered_set_free(server->extra_options);
180 ordered_set_free(server->vendor_options);
181
182 free(server->agent_circuit_id);
183 free(server->agent_remote_id);
184
185 free(server->ifname);
186 return mfree(server);
187 }
188
189 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_server, sd_dhcp_server, dhcp_server_free);
190
sd_dhcp_server_new(sd_dhcp_server ** ret,int ifindex)191 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
192 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
193
194 assert_return(ret, -EINVAL);
195 assert_return(ifindex > 0, -EINVAL);
196
197 server = new(sd_dhcp_server, 1);
198 if (!server)
199 return -ENOMEM;
200
201 *server = (sd_dhcp_server) {
202 .n_ref = 1,
203 .fd_raw = -1,
204 .fd = -1,
205 .fd_broadcast = -1,
206 .address = htobe32(INADDR_ANY),
207 .netmask = htobe32(INADDR_ANY),
208 .ifindex = ifindex,
209 .bind_to_interface = true,
210 .default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC),
211 .max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC),
212 };
213
214 *ret = TAKE_PTR(server);
215
216 return 0;
217 }
218
sd_dhcp_server_set_ifname(sd_dhcp_server * server,const char * ifname)219 int sd_dhcp_server_set_ifname(sd_dhcp_server *server, const char *ifname) {
220 assert_return(server, -EINVAL);
221 assert_return(ifname, -EINVAL);
222
223 if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
224 return -EINVAL;
225
226 return free_and_strdup(&server->ifname, ifname);
227 }
228
sd_dhcp_server_get_ifname(sd_dhcp_server * server,const char ** ret)229 int sd_dhcp_server_get_ifname(sd_dhcp_server *server, const char **ret) {
230 int r;
231
232 assert_return(server, -EINVAL);
233
234 r = get_ifname(server->ifindex, &server->ifname);
235 if (r < 0)
236 return r;
237
238 if (ret)
239 *ret = server->ifname;
240
241 return 0;
242 }
243
sd_dhcp_server_attach_event(sd_dhcp_server * server,sd_event * event,int64_t priority)244 int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
245 int r;
246
247 assert_return(server, -EINVAL);
248 assert_return(!server->event, -EBUSY);
249
250 if (event)
251 server->event = sd_event_ref(event);
252 else {
253 r = sd_event_default(&server->event);
254 if (r < 0)
255 return r;
256 }
257
258 server->event_priority = priority;
259
260 return 0;
261 }
262
sd_dhcp_server_detach_event(sd_dhcp_server * server)263 int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
264 assert_return(server, -EINVAL);
265
266 server->event = sd_event_unref(server->event);
267
268 return 0;
269 }
270
sd_dhcp_server_get_event(sd_dhcp_server * server)271 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
272 assert_return(server, NULL);
273
274 return server->event;
275 }
276
sd_dhcp_server_set_boot_server_address(sd_dhcp_server * server,const struct in_addr * address)277 int sd_dhcp_server_set_boot_server_address(sd_dhcp_server *server, const struct in_addr *address) {
278 assert_return(server, -EINVAL);
279
280 if (address)
281 server->boot_server_address = *address;
282 else
283 server->boot_server_address = (struct in_addr) {};
284
285 return 0;
286 }
287
sd_dhcp_server_set_boot_server_name(sd_dhcp_server * server,const char * name)288 int sd_dhcp_server_set_boot_server_name(sd_dhcp_server *server, const char *name) {
289 int r;
290
291 assert_return(server, -EINVAL);
292
293 if (name) {
294 r = dns_name_is_valid(name);
295 if (r < 0)
296 return r;
297 if (r == 0)
298 return -EINVAL;
299 }
300
301 return free_and_strdup(&server->boot_server_name, name);
302 }
303
sd_dhcp_server_set_boot_filename(sd_dhcp_server * server,const char * filename)304 int sd_dhcp_server_set_boot_filename(sd_dhcp_server *server, const char *filename) {
305 assert_return(server, -EINVAL);
306
307 if (filename && (!string_is_safe(filename) || !ascii_is_valid(filename)))
308 return -EINVAL;
309
310 return free_and_strdup(&server->boot_filename, filename);
311 }
312
sd_dhcp_server_stop(sd_dhcp_server * server)313 int sd_dhcp_server_stop(sd_dhcp_server *server) {
314 bool running;
315
316 if (!server)
317 return 0;
318
319 running = sd_dhcp_server_is_running(server);
320
321 server->receive_message = sd_event_source_disable_unref(server->receive_message);
322 server->receive_broadcast = sd_event_source_disable_unref(server->receive_broadcast);
323
324 server->fd_raw = safe_close(server->fd_raw);
325 server->fd = safe_close(server->fd);
326 server->fd_broadcast = safe_close(server->fd_broadcast);
327
328 if (running)
329 log_dhcp_server(server, "STOPPED");
330
331 return 0;
332 }
333
dhcp_server_send_unicast_raw(sd_dhcp_server * server,uint8_t hlen,const uint8_t * chaddr,DHCPPacket * packet,size_t len)334 static int dhcp_server_send_unicast_raw(
335 sd_dhcp_server *server,
336 uint8_t hlen,
337 const uint8_t *chaddr,
338 DHCPPacket *packet,
339 size_t len) {
340
341 union sockaddr_union link = {
342 .ll.sll_family = AF_PACKET,
343 .ll.sll_protocol = htobe16(ETH_P_IP),
344 .ll.sll_ifindex = server->ifindex,
345 .ll.sll_halen = hlen,
346 };
347
348 assert(server);
349 assert(server->ifindex > 0);
350 assert(server->address != 0);
351 assert(hlen > 0);
352 assert(chaddr);
353 assert(packet);
354 assert(len > sizeof(DHCPPacket));
355
356 memcpy(link.ll.sll_addr, chaddr, hlen);
357
358 if (len > UINT16_MAX)
359 return -EOVERFLOW;
360
361 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
362 packet->dhcp.yiaddr,
363 DHCP_PORT_CLIENT, len, -1);
364
365 return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
366 }
367
dhcp_server_send_udp(sd_dhcp_server * server,be32_t destination,uint16_t destination_port,DHCPMessage * message,size_t len)368 static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
369 uint16_t destination_port,
370 DHCPMessage *message, size_t len) {
371 union sockaddr_union dest = {
372 .in.sin_family = AF_INET,
373 .in.sin_port = htobe16(destination_port),
374 .in.sin_addr.s_addr = destination,
375 };
376 struct iovec iov = {
377 .iov_base = message,
378 .iov_len = len,
379 };
380 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control = {};
381 struct msghdr msg = {
382 .msg_name = &dest,
383 .msg_namelen = sizeof(dest.in),
384 .msg_iov = &iov,
385 .msg_iovlen = 1,
386 };
387 struct cmsghdr *cmsg;
388 struct in_pktinfo *pktinfo;
389
390 assert(server);
391 assert(server->fd >= 0);
392 assert(message);
393 assert(len > sizeof(DHCPMessage));
394
395 if (server->bind_to_interface) {
396 msg.msg_control = &control;
397 msg.msg_controllen = sizeof(control);
398
399 cmsg = CMSG_FIRSTHDR(&msg);
400 assert(cmsg);
401
402 cmsg->cmsg_level = IPPROTO_IP;
403 cmsg->cmsg_type = IP_PKTINFO;
404 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
405
406 /* we attach source interface and address info to the message
407 rather than binding the socket. This will be mostly useful
408 when we gain support for arbitrary number of server addresses
409 */
410 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
411 assert(pktinfo);
412
413 pktinfo->ipi_ifindex = server->ifindex;
414 pktinfo->ipi_spec_dst.s_addr = server->address;
415 }
416
417 if (sendmsg(server->fd, &msg, 0) < 0)
418 return -errno;
419
420 return 0;
421 }
422
requested_broadcast(DHCPMessage * message)423 static bool requested_broadcast(DHCPMessage *message) {
424 assert(message);
425 return message->flags & htobe16(0x8000);
426 }
427
dhcp_server_send(sd_dhcp_server * server,uint8_t hlen,const uint8_t * chaddr,be32_t destination,uint16_t destination_port,DHCPPacket * packet,size_t optoffset,bool l2_broadcast)428 static int dhcp_server_send(
429 sd_dhcp_server *server,
430 uint8_t hlen,
431 const uint8_t *chaddr,
432 be32_t destination,
433 uint16_t destination_port,
434 DHCPPacket *packet,
435 size_t optoffset,
436 bool l2_broadcast) {
437
438 if (destination != INADDR_ANY)
439 return dhcp_server_send_udp(server, destination,
440 destination_port, &packet->dhcp,
441 sizeof(DHCPMessage) + optoffset);
442 else if (l2_broadcast)
443 return dhcp_server_send_udp(server, INADDR_BROADCAST,
444 destination_port, &packet->dhcp,
445 sizeof(DHCPMessage) + optoffset);
446 else
447 /* we cannot send UDP packet to specific MAC address when the
448 address is not yet configured, so must fall back to raw
449 packets */
450 return dhcp_server_send_unicast_raw(server, hlen, chaddr, packet,
451 sizeof(DHCPPacket) + optoffset);
452 }
453
dhcp_server_send_packet(sd_dhcp_server * server,DHCPRequest * req,DHCPPacket * packet,int type,size_t optoffset)454 int dhcp_server_send_packet(sd_dhcp_server *server,
455 DHCPRequest *req, DHCPPacket *packet,
456 int type, size_t optoffset) {
457 be32_t destination = INADDR_ANY;
458 uint16_t destination_port = DHCP_PORT_CLIENT;
459 int r;
460
461 assert(server);
462 assert(req);
463 assert(req->max_optlen > 0);
464 assert(req->message);
465 assert(optoffset <= req->max_optlen);
466 assert(packet);
467
468 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
469 SD_DHCP_OPTION_SERVER_IDENTIFIER,
470 4, &server->address);
471 if (r < 0)
472 return r;
473
474 if (req->agent_info_option) {
475 size_t opt_full_length = *(req->agent_info_option + 1) + 2;
476 /* there must be space left for SD_DHCP_OPTION_END */
477 if (optoffset + opt_full_length < req->max_optlen) {
478 memcpy(packet->dhcp.options + optoffset, req->agent_info_option, opt_full_length);
479 optoffset += opt_full_length;
480 }
481 }
482
483 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
484 SD_DHCP_OPTION_END, 0, NULL);
485 if (r < 0)
486 return r;
487
488 /* RFC 2131 Section 4.1
489
490 If the ’giaddr’ field in a DHCP message from a client is non-zero,
491 the server sends any return messages to the ’DHCP server’ port on the
492 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
493 field is zero and the ’ciaddr’ field is nonzero, then the server
494 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
495 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
496 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
497 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
498 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
499 messages to the client’s hardware address and ’yiaddr’ address. In
500 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
501 messages to 0xffffffff.
502
503 Section 4.3.2
504
505 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
506 different subnet. The server MUST set the broadcast bit in the
507 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
508 client, because the client may not have a correct network address
509 or subnet mask, and the client may not be answering ARP requests.
510 */
511 if (req->message->giaddr != 0) {
512 destination = req->message->giaddr;
513 destination_port = DHCP_PORT_SERVER;
514 if (type == DHCP_NAK)
515 packet->dhcp.flags = htobe16(0x8000);
516 } else if (req->message->ciaddr != 0 && type != DHCP_NAK)
517 destination = req->message->ciaddr;
518
519 bool l2_broadcast = requested_broadcast(req->message) || type == DHCP_NAK;
520 return dhcp_server_send(server, req->message->hlen, req->message->chaddr,
521 destination, destination_port, packet, optoffset, l2_broadcast);
522 }
523
server_message_init(sd_dhcp_server * server,DHCPPacket ** ret,uint8_t type,size_t * ret_optoffset,DHCPRequest * req)524 static int server_message_init(
525 sd_dhcp_server *server,
526 DHCPPacket **ret,
527 uint8_t type,
528 size_t *ret_optoffset,
529 DHCPRequest *req) {
530
531 _cleanup_free_ DHCPPacket *packet = NULL;
532 size_t optoffset = 0;
533 int r;
534
535 assert(server);
536 assert(ret);
537 assert(ret_optoffset);
538 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
539 assert(req);
540
541 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
542 if (!packet)
543 return -ENOMEM;
544
545 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
546 be32toh(req->message->xid), type,
547 req->message->htype, req->message->hlen, req->message->chaddr,
548 req->max_optlen, &optoffset);
549 if (r < 0)
550 return r;
551
552 packet->dhcp.flags = req->message->flags;
553 packet->dhcp.giaddr = req->message->giaddr;
554
555 *ret_optoffset = optoffset;
556 *ret = TAKE_PTR(packet);
557
558 return 0;
559 }
560
server_send_offer_or_ack(sd_dhcp_server * server,DHCPRequest * req,be32_t address,uint8_t type)561 static int server_send_offer_or_ack(
562 sd_dhcp_server *server,
563 DHCPRequest *req,
564 be32_t address,
565 uint8_t type) {
566
567 _cleanup_free_ DHCPPacket *packet = NULL;
568 sd_dhcp_option *j;
569 be32_t lease_time;
570 size_t offset;
571 int r;
572
573 assert(server);
574 assert(req);
575 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK));
576
577 r = server_message_init(server, &packet, type, &offset, req);
578 if (r < 0)
579 return r;
580
581 packet->dhcp.yiaddr = address;
582 packet->dhcp.siaddr = server->boot_server_address.s_addr;
583
584 lease_time = htobe32(req->lifetime);
585 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
586 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
587 &lease_time);
588 if (r < 0)
589 return r;
590
591 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
592 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
593 if (r < 0)
594 return r;
595
596 if (server->emit_router) {
597 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
598 SD_DHCP_OPTION_ROUTER, 4,
599 in4_addr_is_set(&server->router_address) ?
600 &server->router_address.s_addr :
601 &server->address);
602 if (r < 0)
603 return r;
604 }
605
606 if (server->boot_server_name) {
607 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
608 SD_DHCP_OPTION_BOOT_SERVER_NAME,
609 strlen(server->boot_server_name), server->boot_server_name);
610 if (r < 0)
611 return r;
612 }
613
614 if (server->boot_filename) {
615 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
616 SD_DHCP_OPTION_BOOT_FILENAME,
617 strlen(server->boot_filename), server->boot_filename);
618 if (r < 0)
619 return r;
620 }
621
622 if (type == DHCP_ACK) {
623 static const uint8_t option_map[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = {
624 [SD_DHCP_LEASE_DNS] = SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
625 [SD_DHCP_LEASE_NTP] = SD_DHCP_OPTION_NTP_SERVER,
626 [SD_DHCP_LEASE_SIP] = SD_DHCP_OPTION_SIP_SERVER,
627 [SD_DHCP_LEASE_POP3] = SD_DHCP_OPTION_POP3_SERVER,
628 [SD_DHCP_LEASE_SMTP] = SD_DHCP_OPTION_SMTP_SERVER,
629 [SD_DHCP_LEASE_LPR] = SD_DHCP_OPTION_LPR_SERVER,
630 };
631
632 for (sd_dhcp_lease_server_type_t k = 0; k < _SD_DHCP_LEASE_SERVER_TYPE_MAX; k++) {
633 if (server->servers[k].size <= 0)
634 continue;
635
636 r = dhcp_option_append(
637 &packet->dhcp, req->max_optlen, &offset, 0,
638 option_map[k],
639 sizeof(struct in_addr) * server->servers[k].size,
640 server->servers[k].addr);
641 if (r < 0)
642 return r;
643 }
644
645
646 if (server->timezone) {
647 r = dhcp_option_append(
648 &packet->dhcp, req->max_optlen, &offset, 0,
649 SD_DHCP_OPTION_TZDB_TIMEZONE,
650 strlen(server->timezone), server->timezone);
651 if (r < 0)
652 return r;
653 }
654 }
655
656 ORDERED_SET_FOREACH(j, server->extra_options) {
657 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
658 j->option, j->length, j->data);
659 if (r < 0)
660 return r;
661 }
662
663 if (!ordered_set_isempty(server->vendor_options)) {
664 r = dhcp_option_append(
665 &packet->dhcp, req->max_optlen, &offset, 0,
666 SD_DHCP_OPTION_VENDOR_SPECIFIC,
667 ordered_set_size(server->vendor_options), server->vendor_options);
668 if (r < 0)
669 return r;
670 }
671
672 return dhcp_server_send_packet(server, req, packet, type, offset);
673 }
674
server_send_nak_or_ignore(sd_dhcp_server * server,bool init_reboot,DHCPRequest * req)675 static int server_send_nak_or_ignore(sd_dhcp_server *server, bool init_reboot, DHCPRequest *req) {
676 _cleanup_free_ DHCPPacket *packet = NULL;
677 size_t offset;
678 int r;
679
680 /* When a request is refused, RFC 2131, section 4.3.2 mentioned we should send NAK when the
681 * client is in INITREBOOT. If the client is in other state, there is nothing mentioned in the
682 * RFC whether we should send NAK or not. Hence, let's silently ignore the request. */
683
684 if (!init_reboot)
685 return 0;
686
687 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
688 if (r < 0)
689 return log_dhcp_server_errno(server, r, "Failed to create NAK message: %m");
690
691 r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
692 if (r < 0)
693 return log_dhcp_server_errno(server, r, "Could not send NAK message: %m");
694
695 log_dhcp_server(server, "NAK (0x%x)", be32toh(req->message->xid));
696 return DHCP_NAK;
697 }
698
server_send_forcerenew(sd_dhcp_server * server,be32_t address,be32_t gateway,uint8_t htype,uint8_t hlen,const uint8_t * chaddr)699 static int server_send_forcerenew(
700 sd_dhcp_server *server,
701 be32_t address,
702 be32_t gateway,
703 uint8_t htype,
704 uint8_t hlen,
705 const uint8_t *chaddr) {
706
707 _cleanup_free_ DHCPPacket *packet = NULL;
708 size_t optoffset = 0;
709 int r;
710
711 assert(server);
712 assert(address != INADDR_ANY);
713 assert(chaddr);
714
715 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
716 if (!packet)
717 return -ENOMEM;
718
719 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
720 DHCP_FORCERENEW, htype, hlen, chaddr,
721 DHCP_MIN_OPTIONS_SIZE, &optoffset);
722 if (r < 0)
723 return r;
724
725 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
726 &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
727 if (r < 0)
728 return r;
729
730 return dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT,
731 &packet->dhcp,
732 sizeof(DHCPMessage) + optoffset);
733 }
734
parse_request(uint8_t code,uint8_t len,const void * option,void * userdata)735 static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
736 DHCPRequest *req = userdata;
737
738 assert(req);
739
740 switch (code) {
741 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
742 if (len == 4)
743 req->lifetime = unaligned_read_be32(option);
744
745 break;
746 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
747 if (len == 4)
748 memcpy(&req->requested_ip, option, sizeof(be32_t));
749
750 break;
751 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
752 if (len == 4)
753 memcpy(&req->server_id, option, sizeof(be32_t));
754
755 break;
756 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
757 if (len >= 2) {
758 uint8_t *data;
759
760 data = memdup(option, len);
761 if (!data)
762 return -ENOMEM;
763
764 free_and_replace(req->client_id.data, data);
765 req->client_id.length = len;
766 }
767
768 break;
769 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
770
771 if (len == 2 && unaligned_read_be16(option) >= sizeof(DHCPPacket))
772 req->max_optlen = unaligned_read_be16(option) - sizeof(DHCPPacket);
773
774 break;
775 case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION:
776 req->agent_info_option = (uint8_t*)option - 2;
777
778 break;
779 }
780
781 return 0;
782 }
783
dhcp_request_free(DHCPRequest * req)784 static DHCPRequest* dhcp_request_free(DHCPRequest *req) {
785 if (!req)
786 return NULL;
787
788 free(req->client_id.data);
789 return mfree(req);
790 }
791
792 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
793
ensure_sane_request(sd_dhcp_server * server,DHCPRequest * req,DHCPMessage * message)794 static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) {
795 assert(req);
796 assert(message);
797
798 req->message = message;
799
800 if (message->hlen > sizeof(message->chaddr))
801 return -EBADMSG;
802
803 /* set client id based on MAC address if client did not send an explicit one */
804 if (!req->client_id.data) {
805 uint8_t *data;
806
807 if (message->hlen == 0)
808 return -EBADMSG;
809
810 data = new0(uint8_t, message->hlen + 1);
811 if (!data)
812 return -ENOMEM;
813
814 data[0] = 0x01;
815 memcpy(data + 1, message->chaddr, message->hlen);
816
817 req->client_id.length = message->hlen + 1;
818 req->client_id.data = data;
819 }
820
821 if (message->hlen == 0 || memeqzero(message->chaddr, message->hlen)) {
822 /* See RFC2131 section 4.1.1.
823 * hlen and chaddr may not be set for non-ethernet interface.
824 * Let's try to retrieve it from the client ID. */
825
826 if (!req->client_id.data)
827 return -EBADMSG;
828
829 if (req->client_id.length <= 1 || req->client_id.length > sizeof(message->chaddr) + 1)
830 return -EBADMSG;
831
832 if (req->client_id.data[0] != 0x01)
833 return -EBADMSG;
834
835 message->hlen = req->client_id.length - 1;
836 memcpy(message->chaddr, req->client_id.data + 1, message->hlen);
837 }
838
839 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
840 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
841
842 if (req->lifetime <= 0)
843 req->lifetime = MAX(1ULL, server->default_lease_time);
844
845 if (server->max_lease_time > 0 && req->lifetime > server->max_lease_time)
846 req->lifetime = server->max_lease_time;
847
848 return 0;
849 }
850
address_is_in_pool(sd_dhcp_server * server,be32_t address)851 static bool address_is_in_pool(sd_dhcp_server *server, be32_t address) {
852 assert(server);
853
854 if (server->pool_size == 0)
855 return false;
856
857 if (address == server->address)
858 return false;
859
860 if (be32toh(address) < (be32toh(server->subnet) | server->pool_offset) ||
861 be32toh(address) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
862 return false;
863
864 if (hashmap_contains(server->static_leases_by_address, UINT32_TO_PTR(address)))
865 return false;
866
867 return true;
868 }
869
append_agent_information_option(sd_dhcp_server * server,DHCPMessage * message,size_t opt_length,size_t size)870 static int append_agent_information_option(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t size) {
871 int r;
872 size_t offset;
873
874 assert(server);
875 assert(message);
876
877 r = dhcp_option_find_option(message->options, opt_length, SD_DHCP_OPTION_END, &offset);
878 if (r < 0)
879 return r;
880
881 r = dhcp_option_append(message, size, &offset, 0, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION, 0, server);
882 if (r < 0)
883 return r;
884
885 r = dhcp_option_append(message, size, &offset, 0, SD_DHCP_OPTION_END, 0, NULL);
886 if (r < 0)
887 return r;
888 return offset;
889 }
890
dhcp_server_relay_message(sd_dhcp_server * server,DHCPMessage * message,size_t opt_length,size_t buflen)891 static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t buflen) {
892 _cleanup_free_ DHCPPacket *packet = NULL;
893 int r;
894
895 assert(server);
896 assert(message);
897 assert(sd_dhcp_server_is_in_relay_mode(server));
898
899 if (message->hlen == 0 || message->hlen > sizeof(message->chaddr) || memeqzero(message->chaddr, message->hlen))
900 return log_dhcp_server_errno(server, SYNTHETIC_ERRNO(EBADMSG),
901 "(relay agent) received message without/invalid hardware address, discarding.");
902
903 if (message->op == BOOTREQUEST) {
904 log_dhcp_server(server, "(relay agent) BOOTREQUEST (0x%x)", be32toh(message->xid));
905 if (message->hops >= 16)
906 return -ETIME;
907 message->hops++;
908
909 /* https://tools.ietf.org/html/rfc1542#section-4.1.1 */
910 if (message->giaddr == 0)
911 message->giaddr = server->address;
912
913 if (server->agent_circuit_id || server->agent_remote_id) {
914 r = append_agent_information_option(server, message, opt_length, buflen - sizeof(DHCPMessage));
915 if (r < 0)
916 return log_dhcp_server_errno(server, r, "could not append relay option: %m");
917 opt_length = r;
918 }
919
920 return dhcp_server_send_udp(server, server->relay_target.s_addr, DHCP_PORT_SERVER, message, sizeof(DHCPMessage) + opt_length);
921 } else if (message->op == BOOTREPLY) {
922 log_dhcp_server(server, "(relay agent) BOOTREPLY (0x%x)", be32toh(message->xid));
923 if (message->giaddr != server->address)
924 return log_dhcp_server_errno(server, SYNTHETIC_ERRNO(EBADMSG),
925 "(relay agent) BOOTREPLY giaddr mismatch, discarding");
926
927 int message_type = dhcp_option_parse(message, sizeof(DHCPMessage) + opt_length, NULL, NULL, NULL);
928 if (message_type < 0)
929 return message_type;
930
931 packet = malloc0(sizeof(DHCPPacket) + opt_length);
932 if (!packet)
933 return -ENOMEM;
934 memcpy(&packet->dhcp, message, sizeof(DHCPMessage) + opt_length);
935
936 r = dhcp_option_remove_option(packet->dhcp.options, opt_length, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION);
937 if (r > 0)
938 opt_length = r;
939
940 bool l2_broadcast = requested_broadcast(message) || message_type == DHCP_NAK;
941 const be32_t destination = message_type == DHCP_NAK ? INADDR_ANY : message->ciaddr;
942 return dhcp_server_send(server, message->hlen, message->chaddr, destination, DHCP_PORT_CLIENT, packet, opt_length, l2_broadcast);
943 }
944 return -EBADMSG;
945 }
946
prepare_new_lease(DHCPLease ** ret_lease,be32_t address,const DHCPClientId * client_id,uint8_t htype,uint8_t hlen,const uint8_t * chaddr,be32_t gateway,usec_t expiration)947 static int prepare_new_lease(
948 DHCPLease **ret_lease,
949 be32_t address,
950 const DHCPClientId *client_id,
951 uint8_t htype,
952 uint8_t hlen,
953 const uint8_t *chaddr,
954 be32_t gateway,
955 usec_t expiration) {
956
957 _cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
958
959 lease = new(DHCPLease, 1);
960 if (!lease)
961 return -ENOMEM;
962
963 *lease = (DHCPLease) {
964 .address = address,
965 .client_id.length = client_id->length,
966 .htype = htype,
967 .hlen = hlen,
968 .gateway = gateway,
969 .expiration = expiration,
970 };
971 lease->client_id.data = memdup(client_id->data, client_id->length);
972 if (!lease->client_id.data)
973 return -ENOMEM;
974
975 memcpy(lease->chaddr, chaddr, hlen);
976
977 *ret_lease = TAKE_PTR(lease);
978
979 return 0;
980 }
981
server_ack_request(sd_dhcp_server * server,DHCPRequest * req,DHCPLease * existing_lease,be32_t address)982 static int server_ack_request(sd_dhcp_server *server, DHCPRequest *req, DHCPLease *existing_lease, be32_t address) {
983 usec_t time_now, expiration;
984 int r;
985
986 assert(server);
987 assert(req);
988 assert(address != 0);
989
990 r = sd_event_now(server->event, CLOCK_BOOTTIME, &time_now);
991 if (r < 0)
992 return r;
993
994 expiration = usec_add(req->lifetime * USEC_PER_SEC, time_now);
995
996 if (existing_lease) {
997 assert(existing_lease->server);
998 assert(existing_lease->address == address);
999 existing_lease->expiration = expiration;
1000
1001 } else {
1002 _cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
1003
1004 r = prepare_new_lease(&lease, address, &req->client_id,
1005 req->message->htype, req->message->hlen,
1006 req->message->chaddr, req->message->giaddr, expiration);
1007 if (r < 0)
1008 return log_dhcp_server_errno(server, r, "Failed to create new lease: %m");
1009
1010 lease->server = server; /* This must be set just before hashmap_put(). */
1011
1012 r = hashmap_ensure_put(&server->bound_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
1013 if (r < 0)
1014 return log_dhcp_server_errno(server, r, "Could not save lease: %m");
1015
1016 r = hashmap_ensure_put(&server->bound_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
1017 if (r < 0)
1018 return log_dhcp_server_errno(server, r, "Could not save lease: %m");
1019
1020 TAKE_PTR(lease);
1021 }
1022
1023 r = server_send_offer_or_ack(server, req, address, DHCP_ACK);
1024 if (r < 0)
1025 return log_dhcp_server_errno(server, r, "Could not send ACK: %m");
1026
1027 log_dhcp_server(server, "ACK (0x%x)", be32toh(req->message->xid));
1028
1029 if (server->callback)
1030 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
1031
1032 return DHCP_ACK;
1033 }
1034
dhcp_server_cleanup_expired_leases(sd_dhcp_server * server)1035 static int dhcp_server_cleanup_expired_leases(sd_dhcp_server *server) {
1036 DHCPLease *lease;
1037 usec_t time_now;
1038 int r;
1039
1040 assert(server);
1041
1042 r = sd_event_now(server->event, CLOCK_BOOTTIME, &time_now);
1043 if (r < 0)
1044 return r;
1045
1046 HASHMAP_FOREACH(lease, server->bound_leases_by_client_id)
1047 if (lease->expiration < time_now) {
1048 log_dhcp_server(server, "CLEAN (0x%x)", be32toh(lease->address));
1049 dhcp_lease_free(lease);
1050 }
1051
1052 return 0;
1053 }
1054
address_available(sd_dhcp_server * server,be32_t address)1055 static bool address_available(sd_dhcp_server *server, be32_t address) {
1056 assert(server);
1057
1058 if (hashmap_contains(server->bound_leases_by_address, UINT32_TO_PTR(address)) ||
1059 hashmap_contains(server->static_leases_by_address, UINT32_TO_PTR(address)) ||
1060 address == server->address)
1061 return false;
1062
1063 return true;
1064 }
1065
1066 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
1067
dhcp_server_handle_message(sd_dhcp_server * server,DHCPMessage * message,size_t length)1068 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length) {
1069 _cleanup_(dhcp_request_freep) DHCPRequest *req = NULL;
1070 _cleanup_free_ char *error_message = NULL;
1071 DHCPLease *existing_lease, *static_lease;
1072 int type, r;
1073
1074 assert(server);
1075 assert(message);
1076
1077 if (message->op != BOOTREQUEST)
1078 return 0;
1079
1080 req = new0(DHCPRequest, 1);
1081 if (!req)
1082 return -ENOMEM;
1083
1084 type = dhcp_option_parse(message, length, parse_request, req, &error_message);
1085 if (type < 0)
1086 return 0;
1087
1088 r = ensure_sane_request(server, req, message);
1089 if (r < 0)
1090 return r;
1091
1092 r = dhcp_server_cleanup_expired_leases(server);
1093 if (r < 0)
1094 return r;
1095
1096 existing_lease = hashmap_get(server->bound_leases_by_client_id, &req->client_id);
1097 static_lease = hashmap_get(server->static_leases_by_client_id, &req->client_id);
1098
1099 switch (type) {
1100
1101 case DHCP_DISCOVER: {
1102 be32_t address = INADDR_ANY;
1103
1104 log_dhcp_server(server, "DISCOVER (0x%x)", be32toh(req->message->xid));
1105
1106 if (server->pool_size == 0)
1107 /* no pool allocated */
1108 return 0;
1109
1110 /* for now pick a random free address from the pool */
1111 if (static_lease)
1112 address = static_lease->address;
1113 else if (existing_lease)
1114 address = existing_lease->address;
1115 else {
1116 struct siphash state;
1117 uint64_t hash;
1118
1119 /* even with no persistence of leases, we try to offer the same client
1120 the same IP address. we do this by using the hash of the client id
1121 as the offset into the pool of leases when finding the next free one */
1122
1123 siphash24_init(&state, HASH_KEY.bytes);
1124 client_id_hash_func(&req->client_id, &state);
1125 hash = htole64(siphash24_finalize(&state));
1126
1127 for (unsigned i = 0; i < server->pool_size; i++) {
1128 be32_t tmp_address;
1129
1130 tmp_address = server->subnet | htobe32(server->pool_offset + (hash + i) % server->pool_size);
1131 if (address_available(server, tmp_address)) {
1132 address = tmp_address;
1133 break;
1134 }
1135 }
1136 }
1137
1138 if (address == INADDR_ANY)
1139 /* no free addresses left */
1140 return 0;
1141
1142 r = server_send_offer_or_ack(server, req, address, DHCP_OFFER);
1143 if (r < 0)
1144 /* this only fails on critical errors */
1145 return log_dhcp_server_errno(server, r, "Could not send offer: %m");
1146
1147 log_dhcp_server(server, "OFFER (0x%x)", be32toh(req->message->xid));
1148 return DHCP_OFFER;
1149 }
1150 case DHCP_DECLINE:
1151 log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
1152
1153 /* TODO: make sure we don't offer this address again */
1154
1155 return 1;
1156
1157 case DHCP_REQUEST: {
1158 be32_t address;
1159 bool init_reboot = false;
1160
1161 /* see RFC 2131, section 4.3.2 */
1162
1163 if (req->server_id != 0) {
1164 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
1165 be32toh(req->message->xid));
1166
1167 /* SELECTING */
1168 if (req->server_id != server->address)
1169 /* client did not pick us */
1170 return 0;
1171
1172 if (req->message->ciaddr != 0)
1173 /* this MUST be zero */
1174 return 0;
1175
1176 if (req->requested_ip == 0)
1177 /* this must be filled in with the yiaddr
1178 from the chosen OFFER */
1179 return 0;
1180
1181 address = req->requested_ip;
1182 } else if (req->requested_ip != 0) {
1183 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
1184 be32toh(req->message->xid));
1185
1186 /* INIT-REBOOT */
1187 if (req->message->ciaddr != 0)
1188 /* this MUST be zero */
1189 return 0;
1190
1191 /* TODO: check more carefully if IP is correct */
1192 address = req->requested_ip;
1193 init_reboot = true;
1194 } else {
1195 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
1196 be32toh(req->message->xid));
1197
1198 /* REBINDING / RENEWING */
1199 if (req->message->ciaddr == 0)
1200 /* this MUST be filled in with clients IP address */
1201 return 0;
1202
1203 address = req->message->ciaddr;
1204 }
1205
1206 /* disallow our own address */
1207 if (address == server->address)
1208 return 0;
1209
1210 if (static_lease) {
1211 /* Found a static lease for the client ID. */
1212
1213 if (static_lease->address != address)
1214 /* The client requested an address which is different from the static lease. Refuse. */
1215 return server_send_nak_or_ignore(server, init_reboot, req);
1216
1217 return server_ack_request(server, req, existing_lease, address);
1218 }
1219
1220 if (address_is_in_pool(server, address)) {
1221 /* The requested address is in the pool. */
1222
1223 if (existing_lease && existing_lease->address != address)
1224 /* We previously assigned an address, but the client requested another one. Refuse. */
1225 return server_send_nak_or_ignore(server, init_reboot, req);
1226
1227 return server_ack_request(server, req, existing_lease, address);
1228 }
1229
1230 return server_send_nak_or_ignore(server, init_reboot, req);
1231 }
1232
1233 case DHCP_RELEASE: {
1234 log_dhcp_server(server, "RELEASE (0x%x)",
1235 be32toh(req->message->xid));
1236
1237 if (!existing_lease)
1238 return 0;
1239
1240 if (existing_lease->address != req->message->ciaddr)
1241 return 0;
1242
1243 dhcp_lease_free(existing_lease);
1244
1245 if (server->callback)
1246 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
1247
1248 return 0;
1249 }}
1250
1251 return 0;
1252 }
1253
relay_agent_information_length(const char * agent_circuit_id,const char * agent_remote_id)1254 static size_t relay_agent_information_length(const char* agent_circuit_id, const char* agent_remote_id) {
1255 size_t sum = 0;
1256 if (agent_circuit_id)
1257 sum += 2 + strlen(agent_circuit_id);
1258 if (agent_remote_id)
1259 sum += 2 + strlen(agent_remote_id);
1260 return sum;
1261 }
1262
server_receive_message(sd_event_source * s,int fd,uint32_t revents,void * userdata)1263 static int server_receive_message(sd_event_source *s, int fd,
1264 uint32_t revents, void *userdata) {
1265 _cleanup_free_ DHCPMessage *message = NULL;
1266 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control;
1267 sd_dhcp_server *server = userdata;
1268 struct iovec iov = {};
1269 struct msghdr msg = {
1270 .msg_iov = &iov,
1271 .msg_iovlen = 1,
1272 .msg_control = &control,
1273 .msg_controllen = sizeof(control),
1274 };
1275 struct cmsghdr *cmsg;
1276 ssize_t datagram_size, len;
1277 int r;
1278
1279 assert(server);
1280
1281 datagram_size = next_datagram_size_fd(fd);
1282 if (datagram_size < 0) {
1283 if (ERRNO_IS_TRANSIENT(datagram_size) || ERRNO_IS_DISCONNECT(datagram_size))
1284 return 0;
1285
1286 log_dhcp_server_errno(server, datagram_size, "Failed to determine datagram size to read, ignoring: %m");
1287 return 0;
1288 }
1289
1290 size_t buflen = datagram_size;
1291 if (sd_dhcp_server_is_in_relay_mode(server))
1292 /* Preallocate the additional size for DHCP Relay Agent Information Option if needed */
1293 buflen += relay_agent_information_length(server->agent_circuit_id, server->agent_remote_id) + 2;
1294
1295 message = malloc(buflen);
1296 if (!message)
1297 return -ENOMEM;
1298
1299 iov = IOVEC_MAKE(message, datagram_size);
1300
1301 len = recvmsg_safe(fd, &msg, 0);
1302 if (len < 0) {
1303 if (ERRNO_IS_TRANSIENT(len) || ERRNO_IS_DISCONNECT(len))
1304 return 0;
1305
1306 log_dhcp_server_errno(server, len, "Could not receive message, ignoring: %m");
1307 return 0;
1308 }
1309
1310 if ((size_t) len < sizeof(DHCPMessage))
1311 return 0;
1312
1313 CMSG_FOREACH(cmsg, &msg)
1314 if (cmsg->cmsg_level == IPPROTO_IP &&
1315 cmsg->cmsg_type == IP_PKTINFO &&
1316 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
1317 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
1318
1319 /* TODO figure out if this can be done as a filter on
1320 * the socket, like for IPv6 */
1321 if (server->ifindex != info->ipi_ifindex)
1322 return 0;
1323
1324 break;
1325 }
1326
1327 if (sd_dhcp_server_is_in_relay_mode(server)) {
1328 r = dhcp_server_relay_message(server, message, len - sizeof(DHCPMessage), buflen);
1329 if (r < 0)
1330 log_dhcp_server_errno(server, r, "Couldn't relay message, ignoring: %m");
1331 } else {
1332 r = dhcp_server_handle_message(server, message, (size_t) len);
1333 if (r < 0)
1334 log_dhcp_server_errno(server, r, "Couldn't process incoming message, ignoring: %m");
1335 }
1336 return 0;
1337 }
1338
dhcp_server_update_lease_servers(sd_dhcp_server * server)1339 static void dhcp_server_update_lease_servers(sd_dhcp_server *server) {
1340 assert(server);
1341 assert(server->address != 0);
1342
1343 /* Convert null address -> server address */
1344
1345 for (sd_dhcp_lease_server_type_t k = 0; k < _SD_DHCP_LEASE_SERVER_TYPE_MAX; k++)
1346 for (size_t i = 0; i < server->servers[k].size; i++)
1347 if (in4_addr_is_null(&server->servers[k].addr[i]))
1348 server->servers[k].addr[i].s_addr = server->address;
1349 }
1350
sd_dhcp_server_start(sd_dhcp_server * server)1351 int sd_dhcp_server_start(sd_dhcp_server *server) {
1352 int r;
1353
1354 assert_return(server, -EINVAL);
1355 assert_return(server->event, -EINVAL);
1356
1357 if (sd_dhcp_server_is_running(server))
1358 return 0;
1359
1360 assert_return(!server->receive_message, -EBUSY);
1361 assert_return(server->fd_raw < 0, -EBUSY);
1362 assert_return(server->fd < 0, -EBUSY);
1363 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
1364
1365 dhcp_server_update_lease_servers(server);
1366
1367 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
1368 if (r < 0) {
1369 r = -errno;
1370 goto on_error;
1371 }
1372 server->fd_raw = r;
1373
1374 if (server->bind_to_interface)
1375 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER, -1);
1376 else
1377 r = dhcp_network_bind_udp_socket(0, server->address, DHCP_PORT_SERVER, -1);
1378 if (r < 0)
1379 goto on_error;
1380 server->fd = r;
1381
1382 r = sd_event_add_io(server->event, &server->receive_message,
1383 server->fd, EPOLLIN,
1384 server_receive_message, server);
1385 if (r < 0)
1386 goto on_error;
1387
1388 r = sd_event_source_set_priority(server->receive_message,
1389 server->event_priority);
1390 if (r < 0)
1391 goto on_error;
1392
1393 if (!server->bind_to_interface) {
1394 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_BROADCAST, DHCP_PORT_SERVER, -1);
1395 if (r < 0)
1396 goto on_error;
1397
1398 server->fd_broadcast = r;
1399
1400 r = sd_event_add_io(server->event, &server->receive_broadcast,
1401 server->fd_broadcast, EPOLLIN,
1402 server_receive_message, server);
1403 if (r < 0)
1404 goto on_error;
1405
1406 r = sd_event_source_set_priority(server->receive_broadcast,
1407 server->event_priority);
1408 if (r < 0)
1409 goto on_error;
1410 }
1411
1412 log_dhcp_server(server, "STARTED");
1413
1414 return 0;
1415
1416 on_error:
1417 sd_dhcp_server_stop(server);
1418 return r;
1419 }
1420
sd_dhcp_server_forcerenew(sd_dhcp_server * server)1421 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
1422 DHCPLease *lease;
1423 int k, r = 0;
1424
1425 assert_return(server, -EINVAL);
1426
1427 log_dhcp_server(server, "FORCERENEW");
1428
1429 HASHMAP_FOREACH(lease, server->bound_leases_by_client_id) {
1430 k = server_send_forcerenew(server, lease->address, lease->gateway,
1431 lease->htype, lease->hlen, lease->chaddr);
1432 if (k < 0)
1433 r = k;
1434 }
1435
1436 return r;
1437 }
1438
sd_dhcp_server_set_bind_to_interface(sd_dhcp_server * server,int enabled)1439 int sd_dhcp_server_set_bind_to_interface(sd_dhcp_server *server, int enabled) {
1440 assert_return(server, -EINVAL);
1441 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1442
1443 if (!!enabled == server->bind_to_interface)
1444 return 0;
1445
1446 server->bind_to_interface = enabled;
1447
1448 return 1;
1449 }
1450
sd_dhcp_server_set_timezone(sd_dhcp_server * server,const char * tz)1451 int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
1452 int r;
1453
1454 assert_return(server, -EINVAL);
1455 assert_return(timezone_is_valid(tz, LOG_DEBUG), -EINVAL);
1456
1457 if (streq_ptr(tz, server->timezone))
1458 return 0;
1459
1460 r = free_and_strdup(&server->timezone, tz);
1461 if (r < 0)
1462 return r;
1463
1464 return 1;
1465 }
1466
sd_dhcp_server_set_max_lease_time(sd_dhcp_server * server,uint32_t t)1467 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t) {
1468 assert_return(server, -EINVAL);
1469
1470 if (t == server->max_lease_time)
1471 return 0;
1472
1473 server->max_lease_time = t;
1474 return 1;
1475 }
1476
sd_dhcp_server_set_default_lease_time(sd_dhcp_server * server,uint32_t t)1477 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) {
1478 assert_return(server, -EINVAL);
1479
1480 if (t == server->default_lease_time)
1481 return 0;
1482
1483 server->default_lease_time = t;
1484 return 1;
1485 }
1486
sd_dhcp_server_set_servers(sd_dhcp_server * server,sd_dhcp_lease_server_type_t what,const struct in_addr addresses[],size_t n_addresses)1487 int sd_dhcp_server_set_servers(
1488 sd_dhcp_server *server,
1489 sd_dhcp_lease_server_type_t what,
1490 const struct in_addr addresses[],
1491 size_t n_addresses) {
1492
1493 struct in_addr *c = NULL;
1494
1495 assert_return(server, -EINVAL);
1496 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1497 assert_return(addresses || n_addresses == 0, -EINVAL);
1498 assert_return(what >= 0, -EINVAL);
1499 assert_return(what < _SD_DHCP_LEASE_SERVER_TYPE_MAX, -EINVAL);
1500
1501 if (server->servers[what].size == n_addresses &&
1502 memcmp(server->servers[what].addr, addresses, sizeof(struct in_addr) * n_addresses) == 0)
1503 return 0;
1504
1505 if (n_addresses > 0) {
1506 c = newdup(struct in_addr, addresses, n_addresses);
1507 if (!c)
1508 return -ENOMEM;
1509 }
1510
1511 free_and_replace(server->servers[what].addr, c);
1512 server->servers[what].size = n_addresses;
1513 return 1;
1514 }
1515
sd_dhcp_server_set_dns(sd_dhcp_server * server,const struct in_addr dns[],size_t n)1516 int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], size_t n) {
1517 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_DNS, dns, n);
1518 }
sd_dhcp_server_set_ntp(sd_dhcp_server * server,const struct in_addr ntp[],size_t n)1519 int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], size_t n) {
1520 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_NTP, ntp, n);
1521 }
sd_dhcp_server_set_sip(sd_dhcp_server * server,const struct in_addr sip[],size_t n)1522 int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], size_t n) {
1523 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SIP, sip, n);
1524 }
sd_dhcp_server_set_pop3(sd_dhcp_server * server,const struct in_addr pop3[],size_t n)1525 int sd_dhcp_server_set_pop3(sd_dhcp_server *server, const struct in_addr pop3[], size_t n) {
1526 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_POP3, pop3, n);
1527 }
sd_dhcp_server_set_smtp(sd_dhcp_server * server,const struct in_addr smtp[],size_t n)1528 int sd_dhcp_server_set_smtp(sd_dhcp_server *server, const struct in_addr smtp[], size_t n) {
1529 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SMTP, smtp, n);
1530 }
sd_dhcp_server_set_lpr(sd_dhcp_server * server,const struct in_addr lpr[],size_t n)1531 int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], size_t n) {
1532 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_LPR, lpr, n);
1533 }
1534
sd_dhcp_server_set_router(sd_dhcp_server * server,const struct in_addr * router)1535 int sd_dhcp_server_set_router(sd_dhcp_server *server, const struct in_addr *router) {
1536 assert_return(server, -EINVAL);
1537
1538 /* router is NULL: router option will not be appended.
1539 * router is null address (0.0.0.0): the server address will be used as the router address.
1540 * otherwise: the specified address will be used as the router address.*/
1541
1542 server->emit_router = router;
1543 if (router)
1544 server->router_address = *router;
1545
1546 return 0;
1547 }
1548
sd_dhcp_server_add_option(sd_dhcp_server * server,sd_dhcp_option * v)1549 int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v) {
1550 int r;
1551
1552 assert_return(server, -EINVAL);
1553 assert_return(v, -EINVAL);
1554
1555 r = ordered_set_ensure_put(&server->extra_options, &dhcp_option_hash_ops, v);
1556 if (r < 0)
1557 return r;
1558
1559 sd_dhcp_option_ref(v);
1560 return 0;
1561 }
1562
sd_dhcp_server_add_vendor_option(sd_dhcp_server * server,sd_dhcp_option * v)1563 int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v) {
1564 int r;
1565
1566 assert_return(server, -EINVAL);
1567 assert_return(v, -EINVAL);
1568
1569 r = ordered_set_ensure_put(&server->vendor_options, &dhcp_option_hash_ops, v);
1570 if (r < 0)
1571 return r;
1572
1573 sd_dhcp_option_ref(v);
1574
1575 return 1;
1576 }
1577
sd_dhcp_server_set_callback(sd_dhcp_server * server,sd_dhcp_server_callback_t cb,void * userdata)1578 int sd_dhcp_server_set_callback(sd_dhcp_server *server, sd_dhcp_server_callback_t cb, void *userdata) {
1579 assert_return(server, -EINVAL);
1580
1581 server->callback = cb;
1582 server->callback_userdata = userdata;
1583
1584 return 0;
1585 }
1586
sd_dhcp_server_set_relay_target(sd_dhcp_server * server,const struct in_addr * address)1587 int sd_dhcp_server_set_relay_target(sd_dhcp_server *server, const struct in_addr *address) {
1588 assert_return(server, -EINVAL);
1589 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1590
1591 if (memcmp(address, &server->relay_target, sizeof(struct in_addr)) == 0)
1592 return 0;
1593
1594 server->relay_target = *address;
1595 return 1;
1596 }
1597
sd_dhcp_server_set_relay_agent_information(sd_dhcp_server * server,const char * agent_circuit_id,const char * agent_remote_id)1598 int sd_dhcp_server_set_relay_agent_information(
1599 sd_dhcp_server *server,
1600 const char *agent_circuit_id,
1601 const char *agent_remote_id) {
1602 _cleanup_free_ char *circuit_id_dup = NULL, *remote_id_dup = NULL;
1603
1604 assert_return(server, -EINVAL);
1605
1606 if (relay_agent_information_length(agent_circuit_id, agent_remote_id) > UINT8_MAX)
1607 return -ENOBUFS;
1608
1609 if (agent_circuit_id) {
1610 circuit_id_dup = strdup(agent_circuit_id);
1611 if (!circuit_id_dup)
1612 return -ENOMEM;
1613 }
1614
1615 if (agent_remote_id) {
1616 remote_id_dup = strdup(agent_remote_id);
1617 if (!remote_id_dup)
1618 return -ENOMEM;
1619 }
1620
1621 free_and_replace(server->agent_circuit_id, circuit_id_dup);
1622 free_and_replace(server->agent_remote_id, remote_id_dup);
1623 return 0;
1624 }
1625
sd_dhcp_server_set_static_lease(sd_dhcp_server * server,const struct in_addr * address,uint8_t * client_id,size_t client_id_size)1626 int sd_dhcp_server_set_static_lease(
1627 sd_dhcp_server *server,
1628 const struct in_addr *address,
1629 uint8_t *client_id,
1630 size_t client_id_size) {
1631
1632 _cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
1633 int r;
1634
1635 assert_return(server, -EINVAL);
1636 assert_return(client_id, -EINVAL);
1637 assert_return(client_id_size > 0, -EINVAL);
1638 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1639
1640 /* Static lease with an empty or omitted address is a valid entry,
1641 * the server removes any static lease with the specified mac address. */
1642 if (!address || address->s_addr == 0) {
1643 DHCPClientId c;
1644
1645 c = (DHCPClientId) {
1646 .length = client_id_size,
1647 .data = client_id,
1648 };
1649
1650 dhcp_lease_free(hashmap_get(server->static_leases_by_client_id, &c));
1651 return 0;
1652 }
1653
1654 lease = new(DHCPLease, 1);
1655 if (!lease)
1656 return -ENOMEM;
1657
1658 *lease = (DHCPLease) {
1659 .address = address->s_addr,
1660 .client_id.length = client_id_size,
1661 };
1662 lease->client_id.data = memdup(client_id, client_id_size);
1663 if (!lease->client_id.data)
1664 return -ENOMEM;
1665
1666 lease->server = server; /* This must be set just before hashmap_put(). */
1667
1668 r = hashmap_ensure_put(&server->static_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
1669 if (r < 0)
1670 return r;
1671 r = hashmap_ensure_put(&server->static_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
1672 if (r < 0)
1673 return r;
1674
1675 TAKE_PTR(lease);
1676 return 0;
1677 }
1678