#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"
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;
}
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), },
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);