chiark / gitweb /
81f90aa3893cd842d075256b6ef542f2db261aac
[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             (!dev_path || !strv_fnmatch(dev_path, match_paths, 0)))
117                 return false;
118
119         if (!strv_isempty(match_drivers) &&
120             (!dev_driver || !strv_fnmatch(dev_driver, match_drivers, 0)))
121                 return false;
122
123         if (!strv_isempty(match_types) &&
124             (!dev_type || !strv_fnmatch_or_empty(dev_type, match_types, 0)))
125                 return false;
126
127         if (!strv_isempty(match_names) &&
128             (!dev_name || !strv_fnmatch_or_empty(dev_name, match_names, 0)))
129                 return false;
130
131         return true;
132 }
133
134 int config_parse_net_condition(const char *unit,
135                                const char *filename,
136                                unsigned line,
137                                const char *section,
138                                unsigned section_line,
139                                const char *lvalue,
140                                int ltype,
141                                const char *rvalue,
142                                void *data,
143                                void *userdata) {
144
145         ConditionType cond = ltype;
146         Condition **ret = data;
147         bool negate;
148         Condition *c;
149         _cleanup_free_ char *s = NULL;
150
151         assert(filename);
152         assert(lvalue);
153         assert(rvalue);
154         assert(data);
155
156         negate = rvalue[0] == '!';
157         if (negate)
158                 rvalue++;
159
160         s = strdup(rvalue);
161         if (!s)
162                 return log_oom();
163
164         c = condition_new(cond, s, false, negate);
165         if (!c)
166                 return log_oom();
167
168         if (*ret)
169                 condition_free(*ret);
170
171         *ret = c;
172         return 0;
173 }
174
175 int config_parse_ifname(const char *unit,
176                         const char *filename,
177                         unsigned line,
178                         const char *section,
179                         unsigned section_line,
180                         const char *lvalue,
181                         int ltype,
182                         const char *rvalue,
183                         void *data,
184                         void *userdata) {
185
186         char **s = data;
187         _cleanup_free_ char *n = NULL;
188
189         assert(filename);
190         assert(lvalue);
191         assert(rvalue);
192         assert(data);
193
194         n = strdup(rvalue);
195         if (!n)
196                 return log_oom();
197
198         if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
199                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
200                            "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
201                 return 0;
202         }
203
204         free(*s);
205         if (*n) {
206                 *s = n;
207                 n = NULL;
208         } else
209                 *s = NULL;
210
211         return 0;
212 }
213
214 int config_parse_ifnames(const char *unit,
215                         const char *filename,
216                         unsigned line,
217                         const char *section,
218                         unsigned section_line,
219                         const char *lvalue,
220                         int ltype,
221                         const char *rvalue,
222                         void *data,
223                         void *userdata) {
224
225         char ***sv = data;
226         const char *word, *state;
227         size_t l;
228         int r;
229
230         assert(filename);
231         assert(lvalue);
232         assert(rvalue);
233         assert(data);
234
235         FOREACH_WORD(word, l, rvalue, state) {
236                 char *n;
237
238                 n = strndup(word, l);
239                 if (!n)
240                         return log_oom();
241
242                 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
243                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
244                                    "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
245                         free(n);
246                         return 0;
247                 }
248
249                 r = strv_consume(sv, n);
250                 if (r < 0)
251                         return log_oom();
252         }
253
254         return 0;
255 }
256
257 int config_parse_ifalias(const char *unit,
258                          const char *filename,
259                          unsigned line,
260                          const char *section,
261                          unsigned section_line,
262                          const char *lvalue,
263                          int ltype,
264                          const char *rvalue,
265                          void *data,
266                          void *userdata) {
267
268         char **s = data;
269         _cleanup_free_ char *n = NULL;
270
271         assert(filename);
272         assert(lvalue);
273         assert(rvalue);
274         assert(data);
275
276         n = strdup(rvalue);
277         if (!n)
278                 return log_oom();
279
280         if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
281                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
282                            "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
283                 return 0;
284         }
285
286         free(*s);
287         if (*n) {
288                 *s = n;
289                 n = NULL;
290         } else
291                 *s = NULL;
292
293         return 0;
294 }
295
296 int config_parse_hwaddr(const char *unit,
297                         const char *filename,
298                         unsigned line,
299                         const char *section,
300                         unsigned section_line,
301                         const char *lvalue,
302                         int ltype,
303                         const char *rvalue,
304                         void *data,
305                         void *userdata) {
306         struct ether_addr **hwaddr = data;
307         struct ether_addr *n;
308         int r;
309
310         assert(filename);
311         assert(lvalue);
312         assert(rvalue);
313         assert(data);
314
315         n = new0(struct ether_addr, 1);
316         if (!n)
317                 return log_oom();
318
319         r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
320                    &n->ether_addr_octet[0],
321                    &n->ether_addr_octet[1],
322                    &n->ether_addr_octet[2],
323                    &n->ether_addr_octet[3],
324                    &n->ether_addr_octet[4],
325                    &n->ether_addr_octet[5]);
326         if (r != 6) {
327                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
328                            "Not a valid MAC address, ignoring assignment: %s", rvalue);
329                 free(n);
330                 return 0;
331         }
332
333         free(*hwaddr);
334         *hwaddr = n;
335
336         return 0;
337 }
338
339 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
340         unsigned i;
341
342         assert(f);
343         assert(addresses);
344         assert(size);
345
346         for (i = 0; i < size; i++)
347                 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
348                         (i < (size - 1)) ? " ": "");
349 }
350
351 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
352         _cleanup_free_ struct in_addr *addresses = NULL;
353         int size = 0;
354         const char *word, *state;
355         size_t len;
356
357         assert(ret);
358         assert(string);
359
360         FOREACH_WORD(word, len, string, state) {
361                 _cleanup_free_ char *addr_str = NULL;
362                 struct in_addr *new_addresses;
363                 int r;
364
365                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
366                 if (!new_addresses)
367                         return -ENOMEM;
368                 else
369                         addresses = new_addresses;
370
371                 addr_str = strndup(word, len);
372                 if (!addr_str)
373                         return -ENOMEM;
374
375                 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
376                 if (r <= 0)
377                         continue;
378
379                 size ++;
380         }
381
382         *ret = addresses;
383         addresses = NULL;
384
385         return size;
386 }
387
388 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
389         _cleanup_free_ struct in6_addr *addresses = NULL;
390         int size = 0;
391         const char *word, *state;
392         size_t len;
393
394         assert(ret);
395         assert(string);
396
397         FOREACH_WORD(word, len, string, state) {
398                 _cleanup_free_ char *addr_str = NULL;
399                 struct in6_addr *new_addresses;
400                 int r;
401
402                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
403                 if (!new_addresses)
404                         return -ENOMEM;
405                 else
406                         addresses = new_addresses;
407
408                 addr_str = strndup(word, len);
409                 if (!addr_str)
410                         return -ENOMEM;
411
412                 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
413                 if (r <= 0)
414                         continue;
415
416                 size++;
417         }
418
419         *ret = addresses;
420         addresses = NULL;
421
422         return size;
423 }
424
425 void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
426         unsigned i;
427
428         assert(f);
429         assert(key);
430         assert(routes);
431         assert(size);
432
433         fprintf(f, "%s=", key);
434
435         for (i = 0; i < size; i++) {
436                 fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr),
437                         routes[i].dst_prefixlen);
438                 fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr),
439                         (i < (size - 1)) ? " ": "");
440         }
441
442         fputs("\n", f);
443 }
444
445 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
446         _cleanup_free_ struct sd_dhcp_route *routes = NULL;
447         size_t size = 0, allocated = 0;
448         const char *word, *state;
449         size_t len;
450
451         assert(ret);
452         assert(ret_size);
453         assert(ret_allocated);
454         assert(string);
455
456         FOREACH_WORD(word, len, string, state) {
457                 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
458                 _cleanup_free_ char* entry = NULL;
459                 char *tok, *tok_end;
460                 unsigned n;
461                 int r;
462
463                 if (!GREEDY_REALLOC(routes, allocated, size + 1))
464                         return -ENOMEM;
465
466                 entry = strndup(word, len);
467                 if(!entry)
468                         return -ENOMEM;
469
470                 tok = entry;
471
472                 /* get the subnet */
473                 tok_end = strchr(tok, '/');
474                 if (!tok_end)
475                         continue;
476                 *tok_end = '\0';
477
478                 r = inet_aton(tok, &routes[size].dst_addr);
479                 if (r == 0)
480                         continue;
481
482                 tok = tok_end + 1;
483
484                 /* get the prefixlen */
485                 tok_end = strchr(tok, ',');
486                 if (!tok_end)
487                         continue;
488
489                 *tok_end = '\0';
490
491                 r = safe_atou(tok, &n);
492                 if (r < 0 || n > 32)
493                         continue;
494
495                 routes[size].dst_prefixlen = (uint8_t) n;
496                 tok = tok_end + 1;
497
498                 /* get the gateway */
499                 r = inet_aton(tok, &routes[size].gw_addr);
500                 if (r == 0)
501                         continue;
502
503                 size++;
504         }
505
506         *ret_size = size;
507         *ret_allocated = allocated;
508         *ret = routes;
509         routes = NULL;
510
511         return 0;
512 }