[luci] [patch] Add dropbear application
christian Gagneraud
chris at techworks.ie
Sat Apr 21 19:34:55 CEST 2012
This adds a separate interface for dropbear. This is redundant with the
existing code, but as new features have been proposed for inclusion into
OpenWRT [1], I think that the service submenu would be a better place now.
This application allows to configure local and port forwardings and to
manage router and other hosts keys (plus of course the features offered
by the current interface).
Please let me know what you think.
[1] https://lists.openwrt.org/pipermail/openwrt-devel/2012-April/015006.html
Signed-off-by: Christian Gagneraud <chris at techworks.ie>
--- /dev/null
+++ b/applications/luci-dropbear/Makefile
@@ -0,0 +1,3 @@
+PO=dropbear
+include ../../build/config.mk
+include ../../build/module.mk
--- /dev/null
+++ b/applications/luci-dropbear/ipkg/postinst
@@ -0,0 +1,7 @@
+#!/bin/sh
+me="dropbear"
+[ -n "${IPKG_INSTROOT}" ] || {
+ ( . /etc/uci-defaults/luci-$me ) && rm -f /etc/uci-defaults/luci-$me
+ /etc/init.d/$me enabled || /etc/init.d/$me enable
+ exit 0
+}
--- /dev/null
+++ b/applications/luci-dropbear/luasrc/controller/dropbear.lua
@@ -0,0 +1,27 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2012 Christian Gagneraud <chris at techworks.ie>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+module("luci.controller.dropbear", package.seeall)
+
+function index()
+ if not nixio.fs.access("/etc/config/dropbear") then
+ return
+ end
+ + entry({"admin", "services", "ssh"}, alias("admin", "services",
"ssh", "servers"), _("Secure Shell"), 20).index = true
+ entry({"admin", "services", "ssh", "servers"},
cbi("dropbear/servers"), _("Server instances"), 10)
+ entry({"admin", "services", "ssh", "local_port_forwarding"},
cbi("dropbear/local_port_forwarding"), _("Local port forwarding"), 20)
+ entry({"admin", "services", "ssh", "remote_port_forwarding"},
cbi("dropbear/remote_port_forwarding"), _("Remote port forwarding"), 30)
+ entry({"admin", "services", "ssh", "public_keys"},
cbi("dropbear/public_keys"), _("Public keys"), 40)
+end
--- /dev/null
+++
b/applications/luci-dropbear/luasrc/model/cbi/dropbear/local_port_forwarding.lua
@@ -0,0 +1,118 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2012 Christian Gagneraud <chris at techworks.ie>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+--
+-- Local port forwarding:
+-- dbclient - [-g] -L [bind_address:]port:host:hostport user at server/port
+--
+
+m = Map("dropbear", translate("Local port forwarding"),
+ translate("<p>Specifies that the given port on the local (client) host
is to be forwarded " ..
+ "to the given host and port on the remote side. This works by
allocating a " ..
+ "socket to listen to port on the local side, optionally bound to
the specified " ..
+ "bind address. Whenever a connection is made to this port, the
connection is " ..
+ "forwarded over the secure channel, and a connection is made to
host port " ..
+ "hostport from the remote machine.</p> " ..
+ "<p>By default, the local port is bound in accordance with the
\"Gateway " ..
+ "Ports\" setting. However, an explicit interface may be used to
bind the " ..
+ "connection to a specific address.</p> "))
+
+
+s = m:section(TypedSection, "local_forward", "")
+s.anonymous = true
+s.addremove = true
+
+s:tab("server", translate("Server settings"))
+s:tab("forward", translate("Forwarding settings"))
+s:tab("advanced", translate("Advanced settings"))
+
+un = s:taboption("server", Value, "User", translate("Username"))
+un.rmempty = false
+
+sh = s:taboption("server", Value, "Server", translate("Hostname"))
+sh.datatype = "hostname"
+sh.rmempty = false
+
+sp = s:taboption("server", Value, "ServerPort", translate("Port"))
+sp.datatype = "port"
+sp.default = 22
+sp.rmempty = false
+
+uh = s:taboption("server", Flag, "AcceptUnknown", + translate("Accept
server key if unknown"),
+ translate("[dangerous] If enabled, always blindly accept the server
key"))
+uh.enabled = "on"
+uh.disabled = "off"
+uh.default = uh.disabled
+
+
+lp = s:taboption("forward", Value, "Port", + translate("Local
Port"), + translate("Listening port on the local side"))
+lp.datatype = "port"
+lp.rmempty = false
+
+hn = s:taboption("forward", Value, "Host", + translate("Remote
Host"), + translate("Host on the remote side (use \"localhost\" for
the SSH server itself)"))
+hn.datatype = "hostname"
+hn.rmempty = false
+
+hp = s:taboption("forward", Value, "HostPort", + translate("Remote
Host Port"), + translate("Host's port on the remote side"))
+hp.datatype = "port"
+hp.rmempty = false
+
+
+be = s:taboption("advanced", Flag, "BindEnabled", + translate("Enable
interface binding"),
+ translate("If checked, bind to a specific (or all) interface(s); if
unchecked, follow the \"Gateway ports\" option"))
+be.enabled = "on"
+be.disabled = "off"
+be.default = be.disabled
+be.rmempty = false
+
+-- TODO: we should be able to pickup loopback
+bi = s:taboption("advanced", Value, "Interface", + translate("Local
Interface"),
+ translate("Listen only on the given interface or, if unspecified, on
all"))
+
+bi.template = "cbi/network_netlist"
+bi.nocreate = true
+bi.unspecified = true
+bi:depends({BindEnabled="on"})
+
+ -- The dependency doesn't work on the web page
+gp = s:taboption("advanced", Flag, "GatewayPorts", +
translate("Gateway ports"),
+ translate("Allow remote hosts to connect to local SSH forwarded ports"))
+gp.enabled = "on"
+gp.disabled = "off"
+gp.default = gp.disabled
+gp:depends("BindEnabled", "off")
+
+ka = s:taboption("advanced", Value, "KeepAlive", + translate("Keep
alive interval"),
+ translate("Keep alive interval in seconds (if 0, disable it)"))
+ka.default = 0
+ka.datatype = "uinteger"
+
+rw = s:taboption("advanced", Value, "WindowBuffer", +
translate("Receive window buffer"),
+ translate("Buffer size in bytes (if 0, use default settings)"))
+rw.default = 0
+rw.datatype = "uinteger"
+
+return m
--- /dev/null
+++ b/applications/luci-dropbear/luasrc/model/cbi/dropbear/public_keys.lua
@@ -0,0 +1,109 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2012 Christian Gagneraud <chris at techworks.ie>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local fs = require("luci.fs")
+
+m = Map("dropbear", translate("Public keys"))
+
+local function get_key_public_portion(filename)
+ out = luci.sys.exec("dropbearkey -y -f "..filename)
+ lines = {out:match((out:gsub("[^\n]*\n", "([^\n]*)\n")))}
+ return lines[2] or ""
+end
+
+local function get_key_fingerprint(filename)
+ out = luci.sys.exec("dropbearkey -y -f "..filename)
+ lines = {out:match((out:gsub("[^\n]*\n", "([^\n]*)\n")))}
+ line = lines[3] or ""
+ fg, nb = line:gsub("Fingerprint: ", "")
+ return fg
+end
+
+s2 = m:section(TypedSection, "_dummy", translate("SSH-Keys"),
+ translate(""))
+s2.addremove = false
+s2.anonymous = true
+
+function s2.cfgsections()
+ return { "_keys" }
+end
+
+s2:tab("routerkeys", translate("Router's keys"))
+s2:tab("authkeys", translate("Authorized keys"))
+s2:tab("trustedkeys", translate("Known hosts"))
+
+-- TODO: Use readonly TextValue with wrap=off for all router keys and
fingerprint
+rkeyd = s2:taboption("routerkeys", DummyValue, "_routerdsskey", +
translate("DSS Key"))
+function rkeyd.cfgvalue()
+ return get_key_public_portion("/etc/dropbear/dropbear_dss_host_key")
+end
+
+rkeydf = s2:taboption("routerkeys", DummyValue, "_routerdsskeyfg", +
translate("DSS Key fingerprint"))
+function rkeydf.cfgvalue()
+ return get_key_fingerprint("/etc/dropbear/dropbear_dss_host_key")
+end
+
+rkeyr = s2:taboption("routerkeys", DummyValue, "_routerrsakey", +
translate("RSA Key"))
+function rkeyr.cfgvalue()
+ return get_key_public_portion("/etc/dropbear/dropbear_rsa_host_key")
+end
+
+rkeyrf = s2:taboption("routerkeys", DummyValue, "_routerrsakeyfg", +
translate("RSA Key fingerprint"))
+function rkeyrf.cfgvalue()
+ return get_key_fingerprint("/etc/dropbear/dropbear_rsa_host_key")
+end
+
+
+pkeys = s2:taboption("authkeys", TextValue, "_authkeys", + "",
+ translate("Here you can paste public SSH-Keys (one per line) for
SSH public-key authentication."))
+pkeys.optional = true
+pkeys.wrap = "off"
+pkeys.rows = 10
+pkeys.rmempty = true
+
+function pkeys.cfgvalue()
+ return fs.readfile("/etc/dropbear/authorized_keys") or ""
+end
+
+-- FIXME: Never called when the TextValue is empty => impossible to
remove the (last) key(s)!
+function pkeys.write(self, section, value)
+ value = value or ""
+ fs.writefile("/etc/dropbear/authorized_keys", value:gsub("\r\n", "\n"))
+end
+
+-- TODO: make dropbear look at /etc/ssh/known_hosts ?
+skeys = s2:taboption("trustedkeys", TextValue, "_data", + "", +
translate("Here you can paste public SSH-Keys (one per line) of
known SSH servers."))
+skeys.optional = true
+skeys.wrap = "off"
+skeys.rows = 10
+skeys.rmempty = true
+
+function skeys.cfgvalue()
+ return fs.readfile("/root/.ssh/known_hosts") or ""
+end
+
+-- FIXME: Never called when the TextValue is empty => impossible to
remove the (last) key(s)!
+function skeys.write(self, section, value)
+ value = value or ""
+ fs.writefile("/root/.ssh/known_hosts", value:gsub("\r\n", "\n"))
+end
+
+return m
--- /dev/null
+++
b/applications/luci-dropbear/luasrc/model/cbi/dropbear/remote_port_forwarding.lua
@@ -0,0 +1,106 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2012 Christian Gagneraud <chris at techworks.ie>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local fs = require("luci.fs")
+
+--
+-- Remote port forwarding:
+-- dbclient -R [bind_address:]port:host:hostport user at server/port
+--
+
+m = Map("dropbear", translate("Remote port forwarding"),
+ translate("<p>Specifies that the given port on the remote (server)
host is to be forwarded to the given host and port on the local " ..
+ "side. This works by allocating a socket to listen to port on the
remote side, and whenever a connection is made to " ..
+ "this port, the connection is forwarded over the secure channel,
and a connection is made to host port hostport from " ..
+ "the local machine.</p>" .. + "<p>By default, the listening
socket on the server will be bound to the loopback interface only. This
may be overridden " ..
+ "by specifying a bind address. An empty bind address indicates
that the remote socket should listen on all interfaces. " ..
+ "Specifying a remote bind address will only succeed if the server's
\"Gateway Ports\" option is enabled</p>" ..
+ "<p>For the remote port forwarding to work, you have to add the
server's public key to your router's list of known host " ..
+ "public keys and add your router's public key to the server's
authorized keys</p>"))
+
+s = m:section(TypedSection, "remote_forward", "")
+s.anonymous = true
+s.addremove = true
+
+s:tab("server", translate("Server settings"))
+s:tab("forward", translate("Forwarding settings"))
+s:tab("advanced", translate("Advanced settings"))
+
+un = s:taboption("server", Value, "User", translate("Username"))
+un.rmempty = false
+
+sh = s:taboption("server", Value, "Server", translate("Hostname"))
+sh.datatype = "hostname"
+sh.rmempty = false
+
+sp = s:taboption("server", Value, "ServerPort", translate("Port"))
+sp.datatype = "port"
+sp.default = 22
+
+uh = s:taboption("server", Flag, "AcceptUnknown", + translate("Accept
server key if unknown"),
+ translate("[dangerous] If enabled, always blindly accept the server
key"))
+uh.enabled = "on"
+uh.disabled = "off"
+uh.default = uh.disabled
+
+-- TODO: allow the value 0, a port will be dynamically choosen by the
SSH server
+lp = s:taboption("forward", Value, "Port", + translate("Remote
port"), + translate("Listening port on the remote side"))
+lp.datatype = "port"
+lp.rmempty = false
+
+hn = s:taboption("forward", Value, "Host", + translate("Local Host"),
+ translate("Host on the local side (Use \"localhost\" for the router
itself)"))
+hn.datatype = "hostname"
+hn.rmempty = false
+
+hp = s:taboption("forward", Value, "HostPort", + translate("Local
Host Port"),
+ translate("Host's port on the local side"))
+hp.datatype = "port"
+hp.rmempty = false
+
+be = s:taboption("advanced", Flag, "BindEnabled", + translate("Enable
address binding on the remote side"),
+ translate("If checked, bind to a specific address; if unchecked,
bind to the loopback interface"))
+be.enabled = "on"
+be.disabled = "off"
+be.default = be.disabled
+be.rmempty = false
+
+ba = s:taboption("advanced", Value, "Address", + translate("Remote
address"), + translate("Listen only on the given address or, if empty,
on any"))
+ba.optional = true
+ba.datatype = "ipaddr"
+ba:depends({BindEnabled="on"})
+ba.rmempty = false
+
+ka = s:taboption("advanced", Value, "KeepAlive", + translate("Keep
alive interval"),
+ translate("Keep alive interval in seconds (if 0, disable it)"))
+ka.default = 0
+ka.datatype = "uinteger"
+
+rw = s:taboption("advanced", Value, "WindowBuffer", +
translate("Receive window buffer"),
+ translate("Buffer size in bytes (if 0, use default settings)"))
+rw.default = 0
+rw.datatype = "uinteger"
+
+return m
--- /dev/null
+++ b/applications/luci-dropbear/luasrc/model/cbi/dropbear/servers.lua
@@ -0,0 +1,58 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven at midlink.org>
+Copyright 2011 Jo-Philipp Wich <xm at subsignal.org>
+Copyright 2012 Christian Gagneraud <chris at techworks.ie>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+m = Map("dropbear", translate("Server instances"),
+ translate("Dropbear offers <abbr title=\"Secure Shell\">SSH</abbr>
network shell access and an integrated <abbr title=\"Secure
Copy\">SCP</abbr> server"))
+
+s = m:section(TypedSection, "dropbear")
+s.anonymous = true
+s.addremove = true
+
+s:tab("basic", translate("Basic settings"))
+s:tab("advanced", translate("Advanced settings"))
+
+pt = s:taboption("basic", Value, "Port", + translate("Port"),
+ translate("Specifies the listening port of this <em>Dropbear</em>
instance"))
+pt.datatype = "port"
+pt.default = 22
+
+ni = s:taboption("basic", Value, "Interface", translate("Interface"),
+ translate("Listen only on the given interface or, if unspecified, on
all"))
+
+ni.template = "cbi/network_netlist"
+ni.nocreate = true
+ni.unspecified = true
+
+it = s:taboption("advanced", Value, "IdleTimeout", + translate("Idle
timeout"),
+ translate("Idle timeout in seconds (if 0, disable it)"))
+it.default = 0
+it.datatype = "uinteger"
+
+ka = s:taboption("advanced", Value, "KeepAlive", + translate("Keep
alive interval"),
+ translate("Keep alive interval in seconds (if 0, disable it)"))
+ka.default = 0
+ka.datatype = "uinteger"
+
+rw = s:taboption("advanced", Value, "WindowBuffer", +
translate("Receive window buffer"),
+ translate("Buffer size in bytes (if 0, use default settings)"))
+rw.default = 0
+rw.datatype = "uinteger"
+
+return m
--- /dev/null
+++ b/applications/luci-dropbear/root/etc/uci-defaults/luci-dropbear
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+uci -q batch <<-EOF >/dev/null
+ add ucitrack dropbear
+ set ucitrack. at dropbear[-1].init=dropbear
+ add ucitrack dropbear
+ set ucitrack. at dropbear[-1].init=dbclient
+ commit ucitrack
+EOF
+
+rm -f /tmp/luci-indexcache
+exit 0
--- a/contrib/package/luci/Makefile
+++ b/contrib/package/luci/Makefile
@@ -458,6 +458,9 @@ $(eval $(call application,transmission,L
$(eval $(call application,watchcat,LuCI Support for Watchcat,\
+PACKAGE_luci-app-watchcat:watchcat))
+$(eval $(call application,dropbear,LuCI Support for dropbear,\
+ +PACKAGE_luci-app-dropbear:dropbear))
+
### Server Gateway Interfaces ###
define sgi
define Package/luci-sgi-$(1)
More information about the luci
mailing list