diff --git a/LICENSE b/LICENSE
index 4ed3bd8..5f133a2 100644
--- a/LICENSE
+++ b/LICENSE
@@ -139,3 +139,28 @@ If you got Tor as a static binary with OpenSSL included, then you should know:
  "This product includes software developed by the OpenSSL Project
  for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 ===============================================================================
+src/ext/sd-daemon.c and src/ext/sd-daemon.h are licensed under the following
+license:
+
+  Copyright 2010 Lennart Poettering
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+===============================================================================
diff --git a/src/common/compat.c b/src/common/compat.c
index c97a454..aec7bc5 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1094,6 +1094,16 @@ tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
   return s;
 }
 
+/** Register socket from an external source, not created via socket() or
+ * accept()
+ */
+void
+tor_adopt_socket(tor_socket_t sockfd)
+{
+  assert(SOCKET_OK(sockfd));
+  ++n_sockets_open;
+}
+
 /** Return the number of sockets we currently have opened. */
 int
 get_n_open_sockets(void)
diff --git a/src/common/compat.h b/src/common/compat.h
index f0a34aa..1132375 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -447,6 +447,7 @@ int tor_close_socket(tor_socket_t s);
 tor_socket_t tor_open_socket(int domain, int type, int protocol);
 tor_socket_t tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr,
                                   socklen_t *len);
+void tor_adopt_socket(tor_socket_t sockfd);
 int get_n_open_sockets(void);
 
 #define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags)
diff --git a/src/ext/README b/src/ext/README
index 58ba7f6..b26a035 100644
--- a/src/ext/README
+++ b/src/ext/README
@@ -42,3 +42,7 @@ curve25519_donna/*.c
 
     A copy of Adam Langley's curve25519-donna mostly-portable
     implementations of curve25519.
+
+sd-daemon.[ch]
+
+    Helpers for systemd socket activation support on Linux.
diff --git a/src/ext/include.am b/src/ext/include.am
index ea7e58e..417e20b 100644
--- a/src/ext/include.am
+++ b/src/ext/include.am
@@ -10,7 +10,8 @@ EXTHEADERS = \
   src/ext/strlcat.c	\
   src/ext/strlcpy.c	\
   src/ext/tinytest_macros.h \
-  src/ext/tor_queue.h
+  src/ext/tor_queue.h	\
+  src/ext/sd-daemon.h
 
 noinst_HEADERS+= $(EXTHEADERS)
 
diff --git a/src/ext/sd-daemon.c b/src/ext/sd-daemon.c
new file mode 100644
index 0000000..485b301
--- /dev/null
+++ b/src/ext/sd-daemon.c
@@ -0,0 +1,520 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  Copyright 2010 Lennart Poettering
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+***/
+
+#ifndef _GNU_SOURCE
+#  define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <limits.h>
+
+#if defined(__linux__) && !defined(SD_DAEMON_DISABLE_MQ)
+#  include <mqueue.h>
+#endif
+
+#include "sd-daemon.h"
+
+#if (__GNUC__ >= 4)
+#  ifdef SD_EXPORT_SYMBOLS
+/* Export symbols */
+#    define _sd_export_ __attribute__ ((visibility("default")))
+#  else
+/* Don't export the symbols */
+#    define _sd_export_ __attribute__ ((visibility("hidden")))
+#  endif
+#else
+#  define _sd_export_
+#endif
+
+_sd_export_ int sd_listen_fds(int unset_environment) {
+
+#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
+        return 0;
+#else
+        int r, fd;
+        const char *e;
+        char *p = NULL;
+        unsigned long l;
+
+        e = getenv("LISTEN_PID");
+        if (!e) {
+                r = 0;
+                goto finish;
+        }
+
+        errno = 0;
+        l = strtoul(e, &p, 10);
+
+        if (errno > 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (!p || p == e || *p || l <= 0) {
+                r = -EINVAL;
+                goto finish;
+        }
+
+        /* Is this for us? */
+        if (getpid() != (pid_t) l) {
+                r = 0;
+                goto finish;
+        }
+
+        e = getenv("LISTEN_FDS");
+        if (!e) {
+                r = 0;
+                goto finish;
+        }
+
+        errno = 0;
+        l = strtoul(e, &p, 10);
+
+        if (errno > 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (!p || p == e || *p) {
+                r = -EINVAL;
+                goto finish;
+        }
+
+        for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
+                int flags;
+
+                flags = fcntl(fd, F_GETFD);
+                if (flags < 0) {
+                        r = -errno;
+                        goto finish;
+                }
+
+                if (flags & FD_CLOEXEC)
+                        continue;
+
+                if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
+                        r = -errno;
+                        goto finish;
+                }
+        }
+
+        r = (int) l;
+
+finish:
+        if (unset_environment) {
+                unsetenv("LISTEN_PID");
+                unsetenv("LISTEN_FDS");
+        }
+
+        return r;
+#endif
+}
+
+_sd_export_ int sd_is_fifo(int fd, const char *path) {
+        struct stat st_fd;
+
+        if (fd < 0)
+                return -EINVAL;
+
+        if (fstat(fd, &st_fd) < 0)
+                return -errno;
+
+        if (!S_ISFIFO(st_fd.st_mode))
+                return 0;
+
+        if (path) {
+                struct stat st_path;
+
+                if (stat(path, &st_path) < 0) {
+
+                        if (errno == ENOENT || errno == ENOTDIR)
+                                return 0;
+
+                        return -errno;
+                }
+
+                return
+                        st_path.st_dev == st_fd.st_dev &&
+                        st_path.st_ino == st_fd.st_ino;
+        }
+
+        return 1;
+}
+
+_sd_export_ int sd_is_special(int fd, const char *path) {
+        struct stat st_fd;
+
+        if (fd < 0)
+                return -EINVAL;
+
+        if (fstat(fd, &st_fd) < 0)
+                return -errno;
+
+        if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
+                return 0;
+
+        if (path) {
+                struct stat st_path;
+
+                if (stat(path, &st_path) < 0) {
+
+                        if (errno == ENOENT || errno == ENOTDIR)
+                                return 0;
+
+                        return -errno;
+                }
+
+                if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
+                        return
+                                st_path.st_dev == st_fd.st_dev &&
+                                st_path.st_ino == st_fd.st_ino;
+                else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
+                        return st_path.st_rdev == st_fd.st_rdev;
+                else
+                        return 0;
+        }
+
+        return 1;
+}
+
+static int sd_is_socket_internal(int fd, int type, int listening) {
+        struct stat st_fd;
+
+        if (fd < 0 || type < 0)
+                return -EINVAL;
+
+        if (fstat(fd, &st_fd) < 0)
+                return -errno;
+
+        if (!S_ISSOCK(st_fd.st_mode))
+                return 0;
+
+        if (type != 0) {
+                int other_type = 0;
+                socklen_t l = sizeof(other_type);
+
+                if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
+                        return -errno;
+
+                if (l != sizeof(other_type))
+                        return -EINVAL;
+
+                if (other_type != type)
+                        return 0;
+        }
+
+        if (listening >= 0) {
+                int accepting = 0;
+                socklen_t l = sizeof(accepting);
+
+                if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
+                        return -errno;
+
+                if (l != sizeof(accepting))
+                        return -EINVAL;
+
+                if (!accepting != !listening)
+                        return 0;
+        }
+
+        return 1;
+}
+
+union sockaddr_union {
+        struct sockaddr sa;
+        struct sockaddr_in in4;
+        struct sockaddr_in6 in6;
+        struct sockaddr_un un;
+        struct sockaddr_storage storage;
+};
+
+_sd_export_ int sd_is_socket(int fd, int family, int type, int listening) {
+        int r;
+
+        if (family < 0)
+                return -EINVAL;
+
+        r = sd_is_socket_internal(fd, type, listening);
+        if (r <= 0)
+                return r;
+
+        if (family > 0) {
+                union sockaddr_union sockaddr = {};
+                socklen_t l = sizeof(sockaddr);
+
+                if (getsockname(fd, &sockaddr.sa, &l) < 0)
+                        return -errno;
+
+                if (l < sizeof(sa_family_t))
+                        return -EINVAL;
+
+                return sockaddr.sa.sa_family == family;
+        }
+
+        return 1;
+}
+
+_sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
+        union sockaddr_union sockaddr = {};
+        socklen_t l = sizeof(sockaddr);
+        int r;
+
+        if (family != 0 && family != AF_INET && family != AF_INET6)
+                return -EINVAL;
+
+        r = sd_is_socket_internal(fd, type, listening);
+        if (r <= 0)
+                return r;
+
+        if (getsockname(fd, &sockaddr.sa, &l) < 0)
+                return -errno;
+
+        if (l < sizeof(sa_family_t))
+                return -EINVAL;
+
+        if (sockaddr.sa.sa_family != AF_INET &&
+            sockaddr.sa.sa_family != AF_INET6)
+                return 0;
+
+        if (family > 0)
+                if (sockaddr.sa.sa_family != family)
+                        return 0;
+
+        if (port > 0) {
+                if (sockaddr.sa.sa_family == AF_INET) {
+                        if (l < sizeof(struct sockaddr_in))
+                                return -EINVAL;
+
+                        return htons(port) == sockaddr.in4.sin_port;
+                } else {
+                        if (l < sizeof(struct sockaddr_in6))
+                                return -EINVAL;
+
+                        return htons(port) == sockaddr.in6.sin6_port;
+                }
+        }
+
+        return 1;
+}
+
+_sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
+        union sockaddr_union sockaddr = {};
+        socklen_t l = sizeof(sockaddr);
+        int r;
+
+        r = sd_is_socket_internal(fd, type, listening);
+        if (r <= 0)
+                return r;
+
+        if (getsockname(fd, &sockaddr.sa, &l) < 0)
+                return -errno;
+
+        if (l < sizeof(sa_family_t))
+                return -EINVAL;
+
+        if (sockaddr.sa.sa_family != AF_UNIX)
+                return 0;
+
+        if (path) {
+                if (length == 0)
+                        length = strlen(path);
+
+                if (length == 0)
+                        /* Unnamed socket */
+                        return l == offsetof(struct sockaddr_un, sun_path);
+
+                if (path[0])
+                        /* Normal path socket */
+                        return
+                                (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
+                                memcmp(path, sockaddr.un.sun_path, length+1) == 0;
+                else
+                        /* Abstract namespace socket */
+                        return
+                                (l == offsetof(struct sockaddr_un, sun_path) + length) &&
+                                memcmp(path, sockaddr.un.sun_path, length) == 0;
+        }
+
+        return 1;
+}
+
+_sd_export_ int sd_is_mq(int fd, const char *path) {
+#if !defined(__linux__) || defined(SD_DAEMON_DISABLE_MQ)
+        return 0;
+#else
+        struct mq_attr attr;
+
+        if (fd < 0)
+                return -EINVAL;
+
+        if (mq_getattr(fd, &attr) < 0)
+                return -errno;
+
+        if (path) {
+                char fpath[PATH_MAX];
+                struct stat a, b;
+
+                if (path[0] != '/')
+                        return -EINVAL;
+
+                if (fstat(fd, &a) < 0)
+                        return -errno;
+
+                strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
+                fpath[sizeof(fpath)-1] = 0;
+
+                if (stat(fpath, &b) < 0)
+                        return -errno;
+
+                if (a.st_dev != b.st_dev ||
+                    a.st_ino != b.st_ino)
+                        return 0;
+        }
+
+        return 1;
+#endif
+}
+
+_sd_export_ int sd_notify(int unset_environment, const char *state) {
+#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
+        return 0;
+#else
+        int fd = -1, r;
+        struct msghdr msghdr;
+        struct iovec iovec;
+        union sockaddr_union sockaddr;
+        const char *e;
+
+        if (!state) {
+                r = -EINVAL;
+                goto finish;
+        }
+
+        e = getenv("NOTIFY_SOCKET");
+        if (!e)
+                return 0;
+
+        /* Must be an abstract socket, or an absolute path */
+        if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
+                r = -EINVAL;
+                goto finish;
+        }
+
+        fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+        if (fd < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        memset(&sockaddr, 0, sizeof(sockaddr));
+        sockaddr.sa.sa_family = AF_UNIX;
+        strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
+
+        if (sockaddr.un.sun_path[0] == '@')
+                sockaddr.un.sun_path[0] = 0;
+
+        memset(&iovec, 0, sizeof(iovec));
+        iovec.iov_base = (char*) state;
+        iovec.iov_len = strlen(state);
+
+        memset(&msghdr, 0, sizeof(msghdr));
+        msghdr.msg_name = &sockaddr;
+        msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
+
+        if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
+                msghdr.msg_namelen = sizeof(struct sockaddr_un);
+
+        msghdr.msg_iov = &iovec;
+        msghdr.msg_iovlen = 1;
+
+        if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        r = 1;
+
+finish:
+        if (unset_environment)
+                unsetenv("NOTIFY_SOCKET");
+
+        if (fd >= 0)
+                close(fd);
+
+        return r;
+#endif
+}
+
+_sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) {
+#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
+        return 0;
+#else
+        va_list ap;
+        char *p = NULL;
+        int r;
+
+        va_start(ap, format);
+        r = vasprintf(&p, format, ap);
+        va_end(ap);
+
+        if (r < 0 || !p)
+                return -ENOMEM;
+
+        r = sd_notify(unset_environment, p);
+        free(p);
+
+        return r;
+#endif
+}
+
+_sd_export_ int sd_booted(void) {
+#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
+        return 0;
+#else
+        struct stat st;
+
+        /* We test whether the runtime unit file directory has been
+         * created. This takes place in mount-setup.c, so is
+         * guaranteed to happen very early during boot. */
+
+        if (lstat("/run/systemd/system/", &st) < 0)
+                return 0;
+
+        return !!S_ISDIR(st.st_mode);
+#endif
+}
diff --git a/src/ext/sd-daemon.h b/src/ext/sd-daemon.h
new file mode 100644
index 0000000..a6cdc45
--- /dev/null
+++ b/src/ext/sd-daemon.h
@@ -0,0 +1,284 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foosddaemonhfoo
+#define foosddaemonhfoo
+
+#define SD_DAEMON_DISABLE_MQ 1
+
+/***
+  Copyright 2010 Lennart Poettering
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+***/
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+  Reference implementation of a few systemd related interfaces for
+  writing daemons. These interfaces are trivial to implement. To
+  simplify porting we provide this reference implementation.
+  Applications are welcome to reimplement the algorithms described
+  here if they do not want to include these two source files.
+
+  The following functionality is provided:
+
+  - Support for logging with log levels on stderr
+  - File descriptor passing for socket-based activation
+  - Daemon startup and status notification
+  - Detection of systemd boots
+
+  You may compile this with -DDISABLE_SYSTEMD to disable systemd
+  support. This makes all those calls NOPs that are directly related to
+  systemd (i.e. only sd_is_xxx() will stay useful).
+
+  Since this is drop-in code we don't want any of our symbols to be
+  exported in any case. Hence we declare hidden visibility for all of
+  them.
+
+  You may find an up-to-date version of these source files online:
+
+  http://cgit.freedesktop.org/systemd/systemd/plain/src/systemd/sd-daemon.h
+  http://cgit.freedesktop.org/systemd/systemd/plain/src/libsystemd-daemon/sd-daemon.c
+
+  This should compile on non-Linux systems, too, but with the
+  exception of the sd_is_xxx() calls all functions will become NOPs.
+
+  See sd-daemon(3) for more information.
+*/
+
+#ifndef _sd_printf_attr_
+#  if __GNUC__ >= 4
+#    define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b)))
+#  else
+#    define _sd_printf_attr_(a,b)
+#  endif
+#endif
+
+/*
+  Log levels for usage on stderr:
+
+          fprintf(stderr, SD_NOTICE "Hello World!\n");
+
+  This is similar to printk() usage in the kernel.
+*/
+#define SD_EMERG   "<0>"  /* system is unusable */
+#define SD_ALERT   "<1>"  /* action must be taken immediately */
+#define SD_CRIT    "<2>"  /* critical conditions */
+#define SD_ERR     "<3>"  /* error conditions */
+#define SD_WARNING "<4>"  /* warning conditions */
+#define SD_NOTICE  "<5>"  /* normal but significant condition */
+#define SD_INFO    "<6>"  /* informational */
+#define SD_DEBUG   "<7>"  /* debug-level messages */
+
+/* The first passed file descriptor is fd 3 */
+#define SD_LISTEN_FDS_START 3
+
+/*
+  Returns how many file descriptors have been passed, or a negative
+  errno code on failure. Optionally, removes the $LISTEN_FDS and
+  $LISTEN_PID file descriptors from the environment (recommended, but
+  problematic in threaded environments). If r is the return value of
+  this function you'll find the file descriptors passed as fds
+  SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative
+  errno style error code on failure. This function call ensures that
+  the FD_CLOEXEC flag is set for the passed file descriptors, to make
+  sure they are not passed on to child processes. If FD_CLOEXEC shall
+  not be set, the caller needs to unset it after this call for all file
+  descriptors that are used.
+
+  See sd_listen_fds(3) for more information.
+*/
+int sd_listen_fds(int unset_environment);
+
+/*
+  Helper call for identifying a passed file descriptor. Returns 1 if
+  the file descriptor is a FIFO in the file system stored under the
+  specified path, 0 otherwise. If path is NULL a path name check will
+  not be done and the call only verifies if the file descriptor
+  refers to a FIFO. Returns a negative errno style error code on
+  failure.
+
+  See sd_is_fifo(3) for more information.
+*/
+int sd_is_fifo(int fd, const char *path);
+
+/*
+  Helper call for identifying a passed file descriptor. Returns 1 if
+  the file descriptor is a special character device on the file
+  system stored under the specified path, 0 otherwise.
+  If path is NULL a path name check will not be done and the call
+  only verifies if the file descriptor refers to a special character.
+  Returns a negative errno style error code on failure.
+
+  See sd_is_special(3) for more information.
+*/
+int sd_is_special(int fd, const char *path);
+
+/*
+  Helper call for identifying a passed file descriptor. Returns 1 if
+  the file descriptor is a socket of the specified family (AF_INET,
+  ...) and type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If
+  family is 0 a socket family check will not be done. If type is 0 a
+  socket type check will not be done and the call only verifies if
+  the file descriptor refers to a socket. If listening is > 0 it is
+  verified that the socket is in listening mode. (i.e. listen() has
+  been called) If listening is == 0 it is verified that the socket is
+  not in listening mode. If listening is < 0 no listening mode check
+  is done. Returns a negative errno style error code on failure.
+
+  See sd_is_socket(3) for more information.
+*/
+int sd_is_socket(int fd, int family, int type, int listening);
+
+/*
+  Helper call for identifying a passed file descriptor. Returns 1 if
+  the file descriptor is an Internet socket, of the specified family
+  (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM,
+  SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version
+  check is not done. If type is 0 a socket type check will not be
+  done. If port is 0 a socket port check will not be done. The
+  listening flag is used the same way as in sd_is_socket(). Returns a
+  negative errno style error code on failure.
+
+  See sd_is_socket_inet(3) for more information.
+*/
+int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port);
+
+/*
+  Helper call for identifying a passed file descriptor. Returns 1 if
+  the file descriptor is an AF_UNIX socket of the specified type
+  (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0
+  a socket type check will not be done. If path is NULL a socket path
+  check will not be done. For normal AF_UNIX sockets set length to
+  0. For abstract namespace sockets set length to the length of the
+  socket name (including the initial 0 byte), and pass the full
+  socket path in path (including the initial 0 byte). The listening
+  flag is used the same way as in sd_is_socket(). Returns a negative
+  errno style error code on failure.
+
+  See sd_is_socket_unix(3) for more information.
+*/
+int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length);
+
+/*
+  Helper call for identifying a passed file descriptor. Returns 1 if
+  the file descriptor is a POSIX Message Queue of the specified name,
+  0 otherwise. If path is NULL a message queue name check is not
+  done. Returns a negative errno style error code on failure.
+*/
+int sd_is_mq(int fd, const char *path);
+
+/*
+  Informs systemd about changed daemon state. This takes a number of
+  newline separated environment-style variable assignments in a
+  string. The following variables are known:
+
+     READY=1      Tells systemd that daemon startup is finished (only
+                  relevant for services of Type=notify). The passed
+                  argument is a boolean "1" or "0". Since there is
+                  little value in signaling non-readiness the only
+                  value daemons should send is "READY=1".
+
+     STATUS=...   Passes a single-line status string back to systemd
+                  that describes the daemon state. This is free-from
+                  and can be used for various purposes: general state
+                  feedback, fsck-like programs could pass completion
+                  percentages and failing programs could pass a human
+                  readable error message. Example: "STATUS=Completed
+                  66% of file system check..."
+
+     ERRNO=...    If a daemon fails, the errno-style error code,
+                  formatted as string. Example: "ERRNO=2" for ENOENT.
+
+     BUSERROR=... If a daemon fails, the D-Bus error-style error
+                  code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut"
+
+     MAINPID=...  The main pid of a daemon, in case systemd did not
+                  fork off the process itself. Example: "MAINPID=4711"
+
+     WATCHDOG=1   Tells systemd to update the watchdog timestamp.
+                  Services using this feature should do this in
+                  regular intervals. A watchdog framework can use the
+                  timestamps to detect failed services.
+
+  Daemons can choose to send additional variables. However, it is
+  recommended to prefix variable names not listed above with X_.
+
+  Returns a negative errno-style error code on failure. Returns > 0
+  if systemd could be notified, 0 if it couldn't possibly because
+  systemd is not running.
+
+  Example: When a daemon finished starting up, it could issue this
+  call to notify systemd about it:
+
+     sd_notify(0, "READY=1");
+
+  See sd_notifyf() for more complete examples.
+
+  See sd_notify(3) for more information.
+*/
+int sd_notify(int unset_environment, const char *state);
+
+/*
+  Similar to sd_notify() but takes a format string.
+
+  Example 1: A daemon could send the following after initialization:
+
+     sd_notifyf(0, "READY=1\n"
+                   "STATUS=Processing requests...\n"
+                   "MAINPID=%lu",
+                   (unsigned long) getpid());
+
+  Example 2: A daemon could send the following shortly before
+  exiting, on failure:
+
+     sd_notifyf(0, "STATUS=Failed to start up: %s\n"
+                   "ERRNO=%i",
+                   strerror(errno),
+                   errno);
+
+  See sd_notifyf(3) for more information.
+*/
+int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_(2,3);
+
+/*
+  Returns > 0 if the system was booted with systemd. Returns < 0 on
+  error. Returns 0 if the system was not booted with systemd. Note
+  that all of the functions above handle non-systemd boots just
+  fine. You should NOT protect them with a call to this function. Also
+  note that this function checks whether the system, not the user
+  session is controlled by systemd. However the functions above work
+  for both user and system services.
+
+  See sd_booted(3) for more information.
+*/
+int sd_booted(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/or/connection.c b/src/or/connection.c
index 87fa799..6db5763 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -45,6 +45,7 @@
 #include "transports.h"
 #include "routerparse.h"
 #include "transports.h"
+#include "sd-daemon.h"
 
 #ifdef USE_BUFFEREVENTS
 #include <event2/event.h>
@@ -95,6 +96,8 @@ static tor_addr_t *last_interface_ipv6 = NULL;
 /** A list of tor_addr_t for addresses we've used in outgoing connections.
  * Used to detect IP address changes. */
 static smartlist_t *outgoing_addrs = NULL;
+/** Sockets (file descriptors) passed to us from parent process. */
+static smartlist_t *pending_sockets = NULL;
 
 #define CASE_ANY_LISTENER_TYPE \
     case CONN_TYPE_OR_LISTENER: \
@@ -360,6 +363,14 @@ connection_new(int type, int socket_family)
   }
 }
 
+pending_socket_t *
+pending_socket_new(tor_socket_t sockfd)
+{
+  pending_socket_t *sock = tor_malloc_zero(sizeof(pending_socket_t));
+  sock->fd = sockfd;
+  return sock;
+}
+
 /** Initializes conn. (you must call connection_add() to link it into the main
  * array).
  *
@@ -927,6 +938,142 @@ make_socket_reuseable(tor_socket_t sock)
 #endif
 }
 
+/** Adopt socket from a file descriptor passed by systemd */
+static pending_socket_t *
+systemd_adopt_socket(tor_socket_t fd)
+{
+  pending_socket_t *pend = NULL;
+  socklen_t len;
+  int type = 0;
+  int listening = 0;
+  struct sockaddr_storage addrbuf;
+
+  tor_adopt_socket(fd);
+
+  /* Figure out socket type (SOCK_STREAM/SOCK_DGRAM) */
+  len = sizeof(type);
+  if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
+    goto err_errno;
+  if (len != sizeof(type) || (type != SOCK_STREAM && type != SOCK_DGRAM))
+  {
+    log_err(LD_NET, "systemd socket %d has unknown type (%d)", fd, type);
+    goto err;
+  }
+
+  /* If it's a stream socket, make sure it's listening */
+  if (type == SOCK_STREAM)
+  {
+    len = sizeof(listening);
+    if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &listening, &len) < 0)
+      goto err_errno;
+    if (len != sizeof(listening) || listening != 1)
+    {
+      log_err(LD_NET, "systemd socket %d is not listening", fd);
+      goto err;
+    }
+  }
+
+  /* Get the bound address and port */
+  len = sizeof(addrbuf);
+  memset(&addrbuf, 0, sizeof(addrbuf));
+
+  if (getsockname(fd, (struct sockaddr*)&addrbuf, &len) < 0)
+    goto err_errno;
+  if (len < sizeof(sa_family_t))
+  {
+    log_err(LD_NET, "Cannot determine address of systemd socket %d", fd);
+    goto err;
+  }
+
+  /* All OK, add to pending list */
+  pend = pending_socket_new(fd);
+  pend->type = type;
+  tor_addr_from_sockaddr(&pend->addr, (struct sockaddr*)&addrbuf, &pend->port);
+
+  return pend;
+
+err_errno:
+  log_err(LD_NET, "Error adopting systemd socket %d: %s", fd, strerror(errno));
+err:
+  if (pend)
+    tor_free(pend);
+  tor_close_socket(fd);
+  return NULL;
+}
+
+/** Discover sockets passed in from systemd (when started via socket activation)
+ *
+ * systemd passes us sockets in arbitrary order. Here we just dump them to a
+ * list. Later on, after loading the configuration, we try to match up these
+ * sockets to configured ports.
+ *
+ * Sockets that didn't match will be closed and warnings issued later.
+ */
+void
+systemd_discover_sockets(void)
+{
+  tor_socket_t fd;
+  pending_socket_t *pend;
+  int n_sock = sd_listen_fds(1);
+
+  if (!pending_sockets)
+    pending_sockets = smartlist_new();
+
+  for (fd = SD_LISTEN_FDS_START; fd < (SD_LISTEN_FDS_START + n_sock); fd++)
+  {
+    pend = systemd_adopt_socket(fd);
+
+    if (pend)
+      smartlist_add(pending_sockets, pend);
+  }
+}
+
+/** Close sockets passed in from systemd that didn't match any configured
+ * ports and log warnings.
+ */
+int
+systemd_finish_sockets(void)
+{
+  SMARTLIST_FOREACH_BEGIN(pending_sockets, pending_socket_t *, sock) {
+    log_warn(LD_NET, "Closing unmatched socket %s. "
+             "Your Tor configuration does not match the systemd unit.",
+             fmt_addrport(&sock->addr, sock->port));
+
+    tor_close_socket(sock->fd);
+    SMARTLIST_DEL_CURRENT(pending_sockets, sock);
+  }
+  SMARTLIST_FOREACH_END(sock);
+
+  return 0;
+}
+
+/** Find the socket with a given port number from the sockets passed by
+ * systemd. Returns file descriptor and removes from pending list when found,
+ * -1 when not found.
+ */
+static tor_socket_t
+get_pending_socket(int conntype, int socktype, tor_addr_t *listen_addr, uint16_t port)
+{
+  tor_socket_t fd;
+
+  SMARTLIST_FOREACH_BEGIN(pending_sockets, pending_socket_t *, sock) {
+    if (sock->type != socktype || sock->port != port)
+      continue;
+
+    if (tor_addr_compare(listen_addr, &sock->addr, CMP_EXACT) == 0) {
+      SMARTLIST_DEL_CURRENT(pending_sockets, sock);
+      log_notice(LD_NET, "Matched systemd socket for %s on %s",
+                 conn_type_to_string(conntype),
+                 fmt_addrport(&sock->addr, sock->port));
+      fd = sock->fd;
+      tor_free(sock);
+      return fd;
+    }
+  }
+  SMARTLIST_FOREACH_END(sock);
+  return -1;
+}
+
 /** Bind a new non-blocking socket listening to the socket described
  * by <b>listensockaddr</b>.
  *
@@ -959,21 +1106,29 @@ connection_listener_new(const struct sockaddr *listensockaddr,
   if (listensockaddr->sa_family == AF_INET ||
       listensockaddr->sa_family == AF_INET6) {
     int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
+    int is_bound = 0;
+    int socktype = is_tcp ? SOCK_STREAM : SOCK_DGRAM;
     if (is_tcp)
       start_reading = 1;
 
     tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
 
-    log_notice(LD_NET, "Opening %s on %s",
-               conn_type_to_string(type), fmt_addrport(&addr, usePort));
-
-    s = tor_open_socket(tor_addr_family(&addr),
-                        is_tcp ? SOCK_STREAM : SOCK_DGRAM,
-                        is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
-    if (!SOCKET_OK(s)) {
-      log_warn(LD_NET,"Socket creation failed: %s",
-               tor_socket_strerror(tor_socket_errno(-1)));
-      goto err;
+    s = get_pending_socket(type, socktype, &addr, usePort);
+    if (SOCKET_OK(s))
+    {
+      is_bound = 1;
+    }
+    else
+    {
+      log_notice(LD_NET, "Opening %s on %s",
+                 conn_type_to_string(type), fmt_addrport(&addr, usePort));
+
+      s = tor_open_socket(tor_addr_family(&addr), socktype, is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
+      if (!SOCKET_OK(s)) {
+        log_warn(LD_NET,"Socket creation failed: %s",
+                 tor_socket_strerror(tor_socket_errno(-1)));
+        goto err;
+      }
     }
 
     make_socket_reuseable(s);
@@ -998,24 +1153,27 @@ connection_listener_new(const struct sockaddr *listensockaddr,
     }
 #endif
 
-    if (bind(s,listensockaddr,socklen) < 0) {
-      const char *helpfulhint = "";
-      int e = tor_socket_errno(s);
-      if (ERRNO_IS_EADDRINUSE(e))
-        helpfulhint = ". Is Tor already running?";
-      log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort,
-               tor_socket_strerror(e), helpfulhint);
-      tor_close_socket(s);
-      goto err;
-    }
-
-    if (is_tcp) {
-      if (listen(s,SOMAXCONN) < 0) {
-        log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
-                 tor_socket_strerror(tor_socket_errno(s)));
+    if (!is_bound)
+    {
+      if (bind(s,listensockaddr,socklen) < 0) {
+        const char *helpfulhint = "";
+        int e = tor_socket_errno(s);
+        if (ERRNO_IS_EADDRINUSE(e))
+          helpfulhint = ". Is Tor already running?";
+        log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort,
+                 tor_socket_strerror(e), helpfulhint);
         tor_close_socket(s);
         goto err;
       }
+
+      if (is_tcp) {
+        if (listen(s,SOMAXCONN) < 0) {
+          log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
+                   tor_socket_strerror(tor_socket_errno(s)));
+          tor_close_socket(s);
+          goto err;
+        }
+      }
     }
 
     if (usePort != 0) {
diff --git a/src/or/connection.h b/src/or/connection.h
index 3e656ec..9813dbd 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -15,6 +15,18 @@
 /* XXXX For buf_datalen in inline function */
 #include "buffers.h"
 
+/** Temporary container object for pending sockets passed in from parent
+ * process, before given sockets are associated with a connection_t.
+ */
+typedef struct pending_socket_t {
+  tor_socket_t fd;
+  int type; /* SOCK_STREAM, SOCK_DGRAM */
+  tor_addr_t addr;
+  uint16_t port;
+
+} pending_socket_t;
+
+
 const char *conn_type_to_string(int type);
 const char *conn_state_to_string(int type, int state);
 
@@ -25,6 +37,7 @@ entry_connection_t *entry_connection_new(int type, int socket_family);
 control_connection_t *control_connection_new(int socket_family);
 listener_connection_t *listener_connection_new(int type, int socket_family);
 connection_t *connection_new(int type, int socket_family);
+pending_socket_t *pending_socket_new(tor_socket_t fd);
 
 void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
 void connection_free(connection_t *conn);
@@ -103,6 +116,9 @@ void log_failed_proxy_connection(connection_t *conn);
 int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
                        const connection_t *conn);
 
+void systemd_discover_sockets(void);
+int systemd_finish_sockets(void);
+
 int retry_all_listeners(smartlist_t *replaced_conns,
                         smartlist_t *new_conns,
                         int close_all_noncontrol);
diff --git a/src/or/include.am b/src/or/include.am
index 65dbeff..a2d081f 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -75,6 +75,7 @@ src_or_libtor_a_SOURCES = \
 	$(evdns_source)					\
 	$(tor_platform_source)				\
 	$(onion_ntor_source)				\
+	src/ext/sd-daemon.c				\
 	src/or/config_codedigest.c
 
 #libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \
diff --git a/src/or/main.c b/src/or/main.c
index fd8b6cf..8304a7c 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -2365,11 +2365,18 @@ tor_init(int argc, char *argv[])
   }
   atexit(exit_function);
 
+  systemd_discover_sockets();
+
   if (options_init_from_torrc(argc,argv) < 0) {
+    /* Prints additional warnings for non-matching sockets */
+    systemd_finish_sockets();
+
     log_err(LD_CONFIG,"Reading config failed--see warnings above.");
     return -1;
   }
 
+  systemd_finish_sockets();
+
 #ifndef _WIN32
   if (geteuid()==0)
     log_warn(LD_GENERAL,"You are running Tor as root. You don't need to, "
