diff options
author | Thomas Haller <thaller@redhat.com> | 2015-09-16 16:53:25 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-09-16 16:54:03 +0200 |
commit | c05557971c09782316ee7e39ae4e7a7675d338f1 (patch) | |
tree | 25595e64bb7f900b17766270b52e7696d4e615c7 /src | |
parent | 08916936bce4c8ac36156c040999add99175b455 (diff) | |
parent | e82f430eae841032c7961d2eca694435425e4d51 (diff) | |
download | NetworkManager-c05557971c09782316ee7e39ae4e7a7675d338f1.tar.gz |
systemd: merge branch 'systemd-integration' into master
Diffstat (limited to 'src')
34 files changed, 1604 insertions, 748 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 9101a3af6e..220331cff5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,70 +66,71 @@ SYSTEMD_NM_CFLAGS = \ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON libsystemd_nm_la_SOURCES = \ - systemd/src/libsystemd/sd-id128/sd-id128.c \ - systemd/src/libsystemd-network/dhcp-identifier.c \ - systemd/src/libsystemd-network/dhcp-identifier.h \ - systemd/src/libsystemd-network/dhcp-network.c \ - systemd/src/libsystemd-network/dhcp-packet.c \ - systemd/src/libsystemd-network/dhcp-internal.h \ - systemd/src/libsystemd-network/dhcp6-network.c \ - systemd/src/libsystemd-network/dhcp6-lease-internal.h \ - systemd/src/libsystemd-network/dhcp6-option.c \ - systemd/src/libsystemd-network/network-internal.c \ - systemd/src/libsystemd-network/sd-dhcp-lease.c \ - systemd/src/libsystemd-network/sd-dhcp-client.c \ - systemd/src/libsystemd-network/dhcp-option.c \ - systemd/src/libsystemd-network/network-internal.h \ - systemd/src/libsystemd-network/sd-dhcp6-lease.c \ - systemd/src/libsystemd-network/dhcp-protocol.h \ - systemd/src/libsystemd-network/dhcp6-internal.h \ - systemd/src/libsystemd-network/dhcp6-protocol.h \ - systemd/src/libsystemd-network/dhcp-lease-internal.h \ - systemd/src/libsystemd-network/sd-dhcp6-client.c \ - systemd/src/libsystemd-network/ipv4ll-internal.h \ - systemd/src/libsystemd-network/sd-ipv4ll.c \ - systemd/src/libsystemd-network/ipv4ll-packet.c \ - systemd/src/libsystemd-network/ipv4ll-network.c \ + systemd/nm-sd-adapt.c \ + systemd/nm-sd-adapt.h \ systemd/src/basic/async.h \ - systemd/src/basic/time-util.h \ - systemd/src/basic/siphash24.h \ - systemd/src/basic/time-util.c \ - systemd/src/basic/socket-util.h \ - systemd/src/basic/sparse-endian.h \ - systemd/src/basic/macro.h \ - systemd/src/basic/refcnt.h \ - systemd/src/basic/util.c \ + systemd/src/basic/fileio.c \ + systemd/src/basic/fileio.h \ + systemd/src/basic/hostname-util.c \ + systemd/src/basic/hostname-util.h \ systemd/src/basic/in-addr-util.c \ - systemd/src/basic/siphash24.c \ - systemd/src/basic/util.h \ systemd/src/basic/in-addr-util.h \ systemd/src/basic/list.h \ systemd/src/basic/log.h \ - systemd/src/basic/fileio.h \ - systemd/src/basic/fileio.c \ + systemd/src/basic/macro.h \ systemd/src/basic/path-util.c \ systemd/src/basic/path-util.h \ - systemd/src/basic/strv.h \ + systemd/src/basic/random-util.c \ + systemd/src/basic/random-util.h \ + systemd/src/basic/refcnt.h \ + systemd/src/basic/siphash24.c \ + systemd/src/basic/siphash24.h \ + systemd/src/basic/socket-util.h \ + systemd/src/basic/sparse-endian.h \ systemd/src/basic/strv.c \ + systemd/src/basic/strv.h \ + systemd/src/basic/time-util.c \ + systemd/src/basic/time-util.h \ systemd/src/basic/unaligned.h \ - systemd/src/basic/utf8.h \ systemd/src/basic/utf8.c \ - systemd/src/basic/hostname-util.h \ - systemd/src/basic/hostname-util.c \ - systemd/src/basic/random-util.h \ - systemd/src/basic/random-util.c \ + systemd/src/basic/utf8.h \ + systemd/src/basic/util.c \ + systemd/src/basic/util.h \ + systemd/src/libsystemd-network/dhcp-identifier.c \ + systemd/src/libsystemd-network/dhcp-identifier.h \ + systemd/src/libsystemd-network/dhcp-internal.h \ + systemd/src/libsystemd-network/dhcp-lease-internal.h \ + systemd/src/libsystemd-network/dhcp-network.c \ + systemd/src/libsystemd-network/dhcp-option.c \ + systemd/src/libsystemd-network/dhcp-packet.c \ + systemd/src/libsystemd-network/dhcp-protocol.h \ + systemd/src/libsystemd-network/dhcp6-internal.h \ + systemd/src/libsystemd-network/dhcp6-lease-internal.h \ + systemd/src/libsystemd-network/dhcp6-network.c \ + systemd/src/libsystemd-network/dhcp6-option.c \ + systemd/src/libsystemd-network/dhcp6-protocol.h \ + systemd/src/libsystemd-network/ipv4ll-internal.h \ + systemd/src/libsystemd-network/ipv4ll-network.c \ + systemd/src/libsystemd-network/ipv4ll-packet.c \ + systemd/src/libsystemd-network/network-internal.c \ + systemd/src/libsystemd-network/network-internal.h \ + systemd/src/libsystemd-network/sd-dhcp-client.c \ + systemd/src/libsystemd-network/sd-dhcp-lease.c \ + systemd/src/libsystemd-network/sd-dhcp6-client.c \ + systemd/src/libsystemd-network/sd-dhcp6-lease.c \ + systemd/src/libsystemd-network/sd-ipv4ll.c \ + systemd/src/libsystemd/sd-id128/sd-id128.c \ systemd/src/shared/dns-domain.c \ systemd/src/shared/dns-domain.h \ - systemd/src/systemd/sd-dhcp-lease.h \ + systemd/src/systemd/_sd-common.h \ systemd/src/systemd/sd-dhcp-client.h \ - systemd/src/systemd/sd-id128.h \ - systemd/src/systemd/sd-dhcp6-lease.h \ + systemd/src/systemd/sd-dhcp-lease.h \ systemd/src/systemd/sd-dhcp6-client.h \ + systemd/src/systemd/sd-dhcp6-lease.h \ systemd/src/systemd/sd-event.h \ - systemd/src/systemd/_sd-common.h \ - systemd/src/systemd/sd-ipv4ll.h \ - systemd/nm-sd-adapt.h \ - systemd/nm-sd-adapt.c + systemd/src/systemd/sd-icmp6-nd.h \ + systemd/src/systemd/sd-id128.h \ + systemd/src/systemd/sd-ipv4ll.h libsystemd_nm_la_CPPFLAGS = \ -I$(top_srcdir)/include \ diff --git a/src/dhcp-manager/nm-dhcp-systemd.c b/src/dhcp-manager/nm-dhcp-systemd.c index 7f16946d8f..3786f3b279 100644 --- a/src/dhcp-manager/nm-dhcp-systemd.c +++ b/src/dhcp-manager/nm-dhcp-systemd.c @@ -222,7 +222,7 @@ lease_to_ip4_config (const char *iface, guint16 mtu; int r, num; guint64 end_time; - const uint8_t *data; + const void *data; gsize data_len; gboolean metered = FALSE; @@ -607,7 +607,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last client_id + 1, client_id_len - 1); } else if (lease) { - r = sd_dhcp_lease_get_client_id (lease, &client_id, &client_id_len); + r = sd_dhcp_lease_get_client_id (lease, (const void **) &client_id, &client_id_len); if (r == 0 && client_id_len) { sd_dhcp_client_set_client_id (priv->client4, client_id[0], diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c index 7e2fa7c609..b8cd79e52d 100644 --- a/src/systemd/src/basic/hostname-util.c +++ b/src/systemd/src/basic/hostname-util.c @@ -64,16 +64,19 @@ static bool hostname_valid_char(char c) { } /** - * Check if s looks like a valid host name or fqdn. This does not do + * Check if s looks like a valid host name or FQDN. This does not do * full DNS validation, but only checks if the name is composed of * allowed characters and the length is not above the maximum allowed * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if - * relax is true and at least two components are present in the name. + * allow_trailing_dot is true and at least two components are present + * in the name. Note that due to the restricted charset and length + * this call is substantially more conservative than + * dns_domain_is_valid(). */ -bool hostname_is_valid(const char *s, bool relax) { +bool hostname_is_valid(const char *s, bool allow_trailing_dot) { + unsigned n_dots = 0; const char *p; bool dot; - unsigned dots = 0; if (isempty(s)) return false; @@ -89,7 +92,7 @@ bool hostname_is_valid(const char *s, bool relax) { return false; dot = true; - dots ++; + n_dots ++; } else { if (!hostname_valid_char(*p)) return false; @@ -98,10 +101,12 @@ bool hostname_is_valid(const char *s, bool relax) { } } - if (dot && (dots < 2 || !relax)) + if (dot && (n_dots < 2 || !allow_trailing_dot)) return false; - if (p-s > HOST_NAME_MAX) + if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on + * Linux, but DNS allows domain names + * up to 255 characters */ return false; return true; @@ -154,6 +159,17 @@ bool is_localhost(const char *hostname) { } #if 0 /* NM_IGNORED */ +bool is_gateway_hostname(const char *hostname) { + assert(hostname); + + /* This tries to identify the valid syntaxes for the our + * synthetic "gateway" host. */ + + return + strcaseeq(hostname, "gateway") || + strcaseeq(hostname, "gateway."); +} + int sethostname_idempotent(const char *s) { char buf[HOST_NAME_MAX + 1] = {}; diff --git a/src/systemd/src/basic/hostname-util.h b/src/systemd/src/basic/hostname-util.h index fd768ee3c0..a2e6920095 100644 --- a/src/systemd/src/basic/hostname-util.h +++ b/src/systemd/src/basic/hostname-util.h @@ -31,10 +31,13 @@ bool hostname_is_set(void); char* gethostname_malloc(void); -bool hostname_is_valid(const char *s, bool relax) _pure_; +bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_; char* hostname_cleanup(char *s); +#define machine_name_is_valid(s) hostname_is_valid(s, false) + bool is_localhost(const char *hostname); +bool is_gateway_hostname(const char *hostname); int sethostname_idempotent(const char *s); diff --git a/src/systemd/src/basic/macro.h b/src/systemd/src/basic/macro.h index b1cef217ab..80c64904e2 100644 --- a/src/systemd/src/basic/macro.h +++ b/src/systemd/src/basic/macro.h @@ -300,6 +300,9 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { #define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1)) #define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) +#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p)) +#define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) + #define memzero(x,l) (memset((x), 0, (l))) #define zero(x) (memzero(&(x), sizeof(x))) diff --git a/src/systemd/src/basic/refcnt.h b/src/systemd/src/basic/refcnt.h index e6e9a6bd6e..f7a26192ce 100644 --- a/src/systemd/src/basic/refcnt.h +++ b/src/systemd/src/basic/refcnt.h @@ -23,7 +23,9 @@ #include "nm-sd-adapt.h" -/* A type-safe atomic refcounter */ +/* A type-safe atomic refcounter. + * + * DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */ typedef struct { volatile unsigned _value; diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c index df44f61907..de0f371613 100644 --- a/src/systemd/src/basic/strv.c +++ b/src/systemd/src/basic/strv.c @@ -272,16 +272,14 @@ char **strv_split_newlines(const char *s) { if (n <= 0) return l; - if (isempty(l[n-1])) { - free(l[n-1]); - l[n-1] = NULL; - } + if (isempty(l[n - 1])) + l[n - 1] = mfree(l[n - 1]); return l; } #if 0 /* NM_IGNORED */ -int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) { +int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) { size_t n = 0, allocated = 0; _cleanup_strv_free_ char **l = NULL; int r; @@ -292,7 +290,7 @@ int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) { for (;;) { _cleanup_free_ char *word = NULL; - r = unquote_first_word(&s, &word, flags); + r = extract_first_word(&s, &word, separators, flags); if (r < 0) return r; if (r == 0) @@ -697,6 +695,26 @@ char **strv_reverse(char **l) { return l; } +char **strv_shell_escape(char **l, const char *bad) { + char **s; + + /* Escapes every character in every string in l that is in bad, + * edits in-place, does not roll-back on error. */ + + STRV_FOREACH(s, l) { + char *v; + + v = shell_escape(*s, bad); + if (!v) + return NULL; + + free(*s); + *s = v; + } + + return l; +} + bool strv_fnmatch(char* const* patterns, const char *s, int flags) { char* const* p; diff --git a/src/systemd/src/basic/strv.h b/src/systemd/src/basic/strv.h index b583080739..df3855d9fa 100644 --- a/src/systemd/src/basic/strv.h +++ b/src/systemd/src/basic/strv.h @@ -75,7 +75,7 @@ static inline bool strv_isempty(char * const *l) { char **strv_split(const char *s, const char *separator); char **strv_split_newlines(const char *s); -int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags); +int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags); char *strv_join(char **l, const char *separator); char *strv_join_quoted(char **l); @@ -147,6 +147,7 @@ void strv_print(char **l); })) char **strv_reverse(char **l); +char **strv_shell_escape(char **l, const char *bad); bool strv_fnmatch(char* const* patterns, const char *s, int flags); diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index 66f91825bc..5fb666a0c3 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -28,9 +28,8 @@ #include "util.h" #include "time-util.h" -#if 0 /* NM_IGNORED */ +#include "path-util.h" #include "strv.h" -#endif /* NM_IGNORED */ usec_t now(clockid_t clock_id) { struct timespec ts; @@ -40,6 +39,14 @@ usec_t now(clockid_t clock_id) { return timespec_load(&ts); } +nsec_t now_nsec(clockid_t clock_id) { + struct timespec ts; + + assert_se(clock_gettime(clock_id, &ts) == 0); + + return timespec_load_nsec(&ts); +} + dual_timestamp* dual_timestamp_get(dual_timestamp *ts) { assert(ts); @@ -92,6 +99,32 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { return ts; } +dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) { + int64_t delta; + + if (u == USEC_INFINITY) { + ts->realtime = ts->monotonic = USEC_INFINITY; + return ts; + } + ts->realtime = now(CLOCK_REALTIME); + ts->monotonic = now(CLOCK_MONOTONIC); + + delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u; + + if ((int64_t) ts->realtime > delta) + ts->realtime -= delta; + else + ts->realtime = 0; + + if ((int64_t) ts->monotonic > delta) + ts->monotonic -= delta; + else + ts->monotonic = 0; + + return ts; +} + + usec_t timespec_load(const struct timespec *ts) { assert(ts); @@ -107,6 +140,18 @@ usec_t timespec_load(const struct timespec *ts) { (usec_t) ts->tv_nsec / NSEC_PER_USEC; } +nsec_t timespec_load_nsec(const struct timespec *ts) { + assert(ts); + + if (ts->tv_sec == (time_t) -1 && + ts->tv_nsec == (long) -1) + return NSEC_INFINITY; + + return + (nsec_t) ts->tv_sec * NSEC_PER_SEC + + (nsec_t) ts->tv_nsec; +} + struct timespec *timespec_store(struct timespec *ts, usec_t u) { assert(ts); @@ -946,13 +991,17 @@ int get_timezones(char ***ret) { return 0; } +#endif /* NM_IGNORED */ bool timezone_is_valid(const char *name) { bool slash = false; const char *p, *t; struct stat st; - if (!name || *name == 0 || *name == '/') + if (isempty(name)) + return false; + + if (name[0] == '/') return false; for (p = name; *p; p++) { @@ -984,7 +1033,6 @@ bool timezone_is_valid(const char *name) { return true; } -#endif /* NM_IGNORED */ clockid_t clock_boottime_or_monotonic(void) { static clockid_t clock = -1; @@ -1003,3 +1051,32 @@ clockid_t clock_boottime_or_monotonic(void) { return clock; } + +#if 0 /* NM_IGNORED */ +int get_timezone(char **tz) { + _cleanup_free_ char *t = NULL; + const char *e; + char *z; + int r; + + r = readlink_malloc("/etc/localtime", &t); + if (r < 0) + return r; /* returns EINVAL if not a symlink */ + + e = path_startswith(t, "/usr/share/zoneinfo/"); + if (!e) + e = path_startswith(t, "../usr/share/zoneinfo/"); + if (!e) + return -EINVAL; + + if (!timezone_is_valid(e)) + return -EINVAL; + + z = strdup(e); + if (!z) + return -ENOMEM; + + *tz = z; + return 0; +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h index 480c39d902..463d509b4a 100644 --- a/src/systemd/src/basic/time-util.h +++ b/src/systemd/src/basic/time-util.h @@ -72,10 +72,12 @@ typedef struct dual_timestamp { #define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL }) usec_t now(clockid_t clock); +nsec_t now_nsec(clockid_t clock); dual_timestamp* dual_timestamp_get(dual_timestamp *ts); dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u); +dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u); static inline bool dual_timestamp_is_set(dual_timestamp *ts) { return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || @@ -88,6 +90,8 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u); usec_t timeval_load(const struct timeval *tv) _pure_; struct timeval *timeval_store(struct timeval *tv, usec_t u); +nsec_t timespec_load_nsec(const struct timespec *ts) _pure_; + char *format_timestamp(char *buf, size_t l, usec_t t); char *format_timestamp_utc(char *buf, size_t l, usec_t t); char *format_timestamp_us(char *buf, size_t l, usec_t t); @@ -111,3 +115,5 @@ bool timezone_is_valid(const char *name); clockid_t clock_boottime_or_monotonic(void); #define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0) + +int get_timezone(char **timezone); diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index 4293268857..3b41adad8d 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -339,6 +339,33 @@ void close_many(const int fds[], unsigned n_fd) { } #endif /* NM_IGNORED */ +int fclose_nointr(FILE *f) { + assert(f); + + /* Same as close_nointr(), but for fclose() */ + + if (fclose(f) == 0) + return 0; + + if (errno == EINTR) + return 0; + + return -errno; +} + +FILE* safe_fclose(FILE *f) { + + /* Same as safe_close(), but for fclose() */ + + if (f) { + PROTECT_ERRNO; + + assert_se(fclose_nointr(f) != EBADF); + } + + return NULL; +} + int unlink_noerrno(const char *path) { PROTECT_ERRNO; int r; @@ -386,6 +413,19 @@ int parse_pid(const char *s, pid_t* ret_pid) { return 0; } +bool uid_is_valid(uid_t uid) { + + /* Some libc APIs use UID_INVALID as special placeholder */ + if (uid == (uid_t) 0xFFFFFFFF) + return false; + + /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */ + if (uid == (uid_t) 0xFFFF) + return false; + + return true; +} + int parse_uid(const char *s, uid_t* ret_uid) { unsigned long ul = 0; uid_t uid; @@ -402,13 +442,11 @@ int parse_uid(const char *s, uid_t* ret_uid) { if ((unsigned long) uid != ul) return -ERANGE; - /* Some libc APIs use UID_INVALID as special placeholder */ - if (uid == (uid_t) 0xFFFFFFFF) - return -ENXIO; - - /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */ - if (uid == (uid_t) 0xFFFF) - return -ENXIO; + if (!uid_is_valid(uid)) + return -ENXIO; /* we return ENXIO instead of EINVAL + * here, to make it easy to distuingish + * invalid numeric uids invalid + * strings. */ if (ret_uid) *ret_uid = uid; @@ -477,6 +515,7 @@ int safe_atou8(const char *s, uint8_t *ret) { *ret = (uint8_t) l; return 0; } +#endif /* NM_IGNORED */ int safe_atou16(const char *s, uint16_t *ret) { char *x = NULL; @@ -498,6 +537,7 @@ int safe_atou16(const char *s, uint16_t *ret) { return 0; } +#if 0 /* NM_IGNORED */ int safe_atoi16(const char *s, int16_t *ret) { char *x = NULL; long l; @@ -2201,7 +2241,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { return 0; } -int parse_size(const char *t, off_t base, off_t *size) { +int parse_size(const char *t, uint64_t base, uint64_t *size) { /* Soo, sometimes we want to parse IEC binary suffixes, and * sometimes SI decimal suffixes. This function can parse @@ -2229,8 +2269,8 @@ int parse_size(const char *t, off_t base, off_t *size) { { "G", 1024ULL*1024ULL*1024ULL }, { "M", 1024ULL*1024ULL }, { "K", 1024ULL }, - { "B", 1 }, - { "", 1 }, + { "B", 1ULL }, + { "", 1ULL }, }; static const struct table si[] = { @@ -2240,8 +2280,8 @@ int parse_size(const char *t, off_t base, off_t *size) { { "G", 1000ULL*1000ULL*1000ULL }, { "M", 1000ULL*1000ULL }, { "K", 1000ULL }, - { "B", 1 }, - { "", 1 }, + { "B", 1ULL }, + { "", 1ULL }, }; const struct table *table; @@ -2263,33 +2303,32 @@ int parse_size(const char *t, off_t base, off_t *size) { p = t; do { - long long l; - unsigned long long l2; + unsigned long long l, tmp; double frac = 0; char *e; unsigned i; - errno = 0; - l = strtoll(p, &e, 10); + p += strspn(p, WHITESPACE); + if (*p == '-') + return -ERANGE; + errno = 0; + l = strtoull(p, &e, 10); if (errno > 0) return -errno; - - if (l < 0) - return -ERANGE; - if (e == p) return -EINVAL; if (*e == '.') { e++; + + /* strtoull() itself would accept space/+/- */ if (*e >= '0' && *e <= '9') { + unsigned long long l2; char *e2; - /* strotoull itself would accept space/+/- */ l2 = strtoull(e, &e2, 10); - - if (errno == ERANGE) + if (errno > 0) return -errno; /* Ignore failure. E.g. 10.M is valid */ @@ -2302,27 +2341,27 @@ int parse_size(const char *t, off_t base, off_t *size) { e += strspn(e, WHITESPACE); for (i = start_pos; i < n_entries; i++) - if (startswith(e, table[i].suffix)) { - unsigned long long tmp; - if ((unsigned long long) l + (frac > 0) > ULLONG_MAX / table[i].factor) - return -ERANGE; - tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); - if (tmp > ULLONG_MAX - r) - return -ERANGE; - - r += tmp; - if ((unsigned long long) (off_t) r != r) - return -ERANGE; - - p = e + strlen(table[i].suffix); - - start_pos = i + 1; + if (startswith(e, table[i].suffix)) break; - } if (i >= n_entries) return -EINVAL; + if (l + (frac > 0) > ULLONG_MAX / table[i].factor) + return -ERANGE; + + tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); + if (tmp > ULLONG_MAX - r) + return -ERANGE; + + r += tmp; + if ((unsigned long long) (uint64_t) r != r) + return -ERANGE; + + p = e + strlen(table[i].suffix); + + start_pos = i + 1; + } while (*p); *size = r; @@ -3033,21 +3072,6 @@ char* strshorten(char *s, size_t l) { } #if 0 /* NM_IGNORED */ -bool machine_name_is_valid(const char *s) { - - if (!hostname_is_valid(s, false)) - return false; - - /* Machine names should be useful hostnames, but also be - * useful in unit names, hence we enforce a stricter length - * limitation. */ - - if (strlen(s) > 64) - return false; - - return true; -} - int pipe_eof(int fd) { struct pollfd pollfd = { .fd = fd, @@ -3793,38 +3817,38 @@ int prot_from_flags(int flags) { } } -char *format_bytes(char *buf, size_t l, off_t t) { +char *format_bytes(char *buf, size_t l, uint64_t t) { unsigned i; static const struct { const char *suffix; - off_t factor; + uint64_t factor; } table[] = { - { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "M", 1024ULL*1024ULL }, - { "K", 1024ULL }, + { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "M", UINT64_C(1024)*UINT64_C(1024) }, + { "K", UINT64_C(1024) }, }; - if (t == (off_t) -1) + if (t == (uint64_t) -1) return NULL; for (i = 0; i < ELEMENTSOF(table); i++) { if (t >= table[i].factor) { snprintf(buf, l, - "%llu.%llu%s", - (unsigned long long) (t / table[i].factor), - (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL), + "%" PRIu64 ".%" PRIu64 "%s", + t / table[i].factor, + ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10), table[i].suffix); goto finish; } } - snprintf(buf, l, "%lluB", (unsigned long long) t); + snprintf(buf, l, "%" PRIu64 "B", t); finish: buf[l-1] = 0; @@ -4325,7 +4349,7 @@ bool is_locale_utf8(void) { /* Check result, but ignore the result if C was set * explicitly. */ cached_answer = - streq(set, "C") && + STR_IN_SET(set, "C", "POSIX") && !getenv("LC_ALL") && !getenv("LC_CTYPE") && !getenv("LANG"); @@ -4752,7 +4776,6 @@ void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) { return q; } -#if 0 /* NM_IGNORED */ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) { size_t prev; uint8_t *q; @@ -4772,6 +4795,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) { return q; } +#if 0 /* NM_IGNORED */ bool id128_is_valid(const char *s) { size_t i, l; @@ -4860,7 +4884,7 @@ int shall_restore_state(void) { int proc_cmdline(char **ret) { assert(ret); - if (detect_container(NULL) > 0) + if (detect_container() > 0) return get_process_cmdline(1, 0, false, ret); else return read_one_line_file("/proc/cmdline", ret); @@ -4882,7 +4906,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { _cleanup_free_ char *word = NULL; char *value = NULL; - r = unquote_first_word(&p, &word, UNQUOTE_RELAX); + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) return r; if (r == 0) @@ -4922,7 +4946,7 @@ int get_proc_cmdline_key(const char *key, char **value) { _cleanup_free_ char *word = NULL; const char *e; - r = unquote_first_word(&p, &word, UNQUOTE_RELAX); + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) return r; if (r == 0) @@ -4967,6 +4991,9 @@ int container_get_leader(const char *machine, pid_t *pid) { assert(machine); assert(pid); + if (!machine_name_is_valid(machine)) + return -EINVAL; + p = strjoina("/run/systemd/machines/", machine); r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); if (r == -ENOENT) @@ -4989,8 +5016,8 @@ int container_get_leader(const char *machine, pid_t *pid) { return 0; } -int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd) { - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1; +int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1; int rfd = -1; assert(pid >= 0); @@ -5022,6 +5049,15 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int * return -errno; } + if (userns_fd) { + const char *userns; + + userns = procfs_file_alloca(pid, "ns/user"); + usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (usernsfd < 0 && errno != ENOENT) + return -errno; + } + if (root_fd) { const char *root; @@ -5040,15 +5076,33 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int * if (netns_fd) *netns_fd = netnsfd; + if (userns_fd) + *userns_fd = usernsfd; + if (root_fd) *root_fd = rfd; - pidnsfd = mntnsfd = netnsfd = -1; + pidnsfd = mntnsfd = netnsfd = usernsfd = -1; return 0; } -int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) { +int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) { + if (userns_fd >= 0) { + /* Can't setns to your own userns, since then you could + * escalate from non-root to root in your own namespace, so + * check if namespaces equal before attempting to enter. */ + _cleanup_free_ char *userns_fd_path = NULL; + int r; + if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0) + return -ENOMEM; + + r = files_same(userns_fd_path, "/proc/self/ns/user"); + if (r < 0) + return r; + if (r) + userns_fd = -1; + } if (pidns_fd >= 0) if (setns(pidns_fd, CLONE_NEWPID) < 0) @@ -5062,6 +5116,10 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) { if (setns(netns_fd, CLONE_NEWNET) < 0) return -errno; + if (userns_fd >= 0) + if (setns(userns_fd, CLONE_NEWUSER) < 0) + return -errno; + if (root_fd >= 0) { if (fchdir(root_fd) < 0) return -errno; @@ -5741,7 +5799,7 @@ int is_device_node(const char *path) { return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); } -int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { _cleanup_free_ char *s = NULL; size_t allocated = 0, sz = 0; int r; @@ -5754,13 +5812,19 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { SINGLE_QUOTE_ESCAPE, DOUBLE_QUOTE, DOUBLE_QUOTE_ESCAPE, - SPACE, + SEPARATOR, } state = START; assert(p); - assert(*p); assert(ret); + if (!separators) + separators = WHITESPACE; + + /* Bail early if called after last value or with no input */ + if (!*p) + goto finish_force_terminate; + /* Parses the first word of a string, and returns it in * *ret. Removes all quotes in the process. When parsing fails * (because of an uneven number of quotes or similar), leaves @@ -5772,32 +5836,45 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { switch (state) { case START: + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + if (c == 0) - goto finish; - else if (strchr(WHITESPACE, c)) + goto finish_force_terminate; + else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + (*p) ++; + goto finish_force_next; + } break; + } + + /* We found a non-blank character, so we will always + * want to return a string (even if it is empty), + * allocate it here. */ + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; state = VALUE; /* fallthrough */ case VALUE: if (c == 0) - goto finish; - else if (c == '\'') { - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; - + goto finish_force_terminate; + else if (c == '\'' && (flags & EXTRACT_QUOTES)) state = SINGLE_QUOTE; - } else if (c == '\\') + else if (c == '\\') state = VALUE_ESCAPE; - else if (c == '\"') { - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; - + else if (c == '\"' && (flags & EXTRACT_QUOTES)) state = DOUBLE_QUOTE; - } else if (strchr(WHITESPACE, c)) - state = SPACE; - else { + else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + (*p) ++; + goto finish_force_next; + } + state = SEPARATOR; + } else { if (!GREEDY_REALLOC(s, allocated, sz+2)) return -ENOMEM; @@ -5808,8 +5885,8 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { case SINGLE_QUOTE: if (c == 0) { - if (flags & UNQUOTE_RELAX) - goto finish; + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; return -EINVAL; } else if (c == '\'') state = VALUE; @@ -5847,29 +5924,29 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { return -ENOMEM; if (c == 0) { - if ((flags & UNQUOTE_CUNESCAPE_RELAX) && - (state == VALUE_ESCAPE || flags & UNQUOTE_RELAX)) { + if ((flags & EXTRACT_CUNESCAPE_RELAX) && + (state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) { /* If we find an unquoted trailing backslash and we're in - * UNQUOTE_CUNESCAPE_RELAX mode, keep it verbatim in the + * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the * output. * - * Unbalanced quotes will only be allowed in UNQUOTE_RELAX - * mode, UNQUOTE_CUNESCAP_RELAX mode does not allow them. + * Unbalanced quotes will only be allowed in EXTRACT_RELAX + * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. */ s[sz++] = '\\'; - goto finish; + goto finish_force_terminate; } - if (flags & UNQUOTE_RELAX) - goto finish; + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; return -EINVAL; } - if (flags & UNQUOTE_CUNESCAPE) { + if (flags & EXTRACT_CUNESCAPE) { uint32_t u; r = cunescape_one(*p, (size_t) -1, &c, &u); if (r < 0) { - if (flags & UNQUOTE_CUNESCAPE_RELAX) { + if (flags & EXTRACT_CUNESCAPE_RELAX) { s[sz++] = '\\'; s[sz++] = c; goto end_escape; @@ -5892,24 +5969,27 @@ end_escape: VALUE; break; - case SPACE: + case SEPARATOR: if (c == 0) + goto finish_force_terminate; + if (!strchr(separators, c)) goto finish; - if (!strchr(WHITESPACE, c)) - goto finish; - break; } (*p) ++; } +finish_force_terminate: + *p = NULL; finish: if (!s) { + *p = NULL; *ret = NULL; return 0; } +finish_force_next: s[sz] = 0; *ret = s; s = NULL; @@ -5917,26 +5997,27 @@ finish: return 1; } -int unquote_first_word_and_warn( +int extract_first_word_and_warn( const char **p, char **ret, - UnquoteFlags flags, + const char *separators, + ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue) { /* Try to unquote it, if it fails, warn about it and try again but this - * time using UNQUOTE_CUNESCAPE_RELAX to keep the backslashes verbatim + * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim * in invalid escape sequences. */ const char *save; int r; save = *p; - r = unquote_first_word(p, ret, flags); - if (r < 0 && !(flags&UNQUOTE_CUNESCAPE_RELAX)) { - /* Retry it with UNQUOTE_CUNESCAPE_RELAX. */ + r = extract_first_word(p, ret, separators, flags); + if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) { + /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ *p = save; - r = unquote_first_word(p, ret, flags|UNQUOTE_CUNESCAPE_RELAX); + r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); if (r < 0) log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue); @@ -5947,7 +6028,7 @@ int unquote_first_word_and_warn( return r; } -int unquote_many_words(const char **p, UnquoteFlags flags, ...) { +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) { va_list ap; char **l; int n = 0, i, c, r; @@ -5973,7 +6054,7 @@ int unquote_many_words(const char **p, UnquoteFlags flags, ...) { l = newa0(char*, n); for (c = 0; c < n; c++) { - r = unquote_first_word(p, &l[c], flags); + r = extract_first_word(p, &l[c], separators, flags); if (r < 0) { int j; @@ -6055,7 +6136,7 @@ int ptsname_malloc(int fd, char **ret) { } int openpt_in_namespace(pid_t pid, int flags) { - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; _cleanup_close_pair_ int pair[2] = { -1, -1 }; union { struct cmsghdr cmsghdr; @@ -6072,7 +6153,7 @@ int openpt_in_namespace(pid_t pid, int flags) { assert(pid > 0); - r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd); + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); if (r < 0) return r; @@ -6088,7 +6169,7 @@ int openpt_in_namespace(pid_t pid, int flags) { pair[0] = safe_close(pair[0]); - r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd); + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); if (r < 0) _exit(EXIT_FAILURE); @@ -6096,6 +6177,9 @@ int openpt_in_namespace(pid_t pid, int flags) { if (master < 0) _exit(EXIT_FAILURE); + if (unlockpt(master) < 0) + _exit(EXIT_FAILURE); + cmsg = CMSG_FIRSTHDR(&mh); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; @@ -6555,7 +6639,35 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char return 0; } +#endif /* NM_IGNORED */ +static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) { + assert(bad); + + for (; *s; s++) { + if (*s == '\\' || strchr(bad, *s)) + *(t++) = '\\'; + + *(t++) = *s; + } + + return t; +} + +char *shell_escape(const char *s, const char *bad) { + char *r, *t; + + r = new(char, strlen(s)*2+1); + if (!r) + return NULL; + + t = strcpy_backslash_escaped(r, s, bad); + *t = 0; + + return r; +} + +#if 0 /* NM_IGNORED */ char *shell_maybe_quote(const char *s) { const char *p; char *r, *t; @@ -6582,13 +6694,7 @@ char *shell_maybe_quote(const char *s) { *(t++) = '"'; t = mempcpy(t, s, p - s); - for (; *p; p++) { - - if (strchr(SHELL_NEED_ESCAPE, *p)) - *(t++) = '\\'; - - *(t++) = *p; - } + t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE); *(t++)= '"'; *t = 0; diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h index 9e3344ebb8..154aabadee 100644 --- a/src/systemd/src/basic/util.h +++ b/src/systemd/src/basic/util.h @@ -89,7 +89,7 @@ int strcmp_ptr(const char *a, const char *b) _pure_; #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) -#define malloc0(n) (calloc((n), 1)) +#define malloc0(n) (calloc(1, (n))) static inline void *mfree(void *memory) { free(memory); @@ -155,12 +155,18 @@ void safe_close_pair(int p[]); void close_many(const int fds[], unsigned n_fd); -int parse_size(const char *t, off_t base, off_t *size); +int fclose_nointr(FILE *f); +FILE* safe_fclose(FILE *f); + +int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_boolean(const char *v) _pure_; int parse_pid(const char *s, pid_t* ret_pid); int parse_uid(const char *s, uid_t* ret_uid); -#define parse_gid(s, ret_uid) parse_uid(s, ret_uid) +#define parse_gid(s, ret_gid) parse_uid(s, ret_gid) + +bool uid_is_valid(uid_t uid); +#define gid_is_valid(gid) uid_is_valid(gid) int safe_atou(const char *s, unsigned *ret_u); int safe_atoi(const char *s, int *ret_i); @@ -369,6 +375,9 @@ int fd_is_temporary_fs(int fd); int pipe_eof(int fd); +DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); +#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) + cpu_set_t* cpu_set_malloc(unsigned *ncpus); #define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf)) @@ -400,8 +409,6 @@ bool nulstr_contains(const char*nulstr, const char *needle); bool plymouth_running(void); -bool machine_name_is_valid(const char *s) _pure_; - char* strshorten(char *s, size_t l); int symlink_idempotent(const char *from, const char *to); @@ -477,7 +484,7 @@ bool kexec_loaded(void); int prot_from_flags(int flags) _const_; -char *format_bytes(char *buf, size_t l, off_t t); +char *format_bytes(char *buf, size_t l, uint64_t t); int fd_wait_for_event(int fd, int event, usec_t timeout); @@ -516,7 +523,10 @@ static inline void close_pairp(int (*p)[2]) { safe_close_pair(*p); } -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, fclose); +static inline void fclosep(FILE **f) { + safe_fclose(*f); +} + DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); @@ -568,7 +578,10 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *, void *), void *arg); +#if 0 /* NM_IGNORED */ #define _(String) gettext (String) +#define N_(String) String +#endif void init_gettext(void); bool is_locale_utf8(void); @@ -809,8 +822,8 @@ int get_proc_cmdline_key(const char *parameter, char **value); int container_get_leader(const char *machine, pid_t *pid); -int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd); -int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd); +int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd); +int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); #if 0 /* NM_IGNORED */ int getpeercred(int fd, struct ucred *ucred); @@ -864,20 +877,17 @@ int is_symlink(const char *path); int is_dir(const char *path, bool follow); int is_device_node(const char *path); -typedef enum UnquoteFlags { - UNQUOTE_RELAX = 1, - UNQUOTE_CUNESCAPE = 2, - UNQUOTE_CUNESCAPE_RELAX = 4, -} UnquoteFlags; +typedef enum ExtractFlags { + EXTRACT_RELAX = 1, + EXTRACT_CUNESCAPE = 2, + EXTRACT_CUNESCAPE_RELAX = 4, + EXTRACT_QUOTES = 8, + EXTRACT_DONT_COALESCE_SEPARATORS = 16, +} ExtractFlags; -int unquote_first_word(const char **p, char **ret, UnquoteFlags flags); -int unquote_first_word_and_warn(const char **p, char **ret, UnquoteFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); -int unquote_many_words(const char **p, UnquoteFlags flags, ...) _sentinel_; - -static inline void free_and_replace(char **s, char *v) { - free(*s); - *s = v; -} +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); +int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; int free_and_strdup(char **p, const char *s); @@ -927,6 +937,7 @@ void cmsg_close_all(struct msghdr *mh); int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); +char *shell_escape(const char *s, const char *bad); char *shell_maybe_quote(const char *s); int parse_mode(const char *s, mode_t *ret); diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c index 0fbfb7860e..1412b1615e 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.c +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -76,7 +76,7 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i uint64_t id; #if 0 /* NM_IGNORED */ - if (detect_container(NULL) <= 0) { + if (detect_container() <= 0) { /* not in a container, udev will be around */ _cleanup_udev_unref_ struct udev *udev; char ifindex_str[2 + DECIMAL_STR_MAX(int)]; diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h index b94c43f3b8..dc69329921 100644 --- a/src/systemd/src/libsystemd-network/dhcp-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-internal.h @@ -47,10 +47,10 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_ uint8_t code, size_t optlen, const void *optval); typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len, - const uint8_t *option, void *user_data); + const void *option, void *userdata); int dhcp_option_parse(DHCPMessage *message, size_t len, - dhcp_option_cb_t cb, void *user_data); + dhcp_option_cb_t cb, void *userdata); int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, uint8_t type, uint16_t arp_type, size_t optlen, diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h index e4c5a216c0..e024c57a5f 100644 --- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h @@ -27,7 +27,6 @@ #include <stdint.h> #include <linux/if_packet.h> -#include "refcnt.h" #include "util.h" #include "list.h" @@ -50,54 +49,59 @@ struct sd_dhcp_raw_option { }; struct sd_dhcp_lease { - RefCount n_ref; + unsigned n_ref; - int32_t time_offset; + /* each 0 if unset */ uint32_t t1; uint32_t t2; uint32_t lifetime; - uint32_t mtu_aging_timeout; + + /* each 0 if unset */ be32_t address; be32_t server_address; - be32_t subnet_mask; be32_t router; be32_t next_server; + + bool have_subnet_mask; + be32_t subnet_mask; + + bool have_broadcast; be32_t broadcast; + struct in_addr *dns; size_t dns_size; + struct in_addr *ntp; size_t ntp_size; - struct in_addr *policy_filter; - size_t policy_filter_size; + struct sd_dhcp_route *static_route; - size_t static_route_size; - size_t static_route_allocated; - uint16_t boot_file_size; - uint16_t mdr; - uint16_t mtu; - uint8_t ttl; - bool ip_forward; - bool ip_forward_non_local; + size_t static_route_size, static_route_allocated; + + uint16_t mtu; /* 0 if unset */ + char *domainname; char *hostname; char *root_path; - uint8_t *client_id; + + void *client_id; size_t client_id_len; - uint8_t *vendor_specific; + + void *vendor_specific; size_t vendor_specific_len; + + char *timezone; + LIST_HEAD(struct sd_dhcp_raw_option, private_options); }; int dhcp_lease_new(sd_dhcp_lease **ret); -int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, - void *user_data); -int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, - const uint8_t *data, uint8_t len); + +int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata); +int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len); int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease); -int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id, - size_t client_id_len); +int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_lease*, sd_dhcp_lease_unref); #define _cleanup_dhcp_lease_unref_ _cleanup_(sd_dhcp_lease_unrefp) diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c index 50ecf87383..b9a169a54e 100644 --- a/src/systemd/src/libsystemd-network/dhcp-option.c +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -142,7 +142,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload, uint8_t *message_type, dhcp_option_cb_t cb, - void *user_data) { + void *userdata) { uint8_t code, len; size_t offset = 0; @@ -201,7 +201,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo return -EINVAL; if (cb) - cb(code, len, &options[offset], user_data); + cb(code, len, &options[offset], userdata); offset += len; @@ -216,7 +216,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo } int dhcp_option_parse(DHCPMessage *message, size_t len, - dhcp_option_cb_t cb, void *user_data) { + dhcp_option_cb_t cb, void *userdata) { uint8_t overload = 0; uint8_t message_type = 0; int r; @@ -230,20 +230,20 @@ int dhcp_option_parse(DHCPMessage *message, size_t len, len -= sizeof(DHCPMessage); r = parse_options(message->options, len, &overload, &message_type, - cb, user_data); + cb, userdata); if (r < 0) return r; if (overload & DHCP_OVERLOAD_FILE) { r = parse_options(message->file, sizeof(message->file), - NULL, &message_type, cb, user_data); + NULL, &message_type, cb, userdata); if (r < 0) return r; } if (overload & DHCP_OVERLOAD_SNAME) { r = parse_options(message->sname, sizeof(message->sname), - NULL, &message_type, cb, user_data); + NULL, &message_type, cb, userdata); if (r < 0) return r; } diff --git a/src/systemd/src/libsystemd-network/dhcp-protocol.h b/src/systemd/src/libsystemd-network/dhcp-protocol.h index dd5ff56b08..d76f15b94c 100644 --- a/src/systemd/src/libsystemd-network/dhcp-protocol.h +++ b/src/systemd/src/libsystemd-network/dhcp-protocol.h @@ -139,6 +139,8 @@ enum { DHCP_OPTION_REBINDING_T2_TIME = 59, DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, DHCP_OPTION_CLIENT_IDENTIFIER = 61, + DHCP_OPTION_NEW_POSIX_TIMEZONE = 100, + DHCP_OPTION_NEW_TZDB_TIMEZONE = 101, DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, DHCP_OPTION_PRIVATE_BASE = 224, DHCP_OPTION_PRIVATE_LAST = 254, diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h index ee4014faab..b3028c21a9 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h @@ -5,7 +5,7 @@ /*** This file is part of systemd. - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -70,6 +70,11 @@ int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen, uint8_t **optvalue); int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, DHCP6IA *ia); +int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, + struct in6_addr **addrs, size_t count, + size_t *allocated); +int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, + char ***str_arr); int dhcp6_network_bind_udp_socket(int index, struct in6_addr *address); int dhcp6_network_send_udp_socket(int s, struct in6_addr *address, diff --git a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h index 9f7826c466..b21515437c 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h @@ -6,7 +6,7 @@ This file is part of systemd. Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -26,13 +26,11 @@ #include <stdint.h> -#include "refcnt.h" - #include "sd-dhcp6-lease.h" #include "dhcp6-internal.h" struct sd_dhcp6_lease { - RefCount n_ref; + unsigned n_ref; uint8_t *serverid; size_t serverid_len; @@ -42,6 +40,17 @@ struct sd_dhcp6_lease { DHCP6IA ia; DHCP6Address *addr_iter; + + struct in6_addr *dns; + size_t dns_count; + size_t dns_allocated; + char **domains; + size_t domains_count; + struct in6_addr *ntp; + size_t ntp_count; + size_t ntp_allocated; + char **ntp_fqdn; + size_t ntp_fqdn_count; }; int dhcp6_lease_clear_timers(DHCP6IA *ia); @@ -58,6 +67,13 @@ int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit); int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid); +int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen); +int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval, + size_t optlen); +int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen); +int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, + size_t optlen) ; + int dhcp6_lease_new(sd_dhcp6_lease **ret); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_lease*, sd_dhcp6_lease_unref); diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c index 626a4d6a7f..377511a83b 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-network.c +++ b/src/systemd/src/libsystemd-network/dhcp6-network.c @@ -43,8 +43,7 @@ { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } -int dhcp_network_icmp6_bind_router_solicitation(int index) -{ +int dhcp_network_icmp6_bind_router_solicitation(int index) { struct icmp6_filter filter = { }; struct ipv6_mreq mreq = { .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT, @@ -94,8 +93,7 @@ int dhcp_network_icmp6_bind_router_solicitation(int index) return r; } -int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) -{ +int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { struct sockaddr_in6 dst = { .sin6_family = AF_INET6, .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT, diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index 10872a3159..c891fef854 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -3,7 +3,7 @@ /*** This file is part of systemd. - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -28,9 +28,11 @@ #include "sparse-endian.h" #include "unaligned.h" #include "util.h" +#include "strv.h" #include "dhcp6-internal.h" #include "dhcp6-protocol.h" +#include "dns-domain.h" #define DHCP6_OPTION_IA_NA_LEN 12 #define DHCP6_OPTION_IA_TA_LEN 4 @@ -319,3 +321,98 @@ error: return r; } + +int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, + struct in6_addr **addrs, size_t count, + size_t *allocated) { + + if (optlen == 0 || optlen % sizeof(struct in6_addr) != 0) + return -EINVAL; + + if (!GREEDY_REALLOC(*addrs, *allocated, + count * sizeof(struct in6_addr) + optlen)) + return -ENOMEM; + + memcpy(*addrs + count, optval, optlen); + + count += optlen / sizeof(struct in6_addr); + + return count; +} + +int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char ***str_arr) { + size_t pos = 0, idx = 0; + _cleanup_free_ char **names = NULL; + int r; + + assert_return(optlen > 1, -ENODATA); + assert_return(optval[optlen] == '\0', -EINVAL); + + while (pos < optlen) { + _cleanup_free_ char *ret = NULL; + size_t n = 0, allocated = 0; + bool first = true; + + for (;;) { + uint8_t c; + + c = optval[pos++]; + + if (c == 0) + /* End of name */ + break; + else if (c <= 63) { + _cleanup_free_ char *t = NULL; + const char *label; + + /* Literal label */ + label = (const char *)&optval[pos]; + pos += c; + if (pos > optlen) + return -EMSGSIZE; + + r = dns_label_escape(label, c, &t); + if (r < 0) + goto fail; + + if (!GREEDY_REALLOC0(ret, allocated, n + !first + strlen(t) + 1)) { + r = -ENOMEM; + goto fail; + } + + if (!first) + ret[n++] = '.'; + else + first = false; + + memcpy(ret + n, t, r); + n += r; + continue; + } else { + r = -EBADMSG; + goto fail; + } + } + + if (!GREEDY_REALLOC(ret, allocated, n + 1)) { + r = -ENOMEM; + goto fail; + } + + ret[n] = 0; + + r = strv_extend(&names, ret); + if (r < 0) + goto fail; + + idx++; + } + + *str_arr = names; + names = NULL; + + return idx; + +fail: + return r; +} diff --git a/src/systemd/src/libsystemd-network/dhcp6-protocol.h b/src/systemd/src/libsystemd-network/dhcp6-protocol.h index 6598d86074..1318c81630 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-protocol.h +++ b/src/systemd/src/libsystemd-network/dhcp6-protocol.h @@ -125,7 +125,7 @@ enum { DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */ DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */ - DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075 */ + DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */ /* option code 35 is unassigned */ @@ -136,6 +136,12 @@ enum { }; enum { + DHCP6_NTP_SUBOPTION_SRV_ADDR = 1, + DHCP6_NTP_SUBOPTION_MC_ADDR = 2, + DHCP6_NTP_SUBOPTION_SRV_FQDN = 3, +}; + +enum { DHCP6_STATUS_SUCCESS = 0, DHCP6_STATUS_UNSPEC_FAIL = 1, DHCP6_STATUS_NO_ADDRS_AVAIL = 2, diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index 6f5bf11b20..99b59aea75 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -40,6 +40,7 @@ #include "condition.h" #endif /* NM_IGNORED */ #include "network-internal.h" +#include "sd-icmp6-nd.h" #if 0 /* NM_IGNORED */ const char *net_get_name(struct udev_device *device) { @@ -394,6 +395,20 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { return size; } +void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, + size_t size) { + unsigned i; + + assert(f); + assert(addresses); + assert(size); + + for (i = 0; i < size; i++) + fprintf(f, SD_ICMP6_ADDRESS_FORMAT_STR"%s", + SD_ICMP6_ADDRESS_FORMAT_VAL(addresses[i]), + (i < (size - 1)) ? " ": ""); +} + int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { _cleanup_free_ struct in6_addr *addresses = NULL; int size = 0; @@ -520,7 +535,7 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t return 0; } -int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t size) { +int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) { _cleanup_free_ char *hex_buf = NULL; assert(f); @@ -536,7 +551,7 @@ int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t return 0; } -int deserialize_dhcp_option(uint8_t **data, size_t *data_len, const char *string) { +int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) { assert(data); assert(data_len); assert(string); diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index 9e4e0de13f..fd3a0956cd 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -71,6 +71,8 @@ const char *net_get_name(struct udev_device *device); void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size); int deserialize_in_addrs(struct in_addr **addresses, const char *string); +void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, + size_t size); int deserialize_in6_addrs(struct in6_addr **addresses, const char *string); /* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */ @@ -79,5 +81,5 @@ struct sd_dhcp_route; void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size); int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string); -int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t size); -int deserialize_dhcp_option(uint8_t **data, size_t *data_len, const char *string); +int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); +int deserialize_dhcp_option(void **data, size_t *data_len, const char *string); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index ab7adef3c6..ca8e2f24c0 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -29,7 +29,6 @@ #include <sys/ioctl.h> #include "util.h" -#include "refcnt.h" #include "random-util.h" #include "async.h" @@ -43,7 +42,7 @@ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) struct sd_dhcp_client { - RefCount n_ref; + unsigned n_ref; DHCPState state; sd_event *event; @@ -108,7 +107,6 @@ static const uint8_t default_req_opts[] = { DHCP_OPTION_HOST_NAME, DHCP_OPTION_DOMAIN_NAME, DHCP_OPTION_DOMAIN_NAME_SERVER, - DHCP_OPTION_NTP_SERVER, }; static int client_receive_message_raw(sd_event_source *s, int fd, @@ -350,7 +348,7 @@ int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { client->state != DHCP_STATE_REBINDING) return -EADDRNOTAVAIL; - *ret = sd_dhcp_lease_ref(client->lease); + *ret = client->lease; return 0; } @@ -379,8 +377,7 @@ static int client_initialize(sd_dhcp_client *client) { client->state = DHCP_STATE_INIT; client->xid = 0; - if (client->lease) - client->lease = sd_dhcp_lease_unref(client->lease); + client->lease = sd_dhcp_lease_unref(client->lease); return 0; } @@ -1057,18 +1054,16 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, } lease->next_server = offer->siaddr; - lease->address = offer->yiaddr; - if (lease->address == INADDR_ANY || - lease->server_address == INADDR_ANY || + if (lease->address == 0 || + lease->server_address == 0 || lease->lifetime == 0) { - log_dhcp_client(client, "received lease lacks address, server " - "address or lease lifetime, ignoring"); + log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring"); return -ENOMSG; } - if (lease->subnet_mask == INADDR_ANY) { + if (!lease->have_subnet_mask) { r = dhcp_lease_set_default_subnet_mask(lease); if (r < 0) { log_dhcp_client(client, "received lease lacks subnet " @@ -1170,13 +1165,17 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, return r; } -static uint64_t client_compute_timeout(sd_dhcp_client *client, - uint32_t lifetime, double factor) { +static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) { assert(client); assert(client->request_sent); - assert(lifetime); + assert(lifetime > 0); - return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) + + if (lifetime > 3) + lifetime -= 3; + else + lifetime = 0; + + return client->request_sent + (lifetime * USEC_PER_SEC * factor) + + (random_u32() & 0x1fffff); } @@ -1208,7 +1207,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { /* convert the various timeouts from relative (secs) to absolute (usecs) */ lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1); - if (client->lease->t1 && client->lease->t2) { + if (client->lease->t1 > 0 && client->lease->t2 > 0) { /* both T1 and T2 are given */ if (client->lease->t1 < client->lease->t2 && client->lease->t2 < client->lease->lifetime) { @@ -1222,7 +1221,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); client->lease->t1 = client->lease->lifetime / 2; } - } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) { + } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) { /* only T2 is given, and it is valid */ t2_timeout = client_compute_timeout(client, client->lease->t2, 1); t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); @@ -1232,7 +1231,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); client->lease->t2 = (client->lease->lifetime * 7) / 8; } - } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) { + } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) { /* only T1 is given, and it is valid */ t1_timeout = client_compute_timeout(client, client->lease->t1, 1); t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); @@ -1678,30 +1677,41 @@ sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) { } sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) { - if (client) - assert_se(REFCNT_INC(client->n_ref) >= 2); + + if (!client) + return NULL; + + assert(client->n_ref >= 1); + client->n_ref++; return client; } sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { - if (client && REFCNT_DEC(client->n_ref) == 0) { - log_dhcp_client(client, "FREE"); - client_initialize(client); + if (!client) + return NULL; - client->receive_message = - sd_event_source_unref(client->receive_message); + assert(client->n_ref >= 1); + client->n_ref--; - sd_dhcp_client_detach_event(client); + if (client->n_ref > 0) + return NULL; - sd_dhcp_lease_unref(client->lease); + log_dhcp_client(client, "FREE"); - free(client->req_opts); - free(client->hostname); - free(client->vendor_class_identifier); - free(client); - } + client_initialize(client); + + client->receive_message = sd_event_source_unref(client->receive_message); + + sd_dhcp_client_detach_event(client); + + sd_dhcp_lease_unref(client->lease); + + free(client->req_opts); + free(client->hostname); + free(client->vendor_class_identifier); + free(client); return NULL; } @@ -1715,7 +1725,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) { if (!client) return -ENOMEM; - client->n_ref = REFCNT_INIT; + client->n_ref = 1; client->state = DHCP_STATE_INIT; client->index = -1; client->fd = -1; diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index de7cdb3880..054226c757 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -30,18 +30,31 @@ #include "unaligned.h" #include "in-addr-util.h" #include "hostname-util.h" +#include "dns-domain.h" +#include "network-internal.h" #include "dhcp-protocol.h" #include "dhcp-lease-internal.h" #include "sd-dhcp-lease.h" -#include "network-internal.h" -#include "dns-domain.h" int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); + if (lease->address == 0) + return -ENODATA; + addr->s_addr = lease->address; + return 0; +} +int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (!lease->have_broadcast) + return -ENODATA; + + addr->s_addr = lease->broadcast; return 0; } @@ -49,8 +62,32 @@ int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) { assert_return(lease, -EINVAL); assert_return(lifetime, -EINVAL); + if (lease->lifetime <= 0) + return -ENODATA; + *lifetime = lease->lifetime; + return 0; +} + +int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) { + assert_return(lease, -EINVAL); + assert_return(t1, -EINVAL); + + if (lease->t1 <= 0) + return -ENODATA; + *t1 = lease->t1; + return 0; +} + +int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) { + assert_return(lease, -EINVAL); + assert_return(t2, -EINVAL); + + if (lease->t2 <= 0) + return -ENODATA; + + *t2 = lease->t2; return 0; } @@ -58,11 +95,10 @@ int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) { assert_return(lease, -EINVAL); assert_return(mtu, -EINVAL); - if (lease->mtu) - *mtu = lease->mtu; - else - return -ENOENT; + if (lease->mtu <= 0) + return -ENODATA; + *mtu = lease->mtu; return 0; } @@ -70,37 +106,32 @@ int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - if (lease->dns_size) { - *addr = lease->dns; - return lease->dns_size; - } else - return -ENOENT; + if (lease->dns_size <= 0) + return -ENODATA; - return 0; + *addr = lease->dns; + return (int) lease->dns_size; } int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - if (lease->ntp_size) { - *addr = lease->ntp; - return lease->ntp_size; - } else - return -ENOENT; + if (lease->ntp_size <= 0) + return -ENODATA; - return 0; + *addr = lease->ntp; + return (int) lease->ntp_size; } int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) { assert_return(lease, -EINVAL); assert_return(domainname, -EINVAL); - if (lease->domainname) - *domainname = lease->domainname; - else - return -ENOENT; + if (!lease->domainname) + return -ENODATA; + *domainname = lease->domainname; return 0; } @@ -108,11 +139,10 @@ int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) { assert_return(lease, -EINVAL); assert_return(hostname, -EINVAL); - if (lease->hostname) - *hostname = lease->hostname; - else - return -ENOENT; + if (!lease->hostname) + return -ENODATA; + *hostname = lease->hostname; return 0; } @@ -120,11 +150,10 @@ int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) { assert_return(lease, -EINVAL); assert_return(root_path, -EINVAL); - if (lease->root_path) - *root_path = lease->root_path; - else - return -ENOENT; + if (!lease->root_path) + return -ENODATA; + *root_path = lease->root_path; return 0; } @@ -132,11 +161,10 @@ int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - if (lease->router != INADDR_ANY) - addr->s_addr = lease->router; - else - return -ENOENT; + if (lease->router == 0) + return -ENODATA; + addr->s_addr = lease->router; return 0; } @@ -144,8 +172,10 @@ int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - addr->s_addr = lease->subnet_mask; + if (!lease->have_subnet_mask) + return -ENODATA; + addr->s_addr = lease->subnet_mask; return 0; } @@ -153,8 +183,10 @@ int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *ad assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - addr->s_addr = lease->server_address; + if (lease->server_address == 0) + return -ENODATA; + addr->s_addr = lease->server_address; return 0; } @@ -162,136 +194,134 @@ int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - addr->s_addr = lease->next_server; + if (lease->next_server == 0) + return -ENODATA; + addr->s_addr = lease->next_server; return 0; } int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) { - assert_return(lease, -EINVAL); assert_return(routes, -EINVAL); - if (lease->static_route_size) { - *routes = lease->static_route; - return lease->static_route_size; - } else - return -ENOENT; + if (lease->static_route_size <= 0) + return -ENODATA; - return 0; + *routes = lease->static_route; + return (int) lease->static_route_size; } -int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data, - size_t *data_len) { +int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) { assert_return(lease, -EINVAL); assert_return(data, -EINVAL); assert_return(data_len, -EINVAL); - if (!lease->vendor_specific) - return -ENOENT; + if (lease->vendor_specific_len <= 0) + return -ENODATA; *data = lease->vendor_specific; *data_len = lease->vendor_specific_len; - return 0; } sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) { - if (lease) - assert_se(REFCNT_INC(lease->n_ref) >= 2); + + if (!lease) + return NULL; + + assert(lease->n_ref >= 1); + lease->n_ref++; return lease; } sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { - if (lease && REFCNT_DEC(lease->n_ref) == 0) { - while (lease->private_options) { - struct sd_dhcp_raw_option *option = lease->private_options; - LIST_REMOVE(options, lease->private_options, option); + if (!lease) + return NULL; - free(option->data); - free(option); - } - free(lease->hostname); - free(lease->domainname); - free(lease->dns); - free(lease->ntp); - free(lease->static_route); - free(lease->client_id); - free(lease->vendor_specific); - free(lease); - } + assert(lease->n_ref >= 1); + lease->n_ref--; - return NULL; -} + if (lease->n_ref > 0) + return NULL; -static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { - assert(option); - assert(ret); + while (lease->private_options) { + struct sd_dhcp_raw_option *option = lease->private_options; - if (len == 4) { - *ret = unaligned_read_be32((be32_t*) option); + LIST_REMOVE(options, lease->private_options, option); - if (*ret < min) - *ret = min; + free(option->data); + free(option); } -} -static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) { - lease_parse_u32(option, len, (uint32_t *)ret, 0); + free(lease->hostname); + free(lease->domainname); + free(lease->dns); + free(lease->ntp); + free(lease->static_route); + free(lease->client_id); + free(lease->vendor_specific); + free(lease); + + return NULL; } -static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) { +static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { assert(option); assert(ret); - if (len == 2) { - *ret = unaligned_read_be16((be16_t*) option); + if (len != 4) + return -EINVAL; - if (*ret < min) - *ret = min; - } + *ret = unaligned_read_be32((be32_t*) option); + if (*ret < min) + *ret = min; + + return 0; } -static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) { +static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) { assert(option); assert(ret); - if (len == 4) - memcpy(ret, option, 4); -} + if (len != 2) + return -EINVAL; -static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) { - assert(option); - assert(ret); + *ret = unaligned_read_be16((be16_t*) option); + if (*ret < min) + *ret = min; - if (len == 1) - *ret = !!(*option); + return 0; } -static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) { +static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) { assert(option); assert(ret); - if (len == 1) { - *ret = *option; + if (len != 4) + return -EINVAL; - if (*ret < min) - *ret = min; - } + memcpy(ret, option, 4); + return 0; } static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { assert(option); assert(ret); - if (len >= 1) { + if (len <= 0) + *ret = mfree(*ret); + else { char *string; + if (memchr(option, 0, len)) + return -EINVAL; + string = strndup((const char *)option, len); if (!string) - return -errno; + return -ENOMEM; free(*ret); *ret = string; @@ -300,48 +330,47 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { return 0; } -static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) { +static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { assert(option); assert(ret); - assert(ret_size); + assert(n_ret); - if (len && !(len % (4 * mult))) { - size_t size; + if (len <= 0) { + *ret = mfree(*ret); + *n_ret = 0; + } else { + size_t n_addresses; struct in_addr *addresses; - size = len / 4; + if (len % 4 != 0) + return -EINVAL; + + n_addresses = len / 4; - addresses = newdup(struct in_addr, option, size); + addresses = newdup(struct in_addr, option, n_addresses); if (!addresses) return -ENOMEM; free(*ret); *ret = addresses; - *ret_size = size; + *n_ret = n_addresses; } return 0; } -static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) { - return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1); -} - -static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) { - return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2); -} - -static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes, - size_t *routes_size, size_t *routes_allocated) { +static int lease_parse_routes( + const uint8_t *option, size_t len, + struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) { struct in_addr addr; - assert(option); + assert(option || len <= 0); assert(routes); assert(routes_size); assert(routes_allocated); - if (!len) + if (len <= 0) return 0; if (len % 8 != 0) @@ -356,15 +385,15 @@ static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_ r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen); if (r < 0) { - log_error("Failed to determine destination prefix length from class based IP, ignoring"); + log_debug("Failed to determine destination prefix length from class based IP, ignoring"); continue; } - lease_parse_be32(option, 4, &addr.s_addr); + assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0); route->dst_addr = inet_makeaddr(inet_netof(addr), 0); option += 4; - lease_parse_be32(option, 4, &route->gw_addr.s_addr); + assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0); option += 4; len -= 8; @@ -375,14 +404,18 @@ static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_ } /* parses RFC3442 Classless Static Route Option */ -static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes, - size_t *routes_size, size_t *routes_allocated) { +static int lease_parse_classless_routes( + const uint8_t *option, size_t len, + struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) { - assert(option); + assert(option || len <= 0); assert(routes); assert(routes_size); assert(routes_allocated); + if (len <= 0) + return 0; + /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */ while (len > 0) { @@ -390,7 +423,7 @@ static int lease_parse_classless_routes(const uint8_t *option, size_t len, struc struct sd_dhcp_route *route; if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1)) - return -ENOMEM; + return -ENOMEM; route = *routes + *routes_size; @@ -421,223 +454,222 @@ static int lease_parse_classless_routes(const uint8_t *option, size_t len, struc return 0; } -int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, - void *user_data) { - sd_dhcp_lease *lease = user_data; +int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) { + sd_dhcp_lease *lease = userdata; int r; assert(lease); switch(code) { - case DHCP_OPTION_TIME_OFFSET: - lease_parse_s32(option, len, &lease->time_offset); - - break; - - case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT: - lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0); - - break; - case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: - lease_parse_u32(option, len, &lease->lifetime, 1); + r = lease_parse_u32(option, len, &lease->lifetime, 1); + if (r < 0) + log_debug_errno(r, "Failed to parse lease time, ignoring: %m"); break; case DHCP_OPTION_SERVER_IDENTIFIER: - lease_parse_be32(option, len, &lease->server_address); + r = lease_parse_be32(option, len, &lease->server_address); + if (r < 0) + log_debug_errno(r, "Failed to parse server identifier, ignoring: %m"); break; case DHCP_OPTION_SUBNET_MASK: - lease_parse_be32(option, len, &lease->subnet_mask); - + r = lease_parse_be32(option, len, &lease->subnet_mask); + if (r < 0) + log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m"); + else + lease->have_subnet_mask = true; break; case DHCP_OPTION_BROADCAST: - lease_parse_be32(option, len, &lease->broadcast); - + r = lease_parse_be32(option, len, &lease->broadcast); + if (r < 0) + log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m"); + else + lease->have_broadcast = true; break; case DHCP_OPTION_ROUTER: - if(len >= 4) - lease_parse_be32(option, 4, &lease->router); - + if (len >= 4) { + r = lease_parse_be32(option, 4, &lease->router); + if (r < 0) + log_debug_errno(r, "Failed to parse router address, ignoring: %m"); + } break; case DHCP_OPTION_DOMAIN_NAME_SERVER: r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size); if (r < 0) - return r; - + log_debug_errno(r, "Failed to parse DNS server, ignoring: %m"); break; case DHCP_OPTION_NTP_SERVER: r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size); if (r < 0) - return r; - - break; - - case DHCP_OPTION_POLICY_FILTER: - r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size); - if (r < 0) - return r; - + log_debug_errno(r, "Failed to parse NTP server, ignoring: %m"); break; case DHCP_OPTION_STATIC_ROUTE: - r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, - &lease->static_route_allocated); + r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated); if (r < 0) - return r; - + log_debug_errno(r, "Failed to parse static routes, ignoring: %m"); break; case DHCP_OPTION_INTERFACE_MTU: - lease_parse_u16(option, len, &lease->mtu, 68); - - break; - - case DHCP_OPTION_INTERFACE_MDR: - lease_parse_u16(option, len, &lease->mdr, 576); - - break; - - case DHCP_OPTION_INTERFACE_TTL: - lease_parse_u8(option, len, &lease->ttl, 1); - - break; - - case DHCP_OPTION_BOOT_FILE_SIZE: - lease_parse_u16(option, len, &lease->boot_file_size, 0); - + r = lease_parse_u16(option, len, &lease->mtu, 68); + if (r < 0) + log_debug_errno(r, "Failed to parse MTU, ignoring: %m"); break; - case DHCP_OPTION_DOMAIN_NAME: - { - _cleanup_free_ char *domainname = NULL; - char *e; + case DHCP_OPTION_DOMAIN_NAME: { + _cleanup_free_ char *domainname = NULL, *normalized = NULL; r = lease_parse_string(option, len, &domainname); - if (r < 0) - return r; - - /* Chop off trailing dot of domain name that some DHCP - * servers send us back. Internally we want to store - * host names without trailing dots and - * host_name_is_valid() doesn't accept them. */ - e = endswith(domainname, "."); - if (e) - *e = 0; + if (r < 0) { + log_debug_errno(r, "Failed to parse domain name, ignoring: %m"); + return 0; + } - if (is_localhost(domainname)) - break; + r = dns_name_normalize(domainname, &normalized); + if (r < 0) { + log_debug_errno(r, "Failed to normalize domain name '%s': %m", domainname); + return 0; + } - r = dns_name_is_valid(domainname); - if (r <= 0) { - if (r < 0) - log_error_errno(r, "Failed to validate domain name: %s: %m", domainname); - if (r == 0) - log_warning("Domain name is not valid, ignoring: %s", domainname); + if (is_localhost(normalized)) { + log_debug_errno(r, "Detected 'localhost' as suggested domain name, ignoring."); break; } free(lease->domainname); - lease->domainname = domainname; - domainname = NULL; + lease->domainname = normalized; + normalized = NULL; break; } - case DHCP_OPTION_HOST_NAME: - { - _cleanup_free_ char *hostname = NULL; - char *e; + + case DHCP_OPTION_HOST_NAME: { + _cleanup_free_ char *hostname = NULL, *normalized = NULL; r = lease_parse_string(option, len, &hostname); - if (r < 0) - return r; + if (r < 0) { + log_debug_errno(r, "Failed to parse host name, ignoring: %m"); + return 0; + } - e = endswith(hostname, "."); - if (e) - *e = 0; + r = dns_name_normalize(hostname, &normalized); + if (r < 0) { + log_debug_errno(r, "Failed to normalize host name '%s', ignoring: %m", hostname); + return 0; + } - if (!hostname_is_valid(hostname, false) || is_localhost(hostname)) - break; + if (is_localhost(normalized)) { + log_debug_errno(r, "Detected 'localhost' as suggested host name, ignoring."); + return 0; + } - free_and_replace(&lease->hostname, hostname); - hostname = NULL; + free(lease->hostname); + lease->hostname = normalized; + normalized = NULL; break; } + case DHCP_OPTION_ROOT_PATH: r = lease_parse_string(option, len, &lease->root_path); if (r < 0) - return r; - + log_debug_errno(r, "Failed to parse root path, ignoring: %m"); break; case DHCP_OPTION_RENEWAL_T1_TIME: - lease_parse_u32(option, len, &lease->t1, 1); - + r = lease_parse_u32(option, len, &lease->t1, 1); + if (r < 0) + log_debug_errno(r, "Failed to parse T1 time, ignoring: %m"); break; case DHCP_OPTION_REBINDING_T2_TIME: - lease_parse_u32(option, len, &lease->t2, 1); - + r = lease_parse_u32(option, len, &lease->t2, 1); + if (r < 0) + log_debug_errno(r, "Failed to parse T2 time, ignoring: %m"); break; - case DHCP_OPTION_ENABLE_IP_FORWARDING: - lease_parse_bool(option, len, &lease->ip_forward); - + case DHCP_OPTION_CLASSLESS_STATIC_ROUTE: + r = lease_parse_classless_routes( + option, len, + &lease->static_route, + &lease->static_route_size, + &lease->static_route_allocated); + if (r < 0) + log_debug_errno(r, "Failed to parse classless routes, ignoring: %m"); break; - case DHCP_OPTION_ENABLE_IP_FORWARDING_NL: - lease_parse_bool(option, len, &lease->ip_forward_non_local); + case DHCP_OPTION_NEW_TZDB_TIMEZONE: { + _cleanup_free_ char *tz = NULL; - break; + r = lease_parse_string(option, len, &tz); + if (r < 0) { + log_debug_errno(r, "Failed to parse timezone option, ignoring: %m"); + return 0; + } - case DHCP_OPTION_CLASSLESS_STATIC_ROUTE: - r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size, - &lease->static_route_allocated); - if (r < 0) - return r; + if (!timezone_is_valid(tz)) { + log_debug_errno(r, "Timezone is not valid, ignoring: %m"); + return 0; + } + + free(lease->timezone); + lease->timezone = tz; + tz = NULL; break; + } case DHCP_OPTION_VENDOR_SPECIFIC: - if (len >= 1) { - free(lease->vendor_specific); - lease->vendor_specific = memdup(option, len); - if (!lease->vendor_specific) + + if (len <= 0) + lease->vendor_specific = mfree(lease->vendor_specific); + else { + void *p; + + p = memdup(option, len); + if (!p) return -ENOMEM; - lease->vendor_specific_len = len; - } - break; + free(lease->vendor_specific); + lease->vendor_specific = p; + } - default: - if (code < DHCP_OPTION_PRIVATE_BASE || code > DHCP_OPTION_PRIVATE_LAST) - break; + lease->vendor_specific_len = len; + break; + case DHCP_OPTION_PRIVATE_BASE ... DHCP_OPTION_PRIVATE_LAST: r = dhcp_lease_insert_private_option(lease, code, option, len); if (r < 0) return r; + + break; + + default: + log_debug("Ignoring option DHCP option %i while parsing.", code); + break; } return 0; } -int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, - const uint8_t *data, uint8_t len) { +int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) { struct sd_dhcp_raw_option *cur, *option; + assert(lease); + LIST_FOREACH(options, cur, lease->private_options) { if (tag < cur->tag) break; - else if (tag == cur->tag) { - log_error("Ignoring duplicate option, tagged %d.", tag); + if (tag == cur->tag) { + log_debug("Ignoring duplicate option, tagged %i.", tag); return 0; } } @@ -655,7 +687,6 @@ int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, } LIST_INSERT_BEFORE(options, lease->private_options, cur, option); - return 0; } @@ -667,8 +698,7 @@ int dhcp_lease_new(sd_dhcp_lease **ret) { return -ENOMEM; lease->router = INADDR_ANY; - lease->n_ref = REFCNT_INIT; - LIST_HEAD_INIT(lease->private_options); + lease->n_ref = 1; *ret = lease; return 0; @@ -680,11 +710,12 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { struct sd_dhcp_raw_option *option; struct in_addr address; const struct in_addr *addresses; - const uint8_t *client_id, *data; + const void *client_id, *data; size_t client_id_len, data_len; const char *string; uint16_t mtu; struct sd_dhcp_route *routes; + uint32_t t1, t2, lifetime; int r; assert(lease); @@ -696,19 +727,16 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { fchmod(fileno(f), 0644); - r = sd_dhcp_lease_get_address(lease, &address); - if (r < 0) - goto fail; - fprintf(f, - "# This is private data. Do not parse.\n" - "ADDRESS=%s\n", inet_ntoa(address)); + "# This is private data. Do not parse.\n"); - r = sd_dhcp_lease_get_netmask(lease, &address); - if (r < 0) - goto fail; + r = sd_dhcp_lease_get_address(lease, &address); + if (r >= 0) + fprintf(f, "ADDRESS=%s\n", inet_ntoa(address)); - fprintf(f, "NETMASK=%s\n", inet_ntoa(address)); + r = sd_dhcp_lease_get_netmask(lease, &address); + if (r >= 0) + fprintf(f, "NETMASK=%s\n", inet_ntoa(address)); r = sd_dhcp_lease_get_router(lease, &address); if (r >= 0) @@ -716,28 +744,45 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_server_identifier(lease, &address); if (r >= 0) - fprintf(f, "SERVER_ADDRESS=%s\n", - inet_ntoa(address)); + fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address)); r = sd_dhcp_lease_get_next_server(lease, &address); if (r >= 0) fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address)); + r = sd_dhcp_lease_get_broadcast(lease, &address); + if (r >= 0) + fprintf(f, "BROADCAST=%s\n", inet_ntoa(address)); + r = sd_dhcp_lease_get_mtu(lease, &mtu); if (r >= 0) fprintf(f, "MTU=%" PRIu16 "\n", mtu); - fputs("DNS=", f); - r = sd_dhcp_lease_get_dns(lease, &addresses); + r = sd_dhcp_lease_get_t1(lease, &t1); + if (r >= 0) + fprintf(f, "T1=%" PRIu32 "\n", t1); + + r = sd_dhcp_lease_get_t2(lease, &t2); + if (r >= 0) + fprintf(f, "T2=%" PRIu32 "\n", t2); + + r = sd_dhcp_lease_get_lifetime(lease, &lifetime); if (r >= 0) + fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime); + + r = sd_dhcp_lease_get_dns(lease, &addresses); + if (r > 0) { + fputs("DNS=", f); serialize_in_addrs(f, addresses, r); - fputs("\n", f); + fputs("\n", f); + } - fputs("NTP=", f); r = sd_dhcp_lease_get_ntp(lease, &addresses); - if (r >= 0) + if (r > 0) { + fputs("NTP=", f); serialize_in_addrs(f, addresses, r); - fputs("\n", f); + fputs("\n", f); + } r = sd_dhcp_lease_get_domainname(lease, &string); if (r >= 0) @@ -752,9 +797,13 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { fprintf(f, "ROOT_PATH=%s\n", string); r = sd_dhcp_lease_get_routes(lease, &routes); - if (r >= 0) + if (r > 0) serialize_dhcp_routes(f, "ROUTES", routes, r); + r = sd_dhcp_lease_get_timezone(lease, &string); + if (r >= 0) + fprintf(f, "TIMEZONE=%s\n", string); + r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len); if (r >= 0) { _cleanup_free_ char *client_id_hex = NULL; @@ -781,6 +830,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { LIST_FOREACH(options, option, lease->private_options) { char key[strlen("OPTION_000")+1]; + snprintf(key, sizeof(key), "OPTION_%"PRIu8, option->tag); r = serialize_dhcp_option(f, key, option->data, option->length); if (r < 0) @@ -806,15 +856,26 @@ fail: } int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { + _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; - _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL, - *server_address = NULL, *next_server = NULL, - *dns = NULL, *ntp = NULL, *mtu = NULL, - *routes = NULL, *client_id_hex = NULL, - *vendor_specific_hex = NULL, - *options[DHCP_OPTION_PRIVATE_LAST - - DHCP_OPTION_PRIVATE_BASE + 1] = { NULL }; - struct in_addr addr; + _cleanup_free_ char + *address = NULL, + *router = NULL, + *netmask = NULL, + *server_address = NULL, + *next_server = NULL, + *broadcast = NULL, + *dns = NULL, + *ntp = NULL, + *mtu = NULL, + *routes = NULL, + *client_id_hex = NULL, + *vendor_specific_hex = NULL, + *lifetime = NULL, + *t1 = NULL, + *t2 = NULL, + *options[DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE + 1] = {}; + int r, i; assert(lease_file); @@ -830,6 +891,7 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "NETMASK", &netmask, "SERVER_IDENTIFIER", &server_address, "NEXT_SERVER", &next_server, + "BROADCAST", &broadcast, "DNS", &dns, "NTP", &ntp, "MTU", &mtu, @@ -838,7 +900,11 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "ROOT_PATH", &lease->root_path, "ROUTES", &routes, "CLIENTID", &client_id_hex, + "TIMEZONE", &lease->timezone, "VENDOR_SPECIFIC", &vendor_specific_hex, + "LIFETIME", &lifetime, + "T1", &t1, + "T2", &t2, "OPTION_224", &options[0], "OPTION_225", &options[1], "OPTION_226", &options[2], @@ -871,100 +937,123 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "OPTION_253", &options[29], "OPTION_254", &options[30], NULL); - if (r < 0) { - if (r == -ENOENT) - return 0; - - return log_error_errno(r, "Failed to read %s: %m", lease_file); - } - - r = inet_pton(AF_INET, address, &addr); if (r < 0) return r; - lease->address = addr.s_addr; + if (address) { + r = inet_pton(AF_INET, address, &lease->address); + if (r <= 0) + log_debug_errno(errno, "Failed to parse address %s, ignoring: %m", address); + } if (router) { - r = inet_pton(AF_INET, router, &addr); - if (r < 0) - return r; - - lease->router = addr.s_addr; + r = inet_pton(AF_INET, router, &lease->router); + if (r <= 0) + log_debug_errno(errno, "Failed to parse router %s, ignoring: %m", router); } - r = inet_pton(AF_INET, netmask, &addr); - if (r < 0) - return r; - - lease->subnet_mask = addr.s_addr; + if (netmask) { + r = inet_pton(AF_INET, netmask, &lease->subnet_mask); + if (r <= 0) + log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", netmask); + else + lease->have_subnet_mask = true; + } if (server_address) { - r = inet_pton(AF_INET, server_address, &addr); - if (r < 0) - return r; - - lease->server_address = addr.s_addr; + r = inet_pton(AF_INET, server_address, &lease->server_address); + if (r <= 0) + log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", server_address); } if (next_server) { - r = inet_pton(AF_INET, next_server, &addr); - if (r < 0) - return r; + r = inet_pton(AF_INET, next_server, &lease->next_server); + if (r <= 0) + log_debug_errno(errno, "Failed to parse next server %s, ignoring: %m", next_server); + } - lease->next_server = addr.s_addr; + if (broadcast) { + r = inet_pton(AF_INET, broadcast, &lease->broadcast); + if (r <= 0) + log_debug_errno(errno, "Failed to parse broadcast address %s, ignoring: %m", broadcast); + else + lease->have_broadcast = true; } if (dns) { r = deserialize_in_addrs(&lease->dns, dns); if (r < 0) - return r; - - lease->dns_size = r; + log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns); + else + lease->dns_size = r; } if (ntp) { r = deserialize_in_addrs(&lease->ntp, ntp); if (r < 0) - return r; - - lease->ntp_size = r; + log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp); + else + lease->ntp_size = r; } if (mtu) { - uint16_t u; - if (sscanf(mtu, "%" SCNu16, &u) > 0) - lease->mtu = u; + r = safe_atou16(mtu, &lease->mtu); + if (r < 0) + log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu); } if (routes) { - r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size, - &lease->static_route_allocated, routes); + r = deserialize_dhcp_routes( + &lease->static_route, + &lease->static_route_size, + &lease->static_route_allocated, + routes); + if (r < 0) + log_debug_errno(r, "Failed to parse DHCP routes %s, ignoring: %m", routes); + } + + if (lifetime) { + r = safe_atou32(lifetime, &lease->lifetime); + if (r < 0) + log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime); + } + + if (t1) { + r = safe_atou32(t1, &lease->t1); + if (r < 0) + log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1); + } + + if (t2) { + r = safe_atou32(t2, &lease->t2); if (r < 0) - return r; + log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2); } if (client_id_hex) { r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex); if (r < 0) - return r; + log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex); } if (vendor_specific_hex) { r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex); if (r < 0) - return r; + log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex); } for (i = 0; i <= DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE; i++) { - _cleanup_free_ uint8_t *data = NULL; + _cleanup_free_ void *data = NULL; size_t len; if (!options[i]) continue; r = deserialize_dhcp_option(&data, &len, options[i]); - if (r < 0) - return r; + if (r < 0) { + log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]); + continue; + } r = dhcp_lease_insert_private_option(lease, DHCP_OPTION_PRIVATE_BASE + i, data, len); if (r < 0) @@ -978,12 +1067,14 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { } int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { - struct in_addr address; - struct in_addr mask; + struct in_addr address, mask; int r; assert(lease); + if (lease->address == 0) + return -ENODATA; + address.s_addr = lease->address; /* fall back to the default subnet masks based on address class */ @@ -992,35 +1083,53 @@ int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { return r; lease->subnet_mask = mask.s_addr; + lease->have_subnet_mask = true; return 0; } -int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id, - size_t *client_id_len) { +int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) { assert_return(lease, -EINVAL); assert_return(client_id, -EINVAL); assert_return(client_id_len, -EINVAL); + if (!lease->client_id) + return -ENODATA; + *client_id = lease->client_id; *client_id_len = lease->client_id_len; + return 0; } -int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id, - size_t client_id_len) { +int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) { assert_return(lease, -EINVAL); - assert_return((!client_id && !client_id_len) || - (client_id && client_id_len), -EINVAL); + assert_return(client_id || client_id_len <= 0, -EINVAL); + + if (client_id_len <= 0) + lease->client_id = mfree(lease->client_id); + else { + void *p; - free (lease->client_id); - lease->client_id = NULL; - lease->client_id_len = 0; + p = memdup(client_id, client_id_len); + if (!p) + return -ENOMEM; - if (client_id) { - lease->client_id = memdup (client_id, client_id_len); + free(lease->client_id); + lease->client_id = p; lease->client_id_len = client_id_len; } return 0; } + +int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) { + assert_return(lease, -EINVAL); + assert_return(tz, -EINVAL); + + if (!lease->timezone) + return -ENODATA; + + *tz = lease->timezone; + return 0; +} diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index 5ca76045cb..5f1393c60c 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -3,7 +3,7 @@ /*** This file is part of systemd. - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -31,7 +31,6 @@ #include "udev-util.h" #endif /* NM_IGNORED */ #include "util.h" -#include "refcnt.h" #include "random-util.h" #include "network-internal.h" @@ -44,7 +43,7 @@ #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN struct sd_dhcp6_client { - RefCount n_ref; + unsigned n_ref; enum DHCP6State state; sd_event *event; @@ -77,6 +76,7 @@ static const uint16_t default_req_opts[] = { DHCP6_OPTION_DNS_SERVERS, DHCP6_OPTION_DOMAIN_LIST, DHCP6_OPTION_NTP_SERVER, + DHCP6_OPTION_SNTP_SERVERS, }; const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = { @@ -116,9 +116,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref); static int client_start(sd_dhcp6_client *client, enum DHCP6State state); -int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, - sd_dhcp6_client_cb_t cb, void *userdata) -{ +int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) { assert_return(client, -EINVAL); client->cb = cb; @@ -127,8 +125,7 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, return 0; } -int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) -{ +int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) { assert_return(client, -EINVAL); assert_return(interface_index >= -1, -EINVAL); @@ -137,9 +134,11 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) return 0; } -int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type) -{ +int sd_dhcp6_client_set_mac( + sd_dhcp6_client *client, + const uint8_t *addr, size_t addr_len, + uint16_t arp_type) { + assert_return(client, -EINVAL); assert_return(addr, -EINVAL); assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); @@ -163,16 +162,17 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, return 0; } -static int client_ensure_duid(sd_dhcp6_client *client) -{ +static int client_ensure_duid(sd_dhcp6_client *client) { if (client->duid_len != 0) return 0; + return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, - size_t duid_len) -{ +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t type, + uint8_t *duid, size_t duid_len) { assert_return(client, -EINVAL); assert_return(duid, -EINVAL); assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); @@ -206,8 +206,7 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du return 0; } -int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, - bool enabled) { +int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enabled) { assert_return(client, -EINVAL); client->information_request = enabled; @@ -215,8 +214,7 @@ int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, return 0; } -int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, - bool *enabled) { +int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, bool *enabled) { assert_return(client, -EINVAL); assert_return(enabled, -EINVAL); @@ -225,8 +223,7 @@ int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, return 0; } -int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, - uint16_t option) { +int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) { size_t t; assert_return(client, -EINVAL); @@ -263,7 +260,7 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) { if (!client->lease) return -ENOMSG; - *ret = sd_dhcp6_lease_ref(client->lease); + *ret = client->lease; return 0; } @@ -276,6 +273,11 @@ static void client_notify(sd_dhcp6_client *client, int event) { static int client_reset(sd_dhcp6_client *client) { assert_return(client, -EINVAL); + if (client->lease) { + dhcp6_lease_clear_timers(&client->lease->ia); + client->lease = sd_dhcp6_lease_unref(client->lease); + } + client->receive_message = sd_event_source_unref(client->receive_message); @@ -752,7 +754,36 @@ static int client_parse_message(sd_dhcp6_client *client, return r; break; + + case DHCP6_OPTION_DNS_SERVERS: + r = dhcp6_lease_set_dns(lease, optval, optlen); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_DOMAIN_LIST: + r = dhcp6_lease_set_domains(lease, optval, optlen); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_NTP_SERVER: + r = dhcp6_lease_set_ntp(lease, optval, optlen); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_SNTP_SERVERS: + r = dhcp6_lease_set_sntp(lease, optval, optlen); + if (r < 0) + return r; + + break; } + } if (r == -ENOMSG) @@ -774,9 +805,7 @@ static int client_parse_message(sd_dhcp6_client *client, return r; } -static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, - size_t len) -{ +static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) { int r; _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; bool rapid_commit; @@ -806,16 +835,13 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, client->lease = sd_dhcp6_lease_unref(client->lease); } - if (client->state != DHCP6_STATE_INFORMATION_REQUEST) { - client->lease = lease; - lease = NULL; - } + client->lease = lease; + lease = NULL; return DHCP6_STATE_BOUND; } -static int client_receive_advertise(sd_dhcp6_client *client, - DHCP6Message *advertise, size_t len) { +static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) { int r; _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; uint8_t pref_advertise = 0, pref_lease = 0; @@ -850,8 +876,7 @@ static int client_receive_advertise(sd_dhcp6_client *client, return r; } -static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, - void *userdata) { +static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_dhcp6_client *client = userdata; DHCP6_CLIENT_DONT_DESTROY(client); _cleanup_free_ DHCP6Message *message = NULL; @@ -962,8 +987,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, return 0; } -static int client_start(sd_dhcp6_client *client, enum DHCP6State state) -{ +static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { int r; usec_t timeout, time_now; char time_string[FORMAT_TIMESPAN_MAX]; @@ -1092,15 +1116,13 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) return 0; } -int sd_dhcp6_client_stop(sd_dhcp6_client *client) -{ +int sd_dhcp6_client_stop(sd_dhcp6_client *client) { client_stop(client, DHCP6_EVENT_STOP); return 0; } -int sd_dhcp6_client_start(sd_dhcp6_client *client) -{ +int sd_dhcp6_client_start(sd_dhcp6_client *client) { int r = 0; enum DHCP6State state = DHCP6_STATE_SOLICITATION; @@ -1156,9 +1178,7 @@ error: return r; } -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, - int priority) -{ +int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority) { int r; assert_return(client, -EINVAL); @@ -1193,30 +1213,39 @@ sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) { } sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) { - if (client) - assert_se(REFCNT_INC(client->n_ref) >= 2); + + if (!client) + return NULL; + + assert(client->n_ref >= 1); + client->n_ref++; return client; } sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { - if (client && REFCNT_DEC(client->n_ref) == 0) { - client_reset(client); - sd_dhcp6_client_detach_event(client); - sd_dhcp6_lease_unref(client->lease); + if (!client) + return NULL; - free(client->req_opts); - free(client); + assert(client->n_ref >= 1); + client->n_ref--; + if (client->n_ref > 0) return NULL; - } - return client; + client_reset(client); + + sd_dhcp6_client_detach_event(client); + sd_dhcp6_lease_unref(client->lease); + + free(client->req_opts); + free(client); + + return NULL; } -int sd_dhcp6_client_new(sd_dhcp6_client **ret) -{ +int sd_dhcp6_client_new(sd_dhcp6_client **ret) { _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL; size_t t; @@ -1226,7 +1255,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) if (!client) return -ENOMEM; - client->n_ref = REFCNT_INIT; + client->n_ref = 1; client->ia_na.type = DHCP6_OPTION_IA_NA; diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c index 8ac18a7566..a6922f78e7 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -1,8 +1,10 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + /*** This file is part of systemd. Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -22,9 +24,11 @@ #include <errno.h> +#include "strv.h" #include "util.h" #include "dhcp6-lease-internal.h" +#include "dhcp6-protocol.h" int dhcp6_lease_clear_timers(DHCP6IA *ia) { assert_return(ia, -EINVAL); @@ -175,20 +179,221 @@ void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) { lease->addr_iter = lease->ia.addresses; } +int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { + int r; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + if (!optlen) + return 0; + + 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; + } + + lease->dns_count = r; + + return 0; +} + +int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, struct in6_addr **addrs) { + assert_return(lease, -EINVAL); + assert_return(addrs, -EINVAL); + + if (lease->dns_count) { + *addrs = lease->dns; + return lease->dns_count; + } + + return -ENOENT; +} + +int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval, + size_t optlen) { + int r; + char **domains; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + if (!optlen) + return 0; + + r = dhcp6_option_parse_domainname(optval, optlen, &domains); + if (r < 0) + return 0; + + free(lease->domains); + lease->domains = domains; + lease->domains_count = r; + + return r; +} + +int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) { + assert_return(lease, -EINVAL); + assert_return(domains, -EINVAL); + + if (lease->domains_count) { + *domains = lease->domains; + return lease->domains_count; + } + + return -ENOENT; +} + +int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { + int r; + uint16_t subopt; + size_t sublen; + uint8_t *subval; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + free(lease->ntp); + lease->ntp_count = 0; + lease->ntp_allocated = 0; + + while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen, + &subval)) >= 0) { + int s; + char **servers; + + switch(subopt) { + case DHCP6_NTP_SUBOPTION_SRV_ADDR: + case DHCP6_NTP_SUBOPTION_MC_ADDR: + if (sublen != 16) + return 0; + + s = dhcp6_option_parse_ip6addrs(subval, sublen, + &lease->ntp, + lease->ntp_count, + &lease->ntp_allocated); + if (s < 0) + return s; + + lease->ntp_count = s; + + break; + + case DHCP6_NTP_SUBOPTION_SRV_FQDN: + r = dhcp6_option_parse_domainname(subval, sublen, + &servers); + if (r < 0) + return 0; + + lease->ntp_fqdn = strv_free(lease->ntp_fqdn); + lease->ntp_fqdn = servers; + lease->ntp_fqdn_count = r; + + break; + } + } + + if (r != -ENOMSG) + return r; + + return 0; +} + +int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { + int r; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + if (!optlen) + return 0; + + if (lease->ntp || lease->ntp_fqdn) { + log_dhcp6_client(client, "NTP information already provided"); + + return 0; + } + + log_dhcp6_client(client, "Using deprecated SNTP information"); + + 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; + } + + lease->ntp_count = r; + + return 0; +} + +int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, + struct in6_addr **addrs) { + assert_return(lease, -EINVAL); + assert_return(addrs, -EINVAL); + + if (lease->ntp_count) { + *addrs = lease->ntp; + return lease->ntp_count; + } + + return -ENOENT; +} + +int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) { + assert_return(lease, -EINVAL); + assert_return(ntp_fqdn, -EINVAL); + + if (lease->ntp_fqdn_count) { + *ntp_fqdn = lease->ntp_fqdn; + return lease->ntp_fqdn_count; + } + + return -ENOENT; +} + sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) { - if (lease) - assert_se(REFCNT_INC(lease->n_ref) >= 2); + + if (!lease) + return NULL; + + assert(lease->n_ref >= 1); + lease->n_ref++; return lease; } sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) { - if (lease && REFCNT_DEC(lease->n_ref) == 0) { - free(lease->serverid); - dhcp6_lease_free_ia(&lease->ia); - free(lease); - } + if (!lease) + return NULL; + + assert(lease->n_ref >= 1); + lease->n_ref--; + + if (lease->n_ref > 0) + return NULL; + + free(lease->serverid); + dhcp6_lease_free_ia(&lease->ia); + + free(lease->dns); + + lease->domains = strv_free(lease->domains); + + free(lease->ntp); + + lease->ntp_fqdn = strv_free(lease->ntp_fqdn); + free(lease); return NULL; } @@ -200,7 +405,7 @@ int dhcp6_lease_new(sd_dhcp6_lease **ret) { if (!lease) return -ENOMEM; - lease->n_ref = REFCNT_INIT; + lease->n_ref = 1; LIST_HEAD_INIT(lease->ia.addresses); diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index b0d15ddf8b..d652ea9a2f 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -28,7 +28,6 @@ #include "util.h" #include "siphash24.h" #include "list.h" -#include "refcnt.h" #include "random-util.h" #include "ipv4ll-internal.h" @@ -70,7 +69,7 @@ typedef enum IPv4LLState { } IPv4LLState; struct sd_ipv4ll { - RefCount n_ref; + unsigned n_ref; IPv4LLState state; int index; @@ -466,9 +465,8 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){ assert_return(ll, -EINVAL); assert_return(address, -EINVAL); - if (ll->claimed_address == 0) { + if (ll->claimed_address == 0) return -ENOENT; - } address->s_addr = ll->claimed_address; return 0; @@ -600,30 +598,39 @@ int sd_ipv4ll_stop(sd_ipv4ll *ll) { } sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) { - if (ll) - assert_se(REFCNT_INC(ll->n_ref) >= 2); + + if (!ll) + return NULL; + + assert(ll->n_ref >= 1); + ll->n_ref++; return ll; } sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) { - if (ll && REFCNT_DEC(ll->n_ref) == 0) { - ll->receive_message = - sd_event_source_unref(ll->receive_message); - ll->fd = safe_close(ll->fd); - ll->timer = sd_event_source_unref(ll->timer); + if (!ll) + return NULL; - sd_ipv4ll_detach_event(ll); + assert(ll->n_ref >= 1); + ll->n_ref--; - free(ll->random_data); - free(ll->random_data_state); - free(ll); + if (ll->n_ref > 0) + return ll; - return NULL; - } + ll->receive_message = sd_event_source_unref(ll->receive_message); + ll->fd = safe_close(ll->fd); - return ll; + ll->timer = sd_event_source_unref(ll->timer); + + sd_ipv4ll_detach_event(ll); + + free(ll->random_data); + free(ll->random_data_state); + free(ll); + + return NULL; } DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref); @@ -638,7 +645,7 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) { if (!ll) return -ENOMEM; - ll->n_ref = REFCNT_INIT; + ll->n_ref = 1; ll->state = IPV4LL_STATE_INIT; ll->index = -1; ll->fd = -1; diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c index 34ec45f22d..c95654f299 100644 --- a/src/systemd/src/shared/dns-domain.c +++ b/src/systemd/src/shared/dns-domain.c @@ -310,14 +310,14 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, #endif } -int dns_name_normalize(const char *s, char **_ret) { +int dns_name_concat(const char *a, const char *b, char **_ret) { _cleanup_free_ char *ret = NULL; size_t n = 0, allocated = 0; - const char *p = s; + const char *p = a; bool first = true; int r; - assert(s); + assert(a); for (;;) { _cleanup_free_ char *t = NULL; @@ -330,6 +330,14 @@ int dns_name_normalize(const char *s, char **_ret) { if (r == 0) { if (*p != 0) return -EINVAL; + + if (b) { + /* Now continue with the second string, if there is one */ + p = b; + b = NULL; + continue; + } + break; } @@ -343,27 +351,29 @@ int dns_name_normalize(const char *s, char **_ret) { if (r < 0) return r; - if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) - return -ENOMEM; + if (_ret) { + if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) + return -ENOMEM; - if (!first) - ret[n++] = '.'; - else - first = false; + if (!first) + ret[n++] = '.'; + else + first = false; + + memcpy(ret + n, t, r); + } - memcpy(ret + n, t, r); n += r; } if (n > DNS_NAME_MAX) return -EINVAL; - if (!GREEDY_REALLOC(ret, allocated, n + 1)) - return -ENOMEM; - - ret[n] = 0; - if (_ret) { + if (!GREEDY_REALLOC(ret, allocated, n + 1)) + return -ENOMEM; + + ret[n] = 0; *_ret = ret; ret = NULL; } diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h index ad23d99875..89e0901ad4 100644 --- a/src/systemd/src/shared/dns-domain.h +++ b/src/systemd/src/shared/dns-domain.h @@ -38,9 +38,17 @@ int dns_label_escape(const char *p, size_t l, char **ret); 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); -int dns_name_normalize(const char *s, char **_ret); +int dns_name_concat(const char *a, const char *b, char **ret); + +static inline int dns_name_normalize(const char *s, char **ret) { + /* dns_name_concat() normalizes as a side-effect */ + return dns_name_concat(s, NULL, 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, NULL); if (r == -EINVAL) return 0; diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h index e5678db6d7..834143b696 100644 --- a/src/systemd/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/src/systemd/sd-dhcp-lease.h @@ -36,6 +36,9 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease); int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime); +int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1); +int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2); +int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr); @@ -46,11 +49,10 @@ 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_hostname(sd_dhcp_lease *lease, const char **hostname); int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path); -int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn); -int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data, - size_t *data_len); -int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id, - size_t *client_id_len); +int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes); +int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len); +int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len); +int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone); int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file); int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file); diff --git a/src/systemd/src/systemd/sd-dhcp6-lease.h b/src/systemd/src/systemd/sd-dhcp6-lease.h index 84008cf590..1e6322c718 100644 --- a/src/systemd/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/src/systemd/sd-dhcp6-lease.h @@ -7,7 +7,7 @@ This file is part of systemd. Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -35,6 +35,12 @@ int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, uint32_t *lifetime_preferred, uint32_t *lifetime_valid); +int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, struct in6_addr **addrs); +int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains); +int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, + struct in6_addr **addrs); +int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn); + sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease); sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease); diff --git a/src/systemd/src/systemd/sd-icmp6-nd.h b/src/systemd/src/systemd/sd-icmp6-nd.h new file mode 100644 index 0000000000..5f5a9217f1 --- /dev/null +++ b/src/systemd/src/systemd/sd-icmp6-nd.h @@ -0,0 +1,81 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdicmp6ndfoo +#define foosdicmp6ndfoo + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd 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.1 of the License, or + (at your option) any later version. + + systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "nm-sd-adapt.h" + +#include <net/ethernet.h> + +#include "sd-event.h" + +enum { + ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE = 0, + ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1, + ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER = 2, + ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3, + ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED = 4, +}; + +typedef struct sd_icmp6_nd sd_icmp6_nd; + +typedef void(*sd_icmp6_nd_callback_t)(sd_icmp6_nd *nd, int event, + void *userdata); + +int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t cb, + void *userdata); +int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index); +int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr); + +int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority); +int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd); +sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd); + +sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd); +sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd); +int sd_icmp6_nd_new(sd_icmp6_nd **ret); + +int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen, + struct in6_addr *addr); + +int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu); +int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr, + uint8_t *prefixlen); +int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr, + uint8_t *prefixlen); + +int sd_icmp6_nd_stop(sd_icmp6_nd *nd); +int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd); + +#define SD_ICMP6_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" + +#define SD_ICMP6_ADDRESS_FORMAT_VAL(address) \ + be16toh((address).s6_addr16[0]), \ + be16toh((address).s6_addr16[1]), \ + be16toh((address).s6_addr16[2]), \ + be16toh((address).s6_addr16[3]), \ + be16toh((address).s6_addr16[4]), \ + be16toh((address).s6_addr16[5]), \ + be16toh((address).s6_addr16[6]), \ + be16toh((address).s6_addr16[7]) + +#endif |