#include <linux/if_arp.h>
#include "bus-error.h"
+#include "bus-locator.h"
#include "dhcp-identifier.h"
#include "dhcp-internal.h"
#include "dhcp6-internal.h"
#include "escape.h"
#include "hexdecoct.h"
-#include "in-addr-util.h"
+#include "in-addr-prefix-util.h"
#include "networkd-dhcp-common.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "socket-util.h"
#include "string-table.h"
#include "strv.h"
+#include "vrf.h"
+
+static uint32_t link_get_vrf_table(Link *link) {
+ assert(link);
+ assert(link->network);
+
+ return link->network->vrf ? VRF(link->network->vrf)->table : RT_TABLE_MAIN;
+}
+
+uint32_t link_get_dhcp4_route_table(Link *link) {
+ assert(link);
+ assert(link->network);
+
+ /* When the interface is part of an VRF use the VRFs routing table, unless
+ * another table is explicitly specified. */
+
+ if (link->network->dhcp_route_table_set)
+ return link->network->dhcp_route_table;
+ return link_get_vrf_table(link);
+}
+
+uint32_t link_get_ipv6_accept_ra_route_table(Link *link) {
+ assert(link);
+ assert(link->network);
+
+ if (link->network->ipv6_accept_ra_route_table_set)
+ return link->network->ipv6_accept_ra_route_table;
+ return link_get_vrf_table(link);
+}
bool link_dhcp_enabled(Link *link, int family) {
assert(link);
assert(IN_SET(family, AF_INET, AF_INET6));
+ /* Currently, sd-dhcp-client supports only ethernet and infiniband. */
+ if (family == AF_INET && !IN_SET(link->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND))
+ return false;
+
if (family == AF_INET6 && !socket_ipv6_is_supported())
return false;
if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6) &&
FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV6)) {
- log_warning("%s: DHCPv6 client is enabled but IPv6 link local addressing is disabled. "
+ log_warning("%s: DHCPv6 client is enabled but IPv6 link-local addressing is disabled. "
"Disabling DHCPv6 client.", network->filename);
SET_FLAG(network->dhcp, ADDRESS_FAMILY_IPV6, false);
}
}
static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- Manager *manager = userdata;
+ Manager *manager = ASSERT_PTR(userdata);
const sd_bus_error *e;
const void *a;
size_t sz;
int r;
assert(m);
- assert(manager);
/* To avoid calling GetProductUUID() bus method so frequently, set the flag below
* even if the method fails. */
m->product_uuid_requested = false;
- r = sd_bus_call_method_async(
+ r = bus_call_method_async(
m->bus,
NULL,
- "org.freedesktop.hostname1",
- "/org/freedesktop/hostname1",
- "org.freedesktop.hostname1",
+ bus_hostname,
"GetProductUUID",
get_product_uuid_handler,
m,
return 0;
}
+bool address_is_filtered(int family, const union in_addr_union *address, uint8_t prefixlen, Set *allow_list, Set *deny_list) {
+ struct in_addr_prefix *p;
+
+ assert(IN_SET(family, AF_INET, AF_INET6));
+ assert(address);
+
+ if (allow_list) {
+ SET_FOREACH(p, allow_list)
+ if (p->family == family &&
+ p->prefixlen <= prefixlen &&
+ in_addr_prefix_covers(family, &p->address, p->prefixlen, address) > 0)
+ return false;
+
+ return true;
+ }
+
+ SET_FOREACH(p, deny_list)
+ if (p->family == family &&
+ in_addr_prefix_intersect(family, &p->address, p->prefixlen, address, prefixlen) > 0)
+ return true;
+
+ return false;
+}
+
int config_parse_dhcp(
const char* unit,
const char *filename,
return 0;
}
-int config_parse_dhcp_route_metric(
+int config_parse_dhcp_or_ra_route_metric(
const char* unit,
const char *filename,
unsigned line,
assert(filename);
assert(lvalue);
+ assert(IN_SET(ltype, AF_UNSPEC, AF_INET, AF_INET6));
assert(rvalue);
assert(data);
return 0;
}
- if (streq_ptr(section, "DHCPv4")) {
+ switch (ltype) {
+ case AF_INET:
network->dhcp_route_metric = metric;
network->dhcp_route_metric_set = true;
- } else if (STRPTR_IN_SET(section, "DHCPv6", "IPv6AcceptRA")) {
+ break;
+ case AF_INET6:
network->ipv6_accept_ra_route_metric = metric;
network->ipv6_accept_ra_route_metric_set = true;
- } else { /* [DHCP] section */
+ break;
+ case AF_UNSPEC:
+ /* For backward compatibility. */
if (!network->dhcp_route_metric_set)
network->dhcp_route_metric = metric;
if (!network->ipv6_accept_ra_route_metric_set)
network->ipv6_accept_ra_route_metric = metric;
+ break;
+ default:
+ assert_not_reached();
}
return 0;
assert(filename);
assert(lvalue);
+ assert(IN_SET(ltype, AF_UNSPEC, AF_INET, AF_INET6));
assert(rvalue);
assert(data);
return 0;
}
- if (streq_ptr(section, "DHCPv4")) {
+ switch (ltype) {
+ case AF_INET:
network->dhcp_use_dns = r;
network->dhcp_use_dns_set = true;
- } else if (streq_ptr(section, "DHCPv6")) {
+ break;
+ case AF_INET6:
network->dhcp6_use_dns = r;
network->dhcp6_use_dns_set = true;
- } else { /* [DHCP] section */
+ break;
+ case AF_UNSPEC:
+ /* For backward compatibility. */
if (!network->dhcp_use_dns_set)
network->dhcp_use_dns = r;
if (!network->dhcp6_use_dns_set)
network->dhcp6_use_dns = r;
+ break;
+ default:
+ assert_not_reached();
}
return 0;
assert(filename);
assert(lvalue);
+ assert(IN_SET(ltype, AF_UNSPEC, AF_INET, AF_INET6));
assert(rvalue);
assert(data);
return 0;
}
- if (streq_ptr(section, "DHCPv4")) {
+ switch (ltype) {
+ case AF_INET:
network->dhcp_use_domains = d;
network->dhcp_use_domains_set = true;
- } else if (streq_ptr(section, "DHCPv6")) {
+ break;
+ case AF_INET6:
network->dhcp6_use_domains = d;
network->dhcp6_use_domains_set = true;
- } else { /* [DHCP] section */
+ break;
+ case AF_UNSPEC:
+ /* For backward compatibility. */
if (!network->dhcp_use_domains_set)
network->dhcp_use_domains = d;
if (!network->dhcp6_use_domains_set)
network->dhcp6_use_domains = d;
+ break;
+ default:
+ assert_not_reached();
}
return 0;
assert(filename);
assert(lvalue);
+ assert(IN_SET(ltype, AF_UNSPEC, AF_INET, AF_INET6));
assert(rvalue);
assert(data);
return 0;
}
- if (streq_ptr(section, "DHCPv4")) {
+ switch (ltype) {
+ case AF_INET:
network->dhcp_use_ntp = r;
network->dhcp_use_ntp_set = true;
- } else if (streq_ptr(section, "DHCPv6")) {
+ break;
+ case AF_INET6:
network->dhcp6_use_ntp = r;
network->dhcp6_use_ntp_set = true;
- } else { /* [DHCP] section */
+ break;
+ case AF_UNSPEC:
+ /* For backward compatibility. */
if (!network->dhcp_use_ntp_set)
network->dhcp_use_ntp = r;
if (!network->dhcp6_use_ntp_set)
network->dhcp6_use_ntp = r;
+ break;
+ default:
+ assert_not_reached();
}
return 0;
}
-int config_parse_section_route_table(
+int config_parse_dhcp_or_ra_route_table(
const char *unit,
const char *filename,
unsigned line,
void *data,
void *userdata) {
- Network *network = userdata;
+ Network *network = ASSERT_PTR(userdata);
uint32_t rt;
int r;
assert(filename);
assert(lvalue);
+ assert(IN_SET(ltype, AF_INET, AF_INET6));
assert(rvalue);
- assert(data);
r = safe_atou32(rvalue, &rt);
if (r < 0) {
return 0;
}
- if (STRPTR_IN_SET(section, "DHCP", "DHCPv4")) {
+ switch (ltype) {
+ case AF_INET:
network->dhcp_route_table = rt;
network->dhcp_route_table_set = true;
- } else { /* section is IPv6AcceptRA */
+ break;
+ case AF_INET6:
network->ipv6_accept_ra_route_table = rt;
network->ipv6_accept_ra_route_table_set = true;
+ break;
+ default:
+ assert_not_reached();
}
return 0;
void *data,
void *userdata) {
- Network *network = userdata;
+ Network *network = ASSERT_PTR(userdata);
uint32_t iaid;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(network);
assert(IN_SET(ltype, AF_INET, AF_INET6));
r = safe_atou32(rvalue, &iaid);
void *data,
void *userdata) {
- char ***l = data;
+ char ***l = ASSERT_PTR(data);
int r;
- assert(l);
assert(lvalue);
assert(rvalue);
assert(IN_SET(ltype, AF_INET, AF_INET6));
void *data,
void *userdata) {
- _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt4 = NULL, *old4 = NULL;
- _cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *opt6 = NULL, *old6 = NULL;
+ _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt4 = NULL;
+ _cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *opt6 = NULL;
+ _unused_ _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *old4 = NULL;
+ _unused_ _cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *old6 = NULL;
uint32_t uint32_data, enterprise_identifier = 0;
_cleanup_free_ char *word = NULL, *q = NULL;
- OrderedHashmap **options = data;
+ OrderedHashmap **options = ASSERT_PTR(data);
uint16_t u16, uint16_data;
union in_addr_union addr;
DHCPOptionDataType type;
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(data);
if (isempty(rvalue)) {
*options = ordered_hashmap_free(*options);
return 0;
}
- switch(type) {
+ switch (type) {
case DHCP_OPTION_DATA_UINT8:{
r = safe_atou8(p, &uint8_data);
if (r < 0) {
void *userdata) {
_cleanup_free_ char *type_string = NULL;
- const char *p = rvalue;
+ const char *p = ASSERT_PTR(rvalue);
bool force = ltype;
- DUID *duid = data;
+ DUID *duid = ASSERT_PTR(data);
DUIDType type;
int r;
assert(filename);
assert(lvalue);
- assert(rvalue);
- assert(duid);
if (!force && duid->set)
return 0;
void *data,
void *userdata) {
- Manager *manager = userdata;
+ Manager *manager = ASSERT_PTR(userdata);
int r;
- assert(manager);
-
/* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */
r = config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
void *data,
void *userdata) {
- Network *network = userdata;
+ Network *network = ASSERT_PTR(userdata);
int r;
- assert(network);
-
r = config_parse_duid_type(unit, filename, line, section, section_line, lvalue, true, rvalue, &network->dhcp_duid, network);
if (r < 0)
return r;
uint8_t raw_data[MAX_DUID_LEN];
unsigned count = 0;
bool force = ltype;
- DUID *duid = data;
+ DUID *duid = ASSERT_PTR(data);
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(duid);
if (!force && duid->set)
return 0;
void *data,
void *userdata) {
- Manager *manager = userdata;
+ Manager *manager = ASSERT_PTR(userdata);
int r;
- assert(manager);
-
/* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */
r = config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
void *data,
void *userdata) {
- Network *network = userdata;
+ Network *network = ASSERT_PTR(userdata);
int r;
- assert(network);
-
r = config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, true, rvalue, &network->dhcp_duid, network);
if (r < 0)
return r;
/* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
}
+
+int config_parse_uplink(
+ 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 = ASSERT_PTR(userdata);
+ bool accept_none = true;
+ int *index, r;
+ char **name;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (streq(section, "DHCPServer")) {
+ index = &network->dhcp_server_uplink_index;
+ name = &network->dhcp_server_uplink_name;
+ } else if (streq(section, "IPv6SendRA")) {
+ index = &network->router_uplink_index;
+ name = &network->router_uplink_name;
+ } else if (STR_IN_SET(section, "DHCPv6PrefixDelegation", "DHCPPrefixDelegation")) {
+ index = &network->dhcp_pd_uplink_index;
+ name = &network->dhcp_pd_uplink_name;
+ accept_none = false;
+ } else
+ assert_not_reached();
+
+ if (isempty(rvalue) || streq(rvalue, ":auto")) {
+ *index = UPLINK_INDEX_AUTO;
+ *name = mfree(*name);
+ return 0;
+ }
+
+ if (accept_none && streq(rvalue, ":none")) {
+ *index = UPLINK_INDEX_NONE;
+ *name = mfree(*name);
+ return 0;
+ }
+
+ if (!accept_none && streq(rvalue, ":self")) {
+ *index = UPLINK_INDEX_SELF;
+ *name = mfree(*name);
+ return 0;
+ }
+
+ r = parse_ifindex(rvalue);
+ if (r > 0) {
+ *index = r;
+ *name = mfree(*name);
+ return 0;
+ }
+
+ if (!ifname_valid_full(rvalue, IFNAME_VALID_ALTERNATIVE)) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid interface name in %s=, ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ /* The interface name will be resolved later. */
+ r = free_and_strdup_warn(name, rvalue);
+ if (r < 0)
+ return r;
+
+ /* Note, if uplink_name is set, then uplink_index will be ignored. So, the below does not mean
+ * an uplink interface will be selected automatically. */
+ *index = UPLINK_INDEX_AUTO;
+ return 0;
+}