chiark / gitweb /
sd-network: remove redundant array size parameter from functions that return arrays
[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 "dhcp-lease-internal.h"
32 #include "log.h"
33 #include "utf8.h"
34 #include "util.h"
35 #include "conf-parser.h"
36 #include "condition.h"
37
38 const char *net_get_name(struct udev_device *device) {
39         const char *name = NULL, *field = NULL;
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",
45                        "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
46                 name = udev_device_get_property_value(device, field);
47                 if (name)
48                         break;
49         }
50
51         return name;
52 }
53
54 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
55
56 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
57         size_t l, sz = 0;
58         const char *name = NULL;
59         int r;
60         uint8_t *v;
61
62         assert(device);
63
64         name = net_get_name(device);
65         if (!name)
66                 return -ENOENT;
67
68         l = strlen(name);
69         sz = sizeof(sd_id128_t) + l;
70         v = alloca(sz);
71
72         /* fetch some persistent data unique to this machine */
73         r = sd_id128_get_machine((sd_id128_t*) v);
74         if (r < 0)
75                  return r;
76         memcpy(v + sizeof(sd_id128_t), name, l);
77
78         /* Let's hash the machine ID plus the device name. We
79         * use a fixed, but originally randomly created hash
80         * key here. */
81         siphash24(result, v, sz, HASH_KEY.bytes);
82
83         return 0;
84 }
85
86 bool net_match_config(const struct ether_addr *match_mac,
87                       const char *match_path,
88                       const char *match_driver,
89                       const char *match_type,
90                       const char *match_name,
91                       Condition *match_host,
92                       Condition *match_virt,
93                       Condition *match_kernel,
94                       Condition *match_arch,
95                       const struct ether_addr *dev_mac,
96                       const char *dev_path,
97                       const char *dev_parent_driver,
98                       const char *dev_driver,
99                       const char *dev_type,
100                       const char *dev_name) {
101
102         if (match_host && !condition_test_host(match_host))
103                 return 0;
104
105         if (match_virt && !condition_test_virtualization(match_virt))
106                 return 0;
107
108         if (match_kernel && !condition_test_kernel_command_line(match_kernel))
109                 return 0;
110
111         if (match_arch && !condition_test_architecture(match_arch))
112                 return 0;
113
114         if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
115                 return 0;
116
117         if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
118                 return 0;
119
120         if (match_driver) {
121                 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
122                         return 0;
123                 else if (!streq_ptr(match_driver, dev_driver))
124                         return 0;
125         }
126
127         if (match_type && !streq_ptr(match_type, dev_type))
128                 return 0;
129
130         if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
131                 return 0;
132
133         return 1;
134 }
135
136 unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
137         assert(addr);
138
139         return 32 - u32ctz(be32toh(addr->s_addr));
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                 free(n);
210                 return 0;
211         }
212
213         free(*s);
214         if (*n) {
215                 *s = n;
216                 n = NULL;
217         } else
218                 *s = NULL;
219
220         return 0;
221 }
222
223 int config_parse_ifalias(const char *unit,
224                          const char *filename,
225                          unsigned line,
226                          const char *section,
227                          unsigned section_line,
228                          const char *lvalue,
229                          int ltype,
230                          const char *rvalue,
231                          void *data,
232                          void *userdata) {
233
234         char **s = data;
235         char *n;
236
237         assert(filename);
238         assert(lvalue);
239         assert(rvalue);
240         assert(data);
241
242         n = strdup(rvalue);
243         if (!n)
244                 return log_oom();
245
246         if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
247                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
248                            "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
249                 free(n);
250                 return 0;
251         }
252
253         free(*s);
254         if (*n)
255                 *s = n;
256         else {
257                 free(n);
258                 *s = NULL;
259         }
260
261         return 0;
262 }
263
264 int config_parse_hwaddr(const char *unit,
265                         const char *filename,
266                         unsigned line,
267                         const char *section,
268                         unsigned section_line,
269                         const char *lvalue,
270                         int ltype,
271                         const char *rvalue,
272                         void *data,
273                         void *userdata) {
274         struct ether_addr **hwaddr = data;
275         struct ether_addr *n;
276         int r;
277
278         assert(filename);
279         assert(lvalue);
280         assert(rvalue);
281         assert(data);
282
283         n = new0(struct ether_addr, 1);
284         if (!n)
285                 return log_oom();
286
287         r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
288                    &n->ether_addr_octet[0],
289                    &n->ether_addr_octet[1],
290                    &n->ether_addr_octet[2],
291                    &n->ether_addr_octet[3],
292                    &n->ether_addr_octet[4],
293                    &n->ether_addr_octet[5]);
294         if (r != 6) {
295                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
296                            "Not a valid MAC address, ignoring assignment: %s", rvalue);
297                 free(n);
298                 return 0;
299         }
300
301         free(*hwaddr);
302         *hwaddr = n;
303
304         return 0;
305 }
306
307 int net_parse_inaddr(const char *address, unsigned char *family, void *dst) {
308         int r;
309
310         assert(address);
311         assert(family);
312         assert(dst);
313
314         /* IPv4 */
315         r = inet_pton(AF_INET, address, dst);
316         if (r > 0) {
317                 /* succsefully parsed IPv4 address */
318                 if (*family == AF_UNSPEC)
319                         *family = AF_INET;
320                 else if (*family != AF_INET)
321                         return -EINVAL;
322         } else  if (r < 0)
323                 return -errno;
324         else {
325                 /* not an IPv4 address, so let's try IPv6 */
326                 r = inet_pton(AF_INET6, address, dst);
327                 if (r > 0) {
328                         /* successfully parsed IPv6 address */
329                         if (*family == AF_UNSPEC)
330                                 *family = AF_INET6;
331                         else if (*family != AF_INET6)
332                                 return -EINVAL;
333                 } else if (r < 0)
334                         return -errno;
335                 else
336                         return -EINVAL;
337         }
338
339         return 0;
340 }
341
342 void serialize_in_addrs(FILE *f, const char *key, const struct in_addr *addresses, size_t size) {
343         unsigned i;
344
345         assert(f);
346         assert(key);
347         assert(addresses);
348         assert(size);
349
350         fprintf(f, "%s=", key);
351
352         for (i = 0; i < size; i++)
353                 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
354                         (i < (size - 1)) ? " ": "");
355
356         fputs("\n", f);
357 }
358
359 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
360         _cleanup_free_ struct in_addr *addresses = NULL;
361         int size = 0;
362         char *word, *state;
363         size_t len;
364
365         assert(ret);
366         assert(string);
367
368         FOREACH_WORD(word, len, string, state) {
369                 _cleanup_free_ char *addr_str = NULL;
370                 struct in_addr *new_addresses;
371                 int r;
372
373                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
374                 if (!new_addresses)
375                         return -ENOMEM;
376                 else
377                         addresses = new_addresses;
378
379                 addr_str = strndup(word, len);
380                 if (!addr_str)
381                         return -ENOMEM;
382
383                 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
384                 if (r <= 0)
385                         continue;
386
387                 size ++;
388         }
389
390         *ret = addresses;
391         addresses = NULL;
392
393         return size;
394 }
395
396 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
397         _cleanup_free_ struct in6_addr *addresses = NULL;
398         int size = 0;
399         char *word, *state;
400         size_t len;
401
402         assert(ret);
403         assert(string);
404
405         FOREACH_WORD(word, len, string, state) {
406                 _cleanup_free_ char *addr_str = NULL;
407                 struct in6_addr *new_addresses;
408                 int r;
409
410                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
411                 if (!new_addresses)
412                         return -ENOMEM;
413                 else
414                         addresses = new_addresses;
415
416                 addr_str = strndup(word, len);
417                 if (!addr_str)
418                         return -ENOMEM;
419
420                 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
421                 if (r <= 0)
422                         continue;
423
424                 size++;
425         }
426
427         *ret = addresses;
428         addresses = NULL;
429
430         return size;
431 }
432
433 void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
434         unsigned i;
435
436         assert(f);
437         assert(key);
438         assert(routes);
439         assert(size);
440
441         fprintf(f, "%s=", key);
442
443         for (i = 0; i < size; i++)
444                 fprintf(f, "%s/%" PRIu8 ",%s%s", inet_ntoa(routes[i].dst_addr),
445                         routes[i].dst_prefixlen, inet_ntoa(routes[i].gw_addr),
446                         (i < (size - 1)) ? " ": "");
447
448         fputs("\n", f);
449 }
450
451 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
452         _cleanup_free_ struct sd_dhcp_route *routes = NULL;
453         size_t size = 0, allocated = 0;
454         char *word, *state;
455         size_t len;
456
457         assert(ret);
458         assert(ret_size);
459         assert(ret_allocated);
460         assert(string);
461
462         FOREACH_WORD(word, len, string, state) {
463                 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
464                 _cleanup_free_ char* entry = NULL;
465                 char *tok, *tok_end;
466                 unsigned n;
467                 int r;
468
469                 if (!GREEDY_REALLOC(routes, allocated, size + 1))
470                         return -ENOMEM;
471
472                 entry = strndup(word, len);
473                 if(!entry)
474                         return -ENOMEM;
475
476                 tok = entry;
477
478                 /* get the subnet */
479                 tok_end = strchr(tok, '/');
480                 if (!tok_end)
481                         continue;
482                 *tok_end = '\0';
483
484                 r = inet_aton(tok, &routes[size].dst_addr);
485                 if (r == 0)
486                         continue;
487
488                 tok = tok_end + 1;
489
490                 /* get the prefixlen */
491                 tok_end = strchr(tok, ',');
492                 if (!tok_end)
493                         continue;
494
495                 *tok_end = '\0';
496
497                 r = safe_atou(tok, &n);
498                 if (r < 0 || n > 32)
499                         continue;
500
501                 routes[size].dst_prefixlen = (uint8_t) n;
502                 tok = tok_end + 1;
503
504                 /* get the gateway */
505                 r = inet_aton(tok, &routes[size].gw_addr);
506                 if (r == 0)
507                         continue;
508
509                 size++;
510         }
511
512         *ret_size = size;
513         *ret_allocated = allocated;
514         *ret = routes;
515         routes = NULL;
516
517         return 0;
518 }