Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <stdio.h>
4 : : #include <stdlib.h>
5 : :
6 : : #include "alloc-util.h"
7 : : #include "bpf-firewall.h"
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 : 0 : 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 : 0 : IPAddressAccessItem **list = data;
27 : : const char *p;
28 : : int r;
29 : :
30 [ # # ]: 0 : assert(list);
31 : :
32 [ # # ]: 0 : if (isempty(rvalue)) {
33 : 0 : *list = ip_address_access_free_all(*list);
34 : 0 : return 0;
35 : : }
36 : :
37 : 0 : p = rvalue;
38 : :
39 : 0 : for (;;) {
40 [ # # # ]: 0 : _cleanup_free_ IPAddressAccessItem *a = NULL;
41 [ # # # ]: 0 : _cleanup_free_ char *word = NULL;
42 : :
43 : 0 : r = extract_first_word(&p, &word, NULL, 0);
44 [ # # ]: 0 : if (r == 0)
45 : 0 : break;
46 [ # # ]: 0 : if (r == -ENOMEM)
47 : 0 : return log_oom();
48 [ # # ]: 0 : if (r < 0) {
49 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
50 : 0 : break;
51 : : }
52 : :
53 : 0 : a = new0(IPAddressAccessItem, 1);
54 [ # # ]: 0 : if (!a)
55 : 0 : return log_oom();
56 : :
57 [ # # ]: 0 : if (streq(word, "any")) {
58 : : /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
59 : :
60 : 0 : a->family = AF_INET;
61 [ # # # # : 0 : LIST_APPEND(items, *list, a);
# # # # #
# # # ]
62 : :
63 : 0 : a = new0(IPAddressAccessItem, 1);
64 [ # # ]: 0 : if (!a)
65 : 0 : return log_oom();
66 : :
67 : 0 : a->family = AF_INET6;
68 : :
69 [ # # ]: 0 : } else if (is_localhost(word)) {
70 : : /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
71 : :
72 : 0 : a->family = AF_INET;
73 : 0 : a->address.in.s_addr = htobe32(0x7f000000);
74 : 0 : a->prefixlen = 8;
75 [ # # # # : 0 : LIST_APPEND(items, *list, a);
# # # # #
# # # ]
76 : :
77 : 0 : a = new0(IPAddressAccessItem, 1);
78 [ # # ]: 0 : if (!a)
79 : 0 : return log_oom();
80 : :
81 : 0 : a->family = AF_INET6;
82 : 0 : a->address.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
83 : 0 : a->prefixlen = 128;
84 : :
85 [ # # ]: 0 : } else if (streq(word, "link-local")) {
86 : :
87 : : /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
88 : :
89 : 0 : a->family = AF_INET;
90 : 0 : a->address.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
91 : 0 : a->prefixlen = 16;
92 [ # # # # : 0 : LIST_APPEND(items, *list, a);
# # # # #
# # # ]
93 : :
94 : 0 : a = new0(IPAddressAccessItem, 1);
95 [ # # ]: 0 : if (!a)
96 : 0 : return log_oom();
97 : :
98 : 0 : a->family = AF_INET6;
99 : 0 : a->address.in6 = (struct in6_addr) {
100 : 0 : .s6_addr32[0] = htobe32(0xfe800000)
101 : : };
102 : 0 : a->prefixlen = 64;
103 : :
104 [ # # ]: 0 : } else if (streq(word, "multicast")) {
105 : :
106 : : /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
107 : :
108 : 0 : a->family = AF_INET;
109 : 0 : a->address.in.s_addr = htobe32((UINT32_C(224) << 24));
110 : 0 : a->prefixlen = 4;
111 [ # # # # : 0 : LIST_APPEND(items, *list, a);
# # # # #
# # # ]
112 : :
113 : 0 : a = new0(IPAddressAccessItem, 1);
114 [ # # ]: 0 : if (!a)
115 : 0 : return log_oom();
116 : :
117 : 0 : a->family = AF_INET6;
118 : 0 : a->address.in6 = (struct in6_addr) {
119 : 0 : .s6_addr32[0] = htobe32(0xff000000)
120 : : };
121 : 0 : a->prefixlen = 8;
122 : :
123 : : } else {
124 : 0 : r = in_addr_prefix_from_string_auto(word, &a->family, &a->address, &a->prefixlen);
125 [ # # ]: 0 : if (r < 0) {
126 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r, "Address prefix is invalid, ignoring assignment: %s", word);
127 : 0 : return 0;
128 : : }
129 : : }
130 : :
131 [ # # # # : 0 : LIST_APPEND(items, *list, a);
# # # # #
# # # ]
132 : 0 : a = NULL;
133 : : }
134 : :
135 : 0 : *list = ip_address_access_reduce(*list);
136 : :
137 : 0 : return 0;
138 : : }
139 : :
140 : 4712 : IPAddressAccessItem* ip_address_access_free_all(IPAddressAccessItem *first) {
141 : 4712 : IPAddressAccessItem *next, *p = first;
142 : :
143 [ - + ]: 4712 : while (p) {
144 : 0 : next = p->items_next;
145 : 0 : free(p);
146 : :
147 : 0 : p = next;
148 : : }
149 : :
150 : 4712 : return NULL;
151 : : }
152 : :
153 : 0 : IPAddressAccessItem* ip_address_access_reduce(IPAddressAccessItem *first) {
154 : : IPAddressAccessItem *a, *b, *tmp;
155 : : int r;
156 : :
157 : : /* Drops all entries from the list that are covered by another entry in full, thus removing all redundant
158 : : * entries. */
159 : :
160 [ # # ]: 0 : LIST_FOREACH_SAFE(items, a, tmp, first) {
161 : :
162 : : /* Drop irrelevant bits */
163 : 0 : (void) in_addr_mask(a->family, &a->address, a->prefixlen);
164 : :
165 [ # # ]: 0 : LIST_FOREACH(items, b, first) {
166 : :
167 [ # # ]: 0 : if (a == b)
168 : 0 : continue;
169 : :
170 [ # # ]: 0 : if (a->family != b->family)
171 : 0 : continue;
172 : :
173 [ # # ]: 0 : if (b->prefixlen > a->prefixlen)
174 : 0 : continue;
175 : :
176 : 0 : r = in_addr_prefix_covers(b->family,
177 : 0 : &b->address,
178 : 0 : b->prefixlen,
179 : 0 : &a->address);
180 [ # # ]: 0 : if (r > 0) {
181 : : /* b covers a fully, then let's drop a */
182 [ # # # # : 0 : LIST_REMOVE(items, first, a);
# # # # ]
183 : 0 : free(a);
184 : 0 : break;
185 : : }
186 : : }
187 : : }
188 : :
189 : 0 : return first;
190 : : }
191 : :
192 : 0 : bool ip_address_access_item_is_any(IPAddressAccessItem *first) {
193 : : /* Check for exactly two entries */
194 [ # # # # : 0 : if (!first || !first->items_next || first->items_next->items_next)
# # ]
195 : 0 : return false;
196 : :
197 : : /* Check both entries cover the full range */
198 [ # # # # ]: 0 : if (first->prefixlen != 0 || first->items_next->prefixlen != 0)
199 : 0 : return false;
200 : :
201 : : /* Check that one of them is the IPv4 and the other IPv6 */
202 [ # # # # ]: 0 : if (!((first->family == AF_INET && first->items_next->family == AF_INET6) ||
203 [ # # # # ]: 0 : (first->family == AF_INET6 && first->items_next->family == AF_INET)))
204 : 0 : return false;
205 : :
206 : : /* No need to check the actual addresses, they don't matter if the prefix is zero */
207 : 0 : return true;
208 : : }
|