]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-server.c
userdb: shorten code a bit
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-server.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
b44cd882 2/***
810adae9 3 Copyright © 2013 Intel Corporation. All rights reserved.
b44cd882
TG
4***/
5
ddb82ec2 6#include <net/if_arp.h>
ff734080
TG
7#include <sys/ioctl.h>
8
b44cd882 9#include "sd-dhcp-server.h"
6e86b24d 10#include "sd-id128.h"
07630cea 11
b5efdb8a 12#include "alloc-util.h"
ff734080 13#include "dhcp-internal.h"
07630cea 14#include "dhcp-server-internal.h"
3ffd4af2 15#include "fd-util.h"
07630cea 16#include "in-addr-util.h"
cb310866 17#include "io-util.h"
61a9fa8f 18#include "network-common.h"
ebffea2a 19#include "ordered-set.h"
07630cea
LP
20#include "siphash24.h"
21#include "string-util.h"
9ae84244 22#include "unaligned.h"
b44cd882 23
586ac6f7
LP
24#define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
25#define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
4dc35568 26
6121fc30 27static DHCPLease *dhcp_lease_free(DHCPLease *lease) {
45a9eac9 28 if (!lease)
6121fc30 29 return NULL;
45a9eac9
RM
30
31 free(lease->client_id.data);
6121fc30 32 return mfree(lease);
45a9eac9
RM
33}
34
99634696
TG
35/* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
36 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
37 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
38 * accidentally hand it out */
90810f7a
LP
39int sd_dhcp_server_configure_pool(
40 sd_dhcp_server *server,
41 const struct in_addr *address,
42 unsigned char prefixlen,
43 uint32_t offset,
44 uint32_t size) {
45
99634696
TG
46 struct in_addr netmask_addr;
47 be32_t netmask;
48 uint32_t server_off, broadcast_off, size_max;
49
2dead812
TG
50 assert_return(server, -EINVAL);
51 assert_return(address, -EINVAL);
99634696
TG
52 assert_return(address->s_addr != INADDR_ANY, -EINVAL);
53 assert_return(prefixlen <= 32, -ERANGE);
99634696 54
5a941f5f 55 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
99634696
TG
56 netmask = netmask_addr.s_addr;
57
58 server_off = be32toh(address->s_addr & ~netmask);
59 broadcast_off = be32toh(~netmask);
60
61 /* the server address cannot be the subnet address */
62 assert_return(server_off != 0, -ERANGE);
63
64 /* nor the broadcast address */
65 assert_return(server_off != broadcast_off, -ERANGE);
66
67 /* 0 offset means we should set a default, we skip the first (subnet) address
68 and take the next one */
69 if (offset == 0)
70 offset = 1;
71
72 size_max = (broadcast_off + 1) /* the number of addresses in the subnet */
73 - offset /* exclude the addresses before the offset */
74 - 1; /* exclude the last (broadcast) address */
75
76 /* The pool must contain at least one address */
77 assert_return(size_max >= 1, -ERANGE);
78
79 if (size != 0)
80 assert_return(size <= size_max, -ERANGE);
81 else
82 size = size_max;
87322b3a 83
45a9eac9 84 if (server->address != address->s_addr || server->netmask != netmask || server->pool_size != size || server->pool_offset != offset) {
45a9eac9
RM
85
86 free(server->bound_leases);
87 server->bound_leases = new0(DHCPLease*, size);
88 if (!server->bound_leases)
89 return -ENOMEM;
2dead812 90
45a9eac9
RM
91 server->pool_offset = offset;
92 server->pool_size = size;
2dead812 93
45a9eac9
RM
94 server->address = address->s_addr;
95 server->netmask = netmask;
96 server->subnet = address->s_addr & netmask;
99634696 97
45a9eac9
RM
98 if (server_off >= offset && server_off - offset < size)
99 server->bound_leases[server_off - offset] = &server->invalid_lease;
100
101 /* Drop any leases associated with the old address range */
6121fc30 102 hashmap_clear(server->leases_by_client_id);
36d35f22
MAL
103
104 if (server->callback)
105 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
45a9eac9 106 }
20af7091
TG
107
108 return 0;
109}
110
04c01369 111int sd_dhcp_server_is_running(sd_dhcp_server *server) {
75677581 112 assert_return(server, false);
7c16313f
TG
113
114 return !!server->receive_message;
115}
116
c95df587
YA
117int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server) {
118 assert_return(server, -EINVAL);
119
120 return in4_addr_is_set(&server->relay_target);
121}
122
7a08d314 123void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
87322b3a
TG
124 assert(id);
125 assert(id->length);
126 assert(id->data);
127
1e2527a6 128 siphash24_compress(&id->length, sizeof(id->length), state);
b826ab58 129 siphash24_compress(id->data, id->length, state);
87322b3a
TG
130}
131
7a08d314 132int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
a0edd02e 133 int r;
87322b3a 134
87322b3a
TG
135 assert(!a->length || a->data);
136 assert(!b->length || b->data);
137
a0edd02e
FB
138 r = CMP(a->length, b->length);
139 if (r != 0)
140 return r;
87322b3a
TG
141
142 return memcmp(a->data, b->data, a->length);
143}
144
6121fc30
YW
145DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(dhcp_lease_hash_ops, DHCPClientId, client_id_hash_func, client_id_compare_func,
146 DHCPLease, dhcp_lease_free);
d5099efc 147
8301aa0b 148static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
8301aa0b 149 assert(server);
ff734080 150
3bdace9b 151 log_dhcp_server(server, "UNREF");
87322b3a 152
3bdace9b 153 sd_dhcp_server_stop(server);
87322b3a 154
3bdace9b
LP
155 sd_event_unref(server->event);
156
8eb9058d 157 free(server->timezone);
ddb82ec2 158
2324fd3a 159 for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++)
ddb82ec2 160 free(server->servers[i].addr);
8eb9058d 161
3bdace9b
LP
162 hashmap_free(server->leases_by_client_id);
163
ebffea2a
SS
164 ordered_set_free(server->extra_options);
165 ordered_set_free(server->vendor_options);
564ca984 166
11c38d3e
YA
167 free(server->agent_circuit_id);
168 free(server->agent_remote_id);
169
3bdace9b 170 free(server->bound_leases);
61a9fa8f
YW
171
172 free(server->ifname);
6b430fdb 173 return mfree(server);
b44cd882
TG
174}
175
8301aa0b
YW
176DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_server, sd_dhcp_server, dhcp_server_free);
177
3a864fe4 178int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
4afd3348 179 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
b44cd882
TG
180
181 assert_return(ret, -EINVAL);
3a864fe4 182 assert_return(ifindex > 0, -EINVAL);
b44cd882 183
61a9fa8f 184 server = new(sd_dhcp_server, 1);
b44cd882
TG
185 if (!server)
186 return -ENOMEM;
187
61a9fa8f
YW
188 *server = (sd_dhcp_server) {
189 .n_ref = 1,
190 .fd_raw = -1,
191 .fd = -1,
21b6b87e 192 .fd_broadcast = -1,
61a9fa8f
YW
193 .address = htobe32(INADDR_ANY),
194 .netmask = htobe32(INADDR_ANY),
195 .ifindex = ifindex,
21b6b87e 196 .bind_to_interface = true,
61a9fa8f
YW
197 .default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC),
198 .max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC),
199 };
357e1b17 200
6121fc30 201 server->leases_by_client_id = hashmap_new(&dhcp_lease_hash_ops);
357e1b17
LP
202 if (!server->leases_by_client_id)
203 return -ENOMEM;
204
1cc6c93a 205 *ret = TAKE_PTR(server);
b44cd882
TG
206
207 return 0;
208}
209
61a9fa8f
YW
210int sd_dhcp_server_set_ifname(sd_dhcp_server *server, const char *ifname) {
211 assert_return(server, -EINVAL);
212 assert_return(ifname, -EINVAL);
213
214 if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
215 return -EINVAL;
216
217 return free_and_strdup(&server->ifname, ifname);
218}
219
220const char *sd_dhcp_server_get_ifname(sd_dhcp_server *server) {
221 if (!server)
222 return NULL;
223
224 return get_ifname(server->ifindex, &server->ifname);
225}
226
32d20645 227int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
b44cd882
TG
228 int r;
229
230 assert_return(server, -EINVAL);
231 assert_return(!server->event, -EBUSY);
232
233 if (event)
234 server->event = sd_event_ref(event);
235 else {
236 r = sd_event_default(&server->event);
237 if (r < 0)
238 return r;
239 }
240
241 server->event_priority = priority;
242
243 return 0;
244}
245
246int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
247 assert_return(server, -EINVAL);
248
249 server->event = sd_event_unref(server->event);
250
251 return 0;
252}
253
254sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
255 assert_return(server, NULL);
256
257 return server->event;
258}
ff734080
TG
259
260int sd_dhcp_server_stop(sd_dhcp_server *server) {
c8bae363
YW
261 if (!server)
262 return 0;
ff734080 263
21b6b87e
YA
264 server->receive_message = sd_event_source_unref(server->receive_message);
265 server->receive_broadcast = sd_event_source_unref(server->receive_broadcast);
ff734080 266
8de4a226 267 server->fd_raw = safe_close(server->fd_raw);
ff734080 268 server->fd = safe_close(server->fd);
21b6b87e 269 server->fd_broadcast = safe_close(server->fd_broadcast);
ff734080
TG
270
271 log_dhcp_server(server, "STOPPED");
272
273 return 0;
274}
275
a6f1e036
TG
276static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
277 DHCPPacket *packet, size_t len) {
969b009d
TG
278 union sockaddr_union link = {
279 .ll.sll_family = AF_PACKET,
8e38570e 280 .ll.sll_protocol = htobe16(ETH_P_IP),
b3ec603c 281 .ll.sll_ifindex = server->ifindex,
969b009d
TG
282 .ll.sll_halen = ETH_ALEN,
283 };
969b009d
TG
284
285 assert(server);
b3ec603c 286 assert(server->ifindex > 0);
969b009d
TG
287 assert(server->address);
288 assert(packet);
289 assert(len > sizeof(DHCPPacket));
290
291 memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN);
292
293 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
a6f1e036 294 packet->dhcp.yiaddr,
afe42aef 295 DHCP_PORT_CLIENT, len, -1);
969b009d 296
b3ec603c 297 return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
969b009d
TG
298}
299
300static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
8eb7b6a5 301 uint16_t destination_port,
969b009d
TG
302 DHCPMessage *message, size_t len) {
303 union sockaddr_union dest = {
304 .in.sin_family = AF_INET,
8eb7b6a5 305 .in.sin_port = htobe16(destination_port),
969b009d
TG
306 .in.sin_addr.s_addr = destination,
307 };
308 struct iovec iov = {
309 .iov_base = message,
310 .iov_len = len,
311 };
fb29cdbe 312 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control = {};
969b009d
TG
313 struct msghdr msg = {
314 .msg_name = &dest,
315 .msg_namelen = sizeof(dest.in),
316 .msg_iov = &iov,
317 .msg_iovlen = 1,
969b009d
TG
318 };
319 struct cmsghdr *cmsg;
320 struct in_pktinfo *pktinfo;
969b009d
TG
321
322 assert(server);
4c9cb12c 323 assert(server->fd >= 0);
969b009d
TG
324 assert(message);
325 assert(len > sizeof(DHCPMessage));
326
21b6b87e
YA
327 if (server->bind_to_interface) {
328 msg.msg_control = &control;
329 msg.msg_controllen = sizeof(control);
969b009d 330
21b6b87e
YA
331 cmsg = CMSG_FIRSTHDR(&msg);
332 assert(cmsg);
969b009d 333
21b6b87e
YA
334 cmsg->cmsg_level = IPPROTO_IP;
335 cmsg->cmsg_type = IP_PKTINFO;
336 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
969b009d 337
21b6b87e
YA
338 /* we attach source interface and address info to the message
339 rather than binding the socket. This will be mostly useful
340 when we gain support for arbitrary number of server addresses
341 */
342 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
343 assert(pktinfo);
344
345 pktinfo->ipi_ifindex = server->ifindex;
346 pktinfo->ipi_spec_dst.s_addr = server->address;
347 }
969b009d 348
0f01c1f9 349 if (sendmsg(server->fd, &msg, 0) < 0)
969b009d
TG
350 return -errno;
351
352 return 0;
353}
354
c95df587
YA
355static bool requested_broadcast(DHCPMessage *message) {
356 assert(message);
357 return message->flags & htobe16(0x8000);
358}
969b009d 359
c95df587
YA
360static int dhcp_server_send(sd_dhcp_server *server, be32_t destination, uint16_t destination_port,
361 DHCPPacket *packet, size_t optoffset, bool l2_broadcast) {
362 if (destination != INADDR_ANY)
363 return dhcp_server_send_udp(server, destination,
364 destination_port, &packet->dhcp,
365 sizeof(DHCPMessage) + optoffset);
366 else if (l2_broadcast)
367 return dhcp_server_send_udp(server, INADDR_BROADCAST,
368 destination_port, &packet->dhcp,
369 sizeof(DHCPMessage) + optoffset);
370 else
371 /* we cannot send UDP packet to specific MAC address when the
372 address is not yet configured, so must fall back to raw
373 packets */
374 return dhcp_server_send_unicast_raw(server, packet,
375 sizeof(DHCPPacket) + optoffset);
969b009d
TG
376}
377
378int dhcp_server_send_packet(sd_dhcp_server *server,
379 DHCPRequest *req, DHCPPacket *packet,
380 int type, size_t optoffset) {
381 be32_t destination = INADDR_ANY;
8eb7b6a5 382 uint16_t destination_port = DHCP_PORT_CLIENT;
969b009d
TG
383 int r;
384
385 assert(server);
386 assert(req);
387 assert(req->max_optlen);
11c38d3e 388 assert(req->message);
969b009d
TG
389 assert(optoffset <= req->max_optlen);
390 assert(packet);
391
392 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
22805d92 393 SD_DHCP_OPTION_SERVER_IDENTIFIER,
969b009d
TG
394 4, &server->address);
395 if (r < 0)
396 return r;
397
11c38d3e
YA
398 if (req->agent_info_option) {
399 size_t opt_full_length = *(req->agent_info_option + 1) + 2;
400 /* there must be space left for SD_DHCP_OPTION_END */
401 if (optoffset + opt_full_length < req->max_optlen) {
402 memcpy(packet->dhcp.options + optoffset, req->agent_info_option, opt_full_length);
403 optoffset += opt_full_length;
404 }
405 }
406
969b009d 407 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
22805d92 408 SD_DHCP_OPTION_END, 0, NULL);
969b009d
TG
409 if (r < 0)
410 return r;
411
412 /* RFC 2131 Section 4.1
413
414 If the ’giaddr’ field in a DHCP message from a client is non-zero,
415 the server sends any return messages to the ’DHCP server’ port on the
416 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
417 field is zero and the ’ciaddr’ field is nonzero, then the server
418 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
419 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
420 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
421 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
422 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
423 messages to the client’s hardware address and ’yiaddr’ address. In
424 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
425 messages to 0xffffffff.
426
427 Section 4.3.2
428
429 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
430 different subnet. The server MUST set the broadcast bit in the
431 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
432 client, because the client may not have a correct network address
433 or subnet mask, and the client may not be answering ARP requests.
434 */
435 if (req->message->giaddr) {
436 destination = req->message->giaddr;
8eb7b6a5 437 destination_port = DHCP_PORT_SERVER;
969b009d
TG
438 if (type == DHCP_NAK)
439 packet->dhcp.flags = htobe16(0x8000);
440 } else if (req->message->ciaddr && type != DHCP_NAK)
441 destination = req->message->ciaddr;
442
c95df587
YA
443 bool l2_broadcast = requested_broadcast(req->message) || type == DHCP_NAK;
444 return dhcp_server_send(server, destination, destination_port, packet, optoffset, l2_broadcast);
969b009d
TG
445}
446
4dc35568 447static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
a6f1e036
TG
448 uint8_t type, size_t *_optoffset,
449 DHCPRequest *req) {
4dc35568 450 _cleanup_free_ DHCPPacket *packet = NULL;
1231c4d2 451 size_t optoffset = 0;
4dc35568
TG
452 int r;
453
454 assert(server);
455 assert(ret);
456 assert(_optoffset);
bd57b450 457 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
4dc35568
TG
458
459 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
460 if (!packet)
461 return -ENOMEM;
462
a6f1e036 463 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
76253e73
DW
464 be32toh(req->message->xid), type, ARPHRD_ETHER,
465 req->max_optlen, &optoffset);
4dc35568
TG
466 if (r < 0)
467 return r;
468
469 packet->dhcp.flags = req->message->flags;
470 packet->dhcp.giaddr = req->message->giaddr;
471 memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
472
473 *_optoffset = optoffset;
1cc6c93a 474 *ret = TAKE_PTR(packet);
4dc35568
TG
475
476 return 0;
477}
478
986c0edf 479static int server_send_offer_or_ack(
ddb82ec2
LP
480 sd_dhcp_server *server,
481 DHCPRequest *req,
986c0edf
YW
482 be32_t address,
483 uint8_t type) {
ddb82ec2 484
2dead812 485 _cleanup_free_ DHCPPacket *packet = NULL;
7354900d 486 sd_dhcp_option *j;
986c0edf 487 be32_t lease_time;
564ca984 488 size_t offset;
2dead812
TG
489 int r;
490
986c0edf
YW
491 assert(server);
492 assert(req);
493 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK));
494
495 r = server_message_init(server, &packet, type, &offset, req);
2dead812
TG
496 if (r < 0)
497 return r;
498
499 packet->dhcp.yiaddr = address;
500
c7d9ffe6 501 lease_time = htobe32(req->lifetime);
2dead812 502 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
22805d92 503 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
a6f1e036 504 &lease_time);
2dead812
TG
505 if (r < 0)
506 return r;
507
59b8f6b6 508 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
22805d92 509 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
59b8f6b6
TG
510 if (r < 0)
511 return r;
512
77ff6022
CG
513 if (server->emit_router) {
514 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
515 SD_DHCP_OPTION_ROUTER, 4, &server->address);
516 if (r < 0)
517 return r;
518 }
59b8f6b6 519
986c0edf
YW
520 if (type == DHCP_ACK) {
521 static const uint8_t option_map[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = {
522 [SD_DHCP_LEASE_DNS] = SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
523 [SD_DHCP_LEASE_NTP] = SD_DHCP_OPTION_NTP_SERVER,
524 [SD_DHCP_LEASE_SIP] = SD_DHCP_OPTION_SIP_SERVER,
525 [SD_DHCP_LEASE_POP3] = SD_DHCP_OPTION_POP3_SERVER,
526 [SD_DHCP_LEASE_SMTP] = SD_DHCP_OPTION_SMTP_SERVER,
527 [SD_DHCP_LEASE_LPR] = SD_DHCP_OPTION_LPR_SERVER,
528 };
529
530 for (sd_dhcp_lease_server_type_t k = 0; k < _SD_DHCP_LEASE_SERVER_TYPE_MAX; k++) {
531 if (server->servers[k].size <= 0)
532 continue;
533
534 r = dhcp_option_append(
535 &packet->dhcp, req->max_optlen, &offset, 0,
536 option_map[k],
537 sizeof(struct in_addr) * server->servers[k].size,
538 server->servers[k].addr);
539 if (r < 0)
540 return r;
541 }
2c649ca1 542
50018bfa 543
986c0edf
YW
544 if (server->timezone) {
545 r = dhcp_option_append(
546 &packet->dhcp, req->max_optlen, &offset, 0,
547 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE,
548 strlen(server->timezone), server->timezone);
549 if (r < 0)
550 return r;
551 }
8eb9058d
LP
552 }
553
ebffea2a 554 ORDERED_SET_FOREACH(j, server->extra_options) {
7354900d
DW
555 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
556 j->option, j->length, j->data);
557 if (r < 0)
558 return r;
559 }
560
ebffea2a 561 if (!ordered_set_isempty(server->vendor_options)) {
564ca984
SS
562 r = dhcp_option_append(
563 &packet->dhcp, req->max_optlen, &offset, 0,
564 SD_DHCP_OPTION_VENDOR_SPECIFIC,
ebffea2a 565 ordered_set_size(server->vendor_options), server->vendor_options);
564ca984
SS
566 if (r < 0)
567 return r;
568 }
569
986c0edf 570 r = dhcp_server_send_packet(server, req, packet, type, offset);
2dead812
TG
571 if (r < 0)
572 return r;
573
574 return 0;
575}
576
bd57b450
TG
577static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
578 _cleanup_free_ DHCPPacket *packet = NULL;
579 size_t offset;
580 int r;
581
582 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
583 if (r < 0)
584 return r;
585
b3ec603c 586 return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
bd57b450
TG
587}
588
a6f1e036 589static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
141261f1 590 be32_t gateway, const uint8_t chaddr[]) {
52750344
TG
591 _cleanup_free_ DHCPPacket *packet = NULL;
592 size_t optoffset = 0;
593 int r;
594
595 assert(server);
596 assert(address != INADDR_ANY);
597 assert(chaddr);
598
599 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
600 if (!packet)
601 return -ENOMEM;
602
603 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
76253e73
DW
604 DHCP_FORCERENEW, ARPHRD_ETHER,
605 DHCP_MIN_OPTIONS_SIZE, &optoffset);
52750344
TG
606 if (r < 0)
607 return r;
608
609 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
22805d92 610 &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
52750344
TG
611 if (r < 0)
612 return r;
613
614 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
615
8eb7b6a5
PF
616 r = dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT,
617 &packet->dhcp,
52750344 618 sizeof(DHCPMessage) + optoffset);
c15fb62a
TA
619 if (r < 0)
620 return r;
52750344
TG
621
622 return 0;
623}
624
b3ec603c 625static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
89ca10c6 626 DHCPRequest *req = userdata;
816e2e7a
TG
627
628 assert(req);
629
630 switch(code) {
22805d92 631 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
c7d9ffe6 632 if (len == 4)
9ae84244 633 req->lifetime = unaligned_read_be32(option);
c7d9ffe6
TG
634
635 break;
22805d92 636 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
2dead812 637 if (len == 4)
9ae84244 638 memcpy(&req->requested_ip, option, sizeof(be32_t));
2dead812
TG
639
640 break;
22805d92 641 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
816e2e7a 642 if (len == 4)
9ae84244 643 memcpy(&req->server_id, option, sizeof(be32_t));
816e2e7a
TG
644
645 break;
22805d92 646 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
816e2e7a
TG
647 if (len >= 2) {
648 uint8_t *data;
649
650 data = memdup(option, len);
651 if (!data)
652 return -ENOMEM;
653
654 free(req->client_id.data);
655 req->client_id.data = data;
656 req->client_id.length = len;
657 }
658
659 break;
22805d92 660 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
76a9d0f1
LP
661
662 if (len == 2 && unaligned_read_be16(option) >= sizeof(DHCPPacket))
9ae84244 663 req->max_optlen = unaligned_read_be16(option) - sizeof(DHCPPacket);
816e2e7a 664
11c38d3e
YA
665 break;
666 case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION:
667 req->agent_info_option = (uint8_t*)option - 2;
668
816e2e7a
TG
669 break;
670 }
671
672 return 0;
673}
674
75db809a 675static DHCPRequest* dhcp_request_free(DHCPRequest *req) {
816e2e7a 676 if (!req)
75db809a 677 return NULL;
816e2e7a
TG
678
679 free(req->client_id.data);
75db809a 680 return mfree(req);
816e2e7a
TG
681}
682
683DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
816e2e7a 684
586ac6f7 685static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) {
816e2e7a
TG
686 assert(req);
687 assert(message);
688
689 req->message = message;
690
e2acdb6b 691 /* set client id based on MAC address if client did not send an explicit
a6f1e036 692 one */
816e2e7a 693 if (!req->client_id.data) {
9a0f246f 694 void *data;
816e2e7a 695
9a0f246f 696 data = malloc0(ETH_ALEN + 1);
816e2e7a
TG
697 if (!data)
698 return -ENOMEM;
699
9a0f246f
LP
700 ((uint8_t*) data)[0] = 0x01;
701 memcpy((uint8_t*) data + 1, &message->chaddr, ETH_ALEN);
702
816e2e7a
TG
703 req->client_id.length = ETH_ALEN + 1;
704 req->client_id.data = data;
816e2e7a
TG
705 }
706
707 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
708 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
709
9a0f246f 710 if (req->lifetime <= 0)
586ac6f7
LP
711 req->lifetime = MAX(1ULL, server->default_lease_time);
712
713 if (server->max_lease_time > 0 && req->lifetime > server->max_lease_time)
714 req->lifetime = server->max_lease_time;
c7d9ffe6 715
816e2e7a
TG
716 return 0;
717}
718
87322b3a
TG
719static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
720 assert(server);
721
722 if (!server->pool_size)
723 return -EINVAL;
724
99634696
TG
725 if (be32toh(requested_ip) < (be32toh(server->subnet) | server->pool_offset) ||
726 be32toh(requested_ip) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
727 return -ERANGE;
87322b3a 728
99634696 729 return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
87322b3a
TG
730}
731
11c38d3e
YA
732static int append_agent_information_option(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t size) {
733 int r;
734 size_t offset;
735
736 assert(server);
737 assert(message);
738
739 r = dhcp_option_find_option(message->options, opt_length, SD_DHCP_OPTION_END, &offset);
740 if (r < 0)
741 return r;
742
743 r = dhcp_option_append(message, size, &offset, 0, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION, 0, server);
744 if (r < 0)
745 return r;
746
747 r = dhcp_option_append(message, size, &offset, 0, SD_DHCP_OPTION_END, 0, NULL);
748 if (r < 0)
749 return r;
750 return offset;
751}
752
753static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t buflen) {
c95df587 754 _cleanup_free_ DHCPPacket *packet = NULL;
11c38d3e 755 int r;
c95df587
YA
756
757 assert(server);
758 assert(message);
759 assert(sd_dhcp_server_is_in_relay_mode(server));
760
761 if (message->op == BOOTREQUEST) {
762 log_dhcp_server(server, "(relay agent) BOOTREQUEST (0x%x)", be32toh(message->xid));
763 if (message->hops >= 16)
764 return -ETIME;
765 message->hops++;
766
767 /* https://tools.ietf.org/html/rfc1542#section-4.1.1 */
768 if (message->giaddr == 0)
769 message->giaddr = server->address;
770
11c38d3e
YA
771 if (server->agent_circuit_id || server->agent_remote_id) {
772 r = append_agent_information_option(server, message, opt_length, buflen - sizeof(DHCPMessage));
773 if (r < 0)
774 return log_dhcp_server_errno(server, r, "could not append relay option: %m");
775 opt_length = r;
776 }
777
c95df587
YA
778 return dhcp_server_send_udp(server, server->relay_target.s_addr, DHCP_PORT_SERVER, message, sizeof(DHCPMessage) + opt_length);
779 } else if (message->op == BOOTREPLY) {
780 log_dhcp_server(server, "(relay agent) BOOTREPLY (0x%x)", be32toh(message->xid));
11c38d3e 781 if (message->giaddr != server->address)
c95df587 782 return log_dhcp_server_errno(server, SYNTHETIC_ERRNO(EBADMSG),
11c38d3e 783 "(relay agent) BOOTREPLY giaddr mismatch, discarding");
c95df587
YA
784
785 int message_type = dhcp_option_parse(message, sizeof(DHCPMessage) + opt_length, NULL, NULL, NULL);
786 if (message_type < 0)
787 return message_type;
788
789 packet = malloc0(sizeof(DHCPPacket) + opt_length);
790 if (!packet)
791 return -ENOMEM;
792 memcpy(&packet->dhcp, message, sizeof(DHCPMessage) + opt_length);
793
11c38d3e
YA
794 r = dhcp_option_remove_option(packet->dhcp.options, opt_length, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION);
795 if (r > 0)
796 opt_length = r;
797
c95df587
YA
798 bool l2_broadcast = requested_broadcast(message) || message_type == DHCP_NAK;
799 const be32_t destination = message_type == DHCP_NAK ? INADDR_ANY : message->ciaddr;
800 return dhcp_server_send(server, destination, DHCP_PORT_CLIENT, packet, opt_length, l2_broadcast);
801 }
802 return -EBADMSG;
803}
804
83cedf7a
TG
805#define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
806
be077570
TG
807int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
808 size_t length) {
8e766630 809 _cleanup_(dhcp_request_freep) DHCPRequest *req = NULL;
f693e9b3 810 _cleanup_free_ char *error_message = NULL;
87322b3a 811 DHCPLease *existing_lease;
816e2e7a 812 int type, r;
be077570
TG
813
814 assert(server);
815 assert(message);
816
817 if (message->op != BOOTREQUEST ||
818 message->htype != ARPHRD_ETHER ||
819 message->hlen != ETHER_ADDR_LEN)
820 return 0;
821
816e2e7a
TG
822 req = new0(DHCPRequest, 1);
823 if (!req)
824 return -ENOMEM;
825
f693e9b3 826 type = dhcp_option_parse(message, length, parse_request, req, &error_message);
be077570
TG
827 if (type < 0)
828 return 0;
829
586ac6f7 830 r = ensure_sane_request(server, req, message);
816e2e7a
TG
831 if (r < 0)
832 /* this only fails on critical errors */
833 return r;
834
a6f1e036
TG
835 existing_lease = hashmap_get(server->leases_by_client_id,
836 &req->client_id);
87322b3a 837
4dc35568 838 switch(type) {
9a0f246f
LP
839
840 case DHCP_DISCOVER: {
87322b3a
TG
841 be32_t address = INADDR_ANY;
842 unsigned i;
2dead812 843
4dc35568
TG
844 log_dhcp_server(server, "DISCOVER (0x%x)",
845 be32toh(req->message->xid));
846
2dead812
TG
847 if (!server->pool_size)
848 /* no pool allocated */
849 return 0;
850
87322b3a
TG
851 /* for now pick a random free address from the pool */
852 if (existing_lease)
853 address = existing_lease->address;
854 else {
b826ab58 855 struct siphash state;
0cb3c286 856 uint64_t hash;
99634696 857 uint32_t next_offer;
83cedf7a
TG
858
859 /* even with no persistence of leases, we try to offer the same client
860 the same IP address. we do this by using the hash of the client id
861 as the offset into the pool of leases when finding the next free one */
862
0cb3c286 863 siphash24_init(&state, HASH_KEY.bytes);
b826ab58 864 client_id_hash_func(&req->client_id, &state);
933f9cae 865 hash = htole64(siphash24_finalize(&state));
0cb3c286 866 next_offer = hash % server->pool_size;
83cedf7a 867
87322b3a 868 for (i = 0; i < server->pool_size; i++) {
83cedf7a 869 if (!server->bound_leases[next_offer]) {
99634696 870 address = server->subnet | htobe32(server->pool_offset + next_offer);
87322b3a 871 break;
6408ba5f
LP
872 }
873
874 next_offer = (next_offer + 1) % server->pool_size;
87322b3a
TG
875 }
876 }
877
878 if (address == INADDR_ANY)
879 /* no free addresses left */
880 return 0;
2dead812 881
986c0edf 882 r = server_send_offer_or_ack(server, req, address, DHCP_OFFER);
6e741541 883 if (r < 0)
4dc35568 884 /* this only fails on critical errors */
6e741541 885 return log_dhcp_server_errno(server, r, "Could not send offer: %m");
be077570 886
6e741541
LP
887 log_dhcp_server(server, "OFFER (0x%x)", be32toh(req->message->xid));
888 return DHCP_OFFER;
4dc35568 889 }
5b34277c 890 case DHCP_DECLINE:
f693e9b3 891 log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
5b34277c
TG
892
893 /* TODO: make sure we don't offer this address again */
894
895 return 1;
896
9a0f246f 897 case DHCP_REQUEST: {
2dead812 898 be32_t address;
bd57b450 899 bool init_reboot = false;
87322b3a 900 int pool_offset;
2dead812
TG
901
902 /* see RFC 2131, section 4.3.2 */
903
904 if (req->server_id) {
905 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
906 be32toh(req->message->xid));
907
908 /* SELECTING */
909 if (req->server_id != server->address)
910 /* client did not pick us */
911 return 0;
912
913 if (req->message->ciaddr)
914 /* this MUST be zero */
915 return 0;
916
917 if (!req->requested_ip)
918 /* this must be filled in with the yiaddr
919 from the chosen OFFER */
920 return 0;
921
922 address = req->requested_ip;
923 } else if (req->requested_ip) {
924 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
925 be32toh(req->message->xid));
926
927 /* INIT-REBOOT */
928 if (req->message->ciaddr)
929 /* this MUST be zero */
930 return 0;
931
bd57b450 932 /* TODO: check more carefully if IP is correct */
2dead812 933 address = req->requested_ip;
bd57b450 934 init_reboot = true;
2dead812
TG
935 } else {
936 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
937 be32toh(req->message->xid));
938
939 /* REBINDING / RENEWING */
940 if (!req->message->ciaddr)
941 /* this MUST be filled in with clients IP address */
942 return 0;
943
944 address = req->message->ciaddr;
945 }
946
87322b3a
TG
947 pool_offset = get_pool_offset(server, address);
948
949 /* verify that the requested address is from the pool, and either
950 owned by the current client or free */
951 if (pool_offset >= 0 &&
952 server->bound_leases[pool_offset] == existing_lease) {
953 DHCPLease *lease;
a7f7d1bd 954 usec_t time_now = 0;
87322b3a
TG
955
956 if (!existing_lease) {
957 lease = new0(DHCPLease, 1);
357e1b17
LP
958 if (!lease)
959 return -ENOMEM;
28c78e07 960 lease->address = address;
87322b3a
TG
961 lease->client_id.data = memdup(req->client_id.data,
962 req->client_id.length);
02557f97
TA
963 if (!lease->client_id.data) {
964 free(lease);
87322b3a 965 return -ENOMEM;
02557f97 966 }
87322b3a 967 lease->client_id.length = req->client_id.length;
a6f1e036
TG
968 memcpy(&lease->chaddr, &req->message->chaddr,
969 ETH_ALEN);
52750344 970 lease->gateway = req->message->giaddr;
87322b3a
TG
971 } else
972 lease = existing_lease;
973
a6f1e036
TG
974 r = sd_event_now(server->event,
975 clock_boottime_or_monotonic(),
976 &time_now);
bff92d2c
SS
977 if (r < 0) {
978 if (!existing_lease)
979 dhcp_lease_free(lease);
38a03f06 980 return r;
bff92d2c
SS
981 }
982
87322b3a
TG
983 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
984
986c0edf 985 r = server_send_offer_or_ack(server, req, address, DHCP_ACK);
2dead812
TG
986 if (r < 0) {
987 /* this only fails on critical errors */
6e741541 988 log_dhcp_server_errno(server, r, "Could not send ack: %m");
87322b3a
TG
989
990 if (!existing_lease)
991 dhcp_lease_free(lease);
992
2dead812
TG
993 return r;
994 } else {
995 log_dhcp_server(server, "ACK (0x%x)",
996 be32toh(req->message->xid));
87322b3a
TG
997
998 server->bound_leases[pool_offset] = lease;
a6f1e036
TG
999 hashmap_put(server->leases_by_client_id,
1000 &lease->client_id, lease);
87322b3a 1001
36d35f22
MAL
1002 if (server->callback)
1003 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
1004
2dead812
TG
1005 return DHCP_ACK;
1006 }
6e741541 1007
bd57b450
TG
1008 } else if (init_reboot) {
1009 r = server_send_nak(server, req);
6e741541 1010 if (r < 0)
bd57b450 1011 /* this only fails on critical errors */
6e741541
LP
1012 return log_dhcp_server_errno(server, r, "Could not send nak: %m");
1013
1014 log_dhcp_server(server, "NAK (0x%x)", be32toh(req->message->xid));
1015 return DHCP_NAK;
bd57b450 1016 }
2dead812
TG
1017
1018 break;
1019 }
9a0f246f 1020
500792d8
TG
1021 case DHCP_RELEASE: {
1022 int pool_offset;
1023
1024 log_dhcp_server(server, "RELEASE (0x%x)",
1025 be32toh(req->message->xid));
1026
1027 if (!existing_lease)
1028 return 0;
1029
1030 if (existing_lease->address != req->message->ciaddr)
1031 return 0;
1032
1033 pool_offset = get_pool_offset(server, req->message->ciaddr);
1034 if (pool_offset < 0)
1035 return 0;
1036
1037 if (server->bound_leases[pool_offset] == existing_lease) {
1038 server->bound_leases[pool_offset] = NULL;
1039 hashmap_remove(server->leases_by_client_id, existing_lease);
1040 dhcp_lease_free(existing_lease);
36d35f22
MAL
1041
1042 if (server->callback)
1043 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
c3922c0c 1044 }
500792d8 1045
c3922c0c
LP
1046 return 0;
1047 }}
4dc35568
TG
1048
1049 return 0;
be077570
TG
1050}
1051
11c38d3e
YA
1052static size_t relay_agent_information_length(const char* agent_circuit_id, const char* agent_remote_id) {
1053 size_t sum = 0;
1054 if (agent_circuit_id)
1055 sum += 2 + strlen(agent_circuit_id);
1056 if (agent_remote_id)
1057 sum += 2 + strlen(agent_remote_id);
1058 return sum;
1059}
1060
ff734080
TG
1061static int server_receive_message(sd_event_source *s, int fd,
1062 uint32_t revents, void *userdata) {
be077570 1063 _cleanup_free_ DHCPMessage *message = NULL;
fb29cdbe 1064 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control;
ff734080
TG
1065 sd_dhcp_server *server = userdata;
1066 struct iovec iov = {};
1067 struct msghdr msg = {
1068 .msg_iov = &iov,
1069 .msg_iovlen = 1,
fb29cdbe
LP
1070 .msg_control = &control,
1071 .msg_controllen = sizeof(control),
ff734080 1072 };
3a864fe4 1073 struct cmsghdr *cmsg;
11c38d3e 1074 ssize_t datagram_size, len;
57027d03 1075 int r;
ff734080
TG
1076
1077 assert(server);
1078
11c38d3e
YA
1079 datagram_size = next_datagram_size_fd(fd);
1080 if (datagram_size < 0)
1081 return datagram_size;
1082
1083 size_t buflen = datagram_size;
1084 if (sd_dhcp_server_is_in_relay_mode(server))
1085 /* Preallocate the additional size for DHCP Relay Agent Information Option if neeeded */
1086 buflen += relay_agent_information_length(server->agent_circuit_id, server->agent_remote_id) + 2;
ff734080 1087
0d43d2fc 1088 message = malloc(buflen);
ff734080
TG
1089 if (!message)
1090 return -ENOMEM;
1091
11c38d3e 1092 iov = IOVEC_MAKE(message, datagram_size);
ff734080 1093
2efa5bc6
LP
1094 len = recvmsg_safe(fd, &msg, 0);
1095 if (IN_SET(len, -EAGAIN, -EINTR))
1096 return 0;
1097 if (len < 0)
1098 return len;
1099 if ((size_t) len < sizeof(DHCPMessage))
be077570 1100 return 0;
ff734080 1101
2a1288ff 1102 CMSG_FOREACH(cmsg, &msg) {
3a864fe4
TG
1103 if (cmsg->cmsg_level == IPPROTO_IP &&
1104 cmsg->cmsg_type == IP_PKTINFO &&
1105 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
1106 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
1107
a6f1e036
TG
1108 /* TODO figure out if this can be done as a filter on
1109 * the socket, like for IPv6 */
b3ec603c 1110 if (server->ifindex != info->ipi_ifindex)
3a864fe4
TG
1111 return 0;
1112
1113 break;
1114 }
1115 }
1116
c95df587 1117 if (sd_dhcp_server_is_in_relay_mode(server)) {
11c38d3e 1118 r = dhcp_server_relay_message(server, message, len - sizeof(DHCPMessage), buflen);
c95df587
YA
1119 if (r < 0)
1120 log_dhcp_server_errno(server, r, "Couldn't relay message: %m");
1121 } else {
1122 r = dhcp_server_handle_message(server, message, (size_t) len);
1123 if (r < 0)
1124 log_dhcp_server_errno(server, r, "Couldn't process incoming message: %m");
1125 }
57027d03 1126 return 0;
ff734080
TG
1127}
1128
1129int sd_dhcp_server_start(sd_dhcp_server *server) {
1130 int r;
1131
1132 assert_return(server, -EINVAL);
1133 assert_return(server->event, -EINVAL);
1134 assert_return(!server->receive_message, -EBUSY);
cfcbb135
LP
1135 assert_return(server->fd_raw < 0, -EBUSY);
1136 assert_return(server->fd < 0, -EBUSY);
20af7091 1137 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
ff734080 1138
3e29b889 1139 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
8de4a226
TG
1140 if (r < 0) {
1141 r = -errno;
21b6b87e 1142 goto on_error;
8de4a226
TG
1143 }
1144 server->fd_raw = r;
1145
21b6b87e
YA
1146 if (server->bind_to_interface)
1147 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER, -1);
1148 else
1149 r = dhcp_network_bind_udp_socket(0, server->address, DHCP_PORT_SERVER, -1);
1150 if (r < 0)
1151 goto on_error;
ff734080
TG
1152 server->fd = r;
1153
1154 r = sd_event_add_io(server->event, &server->receive_message,
1155 server->fd, EPOLLIN,
1156 server_receive_message, server);
21b6b87e
YA
1157 if (r < 0)
1158 goto on_error;
ff734080
TG
1159
1160 r = sd_event_source_set_priority(server->receive_message,
1161 server->event_priority);
21b6b87e
YA
1162 if (r < 0)
1163 goto on_error;
1164
1165 if (!server->bind_to_interface) {
1166 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_BROADCAST, DHCP_PORT_SERVER, -1);
1167 if (r < 0)
1168 goto on_error;
1169
1170 server->fd_broadcast = r;
1171
1172 r = sd_event_add_io(server->event, &server->receive_broadcast,
1173 server->fd_broadcast, EPOLLIN,
1174 server_receive_message, server);
1175 if (r < 0)
1176 goto on_error;
1177
1178 r = sd_event_source_set_priority(server->receive_broadcast,
1179 server->event_priority);
1180 if (r < 0)
1181 goto on_error;
ff734080
TG
1182 }
1183
1184 log_dhcp_server(server, "STARTED");
1185
1186 return 0;
21b6b87e
YA
1187
1188on_error:
1189 sd_dhcp_server_stop(server);
1190 return r;
ff734080 1191}
52750344
TG
1192
1193int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
621ac3d2 1194 int r = 0;
52750344
TG
1195
1196 assert_return(server, -EINVAL);
1197 assert(server->bound_leases);
1198
fe96c0f8 1199 for (uint32_t i = 0; i < server->pool_size; i++) {
52750344
TG
1200 DHCPLease *lease = server->bound_leases[i];
1201
99634696 1202 if (!lease || lease == &server->invalid_lease)
52750344
TG
1203 continue;
1204
1205 r = server_send_forcerenew(server, lease->address,
1206 lease->gateway,
1207 lease->chaddr);
1208 if (r < 0)
1209 return r;
6408ba5f
LP
1210
1211 log_dhcp_server(server, "FORCERENEW");
52750344
TG
1212 }
1213
1214 return r;
1215}
8eb9058d 1216
21b6b87e
YA
1217int sd_dhcp_server_set_bind_to_interface(sd_dhcp_server *server, int enabled) {
1218 assert_return(server, -EINVAL);
1219 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1220
1221 if (!!enabled == server->bind_to_interface)
1222 return 0;
1223
1224 server->bind_to_interface = enabled;
1225
1226 return 1;
1227}
1228
64d6c229 1229int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
8eb9058d
LP
1230 int r;
1231
1232 assert_return(server, -EINVAL);
089fb865 1233 assert_return(timezone_is_valid(tz, LOG_DEBUG), -EINVAL);
8eb9058d 1234
64d6c229 1235 if (streq_ptr(tz, server->timezone))
8eb9058d
LP
1236 return 0;
1237
64d6c229 1238 r = free_and_strdup(&server->timezone, tz);
8eb9058d
LP
1239 if (r < 0)
1240 return r;
1241
1242 return 1;
1243}
586ac6f7
LP
1244
1245int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t) {
1246 assert_return(server, -EINVAL);
1247
1248 if (t == server->max_lease_time)
1249 return 0;
1250
1251 server->max_lease_time = t;
1252 return 1;
1253}
1254
1255int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) {
1256 assert_return(server, -EINVAL);
1257
1258 if (t == server->default_lease_time)
1259 return 0;
1260
1261 server->default_lease_time = t;
1262 return 1;
1263}
1a04db0f 1264
c8407baf
ZJS
1265int sd_dhcp_server_set_servers(
1266 sd_dhcp_server *server,
2324fd3a 1267 sd_dhcp_lease_server_type_t what,
c8407baf 1268 const struct in_addr addresses[],
90810f7a 1269 size_t n_addresses) {
1a04db0f 1270
ddb82ec2
LP
1271 struct in_addr *c = NULL;
1272
1a04db0f 1273 assert_return(server, -EINVAL);
c8407baf 1274 assert_return(addresses || n_addresses == 0, -EINVAL);
ddb82ec2
LP
1275 assert_return(what >= 0, -EINVAL);
1276 assert_return(what < _SD_DHCP_LEASE_SERVER_TYPE_MAX, -EINVAL);
1a04db0f 1277
ddb82ec2
LP
1278 if (server->servers[what].size == n_addresses &&
1279 memcmp(server->servers[what].addr, addresses, sizeof(struct in_addr) * n_addresses) == 0)
f678ac7e
SS
1280 return 0;
1281
c8407baf
ZJS
1282 if (n_addresses > 0) {
1283 c = newdup(struct in_addr, addresses, n_addresses);
f678ac7e
SS
1284 if (!c)
1285 return -ENOMEM;
f678ac7e
SS
1286 }
1287
ddb82ec2
LP
1288 free(server->servers[what].addr);
1289 server->servers[what].addr = c;
1290 server->servers[what].size = n_addresses;
f678ac7e
SS
1291 return 1;
1292}
1293
90810f7a 1294int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], size_t n) {
ddb82ec2 1295 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_DNS, dns, n);
c8407baf 1296}
90810f7a 1297int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], size_t n) {
ddb82ec2 1298 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_NTP, ntp, n);
c8407baf 1299}
90810f7a 1300int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], size_t n) {
ddb82ec2 1301 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SIP, sip, n);
c8407baf 1302}
90810f7a 1303int sd_dhcp_server_set_pop3(sd_dhcp_server *server, const struct in_addr pop3[], size_t n) {
ddb82ec2 1304 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_POP3, pop3, n);
c8407baf 1305}
90810f7a 1306int sd_dhcp_server_set_smtp(sd_dhcp_server *server, const struct in_addr smtp[], size_t n) {
ddb82ec2 1307 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SMTP, smtp, n);
2c649ca1 1308}
90810f7a 1309int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], size_t n) {
ddb82ec2 1310 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_LPR, lpr, n);
50018bfa 1311}
2c649ca1 1312
77ff6022
CG
1313int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) {
1314 assert_return(server, -EINVAL);
1315
1316 if (enabled == server->emit_router)
1317 return 0;
1318
1319 server->emit_router = enabled;
1320
1321 return 1;
1322}
564ca984 1323
461dbb2f 1324int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v) {
564ca984
SS
1325 int r;
1326
1327 assert_return(server, -EINVAL);
1328 assert_return(v, -EINVAL);
1329
ebffea2a 1330 r = ordered_set_ensure_put(&server->extra_options, &dhcp_option_hash_ops, v);
7354900d
DW
1331 if (r < 0)
1332 return r;
1333
1334 sd_dhcp_option_ref(v);
1335 return 0;
1336}
1337
1338int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v) {
1339 int r;
1340
1341 assert_return(server, -EINVAL);
1342 assert_return(v, -EINVAL);
1343
ebffea2a 1344 r = ordered_set_ensure_put(&server->vendor_options, &dhcp_option_hash_ops, v);
564ca984
SS
1345 if (r < 0)
1346 return r;
1347
461dbb2f 1348 sd_dhcp_option_ref(v);
564ca984
SS
1349
1350 return 1;
1351}
5b03043a
MAL
1352
1353int sd_dhcp_server_set_callback(sd_dhcp_server *server, sd_dhcp_server_callback_t cb, void *userdata) {
1354 assert_return(server, -EINVAL);
1355
1356 server->callback = cb;
1357 server->callback_userdata = userdata;
1358
1359 return 0;
1360}
c95df587 1361
11c38d3e 1362int sd_dhcp_server_set_relay_target(sd_dhcp_server *server, const struct in_addr *address) {
c95df587
YA
1363 assert_return(server, -EINVAL);
1364 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1365
1366 if (memcmp(address, &server->relay_target, sizeof(struct in_addr)) == 0)
1367 return 0;
1368
1369 server->relay_target = *address;
1370 return 1;
1371}
11c38d3e
YA
1372
1373int sd_dhcp_server_set_relay_agent_information(
1374 sd_dhcp_server *server,
1375 const char *agent_circuit_id,
1376 const char *agent_remote_id) {
1377 _cleanup_free_ char *circuit_id_dup = NULL, *remote_id_dup = NULL;
1378
1379 assert_return(server, -EINVAL);
1380
1381 if (relay_agent_information_length(agent_circuit_id, agent_remote_id) > UINT8_MAX)
1382 return -ENOBUFS;
1383
1384 if (agent_circuit_id) {
1385 circuit_id_dup = strdup(agent_circuit_id);
1386 if (!circuit_id_dup)
1387 return -ENOMEM;
1388 }
1389
1390 if (agent_remote_id) {
1391 remote_id_dup = strdup(agent_remote_id);
1392 if (!remote_id_dup)
1393 return -ENOMEM;
1394 }
1395
1396 free_and_replace(server->agent_circuit_id, circuit_id_dup);
1397 free_and_replace(server->agent_remote_id, remote_id_dup);
1398 return 0;
1399}