]>
Commit | Line | Data |
---|---|---|
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 | ||
14 | int 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 | ||
155 | IPAddressAccessItem* 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 | |
168 | IPAddressAccessItem* 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 | } |