tor-hs: add new package
authorJan Pavlinec <jan.pavlinec@nic.cz>
Tue, 24 Mar 2020 14:35:08 +0000 (15:35 +0100)
committerJosef Schlehofer <pepe.schlehofer@gmail.com>
Thu, 6 Aug 2020 11:43:15 +0000 (13:43 +0200)
Signed-off-by: Jan Pavlinec <jan.pavlinec@nic.cz>
(cherry picked from commit 5906bfecd5ee265715debab3ef84143f3cb07a94)

net/tor-hs/Makefile [new file with mode: 0644]
net/tor-hs/README.md [new file with mode: 0644]
net/tor-hs/files/nextcloud-update.sh [new file with mode: 0755]
net/tor-hs/files/tor-hs.conf [new file with mode: 0644]
net/tor-hs/files/tor-hs.init [new file with mode: 0755]
net/tor-hs/files/tor_rpcd.sh [new file with mode: 0755]

diff --git a/net/tor-hs/Makefile b/net/tor-hs/Makefile
new file mode 100644 (file)
index 0000000..3a5490a
--- /dev/null
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 02020 CZ.NIC, z. s. p. o. (https://www.nic.cz/)
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=tor-hs
+PKG_VERSION:=0.0.1
+PKG_RELEASE:=1
+
+PKG_MAINTAINER:=Jan Pavlinec <jan.pavlinec@nic.cz>
+PKG_LICENSE:=GPL-3.0-or-later
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/tor-hs
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=IP Addresses and Names
+  TITLE:=Tor hidden service configurator
+  DEPENDS:=+tor
+endef
+
+define Package/tor-hs/description
+  Tor Hidden Service configurator
+endef
+
+define Package/tor-hs/conffiles
+/etc/config/tor-hs
+endef
+
+define Build/Compile
+endef
+
+define Build/Install
+endef
+
+define Package/tor-hs/install
+       $(INSTALL_DIR) $(1)/etc/config/
+       $(CP) ./files/tor-hs.conf $(1)/etc/config/tor-hs
+       $(INSTALL_DIR) $(1)/etc/init.d/
+       $(INSTALL_BIN) ./files/tor-hs.init $(1)/etc/init.d/tor-hs
+       $(INSTALL_DIR) $(1)/etc/tor/
+       $(INSTALL_BIN) ./files/nextcloud-update.sh $(1)/etc/tor/
+       $(INSTALL_DIR) $(1)/usr/libexec/rpcd
+       $(INSTALL_BIN) ./files/tor_rpcd.sh $(1)/usr/libexec/rpcd/
+endef
+
+$(eval $(call BuildPackage,tor-hs))
diff --git a/net/tor-hs/README.md b/net/tor-hs/README.md
new file mode 100644 (file)
index 0000000..649ff31
--- /dev/null
@@ -0,0 +1,104 @@
+# Tor Hidden service configurator
+**tor-hs** packages tries to simplify creating of hidden services on OpenWrt routers.
+
+## Requirements
+To run **tor-hs**, you need Tor package with uci config support (it was added
+with [this commit](https://github.com/openwrt/packages/commit/ca6528f002d74445e3d0a336aeb9074fc337307a) ).
+
+## Instalation
+To install package simple run
+```
+opkg update
+opkg install tor-hs
+```
+
+## Configuration
+Uci configuration is located in **/etc/config/tor-hs**
+
+### Required section of configuration
+There is  one required section **common**
+
+Example of this section
+```
+config tor-hs common
+       option GenConf "/etc/tor/torrc_hs"
+       option HSDir "/etc/tor/hidden_service"
+       option RestartTor "true"
+       option UpdateTorConf "true"
+```
+
+#### Table with options description
+| Type | Name | Default | Description |
+| ------ | ------ | ------ | ------ |
+| option |GenConf | /etc/tor/torrc_generated|Generated config by tor-hs.|
+| option | HSDir |/etc/tor/hidden_service|Directory with meta-data for hidden services (hostname,keys,etc).|
+| option | RestartTor | true| It will restart tor after running **/etc/init.d/tor-hs start**.|
+| option | UpdateTorConf | true|Update /etc/config/tor with config from **GenConf** option.|
+
+### Hidden service configuration
+If you want to create a new hidden service, you have to add a hidden-service section. For every hidden service, there should be a new **hidden-service** section.
+
+Example of hidden service section for ssh server:
+
+```
+config hidden-service
+       option Name 'sshd'
+       option Description "Hidden service for ssh"
+       option Enabled 'false'
+       option IPv4 '127.0.0.1'
+       #public port=2222, local port=22
+       list PublicLocalPort '2222;22'
+```
+
+#### Table with options description
+
+| Type | Name | Example value | Description |
+| ------ | ------ | ------ | ------ |
+|      option | Name | sshd| Name of hidden service. It is used as directory name in **HSDir**|
+|      option | Description| Hidden service for ssh| Description used in **rpcd** service|
+|      option | Enabled |false| Enable hidden service after running **tor-hs** init script|
+|      option |IPv4 |127.0.0.1|Local IPv4 address of service. Service could run on another device, in that case OpenWrt will redirect comunication.  |
+|      list | PublicLocalPort| 2222;22| Public port is port accesible via Tor network. Local port is normal port of service.|
+|option| HookScript |'/etc/tor/nextcloud-update.php'| Path to script which is executed after starting tor-hs. Script is executed with paramters **--update-onion** **hostname** . Hostname is replaced with Onion v3 address for given hidden service.
+
+## Running service
+
+To enable tor-hs service run
+```
+/etc/init.d/tor-hs enable
+/etc/init.d/tor-hs start
+
+```
+In case you enabled option *RestartTor* and *UpdateTorConf* hidden service should be running.
+Otherwise, you should also restart tor daemon.
+
+```
+/etc/init.d/tor restart
+```
+
+After that you should also restart rpcd daemon, so you can use tor-hs RPCD service.
+```
+/etc/init.d/rpcd restart
+```
+
+### RPCD
+
+RPCD servis helps users to access basic informations about hidden services on router. After running HS it contains onion url for given hidden service in hostname value.
+```
+root@turris:/# ubus call tor_rpcd.sh list-hs '{}'
+{
+       "hs-list": [
+               {
+                       "name": "sshd",
+                       "description": "Hidden service for ssh",
+                       "enabled": "1",
+                       "ipv4": "127.0.0.1",
+                       "hostname": "****hidden-service-hostname****.onion",
+                       "ports": [
+                               "22;22"
+                       ]
+               }
+       ]
+}
+```
+
diff --git a/net/tor-hs/files/nextcloud-update.sh b/net/tor-hs/files/nextcloud-update.sh
new file mode 100755 (executable)
index 0000000..3c485e8
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+# This is example script for tor-hs uci config
+# HookScript option. Script is then called after running
+# hidden service.
+# It disables trusted domain check for nextcloud.
+
+NEXTCLOUD_CLI_SCRIPT="/srv/www/nextcloud/occ"
+
+nextcloud_cli() {
+       sudo -u nobody php-cli "$NEXTCLOUD_CLI_SCRIPT" "$@"
+}
+
+
+nextcloud_add_domain() {
+       onion="$1"
+       if [ -n "$onion" ] && nextcloud_cli config:system:get trusted_domains |grep "$onion" ; then
+               echo "Info: Trusted domains already disabled. Nothing to do." >&2
+       else
+               echo "Info: Disabling trusted domains." >&2
+               nextcloud_cli config:system:set trusted_domains 1000 --value=$onion
+       fi
+}
+
+print_help() {
+       echo "Help"
+}
+
+# Check occ command
+[ -f "$NEXTCLOUD_CLI_SCRIPT" ] || {
+       echo "Error: occ command not found!" >&2
+       exit 1
+}
+
+################################################################
+
+case "$1" in
+--update-onion)
+       nextcloud_add_domain "$2"
+;;
+
+*)
+       print_help
+;;
+esac
diff --git a/net/tor-hs/files/tor-hs.conf b/net/tor-hs/files/tor-hs.conf
new file mode 100644 (file)
index 0000000..5480685
--- /dev/null
@@ -0,0 +1,22 @@
+config tor-hs common
+       #option GenConf "/etc/tor/torrc_hs"
+       option GenConf "/etc/tor/torrc_generated"
+       option HSDir "/etc/tor/hidden_service"
+       option RestartTor "true"
+       option UpdateTorConf "true"
+
+#config hidden-service
+#      option Name 'sshd'
+#      option Description "Hidden service for ssh"
+#      option Enabled 'false'
+#      option IPv4 '127.0.0.1'
+#      #public port=2222, local port=22
+#      list PublicLocalPort '2222;22'
+
+#config hidden-service
+#      option Name 'nextcloud'
+#      option Description "Hidden service for Nextcloud"
+#      option Enabled 'false'
+#      option IPv4 '127.0.0.1'
+#      option HookScript '/etc/tor/nextcloud-update.sh'
+#      list PublicLocalPort '80;80'
diff --git a/net/tor-hs/files/tor-hs.init b/net/tor-hs/files/tor-hs.init
new file mode 100755 (executable)
index 0000000..aab531b
--- /dev/null
@@ -0,0 +1,116 @@
+#!/bin/sh /etc/rc.common
+
+START=52
+STOP=52
+
+USE_PROCD=1
+
+TORRC_FILE=/etc/tor/torrc_generated # file with torrc config
+HS_DIR_PATH=/etc/tor/hidden_service #hidden service directory path
+TOR_USER=tor
+
+clean_hs() {
+       local name=""
+}
+
+config_tor() {
+       local restart_tor update_config
+       config_get_bool restart_tor "common" RestartTor
+       config_get_bool update_config "common" UpdateTorConf
+
+       tail_conf=$(uci show tor.conf.tail_include 2>/dev/null)
+       head_conf=$(uci show tor.conf.head_include 2>/dev/null)
+       echo "tail_conf $tail_conf"
+
+       if [ "$update_config" = "1" ]; then
+               if [ -n "$(echo $tail_conf | grep $TORRC_FILE)" ] || [ -n "$(echo $head_conf | grep $TORRC_FILE)" ]; then
+                       echo "Info. Not updating tor configuration"
+               else
+                       #uci add_list
+                       echo "Info. Updating tor configuration"
+                       uci add_list tor.conf.tail_include="$TORRC_FILE"
+                       uci commit tor
+               fi
+       fi
+
+       if [ "$restart_tor" = "1" ]; then
+               /etc/init.d/tor restart
+       fi
+}
+
+handle_hs_ports_conf() {
+       local public_port local_port
+       local value="$1"
+       local ipv4="$2"
+       local name="$3"
+
+       public_port=$(echo "$value"|awk -F';' '{print $1}')
+       local_port=$(echo "$value"|awk -F';' '{print $2}')
+       echo "HiddenServicePort $public_port $ipv4:$local_port">>$TORRC_FILE
+}
+
+parse_hs_conf() {
+       local name public_port local_port enable_hs ipv4
+       local config="$1"
+
+       config_get name "$config" Name
+       config_get description "$config" Description
+
+       config_get_bool enable_hs "$config" Enabled 0
+       config_get ipv4 "$config" IPv4
+
+       if [ "$enable_hs" = "1" ]; then
+               mkdir -p "$HS_DIR_PATH/$name"
+               chown "$TOR_USER":"$TOR_USER" "$HS_DIR_PATH/"
+               chown "$TOR_USER:$TOR_USER" "$HS_DIR_PATH/$name"
+               chmod 700 "$HS_DIR_PATH/"
+               chmod 700 "$HS_DIR_PATH/$name/"
+
+               echo "HiddenServiceDir $HS_DIR_PATH/$name" >>$TORRC_FILE
+               config_list_foreach "$config" PublicLocalPort handle_hs_ports_conf "$ipv4" "$name"
+       fi
+}
+
+parse_hs_conf_hooks() {
+       local name hook_script enable_hs hostname_file
+       local config="$1"
+
+       config_get enable_hs "$config" Enabled 0
+       config_get hook_script "$config" HookScript
+       config_get name "$config" Name
+
+       hostname="$HS_DIR_PATH/$name/hostname"
+
+       # check if we should run hook_script
+       if [ "$enable_hs" = "true" ] && [ -x "$hook_script" ] && [ -f "$hostname" ] ; then
+               hostname_uri=$(cat "$hostname")
+               # call hook script
+               $hook_script "--update-onion" "$hostname_uri"
+       fi
+}
+
+parse_common_conf() {
+       local hs_dir generated_config
+       config_get generated_config "common" GenConf
+       config_get hs_dir "common" HSDir
+       [ -n "$hs_dir" ] && HS_DIR_PATH="$hs_dir"
+       [ -n "$generated_config" ] && TORRC_FILE="$generated_config"
+}
+
+start_service() {
+       config_load tor-hs
+       # clean config
+       echo "" > $TORRC_FILE # clean config
+
+       # load common config
+       parse_common_conf
+
+       # load hs service
+       config_foreach parse_hs_conf hidden-service
+
+       # update tor config
+       config_tor
+
+       # load and run tor-hs hooks
+       config_foreach parse_hs_conf_hooks hidden-service
+}
diff --git a/net/tor-hs/files/tor_rpcd.sh b/net/tor-hs/files/tor_rpcd.sh
new file mode 100755 (executable)
index 0000000..bfcd788
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+. /lib/functions.sh
+
+get_onion_hostname() {
+       local name="$1"
+       config_get hs_dir common HSDir
+       if [ -f "$hs_dir/$name/hostname" ]; then
+              cat "$hs_dir/$name/hostname"
+       fi
+}
+
+get_port_list() {
+       local config="$1"
+       config_get ports "$config" PublicLocalPort
+       tmp="$(echo $ports |sed "s| |','|g")"
+       echo -ne "['$tmp']"
+}
+
+parse_hs_conf() {
+       local name description public_port local_port enable_bool public_local_port ipv4
+       local config="$1"
+       local custom="$2"
+
+       config_get name "$config" Name
+       config_get description "$config" Description
+
+       config_get_bool enable_hs "$config" Enabled 0
+       config_get ipv4 "$config" IPv4
+
+       hostname="$(get_onion_hostname $name)"
+       port_list="$(get_port_list $config)"
+       echo "{"
+       echo \"name\":\"$name\",
+       echo \"description\":\"$description\",
+       echo \"enabled\":\"$enable_hs\",
+       echo \"ipv4\":\"$ipv4\",
+       echo \"hostname\":\"$hostname\",
+       echo \"ports\":$port_list
+       echo "},"
+}
+
+get_tor_hs_list() {
+       config_load tor-hs
+       echo "{"
+       echo '"hs-list":['
+       config_foreach parse_hs_conf hidden-service
+       echo "]"
+       echo "}"
+}
+
+
+
+case "$1" in
+       list)
+               echo '{ "list-hs": { } }'
+       ;;
+       call)
+               case "$2" in
+                       list-hs)
+                               # return json object
+                               get_tor_hs_list
+                       ;;
+               esac
+       ;;
+esac
+
+
+