sd-dhcp-lease.c revision b14fff6e44eec1752bed2fbb8c5e8f376ea9507b
/***
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;
}
if (lease->static_route_size <= 0)
return -ENODATA;
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;
}
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) {
struct sd_dhcp_route *route;
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;
case DHCP_OPTION_SUBNET_MASK:
if (r < 0)
log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m");
else
lease->have_subnet_mask = true;
break;
case DHCP_OPTION_BROADCAST:
if (r < 0)
log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m");
else
lease->have_broadcast = true;
break;
case 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;
case DHCP_OPTION_NTP_SERVER:
if (r < 0)
log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
break;
case DHCP_OPTION_STATIC_ROUTE:
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;
case DHCP_OPTION_DOMAIN_NAME: {
if (r < 0) {
log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
return 0;
}
if (r < 0) {
return 0;
}
if (is_localhost(normalized)) {
log_debug_errno(r, "Detected 'localhost' as suggested domain name, ignoring.");
break;
}
normalized = NULL;
break;
}
case DHCP_OPTION_HOST_NAME: {
if (r < 0) {
log_debug_errno(r, "Failed to parse host name, ignoring: %m");
return 0;
}
if (r < 0) {
return 0;
}
if (is_localhost(normalized)) {
log_debug_errno(r, "Detected 'localhost' as suggested host name, ignoring.");
return 0;
}
normalized = NULL;
break;
}
case 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 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;
}
struct sd_dhcp_raw_option *option;
const char *string;
struct sd_dhcp_route *routes;
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) {
_cleanup_free_ char *client_id_hex;
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
*server_address = NULL,
*next_server = NULL,
*client_id_hex = NULL,
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 <= DHCP_OPTION_PRIVATE_LAST - 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;
}