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