systemd: update code from upstream

This is a direct dump from systemd git on 2015-09-16, git commit
ac2896bab6.

======

SYSTEMD_DIR=../systemd
COMMIT=ac2896bab61bd8cd0b8a8b92f8347e2c11a088b5

(
  cd "$SYSTEMD_DIR"
  git checkout "$COMMIT"
  git reset --hard
  git clean -fdx
)

git ls-files :/src/systemd/src/ | xargs -d '\n' rm -f

nm_copy_sd() {
    mkdir -p "./src/systemd/$(dirname "$1")"
    cp "$SYSTEMD_DIR/$1" "./src/systemd/$1"
}

nm_copy_sd "src/basic/async.h"
nm_copy_sd "src/basic/fileio.c"
nm_copy_sd "src/basic/fileio.h"
nm_copy_sd "src/basic/hostname-util.c"
nm_copy_sd "src/basic/hostname-util.h"
nm_copy_sd "src/basic/in-addr-util.c"
nm_copy_sd "src/basic/in-addr-util.h"
nm_copy_sd "src/basic/list.h"
nm_copy_sd "src/basic/log.h"
nm_copy_sd "src/basic/macro.h"
nm_copy_sd "src/basic/path-util.c"
nm_copy_sd "src/basic/path-util.h"
nm_copy_sd "src/basic/random-util.c"
nm_copy_sd "src/basic/random-util.h"
nm_copy_sd "src/basic/refcnt.h"
nm_copy_sd "src/basic/siphash24.c"
nm_copy_sd "src/basic/siphash24.h"
nm_copy_sd "src/basic/socket-util.h"
nm_copy_sd "src/basic/sparse-endian.h"
nm_copy_sd "src/basic/strv.c"
nm_copy_sd "src/basic/strv.h"
nm_copy_sd "src/basic/time-util.c"
nm_copy_sd "src/basic/time-util.h"
nm_copy_sd "src/basic/unaligned.h"
nm_copy_sd "src/basic/utf8.c"
nm_copy_sd "src/basic/utf8.h"
nm_copy_sd "src/basic/util.c"
nm_copy_sd "src/basic/util.h"
nm_copy_sd "src/libsystemd-network/dhcp6-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-network.c"
nm_copy_sd "src/libsystemd-network/dhcp6-option.c"
nm_copy_sd "src/libsystemd-network/dhcp6-protocol.h"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.c"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.h"
nm_copy_sd "src/libsystemd-network/dhcp-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-network.c"
nm_copy_sd "src/libsystemd-network/dhcp-option.c"
nm_copy_sd "src/libsystemd-network/dhcp-packet.c"
nm_copy_sd "src/libsystemd-network/dhcp-protocol.h"
nm_copy_sd "src/libsystemd-network/ipv4ll-internal.h"
nm_copy_sd "src/libsystemd-network/ipv4ll-internal.h"
nm_copy_sd "src/libsystemd-network/ipv4ll-network.c"
nm_copy_sd "src/libsystemd-network/ipv4ll-packet.c"
nm_copy_sd "src/libsystemd-network/network-internal.c"
nm_copy_sd "src/libsystemd-network/network-internal.h"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-lease.c"
nm_copy_sd "src/libsystemd-network/sd-ipv4ll.c"
nm_copy_sd "src/libsystemd/sd-id128/sd-id128.c"
nm_copy_sd "src/shared/dns-domain.c"
nm_copy_sd "src/shared/dns-domain.h"
nm_copy_sd "src/systemd/_sd-common.h"
nm_copy_sd "src/systemd/sd-dhcp6-client.h"
nm_copy_sd "src/systemd/sd-dhcp6-lease.h"
nm_copy_sd "src/systemd/sd-dhcp-client.h"
nm_copy_sd "src/systemd/sd-dhcp-lease.h"
nm_copy_sd "src/systemd/sd-event.h"
nm_copy_sd "src/systemd/sd-icmp6-nd.h"
nm_copy_sd "src/systemd/sd-id128.h"
nm_copy_sd "src/systemd/sd-ipv4ll.h"
This commit is contained in:
Thomas Haller 2015-09-16 14:11:11 +02:00
parent 8f4e617526
commit 3383d5d0a6
32 changed files with 1565 additions and 718 deletions

View file

@ -62,16 +62,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;
@ -87,7 +90,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;
@ -96,10 +99,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;
@ -151,6 +156,17 @@ bool is_localhost(const char *hostname) {
endswith_no_case(hostname, ".localdomain.");
}
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] = {};

View file

@ -29,10 +29,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);

View file

@ -298,6 +298,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)))

View file

@ -21,7 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
/* 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;

View file

@ -270,15 +270,13 @@ 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;
}
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;
@ -289,7 +287,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)
@ -693,6 +691,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;

View file

@ -73,7 +73,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);
@ -145,6 +145,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);

View file

@ -26,6 +26,7 @@
#include "util.h"
#include "time-util.h"
#include "path-util.h"
#include "strv.h"
usec_t now(clockid_t clock_id) {
@ -36,6 +37,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);
@ -88,6 +97,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);
@ -103,6 +138,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);
@ -945,7 +992,10 @@ bool timezone_is_valid(const char *name) {
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++) {
@ -995,3 +1045,30 @@ clockid_t clock_boottime_or_monotonic(void) {
return clock;
}
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;
}

View file

@ -70,10 +70,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) ||
@ -86,6 +88,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);
@ -109,3 +113,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);

View file

@ -327,6 +327,33 @@ void close_many(const int fds[], unsigned n_fd) {
safe_close(fds[i]);
}
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;
@ -373,6 +400,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;
@ -389,13 +429,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;
@ -2176,7 +2214,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
@ -2204,8 +2242,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[] = {
@ -2215,8 +2253,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;
@ -2238,33 +2276,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);
if (errno > 0)
return -errno;
if (l < 0)
p += strspn(p, WHITESPACE);
if (*p == '-')
return -ERANGE;
errno = 0;
l = strtoull(p, &e, 10);
if (errno > 0)
return -errno;
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 */
@ -2277,27 +2314,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;
@ -3006,21 +3043,6 @@ char* strshorten(char *s, size_t l) {
return s;
}
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,
@ -3762,38 +3784,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;
@ -4288,7 +4310,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");
@ -4821,7 +4843,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);
@ -4843,7 +4865,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)
@ -4883,7 +4905,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)
@ -4928,6 +4950,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)
@ -4950,8 +4975,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);
@ -4983,6 +5008,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;
@ -5001,15 +5035,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)
@ -5023,6 +5075,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;
@ -5698,7 +5754,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;
@ -5711,13 +5767,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
@ -5729,32 +5791,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;
@ -5765,8 +5840,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;
@ -5804,29 +5879,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;
@ -5849,24 +5924,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;
@ -5874,26 +5952,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);
@ -5904,7 +5983,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;
@ -5930,7 +6009,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;
@ -6012,7 +6091,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;
@ -6029,7 +6108,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;
@ -6045,7 +6124,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);
@ -6053,6 +6132,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;
@ -6511,6 +6593,32 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
return 0;
}
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;
}
char *shell_maybe_quote(const char *s) {
const char *p;
char *r, *t;
@ -6537,13 +6645,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;

View file

@ -83,7 +83,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);
@ -149,12 +149,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);
@ -363,6 +369,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))
@ -394,8 +403,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);
@ -471,7 +478,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);
@ -510,7 +517,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);
@ -563,6 +573,7 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
void *arg);
#define _(String) gettext (String)
#define N_(String) String
void init_gettext(void);
bool is_locale_utf8(void);
@ -803,8 +814,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);
int getpeercred(int fd, struct ucred *ucred);
int getpeersec(int fd, char **ret);
@ -854,20 +865,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);
@ -917,6 +925,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);

View file

@ -66,7 +66,7 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i
const char *name = NULL;
uint64_t id;
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)];

View file

@ -45,10 +45,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,

View file

@ -25,7 +25,6 @@
#include <stdint.h>
#include <linux/if_packet.h>
#include "refcnt.h"
#include "util.h"
#include "list.h"
@ -48,54 +47,62 @@ 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);
int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_lease*, sd_dhcp_lease_unref);
#define _cleanup_dhcp_lease_unref_ _cleanup_(sd_dhcp_lease_unrefp)

View file

@ -140,7 +140,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;
@ -199,7 +199,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;
@ -214,7 +214,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;
@ -228,20 +228,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;
}

View file

@ -137,6 +137,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,

View file

@ -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
@ -68,6 +68,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,

View file

@ -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
@ -24,13 +24,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;
@ -40,6 +38,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);
@ -56,6 +65,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);

View file

@ -41,8 +41,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,
@ -92,8 +91,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,

View file

@ -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
@ -26,9 +26,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
@ -317,3 +319,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;
}

View file

@ -123,7 +123,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 */
@ -133,6 +133,12 @@ enum {
/* option codes 144-65535 are unassigned */
};
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,

View file

@ -32,6 +32,7 @@
#include "conf-parser.h"
#include "condition.h"
#include "network-internal.h"
#include "sd-icmp6-nd.h"
const char *net_get_name(struct udev_device *device) {
const char *name, *field;
@ -384,6 +385,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;
@ -510,7 +525,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);
@ -526,7 +541,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);

View file

@ -67,6 +67,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 */
@ -75,5 +77,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);

View file

@ -27,7 +27,6 @@
#include <sys/ioctl.h>
#include "util.h"
#include "refcnt.h"
#include "random-util.h"
#include "async.h"
@ -41,7 +40,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;
@ -106,7 +105,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,
@ -348,7 +346,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;
}
@ -377,8 +375,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;
}
@ -1055,18 +1052,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 "
@ -1168,13 +1163,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);
}
@ -1206,7 +1205,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) {
@ -1220,7 +1219,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);
@ -1230,7 +1229,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);
@ -1676,30 +1675,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;
}
@ -1713,7 +1723,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;

File diff suppressed because it is too large Load diff

View file

@ -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
@ -27,7 +27,6 @@
#include "udev.h"
#include "udev-util.h"
#include "util.h"
#include "refcnt.h"
#include "random-util.h"
#include "network-internal.h"
@ -40,7 +39,7 @@
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
struct sd_dhcp6_client {
RefCount n_ref;
unsigned n_ref;
enum DHCP6State state;
sd_event *event;
@ -73,6 +72,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] = {
@ -112,9 +112,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;
@ -123,8 +121,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);
@ -133,9 +130,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);
@ -159,16 +158,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);
@ -202,8 +202,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;
@ -211,8 +210,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);
@ -221,8 +219,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);
@ -259,7 +256,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;
}
@ -272,6 +269,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);
@ -748,7 +750,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)
@ -770,9 +801,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;
@ -802,16 +831,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;
@ -846,8 +872,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;
@ -958,8 +983,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];
@ -1088,15 +1112,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;
@ -1152,9 +1174,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);
@ -1189,30 +1209,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);
free(client->req_opts);
free(client);
if (!client)
return NULL;
}
return client;
assert(client->n_ref >= 1);
client->n_ref--;
if (client->n_ref > 0)
return NULL;
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;
@ -1222,7 +1251,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;

View file

@ -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
@ -20,9 +22,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);
@ -173,20 +177,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;
}
@ -198,7 +403,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);

View file

@ -26,7 +26,6 @@
#include "util.h"
#include "siphash24.h"
#include "list.h"
#include "refcnt.h"
#include "random-util.h"
#include "ipv4ll-internal.h"
@ -68,7 +67,7 @@ typedef enum IPv4LLState {
} IPv4LLState;
struct sd_ipv4ll {
RefCount n_ref;
unsigned n_ref;
IPv4LLState state;
int index;
@ -464,9 +463,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;
@ -598,30 +596,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);
sd_ipv4ll_detach_event(ll);
free(ll->random_data);
free(ll->random_data_state);
free(ll);
if (!ll)
return NULL;
}
return ll;
assert(ll->n_ref >= 1);
ll->n_ref--;
if (ll->n_ref > 0)
return ll;
ll->receive_message = sd_event_source_unref(ll->receive_message);
ll->fd = safe_close(ll->fd);
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);
@ -636,7 +643,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;

View file

@ -308,14 +308,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;
@ -328,6 +328,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;
}
@ -341,27 +349,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;
}

View file

@ -35,9 +35,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;

View file

@ -34,6 +34,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);
@ -44,13 +47,9 @@ 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_save(sd_dhcp_lease *lease, const char *lease_file);
int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
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);
#endif

View file

@ -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
@ -33,6 +33,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);

View file

@ -0,0 +1,79 @@
/*-*- 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 <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