chiark / gitweb /
Add helper for fnmatch over strv
[elogind.git] / src / libsystemd-network / network-internal.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4  This file is part of systemd.
5
6  Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/ether.h>
23 #include <linux/if.h>
24 #include <arpa/inet.h>
25
26 #include "strv.h"
27 #include "siphash24.h"
28 #include "libudev-private.h"
29 #include "dhcp-lease-internal.h"
30 #include "log.h"
31 #include "utf8.h"
32 #include "util.h"
33 #include "conf-parser.h"
34 #include "condition.h"
35 #include "network-internal.h"
36
37 const char *net_get_name(struct udev_device *device) {
38         const char *name, *field;
39
40         assert(device);
41
42         /* fetch some persistent data unique (on this machine) to this device */
43         FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
44                 name = udev_device_get_property_value(device, field);
45                 if (name)
46                         return name;
47         }
48
49         return NULL;
50 }
51
52 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
53
54 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
55         size_t l, sz = 0;
56         const char *name = NULL;
57         int r;
58         uint8_t *v;
59
60         assert(device);
61
62         name = net_get_name(device);
63         if (!name)
64                 return -ENOENT;
65
66         l = strlen(name);
67         sz = sizeof(sd_id128_t) + l;
68         v = alloca(sz);
69
70         /* fetch some persistent data unique to this machine */
71         r = sd_id128_get_machine((sd_id128_t*) v);
72         if (r < 0)
73                  return r;
74         memcpy(v + sizeof(sd_id128_t), name, l);
75
76         /* Let's hash the machine ID plus the device name. We
77         * use a fixed, but originally randomly created hash
78         * key here. */
79         siphash24(result, v, sz, HASH_KEY.bytes);
80
81         return 0;
82 }
83
84 bool net_match_config(const struct ether_addr *match_mac,
85                       char * const *match_paths,
86                       char * const *match_drivers,
87                       char * const *match_types,
88                       char * const *match_names,
89                       Condition *match_host,
90                       Condition *match_virt,
91                       Condition *match_kernel,
92                       Condition *match_arch,
93                       const struct ether_addr *dev_mac,
94                       const char *dev_path,
95                       const char *dev_parent_driver,
96                       const char *dev_driver,
97                       const char *dev_type,
98                       const char *dev_name) {
99
100         if (match_host && !condition_test(match_host))
101                 return false;
102
103         if (match_virt && !condition_test(match_virt))
104                 return false;
105
106         if (match_kernel && !condition_test(match_kernel))
107                 return false;
108
109         if (match_arch && !condition_test(match_arch))
110                 return false;
111
112         if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
113                 return false;
114
115         if (!strv_isempty(match_paths))
116                 return strv_fnmatch(dev_path, match_paths, 0);
117
118         if (!strv_isempty(match_drivers))
119                 return strv_fnmatch(dev_driver, match_drivers, 0);
120
121         if (!strv_isempty(match_types))
122                 return strv_fnmatch(dev_type, match_types, 0);
123
124         if (!strv_isempty(match_names))
125                 return strv_fnmatch(dev_name, match_names, 0);
126
127         return true;
128 }
129
130 int config_parse_net_condition(const char *unit,
131                                const char *filename,
132                                unsigned line,
133                                const char *section,
134                                unsigned section_line,
135                                const char *lvalue,
136                                int ltype,
137                                const char *rvalue,
138                                void *data,
139                                void *userdata) {
140
141         ConditionType cond = ltype;
142         Condition **ret = data;
143         bool negate;
144         Condition *c;
145         _cleanup_free_ char *s = NULL;
146
147         assert(filename);
148         assert(lvalue);
149         assert(rvalue);
150         assert(data);
151
152         negate = rvalue[0] == '!';
153         if (negate)
154                 rvalue++;
155
156         s = strdup(rvalue);
157         if (!s)
158                 return log_oom();
159
160         c = condition_new(cond, s, false, negate);
161         if (!c)
162                 return log_oom();
163
164         if (*ret)
165                 condition_free(*ret);
166
167         *ret = c;
168         return 0;
169 }
170
171 int config_parse_ifname(const char *unit,
172                         const char *filename,
173                         unsigned line,
174                         const char *section,
175                         unsigned section_line,
176                         const char *lvalue,
177                         int ltype,
178                         const char *rvalue,
179                         void *data,
180                         void *userdata) {
181
182         char **s = data;
183         _cleanup_free_ char *n = NULL;
184
185         assert(filename);
186         assert(lvalue);
187         assert(rvalue);
188         assert(data);
189
190         n = strdup(rvalue);
191         if (!n)
192                 return log_oom();
193
194         if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
195                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
196                            "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
197                 return 0;
198         }
199
200         free(*s);
201         if (*n) {
202                 *s = n;
203                 n = NULL;
204         } else
205                 *s = NULL;
206
207         return 0;
208 }
209
210 int config_parse_ifnames(const char *unit,
211                         const char *filename,
212                         unsigned line,
213                         const char *section,
214                         unsigned section_line,
215                         const char *lvalue,
216                         int ltype,
217                         const char *rvalue,
218                         void *data,
219                         void *userdata) {
220
221         char ***sv = data;
222         const char *word, *state;
223         size_t l;
224         int r;
225
226         assert(filename);
227         assert(lvalue);
228         assert(rvalue);
229         assert(data);
230
231         FOREACH_WORD(word, l, rvalue, state) {
232                 char *n;
233
234                 n = strndup(word, l);
235                 if (!n)
236                         return log_oom();
237
238                 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
239                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
240                                    "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
241                         free(n);
242                         return 0;
243                 }
244
245                 r = strv_consume(sv, n);
246                 if (r < 0)
247                         return log_oom();
248         }
249
250         return 0;
251 }
252
253 int config_parse_ifalias(const char *unit,
254                          const char *filename,
255                          unsigned line,
256                          const char *section,
257                          unsigned section_line,
258                          const char *lvalue,
259                          int ltype,
260                          const char *rvalue,
261                          void *data,
262                          void *userdata) {
263
264         char **s = data;
265         _cleanup_free_ char *n = NULL;
266
267         assert(filename);
268         assert(lvalue);
269         assert(rvalue);
270         assert(data);
271
272         n = strdup(rvalue);
273         if (!n)
274                 return log_oom();
275
276         if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
277                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
278                            "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
279                 return 0;
280         }
281
282         free(*s);
283         if (*n) {
284                 *s = n;
285                 n = NULL;
286         } else
287                 *s = NULL;
288
289         return 0;
290 }
291
292 int config_parse_hwaddr(const char *unit,
293                         const char *filename,
294                         unsigned line,
295                         const char *section,
296                         unsigned section_line,
297                         const char *lvalue,
298                         int ltype,
299                         const char *rvalue,
300                         void *data,
301                         void *userdata) {
302         struct ether_addr **hwaddr = data;
303         struct ether_addr *n;
304         int r;
305
306         assert(filename);
307         assert(lvalue);
308         assert(rvalue);
309         assert(data);
310
311         n = new0(struct ether_addr, 1);
312         if (!n)
313                 return log_oom();
314
315         r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
316                    &n->ether_addr_octet[0],
317                    &n->ether_addr_octet[1],
318                    &n->ether_addr_octet[2],
319                    &n->ether_addr_octet[3],
320                    &n->ether_addr_octet[4],
321                    &n->ether_addr_octet[5]);
322         if (r != 6) {
323                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
324                            "Not a valid MAC address, ignoring assignment: %s", rvalue);
325                 free(n);
326                 return 0;
327         }
328
329         free(*hwaddr);
330         *hwaddr = n;
331
332         return 0;
333 }
334
335 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
336         unsigned i;
337
338         assert(f);
339         assert(addresses);
340         assert(size);
341
342         for (i = 0; i < size; i++)
343                 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
344                         (i < (size - 1)) ? " ": "");
345 }
346
347 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
348         _cleanup_free_ struct in_addr *addresses = NULL;
349         int size = 0;
350         const char *word, *state;
351         size_t len;
352
353         assert(ret);
354         assert(string);
355
356         FOREACH_WORD(word, len, string, state) {
357                 _cleanup_free_ char *addr_str = NULL;
358                 struct in_addr *new_addresses;
359                 int r;
360
361                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
362                 if (!new_addresses)
363                         return -ENOMEM;
364                 else
365                         addresses = new_addresses;
366
367                 addr_str = strndup(word, len);
368                 if (!addr_str)
369                         return -ENOMEM;
370
371                 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
372                 if (r <= 0)
373                         continue;
374
375                 size ++;
376         }
377
378         *ret = addresses;
379         addresses = NULL;
380
381         return size;
382 }
383
384 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
385         _cleanup_free_ struct in6_addr *addresses = NULL;
386         int size = 0;
387         const char *word, *state;
388         size_t len;
389
390         assert(ret);
391         assert(string);
392
393         FOREACH_WORD(word, len, string, state) {
394                 _cleanup_free_ char *addr_str = NULL;
395                 struct in6_addr *new_addresses;
396                 int r;
397
398                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
399                 if (!new_addresses)
400                         return -ENOMEM;
401                 else
402                         addresses = new_addresses;
403
404                 addr_str = strndup(word, len);
405                 if (!addr_str)
406                         return -ENOMEM;
407
408                 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
409                 if (r <= 0)
410                         continue;
411
412                 size++;
413         }
414
415         *ret = addresses;
416         addresses = NULL;
417
418         return size;
419 }
420
421 void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
422         unsigned i;
423
424         assert(f);
425         assert(key);
426         assert(routes);
427         assert(size);
428
429         fprintf(f, "%s=", key);
430
431         for (i = 0; i < size; i++) {
432                 fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr),
433                         routes[i].dst_prefixlen);
434                 fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr),
435                         (i < (size - 1)) ? " ": "");
436         }
437
438         fputs("\n", f);
439 }
440
441 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
442         _cleanup_free_ struct sd_dhcp_route *routes = NULL;
443         size_t size = 0, allocated = 0;
444         const char *word, *state;
445         size_t len;
446
447         assert(ret);
448         assert(ret_size);
449         assert(ret_allocated);
450         assert(string);
451
452         FOREACH_WORD(word, len, string, state) {
453                 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
454                 _cleanup_free_ char* entry = NULL;
455                 char *tok, *tok_end;
456                 unsigned n;
457                 int r;
458
459                 if (!GREEDY_REALLOC(routes, allocated, size + 1))
460                         return -ENOMEM;
461
462                 entry = strndup(word, len);
463                 if(!entry)
464                         return -ENOMEM;
465
466                 tok = entry;
467
468                 /* get the subnet */
469                 tok_end = strchr(tok, '/');
470                 if (!tok_end)
471                         continue;
472                 *tok_end = '\0';
473
474                 r = inet_aton(tok, &routes[size].dst_addr);
475                 if (r == 0)
476                         continue;
477
478                 tok = tok_end + 1;
479
480                 /* get the prefixlen */
481                 tok_end = strchr(tok, ',');
482                 if (!tok_end)
483                         continue;
484
485                 *tok_end = '\0';
486
487                 r = safe_atou(tok, &n);
488                 if (r < 0 || n > 32)
489                         continue;
490
491                 routes[size].dst_prefixlen = (uint8_t) n;
492                 tok = tok_end + 1;
493
494                 /* get the gateway */
495                 r = inet_aton(tok, &routes[size].gw_addr);
496                 if (r == 0)
497                         continue;
498
499                 size++;
500         }
501
502         *ret_size = size;
503         *ret_allocated = allocated;
504         *ret = routes;
505         routes = NULL;
506
507         return 0;
508 }