1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-13 00:58:27 +03:00

Merge pull request #20697 from yuwata/in-addr-prefix

core: rewrite IPAddressAllow/Deny= parser
This commit is contained in:
Lennart Poettering 2021-09-14 15:58:20 +02:00 committed by GitHub
commit 2fe29f3135
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 600 additions and 437 deletions

View File

@ -11,7 +11,7 @@
#include "bus-util.h"
#include "env-util.h"
#include "format-table.h"
#include "in-addr-util.h"
#include "in-addr-prefix-util.h"
#include "locale-util.h"
#include "macro.h"
#include "manager.h"
@ -2582,10 +2582,10 @@ static int get_security_info(Unit *u, ExecContext *c, CGroupContext *g, Security
return log_oom();
}
IPAddressAccessItem *i;
struct in_addr_prefix *i;
bool deny_ipv4 = false, deny_ipv6 = false;
LIST_FOREACH(items, i, g->ip_address_deny) {
SET_FOREACH(i, g->ip_address_deny) {
if (i->family == AF_INET && i->prefixlen == 0)
deny_ipv4 = true;
else if (i->family == AF_INET6 && i->prefixlen == 0)
@ -2594,7 +2594,7 @@ static int get_security_info(Unit *u, ExecContext *c, CGroupContext *g, Security
info->ip_address_deny_all = deny_ipv4 && deny_ipv6;
info->ip_address_allow_localhost = info->ip_address_allow_other = false;
LIST_FOREACH(items, i, g->ip_address_allow) {
SET_FOREACH(i, g->ip_address_allow) {
if (in_addr_is_localhost(i->family, &i->address))
info->ip_address_allow_localhost = true;
else

View File

@ -831,35 +831,6 @@ static int in_addr_data_compare_func(const struct in_addr_data *x, const struct
DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
static void in_addr_prefix_hash_func(const struct in_addr_prefix *a, struct siphash *state) {
assert(a);
assert(state);
siphash24_compress(&a->family, sizeof(a->family), state);
siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
}
static int in_addr_prefix_compare_func(const struct in_addr_prefix *x, const struct in_addr_prefix *y) {
int r;
assert(x);
assert(y);
r = CMP(x->family, y->family);
if (r != 0)
return r;
r = CMP(x->prefixlen, y->prefixlen);
if (r != 0)
return r;
return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
}
DEFINE_HASH_OPS(in_addr_prefix_hash_ops, struct in_addr_prefix, in_addr_prefix_hash_func, in_addr_prefix_compare_func);
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(in_addr_prefix_hash_ops_free, struct in_addr_prefix, in_addr_prefix_hash_func, in_addr_prefix_compare_func, free);
void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
assert(addr);
assert(state);

View File

@ -20,12 +20,6 @@ struct in_addr_data {
union in_addr_union address;
};
struct in_addr_prefix {
int family;
uint8_t prefixlen;
union in_addr_union address;
};
bool in4_addr_is_null(const struct in_addr *a);
static inline bool in4_addr_is_set(const struct in_addr *a) {
return !in4_addr_is_null(a);
@ -124,8 +118,6 @@ void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state);
int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b);
extern const struct hash_ops in_addr_data_hash_ops;
extern const struct hash_ops in_addr_prefix_hash_ops;
extern const struct hash_ops in_addr_prefix_hash_ops_free;
extern const struct hash_ops in6_addr_hash_ops;
#define IPV4_ADDRESS_FMT_STR "%u.%u.%u.%u"

View File

@ -18,7 +18,7 @@
#include "bpf-firewall.h"
#include "bpf-program.h"
#include "fd-util.h"
#include "ip-address-access.h"
#include "in-addr-prefix-util.h"
#include "memory-util.h"
#include "missing_syscall.h"
#include "unit.h"
@ -335,13 +335,13 @@ static int bpf_firewall_compile_bpf(
return 0;
}
static int bpf_firewall_count_access_items(IPAddressAccessItem *list, size_t *n_ipv4, size_t *n_ipv6) {
IPAddressAccessItem *a;
static int bpf_firewall_count_access_items(Set *prefixes, size_t *n_ipv4, size_t *n_ipv6) {
struct in_addr_prefix *a;
assert(n_ipv4);
assert(n_ipv6);
LIST_FOREACH(items, a, list) {
SET_FOREACH(a, prefixes)
switch (a->family) {
case AF_INET:
@ -355,26 +355,25 @@ static int bpf_firewall_count_access_items(IPAddressAccessItem *list, size_t *n_
default:
return -EAFNOSUPPORT;
}
}
return 0;
}
static int bpf_firewall_add_access_items(
IPAddressAccessItem *list,
Set *prefixes,
int ipv4_map_fd,
int ipv6_map_fd,
int verdict) {
struct bpf_lpm_trie_key *key_ipv4, *key_ipv6;
struct in_addr_prefix *a;
uint64_t value = verdict;
IPAddressAccessItem *a;
int r;
key_ipv4 = alloca0(offsetof(struct bpf_lpm_trie_key, data) + sizeof(uint32_t));
key_ipv6 = alloca0(offsetof(struct bpf_lpm_trie_key, data) + sizeof(uint32_t) * 4);
LIST_FOREACH(items, a, list) {
SET_FOREACH(a, prefixes)
switch (a->family) {
case AF_INET:
@ -400,7 +399,6 @@ static int bpf_firewall_add_access_items(
default:
return -EAFNOSUPPORT;
}
}
return 0;
}
@ -414,7 +412,6 @@ static int bpf_firewall_prepare_access_maps(
_cleanup_close_ int ipv4_map_fd = -1, ipv6_map_fd = -1;
size_t n_ipv4 = 0, n_ipv6 = 0;
IPAddressAccessItem *list;
Unit *p;
int r;
@ -424,18 +421,29 @@ static int bpf_firewall_prepare_access_maps(
for (p = u; p; p = UNIT_GET_SLICE(p)) {
CGroupContext *cc;
Set *prefixes;
bool *reduced;
cc = unit_get_cgroup_context(p);
if (!cc)
continue;
list = verdict == ACCESS_ALLOWED ? cc->ip_address_allow : cc->ip_address_deny;
prefixes = verdict == ACCESS_ALLOWED ? cc->ip_address_allow : cc->ip_address_deny;
reduced = verdict == ACCESS_ALLOWED ? &cc->ip_address_allow_reduced : &cc->ip_address_deny_reduced;
bpf_firewall_count_access_items(list, &n_ipv4, &n_ipv6);
if (!*reduced) {
r = in_addr_prefixes_reduce(prefixes);
if (r < 0)
return r;
*reduced = true;
}
bpf_firewall_count_access_items(prefixes, &n_ipv4, &n_ipv6);
/* Skip making the LPM trie map in cases where we are using "any" in order to hack around
* needing CAP_SYS_ADMIN for allocating LPM trie map. */
if (ip_address_access_item_is_any(list)) {
if (in_addr_prefixes_is_any(prefixes)) {
*ret_has_any = true;
return 0;
}

View File

@ -19,6 +19,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "in-addr-prefix-util.h"
#include "io-util.h"
#include "ip-protocol-list.h"
#include "limits-util.h"
@ -238,8 +239,8 @@ void cgroup_context_done(CGroupContext *c) {
cgroup_context_remove_socket_bind(&c->socket_bind_allow);
cgroup_context_remove_socket_bind(&c->socket_bind_deny);
c->ip_address_allow = ip_address_access_free_all(c->ip_address_allow);
c->ip_address_deny = ip_address_access_free_all(c->ip_address_deny);
c->ip_address_allow = set_free(c->ip_address_allow);
c->ip_address_deny = set_free(c->ip_address_deny);
c->ip_filters_ingress = strv_free(c->ip_filters_ingress);
c->ip_filters_egress = strv_free(c->ip_filters_egress);
@ -395,7 +396,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
CGroupDeviceAllow *a;
CGroupContext *c;
CGroupSocketBindItem *bi;
IPAddressAccessItem *iaai;
struct in_addr_prefix *iaai;
char **path;
char cda[FORMAT_CGROUP_DIFF_MAX];
@ -549,18 +550,18 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
FORMAT_BYTES(b->wbps));
}
LIST_FOREACH(items, iaai, c->ip_address_allow) {
SET_FOREACH(iaai, c->ip_address_allow) {
_cleanup_free_ char *k = NULL;
(void) in_addr_to_string(iaai->family, &iaai->address, &k);
fprintf(f, "%sIPAddressAllow: %s/%u\n", prefix, strnull(k), iaai->prefixlen);
(void) in_addr_prefix_to_string(iaai->family, &iaai->address, iaai->prefixlen, &k);
fprintf(f, "%sIPAddressAllow: %s\n", prefix, strnull(k));
}
LIST_FOREACH(items, iaai, c->ip_address_deny) {
SET_FOREACH(iaai, c->ip_address_deny) {
_cleanup_free_ char *k = NULL;
(void) in_addr_to_string(iaai->family, &iaai->address, &k);
fprintf(f, "%sIPAddressDeny: %s/%u\n", prefix, strnull(k), iaai->prefixlen);
(void) in_addr_prefix_to_string(iaai->family, &iaai->address, iaai->prefixlen, &k);
fprintf(f, "%sIPAddressDeny: %s\n", prefix, strnull(k));
}
STRV_FOREACH(path, c->ip_filters_ingress)
@ -1555,8 +1556,8 @@ static bool unit_get_needs_bpf_firewall(Unit *u) {
return false;
if (c->ip_accounting ||
c->ip_address_allow ||
c->ip_address_deny ||
!set_isempty(c->ip_address_allow) ||
!set_isempty(c->ip_address_deny) ||
c->ip_filters_ingress ||
c->ip_filters_egress)
return true;
@ -1567,8 +1568,8 @@ static bool unit_get_needs_bpf_firewall(Unit *u) {
if (!c)
return false;
if (c->ip_address_allow ||
c->ip_address_deny)
if (!set_isempty(c->ip_address_allow) ||
!set_isempty(c->ip_address_deny))
return true;
}

View File

@ -5,7 +5,6 @@
#include "cgroup-util.h"
#include "cpu-set-util.h"
#include "ip-address-access.h"
#include "list.h"
#include "time-util.h"
@ -148,13 +147,17 @@ struct CGroupContext {
uint64_t memory_max;
uint64_t memory_swap_max;
bool default_memory_min_set;
bool default_memory_low_set;
bool memory_min_set;
bool memory_low_set;
bool default_memory_min_set:1;
bool default_memory_low_set:1;
bool memory_min_set:1;
bool memory_low_set:1;
LIST_HEAD(IPAddressAccessItem, ip_address_allow);
LIST_HEAD(IPAddressAccessItem, ip_address_deny);
Set *ip_address_allow;
Set *ip_address_deny;
/* These two flags indicate that redundant entries have been removed from
* ip_address_allow/ip_address_deny, i.e. in_addr_prefixes_reduce() has already been called. */
bool ip_address_allow_reduced;
bool ip_address_deny_reduced;
char **ip_filters_ingress;
char **ip_filters_egress;

View File

@ -15,6 +15,7 @@
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "in-addr-prefix-util.h"
#include "ip-protocol-list.h"
#include "limits-util.h"
#include "parse-util.h"
@ -318,14 +319,17 @@ static int property_get_ip_address_access(
void *userdata,
sd_bus_error *error) {
IPAddressAccessItem** items = userdata, *i;
Set **prefixes = userdata;
struct in_addr_prefix *i;
int r;
assert(prefixes);
r = sd_bus_message_open_container(reply, 'a', "(iayu)");
if (r < 0)
return r;
LIST_FOREACH(items, i, *items) {
SET_FOREACH(i, *prefixes) {
r = sd_bus_message_open_container(reply, 'r', "iayu");
if (r < 0)
@ -1745,11 +1749,9 @@ int bus_cgroup_set_property(
return 1;
} else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
IPAddressAccessItem **list;
_cleanup_set_free_ Set *new_prefixes = NULL;
size_t n = 0;
list = streq(name, "IPAddressAllow") ? &c->ip_address_allow : &c->ip_address_deny;
r = sd_bus_message_enter_container(message, 'a', "(iayu)");
if (r < 0)
return r;
@ -1789,17 +1791,16 @@ int bus_cgroup_set_property(
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Prefix length %" PRIu32 " too large for address family %s.", prefixlen, af_to_name(family));
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
IPAddressAccessItem *item;
struct in_addr_prefix prefix = {
.family = family,
.prefixlen = prefixlen,
};
item = new0(IPAddressAccessItem, 1);
if (!item)
return -ENOMEM;
memcpy(&prefix.address, ap, an);
item->family = family;
item->prefixlen = prefixlen;
memcpy(&item->address, ap, an);
LIST_PREPEND(items, *list, item);
r = in_addr_prefix_add(&new_prefixes, &prefix);
if (r < 0)
return r;
}
r = sd_bus_message_exit_container(message);
@ -1813,33 +1814,46 @@ int bus_cgroup_set_property(
if (r < 0)
return r;
*list = ip_address_access_reduce(*list);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
_cleanup_free_ char *buf = NULL;
_cleanup_fclose_ FILE *f = NULL;
IPAddressAccessItem *item;
size_t size = 0;
if (n == 0)
*list = ip_address_access_free_all(*list);
Set **prefixes;
bool *reduced;
unit_invalidate_cgroup_bpf(u);
f = open_memstream_unlocked(&buf, &size);
if (!f)
return -ENOMEM;
fputs(name, f);
fputs("=\n", f);
prefixes = streq(name, "IPAddressAllow") ? &c->ip_address_allow : &c->ip_address_deny;
reduced = streq(name, "IPAddressAllow") ? &c->ip_address_allow_reduced : &c->ip_address_deny_reduced;
LIST_FOREACH(items, item, *list) {
char buffer[CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
if (n == 0) {
*reduced = true;
*prefixes = set_free(*prefixes);
fputs(name, f);
fputs("=\n", f);
} else {
struct in_addr_prefix *p;
errno = 0;
if (!inet_ntop(item->family, &item->address, buffer, sizeof(buffer)))
return errno_or_else(EINVAL);
*reduced = false;
fprintf(f, "%s=%s/%u\n", name, buffer, item->prefixlen);
r = in_addr_prefixes_merge(prefixes, new_prefixes);
if (r < 0)
return r;
SET_FOREACH(p, new_prefixes) {
_cleanup_free_ char *buffer = NULL;
r = in_addr_prefix_to_string(p->family, &p->address, p->prefixlen, &buffer);
if (r == -ENOMEM)
return r;
if (r < 0)
continue;
fprintf(f, "%s=%s\n", name, buffer);
}
}
r = fflush_and_check(f);

View File

@ -1,208 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdio.h>
#include <stdlib.h>
#include "alloc-util.h"
#include "bpf-firewall.h"
#include "extract-word.h"
#include "hostname-util.h"
#include "ip-address-access.h"
#include "parse-util.h"
#include "string-util.h"
int config_parse_ip_address_access(
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) {
IPAddressAccessItem **list = data;
const char *p;
int r;
assert(list);
if (isempty(rvalue)) {
*list = ip_address_access_free_all(*list);
return 0;
}
p = rvalue;
for (;;) {
_cleanup_free_ IPAddressAccessItem *a = NULL;
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, 0);
if (r == 0)
break;
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
break;
}
a = new0(IPAddressAccessItem, 1);
if (!a)
return log_oom();
if (streq(word, "any")) {
/* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
a->family = AF_INET;
LIST_APPEND(items, *list, a);
a = new0(IPAddressAccessItem, 1);
if (!a)
return log_oom();
a->family = AF_INET6;
} else if (is_localhost(word)) {
/* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
a->family = AF_INET;
a->address.in.s_addr = htobe32(0x7f000000);
a->prefixlen = 8;
LIST_APPEND(items, *list, a);
a = new0(IPAddressAccessItem, 1);
if (!a)
return log_oom();
a->family = AF_INET6;
a->address.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
a->prefixlen = 128;
} else if (streq(word, "link-local")) {
/* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
a->family = AF_INET;
a->address.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
a->prefixlen = 16;
LIST_APPEND(items, *list, a);
a = new0(IPAddressAccessItem, 1);
if (!a)
return log_oom();
a->family = AF_INET6;
a->address.in6 = (struct in6_addr) {
.s6_addr32[0] = htobe32(0xfe800000)
};
a->prefixlen = 64;
} else if (streq(word, "multicast")) {
/* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
a->family = AF_INET;
a->address.in.s_addr = htobe32((UINT32_C(224) << 24));
a->prefixlen = 4;
LIST_APPEND(items, *list, a);
a = new0(IPAddressAccessItem, 1);
if (!a)
return log_oom();
a->family = AF_INET6;
a->address.in6 = (struct in6_addr) {
.s6_addr32[0] = htobe32(0xff000000)
};
a->prefixlen = 8;
} else {
r = in_addr_prefix_from_string_auto(word, &a->family, &a->address, &a->prefixlen);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Address prefix is invalid, ignoring assignment: %s", word);
return 0;
}
}
LIST_APPEND(items, *list, a);
a = NULL;
}
*list = ip_address_access_reduce(*list);
return 0;
}
IPAddressAccessItem* ip_address_access_free_all(IPAddressAccessItem *first) {
IPAddressAccessItem *next, *p = first;
while (p) {
next = p->items_next;
free(p);
p = next;
}
return NULL;
}
IPAddressAccessItem* ip_address_access_reduce(IPAddressAccessItem *first) {
IPAddressAccessItem *a, *b, *tmp;
int r;
/* Drops all entries from the list that are covered by another entry in full, thus removing all redundant
* entries. */
LIST_FOREACH_SAFE(items, a, tmp, first) {
/* Drop irrelevant bits */
(void) in_addr_mask(a->family, &a->address, a->prefixlen);
LIST_FOREACH(items, b, first) {
if (a == b)
continue;
if (a->family != b->family)
continue;
if (b->prefixlen > a->prefixlen)
continue;
r = in_addr_prefix_covers(b->family,
&b->address,
b->prefixlen,
&a->address);
if (r > 0) {
/* b covers a fully, then let's drop a */
LIST_REMOVE(items, first, a);
free(a);
break;
}
}
}
return first;
}
bool ip_address_access_item_is_any(IPAddressAccessItem *first) {
/* Check for exactly two entries */
if (!first || !first->items_next || first->items_next->items_next)
return false;
/* Check both entries cover the full range */
if (first->prefixlen != 0 || first->items_next->prefixlen != 0)
return false;
/* Check that one of them is the IPv4 and the other IPv6 */
if (!((first->family == AF_INET && first->items_next->family == AF_INET6) ||
(first->family == AF_INET6 && first->items_next->family == AF_INET)))
return false;
/* No need to check the actual addresses, they don't matter if the prefix is zero */
return true;
}

View File

@ -1,25 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "conf-parser.h"
#include "in-addr-util.h"
#include "list.h"
typedef struct IPAddressAccessItem IPAddressAccessItem;
struct IPAddressAccessItem {
int family;
unsigned char prefixlen;
union in_addr_union address;
LIST_FIELDS(IPAddressAccessItem, items);
};
CONFIG_PARSER_PROTOTYPE(config_parse_ip_address_access);
IPAddressAccessItem* ip_address_access_free_all(IPAddressAccessItem *first);
IPAddressAccessItem* ip_address_access_reduce(IPAddressAccessItem *first);
/* Returns true if a list consists of only the two items necessary for "any"
* (0.0.0.0/0 and ::/0). */
bool ip_address_access_item_is_any(IPAddressAccessItem *first);

View File

@ -221,8 +221,8 @@
{{type}}.Delegate, config_parse_delegate, 0, offsetof({{type}}, cgroup_context)
{{type}}.DisableControllers, config_parse_disable_controllers, 0, offsetof({{type}}, cgroup_context)
{{type}}.IPAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.ip_accounting)
{{type}}.IPAddressAllow, config_parse_ip_address_access, 0, offsetof({{type}}, cgroup_context.ip_address_allow)
{{type}}.IPAddressDeny, config_parse_ip_address_access, 0, offsetof({{type}}, cgroup_context.ip_address_deny)
{{type}}.IPAddressAllow, config_parse_in_addr_prefixes, AF_UNSPEC, offsetof({{type}}, cgroup_context.ip_address_allow)
{{type}}.IPAddressDeny, config_parse_in_addr_prefixes, AF_UNSPEC, offsetof({{type}}, cgroup_context.ip_address_deny)
{{type}}.IPIngressFilterPath, config_parse_ip_filter_bpf_progs, 0, offsetof({{type}}, cgroup_context.ip_filters_ingress)
{{type}}.IPEgressFilterPath, config_parse_ip_filter_bpf_progs, 0, offsetof({{type}}, cgroup_context.ip_filters_egress)
{{type}}.ManagedOOMSwap, config_parse_managed_oom_mode, 0, offsetof({{type}}, cgroup_context.moom_swap)
@ -243,6 +243,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include <stddef.h>
#include "all-units.h"
#include "conf-parser.h"
#include "in-addr-prefix-util.h"
#include "load-fragment.h"
%}
struct ConfigPerfItem;

View File

@ -12,7 +12,6 @@
#include "cgroup.h"
#include "fdset.h"
#include "hashmap.h"
#include "ip-address-access.h"
#include "list.h"
#include "prioq.h"
#include "ratelimit.h"

View File

@ -71,8 +71,6 @@ libcore_sources = '''
generator-setup.h
ima-setup.c
ima-setup.h
ip-address-access.c
ip-address-access.h
job.c
job.h
kill.c

View File

@ -3,6 +3,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include "sd-id128.h"

View File

@ -9,7 +9,7 @@
#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"
@ -1265,69 +1265,3 @@ int config_parse_network_duid_rawdata(
/* 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_address_filter(
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) {
Set **list = data;
int r;
assert(filename);
assert(lvalue);
assert(IN_SET(ltype, AF_INET, AF_INET6));
assert(rvalue);
assert(data);
if (isempty(rvalue)) {
*list = set_free(*list);
return 0;
}
for (const char *p = rvalue;;) {
_cleanup_free_ char *n = NULL;
_cleanup_free_ struct in_addr_prefix *a = NULL;
struct in_addr_prefix prefix;
r = extract_first_word(&p, &n, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse NDisc %s=, ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
if (r == 0)
return 0;
r = in_addr_prefix_from_string(n, ltype, &prefix.address, &prefix.prefixlen);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"NDisc %s= entry is invalid, ignoring assignment: %s",
lvalue, n);
continue;
}
prefix.family = ltype;
a = newdup(struct in_addr_prefix, &prefix, 1);
if (!a)
return log_oom();
r = set_ensure_consume(list, &in_addr_prefix_hash_ops_free, TAKE_PTR(a));
if (r < 0)
return log_oom();
if (r == 0)
log_syntax(unit, LOG_WARNING, filename, line, 0,
"%s %s= entry is duplicated, ignoring assignment: %s",
section, lvalue, n);
}
}

View File

@ -99,4 +99,3 @@ CONFIG_PARSER_PROTOTYPE(config_parse_network_duid_type);
CONFIG_PARSER_PROTOTYPE(config_parse_duid_rawdata);
CONFIG_PARSER_PROTOTYPE(config_parse_manager_duid_rawdata);
CONFIG_PARSER_PROTOTYPE(config_parse_network_duid_rawdata);
CONFIG_PARSER_PROTOTYPE(config_parse_address_filter);

View File

@ -12,6 +12,7 @@
#include "hashmap.h"
#include "hostname-setup.h"
#include "hostname-util.h"
#include "in-addr-prefix-util.h"
#include "missing_network.h"
#include "networkd-address.h"
#include "networkd-dhcp6.h"

View File

@ -5,6 +5,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#endif
#include <stddef.h>
#include "conf-parser.h"
#include "in-addr-prefix-util.h"
#include "netem.h"
#include "net-condition.h"
#include "networkd-address-label.h"
@ -228,8 +229,8 @@ DHCPv4.UseTimezone, config_parse_bool,
DHCPv4.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
DHCPv4.SendRelease, config_parse_bool, 0, offsetof(Network, dhcp_send_release)
DHCPv4.SendDecline, config_parse_bool, 0, offsetof(Network, dhcp_send_decline)
DHCPv4.DenyList, config_parse_address_filter, AF_INET, offsetof(Network, dhcp_deny_listed_ip)
DHCPv4.AllowList, config_parse_address_filter, AF_INET, offsetof(Network, dhcp_allow_listed_ip)
DHCPv4.DenyList, config_parse_in_addr_prefixes, AF_INET, offsetof(Network, dhcp_deny_listed_ip)
DHCPv4.AllowList, config_parse_in_addr_prefixes, AF_INET, offsetof(Network, dhcp_allow_listed_ip)
DHCPv4.IPServiceType, config_parse_dhcp_ip_service_type, 0, offsetof(Network, dhcp_ip_service_type)
DHCPv4.SendOption, config_parse_dhcp_send_option, AF_INET, offsetof(Network, dhcp_client_send_options)
DHCPv4.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_vendor_options)
@ -262,12 +263,12 @@ IPv6AcceptRA.UseMTU, config_parse_bool,
IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
IPv6AcceptRA.RouteTable, config_parse_dhcp_or_ra_route_table, (RTPROT_RA<<16) | AF_INET6, 0
IPv6AcceptRA.RouteMetric, config_parse_dhcp_or_ra_route_metric, AF_INET6, 0
IPv6AcceptRA.RouterAllowList, config_parse_address_filter, AF_INET6, offsetof(Network, ndisc_allow_listed_router)
IPv6AcceptRA.RouterDenyList, config_parse_address_filter, AF_INET6, offsetof(Network, ndisc_deny_listed_router)
IPv6AcceptRA.PrefixAllowList, config_parse_address_filter, AF_INET6, offsetof(Network, ndisc_allow_listed_prefix)
IPv6AcceptRA.PrefixDenyList, config_parse_address_filter, AF_INET6, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.RouteAllowList, config_parse_address_filter, AF_INET6, offsetof(Network, ndisc_allow_listed_route_prefix)
IPv6AcceptRA.RouteDenyList, config_parse_address_filter, AF_INET6, offsetof(Network, ndisc_deny_listed_route_prefix)
IPv6AcceptRA.RouterAllowList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_allow_listed_router)
IPv6AcceptRA.RouterDenyList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_router)
IPv6AcceptRA.PrefixAllowList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_allow_listed_prefix)
IPv6AcceptRA.PrefixDenyList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.RouteAllowList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_allow_listed_route_prefix)
IPv6AcceptRA.RouteDenyList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_route_prefix)
DHCPServer.ServerAddress, config_parse_dhcp_server_address, 0, 0
DHCPServer.UplinkInterface, config_parse_uplink, 0, 0
DHCPServer.RelayTarget, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_server_relay_target)
@ -500,7 +501,7 @@ IPv6PrefixDelegation.DNS, config_parse_radv_dns,
IPv6PrefixDelegation.EmitDomains, config_parse_bool, 0, offsetof(Network, router_emit_domains)
IPv6PrefixDelegation.Domains, config_parse_radv_search_domains, 0, 0
IPv6PrefixDelegation.DNSLifetimeSec, config_parse_sec, 0, offsetof(Network, router_dns_lifetime_usec)
DHCPv4.BlackList, config_parse_address_filter, AF_INET, offsetof(Network, dhcp_deny_listed_ip)
DHCPv4.BlackList, config_parse_in_addr_prefixes, AF_INET, offsetof(Network, dhcp_deny_listed_ip)
DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
DHCP.UseDNS, config_parse_dhcp_use_dns, AF_UNSPEC, 0
DHCP.UseNTP, config_parse_dhcp_use_ntp, AF_UNSPEC, 0
@ -528,8 +529,8 @@ DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool,
DHCPv4.UseDomainName, config_parse_dhcp_use_domains, AF_INET, 0
DHCPv4.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
DHCPv6.RouteMetric, config_parse_dhcp_or_ra_route_metric, AF_INET6, 0
IPv6AcceptRA.DenyList, config_parse_address_filter, AF_INET6, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.BlackList, config_parse_address_filter, AF_INET6, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.DenyList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.BlackList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_prefix)
TrafficControlQueueingDiscipline.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0
TrafficControlQueueingDiscipline.NetworkEmulatorDelaySec, config_parse_network_emulator_delay, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorDelayJitterSec, config_parse_network_emulator_delay, 0, 0

View File

@ -0,0 +1,325 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "extract-word.h"
#include "hostname-util.h"
#include "in-addr-prefix-util.h"
#include "string-util.h"
/* 0.0.0.0/0 */
#define IN_ADDR_PREFIX_IPV4_ANY ((struct in_addr_prefix) { .family = AF_INET })
/* ::/0 */
#define IN_ADDR_PREFIX_IPV6_ANY ((struct in_addr_prefix) { .family = AF_INET6 })
/* 127.0.0.0/8 */
#define IN_ADDR_PREFIX_IPV4_LOCALHOST \
((struct in_addr_prefix) { \
.family = AF_INET, \
.address.in.s_addr = htobe32(UINT32_C(127) << 24), \
.prefixlen = 8, \
})
/* ::1/128 */
#define IN_ADDR_PREFIX_IPV6_LOCALHOST \
((struct in_addr_prefix) { \
.family = AF_INET6, \
.address.in6 = IN6ADDR_LOOPBACK_INIT, \
.prefixlen = 128, \
})
/* 169.254.0.0/16 */
#define IN_ADDR_PREFIX_IPV4_LINKLOCAL \
((struct in_addr_prefix) { \
.family = AF_INET, \
.address.in.s_addr = htobe32((UINT32_C(169) << 24) | \
(UINT32_C(254) << 16)), \
.prefixlen = 16, \
})
/* fe80::/64 */
#define IN_ADDR_PREFIX_IPV6_LINKLOCAL \
((struct in_addr_prefix) { \
.family = AF_INET6, \
.address.in6.s6_addr[0] = 0xfe, \
.address.in6.s6_addr[1] = 0x80, \
.prefixlen = 64, \
})
/* 224.0.0.0/4 */
#define IN_ADDR_PREFIX_IPV4_MULTICAST \
((struct in_addr_prefix) { \
.family = AF_INET, \
.address.in.s_addr = htobe32((UINT32_C(224) << 24)), \
.prefixlen = 4, \
})
/* ff00::/8 */
#define IN_ADDR_PREFIX_IPV6_MULTICAST \
((struct in_addr_prefix) { \
.family = AF_INET6, \
.address.in6.s6_addr[0] = 0xff, \
.prefixlen = 8, \
})
static void in_addr_prefix_hash_func(const struct in_addr_prefix *a, struct siphash *state) {
assert(a);
assert(state);
siphash24_compress(&a->family, sizeof(a->family), state);
siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
}
static int in_addr_prefix_compare_func(const struct in_addr_prefix *x, const struct in_addr_prefix *y) {
int r;
assert(x);
assert(y);
r = CMP(x->family, y->family);
if (r != 0)
return r;
r = CMP(x->prefixlen, y->prefixlen);
if (r != 0)
return r;
return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
}
DEFINE_HASH_OPS(in_addr_prefix_hash_ops, struct in_addr_prefix, in_addr_prefix_hash_func, in_addr_prefix_compare_func);
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(in_addr_prefix_hash_ops_free, struct in_addr_prefix, in_addr_prefix_hash_func, in_addr_prefix_compare_func, free);
int in_addr_prefix_add(Set **prefixes, const struct in_addr_prefix *prefix) {
struct in_addr_prefix *copy;
assert(prefixes);
assert(prefix);
assert(IN_SET(prefix->family, AF_INET, AF_INET6));
copy = newdup(struct in_addr_prefix, prefix, 1);
if (!copy)
return -ENOMEM;
(void) in_addr_mask(copy->family, &copy->address, copy->prefixlen);
return set_ensure_consume(prefixes, &in_addr_prefix_hash_ops_free, copy);
}
int in_addr_prefixes_reduce(Set *prefixes) {
uint32_t ipv4_prefixlen_bits = 0;
uint64_t ipv6_prefixlen_bits[128 / sizeof(uint64_t)] = {};
uint8_t ipv4_prefixlens[32] = {}, ipv6_prefixlens[128] = {};
bool ipv4_has_any = false, ipv6_has_any = false;
size_t ipv4_n_prefixlens = 0, ipv6_n_prefixlens = 0;
struct in_addr_prefix *p;
SET_FOREACH(p, prefixes)
switch(p->family) {
case AF_INET:
assert(p->prefixlen <= 32);
if (p->prefixlen == 0)
ipv4_has_any = true;
else
ipv4_prefixlen_bits |= UINT32_C(1) << (p->prefixlen - 1);
break;
case AF_INET6:
assert(p->prefixlen <= 128);
if (p->prefixlen == 0)
ipv6_has_any = true;
else
ipv6_prefixlen_bits[(p->prefixlen - 1) / sizeof(uint64_t)] |=
UINT64_C(1) << ((p->prefixlen - 1) % sizeof(uint64_t));
break;
default:
assert_not_reached();
}
if (!ipv4_has_any)
for (size_t i = 0; i < 32; i++)
if (ipv4_prefixlen_bits & (UINT32_C(1) << i))
ipv4_prefixlens[ipv4_n_prefixlens++] = i + 1;
if (!ipv6_has_any)
for (size_t i = 0; i < 128; i++)
if (ipv6_prefixlen_bits[i / sizeof(uint64_t)] &
(UINT64_C(1) << (i % sizeof(uint64_t))))
ipv6_prefixlens[ipv6_n_prefixlens++] = i + 1;
SET_FOREACH(p, prefixes) {
uint8_t *prefixlens;
bool covered;
size_t *n;
if (p->prefixlen == 0)
continue;
switch(p->family) {
case AF_INET:
prefixlens = ipv4_prefixlens;
n = &ipv4_n_prefixlens;
covered = ipv4_has_any;
break;
case AF_INET6:
prefixlens = ipv6_prefixlens;
n = &ipv6_n_prefixlens;
covered = ipv6_has_any;
break;
default:
assert_not_reached();
}
for (size_t i = 0; i < *n; i++) {
struct in_addr_prefix tmp;
if (covered)
break;
if (prefixlens[i] >= p->prefixlen)
break;
tmp = *p;
tmp.prefixlen = prefixlens[i];
(void) in_addr_mask(tmp.family, &tmp.address, tmp.prefixlen);
covered = set_contains(prefixes, &tmp);
}
if (covered)
free(set_remove(prefixes, p));
}
return 0;
}
int in_addr_prefixes_merge(Set **dest, Set *src) {
struct in_addr_prefix *p;
int r;
assert(dest);
SET_FOREACH(p, src) {
r = in_addr_prefix_add(dest, p);
if (r < 0)
return r;
}
return 0;
}
bool in_addr_prefixes_is_any(Set *prefixes) {
return
set_contains(prefixes, &IN_ADDR_PREFIX_IPV4_ANY) &&
set_contains(prefixes, &IN_ADDR_PREFIX_IPV6_ANY);
}
int config_parse_in_addr_prefixes(
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) {
Set **prefixes = data;
int r;
assert(prefixes);
assert(IN_SET(ltype, AF_UNSPEC, AF_INET, AF_INET6));
if (isempty(rvalue)) {
*prefixes = set_free(*prefixes);
return 0;
}
for (const char *p = rvalue;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
return 0;
}
if (r == 0)
return 0;
if (streq(word, "any")) {
/* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
if (ltype != AF_INET6) {
r = in_addr_prefix_add(prefixes, &IN_ADDR_PREFIX_IPV4_ANY);
if (r < 0)
return log_oom();
}
if (ltype != AF_INET) {
r = in_addr_prefix_add(prefixes, &IN_ADDR_PREFIX_IPV6_ANY);
if (r < 0)
return log_oom();
}
} else if (is_localhost(word)) {
/* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
if (ltype != AF_INET6) {
r = in_addr_prefix_add(prefixes, &IN_ADDR_PREFIX_IPV4_LOCALHOST);
if (r < 0)
return log_oom();
}
if (ltype != AF_INET) {
r = in_addr_prefix_add(prefixes, &IN_ADDR_PREFIX_IPV6_LOCALHOST);
if (r < 0)
return log_oom();
}
} else if (streq(word, "link-local")) {
/* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
if (ltype != AF_INET6) {
r = in_addr_prefix_add(prefixes, &IN_ADDR_PREFIX_IPV4_LINKLOCAL);
if (r < 0)
return log_oom();
}
if (ltype != AF_INET) {
r = in_addr_prefix_add(prefixes, &IN_ADDR_PREFIX_IPV6_LINKLOCAL);
if (r < 0)
return log_oom();
}
} else if (streq(word, "multicast")) {
/* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
if (ltype != AF_INET6) {
r = in_addr_prefix_add(prefixes, &IN_ADDR_PREFIX_IPV4_MULTICAST);
if (r < 0)
return log_oom();
}
if (ltype != AF_INET) {
r = in_addr_prefix_add(prefixes, &IN_ADDR_PREFIX_IPV6_MULTICAST);
if (r < 0)
return log_oom();
}
} else {
struct in_addr_prefix a;
if (ltype == AF_UNSPEC)
r = in_addr_prefix_from_string_auto(word, &a.family, &a.address, &a.prefixlen);
else {
a.family = ltype;
r = in_addr_prefix_from_string(word, a.family, &a.address, &a.prefixlen);
}
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Address prefix is invalid, ignoring assignment: %s", word);
continue;
}
r = in_addr_prefix_add(prefixes, &a);
if (r < 0)
return log_oom();
}
}
}

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "conf-parser.h"
#include "in-addr-util.h"
#include "set.h"
struct in_addr_prefix {
int family;
uint8_t prefixlen;
union in_addr_union address;
};
int in_addr_prefix_add(Set **prefixes, const struct in_addr_prefix *prefix);
int in_addr_prefixes_reduce(Set *prefixes);
int in_addr_prefixes_merge(Set **dest, Set *src);
/* Returns true if a set contains the two items necessary for "any" (0.0.0.0/0 and ::/0). */
bool in_addr_prefixes_is_any(Set *prefixes);
extern const struct hash_ops in_addr_prefix_hash_ops;
extern const struct hash_ops in_addr_prefix_hash_ops_free;
CONFIG_PARSER_PROTOTYPE(config_parse_in_addr_prefixes);

View File

@ -151,6 +151,8 @@ shared_sources = files('''
ima-util.h
import-util.c
import-util.h
in-addr-prefix-util.c
in-addr-prefix-util.h
initreq.h
install-file.c
install-file.h

View File

@ -285,6 +285,8 @@ tests += [
[['src/test/test-in-addr-util.c']],
[['src/test/test-in-addr-prefix-util.c']],
[['src/test/test-barrier.c']],
[['src/test/test-tmpfiles.c']],

View File

@ -6,6 +6,7 @@
#include "bpf-firewall.h"
#include "bpf-program.h"
#include "in-addr-prefix-util.h"
#include "load-fragment.h"
#include "manager.h"
#include "memory-util.h"
@ -106,21 +107,39 @@ int main(int argc, char *argv[]) {
cc->ip_accounting = true;
assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressAllow", 0, "10.0.1.0/24", &cc->ip_address_allow, NULL) == 0);
assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressAllow", 0, "127.0.0.2", &cc->ip_address_allow, NULL) == 0);
assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.3", &cc->ip_address_deny, NULL) == 0);
assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "10.0.3.2/24", &cc->ip_address_deny, NULL) == 0);
assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.1/25", &cc->ip_address_deny, NULL) == 0);
assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.4", &cc->ip_address_deny, NULL) == 0);
assert_se(config_parse_in_addr_prefixes(u->id, "filename", 1, "Service", 1, "IPAddressAllow", 0, "10.0.1.0/24", &cc->ip_address_allow, NULL) == 0);
assert_se(config_parse_in_addr_prefixes(u->id, "filename", 1, "Service", 1, "IPAddressAllow", 0, "127.0.0.2", &cc->ip_address_allow, NULL) == 0);
assert_se(config_parse_in_addr_prefixes(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.3", &cc->ip_address_deny, NULL) == 0);
assert_se(config_parse_in_addr_prefixes(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "10.0.3.2/24", &cc->ip_address_deny, NULL) == 0);
assert_se(config_parse_in_addr_prefixes(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.1/25", &cc->ip_address_deny, NULL) == 0);
assert_se(config_parse_in_addr_prefixes(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.4", &cc->ip_address_deny, NULL) == 0);
assert(cc->ip_address_allow);
assert(cc->ip_address_allow->items_next);
assert(!cc->ip_address_allow->items_next->items_next);
assert_se(set_size(cc->ip_address_allow) == 2);
assert_se(set_size(cc->ip_address_deny) == 4);
/* The deny list is defined redundantly, let's ensure it got properly reduced */
assert(cc->ip_address_deny);
assert(cc->ip_address_deny->items_next);
assert(!cc->ip_address_deny->items_next->items_next);
/* The deny list is defined redundantly, let's ensure it will be properly reduced */
assert_se(in_addr_prefixes_reduce(cc->ip_address_allow) >= 0);
assert_se(in_addr_prefixes_reduce(cc->ip_address_deny) >= 0);
assert_se(set_size(cc->ip_address_allow) == 2);
assert_se(set_size(cc->ip_address_deny) == 2);
assert_se(set_contains(cc->ip_address_allow, &(struct in_addr_prefix) {
.family = AF_INET,
.address.in.s_addr = htobe32((UINT32_C(10) << 24) | (UINT32_C(1) << 8)),
.prefixlen = 24 }));
assert_se(set_contains(cc->ip_address_allow, &(struct in_addr_prefix) {
.family = AF_INET,
.address.in.s_addr = htobe32(0x7f000002),
.prefixlen = 32 }));
assert_se(set_contains(cc->ip_address_deny, &(struct in_addr_prefix) {
.family = AF_INET,
.address.in.s_addr = htobe32(0x7f000000),
.prefixlen = 25 }));
assert_se(set_contains(cc->ip_address_deny, &(struct in_addr_prefix) {
.family = AF_INET,
.address.in.s_addr = htobe32((UINT32_C(10) << 24) | (UINT32_C(3) << 8)),
.prefixlen = 24 }));
assert_se(config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", SERVICE_EXEC_START, "/bin/ping -c 1 127.0.0.2 -W 5", SERVICE(u)->exec_command, u) == 0);
assert_se(config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", SERVICE_EXEC_START, "/bin/ping -c 1 127.0.0.3 -W 5", SERVICE(u)->exec_command, u) == 0);

View File

@ -0,0 +1,94 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "in-addr-prefix-util.h"
#include "tests.h"
static void test_config_parse_in_addr_prefixes_one(int family, const union in_addr_union *addr, uint8_t prefixlen, Set **prefixes) {
_cleanup_free_ char *str = NULL;
assert_se(in_addr_prefix_to_string(family, addr, prefixlen, &str) >= 0);
assert_se(config_parse_in_addr_prefixes("unit", "filename", 1, "Service", 1, "IPAddressAllow", 0, str, prefixes, NULL) >= 0);
}
static void test_config_parse_in_addr_prefixes(Set **ret) {
_cleanup_set_free_ Set *prefixes = NULL;
log_info("/* %s() */", __func__);
for (uint32_t i = 0; i < 256; i++) {
/* ipv4 link-local address */
test_config_parse_in_addr_prefixes_one(AF_INET, &(union in_addr_union) {
.in.s_addr = htobe32((UINT32_C(169) << 24) |
(UINT32_C(254) << 16) |
(i << 8)),
}, 24, &prefixes);
/* ipv6 multicast address */
test_config_parse_in_addr_prefixes_one(AF_INET6, &(union in_addr_union) {
.in6.s6_addr[0] = 0xff,
.in6.s6_addr[1] = i,
}, 16, &prefixes);
for (uint32_t j = 0; j < 256; j++) {
test_config_parse_in_addr_prefixes_one(AF_INET, &(union in_addr_union) {
.in.s_addr = htobe32((UINT32_C(169) << 24) |
(UINT32_C(254) << 16) |
(i << 8) | j),
}, 32, &prefixes);
test_config_parse_in_addr_prefixes_one(AF_INET6, &(union in_addr_union) {
.in6.s6_addr[0] = 0xff,
.in6.s6_addr[1] = i,
.in6.s6_addr[2] = j,
}, 24, &prefixes);
}
}
*ret = TAKE_PTR(prefixes);
}
static void test_in_addr_prefixes_reduce(Set *prefixes) {
log_info("/* %s() */", __func__);
assert_se(set_size(prefixes) == 2 * 256 * 257);
assert_se(!in_addr_prefixes_is_any(prefixes));
assert_se(in_addr_prefixes_reduce(prefixes) >= 0);
assert_se(set_size(prefixes) == 2 * 256);
assert_se(!in_addr_prefixes_is_any(prefixes));
assert_se(config_parse_in_addr_prefixes("unit", "filename", 1, "Service", 1, "IPAddressAllow", 0, "link-local", &prefixes, NULL) == 0);
assert_se(set_size(prefixes) == 2 * 256 + 2);
assert_se(!in_addr_prefixes_is_any(prefixes));
assert_se(in_addr_prefixes_reduce(prefixes) >= 0);
assert_se(set_size(prefixes) == 256 + 2);
assert_se(!in_addr_prefixes_is_any(prefixes));
assert_se(config_parse_in_addr_prefixes("unit", "filename", 1, "Service", 1, "IPAddressAllow", 0, "multicast", &prefixes, NULL) == 0);
assert_se(set_size(prefixes) == 256 + 4);
assert_se(!in_addr_prefixes_is_any(prefixes));
assert_se(in_addr_prefixes_reduce(prefixes) >= 0);
assert_se(set_size(prefixes) == 4);
assert_se(!in_addr_prefixes_is_any(prefixes));
assert_se(config_parse_in_addr_prefixes("unit", "filename", 1, "Service", 1, "IPAddressAllow", 0, "any", &prefixes, NULL) == 0);
assert_se(set_size(prefixes) == 6);
assert_se(in_addr_prefixes_is_any(prefixes));
assert_se(in_addr_prefixes_reduce(prefixes) >= 0);
assert_se(set_size(prefixes) == 2);
assert_se(in_addr_prefixes_is_any(prefixes));
}
int main(int argc, char *argv[]) {
_cleanup_set_free_ Set *prefixes = NULL;
test_setup_logging(LOG_DEBUG);
test_config_parse_in_addr_prefixes(&prefixes);
test_in_addr_prefixes_reduce(prefixes);
return 0;
}

View File

@ -3,9 +3,9 @@
#include <fnmatch.h>
#include <netinet/in.h>
#include "log.h"
#include "strv.h"
#include "in-addr-util.h"
#include "strv.h"
#include "tests.h"
static void test_in_addr_prefix_from_string_one(
const char *p,
@ -238,7 +238,7 @@ static void test_in_addr_prefix_intersect(void) {
static void test_in_addr_prefix_next_one(unsigned f, const char *before, unsigned pl, const char *after) {
union in_addr_union ubefore, uafter, t;
log_info("/* %s(%s, prefixlen=%u) */", __func__, before, pl);
log_debug("/* %s(%s, prefixlen=%u) */", __func__, before, pl);
assert_se(in_addr_from_string(f, before, &ubefore) >= 0);
@ -252,6 +252,8 @@ static void test_in_addr_prefix_next_one(unsigned f, const char *before, unsigne
}
static void test_in_addr_prefix_next(void) {
log_info("/* %s */", __func__);
test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 24, "192.168.1.0");
test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 16, "192.169.0.0");
test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 20, "192.168.16.0");
@ -276,7 +278,7 @@ static void test_in_addr_prefix_next(void) {
static void test_in_addr_prefix_nth_one(unsigned f, const char *before, unsigned pl, uint64_t nth, const char *after) {
union in_addr_union ubefore, uafter, t;
log_info("/* %s(%s, prefixlen=%u, nth=%"PRIu64") */", __func__, before, pl, nth);
log_debug("/* %s(%s, prefixlen=%u, nth=%"PRIu64") */", __func__, before, pl, nth);
assert_se(in_addr_from_string(f, before, &ubefore) >= 0);
@ -290,6 +292,8 @@ static void test_in_addr_prefix_nth_one(unsigned f, const char *before, unsigned
}
static void test_in_addr_prefix_nth(void) {
log_info("/* %s */", __func__);
test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 0, "192.168.0.0");
test_in_addr_prefix_nth_one(AF_INET, "192.168.0.123", 24, 0, "192.168.0.0");
test_in_addr_prefix_nth_one(AF_INET, "192.168.0.123", 24, 1, "192.168.1.0");
@ -323,7 +327,7 @@ static void test_in_addr_prefix_range_one(
union in_addr_union a, s, e;
log_info("/* %s(%s, prefixlen=%u) */", __func__, in, prefixlen);
log_debug("/* %s(%s, prefixlen=%u) */", __func__, in, prefixlen);
assert_se(in_addr_from_string(family, in, &a) >= 0);
assert_se((in_addr_prefix_range(family, &a, prefixlen, &s, &e) >= 0) == !!expected_start);
@ -343,6 +347,8 @@ static void test_in_addr_prefix_range_one(
}
static void test_in_addr_prefix_range(void) {
log_info("/* %s */", __func__);
test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 24, "192.168.123.0", "192.168.124.0");
test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 16, "192.168.0.0", "192.169.0.0");
@ -376,6 +382,8 @@ static void test_in_addr_to_string(void) {
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_in_addr_prefix_from_string();
test_in_addr_random_prefix();
test_in_addr_prefix_to_string();