diff --git a/contrib/c/sockettrap.c b/contrib/c/sockettrap.c
new file mode 100644
index 000000000..e84c1c9ef
--- /dev/null
+++ b/contrib/c/sockettrap.c
@@ -0,0 +1,103 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "util/Hex.h"
+#include "memory/Allocator.h"
+#include "memory/MallocAllocator.h"
+#include "crypto/random/Random.h"
+#include "io/FileReader.h"
+#include "io/FileWriter.h"
+#include "util/CString.h"
+#include "util/Assert.h"
+#include "util/log/Log.h"
+#include "util/log/FileWriterLog.h"
+#include "util/events/Time.h"
+#include "util/events/EventBase.h"
+#include "util/events/Pipe.h"
+#include "util/events/Process.h"
+#include "admin/angel/InterfaceWaiter.h"
+
+static void onCoreExit(int64_t exit_status, int term_signal)
+{
+ Assert_failure("Core exited with status [%d], signal [%d]\n", (int)exit_status, term_signal);
+}
+
+/**
+ * Usage:
+ * pass an absolute path to cjdroute executable as an argument
+ * and this program will act as inetd boostrap,
+ * capturing data comming from STDIN and passing it as inital core config
+ * of cjdroute core and sending response on STDOUT.
+ **/
+
+int main(int argc, char** argv)
+{
+ if (argc != 2) {
+ exit(EX_USAGE);
+ }
+ char* corePath = argv[1];
+
+ struct Except* eh = NULL;
+
+ // Allow it to allocate 1MB
+ struct Allocator* allocator = MallocAllocator_new(1<<20);
+ struct Log* logger = NULL; // We don't want messages from the trap.
+ struct Random* rand = Random_new(allocator, logger, eh);
+ struct EventBase* eventBase = EventBase_new(allocator);
+
+ struct Writer* stdoutWriter = FileWriter_new(stdout, allocator);
+
+ struct Allocator* corePipeAlloc = Allocator_child(allocator);
+ char corePipeName[64] = "client-core-";
+ Random_base32(rand, (uint8_t*)corePipeName+CString_strlen(corePipeName), 31);
+ Assert_ifParanoid(EventBase_eventCount(eventBase) == 0);
+ struct Pipe* corePipe = Pipe_named(corePipeName, eventBase, eh, corePipeAlloc);
+ corePipe->logger = logger;
+ Assert_ifParanoid(EventBase_eventCount(eventBase) == 2);
+
+ struct Message* toCoreMsg = Message_new(0, 1024, allocator);
+ unsigned char buff[1024] = { 0 };
+ int len;
+ do {
+ len = read(STDIN_FILENO, buff, 1024);
+ if (len <= 0 && errno != EAGAIN) {
+ fprintf(stderr, "Read returned: %d with errno %s.\n", len, strerror(errno));
+ exit(EX_NOINPUT);
+ }
+ // read will return -1 and set errno if there is nonblocking pipe.
+ } while (len == -1 && errno == EAGAIN);
+
+ Message_push(toCoreMsg, buff, len, eh);
+
+ char* args[] = { "core", corePipeName, NULL };
+
+ Process_spawn(corePath, args, eventBase, allocator, onCoreExit);
+
+
+ Iface_CALL(corePipe->iface.send, toCoreMsg, &corePipe->iface);
+
+ struct Message* fromCoreMsg =
+ InterfaceWaiter_waitForData(&corePipe->iface, eventBase, allocator, eh);
+ Writer_write(stdoutWriter, fromCoreMsg->bytes, fromCoreMsg->length);
+
+ return 0;
+}
diff --git a/contrib/systemd/README.md b/contrib/systemd/README.md
new file mode 100644
index 000000000..d168109fe
--- /dev/null
+++ b/contrib/systemd/README.md
@@ -0,0 +1,6 @@
+## How to install
+
+```bash
+mv contrib/systemd/cjdns* /usr/lib/systemd/systemd/
+mv ./sockettrap /usr/lib/systemd/scripts/cjdns-trap
+```
diff --git a/contrib/systemd/cjdns.socket b/contrib/systemd/cjdns.socket
new file mode 100644
index 000000000..f52b05583
--- /dev/null
+++ b/contrib/systemd/cjdns.socket
@@ -0,0 +1,11 @@
+[Unit]
+Description=Cjdns activation socket.
+
+[Socket]
+ListenStream=/run/cjdns/cjdns.socket
+Accept=true
+SocketMode=0600
+
+[Install]
+WantedBy=sockets.target
+
diff --git a/contrib/systemd/cjdns@.service b/contrib/systemd/cjdns@.service
new file mode 100644
index 000000000..7873a1ca9
--- /dev/null
+++ b/contrib/systemd/cjdns@.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=cjdns-multinstant: routing engine designed for security, scalability, speed and ease of use
+Wants=network.target
+After=network.target
+Requires=cjdns.socket
+
+[Service]
+ProtectHome=true
+ProtectSystem=true
+SyslogIdentifier=cjdroute
+
+Type=forking
+ExecStart=/usr/lib/systemd/scripts/cjdns-trap /usr/bin/cjdroute
+StandardInput=socket
+StandardOutput=socket
+StandardError=journal
diff --git a/node_build/make.js b/node_build/make.js
index 76eba557b..fbaa4d875 100644
--- a/node_build/make.js
+++ b/node_build/make.js
@@ -409,6 +409,10 @@ Builder.configure({
builder.buildExecutable('contrib/c/privatetopublic.c');
builder.buildExecutable('contrib/c/sybilsim.c');
builder.buildExecutable('contrib/c/makekeys.c');
+ if (builder.config.systemName !== 'win32') {
+ // Everything else is UNIX based.
+ builder.buildExecutable('contrib/c/sockettrap.c');
+ }
builder.buildExecutable('crypto/random/randombytes.c');