chiark / gitweb /
network-internal: split out net_get_name()
[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 "log.h"
32 #include "utf8.h"
33 #include "util.h"
34 #include "conf-parser.h"
35 #include "condition.h"
36
37 const char *net_get_name(struct udev_device *device) {
38         const char *name = NULL, *field = NULL;
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",
44                        "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
45                 name = udev_device_get_property_value(device, field);
46                 if (name)
47                         break;
48         }
49
50         return name;
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                       const char *match_path,
87                       const char *match_driver,
88                       const char *match_type,
89                       const char *match_name,
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
101         if (match_host && !condition_test_host(match_host))
102                 return 0;
103
104         if (match_virt && !condition_test_virtualization(match_virt))
105                 return 0;
106
107         if (match_kernel && !condition_test_kernel_command_line(match_kernel))
108                 return 0;
109
110         if (match_arch && !condition_test_architecture(match_arch))
111                 return 0;
112
113         if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
114                 return 0;
115
116         if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
117                 return 0;
118
119         if (match_driver) {
120                 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
121                         return 0;
122                 else if (!streq_ptr(match_driver, dev_driver))
123                         return 0;
124         }
125
126         if (match_type && !streq_ptr(match_type, dev_type))
127                 return 0;
128
129         if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
130                 return 0;
131
132         return 1;
133 }
134
135 unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
136         assert(addr);
137
138         return 32 - u32ctz(be32toh(addr->s_addr));
139 }
140
141 int config_parse_net_condition(const char *unit,
142                                const char *filename,
143                                unsigned line,
144                                const char *section,
145                                unsigned section_line,
146                                const char *lvalue,
147                                int ltype,
148                                const char *rvalue,
149                                void *data,
150                                void *userdata) {
151
152         ConditionType cond = ltype;
153         Condition **ret = data;
154         bool negate;
155         Condition *c;
156         _cleanup_free_ char *s = NULL;
157
158         assert(filename);
159         assert(lvalue);
160         assert(rvalue);
161         assert(data);
162
163         negate = rvalue[0] == '!';
164         if (negate)
165                 rvalue++;
166
167         s = strdup(rvalue);
168         if (!s)
169                 return log_oom();
170
171         c = condition_new(cond, s, false, negate);
172         if (!c)
173                 return log_oom();
174
175         if (*ret)
176                 condition_free(*ret);
177
178         *ret = c;
179         return 0;
180 }
181
182 int config_parse_ifname(const char *unit,
183                         const char *filename,
184                         unsigned line,
185                         const char *section,
186                         unsigned section_line,
187                         const char *lvalue,
188                         int ltype,
189                         const char *rvalue,
190                         void *data,
191                         void *userdata) {
192
193         char **s = data;
194         _cleanup_free_ char *n = NULL;
195
196         assert(filename);
197         assert(lvalue);
198         assert(rvalue);
199         assert(data);
200
201         n = strdup(rvalue);
202         if (!n)
203                 return log_oom();
204
205         if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
206                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
207                            "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
208                 free(n);
209                 return 0;
210         }
211
212         free(*s);
213         if (*n) {
214                 *s = n;
215                 n = NULL;
216         } else
217                 *s = NULL;
218
219         return 0;
220 }
221
222 int config_parse_ifalias(const char *unit,
223                          const char *filename,
224                          unsigned line,
225                          const char *section,
226                          unsigned section_line,
227                          const char *lvalue,
228                          int ltype,
229                          const char *rvalue,
230                          void *data,
231                          void *userdata) {
232
233         char **s = data;
234         char *n;
235
236         assert(filename);
237         assert(lvalue);
238         assert(rvalue);
239         assert(data);
240
241         n = strdup(rvalue);
242         if (!n)
243                 return log_oom();
244
245         if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
246                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
247                            "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
248                 free(n);
249                 return 0;
250         }
251
252         free(*s);
253         if (*n)
254                 *s = n;
255         else {
256                 free(n);
257                 *s = NULL;
258         }
259
260         return 0;
261 }
262
263 int config_parse_hwaddr(const char *unit,
264                         const char *filename,
265                         unsigned line,
266                         const char *section,
267                         unsigned section_line,
268                         const char *lvalue,
269                         int ltype,
270                         const char *rvalue,
271                         void *data,
272                         void *userdata) {
273         struct ether_addr **hwaddr = data;
274         struct ether_addr *n;
275         int r;
276
277         assert(filename);
278         assert(lvalue);
279         assert(rvalue);
280         assert(data);
281
282         n = new0(struct ether_addr, 1);
283         if (!n)
284                 return log_oom();
285
286         r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
287                    &n->ether_addr_octet[0],
288                    &n->ether_addr_octet[1],
289                    &n->ether_addr_octet[2],
290                    &n->ether_addr_octet[3],
291                    &n->ether_addr_octet[4],
292                    &n->ether_addr_octet[5]);
293         if (r != 6) {
294                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
295                            "Not a valid MAC address, ignoring assignment: %s", rvalue);
296                 free(n);
297                 return 0;
298         }
299
300         free(*hwaddr);
301         *hwaddr = n;
302
303         return 0;
304 }
305
306 int net_parse_inaddr(const char *address, unsigned char *family, void *dst) {
307         int r;
308
309         assert(address);
310         assert(family);
311         assert(dst);
312
313         /* IPv4 */
314         r = inet_pton(AF_INET, address, dst);
315         if (r > 0) {
316                 /* succsefully parsed IPv4 address */
317                 if (*family == AF_UNSPEC)
318                         *family = AF_INET;
319                 else if (*family != AF_INET)
320                         return -EINVAL;
321         } else  if (r < 0)
322                 return -errno;
323         else {
324                 /* not an IPv4 address, so let's try IPv6 */
325                 r = inet_pton(AF_INET6, address, dst);
326                 if (r > 0) {
327                         /* successfully parsed IPv6 address */
328                         if (*family == AF_UNSPEC)
329                                 *family = AF_INET6;
330                         else if (*family != AF_INET6)
331                                 return -EINVAL;
332                 } else if (r < 0)
333                         return -errno;
334                 else
335                         return -EINVAL;
336         }
337
338         return 0;
339 }
340
341 void serialize_in_addrs(FILE *f, const char *key, struct in_addr *addresses, size_t size) {
342         unsigned i;
343
344         assert(f);
345         assert(key);
346         assert(addresses);
347         assert(size);
348
349         fprintf(f, "%s=", key);
350
351         for (i = 0; i < size; i++)
352                 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
353                         (i < (size - 1)) ? " ": "");
354
355         fputs("\n", f);
356 }
357
358 int deserialize_in_addrs(struct in_addr **ret, size_t *ret_size, const char *string) {
359         _cleanup_free_ struct in_addr *addresses = NULL;
360         size_t size = 0;
361         char *word, *state;
362         size_t len;
363
364         assert(ret);
365         assert(ret_size);
366         assert(string);
367
368         FOREACH_WORD(word, len, string, state) {
369                 _cleanup_free_ char *addr_str = NULL;
370                 struct in_addr *new_addresses;
371                 int r;
372
373                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
374                 if (!new_addresses)
375                         return -ENOMEM;
376                 else
377                         addresses = new_addresses;
378
379                 addr_str = strndup(word, len);
380                 if (!addr_str)
381                         return -ENOMEM;
382
383                 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
384                 if (r <= 0)
385                         continue;
386
387                 size ++;
388         }
389
390         *ret_size = size;
391         *ret = addresses;
392         addresses = NULL;
393
394         return 0;
395 }
396
397 int deserialize_in6_addrs(struct in6_addr **ret, size_t *ret_size, const char *string) {
398         _cleanup_free_ struct in6_addr *addresses = NULL;
399         size_t size = 0;
400         char *word, *state;
401         size_t len;
402
403         assert(ret);
404         assert(ret_size);
405         assert(string);
406
407         FOREACH_WORD(word, len, string, state) {
408                 _cleanup_free_ char *addr_str = NULL;
409                 struct in6_addr *new_addresses;
410                 int r;
411
412                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
413                 if (!new_addresses)
414                         return -ENOMEM;
415                 else
416                         addresses = new_addresses;
417
418                 addr_str = strndup(word, len);
419                 if (!addr_str)
420                         return -ENOMEM;
421
422                 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
423                 if (r <= 0)
424                         continue;
425
426                 size++;
427         }
428
429         *ret_size = size;
430         *ret = addresses;
431         addresses = NULL;
432
433         return 0;
434 }