chiark / gitweb /
sysusers: fix selinux context of backup files
[elogind.git] / src / network / networkd-network.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 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 <ctype.h>
23 #include <net/if.h>
24
25 #include "networkd.h"
26 #include "networkd-netdev.h"
27 #include "network-internal.h"
28 #include "path-util.h"
29 #include "conf-files.h"
30 #include "conf-parser.h"
31 #include "util.h"
32
33 static int network_load_one(Manager *manager, const char *filename) {
34         _cleanup_network_free_ Network *network = NULL;
35         _cleanup_fclose_ FILE *file = NULL;
36         Route *route;
37         Address *address;
38         int r;
39
40         assert(manager);
41         assert(filename);
42
43         file = fopen(filename, "re");
44         if (!file) {
45                 if (errno == ENOENT)
46                         return 0;
47                 else
48                         return -errno;
49         }
50
51         if (null_or_empty_fd(fileno(file))) {
52                 log_debug("Skipping empty file: %s", filename);
53                 return 0;
54         }
55
56         network = new0(Network, 1);
57         if (!network)
58                 return log_oom();
59
60         network->manager = manager;
61
62         LIST_HEAD_INIT(network->static_addresses);
63         LIST_HEAD_INIT(network->static_routes);
64
65         network->vlans = hashmap_new(string_hash_func, string_compare_func);
66         if (!network->vlans)
67                 return log_oom();
68
69         network->macvlans = hashmap_new(string_hash_func, string_compare_func);
70         if (!network->macvlans)
71                 return log_oom();
72
73         network->vxlans = hashmap_new(string_hash_func, string_compare_func);
74         if (!network->vxlans)
75                 return log_oom();
76
77         network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
78         if (!network->addresses_by_section)
79                 return log_oom();
80
81         network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
82         if (!network->routes_by_section)
83                 return log_oom();
84
85         network->filename = strdup(filename);
86         if (!network->filename)
87                 return log_oom();
88
89         network->dhcp_ntp = true;
90         network->dhcp_dns = true;
91         network->dhcp_hostname = true;
92         network->dhcp_domainname = true;
93         network->dhcp_routes = true;
94         network->dhcp_sendhost = true;
95
96         r = config_parse(NULL, filename, file,
97                          "Match\0Network\0Address\0Route\0DHCP\0DHCPv4\0",
98                          config_item_perf_lookup, network_network_gperf_lookup,
99                          false, false, true, network);
100         if (r < 0)
101                 return r;
102
103         LIST_PREPEND(networks, manager->networks, network);
104
105         LIST_FOREACH(routes, route, network->static_routes) {
106                 if (!route->family) {
107                         log_warning("Route section without Gateway field configured in %s. "
108                                     "Ignoring", filename);
109                         return 0;
110                 }
111         }
112
113         LIST_FOREACH(addresses, address, network->static_addresses) {
114                 if (!address->family) {
115                         log_warning("Address section without Address field configured in %s. "
116                                     "Ignoring", filename);
117                         return 0;
118                 }
119         }
120
121         network = NULL;
122
123         return 0;
124 }
125
126 int network_load(Manager *manager) {
127         Network *network;
128         _cleanup_strv_free_ char **files = NULL;
129         char **f;
130         int r;
131
132         assert(manager);
133
134         while ((network = manager->networks))
135                 network_free(network);
136
137         r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
138         if (r < 0) {
139                 log_error("Failed to enumerate network files: %s", strerror(-r));
140                 return r;
141         }
142
143         STRV_FOREACH_BACKWARDS(f, files) {
144                 r = network_load_one(manager, *f);
145                 if (r < 0)
146                         return r;
147         }
148
149         return 0;
150 }
151
152 void network_free(Network *network) {
153         NetDev *netdev;
154         Route *route;
155         Address *address;
156         Iterator i;
157
158         if (!network)
159                 return;
160
161         free(network->filename);
162
163         free(network->match_mac);
164         free(network->match_path);
165         free(network->match_driver);
166         free(network->match_type);
167         free(network->match_name);
168
169         free(network->description);
170         free(network->dhcp_vendor_class_identifier);
171
172         while ((address = network->ntp)) {
173                 LIST_REMOVE(addresses, network->ntp, address);
174                 address_free(address);
175         }
176
177         while ((address = network->dns)) {
178                 LIST_REMOVE(addresses, network->dns, address);
179                 address_free(address);
180         }
181
182         netdev_unref(network->bridge);
183
184         netdev_unref(network->bond);
185
186         netdev_unref(network->tunnel);
187
188         HASHMAP_FOREACH(netdev, network->vlans, i)
189                 netdev_unref(netdev);
190         hashmap_free(network->vlans);
191
192         HASHMAP_FOREACH(netdev, network->macvlans, i)
193                 netdev_unref(netdev);
194         hashmap_free(network->macvlans);
195
196         HASHMAP_FOREACH(netdev, network->vxlans, i)
197                 netdev_unref(netdev);
198         hashmap_free(network->vxlans);
199
200         while ((route = network->static_routes))
201                 route_free(route);
202
203         while ((address = network->static_addresses))
204                 address_free(address);
205
206         hashmap_free(network->addresses_by_section);
207         hashmap_free(network->routes_by_section);
208
209         if (network->manager && network->manager->networks)
210                 LIST_REMOVE(networks, network->manager->networks, network);
211
212         condition_free_list(network->match_host);
213         condition_free_list(network->match_virt);
214         condition_free_list(network->match_kernel);
215         condition_free_list(network->match_arch);
216
217         free(network);
218 }
219
220 int network_get(Manager *manager, struct udev_device *device,
221                 const char *ifname, const struct ether_addr *address,
222                 Network **ret) {
223         Network *network;
224
225         assert(manager);
226         assert(ret);
227
228         LIST_FOREACH(networks, network, manager->networks) {
229                 if (net_match_config(network->match_mac, network->match_path,
230                                      network->match_driver, network->match_type,
231                                      network->match_name, network->match_host,
232                                      network->match_virt, network->match_kernel,
233                                      network->match_arch,
234                                      address,
235                                      udev_device_get_property_value(device, "ID_PATH"),
236                                      udev_device_get_driver(udev_device_get_parent(device)),
237                                      udev_device_get_property_value(device, "ID_NET_DRIVER"),
238                                      udev_device_get_devtype(device),
239                                      ifname)) {
240                         log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
241                                   network->filename);
242                         *ret = network;
243                         return 0;
244                 }
245         }
246
247         *ret = NULL;
248
249         return -ENOENT;
250 }
251
252 int network_apply(Manager *manager, Network *network, Link *link) {
253         int r;
254
255         link->network = network;
256
257         if (network->dns || network->ntp) {
258                 r = link_save(link);
259                 if (r < 0)
260                         return r;
261         }
262
263         return 0;
264 }
265
266 int config_parse_netdev(const char *unit,
267                 const char *filename,
268                 unsigned line,
269                 const char *section,
270                 unsigned section_line,
271                 const char *lvalue,
272                 int ltype,
273                 const char *rvalue,
274                 void *data,
275                 void *userdata) {
276         Network *network = userdata;
277         _cleanup_free_ char *kind_string = NULL;
278         char *p;
279         NetDev *netdev;
280         NetDevKind kind;
281         int r;
282
283         assert(filename);
284         assert(lvalue);
285         assert(rvalue);
286         assert(data);
287
288         kind_string = strdup(lvalue);
289         if (!kind_string)
290                 return log_oom();
291
292         /* the keys are CamelCase versions of the kind */
293         for (p = kind_string; *p; p++)
294                 *p = tolower(*p);
295
296         kind = netdev_kind_from_string(kind_string);
297         if (kind == _NETDEV_KIND_INVALID) {
298                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
299                            "Invalid NetDev kind: %s", lvalue);
300                 return 0;
301         }
302
303         r = netdev_get(network->manager, rvalue, &netdev);
304         if (r < 0) {
305                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
306                            "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
307                 return 0;
308         }
309
310         if (netdev->kind != kind) {
311                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
312                            "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
313                 return 0;
314         }
315
316         switch (kind) {
317         case NETDEV_KIND_BRIDGE:
318                 network->bridge = netdev;
319
320                 break;
321         case NETDEV_KIND_BOND:
322                 network->bond = netdev;
323
324                 break;
325         case NETDEV_KIND_VLAN:
326                 r = hashmap_put(network->vlans, netdev->ifname, netdev);
327                 if (r < 0) {
328                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
329                                    "Can not add VLAN '%s' to network: %s",
330                                    rvalue, strerror(-r));
331                         return 0;
332                 }
333
334                 break;
335         case NETDEV_KIND_MACVLAN:
336                 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
337                 if (r < 0) {
338                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
339                                    "Can not add MACVLAN '%s' to network: %s",
340                                    rvalue, strerror(-r));
341                         return 0;
342                 }
343
344                 break;
345         case NETDEV_KIND_VXLAN:
346                 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
347                 if (r < 0) {
348                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
349                                    "Can not add VXLAN '%s' to network: %s",
350                                    rvalue, strerror(-r));
351                         return 0;
352                 }
353
354                 break;
355         default:
356                 assert_not_reached("Can not parse NetDev");
357         }
358
359         netdev_ref(netdev);
360
361         return 0;
362 }
363
364 int config_parse_tunnel(const char *unit,
365                         const char *filename,
366                         unsigned line,
367                         const char *section,
368                         unsigned section_line,
369                         const char *lvalue,
370                         int ltype,
371                         const char *rvalue,
372                         void *data,
373                         void *userdata) {
374         Network *network = userdata;
375         NetDev *netdev;
376         int r;
377
378         assert(filename);
379         assert(lvalue);
380         assert(rvalue);
381         assert(data);
382
383         r = netdev_get(network->manager, rvalue, &netdev);
384         if (r < 0) {
385                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
386                            "Tunnel is invalid, ignoring assignment: %s", rvalue);
387                 return 0;
388         }
389
390         if (netdev->kind != NETDEV_KIND_IPIP &&
391             netdev->kind != NETDEV_KIND_SIT &&
392             netdev->kind != NETDEV_KIND_GRE &&
393             netdev->kind != NETDEV_KIND_VTI) {
394                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
395                            "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
396                 return 0;
397         }
398
399         network->tunnel = netdev;
400
401         return 0;
402 }