diff options
author | ficus <ficus@robocracy.org> | 2012-09-15 19:46:49 +0200 |
---|---|---|
committer | ficus <ficus@robocracy.org> | 2012-09-15 19:46:49 +0200 |
commit | 42725426ec02d359b67cd8d665afe17882d38958 (patch) | |
tree | 148c4082998f7d0b82ec4f22515d7626fca6a0e7 | |
parent | a304d7a56563b16ca98d9b45ebed521c52f6347c (diff) | |
download | tui-42725426ec02d359b67cd8d665afe17882d38958.tar.gz tui-42725426ec02d359b67cd8d665afe17882d38958.zip |
more WIP
-rw-r--r-- | TODO | 22 | ||||
-rw-r--r-- | helpers/netif.py | 188 | ||||
-rw-r--r-- | helpers/sysstatus.py | 26 | ||||
-rw-r--r-- | helpers/tor.py | 11 | ||||
-rw-r--r-- | helpers/util.py | 2 | ||||
-rw-r--r-- | templates/base.html | 12 | ||||
-rw-r--r-- | templates/home.html | 96 | ||||
-rw-r--r-- | templates/lan.html | 32 | ||||
-rw-r--r-- | templates/lib.html | 65 | ||||
-rw-r--r-- | templates/processes.html | 6 | ||||
-rw-r--r-- | templates/tor.html | 19 | ||||
-rw-r--r-- | templates/wan.html | 35 | ||||
-rw-r--r-- | templates/wifi.html | 38 | ||||
-rwxr-xr-x | torouterui.py | 155 |
14 files changed, 625 insertions, 82 deletions
@@ -3,7 +3,7 @@ - imitate Tomato firmware style/layout - flask python web framework -- bootstrap with non-standard color scheme +- bootstrap with a non-standard color scheme - modularize configuration "nuggets"; compare and apply changes all or none - write nugget getters/setters @@ -12,16 +12,20 @@ - in some cases execute changes without restart? - monitoring - enable/disable - bandwidth and system status charts via... mrtg? nagios? - dmesg, syslog, auth, ??? - top + dmesg, syslog, auth + ps aux - front page status uptime current cpu, disk, ram utilization upstream: dhcp ip equivalent + last login (?) +- about + uname + software versions + project links - administration + hostname (?) ssh access, keys autocron updates - WAN network @@ -35,11 +39,19 @@ torification - tor generic status + enable relay + enable bridge common configuration # Later +- dhcp configuration +- enable/disable hotplug in interfaces when method changes +- flesh out README +- installation script +- debian packaging - admin authentication scheme +- not-root permissions scheme for: interfaces, tor, wireless, ssh keys - firewall configuration port forwarding enable remote login diff --git a/helpers/netif.py b/helpers/netif.py index 6d7a194..77f710c 100644 --- a/helpers/netif.py +++ b/helpers/netif.py @@ -1,5 +1,6 @@ import os +import augeas from util import * @@ -20,6 +21,10 @@ def parse_ip(ifname): for k, v in val_indexes.iteritems(): if len(iplinkl) > v and iplinkl[v] == k: d[k] = iplinkl[v+1] + if 'LOWER_UP' in iplinkl[2][1:-1].split(","): + d['state'] = "RUNNING" + elif 'NO-CARRIER' in iplinkl[2][1:-1].split(","): + d['state'] = "DISCONNECTED" d['ipv4addrs'] = list() d['ipv6addrs'] = list() for l in ipinfo[1:]: @@ -38,15 +43,121 @@ def parse_ip(ifname): addr=l[1].split('/')[0], prefix=int(l[1].split('/')[1]), scope=l[3])) - print d['ipv6addrs'] return d -def get_wan_status(ifname='eth1'): +def parse_iw(ifname): + """ + Example `iw dev wlan0 link` string (sic): + + Connected to c0:25:06:51:22:9b (on wlan0) + SSID: fleischfressendepflanze + freq: 2427 + RX: 73744193 bytes (456838 packets) + TX: 3269174 bytes (19709 packets) + signal: -44 dBm + tx bitrate: 72.2 MBit/s MCS 7 short GI + + bss flags: + dtim period: 0 + beacon int: 100 + """ + d = dict() + iwinfo = cli_read_lines('iw dev %s link' % ifname) + if 0 == len(iwinfo): + raise KeyError('No such interface: ' + ifname) + if iwinfo[0].strip() == "Not connected.": + d['radio_state'] = "disabled" + return d + else: + d['radio_state'] = "enabled" + for l in iwinfo: + l = l.strip() + if l.startswith("SSID:"): + d['ssid'] = l[6:].strip() + elif l.startswith("freq:"): + d['freq'] = "%sMHz" % l.split()[-1].strip() + elif l.startswith("signal:"): + d['signal_dbm'] = l.split()[1] + elif l.startswith("tx bitrate:"): + d['signal_throughput'] = ' '.join(l.split()[2:4]) + return d + +def read_augeas_ifinfo(ifname): + d = dict() + aug = augeas.Augeas(flags=augeas.Augeas.NO_MODL_AUTOLOAD) + aug.set("/augeas/load/Interfaces/lens", "Interfaces.lns") + aug.set("/augeas/load/Interfaces/incl", "/etc/network/interfaces") + aug.load() + for iface in aug.match("/files/etc/network/interfaces/iface"): + if aug.get(iface) == ifname: + if aug.get(iface + "/family") == 'inet': + d['ipv4method'] = aug.get(iface + "/method") + if d['ipv4method'] == 'manual': + d['ipv4method'] = 'disabled' + d['ipv4addr'] = aug.get(iface + "/address") + d['ipv4netmask'] = aug.get(iface + "/netmask") + d['ipv4gateway'] = aug.get(iface + "/gateway") + d['ipv4mtu'] = aug.get(iface + "/mtu") + d['ipv4mac'] = aug.get(iface + "/hwaddress") + elif aug.get(iface + "/family") == 'inet6': + # handle ipv6 stuff + pass + aug.close() + return d + aug.close() + return None + +def write_augeas_ifinfo(ifname, settings, method='disabled'): + d = dict() + aug = augeas.Augeas(flags=augeas.Augeas.NO_MODL_AUTOLOAD) + aug.set("/augeas/load/Interfaces/lens", "Interfaces.lns") + aug.set("/augeas/load/Interfaces/incl", "/etc/network/interfaces") + aug.load() + path = None + for iface in aug.match("/files/etc/network/interfaces/iface"): + if aug.get(iface) == ifname and aug.get(iface + "/family") == 'inet': + path = iface + if not path: + # insert iface + if len(aug.match("/files/etc/network/interfaces/iface")) == 0: + # no interfaces at all, insert wherever + path = "/files/etc/network/interfaces/iface" + aug.set(path, ifname) + else: + aug.insert("/files/etc/network/interfaces/iface", "iface", + before=False) + path = aug.match("/files/etc/network/interfaces/iface")[-1] + aug.set(path, ifname) + assert path, "require path to be set" + aug.set(path + "/family", 'inet') + if method == 'disabled': + aug.set(path + "/method", 'manual') + aug.remove(path + "/address") + aug.remove(path + "/netmask") + aug.remove(path + "/gateway") + elif method == 'dhcp': + aug.set(path + "/method", 'dhcp') + aug.remove(path + "/address") + aug.remove(path + "/netmask") + aug.remove(path + "/gateway") + elif method == 'static': + aug.set(path + "/method", 'static') + aug.set(path + "/address", str(settings['ipv4addr'])) + aug.set(path + "/netmask", str(settings['ipv4netmask'])) + aug.set(path + "/gateway", str(settings['ipv4gateway'])) + else: + raise ValueError("unrecognized network interface method: " + method) + print "committing with augeas..." + aug.save() + print "augeas errors: %s" % aug.get("/augeas/error") + aug.close() + +def get_wan_status(ifname='eth0'): d = dict() try: d.update(parse_ip(ifname)) except KeyError: - None + return None return d def get_lan_status(ifname='eth0'): @@ -54,15 +165,80 @@ def get_lan_status(ifname='eth0'): try: d.update(parse_ip(ifname)) except KeyError: - None + return None return d -def get_wireless_status(ifname='wlan0'): +def get_wifi_status(ifname='wlan0'): d = dict() try: d.update(parse_ip(ifname)) except KeyError, ke: - raise ke return None + d.update(parse_iw(ifname)) return d +def get_wan_settings(ifname='eth0'): + return read_augeas_ifinfo(ifname) + +def save_wan_settings(form, ifname='eth0'): + write_augeas_ifinfo(ifname, method=form['ipv4method'], settings=form) + if form['ipv4method'] == 'disabled': + print "ifdown..." + os.system("ifdown %s" % ifname) + else: + print "ifup..." + os.system("ifdown %s" % ifname) + os.system("ifup %s &" % ifname) + +def get_lan_settings(ifname='eth0'): + d = read_augeas_ifinfo(ifname) + return d + +def save_lan_settings(ifname='eth0'): + write_augeas_ifinfo(ifname, method=form['ipv4method'], settings=form) + if form['ipv4method'] == 'disabled': + print "ifdown..." + os.system("ifdown %s" % ifname) + else: + print "ifup..." + os.system("ifdown %s" % ifname) + os.system("ifup %s &" % ifname) + +def get_wifi_settings(ifname='wlan0'): + #d = read_augeas_ifinfo(ifname) + d = dict() + if not d: + return d + d.update(dict()) # extra wireless settings + return d + +def save_wifi_settings(ifname='eth0'): + pass + +def is_valid_ipv4(s): + # TODO: this is a hack + l = s.split('.') + if not len(l) == 4: + return False + try: + l = map(int, l) + except ValueError: + return False + if l[0] > 255 or l[1] > 255 or l[2] > 255 or l[3] > 255: + return False + if l[0] == 0 or l[3] == 0: + return False + return True + +def is_valid_ipv4mask(s): + # TODO: this is a hack + l = s.split('.') + if not len(l) == 4: + return False + try: + l = map(int, l) + except ValueError: + return False + if l[0] > 255 or l[1] > 255 or l[2] > 255 or l[3] > 255: + return False + return True diff --git a/helpers/sysstatus.py b/helpers/sysstatus.py index b2eec6f..933f625 100644 --- a/helpers/sysstatus.py +++ b/helpers/sysstatus.py @@ -12,6 +12,28 @@ def get_system_status(): d['uptime'] = cli_read('uptime') return d +def get_resources_status(): + d = dict() + disk_info = cli_read_lines('df -h /home')[1].split() + d['disk_used'] = disk_info[2] + 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) + + d['cpu_cores'] = 1 + for l in open('/proc/cpuinfo', 'r'): + if l.split(":")[0].strip() == "cpu cores": + d['cpu_cores'] = int(l.split(":")[-1].strip()) + break + cpu_info = cli_read('uptime') + d['cpu_load'] = cpu_info.split()[-3].strip(',') + d['cpu_percent'] = int(float(d['cpu_load'])/float(d['cpu_cores']) * 100.0) + return d + def get_dmesg(): try: return cli_read('dmesg') @@ -21,14 +43,14 @@ def get_dmesg(): def get_authlog(): try: with open('/var/log/auth.log') as f: - return '\n'.join(f.readlines()) + return ''.join(f.readlines()) except IOError: return None def get_syslog(): try: with open('/var/log/syslog') as f: - return '\n'.join(f.readlines()) + return ''.join(f.readlines()) except IOError: return None diff --git a/helpers/tor.py b/helpers/tor.py index e69de29..438cb5d 100644 --- a/helpers/tor.py +++ b/helpers/tor.py @@ -0,0 +1,11 @@ + +def get_tor_status(): + d = dict() + d['state'] = 'DISABLED' + return d + +def get_tor_settings(): + return dict() + +def save_tor_settings(): + pass diff --git a/helpers/util.py b/helpers/util.py index 46030bf..229d975 100644 --- a/helpers/util.py +++ b/helpers/util.py @@ -11,7 +11,7 @@ def cli_read_lines(cmd): def fs_read(path): with open(path, 'r') as f: - return '\n'.join(f.readlines()).strip() + return ''.join(f.readlines()) def prefix_to_ipv4_mask(prefixlen): assert(prefixlen >= 0) diff --git a/templates/base.html b/templates/base.html index a2c1407..4c15c73 100644 --- a/templates/base.html +++ b/templates/base.html @@ -37,13 +37,12 @@ <li {% if path == request.path %}class="active"{% endif %}><a href="{{path}}">{{name}}</a></li> {%- endmacro %} {{ pagelink("/", "Status") }} - {{ pagelink("/admin/", "Administration") }} {{ pagelink("/reboot/", "Reboot...") }} <li class="nav-header">Configuration</li> - {{ pagelink("/wan/", "Upstream") }} - {{ pagelink("/lan/", "Local") }} - {{ pagelink("/wireless/", "Wireless") }} - {{ pagelink("/tor/", "Tor") }} + {{ pagelink("/wan/", "Upstream Ethernet") }} + {{ pagelink("/lan/", "Local Ethernet") }} + {{ pagelink("/wifi/", "WiFi") }} + {{ pagelink("/tor/", "Tor Network") }} <li class="nav-header">Monitoring</li> {{ pagelink("/logs/", "Logs") }} {{ pagelink("/processes/", "Processes") }} @@ -51,8 +50,8 @@ </div><!--/.well --> </div><!--/span--> <div class="span9"> - {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} + {{ mesages }} {% for category, message in messages %} <div class="alert alert-{{ category }}"> <button type="button" class="close" data-dismiss="alert">×</button> @@ -63,7 +62,6 @@ </div> {% endfor %} {% endif %} - {% endwith %} {% block body %}{% endblock %} </div><!--/span--> </div><!--/row--> diff --git a/templates/home.html b/templates/home.html index 30c328e..fa2ed2b 100644 --- a/templates/home.html +++ b/templates/home.html @@ -1,39 +1,71 @@ {% import "lib.html" as lib %} {% extends "base.html" %} {% block body %} -<h3>System</h3> -<table class="table table-condensed"> - <tr> - <th>Host Name - <td><code>{{ status.system.hostname }}</code> - <tr> - <th>Current Time - <td><code>{{ status.system.current_time }}</code> - <tr> - <th>System Uptime - <td><code>{{ status.system.uptime }}</code> -</table> -<h3>WAN</h3> -{% if not status.wan %} -Upstream ethernet interface hardware not detected at all! -{% else %} -{{ lib.ifstatus(status.wan) }} -{% endif %} - -<h3>LAN</h3> -{% if not status.lan %} -Local network ethernet interface hardware not detected at all! -{% else %} -{{ lib.ifstatus(status.lan) }} -{% endif %} - -<h3>Wireless</h3> -{% if not status.wireless %} -Wireless interface hardware not detected at all! -{% else %} -{{ lib.ifstatus(status.wireless) }} -{% endif %} +<div class="row-fluid"> + <div class="span6"> + <h3>System</h3> + <table class="table table-condensed"> + <tr> + <th>Host Name + <td><span style="font-family:monospace;">{{ status.system.hostname }}</span> + <tr> + <th>Current Time + <td><span style="font-family:monospace;">{{ status.system.current_time }}</span> + <tr> + <th>System Uptime + <td><span style="font-family:monospace;">{{ status.system.uptime }}</span> + </table> + </div> + <div class="span6"> + <h3>Resources</h3> + <ul class="unstyled"> + <li> + CPU Load<span class="pull-right strong">{{status.resources.cpu_load}} / {{status.resources.cpu_cores}} cores</span> + <div class="progress progress-striped "> + <div class="bar" style="width: {{status.resources.cpu_percent}}%;"></div> + </div> + </li> + <li>RAM Usage<span class="pull-right strong">{{status.resources.ram_used}} / {{status.resources.ram_avail}}</span> + <div class="progress progress-success progress-striped "> + <div class="bar" style="width: {{ status.resources.ram_percent }}%;"></div> + </div> + </li> + <li>Primary Disk Space<span class="pull-right strong">{{status.resources.disk_used}} / {{status.resources.disk_avail}}</span> + <div class="progress progress-warning progress-striped "> + <div class="bar" style="width: {{ status.resources.disk_percent }}%;"></div> + </div> + </li> + </ul> + </div> +</div> +<div class="row-fluid"> + <div class="span6"> + <h3>WAN</h3> + {{ lib.ifstatus(status.wan) }} + </div> + <div class="span6"> + <h3>LAN</h3> + {{ lib.ifstatus(status.lan) }} + </div> +</div> +<div class="row-fluid"> + <div class="span6"> + <h3>WiFi</h3> + {{ lib.ifstatus(status.wifi) }} + </div> + <div class="span6"> + <h3>Tor</h3> + <table class="table table-condensed {% if status.tor.state in ["DISABLED"] %}muted{% endif %}"> + <tr> + <th>Status + <td><span style="font-weight: bold;" class="label + {% if status.tor.state == 'RUNNING' %}label-success{% elif status.tor.state == 'STARTING' %}label-info{% else %}label-important{% endif %}"> + {{ status.tor.state }} + </span> + </table> + </div> +</div> {% endblock %} diff --git a/templates/lan.html b/templates/lan.html new file mode 100644 index 0000000..09bcf0a --- /dev/null +++ b/templates/lan.html @@ -0,0 +1,32 @@ +{% import "lib.html" as lib %} +{% extends "base.html" %} +{% block body %} + +<form action="/lan/" method="POST" class="form-horizontal"> +<legend>Local Ethernet Configuration</legend> + +{% if not status.lan %} +<span class="text-error">Could not find the local ethernet hardware device!</span> +{% else %} + +{{ lib.formcheckbox(form, formerr, 'ipv4enable', 'Enable this interface', 'true') }} + +<legend>Address Configuration</legend> +{{ lib.forminput(form, formerr, 'ipv4addr', 'IPv4 Address', '0.0.0.0') }} +{{ lib.forminput(form, formerr, 'ipv4netmask', 'Netmask', '255.255.0.0') }} +{{ lib.forminput(form, formerr, 'ipv4gateway', 'Gateway IP Address', '0.0.0.0') }} + +<legend>DHCP Configuration</legend> +{{ lib.forminput(form, formerr, 'dhcpbase', 'DHCP Range Base', '192.168.1.100') }} +{{ lib.forminput(form, formerr, 'dhcptop', 'DHCP Range Top', '192.168.1.200') }} +{{ lib.forminput(form, formerr, 'dhcptime', 'Lease Time', '12h') }} + +<div class="pull-right"> +<a href="."><button class="btn" type="button">Reset</button></a> +<button type="submit" class="btn btn-primary" type="button"> +Save</button> +</div> +</form> +{% endif %} + +{% endblock %} diff --git a/templates/lib.html b/templates/lib.html index 33534da..6ac5e12 100644 --- a/templates/lib.html +++ b/templates/lib.html @@ -1,41 +1,84 @@ + {% macro ifstatus(ifstatus) -%} -<table class="table table-condensed"> +{% if not ifstatus %} +<span class="text-error"> +Network hardware not detected at all! +</span> +{% else %} +<table class="table table-condensed {% if ifstatus.state in ["DOWN", "DISCONNECTED"] %}muted{% endif %}"> <tr> <th>Interface Name - <td><code>{{ ifstatus.ifname }}</code> + <td><span style="font-family:monospace;">{{ ifstatus.ifname }}</span> <tr> <th>Status - <td><span style="font-weight: bold; color: - {% if ifstatus.state == 'UP' %}green{% else %}red{% endif %};"> + <td><span style="font-weight: bold;" class="label + {% if ifstatus.state == 'RUNNING' %}label-success{% elif ifstatus.state == 'up' %}label-info{% else %}label-important{% endif %}"> {{ ifstatus.state }} </span> <tr> <th>MAC Address - <td><code>{{ ifstatus.mac }}</code> + <td><span style="font-family:monospace;">{{ ifstatus.mac }}</span> <tr> <th>IPv4 Addresses - <td><code> + <td><span style="font-family:monospace;"> {% for addr in ifstatus.ipv4addrs %} {{ addr.addr }}/{{ addr.prefix}} ({{ addr.scope }})<br> - {% endfor %}</code> + {% endfor %}</span> <tr> <th>IPv6 Addresses - <td><code> + <td><span style="font-family:monospace;"> {% for addr in ifstatus.ipv6addrs %} {{ addr.addr }}/{{ addr.prefix}} ({{ addr.scope }})<br> - {% endfor %}</code> + {% endfor %}</span> + {% if ifstatus.radio_state %} + <tr> + <th>Radio State + <td><span style="font-family:monospace;">{{ ifstatus.radio_state }}</span> + <tr> + <th>SSID + <td><span style="font-family:monospace;">{{ ifstatus.ssid }}</span> + <tr> + <th>Frequency + <td><span style="font-family:monospace;">{{ ifstatus.freq }}</span> + <tr> + <th>Signal Strength + <td><span style="font-family:monospace;">{{ ifstatus.signal_dbm }}</span> + {% endif %} </table> +{% endif %} {%- endmacro %} + {% macro logbox(name, contents) -%} <h3>{{name}}</h3> {% if contents == None %} <span class="text-error">Access to {{name}} was denied, or file did not exist.</span> {% else %} - -<pre style="height: 18em; width 40em; overflow: auto;"> +<div style="height: 18em; width: 60em;"> +<pre style="height: 18em; width 60em; overflow: auto;"> {{ contents }} </pre> +</div> {% endif%} {%- endmacro %} + + +{% macro forminput(form, formerr, name, title, placeholder) -%} +<div class="control-group {% if formerr[name] %}error{% endif %}"> + <label class="control-label" for="{{name}}">{{ title }}</label> + <div class="controls"> + <input type="text" name="{{name}}" placeholder="{{placeholder}}" {% if form[name] %}value="{{ form[name] }}"{% endif %}> + {% if formerr[name] %} + <span class="help-inline">{{ formerr[name] }}</span> + {% endif %} + </div> +</div> +{%- endmacro %} + +{% macro formcheckbox(form, formerr, name, title, value) -%} + <label class="checkbox"> + <input type="checkbox" name="{{name}}" id="{{name}}" value="{{value}}" {% if form[name] == value %}checked{% endif %}> + <h4>{{title}}</h4> + </label> +{% endmacro %} diff --git a/templates/processes.html b/templates/processes.html index c911b0a..2e35162 100644 --- a/templates/processes.html +++ b/templates/processes.html @@ -8,12 +8,12 @@ <th>PID <th>%CPU <th>%MEM - <th>Status Code + <th>Status <th>Started <th>Time <th>Command {% for proc in process_list %} - <tr> + <tr style="font-family: monospace;"> <td>{{ proc.user }} <td>{{ proc.pid}} <td>{{ proc.perc_cpu }} @@ -21,7 +21,7 @@ <td>{{ proc.status_code }} <td>{{ proc.started }} <td>{{ proc.time }} - <td>{{ proc.command }} + <td><div style="height: 1.5em; overflow:hidden;">{{ proc.command }}</div> {% endfor %} </table> diff --git a/templates/tor.html b/templates/tor.html new file mode 100644 index 0000000..a1f30dc --- /dev/null +++ b/templates/tor.html @@ -0,0 +1,19 @@ +{% import "lib.html" as lib %} +{% extends "base.html" %} +{% block body %} + +<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') }} + +<div class="pull-right"> +<a href="."><button class="btn" type="button">Reset</button></a> +<button type="submit" class="btn btn-primary" type="button"> +Save</button> +</div> +</form> + +{% endblock %} diff --git a/templates/wan.html b/templates/wan.html index e69de29..2da2733 100644 --- a/templates/wan.html +++ b/templates/wan.html @@ -0,0 +1,35 @@ +{% import "lib.html" as lib %} +{% extends "base.html" %} +{% block body %} + +<form action="/wan/" method="POST" class="form-horizontal"> +<legend>Upstream Ethernet Configuration</legend> + +<label class="radio"> + <input type="radio" name="ipv4method" id="ipv4methoddhcp" value="dhcp" {% if form.ipv4method == "dhcp" %}checked{% endif %}> + <h4>Automatic DHCP Addressing</h4> +</label> + +<label class="radio"> + <input type="radio" name="ipv4method" id="ipv4methodstatic" value="static" {% if form.ipv4method == "static" %}checked{% endif %}> + <h4>Manual Addressing</h4> +</label> + +{{ lib.forminput(form, formerr, 'ipv4addr', 'IPv4 Address', '0.0.0.0') }} +{{ lib.forminput(form, formerr, 'ipv4netmask', 'Netmask', '255.255.255.0') }} +{{ lib.forminput(form, formerr, 'ipv4gateway', 'Gateway IP Address', '0.0.0.0') }} + +<label class="radio"> + <input type="radio" name="ipv4method" id="ipv4methoddisabled" value="disabled" {% if form.ipv4method == "disabled" %}checked{% endif %}> + <h4>Disable Interface</h4> +</label> + +<div class="pull-right"> +<a href="."><button class="btn" type="button">Reset</button></a> +<button type="submit" class="btn btn-primary" type="button"> +Save</button> +</div> +</form> + + +{% endblock %} diff --git a/templates/wifi.html b/templates/wifi.html new file mode 100644 index 0000000..3e41788 --- /dev/null +++ b/templates/wifi.html @@ -0,0 +1,38 @@ +{% import "lib.html" as lib %} +{% extends "base.html" %} +{% block body %} + +<form action="/wifi/" method="POST" class="form-horizontal"> +<legend>WiFi Configuration</legend> + +{% if not status.wifi %} +<span class="text-error">Could not find the WiFi hardware device!</span> +{% else %} + +{{ lib.formcheckbox(form, formerr, 'wifienable', 'Enable the radio', 'true') }} +{{ lib.formcheckbox(form, formerr, 'torifylanenable', 'Transparently "Tor-ify" this network interface', 'true') }} + +<legend>Radio</legend> +{{ lib.forminput(form, formerr, 'wifissid', 'SSID name', 'internet') }} +{{ lib.forminput(form, formerr, 'wifipower', 'Transmit Power', 'high, low') }} +{{ lib.forminput(form, formerr, 'wifichannel', 'Channel', '11') }} + +<legend>Network Address</legend> +{{ lib.forminput(form, formerr, 'ipv4addr', 'IPv4 Address', '0.0.0.0') }} +{{ lib.forminput(form, formerr, 'ipv4netmask', 'Netmask', '255.255.0.0') }} +{{ lib.forminput(form, formerr, 'ipv4gateway', 'Gateway IP Address', '0.0.0.0') }} + +<legend>DHCP Server</legend> +{{ lib.forminput(form, formerr, 'dhcpbase', 'DHCP Range Base', '192.168.1.100') }} +{{ lib.forminput(form, formerr, 'dhcptop', 'DHCP Range Top', '192.168.1.200') }} +{{ lib.forminput(form, formerr, 'dhcptime', 'Lease Time', '12h') }} + +<div class="pull-right"> +<a href="."><button class="btn" type="button">Reset</button></a> +<button type="submit" class="btn btn-primary" type="button"> +Save</button> +</div> +</form> +{% endif %} + +{% endblock %} diff --git a/torouterui.py b/torouterui.py index 33a0018..5e8f346 100755 --- a/torouterui.py +++ b/torouterui.py @@ -6,6 +6,7 @@ import os from helpers import sysstatus from helpers import netif +from helpers import tor import config app = Flask(__name__) @@ -15,9 +16,11 @@ app = Flask(__name__) def status(): status = dict() status['system'] = sysstatus.get_system_status() + status['resources'] = sysstatus.get_resources_status() status['wan'] = netif.get_wan_status() status['lan'] = netif.get_lan_status() - status['wireless'] = netif.get_wireless_status() + status['wifi'] = netif.get_wifi_status() + status['tor'] = tor.get_tor_status() return render_template('home.html', settings=None, status=status) @app.route('/administer/', methods=['GET', 'POST']) @@ -26,35 +29,157 @@ def administer(): @app.route('/reboot/', methods=['GET', 'POST']) def administer(): - print request.form if request.method == 'GET': return render_template('reboot.html', status=None) - if request.form.has_key('confirm'): - # TODO: check reboot flag here? + elif request.form.has_key('confirm'): + # XXX: execute reboot return render_template('reboot.html', status='rebooting') else: # XXX: flashing introduces cookies #flash("Didn't confirm, not rebooting", "warning") return render_template('reboot.html', status=None) - @app.route('/wan/', methods=['GET', 'POST']) def wan(): - status = dict() - status['wan'] = netif.get_wan_status() - return render_template('wan.html', settings=None, status=None) + msg = list() + status = dict(wan=netif.get_wan_status()) + if not status['wan']: + msg.append(("error", + "Interface not detected, can not be configured."),) + return render_template('wan.html', form=None, status=status, + messages=msg, formerr=None) + if request.method == 'GET': + form = netif.get_wan_settings() + return render_template('wan.html', form=form, status=status, + formerr=None) + # Got this far, need to validated form + formerr = dict() + if request.form['ipv4method'] == 'disabled': + pass # no further validation + elif request.form['ipv4method'] == 'dhcp': + pass # no further validation + elif request.form['ipv4method'] == 'static': + if not netif.is_valid_ipv4(request.form['ipv4addr']): + formerr['ipv4addr'] = "Not a valid IPv4 address" + if not netif.is_valid_ipv4mask(request.form['ipv4netmask']): + formerr['ipv4netmask'] = "Not a valid IPv4 netmask" + if not netif.is_valid_ipv4(request.form['ipv4gateway']): + formerr['ipv4gateway'] = "Not a valid IPv4 address" + else: + ke = KeyError("Invalid net config method: %s" % form['ipv4method']) + print ke + raise ke + 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: + netif.save_wan_settings(request.form) + msg.append(("success", + "Configuration saved! Check logs for any errors"),) + except IOError, ioerr: + msg.append(("error", + "Was unable to commit changes... permissions problem? \"%s\"" \ + % ioerr)) + return render_template('wan.html', form=request.form, status=status, + formerr=formerr, messages=msg) @app.route('/lan/', methods=['GET', 'POST']) def lan(): - return render_template('lan.html', settings=None, status=None) - -@app.route('/wireless/', methods=['GET', 'POST']) -def wireless(): - return render_template('wireless.html', settings=None, status=None) + msg = list() + status = dict() + status['lan'] = netif.get_lan_status() + if not status['lan']: + msg.append(("error", + "Interface not detected, can not be configured."),) + return render_template('lan.html', form=None, status=status, + messages=msg, formerr=None) + if request.method == 'GET': + form = netif.get_lan_settings() + return render_template('lan.html', form=form, status=status, + formerr=None) + # Got this far, need to validated form + formerr = dict() + if request.form['ipv4method'] == 'disabled': + pass # no further validation + elif request.form['ipv4method'] == 'static': + if not netif.is_valid_ipv4(request.form['ipv4addr']): + formerr['ipv4addr'] = "Not a valid IPv4 address" + if not netif.is_valid_ipv4mask(request.form['ipv4netmask']): + formerr['ipv4netmask'] = "Not a valid IPv4 netmask" + if not netif.is_valid_ipv4(request.form['ipv4gateway']): + formerr['ipv4gateway'] = "Not a valid IPv4 address" + else: + ke = KeyError("Invalid method: %s" % form['ipv4method']) + print ke + raise ke + 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: + netif.save_lan_settings(request.form) + msg.append(("success", + "Configuration saved! Check logs for any errors"),) + except IOError, ioerr: + msg.append(("error", + "Was unable to commit changes... permissions problem? \"%s\"" \ + % ioerr)) + return render_template('lan.html', form=request.form, status=status, + formerr=formerr, messages=msg) + +@app.route('/wifi/', methods=['GET', 'POST']) +def wifi(): + status = dict() + status['wifi'] = netif.get_wifi_status() + if not status['wifi']: + msg.append(("error", + "Interface not detected, can not be configured."),) + return render_template('wifi.html', form=None, status=status, + messages=msg, formerr=None) + if request.method == 'GET': + form = netif.get_wifi_settings() + return render_template('wifi.html', form=form, status=status, + formerr=None) + # Got this far, need to validated form + formerr = dict() + if request.form['ipv4method'] == 'disabled': + pass # no further validation + elif request.form['ipv4method'] == 'static': + if not netif.is_valid_ipv4(request.form['ipv4addr']): + formerr['ipv4addr'] = "Not a valid IPv4 address" + if not netif.is_valid_ipv4mask(request.form['ipv4netmask']): + formerr['ipv4netmask'] = "Not a valid IPv4 netmask" + if not netif.is_valid_ipv4(request.form['ipv4gateway']): + formerr['ipv4gateway'] = "Not a valid IPv4 address" + else: + ke = KeyError("Invalid method: %s" % form['ipv4method']) + print ke + raise ke + 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: + netif.save_wifi_settings(request.form) + msg.append(("success", + "Configuration saved! Check logs for any errors"),) + except IOError, ioerr: + msg.append(("error", + "Was unable to commit changes... permissions problem? \"%s\"" \ + % ioerr)) + return render_template('wifi.html', form=request.form, status=status, + formerr=formerr, messages=msg) + return render_template('wifi.html', settings=None, status=None) @app.route('/tor/', methods=['GET', 'POST']) -def tor(): - return render_template('tor.html', settings=None, status=None) +def torpage(): + msg = list() + return render_template('tor.html', settings=None, status=None, + form=request.form, formerr=None, messages=msg) @app.route('/logs/', methods=['GET']) def logs(): |