]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/ip-address-access.c
tree-wide: drop copyright headers from frequent contributors
[thirdparty/systemd.git] / src / core / ip-address-access.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b36672e0
DM
2
3#include <stdio.h>
4#include <stdlib.h>
5
6#include "alloc-util.h"
078ba556 7#include "bpf-firewall.h"
b36672e0
DM
8#include "extract-word.h"
9#include "hostname-util.h"
10#include "ip-address-access.h"
11#include "parse-util.h"
12#include "string-util.h"
13
14int config_parse_ip_address_access(
15 const char *unit,
16 const char *filename,
17 unsigned line,
18 const char *section,
19 unsigned section_line,
20 const char *lvalue,
21 int ltype,
22 const char *rvalue,
23 void *data,
24 void *userdata) {
25
26 IPAddressAccessItem **list = data;
27 const char *p;
28 int r;
29
30 assert(list);
31
32 if (isempty(rvalue)) {
33 *list = ip_address_access_free_all(*list);
34 return 0;
35 }
36
37 p = rvalue;
38
39 for (;;) {
40 _cleanup_free_ IPAddressAccessItem *a = NULL;
41 _cleanup_free_ char *word = NULL;
42
43 r = extract_first_word(&p, &word, NULL, 0);
44 if (r == 0)
45 break;
46 if (r == -ENOMEM)
47 return log_oom();
48 if (r < 0) {
49 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
50 break;
51 }
52
53 a = new0(IPAddressAccessItem, 1);
54 if (!a)
55 return log_oom();
56
57 if (streq(word, "any")) {
58 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
59
60 a->family = AF_INET;
61 LIST_APPEND(items, *list, a);
62
63 a = new0(IPAddressAccessItem, 1);
64 if (!a)
65 return log_oom();
66
67 a->family = AF_INET6;
68
69 } else if (is_localhost(word)) {
70 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
71
72 a->family = AF_INET;
73 a->address.in.s_addr = htobe32(0x7f000000);
74 a->prefixlen = 8;
75 LIST_APPEND(items, *list, a);
76
77 a = new0(IPAddressAccessItem, 1);
78 if (!a)
79 return log_oom();
80
81 a->family = AF_INET6;
82 a->address.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
83 a->prefixlen = 128;
84
85 } else if (streq(word, "link-local")) {
86
87 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
88
89 a->family = AF_INET;
90 a->address.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
91 a->prefixlen = 16;
92 LIST_APPEND(items, *list, a);
93
94 a = new0(IPAddressAccessItem, 1);
95 if (!a)
96 return log_oom();
97
98 a->family = AF_INET6;
99 a->address.in6 = (struct in6_addr) {
5a10b4d6 100 .s6_addr32[0] = htobe32(0xfe800000)
b36672e0
DM
101 };
102 a->prefixlen = 64;
103
104 } else if (streq(word, "multicast")) {
105
106 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
107
108 a->family = AF_INET;
109 a->address.in.s_addr = htobe32((UINT32_C(224) << 24));
110 a->prefixlen = 4;
111 LIST_APPEND(items, *list, a);
112
113 a = new0(IPAddressAccessItem, 1);
114 if (!a)
115 return log_oom();
116
117 a->family = AF_INET6;
118 a->address.in6 = (struct in6_addr) {
5a10b4d6 119 .s6_addr32[0] = htobe32(0xff000000)
b36672e0
DM
120 };
121 a->prefixlen = 8;
122
123 } else {
124 r = in_addr_prefix_from_string_auto(word, &a->family, &a->address, &a->prefixlen);
125 if (r < 0) {
126 log_syntax(unit, LOG_WARNING, filename, line, r, "Address prefix is invalid, ignoring assignment: %s", word);
127 return 0;
128 }
129 }
130
131 LIST_APPEND(items, *list, a);
132 a = NULL;
133 }
134
1274b6c6
LP
135 *list = ip_address_access_reduce(*list);
136
078ba556
LP
137 if (*list) {
138 r = bpf_firewall_supported();
139 if (r < 0)
140 return r;
2ae7ee58 141 if (r == BPF_FIREWALL_UNSUPPORTED) {
ab8519c2
LP
142 static bool warned = false;
143
144 log_full(warned ? LOG_DEBUG : LOG_WARNING,
145 "File %s:%u configures an IP firewall (%s=%s), but the local system does not support BPF/cgroup based firewalling.\n"
146 "Proceeding WITHOUT firewalling in effect! (This warning is only shown for the first loaded unit using IP firewalling.)", filename, line, lvalue, rvalue);
147
148 warned = true;
149 }
078ba556
LP
150 }
151
b36672e0
DM
152 return 0;
153}
154
155IPAddressAccessItem* ip_address_access_free_all(IPAddressAccessItem *first) {
156 IPAddressAccessItem *next, *p = first;
157
158 while (p) {
159 next = p->items_next;
160 free(p);
161
162 p = next;
163 }
164
165 return NULL;
166}
1274b6c6
LP
167
168IPAddressAccessItem* ip_address_access_reduce(IPAddressAccessItem *first) {
169 IPAddressAccessItem *a, *b, *tmp;
170 int r;
171
172 /* Drops all entries from the list that are covered by another entry in full, thus removing all redundant
173 * entries. */
174
175 LIST_FOREACH_SAFE(items, a, tmp, first) {
176
177 /* Drop irrelevant bits */
178 (void) in_addr_mask(a->family, &a->address, a->prefixlen);
179
180 LIST_FOREACH(items, b, first) {
181
182 if (a == b)
183 continue;
184
185 if (a->family != b->family)
186 continue;
187
188 if (b->prefixlen > a->prefixlen)
189 continue;
190
191 r = in_addr_prefix_covers(b->family,
192 &b->address,
193 b->prefixlen,
194 &a->address);
8ed7742a
LP
195 if (r > 0) {
196 /* b covers a fully, then let's drop a */
197 LIST_REMOVE(items, first, a);
198 free(a);
199 break;
200 }
1274b6c6
LP
201 }
202 }
203
204 return first;
205}