summaryrefslogtreecommitdiff
path: root/src/nm-core-utils.h
blob: ca3e7dbf3b20d6c9161a1262d71352b0f95a5029 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2004 - 2016 Red Hat, Inc.
 * Copyright (C) 2005 - 2008 Novell, Inc.
 */

#ifndef __NM_CORE_UTILS_H__
#define __NM_CORE_UTILS_H__

#include <stdio.h>
#include <arpa/inet.h>

#include "nm-connection.h"

#include "nm-glib-aux/nm-time-utils.h"

/*****************************************************************************/

#define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32

#define NM_DEFINE_SINGLETON_INSTANCE(TYPE) \
static TYPE *singleton_instance

#define NM_DEFINE_SINGLETON_REGISTER(TYPE) \
NM_DEFINE_SINGLETON_INSTANCE (TYPE); \
static void \
_singleton_instance_weak_ref_cb (gpointer data, \
                                 GObject *where_the_object_was) \
{ \
	nm_log_dbg (LOGD_CORE, "disposing %s singleton ("NM_HASH_OBFUSCATE_PTR_FMT")", \
	            G_STRINGIFY (TYPE), \
	            NM_HASH_OBFUSCATE_PTR (singleton_instance)); \
	singleton_instance = NULL; \
} \
static inline void \
nm_singleton_instance_register (void) \
{ \
	g_object_weak_ref (G_OBJECT (singleton_instance), _singleton_instance_weak_ref_cb, NULL); \
	_nm_singleton_instance_register_destruction (G_OBJECT (singleton_instance)); \
}

void _nm_singleton_instance_register_destruction (GObject *instance);

/* By default, the getter will assert that the singleton will be created only once. You can
 * change this by redefining NM_DEFINE_SINGLETON_ALLOW_MULTIPLE. */
#ifndef NM_DEFINE_SINGLETON_ALLOW_MULTIPLE
#define NM_DEFINE_SINGLETON_ALLOW_MULTIPLE     FALSE
#endif

#define NM_DEFINE_SINGLETON_GETTER(TYPE, GETTER, GTYPE, ...) \
NM_DEFINE_SINGLETON_INSTANCE (TYPE); \
NM_DEFINE_SINGLETON_REGISTER (TYPE); \
static char _already_created_##GETTER = FALSE; \
TYPE * \
GETTER (void) \
{ \
	if (G_UNLIKELY (!singleton_instance)) { \
		g_assert (!(_already_created_##GETTER) || (NM_DEFINE_SINGLETON_ALLOW_MULTIPLE)); \
		(_already_created_##GETTER) = TRUE;\
		singleton_instance = (g_object_new (GTYPE, ##__VA_ARGS__, NULL)); \
		g_assert (singleton_instance); \
		nm_singleton_instance_register (); \
		nm_log_dbg (LOGD_CORE, "create %s singleton ("NM_HASH_OBFUSCATE_PTR_FMT")", \
		            G_STRINGIFY (TYPE), \
		            NM_HASH_OBFUSCATE_PTR (singleton_instance)); \
	} \
	return singleton_instance; \
} \
_nm_unused static void \
_nmtst_##GETTER##_reset (TYPE *instance) \
{ \
	/* usually, the singleton can only be created once (and further instantiations
	 * are guarded by an assert). For testing, we need to reset the singleton to
	 * allow multiple instantiations. */ \
	g_assert (G_IS_OBJECT (instance)); \
	g_assert (instance == singleton_instance); \
	g_assert (_already_created_##GETTER); \
	g_object_unref (instance); \
	\
	/* require that the last unref also destroyed the singleton. If this fails,
	 * somebody still keeps a reference. Fix your test! */ \
	g_assert (!singleton_instance); \
	_already_created_##GETTER = FALSE; \
}

/* attach @instance to the data or @owner. @owner owns a reference
 * to @instance thus the lifetime of @instance is at least as long
 * as that of @owner. Use this when @owner depends on @instance. */
#define NM_UTILS_KEEP_ALIVE(owner, instance, unique_token) \
    G_STMT_START { \
         g_object_set_data_full (G_OBJECT (owner), \
                                 ".nm-utils-keep-alive-" unique_token "", \
                                 g_object_ref (instance), \
                                 g_object_unref); \
    } G_STMT_END

/*****************************************************************************/

gboolean nm_ethernet_address_is_valid (gconstpointer addr, gssize len);

gconstpointer nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen);
in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen);
const struct in6_addr *nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen);

static inline int
nm_utils_ip4_address_same_prefix_cmp (in_addr_t addr_a, in_addr_t addr_b, guint8 plen)
{
	NM_CMP_DIRECT (htonl (nm_utils_ip4_address_clear_host_address (addr_a, plen)),
	               htonl (nm_utils_ip4_address_clear_host_address (addr_b, plen)));
	return 0;
}

int nm_utils_ip6_address_same_prefix_cmp (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen);

static inline gboolean
nm_utils_ip4_address_same_prefix (in_addr_t addr_a, in_addr_t addr_b, guint8 plen)
{
	return nm_utils_ip4_address_same_prefix_cmp (addr_a, addr_b, plen) == 0;
}

static inline gboolean
nm_utils_ip6_address_same_prefix (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen)
{
	return nm_utils_ip6_address_same_prefix_cmp (addr_a, addr_b, plen) == 0;
}

#define NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a, b, plen) \
    NM_CMP_RETURN (nm_utils_ip4_address_same_prefix_cmp ((a), (b), (plen)))

#define NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(a, b, plen) \
    NM_CMP_RETURN (nm_utils_ip6_address_same_prefix_cmp ((a), (b), (plen)))

static inline void
nm_hash_update_in6addr (NMHashState *h, const struct in6_addr *addr)
{
	nm_assert (addr);

	nm_hash_update (h, addr, sizeof (*addr));
}

static inline void
nm_hash_update_in6addr_prefix (NMHashState *h, const struct in6_addr *addr, guint8 plen)
{
	struct in6_addr a;

	nm_assert (addr);

	nm_utils_ip6_address_clear_host_address (&a, addr, plen);
	/* we don't hash plen itself. The caller may want to do that.*/
	nm_hash_update_in6addr (h, &a);
}

double nm_utils_exp10 (gint16 e);

/**
 * nm_utils_ip6_route_metric_normalize:
 * @metric: the route metric
 *
 * For IPv6 route, kernel treats the value 0 as IP6_RT_PRIO_USER (1024).
 * Thus, when comparing metric (values), we want to treat zero as NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6.
 *
 * Returns: @metric, if @metric is not zero, otherwise 1024.
 */
static inline guint32
nm_utils_ip6_route_metric_normalize (guint32 metric)
{
	return metric ?: 1024 /*NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6*/;
}

static inline guint32
nm_utils_ip_route_metric_normalize (int addr_family, guint32 metric)
{
	return addr_family == AF_INET6 ? nm_utils_ip6_route_metric_normalize (metric) : metric;
}

static inline guint32
nm_utils_ip_route_metric_penalize (int addr_family, guint32 metric, guint32 penalty)
{
	metric = nm_utils_ip_route_metric_normalize (addr_family, metric);
	if (metric < G_MAXUINT32 - penalty)
		return metric + penalty;
	return G_MAXUINT32;
}

int nm_utils_modprobe (GError **error, gboolean suppress_error_loggin, const char *arg1, ...) G_GNUC_NULL_TERMINATED;

void nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, guint64 log_domain,
                                 const char *log_name, guint32 wait_before_kill_msec,
                                 guint32 sleep_duration_msec, guint32 max_wait_msec);

typedef void (*NMUtilsKillChildAsyncCb) (pid_t pid, gboolean success, int child_status, void *user_data);
void nm_utils_kill_child_async (pid_t pid, int sig, guint64 log_domain, const char *log_name,
                                guint32 wait_before_kill_msec,
                                NMUtilsKillChildAsyncCb callback, void *user_data);
gboolean nm_utils_kill_child_sync (pid_t pid, int sig, guint64 log_domain, const char *log_name,
                                   int *child_status, guint32 wait_before_kill_msec,
                                   guint32 sleep_duration_msec);

const char *nm_utils_find_helper (const char *progname,
                                  const char *try_first,
                                  GError **error);

char *nm_utils_read_link_absolute (const char *link_file, GError **error);

#define NM_MATCH_SPEC_MAC_TAG                    "mac:"
#define NM_MATCH_SPEC_S390_SUBCHANNELS_TAG       "s390-subchannels:"
#define NM_MATCH_SPEC_INTERFACE_NAME_TAG         "interface-name:"

typedef enum {
	NM_MATCH_SPEC_NO_MATCH  = 0,
	NM_MATCH_SPEC_MATCH     = 1,
	NM_MATCH_SPEC_NEG_MATCH = 2,
} NMMatchSpecMatchType;

NMMatchSpecMatchType nm_match_spec_device (const GSList *specs,
                                           const char *interface_name,
                                           const char *device_type,
                                           const char *driver,
                                           const char *driver_version,
                                           const char *hwaddr,
                                           const char *s390_subchannels,
                                           const char *dhcp_plugin);
NMMatchSpecMatchType nm_match_spec_config (const GSList *specs,
                                           guint nm_version,
                                           const char *env);
GSList *nm_match_spec_split (const char *value);
char *nm_match_spec_join (GSList *specs);

gboolean nm_wildcard_match_check (const char *str,
                                  const char *const *patterns,
                                  guint num_patterns);

/*****************************************************************************/

gboolean nm_utils_connection_has_default_route (NMConnection *connection,
                                                int addr_family,
                                                gboolean *out_is_never_default);

char *nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id);
const char *nm_utils_new_infiniband_name (char *name, const char *parent_name, int p_key);

int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection *a, NMConnection *b);

void nm_utils_log_connection_diff (NMConnection *connection,
                                   NMConnection *diff_base,
                                   guint32 level, guint64 domain,
                                   const char *name,
                                   const char *prefix,
                                   const char *dbus_path);

gboolean    nm_utils_is_valid_path_component (const char *name);
const char *NM_ASSERT_VALID_PATH_COMPONENT (const char *name);

#define NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE 100

const char *nm_utils_sysctl_ip_conf_path (int addr_family, char *buf, const char *ifname, const char *property);

gboolean nm_utils_sysctl_ip_conf_is_path (int addr_family, const char *path, const char *ifname, const char *property);

gboolean nm_utils_is_specific_hostname (const char *name);

struct _NMUuid;

const char *nm_utils_machine_id_str (void);
const struct _NMUuid *nm_utils_machine_id_bin (void);
gboolean nm_utils_machine_id_is_fake (void);

const char *nm_utils_boot_id_str (void);
const struct _NMUuid *nm_utils_boot_id_bin (void);

gboolean nm_utils_host_id_get (const guint8 **out_host_id,
                               gsize *out_host_id_len);
gint64 nm_utils_host_id_get_timestamp_ns (void);

/*****************************************************************************/

int nm_utils_arp_type_detect_from_hwaddrlen (gsize hwaddr_len);

gboolean nm_utils_arp_type_validate_hwaddr (int arp_type,
                                            const guint8 *hwaddr,
                                            gsize hwaddr_len);

gboolean nm_utils_arp_type_get_hwaddr_relevant_part (int arp_type,
                                                     const guint8 **hwaddr,
                                                     gsize *hwaddr_len);

/*****************************************************************************/

/* IPv6 Interface Identifier helpers */

/**
 * NMUtilsIPv6IfaceId:
 * @id: convenience member for validity checking; never use directly
 * @id_u8: the 64-bit Interface Identifier
 *
 * Holds a 64-bit IPv6 Interface Identifier.  The IID is a sequence of bytes
 * and should not normally be treated as a %guint64, but this is done for
 * convenience of validity checking and initialization.
 */
struct _NMUtilsIPv6IfaceId {
	union {
		guint64 id;
		guint8  id_u8[8];
	};
};

#define NM_UTILS_IPV6_IFACE_ID_INIT { { .id = 0 } }

void nm_utils_ipv6_addr_set_interface_identifier (struct in6_addr *addr,
                                                 const NMUtilsIPv6IfaceId iid);

void nm_utils_ipv6_interface_identifier_get_from_addr (NMUtilsIPv6IfaceId *iid,
                                                      const struct in6_addr *addr);

gboolean nm_utils_ipv6_interface_identifier_get_from_token (NMUtilsIPv6IfaceId *iid,
                                                           const char *token);

const char *nm_utils_inet6_interface_identifier_to_token (NMUtilsIPv6IfaceId iid,
                                                          char buf[static INET6_ADDRSTRLEN]);

gboolean nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
                                                 const guint8 *hwaddr,
                                                 guint len,
                                                 guint dev_id,
                                                 NMUtilsIPv6IfaceId *out_iid);

typedef enum {
	/* The stable type. Note that this value is encoded in the
	 * generated addresses, thus the numbers MUST not change.
	 *
	 * Also note, if we ever allocate ID 255, we must take care
	 * that nm_utils_ipv6_addr_set_stable_privacy() extends the
	 * uint8 encoding of this value. */
	NM_UTILS_STABLE_TYPE_UUID      = 0,
	NM_UTILS_STABLE_TYPE_STABLE_ID = 1,
	NM_UTILS_STABLE_TYPE_GENERATED = 2,
	NM_UTILS_STABLE_TYPE_RANDOM    = 3,
} NMUtilsStableType;

NMUtilsStableType nm_utils_stable_id_parse (const char *stable_id,
                                            const char *deviceid,
                                            const char *hwaddr,
                                            const char *bootid,
                                            const char *uuid,
                                            char **out_generated);

char *nm_utils_stable_id_random (void);
char *nm_utils_stable_id_generated_complete (const char *msg);

gboolean nm_utils_ipv6_addr_set_stable_privacy_impl (NMUtilsStableType stable_type,
                                                     struct in6_addr *addr,
                                                     const char *ifname,
                                                     const char *network_id,
                                                     guint32 dad_counter,
                                                     guint8 *host_id,
                                                     gsize host_id_len,
                                                     GError **error);

gboolean nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType id_type,
                                                struct in6_addr *addr,
                                                const char *ifname,
                                                const char *network_id,
                                                guint32 dad_counter,
                                                GError **error);

char *nm_utils_hw_addr_gen_random_eth (const char *current_mac_address,
                                       const char *generate_mac_address_mask);
char *nm_utils_hw_addr_gen_stable_eth_impl (NMUtilsStableType stable_type,
                                            const char *stable_id,
                                            const guint8 *host_id,
                                            gsize host_id_len,
                                            const char *ifname,
                                            const char *current_mac_address,
                                            const char *generate_mac_address_mask);
char *nm_utils_hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
                                       const char *stable_id,
                                       const char *ifname,
                                       const char *current_mac_address,
                                       const char *generate_mac_address_mask);

/*****************************************************************************/

GBytes *nm_utils_dhcp_client_id_mac (int arp_type,
                                     const guint8 *hwaddr,
                                     gsize hwaddr_len);

guint32 nm_utils_create_dhcp_iaid (gboolean legacy_unstable_byteorder,
                                   const guint8 *interface_id,
                                   gsize interface_id_len);

GBytes *nm_utils_dhcp_client_id_systemd_node_specific_full (guint32 iaid,
                                                            const guint8 *machine_id,
                                                            gsize machine_id_len);

GBytes *nm_utils_dhcp_client_id_systemd_node_specific (guint32 iaid);

/*****************************************************************************/

void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len);

void nm_utils_setpgid (gpointer unused);

typedef enum {
	NM_UTILS_TEST_NONE                              = 0,

	/* Internal flag, marking that either nm_utils_get_testing() or _nm_utils_set_testing() was called. */
	_NM_UTILS_TEST_INITIALIZED                      = (1LL << 0),

	/* Indicate that test mode is enabled in general. Explicitly calling _nm_utils_set_testing() will always set this flag. */
	_NM_UTILS_TEST_GENERAL                          = (1LL << 1),

	/* Don't check the owner of keyfiles during testing. */
	NM_UTILS_TEST_NO_KEYFILE_OWNER_CHECK            = (1LL << 2),

	_NM_UTILS_TEST_LAST,
	NM_UTILS_TEST_ALL                               = (((_NM_UTILS_TEST_LAST - 1) << 1) - 1) & ~(_NM_UTILS_TEST_INITIALIZED),
} NMUtilsTestFlags;

gboolean nm_utils_get_testing_initialized (void);
NMUtilsTestFlags nm_utils_get_testing (void);
void _nm_utils_set_testing (NMUtilsTestFlags flags);

void nm_utils_g_value_set_strv (GValue *value, GPtrArray *strings);

void nm_utils_ifname_cpy (char *dst, const char *name);

guint32 nm_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp,
                                                       guint32 duration,
                                                       gint32 now);

guint32 nm_utils_lifetime_get (guint32 timestamp,
                               guint32 lifetime,
                               guint32 preferred,
                               gint32 now,
                               guint32 *out_preferred);

gboolean nm_utils_ip4_address_is_link_local (in_addr_t addr);

const char *nm_utils_dnsmasq_status_to_string (int status, char *dest, gsize size);

void nm_utils_get_reverse_dns_domains_ip4 (guint32 ip, guint8 plen, GPtrArray *domains);
void nm_utils_get_reverse_dns_domains_ip6 (const struct in6_addr *ip, guint8 plen, GPtrArray *domains);

struct stat;

gboolean nm_utils_validate_plugin (const char *path, struct stat *stat, GError **error);
char **nm_utils_read_plugin_paths (const char *dirname, const char *prefix);
char *nm_utils_format_con_diff_for_audit (GHashTable *diff);

GVariant *nm_utils_strdict_to_variant (GHashTable *options);

/*****************************************************************************/

/* this enum is compatible with ICMPV6_ROUTER_PREF_* (from <linux/icmpv6.h>,
 * the values for netlink attribute RTA_PREF) and "enum ndp_route_preference"
 * from <ndp.h>. */
typedef enum {
	NM_ICMPV6_ROUTER_PREF_MEDIUM      = 0x0, /* ICMPV6_ROUTER_PREF_MEDIUM */
	NM_ICMPV6_ROUTER_PREF_LOW         = 0x3, /* ICMPV6_ROUTER_PREF_LOW */
	NM_ICMPV6_ROUTER_PREF_HIGH        = 0x1, /* ICMPV6_ROUTER_PREF_HIGH */
	NM_ICMPV6_ROUTER_PREF_INVALID     = 0x2, /* ICMPV6_ROUTER_PREF_INVALID */
} NMIcmpv6RouterPref;

const char *nm_icmpv6_router_pref_to_string (NMIcmpv6RouterPref pref, char *buf, gsize len);

/*****************************************************************************/

const char *nm_activation_type_to_string (NMActivationType activation_type);

/*****************************************************************************/

const char *nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing);

/*****************************************************************************/

guint8 nm_wifi_utils_level_to_quality (int val);

/*****************************************************************************/

#define NM_VPN_ROUTE_METRIC_DEFAULT     50

#define NM_UTILS_ERROR_MSG_REQ_AUTH_FAILED   "Unable to authenticate the request"
#define NM_UTILS_ERROR_MSG_REQ_UID_UKNOWN    "Unable to determine UID of the request"
#define NM_UTILS_ERROR_MSG_INSUFF_PRIV       "Insufficient privileges"

#endif /* __NM_CORE_UTILS_H__ */