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