chiark / gitweb /
machinectl: fix success check when getting pty from within container
[elogind.git] / src / network / networkd-address.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 <net/if.h>
23
24 #include "networkd.h"
25
26 #include "utf8.h"
27 #include "util.h"
28 #include "conf-parser.h"
29 #include "net-util.h"
30
31 int address_new(Network *network, unsigned section, Address **ret) {
32         _cleanup_address_free_ Address *address = NULL;
33
34         if (section) {
35                 uint64_t key = section;
36                 address = hashmap_get(network->addresses_by_section, &key);
37                 if (address) {
38                         *ret = address;
39                         address = NULL;
40
41                         return 0;
42                 }
43         }
44
45         address = new0(Address, 1);
46         if (!address)
47                 return -ENOMEM;
48
49         address->network = network;
50
51         LIST_PREPEND(addresses, network->addresses, address);
52
53         if (section) {
54                 address->section = section;
55                 hashmap_put(network->addresses_by_section, &address->section, address);
56         }
57
58         *ret = address;
59         address = NULL;
60
61         return 0;
62 }
63
64 void address_free(Address *address) {
65         if (!address)
66                 return;
67
68         LIST_REMOVE(addresses, address->network->addresses, address);
69
70         if (address->section)
71                 hashmap_remove(address->network->addresses_by_section,
72                                &address->section);
73
74         free(address);
75 }
76
77 int address_configure(Address *address, Link *link,
78                       sd_rtnl_message_handler_t callback) {
79         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
80         int r;
81
82         assert(address);
83         assert(address->family == AF_INET || address->family == AF_INET6);
84         assert(link);
85         assert(link->ifindex > 0);
86         assert(link->manager);
87         assert(link->manager->rtnl);
88
89         r = sd_rtnl_message_addr_new(RTM_NEWADDR, link->ifindex,
90                         address->family, address->prefixlen,
91                         IFA_F_PERMANENT, RT_SCOPE_UNIVERSE, &req);
92         if (r < 0) {
93                 log_error("Could not allocate RTM_NEWADDR message: %s",
94                           strerror(-r));
95                 return r;
96         }
97
98         if (address->family == AF_INET)
99                 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
100         else if (address->family == AF_INET6)
101                 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
102         if (r < 0) {
103                 log_error("Could not append IFA_LOCAL attribute: %s",
104                           strerror(-r));
105                 return r;
106         }
107
108         if (address->family == AF_INET) {
109                 struct in_addr broadcast;
110
111                 broadcast.s_addr = address->in_addr.in.s_addr | address->netmask.s_addr;
112
113                 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &broadcast);
114                 if (r < 0) {
115                         log_error("Could not append IFA_BROADCAST attribute: %s",
116                                   strerror(-r));
117                         return r;
118                 }
119         }
120
121         if (address->label) {
122                 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
123                 if (r < 0) {
124                         log_error("Could not append IFA_LABEL attribute: %s",
125                                   strerror(-r));
126                         return r;
127                 }
128         }
129
130         r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
131         if (r < 0) {
132                 log_error("Could not send rtnetlink message: %s", strerror(-r));
133                 return r;
134         }
135
136         return 0;
137 }
138
139 int config_parse_address(const char *unit,
140                 const char *filename,
141                 unsigned line,
142                 const char *section,
143                 unsigned section_line,
144                 const char *lvalue,
145                 int ltype,
146                 const char *rvalue,
147                 void *data,
148                 void *userdata) {
149         Network *network = userdata;
150         _cleanup_address_free_ Address *n = NULL;
151         _cleanup_free_ char *address = NULL;
152         const char *e;
153         int r;
154
155         assert(filename);
156         assert(section);
157         assert(lvalue);
158         assert(rvalue);
159         assert(data);
160
161         if (streq(section, "Network")) {
162                 /* we are not in an Address section, so treat
163                  * this as the special '0' section */
164                 section_line = 0;
165         }
166
167         r = address_new(network, section_line, &n);
168         if (r < 0)
169                 return r;
170
171         /* Address=address/prefixlen */
172
173         /* prefixlen */
174         e = strchr(rvalue, '/');
175         if (e) {
176                 unsigned i;
177                 r = safe_atou(e + 1, &i);
178                 if (r < 0) {
179                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
180                                    "Interface prefix length is invalid, "
181                                    "ignoring assignment: %s", e + 1);
182                         return 0;
183                 }
184
185                 n->prefixlen = (unsigned char) i;
186                 n->netmask.s_addr = htonl(0xfffffffflu >> n->prefixlen);
187
188                 address = strndup(rvalue, e - rvalue);
189                 if (!address)
190                         return log_oom();
191         } else {
192                 address = strdup(rvalue);
193                 if (!address)
194                         return log_oom();
195         }
196
197         r = net_parse_inaddr(address, &n->family, &n->in_addr);
198         if (r < 0) {
199                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
200                            "Address is invalid, ignoring assignment: %s", address);
201                 return 0;
202         }
203
204         n = NULL;
205
206         return 0;
207 }
208
209 int config_parse_label(const char *unit,
210                 const char *filename,
211                 unsigned line,
212                 const char *section,
213                 unsigned section_line,
214                 const char *lvalue,
215                 int ltype,
216                 const char *rvalue,
217                 void *data,
218                 void *userdata) {
219         Network *network = userdata;
220         _cleanup_address_free_ Address *n = NULL;
221         char *label;
222         int r;
223
224         assert(filename);
225         assert(section);
226         assert(lvalue);
227         assert(rvalue);
228         assert(data);
229
230         r = address_new(network, section_line, &n);
231         if (r < 0)
232                 return r;
233
234         label = strdup(rvalue);
235         if (!label)
236                 return log_oom();
237
238         if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
239                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
240                            "Interface label is not ASCII clean or is too"
241                            " long, ignoring assignment: %s", rvalue);
242                 free(label);
243                 return 0;
244         }
245
246         free(n->label);
247         if (*label)
248                 n->label = label;
249         else {
250                 free(label);
251                 n->label = NULL;
252         }
253
254         n = NULL;
255
256         return 0;
257 }