2 This file is part of systemd.
4 Copyright 2016 Daniel Mack
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include "alloc-util.h"
24 #include "bpf-firewall.h"
25 #include "extract-word.h"
26 #include "hostname-util.h"
27 #include "ip-address-access.h"
28 #include "parse-util.h"
29 #include "string-util.h"
31 int config_parse_ip_address_access(
36 unsigned section_line
,
43 IPAddressAccessItem
**list
= data
;
49 if (isempty(rvalue
)) {
50 *list
= ip_address_access_free_all(*list
);
57 _cleanup_free_ IPAddressAccessItem
*a
= NULL
;
58 _cleanup_free_
char *word
= NULL
;
60 r
= extract_first_word(&p
, &word
, NULL
, 0);
66 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
70 a
= new0(IPAddressAccessItem
, 1);
74 if (streq(word
, "any")) {
75 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
78 LIST_APPEND(items
, *list
, a
);
80 a
= new0(IPAddressAccessItem
, 1);
86 } else if (is_localhost(word
)) {
87 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
90 a
->address
.in
.s_addr
= htobe32(0x7f000000);
92 LIST_APPEND(items
, *list
, a
);
94 a
= new0(IPAddressAccessItem
, 1);
99 a
->address
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
102 } else if (streq(word
, "link-local")) {
104 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
107 a
->address
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
109 LIST_APPEND(items
, *list
, a
);
111 a
= new0(IPAddressAccessItem
, 1);
115 a
->family
= AF_INET6
;
116 a
->address
.in6
= (struct in6_addr
) {
117 .__in6_u
.__u6_addr32
[0] = htobe32(0xfe800000)
121 } else if (streq(word
, "multicast")) {
123 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
126 a
->address
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
128 LIST_APPEND(items
, *list
, a
);
130 a
= new0(IPAddressAccessItem
, 1);
134 a
->family
= AF_INET6
;
135 a
->address
.in6
= (struct in6_addr
) {
136 .__in6_u
.__u6_addr32
[0] = htobe32(0xff000000)
141 r
= in_addr_prefix_from_string_auto(word
, &a
->family
, &a
->address
, &a
->prefixlen
);
143 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Address prefix is invalid, ignoring assignment: %s", word
);
148 LIST_APPEND(items
, *list
, a
);
152 *list
= ip_address_access_reduce(*list
);
155 r
= bpf_firewall_supported();
159 log_warning("File %s:%u configures an IP firewall (%s=%s), but the local system does not support BPF/cgroup based firewalling.\n"
160 "Proceeding WITHOUT firewalling in effect!", filename
, line
, lvalue
, rvalue
);
166 IPAddressAccessItem
* ip_address_access_free_all(IPAddressAccessItem
*first
) {
167 IPAddressAccessItem
*next
, *p
= first
;
170 next
= p
->items_next
;
179 IPAddressAccessItem
* ip_address_access_reduce(IPAddressAccessItem
*first
) {
180 IPAddressAccessItem
*a
, *b
, *tmp
;
183 /* Drops all entries from the list that are covered by another entry in full, thus removing all redundant
186 LIST_FOREACH_SAFE(items
, a
, tmp
, first
) {
188 /* Drop irrelevant bits */
189 (void) in_addr_mask(a
->family
, &a
->address
, a
->prefixlen
);
191 LIST_FOREACH(items
, b
, first
) {
196 if (a
->family
!= b
->family
)
199 if (b
->prefixlen
> a
->prefixlen
)
202 r
= in_addr_prefix_covers(b
->family
,
209 /* b covers a fully, then let's drop a */
211 LIST_REMOVE(items
, first
, a
);