chiark / gitweb /
network-intenal: user _cleanup_ macro in parse_ifname
[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
101         if (match_host && !condition_test(match_host))
102                 return false;
103
104         if (match_virt && !condition_test(match_virt))
105                 return false;
106
107         if (match_kernel && !condition_test(match_kernel))
108                 return false;
109
110         if (match_arch && !condition_test(match_arch))
111                 return false;
112
113         if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
114                 return false;
115
116         if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
117                 return false;
118
119         if (match_driver) {
120                 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
121                         return false;
122                 else if (!streq_ptr(match_driver, dev_driver))
123                         return false;
124         }
125
126         if (match_type && !streq_ptr(match_type, dev_type))
127                 return false;
128
129         if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
130                         return false;
131
132         return true;
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         _cleanup_free_ char *n = NULL;
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                 return 0;
242         }
243
244         free(*s);
245         if (*n) {
246                 *s = n;
247                 n = NULL;
248         } else
249                 *s = NULL;
250
251         return 0;
252 }
253
254 int config_parse_hwaddr(const char *unit,
255                         const char *filename,
256                         unsigned line,
257                         const char *section,
258                         unsigned section_line,
259                         const char *lvalue,
260                         int ltype,
261                         const char *rvalue,
262                         void *data,
263                         void *userdata) {
264         struct ether_addr **hwaddr = data;
265         struct ether_addr *n;
266         int r;
267
268         assert(filename);
269         assert(lvalue);
270         assert(rvalue);
271         assert(data);
272
273         n = new0(struct ether_addr, 1);
274         if (!n)
275                 return log_oom();
276
277         r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
278                    &n->ether_addr_octet[0],
279                    &n->ether_addr_octet[1],
280                    &n->ether_addr_octet[2],
281                    &n->ether_addr_octet[3],
282                    &n->ether_addr_octet[4],
283                    &n->ether_addr_octet[5]);
284         if (r != 6) {
285                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
286                            "Not a valid MAC address, ignoring assignment: %s", rvalue);
287                 free(n);
288                 return 0;
289         }
290
291         free(*hwaddr);
292         *hwaddr = n;
293
294         return 0;
295 }
296
297 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
298         unsigned i;
299
300         assert(f);
301         assert(addresses);
302         assert(size);
303
304         for (i = 0; i < size; i++)
305                 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
306                         (i < (size - 1)) ? " ": "");
307 }
308
309 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
310         _cleanup_free_ struct in_addr *addresses = NULL;
311         int size = 0;
312         const char *word, *state;
313         size_t len;
314
315         assert(ret);
316         assert(string);
317
318         FOREACH_WORD(word, len, string, state) {
319                 _cleanup_free_ char *addr_str = NULL;
320                 struct in_addr *new_addresses;
321                 int r;
322
323                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
324                 if (!new_addresses)
325                         return -ENOMEM;
326                 else
327                         addresses = new_addresses;
328
329                 addr_str = strndup(word, len);
330                 if (!addr_str)
331                         return -ENOMEM;
332
333                 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
334                 if (r <= 0)
335                         continue;
336
337                 size ++;
338         }
339
340         *ret = addresses;
341         addresses = NULL;
342
343         return size;
344 }
345
346 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
347         _cleanup_free_ struct in6_addr *addresses = NULL;
348         int size = 0;
349         const char *word, *state;
350         size_t len;
351
352         assert(ret);
353         assert(string);
354
355         FOREACH_WORD(word, len, string, state) {
356                 _cleanup_free_ char *addr_str = NULL;
357                 struct in6_addr *new_addresses;
358                 int r;
359
360                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
361                 if (!new_addresses)
362                         return -ENOMEM;
363                 else
364                         addresses = new_addresses;
365
366                 addr_str = strndup(word, len);
367                 if (!addr_str)
368                         return -ENOMEM;
369
370                 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
371                 if (r <= 0)
372                         continue;
373
374                 size++;
375         }
376
377         *ret = addresses;
378         addresses = NULL;
379
380         return size;
381 }
382
383 void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
384         unsigned i;
385
386         assert(f);
387         assert(key);
388         assert(routes);
389         assert(size);
390
391         fprintf(f, "%s=", key);
392
393         for (i = 0; i < size; i++) {
394                 fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr),
395                         routes[i].dst_prefixlen);
396                 fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr),
397                         (i < (size - 1)) ? " ": "");
398         }
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 }