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