]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-lease.c
sd-dhcp-lease: add sd_dhcp_lease_get_server_identifier()
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-lease.c
CommitLineData
a6cc569e
TG
1/***
2 This file is part of systemd.
3
4 Copyright (C) 2013 Intel Corporation. All rights reserved.
5 Copyright (C) 2014 Tom Gundersen
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <stdlib.h>
22#include <errno.h>
23#include <string.h>
24#include <stdio.h>
25#include <net/ethernet.h>
fe8db0c5 26#include <arpa/inet.h>
a6cc569e
TG
27#include <sys/param.h>
28
29#include "util.h"
30#include "list.h"
fe8db0c5
TG
31#include "mkdir.h"
32#include "fileio.h"
a6cc569e
TG
33
34#include "dhcp-protocol.h"
35#include "dhcp-internal.h"
fe8db0c5
TG
36#include "dhcp-lease-internal.h"
37#include "sd-dhcp-lease.h"
a6cc569e
TG
38#include "sd-dhcp-client.h"
39
40int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
41 assert_return(lease, -EINVAL);
42 assert_return(addr, -EINVAL);
43
44 addr->s_addr = lease->address;
45
46 return 0;
47}
48
49int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
50 assert_return(lease, -EINVAL);
51 assert_return(mtu, -EINVAL);
52
53 if (lease->mtu)
54 *mtu = lease->mtu;
55 else
56 return -ENOENT;
57
58 return 0;
59}
60
61int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) {
62 assert_return(lease, -EINVAL);
63 assert_return(addr, -EINVAL);
64 assert_return(addr_size, -EINVAL);
65
66 if (lease->dns_size) {
67 *addr_size = lease->dns_size;
68 *addr = lease->dns;
69 } else
70 return -ENOENT;
71
72 return 0;
73}
74
75int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
76 assert_return(lease, -EINVAL);
77 assert_return(domainname, -EINVAL);
78
79 if (lease->domainname)
80 *domainname = lease->domainname;
81 else
82 return -ENOENT;
83
84 return 0;
85}
86
87int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
88 assert_return(lease, -EINVAL);
89 assert_return(hostname, -EINVAL);
90
91 if (lease->hostname)
92 *hostname = lease->hostname;
93 else
94 return -ENOENT;
95
96 return 0;
97}
98
ce78df79
TG
99int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
100 assert_return(lease, -EINVAL);
101 assert_return(root_path, -EINVAL);
102
103 if (lease->root_path)
104 *root_path = lease->root_path;
105 else
106 return -ENOENT;
107
108 return 0;
109}
110
a6cc569e
TG
111int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
112 assert_return(lease, -EINVAL);
113 assert_return(addr, -EINVAL);
114
115 addr->s_addr = lease->router;
116
117 return 0;
118}
119
120int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
121 assert_return(lease, -EINVAL);
122 assert_return(addr, -EINVAL);
123
124 addr->s_addr = lease->subnet_mask;
125
126 return 0;
127}
128
0ad853bc
TG
129int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
130 assert_return(lease, -EINVAL);
131 assert_return(addr, -EINVAL);
132
133 addr->s_addr = lease->server_address;
134
135 return 0;
136}
137
a6cc569e
TG
138sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
139 if (lease)
140 assert_se(REFCNT_INC(lease->n_ref) >= 2);
141
142 return lease;
143}
144
145sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
146 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
147 free(lease->hostname);
148 free(lease->domainname);
149 free(lease->dns);
150 free(lease);
151 }
152
153 return NULL;
154}
155
156int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
157 void *user_data) {
158 sd_dhcp_lease *lease = user_data;
159 be32_t val;
160
161 switch(code) {
162
163 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
164 if (len == 4) {
165 memcpy(&val, option, 4);
166 lease->lifetime = be32toh(val);
167 }
168
169 break;
170
171 case DHCP_OPTION_SERVER_IDENTIFIER:
172 if (len >= 4)
173 memcpy(&lease->server_address, option, 4);
174
175 break;
176
177 case DHCP_OPTION_SUBNET_MASK:
178 if (len >= 4)
179 memcpy(&lease->subnet_mask, option, 4);
180
181 break;
182
183 case DHCP_OPTION_ROUTER:
184 if (len >= 4)
185 memcpy(&lease->router, option, 4);
186
187 break;
188
189 case DHCP_OPTION_DOMAIN_NAME_SERVER:
190 if (len && !(len % 4)) {
191 unsigned i;
192
193 lease->dns_size = len / 4;
194
195 free(lease->dns);
196 lease->dns = new0(struct in_addr, lease->dns_size);
197 if (!lease->dns)
198 return -ENOMEM;
199
200 for (i = 0; i < lease->dns_size; i++) {
201 memcpy(&lease->dns[i].s_addr, option + 4 * i, 4);
202 }
203 }
204
205 break;
206
207 case DHCP_OPTION_INTERFACE_MTU:
208 if (len >= 2) {
209 be16_t mtu;
210
211 memcpy(&mtu, option, 2);
212 lease->mtu = be16toh(mtu);
213
214 if (lease->mtu < 68)
215 lease->mtu = 0;
216 }
217
218 break;
219
220 case DHCP_OPTION_DOMAIN_NAME:
221 if (len >= 1) {
222 free(lease->domainname);
223 lease->domainname = strndup((const char *)option, len);
224 }
225
226 break;
227
228 case DHCP_OPTION_HOST_NAME:
229 if (len >= 1) {
230 free(lease->hostname);
231 lease->hostname = strndup((const char *)option, len);
232 }
233
234 break;
235
ce78df79
TG
236 case DHCP_OPTION_ROOT_PATH:
237 if (len >= 1) {
238 free(lease->root_path);
239 lease->root_path = strndup((const char *)option, len);
240 }
241
242 break;
243
a6cc569e
TG
244 case DHCP_OPTION_RENEWAL_T1_TIME:
245 if (len == 4) {
246 memcpy(&val, option, 4);
247 lease->t1 = be32toh(val);
248 }
249
250 break;
251
252 case DHCP_OPTION_REBINDING_T2_TIME:
253 if (len == 4) {
254 memcpy(&val, option, 4);
255 lease->t2 = be32toh(val);
256 }
257
258 break;
259 }
260
261 return 0;
262}
263
264int dhcp_lease_new(sd_dhcp_lease **ret) {
265 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
266
267 lease = new0(sd_dhcp_lease, 1);
268 if (!lease)
269 return -ENOMEM;
270
271 lease->n_ref = REFCNT_INIT;
272
273 *ret = lease;
274 lease = NULL;
275
276 return 0;
277}
fe8db0c5
TG
278
279int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
280 _cleanup_free_ char *temp_path = NULL;
281 _cleanup_fclose_ FILE *f = NULL;
282 char buf[INET_ADDRSTRLEN];
283 struct in_addr address;
284 const char *string;
285 uint16_t mtu;
286 int r;
287
288 assert(lease);
289 assert(lease_file);
290
291 r = mkdir_safe_label("/run/systemd/network/leases", 0755, 0, 0);
292 if (r < 0)
293 goto finish;
294
295 r = fopen_temporary(lease_file, &f, &temp_path);
296 if (r < 0)
297 goto finish;
298
299 fchmod(fileno(f), 0644);
300
301 r = sd_dhcp_lease_get_address(lease, &address);
302 if (r < 0)
303 goto finish;
304
305 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
306 if (!string) {
307 r = -errno;
308 goto finish;
309 }
310
311 fprintf(f,
312 "# This is private data. Do not parse.\n"
313 "ADDRESS=%s\n", string);
314
315 r = sd_dhcp_lease_get_router(lease, &address);
316 if (r < 0)
317 goto finish;
318
319 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
320 if (!string) {
321 r = -errno;
322 goto finish;
323 }
324
325 fprintf(f,
326 "ROUTER=%s\n", string);
327
328 r = sd_dhcp_lease_get_netmask(lease, &address);
329 if (r < 0)
330 goto finish;
331
332 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
333 if (!string) {
334 r = -errno;
335 goto finish;
336 }
337
338 fprintf(f,
339 "NETMASK=%s\n", string);
340
0ad853bc
TG
341 r = sd_dhcp_lease_get_server_identifier(lease, &address);
342 if (r >= 0) {
343 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
344 if (!string) {
345 r = -errno;
346 goto finish;
347 }
348
349 fprintf(f,
350 "SERVER_ADDRESS=%s\n", string);
351 }
352
fe8db0c5
TG
353 r = sd_dhcp_lease_get_mtu(lease, &mtu);
354 if (r >= 0)
355 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
356
357/* TODO: DNS. See resolv.conf writing in network-manager.c */
358
359 r = sd_dhcp_lease_get_domainname(lease, &string);
360 if (r >= 0)
361 fprintf(f, "DOMAINNAME=%s\n", string);
362
363 r = sd_dhcp_lease_get_hostname(lease, &string);
364 if (r >= 0)
365 fprintf(f, "HOSTNAME=%s\n", string);
366
ce78df79
TG
367 r = sd_dhcp_lease_get_root_path(lease, &string);
368 if (r >= 0)
369 fprintf(f, "ROOT_PATH=%s\n", string);
370
fe8db0c5
TG
371 r = 0;
372
373 fflush(f);
374
375 if (ferror(f) || rename(temp_path, lease_file) < 0) {
376 r = -errno;
377 unlink(lease_file);
378 unlink(temp_path);
379 }
380
381finish:
382 if (r < 0)
383 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
384
385 return r;
386}
387
388int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
389 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
390 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
0ad853bc 391 *server_address = NULL, *mtu = NULL;
fe8db0c5
TG
392 struct in_addr addr;
393 int r;
394
395 assert(lease_file);
396 assert(ret);
397
398 r = dhcp_lease_new(&lease);
399 if (r < 0)
400 return r;
401
402 r = parse_env_file(lease_file, NEWLINE,
403 "ADDRESS", &address,
404 "ROUTER", &router,
405 "NETMASK", &netmask,
0ad853bc 406 "SERVER_IDENTIFIER", &server_address,
fe8db0c5
TG
407 "MTU", &mtu,
408 "DOMAINNAME", &lease->domainname,
409 "HOSTNAME", &lease->hostname,
ce78df79 410 "ROOT_PATH", &lease->root_path,
fe8db0c5
TG
411 NULL);
412 if (r < 0) {
413 if (r == -ENOENT)
414 return 0;
415
416 log_error("Failed to read %s: %s", lease_file, strerror(-r));
417 return r;
418 }
419
420 r = inet_pton(AF_INET, address, &addr);
421 if (r < 0)
422 return r;
423
424 lease->address = addr.s_addr;
425
426 r = inet_pton(AF_INET, router, &addr);
427 if (r < 0)
428 return r;
429
430 lease->router = addr.s_addr;
431
432 r = inet_pton(AF_INET, netmask, &addr);
433 if (r < 0)
434 return r;
435
436 lease->subnet_mask = addr.s_addr;
437
0ad853bc
TG
438 if (server_address) {
439 r = inet_pton(AF_INET, server_address, &addr);
440 if (r < 0)
441 return r;
442
443 lease->server_address = addr.s_addr;
444 }
445
fe8db0c5
TG
446 if (mtu) {
447 uint16_t u;
448 if (sscanf(mtu, "%" SCNu16, &u) > 0)
449 lease->mtu = u;
450 }
451
452 *ret = lease;
453 lease = NULL;
454
455 return 0;
456}