diff options
Diffstat (limited to 'src/systemd')
35 files changed, 470 insertions, 1615 deletions
diff --git a/src/systemd/meson.build b/src/systemd/meson.build index 257a9462..af1d0c8b 100644 --- a/src/systemd/meson.build +++ b/src/systemd/meson.build @@ -23,9 +23,9 @@ libnm_systemd_core = static_library( 'src/libsystemd/sd-event/sd-event.c', 'src/libsystemd/sd-id128/id128-util.c', 'src/libsystemd/sd-id128/sd-id128.c', - 'src/shared/dns-domain.c', 'nm-sd.c', 'nm-sd-utils-core.c', + 'nm-sd-utils-dhcp.c', ), include_directories: [ src_inc, @@ -33,7 +33,6 @@ libnm_systemd_core = static_library( 'sd-adapt-core', 'src/libsystemd-network', 'src/libsystemd/sd-event', - 'src/shared', 'src/systemd', ) ], diff --git a/src/systemd/nm-sd-utils-dhcp.c b/src/systemd/nm-sd-utils-dhcp.c new file mode 100644 index 00000000..49a924b6 --- /dev/null +++ b/src/systemd/nm-sd-utils-dhcp.c @@ -0,0 +1,54 @@ +/* + * This library 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2019 Red Hat, Inc. + */ + +#include "nm-default.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) +{ + struct sd_dhcp_raw_option *raw_option; + 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; +} diff --git a/src/systemd/nm-sd-utils-dhcp.h b/src/systemd/nm-sd-utils-dhcp.h new file mode 100644 index 00000000..496bf374 --- /dev/null +++ b/src/systemd/nm-sd-utils-dhcp.h @@ -0,0 +1,34 @@ +/* + * This library 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 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__ */ diff --git a/src/systemd/nm-sd.c b/src/systemd/nm-sd.c index 4009c617..bcab328f 100644 --- a/src/systemd/nm-sd.c +++ b/src/systemd/nm-sd.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -133,10 +132,6 @@ nm_sd_event_attach_default (void) /*****************************************************************************/ -const bool mempool_use_allowed = true; - -/*****************************************************************************/ - /* ensure that defines in nm-sd.h correspond to the internal defines. */ #include "nm-sd-adapt-core.h" diff --git a/src/systemd/nm-sd.h b/src/systemd/nm-sd.h index f988dfd0..07fc2ad4 100644 --- a/src/systemd/nm-sd.h +++ b/src/systemd/nm-sd.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) diff --git a/src/systemd/sd-adapt-core/nm-sd-adapt-core.c b/src/systemd/sd-adapt-core/nm-sd-adapt-core.c index d7ed687e..c461752e 100644 --- a/src/systemd/sd-adapt-core/nm-sd-adapt-core.c +++ b/src/systemd/sd-adapt-core/nm-sd-adapt-core.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) diff --git a/src/systemd/sd-adapt-core/nm-sd-adapt-core.h b/src/systemd/sd-adapt-core/nm-sd-adapt-core.h index 8c07c53a..bd71dd18 100644 --- a/src/systemd/sd-adapt-core/nm-sd-adapt-core.h +++ b/src/systemd/sd-adapt-core/nm-sd-adapt-core.h @@ -50,8 +50,6 @@ #include <sys/syscall.h> #include <sys/ioctl.h> -#include <net/if_arp.h> - /* Missing in Linux 3.2.0, in Ubuntu 12.04 */ #ifndef BPF_XOR #define BPF_XOR 0xa0 diff --git a/src/systemd/src/libsystemd-network/arp-util.c b/src/systemd/src/libsystemd-network/arp-util.c index 154ba6b7..e48e4bfe 100644 --- a/src/systemd/src/libsystemd-network/arp-util.c +++ b/src/systemd/src/libsystemd-network/arp-util.c @@ -5,8 +5,9 @@ #include "nm-sd-adapt-core.h" -#include <linux/filter.h> #include <arpa/inet.h> +#include <linux/filter.h> +#include <netinet/if_ether.h> #include "arp-util.h" #include "fd-util.h" diff --git a/src/systemd/src/libsystemd-network/arp-util.h b/src/systemd/src/libsystemd-network/arp-util.h index 10c68486..9a4427e8 100644 --- a/src/systemd/src/libsystemd-network/arp-util.h +++ b/src/systemd/src/libsystemd-network/arp-util.h @@ -5,7 +5,7 @@ Copyright © 2014 Axis Communications AB. All rights reserved. ***/ -#include <netinet/if_ether.h> +#include <net/ethernet.h> #include "socket-util.h" #include "sparse-endian.h" diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c index e3af362d..b28e0ba0 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.c +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -197,7 +197,7 @@ int dhcp_identifier_set_iaid( /* device is under renaming */ return -EBUSY; - name = net_get_name(device); + name = net_get_name_persistent(device); } } diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h index a0f9c229..e0269b54 100644 --- a/src/systemd/src/libsystemd-network/dhcp-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-internal.h @@ -51,5 +51,5 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, ui #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_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__) +#define log_dhcp_client_errno(client, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__) #define log_dhcp_client(client, fmt, ...) log_dhcp_client_errno(client, 0, fmt, ##__VA_ARGS__) diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index 45d2ed89..858fe57c 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -5,6 +5,7 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include <net/ethernet.h> #include <net/if.h> #include <net/if_arp.h> diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c index eaf044bf..50238b0a 100644 --- a/src/systemd/src/libsystemd-network/dhcp-option.c +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -5,6 +5,7 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include <stdint.h> #include <stdio.h> #include <string.h> @@ -199,7 +200,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo if (memchr(option, 0, len - 1)) return -EINVAL; - string = strndup((const char *) option, len); + string = memdup_suffix0((const char *) option, len); if (!string) return -ENOMEM; diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c index 91e8a54e..9e565e28 100644 --- a/src/systemd/src/libsystemd-network/dhcp-packet.c +++ b/src/systemd/src/libsystemd-network/dhcp-packet.c @@ -5,6 +5,7 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include <net/ethernet.h> #include <net/if_arp.h> #include <string.h> diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h index 157fc0aa..f28ba68d 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h @@ -79,7 +79,7 @@ struct DHCP6IA { typedef struct DHCP6IA DHCP6IA; -#define log_dhcp6_client_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__) +#define log_dhcp6_client_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__) #define log_dhcp6_client(p, fmt, ...) log_dhcp6_client_errno(p, 0, fmt, ##__VA_ARGS__) int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c index d786756e..73c195a7 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-network.c +++ b/src/systemd/src/libsystemd-network/dhcp6-network.c @@ -5,6 +5,7 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include <netinet/in.h> #include <netinet/ip6.h> #include <stdio.h> diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index 6172c368..562a34b5 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -5,6 +5,7 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include <netinet/in.h> #include <string.h> diff --git a/src/systemd/src/libsystemd-network/lldp-internal.h b/src/systemd/src/libsystemd-network/lldp-internal.h index 88b54933..9598438d 100644 --- a/src/systemd/src/libsystemd-network/lldp-internal.h +++ b/src/systemd/src/libsystemd-network/lldp-internal.h @@ -32,7 +32,7 @@ struct sd_lldp { struct ether_addr filter_address; }; -#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) +#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) #define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__) const char* lldp_event_to_string(sd_lldp_event e) _const_; diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index de219a6d..209ce884 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -14,6 +14,7 @@ #include "conf-parser.h" #include "device-util.h" #include "dhcp-lease-internal.h" +#include "env-util.h" #include "ether-addr-util.h" #include "hexdecoct.h" #include "log.h" @@ -27,7 +28,7 @@ #include "util.h" #if 0 /* NM_IGNORED */ -const char *net_get_name(sd_device *device) { +const char *net_get_name_persistent(sd_device *device) { const char *name, *field; assert(device); @@ -42,7 +43,7 @@ const char *net_get_name(sd_device *device) { #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) -int net_get_unique_predictable_data(sd_device *device, uint64_t *result) { +int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) { size_t l, sz = 0; const char *name; int r; @@ -50,10 +51,10 @@ int net_get_unique_predictable_data(sd_device *device, uint64_t *result) { assert(device); - /* net_get_name() will return one of the device names based on stable information about the - * device. If this is not available, we fall back to using the device name. */ - name = net_get_name(device); - if (!name) + /* net_get_name_persistent() will return one of the device names based on stable information about + * the device. If this is not available, we fall back to using the actual device name. */ + name = net_get_name_persistent(device); + if (!name && use_sysname) (void) sd_device_get_sysname(device, &name); if (!name) return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA), @@ -76,26 +77,66 @@ int net_get_unique_predictable_data(sd_device *device, uint64_t *result) { return 0; } -static bool net_condition_test_strv(char * const *raw_patterns, - const char *string) { - if (strv_isempty(raw_patterns)) +static bool net_condition_test_strv(char * const *patterns, const char *string) { + char * const *p; + bool match = false, has_positive_rule = false; + + if (strv_isempty(patterns)) return true; - /* If the patterns begin with "!", edit it out and negate the test. */ - if (raw_patterns[0][0] == '!') { - char **patterns; - size_t i, length; + STRV_FOREACH(p, patterns) { + const char *q = *p; + bool invert; + + invert = *q == '!'; + q += invert; + + if (!invert) + has_positive_rule = true; + + if (string && fnmatch(q, string, 0) == 0) { + if (invert) + return false; + else + match = true; + } + } + + return has_positive_rule ? match : true; +} + +static int net_condition_test_property(char * const *match_property, sd_device *device) { + char * const *p; + + if (strv_isempty(match_property)) + return true; + + STRV_FOREACH(p, match_property) { + _cleanup_free_ char *key = NULL; + const char *val, *dev_val; + bool invert, v; + + invert = **p == '!'; + + val = strchr(*p + invert, '='); + if (!val) + return -EINVAL; - length = strv_length(raw_patterns) + 1; /* Include the NULL. */ - patterns = newa(char*, length); - patterns[0] = raw_patterns[0] + 1; /* Skip the "!". */ - for (i = 1; i < length; i++) - patterns[i] = raw_patterns[i]; + key = strndup(*p + invert, val - *p - invert); + if (!key) + return -ENOMEM; + + val++; - return !string || !strv_fnmatch(patterns, string, 0); + v = device && + sd_device_get_property_value(device, key, &dev_val) >= 0 && + fnmatch(val, dev_val, 0) == 0; + + if (invert ? v : !v) + return false; } - return string && strv_fnmatch(raw_patterns, string, 0); + return true; } bool net_match_config(Set *match_mac, @@ -103,12 +144,25 @@ bool net_match_config(Set *match_mac, char * const *match_drivers, char * const *match_types, char * const *match_names, + char * const *match_property, + sd_device *device, const struct ether_addr *dev_mac, - const char *dev_path, - const char *dev_driver, - const char *dev_type, const char *dev_name) { + const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str; + + if (device) { + (void) sd_device_get_property_value(device, "ID_PATH", &dev_path); + (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver); + (void) sd_device_get_devtype(device, &dev_type); + + if (!dev_name) + (void) sd_device_get_sysname(device, &dev_name); + if (!dev_mac && + sd_device_get_sysattr_value(device, "address", &mac_str) >= 0) + dev_mac = ether_aton(mac_str); + } + if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac))) return false; @@ -124,6 +178,9 @@ bool net_match_config(Set *match_mac, if (!net_condition_test_strv(match_names, dev_name)) return false; + if (!net_condition_test_property(match_property, device)) + return false; + return true; } @@ -167,7 +224,7 @@ int config_parse_net_condition(const char *unit, return 0; } -int config_parse_ifnames( +int config_parse_match_strv( const char *unit, const char *filename, unsigned line, @@ -179,7 +236,9 @@ int config_parse_ifnames( void *data, void *userdata) { + const char *p = rvalue; char ***sv = data; + bool invert; int r; assert(filename); @@ -187,30 +246,154 @@ int config_parse_ifnames( assert(rvalue); assert(data); + if (isempty(rvalue)) { + *sv = strv_free(*sv); + return 0; + } + + invert = *p == '!'; + p += invert; + for (;;) { - _cleanup_free_ char *word = NULL; + _cleanup_free_ char *word = NULL, *k = NULL; - r = extract_first_word(&rvalue, &word, NULL, 0); + r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); return 0; } + + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); + if (r < 0) + return log_oom(); + } +} + +int config_parse_match_ifnames( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + const char *p = rvalue; + char ***sv = data; + bool invert; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + invert = *p == '!'; + p += invert; + + for (;;) { + _cleanup_free_ char *word = NULL, *k = NULL; + + r = extract_first_word(&p, &word, NULL, 0); if (r == 0) - break; + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Failed to parse interface name list: %s", rvalue); + return 0; + } if (!ifname_valid(word)) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue); - return 0; + log_syntax(unit, LOG_ERR, filename, line, 0, + "Interface name is not valid or too long, ignoring assignment: %s", word); + continue; } - r = strv_push(sv, word); + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); if (r < 0) return log_oom(); - - word = NULL; } +} - return 0; +int config_parse_match_property( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + const char *p = rvalue; + char ***sv = data; + bool invert; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + invert = *p == '!'; + p += invert; + + for (;;) { + _cleanup_free_ char *word = NULL, *k = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + + if (!env_assignment_is_valid(word)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Invalid property or value, ignoring assignment: %s", word); + continue; + } + + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); + if (r < 0) + return log_oom(); + } } int config_parse_ifalias(const char *unit, @@ -616,7 +799,7 @@ int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t siz assert(data); hex_buf = hexmem(data, size); - if (hex_buf == NULL) + if (!hex_buf) return -ENOMEM; fprintf(f, "%s=%s\n", key, hex_buf); diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index d895103b..487421fb 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -14,27 +14,28 @@ #define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 #define LINK_BRIDGE_PORT_PRIORITY_MAX 63 +#if 0 /* NM_IGNORED */ bool net_match_config(Set *match_mac, char * const *match_path, char * const *match_driver, char * const *match_type, char * const *match_name, + char * const *match_property, + sd_device *device, const struct ether_addr *dev_mac, - const char *dev_path, - const char *dev_driver, - const char *dev_type, const char *dev_name); -#if 0 /* NM_IGNORED */ CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs); -CONFIG_PARSER_PROTOTYPE(config_parse_ifnames); +CONFIG_PARSER_PROTOTYPE(config_parse_match_strv); +CONFIG_PARSER_PROTOTYPE(config_parse_match_ifnames); +CONFIG_PARSER_PROTOTYPE(config_parse_match_property); CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); -int net_get_unique_predictable_data(sd_device *device, uint64_t *result); -const char *net_get_name(sd_device *device); +int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result); +const char *net_get_name_persistent(sd_device *device); #endif /* NM_IGNORED */ size_t serialize_in_addrs(FILE *f, diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index cadcc8a8..2f531bc7 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -5,6 +5,7 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include <net/ethernet.h> #include <net/if_arp.h> #include <stdio.h> @@ -89,7 +90,8 @@ struct sd_dhcp_client { uint32_t mtu; uint32_t xid; usec_t start_time; - unsigned attempt; + uint64_t attempt; + uint64_t max_attempts; usec_t request_sent; sd_event_source *timeout_t1; sd_event_source *timeout_t2; @@ -524,10 +526,18 @@ int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { return 0; } +int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) { + assert_return(client, -EINVAL); + + client->max_attempts = max_attempts; + + return 0; +} + int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { assert_return(client, -EINVAL); - if (!IN_SET(client->state, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING)) + if (!IN_SET(client->state, DHCP_STATE_SELECTING, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING)) return -EADDRNOTAVAIL; if (ret) @@ -536,11 +546,13 @@ int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { return 0; } -static void client_notify(sd_dhcp_client *client, int event) { +static int client_notify(sd_dhcp_client *client, int event) { assert(client); if (client->callback) - client->callback(client, event, client->userdata); + return client->callback(client, event, client->userdata); + + return 0; } static int client_initialize(sd_dhcp_client *client) { @@ -555,7 +567,7 @@ static int client_initialize(sd_dhcp_client *client) { (void) event_source_disable(client->timeout_t2); (void) event_source_disable(client->timeout_expire); - client->attempt = 1; + client->attempt = 0; client->state = DHCP_STATE_INIT; client->xid = 0; @@ -569,7 +581,7 @@ static void client_stop(sd_dhcp_client *client, int error) { assert(client); if (error < 0) - log_dhcp_client(client, "STOPPED: %s", strerror(-error)); + log_dhcp_client_errno(client, error, "STOPPED: %m"); else if (error == SD_DHCP_CLIENT_EVENT_STOP) log_dhcp_client(client, "STOPPED"); else @@ -599,7 +611,7 @@ static int client_message_init( assert(ret); assert(_optlen); assert(_optoffset); - assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST)); + assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE)); optlen = DHCP_MIN_OPTIONS_SIZE; size = sizeof(DHCPPacket) + optlen; @@ -690,7 +702,7 @@ static int client_message_init( MAY contain the Parameter Request List option. */ /* NOTE: in case that there would be an option to do not send * any PRL at all, the size should be checked before sending */ - if (client->req_opts_size > 0) { + if (client->req_opts_size > 0 && type != DHCP_RELEASE) { r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST, client->req_opts_size, client->req_opts); @@ -722,7 +734,7 @@ static int client_message_init( */ /* RFC7844 section 3: SHOULD NOT contain any other option. */ - if (!client->anonymize) { + if (!client->anonymize && type != DHCP_RELEASE) { max_size = htobe16(size); r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, @@ -854,6 +866,41 @@ static int client_send_discover(sd_dhcp_client *client) { return 0; } +static int client_send_release(sd_dhcp_client *client) { + _cleanup_free_ DHCPPacket *release = NULL; + size_t optoffset, optlen; + int r; + + assert(client); + assert(!IN_SET(client->state, DHCP_STATE_STOPPED)); + + r = client_message_init(client, &release, DHCP_RELEASE, + &optlen, &optoffset); + if (r < 0) + return r; + + /* Fill up release IP and MAC */ + release->dhcp.ciaddr = client->lease->address; + memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len); + + r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_END, 0, NULL); + if (r < 0) + return r; + + r = dhcp_network_send_udp_socket(client->fd, + client->lease->server_address, + DHCP_PORT_SERVER, + &release->dhcp, + sizeof(DHCPMessage) + optoffset); + if (r < 0) + return r; + + log_dhcp_client(client, "RELEASE"); + + return 0; +} + static int client_send_request(sd_dhcp_client *client) { _cleanup_free_ DHCPPacket *request = NULL; size_t optoffset, optlen; @@ -1054,10 +1101,12 @@ static int client_timeout_resend( case DHCP_STATE_REQUESTING: case DHCP_STATE_BOUND: - if (client->attempt < 64) - client->attempt *= 2; + if (client->attempt < client->max_attempts) + client->attempt++; + else + goto error; - next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC; + next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC; break; @@ -1081,17 +1130,15 @@ static int client_timeout_resend( r = client_send_discover(client); if (r >= 0) { client->state = DHCP_STATE_SELECTING; - client->attempt = 1; - } else { - if (client->attempt >= 64) - goto error; - } + client->attempt = 0; + } else if (client->attempt >= client->max_attempts) + goto error; break; case DHCP_STATE_SELECTING: r = client_send_discover(client); - if (r < 0 && client->attempt >= 64) + if (r < 0 && client->attempt >= client->max_attempts) goto error; break; @@ -1101,7 +1148,7 @@ static int client_timeout_resend( case DHCP_STATE_RENEWING: case DHCP_STATE_REBINDING: r = client_send_request(client); - if (r < 0 && client->attempt >= 64) + if (r < 0 && client->attempt >= client->max_attempts) goto error; if (client->state == DHCP_STATE_INIT_REBOOT) @@ -1253,7 +1300,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) client->fd = asynchronous_close(client->fd); client->state = DHCP_STATE_REBINDING; - client->attempt = 1; + client->attempt = 0; r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, client->mac_addr, @@ -1273,7 +1320,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) DHCP_CLIENT_DONT_DESTROY(client); client->state = DHCP_STATE_RENEWING; - client->attempt = 1; + client->attempt = 0; return client_initialize_time_events(client); } @@ -1323,6 +1370,9 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_ sd_dhcp_lease_unref(client->lease); client->lease = TAKE_PTR(lease); + if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0) + return -ENOMSG; + log_dhcp_client(client, "OFFER"); return 0; @@ -1340,6 +1390,23 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, return 0; } +static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) { + if (a->address != b->address) + return false; + + if (a->subnet_mask != b->subnet_mask) + return false; + + if (a->router_size != b->router_size) + return false; + + for (size_t i = 0; i < a->router_size; i++) + if (a->router[i].s_addr != b->router[i].s_addr) + return false; + + return true; +} + static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) { _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; _cleanup_free_ char *error_message = NULL; @@ -1392,12 +1459,10 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t le r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE; if (client->lease) { - if (client->lease->address != lease->address || - client->lease->subnet_mask != lease->subnet_mask || - client->lease->router != lease->router) { - r = SD_DHCP_CLIENT_EVENT_IP_CHANGE; - } else + if (lease_equal(client->lease, lease)) r = SD_DHCP_CLIENT_EVENT_RENEW; + else + r = SD_DHCP_CLIENT_EVENT_IP_CHANGE; client->lease = sd_dhcp_lease_unref(client->lease); } @@ -1557,7 +1622,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i if (r >= 0) { client->state = DHCP_STATE_REQUESTING; - client->attempt = 1; + client->attempt = 0; r = event_reset_time(client->event, &client->timeout_resend, clock_boottime_or_monotonic(), @@ -1592,7 +1657,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i notify_event = r; client->state = DHCP_STATE_BOUND; - client->attempt = 1; + client->attempt = 0; client->last_addr = client->lease->address; @@ -1848,6 +1913,14 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { return r; } +int sd_dhcp_client_send_release(sd_dhcp_client *client) { + assert_return(client, -EINVAL); + + client_send_release(client); + + return 0; +} + int sd_dhcp_client_stop(sd_dhcp_client *client) { DHCP_CLIENT_DONT_DESTROY(client); @@ -1931,10 +2004,10 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { .state = DHCP_STATE_INIT, .ifindex = -1, .fd = -1, - .attempt = 1, .mtu = DHCP_DEFAULT_MIN_SIZE, .port = DHCP_PORT_CLIENT, .anonymize = !!anonymize, + .max_attempts = (uint64_t) -1, }; /* NOTE: this could be moved to a function. */ if (anonymize) { diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index 6c7aecc8..7559d066 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -6,8 +6,8 @@ #include "nm-sd-adapt-core.h" #include <arpa/inet.h> +#include <errno.h> #include <stdio.h> -#include <stdio_ext.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> @@ -335,7 +335,7 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { if (memchr(option, 0, len - 1)) return -EINVAL; - string = strndup((const char *) option, len); + string = memdup_suffix0((const char *) option, len); if (!string) return -ENOMEM; @@ -833,7 +833,6 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { if (r < 0) goto fail; - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); (void) fchmod(fileno(f), 0644); fprintf(f, diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index b72cd82d..f67a45bd 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -5,8 +5,10 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include <string.h> #include <sys/ioctl.h> +#include <linux/if_arp.h> #include <linux/if_infiniband.h> #include "sd-dhcp6-client.h" diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c index 7263c96f..35caec7a 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -5,6 +5,7 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include "alloc-util.h" #include "dhcp6-lease-internal.h" @@ -206,12 +207,8 @@ int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->dns, lease->dns_count, &lease->dns_allocated); - if (r < 0) { - log_dhcp6_client(client, "Invalid DNS server option: %s", - strerror(-r)); - - return r; - } + if (r < 0) + return log_dhcp6_client_errno(client, r, "Invalid DNS server option: %m"); lease->dns_count = r; @@ -337,12 +334,8 @@ int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp, lease->ntp_count, &lease->ntp_allocated); - if (r < 0) { - log_dhcp6_client(client, "Invalid SNTP server option: %s", - strerror(-r)); - - return r; - } + if (r < 0) + return log_dhcp6_client_errno(client, r, "Invalid SNTP server option: %m"); lease->ntp_count = r; diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index 53ce8929..e7561480 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -6,6 +6,8 @@ #include "nm-sd-adapt-core.h" #include <arpa/inet.h> +#include <errno.h> +#include <netinet/if_ether.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -73,7 +75,7 @@ struct sd_ipv4acd { void* userdata; }; -#define log_ipv4acd_errno(acd, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__) +#define log_ipv4acd_errno(acd, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__) #define log_ipv4acd(acd, fmt, ...) log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__) static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_counter) { diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index 4f186762..daac8839 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -6,6 +6,7 @@ #include "nm-sd-adapt-core.h" #include <arpa/inet.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -51,7 +52,7 @@ struct sd_ipv4ll { void* userdata; }; -#define log_ipv4ll_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "IPV4LL: " fmt, ##__VA_ARGS__) +#define log_ipv4ll_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "IPV4LL: " fmt, ##__VA_ARGS__) #define log_ipv4ll(ll, fmt, ...) log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__) static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); diff --git a/src/systemd/src/libsystemd/sd-event/event-util.c b/src/systemd/src/libsystemd/sd-event/event-util.c index 2afacfe6..e8384cfd 100644 --- a/src/systemd/src/libsystemd/sd-event/event-util.c +++ b/src/systemd/src/libsystemd/sd-event/event-util.c @@ -2,6 +2,7 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include "event-source.h" #include "event-util.h" diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index dad0801b..c3781706 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -25,6 +25,7 @@ #include "signal-util.h" #include "string-table.h" #include "string-util.h" +#include "strxcpyx.h" #include "time-util.h" #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) @@ -341,6 +342,12 @@ fail: DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_event, sd_event, event_free); +_public_ sd_event_source* sd_event_source_disable_unref(sd_event_source *s) { + if (s) + (void) sd_event_source_set_enabled(s, SD_EVENT_OFF); + return sd_event_source_unref(s); +} + static bool event_pid_changed(sd_event *e) { assert(e); @@ -3026,7 +3033,7 @@ static void event_close_inode_data_fds(sd_event *e) { /* Close the fds pointing to the inodes to watch now. We need to close them as they might otherwise pin * filesystems. But we can't close them right-away as we need them as long as the user still wants to make - * adjustments to the even source, such as changing the priority (which requires us to remove and readd a watch + * adjustments to the even source, such as changing the priority (which requires us to remove and re-add a watch * for the inode). Hence, let's close them when entering the first iteration after they were added, as a * compromise. */ @@ -3246,15 +3253,16 @@ _public_ int sd_event_dispatch(sd_event *e) { } static void event_log_delays(sd_event *e) { - char b[ELEMENTSOF(e->delays) * DECIMAL_STR_MAX(unsigned) + 1]; - unsigned i; - int o; + char b[ELEMENTSOF(e->delays) * DECIMAL_STR_MAX(unsigned) + 1], *p; + size_t l, i; - for (i = o = 0; i < ELEMENTSOF(e->delays); i++) { - o += snprintf(&b[o], sizeof(b) - o, "%u ", e->delays[i]); + p = b; + l = sizeof(b); + for (i = 0; i < ELEMENTSOF(e->delays); i++) { + l = strpcpyf(&p, l, "%u ", e->delays[i]); e->delays[i] = 0; } - log_debug("Event loop iterations: %.*s", o, b); + log_debug("Event loop iterations: %s", b); } _public_ int sd_event_run(sd_event *e, uint64_t timeout) { diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c index 6245e9df..f8f0883c 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.c +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -2,6 +2,7 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include <fcntl.h> #include <unistd.h> diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index d0cae981..eeb29e97 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -2,6 +2,7 @@ #include "nm-sd-adapt-core.h" +#include <errno.h> #include <fcntl.h> #include <unistd.h> diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c deleted file mode 100644 index ebea861f..00000000 --- a/src/systemd/src/shared/dns-domain.c +++ /dev/null @@ -1,1387 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ - -#include "nm-sd-adapt-core.h" - -#if 0 /* NM_IGNORED */ -#if HAVE_LIBIDN2 -# include <idn2.h> -#elif HAVE_LIBIDN -# include <idna.h> -# include <stringprep.h> -#endif -#endif - -#include <endian.h> -#include <netinet/in.h> -#include <stdio.h> -#include <string.h> -#include <sys/socket.h> - -#include "alloc-util.h" -#include "dns-domain.h" -#include "hashmap.h" -#include "hexdecoct.h" -#include "hostname-util.h" -#include "in-addr-util.h" -#include "macro.h" -#include "parse-util.h" -#include "string-util.h" -#include "strv.h" -#include "utf8.h" - -int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags) { - const char *n; - char *d, last_char = 0; - int r = 0; - - assert(name); - assert(*name); - - n = *name; - d = dest; - - for (;;) { - if (*n == 0 || *n == '.') { - if (FLAGS_SET(flags, DNS_LABEL_LDH) && last_char == '-') - /* Trailing dash */ - return -EINVAL; - - if (*n == '.') - n++; - break; - } - - if (r >= DNS_LABEL_MAX) - return -EINVAL; - - if (sz <= 0) - return -ENOBUFS; - - if (*n == '\\') { - /* Escaped character */ - if (FLAGS_SET(flags, DNS_LABEL_NO_ESCAPES)) - return -EINVAL; - - n++; - - if (*n == 0) - /* Ending NUL */ - return -EINVAL; - - else if (IN_SET(*n, '\\', '.')) { - /* Escaped backslash or dot */ - - if (FLAGS_SET(flags, DNS_LABEL_LDH)) - return -EINVAL; - - last_char = *n; - if (d) - *(d++) = *n; - sz--; - r++; - n++; - - } else if (n[0] >= '0' && n[0] <= '9') { - unsigned k; - - /* Escaped literal ASCII character */ - - if (!(n[1] >= '0' && n[1] <= '9') || - !(n[2] >= '0' && n[2] <= '9')) - return -EINVAL; - - k = ((unsigned) (n[0] - '0') * 100) + - ((unsigned) (n[1] - '0') * 10) + - ((unsigned) (n[2] - '0')); - - /* Don't allow anything that doesn't - * fit in 8bit. Note that we do allow - * control characters, as some servers - * (e.g. cloudflare) are happy to - * generate labels with them - * inside. */ - if (k > 255) - return -EINVAL; - - if (FLAGS_SET(flags, DNS_LABEL_LDH) && - !valid_ldh_char((char) k)) - return -EINVAL; - - last_char = (char) k; - if (d) - *(d++) = (char) k; - sz--; - r++; - - n += 3; - } else - return -EINVAL; - - } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) { - - /* Normal character */ - - if (FLAGS_SET(flags, DNS_LABEL_LDH)) { - if (!valid_ldh_char(*n)) - return -EINVAL; - if (r == 0 && *n == '-') - /* Leading dash */ - return -EINVAL; - } - - last_char = *n; - if (d) - *(d++) = *n; - sz--; - r++; - n++; - } else - return -EINVAL; - } - - /* Empty label that is not at the end? */ - if (r == 0 && *n) - return -EINVAL; - - /* More than one trailing dot? */ - if (*n == '.') - return -EINVAL; - - if (sz >= 1 && d) - *d = 0; - - *name = n; - return r; -} - -#if 0 /* NM_IGNORED */ -/* @label_terminal: terminal character of a label, updated to point to the terminal character of - * the previous label (always skipping one dot) or to NULL if there are no more - * labels. */ -int dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) { - const char *terminal; - int r; - - assert(name); - assert(label_terminal); - assert(dest); - - /* no more labels */ - if (!*label_terminal) { - if (sz >= 1) - *dest = 0; - - return 0; - } - - terminal = *label_terminal; - assert(IN_SET(*terminal, 0, '.')); - - /* Skip current terminal character (and accept domain names ending it ".") */ - if (*terminal == 0) - terminal--; - if (terminal >= name && *terminal == '.') - terminal--; - - /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */ - for (;;) { - if (terminal < name) { - /* Reached the first label, so indicate that there are no more */ - terminal = NULL; - break; - } - - /* Find the start of the last label */ - if (*terminal == '.') { - const char *y; - unsigned slashes = 0; - - for (y = terminal - 1; y >= name && *y == '\\'; y--) - slashes++; - - if (slashes % 2 == 0) { - /* The '.' was not escaped */ - name = terminal + 1; - break; - } else { - terminal = y; - continue; - } - } - - terminal--; - } - - r = dns_label_unescape(&name, dest, sz, 0); - if (r < 0) - return r; - - *label_terminal = terminal; - - return r; -} -#endif /* NM_IGNORED */ - -int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) { - char *q; - - /* DNS labels must be between 1 and 63 characters long. A - * zero-length label does not exist. See RFC 2182, Section - * 11. */ - - if (l <= 0 || l > DNS_LABEL_MAX) - return -EINVAL; - if (sz < 1) - return -ENOBUFS; - - assert(p); - assert(dest); - - q = dest; - while (l > 0) { - - if (IN_SET(*p, '.', '\\')) { - - /* Dot or backslash */ - - if (sz < 3) - return -ENOBUFS; - - *(q++) = '\\'; - *(q++) = *p; - - sz -= 2; - - } else if (IN_SET(*p, '_', '-') || - (*p >= '0' && *p <= '9') || - (*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z')) { - - /* Proper character */ - - if (sz < 2) - return -ENOBUFS; - - *(q++) = *p; - sz -= 1; - - } else { - - /* Everything else */ - - if (sz < 5) - return -ENOBUFS; - - *(q++) = '\\'; - *(q++) = '0' + (char) ((uint8_t) *p / 100); - *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10); - *(q++) = '0' + (char) ((uint8_t) *p % 10); - - sz -= 4; - } - - p++; - l--; - } - - *q = 0; - return (int) (q - dest); -} - -#if 0 /* NM_IGNORED */ -int dns_label_escape_new(const char *p, size_t l, char **ret) { - _cleanup_free_ char *s = NULL; - int r; - - assert(p); - assert(ret); - - if (l <= 0 || l > DNS_LABEL_MAX) - return -EINVAL; - - s = new(char, DNS_LABEL_ESCAPED_MAX); - if (!s) - return -ENOMEM; - - r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX); - if (r < 0) - return r; - - *ret = TAKE_PTR(s); - - return r; -} - -#if HAVE_LIBIDN -int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) { - _cleanup_free_ uint32_t *input = NULL; - size_t input_size, l; - const char *p; - bool contains_8bit = false; - char buffer[DNS_LABEL_MAX+1]; - - assert(encoded); - assert(decoded); - - /* Converts an U-label into an A-label */ - - if (encoded_size <= 0) - return -EINVAL; - - for (p = encoded; p < encoded + encoded_size; p++) - if ((uint8_t) *p > 127) - contains_8bit = true; - - if (!contains_8bit) { - if (encoded_size > DNS_LABEL_MAX) - return -EINVAL; - - return 0; - } - - input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); - if (!input) - return -ENOMEM; - - if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0) - return -EINVAL; - - l = strlen(buffer); - - /* Verify that the result is not longer than one DNS label. */ - if (l <= 0 || l > DNS_LABEL_MAX) - return -EINVAL; - if (l > decoded_max) - return -ENOBUFS; - - memcpy(decoded, buffer, l); - - /* If there's room, append a trailing NUL byte, but only then */ - if (decoded_max > l) - decoded[l] = 0; - - return (int) l; -} - -int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) { - size_t input_size, output_size; - _cleanup_free_ uint32_t *input = NULL; - _cleanup_free_ char *result = NULL; - uint32_t *output = NULL; - size_t w; - - /* To be invoked after unescaping. Converts an A-label into an U-label. */ - - assert(encoded); - assert(decoded); - - if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX) - return -EINVAL; - - if (!memory_startswith(encoded, encoded_size, IDNA_ACE_PREFIX)) - return 0; - - input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); - if (!input) - return -ENOMEM; - - output_size = input_size; - output = newa(uint32_t, output_size); - - idna_to_unicode_44i(input, input_size, output, &output_size, 0); - - result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w); - if (!result) - return -ENOMEM; - if (w <= 0) - return -EINVAL; - if (w > decoded_max) - return -ENOBUFS; - - memcpy(decoded, result, w); - - /* Append trailing NUL byte if there's space, but only then. */ - if (decoded_max > w) - decoded[w] = 0; - - return w; -} -#endif -#endif /* NM_IGNORED */ - -int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_ret) { - _cleanup_free_ char *ret = NULL; - size_t n = 0, allocated = 0; - const char *p; - bool first = true; - int r; - - if (a) - p = a; - else if (b) - p = TAKE_PTR(b); - else - goto finish; - - for (;;) { - char label[DNS_LABEL_MAX]; - - r = dns_label_unescape(&p, label, sizeof label, flags); - if (r < 0) - return r; - if (r == 0) { - if (*p != 0) - return -EINVAL; - - if (b) { - /* Now continue with the second string, if there is one */ - p = TAKE_PTR(b); - continue; - } - - break; - } - - if (_ret) { - if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) - return -ENOMEM; - - r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX); - if (r < 0) - return r; - - if (!first) - ret[n] = '.'; - } else { - char escaped[DNS_LABEL_ESCAPED_MAX]; - - r = dns_label_escape(label, r, escaped, sizeof(escaped)); - if (r < 0) - return r; - } - - if (!first) - n++; - else - first = false; - - n += r; - } - -finish: - if (n > DNS_HOSTNAME_MAX) - return -EINVAL; - - if (_ret) { - if (n == 0) { - /* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */ - if (!GREEDY_REALLOC(ret, allocated, 2)) - return -ENOMEM; - - ret[n++] = '.'; - } else { - if (!GREEDY_REALLOC(ret, allocated, n + 1)) - return -ENOMEM; - } - - ret[n] = 0; - *_ret = TAKE_PTR(ret); - } - - return 0; -} - -#if 0 /* NM_IGNORED */ -void dns_name_hash_func(const char *p, struct siphash *state) { - int r; - - assert(p); - - for (;;) { - char label[DNS_LABEL_MAX+1]; - - r = dns_label_unescape(&p, label, sizeof label, 0); - if (r < 0) - break; - if (r == 0) - break; - - ascii_strlower_n(label, r); - siphash24_compress(label, r, state); - siphash24_compress_byte(0, state); /* make sure foobar and foo.bar result in different hashes */ - } - - /* enforce that all names are terminated by the empty label */ - string_hash_func("", state); -} - -int dns_name_compare_func(const char *a, const char *b) { - const char *x, *y; - int r, q; - - assert(a); - assert(b); - - x = a + strlen(a); - y = b + strlen(b); - - for (;;) { - char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX]; - - if (x == NULL && y == NULL) - return 0; - - r = dns_label_unescape_suffix(a, &x, la, sizeof(la)); - q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb)); - if (r < 0 || q < 0) - return CMP(r, q); - - r = ascii_strcasecmp_nn(la, r, lb, q); - if (r != 0) - return r; - } -} - -DEFINE_HASH_OPS(dns_name_hash_ops, char, dns_name_hash_func, dns_name_compare_func); - -int dns_name_equal(const char *x, const char *y) { - int r, q; - - assert(x); - assert(y); - - for (;;) { - char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX]; - - r = dns_label_unescape(&x, la, sizeof la, 0); - if (r < 0) - return r; - - q = dns_label_unescape(&y, lb, sizeof lb, 0); - if (q < 0) - return q; - - if (r != q) - return false; - if (r == 0) - return true; - - if (ascii_strcasecmp_n(la, lb, r) != 0) - return false; - } -} - -int dns_name_endswith(const char *name, const char *suffix) { - const char *n, *s, *saved_n = NULL; - int r, q; - - assert(name); - assert(suffix); - - n = name; - s = suffix; - - for (;;) { - char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX]; - - r = dns_label_unescape(&n, ln, sizeof ln, 0); - if (r < 0) - return r; - - if (!saved_n) - saved_n = n; - - q = dns_label_unescape(&s, ls, sizeof ls, 0); - if (q < 0) - return q; - - if (r == 0 && q == 0) - return true; - if (r == 0 && saved_n == n) - return false; - - if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) { - - /* Not the same, let's jump back, and try with the next label again */ - s = suffix; - n = TAKE_PTR(saved_n); - } - } -} - -int dns_name_startswith(const char *name, const char *prefix) { - const char *n, *p; - int r, q; - - assert(name); - assert(prefix); - - n = name; - p = prefix; - - for (;;) { - char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX]; - - r = dns_label_unescape(&p, lp, sizeof lp, 0); - if (r < 0) - return r; - if (r == 0) - return true; - - q = dns_label_unescape(&n, ln, sizeof ln, 0); - if (q < 0) - return q; - - if (r != q) - return false; - if (ascii_strcasecmp_n(ln, lp, r) != 0) - return false; - } -} - -int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) { - const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix; - int r, q; - - assert(name); - assert(old_suffix); - assert(new_suffix); - assert(ret); - - n = name; - s = old_suffix; - - for (;;) { - char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX]; - - if (!saved_before) - saved_before = n; - - r = dns_label_unescape(&n, ln, sizeof ln, 0); - if (r < 0) - return r; - - if (!saved_after) - saved_after = n; - - q = dns_label_unescape(&s, ls, sizeof ls, 0); - if (q < 0) - return q; - - if (r == 0 && q == 0) - break; - if (r == 0 && saved_after == n) { - *ret = NULL; /* doesn't match */ - return 0; - } - - if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) { - - /* Not the same, let's jump back, and try with the next label again */ - s = old_suffix; - n = TAKE_PTR(saved_after); - saved_before = NULL; - } - } - - /* Found it! Now generate the new name */ - prefix = strndupa(name, saved_before - name); - - r = dns_name_concat(prefix, new_suffix, 0, ret); - if (r < 0) - return r; - - return 1; -} - -int dns_name_between(const char *a, const char *b, const char *c) { - /* Determine if b is strictly greater than a and strictly smaller than c. - We consider the order of names to be circular, so that if a is - strictly greater than c, we consider b to be between them if it is - either greater than a or smaller than c. This is how the canonical - DNS name order used in NSEC records work. */ - - if (dns_name_compare_func(a, c) < 0) - /* - a and c are properly ordered: - a<---b--->c - */ - return dns_name_compare_func(a, b) < 0 && - dns_name_compare_func(b, c) < 0; - else - /* - a and c are equal or 'reversed': - <--b--c a-----> - or: - <-----c a--b--> - */ - return dns_name_compare_func(b, c) < 0 || - dns_name_compare_func(a, b) < 0; -} - -int dns_name_reverse(int family, const union in_addr_union *a, char **ret) { - const uint8_t *p; - int r; - - assert(a); - assert(ret); - - p = (const uint8_t*) a; - - if (family == AF_INET) - r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]); - else if (family == AF_INET6) - r = asprintf(ret, "%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.ip6.arpa", - hexchar(p[15] & 0xF), hexchar(p[15] >> 4), hexchar(p[14] & 0xF), hexchar(p[14] >> 4), - hexchar(p[13] & 0xF), hexchar(p[13] >> 4), hexchar(p[12] & 0xF), hexchar(p[12] >> 4), - hexchar(p[11] & 0xF), hexchar(p[11] >> 4), hexchar(p[10] & 0xF), hexchar(p[10] >> 4), - hexchar(p[ 9] & 0xF), hexchar(p[ 9] >> 4), hexchar(p[ 8] & 0xF), hexchar(p[ 8] >> 4), - hexchar(p[ 7] & 0xF), hexchar(p[ 7] >> 4), hexchar(p[ 6] & 0xF), hexchar(p[ 6] >> 4), - hexchar(p[ 5] & 0xF), hexchar(p[ 5] >> 4), hexchar(p[ 4] & 0xF), hexchar(p[ 4] >> 4), - hexchar(p[ 3] & 0xF), hexchar(p[ 3] >> 4), hexchar(p[ 2] & 0xF), hexchar(p[ 2] >> 4), - hexchar(p[ 1] & 0xF), hexchar(p[ 1] >> 4), hexchar(p[ 0] & 0xF), hexchar(p[ 0] >> 4)); - else - return -EAFNOSUPPORT; - if (r < 0) - return -ENOMEM; - - return 0; -} - -int dns_name_address(const char *p, int *family, union in_addr_union *address) { - int r; - - assert(p); - assert(family); - assert(address); - - r = dns_name_endswith(p, "in-addr.arpa"); - if (r < 0) - return r; - if (r > 0) { - uint8_t a[4]; - unsigned i; - - for (i = 0; i < ELEMENTSOF(a); i++) { - char label[DNS_LABEL_MAX+1]; - - r = dns_label_unescape(&p, label, sizeof label, 0); - if (r < 0) - return r; - if (r == 0) - return -EINVAL; - if (r > 3) - return -EINVAL; - - r = safe_atou8(label, &a[i]); - if (r < 0) - return r; - } - - r = dns_name_equal(p, "in-addr.arpa"); - if (r <= 0) - return r; - - *family = AF_INET; - address->in.s_addr = htobe32(((uint32_t) a[3] << 24) | - ((uint32_t) a[2] << 16) | - ((uint32_t) a[1] << 8) | - (uint32_t) a[0]); - - return 1; - } - - r = dns_name_endswith(p, "ip6.arpa"); - if (r < 0) - return r; - if (r > 0) { - struct in6_addr a; - unsigned i; - - for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) { - char label[DNS_LABEL_MAX+1]; - int x, y; - - r = dns_label_unescape(&p, label, sizeof label, 0); - if (r <= 0) - return r; - if (r != 1) - return -EINVAL; - x = unhexchar(label[0]); - if (x < 0) - return -EINVAL; - - r = dns_label_unescape(&p, label, sizeof label, 0); - if (r <= 0) - return r; - if (r != 1) - return -EINVAL; - y = unhexchar(label[0]); - if (y < 0) - return -EINVAL; - - a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x; - } - - r = dns_name_equal(p, "ip6.arpa"); - if (r <= 0) - return r; - - *family = AF_INET6; - address->in6 = a; - return 1; - } - - return 0; -} -#endif /* NM_IGNORED */ - -bool dns_name_is_root(const char *name) { - - assert(name); - - /* There are exactly two ways to encode the root domain name: - * as empty string, or with a single dot. */ - - return STR_IN_SET(name, "", "."); -} - -bool dns_name_is_single_label(const char *name) { - int r; - - assert(name); - - r = dns_name_parent(&name); - if (r <= 0) - return false; - - return dns_name_is_root(name); -} - -/* Encode a domain name according to RFC 1035 Section 3.1, without compression */ -int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical) { - uint8_t *label_length, *out; - int r; - - assert(domain); - assert(buffer); - - out = buffer; - - do { - /* Reserve a byte for label length */ - if (len <= 0) - return -ENOBUFS; - len--; - label_length = out; - out++; - - /* Convert and copy a single label. Note that - * dns_label_unescape() returns 0 when it hits the end - * of the domain name, which we rely on here to encode - * the trailing NUL byte. */ - r = dns_label_unescape(&domain, (char *) out, len, 0); - if (r < 0) - return r; - - /* Optionally, output the name in DNSSEC canonical - * format, as described in RFC 4034, section 6.2. Or - * in other words: in lower-case. */ - if (canonical) - ascii_strlower_n((char*) out, (size_t) r); - - /* Fill label length, move forward */ - *label_length = r; - out += r; - len -= r; - - } while (r != 0); - - /* Verify the maximum size of the encoded name. The trailing - * dot + NUL byte account are included this time, hence - * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this - * time. */ - if (out - buffer > DNS_HOSTNAME_MAX + 2) - return -EINVAL; - - return out - buffer; -} - -#if 0 /* NM_IGNORED */ -static bool srv_type_label_is_valid(const char *label, size_t n) { - size_t k; - - assert(label); - - if (n < 2) /* Label needs to be at least 2 chars long */ - return false; - - if (label[0] != '_') /* First label char needs to be underscore */ - return false; - - /* Second char must be a letter */ - if (!(label[1] >= 'A' && label[1] <= 'Z') && - !(label[1] >= 'a' && label[1] <= 'z')) - return false; - - /* Third and further chars must be alphanumeric or a hyphen */ - for (k = 2; k < n; k++) { - if (!(label[k] >= 'A' && label[k] <= 'Z') && - !(label[k] >= 'a' && label[k] <= 'z') && - !(label[k] >= '0' && label[k] <= '9') && - label[k] != '-') - return false; - } - - return true; -} - -bool dns_srv_type_is_valid(const char *name) { - unsigned c = 0; - int r; - - if (!name) - return false; - - for (;;) { - char label[DNS_LABEL_MAX]; - - /* This more or less implements RFC 6335, Section 5.1 */ - - r = dns_label_unescape(&name, label, sizeof label, 0); - if (r < 0) - return false; - if (r == 0) - break; - - if (c >= 2) - return false; - - if (!srv_type_label_is_valid(label, r)) - return false; - - c++; - } - - return c == 2; /* exactly two labels */ -} - -bool dnssd_srv_type_is_valid(const char *name) { - return dns_srv_type_is_valid(name) && - ((dns_name_endswith(name, "_tcp") > 0) || - (dns_name_endswith(name, "_udp") > 0)); /* Specific to DNS-SD. RFC 6763, Section 7 */ -} - -bool dns_service_name_is_valid(const char *name) { - size_t l; - - /* This more or less implements RFC 6763, Section 4.1.1 */ - - if (!name) - return false; - - if (!utf8_is_valid(name)) - return false; - - if (string_has_cc(name, NULL)) - return false; - - l = strlen(name); - if (l <= 0) - return false; - if (l > 63) - return false; - - return true; -} - -int dns_service_join(const char *name, const char *type, const char *domain, char **ret) { - char escaped[DNS_LABEL_ESCAPED_MAX]; - _cleanup_free_ char *n = NULL; - int r; - - assert(type); - assert(domain); - assert(ret); - - if (!dns_srv_type_is_valid(type)) - return -EINVAL; - - if (!name) - return dns_name_concat(type, domain, 0, ret); - - if (!dns_service_name_is_valid(name)) - return -EINVAL; - - r = dns_label_escape(name, strlen(name), escaped, sizeof(escaped)); - if (r < 0) - return r; - - r = dns_name_concat(type, domain, 0, &n); - if (r < 0) - return r; - - return dns_name_concat(escaped, n, 0, ret); -} - -static bool dns_service_name_label_is_valid(const char *label, size_t n) { - char *s; - - assert(label); - - if (memchr(label, 0, n)) - return false; - - s = strndupa(label, n); - return dns_service_name_is_valid(s); -} - -int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) { - _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL; - const char *p = joined, *q = NULL, *d = NULL; - char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX]; - int an, bn, cn, r; - unsigned x = 0; - - assert(joined); - - /* Get first label from the full name */ - an = dns_label_unescape(&p, a, sizeof(a), 0); - if (an < 0) - return an; - - if (an > 0) { - x++; - - /* If there was a first label, try to get the second one */ - bn = dns_label_unescape(&p, b, sizeof(b), 0); - if (bn < 0) - return bn; - - if (bn > 0) { - x++; - - /* If there was a second label, try to get the third one */ - q = p; - cn = dns_label_unescape(&p, c, sizeof(c), 0); - if (cn < 0) - return cn; - - if (cn > 0) - x++; - } else - cn = 0; - } else - an = 0; - - if (x >= 2 && srv_type_label_is_valid(b, bn)) { - - if (x >= 3 && srv_type_label_is_valid(c, cn)) { - - if (dns_service_name_label_is_valid(a, an)) { - /* OK, got <name> . <type> . <type2> . <domain> */ - - name = strndup(a, an); - if (!name) - return -ENOMEM; - - type = strjoin(b, ".", c); - if (!type) - return -ENOMEM; - - d = p; - goto finish; - } - - } else if (srv_type_label_is_valid(a, an)) { - - /* OK, got <type> . <type2> . <domain> */ - - name = NULL; - - type = strjoin(a, ".", b); - if (!type) - return -ENOMEM; - - d = q; - goto finish; - } - } - - name = NULL; - type = NULL; - d = joined; - -finish: - r = dns_name_normalize(d, 0, &domain); - if (r < 0) - return r; - - if (_domain) - *_domain = TAKE_PTR(domain); - - if (_type) - *_type = TAKE_PTR(type); - - if (_name) - *_name = TAKE_PTR(name); - - return 0; -} - -static int dns_name_build_suffix_table(const char *name, const char *table[]) { - const char *p; - unsigned n = 0; - int r; - - assert(name); - assert(table); - - p = name; - for (;;) { - if (n > DNS_N_LABELS_MAX) - return -EINVAL; - - table[n] = p; - r = dns_name_parent(&p); - if (r < 0) - return r; - if (r == 0) - break; - - n++; - } - - return (int) n; -} - -int dns_name_suffix(const char *name, unsigned n_labels, const char **ret) { - const char* labels[DNS_N_LABELS_MAX+1]; - int n; - - assert(name); - assert(ret); - - n = dns_name_build_suffix_table(name, labels); - if (n < 0) - return n; - - if ((unsigned) n < n_labels) - return -EINVAL; - - *ret = labels[n - n_labels]; - return (int) (n - n_labels); -} - -int dns_name_skip(const char *a, unsigned n_labels, const char **ret) { - int r; - - assert(a); - assert(ret); - - for (; n_labels > 0; n_labels--) { - r = dns_name_parent(&a); - if (r < 0) - return r; - if (r == 0) { - *ret = ""; - return 0; - } - } - - *ret = a; - return 1; -} - -int dns_name_count_labels(const char *name) { - unsigned n = 0; - const char *p; - int r; - - assert(name); - - p = name; - for (;;) { - r = dns_name_parent(&p); - if (r < 0) - return r; - if (r == 0) - break; - - if (n >= DNS_N_LABELS_MAX) - return -EINVAL; - - n++; - } - - return (int) n; -} - -int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b) { - int r; - - assert(a); - assert(b); - - r = dns_name_skip(a, n_labels, &a); - if (r <= 0) - return r; - - return dns_name_equal(a, b); -} - -int dns_name_common_suffix(const char *a, const char *b, const char **ret) { - const char *a_labels[DNS_N_LABELS_MAX+1], *b_labels[DNS_N_LABELS_MAX+1]; - int n = 0, m = 0, k = 0, r, q; - - assert(a); - assert(b); - assert(ret); - - /* Determines the common suffix of domain names a and b */ - - n = dns_name_build_suffix_table(a, a_labels); - if (n < 0) - return n; - - m = dns_name_build_suffix_table(b, b_labels); - if (m < 0) - return m; - - for (;;) { - char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX]; - const char *x, *y; - - if (k >= n || k >= m) { - *ret = a_labels[n - k]; - return 0; - } - - x = a_labels[n - 1 - k]; - r = dns_label_unescape(&x, la, sizeof la, 0); - if (r < 0) - return r; - - y = b_labels[m - 1 - k]; - q = dns_label_unescape(&y, lb, sizeof lb, 0); - if (q < 0) - return q; - - if (r != q || ascii_strcasecmp_n(la, lb, r) != 0) { - *ret = a_labels[n - k]; - return 0; - } - - k++; - } -} - -int dns_name_apply_idna(const char *name, char **ret) { - /* Return negative on error, 0 if not implemented, positive on success. */ - -#if HAVE_LIBIDN2 - int r; - _cleanup_free_ char *t = NULL; - - assert(name); - assert(ret); - - r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t, - IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL); - log_debug("idn2_lookup_u8: %s → %s", name, t); - if (r == IDN2_OK) { - if (!startswith(name, "xn--")) { - _cleanup_free_ char *s = NULL; - - r = idn2_to_unicode_8z8z(t, &s, 0); - if (r != IDN2_OK) { - log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s", - t, r, idn2_strerror(r)); - return 0; - } - - if (!streq_ptr(name, s)) { - log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.", - name, t, s); - return 0; - } - } - - *ret = TAKE_PTR(t); - - return 1; /* *ret has been written */ - } - - log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r)); - if (r == IDN2_2HYPHEN) - /* The name has two hyphens — forbidden by IDNA2008 in some cases */ - return 0; - if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL)) - return -ENOSPC; - return -EINVAL; -#elif HAVE_LIBIDN - _cleanup_free_ char *buf = NULL; - size_t n = 0, allocated = 0; - bool first = true; - int r, q; - - assert(name); - assert(ret); - - for (;;) { - char label[DNS_LABEL_MAX]; - - r = dns_label_unescape(&name, label, sizeof label, 0); - if (r < 0) - return r; - if (r == 0) - break; - - q = dns_label_apply_idna(label, r, label, sizeof label); - if (q < 0) - return q; - if (q > 0) - r = q; - - if (!GREEDY_REALLOC(buf, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) - return -ENOMEM; - - r = dns_label_escape(label, r, buf + n + !first, DNS_LABEL_ESCAPED_MAX); - if (r < 0) - return r; - - if (first) - first = false; - else - buf[n++] = '.'; - - n += r; - } - - if (n > DNS_HOSTNAME_MAX) - return -EINVAL; - - if (!GREEDY_REALLOC(buf, allocated, n + 1)) - return -ENOMEM; - - buf[n] = 0; - *ret = TAKE_PTR(buf); - - return 1; -#else - return 0; -#endif -} - -int dns_name_is_valid_or_address(const char *name) { - /* Returns > 0 if the specified name is either a valid IP address formatted as string or a valid DNS name */ - - if (isempty(name)) - return 0; - - if (in_addr_from_string_auto(name, NULL, NULL) >= 0) - return 1; - - return dns_name_is_valid(name); -} -#endif /* NM_IGNORED */ diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h deleted file mode 100644 index 17db7c52..00000000 --- a/src/systemd/src/shared/dns-domain.h +++ /dev/null @@ -1,113 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -#pragma once - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -#include "hashmap.h" -#include "in-addr-util.h" - -/* Length of a single label, with all escaping removed, excluding any trailing dot or NUL byte */ -#define DNS_LABEL_MAX 63 - -/* Worst case length of a single label, with all escaping applied and room for a trailing NUL byte. */ -#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1) - -/* Maximum length of a full hostname, consisting of a series of unescaped labels, and no trailing dot or NUL byte */ -#define DNS_HOSTNAME_MAX 253 - -/* Maximum length of a full hostname, on the wire, including the final NUL byte */ -#define DNS_WIRE_FORMAT_HOSTNAME_MAX 255 - -/* Maximum number of labels per valid hostname */ -#define DNS_N_LABELS_MAX 127 - -typedef enum DNSLabelFlags { - DNS_LABEL_LDH = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */ - DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */ -} DNSLabelFlags; - -int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags); -int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz); -int dns_label_escape(const char *p, size_t l, char *dest, size_t sz); -int dns_label_escape_new(const char *p, size_t l, char **ret); - -static inline int dns_name_parent(const char **name) { - return dns_label_unescape(name, NULL, DNS_LABEL_MAX, 0); -} - -#if 0 /* NM_IGNORED */ -#if HAVE_LIBIDN -int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max); -int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max); -#endif -#endif /* NM_IGNORED */ - -int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **ret); - -static inline int dns_name_normalize(const char *s, DNSLabelFlags flags, char **ret) { - /* dns_name_concat() normalizes as a side-effect */ - return dns_name_concat(s, NULL, flags, ret); -} - -static inline int dns_name_is_valid(const char *s) { - int r; - - /* dns_name_normalize() verifies as a side effect */ - r = dns_name_normalize(s, 0, NULL); - if (r == -EINVAL) - return 0; - if (r < 0) - return r; - return 1; -} - -static inline int dns_name_is_valid_ldh(const char *s) { - int r; - - r = dns_name_concat(s, NULL, DNS_LABEL_LDH|DNS_LABEL_NO_ESCAPES, NULL); - if (r == -EINVAL) - return 0; - if (r < 0) - return r; - return 1; -} - -void dns_name_hash_func(const char *s, struct siphash *state); -int dns_name_compare_func(const char *a, const char *b); -extern const struct hash_ops dns_name_hash_ops; - -int dns_name_between(const char *a, const char *b, const char *c); -int dns_name_equal(const char *x, const char *y); -int dns_name_endswith(const char *name, const char *suffix); -int dns_name_startswith(const char *name, const char *prefix); - -int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret); - -int dns_name_reverse(int family, const union in_addr_union *a, char **ret); -int dns_name_address(const char *p, int *family, union in_addr_union *a); - -bool dns_name_is_root(const char *name); -bool dns_name_is_single_label(const char *name); - -int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical); - -bool dns_srv_type_is_valid(const char *name); -bool dnssd_srv_type_is_valid(const char *name); -bool dns_service_name_is_valid(const char *name); - -int dns_service_join(const char *name, const char *type, const char *domain, char **ret); -int dns_service_split(const char *joined, char **name, char **type, char **domain); - -int dns_name_suffix(const char *name, unsigned n_labels, const char **ret); -int dns_name_count_labels(const char *name); - -int dns_name_skip(const char *a, unsigned n_labels, const char **ret); -int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b); - -int dns_name_common_suffix(const char *a, const char *b, const char **ret); - -int dns_name_apply_idna(const char *name, char **ret); - -int dns_name_is_valid_or_address(const char *name); diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index bd0d429d..ab62368e 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -38,6 +38,7 @@ enum { 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, }; enum { @@ -98,7 +99,7 @@ enum { typedef struct sd_dhcp_client sd_dhcp_client; -typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata); +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, @@ -154,6 +155,9 @@ int sd_dhcp_client_get_client_id( 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); @@ -172,6 +176,7 @@ int sd_dhcp_client_get_lease( 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); sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client); sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client); diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index 7bb86093..b14c9269 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -113,6 +113,7 @@ int sd_event_get_iteration(sd_event *e, uint64_t *ret); sd_event_source* sd_event_source_ref(sd_event_source *s); sd_event_source* sd_event_source_unref(sd_event_source *s); +sd_event_source* sd_event_source_disable_unref(sd_event_source *s); sd_event *sd_event_source_get_event(sd_event_source *s); void* sd_event_source_get_userdata(sd_event_source *s); @@ -149,6 +150,7 @@ int sd_event_source_set_floating(sd_event_source *s, int b); /* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */ _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event_source, sd_event_source_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event_source, sd_event_source_disable_unref); _SD_END_DECLARATIONS; diff --git a/src/systemd/src/systemd/sd-id128.h b/src/systemd/src/systemd/sd-id128.h index c5fbe0a4..9b00b76e 100644 --- a/src/systemd/src/systemd/sd-id128.h +++ b/src/systemd/src/systemd/sd-id128.h @@ -54,7 +54,6 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret); #define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ ((const sd_id128_t) SD_ID128_ARRAY(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)) - /* Note that SD_ID128_FORMAT_VAL will evaluate the passed argument 16 * times. It is hence not a good idea to call this macro with an * expensive function as parameter or an expression with side |