]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/ip-address-access.c
Merge pull request #6902 from keszybz/two-property-printing-fixes
[thirdparty/systemd.git] / src / core / ip-address-access.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2016 Daniel Mack
5
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.
10
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.
15
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/>.
18 ***/
19
20 #include <stdio.h>
21 #include <stdlib.h>
22
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"
30
31 int config_parse_ip_address_access(
32 const char *unit,
33 const char *filename,
34 unsigned line,
35 const char *section,
36 unsigned section_line,
37 const char *lvalue,
38 int ltype,
39 const char *rvalue,
40 void *data,
41 void *userdata) {
42
43 IPAddressAccessItem **list = data;
44 const char *p;
45 int r;
46
47 assert(list);
48
49 if (isempty(rvalue)) {
50 *list = ip_address_access_free_all(*list);
51 return 0;
52 }
53
54 p = rvalue;
55
56 for (;;) {
57 _cleanup_free_ IPAddressAccessItem *a = NULL;
58 _cleanup_free_ char *word = NULL;
59
60 r = extract_first_word(&p, &word, NULL, 0);
61 if (r == 0)
62 break;
63 if (r == -ENOMEM)
64 return log_oom();
65 if (r < 0) {
66 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
67 break;
68 }
69
70 a = new0(IPAddressAccessItem, 1);
71 if (!a)
72 return log_oom();
73
74 if (streq(word, "any")) {
75 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
76
77 a->family = AF_INET;
78 LIST_APPEND(items, *list, a);
79
80 a = new0(IPAddressAccessItem, 1);
81 if (!a)
82 return log_oom();
83
84 a->family = AF_INET6;
85
86 } else if (is_localhost(word)) {
87 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
88
89 a->family = AF_INET;
90 a->address.in.s_addr = htobe32(0x7f000000);
91 a->prefixlen = 8;
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) IN6ADDR_LOOPBACK_INIT;
100 a->prefixlen = 128;
101
102 } else if (streq(word, "link-local")) {
103
104 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
105
106 a->family = AF_INET;
107 a->address.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
108 a->prefixlen = 16;
109 LIST_APPEND(items, *list, a);
110
111 a = new0(IPAddressAccessItem, 1);
112 if (!a)
113 return log_oom();
114
115 a->family = AF_INET6;
116 a->address.in6 = (struct in6_addr) {
117 .__in6_u.__u6_addr32[0] = htobe32(0xfe800000)
118 };
119 a->prefixlen = 64;
120
121 } else if (streq(word, "multicast")) {
122
123 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
124
125 a->family = AF_INET;
126 a->address.in.s_addr = htobe32((UINT32_C(224) << 24));
127 a->prefixlen = 4;
128 LIST_APPEND(items, *list, a);
129
130 a = new0(IPAddressAccessItem, 1);
131 if (!a)
132 return log_oom();
133
134 a->family = AF_INET6;
135 a->address.in6 = (struct in6_addr) {
136 .__in6_u.__u6_addr32[0] = htobe32(0xff000000)
137 };
138 a->prefixlen = 8;
139
140 } else {
141 r = in_addr_prefix_from_string_auto(word, &a->family, &a->address, &a->prefixlen);
142 if (r < 0) {
143 log_syntax(unit, LOG_WARNING, filename, line, r, "Address prefix is invalid, ignoring assignment: %s", word);
144 return 0;
145 }
146 }
147
148 LIST_APPEND(items, *list, a);
149 a = NULL;
150 }
151
152 *list = ip_address_access_reduce(*list);
153
154 if (*list) {
155 r = bpf_firewall_supported();
156 if (r < 0)
157 return r;
158 if (r == 0)
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);
161 }
162
163 return 0;
164 }
165
166 IPAddressAccessItem* ip_address_access_free_all(IPAddressAccessItem *first) {
167 IPAddressAccessItem *next, *p = first;
168
169 while (p) {
170 next = p->items_next;
171 free(p);
172
173 p = next;
174 }
175
176 return NULL;
177 }
178
179 IPAddressAccessItem* ip_address_access_reduce(IPAddressAccessItem *first) {
180 IPAddressAccessItem *a, *b, *tmp;
181 int r;
182
183 /* Drops all entries from the list that are covered by another entry in full, thus removing all redundant
184 * entries. */
185
186 LIST_FOREACH_SAFE(items, a, tmp, first) {
187
188 /* Drop irrelevant bits */
189 (void) in_addr_mask(a->family, &a->address, a->prefixlen);
190
191 LIST_FOREACH(items, b, first) {
192
193 if (a == b)
194 continue;
195
196 if (a->family != b->family)
197 continue;
198
199 if (b->prefixlen > a->prefixlen)
200 continue;
201
202 r = in_addr_prefix_covers(b->family,
203 &b->address,
204 b->prefixlen,
205 &a->address);
206 if (r <= 0)
207 continue;
208
209 /* b covers a fully, then let's drop a */
210
211 LIST_REMOVE(items, first, a);
212 free(a);
213 }
214 }
215
216 return first;
217 }