diff --git a/security/tor/Makefile b/security/tor/Makefile
index 6d938aa2e..59ce57587 100644
--- a/security/tor/Makefile
+++ b/security/tor/Makefile
@@ -1,7 +1,7 @@
PLUGIN_NAME= tor
-PLUGIN_VERSION= 1.1
+PLUGIN_VERSION= 1.2
PLUGIN_COMMENT= The Onion Router
-PLUGIN_DEPENDS= tor
+PLUGIN_DEPENDS= tor ruby
PLUGIN_MAINTAINER= franz.fabian.94@gmail.com
.include "../../Mk/plugins.mk"
diff --git a/security/tor/src/opnsense/mvc/app/controllers/OPNsense/Tor/Api/ServiceController.php b/security/tor/src/opnsense/mvc/app/controllers/OPNsense/Tor/Api/ServiceController.php
index 0846d2059..2de3eb487 100644
--- a/security/tor/src/opnsense/mvc/app/controllers/OPNsense/Tor/Api/ServiceController.php
+++ b/security/tor/src/opnsense/mvc/app/controllers/OPNsense/Tor/Api/ServiceController.php
@@ -157,4 +157,24 @@ class ServiceController extends ApiControllerBase
return array('status' => 'failed');
}
}
+ /**
+ * query tor circuits
+ * @return array
+ */
+ public function circuitsAction()
+ {
+ $backend = new Backend();
+ $response = json_decode($backend->configdRun('tor circuit'));
+ return array('response' => $response);
+ }
+ /**
+ * query tor streams
+ * @return array
+ */
+ public function streamsAction()
+ {
+ $backend = new Backend();
+ $response = json_decode($backend->configdRun('tor streams'));
+ return array('response' => $response);
+ }
}
diff --git a/security/tor/src/opnsense/mvc/app/controllers/OPNsense/Tor/IndexController.php b/security/tor/src/opnsense/mvc/app/controllers/OPNsense/Tor/IndexController.php
index c5a04e4cf..881e687b4 100644
--- a/security/tor/src/opnsense/mvc/app/controllers/OPNsense/Tor/IndexController.php
+++ b/security/tor/src/opnsense/mvc/app/controllers/OPNsense/Tor/IndexController.php
@@ -54,4 +54,19 @@ class IndexController extends \OPNsense\Base\IndexController
$this->view->title = gettext("The Onion Router - Information");
$this->view->pick('OPNsense/Tor/info');
}
+ public function diagnosticsAction()
+ {
+ $this->view->title = gettext("The Onion Router - Diagnostics");
+ if ($this->is_tor_running()) {
+ $this->view->pick('OPNsense/Tor/diagnostics');
+ }
+ else {
+ $this->view->pick('OPNsense/Tor/error');
+ }
+ }
+ private function is_tor_running()
+ {
+ $status = (new Api\ServiceController())->statusAction();
+ return $status['status'] == 'running';
+ }
}
diff --git a/security/tor/src/opnsense/mvc/app/models/OPNsense/Tor/Menu/Menu.xml b/security/tor/src/opnsense/mvc/app/models/OPNsense/Tor/Menu/Menu.xml
index a39ace8ad..864e2ef34 100644
--- a/security/tor/src/opnsense/mvc/app/models/OPNsense/Tor/Menu/Menu.xml
+++ b/security/tor/src/opnsense/mvc/app/models/OPNsense/Tor/Menu/Menu.xml
@@ -1,8 +1,9 @@
diff --git a/security/tor/src/opnsense/mvc/app/views/OPNsense/Tor/diagnostics.volt b/security/tor/src/opnsense/mvc/app/views/OPNsense/Tor/diagnostics.volt
new file mode 100644
index 000000000..71fd0a0ff
--- /dev/null
+++ b/security/tor/src/opnsense/mvc/app/views/OPNsense/Tor/diagnostics.volt
@@ -0,0 +1,122 @@
+{#
+
+ Copyright (C) 2017 Fabian Franz
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
+#}
+
+
+
+
+
+
+
+
+
+
+ | {{ lang._('Stream ID') }} |
+ {{ lang._('Stream Status') }} |
+ {{ lang._('Circuit ID') }} |
+ {{ lang._('Destination Host') }} |
+ {{ lang._('Destination Port') }} |
+
+
+
+
+
+
+
+
+
+ | {{ lang._('Circuit ID') }} |
+ {{ lang._('Status') }} |
+ {{ lang._('Hosts') }} |
+ {{ lang._('Flags') }} |
+
+
+
+
+
+
diff --git a/security/tor/src/opnsense/mvc/app/views/OPNsense/Tor/error.volt b/security/tor/src/opnsense/mvc/app/views/OPNsense/Tor/error.volt
new file mode 100644
index 000000000..71500976a
--- /dev/null
+++ b/security/tor/src/opnsense/mvc/app/views/OPNsense/Tor/error.volt
@@ -0,0 +1,32 @@
+{#
+
+ Copyright (C) 2017 Fabian Franz
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
+#}
+
+
+ {{ lang._('This page is not available because Tor is not running. Please go to the %sconfiguration page%s and enable Tor.')|format('
','') }}
+
diff --git a/security/tor/src/opnsense/mvc/app/views/OPNsense/Tor/info.volt b/security/tor/src/opnsense/mvc/app/views/OPNsense/Tor/info.volt
index 675458701..bb41fd704 100644
--- a/security/tor/src/opnsense/mvc/app/views/OPNsense/Tor/info.volt
+++ b/security/tor/src/opnsense/mvc/app/views/OPNsense/Tor/info.volt
@@ -44,7 +44,7 @@ $( document ).ready(function() {
var tmp = '';
for (var name in data) {
if (data.hasOwnProperty(name)) {
- tmp += '| ' + name + ' | ' + data[name] + ' |
';
+ tmp += '| ' + name + ' | ' + data[name].replace("\n",' ') + ' |
';
}
}
@@ -61,7 +61,7 @@ $( document ).ready(function() {
-
+
| {{ lang._('Onion Service Name') }} |
diff --git a/security/tor/src/opnsense/scripts/tor/tor_diag b/security/tor/src/opnsense/scripts/tor/tor_diag
new file mode 100755
index 000000000..edd9f3bbf
--- /dev/null
+++ b/security/tor/src/opnsense/scripts/tor/tor_diag
@@ -0,0 +1,176 @@
+#!/usr/local/bin/ruby
+=begin
+Copyright 2017 Fabian Franz
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+=end
+
+
+require 'enumerator'
+require 'json'
+require 'optparse'
+require 'pp'
+require 'socket'
+require 'rexml/document'
+
+# global for showing debug output if needed
+$TOR_DEBUG = false
+
+
+config = REXML::Document.new(File.new("/conf/config.xml"))
+$TOR_PASSWORD = config.elements['opnsense/OPNsense/tor/general/control_port_password'].text
+
+class TorCTL
+
+ def initialize
+ @tor = TCPSocket.new("127.0.0.1", 9051)
+ send_query("AUTHENTICATE \"#{$TOR_PASSWORD}\"")
+ end
+
+
+ # new ip: signal NEWNYM
+
+ def get_version
+ { version: send_query("GETINFO version") }
+ end
+
+ def close
+ @tor.puts("QUIT")
+ @tor.close
+ end
+
+ def send_query(str)
+ @tor.puts(str)
+ ret = ''
+ while (data = @tor.gets&.strip) && (!data.start_with? "250 ")
+ begin
+ res = data.scan(/^(\d{3})(.*)$/).first
+ if res[1][0] == '-'
+ ret << res[1][1..-1] + "\n"
+ else
+ ret << res[1] + "\n"
+ end
+ rescue
+ ret << data + "\n"
+ end
+ end
+ ret
+ end
+
+ def get_config(str)
+ send_query("getconf #{str}")
+ end
+
+ def get_info(str)
+ d = send_query("getinfo #{str}")
+ lines = d.lines
+ if lines.first.end_with? "=\n"
+ lines.shift # property=
+ lines.pop # .
+ else
+ lines[0] = lines[0][((lines[0].index "=") + 1)...(lines[0].length)]
+ end
+ lines.join
+ end
+
+ def get_circuit
+ lines = get_info('circuit-status').lines
+ pp lines if $TOR_DEBUG
+ lines.each(&:strip!)
+ ret = {}
+ lines.each do |line|
+ data = line.split(' ')
+ circuit_id = data.shift.to_i
+ status = data.shift
+ hosts = data.shift.split(',').map do |host_nickname|
+ h,n = host_nickname.split('~')
+ { host: h, nickname: n }
+ end
+ flags = data.map do |flag_entry|
+ flag_key, flag_value = flag_entry.split('=')
+ [flag_key, flag_value.split(',')]
+ end.to_h
+
+ ret[circuit_id] = { status: status,
+ hosts: hosts,
+ flags: flags }
+ end
+ ret
+ end
+
+ def stream_status
+ stream_status_data = get_info("stream-status")
+ result = []
+ stream_status_data.split(' ').each_slice(4) do |data_set|
+ d_ip, d_port = data_set[3].scan(/(.*):(\d+)/).first
+ result << { stream_id: data_set[0],
+ stream_status: data_set[1],
+ circuit_id: data_set[2],
+ destination_host: d_ip,
+ destination_port: d_port
+ }
+ end
+ result
+ end
+end
+
+
+options = {}
+
+OptionParser.new do |opts|
+ opts.banner = "Usage: #{__FILE__} ARGS"
+ opts.on("-s", "--stream_status", "Print stream status") do |od|
+ options[:action] = :stream_status
+ end
+ opts.on("-c", "--circuit", 'Print the Circuit') do |od|
+ options[:action] = :get_circuit
+ end
+ opts.on("-v", "--version", 'Print the Tor version') do |od|
+ options[:action] = :get_version
+ end
+ opts.on("-x", "--debug", "Prints debug output") do |od|
+ $TOR_DEBUG = true
+ end
+ opts.on("-h", "--help", "Prints this help") do
+ puts opts
+ exit
+ end
+end.parse!
+
+tor = TorCTL.new
+
+no_param_actions = [:get_circuit, :stream_status, :get_version]
+if no_param_actions.include? options[:action]
+ begin
+ data = tor.send(options[:action])
+ if data
+ puts data.to_json
+ else
+ puts error: "no data"
+ end
+ rescue
+ puts error: "execution error", error_str: $!
+ end
+end
+
+#puts tor.get_config("controlport")
+tor.close
+
+
diff --git a/security/tor/src/opnsense/service/conf/actions.d/actions_tor.conf b/security/tor/src/opnsense/service/conf/actions.d/actions_tor.conf
index 1eab63721..ad3672a4f 100644
--- a/security/tor/src/opnsense/service/conf/actions.d/actions_tor.conf
+++ b/security/tor/src/opnsense/service/conf/actions.d/actions_tor.conf
@@ -33,3 +33,15 @@ command:/usr/local/opnsense/scripts/tor/get_hostnames
parameters:
type:script_output
message:Query hostnames of Onion services
+
+[circuit]
+command:/usr/local/opnsense/scripts/tor/tor_diag -c
+parameters:
+type:script_output
+message:Query Tor circuit
+
+[streams]
+command:/usr/local/opnsense/scripts/tor/tor_diag -s
+parameters:
+type:script_output
+message:Query Tor stream information