|
Packit Service |
87a54e |
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
Packit |
5756e2 |
/*
|
|
Packit |
5756e2 |
* Copyright (C) 2005 - 2010 Red Hat, Inc.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include "nm-default.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include <unistd.h>
|
|
Packit |
5756e2 |
#include <arpa/inet.h>
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include "nm-glib-aux/nm-dedup-multi.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include "nm-dhcp-utils.h"
|
|
Packit |
5756e2 |
#include "nm-utils.h"
|
|
Packit |
5756e2 |
#include "nm-config.h"
|
|
Packit |
5756e2 |
#include "NetworkManagerUtils.h"
|
|
Packit |
5756e2 |
#include "platform/nm-platform.h"
|
|
Packit |
5756e2 |
#include "nm-dhcp-client-logging.h"
|
|
Packit |
5756e2 |
#include "nm-core-internal.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static gboolean
|
|
Packit Service |
a1bd4f |
ip4_process_dhcpcd_rfc3442_routes(const char * iface,
|
|
Packit Service |
a1bd4f |
const char * str,
|
|
Packit Service |
a1bd4f |
guint32 route_table,
|
|
Packit Service |
a1bd4f |
guint32 route_metric,
|
|
Packit Service |
a1bd4f |
NMIP4Config *ip4_config,
|
|
Packit Service |
a1bd4f |
guint32 * gwaddr)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gs_free const char **routes = NULL;
|
|
Packit Service |
a1bd4f |
const char ** r;
|
|
Packit Service |
a1bd4f |
gboolean have_routes = FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
routes = nm_utils_strsplit_set(str, " ");
|
|
Packit Service |
a1bd4f |
if (!routes)
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if ((NM_PTRARRAY_LEN(routes) % 2) != 0) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4, iface, " classless static routes provided, but invalid");
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (r = routes; *r; r += 2) {
|
|
Packit Service |
a1bd4f |
char * slash;
|
|
Packit Service |
a1bd4f |
NMPlatformIP4Route route;
|
|
Packit Service |
a1bd4f |
int rt_cidr = 32;
|
|
Packit Service |
a1bd4f |
guint32 rt_addr, rt_route;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
slash = strchr(*r, '/');
|
|
Packit Service |
a1bd4f |
if (slash) {
|
|
Packit Service |
a1bd4f |
*slash = '\0';
|
|
Packit Service |
a1bd4f |
errno = 0;
|
|
Packit Service |
a1bd4f |
rt_cidr = strtol(slash + 1, NULL, 10);
|
|
Packit Service |
a1bd4f |
if (errno || rt_cidr > 32) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4,
|
|
Packit Service |
a1bd4f |
iface,
|
|
Packit Service |
a1bd4f |
"DHCP provided invalid classless static route cidr: '%s'",
|
|
Packit Service |
a1bd4f |
slash + 1);
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET, *r, &rt_addr) <= 0) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4,
|
|
Packit Service |
a1bd4f |
iface,
|
|
Packit Service |
a1bd4f |
"DHCP provided invalid classless static route address: '%s'",
|
|
Packit Service |
a1bd4f |
*r);
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET, *(r + 1), &rt_route) <= 0) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4,
|
|
Packit Service |
a1bd4f |
iface,
|
|
Packit Service |
a1bd4f |
"DHCP provided invalid classless static route gateway: '%s'",
|
|
Packit Service |
a1bd4f |
*(r + 1));
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
have_routes = TRUE;
|
|
Packit Service |
a1bd4f |
if (rt_cidr == 0 && rt_addr == 0) {
|
|
Packit Service |
a1bd4f |
/* FIXME: how to handle multiple routers? */
|
|
Packit Service |
a1bd4f |
*gwaddr = rt_route;
|
|
Packit Service |
a1bd4f |
} else {
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4,
|
|
Packit Service |
a1bd4f |
iface,
|
|
Packit Service |
a1bd4f |
" classless static route %s/%d gw %s",
|
|
Packit Service |
a1bd4f |
*r,
|
|
Packit Service |
a1bd4f |
rt_cidr,
|
|
Packit Service |
a1bd4f |
*(r + 1));
|
|
Packit Service |
a1bd4f |
memset(&route, 0, sizeof(route));
|
|
Packit Service |
a1bd4f |
route.network = nm_utils_ip4_address_clear_host_address(rt_addr, rt_cidr);
|
|
Packit Service |
a1bd4f |
route.plen = rt_cidr;
|
|
Packit Service |
a1bd4f |
route.gateway = rt_route;
|
|
Packit Service |
a1bd4f |
route.rt_source = NM_IP_CONFIG_SOURCE_DHCP;
|
|
Packit Service |
a1bd4f |
route.metric = route_metric;
|
|
Packit Service |
a1bd4f |
route.table_coerced = nm_platform_route_table_coerce(route_table);
|
|
Packit Service |
a1bd4f |
nm_ip4_config_add_route(ip4_config, &route, NULL);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return have_routes;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static gboolean
|
|
Packit Service |
a1bd4f |
process_dhclient_rfc3442_route(const char *const **p_octets, NMPlatformIP4Route *route)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
const char *const *o = *p_octets;
|
|
Packit Service |
a1bd4f |
gs_free char * next_hop = NULL;
|
|
Packit Service |
a1bd4f |
int addr_len;
|
|
Packit Service |
a1bd4f |
int v_plen;
|
|
Packit Service |
a1bd4f |
in_addr_t tmp_addr;
|
|
Packit Service |
a1bd4f |
in_addr_t v_network = 0;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
v_plen = _nm_utils_ascii_str_to_int64(*o, 10, 0, 32, -1);
|
|
Packit Service |
a1bd4f |
if (v_plen == -1)
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
o++;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
addr_len = v_plen > 0 ? ((v_plen - 1) / 8) + 1 : 0;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* ensure there's at least the address + next hop left */
|
|
Packit Service |
a1bd4f |
if (NM_PTRARRAY_LEN(o) < addr_len + 4)
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (v_plen > 0) {
|
|
Packit Service |
a1bd4f |
const char * addr[4] = {"0", "0", "0", "0"};
|
|
Packit Service |
a1bd4f |
gs_free char *str_addr = NULL;
|
|
Packit Service |
a1bd4f |
int i;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (i = 0; i < addr_len; i++)
|
|
Packit Service |
a1bd4f |
addr[i] = *o++;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str_addr = g_strjoin(".", addr[0], addr[1], addr[2], addr[3], NULL);
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET, str_addr, &tmp_addr) <= 0)
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
v_network = nm_utils_ip4_address_clear_host_address(tmp_addr, v_plen);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
next_hop = g_strjoin(".", o[0], o[1], o[2], o[3], NULL);
|
|
Packit Service |
a1bd4f |
o += 4;
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET, next_hop, &tmp_addr) <= 0)
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
*route = (NMPlatformIP4Route){
|
|
Packit Service |
a1bd4f |
.network = v_network,
|
|
Packit Service |
a1bd4f |
.plen = v_plen,
|
|
Packit Service |
a1bd4f |
.gateway = tmp_addr,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
*p_octets = o;
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static gboolean
|
|
Packit Service |
a1bd4f |
ip4_process_dhclient_rfc3442_routes(const char * iface,
|
|
Packit Service |
a1bd4f |
const char * str,
|
|
Packit Service |
a1bd4f |
guint32 route_table,
|
|
Packit Service |
a1bd4f |
guint32 route_metric,
|
|
Packit Service |
a1bd4f |
NMIP4Config *ip4_config,
|
|
Packit Service |
a1bd4f |
guint32 * gwaddr)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gs_free const char **octets = NULL;
|
|
Packit Service |
a1bd4f |
const char *const * o;
|
|
Packit Service |
a1bd4f |
gboolean have_routes = FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
octets = nm_utils_strsplit_set_with_empty(str, " .");
|
|
Packit Service |
a1bd4f |
if (NM_PTRARRAY_LEN(octets) < 5) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4, iface, "ignoring invalid classless static routes '%s'", str);
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
o = octets;
|
|
Packit Service |
a1bd4f |
while (*o) {
|
|
Packit Service |
a1bd4f |
NMPlatformIP4Route route;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!process_dhclient_rfc3442_route(&o, &route)) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4, iface, "ignoring invalid classless static routes");
|
|
Packit Service |
a1bd4f |
return have_routes;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
have_routes = TRUE;
|
|
Packit Service |
a1bd4f |
if (!route.plen) {
|
|
Packit Service |
a1bd4f |
/* gateway passed as classless static route */
|
|
Packit Service |
a1bd4f |
*gwaddr = route.gateway;
|
|
Packit Service |
a1bd4f |
} else {
|
|
Packit Service |
a1bd4f |
char b1[INET_ADDRSTRLEN];
|
|
Packit Service |
a1bd4f |
char b2[INET_ADDRSTRLEN];
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* normal route */
|
|
Packit Service |
a1bd4f |
route.rt_source = NM_IP_CONFIG_SOURCE_DHCP;
|
|
Packit Service |
a1bd4f |
route.metric = route_metric;
|
|
Packit Service |
a1bd4f |
route.table_coerced = nm_platform_route_table_coerce(route_table);
|
|
Packit Service |
a1bd4f |
nm_ip4_config_add_route(ip4_config, &route, NULL);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4,
|
|
Packit Service |
a1bd4f |
iface,
|
|
Packit Service |
a1bd4f |
" classless static route %s/%d gw %s",
|
|
Packit Service |
a1bd4f |
_nm_utils_inet4_ntop(route.network, b1),
|
|
Packit Service |
a1bd4f |
route.plen,
|
|
Packit Service |
a1bd4f |
_nm_utils_inet4_ntop(route.gateway, b2));
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return have_routes;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static gboolean
|
|
Packit Service |
a1bd4f |
ip4_process_classless_routes(const char * iface,
|
|
Packit Service |
a1bd4f |
GHashTable * options,
|
|
Packit Service |
a1bd4f |
guint32 route_table,
|
|
Packit Service |
a1bd4f |
guint32 route_metric,
|
|
Packit Service |
a1bd4f |
NMIP4Config *ip4_config,
|
|
Packit Service |
a1bd4f |
guint32 * gwaddr)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
const char *str, *p;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(options != NULL, FALSE);
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(ip4_config != NULL, FALSE);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
*gwaddr = 0;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* dhcpd/dhclient in Fedora has support for rfc3442 implemented using a
|
|
Packit Service |
a1bd4f |
* slightly different format:
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* option classless-static-routes = array of (destination-descriptor ip-address);
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* which results in:
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* 0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* dhcpcd supports classless static routes natively and uses this same
|
|
Packit Service |
a1bd4f |
* option identifier with the following format:
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* 192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41
|
|
Packit Service |
a1bd4f |
*/
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "classless_static_routes");
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* dhclient doesn't have actual support for rfc3442 classless static routes
|
|
Packit Service |
a1bd4f |
* upstream. Thus, people resort to defining the option in dhclient.conf
|
|
Packit Service |
a1bd4f |
* and using arbitrary formats like so:
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* See https://lists.isc.org/pipermail/dhcp-users/2008-December/007629.html
|
|
Packit Service |
a1bd4f |
*/
|
|
Packit Service |
a1bd4f |
if (!str)
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "rfc3442_classless_static_routes");
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* Microsoft version; same as rfc3442 but with a different option # (249) */
|
|
Packit Service |
a1bd4f |
if (!str)
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "ms_classless_static_routes");
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!str || !strlen(str))
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
p = str;
|
|
Packit Service |
a1bd4f |
while (*p) {
|
|
Packit Service |
a1bd4f |
if (!g_ascii_isdigit(*p) && (*p != ' ') && (*p != '.') && (*p != '/')) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4, iface, "ignoring invalid classless static routes '%s'", str);
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
p++;
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (strchr(str, '/')) {
|
|
Packit Service |
a1bd4f |
/* dhcpcd format */
|
|
Packit Service |
a1bd4f |
return ip4_process_dhcpcd_rfc3442_routes(iface,
|
|
Packit Service |
a1bd4f |
str,
|
|
Packit Service |
a1bd4f |
route_table,
|
|
Packit Service |
a1bd4f |
route_metric,
|
|
Packit Service |
a1bd4f |
ip4_config,
|
|
Packit Service |
a1bd4f |
gwaddr);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return ip4_process_dhclient_rfc3442_routes(iface,
|
|
Packit Service |
a1bd4f |
str,
|
|
Packit Service |
a1bd4f |
route_table,
|
|
Packit Service |
a1bd4f |
route_metric,
|
|
Packit Service |
a1bd4f |
ip4_config,
|
|
Packit Service |
a1bd4f |
gwaddr);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
process_classful_routes(const char * iface,
|
|
Packit Service |
a1bd4f |
GHashTable * options,
|
|
Packit Service |
a1bd4f |
guint32 route_table,
|
|
Packit Service |
a1bd4f |
guint32 route_metric,
|
|
Packit Service |
a1bd4f |
NMIP4Config *ip4_config)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gs_free const char **searches = NULL;
|
|
Packit Service |
a1bd4f |
const char ** s;
|
|
Packit Service |
a1bd4f |
const char * str;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "static_routes");
|
|
Packit Service |
a1bd4f |
if (!str)
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
searches = nm_utils_strsplit_set(str, " ");
|
|
Packit Service |
a1bd4f |
if (!searches)
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if ((NM_PTRARRAY_LEN(searches) % 2) != 0) {
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP, iface, " static routes provided, but invalid");
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (s = searches; *s; s += 2) {
|
|
Packit Service |
a1bd4f |
NMPlatformIP4Route route;
|
|
Packit Service |
a1bd4f |
guint32 rt_addr, rt_route;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET, *s, &rt_addr) <= 0) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP, iface, "DHCP provided invalid static route address: '%s'", *s);
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET, *(s + 1), &rt_route) <= 0) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP, iface, "DHCP provided invalid static route gateway: '%s'", *(s + 1));
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
// FIXME: ensure the IP address and route are sane
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
memset(&route, 0, sizeof(route));
|
|
Packit Service |
a1bd4f |
route.network = rt_addr;
|
|
Packit Service |
a1bd4f |
/* RFC 2132, updated by RFC 3442:
|
|
Packit Service |
a1bd4f |
* The Static Routes option (option 33) does not provide a subnet mask
|
|
Packit Service |
a1bd4f |
* for each route - it is assumed that the subnet mask is implicit in
|
|
Packit Service |
a1bd4f |
* whatever network number is specified in each route entry */
|
|
Packit Service |
a1bd4f |
route.plen = _nm_utils_ip4_get_default_prefix(rt_addr);
|
|
Packit Service |
a1bd4f |
if (rt_addr & ~_nm_utils_ip4_prefix_to_netmask(route.plen)) {
|
|
Packit Service |
a1bd4f |
/* RFC 943: target not "this network"; using host routing */
|
|
Packit Service |
a1bd4f |
route.plen = 32;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
route.gateway = rt_route;
|
|
Packit Service |
a1bd4f |
route.rt_source = NM_IP_CONFIG_SOURCE_DHCP;
|
|
Packit Service |
a1bd4f |
route.metric = route_metric;
|
|
Packit Service |
a1bd4f |
route.table_coerced = nm_platform_route_table_coerce(route_table);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
route.network = nm_utils_ip4_address_clear_host_address(route.network, route.plen);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_ip4_config_add_route(ip4_config, &route, NULL);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP,
|
|
Packit Service |
a1bd4f |
iface,
|
|
Packit Service |
a1bd4f |
" static route %s",
|
|
Packit Service |
a1bd4f |
nm_platform_ip4_route_to_string(&route, NULL, 0));
|
|
Packit Service |
a1bd4f |
}
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
process_domain_search(const char *iface, const char *str, GFunc add_func, gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gs_free const char **searches = NULL;
|
|
Packit Service |
a1bd4f |
gs_free char * unescaped = NULL;
|
|
Packit Service |
a1bd4f |
const char ** s;
|
|
Packit Service |
a1bd4f |
char * p;
|
|
Packit Service |
a1bd4f |
int i;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_return_if_fail(str != NULL);
|
|
Packit Service |
a1bd4f |
g_return_if_fail(add_func != NULL);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
unescaped = g_strdup(str);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
p = unescaped;
|
|
Packit Service |
a1bd4f |
do {
|
|
Packit Service |
a1bd4f |
p = strstr(p, "\\032");
|
|
Packit Service |
a1bd4f |
if (!p)
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* Clear the escaped space with real spaces */
|
|
Packit Service |
a1bd4f |
for (i = 0; i < 4; i++)
|
|
Packit Service |
a1bd4f |
*p++ = ' ';
|
|
Packit Service |
a1bd4f |
} while (*p++);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (strchr(unescaped, '\\')) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP, iface, " invalid domain search: '%s'", unescaped);
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
searches = nm_utils_strsplit_set(unescaped, " ");
|
|
Packit Service |
a1bd4f |
for (s = searches; searches && *s; s++) {
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP, iface, " domain search '%s'", *s);
|
|
Packit Service |
a1bd4f |
add_func((gpointer) *s, user_data);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
ip4_add_domain_search(gpointer data, gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
nm_ip4_config_add_search(NM_IP4_CONFIG(user_data), (const char *) data);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
NMIP4Config *
|
|
Packit Service |
a1bd4f |
nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx,
|
|
Packit Service |
a1bd4f |
int ifindex,
|
|
Packit Service |
a1bd4f |
const char * iface,
|
|
Packit Service |
a1bd4f |
GHashTable * options,
|
|
Packit Service |
a1bd4f |
guint32 route_table,
|
|
Packit Service |
a1bd4f |
guint32 route_metric)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gs_unref_object NMIP4Config *ip4_config = NULL;
|
|
Packit Service |
a1bd4f |
guint32 tmp_addr;
|
|
Packit Service |
a1bd4f |
in_addr_t addr;
|
|
Packit Service |
a1bd4f |
NMPlatformIP4Address address;
|
|
Packit Service |
a1bd4f |
char * str = NULL;
|
|
Packit Service |
a1bd4f |
gboolean gateway_has = FALSE;
|
|
Packit Service |
a1bd4f |
guint32 gateway = 0;
|
|
Packit Service |
a1bd4f |
guint8 plen = 0;
|
|
Packit Service |
a1bd4f |
char sbuf[NM_UTILS_INET_ADDRSTRLEN];
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(options != NULL, NULL);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
ip4_config = nm_ip4_config_new(multi_idx, ifindex);
|
|
Packit Service |
a1bd4f |
memset(&address, 0, sizeof(address));
|
|
Packit Service |
a1bd4f |
address.timestamp = nm_utils_get_monotonic_timestamp_sec();
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "ip_address");
|
|
Packit Service |
a1bd4f |
if (str && (inet_pton(AF_INET, str, &addr) > 0))
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " address %s", str);
|
|
Packit Service |
a1bd4f |
else
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "subnet_mask");
|
|
Packit Service |
a1bd4f |
if (str && (inet_pton(AF_INET, str, &tmp_addr) > 0)) {
|
|
Packit Service |
a1bd4f |
plen = nm_utils_ip4_netmask_to_prefix(tmp_addr);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " plen %d (%s)", plen, str);
|
|
Packit Service |
a1bd4f |
} else {
|
|
Packit Service |
a1bd4f |
/* Get default netmask for the IP according to appropriate class. */
|
|
Packit Service |
a1bd4f |
plen = _nm_utils_ip4_get_default_prefix(addr);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " plen %d (default)", plen);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
nm_platform_ip4_address_set_addr(&address, addr, plen);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* Routes: if the server returns classless static routes, we MUST ignore
|
|
Packit Service |
a1bd4f |
* the 'static_routes' option.
|
|
Packit Service |
a1bd4f |
*/
|
|
Packit Service |
a1bd4f |
if (!ip4_process_classless_routes(iface,
|
|
Packit Service |
a1bd4f |
options,
|
|
Packit Service |
a1bd4f |
route_table,
|
|
Packit Service |
a1bd4f |
route_metric,
|
|
Packit Service |
a1bd4f |
ip4_config,
|
|
Packit Service |
a1bd4f |
&gateway))
|
|
Packit Service |
a1bd4f |
process_classful_routes(iface, options, route_table, route_metric, ip4_config);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (gateway) {
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " gateway %s", _nm_utils_inet4_ntop(gateway, sbuf));
|
|
Packit Service |
a1bd4f |
gateway_has = TRUE;
|
|
Packit Service |
a1bd4f |
} else {
|
|
Packit Service |
a1bd4f |
/* If the gateway wasn't provided as a classless static route with a
|
|
Packit Service |
a1bd4f |
* subnet length of 0, try to find it using the old-style 'routers' option.
|
|
Packit Service |
a1bd4f |
*/
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "routers");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
gs_free const char **routers = nm_utils_strsplit_set(str, " ");
|
|
Packit Service |
a1bd4f |
const char ** s;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (s = routers; routers && *s; s++) {
|
|
Packit Service |
a1bd4f |
/* FIXME: how to handle multiple routers? */
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET, *s, &gateway) > 0) {
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " gateway %s", *s);
|
|
Packit Service |
a1bd4f |
gateway_has = TRUE;
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
} else
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4, iface, "ignoring invalid gateway '%s'", *s);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (gateway_has) {
|
|
Packit Service |
a1bd4f |
const NMPlatformIP4Route r = {
|
|
Packit Service |
a1bd4f |
.rt_source = NM_IP_CONFIG_SOURCE_DHCP,
|
|
Packit Service |
a1bd4f |
.gateway = gateway,
|
|
Packit Service |
a1bd4f |
.table_coerced = nm_platform_route_table_coerce(route_table),
|
|
Packit Service |
a1bd4f |
.metric = route_metric,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_ip4_config_add_route(ip4_config, &r, NULL);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "dhcp_lease_time");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
address.lifetime = address.preferred = strtoul(str, NULL, 10);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " lease time %u", address.lifetime);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
address.addr_source = NM_IP_CONFIG_SOURCE_DHCP;
|
|
Packit Service |
a1bd4f |
nm_ip4_config_add_address(ip4_config, &address);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "host_name");
|
|
Packit Service |
a1bd4f |
if (str)
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " hostname '%s'", str);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "domain_name_servers");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
gs_free const char **dns = nm_utils_strsplit_set(str, " ");
|
|
Packit Service |
a1bd4f |
const char ** s;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (s = dns; dns && *s; s++) {
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET, *s, &tmp_addr) > 0) {
|
|
Packit Service |
a1bd4f |
if (tmp_addr) {
|
|
Packit Service |
a1bd4f |
nm_ip4_config_add_nameserver(ip4_config, tmp_addr);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " nameserver '%s'", *s);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
} else
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4, iface, "ignoring invalid nameserver '%s'", *s);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "domain_name");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
gs_free const char **domains = nm_utils_strsplit_set(str, " ");
|
|
Packit Service |
a1bd4f |
const char ** s;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (s = domains; domains && *s; s++) {
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " domain name '%s'", *s);
|
|
Packit Service |
a1bd4f |
nm_ip4_config_add_domain(ip4_config, *s);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "domain_search");
|
|
Packit Service |
a1bd4f |
if (str)
|
|
Packit Service |
a1bd4f |
process_domain_search(iface, str, ip4_add_domain_search, ip4_config);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "netbios_name_servers");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
gs_free const char **nbns = nm_utils_strsplit_set(str, " ");
|
|
Packit Service |
a1bd4f |
const char ** s;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (s = nbns; nbns && *s; s++) {
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET, *s, &tmp_addr) > 0) {
|
|
Packit Service |
a1bd4f |
if (tmp_addr) {
|
|
Packit Service |
a1bd4f |
nm_ip4_config_add_wins(ip4_config, tmp_addr);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " wins '%s'", *s);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
} else
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4, iface, "ignoring invalid WINS server '%s'", *s);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "interface_mtu");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
int int_mtu;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
errno = 0;
|
|
Packit Service |
a1bd4f |
int_mtu = strtol(str, NULL, 10);
|
|
Packit Service |
a1bd4f |
if (NM_IN_SET(errno, EINVAL, ERANGE))
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (int_mtu > 576)
|
|
Packit Service |
a1bd4f |
nm_ip4_config_set_mtu(ip4_config, int_mtu, NM_IP_CONFIG_SOURCE_DHCP);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "nis_domain");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " NIS domain '%s'", str);
|
|
Packit Service |
a1bd4f |
nm_ip4_config_set_nis_domain(ip4_config, str);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "nis_servers");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
gs_free const char **nis = nm_utils_strsplit_set(str, " ");
|
|
Packit Service |
a1bd4f |
const char ** s;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (s = nis; nis && *s; s++) {
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET, *s, &tmp_addr) > 0) {
|
|
Packit Service |
a1bd4f |
if (tmp_addr) {
|
|
Packit Service |
a1bd4f |
nm_ip4_config_add_nis_server(ip4_config, tmp_addr);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP4, iface, " nis '%s'", *s);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
} else
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP4, iface, "ignoring invalid NIS server '%s'", *s);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "vendor_encapsulated_options");
|
|
Packit Service |
a1bd4f |
nm_ip4_config_set_metered(ip4_config, str && strstr(str, "ANDROID_METERED"));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return g_steal_pointer(&ip4_config);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
ip6_add_domain_search(gpointer data, gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
nm_ip6_config_add_search(NM_IP6_CONFIG(user_data), (const char *) data);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
NMPlatformIP6Address
|
|
Packit Service |
a1bd4f |
nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gs_strfreev char ** split_addr = NULL;
|
|
Packit Service |
a1bd4f |
NMPlatformIP6Address address = {
|
|
Packit Service |
a1bd4f |
0,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
struct in6_addr tmp_addr;
|
|
Packit Service |
a1bd4f |
char * str = NULL;
|
|
Packit Service |
a1bd4f |
int prefix;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(options != NULL, address);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "ip6_prefix");
|
|
Packit Service |
a1bd4f |
if (!str)
|
|
Packit Service |
a1bd4f |
return address;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
split_addr = g_strsplit(str, "/", 2);
|
|
Packit Service |
a1bd4f |
if (split_addr[0] == NULL && split_addr[1] == NULL) {
|
|
Packit Service |
a1bd4f |
nm_log_warn(LOGD_DHCP6, "DHCP returned prefix without length '%s'", str);
|
|
Packit Service |
a1bd4f |
return address;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!inet_pton(AF_INET6, split_addr[0], &tmp_addr)) {
|
|
Packit Service |
a1bd4f |
nm_log_warn(LOGD_DHCP6, "DHCP returned invalid prefix '%s'", str);
|
|
Packit Service |
a1bd4f |
return address;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
prefix = _nm_utils_ascii_str_to_int64(split_addr[1], 10, 0, 128, -1);
|
|
Packit Service |
a1bd4f |
if (prefix < 0) {
|
|
Packit Service |
a1bd4f |
nm_log_warn(LOGD_DHCP6, "DHCP returned prefix with invalid length '%s'", str);
|
|
Packit Service |
a1bd4f |
return address;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
address.address = tmp_addr;
|
|
Packit Service |
a1bd4f |
address.addr_source = NM_IP_CONFIG_SOURCE_DHCP;
|
|
Packit Service |
a1bd4f |
address.plen = prefix;
|
|
Packit Service |
a1bd4f |
address.timestamp = nm_utils_get_monotonic_timestamp_sec();
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "max_life");
|
|
Packit Service |
a1bd4f |
if (str)
|
|
Packit Service |
a1bd4f |
address.lifetime = strtoul(str, NULL, 10);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "preferred_life");
|
|
Packit Service |
a1bd4f |
if (str)
|
|
Packit Service |
a1bd4f |
address.preferred = strtoul(str, NULL, 10);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return address;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
NMIP6Config *
|
|
Packit Service |
a1bd4f |
nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx,
|
|
Packit Service |
a1bd4f |
int ifindex,
|
|
Packit Service |
a1bd4f |
const char * iface,
|
|
Packit Service |
a1bd4f |
GHashTable * options,
|
|
Packit Service |
a1bd4f |
gboolean info_only)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gs_unref_object NMIP6Config *ip6_config = NULL;
|
|
Packit Service |
a1bd4f |
struct in6_addr tmp_addr;
|
|
Packit Service |
a1bd4f |
NMPlatformIP6Address address;
|
|
Packit Service |
a1bd4f |
char * str = NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(options != NULL, NULL);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
memset(&address, 0, sizeof(address));
|
|
Packit Service |
a1bd4f |
address.plen = 128;
|
|
Packit Service |
a1bd4f |
address.timestamp = nm_utils_get_monotonic_timestamp_sec();
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
ip6_config = nm_ip6_config_new(multi_idx, ifindex);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "max_life");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
address.lifetime = strtoul(str, NULL, 10);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP6, iface, " valid_lft %u", address.lifetime);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "preferred_life");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
address.preferred = strtoul(str, NULL, 10);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP6, iface, " preferred_lft %u", address.preferred);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "ip6_address");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
if (!inet_pton(AF_INET6, str, &tmp_addr)) {
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP6, iface, "(%s): DHCP returned invalid address '%s'", iface, str);
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
address.address = tmp_addr;
|
|
Packit Service |
a1bd4f |
address.addr_source = NM_IP_CONFIG_SOURCE_DHCP;
|
|
Packit Service |
a1bd4f |
nm_ip6_config_add_address(ip6_config, &address);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP6, iface, " address %s", str);
|
|
Packit Service |
a1bd4f |
} else if (info_only == FALSE) {
|
|
Packit Service |
a1bd4f |
/* No address in Managed mode is a hard error */
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "host_name");
|
|
Packit Service |
a1bd4f |
if (str)
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP6, iface, " hostname '%s'", str);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "dhcp6_name_servers");
|
|
Packit Service |
a1bd4f |
if (str) {
|
|
Packit Service |
a1bd4f |
gs_free const char **dns = nm_utils_strsplit_set(str, " ");
|
|
Packit Service |
a1bd4f |
const char ** s;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (s = dns; dns && *s; s++) {
|
|
Packit Service |
a1bd4f |
if (inet_pton(AF_INET6, *s, &tmp_addr) > 0) {
|
|
Packit Service |
a1bd4f |
if (!IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) {
|
|
Packit Service |
a1bd4f |
nm_ip6_config_add_nameserver(ip6_config, &tmp_addr);
|
|
Packit Service |
a1bd4f |
_LOG2I(LOGD_DHCP6, iface, " nameserver '%s'", *s);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
} else
|
|
Packit Service |
a1bd4f |
_LOG2W(LOGD_DHCP6, iface, "ignoring invalid nameserver '%s'", *s);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
str = g_hash_table_lookup(options, "dhcp6_domain_search");
|
|
Packit Service |
a1bd4f |
if (str)
|
|
Packit Service |
a1bd4f |
process_domain_search(iface, str, ip6_add_domain_search, ip6_config);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return g_steal_pointer(&ip6_config);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
char *
|
|
Packit Service |
a1bd4f |
nm_dhcp_utils_duid_to_string(GBytes *duid)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gconstpointer data;
|
|
Packit Service |
a1bd4f |
gsize len;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(duid, NULL);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
data = g_bytes_get_data(duid, &len;;
|
|
Packit Service |
a1bd4f |
return nm_utils_bin2hexstr_full(data, len, ':', FALSE, NULL);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nm_dhcp_utils_client_id_string_to_bytes:
|
|
Packit |
5756e2 |
* @client_id: the client ID string
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Accepts either a hex string ("aa:bb:cc") representing a binary client ID
|
|
Packit |
5756e2 |
* (the first byte is assumed to be the 'type' field per RFC 2132 section 9.14),
|
|
Packit |
5756e2 |
* or a string representing a non-hardware-address client ID, in which case
|
|
Packit |
5756e2 |
* the 'type' field is set to 0.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Returns: the binary client ID suitable for sending over the wire
|
|
Packit |
5756e2 |
* to the DHCP server.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
GBytes *
|
|
Packit Service |
a1bd4f |
nm_dhcp_utils_client_id_string_to_bytes(const char *client_id)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
GBytes *bytes = NULL;
|
|
Packit Service |
a1bd4f |
guint len;
|
|
Packit Service |
a1bd4f |
char * c;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(client_id && client_id[0], NULL);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* Try as hex encoded */
|
|
Packit Service |
a1bd4f |
if (strchr(client_id, ':')) {
|
|
Packit Service |
a1bd4f |
bytes = nm_utils_hexstr2bin(client_id);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* the result must be at least two bytes long,
|
|
Packit Service |
a1bd4f |
* because @client_id contains a delimiter
|
|
Packit Service |
a1bd4f |
* but nm_utils_hexstr2bin() does not allow
|
|
Packit Service |
a1bd4f |
* leading nor trailing delimiters. */
|
|
Packit Service |
a1bd4f |
nm_assert(!bytes || g_bytes_get_size(bytes) >= 2);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (!bytes) {
|
|
Packit Service |
a1bd4f |
/* Fall back to string */
|
|
Packit Service |
a1bd4f |
len = strlen(client_id);
|
|
Packit Service |
a1bd4f |
c = g_malloc(len + 1);
|
|
Packit Service |
a1bd4f |
c[0] = 0; /* type: non-hardware address per RFC 2132 section 9.14 */
|
|
Packit Service |
a1bd4f |
memcpy(c + 1, client_id, len);
|
|
Packit Service |
a1bd4f |
bytes = g_bytes_new_take(c, len + 1);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return bytes;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nm_dhcp_utils_get_leasefile_path:
|
|
Packit |
5756e2 |
* @addr_family: the IP address family
|
|
Packit |
5756e2 |
* @plugin_name: the name of the plugin part of the lease file name
|
|
Packit |
5756e2 |
* @iface: the interface name to which the lease relates to
|
|
Packit |
5756e2 |
* @uuid: uuid of the connection to which the lease relates to
|
|
Packit |
5756e2 |
* @out_leasefile_path: will store the computed lease file path
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Constructs the lease file name on the basis of the calling plugin,
|
|
Packit |
5756e2 |
* interface name and connection uuid. Then returns in @out_leasefile_path
|
|
Packit |
5756e2 |
* the full path of the lease filename.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Returns: TRUE if the lease file already exists, FALSE otherwise.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
gboolean
|
|
Packit Service |
a1bd4f |
nm_dhcp_utils_get_leasefile_path(int addr_family,
|
|
Packit Service |
a1bd4f |
const char *plugin_name,
|
|
Packit Service |
a1bd4f |
const char *iface,
|
|
Packit Service |
a1bd4f |
const char *uuid,
|
|
Packit Service |
a1bd4f |
char ** out_leasefile_path)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gs_free char *rundir_path = NULL;
|
|
Packit Service |
a1bd4f |
gs_free char *statedir_path = NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
rundir_path = g_strdup_printf(NMRUNDIR "/%s%s-%s-%s.lease",
|
|
Packit Service |
a1bd4f |
plugin_name,
|
|
Packit Service |
a1bd4f |
addr_family == AF_INET6 ? "6" : "",
|
|
Packit Service |
a1bd4f |
uuid,
|
|
Packit Service |
a1bd4f |
iface);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (g_file_test(rundir_path, G_FILE_TEST_EXISTS)) {
|
|
Packit Service |
a1bd4f |
*out_leasefile_path = g_steal_pointer(&rundir_path);
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
statedir_path = g_strdup_printf(NMSTATEDIR "/%s%s-%s-%s.lease",
|
|
Packit Service |
a1bd4f |
plugin_name,
|
|
Packit Service |
a1bd4f |
addr_family == AF_INET6 ? "6" : "",
|
|
Packit Service |
a1bd4f |
uuid,
|
|
Packit Service |
a1bd4f |
iface);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (g_file_test(statedir_path, G_FILE_TEST_EXISTS)) {
|
|
Packit Service |
a1bd4f |
*out_leasefile_path = g_steal_pointer(&statedir_path);
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (nm_config_get_configure_and_quit(nm_config_get()) == NM_CONFIG_CONFIGURE_AND_QUIT_INITRD)
|
|
Packit Service |
a1bd4f |
*out_leasefile_path = g_steal_pointer(&rundir_path);
|
|
Packit Service |
a1bd4f |
else
|
|
Packit Service |
a1bd4f |
*out_leasefile_path = g_steal_pointer(&statedir_path);
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
char *
|
|
Packit Service |
a1bd4f |
nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
const char *start;
|
|
Packit Service |
a1bd4f |
const char *iaid;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
if (!lease)
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
iaid = g_hash_table_lookup(lease, "iaid");
|
|
Packit Service |
a1bd4f |
if (!iaid)
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
start = g_hash_table_lookup(lease, "life_starts");
|
|
Packit Service |
a1bd4f |
if (!start)
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
return g_strdup_printf("%s|%s", iaid, start);
|
|
Packit |
5756e2 |
}
|