aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorficus <ficus@robocracy.org>2012-09-25 15:59:18 +0200
committerficus <ficus@robocracy.org>2012-09-25 15:59:18 +0200
commit79b260db495e94430d499906f321dc022c68fec1 (patch)
tree71b33694a9b9f7fc7f43b611191dc2cd5d1e1fc5
parentfe4b8a01fc87d1a76fca8e8733270a260aa23cc0 (diff)
downloadtui-79b260db495e94430d499906f321dc022c68fec1.tar.gz
tui-79b260db495e94430d499906f321dc022c68fec1.zip
basic tor control (needs testing)
-rw-r--r--torouterui/sysstatus.py15
-rw-r--r--torouterui/templates/home.html8
-rw-r--r--torouterui/templates/logs.html1
-rw-r--r--torouterui/templates/tor.html29
-rw-r--r--torouterui/tor.py86
-rw-r--r--torouterui/util.py11
-rw-r--r--torouterui/views.py36
7 files changed, 168 insertions, 18 deletions
diff --git a/torouterui/sysstatus.py b/torouterui/sysstatus.py
index 2d19458..3887724 100644
--- a/torouterui/sysstatus.py
+++ b/torouterui/sysstatus.py
@@ -41,10 +41,10 @@ def get_resources_status():
d['disk_avail'] = disk_info[1]
d['disk_percent'] = int(disk_info[4][:-1])
- ram_info = cli_read_lines('free -m')[1].split()
- d['ram_used'] = "%sMB" % ram_info[2]
- d['ram_avail'] = "%sMB" % ram_info[1]
- d['ram_percent'] = int(float(ram_info[2])/float(ram_info[1]) * 100.0)
+ ram_info = cli_read_lines('free -m')
+ d['ram_used'] = "%sMB" % ram_info[2].split()[2]
+ d['ram_avail'] = "%sMB" % ram_info[1].split()[1]
+ d['ram_percent'] = int(float(d['ram_used'].strip('MB'))/float(d['ram_avail'].strip('MB')) * 100.0)
d['cpu_cores'] = 1
for l in open('/proc/cpuinfo', 'r'):
@@ -76,6 +76,13 @@ def get_syslog():
except IOError:
return None
+def get_torlog():
+ try:
+ with open('/var/log/tor/notices.log') as f:
+ return ''.join(f.readlines())
+ except IOError:
+ return None
+
def get_process_list():
"""
Example ``ps aux`` output:
diff --git a/torouterui/templates/home.html b/torouterui/templates/home.html
index 58ed2f2..fa9900c 100644
--- a/torouterui/templates/home.html
+++ b/torouterui/templates/home.html
@@ -71,11 +71,11 @@
<th>Version
<td style="font-family: monospace;">{% if status.tor.version %}{{ status.tor.version }} ({{ status.tor.version_current }}){% endif %}
<tr>
- <th>Traffic TX
- <td style="font-family: monospace;">{% if status.tor.traffic_written_bytes %}{{ status.tor.traffic_written_bytes }} bytes{% endif %}
+ <th>Total TX Data
+ <td style="font-family: monospace;">{% if status.tor.traffic_written_bytes != None %}{{ status.tor.traffic_written_bytes }} bytes{% endif %}
<tr>
- <th>Traffic RX
- <td style="font-family: monospace;">{% if status.tor.traffic_read_bytes %}{{ status.tor.traffic_read_bytes }} bytes{% endif %}
+ <th>Total RX Data
+ <td style="font-family: monospace;">{% if status.tor.traffic_read_bytes != None %}{{ status.tor.traffic_read_bytes }} bytes{% endif %}
</table>
</div>
</div>
diff --git a/torouterui/templates/logs.html b/torouterui/templates/logs.html
index c5ea52a..118c0e0 100644
--- a/torouterui/templates/logs.html
+++ b/torouterui/templates/logs.html
@@ -5,5 +5,6 @@
{{ lib.logbox("dmesg", logs.dmesg) }}
{{ lib.logbox("auth.log", logs.authlog) }}
{{ lib.logbox("syslog", logs.syslog) }}
+{{ lib.logbox("tor", logs.tor) }}
{% endblock %}
diff --git a/torouterui/templates/tor.html b/torouterui/templates/tor.html
index a1f30dc..327ac59 100644
--- a/torouterui/templates/tor.html
+++ b/torouterui/templates/tor.html
@@ -5,9 +5,32 @@
<form action="/tor/" method="POST" class="form-horizontal">
<legend>Tor Network Configuration</legend>
-{{ lib.formcheckbox(form, formerr, 'torenable', 'Enable Tor daemon', 'true') }}
-{{ lib.formcheckbox(form, formerr, 'torrelayenable', 'Enable Tor Relay', 'true') }}
-{{ lib.formcheckbox(form, formerr, 'torbridgeenable', 'Enable Tor Bridge', 'true') }}
+{{ lib.formcheckbox(form, formerr, 'tor_enable', 'Enable Tor daemon', 'true') }}
+
+{{ lib.forminput(form, formerr, 'tor_sockslistenaddress', 'SOCKS Proxy Listen Address', '127.0.0.1:9050') }}
+{{ lib.forminput(form, formerr, 'tor_virtualaddrnetwork', 'Virtual Address Network', '192.168.0.0/16') }}
+{{ lib.forminput(form, formerr, 'tor_translistenaddress', 'Trans Listen Address', '127.0.0.1:9040') }}
+{{ lib.forminput(form, formerr, 'tor_dnslistenaddress', 'DNS Listen Address', '127.0.0.1:5353') }}
+
+<legend>Exit Node Configuration</legend>
+{{ lib.formcheckbox(form, formerr, 'tor_exitnodeenable', 'Enable Exit Node', 'true') }}
+
+<legend>Relay Configuration</legend>
+<label class="radio">
+ <input type="radio" name="tor_relaytype" id="tor_relaytypenode" value="none" {% if form.tor_relaytype == "none" %}checked{% endif %}>
+ <h4>Not a Relay Node</h4>
+</label>
+<label class="radio">
+ <input type="radio" name="tor_relaytype" id="tor_relaytypebridge" value="bridge" {% if form.tor_relaytype == "bridge" %}checked{% endif %}>
+ <h4>Bridge Relay Node</h4>
+</label>
+<label class="radio">
+ <input type="radio" name="tor_relaytype" id="tor_relaytyperelay" value="relay" {% if form.tor_relaytype == "relay" %}checked{% endif %}>
+ <h4>Regular Relay Node</h4>
+</label>
+
+{{ lib.forminput(form, formerr, 'tor_relaybandwidthrateKBps', 'Relay Node Bandwidth (KB/sec)', '50') }}
+{{ lib.forminput(form, formerr, 'tor_relaybandwidthburstKBps', 'Relay Node Burst Bandwidth (KB/sec)', '75') }}
<div class="pull-right">
<a href="."><button class="btn" type="button">Reset</button></a>
diff --git a/torouterui/tor.py b/torouterui/tor.py
index cf18ce2..a44aea4 100644
--- a/torouterui/tor.py
+++ b/torouterui/tor.py
@@ -2,12 +2,18 @@
Helper code for interacting with Tor and modifying the Tor system
configuration.
"""
+import os
+import time
from TorCtl import TorCtl
+import util
def tor_getinfo(conn, key):
return conn.get_info(key)[key]
+def tor_getoption(conn, key):
+ return conn.get_option(key)[0][1]
+
def get_tor_status():
"""Ask for status over torctl pipe"""
d = dict()
@@ -35,6 +41,7 @@ def get_tor_status():
d['version_current'] = tor_getinfo(conn, 'status/version/current')
d['circuit_established'] = bool(
tor_getinfo(conn, 'status/circuit-established'))
+ d['is_alive'] = conn.is_live()
if d['circuit_established']:
d['state'] = 'ESTABLISHED'
else:
@@ -46,9 +53,82 @@ def get_tor_status():
def get_tor_settings():
"""Ask for settings over torctl pipe; don't use augeas"""
d = dict()
- return d
+ conn = TorCtl.connect()
+ if not conn:
+ # couldn't connect; will need to display error to user
+ return None
+ d['tor_relaybandwidthrateKBps'] = \
+ int(int(tor_getoption(conn, 'RelayBandwidthRate'))/1024.)
+ d['tor_relaybandwidthburstKBps'] = \
+ int(int(tor_getoption(conn, 'RelayBandwidthBurst'))/1024.)
+
+ d['tor_sockslistenaddress'] = tor_getoption(conn, 'SocksListenAddress')
+ d['tor_virtualaddrnetwork'] = tor_getoption(conn, 'VirtualAddrNetwork')
+ d['tor_translistenaddress'] = tor_getoption(conn, 'TransListenAddress')
+ d['tor_dnslistenaddress'] = tor_getoption(conn, 'DNSListenAddress')
+ d['tor_enable'] = (not bool(int(tor_getoption(conn, 'DisableNetwork')))) and 'true'
+ if tor_getoption(conn, 'ExitPolicy') == 'reject *:*':
+ d['tor_exitnodeenable'] = False
+ else:
+ d['tor_exitnodeenable'] = 'true'
+
+ orport = tor_getoption(conn, 'ORPort')
+ bridgerelay = tor_getoption(conn, 'BridgeRelay')
+ if orport == 'auto' and bridgerelay == '0':
+ d['tor_relaytype'] = 'relay'
+ elif orport == 'auto' and bridgerelay == '1':
+ d['tor_relaytype'] = 'bridge'
+ elif orport == '0':
+ d['tor_relaytype'] = 'none'
+ else:
+ print "WARNING: unknown tor_relaytype state"
+ d['tor_relaytype'] = 'unknown'
+
+ conn.close()
+ return d
-def save_tor_settings():
+def save_tor_settings(form):
"""Commit settings through torctl pipe, then send SAVECONF"""
- pass
+ conn = TorCtl.connect()
+ if not conn:
+ print "Warning: couldn't connect to tor daemon; need to boot up tor daemon in disabled state"
+ os.system('echo "DisableNetwork 1" >> /etc/tor/torrc')
+ # tor daemon should always be running, even if disabled
+ util.enable_service('tor')
+ time.sleep(3)
+ conn = TorCtl.connect()
+ if not conn:
+ raise Exception("Could not start tor daemon!")
+
+ conn.set_option('RelayBandwidthRate',
+ "%dKB" % int(form['tor_relaybandwidthrateKBps']))
+ conn.set_option('RelayBandwidthBurst',
+ "%dKB" % int(form['tor_relaybandwidthburstKBps']))
+
+ conn.set_option('DNSListenAddress', form['tor_dnslistenaddress'])
+ conn.set_option('SocksListenAddress', form['tor_sockslistenaddress'])
+ conn.set_option('VirtualAddrNetwork', form['tor_virtualaddrnetwork'])
+ conn.set_options([('TransListenAddress', form['tor_translistenaddress']),
+ ('TransPort', form['tor_translistenport'])])
+
+ if form.get('tor_enable') == 'true':
+ conn.set_option('DisableNetwork', '0')
+ else:
+ conn.set_option('DisableNetwork', '1')
+
+ if form.get('tor_exitnodeenable') == 'true':
+ conn.set_option('ExitPolicy', '')
+ else:
+ conn.set_option('ExitPolicy', 'reject *:*')
+
+ if form['tor_relaytype'] == 'relay':
+ conn.set_options([('ORPort', 'auto'), ('BridgeRelay', '0')])
+ elif form['tor_relaytype'] == 'bridge':
+ conn.set_options([('ORPort', 'auto'), ('BridgeRelay', '1')])
+ else: # type = 'none'
+ conn.set_options([('ORPort', '0'), ('BridgeRelay', '0')])
+
+ conn.save_conf()
+ conn.close()
+
diff --git a/torouterui/util.py b/torouterui/util.py
index dc3b6c0..c459fa0 100644
--- a/torouterui/util.py
+++ b/torouterui/util.py
@@ -17,6 +17,17 @@ def fs_read(path):
with open(path, 'r') as f:
return ''.join(f.readlines())
+def enable_service(name):
+ os.system('update-rc.d %s defaults &' % name)
+ # safe to "restart" most services if they are already running
+ os.system('/etc/init.d/%s start &' % name)
+
+def disable_service(name):
+ """Currently, this is never actually called"""
+ os.system('update-rc.d %s remove &' % name)
+ # safe to "restart" most services if they are already running
+ os.system('/etc/init.d/%s stop &' % name)
+
def prefix_to_ipv4_mask(prefixlen):
assert(prefixlen >= 0)
assert(prefixlen <= 32)
diff --git a/torouterui/views.py b/torouterui/views.py
index af17be8..12efb1d 100644
--- a/torouterui/views.py
+++ b/torouterui/views.py
@@ -59,7 +59,7 @@ def wanpage():
form = netif.get_wan_settings()
return render_template('wan.html', form=form, status=status,
formerr=None)
- # Got this far, need to validated form
+ # Got this far, need to validate form
formerr = dict()
if request.form['ipv4method'] == 'disabled':
pass # no further validation
@@ -106,7 +106,7 @@ def lanpage():
form = netif.get_lan_settings()
return render_template('lan.html', form=form, status=status,
formerr=None)
- # Got this far, need to validated form
+ # Got this far, need to validate form
formerr = dict()
if request.form['ipv4method'] == 'disabled':
pass # no further validation
@@ -151,7 +151,7 @@ def wifipage():
form = netif.get_wifi_settings()
return render_template('wifi.html', form=form, status=status,
formerr=None)
- # Got this far, need to validated form
+ # Got this far, need to validate form
formerr = dict()
if request.form['ipv4method'] == 'disabled':
pass # no further validation
@@ -185,8 +185,35 @@ def wifipage():
@app.route('/tor/', methods=['GET', 'POST'])
def torpage():
- # TODO: unimplemented
msg = list()
+ status = dict()
+ status['tor'] = tor.get_tor_status()
+ if request.method == 'GET':
+ if status['tor']['state'] == 'DISABLED':
+ msg.append(("warning",
+ "Could not connect to Tor daemon for control. Will try to restart daemon if settings are saved from this page."),)
+ form = None
+ else:
+ form = tor.get_tor_settings()
+ print form
+ return render_template('tor.html', form=form, status=status,
+ formerr=None, messages=msg)
+ # Got this far, need to validate form
+ formerr = dict()
+ # TODO: form validation
+ if len(formerr.keys()) > 0:
+ msg.append(("error",
+ "Please correct the validation issues below"),)
+ else:
+ # Ok, we have a valid form, now to commit it
+ try:
+ tor.save_tor_settings(request.form)
+ msg.append(("success",
+ "Configuration saved! Check logs for any errors"),)
+ except Exception, err:
+ msg.append(("error",
+ "Was unable to commit changes...\"%s\""
+ % err))
return render_template('tor.html', settings=None, status=None,
form=request.form, formerr=None, messages=msg)
@@ -196,6 +223,7 @@ def logspage():
logs['dmesg'] = sysstatus.get_dmesg()
logs['syslog'] = sysstatus.get_syslog()
logs['authlog'] = sysstatus.get_authlog()
+ logs['tor'] = sysstatus.get_torlog()
return render_template('logs.html', logs=logs)
@app.route('/processes/', methods=['GET'])