cjdns: import package from github.com:SeattleMeshnet/meshbox

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
Daniel Golle 2015-04-17 14:50:16 +02:00
parent 11ebefc174
commit cd765e581d
10 changed files with 806 additions and 0 deletions

100
cjdns/Makefile Normal file
View File

@ -0,0 +1,100 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=cjdns
PKG_VERSION:=0.16
PKG_RELEASE:=9
PKG_SOURCE_URL:=https://github.com/cjdelisle/cjdns.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=2138a1f6a94fc009958cde7b002c077a1eee929a
PKG_LICENSE:=GPL-3.0
PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.bz2
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_SOURCE_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_SOURCE_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/cjdns
SECTION:=net
CATEGORY:=Network
SUBMENU:=Routing and Redirection
TITLE:=Encrypted near-zero-conf mesh routing protocol
URL:=https://github.com/hyperboria/cjdns
MAINTAINER:=Lars Gierth <larsg@systemli.org>
DEPENDS:=+kmod-tun +kmod-ipv6 +libnl-tiny +libpthread +librt \
+libuci-lua +lua-bencode +dkjson +luasocket +lua-sha2
endef
define Package/cjdns/description
Cjdns implements an encrypted IPv6 network using public-key cryptography \
for address allocation and a distributed hash table for routing. \
This provides near-zero-configuration networking, and prevents many \
of the security and scalability issues that plague existing networks.
endef
define Build/Configure
endef
ifneq ($(CONFIG_KERNEL_SECCOMP_FILTER),y)
PKG_DO_VARS:=Seccomp_NO=1
endif
define Build/Compile
CROSS="true" \
CC="$(TARGET_CC)" \
CFLAGS="$(TARGET_CFLAGS)" \
LDFLAGS="$(TARGET_LDFLAGS)" \
SYSTEM="linux" \
TARGET_ARCH="$(CONFIG_ARCH)" \
UCLIBC=1 \
SSP_SUPPORT="$(CONFIG_SSP_SUPPORT)" \
$(PKG_DO_VARS) \
$(PKG_BUILD_DIR)/do
endef
define Package/cjdns/install
$(INSTALL_DIR) \
$(1)/usr/sbin \
$(1)/usr/bin \
$(1)/etc/config \
$(1)/etc/init.d \
$(1)/etc/uci-defaults \
$(1)/usr/lib/lua/cjdns
$(INSTALL_BIN) \
./files/cjdrouteconf \
$(1)/usr/bin
$(INSTALL_BIN) \
$(PKG_BUILD_DIR)/cjdroute \
$(1)/usr/sbin
$(INSTALL_BIN) \
$(PKG_BUILD_DIR)/publictoip6 \
$(1)/usr/bin
$(INSTALL_BIN) \
./files/cjdns.init \
$(1)/etc/init.d/cjdns
$(INSTALL_BIN) \
./files/cjdns.defaults \
$(1)/etc/uci-defaults/cjdns
$(CP) \
./lua/cjdns/* \
$(1)/usr/lib/lua/cjdns
endef
define Package/cjdns/postinst
#!/bin/sh
if [ -z $${IPKG_INSTROOT} ] ; then
( . /etc/uci-defaults/cjdns ) && rm -f /etc/uci-defaults/cjdns
# TODO: we should have an 'Enable' button instead
/etc/init.d/cjdns enabled || /etc/init.d/cjdns enable
exit 0
fi
endef
$(eval $(call BuildPackage,cjdns))

125
cjdns/files/cjdns.defaults Normal file
View File

@ -0,0 +1,125 @@
#!/bin/sh
# if there is an existing config, our work is already done
uci get cjdns.cjdns.ipv6 >/dev/null 2>&1
if [ $? -ne 0 ]; then
# register commit handler
uci -q batch <<-EOF >/dev/null
delete ucitrack.@cjdns[-1]
add ucitrack cjdns
set ucitrack.@cjdns[-1].init=cjdns
commit ucitrack
EOF
# generate configuration
touch /etc/config/cjdns
cjdroute --genconf | cjdroute --cleanconf | cjdrouteconf set
# make sure config is present (might fail for any reason)
uci get cjdns.cjdns.ipv6 >/dev/null 2>&1
if [ $? -ne 0]; then
exit 1
fi
# enable auto-peering on ethernet
uci show network.lan | grep type=bridge >/dev/null 2>&1
if [ $? -eq 0 ]; then
# most routers will set up an ethernet bridge for the lan
ifname="br-lan"
else
# docker containers don't have permission to create bridges by default,
# so we bind to the underlying interface instead (likely eth0)
ifname=`uci get network.lan.ifname`
fi
uci -q batch <<-EOF >/dev/null
add cjdns eth_interface
set cjdns.@eth_interface[-1].beacon=2
set cjdns.@eth_interface[-1].bind=$ifname
EOF
# set the tun interface name
uci set cjdns.cjdns.tun_device=tuncjdns
# create the network interface
uci -q batch <<-EOF >/dev/null
set network.cjdns=interface
set network.cjdns.ifname=tuncjdns
set network.cjdns.proto=none
EOF
# firewall rules by @dangowrt -- thanks <3
# create the firewall zone
uci -q batch <<-EOF >/dev/null
add firewall zone
set firewall.@zone[-1].name=cjdns
add_list firewall.@zone[-1].network=cjdns
set firewall.@zone[-1].input=REJECT
set firewall.@zone[-1].output=ACCEPT
set firewall.@zone[-1].forward=REJECT
set firewall.@zone[-1].conntrack=1
set firewall.@zone[-1].family=ipv6
EOF
# allow ICMP from cjdns zone, e.g. ping6
uci -q batch <<-EOF >/dev/null
add firewall rule
set firewall.@rule[-1].name='Allow-ICMPv6-cjdns'
set firewall.@rule[-1].src=cjdns
set firewall.@rule[-1].proto=icmp
add_list firewall.@rule[-1].icmp_type=echo-request
add_list firewall.@rule[-1].icmp_type=echo-reply
add_list firewall.@rule[-1].icmp_type=destination-unreachable
add_list firewall.@rule[-1].icmp_type=packet-too-big
add_list firewall.@rule[-1].icmp_type=time-exceeded
add_list firewall.@rule[-1].icmp_type=bad-header
add_list firewall.@rule[-1].icmp_type=unknown-header-type
set firewall.@rule[-1].limit='1000/sec'
set firewall.@rule[-1].family=ipv6
set firewall.@rule[-1].target=ACCEPT
EOF
# allow SSH from cjdns zone, needs to be explicitly enabled
uci -q batch <<-EOF >/dev/null
add firewall rule
set firewall.@rule[-1].enabled=0
set firewall.@rule[-1].name='Allow-SSH-cjdns'
set firewall.@rule[-1].src=cjdns
set firewall.@rule[-1].proto=tcp
set firewall.@rule[-1].dest_port=22
set firewall.@rule[-1].target=ACCEPT
EOF
# allow LuCI access from cjdns zone, needs to be explicitly enabled
uci -q batch <<-EOF >/dev/null
add firewall rule
set firewall.@rule[-1].enabled=0
set firewall.@rule[-1].name='Allow-HTTP-cjdns'
set firewall.@rule[-1].src=cjdns
set firewall.@rule[-1].proto=tcp
set firewall.@rule[-1].dest_port=80
set firewall.@rule[-1].target=ACCEPT
EOF
# allow UDP peering from wan zone, if it exists
uci show network.wan >/dev/null 2>&1
if [ $? -eq 0 ]; then
peeringPort=`uci get cjdns.@udp_interface[0].port`
uci -q batch <<-EOF >/dev/null
add firewall rule
set firewall.@rule[-1].name='Allow-cjdns-wan'
set firewall.@rule[-1].src=wan
set firewall.@rule[-1].proto=udp
set firewall.@rule[-1].dest_port=$peeringPort
set firewall.@rule[-1].target=ACCEPT
EOF
fi
uci commit cjdns
uci commit firewall
uci commit network
fi
exit 0

32
cjdns/files/cjdns.init Executable file
View File

@ -0,0 +1,32 @@
#!/bin/sh /etc/rc.common
START=90
STOP=85
USE_PROCD=1
start_service()
{
[ -f /etc/uci-defaults/cjdns ] && ( . /etc/uci-defaults/cjdns )
procd_open_instance
procd_set_param respawn
procd_set_param command /bin/ash -c "cjdrouteconf get | tee /tmp/etc/cjdroute.conf | cjdroute --nobg | logger -t cjdns"
procd_close_instance
}
stop_service()
{
killall cjdroute
}
reload_service()
{
# cat /tmp/etc/cjdroute.conf | cjdrouteconf reload
restart
}
service_triggers()
{
procd_add_reload_trigger cjdns
}

30
cjdns/files/cjdrouteconf Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env lua
dkjson = require("dkjson")
cjdns = require("cjdns")
require("cjdns/uci")
function help()
print("JSON interface to /etc/config/cjdns\n\nExamples: \
cjdrouteconf get > /tmp/etc/cjdroute.conf \
cat /tmp/etc/cjdroute.conf | cjdrouteconf set \
uci changes \
cjdrouteconf get | cjdroute")
end
if arg[1] == "get" then
local json = dkjson.encode(cjdns.uci.get(), { indent = true })
print(json)
elseif arg[1] == "set" then
local json = io.stdin:read("*a")
local obj, pos, err = dkjson.decode(json, 1, nil)
if obj then
cjdns.uci.set(obj)
else
print("dkjson: " .. err .. " (try cjdroute --cleanconf)")
os.exit(1)
end
else
help()
end

105
cjdns/lua/cjdns/admin.lua Normal file
View File

@ -0,0 +1,105 @@
-- Cjdns admin module for Lua
-- Written by Philip Horger
common = require 'cjdns/common'
AdminInterface = {}
AdminInterface.__index = AdminInterface
common.AdminInterface = AdminInterface
function AdminInterface.new(properties)
properties = properties or {}
properties.host = properties.host or "127.0.0.1"
properties.port = properties.port or 11234
properties.password = properties.password or nil
properties.config = properties.config or common.ConfigFile.new("/etc/cjdroute.conf", false)
properties.timeout = properties.timeout or 2
properties.udp = common.UDPInterface.new(properties)
return setmetatable(properties, AdminInterface)
end
function AdminInterface:send(object)
local bencoded, err = bencode.encode(object)
if err then
return nil, err
end
local sock_obj = assert(socket.udp())
sock_obj:settimeout(self.timeout)
local _, err = sock_obj:sendto(bencoded, self.host, self.port)
if err then
return nil, err
end
return sock_obj
end
function AdminInterface:recv(sock_obj)
local retrieved, err = sock_obj:receive()
if not retrieved then
return nil, "ai:recv > " .. err
end
local bencoded, err = bencode.decode(retrieved)
if bencoded then
return bencoded
else
return nil, "ai:recv > " .. err
end
end
function AdminInterface:call(request)
local sock_obj, err = self:send(request)
if err then
return nil, "ai:call > " .. err
end
return self:recv(sock_obj)
end
function AdminInterface:getCookie()
local cookie_response, err = self:call({ q = "cookie" })
if not cookie_response then
return nil, "ai:getCookie > " .. err
end
return cookie_response.cookie
end
function AdminInterface:auth(request)
local funcname = request.q
local args = {}
for k, v in pairs(request) do
args[k] = v
end
-- Step 1: Get cookie
local cookie, err = self:getCookie()
if err then
return nil, err
end
-- Step 2: Calculate hash1 (password + cookie)
local plaintext1 = self.password .. cookie
local hash1 = sha2.sha256hex(plaintext1)
-- Step 3: Calculate hash2 (intermediate stage request)
local request = {
q = "auth",
aq = funcname,
args = args,
hash = hash1,
cookie = cookie
}
local plaintext2, err = bencode.encode(request)
if err then
return nil, err
end
local hash2 = sha2.sha256hex(plaintext2)
-- Step 4: Update hash in request, then ship it out
request.hash = hash2
return self:call(request)
end

View File

@ -0,0 +1,7 @@
-- Cjdns admin module for Lua
-- Written by Philip Horger
-- This table is preserved over multiple imports, and collects
-- submodules import-by-import via init.lua.
return {}

12
cjdns/lua/cjdns/init.lua Normal file
View File

@ -0,0 +1,12 @@
-- Cjdns admin module for Lua
-- Written by Philip Horger
bencode = require "bencode" -- https://bitbucket.org/wilhelmy/lua-bencode/
dkjson = require "dkjson" -- http://dkolf.de/src/dkjson-lua.fsl/home
socket = require "socket" -- http://w3.impa.br/~diego/software/luasocket/
sha2 = require "sha2" -- https://code.google.com/p/sha2/
require "cjdns/admin"
require "cjdns/udp"
return require "cjdns/common"

264
cjdns/lua/cjdns/uci.lua Normal file
View File

@ -0,0 +1,264 @@
common = require("cjdns/common")
uci = require("uci")
UCI = {}
common.uci = UCI
--- Return the configuration defaults as a table suitable for JSON output
--
-- Mostly taken from cjdroute --genconf
-- @return table with configuration defaults
function UCI.defaults()
return {
security = { { exemptAngel = 1, setuser = "nobody" } },
router = {
ipTunnel = { outgoingConnections = {}, allowedConnections = {} },
interface = { type = "TUNInterface" }
},
interfaces = { UDPInterface = {}, ETHInterface = {} },
authorizedPasswords = {},
logging = { logTo = "stdout" }
}
end
--- Return the cjdns configuration as a table suitable for JSON output
--
-- Iterates over cjdns, eth_interface, udp_interface, eth_peer, udp_peer,
-- and password sections. Doesn't include IPTunnel related options yet.
-- @return table with cjdns configuration
function UCI.get()
local obj = UCI.defaults()
local cursor = uci.cursor()
local config = cursor:get_all("cjdns", "cjdns")
if not config then return obj end
obj.ipv6 = config.ipv6
obj.publicKey = config.public_key
obj.privateKey = config.private_key
obj.admin = {
bind = config.admin_address .. ":" .. config.admin_port,
password = config.admin_password }
if config.tun_device and string.len(config.tun_device) > 0 then
obj.router.interface.tunDevice = config.tun_device
end
cursor:foreach("cjdns", "iptunnel_outgoing", function(outgoing)
table.insert(obj.router.ipTunnel.outgoingConnections, outgoing.public_key)
end)
cursor:foreach("cjdns", "iptunnel_allowed", function(allowed)
entry = { publicKey = allowed.public_key }
if allowed.ipv4 then
entry["ip4Address"] = allowed.ipv4
end
if allowed.ipv6 then
entry["ip6Address"] = allowed.ipv6
end
table.insert(obj.router.ipTunnel.allowedConnections, entry)
end)
cursor:foreach("cjdns", "eth_interface", function(eth_interface)
table.insert(obj.interfaces.ETHInterface, {
bind = eth_interface.bind,
beacon = tonumber(eth_interface.beacon),
connectTo = {}
})
end)
cursor:foreach("cjdns", "udp_interface", function(udp_interface)
table.insert(obj.interfaces.UDPInterface, {
bind = udp_interface.address .. ":" .. udp_interface.port,
connectTo = {}
})
end)
cursor:foreach("cjdns", "eth_peer", function(eth_peer)
if not eth_peer.address == "" then
local i = tonumber(eth_peer.interface)
obj.interfaces.ETHInterface[i].connectTo[eth_peer.address] = {
publicKey = eth_peer.public_key,
password = eth_peer.password
}
end
end)
cursor:foreach("cjdns", "udp_peer", function(udp_peer)
local bind = udp_peer.address .. ":" .. udp_peer.port
local i = tonumber(udp_peer.interface)
obj.interfaces.UDPInterface[i].connectTo[bind] = {
user = udp_peer.user,
publicKey = udp_peer.public_key,
password = udp_peer.password
}
end)
cursor:foreach("cjdns", "password", function(password)
table.insert(obj.authorizedPasswords, {
password = password.password,
user = password.user,
contact = password.contact
})
end)
return obj
end
--- Parse and save updated configuration from JSON input
--
-- Transforms general settings, ETHInterface, UDPInterface, connectTo, and
-- authorizedPasswords fields into UCI sections, and replaces the UCI config's
-- contents with them.
-- @param table JSON input
-- @return Boolean whether saving succeeded
function UCI.set(obj)
local cursor = uci.cursor()
for i, section in pairs(cursor:get_all("cjdns")) do
cursor:delete("cjdns", section[".name"])
end
local admin_address, admin_port = string.match(obj.admin.bind, "^(.*):(.*)$")
UCI.cursor_section(cursor, "cjdns", "cjdns", "cjdns", {
ipv6 = obj.ipv6,
public_key = obj.publicKey,
private_key = obj.privateKey,
admin_password = obj.admin.password,
admin_address = admin_address,
admin_port = admin_port,
})
if obj.router.interface.tunDevice then
UCI.cursor_section(cursor, "cjdns", "cjdns", "cjdns", {
tun_device = tostring(obj.router.interface.tunDevice)
})
end
if obj.router.ipTunnel.outgoingConnections then
for i,public_key in pairs(obj.router.ipTunnel.outgoingConnections) do
UCI.cursor_section(cursor, "cjdns", "iptunnel_outgoing", nil, {
public_key = public_key
})
end
end
if obj.router.ipTunnel.allowedConnections then
for i,allowed in pairs(obj.router.ipTunnel.allowedConnections) do
entry = { public_key = allowed.publicKey }
if allowed.ip4Address then
entry["ipv4"] = allowed.ip4Address
end
if allowed.ip6Address then
entry["ipv6"] = allowed.ip6Address
end
UCI.cursor_section(cursor, "cjdns", "iptunnel_allowed", nil, entry)
end
end
if obj.interfaces.ETHInterface then
for i,interface in pairs(obj.interfaces.ETHInterface) do
UCI.cursor_section(cursor, "cjdns", "eth_interface", nil, {
bind = interface.bind,
beacon = tostring(interface.beacon)
})
if interface.connectTo then
for peer_address,peer in pairs(interface.connectTo) do
UCI.cursor_section(cursor, "cjdns", "eth_peer", nil, {
interface = i,
address = peer_address,
public_key = peer.publicKey,
password = peer.password
})
end
end
end
end
if obj.interfaces.UDPInterface then
for i,interface in pairs(obj.interfaces.UDPInterface) do
local address, port = string.match(interface.bind, "^(.*):(.*)$")
UCI.cursor_section(cursor, "cjdns", "udp_interface", nil, {
address = address,
port = port
})
if interface.connectTo then
for peer_bind,peer in pairs(interface.connectTo) do
local peer_address, peer_port = string.match(peer_bind, "^(.*):(.*)$")
UCI.cursor_section(cursor, "cjdns", "udp_peer", nil, {
interface = i,
address = peer_address,
port = peer_port,
user = peer.user,
public_key = peer.publicKey,
password = peer.password
})
end
end
end
end
if obj.authorizedPasswords then
for i,password in pairs(obj.authorizedPasswords) do
local user = password.user
if not user or string.len(user) == 0 then
user = "user-" .. UCI.random_string(6)
end
UCI.cursor_section(cursor, "cjdns", "password", nil, {
password = password.password,
user = user,
contact = password.contact
})
end
end
return cursor:save("cjdns")
end
--- Simple backport of Cursor:section from luci.model.uci
--
-- Backport reason: we don't wanna depend on LuCI.
-- @param Cursor the UCI cursor to operate on
-- @param string name of the config
-- @param string type of the section
-- @param string name of the section (optional)
-- @param table config values
function UCI.cursor_section(cursor, config, type, section, values)
if section then
cursor:set(config, section, type)
else
section = cursor:add("cjdns", type)
end
for k,v in pairs(values) do
cursor:set(config, section, k, v)
end
end
function UCI.makeInterface()
local cursor = uci.cursor()
local config = cursor:get_all("cjdns", "cjdns")
if not config then return nil end
return common.AdminInterface.new({
host = config.admin_address,
port = config.admin_port,
password = config.admin_password,
config = UCI.get(),
timeout = 2
})
end
function UCI.random_string(length)
-- tr -cd 'A-Za-z0-9' < /dev/urandom
local urandom = io.popen("tr -cd 'A-Za-z0-9' 2> /dev/null < /dev/urandom", "r")
local string = urandom:read(length)
urandom:close()
return string
end

102
cjdns/lua/cjdns/udp.lua Normal file
View File

@ -0,0 +1,102 @@
-- Cjdns admin module for Lua
-- Written by Philip Horger
common = require 'cjdns/common'
UDPInterface = {}
UDPInterface.__index = UDPInterface
common.UDPInterface = UDPInterface
function UDPInterface.new(ai, config, ptype)
properties = {
ai = ai,
config = config or ai.config,
ptype = ptype or "ai"
}
return setmetatable(properties, UDPInterface)
end
function UDPInterface:call(name, args)
local func = self[name .. "_" .. self.ptype]
return func(self, unpack(args))
end
function UDPInterface:newBind(...)
return self:call("newBind", arg)
end
function UDPInterface:beginConnection(...)
return self:call("beginConnection", arg)
end
function UDPInterface:newBind_ai(address)
local response, err = self.ai:auth({
q = "UDPInterface_new",
bindAddress = address
})
if not response then
return nil, err
elseif response.error ~= "none" then
return nil, response.error
elseif response.interfaceNumber then
return response.interfaceNumber
else
return nil, "bad response format"
end
end
function UDPInterface:newBind_config(address)
local udpif = self.config.contents.interfaces.UDPInterface
local new_interface = {
bind = address,
connectTo = {}
}
table.insert(udpif, new_interface)
return (#udpif - 1), new_interface
end
function UDPInterface:newBind_perm(...)
return
self:newBind_config(unpack(arg)),
self:newBind_ai(unpack(arg))
end
function UDPInterface:beginConnection_ai(pubkey, addr, password, interface)
local request = {
q = "UDPInterface_beginConnection",
publicKey = pubkey,
address = addr,
password = password
}
if interface then
request.interfaceNumber = interface
end
local response, err = self.ai:auth(request)
if not response then
return nil, err
elseif response.error == "none" then
-- Unfortunately, no real success indicator either.
return "No error"
else
return nil, response.error
end
end
function UDPInterface:beginConnection_config(pubkey, addr, password, interface)
local udpif = self.config.contents.interfaces.UDPInterface
local connections = udpif[(interface or 0) + 1].connectTo
local this_conn = {
password = password,
publicKey = pubkey
}
connections[addr] = this_conn
return this_conn -- allows adding metadata fields afterwards
end
function UDPInterface:beginConnection_perm(...)
return
self:beginConnection_config(unpack(arg)),
self:beginConnection_ai(unpack(arg))
end

View File

@ -0,0 +1,29 @@
Index: cjdns-649e26c7d61ccc66c20e87e1e3d381f9ef0cfcb0/crypto/random/seed/LinuxRandomUuidSysctlRandomSeed.c
===================================================================
--- cjdns-649e26c7d61ccc66c20e87e1e3d381f9ef0cfcb0.orig/crypto/random/seed/LinuxRandomUuidSysctlRandomSeed.c
+++ cjdns-649e26c7d61ccc66c20e87e1e3d381f9ef0cfcb0/crypto/random/seed/LinuxRandomUuidSysctlRandomSeed.c
@@ -18,6 +18,8 @@
#include "util/Hex.h"
#include <unistd.h>
+
+#ifdef __GLIBC__
#include <sys/sysctl.h>
static int getUUID(uint64_t output[2])
@@ -42,6 +44,15 @@ static int get(struct RandomSeed* random
return 0;
}
+#else
+
+static int get(struct RandomSeed* randomSeed, uint64_t output[8])
+{
+ return -1;
+}
+
+#endif
+
struct RandomSeed* LinuxRandomUuidSysctlRandomSeed_new(struct Allocator* alloc)
{
return Allocator_clone(alloc, (&(struct RandomSeed) {