]>
Commit | Line | Data |
---|---|---|
cca2da15 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
7e19cc54 YW |
2 | |
3 | #include <netinet/ether.h> | |
4 | ||
5 | #include "condition.h" | |
6 | #include "env-util.h" | |
7 | #include "log.h" | |
8 | #include "net-condition.h" | |
b5cc5591 | 9 | #include "netif-util.h" |
7e19cc54 YW |
10 | #include "network-util.h" |
11 | #include "socket-util.h" | |
12 | #include "string-table.h" | |
13 | #include "strv.h" | |
abad436d | 14 | #include "wifi-util.h" |
7e19cc54 | 15 | |
5722fb89 YW |
16 | void net_match_clear(NetMatch *match) { |
17 | if (!match) | |
18 | return; | |
19 | ||
52135071 YW |
20 | match->hw_addr = set_free(match->hw_addr); |
21 | match->permanent_hw_addr = set_free(match->permanent_hw_addr); | |
5722fb89 YW |
22 | match->path = strv_free(match->path); |
23 | match->driver = strv_free(match->driver); | |
24 | match->iftype = strv_free(match->iftype); | |
65022cd7 | 25 | match->kind = strv_free(match->kind); |
5722fb89 YW |
26 | match->ifname = strv_free(match->ifname); |
27 | match->property = strv_free(match->property); | |
77f75f4f | 28 | match->wlan_iftype = strv_free(match->wlan_iftype); |
5722fb89 | 29 | match->ssid = strv_free(match->ssid); |
c6df73ca | 30 | match->bssid = set_free(match->bssid); |
5722fb89 YW |
31 | } |
32 | ||
33 | bool net_match_is_empty(const NetMatch *match) { | |
34 | assert(match); | |
35 | ||
36 | return | |
52135071 YW |
37 | set_isempty(match->hw_addr) && |
38 | set_isempty(match->permanent_hw_addr) && | |
5722fb89 YW |
39 | strv_isempty(match->path) && |
40 | strv_isempty(match->driver) && | |
41 | strv_isempty(match->iftype) && | |
65022cd7 | 42 | strv_isempty(match->kind) && |
5722fb89 YW |
43 | strv_isempty(match->ifname) && |
44 | strv_isempty(match->property) && | |
77f75f4f | 45 | strv_isempty(match->wlan_iftype) && |
5722fb89 YW |
46 | strv_isempty(match->ssid) && |
47 | set_isempty(match->bssid); | |
48 | } | |
49 | ||
7e19cc54 | 50 | static bool net_condition_test_strv(char * const *patterns, const char *string) { |
7e19cc54 YW |
51 | bool match = false, has_positive_rule = false; |
52 | ||
53 | if (strv_isempty(patterns)) | |
54 | return true; | |
55 | ||
56 | STRV_FOREACH(p, patterns) { | |
57 | const char *q = *p; | |
58 | bool invert; | |
59 | ||
60 | invert = *q == '!'; | |
61 | q += invert; | |
62 | ||
63 | if (!invert) | |
64 | has_positive_rule = true; | |
65 | ||
66 | if (string && fnmatch(q, string, 0) == 0) { | |
67 | if (invert) | |
68 | return false; | |
69 | else | |
70 | match = true; | |
71 | } | |
72 | } | |
73 | ||
74 | return has_positive_rule ? match : true; | |
75 | } | |
76 | ||
77 | static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) { | |
78 | if (net_condition_test_strv(patterns, ifname)) | |
79 | return true; | |
80 | ||
7e19cc54 YW |
81 | STRV_FOREACH(p, alternative_names) |
82 | if (net_condition_test_strv(patterns, *p)) | |
83 | return true; | |
84 | ||
85 | return false; | |
86 | } | |
87 | ||
88 | static int net_condition_test_property(char * const *match_property, sd_device *device) { | |
7e19cc54 YW |
89 | if (strv_isempty(match_property)) |
90 | return true; | |
91 | ||
92 | STRV_FOREACH(p, match_property) { | |
93 | _cleanup_free_ char *key = NULL; | |
94 | const char *val, *dev_val; | |
95 | bool invert, v; | |
96 | ||
97 | invert = **p == '!'; | |
98 | ||
99 | val = strchr(*p + invert, '='); | |
100 | if (!val) | |
101 | return -EINVAL; | |
102 | ||
103 | key = strndup(*p + invert, val - *p - invert); | |
104 | if (!key) | |
105 | return -ENOMEM; | |
106 | ||
107 | val++; | |
108 | ||
109 | v = device && | |
110 | sd_device_get_property_value(device, key, &dev_val) >= 0 && | |
111 | fnmatch(val, dev_val, 0) == 0; | |
112 | ||
113 | if (invert ? v : !v) | |
114 | return false; | |
115 | } | |
116 | ||
117 | return true; | |
118 | } | |
119 | ||
1a3caa49 | 120 | int net_match_config( |
5722fb89 | 121 | const NetMatch *match, |
7e19cc54 | 122 | sd_device *device, |
52135071 YW |
123 | const struct hw_addr_data *hw_addr, |
124 | const struct hw_addr_data *permanent_hw_addr, | |
5722fb89 YW |
125 | const char *driver, |
126 | unsigned short iftype, | |
65022cd7 | 127 | const char *kind, |
5722fb89 | 128 | const char *ifname, |
7e19cc54 | 129 | char * const *alternative_names, |
77f75f4f | 130 | enum nl80211_iftype wlan_iftype, |
5722fb89 YW |
131 | const char *ssid, |
132 | const struct ether_addr *bssid) { | |
133 | ||
c2b2df60 | 134 | _cleanup_free_ char *iftype_str = NULL; |
5722fb89 | 135 | const char *path = NULL; |
7e19cc54 | 136 | |
5722fb89 | 137 | assert(match); |
7e19cc54 | 138 | |
613701a4 YW |
139 | if (net_get_type_string(device, iftype, &iftype_str) == -ENOMEM) |
140 | return -ENOMEM; | |
7e19cc54 | 141 | |
613701a4 | 142 | if (device) |
5722fb89 | 143 | (void) sd_device_get_property_value(device, "ID_PATH", &path); |
7e19cc54 | 144 | |
52135071 | 145 | if (match->hw_addr && (!hw_addr || !set_contains(match->hw_addr, hw_addr))) |
7e19cc54 YW |
146 | return false; |
147 | ||
52135071 YW |
148 | if (match->permanent_hw_addr && |
149 | (!permanent_hw_addr || | |
150 | !set_contains(match->permanent_hw_addr, permanent_hw_addr))) | |
7e19cc54 YW |
151 | return false; |
152 | ||
5722fb89 | 153 | if (!net_condition_test_strv(match->path, path)) |
7e19cc54 YW |
154 | return false; |
155 | ||
5722fb89 | 156 | if (!net_condition_test_strv(match->driver, driver)) |
7e19cc54 YW |
157 | return false; |
158 | ||
5722fb89 | 159 | if (!net_condition_test_strv(match->iftype, iftype_str)) |
7e19cc54 YW |
160 | return false; |
161 | ||
65022cd7 YW |
162 | if (!net_condition_test_strv(match->kind, kind)) |
163 | return false; | |
164 | ||
5722fb89 | 165 | if (!net_condition_test_ifname(match->ifname, ifname, alternative_names)) |
7e19cc54 YW |
166 | return false; |
167 | ||
5722fb89 | 168 | if (!net_condition_test_property(match->property, device)) |
7e19cc54 YW |
169 | return false; |
170 | ||
77f75f4f | 171 | if (!net_condition_test_strv(match->wlan_iftype, nl80211_iftype_to_string(wlan_iftype))) |
7e19cc54 YW |
172 | return false; |
173 | ||
5722fb89 | 174 | if (!net_condition_test_strv(match->ssid, ssid)) |
7e19cc54 YW |
175 | return false; |
176 | ||
5722fb89 | 177 | if (match->bssid && (!bssid || !set_contains(match->bssid, bssid))) |
7e19cc54 YW |
178 | return false; |
179 | ||
180 | return true; | |
181 | } | |
182 | ||
183 | int config_parse_net_condition( | |
184 | const char *unit, | |
185 | const char *filename, | |
186 | unsigned line, | |
187 | const char *section, | |
188 | unsigned section_line, | |
189 | const char *lvalue, | |
190 | int ltype, | |
191 | const char *rvalue, | |
192 | void *data, | |
193 | void *userdata) { | |
194 | ||
195 | ConditionType cond = ltype; | |
196 | Condition **list = data, *c; | |
197 | bool negate; | |
198 | ||
199 | assert(filename); | |
200 | assert(lvalue); | |
201 | assert(rvalue); | |
202 | assert(data); | |
203 | ||
204 | if (isempty(rvalue)) { | |
205 | *list = condition_free_list_type(*list, cond); | |
206 | return 0; | |
207 | } | |
208 | ||
209 | negate = rvalue[0] == '!'; | |
210 | if (negate) | |
211 | rvalue++; | |
212 | ||
213 | c = condition_new(cond, rvalue, false, negate); | |
214 | if (!c) | |
215 | return log_oom(); | |
216 | ||
217 | /* Drop previous assignment. */ | |
218 | *list = condition_free_list_type(*list, cond); | |
219 | ||
220 | LIST_PREPEND(conditions, *list, c); | |
221 | return 0; | |
222 | } | |
223 | ||
224 | int config_parse_match_strv( | |
225 | const char *unit, | |
226 | const char *filename, | |
227 | unsigned line, | |
228 | const char *section, | |
229 | unsigned section_line, | |
230 | const char *lvalue, | |
231 | int ltype, | |
232 | const char *rvalue, | |
233 | void *data, | |
234 | void *userdata) { | |
235 | ||
99534007 DT |
236 | const char *p = ASSERT_PTR(rvalue); |
237 | char ***sv = ASSERT_PTR(data); | |
7e19cc54 YW |
238 | bool invert; |
239 | int r; | |
240 | ||
241 | assert(filename); | |
242 | assert(lvalue); | |
7e19cc54 YW |
243 | |
244 | if (isempty(rvalue)) { | |
245 | *sv = strv_free(*sv); | |
246 | return 0; | |
247 | } | |
248 | ||
249 | invert = *p == '!'; | |
250 | p += invert; | |
251 | ||
252 | for (;;) { | |
253 | _cleanup_free_ char *word = NULL, *k = NULL; | |
254 | ||
255 | r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); | |
256 | if (r == 0) | |
257 | return 0; | |
258 | if (r == -ENOMEM) | |
259 | return log_oom(); | |
260 | if (r < 0) { | |
261 | log_syntax(unit, LOG_WARNING, filename, line, r, | |
262 | "Invalid syntax, ignoring: %s", rvalue); | |
263 | return 0; | |
264 | } | |
265 | ||
266 | if (invert) { | |
267 | k = strjoin("!", word); | |
268 | if (!k) | |
269 | return log_oom(); | |
270 | } else | |
271 | k = TAKE_PTR(word); | |
272 | ||
273 | r = strv_consume(sv, TAKE_PTR(k)); | |
274 | if (r < 0) | |
275 | return log_oom(); | |
276 | } | |
277 | } | |
278 | ||
279 | int config_parse_match_ifnames( | |
280 | const char *unit, | |
281 | const char *filename, | |
282 | unsigned line, | |
283 | const char *section, | |
284 | unsigned section_line, | |
285 | const char *lvalue, | |
286 | int ltype, | |
287 | const char *rvalue, | |
288 | void *data, | |
289 | void *userdata) { | |
290 | ||
99534007 DT |
291 | const char *p = ASSERT_PTR(rvalue); |
292 | char ***sv = ASSERT_PTR(data); | |
7e19cc54 YW |
293 | bool invert; |
294 | int r; | |
295 | ||
296 | assert(filename); | |
297 | assert(lvalue); | |
7e19cc54 YW |
298 | |
299 | if (isempty(rvalue)) { | |
300 | *sv = strv_free(*sv); | |
301 | return 0; | |
302 | } | |
303 | ||
304 | invert = *p == '!'; | |
305 | p += invert; | |
306 | ||
307 | for (;;) { | |
308 | _cleanup_free_ char *word = NULL, *k = NULL; | |
309 | ||
310 | r = extract_first_word(&p, &word, NULL, 0); | |
311 | if (r == 0) | |
312 | return 0; | |
313 | if (r == -ENOMEM) | |
314 | return log_oom(); | |
315 | if (r < 0) { | |
316 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
317 | "Failed to parse interface name list, ignoring: %s", rvalue); | |
318 | return 0; | |
319 | } | |
320 | ||
321 | if (!ifname_valid_full(word, ltype)) { | |
322 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
323 | "Interface name is not valid or too long, ignoring assignment: %s", word); | |
324 | continue; | |
325 | } | |
326 | ||
327 | if (invert) { | |
328 | k = strjoin("!", word); | |
329 | if (!k) | |
330 | return log_oom(); | |
331 | } else | |
332 | k = TAKE_PTR(word); | |
333 | ||
334 | r = strv_consume(sv, TAKE_PTR(k)); | |
335 | if (r < 0) | |
336 | return log_oom(); | |
337 | } | |
338 | } | |
339 | ||
340 | int config_parse_match_property( | |
341 | const char *unit, | |
342 | const char *filename, | |
343 | unsigned line, | |
344 | const char *section, | |
345 | unsigned section_line, | |
346 | const char *lvalue, | |
347 | int ltype, | |
348 | const char *rvalue, | |
349 | void *data, | |
350 | void *userdata) { | |
351 | ||
99534007 DT |
352 | const char *p = ASSERT_PTR(rvalue); |
353 | char ***sv = ASSERT_PTR(data); | |
7e19cc54 YW |
354 | bool invert; |
355 | int r; | |
356 | ||
357 | assert(filename); | |
358 | assert(lvalue); | |
7e19cc54 YW |
359 | |
360 | if (isempty(rvalue)) { | |
361 | *sv = strv_free(*sv); | |
362 | return 0; | |
363 | } | |
364 | ||
365 | invert = *p == '!'; | |
366 | p += invert; | |
367 | ||
368 | for (;;) { | |
369 | _cleanup_free_ char *word = NULL, *k = NULL; | |
370 | ||
371 | r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); | |
372 | if (r == 0) | |
373 | return 0; | |
374 | if (r == -ENOMEM) | |
375 | return log_oom(); | |
376 | if (r < 0) { | |
377 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
378 | "Invalid syntax, ignoring: %s", rvalue); | |
379 | return 0; | |
380 | } | |
381 | ||
382 | if (!env_assignment_is_valid(word)) { | |
383 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
384 | "Invalid property or value, ignoring assignment: %s", word); | |
385 | continue; | |
386 | } | |
387 | ||
388 | if (invert) { | |
389 | k = strjoin("!", word); | |
390 | if (!k) | |
391 | return log_oom(); | |
392 | } else | |
393 | k = TAKE_PTR(word); | |
394 | ||
395 | r = strv_consume(sv, TAKE_PTR(k)); | |
396 | if (r < 0) | |
397 | return log_oom(); | |
398 | } | |
399 | } |