1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-10 05:18:17 +03:00

network/address: several cleanups for config_parse_address()

- make it accept an empty string,
- use config_parse_in_addr_prefix(),
- move null address checker to address_section_verify().

No functional change, just refactoring.
This commit is contained in:
Yu Watanabe 2024-09-23 03:36:15 +09:00
parent 5d15c7b19c
commit 1cbc8d9168
3 changed files with 36 additions and 41 deletions

View File

@ -3,8 +3,10 @@
#include <net/if.h>
#include <net/if_arp.h>
#include "af-list.h"
#include "alloc-util.h"
#include "firewall-util.h"
#include "in-addr-prefix-util.h"
#include "logarithm.h"
#include "memory-util.h"
#include "netlink-util.h"
@ -2076,53 +2078,33 @@ static int config_parse_address(
void *userdata) {
Address *address = ASSERT_PTR(userdata);
union in_addr_union buffer;
unsigned char prefixlen;
int r, f;
union in_addr_union *a = ASSERT_PTR(data);
struct in_addr_prefix prefix;
int r;
assert(rvalue);
/* Address=address/prefixlen */
r = in_addr_prefix_from_string_auto_full(rvalue, PREFIXLEN_REFUSE, &f, &buffer, &prefixlen);
if (r == -ENOANO) {
r = in_addr_prefix_from_string_auto(rvalue, &f, &buffer, &prefixlen);
if (r >= 0)
log_syntax(unit, LOG_WARNING, filename, line, r,
"Address '%s' is specified without prefix length. Assuming the prefix length is %u. "
"Please specify the prefix length explicitly.", rvalue, prefixlen);
if (isempty(rvalue)) {
/* When an empty string is assigned, clear both Address= and Peer=. */
address->family = AF_UNSPEC;
address->prefixlen = 0;
address->in_addr = IN_ADDR_NULL;
address->in_addr_peer = IN_ADDR_NULL;
return 1;
}
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
if (address->family != AF_UNSPEC && f != address->family) {
r = config_parse_in_addr_prefix(unit, filename, line, section, section_line, lvalue, /* ltype = */ true, rvalue, &prefix, /* userdata = */ NULL);
if (r <= 0)
return r;
if (address->family != AF_UNSPEC && prefix.family != address->family) {
log_syntax(unit, LOG_WARNING, filename, line, 0, "Address is incompatible, ignoring assignment: %s", rvalue);
return 0;
}
if (in_addr_is_null(f, &buffer)) {
/* Will use address from address pool. Note that for ipv6 case, prefix of the address
* pool is 8, but 40 bit is used by the global ID and 16 bit by the subnet ID. So,
* let's limit the prefix length to 64 or larger. See RFC4193. */
if ((f == AF_INET && prefixlen < 8) ||
(f == AF_INET6 && prefixlen < 64)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Null address with invalid prefixlen='%u', ignoring assignment: %s",
prefixlen, rvalue);
return 0;
}
}
address->family = f;
address->prefixlen = prefixlen;
if (streq_ptr(lvalue, "Address")) {
address->in_addr = buffer;
address->requested_as_null = !in_addr_is_set(address->family, &address->in_addr);
} else if (streq_ptr(lvalue, "Peer"))
address->in_addr_peer = buffer;
else
assert_not_reached();
address->family = prefix.family;
address->prefixlen = prefix.prefixlen;
*a = prefix.address;
return 1;
}
@ -2263,7 +2245,8 @@ int config_parse_address_section(
void *userdata) {
static const ConfigSectionParser table[_ADDRESS_CONF_PARSER_MAX] = {
[ADDRESS_ADDRESS] = { .parser = config_parse_address, .ltype = 0, .offset = 0, },
[ADDRESS_ADDRESS] = { .parser = config_parse_address, .ltype = 0, .offset = offsetof(Address, in_addr), },
[ADDRESS_PEER] = { .parser = config_parse_address, .ltype = 0, .offset = offsetof(Address, in_addr_peer), },
[ADDRESS_BROADCAST] = { .parser = config_parse_broadcast, .ltype = 0, .offset = 0, },
[ADDRESS_LABEL] = { .parser = config_parse_address_label, .ltype = 0, .offset = offsetof(Address, label), },
[ADDRESS_PREFERRED_LIFETIME] = { .parser = config_parse_address_lifetime, .ltype = 0, .offset = offsetof(Address, lifetime_preferred_usec), },
@ -2366,11 +2349,22 @@ int address_section_verify(Address *address) {
if (address->family == AF_UNSPEC)
return log_address_section(address, "Address section without Address= field was configured.");
assert(IN_SET(address->family, AF_INET, AF_INET6));
if (address->family == AF_INET6 && !socket_ipv6_is_supported())
return log_address_section(address, "An IPv6 address was configured, but the kernel does not support IPv6.");
assert(IN_SET(address->family, AF_INET, AF_INET6));
if (in_addr_is_null(address->family, &address->in_addr)) {
/* Will use address from address pool. Note that for ipv6 case, prefix of the address
* pool is 8, but 40 bit is used by the global ID and 16 bit by the subnet ID. So,
* let's limit the prefix length to 64 or larger. See RFC4193. */
unsigned min_prefixlen = address->family == AF_INET ? 8 : 64;
if (address->prefixlen < min_prefixlen)
return log_address_section(address, "Prefix length for %s null address must be equal or larger than %u.",
af_to_ipv4_ipv6(address->family), min_prefixlen);
address->requested_as_null = !in_addr_is_set(address->family, &address->in_addr);
}
address_section_adjust_broadcast(address);

View File

@ -161,6 +161,7 @@ void link_mark_addresses(Link *link, NetworkConfigSource source);
typedef enum AddressConfParserType {
ADDRESS_ADDRESS,
ADDRESS_PEER,
ADDRESS_BROADCAST,
ADDRESS_LABEL,
ADDRESS_PREFERRED_LIFETIME,

View File

@ -157,7 +157,7 @@ Network.KeepConfiguration, config_parse_keep_configuration,
Network.IPv6SendRA, config_parse_router_prefix_delegation, 0, offsetof(Network, router_prefix_delegation)
Network.DHCPPrefixDelegation, config_parse_tristate, 0, offsetof(Network, dhcp_pd)
Address.Address, config_parse_address_section, ADDRESS_ADDRESS, 0
Address.Peer, config_parse_address_section, ADDRESS_ADDRESS, 0
Address.Peer, config_parse_address_section, ADDRESS_PEER, 0
Address.Broadcast, config_parse_address_section, ADDRESS_BROADCAST, 0
Address.Label, config_parse_address_section, ADDRESS_LABEL, 0
Address.PreferredLifetime, config_parse_address_section, ADDRESS_PREFERRED_LIFETIME, 0