X Tutup
Skip to content

Commit c995fa0

Browse files
committed
network: dhcp4,ndisc: make addresses in Allow/DenyList= optionally take prefix length
Closes systemd#20505.
1 parent f95d1ef commit c995fa0

File tree

9 files changed

+172
-217
lines changed

9 files changed

+172
-217
lines changed

man/systemd.network.xml

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,7 +1965,8 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
19651965
<varlistentry>
19661966
<term><varname>DenyList=</varname></term>
19671967
<listitem>
1968-
<para>A whitespace-separated list of IPv4 addresses. DHCP offers from servers in the list are
1968+
<para>A whitespace-separated list of IPv4 addresses. Each address can optionally take a
1969+
prefix length after <literal>/</literal>. DHCP offers from servers in the list are
19691970
rejected. Note that if <varname>AllowList=</varname> is configured then
19701971
<varname>DenyList=</varname> is ignored.</para>
19711972
</listitem>
@@ -1974,7 +1975,8 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
19741975
<varlistentry>
19751976
<term><varname>AllowList=</varname></term>
19761977
<listitem>
1977-
<para>A whitespace-separated list of IPv4 addresses. DHCP offers from servers in the list are
1978+
<para>A whitespace-separated list of IPv4 addresses. Each address can optionally take a
1979+
prefix length after <literal>/</literal>. DHCP offers from servers in the list are
19781980
accepted.</para>
19791981
</listitem>
19801982
</varlistentry>
@@ -2292,50 +2294,56 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
22922294
<varlistentry>
22932295
<term><varname>RouterDenyList=</varname></term>
22942296
<listitem>
2295-
<para>A whitespace-separated list of IPv6 router addresses. Any information advertised by
2296-
the listed router is ignored.</para>
2297+
<para>A whitespace-separated list of IPv6 router addresses. Each address can optionally
2298+
take a prefix length after <literal>/</literal>. Any information advertised by the listed
2299+
router is ignored.</para>
22972300
</listitem>
22982301
</varlistentry>
22992302

23002303
<varlistentry>
23012304
<term><varname>RouterAllowList=</varname></term>
23022305
<listitem>
2303-
<para>A whitespace-separated list of IPv6 router addresses. Only information advertised by
2304-
the listed router is accepted. Note that if <varname>RouterAllowList=</varname> is
2305-
configured then <varname>RouterDenyList=</varname> is ignored.</para>
2306+
<para>A whitespace-separated list of IPv6 router addresses. Each address can optionally
2307+
take a prefix length after <literal>/</literal>. Only information advertised by the listed
2308+
router is accepted. Note that if <varname>RouterAllowList=</varname> is configured then
2309+
<varname>RouterDenyList=</varname> is ignored.</para>
23062310
</listitem>
23072311
</varlistentry>
23082312

23092313
<varlistentry>
23102314
<term><varname>PrefixDenyList=</varname></term>
23112315
<listitem>
2312-
<para>A whitespace-separated list of IPv6 prefixes. IPv6 prefixes supplied via router
2313-
advertisements in the list are ignored.</para>
2316+
<para>A whitespace-separated list of IPv6 prefixes. Each prefix can optionally take its
2317+
prefix length after <literal>/</literal>. IPv6 prefixes supplied via router advertisements
2318+
in the list are ignored.</para>
23142319
</listitem>
23152320
</varlistentry>
23162321

23172322
<varlistentry>
23182323
<term><varname>PrefixAllowList=</varname></term>
23192324
<listitem>
2320-
<para>A whitespace-separated list of IPv6 prefixes. IPv6 prefixes supplied via router
2321-
advertisements in the list are allowed. Note that if <varname>PrefixAllowList=</varname> is
2322-
configured then <varname>PrefixDenyList=</varname> is ignored.</para>
2325+
<para>A whitespace-separated list of IPv6 prefixes. Each prefix can optionally take its
2326+
prefix length after <literal>/</literal>. IPv6 prefixes supplied via router advertisements
2327+
in the list are allowed. Note that if <varname>PrefixAllowList=</varname> is configured
2328+
then <varname>PrefixDenyList=</varname> is ignored.</para>
23232329
</listitem>
23242330
</varlistentry>
23252331

23262332
<varlistentry>
23272333
<term><varname>RouteDenyList=</varname></term>
23282334
<listitem>
2329-
<para>A whitespace-separated list of IPv6 route prefixes. IPv6 route prefixes supplied via
2330-
router advertisements in the list are ignored.</para>
2335+
<para>A whitespace-separated list of IPv6 route prefixes. Each prefix can optionally take
2336+
its prefix length after <literal>/</literal>. IPv6 route prefixes supplied via router
2337+
advertisements in the list are ignored.</para>
23312338
</listitem>
23322339
</varlistentry>
23332340

23342341
<varlistentry>
23352342
<term><varname>RouteAllowList=</varname></term>
23362343
<listitem>
2337-
<para>A whitespace-separated list of IPv6 route prefixes. IPv6 route prefixes supplied via
2338-
router advertisements in the list are allowed. Note that if <varname>RouteAllowList=</varname> is
2344+
<para>A whitespace-separated list of IPv6 route prefixes. Each prefix can optionally take
2345+
its prefix length after <literal>/</literal>. IPv6 route prefixes supplied via router
2346+
advertisements in the list are allowed. Note that if <varname>RouteAllowList=</varname> is
23392347
configured then <varname>RouteDenyList=</varname> is ignored.</para>
23402348
</listitem>
23412349
</varlistentry>

src/network/networkd-dhcp-common.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,30 @@ int dhcp_configure_duid(Link *link, const DUID *duid) {
203203
return 0;
204204
}
205205

206+
bool address_is_filtered(int family, const union in_addr_union *address, uint8_t prefixlen, Set *allow_list, Set *deny_list) {
207+
struct in_addr_prefix *p;
208+
209+
assert(IN_SET(family, AF_INET, AF_INET6));
210+
assert(address);
211+
212+
if (allow_list) {
213+
SET_FOREACH(p, allow_list)
214+
if (p->family == family &&
215+
p->prefixlen <= prefixlen &&
216+
in_addr_prefix_covers(family, &p->address, p->prefixlen, address) > 0)
217+
return false;
218+
219+
return true;
220+
}
221+
222+
SET_FOREACH(p, deny_list)
223+
if (p->family == family &&
224+
in_addr_prefix_intersect(family, &p->address, p->prefixlen, address, prefixlen) > 0)
225+
return true;
226+
227+
return false;
228+
}
229+
206230
int config_parse_dhcp(
207231
const char* unit,
208232
const char *filename,
@@ -1144,3 +1168,69 @@ int config_parse_network_duid_rawdata(
11441168
/* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
11451169
return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
11461170
}
1171+
1172+
int config_parse_address_filter(
1173+
const char *unit,
1174+
const char *filename,
1175+
unsigned line,
1176+
const char *section,
1177+
unsigned section_line,
1178+
const char *lvalue,
1179+
int ltype,
1180+
const char *rvalue,
1181+
void *data,
1182+
void *userdata) {
1183+
1184+
Set **list = data;
1185+
int r;
1186+
1187+
assert(filename);
1188+
assert(lvalue);
1189+
assert(IN_SET(ltype, AF_INET, AF_INET6));
1190+
assert(rvalue);
1191+
assert(data);
1192+
1193+
if (isempty(rvalue)) {
1194+
*list = set_free(*list);
1195+
return 0;
1196+
}
1197+
1198+
for (const char *p = rvalue;;) {
1199+
_cleanup_free_ char *n = NULL;
1200+
_cleanup_free_ struct in_addr_prefix *a = NULL;
1201+
struct in_addr_prefix prefix;
1202+
1203+
r = extract_first_word(&p, &n, NULL, 0);
1204+
if (r == -ENOMEM)
1205+
return log_oom();
1206+
if (r < 0) {
1207+
log_syntax(unit, LOG_WARNING, filename, line, r,
1208+
"Failed to parse NDisc %s=, ignoring assignment: %s",
1209+
lvalue, rvalue);
1210+
return 0;
1211+
}
1212+
if (r == 0)
1213+
return 0;
1214+
1215+
r = in_addr_prefix_from_string(n, ltype, &prefix.address, &prefix.prefixlen);
1216+
if (r < 0) {
1217+
log_syntax(unit, LOG_WARNING, filename, line, r,
1218+
"NDisc %s= entry is invalid, ignoring assignment: %s",
1219+
lvalue, n);
1220+
continue;
1221+
}
1222+
1223+
prefix.family = ltype;
1224+
a = newdup(struct in_addr_prefix, &prefix, 1);
1225+
if (!a)
1226+
return log_oom();
1227+
1228+
r = set_ensure_consume(list, &in_addr_prefix_hash_ops_free, TAKE_PTR(a));
1229+
if (r < 0)
1230+
return log_oom();
1231+
if (r == 0)
1232+
log_syntax(unit, LOG_WARNING, filename, line, 0,
1233+
"%s %s= entry is duplicated, ignoring assignment: %s",
1234+
section, lvalue, n);
1235+
}
1236+
}

src/network/networkd-dhcp-common.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
#include "conf-parser.h"
77
#include "dhcp-identifier.h"
8+
#include "in-addr-util.h"
9+
#include "set.h"
810
#include "time-util.h"
911

1012
#define DHCP_ROUTE_METRIC 1024
@@ -63,6 +65,14 @@ static inline const DUID *link_get_dhcp6_duid(Link *link) {
6365
int dhcp_configure_duid(Link *link, const DUID *duid);
6466
int manager_request_product_uuid(Manager *m);
6567

68+
bool address_is_filtered(int family, const union in_addr_union *address, uint8_t prefixlen, Set *allow_list, Set *deny_list);
69+
static inline bool in4_address_is_filtered(const struct in_addr *address, Set *allow_list, Set *deny_list) {
70+
return address_is_filtered(AF_INET, &(union in_addr_union) { .in = *address }, 32, allow_list, deny_list);
71+
}
72+
static inline bool in6_prefix_is_filtered(const struct in6_addr *prefix, uint8_t prefixlen, Set *allow_list, Set *deny_list) {
73+
return address_is_filtered(AF_INET6, &(union in_addr_union) { .in6 = *prefix }, prefixlen, allow_list, deny_list);
74+
}
75+
6676
const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_;
6777
DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_;
6878

@@ -85,3 +95,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_network_duid_type);
8595
CONFIG_PARSER_PROTOTYPE(config_parse_duid_rawdata);
8696
CONFIG_PARSER_PROTOTYPE(config_parse_manager_duid_rawdata);
8797
CONFIG_PARSER_PROTOTYPE(config_parse_network_duid_rawdata);
98+
CONFIG_PARSER_PROTOTYPE(config_parse_address_filter);

src/network/networkd-dhcp4.c

Lines changed: 16 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,7 @@ static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) {
11251125
return r;
11261126
}
11271127

1128-
static int dhcp_server_is_deny_listed(Link *link, sd_dhcp_client *client) {
1128+
static int dhcp_server_is_filtered(Link *link, sd_dhcp_client *client) {
11291129
sd_dhcp_lease *lease;
11301130
struct in_addr addr;
11311131
int r;
@@ -1142,39 +1142,16 @@ static int dhcp_server_is_deny_listed(Link *link, sd_dhcp_client *client) {
11421142
if (r < 0)
11431143
return log_link_debug_errno(link, r, "Failed to get DHCP server IP address: %m");
11441144

1145-
if (set_contains(link->network->dhcp_deny_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
1146-
log_struct(LOG_DEBUG,
1147-
LOG_LINK_INTERFACE(link),
1148-
LOG_LINK_MESSAGE(link, "DHCPv4 server IP address "IPV4_ADDRESS_FMT_STR" found in deny-list, ignoring offer",
1149-
IPV4_ADDRESS_FMT_VAL(addr)));
1150-
return true;
1151-
}
1152-
1153-
return false;
1154-
}
1155-
1156-
static int dhcp_server_is_allow_listed(Link *link, sd_dhcp_client *client) {
1157-
sd_dhcp_lease *lease;
1158-
struct in_addr addr;
1159-
int r;
1160-
1161-
assert(link);
1162-
assert(link->network);
1163-
assert(client);
1164-
1165-
r = sd_dhcp_client_get_lease(client, &lease);
1166-
if (r < 0)
1167-
return log_link_error_errno(link, r, "Failed to get DHCP lease: %m");
1168-
1169-
r = sd_dhcp_lease_get_server_identifier(lease, &addr);
1170-
if (r < 0)
1171-
return log_link_debug_errno(link, r, "Failed to get DHCP server IP address: %m");
1145+
if (in4_address_is_filtered(&addr, link->network->dhcp_allow_listed_ip, link->network->dhcp_deny_listed_ip)) {
1146+
if (DEBUG_LOGGING) {
1147+
if (link->network->dhcp_allow_listed_ip)
1148+
log_link_debug(link, "DHCPv4 server IP address "IPV4_ADDRESS_FMT_STR" not found in allow-list, ignoring offer.",
1149+
IPV4_ADDRESS_FMT_VAL(addr));
1150+
else
1151+
log_link_debug(link, "DHCPv4 server IP address "IPV4_ADDRESS_FMT_STR" found in deny-list, ignoring offer.",
1152+
IPV4_ADDRESS_FMT_VAL(addr));
1153+
}
11721154

1173-
if (set_contains(link->network->dhcp_allow_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
1174-
log_struct(LOG_DEBUG,
1175-
LOG_LINK_INTERFACE(link),
1176-
LOG_LINK_MESSAGE(link, "DHCPv4 server IP address "IPV4_ADDRESS_FMT_STR" found in allow-list, accepting offer",
1177-
IPV4_ADDRESS_FMT_VAL(addr)));
11781155
return true;
11791156
}
11801157

@@ -1267,19 +1244,13 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
12671244
}
12681245
break;
12691246
case SD_DHCP_CLIENT_EVENT_SELECTING:
1270-
if (!set_isempty(link->network->dhcp_allow_listed_ip)) {
1271-
r = dhcp_server_is_allow_listed(link, client);
1272-
if (r < 0)
1273-
return r;
1274-
if (r == 0)
1275-
return -ENOMSG;
1276-
} else {
1277-
r = dhcp_server_is_deny_listed(link, client);
1278-
if (r < 0)
1279-
return r;
1280-
if (r != 0)
1281-
return -ENOMSG;
1247+
r = dhcp_server_is_filtered(link, client);
1248+
if (r < 0) {
1249+
link_enter_failed(link);
1250+
return r;
12821251
}
1252+
if (r > 0)
1253+
return -ENOMSG;
12831254
break;
12841255

12851256
case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE:
@@ -1759,64 +1730,6 @@ int config_parse_dhcp_max_attempts(
17591730
return 0;
17601731
}
17611732

1762-
int config_parse_dhcp_acl_ip_address(
1763-
const char *unit,
1764-
const char *filename,
1765-
unsigned line,
1766-
const char *section,
1767-
unsigned section_line,
1768-
const char *lvalue,
1769-
int ltype,
1770-
const char *rvalue,
1771-
void *data,
1772-
void *userdata) {
1773-
1774-
Network *network = data;
1775-
Set **acl;
1776-
int r;
1777-
1778-
assert(filename);
1779-
assert(lvalue);
1780-
assert(rvalue);
1781-
assert(data);
1782-
1783-
acl = STR_IN_SET(lvalue, "DenyList", "BlackList") ? &network->dhcp_deny_listed_ip : &network->dhcp_allow_listed_ip;
1784-
1785-
if (isempty(rvalue)) {
1786-
*acl = set_free(*acl);
1787-
return 0;
1788-
}
1789-
1790-
for (const char *p = rvalue;;) {
1791-
_cleanup_free_ char *n = NULL;
1792-
union in_addr_union ip;
1793-
1794-
r = extract_first_word(&p, &n, NULL, 0);
1795-
if (r == -ENOMEM)
1796-
return log_oom();
1797-
if (r < 0) {
1798-
log_syntax(unit, LOG_WARNING, filename, line, r,
1799-
"Failed to parse DHCP '%s=' IP address, ignoring assignment: %s",
1800-
lvalue, rvalue);
1801-
return 0;
1802-
}
1803-
if (r == 0)
1804-
return 0;
1805-
1806-
r = in_addr_from_string(AF_INET, n, &ip);
1807-
if (r < 0) {
1808-
log_syntax(unit, LOG_WARNING, filename, line, r,
1809-
"DHCP '%s=' IP address is invalid, ignoring assignment: %s", lvalue, n);
1810-
continue;
1811-
}
1812-
1813-
r = set_ensure_put(acl, NULL, UINT32_TO_PTR(ip.in.s_addr));
1814-
if (r < 0)
1815-
log_syntax(unit, LOG_WARNING, filename, line, r,
1816-
"Failed to store DHCP '%s=' IP address '%s', ignoring assignment: %m", lvalue, n);
1817-
}
1818-
}
1819-
18201733
int config_parse_dhcp_ip_service_type(
18211734
const char *unit,
18221735
const char *filename,

src/network/networkd-dhcp4.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ int request_process_dhcp4_client(Request *req);
2828
int link_request_dhcp4_client(Link *link);
2929

3030
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
31-
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address);
3231
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
3332
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_ip_service_type);
3433
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_mud_url);

0 commit comments

Comments
 (0)
X Tutup