--- /dev/null
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=luci-app-cjdns
+PKG_VERSION:=1.3
+PKG_RELEASE:=4
+
+PKG_LICENSE:=GPL-3.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/luci-app-cjdns
+ SECTION:=luci
+ CATEGORY:=LuCI
+ SUBMENU:=3. Applications
+ TITLE:=Encrypted near-zero-conf mesh routing protocol
+ URL:=https://github.com/hyperboria/cjdns
+ MAINTAINER:=Lars Gierth <larsg@systemli.org>
+ DEPENDS:=+cjdns +luci-base
+endef
+
+define Package/luci-app-cjdns/description
+ This package allows you to configure and inspect cjdns networking using LuCI.
+
+ 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/Compile
+endef
+
+define Package/luci-app-cjdns/install
+ $(INSTALL_DIR) $(1)/usr/lib/lua/luci
+ $(CP) ./luasrc/* $(1)/usr/lib/lua/luci
+endef
+
+$(eval $(call BuildPackage,luci-app-cjdns))
--- /dev/null
+module("luci.controller.cjdns", package.seeall)
+
+cjdns = require "cjdns/init"
+dkjson = require "dkjson"
+
+function index()
+ if not nixio.fs.access("/etc/config/cjdns") then
+ return
+ end
+
+ entry({"admin", "services", "cjdns"},
+ cbi("cjdns/overview"), _("cjdns")).dependent = true
+
+ entry({"admin", "services", "cjdns", "overview"},
+ cbi("cjdns/overview"), _("Overview"), 1).leaf = false
+
+ entry({"admin", "services", "cjdns", "peering"},
+ cbi("cjdns/peering"), _("Peers"), 2).leaf = false
+
+ entry({"admin", "services", "cjdns", "iptunnel"},
+ cbi("cjdns/iptunnel"), _("IP Tunnel"), 3).leaf = false
+
+ entry({"admin", "services", "cjdns", "settings"},
+ cbi("cjdns/settings"), _("Settings"), 4).leaf = false
+
+ entry({"admin", "services", "cjdns", "cjdrouteconf"},
+ cbi("cjdns/cjdrouteconf"), _("cjdroute.conf"), 5).leaf = false
+
+ entry({"admin", "services", "cjdns", "peers"}, call("act_peers")).leaf = true
+ entry({"admin", "services", "cjdns", "ping"}, call("act_ping")).leaf = true
+end
+
+function act_peers()
+ require("cjdns/uci")
+ admin = cjdns.uci.makeInterface()
+
+ local page = 0
+ local peers = {}
+
+ while page do
+ local response, err = admin:auth({
+ q = "InterfaceController_peerStats",
+ page = page
+ })
+
+ if err or response.error then
+ luci.http.status(502, "Bad Gateway")
+ luci.http.prepare_content("application/json")
+ luci.http.write_json({ err = err, response = response })
+ return
+ end
+
+ for i,peer in pairs(response.peers) do
+ peer.ipv6 = publictoip6(peer.publicKey)
+ if peer.user == nil then
+ peer.user = ''
+ uci.cursor():foreach("cjdns", "udp_peer", function(udp_peer)
+ if peer.publicKey == udp_peer.public_key then
+ peer.user = udp_peer.user
+ end
+ end)
+ end
+ peers[#peers + 1] = peer
+ end
+
+ if response.more then
+ page = page + 1
+ else
+ page = nil
+ end
+ end
+
+ luci.http.status(200, "OK")
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(peers)
+end
+
+function act_ping()
+ require("cjdns/uci")
+ admin = cjdns.uci.makeInterface()
+
+ local response, err = admin:auth({
+ q = "SwitchPinger_ping",
+ path = luci.http.formvalue("label"),
+ timeout = tonumber(luci.http.formvalue("timeout"))
+ })
+
+ if err or response.error then
+ luci.http.status(502, "Bad Gateway")
+ luci.http.prepare_content("application/json")
+ luci.http.write_json({ err = err, response = response })
+ return
+ end
+
+ luci.http.status(200, "OK")
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(response)
+end
+
+function publictoip6(publicKey)
+ local process = io.popen("/usr/bin/publictoip6 " .. publicKey, "r")
+ local ipv6 = process:read()
+ process:close()
+ return ipv6
+end
--- /dev/null
+m = Map("cjdns", translate("cjdns"),
+ translate("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."))
+
+dkjson = require("dkjson")
+cjdns = require("cjdns")
+require("cjdns/uci")
+
+local f = SimpleForm("cjdrouteconf", translate("Edit cjdroute.conf"),
+ translate("JSON interface to what's /etc/cjdroute.conf on other systems. \
+ Will be parsed and written to UCI by <code>cjdrouteconf set</code>."))
+
+local o = f:field(Value, "_cjdrouteconf")
+o.template = "cbi/tvalue"
+o.rows = 25
+
+function o.cfgvalue(self, section)
+ return dkjson.encode(cjdns.uci.get(), { indent = true })
+end
+
+function o.write(self, section, value)
+ local obj, pos, err = dkjson.decode(value, 1, nil)
+
+ if obj then
+ cjdns.uci.set(obj)
+ end
+end
+
+return f
--- /dev/null
+uci = require "luci.model.uci"
+cursor = uci:cursor_state()
+
+m = Map("cjdns", translate("cjdns"),
+ translate("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."))
+
+m.on_after_commit = function(self)
+ os.execute("/etc/init.d/cjdns restart")
+end
+
+-- Outgoing
+outgoing = m:section(TypedSection, "iptunnel_outgoing", translate("Outgoing IP Tunnel Connections"),
+ translate("Enter the public keys of the nodes that will provide Internet access."))
+outgoing.anonymous = true
+outgoing.addremove = true
+outgoing.template = "cbi/tblsection"
+
+outgoing:option(Value, "public_key", translate("Public Key")).size = 55
+
+-- Allowed
+allowed = m:section(TypedSection, "iptunnel_allowed", translate("Allowed IP Tunnel Connections"),
+ translate("Enter the public key of the node you will provide Internet access to, along with the \
+ IPv4 and/or IPv6 address you will assign them."))
+allowed.anonymous = true
+allowed.addremove = true
+
+public_key = allowed:option(Value, "public_key", translate("Public Key"))
+public_key.template = "cjdns/value"
+public_key.size = 55
+
+ipv4 = allowed:option(Value, "ipv4", translate("IPv4"))
+ipv4.template = "cjdns/value"
+ipv4.datatype = 'ipaddr'
+ipv4.size = 55
+
+ipv6 = allowed:option(Value, "ipv6", translate("IPv6"),
+ translate("IPv6 addresses should be entered <em>without</em> brackets here, e.g. <code>2001:123:ab::10</code>."))
+ipv6.template = "cjdns/value"
+ipv6.datatype = 'ip6addr'
+ipv6.size = 55
+
+return m
--- /dev/null
+m = Map("cjdns", translate("cjdns"),
+ translate("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."))
+
+m:section(SimpleSection).template = "cjdns/status"
+
+return m
--- /dev/null
+uci = require "luci.model.uci"
+cursor = uci:cursor_state()
+
+cjdns = require("cjdns")
+require("cjdns/uci")
+
+m = Map("cjdns", translate("cjdns"),
+ translate("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."))
+
+m.on_after_commit = function(self)
+ os.execute("/etc/init.d/cjdns restart")
+end
+
+-- Authorized Passwords
+passwords = m:section(TypedSection, "password", translate("Authorized Passwords"),
+ translate("Anyone offering one of the these passwords will be allowed to peer with you on the existing UDP and Ethernet interfaces."))
+passwords.anonymous = true
+passwords.addremove = true
+passwords.template = "cbi/tblsection"
+
+passwords:option(Value, "user", translate("User/Name"),
+ translate("Must be unique.")
+).default = "user-" .. cjdns.uci.random_string(6)
+passwords:option(Value, "contact", translate("Contact"), translate("Optional, for out-of-band communication."))
+passwords:option(Value, "password", translate("Password"),
+ translate("Hand out to your peer, in accordance with the peering best practices of the network.")
+).default = cjdns.uci.random_string(32)
+
+-- UDP Peers
+udp_peers = m:section(TypedSection, "udp_peer", translate("Outgoing UDP Peers"),
+ translate("For peering via public IP networks, the peer handed you their Public Key and IP address/port along with a password. IPv6 addresses should be entered with square brackets, like so: <code>[2001::1]</code>."))
+udp_peers.anonymous = true
+udp_peers.addremove = true
+udp_peers.template = "cbi/tblsection"
+udp_peers:option(Value, "user", translate("User/Name")).datatype = "string"
+
+udp_interface = udp_peers:option(Value, "interface", translate("UDP interface"))
+local index = 1
+for i,section in pairs(cursor:get_all("cjdns")) do
+ if section[".type"] == "udp_interface" then
+ udp_interface:value(index, section.address .. ":" .. section.port)
+ end
+end
+udp_interface.default = 1
+udp_peers:option(Value, "address", translate("IP address"))
+udp_peers:option(Value, "port", translate("Port")).datatype = "portrange"
+udp_peers:option(Value, "public_key", translate("Public key"))
+udp_peers:option(Value, "password", translate("Password"))
+
+-- Ethernet Peers
+eth_peers = m:section(TypedSection, "eth_peer", translate("Outgoing Ethernet Peers"),
+ translate("For peering via local Ethernet networks, the peer handed you their Public Key and MAC address along with a password."))
+eth_peers.anonymous = true
+eth_peers.addremove = true
+eth_peers.template = "cbi/tblsection"
+
+eth_interface = eth_peers:option(Value, "interface", translate("Ethernet interface"))
+local index = 1
+for i,section in pairs(cursor:get_all("cjdns")) do
+ if section[".type"] == "eth_interface" then
+ eth_interface:value(index, section.bind)
+ end
+end
+eth_interface.default = 1
+eth_peers:option(Value, "address", translate("MAC address")).datatype = "macaddr"
+eth_peers:option(Value, "public_key", translate("Public key"))
+eth_peers:option(Value, "password", translate("Password"))
+
+return m
--- /dev/null
+m = Map("cjdns", translate("cjdns"),
+ translate("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."))
+
+m.on_after_commit = function(self)
+ os.execute("/etc/init.d/cjdns restart")
+end
+
+s = m:section(NamedSection, "cjdns", nil, translate("Settings"))
+s.addremove = false
+
+-- Identity
+s:tab("identity", translate("Identity"))
+node6 = s:taboption("identity", Value, "ipv6", translate("IPv6 address"),
+ translate("This node's IPv6 address within the cjdns network."))
+node6.datatype = "ip6addr"
+pbkey = s:taboption("identity", Value, "public_key", translate("Public key"),
+ translate("Used for packet encryption and authentication."))
+pbkey.datatype = "string"
+prkey = s:taboption("identity", Value, "private_key", translate("Private key"),
+ translate("Keep this private. When compromised, generate a new keypair and IPv6."))
+prkey.datatype = "string"
+
+-- Admin Interface
+s:tab("admin", translate("Admin API"), translate("The Admin API can be used by other applications or services to configure and inspect cjdns' routing and peering.<br/><br/>Documentation: <a href=\"https://github.com/cjdelisle/cjdns/tree/master/admin#cjdns-admin-api\">admin/README.md</a>"))
+aip = s:taboption("admin", Value, "admin_address", translate("IP Address"),
+ translate("IPv6 addresses should be entered like so: <code>[2001::1]</code>."))
+apt = s:taboption("admin", Value, "admin_port", translate("Port"))
+apt.datatype = "port"
+apw = s:taboption("admin", Value, "admin_password", translate("Password"))
+apw.datatype = "string"
+
+-- UDP Interfaces
+udp_interfaces = m:section(TypedSection, "udp_interface", translate("UDP Interfaces"),
+ translate("These interfaces allow peering via public IP networks, such as the Internet, or many community-operated wireless networks. IPv6 addresses should be entered with square brackets, like so: <code>[2001::1]</code>."))
+udp_interfaces.anonymous = true
+udp_interfaces.addremove = true
+udp_interfaces.template = "cbi/tblsection"
+
+udp_address = udp_interfaces:option(Value, "address", translate("IP Address"))
+udp_address.placeholder = "0.0.0.0"
+udp_interfaces:option(Value, "port", translate("Port")).datatype = "portrange"
+
+-- Ethernet Interfaces
+eth_interfaces = m:section(TypedSection, "eth_interface", translate("Ethernet Interfaces"),
+ translate("These interfaces allow peering via local Ethernet networks, such as home or office networks, or phone tethering. If an interface name is set to \"all\" each available device will be used."))
+eth_interfaces.anonymous = true
+eth_interfaces.addremove = true
+eth_interfaces.template = "cbi/tblsection"
+
+eth_bind = eth_interfaces:option(Value, "bind", translate("Network Interface"))
+eth_bind.placeholder = "br-lan"
+eth_beacon = eth_interfaces:option(Value, "beacon", translate("Beacon Mode"))
+eth_beacon:value(0, translate("0 -- Disabled"))
+eth_beacon:value(1, translate("1 -- Accept beacons"))
+eth_beacon:value(2, translate("2 -- Accept and send beacons"))
+eth_beacon.default = 2
+eth_beacon.datatype = "integer(range(0,2))"
+
+return m
--- /dev/null
+<%+cjdns/status%>
--- /dev/null
+<script type="text/javascript">//<![CDATA[
+
+ var peersURI = '<%=luci.dispatcher.build_url("admin", "services", "cjdns", "peers")%>';
+ var updatePeers = function(x, peers) {
+ var table = document.getElementById('cjdns-peerings');
+ while (table.rows.length > 1) {
+ table.deleteRow(1);
+ }
+
+ if ((peers) && ((peers.err) || (typeof peers.length === 'undefined'))) {
+ var errpeer = (peers.err)
+ ? 'Socket Error: unable to connect to Admin API'
+ : 'No active peers';
+ var row = table.insertRow(-1);
+ row.className = 'cbi-section-table-row';
+ var cell = row.insertCell(-1);
+ cell.colSpan = 7;
+ cell.textContent = errpeer;
+ return;
+ };
+
+ peers.forEach(function(peer, i) {
+ if (peer.user == null) {
+ var user = '';
+ } else if (peer.user == 'Local Peers') {
+ var user = 'beacon';
+ } else {
+ var user = peer.user;
+ }
+
+ if (peer.isIncoming === 0) {
+ var interface = 'outgoing';
+ } else {
+ var interface = 'incoming';
+ }
+
+ var status = interface + ', ' + peer.state.toLowerCase();
+
+ if (peer.version === 0) {
+ var version = '-';
+ } else {
+ var version = 'v' + peer.version;
+ }
+
+ var rxtx = lbbytes(peer.bytesIn) + ' / ' + lbbytes(peer.bytesOut);
+
+ var row = table.insertRow(-1);
+ row.className = 'cbi-section-table-row cbi-rowstyle-' + ((i % 2) + 1);
+ row.insertCell(-1).textContent = user;
+ row.insertCell(-1).textContent = peer.ipv6;
+ row.insertCell(-1).textContent = status;
+ row.insertCell(-1).textContent = version;
+ row.insertCell(-1).textContent = rxtx;
+ var latencyCell = row.insertCell(-1);
+ latencyCell.textContent = 'waiting';
+
+ var pingURI = '<%=luci.dispatcher.build_url("admin", "services", "cjdns", "ping")%>';
+ var timeout = 2000;
+ XHR.get(pingURI, { label: peer.switchLabel, timeout: timeout }, function(x, pong) {
+ var pongrsp = ((pong.err == "ai:recv > timeout") || (pong == "undefined") || (pong.ms >= timeout))
+ ? '> ' + timeout + ' ms'
+ : pong.ms + ' ms';
+ latencyCell.textContent = pongrsp;
+ })
+ });
+
+ };
+
+ XHR.get(peersURI, null, updatePeers);
+ XHR.poll(5, peersURI, null, updatePeers);
+
+//]]></script>
+
+<script type="text/javascript">
+<%# Author: [GitHub/75lb] -%>
+//<![CDATA[
+function lbbytes (bytes){
+
+ var kilobyte = 1024,
+ megabyte = kilobyte * 1024,
+ gigabyte = megabyte * 1024,
+ terabyte = gigabyte * 1024;
+
+ if ((bytes >= 0) && (bytes < kilobyte)) {
+ return bytes + " B";
+ } else if ((bytes >= kilobyte) && (bytes < megabyte)) {
+ return (bytes / kilobyte).toFixed(2) + " KB";
+ } else if ((bytes >= megabyte) && (bytes < gigabyte)) {
+ return (bytes / megabyte).toFixed(2) + " MB";
+ } else if ((bytes >= gigabyte) && (bytes < terabyte)) {
+ return (bytes / gigabyte).toFixed(2) + " GB";
+ } else if (bytes >= terabyte) {
+ return (bytes / terabyte).toFixed(2) + " TB";
+ } else {
+ return bytes + " B";
+ }
+};
+//]]>
+</script>
+
+<fieldset class="cbi-section">
+ <legend>Active cjdns peers</legend>
+ <table class="cbi-section-table" id="cjdns-peerings">
+ <tr class="cbi-section-table-titles">
+ <th class="cbi-section-table-cell">User/Name</th>
+ <th class="cbi-section-table-cell">IPv6</th>
+ <th class="cbi-section-table-cell">Status</th>
+ <th class="cbi-section-table-cell">Version</th>
+ <th class="cbi-section-table-cell">Rx / Tx</th>
+ <th class="cbi-section-table-cell">Latency</th>
+ </tr>
+ <tr class="cbi-section-table-row">
+ <td colspan="7">Querying Admin API</td>
+ </tr>
+ </table>
+</fieldset>
--- /dev/null
+<%+cbi/valueheader%>
+ <input type="<%=self.password and 'password" class="cbi-input-password' or 'text" class="cbi-input-text' %>" onchange="cbi_d_update(this.id)"<%=
+ attr("name", cbid) .. attr("id", cbid) .. attr("value", self:cfgvalue(section) or self.default) ..
+ ifattr(self.size, "size") .. ifattr(self.placeholder, "placeholder")
+ %> style="width: auto" />
+ <% if self.password then %><img src="<%=resource%>/cbi/reload.gif" style="vertical-align:middle" title="<%:Reveal/hide password%>" onclick="var e = document.getElementById('<%=cbid%>'); e.type = (e.type=='password') ? 'text' : 'password';" /><% end %>
+ <% if #self.keylist > 0 or self.datatype then -%>
+ <script type="text/javascript">//<![CDATA[
+ <% if #self.keylist > 0 then -%>
+ cbi_combobox_init('<%=cbid%>', {
+ <%-
+ for i, k in ipairs(self.keylist) do
+ -%>
+ <%-=string.format("%q", k) .. ":" .. string.format("%q", self.vallist[i])-%>
+ <%-if i<#self.keylist then-%>,<%-end-%>
+ <%-
+ end
+ -%>
+ }, '<%- if not self.rmempty and not self.optional then -%>
+ <%-: -- Please choose -- -%>
+ <%- elseif self.placeholder then -%>
+ <%-= pcdata(self.placeholder) -%>
+ <%- end -%>', '
+ <%- if self.combobox_manual then -%>
+ <%-=self.combobox_manual-%>
+ <%- else -%>
+ <%-: -- custom -- -%>
+ <%- end -%>');
+ <%- end %>
+ <% if self.datatype then -%>
+ cbi_validate_field('<%=cbid%>', <%=tostring((self.optional or self.rmempty) == true)%>, '<%=self.datatype:gsub("'", "\\'")%>');
+ <%- end %>
+ //]]></script>
+ <% end -%>
+<%+cbi/valuefooter%>
+++ /dev/null
-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))
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
-}
+++ /dev/null
-#!/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
+++ /dev/null
--- 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
+++ /dev/null
--- 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 {}
+++ /dev/null
--- 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"
+++ /dev/null
-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
+++ /dev/null
--- 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
+++ /dev/null
-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) {