chiark / gitweb /
dhcp-server: simplify dhcp server unref call
[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 "log.h"
32 #include "utf8.h"
33 #include "util.h"
34 #include "conf-parser.h"
35 #include "condition.h"
36
37 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
38
39 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
40         size_t l, sz = 0;
41         const char *name = NULL, *field = NULL;
42         int r;
43         uint8_t *v;
44
45         /* fetch some persistent data unique (on this machine) to this device */
46         FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
47                 name = udev_device_get_property_value(device, field);
48                 if (name)
49                         break;
50         }
51
52         if (!name)
53                 return -ENOENT;
54
55         l = strlen(name);
56         sz = sizeof(sd_id128_t) + l;
57         v = alloca(sz);
58
59         /* fetch some persistent data unique to this machine */
60         r = sd_id128_get_machine((sd_id128_t*) v);
61         if (r < 0)
62                  return r;
63         memcpy(v + sizeof(sd_id128_t), name, l);
64
65         /* Let's hash the machine ID plus the device name. We
66         * use a fixed, but originally randomly created hash
67         * key here. */
68         siphash24(result, v, sz, HASH_KEY.bytes);
69
70         return 0;
71 }
72
73 bool net_match_config(const struct ether_addr *match_mac,
74                       const char *match_path,
75                       const char *match_driver,
76                       const char *match_type,
77                       const char *match_name,
78                       Condition *match_host,
79                       Condition *match_virt,
80                       Condition *match_kernel,
81                       Condition *match_arch,
82                       const struct ether_addr *dev_mac,
83                       const char *dev_path,
84                       const char *dev_parent_driver,
85                       const char *dev_driver,
86                       const char *dev_type,
87                       const char *dev_name) {
88
89         if (match_host && !condition_test_host(match_host))
90                 return 0;
91
92         if (match_virt && !condition_test_virtualization(match_virt))
93                 return 0;
94
95         if (match_kernel && !condition_test_kernel_command_line(match_kernel))
96                 return 0;
97
98         if (match_arch && !condition_test_architecture(match_arch))
99                 return 0;
100
101         if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
102                 return 0;
103
104         if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
105                 return 0;
106
107         if (match_driver) {
108                 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
109                         return 0;
110                 else if (!streq_ptr(match_driver, dev_driver))
111                         return 0;
112         }
113
114         if (match_type && !streq_ptr(match_type, dev_type))
115                 return 0;
116
117         if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
118                 return 0;
119
120         return 1;
121 }
122
123 unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
124         assert(addr);
125
126         return 32 - u32ctz(be32toh(addr->s_addr));
127 }
128
129 int config_parse_net_condition(const char *unit,
130                                const char *filename,
131                                unsigned line,
132                                const char *section,
133                                unsigned section_line,
134                                const char *lvalue,
135                                int ltype,
136                                const char *rvalue,
137                                void *data,
138                                void *userdata) {
139
140         ConditionType cond = ltype;
141         Condition **ret = data;
142         bool negate;
143         Condition *c;
144         _cleanup_free_ char *s = NULL;
145
146         assert(filename);
147         assert(lvalue);
148         assert(rvalue);
149         assert(data);
150
151         negate = rvalue[0] == '!';
152         if (negate)
153                 rvalue++;
154
155         s = strdup(rvalue);
156         if (!s)
157                 return log_oom();
158
159         c = condition_new(cond, s, false, negate);
160         if (!c)
161                 return log_oom();
162
163         if (*ret)
164                 condition_free(*ret);
165
166         *ret = c;
167         return 0;
168 }
169
170 int config_parse_ifname(const char *unit,
171                         const char *filename,
172                         unsigned line,
173                         const char *section,
174                         unsigned section_line,
175                         const char *lvalue,
176                         int ltype,
177                         const char *rvalue,
178                         void *data,
179                         void *userdata) {
180
181         char **s = data;
182         _cleanup_free_ char *n = NULL;
183
184         assert(filename);
185         assert(lvalue);
186         assert(rvalue);
187         assert(data);
188
189         n = strdup(rvalue);
190         if (!n)
191                 return log_oom();
192
193         if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
194                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
195                            "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
196                 free(n);
197                 return 0;
198         }
199
200         free(*s);
201         if (*n) {
202                 *s = n;
203                 n = NULL;
204         } else
205                 *s = NULL;
206
207         return 0;
208 }
209
210 int config_parse_ifalias(const char *unit,
211                          const char *filename,
212                          unsigned line,
213                          const char *section,
214                          unsigned section_line,
215                          const char *lvalue,
216                          int ltype,
217                          const char *rvalue,
218                          void *data,
219                          void *userdata) {
220
221         char **s = data;
222         char *n;
223
224         assert(filename);
225         assert(lvalue);
226         assert(rvalue);
227         assert(data);
228
229         n = strdup(rvalue);
230         if (!n)
231                 return log_oom();
232
233         if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
234                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
235                            "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
236                 free(n);
237                 return 0;
238         }
239
240         free(*s);
241         if (*n)
242                 *s = n;
243         else {
244                 free(n);
245                 *s = NULL;
246         }
247
248         return 0;
249 }
250
251 int config_parse_hwaddr(const char *unit,
252                         const char *filename,
253                         unsigned line,
254                         const char *section,
255                         unsigned section_line,
256                         const char *lvalue,
257                         int ltype,
258                         const char *rvalue,
259                         void *data,
260                         void *userdata) {
261         struct ether_addr **hwaddr = data;
262         struct ether_addr *n;
263         int r;
264
265         assert(filename);
266         assert(lvalue);
267         assert(rvalue);
268         assert(data);
269
270         n = new0(struct ether_addr, 1);
271         if (!n)
272                 return log_oom();
273
274         r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
275                    &n->ether_addr_octet[0],
276                    &n->ether_addr_octet[1],
277                    &n->ether_addr_octet[2],
278                    &n->ether_addr_octet[3],
279                    &n->ether_addr_octet[4],
280                    &n->ether_addr_octet[5]);
281         if (r != 6) {
282                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
283                            "Not a valid MAC address, ignoring assignment: %s", rvalue);
284                 free(n);
285                 return 0;
286         }
287
288         free(*hwaddr);
289         *hwaddr = n;
290
291         return 0;
292 }
293
294 int net_parse_inaddr(const char *address, unsigned char *family, void *dst) {
295         int r;
296
297         assert(address);
298         assert(family);
299         assert(dst);
300
301         /* IPv4 */
302         r = inet_pton(AF_INET, address, dst);
303         if (r > 0) {
304                 /* succsefully parsed IPv4 address */
305                 if (*family == AF_UNSPEC)
306                         *family = AF_INET;
307                 else if (*family != AF_INET)
308                         return -EINVAL;
309         } else  if (r < 0)
310                 return -errno;
311         else {
312                 /* not an IPv4 address, so let's try IPv6 */
313                 r = inet_pton(AF_INET6, address, dst);
314                 if (r > 0) {
315                         /* successfully parsed IPv6 address */
316                         if (*family == AF_UNSPEC)
317                                 *family = AF_INET6;
318                         else if (*family != AF_INET6)
319                                 return -EINVAL;
320                 } else if (r < 0)
321                         return -errno;
322                 else
323                         return -EINVAL;
324         }
325
326         return 0;
327 }
328
329 void serialize_in_addrs(FILE *f, const char *key, struct in_addr *addresses, size_t size) {
330         unsigned i;
331
332         assert(f);
333         assert(key);
334         assert(addresses);
335         assert(size);
336
337         fprintf(f, "%s=", key);
338
339         for (i = 0; i < size; i++)
340                 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
341                         (i < (size - 1)) ? " ": "");
342
343         fputs("\n", f);
344 }
345
346 int deserialize_in_addrs(struct in_addr **ret, size_t *ret_size, const char *string) {
347         _cleanup_free_ struct in_addr *addresses = NULL;
348         size_t size = 0;
349         char *word, *state;
350         size_t len;
351
352         assert(ret);
353         assert(ret_size);
354         assert(string);
355
356         FOREACH_WORD(word, len, string, state) {
357                 _cleanup_free_ char *addr_str = NULL;
358                 struct in_addr *new_addresses;
359                 int r;
360
361                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
362                 if (!new_addresses)
363                         return -ENOMEM;
364                 else
365                         addresses = new_addresses;
366
367                 addr_str = strndup(word, len);
368                 if (!addr_str)
369                         return -ENOMEM;
370
371                 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
372                 if (r <= 0)
373                         continue;
374
375                 size ++;
376         }
377
378         *ret_size = size;
379         *ret = addresses;
380         addresses = NULL;
381
382         return 0;
383 }
384
385 int deserialize_in6_addrs(struct in6_addr **ret, size_t *ret_size, const char *string) {
386         _cleanup_free_ struct in6_addr *addresses = NULL;
387         size_t size = 0;
388         char *word, *state;
389         size_t len;
390
391         assert(ret);
392         assert(ret_size);
393         assert(string);
394
395         FOREACH_WORD(word, len, string, state) {
396                 _cleanup_free_ char *addr_str = NULL;
397                 struct in6_addr *new_addresses;
398                 int r;
399
400                 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
401                 if (!new_addresses)
402                         return -ENOMEM;
403                 else
404                         addresses = new_addresses;
405
406                 addr_str = strndup(word, len);
407                 if (!addr_str)
408                         return -ENOMEM;
409
410                 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
411                 if (r <= 0)
412                         continue;
413
414                 size++;
415         }
416
417         *ret_size = size;
418         *ret = addresses;
419         addresses = NULL;
420
421         return 0;
422 }