diff --git a/Makefile.am b/Makefile.am index e1b7b12ab..04c767adb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1937,6 +1937,8 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \ shared/systemd/src/basic/util.h \ shared/systemd/src/shared/dns-domain.c \ shared/systemd/src/shared/dns-domain.h \ + shared/systemd/src/shared/web-util.c \ + shared/systemd/src/shared/web-util.h \ $(NULL) shared_systemd_libnm_systemd_shared_la_LIBADD = \ diff --git a/shared/meson.build b/shared/meson.build index 2d26c6557..9a8768f53 100644 --- a/shared/meson.build +++ b/shared/meson.build @@ -232,6 +232,7 @@ sources = files( 'systemd/src/basic/utf8.c', 'systemd/src/basic/util.c', 'systemd/src/shared/dns-domain.c', + 'systemd/src/shared/web-util.c', ) incs = include_directories( diff --git a/shared/systemd/src/basic/cgroup-util.h b/shared/systemd/src/basic/cgroup-util.h index 300555f1a..237139fad 100644 --- a/shared/systemd/src/basic/cgroup-util.h +++ b/shared/systemd/src/basic/cgroup-util.h @@ -184,10 +184,13 @@ int cg_set_attribute(const char *controller, const char *path, const char *attri int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret); int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, char **keys, char **values); +int cg_get_attribute_as_uint64(const char *controller, const char *path, const char *attribute, uint64_t *ret); + int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid); int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags); int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size); +int cg_get_xattr_malloc(const char *controller, const char *path, const char *name, char **ret); int cg_remove_xattr(const char *controller, const char *path, const char *name); int cg_install_release_agent(const char *controller, const char *agent); diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c index 02d62c899..543dd4eb9 100644 --- a/shared/systemd/src/basic/fileio.c +++ b/shared/systemd/src/basic/fileio.c @@ -56,6 +56,44 @@ int fdopen_unlocked(int fd, const char *options, FILE **ret) { return 0; } +int take_fdopen_unlocked(int *fd, const char *options, FILE **ret) { + int r; + + assert(fd); + + r = fdopen_unlocked(*fd, options, ret); + if (r < 0) + return r; + + *fd = -1; + + return 0; +} + +FILE* take_fdopen(int *fd, const char *options) { + assert(fd); + + FILE *f = fdopen(*fd, options); + if (!f) + return NULL; + + *fd = -1; + + return f; +} + +DIR* take_fdopendir(int *dfd) { + assert(dfd); + + DIR *d = fdopendir(*dfd); + if (!d) + return NULL; + + *dfd = -1; + + return d; +} + FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc) { FILE *f = open_memstream(ptr, sizeloc); if (!f) diff --git a/shared/systemd/src/basic/fileio.h b/shared/systemd/src/basic/fileio.h index e6fea2afd..58daabaa8 100644 --- a/shared/systemd/src/basic/fileio.h +++ b/shared/systemd/src/basic/fileio.h @@ -39,6 +39,9 @@ typedef enum { int fopen_unlocked(const char *path, const char *options, FILE **ret); int fdopen_unlocked(int fd, const char *options, FILE **ret); +int take_fdopen_unlocked(int *fd, const char *options, FILE **ret); +FILE* take_fdopen(int *fd, const char *options); +DIR* take_fdopendir(int *dfd); FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc); FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode); diff --git a/shared/systemd/src/basic/log.h b/shared/systemd/src/basic/log.h index b81c93a59..3725b08f8 100644 --- a/shared/systemd/src/basic/log.h +++ b/shared/systemd/src/basic/log.h @@ -59,9 +59,12 @@ void log_show_color(bool b); bool log_get_show_color(void) _pure_; void log_show_location(bool b); bool log_get_show_location(void) _pure_; +void log_show_time(bool b); +bool log_get_show_time(void) _pure_; int log_show_color_from_string(const char *e); int log_show_location_from_string(const char *e); +int log_show_time_from_string(const char *e); LogTarget log_get_target(void) _pure_; #if 0 /* NM_IGNORED */ @@ -77,7 +80,7 @@ int log_get_max_level_realm(LogRealm realm) _pure_; #if 0 /* NM_IGNORED */ assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1); -#define PROJECT_FILE (__FILE__ + STRLEN(RELATIVE_SOURCE_PATH) + 1) +#define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1]) #endif /* NM_IGNORED */ #define PROJECT_FILE __FILE__ diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c index 57c84fd86..2de3541cb 100644 --- a/shared/systemd/src/basic/process-util.c +++ b/shared/systemd/src/basic/process-util.c @@ -1188,6 +1188,11 @@ int must_be_root(void) { return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be root."); } +static void restore_sigsetp(sigset_t **ssp) { + if (*ssp) + (void) sigprocmask(SIG_SETMASK, *ssp, NULL); +} + int safe_fork_full( const char *name, const int except_fds[], @@ -1197,7 +1202,8 @@ int safe_fork_full( pid_t original_pid, pid; sigset_t saved_ss, ss; - bool block_signals = false; + _cleanup_(restore_sigsetp) sigset_t *saved_ssp = NULL; + bool block_signals = false, block_all = false; int prio, r; /* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always @@ -1212,7 +1218,7 @@ int safe_fork_full( * be sure that SIGTERMs are not lost we might send to the child. */ assert_se(sigfillset(&ss) >= 0); - block_signals = true; + block_signals = block_all = true; } else if (flags & FORK_WAIT) { /* Let's block SIGCHLD at least, so that we can safely watch for the child process */ @@ -1222,28 +1228,31 @@ int safe_fork_full( block_signals = true; } - if (block_signals) + if (block_signals) { if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0) return log_full_errno(prio, errno, "Failed to set signal mask: %m"); + saved_ssp = &saved_ss; + } if (flags & FORK_NEW_MOUNTNS) pid = raw_clone(SIGCHLD|CLONE_NEWNS); else pid = fork(); - if (pid < 0) { - r = -errno; - - if (block_signals) /* undo what we did above */ - (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL); - - return log_full_errno(prio, r, "Failed to fork: %m"); - } + if (pid < 0) + return log_full_errno(prio, errno, "Failed to fork: %m"); if (pid > 0) { /* We are in the parent process */ log_debug("Successfully forked off '%s' as PID " PID_FMT ".", strna(name), pid); if (flags & FORK_WAIT) { + if (block_all) { + /* undo everything except SIGCHLD */ + ss = saved_ss; + assert_se(sigaddset(&ss, SIGCHLD) >= 0); + (void) sigprocmask(SIG_SETMASK, &ss, NULL); + } + r = wait_for_terminate_and_check(name, pid, (flags & FORK_LOG ? WAIT_LOG : 0)); if (r < 0) return r; @@ -1251,9 +1260,6 @@ int safe_fork_full( return -EPROTO; } - if (block_signals) /* undo what we did above */ - (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL); - if (ret_pid) *ret_pid = pid; @@ -1262,6 +1268,9 @@ int safe_fork_full( /* We are in the child process */ + /* Restore signal mask manually */ + saved_ssp = NULL; + if (flags & FORK_REOPEN_LOG) { /* Close the logs if requested, before we log anything. And make sure we reopen it if needed. */ log_close(); diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c index 848812cd0..a895c1c34 100644 --- a/shared/systemd/src/basic/stat-util.c +++ b/shared/systemd/src/basic/stat-util.c @@ -12,6 +12,7 @@ #include "alloc-util.h" #include "dirent-util.h" #include "fd-util.h" +#include "fileio.h" #include "fs-util.h" #include "macro.h" #include "missing_fs.h" @@ -82,10 +83,9 @@ int dir_is_empty_at(int dir_fd, const char *path) { if (fd < 0) return -errno; - d = fdopendir(fd); + d = take_fdopendir(&fd); if (!d) return -errno; - fd = -1; FOREACH_DIRENT(de, d, return -errno) return 0; diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c index 333da61ab..9f15cacae 100644 --- a/shared/systemd/src/basic/string-util.c +++ b/shared/systemd/src/basic/string-util.c @@ -115,7 +115,7 @@ static size_t strcspn_escaped(const char *s, const char *reject) { bool escaped = false; int n; - for (n=0; s[n]; n++) { + for (n = 0; s[n] != '\0'; n++) { if (escaped) escaped = false; else if (s[n] == '\\') @@ -124,50 +124,62 @@ static size_t strcspn_escaped(const char *s, const char *reject) { break; } - /* if s ends in \, return index of previous char */ - return n - escaped; + return n; } /* Split a string into words. */ -const char* split(const char **state, size_t *l, const char *separator, SplitFlags flags) { +const char* split( + const char **state, + size_t *l, + const char *separator, + SplitFlags flags) { + const char *current; + assert(state); + assert(l); + + if (!separator) + separator = WHITESPACE; + current = *state; - if (!*current) { - assert(**state == '\0'); + if (*current == '\0') /* already at the end? */ return NULL; - } - current += strspn(current, separator); - if (!*current) { + current += strspn(current, separator); /* skip leading separators */ + if (*current == '\0') { /* at the end now? */ *state = current; return NULL; } - if (flags & SPLIT_QUOTES && strchr("\'\"", *current)) { - char quotechars[2] = {*current, '\0'}; + if (FLAGS_SET(flags, SPLIT_QUOTES)) { - *l = strcspn_escaped(current + 1, quotechars); - if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || - (current[*l + 2] && !strchr(separator, current[*l + 2]))) { - /* right quote missing or garbage at the end */ - if (flags & SPLIT_RELAX) { - *state = current + *l + 1 + (current[*l + 1] != '\0'); - return current + 1; + if (strchr(QUOTES, *current)) { + /* We are looking at a quote */ + *l = strcspn_escaped(current + 1, CHAR_TO_STR(*current)); + if (current[*l + 1] != *current || + (current[*l + 2] != 0 && !strchr(separator, current[*l + 2]))) { + /* right quote missing or garbage at the end */ + if (FLAGS_SET(flags, SPLIT_RELAX)) { + *state = current + *l + 1 + (current[*l + 1] != '\0'); + return current + 1; + } + *state = current; + return NULL; } - *state = current; - return NULL; + *state = current++ + *l + 2; + + } else { + /* We are looking at a something that is not a quote */ + *l = strcspn_escaped(current, separator); + if (current[*l] && !strchr(separator, current[*l]) && !FLAGS_SET(flags, SPLIT_RELAX)) { + /* unfinished escape */ + *state = current; + return NULL; + } + *state = current + *l; } - *state = current++ + *l + 2; - } else if (flags & SPLIT_QUOTES) { - *l = strcspn_escaped(current, separator); - if (current[*l] && !strchr(separator, current[*l]) && !(flags & SPLIT_RELAX)) { - /* unfinished escape */ - *state = current; - return NULL; - } - *state = current + *l; } else { *l = strcspn(current, separator); *state = current + *l; diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h index f98fbdddd..2a344b996 100644 --- a/shared/systemd/src/basic/string-util.h +++ b/shared/systemd/src/basic/string-util.h @@ -112,8 +112,10 @@ typedef enum SplitFlags { SPLIT_RELAX = 0x01 << 1, } SplitFlags; +/* Smelly. Do not use this anymore. Use extract_first_word() instead! */ const char* split(const char **state, size_t *l, const char *separator, SplitFlags flags); +/* Similar, don't use this anymore */ #define FOREACH_WORD(word, length, s, state) \ _FOREACH_WORD(word, length, s, WHITESPACE, 0, state) diff --git a/shared/systemd/src/basic/strv.h b/shared/systemd/src/basic/strv.h index e7c2b1a60..dd3323c22 100644 --- a/shared/systemd/src/basic/strv.h +++ b/shared/systemd/src/basic/strv.h @@ -87,6 +87,16 @@ char **strv_parse_nulstr(const char *s, size_t l); char **strv_split_nulstr(const char *s); int strv_make_nulstr(char * const *l, char **p, size_t *n); +static inline int strv_from_nulstr(char ***a, const char *nulstr) { + char **t; + + t = strv_split_nulstr(nulstr); + if (!t) + return -ENOMEM; + *a = t; + return 0; +} + bool strv_overlap(char * const *a, char * const *b) _pure_; #define STRV_FOREACH(s, l) \ diff --git a/shared/systemd/src/basic/tmpfile-util.c b/shared/systemd/src/basic/tmpfile-util.c index 83c69205e..8bbd12b01 100644 --- a/shared/systemd/src/basic/tmpfile-util.c +++ b/shared/systemd/src/basic/tmpfile-util.c @@ -50,14 +50,12 @@ int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) { /* This assumes that returned FILE object is short-lived and used within the same single-threaded * context and never shared externally, hence locking is not necessary. */ - r = fdopen_unlocked(fd, "w", &f); + r = take_fdopen_unlocked(&fd, "w", &f); if (r < 0) { (void) unlink(t); return r; } - TAKE_FD(fd); - if (ret_f) *ret_f = TAKE_PTR(f); @@ -83,18 +81,16 @@ int mkostemp_safe(char *pattern) { #if 0 /* NM_IGNORED */ int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) { - int fd; + _cleanup_close_ int fd = -1; FILE *f; fd = mkostemp_safe(pattern); if (fd < 0) return fd; - f = fdopen(fd, mode); - if (!f) { - safe_close(fd); + f = take_fdopen(&fd, mode); + if (!f) return -errno; - } *ret_f = f; return 0; diff --git a/shared/systemd/src/shared/web-util.c b/shared/systemd/src/shared/web-util.c new file mode 100644 index 000000000..f5a5362bd --- /dev/null +++ b/shared/systemd/src/shared/web-util.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "nm-sd-adapt-shared.h" + +#include + +#include "string-util.h" +#include "strv.h" +#include "utf8.h" +#include "web-util.h" + +#if 0 /* NM_IGNORED */ +bool http_etag_is_valid(const char *etag) { + if (isempty(etag)) + return false; + + if (!endswith(etag, "\"")) + return false; + + if (!STARTSWITH_SET(etag, "\"", "W/\"")) + return false; + + return true; +} +#endif /* NM_IGNORED */ + +bool http_url_is_valid(const char *url) { + const char *p; + + if (isempty(url)) + return false; + + p = STARTSWITH_SET(url, "http://", "https://"); + if (!p) + return false; + + if (isempty(p)) + return false; + + return ascii_is_valid(p); +} + +#if 0 /* NM_IGNORED */ +bool documentation_url_is_valid(const char *url) { + const char *p; + + if (isempty(url)) + return false; + + if (http_url_is_valid(url)) + return true; + + p = STARTSWITH_SET(url, "file:/", "info:", "man:"); + if (isempty(p)) + return false; + + return ascii_is_valid(p); +} +#endif /* NM_IGNORED */ diff --git a/shared/systemd/src/shared/web-util.h b/shared/systemd/src/shared/web-util.h new file mode 100644 index 000000000..c9e67e5c0 --- /dev/null +++ b/shared/systemd/src/shared/web-util.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include + +#include "macro.h" + +bool http_url_is_valid(const char *url) _pure_; + +bool documentation_url_is_valid(const char *url) _pure_; + +bool http_etag_is_valid(const char *etag); diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h index a2d0f8bd5..5cbebb4a3 100644 --- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h @@ -61,6 +61,12 @@ struct sd_dhcp_lease { struct in_addr *sip; size_t sip_size; + struct in_addr *pop3_server; + size_t pop3_server_size; + + struct in_addr *smtp_server; + size_t smtp_server_size; + struct sd_dhcp_route *static_route; size_t static_route_size, static_route_allocated; diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index ca850f1ac..6724cbbf1 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -8,7 +8,6 @@ #include "sd-dhcp-lease.h" #include "conf-parser.h" -#include "def.h" #include "set.h" #include "strv.h" @@ -67,5 +66,3 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t /* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */ int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); - -#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network")) diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index 405213ef2..63321cca6 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -29,6 +29,7 @@ #include "random-util.h" #include "string-util.h" #include "strv.h" +#include "web-util.h" #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) @@ -85,6 +86,7 @@ struct sd_dhcp_client { size_t client_id_len; char *hostname; char *vendor_class_identifier; + char *mudurl; char **user_class; uint32_t mtu; uint32_t xid; @@ -498,6 +500,18 @@ int sd_dhcp_client_set_vendor_class_identifier( return free_and_strdup(&client->vendor_class_identifier, vci); } +int sd_dhcp_client_set_mud_url( + sd_dhcp_client *client, + const char *mudurl) { + + assert_return(client, -EINVAL); + assert_return(mudurl, -EINVAL); + assert_return(strlen(mudurl) <= 255, -EINVAL); + assert_return(http_url_is_valid(mudurl), -EINVAL); + + return free_and_strdup(&client->mudurl, mudurl); +} + int sd_dhcp_client_set_user_class( sd_dhcp_client *client, const char* const* user_class) { @@ -900,6 +914,15 @@ static int client_send_discover(sd_dhcp_client *client) { return r; } + if (client->mudurl) { + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_MUD_URL, + strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + if (client->user_class) { r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_USER_CLASS, @@ -1037,6 +1060,16 @@ static int client_send_request(sd_dhcp_client *client) { return r; } + if (client->mudurl) { + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_MUD_URL, + strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL); if (r < 0) @@ -2106,6 +2139,7 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) { free(client->req_opts); free(client->hostname); free(client->vendor_class_identifier); + free(client->mudurl); client->user_class = strv_free(client->user_class); ordered_hashmap_free(client->extra_options); ordered_hashmap_free(client->vendor_options); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index ac6fe3f4d..86f212906 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -131,6 +131,28 @@ int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) { return (int) lease->sip_size; } +int sd_dhcp_lease_get_pop3_server(sd_dhcp_lease *lease, const struct in_addr **addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (lease->pop3_server_size <= 0) + return -ENODATA; + + *addr = lease->pop3_server; + return (int) lease->pop3_server_size; +} + +int sd_dhcp_lease_get_smtp_server(sd_dhcp_lease *lease, const struct in_addr **addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (lease->smtp_server_size <= 0) + return -ENODATA; + + *addr = lease->smtp_server; + return (int) lease->smtp_server_size; +} + int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) { assert_return(lease, -EINVAL); assert_return(domainname, -EINVAL); @@ -281,6 +303,8 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { free(lease->dns); free(lease->ntp); free(lease->sip); + free(lease->pop3_server); + free(lease->smtp_server); free(lease->static_route); free(lease->client_id); free(lease->vendor_specific); @@ -603,6 +627,18 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void log_debug_errno(r, "Failed to parse SIP server, ignoring: %m"); break; + case SD_DHCP_OPTION_POP3_SERVER: + r = lease_parse_in_addrs(option, len, &lease->pop3_server, &lease->pop3_server_size); + if (r < 0) + log_debug_errno(r, "Failed to parse POP3 server, ignoring: %m"); + break; + + case SD_DHCP_OPTION_SMTP_SERVER: + r = lease_parse_in_addrs(option, len, &lease->smtp_server, &lease->smtp_server_size); + if (r < 0) + log_debug_errno(r, "Failed to parse SMTP server, ignoring: %m"); + break; + case SD_DHCP_OPTION_STATIC_ROUTE: r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated); if (r < 0) @@ -1039,6 +1075,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { *dns = NULL, *ntp = NULL, *sip = NULL, + *pop3_server = NULL, + *smtp_server = NULL, *mtu = NULL, *routes = NULL, *domains = NULL, @@ -1068,6 +1106,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "DNS", &dns, "NTP", &ntp, "SIP", &sip, + "POP3_SERVERS", &pop3_server, + "SMTP_SERVERS", &smtp_server, "MTU", &mtu, "DOMAINNAME", &lease->domainname, "HOSTNAME", &lease->hostname, @@ -1177,7 +1217,23 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (r < 0) log_debug_errno(r, "Failed to deserialize SIP servers %s, ignoring: %m", sip); else - lease->ntp_size = r; + lease->sip_size = r; + } + + if (pop3_server) { + r = deserialize_in_addrs(&lease->pop3_server, pop3_server); + if (r < 0) + log_debug_errno(r, "Failed to deserialize POP3 server %s, ignoring: %m", pop3_server); + else + lease->pop3_server_size = r; + } + + if (smtp_server) { + r = deserialize_in_addrs(&lease->smtp_server, smtp_server); + if (r < 0) + log_debug_errno(r, "Failed to deserialize SMTP server %s, ignoring: %m", smtp_server); + else + lease->smtp_server_size = r; } if (mtu) { diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index e612b33b1..826ad56a9 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -27,6 +27,7 @@ #include "socket-util.h" #include "string-table.h" #include "util.h" +#include "web-util.h" #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN @@ -67,6 +68,7 @@ struct sd_dhcp6_client { size_t req_opts_allocated; size_t req_opts_len; char *fqdn; + char *mudurl; sd_event_source *receive_message; usec_t retransmit_time; uint8_t retransmit_count; @@ -369,6 +371,17 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) return 0; } +int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, char *mudurl) { + + assert_return(client, -EINVAL); + assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); + assert_return(mudurl, -EINVAL); + assert_return(strlen(mudurl) <= 255, -EINVAL); + assert_return(http_url_is_valid(mudurl), -EINVAL); + + return free_and_strdup(&client->mudurl, mudurl); +} + int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) { assert_return(client, -EINVAL); assert_return(delegation, -EINVAL); @@ -490,6 +503,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { case DHCP6_STATE_INFORMATION_REQUEST: message->type = DHCP6_INFORMATION_REQUEST; + if (client->mudurl) { + r = dhcp6_option_append(&opt, &optlen, + SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + break; case DHCP6_STATE_SOLICITATION: @@ -513,6 +534,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return r; } + if (client->mudurl) { + r = dhcp6_option_append(&opt, &optlen, + SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix); if (r < 0) @@ -551,6 +580,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return r; } + if (client->mudurl) { + r = dhcp6_option_append(&opt, &optlen, + SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); if (r < 0) @@ -577,6 +614,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return r; } + if (client->mudurl) { + r = dhcp6_option_append(&opt, &optlen, + SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); if (r < 0) @@ -1527,6 +1572,7 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) { free(client->req_opts); free(client->fqdn); + free(client->mudurl); return mfree(client); } diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index 9dd562fa4..da2aa6c73 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -83,6 +83,8 @@ enum { SD_DHCP_OPTION_REBINDING_T2_TIME = 59, SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61, + SD_DHCP_OPTION_SMTP_SERVER = 69, + SD_DHCP_OPTION_POP3_SERVER = 70, SD_DHCP_OPTION_USER_CLASS = 77, SD_DHCP_OPTION_FQDN = 81, SD_DHCP_OPTION_NEW_POSIX_TIMEZONE = 100, @@ -90,6 +92,7 @@ enum { SD_DHCP_OPTION_DOMAIN_SEARCH_LIST = 119, SD_DHCP_OPTION_SIP_SERVER = 120, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, + SD_DHCP_OPTION_MUD_URL = 161, SD_DHCP_OPTION_PRIVATE_BASE = 224, /* Windows 10 option to send when Anonymize=true */ SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249, @@ -169,6 +172,9 @@ int sd_dhcp_client_set_hostname( int sd_dhcp_client_set_vendor_class_identifier( sd_dhcp_client *client, const char *vci); +int sd_dhcp_client_set_mud_url( + sd_dhcp_client *client, + const char *mudurl); int sd_dhcp_client_set_user_class( sd_dhcp_client *client, const char* const *user_class); diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h index b80d607fe..1ed5bf27a 100644 --- a/src/systemd/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/src/systemd/sd-dhcp-lease.h @@ -45,6 +45,8 @@ int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *ad int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr); +int sd_dhcp_lease_get_pop3_server(sd_dhcp_lease *lease, const struct in_addr **addr); +int sd_dhcp_lease_get_smtp_server(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu); int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains); diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h index be34d43e7..42d4ec752 100644 --- a/src/systemd/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/src/systemd/sd-dhcp6-client.h @@ -73,6 +73,7 @@ enum { SD_DHCP6_OPTION_FQDN = 39, /* RFC 4704 */ SD_DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */ + SD_DHCP6_OPTION_MUD_URL = 112, /* RFC 8250 */ /* option codes 89-142 are unassigned */ /* option codes 144-65535 are unassigned */ @@ -120,6 +121,9 @@ int sd_dhcp6_client_get_information_request( int sd_dhcp6_client_set_request_option( sd_dhcp6_client *client, uint16_t option); +int sd_dhcp6_client_set_request_mud_url( + sd_dhcp6_client *client, + char *mudurl); int sd_dhcp6_client_set_prefix_delegation_hint( sd_dhcp6_client *client, uint8_t prefixlen,