chiark / gitweb /
b90fd1ccc8f656438c30c4480431eb7813cfb53a
[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.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                       bool ignore_name_match) {
101
102         if (match_host && !condition_test(match_host))
103                 return false;
104
105         if (match_virt && !condition_test(match_virt))
106                 return false;
107
108         if (match_kernel && !condition_test(match_kernel))
109                 return false;
110
111         if (match_arch && !condition_test(match_arch))
112                 return false;
113
114         if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
115                 return false;
116
117         if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
118                 return false;
119
120         if (match_driver) {
121                 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
122                         return false;
123                 else if (!streq_ptr(match_driver, dev_driver))
124                         return false;
125         }
126
127         if (match_type && !streq_ptr(match_type, dev_type))
128                 return false;
129
130         if (match_name) {
131                 if (!dev_name || fnmatch(match_name, dev_name, 0))
132                         return false;
133                 else if (ignore_name_match) {
134                         log_warning("ifname (%s) matched config, but is ignored as it is not the original name", dev_name);
135                         return false;
136                 }
137         }
138
139         return true;
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                 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 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
307         unsigned i;
308
309         assert(f);
310         assert(addresses);
311         assert(size);
312
313         for (i = 0; i < size; i++)
314                 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
315                         (i < (size - 1)) ? " ": "");
316 }
317
318 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
319         _cleanup_free_ struct in_addr *addresses = NULL;
320         int size = 0;
321         const char *word, *state;
322         size_t len;
323
324         assert(ret);
325         assert(string);
326
327         FOREACH_WORD(word, len, string, state) {
328                 _cleanup_free_ char *addr_str = NULL;
329                 struct in_addr *new_addresses;
330                 int r;
331
332                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
333                 if (!new_addresses)
334                         return -ENOMEM;
335                 else
336                         addresses = new_addresses;
337
338                 addr_str = strndup(word, len);
339                 if (!addr_str)
340                         return -ENOMEM;
341
342                 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
343                 if (r <= 0)
344                         continue;
345
346                 size ++;
347         }
348
349         *ret = addresses;
350         addresses = NULL;
351
352         return size;
353 }
354
355 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
356         _cleanup_free_ struct in6_addr *addresses = NULL;
357         int size = 0;
358         const char *word, *state;
359         size_t len;
360
361         assert(ret);
362         assert(string);
363
364         FOREACH_WORD(word, len, string, state) {
365                 _cleanup_free_ char *addr_str = NULL;
366                 struct in6_addr *new_addresses;
367                 int r;
368
369                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
370                 if (!new_addresses)
371                         return -ENOMEM;
372                 else
373                         addresses = new_addresses;
374
375                 addr_str = strndup(word, len);
376                 if (!addr_str)
377                         return -ENOMEM;
378
379                 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
380                 if (r <= 0)
381                         continue;
382
383                 size++;
384         }
385
386         *ret = addresses;
387         addresses = NULL;
388
389         return size;
390 }
391
392 void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
393         unsigned i;
394
395         assert(f);
396         assert(key);
397         assert(routes);
398         assert(size);
399
400         fprintf(f, "%s=", key);
401
402         for (i = 0; i < size; i++)
403                 fprintf(f, "%s/%" PRIu8 ",%s%s", inet_ntoa(routes[i].dst_addr),
404                         routes[i].dst_prefixlen, inet_ntoa(routes[i].gw_addr),
405                         (i < (size - 1)) ? " ": "");
406
407         fputs("\n", f);
408 }
409
410 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
411         _cleanup_free_ struct sd_dhcp_route *routes = NULL;
412         size_t size = 0, allocated = 0;
413         const char *word, *state;
414         size_t len;
415
416         assert(ret);
417         assert(ret_size);
418         assert(ret_allocated);
419         assert(string);
420
421         FOREACH_WORD(word, len, string, state) {
422                 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
423                 _cleanup_free_ char* entry = NULL;
424                 char *tok, *tok_end;
425                 unsigned n;
426                 int r;
427
428                 if (!GREEDY_REALLOC(routes, allocated, size + 1))
429                         return -ENOMEM;
430
431                 entry = strndup(word, len);
432                 if(!entry)
433                         return -ENOMEM;
434
435                 tok = entry;
436
437                 /* get the subnet */
438                 tok_end = strchr(tok, '/');
439                 if (!tok_end)
440                         continue;
441                 *tok_end = '\0';
442
443                 r = inet_aton(tok, &routes[size].dst_addr);
444                 if (r == 0)
445                         continue;
446
447                 tok = tok_end + 1;
448
449                 /* get the prefixlen */
450                 tok_end = strchr(tok, ',');
451                 if (!tok_end)
452                         continue;
453
454                 *tok_end = '\0';
455
456                 r = safe_atou(tok, &n);
457                 if (r < 0 || n > 32)
458                         continue;
459
460                 routes[size].dst_prefixlen = (uint8_t) n;
461                 tok = tok_end + 1;
462
463                 /* get the gateway */
464                 r = inet_aton(tok, &routes[size].gw_addr);
465                 if (r == 0)
466                         continue;
467
468                 size++;
469         }
470
471         *ret_size = size;
472         *ret_allocated = allocated;
473         *ret = routes;
474         routes = NULL;
475
476         return 0;
477 }