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