summaryrefslogtreecommitdiff
path: root/src/libsystemd-network/sd-dhcp-server.c
diff options
context:
space:
mode:
authorYegor Alexeyev <yegor.alexeyev@gmail.com>2021-03-09 14:57:37 +0300
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-04-14 07:30:40 +0900
commit21b6b87eb326a447ca5ed9e566e1ec7a2f227cfe (patch)
treea08c195b4851769a3d9f50611d5c6ccb5db2562d /src/libsystemd-network/sd-dhcp-server.c
parentbcaf24cd77d80529f70643e9b96c45a437dbed54 (diff)
downloadsystemd-21b6b87eb326a447ca5ed9e566e1ec7a2f227cfe.tar.gz
dhcp: Implemented BindToInterface= configuration option
Diffstat (limited to 'src/libsystemd-network/sd-dhcp-server.c')
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c99
1 files changed, 68 insertions, 31 deletions
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 0036cddbf9..be61474758 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -180,9 +180,11 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
.n_ref = 1,
.fd_raw = -1,
.fd = -1,
+ .fd_broadcast = -1,
.address = htobe32(INADDR_ANY),
.netmask = htobe32(INADDR_ANY),
.ifindex = ifindex,
+ .bind_to_interface = true,
.default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC),
.max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC),
};
@@ -250,11 +252,12 @@ int sd_dhcp_server_stop(sd_dhcp_server *server) {
if (!server)
return 0;
- server->receive_message =
- sd_event_source_unref(server->receive_message);
+ server->receive_message = sd_event_source_unref(server->receive_message);
+ server->receive_broadcast = sd_event_source_unref(server->receive_broadcast);
server->fd_raw = safe_close(server->fd_raw);
server->fd = safe_close(server->fd);
+ server->fd_broadcast = safe_close(server->fd_broadcast);
log_dhcp_server(server, "STOPPED");
@@ -303,8 +306,6 @@ static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
.msg_namelen = sizeof(dest.in),
.msg_iov = &iov,
.msg_iovlen = 1,
- .msg_control = &control,
- .msg_controllen = sizeof(control),
};
struct cmsghdr *cmsg;
struct in_pktinfo *pktinfo;
@@ -314,22 +315,27 @@ static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
assert(message);
assert(len > sizeof(DHCPMessage));
- cmsg = CMSG_FIRSTHDR(&msg);
- assert(cmsg);
+ if (server->bind_to_interface) {
+ msg.msg_control = &control;
+ msg.msg_controllen = sizeof(control);
- cmsg->cmsg_level = IPPROTO_IP;
- cmsg->cmsg_type = IP_PKTINFO;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+ cmsg = CMSG_FIRSTHDR(&msg);
+ assert(cmsg);
- /* we attach source interface and address info to the message
- rather than binding the socket. This will be mostly useful
- when we gain support for arbitrary number of server addresses
- */
- pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
- assert(pktinfo);
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
- pktinfo->ipi_ifindex = server->ifindex;
- pktinfo->ipi_spec_dst.s_addr = server->address;
+ /* we attach source interface and address info to the message
+ rather than binding the socket. This will be mostly useful
+ when we gain support for arbitrary number of server addresses
+ */
+ pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
+ assert(pktinfo);
+
+ pktinfo->ipi_ifindex = server->ifindex;
+ pktinfo->ipi_spec_dst.s_addr = server->address;
+ }
if (sendmsg(server->fd, &msg, 0) < 0)
return -errno;
@@ -1013,36 +1019,55 @@ int sd_dhcp_server_start(sd_dhcp_server *server) {
r = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (r < 0) {
r = -errno;
- sd_dhcp_server_stop(server);
- return r;
+ goto on_error;
}
server->fd_raw = r;
- r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER, -1);
- if (r < 0) {
- sd_dhcp_server_stop(server);
- return r;
- }
+ if (server->bind_to_interface)
+ r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER, -1);
+ else
+ r = dhcp_network_bind_udp_socket(0, server->address, DHCP_PORT_SERVER, -1);
+ if (r < 0)
+ goto on_error;
server->fd = r;
r = sd_event_add_io(server->event, &server->receive_message,
server->fd, EPOLLIN,
server_receive_message, server);
- if (r < 0) {
- sd_dhcp_server_stop(server);
- return r;
- }
+ if (r < 0)
+ goto on_error;
r = sd_event_source_set_priority(server->receive_message,
server->event_priority);
- if (r < 0) {
- sd_dhcp_server_stop(server);
- return r;
+ if (r < 0)
+ goto on_error;
+
+ if (!server->bind_to_interface) {
+ r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_BROADCAST, DHCP_PORT_SERVER, -1);
+ if (r < 0)
+ goto on_error;
+
+ server->fd_broadcast = r;
+
+ r = sd_event_add_io(server->event, &server->receive_broadcast,
+ server->fd_broadcast, EPOLLIN,
+ server_receive_message, server);
+ if (r < 0)
+ goto on_error;
+
+ r = sd_event_source_set_priority(server->receive_broadcast,
+ server->event_priority);
+ if (r < 0)
+ goto on_error;
}
log_dhcp_server(server, "STARTED");
return 0;
+
+on_error:
+ sd_dhcp_server_stop(server);
+ return r;
}
int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
@@ -1069,6 +1094,18 @@ int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
return r;
}
+int sd_dhcp_server_set_bind_to_interface(sd_dhcp_server *server, int enabled) {
+ assert_return(server, -EINVAL);
+ assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
+
+ if (!!enabled == server->bind_to_interface)
+ return 0;
+
+ server->bind_to_interface = enabled;
+
+ return 1;
+}
+
int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
int r;