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