mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-26 14:40:08 +01:00
dhcp: merge branch 'th/systemd-no-dhcp4'
https://bugzilla.redhat.com/show_bug.cgi?id=2073067 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1188
This commit is contained in:
commit
e05f439ff4
30 changed files with 488 additions and 6729 deletions
17
Makefile.am
17
Makefile.am
|
|
@ -2333,8 +2333,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/nm-sd-utils-core.h \
|
||||
src/libnm-systemd-core/nm-sd.c \
|
||||
src/libnm-systemd-core/nm-sd.h \
|
||||
src/libnm-systemd-core/nm-sd-utils-dhcp.h \
|
||||
src/libnm-systemd-core/nm-sd-utils-dhcp.c \
|
||||
src/libnm-systemd-core/sd-adapt-core/condition.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/conf-parser.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/device-util.h \
|
||||
|
|
@ -2345,16 +2343,8 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/sd-adapt-core/sd-daemon.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/sd-device.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/udev-util.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/arp-util.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/arp-util.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c \
|
||||
|
|
@ -2369,10 +2359,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/src/libsystemd-network/lldp-rx-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/network-common.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/network-common.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/network-internal.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/network-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c \
|
||||
|
|
@ -2384,9 +2370,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h \
|
||||
src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c \
|
||||
src/libnm-systemd-core/src/systemd/_sd-common.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp-client.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp-option.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h \
|
||||
|
|
|
|||
3
NEWS
3
NEWS
|
|
@ -8,6 +8,9 @@ subject to change and not guaranteed to be compatible with
|
|||
the later release.
|
||||
USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
|
||||
|
||||
* Drop unused, internal systemd DHCPv4 client. This is long
|
||||
replaced by nettools' n-dhcp4 implementation.
|
||||
|
||||
=============================================
|
||||
NetworkManager-1.38
|
||||
Overview of changes since NetworkManager-1.36
|
||||
|
|
|
|||
|
|
@ -13,22 +13,24 @@
|
|||
#include <ctype.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include "libnm-glib-aux/nm-dedup-multi.h"
|
||||
#include "libnm-std-aux/unaligned.h"
|
||||
#include "libnm-glib-aux/nm-str-buf.h"
|
||||
#include "n-dhcp4/src/n-dhcp4.h"
|
||||
|
||||
#include "libnm-glib-aux/nm-dedup-multi.h"
|
||||
#include "libnm-glib-aux/nm-io-utils.h"
|
||||
#include "libnm-glib-aux/nm-str-buf.h"
|
||||
#include "libnm-std-aux/unaligned.h"
|
||||
|
||||
#include "nm-l3-config-data.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-config.h"
|
||||
#include "nm-dhcp-utils.h"
|
||||
#include "nm-dhcp-options.h"
|
||||
#include "nm-core-utils.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "libnm-platform/nm-platform.h"
|
||||
#include "nm-config.h"
|
||||
#include "nm-core-utils.h"
|
||||
#include "nm-dhcp-client-logging.h"
|
||||
#include "n-dhcp4/src/n-dhcp4.h"
|
||||
#include "nm-dhcp-options.h"
|
||||
#include "nm-dhcp-utils.h"
|
||||
#include "nm-l3-config-data.h"
|
||||
#include "nm-utils.h"
|
||||
|
||||
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
|
||||
#include "libnm-systemd-core/nm-sd-utils-dhcp.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -1110,18 +1112,20 @@ ip4_start(NMDhcpClient *client, GError **error)
|
|||
if (client_config->v4.last_address)
|
||||
inet_pton(AF_INET, client_config->v4.last_address, &last_addr);
|
||||
else {
|
||||
/*
|
||||
* TODO: we stick to the systemd-networkd lease file format. Quite easy for now to
|
||||
* just use the functions in systemd code. Anyway, as in the end we just use the
|
||||
* ip address from all the options found in the lease, write a function that parses
|
||||
* the lease file just for the assigned address and returns it in &last_address.
|
||||
* Then drop reference to systemd-networkd structures and functions.
|
||||
*/
|
||||
nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
|
||||
gs_free char *contents = NULL;
|
||||
gs_free char *s_addr = NULL;
|
||||
|
||||
dhcp_lease_load(&lease, lease_file);
|
||||
if (lease)
|
||||
sd_dhcp_lease_get_address(lease, &last_addr);
|
||||
nm_utils_file_get_contents(-1,
|
||||
lease_file,
|
||||
64 * 1024,
|
||||
NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
|
||||
&contents,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
nm_parse_env_file(contents, "ADDRESS", &s_addr);
|
||||
if (s_addr)
|
||||
nm_utils_parse_inaddr_bin(AF_INET, s_addr, NULL, &last_addr);
|
||||
}
|
||||
|
||||
if (last_addr.s_addr) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
#include "libnm-platform/nm-platform.h"
|
||||
#include "nm-dhcp-client-logging.h"
|
||||
#include "libnm-systemd-core/nm-sd.h"
|
||||
#include "libnm-systemd-core/nm-sd-utils-dhcp.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -47,7 +46,6 @@ static GType nm_dhcp_systemd_get_type(void);
|
|||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
sd_dhcp_client *client4;
|
||||
sd_dhcp6_client *client6;
|
||||
char *lease_file;
|
||||
|
||||
|
|
@ -69,675 +67,6 @@ G_DEFINE_TYPE(NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static NML3ConfigData *
|
||||
lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
||||
const char *iface,
|
||||
int ifindex,
|
||||
sd_dhcp_lease *lease,
|
||||
GError **error)
|
||||
{
|
||||
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
|
||||
gs_unref_hashtable GHashTable *options = NULL;
|
||||
const struct in_addr *addr_list;
|
||||
char addr_str[NM_UTILS_INET_ADDRSTRLEN];
|
||||
const char *s;
|
||||
nm_auto_free_gstring GString *str = NULL;
|
||||
nm_auto_free sd_dhcp_route **routes_static = NULL;
|
||||
nm_auto_free sd_dhcp_route **routes_classless = NULL;
|
||||
const char *const *search_domains = NULL;
|
||||
guint32 default_route_metric_offset;
|
||||
guint16 mtu;
|
||||
int i;
|
||||
int num;
|
||||
int is_classless;
|
||||
int n_routes_static;
|
||||
int n_routes_classless;
|
||||
const void *data;
|
||||
gsize data_len;
|
||||
gboolean has_router_from_classless = FALSE;
|
||||
const gint32 ts = nm_utils_get_monotonic_timestamp_sec();
|
||||
gint64 ts_time = time(NULL);
|
||||
struct in_addr a_address;
|
||||
struct in_addr a_netmask;
|
||||
struct in_addr a_next_server;
|
||||
struct in_addr server_id;
|
||||
struct in_addr broadcast;
|
||||
const struct in_addr *a_router;
|
||||
guint32 a_plen;
|
||||
guint32 a_lifetime;
|
||||
guint32 renewal;
|
||||
guint32 rebinding;
|
||||
gs_free nm_sd_dhcp_option *private_options = NULL;
|
||||
|
||||
nm_assert(lease != NULL);
|
||||
|
||||
if (sd_dhcp_lease_get_address(lease, &a_address) < 0) {
|
||||
nm_utils_error_set_literal(error,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"could not get address from lease");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_netmask(lease, &a_netmask) < 0) {
|
||||
nm_utils_error_set_literal(error,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"could not get netmask from lease");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_lifetime(lease, &a_lifetime) < 0) {
|
||||
nm_utils_error_set_literal(error,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"could not get lifetime from lease");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP);
|
||||
|
||||
options = nm_dhcp_option_create_options_dict();
|
||||
|
||||
_nm_utils_inet4_ntop(a_address.s_addr, addr_str);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, addr_str);
|
||||
|
||||
a_plen = nm_utils_ip4_netmask_to_prefix(a_netmask.s_addr);
|
||||
nm_dhcp_option_add_option(options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_SUBNET_MASK,
|
||||
_nm_utils_inet4_ntop(a_netmask.s_addr, addr_str));
|
||||
|
||||
nm_dhcp_option_add_option_u64(options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME,
|
||||
a_lifetime);
|
||||
nm_dhcp_option_add_option_u64(options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_NM_EXPIRY,
|
||||
(guint64) (ts_time + a_lifetime));
|
||||
|
||||
if (sd_dhcp_lease_get_next_server(lease, &a_next_server) == 0) {
|
||||
_nm_utils_inet4_ntop(a_next_server.s_addr, addr_str);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, addr_str);
|
||||
}
|
||||
|
||||
nm_l3_config_data_add_address_4(l3cd,
|
||||
&((const NMPlatformIP4Address){
|
||||
.address = a_address.s_addr,
|
||||
.peer_address = a_address.s_addr,
|
||||
.plen = a_plen,
|
||||
.addr_source = NM_IP_CONFIG_SOURCE_DHCP,
|
||||
.timestamp = ts,
|
||||
.lifetime = a_lifetime,
|
||||
.preferred = a_lifetime,
|
||||
}));
|
||||
|
||||
if (sd_dhcp_lease_get_server_identifier(lease, &server_id) >= 0) {
|
||||
_nm_utils_inet4_ntop(server_id.s_addr, addr_str);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_SERVER_ID, addr_str);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_broadcast(lease, &broadcast) >= 0) {
|
||||
_nm_utils_inet4_ntop(broadcast.s_addr, addr_str);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_BROADCAST, addr_str);
|
||||
}
|
||||
|
||||
num = sd_dhcp_lease_get_dns(lease, &addr_list);
|
||||
if (num > 0) {
|
||||
nm_gstring_prepare(&str);
|
||||
for (i = 0; i < num; i++) {
|
||||
_nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str);
|
||||
g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
|
||||
|
||||
if (addr_list[i].s_addr == 0 || nm_ip4_addr_is_localhost(addr_list[i].s_addr)) {
|
||||
/* Skip localhost addresses, like also networkd does.
|
||||
* See https://github.com/systemd/systemd/issues/4524. */
|
||||
continue;
|
||||
}
|
||||
nm_l3_config_data_add_nameserver(l3cd, AF_INET, &addr_list[i].s_addr);
|
||||
}
|
||||
nm_dhcp_option_add_option(options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER,
|
||||
str->str);
|
||||
}
|
||||
|
||||
num = sd_dhcp_lease_get_search_domains(lease, (char ***) &search_domains);
|
||||
if (num > 0) {
|
||||
nm_gstring_prepare(&str);
|
||||
for (i = 0; i < num; i++) {
|
||||
g_string_append(nm_gstring_add_space_delimiter(str), search_domains[i]);
|
||||
nm_l3_config_data_add_search(l3cd, AF_INET, search_domains[i]);
|
||||
}
|
||||
nm_dhcp_option_add_option(options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST,
|
||||
str->str);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_domainname(lease, &s) >= 0) {
|
||||
gs_strfreev char **domains = NULL;
|
||||
char **d;
|
||||
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, s);
|
||||
|
||||
/* Multiple domains sometimes stuffed into option 15 "Domain Name".
|
||||
* As systemd escapes such characters, split them at \\032. */
|
||||
domains = g_strsplit(s, "\\032", 0);
|
||||
for (d = domains; *d; d++)
|
||||
nm_l3_config_data_add_domain(l3cd, AF_INET, *d);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_hostname(lease, &s) >= 0) {
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_HOST_NAME, s);
|
||||
}
|
||||
|
||||
default_route_metric_offset = 0;
|
||||
n_routes_static = sd_dhcp_lease_get_static_routes(lease, &routes_static);
|
||||
n_routes_classless = sd_dhcp_lease_get_classless_routes(lease, &routes_classless);
|
||||
for (is_classless = 1; is_classless >= 0; is_classless--) {
|
||||
int n_routes = (is_classless ? n_routes_classless : n_routes_static);
|
||||
sd_dhcp_route *const *routes = (is_classless ? routes_classless : routes_static);
|
||||
|
||||
if (n_routes <= 0)
|
||||
continue;
|
||||
|
||||
nm_gstring_prepare(&str);
|
||||
|
||||
for (i = 0; i < n_routes; i++) {
|
||||
char network_net_str[NM_UTILS_INET_ADDRSTRLEN];
|
||||
char gateway_str[NM_UTILS_INET_ADDRSTRLEN];
|
||||
guint8 r_plen;
|
||||
struct in_addr r_network;
|
||||
struct in_addr r_gateway;
|
||||
in_addr_t network_net;
|
||||
guint32 m;
|
||||
|
||||
if (sd_dhcp_route_get_destination(routes[i], &r_network) < 0)
|
||||
continue;
|
||||
if (sd_dhcp_route_get_destination_prefix_length(routes[i], &r_plen) < 0 || r_plen > 32)
|
||||
continue;
|
||||
if (sd_dhcp_route_get_gateway(routes[i], &r_gateway) < 0)
|
||||
continue;
|
||||
|
||||
network_net = nm_utils_ip4_address_clear_host_address(r_network.s_addr, r_plen);
|
||||
_nm_utils_inet4_ntop(network_net, network_net_str);
|
||||
_nm_utils_inet4_ntop(r_gateway.s_addr, gateway_str);
|
||||
|
||||
g_string_append_printf(nm_gstring_add_space_delimiter(str),
|
||||
"%s/%d %s",
|
||||
network_net_str,
|
||||
(int) r_plen,
|
||||
gateway_str);
|
||||
|
||||
if (!is_classless && n_routes_classless > 0) {
|
||||
/* RFC 3443: if the DHCP server returns both a Classless Static Routes
|
||||
* option and a Static Routes option, the DHCP client MUST ignore the
|
||||
* Static Routes option. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r_plen == 0) {
|
||||
if (!is_classless) {
|
||||
/* for option 33 (static route), RFC 2132 says:
|
||||
*
|
||||
* The default route (0.0.0.0) is an illegal destination for a static
|
||||
* route. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if there are multiple default routes, we add them with differing
|
||||
* metrics. */
|
||||
m = default_route_metric_offset++;
|
||||
has_router_from_classless = TRUE;
|
||||
} else
|
||||
m = 0;
|
||||
|
||||
nm_l3_config_data_add_route_4(l3cd,
|
||||
&((const NMPlatformIP4Route){
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_DHCP,
|
||||
.network = network_net,
|
||||
.plen = r_plen,
|
||||
.gateway = r_gateway.s_addr,
|
||||
.pref_src = a_address.s_addr,
|
||||
.metric_any = TRUE,
|
||||
.metric = m,
|
||||
.table_any = TRUE,
|
||||
.table_coerced = 0,
|
||||
}));
|
||||
}
|
||||
|
||||
if (str->len > 0) {
|
||||
nm_dhcp_option_add_option(options,
|
||||
AF_INET,
|
||||
is_classless ? NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE
|
||||
: NM_DHCP_OPTION_DHCP4_STATIC_ROUTE,
|
||||
str->str);
|
||||
}
|
||||
}
|
||||
|
||||
num = sd_dhcp_lease_get_router(lease, &a_router);
|
||||
if (num > 0) {
|
||||
default_route_metric_offset = 0;
|
||||
|
||||
nm_gstring_prepare(&str);
|
||||
for (i = 0; i < num; i++) {
|
||||
guint32 m;
|
||||
|
||||
s = _nm_utils_inet4_ntop(a_router[i].s_addr, addr_str);
|
||||
g_string_append(nm_gstring_add_space_delimiter(str), s);
|
||||
|
||||
if (a_router[i].s_addr == 0) {
|
||||
/* silently skip 0.0.0.0 */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (has_router_from_classless) {
|
||||
/* If the DHCP server returns both a Classless Static Routes option and a
|
||||
* Router option, the DHCP client MUST ignore the Router option [RFC 3442].
|
||||
*
|
||||
* Be more lenient and ignore the Router option only if Classless Static
|
||||
* Routes contain a default gateway (as other DHCP backends do).
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if there are multiple default routes, we add them with differing
|
||||
* metrics. */
|
||||
m = default_route_metric_offset++;
|
||||
|
||||
nm_l3_config_data_add_route_4(l3cd,
|
||||
&((const NMPlatformIP4Route){
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_DHCP,
|
||||
.gateway = a_router[i].s_addr,
|
||||
.pref_src = a_address.s_addr,
|
||||
.table_any = TRUE,
|
||||
.table_coerced = 0,
|
||||
.metric_any = TRUE,
|
||||
.metric = m,
|
||||
}));
|
||||
}
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROUTER, str->str);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_mtu(lease, &mtu) >= 0 && mtu) {
|
||||
nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, mtu);
|
||||
nm_l3_config_data_set_mtu(l3cd, mtu);
|
||||
}
|
||||
|
||||
num = sd_dhcp_lease_get_ntp(lease, &addr_list);
|
||||
if (num > 0) {
|
||||
nm_gstring_prepare(&str);
|
||||
for (i = 0; i < num; i++) {
|
||||
_nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str);
|
||||
g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
|
||||
}
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NTP_SERVER, str->str);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_root_path(lease, &s) >= 0) {
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROOT_PATH, s);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_t1(lease, &renewal) >= 0) {
|
||||
nm_dhcp_option_add_option_u64(options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_RENEWAL_T1_TIME,
|
||||
renewal);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_t2(lease, &rebinding) >= 0) {
|
||||
nm_dhcp_option_add_option_u64(options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_REBINDING_T2_TIME,
|
||||
rebinding);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_timezone(lease, &s) >= 0) {
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE, s);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len) >= 0) {
|
||||
if (!!memmem(data, data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED")))
|
||||
nm_l3_config_data_set_metered(l3cd, TRUE);
|
||||
}
|
||||
|
||||
num = nm_sd_dhcp_lease_get_private_options(lease, &private_options);
|
||||
if (num > 0) {
|
||||
for (i = 0; i < num; i++) {
|
||||
guint8 code = private_options[i].code;
|
||||
const guint8 *l_data = private_options[i].data;
|
||||
gsize l_data_len = private_options[i].data_len;
|
||||
char *option_string;
|
||||
|
||||
if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY) {
|
||||
if (nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) {
|
||||
gs_free char *to_free = NULL;
|
||||
const char *escaped;
|
||||
|
||||
escaped =
|
||||
nm_utils_buf_utf8safe_escape((char *) l_data, l_data_len, 0, &to_free);
|
||||
nm_dhcp_option_add_option(options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY,
|
||||
escaped ?: "");
|
||||
|
||||
nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO);
|
||||
nm_l3_config_data_set_proxy_pac_url(l3cd, escaped ?: "");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE) {
|
||||
/* nettools and dhclient parse option 249 (Microsoft Classless Static Route)
|
||||
* as fallback for routes and ignores them from private options.
|
||||
*
|
||||
* The systemd plugin does not, and for consistency with nettools we
|
||||
* also don't expose it as private option either. */
|
||||
continue;
|
||||
}
|
||||
|
||||
option_string = nm_utils_bin2hexstr_full(l_data, l_data_len, ':', FALSE, NULL);
|
||||
nm_dhcp_option_take_option(options, AF_INET, code, option_string);
|
||||
}
|
||||
}
|
||||
|
||||
nm_dhcp_option_add_requests_to_options(options, AF_INET);
|
||||
|
||||
nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET, g_steal_pointer(&options));
|
||||
|
||||
return g_steal_pointer(&l3cd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
bound4_handle(NMDhcpSystemd *self, gboolean extended)
|
||||
{
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self);
|
||||
const char *iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self));
|
||||
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
|
||||
sd_dhcp_lease *lease = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
if (sd_dhcp_client_get_lease(priv->client4, &lease) < 0 || !lease) {
|
||||
_LOGW("no lease!");
|
||||
nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
_LOGD("lease available");
|
||||
|
||||
l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)),
|
||||
iface,
|
||||
nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)),
|
||||
lease,
|
||||
&error);
|
||||
if (!l3cd) {
|
||||
_LOGW("%s", error->message);
|
||||
g_clear_error(&error);
|
||||
nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
dhcp_lease_save(lease, priv->lease_file);
|
||||
|
||||
nm_dhcp_client_set_state(NM_DHCP_CLIENT(self),
|
||||
extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND,
|
||||
l3cd);
|
||||
}
|
||||
|
||||
static int
|
||||
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);
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
sd_dhcp_lease *lease = NULL;
|
||||
struct in_addr addr;
|
||||
int r;
|
||||
|
||||
nm_assert(priv->client4 == client);
|
||||
|
||||
_LOGD("client event %d", event);
|
||||
|
||||
switch (event) {
|
||||
case SD_DHCP_CLIENT_EVENT_EXPIRED:
|
||||
nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_EXPIRE, NULL);
|
||||
break;
|
||||
case SD_DHCP_CLIENT_EVENT_STOP:
|
||||
nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL);
|
||||
break;
|
||||
case SD_DHCP_CLIENT_EVENT_RENEW:
|
||||
case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
|
||||
bound4_handle(self, TRUE);
|
||||
break;
|
||||
case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
|
||||
bound4_handle(self, FALSE);
|
||||
break;
|
||||
case SD_DHCP_CLIENT_EVENT_SELECTING:
|
||||
r = sd_dhcp_client_get_lease(priv->client4, &lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = sd_dhcp_lease_get_server_identifier(lease, &addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (nm_dhcp_client_server_id_is_rejected(NM_DHCP_CLIENT(user_data), &addr)) {
|
||||
_LOGD("server-id %s is in the reject-list, ignoring",
|
||||
nm_utils_inet_ntop(AF_INET, &addr, addr_str));
|
||||
return -ENOMSG;
|
||||
}
|
||||
break;
|
||||
case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE:
|
||||
break;
|
||||
default:
|
||||
_LOGW("unhandled DHCP event %d", event);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_start(NMDhcpClient *client, GError **error)
|
||||
{
|
||||
nm_auto(sd_dhcp_client_unrefp) sd_dhcp_client *sd_client = NULL;
|
||||
NMDhcpSystemd *self = NM_DHCP_SYSTEMD(client);
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self);
|
||||
const NMDhcpClientConfig *client_config;
|
||||
gs_free char *lease_file = NULL;
|
||||
GBytes *hwaddr;
|
||||
const uint8_t *hwaddr_arr;
|
||||
gsize hwaddr_len;
|
||||
int arp_type;
|
||||
GBytes *client_id;
|
||||
gs_unref_bytes GBytes *client_id_new = NULL;
|
||||
GBytes *vendor_class_identifier;
|
||||
const uint8_t *client_id_arr;
|
||||
size_t client_id_len;
|
||||
struct in_addr last_addr = {0};
|
||||
const char *hostname;
|
||||
const char *mud_url;
|
||||
int r, i;
|
||||
GBytes *bcast_hwaddr;
|
||||
const uint8_t *bcast_hwaddr_arr;
|
||||
gsize bcast_hwaddr_len;
|
||||
|
||||
g_return_val_if_fail(!priv->client4, FALSE);
|
||||
g_return_val_if_fail(!priv->client6, FALSE);
|
||||
|
||||
client_config = nm_dhcp_client_get_config(client);
|
||||
|
||||
/* TODO: honor nm_dhcp_client_get_anycast_address() */
|
||||
|
||||
r = sd_dhcp_client_new(&sd_client, FALSE);
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to create dhcp-client: %s");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_LOGT("dhcp-client4: set " NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(sd_client));
|
||||
|
||||
r = sd_dhcp_client_attach_event(sd_client, NULL, 0);
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to attach event: %s");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hwaddr = client_config->hwaddr;
|
||||
if (!hwaddr || !(hwaddr_arr = g_bytes_get_data(hwaddr, &hwaddr_len))
|
||||
|| (arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len)) < 0) {
|
||||
nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bcast_hwaddr_arr = NULL;
|
||||
bcast_hwaddr = client_config->bcast_hwaddr;
|
||||
if (bcast_hwaddr) {
|
||||
bcast_hwaddr_arr = g_bytes_get_data(bcast_hwaddr, &bcast_hwaddr_len);
|
||||
if (bcast_hwaddr_len != hwaddr_len)
|
||||
bcast_hwaddr_arr = NULL;
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_set_mac(sd_client,
|
||||
hwaddr_arr,
|
||||
bcast_hwaddr_arr,
|
||||
hwaddr_len,
|
||||
(guint16) arp_type);
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to set MAC address: %s");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_set_ifindex(sd_client, nm_dhcp_client_get_ifindex(client));
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to set ifindex: %s");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nm_dhcp_utils_get_leasefile_path(AF_INET,
|
||||
"internal",
|
||||
client_config->iface,
|
||||
client_config->uuid,
|
||||
&lease_file);
|
||||
|
||||
if (client_config->v4.last_address)
|
||||
inet_pton(AF_INET, client_config->v4.last_address, &last_addr);
|
||||
else {
|
||||
nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
|
||||
|
||||
dhcp_lease_load(&lease, lease_file);
|
||||
if (lease)
|
||||
sd_dhcp_lease_get_address(lease, &last_addr);
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_set_request_broadcast(sd_client, client_config->v4.request_broadcast);
|
||||
nm_assert(r >= 0);
|
||||
|
||||
if (last_addr.s_addr) {
|
||||
r = sd_dhcp_client_set_request_address(sd_client, &last_addr);
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to set last IPv4 address: %s");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
client_id = client_config->client_id;
|
||||
if (!client_id) {
|
||||
client_id_new = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_arr, hwaddr_len);
|
||||
client_id = client_id_new;
|
||||
}
|
||||
|
||||
if (!(client_id_arr = g_bytes_get_data(client_id, &client_id_len)) || client_id_len < 2) {
|
||||
/* invalid client-ids are not expected. */
|
||||
nm_assert_not_reached();
|
||||
|
||||
nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Note that we always set a client-id. In particular for infiniband that is necessary,
|
||||
* see https://tools.ietf.org/html/rfc4390#section-2.1 . */
|
||||
r = sd_dhcp_client_set_client_id(sd_client,
|
||||
client_id_arr[0],
|
||||
client_id_arr + 1,
|
||||
NM_MIN(client_id_len - 1, _NM_MAX_CLIENT_ID_LEN));
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to set IPv4 client-id: %s");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Add requested options */
|
||||
for (i = 0; i < (int) G_N_ELEMENTS(_nm_dhcp_option_dhcp4_options); i++) {
|
||||
if (_nm_dhcp_option_dhcp4_options[i].include) {
|
||||
nm_assert(_nm_dhcp_option_dhcp4_options[i].option_num <= 255);
|
||||
r = sd_dhcp_client_set_request_option(sd_client,
|
||||
_nm_dhcp_option_dhcp4_options[i].option_num);
|
||||
nm_assert(r >= 0 || r == -EEXIST);
|
||||
}
|
||||
}
|
||||
|
||||
hostname = client_config->hostname;
|
||||
if (hostname) {
|
||||
/* FIXME: sd-dhcp decides which hostname/FQDN option to send (12 or 81)
|
||||
* only based on whether the hostname has a domain part or not. At the
|
||||
* moment there is no way to force one or another.
|
||||
*/
|
||||
r = sd_dhcp_client_set_hostname(sd_client, hostname);
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to set DHCP hostname: %s");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
mud_url = client_config->mud_url;
|
||||
if (mud_url) {
|
||||
r = sd_dhcp_client_set_mud_url(sd_client, mud_url);
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to set DHCP MUDURL: %s");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
vendor_class_identifier = client_config->vendor_class_identifier;
|
||||
if (vendor_class_identifier) {
|
||||
const char *option_data;
|
||||
gsize len;
|
||||
|
||||
option_data = g_bytes_get_data(vendor_class_identifier, &len);
|
||||
nm_assert(option_data);
|
||||
nm_assert(len <= 255);
|
||||
|
||||
option_data = nm_strndup_a(300, option_data, len, NULL);
|
||||
|
||||
r = sd_dhcp_client_set_vendor_class_identifier(sd_client, option_data);
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to set DHCP vendor class identifier: %s");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_set_callback(sd_client, dhcp_event_cb, client);
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to set callback: %s");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
priv->client4 = g_steal_pointer(&sd_client);
|
||||
|
||||
g_free(priv->lease_file);
|
||||
priv->lease_file = g_steal_pointer(&lease_file);
|
||||
|
||||
nm_dhcp_client_set_effective_client_id(client, client_id);
|
||||
|
||||
r = sd_dhcp_client_start(priv->client4);
|
||||
if (r < 0) {
|
||||
sd_dhcp_client_set_callback(priv->client4, NULL, NULL);
|
||||
nm_clear_pointer(&priv->client4, sd_dhcp_client_unref);
|
||||
nm_utils_error_set_errno(error, r, "failed to start DHCP client: %s");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static NML3ConfigData *
|
||||
lease_to_ip6_config(NMDedupMultiIndex *multi_idx,
|
||||
const char *iface,
|
||||
|
|
@ -945,7 +274,6 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
|
|||
GBytes *duid;
|
||||
gboolean prefix_delegation;
|
||||
|
||||
g_return_val_if_fail(!priv->client4, FALSE);
|
||||
g_return_val_if_fail(!priv->client6, FALSE);
|
||||
|
||||
client_config = nm_dhcp_client_get_config(client);
|
||||
|
|
@ -1073,18 +401,13 @@ stop(NMDhcpClient *client, gboolean release)
|
|||
|
||||
NM_DHCP_CLIENT_CLASS(nm_dhcp_systemd_parent_class)->stop(client, release);
|
||||
|
||||
_LOGT("dhcp-client%d: stop %p",
|
||||
priv->client4 ? '4' : '6',
|
||||
priv->client4 ? (gpointer) priv->client4 : (gpointer) priv->client6);
|
||||
_LOGT("dhcp-client6: stop");
|
||||
|
||||
if (priv->client4) {
|
||||
sd_dhcp_client_set_callback(priv->client4, NULL, NULL);
|
||||
r = sd_dhcp_client_stop(priv->client4);
|
||||
} else if (priv->client6) {
|
||||
sd_dhcp6_client_set_callback(priv->client6, NULL, NULL);
|
||||
r = sd_dhcp6_client_stop(priv->client6);
|
||||
}
|
||||
if (!priv->client6)
|
||||
return;
|
||||
|
||||
sd_dhcp6_client_set_callback(priv->client6, NULL, NULL);
|
||||
r = sd_dhcp6_client_stop(priv->client6);
|
||||
if (r)
|
||||
_LOGW("failed to stop client (%d)", r);
|
||||
}
|
||||
|
|
@ -1102,12 +425,6 @@ dispose(GObject *object)
|
|||
|
||||
nm_clear_g_free(&priv->lease_file);
|
||||
|
||||
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);
|
||||
|
|
@ -1125,14 +442,13 @@ nm_dhcp_systemd_class_init(NMDhcpSystemdClass *sdhcp_class)
|
|||
|
||||
object_class->dispose = dispose;
|
||||
|
||||
client_class->ip4_start = ip4_start;
|
||||
client_class->ip6_start = ip6_start;
|
||||
client_class->stop = stop;
|
||||
}
|
||||
|
||||
const NMDhcpClientFactory _nm_dhcp_client_factory_systemd = {
|
||||
.name = "systemd",
|
||||
.get_type_4 = nm_dhcp_systemd_get_type,
|
||||
.get_type_4 = nm_dhcp_nettools_get_type,
|
||||
.get_type_6 = nm_dhcp_systemd_get_type,
|
||||
.undocumented = TRUE,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,27 +12,6 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_dhcp_create(void)
|
||||
{
|
||||
sd_dhcp_client *client4 = NULL;
|
||||
int r;
|
||||
|
||||
r = sd_dhcp_client_new(&client4, FALSE);
|
||||
g_assert(r == 0);
|
||||
g_assert(client4);
|
||||
|
||||
if (/* never true */ client4 == (gpointer) &r) {
|
||||
/* we don't want to call this, but ensure that the linker
|
||||
* includes all these symbols. */
|
||||
sd_dhcp_client_start(client4);
|
||||
}
|
||||
|
||||
sd_dhcp_client_unref(client4);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_lldp_create(void)
|
||||
{
|
||||
|
|
@ -261,7 +240,6 @@ main(int argc, char **argv)
|
|||
{
|
||||
nmtst_init(&argc, &argv, TRUE);
|
||||
|
||||
g_test_add_func("/systemd/dhcp/create", test_dhcp_create);
|
||||
g_test_add_func("/systemd/lldp/create", test_lldp_create);
|
||||
g_test_add_func("/systemd/sd-event", test_sd_event);
|
||||
g_test_add_func("/systemd/test_path_equal", test_path_equal);
|
||||
|
|
|
|||
|
|
@ -723,3 +723,288 @@ nm_sd_notify(const char *state)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define SHELL_NEED_ESCAPE "\"\\`$"
|
||||
|
||||
int
|
||||
nm_parse_env_file_full(
|
||||
const char *contents,
|
||||
int (*push)(unsigned line, const char *key, const char *value, void *userdata),
|
||||
void *userdata)
|
||||
{
|
||||
gsize last_value_whitespace = G_MAXSIZE;
|
||||
gsize last_key_whitespace = G_MAXSIZE;
|
||||
nm_auto_str_buf NMStrBuf key = NM_STR_BUF_INIT(0, FALSE);
|
||||
nm_auto_str_buf NMStrBuf value = NM_STR_BUF_INIT(0, FALSE);
|
||||
unsigned line = 1;
|
||||
int r;
|
||||
enum {
|
||||
PRE_KEY,
|
||||
KEY,
|
||||
PRE_VALUE,
|
||||
VALUE,
|
||||
VALUE_ESCAPE,
|
||||
SINGLE_QUOTE_VALUE,
|
||||
DOUBLE_QUOTE_VALUE,
|
||||
DOUBLE_QUOTE_VALUE_ESCAPE,
|
||||
COMMENT,
|
||||
COMMENT_ESCAPE
|
||||
} state = PRE_KEY;
|
||||
|
||||
/* Copied and adjusted from systemd's parse_env_file_internal().
|
||||
* https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L15 */
|
||||
|
||||
nm_assert(push);
|
||||
|
||||
if (!contents)
|
||||
return -ENOENT;
|
||||
|
||||
for (const char *p = contents; *p; p++) {
|
||||
char c = *p;
|
||||
|
||||
switch (state) {
|
||||
case PRE_KEY:
|
||||
if (NM_IN_SET(c, '#', ';'))
|
||||
state = COMMENT;
|
||||
else if (!nm_ascii_is_whitespace(c)) {
|
||||
state = KEY;
|
||||
last_key_whitespace = G_MAXSIZE;
|
||||
nm_str_buf_append_c(&key, c);
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY:
|
||||
if (nm_ascii_is_newline(c)) {
|
||||
state = PRE_KEY;
|
||||
line++;
|
||||
nm_str_buf_reset(&key);
|
||||
} else if (c == '=') {
|
||||
state = PRE_VALUE;
|
||||
last_value_whitespace = G_MAXSIZE;
|
||||
} else {
|
||||
if (!nm_ascii_is_whitespace(c))
|
||||
last_key_whitespace = G_MAXSIZE;
|
||||
else if (last_key_whitespace == G_MAXSIZE)
|
||||
last_key_whitespace = key.len;
|
||||
nm_str_buf_append_c(&key, c);
|
||||
}
|
||||
break;
|
||||
|
||||
case PRE_VALUE:
|
||||
if (nm_ascii_is_newline(c)) {
|
||||
state = PRE_KEY;
|
||||
line++;
|
||||
|
||||
/* strip trailing whitespace from key */
|
||||
if (last_key_whitespace != G_MAXSIZE)
|
||||
nm_str_buf_get_str_unsafe(&key)[last_key_whitespace] = 0;
|
||||
|
||||
r = push(line,
|
||||
nm_str_buf_get_str(&key),
|
||||
nm_str_buf_get_str(&value) ?: "",
|
||||
userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
nm_str_buf_reset(&key);
|
||||
nm_str_buf_reset(&value);
|
||||
} else if (c == '\'')
|
||||
state = SINGLE_QUOTE_VALUE;
|
||||
else if (c == '"')
|
||||
state = DOUBLE_QUOTE_VALUE;
|
||||
else if (c == '\\')
|
||||
state = VALUE_ESCAPE;
|
||||
else if (!nm_ascii_is_whitespace(c)) {
|
||||
state = VALUE;
|
||||
nm_str_buf_append_c(&value, c);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case VALUE:
|
||||
if (nm_ascii_is_newline(c)) {
|
||||
state = PRE_KEY;
|
||||
line++;
|
||||
|
||||
/* Chomp off trailing whitespace from value */
|
||||
if (last_value_whitespace != G_MAXSIZE)
|
||||
nm_str_buf_get_str_unsafe(&value)[last_value_whitespace] = 0;
|
||||
|
||||
/* strip trailing whitespace from key */
|
||||
if (last_key_whitespace != G_MAXSIZE)
|
||||
nm_str_buf_get_str_unsafe(&key)[last_key_whitespace] = 0;
|
||||
|
||||
r = push(line,
|
||||
nm_str_buf_get_str(&key),
|
||||
nm_str_buf_get_str(&value) ?: "",
|
||||
userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
nm_str_buf_reset(&key);
|
||||
nm_str_buf_reset(&value);
|
||||
} else if (c == '\\') {
|
||||
state = VALUE_ESCAPE;
|
||||
last_value_whitespace = G_MAXSIZE;
|
||||
} else {
|
||||
if (!nm_ascii_is_whitespace(c))
|
||||
last_value_whitespace = G_MAXSIZE;
|
||||
else if (last_value_whitespace == G_MAXSIZE)
|
||||
last_value_whitespace = value.len;
|
||||
nm_str_buf_append_c(&value, c);
|
||||
}
|
||||
break;
|
||||
|
||||
case VALUE_ESCAPE:
|
||||
state = VALUE;
|
||||
if (!nm_ascii_is_newline(c)) {
|
||||
/* Escaped newlines we eat up entirely */
|
||||
nm_str_buf_append_c(&value, c);
|
||||
}
|
||||
break;
|
||||
|
||||
case SINGLE_QUOTE_VALUE:
|
||||
if (c == '\'')
|
||||
state = PRE_VALUE;
|
||||
else
|
||||
nm_str_buf_append_c(&value, c);
|
||||
break;
|
||||
|
||||
case DOUBLE_QUOTE_VALUE:
|
||||
if (c == '"')
|
||||
state = PRE_VALUE;
|
||||
else if (c == '\\')
|
||||
state = DOUBLE_QUOTE_VALUE_ESCAPE;
|
||||
else
|
||||
nm_str_buf_append_c(&value, c);
|
||||
break;
|
||||
|
||||
case DOUBLE_QUOTE_VALUE_ESCAPE:
|
||||
state = DOUBLE_QUOTE_VALUE;
|
||||
if (strchr(SHELL_NEED_ESCAPE, c)) {
|
||||
/* If this is a char that needs escaping, just unescape it. */
|
||||
nm_str_buf_append_c(&value, c);
|
||||
} else if (c != '\n') {
|
||||
/* If other char than what needs escaping, keep the "\" in place, like the
|
||||
* real shell does. */
|
||||
nm_str_buf_append_c(&value, '\\', c);
|
||||
}
|
||||
/* Escaped newlines (aka "continuation lines") are eaten up entirely */
|
||||
break;
|
||||
|
||||
case COMMENT:
|
||||
if (c == '\\')
|
||||
state = COMMENT_ESCAPE;
|
||||
else if (nm_ascii_is_newline(c)) {
|
||||
state = PRE_KEY;
|
||||
line++;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMENT_ESCAPE:
|
||||
state = COMMENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NM_IN_SET(state,
|
||||
PRE_VALUE,
|
||||
VALUE,
|
||||
VALUE_ESCAPE,
|
||||
SINGLE_QUOTE_VALUE,
|
||||
DOUBLE_QUOTE_VALUE,
|
||||
DOUBLE_QUOTE_VALUE_ESCAPE)) {
|
||||
if (state == VALUE)
|
||||
if (last_value_whitespace != G_MAXSIZE)
|
||||
nm_str_buf_get_str_unsafe(&value)[last_value_whitespace] = 0;
|
||||
|
||||
/* strip trailing whitespace from key */
|
||||
if (last_key_whitespace != G_MAXSIZE)
|
||||
nm_str_buf_get_str_unsafe(&key)[last_key_whitespace] = 0;
|
||||
|
||||
r = push(line, nm_str_buf_get_str(&key), nm_str_buf_get_str(&value) ?: "", userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int
|
||||
check_utf8ness_and_warn(const char *key, const char *value)
|
||||
{
|
||||
/* Taken from systemd's check_utf8ness_and_warn()
|
||||
* https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L273 */
|
||||
|
||||
if (!g_utf8_validate(key, -1, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
if (!g_utf8_validate(value, -1, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_env_file_push(unsigned line, const char *key, const char *value, void *userdata)
|
||||
{
|
||||
const char *k;
|
||||
va_list *ap = userdata;
|
||||
va_list aq;
|
||||
int r;
|
||||
|
||||
r = check_utf8ness_and_warn(key, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
va_copy(aq, *ap);
|
||||
|
||||
while ((k = va_arg(aq, const char *))) {
|
||||
char **v;
|
||||
|
||||
v = va_arg(aq, char **);
|
||||
if (nm_streq(key, k)) {
|
||||
va_end(aq);
|
||||
g_free(*v);
|
||||
*v = g_strdup(value);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(aq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nm_parse_env_filev(const char *contents, va_list ap)
|
||||
{
|
||||
va_list aq;
|
||||
int r;
|
||||
|
||||
/* Copied from systemd's parse_env_filev().
|
||||
* https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L333 */
|
||||
|
||||
va_copy(aq, ap);
|
||||
r = nm_parse_env_file_full(contents, parse_env_file_push, &aq);
|
||||
va_end(aq);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
nm_parse_env_file_sentinel(const char *contents, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
/* Copied from systemd's parse_env_file_sentinel().
|
||||
* https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L347 */
|
||||
|
||||
va_start(ap, contents);
|
||||
r = nm_parse_env_filev(contents, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,4 +77,15 @@ int nm_io_sockaddr_un_set(struct sockaddr_un *ret, NMOptionBool is_abstract, con
|
|||
|
||||
int nm_sd_notify(const char *state);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int nm_parse_env_file_full(
|
||||
const char *contents,
|
||||
int (*push)(unsigned line, const char *key, const char *value, void *userdata),
|
||||
void *userdata);
|
||||
|
||||
int nm_parse_env_filev(const char *contents, va_list ap);
|
||||
int nm_parse_env_file_sentinel(const char *contents, ...) G_GNUC_NULL_TERMINATED;
|
||||
#define nm_parse_env_file(contents, ...) nm_parse_env_file_sentinel((contents), __VA_ARGS__, NULL)
|
||||
|
||||
#endif /* __NM_IO_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -1053,6 +1053,24 @@ nm_g_variant_equal(GVariant *a, GVariant *b)
|
|||
* the kernel command line. */
|
||||
#define NM_ASCII_WHITESPACES " \n\t\r"
|
||||
|
||||
static inline gboolean
|
||||
nm_ascii_is_whitespace(char ch)
|
||||
{
|
||||
/* Checks whether @ch is in NM_ASCII_WHITESPACES.
|
||||
* Similar to g_ascii_isspace(), however this one does not accept '\f'.
|
||||
* This is the same as systemd's strchr(WHITESPACE, ch). */
|
||||
return NM_IN_SET(ch, ' ', '\n', '\t', '\r');
|
||||
}
|
||||
|
||||
#define NM_ASCII_NEWLINE "\n\r"
|
||||
|
||||
static inline gboolean
|
||||
nm_ascii_is_newline(char ch)
|
||||
{
|
||||
/* This is the same as systemd's (!!strchr(NEWLINE, ch)). */
|
||||
return NM_IN_SET(ch, '\n', '\t');
|
||||
}
|
||||
|
||||
#define nm_str_skip_leading_spaces(str) \
|
||||
({ \
|
||||
typeof(*(str)) *_str_sls = (str); \
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@
|
|||
#define nmtst_assert_strv(strv, ...) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
const char *const *const _strv = (strv); \
|
||||
const char *const *const _strv = NM_CAST_STRV_CC(strv); \
|
||||
const char *const _exp[] = {__VA_ARGS__, NULL}; \
|
||||
const gsize _n = G_N_ELEMENTS(_exp) - 1; \
|
||||
gsize _i; \
|
||||
|
|
@ -196,6 +196,7 @@
|
|||
g_assert(_exp[_i]); \
|
||||
g_assert_cmpstr(_strv[_i], ==, _exp[_i]); \
|
||||
} \
|
||||
g_assert(!_strv[_n]); \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "libnm-glib-aux/nm-str-buf.h"
|
||||
#include "libnm-glib-aux/nm-time-utils.h"
|
||||
#include "libnm-glib-aux/nm-ref-string.h"
|
||||
#include "libnm-glib-aux/nm-io-utils.h"
|
||||
|
||||
#include "libnm-glib-aux/nm-test-utils.h"
|
||||
|
||||
|
|
@ -1420,6 +1421,141 @@ test_nm_ascii(void)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int
|
||||
_env_file_push_cb(unsigned line, const char *key, const char *value, void *user_data)
|
||||
{
|
||||
char ***strv = user_data;
|
||||
char *s_line;
|
||||
gsize key_l;
|
||||
gsize strv_l;
|
||||
gsize i;
|
||||
|
||||
g_assert(strv);
|
||||
g_assert(key);
|
||||
g_assert(key[0]);
|
||||
g_assert(!strchr(key, '='));
|
||||
g_assert(value);
|
||||
|
||||
key_l = strlen(key);
|
||||
|
||||
s_line = g_strconcat(key, "=", value, NULL);
|
||||
|
||||
strv_l = 0;
|
||||
if (*strv) {
|
||||
const char *s;
|
||||
|
||||
for (i = 0; (s = (*strv)[i]); i++) {
|
||||
if (g_str_has_prefix(s, key) && s[key_l] == '=') {
|
||||
g_free((*strv)[i]);
|
||||
(*strv)[i] = s_line;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
strv_l = i;
|
||||
}
|
||||
|
||||
*strv = g_realloc(*strv, sizeof(char *) * (strv_l + 2));
|
||||
(*strv)[strv_l] = s_line;
|
||||
(*strv)[strv_l + 1] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_env_file(void)
|
||||
{
|
||||
gs_strfreev char **data = NULL;
|
||||
gs_free char *arg1 = NULL;
|
||||
gs_free char *arg2 = NULL;
|
||||
int r;
|
||||
|
||||
#define env_file_1 \
|
||||
"a=a\n" \
|
||||
"a=b\n" \
|
||||
"a=b\n" \
|
||||
"a=a\n" \
|
||||
"b=b\\\n" \
|
||||
"c\n" \
|
||||
"d= d\\\n" \
|
||||
"e \\\n" \
|
||||
"f \n" \
|
||||
"g=g\\ \n" \
|
||||
"h= ąęół\\ śćńźżµ \n" \
|
||||
"i=i\\"
|
||||
r = nm_parse_env_file_full(env_file_1, _env_file_push_cb, &data);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
nmtst_assert_strv(data, "a=a", "b=bc", "d=de f", "g=g ", "h=ąęół śćńźżµ", "i=i");
|
||||
nm_clear_pointer(&data, g_strfreev);
|
||||
|
||||
r = nm_parse_env_file(env_file_1, "a", &arg1);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
g_assert_cmpstr(arg1, ==, "a");
|
||||
nm_clear_g_free(&arg1);
|
||||
|
||||
r = nm_parse_env_file(env_file_1, "a", &arg1, "d", &arg2);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
g_assert_cmpstr(arg1, ==, "a");
|
||||
g_assert_cmpstr(arg2, ==, "de f");
|
||||
nm_clear_g_free(&arg1);
|
||||
nm_clear_g_free(&arg2);
|
||||
|
||||
#define env_file_2 "a=a\\\n"
|
||||
r = nm_parse_env_file_full(env_file_2, _env_file_push_cb, &data);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
nmtst_assert_strv(data, "a=a");
|
||||
nm_clear_pointer(&data, g_strfreev);
|
||||
|
||||
#define env_file_3 \
|
||||
"#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
|
||||
"#--nouser-config \\\n" \
|
||||
"normal=line \\\n" \
|
||||
";normal=ignored \\\n" \
|
||||
"normal_ignored \\\n" \
|
||||
"normal ignored \\\n"
|
||||
r = nm_parse_env_file_full(env_file_3, _env_file_push_cb, &data);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
g_assert(!data);
|
||||
|
||||
#define env_file_4 \
|
||||
"# Generated\n" \
|
||||
"\n" \
|
||||
"HWMON_MODULES=\"coretemp f71882fg\"\n" \
|
||||
"\n" \
|
||||
"# For compatibility reasons\n" \
|
||||
"\n" \
|
||||
"MODULE_0=coretemp\n" \
|
||||
"MODULE_1=f71882fg"
|
||||
r = nm_parse_env_file_full(env_file_4, _env_file_push_cb, &data);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
nmtst_assert_strv(data,
|
||||
"HWMON_MODULES=coretemp f71882fg",
|
||||
"MODULE_0=coretemp",
|
||||
"MODULE_1=f71882fg");
|
||||
nm_clear_pointer(&data, g_strfreev);
|
||||
|
||||
#define env_file_5 \
|
||||
"a=\n" \
|
||||
"b="
|
||||
r = nm_parse_env_file_full(env_file_5, _env_file_push_cb, &data);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
nmtst_assert_strv(data, "a=", "b=");
|
||||
nm_clear_pointer(&data, g_strfreev);
|
||||
|
||||
#define env_file_6 \
|
||||
"a=\\ \\n \\t \\x \\y \\' \n" \
|
||||
"b= \\$' \n" \
|
||||
"c= ' \\n\\t\\$\\`\\\\\n" \
|
||||
"' \n" \
|
||||
"d= \" \\n\\t\\$\\`\\\\\n" \
|
||||
"\" \n"
|
||||
r = nm_parse_env_file_full(env_file_6, _env_file_push_cb, &data);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
nmtst_assert_strv(data, "a= n t x y '", "b=$'", "c= \\n\\t\\$\\`\\\\\n", "d= \\n\\t$`\\\n");
|
||||
nm_clear_pointer(&data, g_strfreev);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMTST_DEFINE();
|
||||
|
||||
int
|
||||
|
|
@ -1453,6 +1589,7 @@ main(int argc, char **argv)
|
|||
g_test_add_func("/general/test_utils_hashtable_cmp", test_utils_hashtable_cmp);
|
||||
g_test_add_func("/general/test_nm_g_source_sentinel", test_nm_g_source_sentinel);
|
||||
g_test_add_func("/general/test_nm_ascii", test_nm_ascii);
|
||||
g_test_add_func("/general/test_parse_env_file", test_parse_env_file);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,20 +3,13 @@
|
|||
libnm_systemd_core = static_library(
|
||||
'nm-systemd-core',
|
||||
sources: files(
|
||||
'src/libsystemd-network/arp-util.c',
|
||||
'src/libsystemd-network/dhcp-identifier.c',
|
||||
'src/libsystemd-network/dhcp-network.c',
|
||||
'src/libsystemd-network/dhcp-option.c',
|
||||
'src/libsystemd-network/dhcp-packet.c',
|
||||
'src/libsystemd-network/dhcp6-network.c',
|
||||
'src/libsystemd-network/dhcp6-option.c',
|
||||
'src/libsystemd-network/dhcp6-protocol.c',
|
||||
'src/libsystemd-network/lldp-neighbor.c',
|
||||
'src/libsystemd-network/lldp-network.c',
|
||||
'src/libsystemd-network/network-common.c',
|
||||
'src/libsystemd-network/network-internal.c',
|
||||
'src/libsystemd-network/sd-dhcp-client.c',
|
||||
'src/libsystemd-network/sd-dhcp-lease.c',
|
||||
'src/libsystemd-network/sd-dhcp6-client.c',
|
||||
'src/libsystemd-network/sd-dhcp6-lease.c',
|
||||
'src/libsystemd-network/sd-lldp-rx.c',
|
||||
|
|
@ -26,7 +19,6 @@ libnm_systemd_core = static_library(
|
|||
'src/libsystemd/sd-id128/sd-id128.c',
|
||||
'nm-sd.c',
|
||||
'nm-sd-utils-core.c',
|
||||
'nm-sd-utils-dhcp.c',
|
||||
'sd-adapt-core/nm-sd-adapt-core.c',
|
||||
),
|
||||
include_directories: [
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "libnm-systemd-core/nm-default-systemd-core.h"
|
||||
|
||||
#include "nm-sd-utils-dhcp.h"
|
||||
|
||||
#include "sd-adapt-core/nm-sd-adapt-core.h"
|
||||
#include "src/libsystemd-network/dhcp-lease-internal.h"
|
||||
|
||||
int
|
||||
nm_sd_dhcp_lease_get_private_options(sd_dhcp_lease *lease, nm_sd_dhcp_option **out_options)
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
g_return_val_if_fail(lease, -EINVAL);
|
||||
g_return_val_if_fail(out_options, -EINVAL);
|
||||
g_return_val_if_fail(*out_options == NULL, -EINVAL);
|
||||
|
||||
if (lease->private_options == NULL)
|
||||
return -ENODATA;
|
||||
|
||||
LIST_FOREACH(options, raw_option, lease->private_options)
|
||||
cnt++;
|
||||
|
||||
*out_options = g_new(nm_sd_dhcp_option, cnt);
|
||||
cnt = 0;
|
||||
|
||||
LIST_FOREACH(options, raw_option, lease->private_options)
|
||||
{
|
||||
(*out_options)[cnt].code = raw_option->tag;
|
||||
(*out_options)[cnt].data = raw_option->data;
|
||||
(*out_options)[cnt].data_len = raw_option->length;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__
|
||||
#define __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__
|
||||
|
||||
#include "nm-sd.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t code;
|
||||
uint8_t data_len;
|
||||
void *data;
|
||||
} nm_sd_dhcp_option;
|
||||
|
||||
int nm_sd_dhcp_lease_get_private_options(sd_dhcp_lease *lease, nm_sd_dhcp_option **out_options);
|
||||
|
||||
#endif /* __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__ */
|
||||
|
|
@ -108,6 +108,5 @@ nm_sd_event_attach_default(void)
|
|||
/* ensure that defines in nm-sd.h correspond to the internal defines. */
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#ifndef __NM_SD_H__
|
||||
#define __NM_SD_H__
|
||||
|
||||
#include "src/systemd/sd-dhcp-client.h"
|
||||
#include "src/systemd/sd-dhcp6-client.h"
|
||||
#include "src/systemd/sd-lldp-rx.h"
|
||||
|
||||
|
|
@ -14,15 +13,4 @@
|
|||
|
||||
guint nm_sd_event_attach_default(void);
|
||||
|
||||
/*****************************************************************************
|
||||
* expose internal systemd API
|
||||
*
|
||||
* FIXME: don't use any internal systemd API.
|
||||
*****************************************************************************/
|
||||
|
||||
struct sd_dhcp_lease;
|
||||
|
||||
int dhcp_lease_save(struct sd_dhcp_lease *lease, const char *lease_file);
|
||||
int dhcp_lease_load(struct sd_dhcp_lease **ret, const char *lease_file);
|
||||
|
||||
#endif /* __NM_SD_H__ */
|
||||
|
|
|
|||
|
|
@ -1,142 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/***
|
||||
Copyright © 2014 Axis Communications AB. All rights reserved.
|
||||
***/
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/filter.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include "arp-util.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "unaligned.h"
|
||||
#include "util.h"
|
||||
|
||||
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac) {
|
||||
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(struct ether_arp), 1, 0), /* packet >= arp packet ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hln)), /* A <- hardware address length */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct ether_addr), 1, 0), /* length == sizeof(ether_addr)? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pln)), /* A <- protocol address length */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct in_addr), 1, 0), /* length == sizeof(in_addr) ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), /* protocol == request ? */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
/* Sender Hardware Address must be different from our own */
|
||||
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(&mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 4), /* A == X ? */
|
||||
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(&mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
/* Sender Protocol Address or Target Protocol Address must be equal to the one we care about */
|
||||
BPF_STMT(BPF_LDX + BPF_IMM, htobe32(a->s_addr)), /* X <- clients IP */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
};
|
||||
struct sock_fprog fprog = {
|
||||
.len = ELEMENTSOF(filter),
|
||||
.filter = (struct sock_filter*) filter,
|
||||
};
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac) {
|
||||
union sockaddr_union link = {
|
||||
.ll.sll_family = AF_PACKET,
|
||||
.ll.sll_protocol = htobe16(ETH_P_ARP),
|
||||
.ll.sll_ifindex = ifindex,
|
||||
.ll.sll_halen = ETH_ALEN,
|
||||
.ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r;
|
||||
|
||||
assert(ifindex > 0);
|
||||
assert(mac);
|
||||
|
||||
s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
r = arp_update_filter(s, a, mac);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (bind(s, &link.sa, sizeof(link.ll)) < 0)
|
||||
return -errno;
|
||||
|
||||
return TAKE_FD(s);
|
||||
}
|
||||
|
||||
int arp_send_packet(
|
||||
int fd,
|
||||
int ifindex,
|
||||
const struct in_addr *pa,
|
||||
const struct ether_addr *ha,
|
||||
bool announce) {
|
||||
|
||||
union sockaddr_union link = {
|
||||
.ll.sll_family = AF_PACKET,
|
||||
.ll.sll_protocol = htobe16(ETH_P_ARP),
|
||||
.ll.sll_ifindex = ifindex,
|
||||
.ll.sll_halen = ETH_ALEN,
|
||||
.ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
||||
};
|
||||
struct ether_arp arp = {
|
||||
.ea_hdr.ar_hrd = htobe16(ARPHRD_ETHER), /* HTYPE */
|
||||
.ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */
|
||||
.ea_hdr.ar_hln = ETH_ALEN, /* HLEN */
|
||||
.ea_hdr.ar_pln = sizeof(struct in_addr), /* PLEN */
|
||||
.ea_hdr.ar_op = htobe16(ARPOP_REQUEST), /* REQUEST */
|
||||
};
|
||||
ssize_t n;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(ifindex > 0);
|
||||
assert(pa);
|
||||
assert(in4_addr_is_set(pa));
|
||||
assert(ha);
|
||||
assert(!ether_addr_is_null(ha));
|
||||
|
||||
memcpy(&arp.arp_sha, ha, ETH_ALEN);
|
||||
memcpy(&arp.arp_tpa, pa, sizeof(struct in_addr));
|
||||
|
||||
if (announce)
|
||||
memcpy(&arp.arp_spa, pa, sizeof(struct in_addr));
|
||||
|
||||
n = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll));
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
if (n != sizeof(struct ether_arp))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
Copyright © 2014 Axis Communications AB. All rights reserved.
|
||||
***/
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
#include "sparse-endian.h"
|
||||
|
||||
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac);
|
||||
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac);
|
||||
|
||||
int arp_send_packet(
|
||||
int fd,
|
||||
int ifindex,
|
||||
const struct in_addr *pa,
|
||||
const struct ether_addr *ha,
|
||||
bool announce);
|
||||
static inline int arp_send_probe(
|
||||
int fd,
|
||||
int ifindex,
|
||||
const struct in_addr *pa,
|
||||
const struct ether_addr *ha) {
|
||||
return arp_send_packet(fd, ifindex, pa, ha, false);
|
||||
}
|
||||
static inline int arp_send_announcement(
|
||||
int fd,
|
||||
int ifindex,
|
||||
const struct in_addr *pa,
|
||||
const struct ether_addr *ha) {
|
||||
return arp_send_packet(fd, ifindex, pa, ha, true);
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
***/
|
||||
|
||||
#include <linux/if_packet.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "sd-dhcp-client.h"
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
#include "network-common.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
typedef struct sd_dhcp_option {
|
||||
unsigned n_ref;
|
||||
|
||||
uint8_t option;
|
||||
void *data;
|
||||
size_t length;
|
||||
} sd_dhcp_option;
|
||||
|
||||
typedef struct DHCPServerData {
|
||||
struct in_addr *addr;
|
||||
size_t size;
|
||||
} DHCPServerData;
|
||||
|
||||
extern const struct hash_ops dhcp_option_hash_ops;
|
||||
|
||||
typedef struct sd_dhcp_client sd_dhcp_client;
|
||||
|
||||
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,
|
||||
const uint8_t *bcast_addr, size_t bcast_addr_len,
|
||||
uint16_t arp_type, uint16_t port);
|
||||
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
|
||||
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);
|
||||
int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t wanted_code, size_t *ret_offset);
|
||||
int dhcp_option_remove_option(uint8_t *options, size_t buflen, uint8_t option_code);
|
||||
|
||||
typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len,
|
||||
const void *option, void *userdata);
|
||||
|
||||
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message);
|
||||
|
||||
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
|
||||
uint8_t type, uint16_t arp_type, uint8_t hlen, const uint8_t *chaddr,
|
||||
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 ip_service_type);
|
||||
|
||||
int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port);
|
||||
|
||||
void dhcp_client_set_test_mode(sd_dhcp_client *client, bool test_mode);
|
||||
|
||||
/* 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_(sd_dhcp_client_unrefp) _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client)
|
||||
|
||||
#define log_dhcp_client_errno(client, error, fmt, ...) \
|
||||
log_interface_prefix_full_errno( \
|
||||
"DHCPv4 client: ", \
|
||||
sd_dhcp_client, client, \
|
||||
error, fmt, ##__VA_ARGS__)
|
||||
#define log_dhcp_client(client, fmt, ...) \
|
||||
log_interface_prefix_full_errno_zerook( \
|
||||
"DHCPv4 client: ", \
|
||||
sd_dhcp_client, client, \
|
||||
0, fmt, ##__VA_ARGS__)
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
***/
|
||||
|
||||
#include "sd-dhcp-client.h"
|
||||
|
||||
#include "dhcp-internal.h"
|
||||
#include "dhcp-protocol.h"
|
||||
#include "list.h"
|
||||
#include "util.h"
|
||||
|
||||
struct sd_dhcp_route {
|
||||
struct in_addr dst_addr;
|
||||
struct in_addr gw_addr;
|
||||
unsigned char dst_prefixlen;
|
||||
};
|
||||
|
||||
struct sd_dhcp_raw_option {
|
||||
LIST_FIELDS(struct sd_dhcp_raw_option, options);
|
||||
|
||||
uint8_t tag;
|
||||
uint8_t length;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct sd_dhcp_lease {
|
||||
unsigned n_ref;
|
||||
|
||||
/* each 0 if unset */
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
uint32_t lifetime;
|
||||
|
||||
/* each 0 if unset */
|
||||
be32_t address;
|
||||
be32_t server_address;
|
||||
be32_t next_server;
|
||||
|
||||
bool have_subnet_mask;
|
||||
be32_t subnet_mask;
|
||||
|
||||
bool have_broadcast;
|
||||
be32_t broadcast;
|
||||
|
||||
struct in_addr *router;
|
||||
size_t router_size;
|
||||
|
||||
DHCPServerData servers[_SD_DHCP_LEASE_SERVER_TYPE_MAX];
|
||||
|
||||
struct sd_dhcp_route *static_routes;
|
||||
size_t n_static_routes;
|
||||
struct sd_dhcp_route *classless_routes;
|
||||
size_t n_classless_routes;
|
||||
|
||||
uint16_t mtu; /* 0 if unset */
|
||||
|
||||
char *domainname;
|
||||
char **search_domains;
|
||||
char *hostname;
|
||||
char *root_path;
|
||||
|
||||
void *client_id;
|
||||
size_t client_id_len;
|
||||
|
||||
void *vendor_specific;
|
||||
size_t vendor_specific_len;
|
||||
|
||||
char *timezone;
|
||||
|
||||
uint8_t sixrd_ipv4masklen;
|
||||
uint8_t sixrd_prefixlen;
|
||||
struct in6_addr sixrd_prefix;
|
||||
struct in_addr *sixrd_br_addresses;
|
||||
size_t sixrd_n_br_addresses;
|
||||
|
||||
LIST_HEAD(struct sd_dhcp_raw_option, private_options);
|
||||
};
|
||||
|
||||
int dhcp_lease_new(sd_dhcp_lease **ret);
|
||||
|
||||
int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata);
|
||||
int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains);
|
||||
int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len);
|
||||
|
||||
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);
|
||||
|
||||
int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len);
|
||||
|
|
@ -1,257 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
***/
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/if_infiniband.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
#include "dhcp-internal.h"
|
||||
#include "fd-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
|
||||
uint32_t xid,
|
||||
const uint8_t *bcast_addr,
|
||||
size_t bcast_addr_len,
|
||||
const struct ether_addr *eth_mac,
|
||||
uint16_t arp_type, uint8_t dhcp_hlen,
|
||||
uint16_t port) {
|
||||
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, port, 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_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_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 */
|
||||
|
||||
/* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally
|
||||
* compare chaddr for ETH_ALEN bytes. */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8), /* A (the MAC address length) == ETH_ALEN ? */
|
||||
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(ð_mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
|
||||
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, UINT32_MAX), /* accept */
|
||||
};
|
||||
struct sock_fprog fprog = {
|
||||
.len = ELEMENTSOF(filter),
|
||||
.filter = filter
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r;
|
||||
|
||||
assert(ifindex > 0);
|
||||
assert(link);
|
||||
|
||||
s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt_int(s, SOL_PACKET, PACKET_AUXDATA, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
link->ll = (struct sockaddr_ll) {
|
||||
.sll_family = AF_PACKET,
|
||||
.sll_protocol = htobe16(ETH_P_IP),
|
||||
.sll_ifindex = ifindex,
|
||||
.sll_hatype = htobe16(arp_type),
|
||||
.sll_halen = bcast_addr_len,
|
||||
};
|
||||
memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len); /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */
|
||||
|
||||
r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return TAKE_FD(s);
|
||||
}
|
||||
|
||||
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,
|
||||
const uint8_t *bcast_addr,
|
||||
size_t bcast_addr_len,
|
||||
uint16_t arp_type,
|
||||
uint16_t port) {
|
||||
|
||||
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 *default_bcast_addr;
|
||||
size_t expected_bcast_addr_len;
|
||||
uint8_t dhcp_hlen = 0;
|
||||
|
||||
if (arp_type == ARPHRD_ETHER) {
|
||||
assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
|
||||
memcpy(ð_mac, mac_addr, ETH_ALEN);
|
||||
dhcp_hlen = ETH_ALEN;
|
||||
|
||||
default_bcast_addr = eth_bcast;
|
||||
expected_bcast_addr_len = ETH_ALEN;
|
||||
} else if (arp_type == ARPHRD_INFINIBAND) {
|
||||
default_bcast_addr = ib_bcast;
|
||||
expected_bcast_addr_len = INFINIBAND_ALEN;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
if (bcast_addr && bcast_addr_len > 0)
|
||||
assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL);
|
||||
else {
|
||||
bcast_addr = default_bcast_addr;
|
||||
bcast_addr_len = expected_bcast_addr_len;
|
||||
}
|
||||
|
||||
return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len,
|
||||
ð_mac, arp_type, dhcp_hlen, port);
|
||||
}
|
||||
|
||||
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
|
||||
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;
|
||||
|
||||
s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
if (ip_service_type >= 0)
|
||||
r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type);
|
||||
else
|
||||
r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = setsockopt_int(s, SOL_SOCKET, SO_REUSEADDR, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ifindex > 0) {
|
||||
r = socket_bind_to_ifindex(s, ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (port == DHCP_PORT_SERVER) {
|
||||
r = setsockopt_int(s, SOL_SOCKET, SO_BROADCAST, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (address == INADDR_ANY) {
|
||||
/* IP_PKTINFO filter should not be applied when packets are
|
||||
allowed to enter/leave through the interface other than
|
||||
DHCP server sits on(BindToInterface option). */
|
||||
r = setsockopt_int(s, IPPROTO_IP, IP_PKTINFO, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
r = setsockopt_int(s, IPPROTO_IP, IP_FREEBIND, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (bind(s, &src.sa, sizeof(src.in)) < 0)
|
||||
return -errno;
|
||||
|
||||
return TAKE_FD(s);
|
||||
}
|
||||
|
||||
int dhcp_network_send_raw_socket(
|
||||
int s,
|
||||
const union sockaddr_union *link,
|
||||
const void *packet,
|
||||
size_t len) {
|
||||
|
||||
/* Do not add assert(s >= 0) here, as this is called in fuzz-dhcp-server, and in that case this
|
||||
* function should fail with negative errno. */
|
||||
|
||||
assert(link);
|
||||
assert(packet);
|
||||
assert(len > 0);
|
||||
|
||||
if (sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll)) < 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,
|
||||
};
|
||||
|
||||
assert(s >= 0);
|
||||
assert(packet);
|
||||
assert(len > 0);
|
||||
|
||||
if (sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in)) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,443 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
***/
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp-internal.h"
|
||||
#include "dhcp-server-internal.h"
|
||||
#include "memory-util.h"
|
||||
#include "strv.h"
|
||||
#include "utf8.h"
|
||||
|
||||
/* Append type-length value structure to the options buffer */
|
||||
static int dhcp_option_append_tlv(uint8_t options[], size_t size, size_t *offset, uint8_t code, size_t optlen, const void *optval) {
|
||||
assert(options);
|
||||
assert(size > 0);
|
||||
assert(offset);
|
||||
assert(optlen <= UINT8_MAX);
|
||||
assert(*offset < size);
|
||||
|
||||
if (*offset + 2 + optlen > size)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = optlen;
|
||||
|
||||
memcpy_safe(&options[*offset + 2], optval, optlen);
|
||||
*offset += 2 + optlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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(size > 0);
|
||||
assert(offset);
|
||||
|
||||
int r;
|
||||
|
||||
if (code != SD_DHCP_OPTION_END)
|
||||
/* always make sure there is space for an END option */
|
||||
size--;
|
||||
|
||||
switch (code) {
|
||||
|
||||
case SD_DHCP_OPTION_PAD:
|
||||
case SD_DHCP_OPTION_END:
|
||||
if (*offset + 1 > size)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
*offset += 1;
|
||||
break;
|
||||
|
||||
case SD_DHCP_OPTION_USER_CLASS: {
|
||||
size_t total = 0;
|
||||
|
||||
if (strv_isempty((char **) optval))
|
||||
return -EINVAL;
|
||||
|
||||
STRV_FOREACH(s, (char **) optval) {
|
||||
size_t len = strlen(*s);
|
||||
|
||||
if (len > 255 || len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
total += 1 + len;
|
||||
}
|
||||
|
||||
if (*offset + 2 + total > size)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = total;
|
||||
*offset += 2;
|
||||
|
||||
STRV_FOREACH(s, (char **) optval) {
|
||||
size_t len = strlen(*s);
|
||||
|
||||
options[*offset] = len;
|
||||
memcpy(&options[*offset + 1], *s, len);
|
||||
*offset += 1 + len;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SD_DHCP_OPTION_SIP_SERVER:
|
||||
if (*offset + 3 + optlen > size)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = optlen + 1;
|
||||
options[*offset + 2] = 1;
|
||||
|
||||
memcpy_safe(&options[*offset + 3], optval, optlen);
|
||||
*offset += 3 + optlen;
|
||||
|
||||
break;
|
||||
case SD_DHCP_OPTION_VENDOR_SPECIFIC: {
|
||||
OrderedSet *s = (OrderedSet *) optval;
|
||||
struct sd_dhcp_option *p;
|
||||
size_t l = 0;
|
||||
|
||||
ORDERED_SET_FOREACH(p, s)
|
||||
l += p->length + 2;
|
||||
|
||||
if (*offset + l + 2 > size)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = l;
|
||||
*offset += 2;
|
||||
|
||||
ORDERED_SET_FOREACH(p, s) {
|
||||
r = dhcp_option_append_tlv(options, size, offset, p->option, p->length, p->data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION: {
|
||||
#if 0 /* NM_IGNORED */
|
||||
sd_dhcp_server *server = (sd_dhcp_server *) optval;
|
||||
size_t current_offset = *offset + 2;
|
||||
|
||||
if (server->agent_circuit_id) {
|
||||
r = dhcp_option_append_tlv(options, size, ¤t_offset, SD_DHCP_RELAY_AGENT_CIRCUIT_ID,
|
||||
strlen(server->agent_circuit_id), server->agent_circuit_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (server->agent_remote_id) {
|
||||
r = dhcp_option_append_tlv(options, size, ¤t_offset, SD_DHCP_RELAY_AGENT_REMOTE_ID,
|
||||
strlen(server->agent_remote_id), server->agent_remote_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = current_offset - *offset - 2;
|
||||
assert(current_offset - *offset - 2 <= UINT8_MAX);
|
||||
*offset = current_offset;
|
||||
break;
|
||||
#endif /* NM_IGNORED */
|
||||
g_return_val_if_reached(-EINVAL);
|
||||
}
|
||||
default:
|
||||
return dhcp_option_append_tlv(options, size, offset, code, optlen, optval);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int option_length(uint8_t *options, size_t length, size_t offset) {
|
||||
assert(options);
|
||||
assert(offset < length);
|
||||
|
||||
if (IN_SET(options[offset], SD_DHCP_OPTION_PAD, SD_DHCP_OPTION_END))
|
||||
return 1;
|
||||
if (length < offset + 2)
|
||||
return -ENOBUFS;
|
||||
|
||||
/* validating that buffer is long enough */
|
||||
if (length < offset + 2 + options[offset + 1])
|
||||
return -ENOBUFS;
|
||||
|
||||
return options[offset + 1] + 2;
|
||||
}
|
||||
|
||||
int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t code, size_t *ret_offset) {
|
||||
int r;
|
||||
|
||||
assert(options);
|
||||
assert(ret_offset);
|
||||
|
||||
for (size_t offset = 0; offset < length; offset += r) {
|
||||
r = option_length(options, length, offset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (code == options[offset]) {
|
||||
*ret_offset = offset;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int dhcp_option_remove_option(uint8_t *options, size_t length, uint8_t option_code) {
|
||||
int r;
|
||||
size_t offset;
|
||||
|
||||
assert(options);
|
||||
|
||||
r = dhcp_option_find_option(options, length, option_code, &offset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
memmove(options + offset, options + offset + r, length - offset - r);
|
||||
return length - r;
|
||||
}
|
||||
|
||||
int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
|
||||
uint8_t overload,
|
||||
uint8_t code, size_t optlen, const void *optval) {
|
||||
const bool use_file = overload & DHCP_OVERLOAD_FILE;
|
||||
const bool use_sname = overload & DHCP_OVERLOAD_SNAME;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(offset);
|
||||
|
||||
/* If *offset is in range [0, size), we are writing to ->options,
|
||||
* if *offset is in range [size, size + sizeof(message->file)) and use_file, we are writing to ->file,
|
||||
* if *offset is in range [size + use_file*sizeof(message->file), size + use_file*sizeof(message->file) + sizeof(message->sname))
|
||||
* and use_sname, we are writing to ->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 && (use_file || use_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, SD_DHCP_OPTION_END, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*offset = size;
|
||||
} else
|
||||
return r;
|
||||
}
|
||||
|
||||
if (use_file) {
|
||||
size_t 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 && use_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->file, sizeof(message->file), &file_offset, SD_DHCP_OPTION_END, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*offset = size + sizeof(message->file);
|
||||
} else
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_sname) {
|
||||
size_t sname_offset = *offset - size - use_file*sizeof(message->file);
|
||||
|
||||
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 + use_file*sizeof(message->file) + 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, char **error_message, dhcp_option_callback_t cb,
|
||||
void *userdata) {
|
||||
uint8_t code, len;
|
||||
const uint8_t *option;
|
||||
size_t offset = 0;
|
||||
|
||||
while (offset < buflen) {
|
||||
code = options[offset ++];
|
||||
|
||||
switch (code) {
|
||||
case SD_DHCP_OPTION_PAD:
|
||||
continue;
|
||||
|
||||
case SD_DHCP_OPTION_END:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buflen < offset + 1)
|
||||
return -ENOBUFS;
|
||||
|
||||
len = options[offset ++];
|
||||
|
||||
if (buflen < offset + len)
|
||||
return -EINVAL;
|
||||
|
||||
option = &options[offset];
|
||||
|
||||
switch (code) {
|
||||
case SD_DHCP_OPTION_MESSAGE_TYPE:
|
||||
if (len != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (message_type)
|
||||
*message_type = *option;
|
||||
|
||||
break;
|
||||
|
||||
case SD_DHCP_OPTION_ERROR_MESSAGE:
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (error_message) {
|
||||
_cleanup_free_ char *string = NULL;
|
||||
|
||||
/* Accept a trailing NUL byte */
|
||||
if (memchr(option, 0, len - 1))
|
||||
return -EINVAL;
|
||||
|
||||
string = memdup_suffix0((const char *) option, len);
|
||||
if (!string)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!ascii_is_valid(string))
|
||||
return -EINVAL;
|
||||
|
||||
free_and_replace(*error_message, string);
|
||||
}
|
||||
|
||||
break;
|
||||
case SD_DHCP_OPTION_OVERLOAD:
|
||||
if (len != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (overload)
|
||||
*overload = *option;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (cb)
|
||||
cb(code, len, option, userdata);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (offset < buflen)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **_error_message) {
|
||||
_cleanup_free_ char *error_message = NULL;
|
||||
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, &error_message, cb, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (overload & DHCP_OVERLOAD_FILE) {
|
||||
r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (overload & DHCP_OVERLOAD_SNAME) {
|
||||
r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (message_type == 0)
|
||||
return -ENOMSG;
|
||||
|
||||
if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE))
|
||||
*_error_message = TAKE_PTR(error_message);
|
||||
|
||||
return message_type;
|
||||
}
|
||||
|
||||
static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) {
|
||||
if (!i)
|
||||
return NULL;
|
||||
|
||||
free(i->data);
|
||||
return mfree(i);
|
||||
}
|
||||
|
||||
int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret) {
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(length == 0 || data, -EINVAL);
|
||||
|
||||
_cleanup_free_ void *q = memdup(data, length);
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
|
||||
sd_dhcp_option *p = new(sd_dhcp_option, 1);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*p = (sd_dhcp_option) {
|
||||
.n_ref = 1,
|
||||
.option = option,
|
||||
.length = length,
|
||||
.data = TAKE_PTR(q),
|
||||
};
|
||||
|
||||
*ret = TAKE_PTR(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_option, sd_dhcp_option, dhcp_option_free);
|
||||
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
dhcp_option_hash_ops,
|
||||
void,
|
||||
trivial_hash_func,
|
||||
trivial_compare_func,
|
||||
sd_dhcp_option,
|
||||
sd_dhcp_option_unref);
|
||||
|
|
@ -1,196 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
***/
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dhcp-internal.h"
|
||||
#include "dhcp-protocol.h"
|
||||
#include "memory-util.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,
|
||||
uint8_t hlen,
|
||||
const uint8_t *chaddr,
|
||||
size_t optlen,
|
||||
size_t *optoffset) {
|
||||
|
||||
size_t offset = 0;
|
||||
int r;
|
||||
|
||||
assert(IN_SET(op, BOOTREQUEST, BOOTREPLY));
|
||||
assert(chaddr || hlen == 0);
|
||||
|
||||
message->op = op;
|
||||
message->htype = arp_type;
|
||||
|
||||
/* RFC2131 section 4.1.1:
|
||||
The client MUST include its hardware address in the ’chaddr’ field, if
|
||||
necessary for delivery of DHCP reply messages.
|
||||
|
||||
RFC 4390 section 2.1:
|
||||
A DHCP client, when working over an IPoIB interface, MUST follow the
|
||||
following rules:
|
||||
"htype" (hardware address type) MUST be 32 [ARPPARAM].
|
||||
"hlen" (hardware address length) MUST be 0.
|
||||
"chaddr" (client hardware address) field MUST be zeroed.
|
||||
*/
|
||||
message->hlen = (arp_type == ARPHRD_INFINIBAND) ? 0 : hlen;
|
||||
memcpy_safe(message->chaddr, chaddr, message->hlen);
|
||||
|
||||
message->xid = htobe32(xid);
|
||||
message->magic = htobe32(DHCP_MAGIC_COOKIE);
|
||||
|
||||
r = dhcp_option_append(message, optlen, &offset, 0,
|
||||
SD_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, int ip_service_type) {
|
||||
packet->ip.version = IPVERSION;
|
||||
packet->ip.ihl = DHCP_IP_SIZE / 4;
|
||||
packet->ip.tot_len = htobe16(len);
|
||||
|
||||
if (ip_service_type >= 0)
|
||||
packet->ip.tos = ip_service_type;
|
||||
else
|
||||
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, uint16_t port) {
|
||||
size_t hdrlen;
|
||||
|
||||
assert(packet);
|
||||
|
||||
/* IP */
|
||||
|
||||
if (packet->ip.version != IPVERSION)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: not IPv4");
|
||||
|
||||
if (packet->ip.ihl < 5)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: IPv4 IHL (%u words) invalid",
|
||||
packet->ip.ihl);
|
||||
|
||||
hdrlen = packet->ip.ihl * 4;
|
||||
if (hdrlen < 20)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: IPv4 IHL (%zu bytes) "
|
||||
"smaller than minimum (20 bytes)",
|
||||
hdrlen);
|
||||
|
||||
if (len < hdrlen)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: packet (%zu bytes) "
|
||||
"smaller than expected (%zu) by IP header",
|
||||
len, hdrlen);
|
||||
|
||||
/* UDP */
|
||||
|
||||
if (packet->ip.protocol != IPPROTO_UDP)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: not UDP");
|
||||
|
||||
if (len < hdrlen + be16toh(packet->udp.len))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: packet (%zu bytes) "
|
||||
"smaller than expected (%zu) by UDP header",
|
||||
len, hdrlen + be16toh(packet->udp.len));
|
||||
|
||||
if (be16toh(packet->udp.dest) != port)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: to port %u, which "
|
||||
"is not the DHCP client port (%u)",
|
||||
be16toh(packet->udp.dest), port);
|
||||
|
||||
/* 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))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: invalid IP checksum");
|
||||
|
||||
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))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: invalid UDP checksum");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
***/
|
||||
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.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, /* [RFC2132] */
|
||||
DHCP_OFFER = 2, /* [RFC2132] */
|
||||
DHCP_REQUEST = 3, /* [RFC2132] */
|
||||
DHCP_DECLINE = 4, /* [RFC2132] */
|
||||
DHCP_ACK = 5, /* [RFC2132] */
|
||||
DHCP_NAK = 6, /* [RFC2132] */
|
||||
DHCP_RELEASE = 7, /* [RFC2132] */
|
||||
DHCP_INFORM = 8, /* [RFC2132] */
|
||||
DHCP_FORCERENEW = 9, /* [RFC3203] */
|
||||
DHCPLEASEQUERY = 10, /* [RFC4388] */
|
||||
DHCPLEASEUNASSIGNED = 11, /* [RFC4388] */
|
||||
DHCPLEASEUNKNOWN = 12, /* [RFC4388] */
|
||||
DHCPLEASEACTIVE = 13, /* [RFC4388] */
|
||||
DHCPBULKLEASEQUERY = 14, /* [RFC6926] */
|
||||
DHCPLEASEQUERYDONE = 15, /* [RFC6926] */
|
||||
DHCPACTIVELEASEQUERY = 16, /* [RFC7724] */
|
||||
DHCPLEASEQUERYSTATUS = 17, /* [RFC7724] */
|
||||
DHCPTLS = 18, /* [RFC7724] */
|
||||
};
|
||||
|
||||
enum {
|
||||
DHCP_OVERLOAD_FILE = 1,
|
||||
DHCP_OVERLOAD_SNAME = 2,
|
||||
};
|
||||
|
||||
#define DHCP_MAX_FQDN_LENGTH 255
|
||||
|
||||
enum {
|
||||
DHCP_FQDN_FLAG_S = (1 << 0),
|
||||
DHCP_FQDN_FLAG_O = (1 << 1),
|
||||
DHCP_FQDN_FLAG_E = (1 << 2),
|
||||
DHCP_FQDN_FLAG_N = (1 << 3),
|
||||
};
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if.h>
|
||||
#include <netinet/ether.h>
|
||||
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "extract-word.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "log.h"
|
||||
#include "network-internal.h"
|
||||
#include "parse-util.h"
|
||||
|
||||
size_t serialize_in_addrs(FILE *f,
|
||||
const struct in_addr *addresses,
|
||||
size_t size,
|
||||
bool *with_leading_space,
|
||||
bool (*predicate)(const struct in_addr *addr)) {
|
||||
assert(f);
|
||||
assert(addresses);
|
||||
|
||||
size_t count = 0;
|
||||
bool _space = false;
|
||||
if (!with_leading_space)
|
||||
with_leading_space = &_space;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
char sbuf[INET_ADDRSTRLEN];
|
||||
|
||||
if (predicate && !predicate(&addresses[i]))
|
||||
continue;
|
||||
|
||||
if (*with_leading_space)
|
||||
fputc(' ', f);
|
||||
fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f);
|
||||
count++;
|
||||
*with_leading_space = true;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int deserialize_in_addrs(struct in_addr **ret, const char *string) {
|
||||
_cleanup_free_ struct in_addr *addresses = NULL;
|
||||
int size = 0;
|
||||
|
||||
assert(ret);
|
||||
assert(string);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
struct in_addr *new_addresses;
|
||||
int r;
|
||||
|
||||
r = extract_first_word(&string, &word, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
|
||||
if (!new_addresses)
|
||||
return -ENOMEM;
|
||||
else
|
||||
addresses = new_addresses;
|
||||
|
||||
r = inet_pton(AF_INET, word, &(addresses[size]));
|
||||
if (r <= 0)
|
||||
continue;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
*ret = size > 0 ? TAKE_PTR(addresses) : NULL;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size, bool *with_leading_space) {
|
||||
assert(f);
|
||||
assert(addresses);
|
||||
assert(size);
|
||||
|
||||
bool _space = false;
|
||||
if (!with_leading_space)
|
||||
with_leading_space = &_space;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
char buffer[INET6_ADDRSTRLEN];
|
||||
|
||||
if (*with_leading_space)
|
||||
fputc(' ', f);
|
||||
fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
|
||||
*with_leading_space = true;
|
||||
}
|
||||
}
|
||||
|
||||
int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
|
||||
_cleanup_free_ struct in6_addr *addresses = NULL;
|
||||
int size = 0;
|
||||
|
||||
assert(ret);
|
||||
assert(string);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
struct in6_addr *new_addresses;
|
||||
int r;
|
||||
|
||||
r = extract_first_word(&string, &word, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
|
||||
if (!new_addresses)
|
||||
return -ENOMEM;
|
||||
else
|
||||
addresses = new_addresses;
|
||||
|
||||
r = inet_pton(AF_INET6, word, &(addresses[size]));
|
||||
if (r <= 0)
|
||||
continue;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(addresses);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
|
||||
assert(f);
|
||||
assert(key);
|
||||
assert(routes);
|
||||
assert(size);
|
||||
|
||||
fprintf(f, "%s=", key);
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
char sbuf[INET_ADDRSTRLEN];
|
||||
struct in_addr dest, gw;
|
||||
uint8_t length;
|
||||
|
||||
assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
|
||||
assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
|
||||
assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
|
||||
|
||||
fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof sbuf), length);
|
||||
fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof sbuf), i < size - 1 ? " ": "");
|
||||
}
|
||||
|
||||
fputs("\n", f);
|
||||
}
|
||||
|
||||
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, const char *string) {
|
||||
_cleanup_free_ struct sd_dhcp_route *routes = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
assert(ret);
|
||||
assert(ret_size);
|
||||
assert(string);
|
||||
|
||||
/* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
char *tok, *tok_end;
|
||||
unsigned n;
|
||||
int r;
|
||||
|
||||
r = extract_first_word(&string, &word, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (!GREEDY_REALLOC(routes, size + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
tok = word;
|
||||
|
||||
/* 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 = TAKE_PTR(routes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
|
||||
_cleanup_free_ char *hex_buf = NULL;
|
||||
|
||||
assert(f);
|
||||
assert(key);
|
||||
assert(data);
|
||||
|
||||
hex_buf = hexmem(data, size);
|
||||
if (!hex_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
fprintf(f, "%s=%s\n", key, hex_buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sd-dhcp-lease.h"
|
||||
|
||||
size_t serialize_in_addrs(FILE *f,
|
||||
const struct in_addr *addresses,
|
||||
size_t size,
|
||||
bool *with_leading_space,
|
||||
bool (*predicate)(const struct in_addr *addr));
|
||||
int deserialize_in_addrs(struct in_addr **addresses, const char *string);
|
||||
void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
|
||||
size_t size,
|
||||
bool *with_leading_space);
|
||||
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;
|
||||
struct sd_dhcp_lease;
|
||||
|
||||
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, const char *string);
|
||||
|
||||
/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
|
||||
int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
|
||||
|
||||
int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
|
||||
int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,345 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddhcpclienthfoo
|
||||
#define foosddhcpclienthfoo
|
||||
|
||||
/***
|
||||
Copyright © 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 <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-dhcp-lease.h"
|
||||
#include "sd-dhcp-option.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
enum {
|
||||
SD_DHCP_CLIENT_EVENT_STOP = 0,
|
||||
SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1,
|
||||
SD_DHCP_CLIENT_EVENT_IP_CHANGE = 2,
|
||||
SD_DHCP_CLIENT_EVENT_EXPIRED = 3,
|
||||
SD_DHCP_CLIENT_EVENT_RENEW = 4,
|
||||
SD_DHCP_CLIENT_EVENT_SELECTING = 5,
|
||||
SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts.
|
||||
* The client may want to start acquiring link-local addresses. */
|
||||
};
|
||||
|
||||
/* https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options */
|
||||
enum {
|
||||
SD_DHCP_OPTION_PAD = 0, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_SUBNET_MASK = 1, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_TIME_OFFSET = 2, /* [RFC2132], deprecated by 100 and 101 */
|
||||
SD_DHCP_OPTION_ROUTER = 3, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_TIME_SERVER = 4, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NAME_SERVER = 5, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_DOMAIN_NAME_SERVER = 6, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_LOG_SERVER = 7, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_QUOTES_SERVER = 8, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_LPR_SERVER = 9, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_IMPRESS_SERVER = 10, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_RLP_SERVER = 11, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_HOST_NAME = 12, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_BOOT_FILE_SIZE = 13, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MERIT_DUMP_FILE = 14, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_DOMAIN_NAME = 15, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_SWAP_SERVER = 16, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ROOT_PATH = 17, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_EXTENSION_FILE = 18, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_FORWARD = 19, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_SOURCE_ROUTE = 20, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_POLICY_FILTER = 21, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MAX_DATAGRAM_ASSEMBLY = 22, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_DEFAULT_IP_TTL = 23, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MTU_TIMEOUT = 24, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MTU_PLATEAU = 25, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MTU_INTERFACE = 26, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MTU_SUBNET = 27, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_BROADCAST = 28, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MASK_DISCOVERY = 29, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MASK_SUPPLIER = 30, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ROUTER_DISCOVERY = 31, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ROUTER_REQUEST = 32, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_STATIC_ROUTE = 33, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_TRAILERS = 34, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ARP_TIMEOUT = 35, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ETHERNET = 36, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_DEFAULT_TCP_TTL = 37, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_KEEPALIVE_TIME = 38, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_KEEPALIVE_DATA = 39, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NIS_DOMAIN = 40, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NIS_SERVER = 41, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NTP_SERVER = 42, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_VENDOR_SPECIFIC = 43, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NETBIOS_NAME_SERVER = 44, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NETBIOS_DIST_SERVER = 45, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NETBIOS_NODE_TYPE = 46, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NETBIOS_SCOPE = 47, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_X_WINDOW_FONT = 48, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_X_WINDOW_MANAGER = 49, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_OVERLOAD = 52, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MESSAGE_TYPE = 53, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_SERVER_IDENTIFIER = 54, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ERROR_MESSAGE = 56, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_RENEWAL_TIME = 58, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_REBINDING_TIME = 59, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NETWARE_IP_DOMAIN = 62, /* [RFC2242] */
|
||||
SD_DHCP_OPTION_NETWARE_IP_OPTION = 63, /* [RFC2242] */
|
||||
SD_DHCP_OPTION_NIS_DOMAIN_NAME = 64, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NIS_SERVER_ADDR = 65, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_BOOT_SERVER_NAME = 66, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_BOOT_FILENAME = 67, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_HOME_AGENT_ADDRESSES = 68, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_SMTP_SERVER = 69, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_POP3_SERVER = 70, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NNTP_SERVER = 71, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_WWW_SERVER = 72, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_FINGER_SERVER = 73, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_IRC_SERVER = 74, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_STREETTALK_SERVER = 75, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_STDA_SERVER = 76, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_USER_CLASS = 77, /* [RFC3004] */
|
||||
SD_DHCP_OPTION_DIRECTORY_AGENT = 78, /* [RFC2610] */
|
||||
SD_DHCP_OPTION_SERVICE_SCOPE = 79, /* [RFC2610] */
|
||||
SD_DHCP_OPTION_RAPID_COMMIT = 80, /* [RFC4039] */
|
||||
SD_DHCP_OPTION_FQDN = 81, /* [RFC4702] */
|
||||
SD_DHCP_OPTION_RELAY_AGENT_INFORMATION = 82, /* [RFC3046] */
|
||||
SD_DHCP_OPTION_ISNS = 83, /* [RFC4174] */
|
||||
/* option code 84 is unassigned [RFC3679] */
|
||||
SD_DHCP_OPTION_NDS_SERVER = 85, /* [RFC2241] */
|
||||
SD_DHCP_OPTION_NDS_TREE_NAME = 86, /* [RFC2241] */
|
||||
SD_DHCP_OPTION_NDS_CONTEXT = 87, /* [RFC2241] */
|
||||
SD_DHCP_OPTION_BCMCS_CONTROLLER_DOMAIN_NAM = 88, /* [RFC4280] */
|
||||
SD_DHCP_OPTION_BCMCS_CONTROLLER_ADDRESS = 89, /* [RFC4280] */
|
||||
SD_DHCP_OPTION_AUTHENTICATION = 90, /* [RFC3118] */
|
||||
SD_DHCP_OPTION_CLIENT_LAST_TRANSACTION_TIME = 91, /* [RFC4388] */
|
||||
SD_DHCP_OPTION_ASSOCIATED_IP = 92, /* [RFC4388] */
|
||||
SD_DHCP_OPTION_CLIENT_SYSTEM = 93, /* [RFC4578] */
|
||||
SD_DHCP_OPTION_CLIENT_NDI = 94, /* [RFC4578] */
|
||||
SD_DHCP_OPTION_LDAP = 95, /* [RFC3679] */
|
||||
/* option code 96 is unassigned [RFC3679] */
|
||||
SD_DHCP_OPTION_UUID = 97, /* [RFC4578] */
|
||||
SD_DHCP_OPTION_USER_AUTHENTICATION = 98, /* [RFC2485] */
|
||||
SD_DHCP_OPTION_GEOCONF_CIVIC = 99, /* [RFC4776] */
|
||||
SD_DHCP_OPTION_POSIX_TIMEZONE = 100, /* [RFC4833] */
|
||||
SD_DHCP_OPTION_TZDB_TIMEZONE = 101, /* [RFC4833] */
|
||||
/* option codes 102-107 are unassigned [RFC3679] */
|
||||
SD_DHCP_OPTION_IPV6_ONLY_PREFERRED = 108, /* [RFC8925] */
|
||||
SD_DHCP_OPTION_DHCP4O6_SOURCE_ADDRESS = 109, /* [RFC8539] */
|
||||
/* option codes 110-111 are unassigned [RFC3679] */
|
||||
SD_DHCP_OPTION_NETINFO_ADDRESS = 112, /* [RFC3679] */
|
||||
SD_DHCP_OPTION_NETINFO_TAG = 113, /* [RFC3679] */
|
||||
SD_DHCP_OPTION_DHCP_CAPTIVE_PORTAL = 114, /* [RFC8910] */
|
||||
/* option code 115 is unassigned [RFC3679] */
|
||||
SD_DHCP_OPTION_AUTO_CONFIG = 116, /* [RFC2563] */
|
||||
SD_DHCP_OPTION_NAME_SERVICE_SEARCH = 117, /* [RFC2937] */
|
||||
SD_DHCP_OPTION_SUBNET_SELECTION = 118, /* [RFC3011] */
|
||||
SD_DHCP_OPTION_DOMAIN_SEARCH = 119, /* [RFC3397] */
|
||||
SD_DHCP_OPTION_SIP_SERVER = 120, /* [RFC3361] */
|
||||
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, /* [RFC3442] */
|
||||
SD_DHCP_OPTION_CABLELABS_CLIENT_CONFIGURATION = 122, /* [RFC3495] */
|
||||
SD_DHCP_OPTION_GEOCONF = 123, /* [RFC6225] */
|
||||
SD_DHCP_OPTION_VENDOR_CLASS = 124, /* [RFC3925] */
|
||||
SD_DHCP_OPTION_VENDOR_SPECIFIC_INFORMATION = 125, /* [RFC3925] */
|
||||
/* option codes 126-127 are unassigned [RFC3679] */
|
||||
/* option codes 128-135 are assigned to use by PXE, but they are vendor specific [RFC4578] */
|
||||
SD_DHCP_OPTION_PANA_AGENT = 136, /* [RFC5192] */
|
||||
SD_DHCP_OPTION_LOST_SERVER_FQDN = 137, /* [RFC5223] */
|
||||
SD_DHCP_OPTION_CAPWAP_AC_ADDRESS = 138, /* [RFC5417] */
|
||||
SD_DHCP_OPTION_MOS_ADDRESS = 139, /* [RFC5678] */
|
||||
SD_DHCP_OPTION_MOS_FQDN = 140, /* [RFC5678] */
|
||||
SD_DHCP_OPTION_SIP_SERVICE_DOMAINS = 141, /* [RFC6011] */
|
||||
SD_DHCP_OPTION_ANDSF_ADDRESS = 142, /* [RFC6153] */
|
||||
SD_DHCP_OPTION_SZTP_REDIRECT = 143, /* [RFC8572] */
|
||||
SD_DHCP_OPTION_GEOLOC = 144, /* [RFC6225] */
|
||||
SD_DHCP_OPTION_FORCERENEW_NONCE_CAPABLE = 145, /* [RFC6704] */
|
||||
SD_DHCP_OPTION_RDNSS_SELECTION = 146, /* [RFC6731] */
|
||||
SD_DHCP_OPTION_DOTS_RI = 147, /* [RFC8973] */
|
||||
SD_DHCP_OPTION_DOTS_ADDRESS = 148, /* [RFC8973] */
|
||||
/* option code 149 is unassigned [RFC3942] */
|
||||
SD_DHCP_OPTION_TFTP_SERVER_ADDRESS = 150, /* [RFC5859] */
|
||||
SD_DHCP_OPTION_STATUS_CODE = 151, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_BASE_TIME = 152, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_START_TIME_OF_STATE = 153, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_QUERY_START_TIME = 154, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_QUERY_END_TIME = 155, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_DHCP_STATE = 156, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_DATA_SOURCE = 157, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_PCP_SERVER = 158, /* [RFC7291] */
|
||||
SD_DHCP_OPTION_PORT_PARAMS = 159, /* [RFC7618] */
|
||||
/* option code 160 is unassigned [RFC7710][RFC8910] */
|
||||
SD_DHCP_OPTION_MUD_URL = 161, /* [RFC8520] */
|
||||
/* option codes 162-174 are unassigned [RFC3942] */
|
||||
/* option codes 175-177 are temporary assigned. */
|
||||
/* option codes 178-207 are unassigned [RFC3942] */
|
||||
SD_DHCP_OPTION_PXELINUX_MAGIC = 208, /* [RFC5071] Deprecated */
|
||||
SD_DHCP_OPTION_CONFIGURATION_FILE = 209, /* [RFC5071] */
|
||||
SD_DHCP_OPTION_PATH_PREFIX = 210, /* [RFC5071] */
|
||||
SD_DHCP_OPTION_REBOOT_TIME = 211, /* [RFC5071] */
|
||||
SD_DHCP_OPTION_6RD = 212, /* [RFC5969] */
|
||||
SD_DHCP_OPTION_ACCESS_DOMAIN = 213, /* [RFC5986] */
|
||||
/* option codes 214-219 are unassigned */
|
||||
SD_DHCP_OPTION_SUBNET_ALLOCATION = 220, /* [RFC6656] */
|
||||
SD_DHCP_OPTION_VIRTUAL_SUBNET_SELECTION = 221, /* [RFC6607] */
|
||||
/* option codes 222-223 are unassigned [RFC3942] */
|
||||
/* option codes 224-254 are reserved for private use */
|
||||
SD_DHCP_OPTION_PRIVATE_BASE = 224,
|
||||
SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249, /* [RFC7844] */
|
||||
SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY = 252, /* [RFC7844] */
|
||||
SD_DHCP_OPTION_PRIVATE_LAST = 254,
|
||||
SD_DHCP_OPTION_END = 255, /* [RFC2132] */
|
||||
};
|
||||
|
||||
/* Suboptions for SD_DHCP_OPTION_RELAY_AGENT_INFORMATION option */
|
||||
enum {
|
||||
SD_DHCP_RELAY_AGENT_CIRCUIT_ID = 1,
|
||||
SD_DHCP_RELAY_AGENT_REMOTE_ID = 2,
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp_client sd_dhcp_client;
|
||||
|
||||
typedef int (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata);
|
||||
int sd_dhcp_client_set_callback(
|
||||
sd_dhcp_client *client,
|
||||
sd_dhcp_client_callback_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_ifindex(
|
||||
sd_dhcp_client *client,
|
||||
int interface_index);
|
||||
int sd_dhcp_client_set_ifname(
|
||||
sd_dhcp_client *client,
|
||||
const char *interface_name);
|
||||
int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret);
|
||||
int sd_dhcp_client_set_mac(
|
||||
sd_dhcp_client *client,
|
||||
const uint8_t *addr,
|
||||
const uint8_t *bcast_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);
|
||||
int sd_dhcp_client_set_iaid_duid(
|
||||
sd_dhcp_client *client,
|
||||
bool iaid_set,
|
||||
uint32_t iaid,
|
||||
uint16_t duid_type,
|
||||
const void *duid,
|
||||
size_t duid_len);
|
||||
int sd_dhcp_client_set_iaid_duid_llt(
|
||||
sd_dhcp_client *client,
|
||||
bool iaid_set,
|
||||
uint32_t iaid,
|
||||
uint64_t llt_time);
|
||||
int sd_dhcp_client_set_duid(
|
||||
sd_dhcp_client *client,
|
||||
uint16_t duid_type,
|
||||
const void *duid,
|
||||
size_t duid_len);
|
||||
int sd_dhcp_client_set_duid_llt(
|
||||
sd_dhcp_client *client,
|
||||
uint64_t llt_time);
|
||||
int sd_dhcp_client_get_client_id(
|
||||
sd_dhcp_client *client,
|
||||
uint8_t *type,
|
||||
const uint8_t **data,
|
||||
size_t *data_len);
|
||||
int sd_dhcp_client_set_mtu(
|
||||
sd_dhcp_client *client,
|
||||
uint32_t mtu);
|
||||
int sd_dhcp_client_set_max_attempts(
|
||||
sd_dhcp_client *client,
|
||||
uint64_t attempt);
|
||||
int sd_dhcp_client_set_client_port(
|
||||
sd_dhcp_client *client,
|
||||
uint16_t port);
|
||||
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_set_mud_url(
|
||||
sd_dhcp_client *client,
|
||||
const char *mudurl);
|
||||
int sd_dhcp_client_set_user_class(
|
||||
sd_dhcp_client *client,
|
||||
char * const *user_class);
|
||||
int sd_dhcp_client_get_lease(
|
||||
sd_dhcp_client *client,
|
||||
sd_dhcp_lease **ret);
|
||||
int sd_dhcp_client_set_service_type(
|
||||
sd_dhcp_client *client,
|
||||
int type);
|
||||
int sd_dhcp_client_set_fallback_lease_lifetime(
|
||||
sd_dhcp_client *client,
|
||||
uint32_t fallback_lease_lifetime);
|
||||
|
||||
int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
|
||||
int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
|
||||
|
||||
int sd_dhcp_client_is_running(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_stop(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_start(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_send_release(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_send_decline(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_send_renew(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);
|
||||
|
||||
/* NOTE: anonymize parameter is used to initialize PRL memory with different
|
||||
* options when using RFC7844 Anonymity Profiles */
|
||||
int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize);
|
||||
|
||||
int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret);
|
||||
|
||||
int sd_dhcp_client_attach_event(
|
||||
sd_dhcp_client *client,
|
||||
sd_event *event,
|
||||
int64_t priority);
|
||||
int sd_dhcp_client_detach_event(sd_dhcp_client *client);
|
||||
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_client, sd_dhcp_client_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddhcpleasehfoo
|
||||
#define foosddhcpleasehfoo
|
||||
|
||||
/***
|
||||
Copyright © 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 <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_dhcp_lease sd_dhcp_lease;
|
||||
typedef struct sd_dhcp_route 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);
|
||||
|
||||
typedef enum sd_dhcp_lease_server_type_t {
|
||||
SD_DHCP_LEASE_DNS,
|
||||
SD_DHCP_LEASE_NTP,
|
||||
SD_DHCP_LEASE_SIP,
|
||||
SD_DHCP_LEASE_POP3,
|
||||
SD_DHCP_LEASE_SMTP,
|
||||
SD_DHCP_LEASE_LPR,
|
||||
_SD_DHCP_LEASE_SERVER_TYPE_MAX,
|
||||
_SD_DHCP_LEASE_SERVER_TYPE_INVALID = -EINVAL,
|
||||
_SD_ENUM_FORCE_S64(DHCP_LEASE_SERVER_TYPE),
|
||||
} sd_dhcp_lease_server_type_t;
|
||||
|
||||
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_t1(sd_dhcp_lease *lease, uint32_t *t1);
|
||||
int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2);
|
||||
int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const 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_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const 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_sip(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_lpr(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_search_domains(sd_dhcp_lease *lease, char ***domains);
|
||||
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_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret);
|
||||
int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret);
|
||||
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len);
|
||||
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len);
|
||||
int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone);
|
||||
int sd_dhcp_lease_get_6rd(
|
||||
sd_dhcp_lease *lease,
|
||||
uint8_t *ret_ipv4masklen,
|
||||
uint8_t *ret_prefixlen,
|
||||
struct in6_addr *ret_prefix,
|
||||
const struct in_addr **ret_br_addresses,
|
||||
size_t *ret_n_br_addresses);
|
||||
|
||||
int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination);
|
||||
int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length);
|
||||
int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddhcpoptionhfoo
|
||||
#define foosddhcpoptionhfoo
|
||||
|
||||
/***
|
||||
Copyright © 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 <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_dhcp_option sd_dhcp_option;
|
||||
|
||||
int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret);
|
||||
sd_dhcp_option *sd_dhcp_option_ref(sd_dhcp_option *ra);
|
||||
sd_dhcp_option *sd_dhcp_option_unref(sd_dhcp_option *ra);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_option, sd_dhcp_option_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Reference in a new issue