Commit ec17242f authored by Thomas Haller's avatar Thomas Haller

platform: merge branch 'th/platform-wireguard'

Various cleanups. Also fixes a crash.

https://github.com/NetworkManager/NetworkManager/pull/193
parents c882633d 62d14e18
......@@ -31,31 +31,6 @@ typedef struct {
guint32 to;
} NMVlanQosMapping;
typedef struct {
NMIPAddr ip;
guint8 family;
guint8 mask;
} NMWireGuardAllowedIP;
#define NM_WG_PUBLIC_KEY_LEN 32
#define NM_WG_SYMMETRIC_KEY_LEN 32
typedef struct {
guint8 public_key[NM_WG_PUBLIC_KEY_LEN];
guint8 preshared_key[NM_WG_SYMMETRIC_KEY_LEN];
union {
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
} endpoint;
guint16 persistent_keepalive_interval;
struct timespec last_handshake_time;
guint64 rx_bytes, tx_bytes;
gsize allowedips_len;
NMWireGuardAllowedIP *allowedips;
} NMWireGuardPeer;
#define _NM_IP_TUNNEL_FLAG_ALL_IP6TNL \
( NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT \
| NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS \
......
......@@ -60,7 +60,8 @@ _get_keys (NMSettingVpn *setting,
if (len) {
g_ptr_array_sort (a, nm_strcmp_p);
g_ptr_array_add (a, NULL);
keys = g_memdup (a->pdata, a->len * sizeof (gpointer));
keys = g_malloc (a->len * sizeof (gpointer));
memcpy (keys, a->pdata, a->len * sizeof (gpointer));
/* we need to cache the keys *somewhere*. */
g_object_set_qdata_full (G_OBJECT (setting),
......
......@@ -57,6 +57,11 @@ nm_hash_update (NMHashState *state, const void *ptr, gsize n)
nm_assert (ptr);
nm_assert (n > 0);
/* Note: the data passed in here might be sensitive data (secrets),
* that we should nm_explicty_zero() afterwards. However, since
* we are using siphash24 with a random key, that is not really
* necessary. Something to keep in mind, if we ever move away from
* this hash implementation. */
c_siphash_append (&state->_state, ptr, n);
}
......
......@@ -106,7 +106,7 @@ nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
retval = g_vsnprintf (p, *len, format, args);
va_end (args);
if (retval >= *len) {
if ((gsize) retval >= *len) {
*buf = &p[*len];
*len = 0;
} else {
......@@ -115,6 +115,88 @@ nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
}
}
/**
* nm_utils_strbuf_seek_end:
* @buf: the input/output buffer
* @len: the input/output lenght of the buffer.
*
* Commonly, one uses nm_utils_strbuf_append*(), to incrementally
* append strings to the buffer. However, sometimes we need to use
* existing API to write to the buffer.
* After doing so, we want to adjust the buffer counter.
* Essentially,
*
* g_snprintf (buf, len, ...);
* nm_utils_strbuf_seek_end (&buf, &len);
*
* is almost the same as
*
* nm_utils_strbuf_append (&buf, &len, ...);
*
* They only behave differently, if the string fits exactly
* into the buffer without truncation. The former cannot distinguish
* the two cases, while the latter can.
*/
void
nm_utils_strbuf_seek_end (char **buf, gsize *len)
{
gsize l;
char *end;
nm_assert (len);
nm_assert (buf && *buf);
if (*len == 0)
return;
end = memchr (*buf, 0, *len);
if (!end) {
/* hm, no NUL character within len bytes.
* Just NUL terminate the array and consume them
* all. */
*buf += *len;
(*buf)[-1] = '\0';
*len = 0;
return;
}
l = end - *buf;
nm_assert (l < *len);
*buf = end;
*len -= l;
if (*len == 1) {
/* the last character of a buffer is the '\0'. There are two
* cases why that may happen:
* - but string was truncated
* - the string fit exactly into the buffer.
* Here we cannot distinguish between the two, so assume the string
* was truncated and signal that by setting @len to 0 and pointing the
* buffer *past* the end (like all other nm_utils_strbuf_*() functions).
*
* Note that nm_utils_strbuf_append_str() can distinguish between
* the two cases, and leaves @len at 1, if the string was not actually
* truncated.
*
* For consistancy, it might be better not to do this and just
* seek to end of the buffer (not past it). However, that would mean,
* in a series of
* g_snprintf()
* nm_utils_strbuf_seek_end()
* the length would never reach zero, but stay at 1. With this,
* it reaches len 0 early.
* It seems better to declare the buffer as fully consumed and set
* the length to zero.
*
* If the caller does not care about truncation, then this behavior
* is more sensible. If the caller cares about truncation, it must
* check earlier (right when the truncation occures).
*/
(*buf)++;
*len = 0;
}
}
/*****************************************************************************/
/**
......
......@@ -190,6 +190,53 @@ nm_ip_addr_set (int addr_family, gpointer dst, const NMIPAddr *src)
/*****************************************************************************/
static inline gboolean
nm_utils_mem_all_zero (gconstpointer mem, gsize len)
{
const guint8 *p;
for (p = mem; len-- > 0; p++) {
if (*p != 0)
return FALSE;
}
/* incidentally, a buffer with len==0, is also *all-zero*. */
return TRUE;
}
/*****************************************************************************/
/* like g_memdup(). The difference is that the @size argument is of type
* gsize, while g_memdup() has type guint. Since, the size of container types
* like GArray is guint as well, this means trying to g_memdup() an
* array,
* g_memdup (array->data, array->len * sizeof (ElementType))
* will lead to integer overflow, if there are more than G_MAXUINT/sizeof(ElementType)
* bytes. That seems unnecessarily dangerous to me.
* nm_memdup() avoids that, because its size argument is always large enough
* to contain all data that a GArray can hold.
*
* Another minor difference to g_memdup() is that the glib version also
* returns %NULL if @data is %NULL. E.g. g_memdup(NULL, 1)
* gives %NULL, but nm_memdup(NULL, 1) crashes. I think that
* is desirable, because @size MUST be correct at all times. @size
* may be zero, but one must not claim to have non-zero bytes when
* passing a %NULL @data pointer.
*/
static inline gpointer
nm_memdup (gconstpointer data, gsize size)
{
gpointer p;
if (size == 0)
return NULL;
p = g_malloc (size);
memcpy (p, data, size);
return p;
}
/*****************************************************************************/
extern const void *const _NM_PTRARRAY_EMPTY[1];
#define NM_PTRARRAY_EMPTY(type) ((type const*) _NM_PTRARRAY_EMPTY)
......@@ -210,6 +257,7 @@ _nm_utils_strbuf_init (char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len)
void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) _nm_printf (3, 4);
void nm_utils_strbuf_append_c (char **buf, gsize *len, char c);
void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str);
void nm_utils_strbuf_seek_end (char **buf, gsize *len);
const char *nm_strquote (char *buf, gsize buf_len, const char *str);
......
......@@ -188,7 +188,7 @@ ck_load_cache (GHashTable *cache)
if (error)
goto out;
g_hash_table_insert (cache, GUINT_TO_POINTER (uid), g_memdup (&session, sizeof session));
g_hash_table_insert (cache, GUINT_TO_POINTER (uid), nm_memdup (&session, sizeof session));
}
finished = TRUE;
......
......@@ -216,8 +216,8 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP
g_assert (b);
if (ignore_order) {
a = c_a = g_memdup (a, sizeof (NMPlatformIP4Route) * len);
b = c_b = g_memdup (b, sizeof (NMPlatformIP4Route) * len);
a = c_a = nm_memdup (a, sizeof (NMPlatformIP4Route) * len);
b = c_b = nm_memdup (b, sizeof (NMPlatformIP4Route) * len);
g_qsort_with_data (c_a, len, sizeof (NMPlatformIP4Route), _nmtst_platform_ip4_routes_equal_sort, NULL);
g_qsort_with_data (c_b, len, sizeof (NMPlatformIP4Route), _nmtst_platform_ip4_routes_equal_sort, NULL);
}
......@@ -269,8 +269,8 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP
g_assert (b);
if (ignore_order) {
a = c_a = g_memdup (a, sizeof (NMPlatformIP6Route) * len);
b = c_b = g_memdup (b, sizeof (NMPlatformIP6Route) * len);
a = c_a = nm_memdup (a, sizeof (NMPlatformIP6Route) * len);
b = c_b = nm_memdup (b, sizeof (NMPlatformIP6Route) * len);
g_qsort_with_data (c_a, len, sizeof (NMPlatformIP6Route), _nmtst_platform_ip6_routes_equal_sort, NULL);
g_qsort_with_data (c_b, len, sizeof (NMPlatformIP6Route), _nmtst_platform_ip6_routes_equal_sort, NULL);
}
......
This diff is collapsed.
......@@ -52,7 +52,6 @@ struct nl_msg {
struct ucred nm_creds;
struct nlmsghdr * nm_nlh;
size_t nm_size;
int nm_refcnt;
};
struct nl_sock {
......@@ -259,20 +258,6 @@ nlmsg_reserve (struct nl_msg *n, size_t len, int pad)
/*****************************************************************************/
static int
get_default_page_size (void)
{
static int val = 0;
int v;
if (G_UNLIKELY (val == 0)) {
v = getpagesize ();
g_assert (v > 0);
val = v;
}
return val;
}
struct nlattr *
nla_reserve (struct nl_msg *msg, int attrtype, int attrlen)
{
......@@ -298,6 +283,22 @@ nla_reserve (struct nl_msg *msg, int attrtype, int attrlen)
return nla;
}
/*****************************************************************************/
static int
get_default_page_size (void)
{
static int val = 0;
int v;
if (G_UNLIKELY (val == 0)) {
v = getpagesize ();
g_assert (v > 0);
val = v;
}
return val;
}
struct nl_msg *
nlmsg_alloc_size (size_t len)
{
......@@ -308,7 +309,6 @@ nlmsg_alloc_size (size_t len)
nm = g_slice_new0 (struct nl_msg);
nm->nm_refcnt = 1;
nm->nm_protocol = -1;
nm->nm_size = len;
nm->nm_nlh = g_malloc0 (len);
......@@ -331,48 +331,40 @@ nlmsg_alloc (void)
return nlmsg_alloc_size (get_default_page_size ());
}
/**
* Allocate a new netlink message with maximum payload size specified.
*/
struct nl_msg *
nlmsg_alloc_inherit (struct nlmsghdr *hdr)
nlmsg_alloc_convert (struct nlmsghdr *hdr)
{
struct nl_msg *nm;
nm = nlmsg_alloc ();
if (hdr) {
struct nlmsghdr *new = nm->nm_nlh;
new->nlmsg_type = hdr->nlmsg_type;
new->nlmsg_flags = hdr->nlmsg_flags;
new->nlmsg_seq = hdr->nlmsg_seq;
new->nlmsg_pid = hdr->nlmsg_pid;
}
nm = nlmsg_alloc_size (NLMSG_ALIGN (hdr->nlmsg_len));
memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
return nm;
}
struct nl_msg *
nlmsg_alloc_convert (struct nlmsghdr *hdr)
nlmsg_alloc_simple (int nlmsgtype, int flags)
{
struct nl_msg *nm;
struct nlmsghdr *new;
nm = nlmsg_alloc_size (NLMSG_ALIGN (hdr->nlmsg_len));
memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
nm = nlmsg_alloc ();
new = nm->nm_nlh;
new->nlmsg_type = nlmsgtype;
new->nlmsg_flags = flags;
return nm;
}
struct nl_msg *
nlmsg_alloc_simple (int nlmsgtype, int flags)
void nlmsg_free (struct nl_msg *msg)
{
struct nlmsghdr nlh = {
.nlmsg_type = nlmsgtype,
.nlmsg_flags = flags,
};
if (!msg)
return;
return nlmsg_alloc_inherit (&nlh);
g_free (msg->nm_nlh);
g_slice_free (struct nl_msg, msg);
}
/*****************************************************************************/
int
nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad)
{
......@@ -386,6 +378,8 @@ nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad)
return 0;
}
/*****************************************************************************/
int
nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
int maxtype, const struct nla_policy *policy)
......@@ -639,22 +633,6 @@ errout:
/*****************************************************************************/
void nlmsg_free (struct nl_msg *msg)
{
if (!msg)
return;
if (msg->nm_refcnt < 1)
g_return_if_reached ();
msg->nm_refcnt--;
if (msg->nm_refcnt <= 0) {
g_free (msg->nm_nlh);
g_slice_free (struct nl_msg, msg);
}
}
int
nlmsg_get_proto (struct nl_msg *msg)
{
......@@ -813,7 +791,7 @@ int
genl_ctrl_resolve (struct nl_sock *sk, const char *name)
{
nm_auto_nlmsg struct nl_msg *msg = NULL;
int result = -ENOMEM;
int nlerr;
gint32 response_data = -1;
const struct nl_cb cb = {
.valid_cb = _genl_parse_getfamily,
......@@ -824,31 +802,29 @@ genl_ctrl_resolve (struct nl_sock *sk, const char *name)
if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL,
0, 0, CTRL_CMD_GETFAMILY, 1))
goto out;
return -ENOMEM;
if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0)
goto out;
nlerr = nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name);
if (nlerr < 0)
return nlerr;
result = nl_send_auto (sk, msg);
if (result < 0)
goto out;
nlerr = nl_send_auto (sk, msg);
if (nlerr < 0)
return nlerr;
result = nl_recvmsgs (sk, &cb);
if (result < 0)
goto out;
nlerr = nl_recvmsgs (sk, &cb);
if (nlerr < 0)
return nlerr;
/* If search was successful, request may be ACKed after data */
result = nl_wait_for_ack (sk, NULL);
if (result < 0)
goto out;
nlerr = nl_wait_for_ack (sk, NULL);
if (nlerr < 0)
return nlerr;
if (response_data > 0)
result = response_data;
else
result = -ENOENT;
if (response_data < 0)
return -NLE_UNSPEC;
out:
return result;
return response_data;
}
/*****************************************************************************/
......@@ -1131,6 +1107,10 @@ do { \
case NL_STOP: \
goto stop; \
default: \
if (err >= 0) { \
nm_assert_not_reached (); \
err = -NLE_BUG; \
} \
goto out; \
} \
} \
......@@ -1238,11 +1218,12 @@ continue_reading:
else if (err == NL_SKIP)
goto skip;
else if (err == NL_STOP) {
err = -e->error;
err = -nl_syserr2nlerr (e->error);
goto out;
}
nm_assert (err == NL_OK);
} else {
err = -e->error;
err = -nl_syserr2nlerr (e->error);
goto out;
}
} else
......@@ -1273,6 +1254,7 @@ out:
if (interrupted)
err = -NLE_DUMP_INTR;
nm_assert (err <= 0);
return err ?: nrecv;
}
......@@ -1328,7 +1310,7 @@ nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsign
memcpy(CMSG_DATA(cmsg), creds, sizeof (struct ucred));
}
return nl_sendmsg(sk, msg, &hdr);
return nl_sendmsg (sk, msg, &hdr);
}
void
......@@ -1365,9 +1347,9 @@ nl_send (struct nl_sock *sk, struct nl_msg *msg)
int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
{
nl_complete_msg(sk, msg);
nl_complete_msg (sk, msg);
return nl_send(sk, msg);
return nl_send (sk, msg);
}
int
......@@ -1470,7 +1452,7 @@ retry:
continue;
if (cmsg->cmsg_type != SCM_CREDENTIALS)
continue;
tmpcreds = g_memdup (CMSG_DATA(cmsg), sizeof (*tmpcreds));
tmpcreds = nm_memdup (CMSG_DATA(cmsg), sizeof (*tmpcreds));
break;
}
}
......
......@@ -62,7 +62,7 @@ nl_errno (int err)
* normalizes the error and returns its positive value. */
return err >= 0
? err
: ((err == G_MININT) ? NLE_BUG : -errno);
: ((err == G_MININT) ? NLE_BUG : -err);
}
static inline int
......@@ -314,8 +314,6 @@ struct nl_msg *nlmsg_alloc (void);
struct nl_msg *nlmsg_alloc_size (size_t max);
struct nl_msg *nlmsg_alloc_inherit (struct nlmsghdr *hdr);
struct nl_msg *nlmsg_alloc_convert (struct nlmsghdr *hdr);
struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags);
......
......@@ -5532,67 +5532,57 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize
}
const char *
nm_platform_wireguard_peer_to_string (const NMWireGuardPeer *peer, char *buf, gsize len)
nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, gsize len)
{
gs_free char *public_b64 = NULL;
char s_address[INET6_ADDRSTRLEN] = {0};
char s_endpoint[INET6_ADDRSTRLEN + NI_MAXSERV + sizeof("endpoint []:") + 1] = {0};
guint8 nonzero_key = 0;
gsize i;
gs_free char *public_key_b64 = NULL;
char s_endpoint[NM_UTILS_INET_ADDRSTRLEN + 100];
char s_addr[NM_UTILS_INET_ADDRSTRLEN];
guint i;
nm_utils_to_string_buffer_init (&buf, &len);
if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) {
char s_service[NI_MAXSERV];
socklen_t addr_len = 0;
if (peer->endpoint.addr.sa_family == AF_INET)
addr_len = sizeof (struct sockaddr_in);
else if (peer->endpoint.addr.sa_family == AF_INET6)
addr_len = sizeof (struct sockaddr_in6);
if (!getnameinfo (&peer->endpoint.addr, addr_len, s_address, sizeof(s_address), s_service, sizeof(s_service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST)) {
if (peer->endpoint.addr.sa_family == AF_INET6 && strchr (s_address, ':'))
g_snprintf(s_endpoint, sizeof (s_endpoint), "endpoint [%s]:%s ", s_address, s_service);
else
g_snprintf(s_endpoint, sizeof (s_endpoint), "endpoint %s:%s ", s_address, s_service);
}
}
for (i = 0; i < sizeof (peer->preshared_key); i++)
nonzero_key |= peer->preshared_key[i];
if (peer->endpoint_family == AF_INET) {
nm_sprintf_buf (s_endpoint,
" endpoint %s:%u",
nm_utils_inet4_ntop (peer->endpoint_addr.addr4, s_addr),
(guint) peer->endpoint_port);
} else if (peer->endpoint_family == AF_INET6) {
nm_sprintf_buf (s_endpoint,
" endpoint [%s]:%u",
nm_utils_inet6_ntop (&peer->endpoint_addr.addr6, s_addr),
(guint) peer->endpoint_port);
} else
s_endpoint[0] = '\0';
public_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key));
public_key_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key));
nm_utils_strbuf_append (&buf, &len,
"{ "
"public_key %s "
"%s" /* preshared key indicator */
"public-key %s"
"%s" /* preshared-key */
"%s" /* endpoint */
"rx %"G_GUINT64_FORMAT" "
"tx %"G_GUINT64_FORMAT" "
"allowedips (%"G_GSIZE_FORMAT") {",
public_b64,
nonzero_key ? "preshared_key (hidden) " : "",
" rx %"G_GUINT64_FORMAT
" tx %"G_GUINT64_FORMAT
"%s", /* allowed-ips */
public_key_b64,
nm_utils_mem_all_zero (peer->preshared_key, sizeof (peer->preshared_key))
? ""
: " preshared-key (hidden)",
s_endpoint,
peer->rx_bytes,
peer->tx_bytes,
peer->allowedips_len);
for (i = 0; i < peer->allowedips_len; i++) {
NMWireGuardAllowedIP *allowedip = &peer->allowedips[i];
const char *ret;
peer->allowed_ips_len > 0
? " allowed-ips"
: "");
ret = inet_ntop (allowedip->family, &allowedip->ip, s_address, sizeof(s_address));
for (i = 0; i < peer->allowed_ips_len; i++) {
const NMPWireGuardAllowedIP *allowed_ip = &peer->allowed_ips[i];
nm_utils_strbuf_append (&buf, &len,
" %s/%u",
ret ? s_address : "<EAFNOSUPPORT>",
allowedip->mask);
nm_utils_inet_ntop (allowed_ip->family, &allowed_ip->addr, s_addr),
allowed_ip->mask);
}
nm_utils_strbuf_append_str (&buf, &len, " } }");