mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-02 13:30:13 +01:00
merge: add an 'internal' DHCP client based on systemd's DHCP code (bgo #733384)
This commit is contained in:
commit
25960c2205
55 changed files with 21066 additions and 9 deletions
|
|
@ -29,7 +29,7 @@ if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then
|
|||
-fno-strict-aliasing -Wno-unused-but-set-variable \
|
||||
-Wundef -Wimplicit-function-declaration \
|
||||
-Wpointer-arith -Winit-self \
|
||||
-Wmissing-include-dirs -Waggregate-return; do
|
||||
-Wmissing-include-dirs; do
|
||||
CFLAGS="$CFLAGS_MORE_WARNINGS $CFLAGS_EXTRA $option $CFLAGS_SAVED"
|
||||
AC_MSG_CHECKING([whether gcc understands $option])
|
||||
AC_TRY_COMPILE([], [],
|
||||
|
|
|
|||
|
|
@ -48,6 +48,74 @@ AM_CPPFLAGS = \
|
|||
# primarily for its side effect of removing duplicates.
|
||||
AM_CPPFLAGS += $(foreach d,$(sort $(dir $(libNetworkManager_la_SOURCES))),-I$(top_srcdir)/src/$d)
|
||||
|
||||
noinst_LTLIBRARIES = libNetworkManager.la libsystemd-dhcp.la
|
||||
|
||||
######################
|
||||
# libsystemd-dhcp
|
||||
######################
|
||||
|
||||
SYSTEMD_DHCP_CFLAGS = \
|
||||
-I$(top_srcdir)/src/dhcp-manager/systemd-dhcp/src/systemd \
|
||||
-I$(top_srcdir)/src/dhcp-manager/systemd-dhcp/src/libsystemd-network \
|
||||
-I$(top_srcdir)/src/dhcp-manager/systemd-dhcp/src/shared \
|
||||
-I$(top_srcdir)/src/dhcp-manager/systemd-dhcp
|
||||
|
||||
libsystemd_dhcp_la_SOURCES = \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-lease-internal.h \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c \
|
||||
dhcp-manager/systemd-dhcp/src/shared/async.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/time-util.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/siphash24.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/time-util.c \
|
||||
dhcp-manager/systemd-dhcp/src/shared/socket-util.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/sparse-endian.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/macro.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/refcnt.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/util.c \
|
||||
dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c \
|
||||
dhcp-manager/systemd-dhcp/src/shared/siphash24.c \
|
||||
dhcp-manager/systemd-dhcp/src/shared/util.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/list.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/fileio.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/fileio.c \
|
||||
dhcp-manager/systemd-dhcp/src/shared/strv.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/strv.c \
|
||||
dhcp-manager/systemd-dhcp/src/shared/utf8.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/utf8.c \
|
||||
dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h \
|
||||
dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h \
|
||||
dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h \
|
||||
dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h \
|
||||
dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h \
|
||||
dhcp-manager/systemd-dhcp/src/systemd/sd-event.h \
|
||||
dhcp-manager/systemd-dhcp/src/systemd/_sd-common.h \
|
||||
dhcp-manager/systemd-dhcp/nm-sd-adapt.h \
|
||||
dhcp-manager/systemd-dhcp/nm-sd-adapt.c
|
||||
|
||||
libsystemd_dhcp_la_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
$(SYSTEMD_DHCP_CFLAGS) \
|
||||
$(GLIB_CFLAGS)
|
||||
|
||||
libsystemd_dhcp_la_LIBADD = \
|
||||
$(GLIB_LIBS)
|
||||
|
||||
###########################################
|
||||
# NetworkManager
|
||||
###########################################
|
||||
|
|
@ -60,8 +128,6 @@ NetworkManager_SOURCES = \
|
|||
|
||||
NetworkManager_LDADD = libNetworkManager.la
|
||||
|
||||
noinst_LTLIBRARIES = libNetworkManager.la
|
||||
|
||||
nm_device_sources = \
|
||||
devices/nm-device-bond.c \
|
||||
devices/nm-device-bridge.c \
|
||||
|
|
@ -110,6 +176,8 @@ nm_sources = \
|
|||
dhcp-manager/nm-dhcp-dhclient-utils.h \
|
||||
dhcp-manager/nm-dhcp-dhcpcd.c \
|
||||
dhcp-manager/nm-dhcp-dhcpcd.h \
|
||||
dhcp-manager/nm-dhcp-systemd.h \
|
||||
dhcp-manager/nm-dhcp-systemd.c \
|
||||
dhcp-manager/nm-dhcp-manager.c \
|
||||
dhcp-manager/nm-dhcp-manager.h \
|
||||
\
|
||||
|
|
@ -328,6 +396,7 @@ AM_CPPFLAGS += \
|
|||
$(LIBNDP_CFLAGS) \
|
||||
$(LIBSOUP_CFLAGS) \
|
||||
$(SYSTEMD_LOGIN_CFLAGS) \
|
||||
$(SYSTEMD_DHCP_CFLAGS) \
|
||||
\
|
||||
-DBINDIR=\"$(bindir)\" \
|
||||
-DDATADIR=\"$(datadir)\" \
|
||||
|
|
@ -359,6 +428,7 @@ libNetworkManager_la_SOURCES = \
|
|||
|
||||
libNetworkManager_la_LIBADD = \
|
||||
$(top_builddir)/libnm-core/libnm-core.la \
|
||||
libsystemd-dhcp.la \
|
||||
$(DBUS_LIBS) \
|
||||
$(GLIB_LIBS) \
|
||||
$(GUDEV_LIBS) \
|
||||
|
|
@ -374,6 +444,8 @@ endif
|
|||
|
||||
NetworkManager_LDFLAGS = -rdynamic
|
||||
|
||||
######################
|
||||
|
||||
dbusservicedir = $(DBUS_SYS_DIR)
|
||||
dbusservice_DATA = org.freedesktop.NetworkManager.conf
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "nm-dhcp-manager.h"
|
||||
#include "nm-dhcp-dhclient.h"
|
||||
#include "nm-dhcp-dhcpcd.h"
|
||||
#include "nm-dhcp-systemd.h"
|
||||
#include "nm-logging.h"
|
||||
#include "nm-dbus-manager.h"
|
||||
#include "nm-config.h"
|
||||
|
|
@ -313,6 +314,9 @@ get_client_type (const char *client, GError **error)
|
|||
return NM_TYPE_DHCP_DHCPCD;
|
||||
}
|
||||
|
||||
if (!strcmp (client, "internal"))
|
||||
return NM_TYPE_DHCP_SYSTEMD;
|
||||
|
||||
g_set_error (error,
|
||||
NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
_("unsupported DHCP client '%s'"), client);
|
||||
|
|
@ -537,6 +541,8 @@ nm_dhcp_manager_init (NMDhcpManager *self)
|
|||
|
||||
if (priv->client_type == NM_TYPE_DHCP_DHCLIENT)
|
||||
priv->get_lease_ip_configs_func = nm_dhcp_dhclient_get_lease_ip_configs;
|
||||
else if (priv->client_type == NM_TYPE_DHCP_SYSTEMD)
|
||||
priv->get_lease_ip_configs_func = nm_dhcp_systemd_get_lease_ip_configs;
|
||||
else if (priv->client_type == G_TYPE_INVALID) {
|
||||
nm_log_warn (LOGD_DHCP, "No usable DHCP client found (%s)! DHCP configurations will fail.",
|
||||
error->message);
|
||||
|
|
|
|||
808
src/dhcp-manager/nm-dhcp-systemd.c
Normal file
808
src/dhcp-manager/nm-dhcp-systemd.c
Normal file
|
|
@ -0,0 +1,808 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gio/gio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include "nm-dhcp-systemd.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-logging.h"
|
||||
#include "nm-dhcp-utils.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "sd-dhcp-client.h"
|
||||
#include "sd-dhcp6-client.h"
|
||||
#include "dhcp-protocol.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
#include "dhcp6-lease-internal.h"
|
||||
|
||||
G_DEFINE_TYPE (NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT)
|
||||
|
||||
#define NM_DHCP_SYSTEMD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_SYSTEMD, NMDhcpSystemdPrivate))
|
||||
|
||||
typedef struct {
|
||||
struct sd_dhcp_client *client4;
|
||||
struct sd_dhcp6_client *client6;
|
||||
char *lease_file;
|
||||
|
||||
guint timeout_id;
|
||||
guint request_count;
|
||||
|
||||
gboolean privacy;
|
||||
} NMDhcpSystemdPrivate;
|
||||
|
||||
/************************************************************/
|
||||
|
||||
#define DHCP_OPTION_NIS_DOMAIN 40
|
||||
#define DHCP_OPTION_NIS_SERVERS 41
|
||||
#define DHCP_OPTION_DOMAIN_SEARCH 119
|
||||
#define DHCP_OPTION_RFC3442_ROUTES 121
|
||||
#define DHCP_OPTION_MS_ROUTES 249
|
||||
#define DHCP_OPTION_WPAD 252
|
||||
|
||||
/* Internal values */
|
||||
#define DHCP_OPTION_IP_ADDRESS 1024
|
||||
#define DHCP_OPTION_EXPIRY 1025
|
||||
#define DHCP6_OPTION_IP_ADDRESS 1026
|
||||
#define DHCP6_OPTION_PREFIXLEN 1027
|
||||
#define DHCP6_OPTION_PREFERRED_LIFE 1028
|
||||
#define DHCP6_OPTION_MAX_LIFE 1029
|
||||
#define DHCP6_OPTION_STARTS 1030
|
||||
#define DHCP6_OPTION_LIFE_STARTS 1031
|
||||
#define DHCP6_OPTION_RENEW 1032
|
||||
#define DHCP6_OPTION_REBIND 1033
|
||||
#define DHCP6_OPTION_IAID 1034
|
||||
|
||||
typedef struct {
|
||||
guint num;
|
||||
const char *name;
|
||||
gboolean include;
|
||||
} ReqOption;
|
||||
|
||||
#define REQPREFIX "requested_"
|
||||
|
||||
static const ReqOption dhcp4_requests[] = {
|
||||
{ DHCP_OPTION_SUBNET_MASK, REQPREFIX "subnet_mask", TRUE },
|
||||
{ DHCP_OPTION_TIME_OFFSET, REQPREFIX "time_offset", TRUE },
|
||||
{ DHCP_OPTION_ROUTER, REQPREFIX "routers", TRUE },
|
||||
{ DHCP_OPTION_DOMAIN_NAME_SERVER, REQPREFIX "domain_name_servers", TRUE },
|
||||
{ DHCP_OPTION_HOST_NAME, REQPREFIX "host_name", TRUE },
|
||||
{ DHCP_OPTION_DOMAIN_NAME, REQPREFIX "domain_name", TRUE },
|
||||
{ DHCP_OPTION_INTERFACE_MTU, REQPREFIX "interface_mtu", TRUE },
|
||||
{ DHCP_OPTION_BROADCAST, REQPREFIX "broadcast_address", TRUE },
|
||||
{ DHCP_OPTION_STATIC_ROUTE, REQPREFIX "static_routes", TRUE },
|
||||
{ DHCP_OPTION_NIS_DOMAIN, REQPREFIX "nis_domain", TRUE },
|
||||
{ DHCP_OPTION_NIS_SERVERS, REQPREFIX "nis_servers", TRUE },
|
||||
{ DHCP_OPTION_NTP_SERVER, REQPREFIX "ntp_servers", TRUE },
|
||||
{ DHCP_OPTION_SERVER_IDENTIFIER, REQPREFIX "dhcp_server_identifier", TRUE },
|
||||
{ DHCP_OPTION_DOMAIN_SEARCH, REQPREFIX "domain_search", TRUE },
|
||||
{ DHCP_OPTION_CLASSLESS_STATIC_ROUTE, REQPREFIX "rfc3442_classless_static_routes", TRUE },
|
||||
{ DHCP_OPTION_MS_ROUTES, REQPREFIX "ms_classless_static_routes", TRUE },
|
||||
{ DHCP_OPTION_WPAD, REQPREFIX "wpad", TRUE },
|
||||
|
||||
/* Internal values */
|
||||
{ DHCP_OPTION_IP_ADDRESS_LEASE_TIME, REQPREFIX "expiry", FALSE },
|
||||
{ DHCP_OPTION_CLIENT_IDENTIFIER, REQPREFIX "dhcp_client_identifier", FALSE },
|
||||
{ DHCP_OPTION_IP_ADDRESS, REQPREFIX "ip_address", FALSE },
|
||||
{ 0, NULL, FALSE }
|
||||
};
|
||||
|
||||
static const ReqOption dhcp6_requests[] = {
|
||||
{ DHCP6_OPTION_CLIENTID, REQPREFIX "dhcp6_client_id", TRUE },
|
||||
|
||||
/* Don't request server ID by default; some servers don't reply to
|
||||
* Information Requests that request the Server ID.
|
||||
*/
|
||||
{ DHCP6_OPTION_SERVERID, REQPREFIX "dhcp6_server_id", FALSE },
|
||||
|
||||
{ DHCP6_OPTION_DNS_SERVERS, REQPREFIX "dhcp6_name_servers", TRUE },
|
||||
{ DHCP6_OPTION_DOMAIN_LIST, REQPREFIX "dhcp6_domain_search", TRUE },
|
||||
{ DHCP6_OPTION_SNTP_SERVERS, REQPREFIX "dhcp6_sntp_servers", TRUE },
|
||||
|
||||
/* Internal values */
|
||||
{ DHCP6_OPTION_IP_ADDRESS, REQPREFIX "ip6_address", FALSE },
|
||||
{ DHCP6_OPTION_PREFIXLEN, REQPREFIX "ip6_prefixlen", FALSE },
|
||||
{ DHCP6_OPTION_PREFERRED_LIFE, REQPREFIX "preferred_life", FALSE },
|
||||
{ DHCP6_OPTION_MAX_LIFE, REQPREFIX "max_life", FALSE },
|
||||
{ DHCP6_OPTION_STARTS, REQPREFIX "starts", FALSE },
|
||||
{ DHCP6_OPTION_LIFE_STARTS, REQPREFIX "life_starts", FALSE },
|
||||
{ DHCP6_OPTION_RENEW, REQPREFIX "renew", FALSE },
|
||||
{ DHCP6_OPTION_REBIND, REQPREFIX "rebind", FALSE },
|
||||
{ DHCP6_OPTION_IAID, REQPREFIX "iaid", FALSE },
|
||||
{ 0, NULL, FALSE }
|
||||
};
|
||||
|
||||
static void
|
||||
take_option (GHashTable *options,
|
||||
const ReqOption *requests,
|
||||
guint option,
|
||||
char *value)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (value != NULL);
|
||||
|
||||
for (i = 0; requests[i].name; i++) {
|
||||
if (requests[i].num == option) {
|
||||
g_hash_table_insert (options,
|
||||
(gpointer) (requests[i].name + STRLEN (REQPREFIX)),
|
||||
value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Option should always be found */
|
||||
g_assert (requests[i].name);
|
||||
}
|
||||
|
||||
static void
|
||||
add_option (GHashTable *options, const ReqOption *requests, guint option, const char *value)
|
||||
{
|
||||
if (options)
|
||||
take_option (options, requests, option, g_strdup (value));
|
||||
}
|
||||
|
||||
static void
|
||||
add_option_u32 (GHashTable *options, const ReqOption *requests, guint option, guint32 value)
|
||||
{
|
||||
if (options)
|
||||
take_option (options, requests, option, g_strdup_printf ("%u", value));
|
||||
}
|
||||
|
||||
static void
|
||||
add_requests_to_options (GHashTable *options, const ReqOption *requests)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; options && requests[i].name; i++) {
|
||||
if (requests[i].include)
|
||||
g_hash_table_insert (options, (gpointer) requests[i].name, g_strdup ("1"));
|
||||
}
|
||||
}
|
||||
|
||||
#define LOG_LEASE(domain, ...) \
|
||||
G_STMT_START { \
|
||||
if (log_lease) { \
|
||||
nm_log (LOGL_INFO, (domain), __VA_ARGS__); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
static NMIP4Config *
|
||||
lease_to_ip4_config (sd_dhcp_lease *lease,
|
||||
GHashTable *options,
|
||||
guint32 default_priority,
|
||||
gboolean log_lease,
|
||||
GError **error)
|
||||
{
|
||||
NMIP4Config *ip4_config = NULL;
|
||||
struct in_addr tmp_addr;
|
||||
const struct in_addr *addr_list;
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
const char *str;
|
||||
guint32 lifetime = 0, plen = 0, i;
|
||||
NMPlatformIP4Address address;
|
||||
GString *l;
|
||||
struct sd_dhcp_route *routes;
|
||||
guint16 mtu;
|
||||
int r, num;
|
||||
gint64 end_time;
|
||||
|
||||
r = sd_dhcp_lease_get_address (lease, &tmp_addr);
|
||||
if (r < 0) {
|
||||
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
"failed to read address from lease");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ip4_config = nm_ip4_config_new ();
|
||||
|
||||
/* Address */
|
||||
memset (&address, 0, sizeof (address));
|
||||
address.address = tmp_addr.s_addr;
|
||||
str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL);
|
||||
LOG_LEASE (LOGD_DHCP4, " address %s", str);
|
||||
add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, str);
|
||||
|
||||
/* Prefix/netmask */
|
||||
r = sd_dhcp_lease_get_netmask (lease, &tmp_addr);
|
||||
if (r < 0) {
|
||||
/* Get default netmask for the IP according to appropriate class. */
|
||||
plen = nm_utils_ip4_get_default_prefix (address.address);
|
||||
LOG_LEASE (LOGD_DHCP4, " plen %d (default)", plen);
|
||||
} else {
|
||||
plen = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr);
|
||||
LOG_LEASE (LOGD_DHCP4, " plen %d", plen);
|
||||
}
|
||||
address.plen = plen;
|
||||
tmp_addr.s_addr = nm_utils_ip4_prefix_to_netmask (plen);
|
||||
add_option (options,
|
||||
dhcp4_requests,
|
||||
DHCP_OPTION_SUBNET_MASK,
|
||||
nm_utils_inet4_ntop (tmp_addr.s_addr, NULL));
|
||||
|
||||
/* Lease time */
|
||||
r = sd_dhcp_lease_get_lifetime (lease, &lifetime);
|
||||
if (r < 0)
|
||||
lifetime = 3600; /* one hour */
|
||||
address.timestamp = nm_utils_get_monotonic_timestamp_s ();
|
||||
address.lifetime = address.preferred = lifetime;
|
||||
end_time = (gint64) time (NULL) + lifetime;
|
||||
add_option_u32 (options,
|
||||
dhcp4_requests,
|
||||
DHCP_OPTION_IP_ADDRESS_LEASE_TIME,
|
||||
(guint) CLAMP (end_time, 0, G_MAXUINT32 - 1));
|
||||
|
||||
address.source = NM_IP_CONFIG_SOURCE_DHCP;
|
||||
nm_ip4_config_add_address (ip4_config, &address);
|
||||
|
||||
/* Gateway */
|
||||
r = sd_dhcp_lease_get_router (lease, &tmp_addr);
|
||||
if (r == 0) {
|
||||
nm_ip4_config_set_gateway (ip4_config, tmp_addr.s_addr);
|
||||
str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL);
|
||||
LOG_LEASE (LOGD_DHCP4, " gateway %s", str);
|
||||
add_option (options, dhcp4_requests, DHCP_OPTION_ROUTER, str);
|
||||
}
|
||||
|
||||
/* DNS Servers */
|
||||
num = sd_dhcp_lease_get_dns (lease, &addr_list);
|
||||
if (num > 0) {
|
||||
l = g_string_sized_new (30);
|
||||
for (i = 0; i < num; i++) {
|
||||
if (addr_list[i].s_addr) {
|
||||
nm_ip4_config_add_nameserver (ip4_config, addr_list[i].s_addr);
|
||||
str = nm_utils_inet4_ntop (addr_list[i].s_addr, NULL);
|
||||
LOG_LEASE (LOGD_DHCP4, " nameserver '%s'", str);
|
||||
g_string_append_printf (l, "%s%s", l->len ? " " : "", str);
|
||||
}
|
||||
}
|
||||
if (l->len)
|
||||
add_option (options, dhcp4_requests, DHCP_OPTION_DOMAIN_NAME_SERVER, l->str);
|
||||
g_string_free (l, TRUE);
|
||||
}
|
||||
|
||||
/* Domain Name */
|
||||
r = sd_dhcp_lease_get_domainname (lease, &str);
|
||||
if (r == 0) {
|
||||
/* Multiple domains sometimes stuffed into the option */
|
||||
char **domains = g_strsplit (str, " ", 0);
|
||||
char **s;
|
||||
|
||||
for (s = domains; *s; s++) {
|
||||
LOG_LEASE (LOGD_DHCP4, " domain name '%s'", *s);
|
||||
nm_ip4_config_add_domain (ip4_config, *s);
|
||||
}
|
||||
g_strfreev (domains);
|
||||
add_option (options, dhcp4_requests, DHCP_OPTION_DOMAIN_NAME, str);
|
||||
}
|
||||
|
||||
/* Hostname */
|
||||
r = sd_dhcp_lease_get_hostname (lease, &str);
|
||||
if (r == 0) {
|
||||
LOG_LEASE (LOGD_DHCP4, " hostname '%s'", str);
|
||||
add_option (options, dhcp4_requests, DHCP_OPTION_HOST_NAME, str);
|
||||
}
|
||||
|
||||
/* Routes */
|
||||
num = sd_dhcp_lease_get_routes (lease, &routes);
|
||||
if (num > 0) {
|
||||
l = g_string_sized_new (30);
|
||||
for (i = 0; i < num; i++) {
|
||||
NMPlatformIP4Route route;
|
||||
const char *gw_str;
|
||||
|
||||
memset (&route, 0, sizeof (route));
|
||||
route.network = routes[i].dst_addr.s_addr;
|
||||
route.plen = routes[i].dst_prefixlen;
|
||||
route.gateway = routes[i].gw_addr.s_addr;
|
||||
route.source = NM_IP_CONFIG_SOURCE_DHCP;
|
||||
route.metric = default_priority;
|
||||
nm_ip4_config_add_route (ip4_config, &route);
|
||||
|
||||
str = nm_utils_inet4_ntop (route.network, buf);
|
||||
gw_str = nm_utils_inet4_ntop (route.gateway, NULL);
|
||||
LOG_LEASE (LOGD_DHCP4, " static route %s/%d gw %s", str, route.plen, gw_str);
|
||||
|
||||
g_string_append_printf (l, "%s%s/%d %s", l->len ? " " : "", str, route.plen, gw_str);
|
||||
}
|
||||
add_option (options, dhcp4_requests, DHCP_OPTION_RFC3442_ROUTES, l->str);
|
||||
g_string_free (l, TRUE);
|
||||
}
|
||||
|
||||
/* MTU */
|
||||
r = sd_dhcp_lease_get_mtu (lease, &mtu);
|
||||
if (r == 0 && mtu) {
|
||||
nm_ip4_config_set_mtu (ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP);
|
||||
add_option_u32 (options, dhcp4_requests, DHCP_OPTION_INTERFACE_MTU, mtu);
|
||||
LOG_LEASE (LOGD_DHCP4, " mtu %u", mtu);
|
||||
}
|
||||
|
||||
/* NTP servers */
|
||||
num = sd_dhcp_lease_get_ntp(lease, &addr_list);
|
||||
if (num > 0) {
|
||||
l = g_string_sized_new (30);
|
||||
for (i = 0; i < num; i++) {
|
||||
str = nm_utils_inet4_ntop (addr_list[i].s_addr, buf);
|
||||
g_string_append_printf (l, "%s%s", l->len ? " " : "", str);
|
||||
}
|
||||
add_option (options, dhcp4_requests, DHCP_OPTION_NTP_SERVER, l->str);
|
||||
g_string_free (l, TRUE);
|
||||
}
|
||||
|
||||
return ip4_config;
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
|
||||
static char *
|
||||
get_leasefile_path (const char *iface, const char *uuid, gboolean ipv6)
|
||||
{
|
||||
return g_strdup_printf (NMSTATEDIR "/internal%s-%s-%s.lease",
|
||||
ipv6 ? "6" : "",
|
||||
uuid,
|
||||
iface);
|
||||
}
|
||||
|
||||
GSList *
|
||||
nm_dhcp_systemd_get_lease_ip_configs (const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6)
|
||||
{
|
||||
GSList *leases = NULL;
|
||||
gs_free char *path = NULL;
|
||||
sd_dhcp_lease *lease = NULL;
|
||||
NMIP4Config *ip4_config;
|
||||
int r;
|
||||
|
||||
if (ipv6)
|
||||
return NULL;
|
||||
|
||||
path = get_leasefile_path (iface, uuid, FALSE);
|
||||
r = sd_dhcp_lease_load (path, &lease);
|
||||
if (r == 0) {
|
||||
ip4_config = lease_to_ip4_config (lease, NULL, 0, FALSE, NULL);
|
||||
if (ip4_config)
|
||||
leases = g_slist_append (leases, ip4_config);
|
||||
}
|
||||
|
||||
return leases;
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
|
||||
static void
|
||||
bound4_handle (NMDhcpSystemd *self)
|
||||
{
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
|
||||
const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self));
|
||||
sd_dhcp_lease *lease;
|
||||
NMIP4Config *ip4_config;
|
||||
GHashTable *options;
|
||||
GError *error = NULL;
|
||||
int r;
|
||||
|
||||
nm_log_dbg (LOGD_DHCP4, "(%s): lease available", iface);
|
||||
|
||||
r = sd_dhcp_client_get_lease (priv->client4, &lease);
|
||||
if (r < 0 || !lease) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): no lease!", iface);
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
options = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
|
||||
ip4_config = lease_to_ip4_config (lease,
|
||||
options,
|
||||
nm_dhcp_client_get_priority (NM_DHCP_CLIENT (self)),
|
||||
TRUE,
|
||||
&error);
|
||||
if (ip4_config) {
|
||||
add_requests_to_options (options, dhcp4_requests);
|
||||
sd_dhcp_lease_save (lease, priv->lease_file);
|
||||
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (self),
|
||||
NM_DHCP_STATE_BOUND,
|
||||
G_OBJECT (ip4_config),
|
||||
options);
|
||||
} else {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): %s", iface, error->message);
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
sd_dhcp_lease_unref (lease);
|
||||
g_hash_table_destroy (options);
|
||||
g_clear_object (&ip4_config);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp_event_cb (sd_dhcp_client *client, int event, gpointer user_data)
|
||||
{
|
||||
NMDhcpSystemd *self = NM_DHCP_SYSTEMD (user_data);
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
|
||||
const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self));
|
||||
|
||||
g_assert (priv->client4 == client);
|
||||
|
||||
nm_log_dbg (LOGD_DHCP4, "(%s): DHCPv4 client event %d", iface, event);
|
||||
|
||||
switch (event) {
|
||||
case DHCP_EVENT_EXPIRED:
|
||||
case DHCP_EVENT_STOP:
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_FAIL, NULL, NULL);
|
||||
break;
|
||||
case DHCP_EVENT_RENEW:
|
||||
case DHCP_EVENT_IP_CHANGE:
|
||||
case DHCP_EVENT_IP_ACQUIRE:
|
||||
bound4_handle (self);
|
||||
break;
|
||||
default:
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): unhandled DHCP event %d", iface, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static guint16
|
||||
get_arp_type (const GByteArray *hwaddr)
|
||||
{
|
||||
if (hwaddr->len == ETH_ALEN)
|
||||
return ARPHRD_ETHER;
|
||||
else if (hwaddr->len == INFINIBAND_ALEN)
|
||||
return ARPHRD_INFINIBAND;
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_start (NMDhcpClient *client,
|
||||
const char *dhcp_client_id,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname)
|
||||
{
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (client);
|
||||
const char *iface = nm_dhcp_client_get_iface (client);
|
||||
const GByteArray *hwaddr;
|
||||
sd_dhcp_lease *lease = NULL;
|
||||
const uint8_t *client_id = NULL;
|
||||
size_t client_id_len = 0;
|
||||
struct in_addr last_addr;
|
||||
int r, i;
|
||||
|
||||
g_assert (priv->client4 == NULL);
|
||||
g_assert (priv->client6 == NULL);
|
||||
|
||||
g_free (priv->lease_file);
|
||||
priv->lease_file = get_leasefile_path (iface, nm_dhcp_client_get_uuid (client), FALSE);
|
||||
|
||||
r = sd_dhcp_client_new (&priv->client4);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to create DHCPv4 client (%d)", iface, r);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_attach_event (priv->client4, NULL, 0);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to attach DHCP event (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
hwaddr = nm_dhcp_client_get_hw_addr (client);
|
||||
if (hwaddr) {
|
||||
r = sd_dhcp_client_set_mac (priv->client4,
|
||||
hwaddr->data,
|
||||
hwaddr->len,
|
||||
get_arp_type (hwaddr));
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP MAC address (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_set_index (priv->client4, nm_dhcp_client_get_ifindex (client));
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP ifindex (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_set_callback (priv->client4, dhcp_event_cb, client);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP callback (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_set_request_broadcast (priv->client4, true);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP broadcast (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
sd_dhcp_lease_load (priv->lease_file, &lease);
|
||||
|
||||
if (lease) {
|
||||
r = sd_dhcp_lease_get_address (lease, &last_addr);
|
||||
if (r == 0) {
|
||||
r = sd_dhcp_client_set_request_address (priv->client4, &last_addr);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to set last IPv4 address (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dhcp_client_id) {
|
||||
gs_unref_bytes GBytes *b = NULL;
|
||||
|
||||
b = nm_dhcp_utils_client_id_string_to_bytes (dhcp_client_id);
|
||||
if (b) {
|
||||
client_id = (const guint8 *) g_bytes_get_data (b, &client_id_len);
|
||||
g_assert (client_id && client_id_len);
|
||||
sd_dhcp_client_set_client_id (priv->client4,
|
||||
client_id[0],
|
||||
client_id + 1,
|
||||
client_id_len - 1);
|
||||
}
|
||||
} else {
|
||||
r = sd_dhcp_lease_get_client_id (lease, &client_id, &client_id_len);
|
||||
if (r == 0 && client_id_len) {
|
||||
sd_dhcp_client_set_client_id (priv->client4,
|
||||
client_id[0],
|
||||
client_id + 1,
|
||||
client_id_len - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (lease)
|
||||
sd_dhcp_lease_unref (lease);
|
||||
|
||||
/* Add requested options */
|
||||
for (i = 0; dhcp4_requests[i].name; i++) {
|
||||
if (dhcp4_requests[i].include)
|
||||
sd_dhcp_client_set_request_option (priv->client4, dhcp4_requests[i].num);
|
||||
}
|
||||
|
||||
if (hostname) {
|
||||
r = sd_dhcp_client_set_hostname (priv->client4, hostname);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP hostname (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_start (priv->client4);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to start DHCP (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
sd_dhcp_client_unref (priv->client4);
|
||||
priv->client4 = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
bound6_handle (NMDhcpSystemd *self)
|
||||
{
|
||||
/* not yet supported... */
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): internal DHCP does not yet support DHCPv6",
|
||||
nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self)));
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp6_event_cb (sd_dhcp6_client *client, int event, gpointer user_data)
|
||||
{
|
||||
NMDhcpSystemd *self = NM_DHCP_SYSTEMD (user_data);
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
|
||||
const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self));
|
||||
|
||||
g_assert (priv->client6 == client);
|
||||
|
||||
nm_log_dbg (LOGD_DHCP6, "(%s): DHCPv6 client event %d", iface, event);
|
||||
|
||||
switch (event) {
|
||||
case DHCP6_EVENT_RETRANS_MAX:
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_TIMEOUT, NULL, NULL);
|
||||
break;
|
||||
case DHCP6_EVENT_RESEND_EXPIRE:
|
||||
case DHCP6_EVENT_STOP:
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_FAIL, NULL, NULL);
|
||||
break;
|
||||
case DHCP6_EVENT_IP_ACQUIRE:
|
||||
bound6_handle (self);
|
||||
break;
|
||||
default:
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): unhandled DHCPv6 event %d", iface, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_start (NMDhcpClient *client,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid)
|
||||
{
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (client);
|
||||
const char *iface = nm_dhcp_client_get_iface (client);
|
||||
const GByteArray *hwaddr;
|
||||
int r, i;
|
||||
|
||||
g_assert (priv->client4 == NULL);
|
||||
g_assert (priv->client6 == NULL);
|
||||
g_return_val_if_fail (duid != NULL, FALSE);
|
||||
|
||||
g_free (priv->lease_file);
|
||||
priv->lease_file = get_leasefile_path (iface, nm_dhcp_client_get_uuid (client), TRUE);
|
||||
|
||||
r = sd_dhcp6_client_new (&priv->client6);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to create DHCPv6 client (%d)", iface, r);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* NM stores the entire DUID which includes the uint16 "type", while systemd
|
||||
* wants the type passed separately from the following data.
|
||||
*/
|
||||
r = sd_dhcp6_client_set_duid (priv->client6,
|
||||
ntohs (((const guint16 *) duid->data)[0]),
|
||||
duid->data + 2,
|
||||
duid->len - 2);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to create DHCPv6 client (%d)", iface, r);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_attach_event (priv->client6, NULL, 0);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to attach DHCP event (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
hwaddr = nm_dhcp_client_get_hw_addr (client);
|
||||
if (hwaddr) {
|
||||
r = sd_dhcp6_client_set_mac (priv->client6,
|
||||
hwaddr->data,
|
||||
hwaddr->len,
|
||||
get_arp_type (hwaddr));
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to set DHCP MAC address (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_set_index (priv->client6, nm_dhcp_client_get_ifindex (client));
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to set DHCP ifindex (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_set_ifname (priv->client6, iface);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to set DHCP ifname (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_set_callback (priv->client6, dhcp6_event_cb, client);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to set DHCP callback (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Add requested options */
|
||||
for (i = 0; dhcp6_requests[i].name; i++) {
|
||||
if (dhcp6_requests[i].include)
|
||||
sd_dhcp6_client_set_request_option (priv->client6, dhcp6_requests[i].num);
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_start (priv->client6);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to start DHCP (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
sd_dhcp6_client_unref (priv->client6);
|
||||
priv->client6 = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
stop (NMDhcpClient *client, gboolean release, const GByteArray *duid)
|
||||
{
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (client);
|
||||
int r = 0;
|
||||
|
||||
if (priv->client4)
|
||||
r = sd_dhcp_client_stop (priv->client4);
|
||||
else if (priv->client6)
|
||||
r = sd_dhcp6_client_stop (priv->client6);
|
||||
|
||||
if (r) {
|
||||
nm_log_warn (priv->client6 ? LOGD_DHCP6 : LOGD_DHCP4,
|
||||
"(%s): failed to stop DHCP client (%d)",
|
||||
nm_dhcp_client_get_iface (client),
|
||||
r);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
static void
|
||||
nm_dhcp_systemd_init (NMDhcpSystemd *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (object);
|
||||
|
||||
g_clear_pointer (&priv->lease_file, g_free);
|
||||
|
||||
if (priv->client4) {
|
||||
sd_dhcp_client_stop (priv->client4);
|
||||
sd_dhcp_client_unref (priv->client4);
|
||||
priv->client4 = NULL;
|
||||
}
|
||||
|
||||
if (priv->client6) {
|
||||
sd_dhcp6_client_stop (priv->client6);
|
||||
sd_dhcp6_client_unref (priv->client6);
|
||||
priv->client6 = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (nm_dhcp_systemd_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_dhcp_systemd_class_init (NMDhcpSystemdClass *sdhcp_class)
|
||||
{
|
||||
NMDhcpClientClass *client_class = NM_DHCP_CLIENT_CLASS (sdhcp_class);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (sdhcp_class);
|
||||
|
||||
g_type_class_add_private (sdhcp_class, sizeof (NMDhcpSystemdPrivate));
|
||||
|
||||
/* virtual methods */
|
||||
object_class->dispose = dispose;
|
||||
|
||||
client_class->ip4_start = ip4_start;
|
||||
client_class->ip6_start = ip6_start;
|
||||
client_class->stop = stop;
|
||||
}
|
||||
|
||||
49
src/dhcp-manager/nm-dhcp-systemd.h
Normal file
49
src/dhcp-manager/nm-dhcp-systemd.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef NM_DHCP_SYSTEMD_H
|
||||
#define NM_DHCP_SYSTEMD_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "nm-dhcp-client.h"
|
||||
|
||||
#define NM_TYPE_DHCP_SYSTEMD (nm_dhcp_systemd_get_type ())
|
||||
#define NM_DHCP_SYSTEMD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_SYSTEMD, NMDhcpSystemd))
|
||||
#define NM_DHCP_SYSTEMD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP_SYSTEMD, NMDhcpSystemdClass))
|
||||
#define NM_IS_DHCP_SYSTEMD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP_SYSTEMD))
|
||||
#define NM_IS_DHCP_SYSTEMD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP_SYSTEMD))
|
||||
#define NM_DHCP_SYSTEMD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_SYSTEMD, NMDhcpSystemdClass))
|
||||
|
||||
typedef struct {
|
||||
NMDhcpClient parent;
|
||||
} NMDhcpSystemd;
|
||||
|
||||
typedef struct {
|
||||
NMDhcpClientClass parent;
|
||||
} NMDhcpSystemdClass;
|
||||
|
||||
GType nm_dhcp_systemd_get_type (void);
|
||||
|
||||
GSList *nm_dhcp_systemd_get_lease_ip_configs (const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6);
|
||||
|
||||
#endif /* NM_DHCP_SYSTEMD_H */
|
||||
|
||||
|
|
@ -692,3 +692,68 @@ nm_dhcp_utils_duid_to_string (const GByteArray *duid)
|
|||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_dhcp_utils_client_id_string_to_bytes:
|
||||
* @client_id: the client ID string
|
||||
*
|
||||
* Accepts either a hex string ("aa:bb:cc") representing a binary client ID
|
||||
* (the first byte is assumed to be the 'type' field per RFC 2132 section 9.14),
|
||||
* or a string representing a non-hardware-address client ID, in which case
|
||||
* the 'type' field is set to 0.
|
||||
*
|
||||
* Returns: the binary client ID suitable for sending over the wire
|
||||
* to the DHCP server.
|
||||
*/
|
||||
GBytes *
|
||||
nm_dhcp_utils_client_id_string_to_bytes (const char *client_id)
|
||||
{
|
||||
GBytes *bytes = NULL;
|
||||
guint i = 0, x = 0;
|
||||
guint len;
|
||||
char *c;
|
||||
int a;
|
||||
|
||||
g_return_val_if_fail (client_id && client_id[0], NULL);
|
||||
|
||||
/* Accept a binary client ID in hex digits with the ':' delimiter,
|
||||
* otherwise treat it as a string.
|
||||
*/
|
||||
len = strlen (client_id);
|
||||
c = g_malloc0 (len / 2 + 1);
|
||||
while (client_id[i]) {
|
||||
a = g_ascii_xdigit_value (client_id[i++]);
|
||||
if (a >= 0) {
|
||||
if (client_id[i] != ':') {
|
||||
c[x] = ((guint8) a << 4);
|
||||
a = g_ascii_xdigit_value (client_id[i++]);
|
||||
}
|
||||
if (a >= 0)
|
||||
c[x++] |= (guint8) a;
|
||||
}
|
||||
if (client_id[i]) {
|
||||
if (client_id[i] != ':' || !client_id[i + 1]) {
|
||||
/* missing or trailing ':' is invalid for hex-format */
|
||||
a = -1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (a < 0) {
|
||||
g_clear_pointer (&c, g_free);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (c) {
|
||||
g_assert (x > 0);
|
||||
bytes = g_bytes_new_take (c, x);
|
||||
} else {
|
||||
c = g_malloc (len + 1);
|
||||
c[0] = 0; /* type: non-hardware address per RFC 2132 section 9.14 */
|
||||
memcpy (c + 1, client_id, len);
|
||||
bytes = g_bytes_new_take (c, len + 1);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,5 +35,7 @@ NMIP6Config *nm_dhcp_utils_ip6_config_from_options (const char *iface,
|
|||
|
||||
char * nm_dhcp_utils_duid_to_string (const GByteArray *duid);
|
||||
|
||||
GBytes * nm_dhcp_utils_client_id_string_to_bytes (const char *client_id);
|
||||
|
||||
#endif /* __NETWORKMANAGER_DHCP_UTILS_H__ */
|
||||
|
||||
|
|
|
|||
208
src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
Normal file
208
src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <glib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
#include "time-util.h"
|
||||
|
||||
struct sd_event_source {
|
||||
guint refcount;
|
||||
guint id;
|
||||
gpointer user_data;
|
||||
|
||||
GIOChannel *channel;
|
||||
sd_event_io_handler_t io_cb;
|
||||
|
||||
uint64_t usec;
|
||||
sd_event_time_handler_t time_cb;
|
||||
};
|
||||
|
||||
int
|
||||
sd_event_source_set_priority (sd_event_source *s, int64_t priority)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_event_source*
|
||||
sd_event_source_unref (sd_event_source *s)
|
||||
{
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
g_return_val_if_fail (s->refcount, NULL);
|
||||
|
||||
s->refcount--;
|
||||
if (s->refcount == 0) {
|
||||
if (s->id)
|
||||
g_source_remove (s->id);
|
||||
if (s->channel) {
|
||||
/* Don't shut down the channel since systemd will soon close
|
||||
* the file descriptor itself, which would cause -EBADF.
|
||||
*/
|
||||
g_io_channel_unref (s->channel);
|
||||
}
|
||||
g_free (s);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
sd_event_source_set_name(sd_event_source *s, const char *name)
|
||||
{
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
g_source_set_name_by_id (s->id, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
io_ready (GIOChannel *channel, GIOCondition condition, struct sd_event_source *source)
|
||||
{
|
||||
int r, revents = 0;
|
||||
|
||||
if (condition & G_IO_IN)
|
||||
revents |= EPOLLIN;
|
||||
if (condition & G_IO_OUT)
|
||||
revents |= EPOLLOUT;
|
||||
if (condition & G_IO_PRI)
|
||||
revents |= EPOLLPRI;
|
||||
if (condition & G_IO_ERR)
|
||||
revents |= EPOLLERR;
|
||||
if (condition & G_IO_HUP)
|
||||
revents |= EPOLLHUP;
|
||||
|
||||
r = source->io_cb (source, g_io_channel_unix_get_fd (channel), revents, source->user_data);
|
||||
if (r < 0) {
|
||||
source->id = 0;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
int
|
||||
sd_event_add_io (sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata)
|
||||
{
|
||||
struct sd_event_source *source;
|
||||
GIOChannel *channel;
|
||||
GIOCondition condition = 0;
|
||||
|
||||
channel = g_io_channel_unix_new (fd);
|
||||
if (!channel)
|
||||
return -EINVAL;
|
||||
|
||||
source = g_new0 (struct sd_event_source, 1);
|
||||
source->refcount = 1;
|
||||
source->io_cb = callback;
|
||||
source->user_data = userdata;
|
||||
source->channel = channel;
|
||||
|
||||
if (events & EPOLLIN)
|
||||
condition |= G_IO_IN;
|
||||
if (events & EPOLLOUT)
|
||||
condition |= G_IO_OUT;
|
||||
if (events & EPOLLPRI)
|
||||
condition |= G_IO_PRI;
|
||||
if (events & EPOLLERR)
|
||||
condition |= G_IO_ERR;
|
||||
if (events & EPOLLHUP)
|
||||
condition |= G_IO_HUP;
|
||||
|
||||
g_io_channel_set_encoding (source->channel, NULL, NULL);
|
||||
g_io_channel_set_buffered (source->channel, FALSE);
|
||||
source->id = g_io_add_watch (source->channel, condition, (GIOFunc) io_ready, source);
|
||||
|
||||
*s = source;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
time_ready (struct sd_event_source *source)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = source->time_cb (source, source->usec, source->user_data);
|
||||
if (r < 0) {
|
||||
source->id = 0;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
int
|
||||
sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata)
|
||||
{
|
||||
struct sd_event_source *source;
|
||||
uint64_t n = now (clock);
|
||||
|
||||
source = g_new0 (struct sd_event_source, 1);
|
||||
source->refcount = 1;
|
||||
source->time_cb = callback;
|
||||
source->user_data = userdata;
|
||||
source->usec = usec;
|
||||
|
||||
if (usec > 1000)
|
||||
usec = n < usec - 1000 ? usec - n : 1000;
|
||||
source->id = g_timeout_add (usec / 1000, (GSourceFunc) time_ready, source);
|
||||
|
||||
*s = source;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* sd_event is basically a GMainContext; but since we only
|
||||
* ever use the default context, nothing to do here.
|
||||
*/
|
||||
|
||||
int
|
||||
sd_event_default (sd_event **e)
|
||||
{
|
||||
*e = GUINT_TO_POINTER (1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_event*
|
||||
sd_event_ref (sd_event *e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
|
||||
sd_event*
|
||||
sd_event_unref (sd_event *e)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
sd_event_now (sd_event *e, clockid_t clock, uint64_t *usec)
|
||||
{
|
||||
*usec = now (clock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asynchronous_close(int fd) {
|
||||
safe_close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
104
src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h
Normal file
104
src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef NM_SD_ADAPT_H
|
||||
#define NM_SD_ADAPT_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <elf.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "nm-logging.h"
|
||||
|
||||
static inline guint32
|
||||
_slog_level_to_nm (int slevel)
|
||||
{
|
||||
switch (slevel) {
|
||||
case LOG_DEBUG: return LOGL_DEBUG;
|
||||
case LOG_WARNING: return LOGL_WARN;
|
||||
case LOG_ERR: return LOGL_ERR;
|
||||
case LOG_INFO:
|
||||
case LOG_NOTICE:
|
||||
default: return LOGL_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
#define log_meta(level, file, line, func, format, ...) \
|
||||
G_STMT_START { \
|
||||
guint32 _l = _slog_level_to_nm ((level)); \
|
||||
if (nm_logging_enabled (_l, LOGD_DHCP)) \
|
||||
_nm_log (#file ":" #line, func, LOGD_DHCP, _l, format, ## __VA_ARGS__); \
|
||||
} G_STMT_END
|
||||
|
||||
#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__)
|
||||
#define log_error(...) log_full(LOG_ERR, __VA_ARGS__)
|
||||
#define log_full(level, ...) log_meta((level), __FILE__, __LINE__, __func__, __VA_ARGS__);
|
||||
|
||||
#define log_dhcp_client(client, fmt, ...) \
|
||||
log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
|
||||
|
||||
#define log_assert_failed(e, file, line, func) \
|
||||
G_STMT_START { \
|
||||
nm_log_err (LOGD_DHCP, #file ":" #line "(" #func "): assertion failed: " # e); \
|
||||
g_assert (FALSE); \
|
||||
} G_STMT_END
|
||||
|
||||
#define log_assert_failed_unreachable(t, file, line, func) \
|
||||
G_STMT_START { \
|
||||
nm_log_err (LOGD_DHCP, #file ":" #line "(" #func "): assert unreachable: " # t); \
|
||||
g_assert_not_reached (); \
|
||||
} G_STMT_END
|
||||
|
||||
#define log_assert_failed_return(e, file, line, func) \
|
||||
nm_log_err (LOGD_DHCP, #file ":" #line "(" #func "): assert return: " # e); \
|
||||
|
||||
#define log_oom nm_log_err(LOGD_CORE, "%s:%s/%s: OOM", __FILE__, __LINE__, __func__)
|
||||
|
||||
/* Can't include both net/if.h and linux/if.h; so have to define this here */
|
||||
#ifndef IFNAMSIZ
|
||||
#define IFNAMSIZ 16
|
||||
#endif
|
||||
|
||||
#ifndef MAX_HANDLE_SZ
|
||||
#define MAX_HANDLE_SZ 128
|
||||
#endif
|
||||
|
||||
#define noreturn G_GNUC_NORETURN
|
||||
|
||||
#include "sd-id128.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "async.h"
|
||||
#include "util.h"
|
||||
|
||||
static inline pid_t gettid(void) {
|
||||
return (pid_t) syscall(SYS_gettid);
|
||||
}
|
||||
|
||||
#endif /* NM_SD_ADAPT_H */
|
||||
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
Copyright (C) 2014 Tom Gundersen
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
|
||||
#include "sd-dhcp-client.h"
|
||||
#include "dhcp-protocol.h"
|
||||
|
||||
int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
|
||||
uint32_t xid, const uint8_t *mac_addr,
|
||||
size_t mac_addr_len, uint16_t arp_type);
|
||||
int dhcp_network_bind_udp_socket(be32_t address, uint16_t port);
|
||||
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
|
||||
const void *packet, size_t len);
|
||||
int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
|
||||
const void *packet, size_t len);
|
||||
|
||||
int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload,
|
||||
uint8_t code, size_t optlen, const void *optval);
|
||||
|
||||
typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
|
||||
const uint8_t *option, void *user_data);
|
||||
|
||||
int dhcp_option_parse(DHCPMessage *message, size_t len,
|
||||
dhcp_option_cb_t cb, void *user_data);
|
||||
|
||||
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
|
||||
uint8_t type, uint16_t arp_type, size_t optlen,
|
||||
size_t *optoffset);
|
||||
|
||||
uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
|
||||
|
||||
void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
|
||||
uint16_t source, be32_t destination_addr,
|
||||
uint16_t destination, uint16_t len);
|
||||
|
||||
int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
|
||||
#define _cleanup_dhcp_client_unref_ _cleanup_(sd_dhcp_client_unrefp)
|
||||
|
||||
/* If we are invoking callbacks of a dhcp-client, ensure unreffing the
|
||||
* client from the callback doesn't destroy the object we are working
|
||||
* on */
|
||||
#define DHCP_CLIENT_DONT_DESTROY(client) \
|
||||
_cleanup_dhcp_client_unref_ _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client)
|
||||
|
||||
#define log_dhcp_client(client, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
Copyright (C) 2014 Tom Gundersen
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <stdint.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
#include "refcnt.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
|
||||
#include "sd-dhcp-client.h"
|
||||
|
||||
struct sd_dhcp_route {
|
||||
struct in_addr dst_addr;
|
||||
struct in_addr gw_addr;
|
||||
uint8_t dst_prefixlen;
|
||||
};
|
||||
|
||||
struct sd_dhcp_lease {
|
||||
RefCount n_ref;
|
||||
|
||||
int32_t time_offset;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
uint32_t lifetime;
|
||||
uint32_t mtu_aging_timeout;
|
||||
be32_t address;
|
||||
be32_t server_address;
|
||||
be32_t subnet_mask;
|
||||
be32_t router;
|
||||
be32_t next_server;
|
||||
be32_t broadcast;
|
||||
struct in_addr *dns;
|
||||
size_t dns_size;
|
||||
struct in_addr *ntp;
|
||||
size_t ntp_size;
|
||||
struct in_addr *policy_filter;
|
||||
size_t policy_filter_size;
|
||||
struct sd_dhcp_route *static_route;
|
||||
size_t static_route_size;
|
||||
size_t static_route_allocated;
|
||||
uint16_t boot_file_size;
|
||||
uint16_t mdr;
|
||||
uint16_t mtu;
|
||||
uint8_t ttl;
|
||||
bool ip_forward;
|
||||
bool ip_forward_non_local;
|
||||
char *domainname;
|
||||
char *hostname;
|
||||
char *root_path;
|
||||
uint8_t *client_id;
|
||||
size_t client_id_len;
|
||||
};
|
||||
|
||||
int dhcp_lease_new(sd_dhcp_lease **ret);
|
||||
int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
|
||||
void *user_data);
|
||||
|
||||
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);
|
||||
|
||||
int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
|
||||
size_t client_id_len);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_lease*, sd_dhcp_lease_unref);
|
||||
#define _cleanup_dhcp_lease_unref_ _cleanup_(sd_dhcp_lease_unrefp)
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/if_infiniband.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/filter.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
|
||||
#include "dhcp-internal.h"
|
||||
|
||||
static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
|
||||
uint32_t xid, const uint8_t *mac_addr,
|
||||
size_t mac_addr_len,
|
||||
const uint8_t *bcast_addr,
|
||||
const struct ether_addr *eth_mac,
|
||||
uint16_t arp_type, uint8_t dhcp_hlen) {
|
||||
struct sock_filter filter[] = {
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
|
||||
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0), /* packet >= DHCPPacket ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.protocol)), /* A <- IP protocol */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0), /* IP protocol == UDP ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags */
|
||||
BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x20), /* A <- A & 0x20 (More Fragments bit) */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags + Fragment offset */
|
||||
BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x1fff), /* A <- A & 0x1fff (Fragment offset) */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)), /* A <- UDP destination port */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_PORT_CLIENT, 1, 0), /* UDP destination port == DHCP client port ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)), /* A <- DHCP op */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), /* op == BOOTREPLY ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)), /* A <- DHCP header type */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0), /* header type == arp_type ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- mac address length */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((unsigned int *) eth_mac))), /* A <- 4 bytes of client's MAC */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((unsigned short *) (((char *) eth_mac) + 4)))), /* A <- remainder of client's MAC */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
|
||||
};
|
||||
struct sock_fprog fprog = {
|
||||
.len = ELEMENTSOF(filter),
|
||||
.filter = filter
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r, on = 1;
|
||||
|
||||
assert(ifindex > 0);
|
||||
assert(link);
|
||||
|
||||
s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, SOL_PACKET, PACKET_AUXDATA, &on, sizeof(on));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
link->ll.sll_family = AF_PACKET;
|
||||
link->ll.sll_protocol = htons(ETH_P_IP);
|
||||
link->ll.sll_ifindex = ifindex;
|
||||
link->ll.sll_hatype = htons(arp_type);
|
||||
link->ll.sll_halen = mac_addr_len;
|
||||
memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
|
||||
|
||||
r = bind(s, &link->sa, sizeof(link->ll));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = s;
|
||||
s = -1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
|
||||
uint32_t xid, const uint8_t *mac_addr,
|
||||
size_t mac_addr_len, uint16_t arp_type) {
|
||||
static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
/* Default broadcast address for IPoIB */
|
||||
static const uint8_t ib_bcast[] = {
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } };
|
||||
const uint8_t *bcast_addr = NULL;
|
||||
uint8_t dhcp_hlen = 0;
|
||||
|
||||
assert_return(mac_addr_len > 0, -EINVAL);
|
||||
|
||||
if (arp_type == ARPHRD_ETHER) {
|
||||
assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
|
||||
memcpy(ð_mac, mac_addr, ETH_ALEN);
|
||||
bcast_addr = eth_bcast;
|
||||
dhcp_hlen = ETH_ALEN;
|
||||
} else if (arp_type == ARPHRD_INFINIBAND) {
|
||||
assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL);
|
||||
bcast_addr = ib_bcast;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len,
|
||||
bcast_addr, ð_mac, arp_type, dhcp_hlen);
|
||||
}
|
||||
|
||||
int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) {
|
||||
union sockaddr_union src = {
|
||||
.in.sin_family = AF_INET,
|
||||
.in.sin_port = htobe16(port),
|
||||
.in.sin_addr.s_addr = address,
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r, on = 1, tos = IPTOS_CLASS_CS6;
|
||||
|
||||
s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (address == INADDR_ANY) {
|
||||
r = setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
} else {
|
||||
r = setsockopt(s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = bind(s, &src.sa, sizeof(src.in));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = s;
|
||||
s = -1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
|
||||
const void *packet, size_t len) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(packet);
|
||||
assert(len);
|
||||
|
||||
r = sendto(s, packet, len, 0, &link->sa, sizeof(link->ll));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
|
||||
const void *packet, size_t len) {
|
||||
union sockaddr_union dest = {
|
||||
.in.sin_family = AF_INET,
|
||||
.in.sin_port = htobe16(port),
|
||||
.in.sin_addr.s_addr = address,
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(s >= 0);
|
||||
assert(packet);
|
||||
assert(len);
|
||||
|
||||
r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dhcp-internal.h"
|
||||
|
||||
static int option_append(uint8_t options[], size_t size, size_t *offset,
|
||||
uint8_t code, size_t optlen, const void *optval) {
|
||||
assert(options);
|
||||
assert(offset);
|
||||
|
||||
if (code != DHCP_OPTION_END)
|
||||
/* always make sure there is space for an END option */
|
||||
size --;
|
||||
|
||||
switch (code) {
|
||||
|
||||
case DHCP_OPTION_PAD:
|
||||
case DHCP_OPTION_END:
|
||||
if (size < *offset + 1)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
*offset += 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (size < *offset + optlen + 2)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = optlen;
|
||||
|
||||
if (optlen) {
|
||||
assert(optval);
|
||||
|
||||
memcpy(&options[*offset + 2], optval, optlen);
|
||||
}
|
||||
|
||||
*offset += optlen + 2;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
|
||||
uint8_t overload,
|
||||
uint8_t code, size_t optlen, const void *optval) {
|
||||
size_t file_offset = 0, sname_offset =0;
|
||||
bool file, sname;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(offset);
|
||||
|
||||
file = overload & DHCP_OVERLOAD_FILE;
|
||||
sname = overload & DHCP_OVERLOAD_SNAME;
|
||||
|
||||
if (*offset < size) {
|
||||
/* still space in the options array */
|
||||
r = option_append(message->options, size, offset, code, optlen, optval);
|
||||
if (r >= 0)
|
||||
return 0;
|
||||
else if (r == -ENOBUFS && (file || sname)) {
|
||||
/* did not fit, but we have more buffers to try
|
||||
close the options array and move the offset to its end */
|
||||
r = option_append(message->options, size, offset, DHCP_OPTION_END, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*offset = size;
|
||||
} else
|
||||
return r;
|
||||
}
|
||||
|
||||
if (overload & DHCP_OVERLOAD_FILE) {
|
||||
file_offset = *offset - size;
|
||||
|
||||
if (file_offset < sizeof(message->file)) {
|
||||
/* still space in the 'file' array */
|
||||
r = option_append(message->file, sizeof(message->file), &file_offset, code, optlen, optval);
|
||||
if (r >= 0) {
|
||||
*offset = size + file_offset;
|
||||
return 0;
|
||||
} else if (r == -ENOBUFS && sname) {
|
||||
/* did not fit, but we have more buffers to try
|
||||
close the file array and move the offset to its end */
|
||||
r = option_append(message->options, size, offset, DHCP_OPTION_END, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*offset = size + sizeof(message->file);
|
||||
} else
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (overload & DHCP_OVERLOAD_SNAME) {
|
||||
sname_offset = *offset - size - (file ? sizeof(message->file) : 0);
|
||||
|
||||
if (sname_offset < sizeof(message->sname)) {
|
||||
/* still space in the 'sname' array */
|
||||
r = option_append(message->sname, sizeof(message->sname), &sname_offset, code, optlen, optval);
|
||||
if (r >= 0) {
|
||||
*offset = size + (file ? sizeof(message->file) : 0) + sname_offset;
|
||||
return 0;
|
||||
} else {
|
||||
/* no space, or other error, give up */
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
|
||||
uint8_t *message_type, dhcp_option_cb_t cb,
|
||||
void *user_data) {
|
||||
uint8_t code, len;
|
||||
size_t offset = 0;
|
||||
|
||||
while (offset < buflen) {
|
||||
switch (options[offset]) {
|
||||
case DHCP_OPTION_PAD:
|
||||
offset++;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_END:
|
||||
return 0;
|
||||
|
||||
case DHCP_OPTION_MESSAGE_TYPE:
|
||||
if (buflen < offset + 3)
|
||||
return -ENOBUFS;
|
||||
|
||||
len = options[++offset];
|
||||
if (len != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (message_type)
|
||||
*message_type = options[++offset];
|
||||
else
|
||||
offset++;
|
||||
|
||||
offset++;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_OVERLOAD:
|
||||
if (buflen < offset + 3)
|
||||
return -ENOBUFS;
|
||||
|
||||
len = options[++offset];
|
||||
if (len != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (overload)
|
||||
*overload = options[++offset];
|
||||
else
|
||||
offset++;
|
||||
|
||||
offset++;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (buflen < offset + 3)
|
||||
return -ENOBUFS;
|
||||
|
||||
code = options[offset];
|
||||
len = options[++offset];
|
||||
|
||||
if (buflen < ++offset + len)
|
||||
return -EINVAL;
|
||||
|
||||
if (cb)
|
||||
cb(code, len, &options[offset], user_data);
|
||||
|
||||
offset += len;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset < buflen)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_option_parse(DHCPMessage *message, size_t len,
|
||||
dhcp_option_cb_t cb, void *user_data) {
|
||||
uint8_t overload = 0;
|
||||
uint8_t message_type = 0;
|
||||
int r;
|
||||
|
||||
if (!message)
|
||||
return -EINVAL;
|
||||
|
||||
if (len < sizeof(DHCPMessage))
|
||||
return -EINVAL;
|
||||
|
||||
len -= sizeof(DHCPMessage);
|
||||
|
||||
r = parse_options(message->options, len, &overload, &message_type,
|
||||
cb, user_data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (overload & DHCP_OVERLOAD_FILE) {
|
||||
r = parse_options(message->file, sizeof(message->file),
|
||||
NULL, &message_type, cb, user_data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (overload & DHCP_OVERLOAD_SNAME) {
|
||||
r = parse_options(message->sname, sizeof(message->sname),
|
||||
NULL, &message_type, cb, user_data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (message_type)
|
||||
return message_type;
|
||||
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
Copyright (C) 2014 Tom Gundersen
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "list.h"
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "dhcp-internal.h"
|
||||
#include "sd-dhcp-lease.h"
|
||||
#include "sd-dhcp-client.h"
|
||||
|
||||
#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
|
||||
|
||||
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
|
||||
uint8_t type, uint16_t arp_type, size_t optlen,
|
||||
size_t *optoffset) {
|
||||
size_t offset = 0;
|
||||
int r;
|
||||
|
||||
assert(op == BOOTREQUEST || op == BOOTREPLY);
|
||||
assert(arp_type == ARPHRD_ETHER || arp_type == ARPHRD_INFINIBAND);
|
||||
|
||||
message->op = op;
|
||||
message->htype = arp_type;
|
||||
message->hlen = (arp_type == ARPHRD_ETHER) ? ETHER_ADDR_LEN : 0;
|
||||
message->xid = htobe32(xid);
|
||||
message->magic = htobe32(DHCP_MAGIC_COOKIE);
|
||||
|
||||
r = dhcp_option_append(message, optlen, &offset, 0,
|
||||
DHCP_OPTION_MESSAGE_TYPE, 1, &type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*optoffset = offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
|
||||
uint64_t *buf_64 = (uint64_t*)buf;
|
||||
uint64_t *end_64 = buf_64 + (len / sizeof(uint64_t));
|
||||
uint64_t sum = 0;
|
||||
|
||||
/* See RFC1071 */
|
||||
|
||||
while (buf_64 < end_64) {
|
||||
sum += *buf_64;
|
||||
if (sum < *buf_64)
|
||||
/* wrap around in one's complement */
|
||||
sum++;
|
||||
|
||||
buf_64 ++;
|
||||
}
|
||||
|
||||
if (len % sizeof(uint64_t)) {
|
||||
/* If the buffer is not aligned to 64-bit, we need
|
||||
to zero-pad the last few bytes and add them in */
|
||||
uint64_t buf_tail = 0;
|
||||
|
||||
memcpy(&buf_tail, buf_64, len % sizeof(uint64_t));
|
||||
|
||||
sum += buf_tail;
|
||||
if (sum < buf_tail)
|
||||
/* wrap around */
|
||||
sum++;
|
||||
}
|
||||
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
return ~sum;
|
||||
}
|
||||
|
||||
void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
|
||||
uint16_t source_port, be32_t destination_addr,
|
||||
uint16_t destination_port, uint16_t len) {
|
||||
packet->ip.version = IPVERSION;
|
||||
packet->ip.ihl = DHCP_IP_SIZE / 4;
|
||||
packet->ip.tot_len = htobe16(len);
|
||||
|
||||
packet->ip.tos = IPTOS_CLASS_CS6;
|
||||
|
||||
packet->ip.protocol = IPPROTO_UDP;
|
||||
packet->ip.saddr = source_addr;
|
||||
packet->ip.daddr = destination_addr;
|
||||
|
||||
packet->udp.source = htobe16(source_port);
|
||||
packet->udp.dest = htobe16(destination_port);
|
||||
|
||||
packet->udp.len = htobe16(len - DHCP_IP_SIZE);
|
||||
|
||||
packet->ip.check = packet->udp.len;
|
||||
packet->udp.check = dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, len - 8);
|
||||
|
||||
packet->ip.ttl = IPDEFTTL;
|
||||
packet->ip.check = 0;
|
||||
packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE);
|
||||
}
|
||||
|
||||
int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) {
|
||||
size_t hdrlen;
|
||||
|
||||
assert(packet);
|
||||
|
||||
/* IP */
|
||||
|
||||
if (packet->ip.version != IPVERSION) {
|
||||
log_debug("ignoring packet: not IPv4");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (packet->ip.ihl < 5) {
|
||||
log_debug("ignoring packet: IPv4 IHL (%u words) invalid",
|
||||
packet->ip.ihl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdrlen = packet->ip.ihl * 4;
|
||||
if (hdrlen < 20) {
|
||||
log_debug("ignoring packet: IPv4 IHL (%zu bytes) "
|
||||
"smaller than minimum (20 bytes)", hdrlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (len < hdrlen) {
|
||||
log_debug("ignoring packet: packet (%zu bytes) "
|
||||
"smaller than expected (%zu) by IP header", len,
|
||||
hdrlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* UDP */
|
||||
|
||||
if (packet->ip.protocol != IPPROTO_UDP) {
|
||||
log_debug("ignoring packet: not UDP");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (len < hdrlen + be16toh(packet->udp.len)) {
|
||||
log_debug("ignoring packet: packet (%zu bytes) "
|
||||
"smaller than expected (%zu) by UDP header", len,
|
||||
hdrlen + be16toh(packet->udp.len));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (be16toh(packet->udp.dest) != DHCP_PORT_CLIENT) {
|
||||
log_debug("ignoring packet: to port %u, which "
|
||||
"is not the DHCP client port (%u)",
|
||||
be16toh(packet->udp.dest), DHCP_PORT_CLIENT);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* checksums - computing these is relatively expensive, so only do it
|
||||
if all the other checks have passed
|
||||
*/
|
||||
|
||||
if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen)) {
|
||||
log_debug("ignoring packet: invalid IP checksum");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (checksum && packet->udp.check) {
|
||||
packet->ip.check = packet->udp.len;
|
||||
packet->ip.ttl = 0;
|
||||
|
||||
if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl,
|
||||
be16toh(packet->udp.len) + 12)) {
|
||||
log_debug("ignoring packet: invalid UDP checksum");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <netinet/udp.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "sparse-endian.h"
|
||||
|
||||
struct DHCPMessage {
|
||||
uint8_t op;
|
||||
uint8_t htype;
|
||||
uint8_t hlen;
|
||||
uint8_t hops;
|
||||
be32_t xid;
|
||||
be16_t secs;
|
||||
be16_t flags;
|
||||
be32_t ciaddr;
|
||||
be32_t yiaddr;
|
||||
be32_t siaddr;
|
||||
be32_t giaddr;
|
||||
uint8_t chaddr[16];
|
||||
uint8_t sname[64];
|
||||
uint8_t file[128];
|
||||
be32_t magic;
|
||||
uint8_t options[0];
|
||||
} _packed_;
|
||||
|
||||
typedef struct DHCPMessage DHCPMessage;
|
||||
|
||||
struct DHCPPacket {
|
||||
struct iphdr ip;
|
||||
struct udphdr udp;
|
||||
DHCPMessage dhcp;
|
||||
} _packed_;
|
||||
|
||||
typedef struct DHCPPacket DHCPPacket;
|
||||
|
||||
#define DHCP_IP_SIZE (int32_t)(sizeof(struct iphdr))
|
||||
#define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE)
|
||||
#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage))
|
||||
#define DHCP_DEFAULT_MIN_SIZE 576 /* the minimum internet hosts must be able to receive */
|
||||
#define DHCP_MIN_OPTIONS_SIZE DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE
|
||||
#define DHCP_MAGIC_COOKIE (uint32_t)(0x63825363)
|
||||
|
||||
enum {
|
||||
DHCP_PORT_SERVER = 67,
|
||||
DHCP_PORT_CLIENT = 68,
|
||||
};
|
||||
|
||||
enum DHCPState {
|
||||
DHCP_STATE_INIT = 0,
|
||||
DHCP_STATE_SELECTING = 1,
|
||||
DHCP_STATE_INIT_REBOOT = 2,
|
||||
DHCP_STATE_REBOOTING = 3,
|
||||
DHCP_STATE_REQUESTING = 4,
|
||||
DHCP_STATE_BOUND = 5,
|
||||
DHCP_STATE_RENEWING = 6,
|
||||
DHCP_STATE_REBINDING = 7,
|
||||
DHCP_STATE_STOPPED = 8,
|
||||
};
|
||||
|
||||
typedef enum DHCPState DHCPState;
|
||||
|
||||
enum {
|
||||
BOOTREQUEST = 1,
|
||||
BOOTREPLY = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
DHCP_DISCOVER = 1,
|
||||
DHCP_OFFER = 2,
|
||||
DHCP_REQUEST = 3,
|
||||
DHCP_DECLINE = 4,
|
||||
DHCP_ACK = 5,
|
||||
DHCP_NAK = 6,
|
||||
DHCP_RELEASE = 7,
|
||||
DHCP_INFORM = 8,
|
||||
DHCP_FORCERENEW = 9,
|
||||
};
|
||||
|
||||
enum {
|
||||
DHCP_OVERLOAD_FILE = 1,
|
||||
DHCP_OVERLOAD_SNAME = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
DHCP_OPTION_PAD = 0,
|
||||
DHCP_OPTION_SUBNET_MASK = 1,
|
||||
DHCP_OPTION_TIME_OFFSET = 2,
|
||||
DHCP_OPTION_ROUTER = 3,
|
||||
DHCP_OPTION_DOMAIN_NAME_SERVER = 6,
|
||||
DHCP_OPTION_HOST_NAME = 12,
|
||||
DHCP_OPTION_BOOT_FILE_SIZE = 13,
|
||||
DHCP_OPTION_DOMAIN_NAME = 15,
|
||||
DHCP_OPTION_ROOT_PATH = 17,
|
||||
DHCP_OPTION_ENABLE_IP_FORWARDING = 19,
|
||||
DHCP_OPTION_ENABLE_IP_FORWARDING_NL = 20,
|
||||
DHCP_OPTION_POLICY_FILTER = 21,
|
||||
DHCP_OPTION_INTERFACE_MDR = 22,
|
||||
DHCP_OPTION_INTERFACE_TTL = 23,
|
||||
DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24,
|
||||
DHCP_OPTION_INTERFACE_MTU = 26,
|
||||
DHCP_OPTION_BROADCAST = 28,
|
||||
DHCP_OPTION_STATIC_ROUTE = 33,
|
||||
DHCP_OPTION_NTP_SERVER = 42,
|
||||
DHCP_OPTION_REQUESTED_IP_ADDRESS = 50,
|
||||
DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51,
|
||||
DHCP_OPTION_OVERLOAD = 52,
|
||||
DHCP_OPTION_MESSAGE_TYPE = 53,
|
||||
DHCP_OPTION_SERVER_IDENTIFIER = 54,
|
||||
DHCP_OPTION_PARAMETER_REQUEST_LIST = 55,
|
||||
DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57,
|
||||
DHCP_OPTION_RENEWAL_T1_TIME = 58,
|
||||
DHCP_OPTION_REBINDING_T2_TIME = 59,
|
||||
DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60,
|
||||
DHCP_OPTION_CLIENT_IDENTIFIER = 61,
|
||||
DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121,
|
||||
DHCP_OPTION_END = 255,
|
||||
};
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "sparse-endian.h"
|
||||
#include "sd-event.h"
|
||||
#include "list.h"
|
||||
#include "macro.h"
|
||||
|
||||
typedef struct DHCP6Address DHCP6Address;
|
||||
|
||||
struct DHCP6Address {
|
||||
LIST_FIELDS(DHCP6Address, addresses);
|
||||
|
||||
struct {
|
||||
struct in6_addr address;
|
||||
be32_t lifetime_preferred;
|
||||
be32_t lifetime_valid;
|
||||
} iaaddr _packed_;
|
||||
};
|
||||
|
||||
struct DHCP6IA {
|
||||
uint16_t type;
|
||||
struct {
|
||||
be32_t id;
|
||||
be32_t lifetime_t1;
|
||||
be32_t lifetime_t2;
|
||||
} _packed_;
|
||||
sd_event_source *timeout_t1;
|
||||
sd_event_source *timeout_t2;
|
||||
|
||||
LIST_HEAD(DHCP6Address, addresses);
|
||||
};
|
||||
|
||||
typedef struct DHCP6IA DHCP6IA;
|
||||
|
||||
#define log_dhcp6_client(p, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
|
||||
|
||||
int dhcp_network_icmp6_bind_router_solicitation(int index);
|
||||
int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
|
||||
|
||||
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
|
||||
size_t optlen, const void *optval);
|
||||
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia);
|
||||
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
|
||||
size_t *optlen, uint8_t **optvalue);
|
||||
int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype,
|
||||
DHCP6IA *ia);
|
||||
|
||||
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *address);
|
||||
int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
|
||||
const void *packet, size_t len);
|
||||
|
||||
const char *dhcp6_message_type_to_string(int s) _const_;
|
||||
int dhcp6_message_type_from_string(const char *s) _pure_;
|
||||
const char *dhcp6_message_status_to_string(int s) _const_;
|
||||
int dhcp6_message_status_from_string(const char *s) _pure_;
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Tom Gundersen
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "refcnt.h"
|
||||
|
||||
#include "sd-dhcp6-lease.h"
|
||||
#include "dhcp6-internal.h"
|
||||
|
||||
struct sd_dhcp6_lease {
|
||||
RefCount n_ref;
|
||||
|
||||
uint8_t *serverid;
|
||||
size_t serverid_len;
|
||||
uint8_t preference;
|
||||
bool rapid_commit;
|
||||
|
||||
DHCP6IA ia;
|
||||
|
||||
DHCP6Address *addr_iter;
|
||||
};
|
||||
|
||||
int dhcp6_lease_clear_timers(DHCP6IA *ia);
|
||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
|
||||
DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
|
||||
|
||||
int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
|
||||
size_t len);
|
||||
int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len);
|
||||
int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference);
|
||||
int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference);
|
||||
int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease);
|
||||
int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
|
||||
|
||||
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
||||
|
||||
int dhcp6_lease_new(sd_dhcp6_lease **ret);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_lease*, sd_dhcp6_lease_unref);
|
||||
#define _cleanup_dhcp6_lease_free_ _cleanup_(sd_dhcp6_lease_unrefp)
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
|
||||
#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
|
||||
{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
|
||||
|
||||
#define IN6ADDR_ALL_NODES_MULTICAST_INIT \
|
||||
{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
|
||||
|
||||
int dhcp_network_icmp6_bind_router_solicitation(int index)
|
||||
{
|
||||
struct icmp6_filter filter = { };
|
||||
struct ipv6_mreq mreq = {
|
||||
.ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
|
||||
.ipv6mr_interface = index,
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r, zero = 0, hops = 255;
|
||||
|
||||
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
IPPROTO_ICMPV6);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
|
||||
r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
|
||||
sizeof(filter));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
/* RFC 3315, section 6.7, bullet point 2 may indicate that an
|
||||
IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
|
||||
Empirical experiments indicates otherwise and therefore an
|
||||
IPV6_MULTICAST_IF socket option is used here instead */
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
|
||||
sizeof(index));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
|
||||
sizeof(zero));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
|
||||
sizeof(hops));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
|
||||
sizeof(mreq));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = s;
|
||||
s = -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr)
|
||||
{
|
||||
struct sockaddr_in6 dst = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
|
||||
};
|
||||
struct {
|
||||
struct nd_router_solicit rs;
|
||||
struct nd_opt_hdr rs_opt;
|
||||
struct ether_addr rs_opt_mac;
|
||||
} _packed_ rs = {
|
||||
.rs.nd_rs_type = ND_ROUTER_SOLICIT,
|
||||
};
|
||||
struct iovec iov[1] = {
|
||||
{ &rs, },
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_name = &dst,
|
||||
.msg_namelen = sizeof(dst),
|
||||
.msg_iov = iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
int r;
|
||||
|
||||
if (ether_addr) {
|
||||
memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
|
||||
rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
|
||||
rs.rs_opt.nd_opt_len = 1;
|
||||
iov[0].iov_len = sizeof(rs);
|
||||
} else
|
||||
iov[0].iov_len = sizeof(rs.rs);
|
||||
|
||||
r = sendmsg(s, &msg, 0);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
|
||||
struct in6_pktinfo pktinfo = {
|
||||
.ipi6_ifindex = index,
|
||||
};
|
||||
union sockaddr_union src = {
|
||||
.in6.sin6_family = AF_INET6,
|
||||
.in6.sin6_port = htobe16(DHCP6_PORT_CLIENT),
|
||||
.in6.sin6_addr = IN6ADDR_ANY_INIT,
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r, off = 0, on = 1;
|
||||
|
||||
if (local_address)
|
||||
memcpy(&src.in6.sin6_addr, local_address,
|
||||
sizeof(src.in6.sin6_addr));
|
||||
|
||||
s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
IPPROTO_UDP);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &pktinfo,
|
||||
sizeof(pktinfo));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = bind(s, &src.sa, sizeof(src.in6));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = s;
|
||||
s = -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
|
||||
const void *packet, size_t len) {
|
||||
union sockaddr_union dest = {
|
||||
.in6.sin6_family = AF_INET6,
|
||||
.in6.sin6_port = htobe16(DHCP6_PORT_SERVER),
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(server_address);
|
||||
|
||||
memcpy(&dest.in6.sin6_addr, server_address, sizeof(dest.in6.sin6_addr));
|
||||
|
||||
r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in6));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,315 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sparse-endian.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
|
||||
#define DHCP6_OPTION_HDR_LEN 4
|
||||
#define DHCP6_OPTION_IA_NA_LEN 12
|
||||
#define DHCP6_OPTION_IA_TA_LEN 4
|
||||
|
||||
static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode,
|
||||
size_t optlen) {
|
||||
assert_return(buf, -EINVAL);
|
||||
assert_return(*buf, -EINVAL);
|
||||
assert_return(buflen, -EINVAL);
|
||||
|
||||
if (optlen > 0xffff || *buflen < optlen + DHCP6_OPTION_HDR_LEN)
|
||||
return -ENOBUFS;
|
||||
|
||||
(*buf)[0] = optcode >> 8;
|
||||
(*buf)[1] = optcode & 0xff;
|
||||
(*buf)[2] = optlen >> 8;
|
||||
(*buf)[3] = optlen & 0xff;
|
||||
|
||||
*buf += DHCP6_OPTION_HDR_LEN;
|
||||
*buflen -= DHCP6_OPTION_HDR_LEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
|
||||
size_t optlen, const void *optval) {
|
||||
int r;
|
||||
|
||||
assert_return(optval || optlen == 0, -EINVAL);
|
||||
|
||||
r = option_append_hdr(buf, buflen, code, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (optval)
|
||||
memcpy(*buf, optval, optlen);
|
||||
|
||||
*buf += optlen;
|
||||
*buflen -= optlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) {
|
||||
uint16_t len;
|
||||
uint8_t *ia_hdr;
|
||||
size_t ia_buflen, ia_addrlen = 0;
|
||||
DHCP6Address *addr;
|
||||
int r;
|
||||
|
||||
assert_return(buf && *buf && buflen && ia, -EINVAL);
|
||||
|
||||
switch (ia->type) {
|
||||
case DHCP6_OPTION_IA_NA:
|
||||
len = DHCP6_OPTION_IA_NA_LEN;
|
||||
break;
|
||||
|
||||
case DHCP6_OPTION_IA_TA:
|
||||
len = DHCP6_OPTION_IA_TA_LEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (*buflen < len)
|
||||
return -ENOBUFS;
|
||||
|
||||
ia_hdr = *buf;
|
||||
ia_buflen = *buflen;
|
||||
|
||||
*buf += DHCP6_OPTION_HDR_LEN;
|
||||
*buflen -= DHCP6_OPTION_HDR_LEN;
|
||||
|
||||
memcpy(*buf, &ia->id, len);
|
||||
|
||||
*buf += len;
|
||||
*buflen -= len;
|
||||
|
||||
LIST_FOREACH(addresses, addr, ia->addresses) {
|
||||
r = option_append_hdr(buf, buflen, DHCP6_OPTION_IAADDR,
|
||||
sizeof(addr->iaaddr));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
memcpy(*buf, &addr->iaaddr, sizeof(addr->iaaddr));
|
||||
|
||||
*buf += sizeof(addr->iaaddr);
|
||||
*buflen -= sizeof(addr->iaaddr);
|
||||
|
||||
ia_addrlen += DHCP6_OPTION_HDR_LEN + sizeof(addr->iaaddr);
|
||||
}
|
||||
|
||||
r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *opt,
|
||||
size_t *optlen) {
|
||||
uint16_t len;
|
||||
|
||||
assert_return(buf, -EINVAL);
|
||||
assert_return(opt, -EINVAL);
|
||||
assert_return(optlen, -EINVAL);
|
||||
|
||||
if (*buflen < 4)
|
||||
return -ENOMSG;
|
||||
|
||||
len = (*buf)[2] << 8 | (*buf)[3];
|
||||
|
||||
if (len > *buflen)
|
||||
return -ENOMSG;
|
||||
|
||||
*opt = (*buf)[0] << 8 | (*buf)[1];
|
||||
*optlen = len;
|
||||
|
||||
*buf += 4;
|
||||
*buflen -= 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
|
||||
size_t *optlen, uint8_t **optvalue) {
|
||||
int r;
|
||||
|
||||
assert_return(buf && buflen && optcode && optlen && optvalue, -EINVAL);
|
||||
|
||||
r = option_parse_hdr(buf, buflen, optcode, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (*optlen > *buflen)
|
||||
return -ENOBUFS;
|
||||
|
||||
*optvalue = *buf;
|
||||
*buflen -= *optlen;
|
||||
*buf += *optlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype,
|
||||
DHCP6IA *ia) {
|
||||
int r;
|
||||
uint16_t opt, status;
|
||||
size_t optlen;
|
||||
size_t iaaddr_offset;
|
||||
DHCP6Address *addr;
|
||||
uint32_t lt_t1, lt_t2, lt_valid, lt_pref, lt_min = ~0;
|
||||
|
||||
assert_return(ia, -EINVAL);
|
||||
assert_return(!ia->addresses, -EINVAL);
|
||||
|
||||
switch (iatype) {
|
||||
case DHCP6_OPTION_IA_NA:
|
||||
|
||||
if (*buflen < DHCP6_OPTION_IA_NA_LEN + DHCP6_OPTION_HDR_LEN +
|
||||
sizeof(addr->iaaddr)) {
|
||||
r = -ENOBUFS;
|
||||
goto error;
|
||||
}
|
||||
|
||||
iaaddr_offset = DHCP6_OPTION_IA_NA_LEN;
|
||||
memcpy(&ia->id, *buf, iaaddr_offset);
|
||||
|
||||
lt_t1 = be32toh(ia->lifetime_t1);
|
||||
lt_t2 = be32toh(ia->lifetime_t2);
|
||||
|
||||
if (lt_t1 && lt_t2 && lt_t1 > lt_t2) {
|
||||
log_dhcp6_client(client, "IA T1 %ds > T2 %ds",
|
||||
lt_t1, lt_t2);
|
||||
r = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DHCP6_OPTION_IA_TA:
|
||||
if (*buflen < DHCP6_OPTION_IA_TA_LEN + DHCP6_OPTION_HDR_LEN +
|
||||
sizeof(addr->iaaddr)) {
|
||||
r = -ENOBUFS;
|
||||
goto error;
|
||||
}
|
||||
|
||||
iaaddr_offset = DHCP6_OPTION_IA_TA_LEN;
|
||||
memcpy(&ia->id, *buf, iaaddr_offset);
|
||||
|
||||
ia->lifetime_t1 = 0;
|
||||
ia->lifetime_t2 = 0;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
r = -ENOMSG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ia->type = iatype;
|
||||
|
||||
*buflen -= iaaddr_offset;
|
||||
*buf += iaaddr_offset;
|
||||
|
||||
while ((r = option_parse_hdr(buf, buflen, &opt, &optlen)) >= 0) {
|
||||
|
||||
switch (opt) {
|
||||
case DHCP6_OPTION_IAADDR:
|
||||
|
||||
addr = new0(DHCP6Address, 1);
|
||||
if (!addr) {
|
||||
r = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
LIST_INIT(addresses, addr);
|
||||
|
||||
memcpy(&addr->iaaddr, *buf, sizeof(addr->iaaddr));
|
||||
|
||||
lt_valid = be32toh(addr->iaaddr.lifetime_valid);
|
||||
lt_pref = be32toh(addr->iaaddr.lifetime_valid);
|
||||
|
||||
if (!lt_valid || lt_pref > lt_valid) {
|
||||
log_dhcp6_client(client, "IA preferred %ds > valid %ds",
|
||||
lt_pref, lt_valid);
|
||||
free(addr);
|
||||
} else {
|
||||
LIST_PREPEND(addresses, ia->addresses, addr);
|
||||
if (lt_valid < lt_min)
|
||||
lt_min = lt_valid;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DHCP6_OPTION_STATUS_CODE:
|
||||
if (optlen < sizeof(status))
|
||||
break;
|
||||
|
||||
status = (*buf)[0] << 8 | (*buf)[1];
|
||||
if (status) {
|
||||
log_dhcp6_client(client, "IA status %d",
|
||||
status);
|
||||
r = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
log_dhcp6_client(client, "Unknown IA option %d", opt);
|
||||
break;
|
||||
}
|
||||
|
||||
*buflen -= optlen;
|
||||
*buf += optlen;
|
||||
}
|
||||
|
||||
if (r == -ENOMSG)
|
||||
r = 0;
|
||||
|
||||
if (!ia->lifetime_t1 && !ia->lifetime_t2) {
|
||||
lt_t1 = lt_min / 2;
|
||||
lt_t2 = lt_min / 10 * 8;
|
||||
ia->lifetime_t1 = htobe32(lt_t1);
|
||||
ia->lifetime_t2 = htobe32(lt_t2);
|
||||
|
||||
log_dhcp6_client(client, "Computed IA T1 %ds and T2 %ds as both were zero",
|
||||
lt_t1, lt_t2);
|
||||
}
|
||||
|
||||
if (*buflen)
|
||||
r = -ENOMSG;
|
||||
|
||||
error:
|
||||
*buf += *buflen;
|
||||
*buflen = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <netinet/ip6.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "sparse-endian.h"
|
||||
|
||||
struct DHCP6Message {
|
||||
union {
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t _pad[3];
|
||||
} _packed_;
|
||||
be32_t transaction_id;
|
||||
};
|
||||
} _packed_;
|
||||
|
||||
typedef struct DHCP6Message DHCP6Message;
|
||||
|
||||
#define DHCP6_MIN_OPTIONS_SIZE \
|
||||
1280 - sizeof(struct ip6_hdr) - sizeof(struct udphdr)
|
||||
|
||||
#define IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT \
|
||||
{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02 } } }
|
||||
|
||||
enum {
|
||||
DHCP6_PORT_SERVER = 547,
|
||||
DHCP6_PORT_CLIENT = 546,
|
||||
};
|
||||
|
||||
#define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC
|
||||
#define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC
|
||||
#define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC
|
||||
#define DHCP6_REQ_TIMEOUT 1 * USEC_PER_SEC
|
||||
#define DHCP6_REQ_MAX_RT 120 * USEC_PER_SEC
|
||||
#define DHCP6_REQ_MAX_RC 10
|
||||
#define DHCP6_REN_TIMEOUT 10 * USEC_PER_SEC
|
||||
#define DHCP6_REN_MAX_RT 600 * USEC_PER_SEC
|
||||
#define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC
|
||||
#define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC
|
||||
|
||||
enum {
|
||||
DHCP6_DUID_LLT = 1,
|
||||
DHCP6_DUID_EN = 2,
|
||||
DHCP6_DUID_LL = 3,
|
||||
DHCP6_DUID_UUID = 4,
|
||||
};
|
||||
|
||||
enum DHCP6State {
|
||||
DHCP6_STATE_STOPPED = 0,
|
||||
DHCP6_STATE_SOLICITATION = 2,
|
||||
DHCP6_STATE_REQUEST = 3,
|
||||
DHCP6_STATE_BOUND = 4,
|
||||
DHCP6_STATE_RENEW = 5,
|
||||
DHCP6_STATE_REBIND = 6,
|
||||
};
|
||||
|
||||
enum {
|
||||
DHCP6_SOLICIT = 1,
|
||||
DHCP6_ADVERTISE = 2,
|
||||
DHCP6_REQUEST = 3,
|
||||
DHCP6_CONFIRM = 4,
|
||||
DHCP6_RENEW = 5,
|
||||
DHCP6_REBIND = 6,
|
||||
DHCP6_REPLY = 7,
|
||||
DHCP6_RELEASE = 8,
|
||||
DHCP6_DECLINE = 9,
|
||||
DHCP6_RECONFIGURE = 10,
|
||||
DHCP6_INFORMATION_REQUEST = 11,
|
||||
DHCP6_RELAY_FORW = 12,
|
||||
DHCP6_RELAY_REPL = 13,
|
||||
_DHCP6_MESSAGE_MAX = 14,
|
||||
};
|
||||
|
||||
enum {
|
||||
DHCP6_OPTION_CLIENTID = 1,
|
||||
DHCP6_OPTION_SERVERID = 2,
|
||||
DHCP6_OPTION_IA_NA = 3,
|
||||
DHCP6_OPTION_IA_TA = 4,
|
||||
DHCP6_OPTION_IAADDR = 5,
|
||||
DHCP6_OPTION_ORO = 6,
|
||||
DHCP6_OPTION_PREFERENCE = 7,
|
||||
DHCP6_OPTION_ELAPSED_TIME = 8,
|
||||
DHCP6_OPTION_RELAY_MSG = 9,
|
||||
/* option code 10 is unassigned */
|
||||
DHCP6_OPTION_AUTH = 11,
|
||||
DHCP6_OPTION_UNICAST = 12,
|
||||
DHCP6_OPTION_STATUS_CODE = 13,
|
||||
DHCP6_OPTION_RAPID_COMMIT = 14,
|
||||
DHCP6_OPTION_USER_CLASS = 15,
|
||||
DHCP6_OPTION_VENDOR_CLASS = 16,
|
||||
DHCP6_OPTION_VENDOR_OPTS = 17,
|
||||
DHCP6_OPTION_INTERFACE_ID = 18,
|
||||
DHCP6_OPTION_RECONF_MSG = 19,
|
||||
DHCP6_OPTION_RECONF_ACCEPT = 20,
|
||||
|
||||
DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */
|
||||
DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */
|
||||
|
||||
DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075 */
|
||||
|
||||
/* option code 35 is unassigned */
|
||||
|
||||
DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */
|
||||
|
||||
/* option codes 89-142 are unassigned */
|
||||
/* option codes 144-65535 are unassigned */
|
||||
};
|
||||
|
||||
enum {
|
||||
DHCP6_STATUS_SUCCESS = 0,
|
||||
DHCP6_STATUS_UNSPEC_FAIL = 1,
|
||||
DHCP6_STATUS_NO_ADDRS_AVAIL = 2,
|
||||
DHCP6_STATUS_NO_BINDING = 3,
|
||||
DHCP6_STATUS_NOT_ON_LINK = 4,
|
||||
DHCP6_STATUS_USE_MULTICAST = 5,
|
||||
_DHCP6_STATUS_MAX = 6,
|
||||
};
|
||||
|
|
@ -0,0 +1,480 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <netinet/ether.h>
|
||||
#include <linux/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "strv.h"
|
||||
#include "siphash24.h"
|
||||
#include "libudev-private.h"
|
||||
#endif
|
||||
#include "dhcp-lease-internal.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "log.h"
|
||||
#include "utf8.h"
|
||||
#endif
|
||||
#include "util.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "conf-parser.h"
|
||||
#include "condition.h"
|
||||
#endif
|
||||
#include "network-internal.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
const char *net_get_name(struct udev_device *device) {
|
||||
const char *name, *field;
|
||||
|
||||
assert(device);
|
||||
|
||||
/* fetch some persistent data unique (on this machine) to this device */
|
||||
FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
|
||||
name = udev_device_get_property_value(device, field);
|
||||
if (name)
|
||||
return name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
|
||||
|
||||
int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
|
||||
size_t l, sz = 0;
|
||||
const char *name = NULL;
|
||||
int r;
|
||||
uint8_t *v;
|
||||
|
||||
assert(device);
|
||||
|
||||
name = net_get_name(device);
|
||||
if (!name)
|
||||
return -ENOENT;
|
||||
|
||||
l = strlen(name);
|
||||
sz = sizeof(sd_id128_t) + l;
|
||||
v = alloca(sz);
|
||||
|
||||
/* fetch some persistent data unique to this machine */
|
||||
r = sd_id128_get_machine((sd_id128_t*) v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
memcpy(v + sizeof(sd_id128_t), name, l);
|
||||
|
||||
/* Let's hash the machine ID plus the device name. We
|
||||
* use a fixed, but originally randomly created hash
|
||||
* key here. */
|
||||
siphash24(result, v, sz, HASH_KEY.bytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool net_match_config(const struct ether_addr *match_mac,
|
||||
const char *match_path,
|
||||
const char *match_driver,
|
||||
const char *match_type,
|
||||
const char *match_name,
|
||||
Condition *match_host,
|
||||
Condition *match_virt,
|
||||
Condition *match_kernel,
|
||||
Condition *match_arch,
|
||||
const struct ether_addr *dev_mac,
|
||||
const char *dev_path,
|
||||
const char *dev_parent_driver,
|
||||
const char *dev_driver,
|
||||
const char *dev_type,
|
||||
const char *dev_name) {
|
||||
|
||||
if (match_host && !condition_test_host(match_host))
|
||||
return 0;
|
||||
|
||||
if (match_virt && !condition_test_virtualization(match_virt))
|
||||
return 0;
|
||||
|
||||
if (match_kernel && !condition_test_kernel_command_line(match_kernel))
|
||||
return 0;
|
||||
|
||||
if (match_arch && !condition_test_architecture(match_arch))
|
||||
return 0;
|
||||
|
||||
if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
|
||||
return 0;
|
||||
|
||||
if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
|
||||
return 0;
|
||||
|
||||
if (match_driver) {
|
||||
if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
|
||||
return 0;
|
||||
else if (!streq_ptr(match_driver, dev_driver))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (match_type && !streq_ptr(match_type, dev_type))
|
||||
return 0;
|
||||
|
||||
if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int config_parse_net_condition(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
ConditionType cond = ltype;
|
||||
Condition **ret = data;
|
||||
bool negate;
|
||||
Condition *c;
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
negate = rvalue[0] == '!';
|
||||
if (negate)
|
||||
rvalue++;
|
||||
|
||||
s = strdup(rvalue);
|
||||
if (!s)
|
||||
return log_oom();
|
||||
|
||||
c = condition_new(cond, s, false, negate);
|
||||
if (!c)
|
||||
return log_oom();
|
||||
|
||||
if (*ret)
|
||||
condition_free(*ret);
|
||||
|
||||
*ret = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_ifname(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
char **s = data;
|
||||
_cleanup_free_ char *n = NULL;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
n = strdup(rvalue);
|
||||
if (!n)
|
||||
return log_oom();
|
||||
|
||||
if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(*s);
|
||||
if (*n) {
|
||||
*s = n;
|
||||
n = NULL;
|
||||
} else
|
||||
*s = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_ifalias(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
char **s = data;
|
||||
char *n;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
n = strdup(rvalue);
|
||||
if (!n)
|
||||
return log_oom();
|
||||
|
||||
if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
|
||||
free(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(*s);
|
||||
if (*n)
|
||||
*s = n;
|
||||
else {
|
||||
free(n);
|
||||
*s = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_hwaddr(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
struct ether_addr **hwaddr = data;
|
||||
struct ether_addr *n;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
n = new0(struct ether_addr, 1);
|
||||
if (!n)
|
||||
return log_oom();
|
||||
|
||||
r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
||||
&n->ether_addr_octet[0],
|
||||
&n->ether_addr_octet[1],
|
||||
&n->ether_addr_octet[2],
|
||||
&n->ether_addr_octet[3],
|
||||
&n->ether_addr_octet[4],
|
||||
&n->ether_addr_octet[5]);
|
||||
if (r != 6) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Not a valid MAC address, ignoring assignment: %s", rvalue);
|
||||
free(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(*hwaddr);
|
||||
*hwaddr = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
|
||||
unsigned i;
|
||||
|
||||
assert(f);
|
||||
assert(addresses);
|
||||
assert(size);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
fprintf(f, "%s%s", inet_ntoa(addresses[i]),
|
||||
(i < (size - 1)) ? " ": "");
|
||||
}
|
||||
|
||||
int deserialize_in_addrs(struct in_addr **ret, const char *string) {
|
||||
_cleanup_free_ struct in_addr *addresses = NULL;
|
||||
int size = 0;
|
||||
const char *word, *state;
|
||||
size_t len;
|
||||
|
||||
assert(ret);
|
||||
assert(string);
|
||||
|
||||
FOREACH_WORD(word, len, string, state) {
|
||||
_cleanup_free_ char *addr_str = NULL;
|
||||
struct in_addr *new_addresses;
|
||||
int r;
|
||||
|
||||
new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
|
||||
if (!new_addresses)
|
||||
return -ENOMEM;
|
||||
else
|
||||
addresses = new_addresses;
|
||||
|
||||
addr_str = strndup(word, len);
|
||||
if (!addr_str)
|
||||
return -ENOMEM;
|
||||
|
||||
r = inet_pton(AF_INET, addr_str, &(addresses[size]));
|
||||
if (r <= 0)
|
||||
continue;
|
||||
|
||||
size ++;
|
||||
}
|
||||
|
||||
*ret = addresses;
|
||||
addresses = NULL;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
|
||||
_cleanup_free_ struct in6_addr *addresses = NULL;
|
||||
int size = 0;
|
||||
const char *word, *state;
|
||||
size_t len;
|
||||
|
||||
assert(ret);
|
||||
assert(string);
|
||||
|
||||
FOREACH_WORD(word, len, string, state) {
|
||||
_cleanup_free_ char *addr_str = NULL;
|
||||
struct in6_addr *new_addresses;
|
||||
int r;
|
||||
|
||||
new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
|
||||
if (!new_addresses)
|
||||
return -ENOMEM;
|
||||
else
|
||||
addresses = new_addresses;
|
||||
|
||||
addr_str = strndup(word, len);
|
||||
if (!addr_str)
|
||||
return -ENOMEM;
|
||||
|
||||
r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
|
||||
if (r <= 0)
|
||||
continue;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
*ret = addresses;
|
||||
addresses = NULL;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
|
||||
unsigned i;
|
||||
|
||||
assert(f);
|
||||
assert(key);
|
||||
assert(routes);
|
||||
assert(size);
|
||||
|
||||
fprintf(f, "%s=", key);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
fprintf(f, "%s/%" PRIu8 ",%s%s", inet_ntoa(routes[i].dst_addr),
|
||||
routes[i].dst_prefixlen, inet_ntoa(routes[i].gw_addr),
|
||||
(i < (size - 1)) ? " ": "");
|
||||
|
||||
fputs("\n", f);
|
||||
}
|
||||
|
||||
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
|
||||
_cleanup_free_ struct sd_dhcp_route *routes = NULL;
|
||||
size_t size = 0, allocated = 0;
|
||||
const char *word, *state;
|
||||
size_t len;
|
||||
|
||||
assert(ret);
|
||||
assert(ret_size);
|
||||
assert(ret_allocated);
|
||||
assert(string);
|
||||
|
||||
FOREACH_WORD(word, len, string, state) {
|
||||
/* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
|
||||
_cleanup_free_ char* entry = NULL;
|
||||
char *tok, *tok_end;
|
||||
unsigned n;
|
||||
int r;
|
||||
|
||||
if (!GREEDY_REALLOC(routes, allocated, size + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
entry = strndup(word, len);
|
||||
if(!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
tok = entry;
|
||||
|
||||
/* get the subnet */
|
||||
tok_end = strchr(tok, '/');
|
||||
if (!tok_end)
|
||||
continue;
|
||||
*tok_end = '\0';
|
||||
|
||||
r = inet_aton(tok, &routes[size].dst_addr);
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
tok = tok_end + 1;
|
||||
|
||||
/* get the prefixlen */
|
||||
tok_end = strchr(tok, ',');
|
||||
if (!tok_end)
|
||||
continue;
|
||||
|
||||
*tok_end = '\0';
|
||||
|
||||
r = safe_atou(tok, &n);
|
||||
if (r < 0 || n > 32)
|
||||
continue;
|
||||
|
||||
routes[size].dst_prefixlen = (uint8_t) n;
|
||||
tok = tok_end + 1;
|
||||
|
||||
/* get the gateway */
|
||||
r = inet_aton(tok, &routes[size].gw_addr);
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
*ret_size = size;
|
||||
*ret_allocated = allocated;
|
||||
*ret = routes;
|
||||
routes = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <netinet/ether.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "udev.h"
|
||||
#include "condition-util.h"
|
||||
|
||||
bool net_match_config(const struct ether_addr *match_mac,
|
||||
const char *match_path,
|
||||
const char *match_driver,
|
||||
const char *match_type,
|
||||
const char *match_name,
|
||||
Condition *match_host,
|
||||
Condition *match_virt,
|
||||
Condition *match_kernel,
|
||||
Condition *match_arch,
|
||||
const struct ether_addr *dev_mac,
|
||||
const char *dev_path,
|
||||
const char *dev_parent_driver,
|
||||
const char *dev_driver,
|
||||
const char *dev_type,
|
||||
const char *dev_name);
|
||||
|
||||
int config_parse_net_condition(const char *unit, const char *filename, unsigned line,
|
||||
const char *section, unsigned section_line, const char *lvalue,
|
||||
int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
int config_parse_hwaddr(const char *unit, const char *filename, unsigned line,
|
||||
const char *section, unsigned section_line, const char *lvalue,
|
||||
int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
int config_parse_ifname(const char *unit, const char *filename, unsigned line,
|
||||
const char *section, unsigned section_line, const char *lvalue,
|
||||
int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
int config_parse_ifalias(const char *unit, const char *filename, unsigned line,
|
||||
const char *section, unsigned section_line, const char *lvalue,
|
||||
int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]);
|
||||
const char *net_get_name(struct udev_device *device);
|
||||
#endif
|
||||
|
||||
void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size);
|
||||
int deserialize_in_addrs(struct in_addr **addresses, const char *string);
|
||||
int deserialize_in6_addrs(struct in6_addr **addresses, const char *string);
|
||||
|
||||
/* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */
|
||||
struct sd_dhcp_route;
|
||||
|
||||
void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size);
|
||||
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string);
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,883 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
Copyright (C) 2014 Tom Gundersen
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "list.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "mkdir.h"
|
||||
#endif
|
||||
#include "fileio.h"
|
||||
#include "in-addr-util.h"
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
#include "dhcp-internal.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "sd-dhcp-lease.h"
|
||||
#include "sd-dhcp-client.h"
|
||||
#include "network-internal.h"
|
||||
|
||||
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
|
||||
addr->s_addr = lease->address;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
*lifetime = lease->lifetime;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(mtu, -EINVAL);
|
||||
|
||||
if (lease->mtu)
|
||||
*mtu = lease->mtu;
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
|
||||
if (lease->dns_size) {
|
||||
*addr = lease->dns;
|
||||
return lease->dns_size;
|
||||
} else
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
|
||||
if (lease->ntp_size) {
|
||||
*addr = lease->ntp;
|
||||
return lease->ntp_size;
|
||||
} else
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(domainname, -EINVAL);
|
||||
|
||||
if (lease->domainname)
|
||||
*domainname = lease->domainname;
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(hostname, -EINVAL);
|
||||
|
||||
if (lease->hostname)
|
||||
*hostname = lease->hostname;
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(root_path, -EINVAL);
|
||||
|
||||
if (lease->root_path)
|
||||
*root_path = lease->root_path;
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
|
||||
if (lease->router != INADDR_ANY)
|
||||
addr->s_addr = lease->router;
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
|
||||
addr->s_addr = lease->subnet_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
|
||||
addr->s_addr = lease->server_address;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
|
||||
addr->s_addr = lease->next_server;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) {
|
||||
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(routes, -EINVAL);
|
||||
|
||||
if (lease->static_route_size) {
|
||||
*routes = lease->static_route;
|
||||
return lease->static_route_size;
|
||||
} else
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
|
||||
if (lease)
|
||||
assert_se(REFCNT_INC(lease->n_ref) >= 2);
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
|
||||
if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
|
||||
free(lease->hostname);
|
||||
free(lease->domainname);
|
||||
free(lease->dns);
|
||||
free(lease->ntp);
|
||||
free(lease->static_route);
|
||||
free(lease->client_id);
|
||||
free(lease);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
|
||||
be32_t val;
|
||||
|
||||
assert(option);
|
||||
assert(ret);
|
||||
|
||||
if (len == 4) {
|
||||
memcpy(&val, option, 4);
|
||||
*ret = be32toh(val);
|
||||
|
||||
if (*ret < min)
|
||||
*ret = min;
|
||||
}
|
||||
}
|
||||
|
||||
static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
|
||||
lease_parse_u32(option, len, (uint32_t *)ret, 0);
|
||||
}
|
||||
|
||||
static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
|
||||
be16_t val;
|
||||
|
||||
assert(option);
|
||||
assert(ret);
|
||||
|
||||
if (len == 2) {
|
||||
memcpy(&val, option, 2);
|
||||
*ret = be16toh(val);
|
||||
|
||||
if (*ret < min)
|
||||
*ret = min;
|
||||
}
|
||||
}
|
||||
|
||||
static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
|
||||
assert(option);
|
||||
assert(ret);
|
||||
|
||||
if (len == 4)
|
||||
memcpy(ret, option, 4);
|
||||
}
|
||||
|
||||
static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
|
||||
assert(option);
|
||||
assert(ret);
|
||||
|
||||
if (len == 1)
|
||||
*ret = !!(*option);
|
||||
}
|
||||
|
||||
static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
|
||||
assert(option);
|
||||
assert(ret);
|
||||
|
||||
if (len == 1) {
|
||||
*ret = *option;
|
||||
|
||||
if (*ret < min)
|
||||
*ret = min;
|
||||
}
|
||||
}
|
||||
|
||||
static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
|
||||
assert(option);
|
||||
assert(ret);
|
||||
|
||||
if (len >= 1) {
|
||||
char *string;
|
||||
|
||||
string = strndup((const char *)option, len);
|
||||
if (!string)
|
||||
return -errno;
|
||||
|
||||
free(*ret);
|
||||
*ret = string;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) {
|
||||
assert(option);
|
||||
assert(ret);
|
||||
assert(ret_size);
|
||||
|
||||
if (len && !(len % (4 * mult))) {
|
||||
size_t size;
|
||||
struct in_addr *addresses;
|
||||
|
||||
size = len / 4;
|
||||
|
||||
addresses = newdup(struct in_addr, option, size);
|
||||
if (!addresses)
|
||||
return -ENOMEM;
|
||||
|
||||
free(*ret);
|
||||
*ret = addresses;
|
||||
*ret_size = size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
|
||||
return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
|
||||
}
|
||||
|
||||
static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
|
||||
return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
|
||||
}
|
||||
|
||||
static int class_prefixlen(uint8_t msb_octet, uint8_t *ret) {
|
||||
if (msb_octet < 128)
|
||||
/* Class A */
|
||||
*ret = 8;
|
||||
else if (msb_octet < 192)
|
||||
/* Class B */
|
||||
*ret = 16;
|
||||
else if (msb_octet < 224)
|
||||
/* Class C */
|
||||
*ret = 24;
|
||||
else
|
||||
/* Class D or E -- no subnet mask */
|
||||
return -ERANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
|
||||
size_t *routes_size, size_t *routes_allocated) {
|
||||
|
||||
struct in_addr addr;
|
||||
|
||||
assert(option);
|
||||
assert(routes);
|
||||
assert(routes_size);
|
||||
assert(routes_allocated);
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (len % 8 != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
|
||||
return -ENOMEM;
|
||||
|
||||
while (len >= 8) {
|
||||
struct sd_dhcp_route *route = *routes + *routes_size;
|
||||
|
||||
if (class_prefixlen(*option, &route->dst_prefixlen) < 0) {
|
||||
log_error("Failed to determine destination prefix length from class based IP, ignoring");
|
||||
continue;
|
||||
}
|
||||
|
||||
lease_parse_be32(option, 4, &addr.s_addr);
|
||||
route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
|
||||
option += 4;
|
||||
|
||||
lease_parse_be32(option, 4, &route->gw_addr.s_addr);
|
||||
option += 4;
|
||||
|
||||
len -= 8;
|
||||
(*routes_size)++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parses RFC3442 Classless Static Route Option */
|
||||
static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
|
||||
size_t *routes_size, size_t *routes_allocated) {
|
||||
|
||||
assert(option);
|
||||
assert(routes);
|
||||
assert(routes_size);
|
||||
assert(routes_allocated);
|
||||
|
||||
/* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
|
||||
|
||||
while (len > 0) {
|
||||
uint8_t dst_octets;
|
||||
struct sd_dhcp_route *route;
|
||||
|
||||
if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
route = *routes + *routes_size;
|
||||
|
||||
dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
|
||||
route->dst_prefixlen = *option;
|
||||
option++;
|
||||
len--;
|
||||
|
||||
/* can't have more than 4 octets in IPv4 */
|
||||
if (dst_octets > 4 || len < dst_octets)
|
||||
return -EINVAL;
|
||||
|
||||
route->dst_addr.s_addr = 0;
|
||||
memcpy(&route->dst_addr.s_addr, option, dst_octets);
|
||||
option += dst_octets;
|
||||
len -= dst_octets;
|
||||
|
||||
if (len < 4)
|
||||
return -EINVAL;
|
||||
|
||||
lease_parse_be32(option, 4, &route->gw_addr.s_addr);
|
||||
option += 4;
|
||||
len -= 4;
|
||||
|
||||
(*routes_size)++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
|
||||
void *user_data) {
|
||||
sd_dhcp_lease *lease = user_data;
|
||||
int r;
|
||||
|
||||
assert(lease);
|
||||
|
||||
switch(code) {
|
||||
|
||||
case DHCP_OPTION_TIME_OFFSET:
|
||||
lease_parse_s32(option, len, &lease->time_offset);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
|
||||
lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
|
||||
lease_parse_u32(option, len, &lease->lifetime, 1);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_SERVER_IDENTIFIER:
|
||||
lease_parse_be32(option, len, &lease->server_address);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_SUBNET_MASK:
|
||||
lease_parse_be32(option, len, &lease->subnet_mask);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_BROADCAST:
|
||||
lease_parse_be32(option, len, &lease->broadcast);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_ROUTER:
|
||||
lease_parse_be32(option, len, &lease->router);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_DOMAIN_NAME_SERVER:
|
||||
r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_NTP_SERVER:
|
||||
r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_POLICY_FILTER:
|
||||
r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
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)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_INTERFACE_MTU:
|
||||
lease_parse_u16(option, len, &lease->mtu, 68);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_INTERFACE_MDR:
|
||||
lease_parse_u16(option, len, &lease->mdr, 576);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_INTERFACE_TTL:
|
||||
lease_parse_u8(option, len, &lease->ttl, 1);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_BOOT_FILE_SIZE:
|
||||
lease_parse_u16(option, len, &lease->boot_file_size, 0);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_DOMAIN_NAME:
|
||||
{
|
||||
_cleanup_free_ char *domainname = NULL;
|
||||
|
||||
r = lease_parse_string(option, len, &domainname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!hostname_is_valid(domainname) || is_localhost(domainname))
|
||||
break;
|
||||
|
||||
free(lease->domainname);
|
||||
lease->domainname = domainname;
|
||||
domainname = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
case DHCP_OPTION_HOST_NAME:
|
||||
{
|
||||
_cleanup_free_ char *hostname = NULL;
|
||||
|
||||
r = lease_parse_string(option, len, &hostname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!hostname_is_valid(hostname) || is_localhost(hostname))
|
||||
break;
|
||||
|
||||
free(lease->hostname);
|
||||
lease->hostname = hostname;
|
||||
hostname = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
case DHCP_OPTION_ROOT_PATH:
|
||||
r = lease_parse_string(option, len, &lease->root_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_RENEWAL_T1_TIME:
|
||||
lease_parse_u32(option, len, &lease->t1, 1);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_REBINDING_T2_TIME:
|
||||
lease_parse_u32(option, len, &lease->t2, 1);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_ENABLE_IP_FORWARDING:
|
||||
lease_parse_bool(option, len, &lease->ip_forward);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
|
||||
lease_parse_bool(option, len, &lease->ip_forward_non_local);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
|
||||
r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
|
||||
&lease->static_route_allocated);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_lease_new(sd_dhcp_lease **ret) {
|
||||
sd_dhcp_lease *lease;
|
||||
|
||||
lease = new0(sd_dhcp_lease, 1);
|
||||
if (!lease)
|
||||
return -ENOMEM;
|
||||
|
||||
lease->router = INADDR_ANY;
|
||||
lease->n_ref = REFCNT_INIT;
|
||||
|
||||
*ret = lease;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
|
||||
_cleanup_free_ char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
struct in_addr address;
|
||||
const struct in_addr *addresses;
|
||||
const uint8_t *client_id;
|
||||
size_t client_id_len;
|
||||
const char *string;
|
||||
uint16_t mtu;
|
||||
struct sd_dhcp_route *routes;
|
||||
int r;
|
||||
|
||||
assert(lease);
|
||||
assert(lease_file);
|
||||
|
||||
r = fopen_temporary(lease_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
fchmod(fileno(f), 0644);
|
||||
|
||||
r = sd_dhcp_lease_get_address(lease, &address);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
fprintf(f,
|
||||
"# This is private data. Do not parse.\n"
|
||||
"ADDRESS=%s\n", inet_ntoa(address));
|
||||
|
||||
r = sd_dhcp_lease_get_netmask(lease, &address);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
|
||||
|
||||
r = sd_dhcp_lease_get_router(lease, &address);
|
||||
if (r >= 0)
|
||||
fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
|
||||
|
||||
r = sd_dhcp_lease_get_server_identifier(lease, &address);
|
||||
if (r >= 0)
|
||||
fprintf(f, "SERVER_ADDRESS=%s\n",
|
||||
inet_ntoa(address));
|
||||
|
||||
r = sd_dhcp_lease_get_next_server(lease, &address);
|
||||
if (r >= 0)
|
||||
fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
|
||||
|
||||
r = sd_dhcp_lease_get_mtu(lease, &mtu);
|
||||
if (r >= 0)
|
||||
fprintf(f, "MTU=%" PRIu16 "\n", mtu);
|
||||
|
||||
fputs("DNS=", f);
|
||||
r = sd_dhcp_lease_get_dns(lease, &addresses);
|
||||
if (r >= 0)
|
||||
serialize_in_addrs(f, addresses, r);
|
||||
fputs("\n", f);
|
||||
|
||||
fputs("NTP=", f);
|
||||
r = sd_dhcp_lease_get_ntp(lease, &addresses);
|
||||
if (r >= 0)
|
||||
serialize_in_addrs(f, addresses, r);
|
||||
fputs("\n", f);
|
||||
|
||||
r = sd_dhcp_lease_get_domainname(lease, &string);
|
||||
if (r >= 0)
|
||||
fprintf(f, "DOMAINNAME=%s\n", string);
|
||||
|
||||
r = sd_dhcp_lease_get_hostname(lease, &string);
|
||||
if (r >= 0)
|
||||
fprintf(f, "HOSTNAME=%s\n", string);
|
||||
|
||||
r = sd_dhcp_lease_get_root_path(lease, &string);
|
||||
if (r >= 0)
|
||||
fprintf(f, "ROOT_PATH=%s\n", string);
|
||||
|
||||
r = sd_dhcp_lease_get_routes(lease, &routes);
|
||||
if (r >= 0)
|
||||
serialize_dhcp_routes(f, "ROUTES", routes, r);
|
||||
|
||||
r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
|
||||
if (r >= 0) {
|
||||
_cleanup_free_ char *client_id_hex;
|
||||
|
||||
client_id_hex = hexmem (client_id, client_id_len);
|
||||
if (!client_id_hex) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
fprintf(f, "CLIENTID=%s\n", client_id_hex);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
fflush(f);
|
||||
|
||||
if (ferror(f) || rename(temp_path, lease_file) < 0) {
|
||||
r = -errno;
|
||||
unlink(lease_file);
|
||||
unlink(temp_path);
|
||||
}
|
||||
|
||||
finish:
|
||||
if (r < 0)
|
||||
log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
|
||||
_cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
|
||||
_cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
|
||||
*server_address = NULL, *next_server = NULL,
|
||||
*dns = NULL, *ntp = NULL, *mtu = NULL,
|
||||
*routes = NULL, *client_id_hex = NULL;
|
||||
struct in_addr addr;
|
||||
int r;
|
||||
|
||||
assert(lease_file);
|
||||
assert(ret);
|
||||
|
||||
r = dhcp_lease_new(&lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = parse_env_file(lease_file, NEWLINE,
|
||||
"ADDRESS", &address,
|
||||
"ROUTER", &router,
|
||||
"NETMASK", &netmask,
|
||||
"SERVER_IDENTIFIER", &server_address,
|
||||
"NEXT_SERVER", &next_server,
|
||||
"DNS", &dns,
|
||||
"NTP", &ntp,
|
||||
"MTU", &mtu,
|
||||
"DOMAINNAME", &lease->domainname,
|
||||
"HOSTNAME", &lease->hostname,
|
||||
"ROOT_PATH", &lease->root_path,
|
||||
"ROUTES", &routes,
|
||||
"CLIENTID", &client_id_hex,
|
||||
NULL);
|
||||
if (r < 0) {
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
|
||||
log_error("Failed to read %s: %s", lease_file, strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = inet_pton(AF_INET, address, &addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lease->address = addr.s_addr;
|
||||
|
||||
if (router) {
|
||||
r = inet_pton(AF_INET, router, &addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lease->router = addr.s_addr;
|
||||
}
|
||||
|
||||
r = inet_pton(AF_INET, netmask, &addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lease->subnet_mask = addr.s_addr;
|
||||
|
||||
if (server_address) {
|
||||
r = inet_pton(AF_INET, server_address, &addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lease->server_address = addr.s_addr;
|
||||
}
|
||||
|
||||
if (next_server) {
|
||||
r = inet_pton(AF_INET, next_server, &addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lease->next_server = addr.s_addr;
|
||||
}
|
||||
|
||||
if (dns) {
|
||||
r = deserialize_in_addrs(&lease->dns, dns);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lease->dns_size = r;
|
||||
}
|
||||
|
||||
if (ntp) {
|
||||
r = deserialize_in_addrs(&lease->ntp, ntp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lease->ntp_size = r;
|
||||
}
|
||||
|
||||
if (mtu) {
|
||||
uint16_t u;
|
||||
if (sscanf(mtu, "%" SCNu16, &u) > 0)
|
||||
lease->mtu = u;
|
||||
}
|
||||
|
||||
if (routes) {
|
||||
r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
|
||||
&lease->static_route_allocated, routes);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client_id_hex) {
|
||||
if (strlen (client_id_hex) % 2)
|
||||
return -EINVAL;
|
||||
|
||||
lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex));
|
||||
if (!lease->client_id)
|
||||
return -ENOMEM;
|
||||
lease->client_id_len = strlen (client_id_hex) / 2;
|
||||
}
|
||||
|
||||
*ret = lease;
|
||||
lease = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
|
||||
struct in_addr address;
|
||||
struct in_addr mask;
|
||||
int r;
|
||||
|
||||
assert(lease);
|
||||
|
||||
address.s_addr = lease->address;
|
||||
|
||||
/* fall back to the default subnet masks based on address class */
|
||||
r = in_addr_default_subnet_mask(&address, &mask);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lease->subnet_mask = mask.s_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
|
||||
size_t *client_id_len) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(client_id, -EINVAL);
|
||||
assert_return(client_id_len, -EINVAL);
|
||||
|
||||
*client_id = lease->client_id;
|
||||
*client_id_len = lease->client_id_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
|
||||
size_t client_id_len) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return((!client_id && !client_id_len) ||
|
||||
(client_id && client_id_len), -EINVAL);
|
||||
|
||||
free (lease->client_id);
|
||||
lease->client_id = NULL;
|
||||
lease->client_id_len = 0;
|
||||
|
||||
if (client_id) {
|
||||
lease->client_id = memdup (client_id, client_id_len);
|
||||
lease->client_id_len = client_id_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,221 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Tom Gundersen
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "dhcp6-lease-internal.h"
|
||||
|
||||
int dhcp6_lease_clear_timers(DHCP6IA *ia) {
|
||||
assert_return(ia, -EINVAL);
|
||||
|
||||
ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1);
|
||||
ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
|
||||
DHCP6Address *addr;
|
||||
uint32_t valid = 0, t;
|
||||
|
||||
assert_return(ia, -EINVAL);
|
||||
assert_return(expire, -EINVAL);
|
||||
|
||||
LIST_FOREACH(addresses, addr, ia->addresses) {
|
||||
t = be32toh(addr->iaaddr.lifetime_valid);
|
||||
if (valid < t)
|
||||
valid = t;
|
||||
}
|
||||
|
||||
t = be32toh(ia->lifetime_t2);
|
||||
if (t > valid)
|
||||
return -EINVAL;
|
||||
|
||||
*expire = valid - t;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
|
||||
DHCP6Address *address;
|
||||
|
||||
if (!ia)
|
||||
return NULL;
|
||||
|
||||
dhcp6_lease_clear_timers(ia);
|
||||
|
||||
while (ia->addresses) {
|
||||
address = ia->addresses;
|
||||
|
||||
LIST_REMOVE(addresses, ia->addresses, address);
|
||||
|
||||
free(address);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
|
||||
size_t len) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(id, -EINVAL);
|
||||
|
||||
free(lease->serverid);
|
||||
|
||||
lease->serverid = memdup(id, len);
|
||||
if (!lease->serverid)
|
||||
return -EINVAL;
|
||||
|
||||
lease->serverid_len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(id, -EINVAL);
|
||||
assert_return(len, -EINVAL);
|
||||
|
||||
*id = lease->serverid;
|
||||
*len = lease->serverid_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) {
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
lease->preference = preference;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(preference, -EINVAL);
|
||||
|
||||
*preference = lease->preference;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease) {
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
lease->rapid_commit = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(rapid_commit, -EINVAL);
|
||||
|
||||
*rapid_commit = lease->rapid_commit;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(iaid, -EINVAL);
|
||||
|
||||
*iaid = lease->ia.id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_next_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert_return(lifetime_preferred, -EINVAL);
|
||||
assert_return(lifetime_valid, -EINVAL);
|
||||
|
||||
if (!lease->addr_iter)
|
||||
return -ENOMSG;
|
||||
|
||||
memcpy(addr, &lease->addr_iter->iaaddr.address,
|
||||
sizeof(struct in6_addr));
|
||||
*lifetime_preferred =
|
||||
be32toh(lease->addr_iter->iaaddr.lifetime_preferred);
|
||||
*lifetime_valid = be32toh(lease->addr_iter->iaaddr.lifetime_valid);
|
||||
|
||||
lease->addr_iter = lease->addr_iter->addresses_next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_first_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert_return(lifetime_preferred, -EINVAL);
|
||||
assert_return(lifetime_valid, -EINVAL);
|
||||
|
||||
if (!lease->ia.addresses)
|
||||
return -ENOMSG;
|
||||
|
||||
lease->addr_iter = lease->ia.addresses;
|
||||
|
||||
return sd_dhcp6_lease_get_next_address(lease, addr, lifetime_preferred,
|
||||
lifetime_valid);
|
||||
}
|
||||
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) {
|
||||
if (lease)
|
||||
assert_se(REFCNT_INC(lease->n_ref) >= 2);
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) {
|
||||
if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
|
||||
free(lease->serverid);
|
||||
dhcp6_lease_free_ia(&lease->ia);
|
||||
|
||||
free(lease);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dhcp6_lease_new(sd_dhcp6_lease **ret) {
|
||||
sd_dhcp6_lease *lease;
|
||||
|
||||
lease = new0(sd_dhcp6_lease, 1);
|
||||
if (!lease)
|
||||
return -ENOMEM;
|
||||
|
||||
lease->n_ref = REFCNT_INIT;
|
||||
|
||||
LIST_HEAD_INIT(lease->ia.addresses);
|
||||
|
||||
*ret = lease;
|
||||
return 0;
|
||||
}
|
||||
27
src/dhcp-manager/systemd-dhcp/src/shared/async.h
Normal file
27
src/dhcp-manager/systemd-dhcp/src/shared/async.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
int asynchronous_job(void* (*func)(void *p), void *arg);
|
||||
|
||||
int asynchronous_sync(void);
|
||||
int asynchronous_close(int fd);
|
||||
898
src/dhcp-manager/systemd-dhcp/src/shared/fileio.c
Normal file
898
src/dhcp-manager/systemd-dhcp/src/shared/fileio.c
Normal file
|
|
@ -0,0 +1,898 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <unistd.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include "fileio.h"
|
||||
#include "util.h"
|
||||
#include "strv.h"
|
||||
#include "utf8.h"
|
||||
#include "ctype.h"
|
||||
|
||||
int write_string_stream(FILE *f, const char *line) {
|
||||
assert(f);
|
||||
assert(line);
|
||||
|
||||
errno = 0;
|
||||
|
||||
fputs(line, f);
|
||||
if (!endswith(line, "\n"))
|
||||
fputc('\n', f);
|
||||
|
||||
fflush(f);
|
||||
|
||||
if (ferror(f))
|
||||
return errno ? -errno : -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_string_file(const char *fn, const char *line) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
assert(fn);
|
||||
assert(line);
|
||||
|
||||
f = fopen(fn, "we");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
return write_string_stream(f, line);
|
||||
}
|
||||
|
||||
int write_string_file_no_create(const char *fn, const char *line) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int fd;
|
||||
|
||||
assert(fn);
|
||||
assert(line);
|
||||
|
||||
/* We manually build our own version of fopen(..., "we") that
|
||||
* without O_CREAT */
|
||||
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
f = fdopen(fd, "we");
|
||||
if (!f) {
|
||||
safe_close(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return write_string_stream(f, line);
|
||||
}
|
||||
|
||||
int write_string_file_atomic(const char *fn, const char *line) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(fn);
|
||||
assert(line);
|
||||
|
||||
r = fopen_temporary(fn, &f, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fchmod_umask(fileno(f), 0644);
|
||||
|
||||
errno = 0;
|
||||
fputs(line, f);
|
||||
if (!endswith(line, "\n"))
|
||||
fputc('\n', f);
|
||||
|
||||
fflush(f);
|
||||
|
||||
if (ferror(f))
|
||||
r = errno ? -errno : -EIO;
|
||||
else {
|
||||
if (rename(p, fn) < 0)
|
||||
r = -errno;
|
||||
else
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
unlink(p);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int read_one_line_file(const char *fn, char **line) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
char t[LINE_MAX], *c;
|
||||
|
||||
assert(fn);
|
||||
assert(line);
|
||||
|
||||
f = fopen(fn, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
if (!fgets(t, sizeof(t), f)) {
|
||||
|
||||
if (ferror(f))
|
||||
return errno ? -errno : -EIO;
|
||||
|
||||
t[0] = 0;
|
||||
}
|
||||
|
||||
c = strdup(t);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
truncate_nl(c);
|
||||
|
||||
*line = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t sendfile_full(int out_fd, const char *fn) {
|
||||
_cleanup_fclose_ FILE *f;
|
||||
struct stat st;
|
||||
int r;
|
||||
ssize_t s;
|
||||
|
||||
size_t n, l;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
||||
assert(out_fd > 0);
|
||||
assert(fn);
|
||||
|
||||
f = fopen(fn, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
r = fstat(fileno(f), &st);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
s = sendfile(out_fd, fileno(f), NULL, st.st_size);
|
||||
if (s < 0)
|
||||
if (errno == EINVAL || errno == ENOSYS) {
|
||||
/* continue below */
|
||||
} else
|
||||
return -errno;
|
||||
else
|
||||
return s;
|
||||
|
||||
/* sendfile() failed, fall back to read/write */
|
||||
|
||||
/* Safety check */
|
||||
if (st.st_size > 4*1024*1024)
|
||||
return -E2BIG;
|
||||
|
||||
n = st.st_size > 0 ? st.st_size : LINE_MAX;
|
||||
l = 0;
|
||||
|
||||
while (true) {
|
||||
char *t;
|
||||
size_t k;
|
||||
|
||||
t = realloc(buf, n);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
buf = t;
|
||||
k = fread(buf + l, 1, n - l, f);
|
||||
|
||||
if (k <= 0) {
|
||||
if (ferror(f))
|
||||
return -errno;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
l += k;
|
||||
n *= 2;
|
||||
|
||||
/* Safety check */
|
||||
if (n > 4*1024*1024)
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
r = write(out_fd, buf, l);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return (ssize_t) l;
|
||||
}
|
||||
|
||||
int read_full_stream(FILE *f, char **contents, size_t *size) {
|
||||
size_t n, l;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
struct stat st;
|
||||
|
||||
assert(f);
|
||||
assert(contents);
|
||||
|
||||
if (fstat(fileno(f), &st) < 0)
|
||||
return -errno;
|
||||
|
||||
n = LINE_MAX;
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
|
||||
/* Safety check */
|
||||
if (st.st_size > 4*1024*1024)
|
||||
return -E2BIG;
|
||||
|
||||
/* Start with the right file size, but be prepared for
|
||||
* files from /proc which generally report a file size
|
||||
* of 0 */
|
||||
if (st.st_size > 0)
|
||||
n = st.st_size;
|
||||
}
|
||||
|
||||
l = 0;
|
||||
for (;;) {
|
||||
char *t;
|
||||
size_t k;
|
||||
|
||||
t = realloc(buf, n+1);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
buf = t;
|
||||
k = fread(buf + l, 1, n - l, f);
|
||||
|
||||
if (k <= 0) {
|
||||
if (ferror(f))
|
||||
return -errno;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
l += k;
|
||||
n *= 2;
|
||||
|
||||
/* Safety check */
|
||||
if (n > 4*1024*1024)
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
buf[l] = 0;
|
||||
*contents = buf;
|
||||
buf = NULL; /* do not free */
|
||||
|
||||
if (size)
|
||||
*size = l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_full_file(const char *fn, char **contents, size_t *size) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
assert(fn);
|
||||
assert(contents);
|
||||
|
||||
f = fopen(fn, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
return read_full_stream(f, contents, size);
|
||||
}
|
||||
|
||||
static int parse_env_file_internal(
|
||||
FILE *f,
|
||||
const char *fname,
|
||||
const char *newline,
|
||||
int (*push) (const char *filename, unsigned line,
|
||||
const char *key, char *value, void *userdata, int *n_pushed),
|
||||
void *userdata,
|
||||
int *n_pushed) {
|
||||
|
||||
_cleanup_free_ char *contents = NULL, *key = NULL;
|
||||
size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
|
||||
char *p, *value = NULL;
|
||||
int r;
|
||||
unsigned line = 1;
|
||||
|
||||
enum {
|
||||
PRE_KEY,
|
||||
KEY,
|
||||
PRE_VALUE,
|
||||
VALUE,
|
||||
VALUE_ESCAPE,
|
||||
SINGLE_QUOTE_VALUE,
|
||||
SINGLE_QUOTE_VALUE_ESCAPE,
|
||||
DOUBLE_QUOTE_VALUE,
|
||||
DOUBLE_QUOTE_VALUE_ESCAPE,
|
||||
COMMENT,
|
||||
COMMENT_ESCAPE
|
||||
} state = PRE_KEY;
|
||||
|
||||
assert(newline);
|
||||
|
||||
if (f)
|
||||
r = read_full_stream(f, &contents, NULL);
|
||||
else
|
||||
r = read_full_file(fname, &contents, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (p = contents; *p; p++) {
|
||||
char c = *p;
|
||||
|
||||
switch (state) {
|
||||
|
||||
case PRE_KEY:
|
||||
if (strchr(COMMENTS, c))
|
||||
state = COMMENT;
|
||||
else if (!strchr(WHITESPACE, c)) {
|
||||
state = KEY;
|
||||
last_key_whitespace = (size_t) -1;
|
||||
|
||||
if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
key[n_key++] = c;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY:
|
||||
if (strchr(newline, c)) {
|
||||
state = PRE_KEY;
|
||||
line ++;
|
||||
n_key = 0;
|
||||
} else if (c == '=') {
|
||||
state = PRE_VALUE;
|
||||
last_value_whitespace = (size_t) -1;
|
||||
} else {
|
||||
if (!strchr(WHITESPACE, c))
|
||||
last_key_whitespace = (size_t) -1;
|
||||
else if (last_key_whitespace == (size_t) -1)
|
||||
last_key_whitespace = n_key;
|
||||
|
||||
if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
key[n_key++] = c;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PRE_VALUE:
|
||||
if (strchr(newline, c)) {
|
||||
state = PRE_KEY;
|
||||
line ++;
|
||||
key[n_key] = 0;
|
||||
|
||||
if (value)
|
||||
value[n_value] = 0;
|
||||
|
||||
/* strip trailing whitespace from key */
|
||||
if (last_key_whitespace != (size_t) -1)
|
||||
key[last_key_whitespace] = 0;
|
||||
|
||||
r = push(fname, line, key, value, userdata, n_pushed);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
n_key = 0;
|
||||
value = NULL;
|
||||
value_alloc = n_value = 0;
|
||||
|
||||
} else if (c == '\'')
|
||||
state = SINGLE_QUOTE_VALUE;
|
||||
else if (c == '\"')
|
||||
state = DOUBLE_QUOTE_VALUE;
|
||||
else if (c == '\\')
|
||||
state = VALUE_ESCAPE;
|
||||
else if (!strchr(WHITESPACE, c)) {
|
||||
state = VALUE;
|
||||
|
||||
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value[n_value++] = c;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case VALUE:
|
||||
if (strchr(newline, c)) {
|
||||
state = PRE_KEY;
|
||||
line ++;
|
||||
|
||||
key[n_key] = 0;
|
||||
|
||||
if (value)
|
||||
value[n_value] = 0;
|
||||
|
||||
/* Chomp off trailing whitespace from value */
|
||||
if (last_value_whitespace != (size_t) -1)
|
||||
value[last_value_whitespace] = 0;
|
||||
|
||||
/* strip trailing whitespace from key */
|
||||
if (last_key_whitespace != (size_t) -1)
|
||||
key[last_key_whitespace] = 0;
|
||||
|
||||
r = push(fname, line, key, value, userdata, n_pushed);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
n_key = 0;
|
||||
value = NULL;
|
||||
value_alloc = n_value = 0;
|
||||
|
||||
} else if (c == '\\') {
|
||||
state = VALUE_ESCAPE;
|
||||
last_value_whitespace = (size_t) -1;
|
||||
} else {
|
||||
if (!strchr(WHITESPACE, c))
|
||||
last_value_whitespace = (size_t) -1;
|
||||
else if (last_value_whitespace == (size_t) -1)
|
||||
last_value_whitespace = n_value;
|
||||
|
||||
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value[n_value++] = c;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case VALUE_ESCAPE:
|
||||
state = VALUE;
|
||||
|
||||
if (!strchr(newline, c)) {
|
||||
/* Escaped newlines we eat up entirely */
|
||||
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value[n_value++] = c;
|
||||
}
|
||||
break;
|
||||
|
||||
case SINGLE_QUOTE_VALUE:
|
||||
if (c == '\'')
|
||||
state = PRE_VALUE;
|
||||
else if (c == '\\')
|
||||
state = SINGLE_QUOTE_VALUE_ESCAPE;
|
||||
else {
|
||||
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value[n_value++] = c;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SINGLE_QUOTE_VALUE_ESCAPE:
|
||||
state = SINGLE_QUOTE_VALUE;
|
||||
|
||||
if (!strchr(newline, c)) {
|
||||
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value[n_value++] = c;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOUBLE_QUOTE_VALUE:
|
||||
if (c == '\"')
|
||||
state = PRE_VALUE;
|
||||
else if (c == '\\')
|
||||
state = DOUBLE_QUOTE_VALUE_ESCAPE;
|
||||
else {
|
||||
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value[n_value++] = c;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DOUBLE_QUOTE_VALUE_ESCAPE:
|
||||
state = DOUBLE_QUOTE_VALUE;
|
||||
|
||||
if (!strchr(newline, c)) {
|
||||
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value[n_value++] = c;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMENT:
|
||||
if (c == '\\')
|
||||
state = COMMENT_ESCAPE;
|
||||
else if (strchr(newline, c)) {
|
||||
state = PRE_KEY;
|
||||
line ++;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMENT_ESCAPE:
|
||||
state = COMMENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == PRE_VALUE ||
|
||||
state == VALUE ||
|
||||
state == VALUE_ESCAPE ||
|
||||
state == SINGLE_QUOTE_VALUE ||
|
||||
state == SINGLE_QUOTE_VALUE_ESCAPE ||
|
||||
state == DOUBLE_QUOTE_VALUE ||
|
||||
state == DOUBLE_QUOTE_VALUE_ESCAPE) {
|
||||
|
||||
key[n_key] = 0;
|
||||
|
||||
if (value)
|
||||
value[n_value] = 0;
|
||||
|
||||
if (state == VALUE)
|
||||
if (last_value_whitespace != (size_t) -1)
|
||||
value[last_value_whitespace] = 0;
|
||||
|
||||
/* strip trailing whitespace from key */
|
||||
if (last_key_whitespace != (size_t) -1)
|
||||
key[last_key_whitespace] = 0;
|
||||
|
||||
r = push(fname, line, key, value, userdata, n_pushed);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
free(value);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int parse_env_file_push(
|
||||
const char *filename, unsigned line,
|
||||
const char *key, char *value,
|
||||
void *userdata,
|
||||
int *n_pushed) {
|
||||
|
||||
const char *k;
|
||||
va_list aq, *ap = userdata;
|
||||
|
||||
if (!utf8_is_valid(key)) {
|
||||
_cleanup_free_ char *p;
|
||||
|
||||
p = utf8_escape_invalid(key);
|
||||
log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value && !utf8_is_valid(value)) {
|
||||
_cleanup_free_ char *p;
|
||||
|
||||
p = utf8_escape_invalid(value);
|
||||
log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
va_copy(aq, *ap);
|
||||
|
||||
while ((k = va_arg(aq, const char *))) {
|
||||
char **v;
|
||||
|
||||
v = va_arg(aq, char **);
|
||||
|
||||
if (streq(key, k)) {
|
||||
va_end(aq);
|
||||
free(*v);
|
||||
*v = value;
|
||||
|
||||
if (n_pushed)
|
||||
(*n_pushed)++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(aq);
|
||||
free(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_env_file(
|
||||
const char *fname,
|
||||
const char *newline, ...) {
|
||||
|
||||
va_list ap;
|
||||
int r, n_pushed = 0;
|
||||
|
||||
if (!newline)
|
||||
newline = NEWLINE;
|
||||
|
||||
va_start(ap, newline);
|
||||
r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed);
|
||||
va_end(ap);
|
||||
|
||||
return r < 0 ? r : n_pushed;
|
||||
}
|
||||
|
||||
static int load_env_file_push(
|
||||
const char *filename, unsigned line,
|
||||
const char *key, char *value,
|
||||
void *userdata,
|
||||
int *n_pushed) {
|
||||
char ***m = userdata;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
if (!utf8_is_valid(key)) {
|
||||
_cleanup_free_ char *t = utf8_escape_invalid(key);
|
||||
|
||||
log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value && !utf8_is_valid(value)) {
|
||||
_cleanup_free_ char *t = utf8_escape_invalid(value);
|
||||
|
||||
log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
p = strjoin(key, "=", strempty(value), NULL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = strv_consume(m, p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (n_pushed)
|
||||
(*n_pushed)++;
|
||||
|
||||
free(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
|
||||
char **m = NULL;
|
||||
int r;
|
||||
|
||||
if (!newline)
|
||||
newline = NEWLINE;
|
||||
|
||||
r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
|
||||
if (r < 0) {
|
||||
strv_free(m);
|
||||
return r;
|
||||
}
|
||||
|
||||
*rl = m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_env_file_push_pairs(
|
||||
const char *filename, unsigned line,
|
||||
const char *key, char *value,
|
||||
void *userdata,
|
||||
int *n_pushed) {
|
||||
char ***m = userdata;
|
||||
int r;
|
||||
|
||||
if (!utf8_is_valid(key)) {
|
||||
_cleanup_free_ char *t = utf8_escape_invalid(key);
|
||||
|
||||
log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value && !utf8_is_valid(value)) {
|
||||
_cleanup_free_ char *t = utf8_escape_invalid(value);
|
||||
|
||||
log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = strv_extend(m, key);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!value) {
|
||||
r = strv_extend(m, "");
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
r = strv_push(m, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (n_pushed)
|
||||
(*n_pushed)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
|
||||
char **m = NULL;
|
||||
int r;
|
||||
|
||||
if (!newline)
|
||||
newline = NEWLINE;
|
||||
|
||||
r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
|
||||
if (r < 0) {
|
||||
strv_free(m);
|
||||
return r;
|
||||
}
|
||||
|
||||
*rl = m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void write_env_var(FILE *f, const char *v) {
|
||||
const char *p;
|
||||
|
||||
p = strchr(v, '=');
|
||||
if (!p) {
|
||||
/* Fallback */
|
||||
fputs(v, f);
|
||||
fputc('\n', f);
|
||||
return;
|
||||
}
|
||||
|
||||
p++;
|
||||
fwrite(v, 1, p-v, f);
|
||||
|
||||
if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
|
||||
fputc('\"', f);
|
||||
|
||||
for (; *p; p++) {
|
||||
if (strchr(SHELL_NEED_ESCAPE, *p))
|
||||
fputc('\\', f);
|
||||
|
||||
fputc(*p, f);
|
||||
}
|
||||
|
||||
fputc('\"', f);
|
||||
} else
|
||||
fputs(p, f);
|
||||
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
int write_env_file(const char *fname, char **l) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
char **i;
|
||||
int r;
|
||||
|
||||
assert(fname);
|
||||
|
||||
r = fopen_temporary(fname, &f, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fchmod_umask(fileno(f), 0644);
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
write_env_var(f, *i);
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r >= 0) {
|
||||
if (rename(p, fname) >= 0)
|
||||
return 0;
|
||||
|
||||
r = -errno;
|
||||
}
|
||||
|
||||
unlink(p);
|
||||
return r;
|
||||
}
|
||||
|
||||
int executable_is_script(const char *path, char **interpreter) {
|
||||
int r;
|
||||
_cleanup_free_ char *line = NULL;
|
||||
int len;
|
||||
char *ans;
|
||||
|
||||
assert(path);
|
||||
|
||||
r = read_one_line_file(path, &line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!startswith(line, "#!"))
|
||||
return 0;
|
||||
|
||||
ans = strstrip(line + 2);
|
||||
len = strcspn(ans, " \t");
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
ans = strndup(ans, len);
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
|
||||
*interpreter = ans;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve one field from a file like /proc/self/status. pattern
|
||||
* should start with '\n' and end with a ':'. Whitespace and zeros
|
||||
* after the ':' will be skipped. field must be freed afterwards.
|
||||
*/
|
||||
int get_status_field(const char *filename, const char *pattern, char **field) {
|
||||
_cleanup_free_ char *status = NULL;
|
||||
char *t;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(pattern);
|
||||
assert(field);
|
||||
|
||||
r = read_full_file(filename, &status, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t = strstr(status, pattern);
|
||||
if (!t)
|
||||
return -ENOENT;
|
||||
|
||||
t += strlen(pattern);
|
||||
if (*t) {
|
||||
t += strspn(t, " \t");
|
||||
|
||||
/* Also skip zeros, because when this is used for
|
||||
* capabilities, we don't want the zeros. This way the
|
||||
* same capability set always maps to the same string,
|
||||
* irrespective of the total capability set size. For
|
||||
* other numbers it shouldn't matter. */
|
||||
t += strspn(t, "0");
|
||||
/* Back off one char if there's nothing but whitespace
|
||||
and zeros */
|
||||
if (!*t || isspace(*t))
|
||||
t --;
|
||||
}
|
||||
|
||||
len = strcspn(t, WHITESPACE);
|
||||
|
||||
*field = strndup(t, len);
|
||||
if (!*field)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
46
src/dhcp-manager/systemd-dhcp/src/shared/fileio.h
Normal file
46
src/dhcp-manager/systemd-dhcp/src/shared/fileio.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
int write_string_stream(FILE *f, const char *line);
|
||||
int write_string_file(const char *fn, const char *line);
|
||||
int write_string_file_no_create(const char *fn, const char *line);
|
||||
int write_string_file_atomic(const char *fn, const char *line);
|
||||
|
||||
int read_one_line_file(const char *fn, char **line);
|
||||
int read_full_file(const char *fn, char **contents, size_t *size);
|
||||
int read_full_stream(FILE *f, char **contents, size_t *size);
|
||||
ssize_t sendfile_full(int out_fd, const char *fn);
|
||||
|
||||
int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
|
||||
int load_env_file(FILE *f, const char *fname, const char *separator, char ***l);
|
||||
int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l);
|
||||
|
||||
int write_env_file(const char *fname, char **l);
|
||||
|
||||
int executable_is_script(const char *path, char **interpreter);
|
||||
|
||||
int get_status_field(const char *filename, const char *pattern, char **field);
|
||||
293
src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c
Normal file
293
src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <arpa/inet.h>
|
||||
|
||||
#include "in-addr-util.h"
|
||||
|
||||
int in_addr_is_null(int family, const union in_addr_union *u) {
|
||||
assert(u);
|
||||
|
||||
if (family == AF_INET)
|
||||
return u->in.s_addr == 0;
|
||||
|
||||
if (family == AF_INET6)
|
||||
return
|
||||
u->in6.s6_addr32[0] == 0 &&
|
||||
u->in6.s6_addr32[1] == 0 &&
|
||||
u->in6.s6_addr32[2] == 0 &&
|
||||
u->in6.s6_addr32[3] == 0;
|
||||
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
int in_addr_is_link_local(int family, const union in_addr_union *u) {
|
||||
assert(u);
|
||||
|
||||
if (family == AF_INET)
|
||||
return (be32toh(u->in.s_addr) & 0xFFFF0000) == (169U << 24 | 254U << 16);
|
||||
|
||||
if (family == AF_INET6)
|
||||
return IN6_IS_ADDR_LINKLOCAL(&u->in6);
|
||||
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
if (family == AF_INET)
|
||||
return a->in.s_addr == b->in.s_addr;
|
||||
|
||||
if (family == AF_INET6)
|
||||
return
|
||||
a->in6.s6_addr32[0] == b->in6.s6_addr32[0] &&
|
||||
a->in6.s6_addr32[1] == b->in6.s6_addr32[1] &&
|
||||
a->in6.s6_addr32[2] == b->in6.s6_addr32[2] &&
|
||||
a->in6.s6_addr32[3] == b->in6.s6_addr32[3];
|
||||
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
int in_addr_prefix_intersect(
|
||||
int family,
|
||||
const union in_addr_union *a,
|
||||
unsigned aprefixlen,
|
||||
const union in_addr_union *b,
|
||||
unsigned bprefixlen) {
|
||||
|
||||
unsigned m;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
/* Checks whether there are any addresses that are in both
|
||||
* networks */
|
||||
|
||||
m = MIN(aprefixlen, bprefixlen);
|
||||
|
||||
if (family == AF_INET) {
|
||||
uint32_t x, nm;
|
||||
|
||||
x = be32toh(a->in.s_addr ^ b->in.s_addr);
|
||||
nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m);
|
||||
|
||||
return (x & nm) == 0;
|
||||
}
|
||||
|
||||
if (family == AF_INET6) {
|
||||
unsigned i;
|
||||
|
||||
if (m > 128)
|
||||
m = 128;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
uint8_t x, nm;
|
||||
|
||||
x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
|
||||
|
||||
if (m < 8)
|
||||
nm = 0xFF << (8 - m);
|
||||
else
|
||||
nm = 0xFF;
|
||||
|
||||
if ((x & nm) != 0)
|
||||
return 0;
|
||||
|
||||
if (m > 8)
|
||||
m -= 8;
|
||||
else
|
||||
m = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
|
||||
assert(u);
|
||||
|
||||
/* Increases the network part of an address by one. Returns
|
||||
* positive it that succeeds, or 0 if this overflows. */
|
||||
|
||||
if (prefixlen <= 0)
|
||||
return 0;
|
||||
|
||||
if (family == AF_INET) {
|
||||
uint32_t c, n;
|
||||
|
||||
if (prefixlen > 32)
|
||||
prefixlen = 32;
|
||||
|
||||
c = be32toh(u->in.s_addr);
|
||||
n = c + (1UL << (32 - prefixlen));
|
||||
if (n < c)
|
||||
return 0;
|
||||
n &= 0xFFFFFFFFUL << (32 - prefixlen);
|
||||
|
||||
u->in.s_addr = htobe32(n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (family == AF_INET6) {
|
||||
struct in6_addr add = {}, result;
|
||||
uint8_t overflow = 0;
|
||||
unsigned i;
|
||||
|
||||
if (prefixlen > 128)
|
||||
prefixlen = 128;
|
||||
|
||||
/* First calculate what we have to add */
|
||||
add.s6_addr[(prefixlen-1) / 8] = 1 << (7 - (prefixlen-1) % 8);
|
||||
|
||||
for (i = 16; i > 0; i--) {
|
||||
unsigned j = i - 1;
|
||||
|
||||
result.s6_addr[j] = u->in6.s6_addr[j] + add.s6_addr[j] + overflow;
|
||||
overflow = (result.s6_addr[j] < u->in6.s6_addr[j]);
|
||||
}
|
||||
|
||||
if (overflow)
|
||||
return 0;
|
||||
|
||||
u->in6 = result;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
|
||||
char *x;
|
||||
size_t l;
|
||||
|
||||
assert(u);
|
||||
assert(ret);
|
||||
|
||||
if (family == AF_INET)
|
||||
l = INET_ADDRSTRLEN;
|
||||
else if (family == AF_INET6)
|
||||
l = INET6_ADDRSTRLEN;
|
||||
else
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
x = new(char, l);
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
|
||||
errno = 0;
|
||||
if (!inet_ntop(family, u, x, l)) {
|
||||
free(x);
|
||||
return errno ? -errno : -EINVAL;
|
||||
}
|
||||
|
||||
*ret = x;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
if (!IN_SET(family, AF_INET, AF_INET6))
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
errno = 0;
|
||||
if (inet_pton(family, s, ret) <= 0)
|
||||
return errno ? -errno : -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(family);
|
||||
assert(ret);
|
||||
|
||||
r = in_addr_from_string(AF_INET, s, ret);
|
||||
if (r >= 0) {
|
||||
*family = AF_INET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = in_addr_from_string(AF_INET6, s, ret);
|
||||
if (r >= 0) {
|
||||
*family = AF_INET6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
|
||||
assert(addr);
|
||||
|
||||
return 32 - u32ctz(be32toh(addr->s_addr));
|
||||
}
|
||||
|
||||
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
|
||||
uint32_t address;
|
||||
|
||||
assert(addr);
|
||||
assert(addr->s_addr != INADDR_ANY);
|
||||
assert(prefixlen);
|
||||
|
||||
address = be32toh(addr->s_addr);
|
||||
|
||||
if ((address >> 31) == 0x0)
|
||||
/* class A, leading bits: 0 */
|
||||
*prefixlen = 8;
|
||||
else if ((address >> 30) == 0x2)
|
||||
/* class B, leading bits 10 */
|
||||
*prefixlen = 16;
|
||||
else if ((address >> 29) == 0x6)
|
||||
/* class C, leading bits 110 */
|
||||
*prefixlen = 24;
|
||||
else
|
||||
/* class D or E, no default prefixlen */
|
||||
return -ERANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
|
||||
unsigned char prefixlen;
|
||||
int r;
|
||||
|
||||
assert(addr);
|
||||
assert(mask);
|
||||
|
||||
r = in_addr_default_prefixlen(addr, &prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(prefixlen > 0 && prefixlen < 32);
|
||||
|
||||
mask->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
49
src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h
Normal file
49
src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <netinet/in.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
|
||||
union in_addr_union {
|
||||
struct in_addr in;
|
||||
struct in6_addr in6;
|
||||
};
|
||||
|
||||
int in_addr_is_null(int family, const union in_addr_union *u);
|
||||
int in_addr_is_link_local(int family, const union in_addr_union *u);
|
||||
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
|
||||
int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
|
||||
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
|
||||
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
|
||||
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
|
||||
int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret);
|
||||
unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr);
|
||||
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
|
||||
int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
|
||||
|
||||
static inline size_t FAMILY_ADDRESS_SIZE(int family) {
|
||||
assert(family == AF_INET || family == AF_INET6);
|
||||
return family == AF_INET6 ? 16 : 4;
|
||||
}
|
||||
138
src/dhcp-manager/systemd-dhcp/src/shared/list.h
Normal file
138
src/dhcp-manager/systemd-dhcp/src/shared/list.h
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
/* The head of the linked list. Use this in the structure that shall
|
||||
* contain the head of the linked list */
|
||||
#define LIST_HEAD(t,name) \
|
||||
t *name
|
||||
|
||||
/* The pointers in the linked list's items. Use this in the item structure */
|
||||
#define LIST_FIELDS(t,name) \
|
||||
t *name##_next, *name##_prev
|
||||
|
||||
/* Initialize the list's head */
|
||||
#define LIST_HEAD_INIT(head) \
|
||||
do { \
|
||||
(head) = NULL; } \
|
||||
while(false)
|
||||
|
||||
/* Initialize a list item */
|
||||
#define LIST_INIT(name,item) \
|
||||
do { \
|
||||
typeof(*(item)) *_item = (item); \
|
||||
assert(_item); \
|
||||
_item->name##_prev = _item->name##_next = NULL; \
|
||||
} while(false)
|
||||
|
||||
/* Prepend an item to the list */
|
||||
#define LIST_PREPEND(name,head,item) \
|
||||
do { \
|
||||
typeof(*(head)) **_head = &(head), *_item = (item); \
|
||||
assert(_item); \
|
||||
if ((_item->name##_next = *_head)) \
|
||||
_item->name##_next->name##_prev = _item; \
|
||||
_item->name##_prev = NULL; \
|
||||
*_head = _item; \
|
||||
} while(false)
|
||||
|
||||
/* Remove an item from the list */
|
||||
#define LIST_REMOVE(name,head,item) \
|
||||
do { \
|
||||
typeof(*(head)) **_head = &(head), *_item = (item); \
|
||||
assert(_item); \
|
||||
if (_item->name##_next) \
|
||||
_item->name##_next->name##_prev = _item->name##_prev; \
|
||||
if (_item->name##_prev) \
|
||||
_item->name##_prev->name##_next = _item->name##_next; \
|
||||
else { \
|
||||
assert(*_head == _item); \
|
||||
*_head = _item->name##_next; \
|
||||
} \
|
||||
_item->name##_next = _item->name##_prev = NULL; \
|
||||
} while(false)
|
||||
|
||||
/* Find the head of the list */
|
||||
#define LIST_FIND_HEAD(name,item,head) \
|
||||
do { \
|
||||
typeof(*(item)) *_item = (item); \
|
||||
if (!_item) \
|
||||
(head) = NULL; \
|
||||
else { \
|
||||
while (_item->name##_prev) \
|
||||
_item = _item->name##_prev; \
|
||||
(head) = _item; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
/* Find the tail of the list */
|
||||
#define LIST_FIND_TAIL(name,item,tail) \
|
||||
do { \
|
||||
typeof(*(item)) *_item = (item); \
|
||||
if (!_item) \
|
||||
(tail) = NULL; \
|
||||
else { \
|
||||
while (_item->name##_next) \
|
||||
_item = _item->name##_next; \
|
||||
(tail) = _item; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
/* Insert an item after another one (a = where, b = what) */
|
||||
#define LIST_INSERT_AFTER(name,head,a,b) \
|
||||
do { \
|
||||
typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \
|
||||
assert(_b); \
|
||||
if (!_a) { \
|
||||
if ((_b->name##_next = *_head)) \
|
||||
_b->name##_next->name##_prev = _b; \
|
||||
_b->name##_prev = NULL; \
|
||||
*_head = _b; \
|
||||
} else { \
|
||||
if ((_b->name##_next = _a->name##_next)) \
|
||||
_b->name##_next->name##_prev = _b; \
|
||||
_b->name##_prev = _a; \
|
||||
_a->name##_next = _b; \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
#define LIST_JUST_US(name,item) \
|
||||
(!(item)->name##_prev && !(item)->name##_next) \
|
||||
|
||||
#define LIST_FOREACH(name,i,head) \
|
||||
for ((i) = (head); (i); (i) = (i)->name##_next)
|
||||
|
||||
#define LIST_FOREACH_SAFE(name,i,n,head) \
|
||||
for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
|
||||
|
||||
#define LIST_FOREACH_BEFORE(name,i,p) \
|
||||
for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev)
|
||||
|
||||
#define LIST_FOREACH_AFTER(name,i,p) \
|
||||
for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next)
|
||||
|
||||
/* Loop starting from p->next until p->prev.
|
||||
p can be adjusted meanwhile. */
|
||||
#define LIST_LOOP_BUT_ONE(name,i,head,p) \
|
||||
for ((i) = (p)->name##_next ? (p)->name##_next : (head); \
|
||||
(i) != (p); \
|
||||
(i) = (i)->name##_next ? (i)->name##_next : (head))
|
||||
413
src/dhcp-manager/systemd-dhcp/src/shared/macro.h
Normal file
413
src/dhcp-manager/systemd-dhcp/src/shared/macro.h
Normal file
|
|
@ -0,0 +1,413 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <assert.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define _printf_(a,b) __attribute__ ((format (printf, a, b)))
|
||||
#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
|
||||
#define _sentinel_ __attribute__ ((sentinel))
|
||||
#define _unused_ __attribute__ ((unused))
|
||||
#define _destructor_ __attribute__ ((destructor))
|
||||
#define _pure_ __attribute__ ((pure))
|
||||
#define _const_ __attribute__ ((const))
|
||||
#define _deprecated_ __attribute__ ((deprecated))
|
||||
#define _packed_ __attribute__ ((packed))
|
||||
#define _malloc_ __attribute__ ((malloc))
|
||||
#define _weak_ __attribute__ ((weak))
|
||||
#define _likely_(x) (__builtin_expect(!!(x),1))
|
||||
#define _unlikely_(x) (__builtin_expect(!!(x),0))
|
||||
#define _public_ __attribute__ ((visibility("default")))
|
||||
#define _hidden_ __attribute__ ((visibility("hidden")))
|
||||
#define _weakref_(x) __attribute__((weakref(#x)))
|
||||
#define _alignas_(x) __attribute__((aligned(__alignof(x))))
|
||||
#define _cleanup_(x) __attribute__((cleanup(x)))
|
||||
|
||||
/* Temporarily disable some warnings */
|
||||
#define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT \
|
||||
_Pragma("GCC diagnostic push"); \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeclaration-after-statement\"")
|
||||
|
||||
#define DISABLE_WARNING_FORMAT_NONLITERAL \
|
||||
_Pragma("GCC diagnostic push"); \
|
||||
_Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
|
||||
|
||||
#define DISABLE_WARNING_MISSING_PROTOTYPES \
|
||||
_Pragma("GCC diagnostic push"); \
|
||||
_Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"")
|
||||
|
||||
#define DISABLE_WARNING_NONNULL \
|
||||
_Pragma("GCC diagnostic push"); \
|
||||
_Pragma("GCC diagnostic ignored \"-Wnonnull\"")
|
||||
|
||||
#define DISABLE_WARNING_SHADOW \
|
||||
_Pragma("GCC diagnostic push"); \
|
||||
_Pragma("GCC diagnostic ignored \"-Wshadow\"")
|
||||
|
||||
#define REENABLE_WARNING \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
|
||||
/* automake test harness */
|
||||
#define EXIT_TEST_SKIP 77
|
||||
|
||||
#define XSTRINGIFY(x) #x
|
||||
#define STRINGIFY(x) XSTRINGIFY(x)
|
||||
|
||||
#define XCONCATENATE(x, y) x ## y
|
||||
#define CONCATENATE(x, y) XCONCATENATE(x, y)
|
||||
|
||||
#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
|
||||
#define UNIQ __COUNTER__
|
||||
|
||||
/* Rounds up */
|
||||
|
||||
#define ALIGN4(l) (((l) + 3) & ~3)
|
||||
#define ALIGN8(l) (((l) + 7) & ~7)
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
#define ALIGN(l) ALIGN8(l)
|
||||
#elif __SIZEOF_POINTER__ == 4
|
||||
#define ALIGN(l) ALIGN4(l)
|
||||
#else
|
||||
#error "Wut? Pointers are neither 4 nor 8 bytes long?"
|
||||
#endif
|
||||
|
||||
#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) p))
|
||||
#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) p))
|
||||
#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) p))
|
||||
|
||||
static inline size_t ALIGN_TO(size_t l, size_t ali) {
|
||||
return ((l + ali - 1) & ~(ali - 1));
|
||||
}
|
||||
|
||||
#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) p, ali))
|
||||
|
||||
/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */
|
||||
static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
||||
/* clz(0) is undefined */
|
||||
if (u == 1)
|
||||
return 1;
|
||||
|
||||
/* left-shift overflow is undefined */
|
||||
if (__builtin_clzl(u - 1UL) < 1)
|
||||
return 0;
|
||||
|
||||
return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL));
|
||||
}
|
||||
|
||||
#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
/*
|
||||
* container_of - cast a member of a structure out to the containing structure
|
||||
* @ptr: the pointer to the member.
|
||||
* @type: the type of the container struct this is embedded in.
|
||||
* @member: the name of the member within the struct.
|
||||
*/
|
||||
#define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member)
|
||||
#define __container_of(uniq, ptr, type, member) \
|
||||
__extension__ ({ \
|
||||
const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \
|
||||
(type*)( (char *)UNIQ_T(A, uniq) - offsetof(type,member) ); \
|
||||
})
|
||||
|
||||
#undef MAX
|
||||
#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b))
|
||||
#define __MAX(aq, a, bq, b) \
|
||||
__extension__ ({ \
|
||||
const typeof(a) UNIQ_T(A, aq) = (a); \
|
||||
const typeof(b) UNIQ_T(B, bq) = (b); \
|
||||
UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \
|
||||
})
|
||||
|
||||
/* evaluates to (void) if _A or _B are not constant or of different types */
|
||||
#define CONST_MAX(_A, _B) \
|
||||
__extension__ (__builtin_choose_expr( \
|
||||
__builtin_constant_p(_A) && \
|
||||
__builtin_constant_p(_B) && \
|
||||
__builtin_types_compatible_p(typeof(_A), typeof(_B)), \
|
||||
((_A) > (_B)) ? (_A) : (_B), \
|
||||
(void)0))
|
||||
|
||||
/* takes two types and returns the size of the larger one */
|
||||
#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; }))
|
||||
|
||||
#define MAX3(x,y,z) \
|
||||
__extension__ ({ \
|
||||
const typeof(x) _c = MAX(x,y); \
|
||||
MAX(_c, z); \
|
||||
})
|
||||
|
||||
#undef MIN
|
||||
#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
|
||||
#define __MIN(aq, a, bq, b) \
|
||||
__extension__ ({ \
|
||||
const typeof(a) UNIQ_T(A, aq) = (a); \
|
||||
const typeof(b) UNIQ_T(B, bq) = (b); \
|
||||
UNIQ_T(A,aq) < UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \
|
||||
})
|
||||
|
||||
#define MIN3(x,y,z) \
|
||||
__extension__ ({ \
|
||||
const typeof(x) _c = MIN(x,y); \
|
||||
MIN(_c, z); \
|
||||
})
|
||||
|
||||
#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
|
||||
#define __LESS_BY(aq, a, bq, b) \
|
||||
__extension__ ({ \
|
||||
const typeof(a) UNIQ_T(A, aq) = (a); \
|
||||
const typeof(b) UNIQ_T(B, bq) = (b); \
|
||||
UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) - UNIQ_T(B,bq) : 0; \
|
||||
})
|
||||
|
||||
#undef CLAMP
|
||||
#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high))
|
||||
#define __CLAMP(xq, x, lowq, low, highq, high) \
|
||||
__extension__ ({ \
|
||||
const typeof(x) UNIQ_T(X,xq) = (x); \
|
||||
const typeof(low) UNIQ_T(LOW,lowq) = (low); \
|
||||
const typeof(high) UNIQ_T(HIGH,highq) = (high); \
|
||||
UNIQ_T(X,xq) > UNIQ_T(HIGH,highq) ? \
|
||||
UNIQ_T(HIGH,highq) : \
|
||||
UNIQ_T(X,xq) < UNIQ_T(LOW,lowq) ? \
|
||||
UNIQ_T(LOW,lowq) : \
|
||||
UNIQ_T(X,xq); \
|
||||
})
|
||||
|
||||
#define assert_se(expr) \
|
||||
do { \
|
||||
if (_unlikely_(!(expr))) \
|
||||
log_assert_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
||||
} while (false) \
|
||||
|
||||
/* We override the glibc assert() here. */
|
||||
#undef assert
|
||||
#ifdef NDEBUG
|
||||
#define assert(expr) do {} while(false)
|
||||
#else
|
||||
#define assert(expr) assert_se(expr)
|
||||
#endif
|
||||
|
||||
#define assert_not_reached(t) \
|
||||
do { \
|
||||
log_assert_failed_unreachable(t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
||||
} while (false)
|
||||
|
||||
#if defined(static_assert)
|
||||
/* static_assert() is sometimes defined in a way that trips up
|
||||
* -Wdeclaration-after-statement, hence let's temporarily turn off
|
||||
* this warning around it. */
|
||||
#define assert_cc(expr) \
|
||||
DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \
|
||||
static_assert(expr, #expr); \
|
||||
REENABLE_WARNING
|
||||
#else
|
||||
#define assert_cc(expr) \
|
||||
DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \
|
||||
struct CONCATENATE(_assert_struct_, __LINE__) { \
|
||||
char x[(expr) ? 0 : -1]; \
|
||||
}; \
|
||||
REENABLE_WARNING
|
||||
#endif
|
||||
|
||||
#define assert_return(expr, r) \
|
||||
do { \
|
||||
if (_unlikely_(!(expr))) { \
|
||||
log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
||||
return (r); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
|
||||
#define INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
|
||||
#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p)))
|
||||
#define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u)))
|
||||
|
||||
#define PTR_TO_LONG(p) ((long) ((intptr_t) (p)))
|
||||
#define LONG_TO_PTR(u) ((void *) ((intptr_t) (u)))
|
||||
#define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p)))
|
||||
#define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u)))
|
||||
|
||||
#define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p)))
|
||||
#define INT32_TO_PTR(u) ((void *) ((intptr_t) (u)))
|
||||
#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
|
||||
#define UINT32_TO_PTR(u) ((void *) ((uintptr_t) (u)))
|
||||
|
||||
#define PTR_TO_INT64(p) ((int64_t) ((intptr_t) (p)))
|
||||
#define INT64_TO_PTR(u) ((void *) ((intptr_t) (u)))
|
||||
#define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p)))
|
||||
#define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u)))
|
||||
|
||||
#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p)))
|
||||
#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u)))
|
||||
|
||||
#define memzero(x,l) (memset((x), 0, (l)))
|
||||
#define zero(x) (memzero(&(x), sizeof(x)))
|
||||
|
||||
#define CHAR_TO_STR(x) ((char[2]) { x, 0 })
|
||||
|
||||
#define char_array_0(x) x[sizeof(x)-1] = 0;
|
||||
|
||||
#define IOVEC_SET_STRING(i, s) \
|
||||
do { \
|
||||
struct iovec *_i = &(i); \
|
||||
char *_s = (char *)(s); \
|
||||
_i->iov_base = _s; \
|
||||
_i->iov_len = strlen(_s); \
|
||||
} while(false)
|
||||
|
||||
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
|
||||
unsigned j;
|
||||
size_t r = 0;
|
||||
|
||||
for (j = 0; j < n; j++)
|
||||
r += i[j].iov_len;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
|
||||
unsigned j;
|
||||
|
||||
for (j = 0; j < n; j++) {
|
||||
size_t sub;
|
||||
|
||||
if (_unlikely_(k <= 0))
|
||||
break;
|
||||
|
||||
sub = MIN(i[j].iov_len, k);
|
||||
i[j].iov_len -= sub;
|
||||
i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
|
||||
k -= sub;
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
#define VA_FORMAT_ADVANCE(format, ap) \
|
||||
do { \
|
||||
int _argtypes[128]; \
|
||||
size_t _i, _k; \
|
||||
_k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
|
||||
assert(_k < ELEMENTSOF(_argtypes)); \
|
||||
for (_i = 0; _i < _k; _i++) { \
|
||||
if (_argtypes[_i] & PA_FLAG_PTR) { \
|
||||
(void) va_arg(ap, void*); \
|
||||
continue; \
|
||||
} \
|
||||
\
|
||||
switch (_argtypes[_i]) { \
|
||||
case PA_INT: \
|
||||
case PA_INT|PA_FLAG_SHORT: \
|
||||
case PA_CHAR: \
|
||||
(void) va_arg(ap, int); \
|
||||
break; \
|
||||
case PA_INT|PA_FLAG_LONG: \
|
||||
(void) va_arg(ap, long int); \
|
||||
break; \
|
||||
case PA_INT|PA_FLAG_LONG_LONG: \
|
||||
(void) va_arg(ap, long long int); \
|
||||
break; \
|
||||
case PA_WCHAR: \
|
||||
(void) va_arg(ap, wchar_t); \
|
||||
break; \
|
||||
case PA_WSTRING: \
|
||||
case PA_STRING: \
|
||||
case PA_POINTER: \
|
||||
(void) va_arg(ap, void*); \
|
||||
break; \
|
||||
case PA_FLOAT: \
|
||||
case PA_DOUBLE: \
|
||||
(void) va_arg(ap, double); \
|
||||
break; \
|
||||
case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \
|
||||
(void) va_arg(ap, long double); \
|
||||
break; \
|
||||
default: \
|
||||
assert_not_reached("Unknown format string argument."); \
|
||||
} \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
/* Because statfs.t_type can be int on some architectures, we have to cast
|
||||
* the const magic to the type, otherwise the compiler warns about
|
||||
* signed/unsigned comparison, because the magic can be 32 bit unsigned.
|
||||
*/
|
||||
#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
|
||||
|
||||
/* Returns the number of chars needed to format variables of the
|
||||
* specified type as a decimal string. Adds in extra space for a
|
||||
* negative '-' prefix. */
|
||||
#define DECIMAL_STR_MAX(type) \
|
||||
(2+(sizeof(type) <= 1 ? 3 : \
|
||||
sizeof(type) <= 2 ? 5 : \
|
||||
sizeof(type) <= 4 ? 10 : \
|
||||
sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)])))
|
||||
|
||||
#define SET_FLAG(v, flag, b) \
|
||||
(v) = (b) ? ((v) | (flag)) : ((v) & ~(flag))
|
||||
|
||||
#define IN_SET(x, y, ...) \
|
||||
({ \
|
||||
const typeof(y) _y = (y); \
|
||||
typeof(_y) _x = (x); \
|
||||
unsigned _i; \
|
||||
bool _found = false; \
|
||||
for (_i = 0; _i < 1 + sizeof((typeof(_x)[]) { __VA_ARGS__ })/sizeof(typeof(_x)); _i++) \
|
||||
if (((typeof(_x)[]) { _y, __VA_ARGS__ })[_i] == _x) { \
|
||||
_found = true; \
|
||||
break; \
|
||||
} \
|
||||
_found; \
|
||||
})
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
/* Define C11 thread_local attribute even on older gcc compiler
|
||||
* version */
|
||||
#ifndef thread_local
|
||||
/*
|
||||
* Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
|
||||
* see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
|
||||
*/
|
||||
#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
|
||||
#define thread_local _Thread_local
|
||||
#else
|
||||
#define thread_local __thread
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
|
||||
* compiler versions */
|
||||
#ifndef noreturn
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define noreturn _Noreturn
|
||||
#else
|
||||
#define noreturn __attribute__((noreturn))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#endif
|
||||
34
src/dhcp-manager/systemd-dhcp/src/shared/refcnt.h
Normal file
34
src/dhcp-manager/systemd-dhcp/src/shared/refcnt.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
/* A type-safe atomic refcounter */
|
||||
|
||||
typedef struct {
|
||||
volatile unsigned _value;
|
||||
} RefCount;
|
||||
|
||||
#define REFCNT_GET(r) ((r)._value)
|
||||
#define REFCNT_INC(r) (__sync_add_and_fetch(&(r)._value, 1))
|
||||
#define REFCNT_DEC(r) (__sync_sub_and_fetch(&(r)._value, 1))
|
||||
|
||||
#define REFCNT_INIT ((RefCount) { ._value = 1 })
|
||||
135
src/dhcp-manager/systemd-dhcp/src/shared/siphash24.c
Normal file
135
src/dhcp-manager/systemd-dhcp/src/shared/siphash24.c
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
SipHash reference C implementation
|
||||
|
||||
Written in 2012 by
|
||||
Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
|
||||
Daniel J. Bernstein <djb@cr.yp.to>
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
|
||||
(Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd)
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "siphash24.h"
|
||||
|
||||
typedef uint64_t u64;
|
||||
typedef uint32_t u32;
|
||||
typedef uint8_t u8;
|
||||
|
||||
#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) )
|
||||
|
||||
#define U32TO8_LE(p, v) \
|
||||
(p)[0] = (u8)((v) ); (p)[1] = (u8)((v) >> 8); \
|
||||
(p)[2] = (u8)((v) >> 16); (p)[3] = (u8)((v) >> 24);
|
||||
|
||||
#define U64TO8_LE(p, v) \
|
||||
U32TO8_LE((p), (u32)((v) )); \
|
||||
U32TO8_LE((p) + 4, (u32)((v) >> 32));
|
||||
|
||||
#define U8TO64_LE(p) \
|
||||
(((u64)((p)[0]) ) | \
|
||||
((u64)((p)[1]) << 8) | \
|
||||
((u64)((p)[2]) << 16) | \
|
||||
((u64)((p)[3]) << 24) | \
|
||||
((u64)((p)[4]) << 32) | \
|
||||
((u64)((p)[5]) << 40) | \
|
||||
((u64)((p)[6]) << 48) | \
|
||||
((u64)((p)[7]) << 56))
|
||||
|
||||
#define SIPROUND \
|
||||
do { \
|
||||
v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \
|
||||
v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \
|
||||
v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \
|
||||
v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \
|
||||
} while(0)
|
||||
|
||||
/* SipHash-2-4 */
|
||||
void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16])
|
||||
{
|
||||
/* "somepseudorandomlygeneratedbytes" */
|
||||
u64 v0 = 0x736f6d6570736575ULL;
|
||||
u64 v1 = 0x646f72616e646f6dULL;
|
||||
u64 v2 = 0x6c7967656e657261ULL;
|
||||
u64 v3 = 0x7465646279746573ULL;
|
||||
u64 b;
|
||||
u64 k0 = U8TO64_LE( k );
|
||||
u64 k1 = U8TO64_LE( k + 8 );
|
||||
u64 m;
|
||||
const u8 *in = _in;
|
||||
const u8 *end = in + inlen - ( inlen % sizeof( u64 ) );
|
||||
const int left = inlen & 7;
|
||||
b = ( ( u64 )inlen ) << 56;
|
||||
v3 ^= k1;
|
||||
v2 ^= k0;
|
||||
v1 ^= k1;
|
||||
v0 ^= k0;
|
||||
|
||||
for ( ; in != end; in += 8 )
|
||||
{
|
||||
m = U8TO64_LE( in );
|
||||
#ifdef DEBUG
|
||||
printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
|
||||
printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
|
||||
printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
|
||||
printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
|
||||
printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m );
|
||||
#endif
|
||||
v3 ^= m;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= m;
|
||||
}
|
||||
|
||||
switch( left )
|
||||
{
|
||||
case 7: b |= ( ( u64 )in[ 6] ) << 48;
|
||||
|
||||
case 6: b |= ( ( u64 )in[ 5] ) << 40;
|
||||
|
||||
case 5: b |= ( ( u64 )in[ 4] ) << 32;
|
||||
|
||||
case 4: b |= ( ( u64 )in[ 3] ) << 24;
|
||||
|
||||
case 3: b |= ( ( u64 )in[ 2] ) << 16;
|
||||
|
||||
case 2: b |= ( ( u64 )in[ 1] ) << 8;
|
||||
|
||||
case 1: b |= ( ( u64 )in[ 0] ); break;
|
||||
|
||||
case 0: break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
|
||||
printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
|
||||
printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
|
||||
printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
|
||||
printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b );
|
||||
#endif
|
||||
v3 ^= b;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= b;
|
||||
#ifdef DEBUG
|
||||
printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
|
||||
printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
|
||||
printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
|
||||
printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
|
||||
#endif
|
||||
v2 ^= 0xff;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
b = v0 ^ v1 ^ v2 ^ v3;
|
||||
U64TO8_LE( out, b );
|
||||
}
|
||||
6
src/dhcp-manager/systemd-dhcp/src/shared/siphash24.h
Normal file
6
src/dhcp-manager/systemd-dhcp/src/shared/siphash24.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]);
|
||||
118
src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h
Normal file
118
src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <sys/un.h>
|
||||
#include <asm/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
|
||||
union sockaddr_union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
struct sockaddr_un un;
|
||||
struct sockaddr_nl nl;
|
||||
struct sockaddr_storage storage;
|
||||
struct sockaddr_ll ll;
|
||||
};
|
||||
|
||||
typedef struct SocketAddress {
|
||||
union sockaddr_union sockaddr;
|
||||
|
||||
/* We store the size here explicitly due to the weird
|
||||
* sockaddr_un semantics for abstract sockets */
|
||||
socklen_t size;
|
||||
|
||||
/* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */
|
||||
int type;
|
||||
|
||||
/* Socket protocol, IPPROTO_xxx, usually 0, except for netlink */
|
||||
int protocol;
|
||||
} SocketAddress;
|
||||
|
||||
typedef enum SocketAddressBindIPv6Only {
|
||||
SOCKET_ADDRESS_DEFAULT,
|
||||
SOCKET_ADDRESS_BOTH,
|
||||
SOCKET_ADDRESS_IPV6_ONLY,
|
||||
_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX,
|
||||
_SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -1
|
||||
} SocketAddressBindIPv6Only;
|
||||
|
||||
#define socket_address_family(a) ((a)->sockaddr.sa.sa_family)
|
||||
|
||||
int socket_address_parse(SocketAddress *a, const char *s);
|
||||
int socket_address_parse_netlink(SocketAddress *a, const char *s);
|
||||
int socket_address_print(const SocketAddress *a, char **p);
|
||||
int socket_address_verify(const SocketAddress *a) _pure_;
|
||||
int socket_address_unlink(SocketAddress *a);
|
||||
|
||||
bool socket_address_can_accept(const SocketAddress *a) _pure_;
|
||||
|
||||
int socket_address_listen(
|
||||
const SocketAddress *a,
|
||||
int flags,
|
||||
int backlog,
|
||||
SocketAddressBindIPv6Only only,
|
||||
const char *bind_to_device,
|
||||
bool free_bind,
|
||||
bool transparent,
|
||||
mode_t directory_mode,
|
||||
mode_t socket_mode,
|
||||
const char *label);
|
||||
int make_socket_fd(int log_level, const char* address, int flags);
|
||||
|
||||
bool socket_address_is(const SocketAddress *a, const char *s, int type);
|
||||
bool socket_address_is_netlink(const SocketAddress *a, const char *s);
|
||||
|
||||
bool socket_address_matches_fd(const SocketAddress *a, int fd);
|
||||
|
||||
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_;
|
||||
|
||||
const char* socket_address_get_path(const SocketAddress *a);
|
||||
|
||||
bool socket_ipv6_is_supported(void);
|
||||
|
||||
int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret);
|
||||
int getpeername_pretty(int fd, char **ret);
|
||||
int getsockname_pretty(int fd, char **ret);
|
||||
|
||||
int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret);
|
||||
int getnameinfo_pretty(int fd, char **ret);
|
||||
|
||||
const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_;
|
||||
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_;
|
||||
|
||||
int netlink_family_to_string_alloc(int b, char **s);
|
||||
int netlink_family_from_string(const char *s) _pure_;
|
||||
|
||||
bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b);
|
||||
|
||||
#define ETHER_ADDR_TO_STRING_MAX (3*6)
|
||||
|
||||
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
|
||||
88
src/dhcp-manager/systemd-dhcp/src/shared/sparse-endian.h
Normal file
88
src/dhcp-manager/systemd-dhcp/src/shared/sparse-endian.h
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/* Copyright (c) 2012 Josh Triplett <josh@joshtriplett.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SPARSE_ENDIAN_H
|
||||
#define SPARSE_ENDIAN_H
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <endian.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __CHECKER__
|
||||
#define __bitwise __attribute__((bitwise))
|
||||
#define __force __attribute__((force))
|
||||
#else
|
||||
#define __bitwise
|
||||
#define __force
|
||||
#endif
|
||||
|
||||
typedef uint16_t __bitwise le16_t;
|
||||
typedef uint16_t __bitwise be16_t;
|
||||
typedef uint32_t __bitwise le32_t;
|
||||
typedef uint32_t __bitwise be32_t;
|
||||
typedef uint64_t __bitwise le64_t;
|
||||
typedef uint64_t __bitwise be64_t;
|
||||
|
||||
#undef htobe16
|
||||
#undef htole16
|
||||
#undef be16toh
|
||||
#undef le16toh
|
||||
#undef htobe32
|
||||
#undef htole32
|
||||
#undef be32toh
|
||||
#undef le32toh
|
||||
#undef htobe64
|
||||
#undef htole64
|
||||
#undef be64toh
|
||||
#undef le64toh
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define bswap_16_on_le(x) __bswap_16(x)
|
||||
#define bswap_32_on_le(x) __bswap_32(x)
|
||||
#define bswap_64_on_le(x) __bswap_64(x)
|
||||
#define bswap_16_on_be(x) (x)
|
||||
#define bswap_32_on_be(x) (x)
|
||||
#define bswap_64_on_be(x) (x)
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define bswap_16_on_le(x) (x)
|
||||
#define bswap_32_on_le(x) (x)
|
||||
#define bswap_64_on_le(x) (x)
|
||||
#define bswap_16_on_be(x) __bswap_16(x)
|
||||
#define bswap_32_on_be(x) __bswap_32(x)
|
||||
#define bswap_64_on_be(x) __bswap_64(x)
|
||||
#endif
|
||||
|
||||
static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); }
|
||||
static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); }
|
||||
static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); }
|
||||
|
||||
static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); }
|
||||
static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); }
|
||||
static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); }
|
||||
|
||||
static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); }
|
||||
static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); }
|
||||
static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); }
|
||||
|
||||
static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); }
|
||||
static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); }
|
||||
static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); }
|
||||
|
||||
#endif /* SPARSE_ENDIAN_H */
|
||||
611
src/dhcp-manager/systemd-dhcp/src/shared/strv.c
Normal file
611
src/dhcp-manager/systemd-dhcp/src/shared/strv.c
Normal file
|
|
@ -0,0 +1,611 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "strv.h"
|
||||
|
||||
char *strv_find(char **l, const char *name) {
|
||||
char **i;
|
||||
|
||||
assert(name);
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
if (streq(*i, name))
|
||||
return *i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strv_find_prefix(char **l, const char *name) {
|
||||
char **i;
|
||||
|
||||
assert(name);
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
if (startswith(*i, name))
|
||||
return *i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strv_find_startswith(char **l, const char *name) {
|
||||
char **i, *e;
|
||||
|
||||
assert(name);
|
||||
|
||||
/* Like strv_find_prefix, but actually returns only the
|
||||
* suffix, not the whole item */
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
e = startswith(*i, name);
|
||||
if (e)
|
||||
return e;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void strv_free(char **l) {
|
||||
char **k;
|
||||
|
||||
if (!l)
|
||||
return;
|
||||
|
||||
for (k = l; *k; k++)
|
||||
free(*k);
|
||||
|
||||
free(l);
|
||||
}
|
||||
|
||||
char **strv_copy(char * const *l) {
|
||||
char **r, **k;
|
||||
|
||||
k = r = new(char*, strv_length(l) + 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
if (l)
|
||||
for (; *l; k++, l++) {
|
||||
*k = strdup(*l);
|
||||
if (!*k) {
|
||||
strv_free(r);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
*k = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned strv_length(char * const *l) {
|
||||
unsigned n = 0;
|
||||
|
||||
if (!l)
|
||||
return 0;
|
||||
|
||||
for (; *l; l++)
|
||||
n++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
char **strv_new_ap(const char *x, va_list ap) {
|
||||
const char *s;
|
||||
char **a;
|
||||
unsigned n = 0, i = 0;
|
||||
va_list aq;
|
||||
|
||||
/* As a special trick we ignore all listed strings that equal
|
||||
* (const char*) -1. This is supposed to be used with the
|
||||
* STRV_IFNOTNULL() macro to include possibly NULL strings in
|
||||
* the string list. */
|
||||
|
||||
if (x) {
|
||||
n = x == (const char*) -1 ? 0 : 1;
|
||||
|
||||
va_copy(aq, ap);
|
||||
while ((s = va_arg(aq, const char*))) {
|
||||
if (s == (const char*) -1)
|
||||
continue;
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
va_end(aq);
|
||||
}
|
||||
|
||||
a = new(char*, n+1);
|
||||
if (!a)
|
||||
return NULL;
|
||||
|
||||
if (x) {
|
||||
if (x != (const char*) -1) {
|
||||
a[i] = strdup(x);
|
||||
if (!a[i])
|
||||
goto fail;
|
||||
i++;
|
||||
}
|
||||
|
||||
while ((s = va_arg(ap, const char*))) {
|
||||
|
||||
if (s == (const char*) -1)
|
||||
continue;
|
||||
|
||||
a[i] = strdup(s);
|
||||
if (!a[i])
|
||||
goto fail;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
a[i] = NULL;
|
||||
|
||||
return a;
|
||||
|
||||
fail:
|
||||
strv_free(a);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **strv_new(const char *x, ...) {
|
||||
char **r;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, x);
|
||||
r = strv_new_ap(x, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int strv_extend_strv(char ***a, char **b) {
|
||||
int r;
|
||||
char **s;
|
||||
|
||||
STRV_FOREACH(s, b) {
|
||||
r = strv_extend(a, *s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
|
||||
int r;
|
||||
char **s;
|
||||
|
||||
STRV_FOREACH(s, b) {
|
||||
char *v;
|
||||
|
||||
v = strappend(*s, suffix);
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
r = strv_push(a, v);
|
||||
if (r < 0) {
|
||||
free(v);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char **strv_split(const char *s, const char *separator) {
|
||||
const char *word, *state;
|
||||
size_t l;
|
||||
unsigned n, i;
|
||||
char **r;
|
||||
|
||||
assert(s);
|
||||
|
||||
n = 0;
|
||||
FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
|
||||
n++;
|
||||
|
||||
r = new(char*, n+1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
i = 0;
|
||||
FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
|
||||
r[i] = strndup(word, l);
|
||||
if (!r[i]) {
|
||||
strv_free(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
r[i] = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
int strv_split_quoted(char ***t, const char *s) {
|
||||
const char *word, *state;
|
||||
size_t l;
|
||||
unsigned n, i;
|
||||
char **r;
|
||||
|
||||
assert(s);
|
||||
|
||||
n = 0;
|
||||
FOREACH_WORD_QUOTED(word, l, s, state)
|
||||
n++;
|
||||
if (!isempty(state))
|
||||
/* bad syntax */
|
||||
return -EINVAL;
|
||||
|
||||
r = new(char*, n+1);
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
|
||||
i = 0;
|
||||
FOREACH_WORD_QUOTED(word, l, s, state) {
|
||||
r[i] = cunescape_length(word, l);
|
||||
if (!r[i]) {
|
||||
strv_free(r);
|
||||
return -ENOMEM;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
r[i] = NULL;
|
||||
*t = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char **strv_split_newlines(const char *s) {
|
||||
char **l;
|
||||
unsigned n;
|
||||
|
||||
assert(s);
|
||||
|
||||
/* Special version of strv_split() that splits on newlines and
|
||||
* suppresses an empty string at the end */
|
||||
|
||||
l = strv_split(s, NEWLINE);
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
n = strv_length(l);
|
||||
if (n <= 0)
|
||||
return l;
|
||||
|
||||
if (isempty(l[n-1])) {
|
||||
free(l[n-1]);
|
||||
l[n-1] = NULL;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
char *strv_join(char **l, const char *separator) {
|
||||
char *r, *e;
|
||||
char **s;
|
||||
size_t n, k;
|
||||
|
||||
if (!separator)
|
||||
separator = " ";
|
||||
|
||||
k = strlen(separator);
|
||||
|
||||
n = 0;
|
||||
STRV_FOREACH(s, l) {
|
||||
if (n != 0)
|
||||
n += k;
|
||||
n += strlen(*s);
|
||||
}
|
||||
|
||||
r = new(char, n+1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
e = r;
|
||||
STRV_FOREACH(s, l) {
|
||||
if (e != r)
|
||||
e = stpcpy(e, separator);
|
||||
|
||||
e = stpcpy(e, *s);
|
||||
}
|
||||
|
||||
*e = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *strv_join_quoted(char **l) {
|
||||
char *buf = NULL;
|
||||
char **s;
|
||||
size_t allocated = 0, len = 0;
|
||||
|
||||
STRV_FOREACH(s, l) {
|
||||
/* assuming here that escaped string cannot be more
|
||||
* than twice as long, and reserving space for the
|
||||
* separator and quotes.
|
||||
*/
|
||||
_cleanup_free_ char *esc = NULL;
|
||||
size_t needed;
|
||||
|
||||
if (!GREEDY_REALLOC(buf, allocated,
|
||||
len + strlen(*s) * 2 + 3))
|
||||
goto oom;
|
||||
|
||||
esc = cescape(*s);
|
||||
if (!esc)
|
||||
goto oom;
|
||||
|
||||
needed = snprintf(buf + len, allocated - len, "%s\"%s\"",
|
||||
len > 0 ? " " : "", esc);
|
||||
assert(needed < allocated - len);
|
||||
len += needed;
|
||||
}
|
||||
|
||||
if (!buf)
|
||||
buf = malloc0(1);
|
||||
|
||||
return buf;
|
||||
|
||||
oom:
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int strv_push(char ***l, char *value) {
|
||||
char **c;
|
||||
unsigned n, m;
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
n = strv_length(*l);
|
||||
|
||||
/* increase and check for overflow */
|
||||
m = n + 2;
|
||||
if (m < n)
|
||||
return -ENOMEM;
|
||||
|
||||
c = realloc_multiply(*l, sizeof(char*), m);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
c[n] = value;
|
||||
c[n+1] = NULL;
|
||||
|
||||
*l = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strv_push_prepend(char ***l, char *value) {
|
||||
char **c;
|
||||
unsigned n, m, i;
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
n = strv_length(*l);
|
||||
|
||||
/* increase and check for overflow */
|
||||
m = n + 2;
|
||||
if (m < n)
|
||||
return -ENOMEM;
|
||||
|
||||
c = new(char*, m);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
c[i+1] = (*l)[i];
|
||||
|
||||
c[0] = value;
|
||||
c[n+1] = NULL;
|
||||
|
||||
free(*l);
|
||||
*l = c;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strv_consume(char ***l, char *value) {
|
||||
int r;
|
||||
|
||||
r = strv_push(l, value);
|
||||
if (r < 0)
|
||||
free(value);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int strv_consume_prepend(char ***l, char *value) {
|
||||
int r;
|
||||
|
||||
r = strv_push_prepend(l, value);
|
||||
if (r < 0)
|
||||
free(value);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int strv_extend(char ***l, const char *value) {
|
||||
char *v;
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
v = strdup(value);
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
return strv_consume(l, v);
|
||||
}
|
||||
|
||||
char **strv_uniq(char **l) {
|
||||
char **i;
|
||||
|
||||
/* Drops duplicate entries. The first identical string will be
|
||||
* kept, the others dropped */
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
strv_remove(i+1, *i);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
char **strv_remove(char **l, const char *s) {
|
||||
char **f, **t;
|
||||
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
assert(s);
|
||||
|
||||
/* Drops every occurrence of s in the string list, edits
|
||||
* in-place. */
|
||||
|
||||
for (f = t = l; *f; f++)
|
||||
if (streq(*f, s))
|
||||
free(*f);
|
||||
else
|
||||
*(t++) = *f;
|
||||
|
||||
*t = NULL;
|
||||
return l;
|
||||
}
|
||||
|
||||
char **strv_parse_nulstr(const char *s, size_t l) {
|
||||
const char *p;
|
||||
unsigned c = 0, i = 0;
|
||||
char **v;
|
||||
|
||||
assert(s || l <= 0);
|
||||
|
||||
if (l <= 0)
|
||||
return new0(char*, 1);
|
||||
|
||||
for (p = s; p < s + l; p++)
|
||||
if (*p == 0)
|
||||
c++;
|
||||
|
||||
if (s[l-1] != 0)
|
||||
c++;
|
||||
|
||||
v = new0(char*, c+1);
|
||||
if (!v)
|
||||
return NULL;
|
||||
|
||||
p = s;
|
||||
while (p < s + l) {
|
||||
const char *e;
|
||||
|
||||
e = memchr(p, 0, s + l - p);
|
||||
|
||||
v[i] = strndup(p, e ? e - p : s + l - p);
|
||||
if (!v[i]) {
|
||||
strv_free(v);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if (!e)
|
||||
break;
|
||||
|
||||
p = e + 1;
|
||||
}
|
||||
|
||||
assert(i == c);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
char **strv_split_nulstr(const char *s) {
|
||||
const char *i;
|
||||
char **r = NULL;
|
||||
|
||||
NULSTR_FOREACH(i, s)
|
||||
if (strv_extend(&r, i) < 0) {
|
||||
strv_free(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!r)
|
||||
return strv_new(NULL, NULL);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool strv_overlap(char **a, char **b) {
|
||||
char **i;
|
||||
|
||||
STRV_FOREACH(i, a)
|
||||
if (strv_contains(b, *i))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int str_compare(const void *_a, const void *_b) {
|
||||
const char **a = (const char**) _a, **b = (const char**) _b;
|
||||
|
||||
return strcmp(*a, *b);
|
||||
}
|
||||
|
||||
char **strv_sort(char **l) {
|
||||
|
||||
if (strv_isempty(l))
|
||||
return l;
|
||||
|
||||
qsort(l, strv_length(l), sizeof(char*), str_compare);
|
||||
return l;
|
||||
}
|
||||
|
||||
void strv_print(char **l) {
|
||||
char **s;
|
||||
|
||||
STRV_FOREACH(s, l)
|
||||
puts(*s);
|
||||
}
|
||||
|
||||
int strv_extendf(char ***l, const char *format, ...) {
|
||||
va_list ap;
|
||||
char *x;
|
||||
int r;
|
||||
|
||||
va_start(ap, format);
|
||||
r = vasprintf(&x, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return strv_consume(l, x);
|
||||
}
|
||||
136
src/dhcp-manager/systemd-dhcp/src/shared/strv.h
Normal file
136
src/dhcp-manager/systemd-dhcp/src/shared/strv.h
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
char *strv_find(char **l, const char *name) _pure_;
|
||||
char *strv_find_prefix(char **l, const char *name) _pure_;
|
||||
char *strv_find_startswith(char **l, const char *name) _pure_;
|
||||
|
||||
void strv_free(char **l);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
|
||||
#define _cleanup_strv_free_ _cleanup_(strv_freep)
|
||||
|
||||
char **strv_copy(char * const *l);
|
||||
unsigned strv_length(char * const *l) _pure_;
|
||||
|
||||
int strv_extend_strv(char ***a, char **b);
|
||||
int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
|
||||
int strv_extend(char ***l, const char *value);
|
||||
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
|
||||
int strv_push(char ***l, char *value);
|
||||
int strv_push_prepend(char ***l, char *value);
|
||||
int strv_consume(char ***l, char *value);
|
||||
int strv_consume_prepend(char ***l, char *value);
|
||||
|
||||
char **strv_remove(char **l, const char *s);
|
||||
char **strv_uniq(char **l);
|
||||
|
||||
#define strv_contains(l, s) (!!strv_find((l), (s)))
|
||||
|
||||
char **strv_new(const char *x, ...) _sentinel_;
|
||||
char **strv_new_ap(const char *x, va_list ap);
|
||||
|
||||
static inline const char* STRV_IFNOTNULL(const char *x) {
|
||||
return x ? x : (const char *) -1;
|
||||
}
|
||||
|
||||
static inline bool strv_isempty(char * const *l) {
|
||||
return !l || !*l;
|
||||
}
|
||||
|
||||
char **strv_split(const char *s, const char *separator);
|
||||
int strv_split_quoted(char ***t, const char *s);
|
||||
char **strv_split_newlines(const char *s);
|
||||
|
||||
char *strv_join(char **l, const char *separator);
|
||||
char *strv_join_quoted(char **l);
|
||||
|
||||
char **strv_parse_nulstr(const char *s, size_t l);
|
||||
char **strv_split_nulstr(const char *s);
|
||||
|
||||
bool strv_overlap(char **a, char **b) _pure_;
|
||||
|
||||
#define STRV_FOREACH(s, l) \
|
||||
for ((s) = (l); (s) && *(s); (s)++)
|
||||
|
||||
#define STRV_FOREACH_BACKWARDS(s, l) \
|
||||
STRV_FOREACH(s, l) \
|
||||
; \
|
||||
for ((s)--; (l) && ((s) >= (l)); (s)--)
|
||||
|
||||
#define STRV_FOREACH_PAIR(x, y, l) \
|
||||
for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
|
||||
|
||||
char **strv_sort(char **l);
|
||||
void strv_print(char **l);
|
||||
|
||||
#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
|
||||
|
||||
#define STRV_MAKE_EMPTY ((char*[1]) { NULL })
|
||||
|
||||
#define strv_from_stdarg_alloca(first) \
|
||||
({ \
|
||||
char **_l; \
|
||||
\
|
||||
if (!first) \
|
||||
_l = (char**) &first; \
|
||||
else { \
|
||||
unsigned _n; \
|
||||
va_list _ap; \
|
||||
\
|
||||
_n = 1; \
|
||||
va_start(_ap, first); \
|
||||
while (va_arg(_ap, char*)) \
|
||||
_n++; \
|
||||
va_end(_ap); \
|
||||
\
|
||||
_l = newa(char*, _n+1); \
|
||||
_l[_n = 0] = (char*) first; \
|
||||
va_start(_ap, first); \
|
||||
for (;;) { \
|
||||
_l[++_n] = va_arg(_ap, char*); \
|
||||
if (!_l[_n]) \
|
||||
break; \
|
||||
} \
|
||||
va_end(_ap); \
|
||||
} \
|
||||
_l; \
|
||||
})
|
||||
|
||||
#define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x)
|
||||
|
||||
#define FOREACH_STRING(x, ...) \
|
||||
for (char **_l = ({ \
|
||||
char **_ll = STRV_MAKE(__VA_ARGS__); \
|
||||
x = _ll ? _ll[0] : NULL; \
|
||||
_ll; \
|
||||
}); \
|
||||
_l && *_l; \
|
||||
x = ({ \
|
||||
_l ++; \
|
||||
_l[0]; \
|
||||
}))
|
||||
1003
src/dhcp-manager/systemd-dhcp/src/shared/time-util.c
Normal file
1003
src/dhcp-manager/systemd-dhcp/src/shared/time-util.c
Normal file
File diff suppressed because it is too large
Load diff
111
src/dhcp-manager/systemd-dhcp/src/shared/time-util.h
Normal file
111
src/dhcp-manager/systemd-dhcp/src/shared/time-util.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef uint64_t usec_t;
|
||||
typedef uint64_t nsec_t;
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#define NSEC_FMT "%" PRIu64
|
||||
#define USEC_FMT "%" PRIu64
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
typedef struct dual_timestamp {
|
||||
usec_t realtime;
|
||||
usec_t monotonic;
|
||||
} dual_timestamp;
|
||||
|
||||
#define USEC_INFINITY ((usec_t) -1)
|
||||
#define NSEC_INFINITY ((nsec_t) -1)
|
||||
|
||||
#define MSEC_PER_SEC 1000ULL
|
||||
#define USEC_PER_SEC ((usec_t) 1000000ULL)
|
||||
#define USEC_PER_MSEC ((usec_t) 1000ULL)
|
||||
#define NSEC_PER_SEC ((nsec_t) 1000000000ULL)
|
||||
#define NSEC_PER_MSEC ((nsec_t) 1000000ULL)
|
||||
#define NSEC_PER_USEC ((nsec_t) 1000ULL)
|
||||
|
||||
#define USEC_PER_MINUTE ((usec_t) (60ULL*USEC_PER_SEC))
|
||||
#define NSEC_PER_MINUTE ((nsec_t) (60ULL*NSEC_PER_SEC))
|
||||
#define USEC_PER_HOUR ((usec_t) (60ULL*USEC_PER_MINUTE))
|
||||
#define NSEC_PER_HOUR ((nsec_t) (60ULL*NSEC_PER_MINUTE))
|
||||
#define USEC_PER_DAY ((usec_t) (24ULL*USEC_PER_HOUR))
|
||||
#define NSEC_PER_DAY ((nsec_t) (24ULL*NSEC_PER_HOUR))
|
||||
#define USEC_PER_WEEK ((usec_t) (7ULL*USEC_PER_DAY))
|
||||
#define NSEC_PER_WEEK ((nsec_t) (7ULL*NSEC_PER_DAY))
|
||||
#define USEC_PER_MONTH ((usec_t) (2629800ULL*USEC_PER_SEC))
|
||||
#define NSEC_PER_MONTH ((nsec_t) (2629800ULL*NSEC_PER_SEC))
|
||||
#define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC))
|
||||
#define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC))
|
||||
|
||||
#define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1) /* weekdays can be unicode */
|
||||
#define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */
|
||||
#define FORMAT_TIMESTAMP_RELATIVE_MAX 256
|
||||
#define FORMAT_TIMESPAN_MAX 64
|
||||
|
||||
#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
|
||||
|
||||
#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0, 0 })
|
||||
|
||||
usec_t now(clockid_t clock);
|
||||
|
||||
dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
|
||||
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
|
||||
dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u);
|
||||
|
||||
static inline bool dual_timestamp_is_set(dual_timestamp *ts) {
|
||||
return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) ||
|
||||
(ts->monotonic > 0 && ts->monotonic != USEC_INFINITY));
|
||||
}
|
||||
|
||||
usec_t timespec_load(const struct timespec *ts) _pure_;
|
||||
struct timespec *timespec_store(struct timespec *ts, usec_t u);
|
||||
|
||||
usec_t timeval_load(const struct timeval *tv) _pure_;
|
||||
struct timeval *timeval_store(struct timeval *tv, usec_t u);
|
||||
|
||||
char *format_timestamp(char *buf, size_t l, usec_t t);
|
||||
char *format_timestamp_utc(char *buf, size_t l, usec_t t);
|
||||
char *format_timestamp_us(char *buf, size_t l, usec_t t);
|
||||
char *format_timestamp_us_utc(char *buf, size_t l, usec_t t);
|
||||
char *format_timestamp_relative(char *buf, size_t l, usec_t t);
|
||||
char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
|
||||
|
||||
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t);
|
||||
void dual_timestamp_deserialize(const char *value, dual_timestamp *t);
|
||||
|
||||
int parse_timestamp(const char *t, usec_t *usec);
|
||||
|
||||
int parse_sec(const char *t, usec_t *usec);
|
||||
int parse_nsec(const char *t, nsec_t *nsec);
|
||||
|
||||
bool ntp_synced(void);
|
||||
|
||||
int get_timezones(char ***l);
|
||||
bool timezone_is_valid(const char *name);
|
||||
|
||||
clockid_t clock_boottime_or_monotonic(void);
|
||||
310
src/dhcp-manager/systemd-dhcp/src/shared/utf8.c
Normal file
310
src/dhcp-manager/systemd-dhcp/src/shared/utf8.c
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2008-2011 Kay Sievers
|
||||
Copyright 2012 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
/* Parts of this file are based on the GLIB utf8 validation functions. The
|
||||
* original license text follows. */
|
||||
|
||||
/* gutf8.c - Operations on UTF-8 strings.
|
||||
*
|
||||
* Copyright (C) 1999 Tom Tromey
|
||||
* Copyright (C) 2000 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "utf8.h"
|
||||
#include "util.h"
|
||||
|
||||
static inline bool is_unicode_valid(uint32_t ch) {
|
||||
|
||||
if (ch >= 0x110000) /* End of unicode space */
|
||||
return false;
|
||||
if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */
|
||||
return false;
|
||||
if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */
|
||||
return false;
|
||||
if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_unicode_control(uint32_t ch) {
|
||||
|
||||
/*
|
||||
0 to ' '-1 is the C0 range.
|
||||
DEL=0x7F, and DEL+1 to 0x9F is C1 range.
|
||||
'\t' is in C0 range, but more or less harmless and commonly used.
|
||||
*/
|
||||
|
||||
return (ch < ' ' && ch != '\t' && ch != '\n') ||
|
||||
(0x7F <= ch && ch <= 0x9F);
|
||||
}
|
||||
|
||||
/* count of characters used to encode one unicode char */
|
||||
static int utf8_encoded_expected_len(const char *str) {
|
||||
unsigned char c;
|
||||
|
||||
assert(str);
|
||||
|
||||
c = (unsigned char) str[0];
|
||||
if (c < 0x80)
|
||||
return 1;
|
||||
if ((c & 0xe0) == 0xc0)
|
||||
return 2;
|
||||
if ((c & 0xf0) == 0xe0)
|
||||
return 3;
|
||||
if ((c & 0xf8) == 0xf0)
|
||||
return 4;
|
||||
if ((c & 0xfc) == 0xf8)
|
||||
return 5;
|
||||
if ((c & 0xfe) == 0xfc)
|
||||
return 6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* decode one unicode char */
|
||||
int utf8_encoded_to_unichar(const char *str) {
|
||||
int unichar, len, i;
|
||||
|
||||
assert(str);
|
||||
|
||||
len = utf8_encoded_expected_len(str);
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
return (int)str[0];
|
||||
case 2:
|
||||
unichar = str[0] & 0x1f;
|
||||
break;
|
||||
case 3:
|
||||
unichar = (int)str[0] & 0x0f;
|
||||
break;
|
||||
case 4:
|
||||
unichar = (int)str[0] & 0x07;
|
||||
break;
|
||||
case 5:
|
||||
unichar = (int)str[0] & 0x03;
|
||||
break;
|
||||
case 6:
|
||||
unichar = (int)str[0] & 0x01;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 1; i < len; i++) {
|
||||
if (((int)str[i] & 0xc0) != 0x80)
|
||||
return -EINVAL;
|
||||
unichar <<= 6;
|
||||
unichar |= (int)str[i] & 0x3f;
|
||||
}
|
||||
|
||||
return unichar;
|
||||
}
|
||||
|
||||
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
|
||||
const uint8_t *p;
|
||||
|
||||
assert(str);
|
||||
|
||||
for (p = (const uint8_t*) str; length;) {
|
||||
int encoded_len, val;
|
||||
|
||||
encoded_len = utf8_encoded_valid_unichar((const char *) p);
|
||||
val = utf8_encoded_to_unichar((const char*) p);
|
||||
|
||||
if (encoded_len < 0 ||
|
||||
val < 0 ||
|
||||
is_unicode_control(val) ||
|
||||
(!newline && val == '\n'))
|
||||
return false;
|
||||
|
||||
length -= encoded_len;
|
||||
p += encoded_len;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *utf8_is_valid(const char *str) {
|
||||
const uint8_t *p;
|
||||
|
||||
assert(str);
|
||||
|
||||
for (p = (const uint8_t*) str; *p; ) {
|
||||
int len;
|
||||
|
||||
len = utf8_encoded_valid_unichar((const char *)p);
|
||||
if (len < 0)
|
||||
return NULL;
|
||||
|
||||
p += len;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char *utf8_escape_invalid(const char *str) {
|
||||
char *p, *s;
|
||||
|
||||
assert(str);
|
||||
|
||||
p = s = malloc(strlen(str) * 4 + 1);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
while (*str) {
|
||||
int len;
|
||||
|
||||
len = utf8_encoded_valid_unichar(str);
|
||||
if (len > 0) {
|
||||
s = mempcpy(s, str, len);
|
||||
str += len;
|
||||
} else {
|
||||
s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER));
|
||||
str += 1;
|
||||
}
|
||||
}
|
||||
|
||||
*s = '\0';
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
char *ascii_is_valid(const char *str) {
|
||||
const char *p;
|
||||
|
||||
assert(str);
|
||||
|
||||
for (p = str; *p; p++)
|
||||
if ((unsigned char) *p >= 128)
|
||||
return NULL;
|
||||
|
||||
return (char*) str;
|
||||
}
|
||||
|
||||
char *utf16_to_utf8(const void *s, size_t length) {
|
||||
char *r;
|
||||
const uint8_t *f;
|
||||
uint8_t *t;
|
||||
|
||||
r = new(char, (length*3+1)/2 + 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
t = (uint8_t*) r;
|
||||
|
||||
for (f = s; f < (const uint8_t*) s + length; f += 2) {
|
||||
uint16_t c;
|
||||
|
||||
c = (f[1] << 8) | f[0];
|
||||
|
||||
if (c == 0) {
|
||||
*t = 0;
|
||||
return r;
|
||||
} else if (c < 0x80) {
|
||||
*(t++) = (uint8_t) c;
|
||||
} else if (c < 0x800) {
|
||||
*(t++) = (uint8_t) (0xc0 | (c >> 6));
|
||||
*(t++) = (uint8_t) (0x80 | (c & 0x3f));
|
||||
} else {
|
||||
*(t++) = (uint8_t) (0xe0 | (c >> 12));
|
||||
*(t++) = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
|
||||
*(t++) = (uint8_t) (0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
*t = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* expected size used to encode one unicode char */
|
||||
static int utf8_unichar_to_encoded_len(int unichar) {
|
||||
|
||||
if (unichar < 0x80)
|
||||
return 1;
|
||||
if (unichar < 0x800)
|
||||
return 2;
|
||||
if (unichar < 0x10000)
|
||||
return 3;
|
||||
if (unichar < 0x200000)
|
||||
return 4;
|
||||
if (unichar < 0x4000000)
|
||||
return 5;
|
||||
|
||||
return 6;
|
||||
}
|
||||
|
||||
/* validate one encoded unicode char and return its length */
|
||||
int utf8_encoded_valid_unichar(const char *str) {
|
||||
int len, unichar, i;
|
||||
|
||||
assert(str);
|
||||
|
||||
len = utf8_encoded_expected_len(str);
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* ascii is valid */
|
||||
if (len == 1)
|
||||
return 1;
|
||||
|
||||
/* check if expected encoded chars are available */
|
||||
for (i = 0; i < len; i++)
|
||||
if ((str[i] & 0x80) != 0x80)
|
||||
return -EINVAL;
|
||||
|
||||
unichar = utf8_encoded_to_unichar(str);
|
||||
|
||||
/* check if encoded length matches encoded value */
|
||||
if (utf8_unichar_to_encoded_len(unichar) != len)
|
||||
return -EINVAL;
|
||||
|
||||
/* check if value has valid range */
|
||||
if (!is_unicode_valid(unichar))
|
||||
return -EINVAL;
|
||||
|
||||
return len;
|
||||
}
|
||||
42
src/dhcp-manager/systemd-dhcp/src/shared/utf8.h
Normal file
42
src/dhcp-manager/systemd-dhcp/src/shared/utf8.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2012 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <stdbool.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd"
|
||||
|
||||
const char *utf8_is_valid(const char *s) _pure_;
|
||||
char *ascii_is_valid(const char *s) _pure_;
|
||||
char *utf8_escape_invalid(const char *s);
|
||||
|
||||
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_;
|
||||
_pure_ static inline bool utf8_is_printable(const char* str, size_t length) {
|
||||
return utf8_is_printable_newline(str, length, true);
|
||||
}
|
||||
|
||||
char *utf16_to_utf8(const void *s, size_t length);
|
||||
|
||||
int utf8_encoded_valid_unichar(const char *str);
|
||||
int utf8_encoded_to_unichar(const char *str);
|
||||
7242
src/dhcp-manager/systemd-dhcp/src/shared/util.c
Normal file
7242
src/dhcp-manager/systemd-dhcp/src/shared/util.c
Normal file
File diff suppressed because it is too large
Load diff
1011
src/dhcp-manager/systemd-dhcp/src/shared/util.h
Normal file
1011
src/dhcp-manager/systemd-dhcp/src/shared/util.h
Normal file
File diff suppressed because it is too large
Load diff
78
src/dhcp-manager/systemd-dhcp/src/systemd/_sd-common.h
Normal file
78
src/dhcp-manager/systemd-dhcp/src/systemd/_sd-common.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosdcommonhfoo
|
||||
#define foosdcommonhfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
/* This is a private header; never even think of including this directly! */
|
||||
|
||||
#if __INCLUDE_LEVEL__ <= 1
|
||||
#error "Do not include _sd-common.h directly; it is a private header."
|
||||
#endif
|
||||
|
||||
#ifndef _sd_printf_
|
||||
# if __GNUC__ >= 4
|
||||
# define _sd_printf_(a,b) __attribute__ ((format (printf, a, b)))
|
||||
# else
|
||||
# define _sd_printf_(a,b)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _sd_sentinel_
|
||||
# define _sd_sentinel_ __attribute__((sentinel))
|
||||
#endif
|
||||
|
||||
#ifndef _sd_packed_
|
||||
# define _sd_packed_ __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#ifndef _sd_pure_
|
||||
# define _sd_pure_ __attribute__((pure))
|
||||
#endif
|
||||
|
||||
#ifndef _SD_STRINGIFY
|
||||
# define _SD_XSTRINGIFY(x) #x
|
||||
# define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x)
|
||||
#endif
|
||||
|
||||
#ifndef _SD_BEGIN_DECLARATIONS
|
||||
# ifdef __cplusplus
|
||||
# define _SD_BEGIN_DECLARATIONS \
|
||||
extern "C" { \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
# else
|
||||
# define _SD_BEGIN_DECLARATIONS \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _SD_END_DECLARATIONS
|
||||
# ifdef __cplusplus
|
||||
# define _SD_END_DECLARATIONS \
|
||||
} \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
# else
|
||||
# define _SD_END_DECLARATIONS \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
76
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h
Normal file
76
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosddhcpclienthfoo
|
||||
#define foosddhcpclienthfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <netinet/in.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
#include "sd-dhcp-lease.h"
|
||||
|
||||
enum {
|
||||
DHCP_EVENT_STOP = 0,
|
||||
DHCP_EVENT_IP_ACQUIRE = 1,
|
||||
DHCP_EVENT_IP_CHANGE = 2,
|
||||
DHCP_EVENT_EXPIRED = 3,
|
||||
DHCP_EVENT_RENEW = 4,
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp_client sd_dhcp_client;
|
||||
|
||||
typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event,
|
||||
void *userdata);
|
||||
int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
|
||||
void *userdata);
|
||||
|
||||
|
||||
int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option);
|
||||
int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
|
||||
const struct in_addr *last_address);
|
||||
int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast);
|
||||
int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index);
|
||||
int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
|
||||
size_t addr_len, uint16_t arp_type);
|
||||
int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
|
||||
const uint8_t *data, size_t data_len);
|
||||
const uint8_t *sd_dhcp_client_get_client_id(sd_dhcp_client *client,
|
||||
uint8_t *type,
|
||||
size_t *len);
|
||||
int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu);
|
||||
int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname);
|
||||
int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci);
|
||||
int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret);
|
||||
|
||||
int sd_dhcp_client_stop(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_start(sd_dhcp_client *client);
|
||||
|
||||
sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);
|
||||
sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client);
|
||||
|
||||
int sd_dhcp_client_new(sd_dhcp_client **ret);
|
||||
|
||||
int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority);
|
||||
int sd_dhcp_client_detach_event(sd_dhcp_client *client);
|
||||
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
|
||||
|
||||
#endif
|
||||
54
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h
Normal file
54
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosddhcpleasehfoo
|
||||
#define foosddhcpleasehfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
Copyright (C) 2014 Tom Gundersen
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <netinet/in.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
typedef struct sd_dhcp_lease sd_dhcp_lease;
|
||||
struct sd_dhcp_route;
|
||||
|
||||
sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease);
|
||||
sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease);
|
||||
|
||||
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime);
|
||||
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu);
|
||||
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
|
||||
int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
|
||||
int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
|
||||
int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn);
|
||||
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
|
||||
size_t *client_id_len);
|
||||
|
||||
int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
|
||||
int sd_dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret);
|
||||
|
||||
#endif
|
||||
66
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h
Normal file
66
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosddhcp6clienthfoo
|
||||
#define foosddhcp6clienthfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <net/ethernet.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "sd-dhcp6-lease.h"
|
||||
|
||||
enum {
|
||||
DHCP6_EVENT_STOP = 0,
|
||||
DHCP6_EVENT_RESEND_EXPIRE = 10,
|
||||
DHCP6_EVENT_RETRANS_MAX = 11,
|
||||
DHCP6_EVENT_IP_ACQUIRE = 12,
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp6_client sd_dhcp6_client;
|
||||
|
||||
typedef void (*sd_dhcp6_client_cb_t)(sd_dhcp6_client *client, int event,
|
||||
void *userdata);
|
||||
int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
|
||||
sd_dhcp6_client_cb_t cb, void *userdata);
|
||||
|
||||
int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
|
||||
int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
|
||||
size_t addr_len, uint16_t arp_type);
|
||||
int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
|
||||
size_t duid_len);
|
||||
int sd_dhcp6_client_set_ifname(sd_dhcp6_client *client, const char *ifname);
|
||||
int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
|
||||
uint16_t option);
|
||||
|
||||
int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret);
|
||||
|
||||
int sd_dhcp6_client_stop(sd_dhcp6_client *client);
|
||||
int sd_dhcp6_client_start(sd_dhcp6_client *client);
|
||||
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
|
||||
int priority);
|
||||
int sd_dhcp6_client_detach_event(sd_dhcp6_client *client);
|
||||
sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client);
|
||||
sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);
|
||||
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client);
|
||||
int sd_dhcp6_client_new(sd_dhcp6_client **ret);
|
||||
|
||||
#endif
|
||||
42
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h
Normal file
42
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosddhcp6leasehfoo
|
||||
#define foosddhcp6leasehfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Tom Gundersen
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <netinet/in.h>
|
||||
|
||||
typedef struct sd_dhcp6_lease sd_dhcp6_lease;
|
||||
|
||||
int sd_dhcp6_lease_get_first_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid);
|
||||
int sd_dhcp6_lease_get_next_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid);
|
||||
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease);
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
|
||||
|
||||
#endif
|
||||
135
src/dhcp-manager/systemd-dhcp/src/systemd/sd-event.h
Normal file
135
src/dhcp-manager/systemd-dhcp/src/systemd/sd-event.h
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosdeventhfoo
|
||||
#define foosdeventhfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <sys/types.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
/*
|
||||
Why is this better than pure epoll?
|
||||
|
||||
- Supports event source prioritization
|
||||
- Scales better with a large number of time events because it does not require one timerfd each
|
||||
- Automatically tries to coalesce timer events system-wide
|
||||
- Handles signals and child PIDs
|
||||
*/
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_event sd_event;
|
||||
typedef struct sd_event_source sd_event_source;
|
||||
|
||||
enum {
|
||||
SD_EVENT_OFF = 0,
|
||||
SD_EVENT_ON = 1,
|
||||
SD_EVENT_ONESHOT = -1
|
||||
};
|
||||
|
||||
enum {
|
||||
SD_EVENT_PASSIVE,
|
||||
SD_EVENT_PREPARED,
|
||||
SD_EVENT_PENDING,
|
||||
SD_EVENT_RUNNING,
|
||||
SD_EVENT_EXITING,
|
||||
SD_EVENT_FINISHED
|
||||
};
|
||||
|
||||
enum {
|
||||
/* And everything in-between and outside is good too */
|
||||
SD_EVENT_PRIORITY_IMPORTANT = -100,
|
||||
SD_EVENT_PRIORITY_NORMAL = 0,
|
||||
SD_EVENT_PRIORITY_IDLE = 100
|
||||
};
|
||||
|
||||
typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata);
|
||||
typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata);
|
||||
typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata);
|
||||
typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata);
|
||||
typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata);
|
||||
|
||||
int sd_event_default(sd_event **e);
|
||||
|
||||
int sd_event_new(sd_event **e);
|
||||
sd_event* sd_event_ref(sd_event *e);
|
||||
sd_event* sd_event_unref(sd_event *e);
|
||||
|
||||
int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata);
|
||||
int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata);
|
||||
int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata);
|
||||
int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata);
|
||||
int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
|
||||
int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
|
||||
int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
|
||||
|
||||
int sd_event_prepare(sd_event *e);
|
||||
int sd_event_wait(sd_event *e, uint64_t timeout);
|
||||
int sd_event_dispatch(sd_event *e);
|
||||
int sd_event_run(sd_event *e, uint64_t timeout);
|
||||
int sd_event_loop(sd_event *e);
|
||||
int sd_event_exit(sd_event *e, int code);
|
||||
|
||||
int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec);
|
||||
|
||||
int sd_event_get_fd(sd_event *e);
|
||||
int sd_event_get_state(sd_event *e);
|
||||
int sd_event_get_tid(sd_event *e, pid_t *tid);
|
||||
int sd_event_get_exit_code(sd_event *e, int *code);
|
||||
int sd_event_set_watchdog(sd_event *e, int b);
|
||||
int sd_event_get_watchdog(sd_event *e);
|
||||
|
||||
sd_event_source* sd_event_source_ref(sd_event_source *s);
|
||||
sd_event_source* sd_event_source_unref(sd_event_source *s);
|
||||
|
||||
sd_event *sd_event_source_get_event(sd_event_source *s);
|
||||
void* sd_event_source_get_userdata(sd_event_source *s);
|
||||
void* sd_event_source_set_userdata(sd_event_source *s, void *userdata);
|
||||
|
||||
int sd_event_source_set_name(sd_event_source *s, const char *name);
|
||||
int sd_event_source_get_name(sd_event_source *s, const char **name);
|
||||
int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback);
|
||||
int sd_event_source_get_pending(sd_event_source *s);
|
||||
int sd_event_source_get_priority(sd_event_source *s, int64_t *priority);
|
||||
int sd_event_source_set_priority(sd_event_source *s, int64_t priority);
|
||||
int sd_event_source_get_enabled(sd_event_source *s, int *enabled);
|
||||
int sd_event_source_set_enabled(sd_event_source *s, int enabled);
|
||||
int sd_event_source_get_io_fd(sd_event_source *s);
|
||||
int sd_event_source_set_io_fd(sd_event_source *s, int fd);
|
||||
int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events);
|
||||
int sd_event_source_set_io_events(sd_event_source *s, uint32_t events);
|
||||
int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents);
|
||||
int sd_event_source_get_time(sd_event_source *s, uint64_t *usec);
|
||||
int sd_event_source_set_time(sd_event_source *s, uint64_t usec);
|
||||
int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec);
|
||||
int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec);
|
||||
int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock);
|
||||
int sd_event_source_get_signal(sd_event_source *s);
|
||||
int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
113
src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h
Normal file
113
src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosdid128hfoo
|
||||
#define foosdid128hfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
/* 128-bit ID APIs. See sd-id128(3) for more information. */
|
||||
|
||||
typedef union sd_id128 sd_id128_t;
|
||||
|
||||
union sd_id128 {
|
||||
uint8_t bytes[16];
|
||||
uint64_t qwords[2];
|
||||
};
|
||||
|
||||
#define SD_ID128_STRING_MAX 33
|
||||
|
||||
char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]);
|
||||
|
||||
int sd_id128_from_string(const char *s, sd_id128_t *ret);
|
||||
|
||||
int sd_id128_randomize(sd_id128_t *ret);
|
||||
|
||||
int sd_id128_get_machine(sd_id128_t *ret);
|
||||
|
||||
int sd_id128_get_boot(sd_id128_t *ret);
|
||||
|
||||
#define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \
|
||||
((const sd_id128_t) { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \
|
||||
0x##v8, 0x##v9, 0x##v10, 0x##v11, 0x##v12, 0x##v13, 0x##v14, 0x##v15 }})
|
||||
|
||||
#define SD_ID128_ARRAY(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \
|
||||
{ .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \
|
||||
0x##v8, 0x##v9, 0x##v10, 0x##v11, 0x##v12, 0x##v13, 0x##v14, 0x##v15 }}
|
||||
|
||||
/* Note that SD_ID128_FORMAT_VAL will evaluate the passed argument 16
|
||||
* times. It is hence not a good idea to call this macro with an
|
||||
* expensive function as paramater or an expression with side
|
||||
* effects */
|
||||
|
||||
#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
|
||||
#define SD_ID128_FORMAT_VAL(x) (x).bytes[0], (x).bytes[1], (x).bytes[2], (x).bytes[3], (x).bytes[4], (x).bytes[5], (x).bytes[6], (x).bytes[7], (x).bytes[8], (x).bytes[9], (x).bytes[10], (x).bytes[11], (x).bytes[12], (x).bytes[13], (x).bytes[14], (x).bytes[15]
|
||||
|
||||
#define SD_ID128_CONST_STR(x) \
|
||||
((const char[SD_ID128_STRING_MAX]) { \
|
||||
((x).bytes[0] >> 4) >= 10 ? 'a' + ((x).bytes[0] >> 4) - 10 : '0' + ((x).bytes[0] >> 4), \
|
||||
((x).bytes[0] & 15) >= 10 ? 'a' + ((x).bytes[0] & 15) - 10 : '0' + ((x).bytes[0] & 15), \
|
||||
((x).bytes[1] >> 4) >= 10 ? 'a' + ((x).bytes[1] >> 4) - 10 : '0' + ((x).bytes[1] >> 4), \
|
||||
((x).bytes[1] & 15) >= 10 ? 'a' + ((x).bytes[1] & 15) - 10 : '0' + ((x).bytes[1] & 15), \
|
||||
((x).bytes[2] >> 4) >= 10 ? 'a' + ((x).bytes[2] >> 4) - 10 : '0' + ((x).bytes[2] >> 4), \
|
||||
((x).bytes[2] & 15) >= 10 ? 'a' + ((x).bytes[2] & 15) - 10 : '0' + ((x).bytes[2] & 15), \
|
||||
((x).bytes[3] >> 4) >= 10 ? 'a' + ((x).bytes[3] >> 4) - 10 : '0' + ((x).bytes[3] >> 4), \
|
||||
((x).bytes[3] & 15) >= 10 ? 'a' + ((x).bytes[3] & 15) - 10 : '0' + ((x).bytes[3] & 15), \
|
||||
((x).bytes[4] >> 4) >= 10 ? 'a' + ((x).bytes[4] >> 4) - 10 : '0' + ((x).bytes[4] >> 4), \
|
||||
((x).bytes[4] & 15) >= 10 ? 'a' + ((x).bytes[4] & 15) - 10 : '0' + ((x).bytes[4] & 15), \
|
||||
((x).bytes[5] >> 4) >= 10 ? 'a' + ((x).bytes[5] >> 4) - 10 : '0' + ((x).bytes[5] >> 4), \
|
||||
((x).bytes[5] & 15) >= 10 ? 'a' + ((x).bytes[5] & 15) - 10 : '0' + ((x).bytes[5] & 15), \
|
||||
((x).bytes[6] >> 4) >= 10 ? 'a' + ((x).bytes[6] >> 4) - 10 : '0' + ((x).bytes[6] >> 4), \
|
||||
((x).bytes[6] & 15) >= 10 ? 'a' + ((x).bytes[6] & 15) - 10 : '0' + ((x).bytes[6] & 15), \
|
||||
((x).bytes[7] >> 4) >= 10 ? 'a' + ((x).bytes[7] >> 4) - 10 : '0' + ((x).bytes[7] >> 4), \
|
||||
((x).bytes[7] & 15) >= 10 ? 'a' + ((x).bytes[7] & 15) - 10 : '0' + ((x).bytes[7] & 15), \
|
||||
((x).bytes[8] >> 4) >= 10 ? 'a' + ((x).bytes[8] >> 4) - 10 : '0' + ((x).bytes[8] >> 4), \
|
||||
((x).bytes[8] & 15) >= 10 ? 'a' + ((x).bytes[8] & 15) - 10 : '0' + ((x).bytes[8] & 15), \
|
||||
((x).bytes[9] >> 4) >= 10 ? 'a' + ((x).bytes[9] >> 4) - 10 : '0' + ((x).bytes[9] >> 4), \
|
||||
((x).bytes[9] & 15) >= 10 ? 'a' + ((x).bytes[9] & 15) - 10 : '0' + ((x).bytes[9] & 15), \
|
||||
((x).bytes[10] >> 4) >= 10 ? 'a' + ((x).bytes[10] >> 4) - 10 : '0' + ((x).bytes[10] >> 4), \
|
||||
((x).bytes[10] & 15) >= 10 ? 'a' + ((x).bytes[10] & 15) - 10 : '0' + ((x).bytes[10] & 15), \
|
||||
((x).bytes[11] >> 4) >= 10 ? 'a' + ((x).bytes[11] >> 4) - 10 : '0' + ((x).bytes[11] >> 4), \
|
||||
((x).bytes[11] & 15) >= 10 ? 'a' + ((x).bytes[11] & 15) - 10 : '0' + ((x).bytes[11] & 15), \
|
||||
((x).bytes[12] >> 4) >= 10 ? 'a' + ((x).bytes[12] >> 4) - 10 : '0' + ((x).bytes[12] >> 4), \
|
||||
((x).bytes[12] & 15) >= 10 ? 'a' + ((x).bytes[12] & 15) - 10 : '0' + ((x).bytes[12] & 15), \
|
||||
((x).bytes[13] >> 4) >= 10 ? 'a' + ((x).bytes[13] >> 4) - 10 : '0' + ((x).bytes[13] >> 4), \
|
||||
((x).bytes[13] & 15) >= 10 ? 'a' + ((x).bytes[13] & 15) - 10 : '0' + ((x).bytes[13] & 15), \
|
||||
((x).bytes[14] >> 4) >= 10 ? 'a' + ((x).bytes[14] >> 4) - 10 : '0' + ((x).bytes[14] >> 4), \
|
||||
((x).bytes[14] & 15) >= 10 ? 'a' + ((x).bytes[14] & 15) - 10 : '0' + ((x).bytes[14] & 15), \
|
||||
((x).bytes[15] >> 4) >= 10 ? 'a' + ((x).bytes[15] >> 4) - 10 : '0' + ((x).bytes[15] >> 4), \
|
||||
((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \
|
||||
0 })
|
||||
|
||||
_sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
|
||||
return memcmp(&a, &b, 16) == 0;
|
||||
}
|
||||
|
||||
#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }})
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
|
@ -13,7 +13,7 @@ AM_CPPFLAGS = \
|
|||
|
||||
noinst_PROGRAMS = \
|
||||
test-dhcp-dhclient \
|
||||
test-dhcp-options
|
||||
test-dhcp-utils
|
||||
|
||||
####### dhclient leases test #######
|
||||
|
||||
|
|
@ -23,17 +23,17 @@ test_dhcp_dhclient_SOURCES = \
|
|||
test_dhcp_dhclient_LDADD = \
|
||||
$(top_builddir)/src/libNetworkManager.la
|
||||
|
||||
####### DHCP options test #######
|
||||
####### DHCP utils test #######
|
||||
|
||||
test_dhcp_options_SOURCES = \
|
||||
test-dhcp-options.c
|
||||
test_dhcp_utils_SOURCES = \
|
||||
test-dhcp-utils.c
|
||||
|
||||
test_dhcp_options_LDADD = \
|
||||
test_dhcp_utils_LDADD = \
|
||||
$(top_builddir)/src/libNetworkManager.la
|
||||
|
||||
#################################
|
||||
|
||||
TESTS = test-dhcp-dhclient test-dhcp-options
|
||||
TESTS = test-dhcp-dhclient test-dhcp-utils
|
||||
|
||||
EXTRA_DIST = \
|
||||
test-dhclient-duid.leases \
|
||||
|
|
|
|||
|
|
@ -652,6 +652,42 @@ test_ip4_prefix_classless (void)
|
|||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
#define COMPARE_ID(src, is_str, expected, expected_len) \
|
||||
G_STMT_START { \
|
||||
gs_unref_bytes GBytes *b = NULL; \
|
||||
gconstpointer p; \
|
||||
gsize l; \
|
||||
\
|
||||
b = nm_dhcp_utils_client_id_string_to_bytes (src); \
|
||||
g_assert (b); \
|
||||
p = g_bytes_get_data (b, &l); \
|
||||
if (is_str) { \
|
||||
g_assert_cmpint (l, ==, expected_len + 1); \
|
||||
g_assert_cmpint (((const char *) p)[0], ==, 0); \
|
||||
g_assert (memcmp (p + 1, expected, expected_len) == 0); \
|
||||
} else { \
|
||||
g_assert_cmpint (l, ==, expected_len); \
|
||||
g_assert (memcmp (p, expected, expected_len) == 0); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
static void
|
||||
test_client_id_from_string (void)
|
||||
{
|
||||
const char *nothex = "asdfasdfasdfasdfasdfasdfasdf";
|
||||
const char *allhex = "00:11:22:33:4:55:66:77:88";
|
||||
const guint8 allhex_bin[] = { 0x00, 0x11, 0x22, 0x33, 0x04, 0x55, 0x66, 0x77, 0x88 };
|
||||
const char *somehex = "00:11:22:33:44:55:asdfasdfasdf:99:10";
|
||||
const char *nocolons = "0011223344559910";
|
||||
const char *endcolon = "00:11:22:33:44:55:";
|
||||
|
||||
COMPARE_ID (nothex, TRUE, nothex, strlen (nothex));
|
||||
COMPARE_ID (allhex, FALSE, allhex_bin, sizeof (allhex_bin));
|
||||
COMPARE_ID (somehex, TRUE, somehex, strlen (somehex));
|
||||
COMPARE_ID (nocolons, TRUE, nocolons, strlen (nocolons));
|
||||
COMPARE_ID (endcolon, TRUE, endcolon, strlen (endcolon));
|
||||
}
|
||||
|
||||
NMTST_DEFINE ();
|
||||
|
||||
int main (int argc, char **argv)
|
||||
|
|
@ -678,6 +714,7 @@ int main (int argc, char **argv)
|
|||
g_test_add_func ("/dhcp/ip4-missing-prefix-16", test_ip4_missing_prefix_16);
|
||||
g_test_add_func ("/dhcp/ip4-missing-prefix-8", test_ip4_missing_prefix_8);
|
||||
g_test_add_func ("/dhcp/ip4-prefix-classless", test_ip4_prefix_classless);
|
||||
g_test_add_func ("/dhcp/client-id-from-string", test_client_id_from_string);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue