req->after_configure = static_address_after_configure;
}
+ if (in4_addr_is_set(&link->network->dhcp_server_address)) {
+ _cleanup_(address_freep) Address *address = NULL;
+
+ r = address_new(&address);
+ if (r < 0)
+ return log_oom();
+
+ address->family = AF_INET;
+ address->in_addr.in = link->network->dhcp_server_address;
+ address->prefixlen = link->network->dhcp_server_address_prefixlen;
+ address_set_broadcast(address);
+
+ /* The same address may be explicitly configured in [Address] or [Network] section.
+ * Configure the DHCP server address only when it is not. */
+ if (!link_is_static_address_configured(link, address)) {
+ Request *req;
+
+ r = link_request_address(link, TAKE_PTR(address), true, &link->static_address_messages,
+ static_address_handler, &req);
+ if (r < 0)
+ return r;
+
+ req->after_configure = static_address_after_configure;
+ }
+ }
+
if (link->static_address_messages == 0) {
link->static_addresses_configured = true;
link_check_ready(link);
if (!link->network)
return false;
- if (link->network->bond)
- return false;
-
if (link->iftype == ARPHRD_CAN)
return false;
return link->network->dhcp_server;
}
-static Address* link_find_dhcp_server_address(Link *link) {
+void network_adjust_dhcp_server(Network *network) {
+ assert(network);
+
+ if (!network->dhcp_server)
+ return;
+
+ if (network->bond) {
+ log_warning("%s: DHCPServer= is enabled for bond slave. Disabling DHCP server.",
+ network->filename);
+ network->dhcp_server = false;
+ return;
+ }
+
+ if (!in4_addr_is_set(&network->dhcp_server_address)) {
+ Address *address;
+ bool have = false;
+
+ ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section) {
+ if (section_is_invalid(address->section))
+ continue;
+ if (address->family == AF_INET &&
+ !in4_addr_is_localhost(&address->in_addr.in) &&
+ in4_addr_is_null(&address->in_addr_peer.in)) {
+ have = true;
+ break;
+ }
+ }
+ if (!have) {
+ log_warning("%s: DHCPServer= is enabled, but no static address configured. "
+ "Disabling DHCP server.",
+ network->filename);
+ network->dhcp_server = false;
+ return;
+ }
+ }
+}
+
+static int link_find_dhcp_server_address(Link *link, Address **ret) {
Address *address;
assert(link);
assert(link->network);
- /* The first statically configured address if there is any */
- ORDERED_HASHMAP_FOREACH(address, link->network->addresses_by_section)
- if (address->family == AF_INET &&
- in_addr_is_set(address->family, &address->in_addr))
- return address;
+ /* If ServerAddress= is specified, then use the address. */
+ if (in4_addr_is_set(&link->network->dhcp_server_address))
+ return link_get_ipv4_address(link, &link->network->dhcp_server_address,
+ link->network->dhcp_server_address_prefixlen, ret);
- /* If that didn't work, find a suitable address we got from the pool */
- SET_FOREACH(address, link->pool_addresses)
- if (address->family == AF_INET)
- return address;
+ /* If not, then select one from static addresses. */
+ SET_FOREACH(address, link->static_addresses)
+ if (address->family == AF_INET &&
+ !in4_addr_is_localhost(&address->in_addr.in) &&
+ in4_addr_is_null(&address->in_addr_peer.in)) {
+ *ret = address;
+ return 0;
+ }
- return NULL;
+ return -ENOENT;
}
static int link_push_uplink_to_dhcp_server(
if (r < 0)
return log_link_warning_errno(link, r, "Failed to set callback for DHCPv4 server instance: %m");
- address = link_find_dhcp_server_address(link);
- if (!address)
- return log_link_error_errno(link, SYNTHETIC_ERRNO(EBUSY),
- "Failed to find suitable address for DHCPv4 server instance.");
+ r = link_find_dhcp_server_address(link, &address);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to find suitable address for DHCPv4 server instance: %m");
/* use the server address' subnet as the pool */
r = sd_dhcp_server_configure_pool(link->dhcp_server, &address->in_addr.in, address->prefixlen,
assert(lvalue);
assert(rvalue);
-
if (isempty(rvalue)) {
*suboption_value = mfree(*suboption_value);
return 0;
emit->addresses[emit->n_addresses++] = a.in;
}
}
+
+int config_parse_dhcp_server_address(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *network = userdata;
+ union in_addr_union a;
+ unsigned char prefixlen;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ network->dhcp_server_address = (struct in_addr) {};
+ network->dhcp_server_address_prefixlen = 0;
+ return 0;
+ }
+
+ r = in_addr_prefix_from_string(rvalue, AF_INET, &a, &prefixlen);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+ }
+ if (in4_addr_is_null(&a.in) || in4_addr_is_localhost(&a.in)) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "DHCP server address cannot be the ANY address or a localhost address, "
+ "ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ network->dhcp_server_address = a.in;
+ network->dhcp_server_address_prefixlen = prefixlen;
+ return 0;
+}
IPv6AcceptRA.PrefixDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.RouteAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_route_prefix)
IPv6AcceptRA.RouteDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_route_prefix)
+DHCPServer.ServerAddress, config_parse_dhcp_server_address, 0, 0
DHCPServer.RelayTarget, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_server_relay_target)
DHCPServer.RelayAgentCircuitId, config_parse_dhcp_server_relay_agent_suboption, 0, offsetof(Network, dhcp_server_relay_agent_circuit_id)
DHCPServer.RelayAgentRemoteId, config_parse_dhcp_server_relay_agent_suboption, 0, offsetof(Network, dhcp_server_relay_agent_remote_id)