chiark / gitweb /
networkd: fdb - fix const warning
[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 #include <fnmatch.h>
26
27 #include "strv.h"
28 #include "siphash24.h"
29 #include "libudev-private.h"
30 #include "dhcp-lease-internal.h"
31 #include "log.h"
32 #include "utf8.h"
33 #include "util.h"
34 #include "conf-parser.h"
35 #include "condition.h"
36 #include "network-internal.h"
37
38 const char *net_get_name(struct udev_device *device) {
39         const char *name, *field;
40
41         assert(device);
42
43         /* fetch some persistent data unique (on this machine) to this device */
44         FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
45                 name = udev_device_get_property_value(device, field);
46                 if (name)
47                         return name;
48         }
49
50         return NULL;
51 }
52
53 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
54
55 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
56         size_t l, sz = 0;
57         const char *name = NULL;
58         int r;
59         uint8_t *v;
60
61         assert(device);
62
63         name = net_get_name(device);
64         if (!name)
65                 return -ENOENT;
66
67         l = strlen(name);
68         sz = sizeof(sd_id128_t) + l;
69         v = alloca(sz);
70
71         /* fetch some persistent data unique to this machine */
72         r = sd_id128_get_machine((sd_id128_t*) v);
73         if (r < 0)
74                  return r;
75         memcpy(v + sizeof(sd_id128_t), name, l);
76
77         /* Let's hash the machine ID plus the device name. We
78         * use a fixed, but originally randomly created hash
79         * key here. */
80         siphash24(result, v, sz, HASH_KEY.bytes);
81
82         return 0;
83 }
84
85 bool net_match_config(const struct ether_addr *match_mac,
86                       char * const *match_paths,
87                       char * const *match_drivers,
88                       char * const *match_types,
89                       char * const *match_names,
90                       Condition *match_host,
91                       Condition *match_virt,
92                       Condition *match_kernel,
93                       Condition *match_arch,
94                       const struct ether_addr *dev_mac,
95                       const char *dev_path,
96                       const char *dev_parent_driver,
97                       const char *dev_driver,
98                       const char *dev_type,
99                       const char *dev_name) {
100         char * const *match_path;
101         char * const *match_driver;
102         char * const *match_type;
103         char * const *match_name;
104
105         if (match_host && !condition_test(match_host))
106                 return false;
107
108         if (match_virt && !condition_test(match_virt))
109                 return false;
110
111         if (match_kernel && !condition_test(match_kernel))
112                 return false;
113
114         if (match_arch && !condition_test(match_arch))
115                 return false;
116
117         if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
118                 return false;
119
120         if (!strv_isempty(match_paths)) {
121                 if (!dev_path)
122                         return false;
123
124                 STRV_FOREACH(match_path, match_paths)
125                         if (fnmatch(*match_path, dev_path, 0) != 0)
126                                 return true;
127
128                 return false;
129         }
130
131         if (!strv_isempty(match_drivers)) {
132                 if (!dev_driver)
133                         return false;
134
135                 STRV_FOREACH(match_driver, match_drivers)
136                         if (fnmatch(*match_driver, dev_driver, 0) != 0)
137                                 return true;
138
139                 return false;
140         }
141
142         if (!strv_isempty(match_types)) {
143                 if (!dev_type)
144                         return false;
145
146                 STRV_FOREACH(match_type, match_types)
147                         if (fnmatch(*match_type, dev_type, 0) != 0)
148                                 return true;
149
150                 return false;
151         }
152
153         if (!strv_isempty(match_names)) {
154                 if (!dev_name)
155                         return false;
156
157                 STRV_FOREACH(match_name, match_names)
158                         if (fnmatch(*match_name, dev_name, 0) != 0)
159                                 return true;
160
161                 return false;
162         }
163
164         return true;
165 }
166
167 int config_parse_net_condition(const char *unit,
168                                const char *filename,
169                                unsigned line,
170                                const char *section,
171                                unsigned section_line,
172                                const char *lvalue,
173                                int ltype,
174                                const char *rvalue,
175                                void *data,
176                                void *userdata) {
177
178         ConditionType cond = ltype;
179         Condition **ret = data;
180         bool negate;
181         Condition *c;
182         _cleanup_free_ char *s = NULL;
183
184         assert(filename);
185         assert(lvalue);
186         assert(rvalue);
187         assert(data);
188
189         negate = rvalue[0] == '!';
190         if (negate)
191                 rvalue++;
192
193         s = strdup(rvalue);
194         if (!s)
195                 return log_oom();
196
197         c = condition_new(cond, s, false, negate);
198         if (!c)
199                 return log_oom();
200
201         if (*ret)
202                 condition_free(*ret);
203
204         *ret = c;
205         return 0;
206 }
207
208 int config_parse_ifname(const char *unit,
209                         const char *filename,
210                         unsigned line,
211                         const char *section,
212                         unsigned section_line,
213                         const char *lvalue,
214                         int ltype,
215                         const char *rvalue,
216                         void *data,
217                         void *userdata) {
218
219         char **s = data;
220         _cleanup_free_ char *n = NULL;
221
222         assert(filename);
223         assert(lvalue);
224         assert(rvalue);
225         assert(data);
226
227         n = strdup(rvalue);
228         if (!n)
229                 return log_oom();
230
231         if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
232                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
233                            "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
234                 return 0;
235         }
236
237         free(*s);
238         if (*n) {
239                 *s = n;
240                 n = NULL;
241         } else
242                 *s = NULL;
243
244         return 0;
245 }
246
247 int config_parse_ifnames(const char *unit,
248                         const char *filename,
249                         unsigned line,
250                         const char *section,
251                         unsigned section_line,
252                         const char *lvalue,
253                         int ltype,
254                         const char *rvalue,
255                         void *data,
256                         void *userdata) {
257
258         char ***sv = data;
259         const char *word, *state;
260         size_t l;
261         int r;
262
263         assert(filename);
264         assert(lvalue);
265         assert(rvalue);
266         assert(data);
267
268         FOREACH_WORD(word, l, rvalue, state) {
269                 char *n;
270
271                 n = strndup(word, l);
272                 if (!n)
273                         return log_oom();
274
275                 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
276                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
277                                    "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
278                         free(n);
279                         return 0;
280                 }
281
282                 r = strv_consume(sv, n);
283                 if (r < 0)
284                         return log_oom();
285         }
286
287         return 0;
288 }
289
290 int config_parse_ifalias(const char *unit,
291                          const char *filename,
292                          unsigned line,
293                          const char *section,
294                          unsigned section_line,
295                          const char *lvalue,
296                          int ltype,
297                          const char *rvalue,
298                          void *data,
299                          void *userdata) {
300
301         char **s = data;
302         _cleanup_free_ char *n = NULL;
303
304         assert(filename);
305         assert(lvalue);
306         assert(rvalue);
307         assert(data);
308
309         n = strdup(rvalue);
310         if (!n)
311                 return log_oom();
312
313         if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
314                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
315                            "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
316                 return 0;
317         }
318
319         free(*s);
320         if (*n) {
321                 *s = n;
322                 n = NULL;
323         } else
324                 *s = NULL;
325
326         return 0;
327 }
328
329 int config_parse_hwaddr(const char *unit,
330                         const char *filename,
331                         unsigned line,
332                         const char *section,
333                         unsigned section_line,
334                         const char *lvalue,
335                         int ltype,
336                         const char *rvalue,
337                         void *data,
338                         void *userdata) {
339         struct ether_addr **hwaddr = data;
340         struct ether_addr *n;
341         int r;
342
343         assert(filename);
344         assert(lvalue);
345         assert(rvalue);
346         assert(data);
347
348         n = new0(struct ether_addr, 1);
349         if (!n)
350                 return log_oom();
351
352         r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
353                    &n->ether_addr_octet[0],
354                    &n->ether_addr_octet[1],
355                    &n->ether_addr_octet[2],
356                    &n->ether_addr_octet[3],
357                    &n->ether_addr_octet[4],
358                    &n->ether_addr_octet[5]);
359         if (r != 6) {
360                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
361                            "Not a valid MAC address, ignoring assignment: %s", rvalue);
362                 free(n);
363                 return 0;
364         }
365
366         free(*hwaddr);
367         *hwaddr = n;
368
369         return 0;
370 }
371
372 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
373         unsigned i;
374
375         assert(f);
376         assert(addresses);
377         assert(size);
378
379         for (i = 0; i < size; i++)
380                 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
381                         (i < (size - 1)) ? " ": "");
382 }
383
384 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
385         _cleanup_free_ struct in_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 in_addr *new_addresses;
396                 int r;
397
398                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_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_INET, 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 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
422         _cleanup_free_ struct in6_addr *addresses = NULL;
423         int size = 0;
424         const char *word, *state;
425         size_t len;
426
427         assert(ret);
428         assert(string);
429
430         FOREACH_WORD(word, len, string, state) {
431                 _cleanup_free_ char *addr_str = NULL;
432                 struct in6_addr *new_addresses;
433                 int r;
434
435                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
436                 if (!new_addresses)
437                         return -ENOMEM;
438                 else
439                         addresses = new_addresses;
440
441                 addr_str = strndup(word, len);
442                 if (!addr_str)
443                         return -ENOMEM;
444
445                 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
446                 if (r <= 0)
447                         continue;
448
449                 size++;
450         }
451
452         *ret = addresses;
453         addresses = NULL;
454
455         return size;
456 }
457
458 void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
459         unsigned i;
460
461         assert(f);
462         assert(key);
463         assert(routes);
464         assert(size);
465
466         fprintf(f, "%s=", key);
467
468         for (i = 0; i < size; i++) {
469                 fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr),
470                         routes[i].dst_prefixlen);
471                 fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr),
472                         (i < (size - 1)) ? " ": "");
473         }
474
475         fputs("\n", f);
476 }
477
478 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
479         _cleanup_free_ struct sd_dhcp_route *routes = NULL;
480         size_t size = 0, allocated = 0;
481         const char *word, *state;
482         size_t len;
483
484         assert(ret);
485         assert(ret_size);
486         assert(ret_allocated);
487         assert(string);
488
489         FOREACH_WORD(word, len, string, state) {
490                 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
491                 _cleanup_free_ char* entry = NULL;
492                 char *tok, *tok_end;
493                 unsigned n;
494                 int r;
495
496                 if (!GREEDY_REALLOC(routes, allocated, size + 1))
497                         return -ENOMEM;
498
499                 entry = strndup(word, len);
500                 if(!entry)
501                         return -ENOMEM;
502
503                 tok = entry;
504
505                 /* get the subnet */
506                 tok_end = strchr(tok, '/');
507                 if (!tok_end)
508                         continue;
509                 *tok_end = '\0';
510
511                 r = inet_aton(tok, &routes[size].dst_addr);
512                 if (r == 0)
513                         continue;
514
515                 tok = tok_end + 1;
516
517                 /* get the prefixlen */
518                 tok_end = strchr(tok, ',');
519                 if (!tok_end)
520                         continue;
521
522                 *tok_end = '\0';
523
524                 r = safe_atou(tok, &n);
525                 if (r < 0 || n > 32)
526                         continue;
527
528                 routes[size].dst_prefixlen = (uint8_t) n;
529                 tok = tok_end + 1;
530
531                 /* get the gateway */
532                 r = inet_aton(tok, &routes[size].gw_addr);
533                 if (r == 0)
534                         continue;
535
536                 size++;
537         }
538
539         *ret_size = size;
540         *ret_allocated = allocated;
541         *ret = routes;
542         routes = NULL;
543
544         return 0;
545 }