/***
This file is part of systemd.
Copyright (C) 2013 Intel Corporation. All rights reserved.
Copyright (C) 2014 Tom Gundersen
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sd-dhcp-lease.h"
#include "alloc-util.h"
#include "dhcp-lease-internal.h"
#include "dhcp-protocol.h"
#include "dns-domain.h"
#include "fd-util.h"
#include "fileio.h"
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
#include "network-internal.h"
#include "parse-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "unaligned.h"
return -ENODATA;
return 0;
}
if (!lease->have_broadcast)
return -ENODATA;
return 0;
}
return -ENODATA;
return 0;
}
return -ENODATA;
return 0;
}
return -ENODATA;
return 0;
}
return -ENODATA;
return 0;
}
return -ENODATA;
}
return -ENODATA;
}
if (!lease->domainname)
return -ENODATA;
return 0;
}
return -ENODATA;
return 0;
}
return -ENODATA;
return 0;
}
return -ENODATA;
return 0;
}
if (!lease->have_subnet_mask)
return -ENODATA;
return 0;
}
if (lease->server_address == 0)
return -ENODATA;
return 0;
}
if (lease->next_server == 0)
return -ENODATA;
return 0;
}
/*
* The returned routes array must be freed by the caller.
* Route objects have the same lifetime of the lease and must not be freed.
*/
unsigned i;
if (lease->static_route_size <= 0)
return -ENODATA;
if (!ret)
return -ENOMEM;
for (i = 0; i < lease->static_route_size; i++)
return (int) lease->static_route_size;
}
if (lease->vendor_specific_len <= 0)
return -ENODATA;
return 0;
}
if (!lease)
return NULL;
return lease;
}
if (!lease)
return NULL;
return NULL;
while (lease->private_options) {
}
return NULL;
}
if (len != 4)
return -EINVAL;
return 0;
}
if (len != 2)
return -EINVAL;
return 0;
}
if (len != 4)
return -EINVAL;
return 0;
}
if (len <= 0)
else {
char *string;
/*
* One trailing NUL byte is OK, we don't mind. See:
*/
return -EINVAL;
if (!string)
return -ENOMEM;
}
return 0;
}
int r;
if (r < 0)
return r;
if (!name) {
return 0;
}
if (r < 0)
return r;
if (is_localhost(normalized))
return -EINVAL;
if (dns_name_is_root(normalized))
return -EINVAL;
*ret = normalized;
normalized = NULL;
return 0;
}
static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
if (len <= 0) {
*n_ret = 0;
} else {
if (len % 4 != 0)
return -EINVAL;
if (!addresses)
return -ENOMEM;
*n_ret = n_addresses;
}
return 0;
}
static int lease_parse_routes(
if (len <= 0)
return 0;
if (len % 8 != 0)
return -EINVAL;
return -ENOMEM;
while (len >= 8) {
int r;
if (r < 0) {
log_debug("Failed to determine destination prefix length from class based IP, ignoring");
continue;
}
option += 4;
option += 4;
len -= 8;
(*routes_size)++;
}
return 0;
}
/* parses RFC3442 Classless Static Route Option */
static int lease_parse_classless_routes(
if (len <= 0)
return 0;
/* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
while (len > 0) {
return -ENOMEM;
option++;
len--;
/* can't have more than 4 octets in IPv4 */
return -EINVAL;
option += dst_octets;
len -= dst_octets;
if (len < 4)
return -EINVAL;
option += 4;
len -= 4;
(*routes_size)++;
}
return 0;
}
int r;
switch(code) {
if (r < 0)
log_debug_errno(r, "Failed to parse lease time, ignoring: %m");
break;
if (r < 0)
log_debug_errno(r, "Failed to parse server identifier, ignoring: %m");
break;
if (r < 0)
log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m");
else
lease->have_subnet_mask = true;
break;
case SD_DHCP_OPTION_BROADCAST:
if (r < 0)
log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m");
else
lease->have_broadcast = true;
break;
case SD_DHCP_OPTION_ROUTER:
if (len >= 4) {
if (r < 0)
log_debug_errno(r, "Failed to parse router address, ignoring: %m");
}
break;
if (r < 0)
log_debug_errno(r, "Failed to parse DNS server, ignoring: %m");
break;
if (r < 0)
log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
break;
r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated);
if (r < 0)
log_debug_errno(r, "Failed to parse static routes, ignoring: %m");
break;
if (r < 0)
log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
break;
if (r < 0) {
log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
return 0;
}
break;
case SD_DHCP_OPTION_HOST_NAME:
if (r < 0) {
log_debug_errno(r, "Failed to parse host name, ignoring: %m");
return 0;
}
break;
case SD_DHCP_OPTION_ROOT_PATH:
if (r < 0)
log_debug_errno(r, "Failed to parse root path, ignoring: %m");
break;
if (r < 0)
log_debug_errno(r, "Failed to parse T1 time, ignoring: %m");
break;
if (r < 0)
log_debug_errno(r, "Failed to parse T2 time, ignoring: %m");
break;
if (r < 0)
log_debug_errno(r, "Failed to parse classless routes, ignoring: %m");
break;
case SD_DHCP_OPTION_NEW_TZDB_TIMEZONE: {
if (r < 0) {
log_debug_errno(r, "Failed to parse timezone option, ignoring: %m");
return 0;
}
if (!timezone_is_valid(tz)) {
log_debug_errno(r, "Timezone is not valid, ignoring: %m");
return 0;
}
break;
}
if (len <= 0)
else {
void *p;
if (!p)
return -ENOMEM;
lease->vendor_specific = p;
}
break;
if (r < 0)
return r;
break;
default:
break;
}
return 0;
}
int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) {
break;
return 0;
}
}
if (!option)
return -ENOMEM;
return -ENOMEM;
}
return 0;
}
if (!lease)
return -ENOMEM;
return 0;
}
const char *string;
int r;
if (r < 0)
goto fail;
fprintf(f,
"# This is private data. Do not parse.\n");
if (r >= 0)
if (r >= 0)
if (r >= 0)
if (r >= 0)
if (r >= 0)
if (r >= 0)
if (r >= 0)
if (r >= 0)
if (r >= 0)
if (r >= 0)
if (r > 0) {
fputs("DNS=", f);
serialize_in_addrs(f, addresses, r);
fputs("\n", f);
}
if (r > 0) {
fputs("NTP=", f);
serialize_in_addrs(f, addresses, r);
fputs("\n", f);
}
if (r >= 0)
if (r >= 0)
if (r >= 0)
if (r > 0)
if (r >= 0)
if (r >= 0) {
if (!client_id_hex) {
r = -ENOMEM;
goto fail;
}
}
if (r >= 0) {
if (!option_hex) {
r = -ENOMEM;
goto fail;
}
}
if (r < 0)
goto fail;
}
r = fflush_and_check(f);
if (r < 0)
goto fail;
r = -errno;
goto fail;
}
return 0;
fail:
if (temp_path)
}
_cleanup_free_ char
int r, i;
r = dhcp_lease_new(&lease);
if (r < 0)
return r;
"ADDRESS", &address,
"ROUTER", &router,
"NETMASK", &netmask,
"SERVER_IDENTIFIER", &server_address,
"NEXT_SERVER", &next_server,
"BROADCAST", &broadcast,
"DNS", &dns,
"NTP", &ntp,
"MTU", &mtu,
"ROUTES", &routes,
"CLIENTID", &client_id_hex,
"VENDOR_SPECIFIC", &vendor_specific_hex,
"LIFETIME", &lifetime,
"T1", &t1,
"T2", &t2,
"OPTION_224", &options[0],
NULL);
if (r < 0)
return r;
if (address) {
if (r <= 0)
}
if (router) {
if (r <= 0)
}
if (netmask) {
if (r <= 0)
else
lease->have_subnet_mask = true;
}
if (server_address) {
if (r <= 0)
}
if (next_server) {
if (r <= 0)
}
if (broadcast) {
if (r <= 0)
else
lease->have_broadcast = true;
}
if (dns) {
if (r < 0)
else
}
if (ntp) {
if (r < 0)
else
}
if (mtu) {
if (r < 0)
}
if (routes) {
routes);
if (r < 0)
}
if (lifetime) {
if (r < 0)
}
if (t1) {
if (r < 0)
}
if (t2) {
if (r < 0)
}
if (client_id_hex) {
if (r < 0)
}
if (vendor_specific_hex) {
r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex);
if (r < 0)
}
for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) {
if (!options[i])
continue;
if (r < 0) {
continue;
}
if (r < 0)
return r;
}
return 0;
}
int r;
return -ENODATA;
/* fall back to the default subnet masks based on address class */
if (r < 0)
return r;
lease->have_subnet_mask = true;
return 0;
}
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
return -ENODATA;
return 0;
}
if (client_id_len <= 0)
else {
void *p;
if (!p)
return -ENOMEM;
}
return 0;
}
return -ENODATA;
return 0;
}
return 0;
}
return 0;
}
return 0;
}