From 246cc85640985983b2b2c2c9d3422a654c557b0a Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Mon, 11 Dec 2006 21:36:44 +0100 Subject: [PATCH] initial commit --- bridge-ctrl.php | 741 +++++++++++++++++++++++++++++ dbdump.sql | 160 +++++++ web/bridge.php | 177 +++++++ web/config.php | 81 ++++ web/forward.php | 76 +++ web/hlsw.php | 82 ++++ web/include.php | 26 + web/include/Database.class.php | 97 ++++ web/include/Helper.class.php | 33 ++ web/include/Input.class.php | 101 ++++ web/include/MySmarty.class.php | 21 + web/include/db_Bridge.class.php | 126 +++++ web/include/db_Forward.class.php | 90 ++++ web/include/db_Hlsw.class.php | 82 ++++ web/include/db_Trunk.class.php | 85 ++++ web/include/db_Vlan.class.php | 86 ++++ web/index.php | 9 + web/smarty/templates/bridge.tpl | 109 +++++ web/smarty/templates/forward.tpl | 39 ++ web/smarty/templates/hlsw.tpl | 47 ++ web/smarty/templates/overview.tpl | 13 + web/smarty/templates/siteframe.tpl | 50 ++ web/style.css | 117 +++++ 23 files changed, 2448 insertions(+) create mode 100644 bridge-ctrl.php create mode 100644 dbdump.sql create mode 100644 web/bridge.php create mode 100644 web/config.php create mode 100644 web/forward.php create mode 100644 web/hlsw.php create mode 100644 web/include.php create mode 100644 web/include/Database.class.php create mode 100644 web/include/Helper.class.php create mode 100644 web/include/Input.class.php create mode 100644 web/include/MySmarty.class.php create mode 100644 web/include/db_Bridge.class.php create mode 100644 web/include/db_Forward.class.php create mode 100644 web/include/db_Hlsw.class.php create mode 100644 web/include/db_Trunk.class.php create mode 100644 web/include/db_Vlan.class.php create mode 100644 web/index.php create mode 100644 web/smarty/templates/bridge.tpl create mode 100644 web/smarty/templates/forward.tpl create mode 100644 web/smarty/templates/hlsw.tpl create mode 100644 web/smarty/templates/overview.tpl create mode 100644 web/smarty/templates/siteframe.tpl create mode 100644 web/style.css diff --git a/bridge-ctrl.php b/bridge-ctrl.php new file mode 100644 index 0000000..324523f --- /dev/null +++ b/bridge-ctrl.php @@ -0,0 +1,741 @@ +#!/usr/bin/php + array(), + 'tunnel' => array(), + 'vlan' => array(), + 'hlsw' => array(), + 'forward' => array() + ); + } + + function save($arr) { + if ($arr == self::getEmpty()) + return; + + if (!$fp = @fopen(OLDFILE, "w")) { + echo "write error\n"; + return; + } + + fwrite($fp, @serialize($arr)); + fclose($fp); + } +} + +class BaseTables { + function init($bridge) { + // bridge present? + if (!is_dir("/sys/class/net/br0")) { + // create bridge + Cmd::brctl("addbr br0"); + + } else { + // delete all subdevices + $dir = opendir("/sys/class/net/br0/brif"); + while ($dir !== false && (($file = readdir($dir)) !== false)) { + if ($file == "." || $file == "..") + continue; + + Cmd::brctl("delif br0 {$file}"); + } + closedir($dir); + } + + // bridge init + Cmd::brctl("setfd 2"); + Cmd::ifconfig("br0 0.0.0.0 up"); + + // delete all rules & chains + Cmd::ebtables("-t nat -F"); + Cmd::ebtables("-t nat -X"); + Cmd::ebtables("-t filter -F"); + Cmd::ebtables("-t filter -X"); + + Cmd::ebtables("-t nat -N loop_pkts"); + Cmd::ebtables("-t nat -A loop_pkts -j DROP"); + + // TODO: tap_block wird pakete * interfaces durchlaufen + Cmd::ebtables("-t filter -N tap_block"); + Cmd::ebtables("-t filter -A tap_block -j RETURN"); + + // eigene pakete empfangen -> loop + Cmd::ebtables("-t nat -A PREROUTING -s {$bridge['macmask']} -j loop_pkts"); + } + + function add_tunnel($tunnels) { + foreach ($tunnels as $tunnel) { + // pakete durch tunnel von anderer Bridge -> ok + // pakete von anderen Bridges auf normalen ports -> loop + Cmd::ebtables("-t nat -A PREROUTING -i {$tunnel['device']} -j ACCEPT"); + Cmd::ebtables("-t nat -A PREROUTING -s {$tunnel['macmask']} -j loop_pkts"); + + // wenns ausm tunnel kommt, nicht in nen tunnel stecken + Cmd::ebtables("-t filter -A FORWARD -i {$tunnel['device']} -j tap_block"); + Cmd::ebtables("-t filter -I tap_block 1 -o {$tunnel['device']} -j DROP"); + } + + // ansonsten alles in den tunnel packen + foreach ($tunnels as $tunnel) + Cmd::ebtables("-t filter -A FORWARD -o {$tunnel['device']} -j ACCEPT"); + } +} + +class ForwardTables { + function init() { + // delete all vlan devices + $dir = opendir("/sys/class/net/"); + while ($dir !== false && (($file = readdir($dir)) !== false)) { + if ($file == "." || $file == "..") + continue; + + if (strncmp($file, "eth", 3)) + continue; + + $part = explode('.', $file); + if (!isset($part[1])) + continue; + + $address = Cmd::ip("-4 addr show dev ${file}"); + if (count($address)) + continue; + + Cmd::ifconfig("{$file} down"); + Cmd::vconfig("rem {$file}"); + } + closedir($dir); + + Cmd::ebtables("-t nat -N hlswmaster"); + Cmd::ebtables("-t nat -A hlswmaster -j DROP"); + + Cmd::ebtables("-t nat -N arp_pkts"); + Cmd::ebtables("-t nat -A arp_pkts -j DROP"); + + Cmd::ebtables("-t nat -N nonip_pkts"); + Cmd::ebtables("-t nat -A nonip_pkts -j DROP"); + + Cmd::ebtables("-t nat -N udp_blocked"); + Cmd::ebtables("-t nat -A udp_blocked -j DROP"); + + Cmd::ebtables("-t nat -N udp_forwarded"); + Cmd::ebtables("-t nat -A udp_forwarded -j ACCEPT"); + + Cmd::ebtables("-t nat -N fwdfilter"); + Cmd::ebtables("-t nat -A fwdfilter -j udp_blocked"); + + Cmd::ebtables("-t filter -N hlswmaster"); + Cmd::ebtables("-t filter -A hlswmaster -j DROP"); + + // allow hlsw-master-querys from all clients + // but forward them only to our masters + Cmd::ebtables("-t nat -A PREROUTING -p ipv4 --ip-proto udp --ip-dport 7140 -j ACCEPT"); + Cmd::ebtables("-t filter -A FORWARD -p ipv4 --ip-proto udp --ip-dport 7140 -j hlswmaster"); + + // only allow hlsw-querys from master servers + Cmd::ebtables("-t nat -A PREROUTING -p ipv4 --ip-proto udp --ip-sport 7130:7139 -j hlswmaster"); + + // udp broadcast und multicast filtern + Cmd::ebtables("-t nat -A PREROUTING -p ipv4 --ip-proto udp --ip-dst 255.255.255.255 -j fwdfilter"); + Cmd::ebtables("-t nat -A PREROUTING -p ipv4 --ip-proto udp --ip-dst 224.0.0.0/8 -j fwdfilter"); + + // udp unicast (falsche netmask beim client) blocken + Cmd::ebtables("-t nat -A PREROUTING -p ipv4 --ip-proto udp -j udp_blocked"); + + // andere protos fuer stats auseinandernehmen + Cmd::ebtables("-t nat -A PREROUTING -p arp -j arp_pkts"); + Cmd::ebtables("-t nat -A PREROUTING -j nonip_pkts"); + } + + private function add_hlsw($hlsw) { + Cmd::ebtables("-t nat -I hlswmaster 1 -p ipv4 --ip-src {$hlsw['ip']} -j ACCEPT"); + Cmd::ebtables("-t filter -I hlswmaster 1 -o {$hlsw['dev']} -j ACCEPT"); + } + + private function del_hlsw($hlsw) { + Cmd::ebtables("-t nat -D hlswmaster -p ipv4 --ip-src {$hlsw['ip']} -j ACCEPT"); + Cmd::ebtables("-t filter -D hlswmaster -o {$hlsw['dev']} -j ACCEPT"); + } + + private function add_vlan($vlan) { + // vlan 0 and vlan 1 are invalid -> use basename (eth1.1 -> eth1) + $part = explode('.', $vlan['name']); + if (isset($part[1]) && ($part[1] >= 2)) { + Cmd::ifconfig("{$part[0]} 0.0.0.0 up"); + Cmd::vconfig("add {$part[0]} {$part[1]}"); + } + + // add device to bridge + Cmd::ifconfig("{$vlan['name']} 0.0.0.0 up"); + Cmd::brctl("addif br0 {$vlan['name']}"); + // TODO: bei echten devices kann qdisc noch vorhanden sein + Cmd::tc("qdisc add dev {$vlan['name']} root tbf rate {$vlan['bw']}kbit burst 4k latency 100ms"); + + // stats + Cmd::ebtables("-t nat -I loop_pkts 1 -i {$vlan['name']} -j DROP"); + Cmd::ebtables("-t nat -I arp_pkts 1 -i {$vlan['name']} -j DROP"); + Cmd::ebtables("-t nat -I nonip_pkts 1 -i {$vlan['name']} -j DROP"); + Cmd::ebtables("-t nat -I udp_blocked 1 -i {$vlan['name']} -j DROP"); + Cmd::ebtables("-t nat -I udp_forwarded 1 -i {$vlan['name']} -j ACCEPT"); + + // ausgehende src-mac anpassen fuer loop detection + // und damit non-cisco HW funktionieren wuerde :) + Cmd::ebtables("-t nat -I POSTROUTING 1 -o {$vlan['name']} -j snat --to-source {$vlan['mac']}"); + } + + private function del_vlan($vlan) { + // remove from bridge + Cmd::brctl("delif br0 {$vlan['name']}"); + Cmd::ifconfig("{$vlan['name']} down"); + + // remove vlan + $part = explode('.', $vlan['name']); + if (isset($part[1]) && ($part[1] >= 2)) + Cmd::vconfig("rem {$vlan['name']}"); + + // stats + Cmd::ebtables("-t nat -D loop_pkts -i {$vlan['name']} -j DROP"); + Cmd::ebtables("-t nat -D arp_pkts -i {$vlan['name']} -j DROP"); + Cmd::ebtables("-t nat -D nonip_pkts -i {$vlan['name']} -j DROP"); + Cmd::ebtables("-t nat -D udp_blocked -i {$vlan['name']} -j DROP"); + Cmd::ebtables("-t nat -D udp_forwarded -i {$vlan['name']} -j ACCEPT"); + + // snat mac + Cmd::ebtables("-t nat -D POSTROUTING -o {$vlan['name']} -j snat --to-source {$vlan['mac']}"); + } + + private function add_fwd($fwd) { + $port = $fwd['portlo']; + if ($fwd['porthi'] != 0) + $port .= ':'.$fwd['porthi']; + + $target = ($fwd['active'] ? "udp_forwarded" : "udp_blocked"); + Cmd::ebtables("-t nat -I fwdfilter 1 -p ipv4 --ip-proto udp --ip-dport {$port} -j {$target}"); + } + + private function del_fwd($fwd) { + $port = $fwd['portlo']; + if ($fwd['porthi'] != 0) + $port .= ':'.$fwd['porthi']; + + $target = ($fwd['active'] ? "udp_forwarded" : "udp_blocked"); + Cmd::ebtables("-t nat -D fwdfilter -p ipv4 --ip-proto udp --ip-dport {$port} -j {$target}"); + } + + function checkDiff($old, $new) { + $oldarr = $old['vlan']; + $newarr = $new['vlan']; + foreach ($newarr as $id => $tmp) { + if (!isset($oldarr[$id])) { + self::add_vlan($tmp); + + } else if ($tmp !== $oldarr[$id]) { + // TODO: this is slow + self::del_vlan($oldarr[$id]); + self::add_vlan($tmp); + } + } + foreach ($oldarr as $id => $tmp) { + if (!isset($newarr[$id])) + self::del_vlan($tmp); + } + + $oldarr = $old['forward']; + $newarr = $new['forward']; + foreach ($newarr as $id => $tmp) { + if (!isset($oldarr[$id])) { + self::add_fwd($tmp); + + } else if ($tmp !== $oldarr[$id]) { + self::del_fwd($oldarr[$id]); + self::add_fwd($tmp); + } + } + foreach ($oldarr as $id => $tmp) { + if (!isset($newarr[$id])) + self::del_fwd($tmp); + } + + $oldarr = $old['hlsw']; + $newarr = $new['hlsw']; + foreach ($newarr as $id => $tmp) { + if (!isset($oldarr[$id])) { + self::add_hlsw($tmp); + + } else if ($tmp !== $oldarr[$id]) { + self::del_hlsw($oldarr[$id]); + self::add_hlsw($tmp); + } + } + foreach ($oldarr as $id => $tmp) { + if (!isset($newarr[$id])) + self::del_hlsw($tmp); + } + } +} + +class Vtund { + function getBaseConfig() { + return " +options { + type stand; + port 5000; + timeout 60; + syslog daemon; + ifconfig /sbin/ifconfig; +} + +default { + type ether; + proto udp; + timeout 60; + compress no; + encrypt no; + keepalive yes; + stat no; + speed 0; + multi kill; + + up { + ifconfig \"%d 0.0.0.0 up\"; + program /usr/sbin/brctl \"addif br0 %d\"; + }; + + down { + program /usr/sbin/brctl \"delif br0 %d\"; + ifconfig \"%d down\"; + }; +} + +"; + } + + function getSession($tunnel) { + return " +{$tunnel['name']} { + # partner {$tunnel['dest']} + # our mode: {$tunnel['mode']} + device {$tunnel['device']}; + password whiterabbit; +} +"; + } + + function buildConfig($arr) { + if (!$fp = @fopen("/etc/vtund.conf", "w")) { + echo "could not write vtund config"; + return; + } + + // basic config + fwrite($fp, self::getBaseConfig()); + + // add sessions + foreach ($arr as $tunnel) + fwrite($fp, self::getSession($tunnel)); + + fclose($fp); + } + + function init($arr) { + self::buildConfig($arr); + + // check if vtund server runs + $srv_running = false; + if (file_exists("/var/run/vtund.pid")) { + $pid = file_get_contents("/var/run/vtund.pid"); + + // send SIGHUP, to reread the config + $srv_running = posix_kill($pid, 1); + } + + // start the server + if (!$srv_running) + Cmd::vtund("-f /etc/vtund.conf -s"); + + // kill all clients (_our_ clients, not server childs!) + $dir = opendir("/var/run/"); + while ($dir !== false && (($file = readdir($dir)) !== false)) { + if ($file == "." || $file == "..") + continue; + + if (strncmp($file, "vtund.tap", 9)) + continue; + + // send SIGTERM to client vtund + $pid = file_get_contents("/var/run/".$file); + posix_kill($pid, 15); + } + closedir($dir); + + // start all clients + foreach ($arr as $tunnel) { + if ($tunnel['mode'] == "client") + Cmd::vtund("-f /etc/vtund.conf -p {$tunnel['name']} {$tunnel['dest']}"); + } + } +} + +class Stats { + private $sock; + private $files = array(); + + private function write($msg) { + socket_write($this->sock, $msg."\r\n", strlen($msg."\r\n")); + } + + private function read() { + while (true) { + $fdset = array($this->sock); + $sel = socket_select($fdset, $write = NULL, $except = NULL, 0, 100000); + if ($sel == 0 || $sel === false) + return false; + + return socket_read($this->sock, 1024, PHP_NORMAL_READ); + } + } + + private function waitcmd() { + $retval = array(); + while (($line = $this->read()) !== false && strlen($line) > 0) { + if (!strncmp($line, 'OK', 2)) + break; + + if (!strncmp($line, 'ERROR', 2)) { + echo $line; + break; + } + $retval[] = $line; + } + return $retval; + } + + function connect($id) { + $this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + socket_connect($this->sock, RRDSRV, 5001); + + self::write('ls'); + $list = self::waitcmd(); + foreach ($list as $num => $name) + $list[$num] = substr(trim($name), 2, 32); + + $dirname = 'bridge-'.$id; + if (!in_array($dirname, $list)) { + self::write('mkdir '. $dirname); + self::waitcmd(); + } + + self::write('cd '. $dirname); + self::waitcmd(); + + self::write('ls'); + $list = self::waitcmd(); + foreach ($list as $num => $name) + $list[$num] = substr(trim($name), 2, 32); + + $this->files = $list; + } + + function get_vlans() { + $result = array(); + + unset($lines); + $lines = Cmd::ebtables('-t nat -L loop_pkts --Lc'); + foreach ($lines as $line) { + if (strpos($line, '-i') !== false) { + $parts = explode(' ', $line); + $result[$parts[1]]['loop'] = $parts[11]; + } + } + + unset($lines); + $lines = Cmd::ebtables('-t nat -L arp_pkts --Lc'); + foreach ($lines as $line) { + if (strpos($line, '-i') !== false) { + $parts = explode(' ', $line); + $result[$parts[1]]['arp'] = $parts[11]; + } + } + + unset($lines); + $lines = Cmd::ebtables('-t nat -L nonip_pkts --Lc'); + foreach ($lines as $line) { + if (strpos($line, '-i') !== false) { + $parts = explode(' ', $line); + $result[$parts[1]]['nonip'] = $parts[11]; + } + } + + unset($lines); + $lines = Cmd::ebtables('-t nat -L udp_blocked --Lc'); + foreach ($lines as $line) { + if (strpos($line, '-i') !== false) { + $parts = explode(' ', $line); + $result[$parts[1]]['blocked'] = $parts[11]; + } + } + + unset($lines); + $lines = Cmd::ebtables('-t nat -L udp_forwarded --Lc'); + foreach ($lines as $line) { + if (strpos($line, '-i') !== false) { + $parts = explode(' ', $line); + $result[$parts[1]]['forwarded'] = $parts[11]; + } + } + + unset($lines); + $lines = Cmd::ebtables('-t nat -L POSTROUTING --Lc'); + foreach ($lines as $line) { + if (strpos($line, '-o') !== false) { + $parts = explode(' ', $line); + $result[$parts[1]]['output'] = $parts[14]; + } + } + + foreach ($result as $name => $data) { + $fullname = "vlan-$name.rrd"; + if (!in_array($fullname, $this->files)) { + $cmd = "create $fullname --start now -s 60 ". + 'DS:loop:DERIVE:60:0:10000000 '. + 'DS:arp:DERIVE:60:0:10000000 '. + 'DS:nonip:DERIVE:60:0:10000000 '. + 'DS:block:DERIVE:60:0:10000000 '. + 'DS:fwd:DERIVE:60:0:10000000 '. + 'DS:out:DERIVE:60:0:10000000 '. + 'RRA:AVERAGE:0.5:1:720 RRA:AVERAGE:0.5:5:576 '. + 'RRA:MIN:0.5:1:720 RRA:MIN:0.5:5:576 '. + 'RRA:MAX:0.5:1:720 RRA:MAX:0.5:5:576 '; + self::write($cmd); + self::waitcmd(); + } + + $cmd = "update $fullname N:{$data['loop']}:{$data['arp']}:{$data['nonip']}:{$data['blocked']}:{$data['forwarded']}:{$data['output']}"; + self::write($cmd); + self::waitcmd(); + } + } + + function get_forwards($forwards) { + $names = array(); + foreach ($forwards as $id => $fwd) { + $key = $fwd['portlo']; + if ($fwd['porthi'] != 0) + $key .= ':'.$fwd['porthi']; + + $names[$key] = "forward-$id.rrd"; + } + + $result = array(); + $lines = Cmd::ebtables('-t nat -L fwdfilter --Lc'); + foreach ($lines as $line) { + if (strpos($line, '-p') !== false) { + $parts = explode(' ', $line); + if (!isset($names[$parts[5]])) + continue; + + switch ($parts[7]) { + case 'udp_forwarded,': + $result[$names[$parts[5]]] = "N:{$parts[14]}:0"; + break; + + case 'udp_blocked,': + $result[$names[$parts[5]]] = "N:0:{$parts[14]}"; + break; + } + } + } + + foreach ($result as $fullname => $data) { + if (!in_array($fullname, $this->files)) { + $cmd = "create $fullname --start now -s 60 ". + 'DS:fwd:DERIVE:60:0:10000000 '. + 'DS:block:DERIVE:60:0:10000000 '. + 'RRA:AVERAGE:0.5:1:720 RRA:AVERAGE:0.5:5:576 '. + 'RRA:MIN:0.5:1:720 RRA:MIN:0.5:5:576 '. + 'RRA:MAX:0.5:1:720 RRA:MAX:0.5:5:576 '; + self::write($cmd); + self::waitcmd(); + } + + self::write("update $fullname $data"); + self::waitcmd(); + } + } + + function get_masters($masters) { + $lines_from = Cmd::ebtables('-t nat -L hlswmaster --Lc'); + $lines_to = Cmd::ebtables('-t filter -L hlswmaster --Lc'); + + $result = array(); + foreach ($masters as $id => $hlsw) { + foreach ($lines_from as $line) { + if (strpos($line, $hlsw['ip'])) { + $parts = explode(' ', $line); + $from = $parts[14]; + break; + } + } + + foreach ($lines_to as $line) { + if (strpos($line, $hlsw['dev'])) { + $parts = explode(' ', $line); + $to = $parts[12]; + break; + } + } + $result['hlsw-'.$id.'.rrd'] = "N:{$from}:{$to}"; + } + + foreach ($result as $fullname => $data) { + if (!in_array($fullname, $this->files)) { + $cmd = "create $fullname --start now -s 60 ". + 'DS:from:DERIVE:60:0:10000000 '. + 'DS:to:DERIVE:60:0:10000000 '. + 'RRA:AVERAGE:0.5:1:720 RRA:AVERAGE:0.5:5:576 '. + 'RRA:MIN:0.5:1:720 RRA:MIN:0.5:5:576 '. + 'RRA:MAX:0.5:1:720 RRA:MAX:0.5:5:576 '; + self::write($cmd); + self::waitcmd(); + } + + self::write("update $fullname $data"); + self::waitcmd(); + } + } + + function close() { + socket_close($this->sock); + } +} + + +/* teh main */ + +$init = (isset($_SERVER['argv'][1]) && $_SERVER['argv'][1] == "init"); + +// get old config, fallback to the empty config +$oldarr = Config::getOld(); +if ($oldarr === false) + $oldarr = Config::getEmpty(); + +// get new config, fallback to old config +$newarr = Config::fetch(); +if ($newarr === false) { + echo "Fetch failed!\n"; + $newarr = $oldarr; +} + +// main config changed -> reset everything +if ($oldarr['bridge'] != $newarr['bridge']) + $init = true; + +// tunnel config changed -> reset everything +if ($oldarr['tunnel'] != $newarr['tunnel']) + $init = true; + +if ($init) { + // basic bridge layout, loop detection + BaseTables::init($newarr['bridge']); + + // add bridge rules for tunnels + BaseTables::add_tunnel($newarr['tunnel']); + + // vlan + port stuff + ForwardTables::init(); + + // setup tunnels + Vtund::init($newarr['tunnel']); + + // we do a init, so diff between $empty -> $new + $oldarr = Config::getEmpty(); +} + +// add VLANs, Forward-Ports and HLSW Master Server +ForwardTables::checkDiff($oldarr, $newarr); + +// gather stats and send them to rrdtool server via tcp +$stats = new Stats(); +$stats->connect($newarr['bridge']['id']); +$stats->get_vlans(); +$stats->get_forwards($newarr['forward']); +$stats->get_masters($newarr['hlsw']); +$stats->close(); + +// save the config +Config::save($newarr); + +?> diff --git a/dbdump.sql b/dbdump.sql new file mode 100644 index 0000000..81a39d1 --- /dev/null +++ b/dbdump.sql @@ -0,0 +1,160 @@ +-- MySQL dump 10.10 +-- +-- Host: localhost Database: bridge +-- ------------------------------------------------------ +-- Server version 5.0.24a-Debian_9-log + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `bridge` +-- + +DROP TABLE IF EXISTS `bridge`; +CREATE TABLE `bridge` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(32) NOT NULL, + `ctrldev` varchar(16) NOT NULL, + `ctrlip` int(10) unsigned NOT NULL default '0', + `ctrlmask` varchar(16) NOT NULL, + `ctrlgw` int(10) unsigned NOT NULL default '0', + `basemac` varchar(32) NOT NULL default '00:00:00:00:00:00', + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`), + UNIQUE KEY `basemac` (`basemac`), + UNIQUE KEY `ctrlip` (`ctrlip`) +) ENGINE=MyISAM AUTO_INCREMENT=29 DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `bridge` +-- + + +/*!40000 ALTER TABLE `bridge` DISABLE KEYS */; +LOCK TABLES `bridge` WRITE; +INSERT INTO `bridge` VALUES (22,'Bridge #1','eth0',168492644,'255.255.0.0',168491770,'00:DE:AD:BE:EF:00'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `bridge` ENABLE KEYS */; + +-- +-- Table structure for table `forward` +-- + +DROP TABLE IF EXISTS `forward`; +CREATE TABLE `forward` ( + `id` int(11) NOT NULL auto_increment, + `flags` int(11) NOT NULL, + `portlo` int(11) NOT NULL, + `porthi` int(11) NOT NULL, + `name` varchar(64) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=52 DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `forward` +-- + + +/*!40000 ALTER TABLE `forward` DISABLE KEYS */; +LOCK TABLES `forward` WRITE; +INSERT INTO `forward` VALUES (1,1,27960,27963,'Quake3'),(2,1,27015,27024,'Halflife'),(3,1,1716,1727,'Americas Army Operations'),(4,1,2092,0,'Descent 3'),(5,1,2234,2245,'Operation Flashpoint'),(6,1,2299,0,'Age of Empires 3'),(7,1,2302,2313,'Operation Flashpoint: Resistance'),(8,1,2346,0,'Ghost Recon'),(9,1,2350,2360,'Trackmania'),(10,1,5120,5131,'Neverwinter Nights'),(11,1,5678,0,'FarCry'),(12,1,6073,0,'Freelancer'),(13,1,6111,0,'StarCraft'),(14,1,6112,0,'Warcraft 3'),(15,1,7075,0,'Siedler 5'),(16,1,7777,7788,'Unreal Tournament'),(17,1,8086,0,'Command Conquer: Generals'),(18,1,8086,8093,'Schlacht um Mittelerde'),(19,1,8777,8786,'Ravenshield'),(20,1,9999,0,'Need for Speed Underground 2'),(21,1,10481,10482,'SWAT 4'),(22,1,10777,0,'Unreal Tournament 2004'),(23,1,12203,12218,'Medal of Honor: Spearhead'),(24,1,12299,12310,'Medal of Honor: Allied Assault'),(25,1,15250,0,'Ghost Recon'),(26,1,20000,0,'Söldner'),(27,1,20099,20110,'Soldier of Fortune 2'),(28,1,22000,22010,'Battlefield 1942'),(29,1,22450,0,'Sin'),(30,1,23756,23757,'Flatout (?)'),(31,1,25299,25310,'Command Conquer: Renegade'),(32,1,25601,25621,'Serious Sam 2'),(33,1,26000,0,'Quake'),(34,1,26001,26010,'IGI2: Covert Ops'),(35,1,26900,0,'Hexen 2'),(36,1,27500,0,'QuakeWorld'),(37,1,27665,27676,'Doom 3'),(38,1,27887,27898,'Aliens vs. Predators 2'),(39,1,27910,0,'Quake 2'),(40,1,27950,27953,'Enemy Territory'),(41,1,28000,0,'Tribes 2'),(42,1,28001,0,'StarSiege'),(43,1,28004,28008,'Quake 4'),(44,1,28069,28080,'Jedi Knight 2'),(45,1,28960,28963,'Call of Duty'),(46,1,29252,29263,'Elite Force 2'),(47,1,29900,29910,'Battlefield 2'),(48,1,31510,0,'KingPin'),(49,1,47624,0,'Total Annihilation'),(50,1,61220,61230,'Need for Speed: Hot Pursuit'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `forward` ENABLE KEYS */; + +-- +-- Table structure for table `hlsw` +-- + +DROP TABLE IF EXISTS `hlsw`; +CREATE TABLE `hlsw` ( + `id` int(11) NOT NULL auto_increment, + `vlanid` int(11) NOT NULL, + `flags` int(11) NOT NULL, + `ip` int(10) unsigned NOT NULL, + `name` varchar(32) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ip` (`ip`), + UNIQUE KEY `name` (`name`) +) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `hlsw` +-- + + +/*!40000 ALTER TABLE `hlsw` DISABLE KEYS */; +LOCK TABLES `hlsw` WRITE; +INSERT INTO `hlsw` VALUES (8,607,0,168427551,'hbuss?'),(10,607,0,168492644,'bridge'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `hlsw` ENABLE KEYS */; + +-- +-- Table structure for table `trunk` +-- + +DROP TABLE IF EXISTS `trunk`; +CREATE TABLE `trunk` ( + `id` int(11) NOT NULL auto_increment, + `bridgeid` int(11) NOT NULL, + `flags` int(11) NOT NULL, + `name` varchar(16) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `bridgeid` (`bridgeid`,`name`) +) ENGINE=MyISAM AUTO_INCREMENT=63 DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `trunk` +-- + + +/*!40000 ALTER TABLE `trunk` DISABLE KEYS */; +LOCK TABLES `trunk` WRITE; +INSERT INTO `trunk` VALUES (55,22,0,'eth3'),(46,22,0,'eth1'),(47,22,0,'eth2'),(62,22,0,'eth4'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `trunk` ENABLE KEYS */; + +-- +-- Table structure for table `vlan` +-- + +DROP TABLE IF EXISTS `vlan`; +CREATE TABLE `vlan` ( + `id` int(11) NOT NULL auto_increment, + `trunkid` int(11) NOT NULL, + `flags` int(11) NOT NULL, + `vlannum` int(11) NOT NULL, + `bandwidth` int(11) NOT NULL, + `mac` varchar(32) NOT NULL default '00:00:00:00:00:00', + PRIMARY KEY (`id`), + UNIQUE KEY `trunkid` (`trunkid`,`vlannum`) +) ENGINE=MyISAM AUTO_INCREMENT=936 DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `vlan` +-- + + +/*!40000 ALTER TABLE `vlan` DISABLE KEYS */; +LOCK TABLES `vlan` WRITE; +INSERT INTO `vlan` VALUES (607,46,0,1,400,'00:DE:AD:BE:EF:01'),(935,47,0,323,400,'00:DE:AD:BE:EF:2F'),(934,47,0,322,400,'00:DE:AD:BE:EF:2E'),(799,55,0,1,400,'00:DE:AD:BE:EF:30'),(798,47,0,123,400,'00:DE:AD:BE:EF:18'),(797,47,0,122,400,'00:DE:AD:BE:EF:17'),(776,47,0,101,400,'00:DE:AD:BE:EF:02'),(777,47,0,102,400,'00:DE:AD:BE:EF:03'),(778,47,0,103,400,'00:DE:AD:BE:EF:04'),(779,47,0,104,400,'00:DE:AD:BE:EF:05'),(780,47,0,105,400,'00:DE:AD:BE:EF:06'),(781,47,0,106,400,'00:DE:AD:BE:EF:07'),(782,47,0,107,400,'00:DE:AD:BE:EF:08'),(783,47,0,108,400,'00:DE:AD:BE:EF:09'),(784,47,0,109,400,'00:DE:AD:BE:EF:0A'),(785,47,0,110,400,'00:DE:AD:BE:EF:0B'),(786,47,0,111,400,'00:DE:AD:BE:EF:0C'),(787,47,0,112,400,'00:DE:AD:BE:EF:0D'),(788,47,0,113,400,'00:DE:AD:BE:EF:0E'),(789,47,0,114,400,'00:DE:AD:BE:EF:0F'),(790,47,0,115,400,'00:DE:AD:BE:EF:10'),(791,47,0,116,400,'00:DE:AD:BE:EF:11'),(792,47,0,117,400,'00:DE:AD:BE:EF:12'),(793,47,0,118,400,'00:DE:AD:BE:EF:13'),(794,47,0,119,400,'00:DE:AD:BE:EF:14'),(795,47,0,120,400,'00:DE:AD:BE:EF:15'),(796,47,0,121,400,'00:DE:AD:BE:EF:16'),(933,47,0,321,400,'00:DE:AD:BE:EF:2D'),(932,47,0,320,400,'00:DE:AD:BE:EF:2C'),(931,47,0,319,400,'00:DE:AD:BE:EF:2B'),(930,47,0,318,400,'00:DE:AD:BE:EF:2A'),(929,47,0,317,400,'00:DE:AD:BE:EF:29'),(928,47,0,316,400,'00:DE:AD:BE:EF:28'),(927,47,0,315,400,'00:DE:AD:BE:EF:27'),(926,47,0,314,400,'00:DE:AD:BE:EF:26'),(925,47,0,313,400,'00:DE:AD:BE:EF:25'),(924,47,0,312,400,'00:DE:AD:BE:EF:24'),(923,47,0,311,400,'00:DE:AD:BE:EF:23'),(922,47,0,310,400,'00:DE:AD:BE:EF:22'),(921,47,0,309,400,'00:DE:AD:BE:EF:21'),(920,47,0,308,400,'00:DE:AD:BE:EF:20'),(919,47,0,307,400,'00:DE:AD:BE:EF:1F'),(918,47,0,306,400,'00:DE:AD:BE:EF:1E'),(917,47,0,305,400,'00:DE:AD:BE:EF:1D'),(916,47,0,304,400,'00:DE:AD:BE:EF:1C'),(915,47,0,303,400,'00:DE:AD:BE:EF:1B'),(914,47,0,302,400,'00:DE:AD:BE:EF:1A'),(913,47,0,301,400,'00:DE:AD:BE:EF:19'),(890,62,0,501,400,'00:DE:AD:BE:EF:31'),(891,62,0,502,400,'00:DE:AD:BE:EF:32'),(892,62,0,503,400,'00:DE:AD:BE:EF:33'),(893,62,0,504,400,'00:DE:AD:BE:EF:34'),(894,62,0,505,400,'00:DE:AD:BE:EF:35'),(895,62,0,506,400,'00:DE:AD:BE:EF:36'),(896,62,0,507,400,'00:DE:AD:BE:EF:37'),(897,62,0,508,400,'00:DE:AD:BE:EF:38'),(898,62,0,509,400,'00:DE:AD:BE:EF:39'),(899,62,0,510,400,'00:DE:AD:BE:EF:3A'),(900,62,0,511,400,'00:DE:AD:BE:EF:3B'),(901,62,0,512,400,'00:DE:AD:BE:EF:3C'),(902,62,0,513,400,'00:DE:AD:BE:EF:3D'),(903,62,0,514,400,'00:DE:AD:BE:EF:3E'),(904,62,0,515,400,'00:DE:AD:BE:EF:3F'),(905,62,0,516,400,'00:DE:AD:BE:EF:40'),(906,62,0,517,400,'00:DE:AD:BE:EF:41'),(907,62,0,518,400,'00:DE:AD:BE:EF:42'),(908,62,0,519,400,'00:DE:AD:BE:EF:43'),(909,62,0,520,400,'00:DE:AD:BE:EF:44'),(910,62,0,521,400,'00:DE:AD:BE:EF:45'),(911,62,0,522,400,'00:DE:AD:BE:EF:46'),(912,62,0,523,400,'00:DE:AD:BE:EF:47'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `vlan` ENABLE KEYS */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + diff --git a/web/bridge.php b/web/bridge.php new file mode 100644 index 0000000..385f362 --- /dev/null +++ b/web/bridge.php @@ -0,0 +1,177 @@ +name = "New Bridge"; + $bridge->save(); + + Helper::reload(false, "bridge-{$bridge->id}"); +} + +function mod_bridge() { + $bridgeid = Input::getVar('bridgeid', INP_GET | INP_INT | INP_DEFAULT, 0); + if ($bridgeid == 0) + Helper::reload(); + + $arr = Input::getVar('bridge', INP_POST | INP_ARRAY | INP_DEFAULT, array()); + + $bridge = Bridge::load($bridgeid); + $bridge->name = $arr['name']; + $bridge->ctrlip = $arr['ctrlip']; + $bridge->basemac = strtoupper($arr['basemac']); + $bridge->save(); + + $bridge->reorder_macs(); + Helper::reload(false, "bridge-{$bridge->id}"); +} + +function del_bridge() { + $bridgeid = Input::getVar('bridgeid', INP_GET | INP_INT | INP_DEFAULT, 0); + if ($bridgeid == 0) + Helper::reload(); + + Bridge::delete($bridgeid); + Helper::reload(); +} + +function mod_trunk() { + $bridgeid = Input::getVar('bridgeid', INP_GET | INP_INT | INP_DEFAULT, 0); + if ($bridgeid == 0) + Helper::reload(); + + $bridge = Bridge::load($bridgeid); + + $subaction = Input::getVar('subaction', INP_POST | INP_STRING | INP_EMPTY); + switch ($subaction) { + case 'add': + $name = Input::getVar('name', INP_POST | INP_STRING | INP_DEFAULT, ""); + if (!empty($name)) { + $trunk = new Trunk(); + $trunk->bridgeid = $bridge->id; + $trunk->name = $name; + $trunk->save(); + } + break;; + + case 'del': + $trunk_arr = Input::getVar('trunkarr', INP_POST | INP_ARRAY | INP_DEFAULT, array()); + foreach ($trunk_arr as $trunkid) + Trunk::delete($trunkid); + + break; + } + + $bridge->reorder_macs(); + Helper::reload(false, "bridge-{$bridge->id}"); +} + +function mod_vlan() { + $bridgeid = Input::getVar('bridgeid', INP_GET | INP_INT | INP_DEFAULT, 0); + if ($bridgeid == 0) + Helper::reload(); + + $bridge = Bridge::load($bridgeid); + + $subaction = Input::getVar('subaction', INP_POST | INP_STRING | INP_EMPTY); + switch ($subaction) { + case 'add': + $vlannum = Input::getVar('name', INP_POST | INP_STRING | INP_DEFAULT, ""); + $trunkid = Input::getVar('trunk', INP_POST | INP_INT | INP_DEFAULT, 0); + $bandwidth = Input::getVar('bandwidth', INP_POST | INP_INT | INP_DEFAULT, -1); + + if (!empty($vlannum) && $trunkid != 0 && $bandwidth != -1) { + $arr = explode('-', $vlannum); + if (!isset($arr[1])) { + $vlan = new Vlan(); + $vlan->trunkid = $trunkid; + $vlan->vlannum = $arr[0]; + $vlan->bandwidth = $bandwidth; + $vlan->save(); + + } else { + for ($i = $arr[0]; $i <= $arr[1]; $i++) { + $vlan = new Vlan(); + $vlan->trunkid = $trunkid; + $vlan->vlannum = $i; + $vlan->bandwidth = $bandwidth; + $vlan->save(); + } + } + } + break; + + case 'save': + $vlan_arr = Input::getVar('vlanarr', INP_POST | INP_ARRAY | INP_DEFAULT, array()); + $bandwidth = Input::getVar('bandwidth', INP_POST | INP_INT | INP_DEFAULT, -1); + + if ($bandwidth != -1) { + foreach ($vlan_arr as $vlanid) { + $vlan = Vlan::load($vlanid); + $vlan->bandwidth = $bandwidth; + $vlan->save(); + } + } + break; + + case 'del': + $vlan_arr = Input::getVar('vlanarr', INP_POST | INP_ARRAY | INP_DEFAULT, array()); + foreach ($vlan_arr as $vlanid) + Vlan::delete($vlanid); + + break; + } + + $bridge->reorder_macs(); + Helper::reload(false, "bridge-{$bridge->id}"); +} + +function show() { + $smarty = new MySmarty(); + + // TODO: single query? + $bridges = Bridge::getAll(); + foreach ($bridges as $bridge) { + $bridge->trunks = Trunk::getAll($bridge->id); + + foreach ($bridge->trunks as $trunk) { + $trunk->vlans = Vlan::getAll($trunk->id); + $trunk->vlancnt = count($trunk->vlans); + } + } + + $smarty->assign('bridges', $bridges); + $smarty->displaySite('Configuration: Bridges', 'bridge.tpl'); +} + + +$action = Input::getVar('action', INP_GET | INP_STRING | INP_DEFAULT, "show"); +switch ($action) { + +case 'add_bridge': + add_bridge(); + break; + +case 'mod_bridge': + mod_bridge(); + break; + +case 'del_bridge': + del_bridge(); + break; + +case 'mod_trunk': + mod_trunk(); + break; + +case 'mod_vlan': + mod_vlan(); + break; + +default: +case 'show': + show(); + break; +} + +?> diff --git a/web/config.php b/web/config.php new file mode 100644 index 0000000..9799d4e --- /dev/null +++ b/web/config.php @@ -0,0 +1,81 @@ + $bridge->id, + 'ctrlip' => $bridge->ctrlip, + 'macmask' => $bridge->basemac."/FF:FF:FF:FF:FF:00" + ); + +$device = 0; +$retval['tunnel'] = array(); +foreach ($bridges as $bridge) { + if ($bridge->id == $bridgeid) + continue; + + if ($bridge->ctrlip == "0.0.0.0") + continue; + + $retval['tunnel'][$bridge->id] = array( + 'name' => (($bridge->id < $bridgeid) ? "tap-{$bridgeid}-{$bridge->id}" : "tap-{$bridge->id}-{$bridgeid}"), + 'dest' => $bridge->ctrlip, + 'mode' => (($bridge->id < $bridgeid) ? "client" : "server"), + 'device' => "tap".$device++, + 'macmask' => $bridge->basemac."/FF:FF:FF:FF:FF:00" + ); +} + +$retval['vlan'] = array(); +$trunks = Trunk::getAll($bridgeid); +foreach ($trunks as $trunk) { + $vlans = Vlan::getAll($trunk->id); + foreach ($vlans as $vlan) + $retval['vlan'][$vlan->id] = array( + 'name' => (($vlan->vlannum > 1) ? "{$trunk->name}.{$vlan->vlannum}" : $trunk->name), + 'bw' => $vlan->bandwidth, + 'mac' => $vlan->mac + ); +} + +$retval['hlsw'] = array(); +$masters = Hlsw::getAll(); +foreach ($masters as $hlsw) { + if (isset($retval['vlan'][$hlsw->vlanid])) { + $retval['hlsw'][$hlsw->id] = array( + 'dev' => $retval['vlan'][$hlsw->vlanid]['name'], + 'ip' => $hlsw->ip + ); + } +} + +$retval['forward'] = array(); +$forwards = Forward::getAll(); +foreach ($forwards as $forward) + $retval['forward'][$forward->id] = array( + 'portlo' => $forward->portlo, + 'porthi' => $forward->porthi, + 'active' => $forward->isActive() + ); + +$action = Input::getVar('action', INP_GET | INP_STRING | INP_DEFAULT, 'fetch'); +switch ($action) { +case 'show': + Helper::show($retval); + break; + +default: +case 'fetch': + header("Content-Type: file/plain"); + echo serialize($retval); + break; +} + +?> diff --git a/web/forward.php b/web/forward.php new file mode 100644 index 0000000..0e327b4 --- /dev/null +++ b/web/forward.php @@ -0,0 +1,76 @@ +flags |= 0x01; + $forward->name = $name; + + $part = explode('-', $ports); + if (is_numeric($part[0]) && $part[0] > 0 && $part[0] < 65535) { + $forward->portlo = $part[0]; + + if (is_numeric($part[1]) && $part[1] > 0 && $part[1] < 65535) + $forward->porthi = $part[1]; + + $forward->save(); + } + } + Helper::reload(); +} + +function del_forward() { + $forwardid = Input::getVar('forwardid', INP_GET | INP_INT | INP_DEFAULT, 0); + if ($forwardid == 0) + Helper::reload(); + + Forward::delete($forwardid); + Helper::reload(); +} + +function toggle_forward() { + $forwardid = Input::getVar('forwardid', INP_GET | INP_INT | INP_DEFAULT, 0); + if ($forwardid == 0) + Helper::reload(); + + $forward = Forward::load($forwardid); + $forward->toggle(); + $forward->save(); + Helper::reload(); +} + +function show() { + $smarty = new MySmarty(); + + $forwards = Forward::getAll(); + $smarty->assign('forwards', $forwards); + + $smarty->displaySite('Bridge Configuration: Forward Ports', 'forward.tpl'); +} + +$action = Input::getVar('action', INP_GET | INP_STRING | INP_DEFAULT, "show"); +switch ($action) { + +case 'add_forward': + add_forward(); + break; + +case 'del_forward': + del_forward(); + break; + +case 'toggle_forward': + toggle_forward(); + break; + +default: +case 'show': + show(); + break; +} + +?> diff --git a/web/hlsw.php b/web/hlsw.php new file mode 100644 index 0000000..ee59a8a --- /dev/null +++ b/web/hlsw.php @@ -0,0 +1,82 @@ +name = "New Master"; + $master->save(); + Helper::reload(); +} + +function del_hlsw() { + $hlswid = Input::getVar('hlswid', INP_GET | INP_INT | INP_DEFAULT, 0); + if ($hlswid == 0) + Helper::reload(); + + Hlsw::delete($hlswid); + Helper::reload(); +} + +function mod_hlsw() { + $hlswid = Input::getVar('hlswid', INP_GET | INP_INT | INP_DEFAULT, 0); + if ($hlswid == 0) + Helper::reload(); + + $arr = Input::getVar('hlsw', INP_POST | INP_ARRAY | INP_DEFAULT, array()); + + $hlsw = Hlsw::load($hlswid); + $hlsw->name = $arr['name']; + $hlsw->ip = $arr['ip']; + $hlsw->vlanid = $arr['vlanid']; + $hlsw->save(); + + Helper::reload(); +} + +function show() { + $smarty = new MySmarty(); + + $masters = Hlsw::getAll(); + $smarty->assign('masters', $masters); + + $ifarr = array(0 => '- None -'); + $bridges = Bridge::getAll(); + foreach ($bridges as $bridge) { + $trunks = Trunk::getAll($bridge->id); + foreach ($trunks as $trunk) { + $vlans = Vlan::getAll($trunk->id); + foreach ($vlans as $vlan) { + if ($vlan->vlannum < 2) + $ifarr[$vlan->id] = "{$bridge->name} - {$trunk->name}"; + else + $ifarr[$vlan->id] = "{$bridge->name} - {$trunk->name}.{$vlan->vlannum}"; + } + } + } + + $smarty->assign('ifarr', $ifarr); + $smarty->displaySite('Configuration: HLSW Master Server', 'hlsw.tpl'); +} + +$action = Input::getVar('action', INP_GET | INP_STRING | INP_DEFAULT, "show"); +switch ($action) { + +case 'add_hlsw': + add_hlsw(); + break; + +case 'del_hlsw': + del_hlsw(); + break; + +case 'mod_hlsw': + mod_hlsw(); + break; + +default: +case 'show': + show(); + break; +} + +?> diff --git a/web/include.php b/web/include.php new file mode 100644 index 0000000..382a373 --- /dev/null +++ b/web/include.php @@ -0,0 +1,26 @@ + diff --git a/web/include/Database.class.php b/web/include/Database.class.php new file mode 100644 index 0000000..d40de9d --- /dev/null +++ b/web/include/Database.class.php @@ -0,0 +1,97 @@ +dbh = mysql_pconnect(DB_HOST, DB_USER, DB_PASS); + mysql_select_db(DB_NAME, $this->dbh); + + $stats = array(); + } + + /* + * TODO: errorhandling? + */ + function query($sql) { + $start = microtime(true); + $this->result = mysql_query($sql, $this->dbh); + $error = mysql_error($this->dbh); + $end = microtime(true); + $this->stats[] = array('query' => $sql, 'error' => $error, 'time' => $end - $start); + return $this->result; + } + + function fetch_assoc() { + return mysql_fetch_assoc($this->result); + } + + function fetch_array() { + return mysql_fetch_array($this->result); + } + + function fetch_row() { + return mysql_fetch_row($this->result); + } + + function num_rows() { + return mysql_num_rows($this->result); + } + + function insert_id() { + return mysql_insert_id(); + } + + function affected_rows() { + return mysql_affected_rows($this->result); + } + + static function getQueryStats() { + $sum = 0; + $errors = 0; + $stats = self::$instance->stats; + unset($stats['last']); + + if (count($stats) > 0) { + foreach ($stats as $key => $val) { + $sum += $val['time']; + + if (!empty($val['error'])) + $errors++; + } + + foreach ($stats as $key => $val) + $stats[$key]['percent'] = round($val['time'] / $sum, 2); + } + + $stats['last'] = array('count' => count($stats), 'errors' => $errors, 'sum' => round($sum, 4)); + return $stats; + } + + static function resetQueryStats() { + unset($instance->stats); + } + + function close($force = false) { + if ($force) { + mysql_close($instance->dbh); + unset($instance); + } + } +} + +?> diff --git a/web/include/Helper.class.php b/web/include/Helper.class.php new file mode 100644 index 0000000..f4aced7 --- /dev/null +++ b/web/include/Helper.class.php @@ -0,0 +1,33 @@ +'; + print_r($var); + echo ''; + } + + static function show2($var) { + echo '
';
+		var_dump($var);
+		echo '
'; + } + + static function redirect($uri) { + header('Location: '.$uri); + die(); + } + + static function reload($args = false, $anker = false) { + $dest = $_SERVER['PHP_SELF']; + if ($args) + $dest .= "?".$args; + + if ($anker) + $dest .= "#".$anker; + + Helper::redirect($dest); + } +} + +?> diff --git a/web/include/Input.class.php b/web/include/Input.class.php new file mode 100644 index 0000000..0905ca7 --- /dev/null +++ b/web/include/Input.class.php @@ -0,0 +1,101 @@ + 0) { + $tmp = 0; + foreach ($var as $key => $value) + $tmp |= $value; + + $var = $tmp; + + } else { + $var = false; + } + } + + /* Erlaubter Wert */ + if (is_array($values) && !in_array($var, $values)) + $var = false; + + /* Empty erlaubt */ + } else if ($flags & INP_EMPTY) { + return; + + /* Empty nicht erlaubt */ + } else { + $var = false; + } + + /* Defaultwert einsetzen */ + if (($flags & INP_DEFAULT) && ($var === false)) + $var = $default; + + return $var; + } + + /** + * Holt eine Integervariable vom Request + * @param string $name - Name der Variable + * @param int $flags - Flags + * @param int $default - Defaultwert + * @param int $min - Minimaler Wert + * @param int $max - Maximaler Wert + * @return int + */ + static function getInteger($name, $flags, $default, $min, $max) { + $flags &= ~(INP_STRING | INP_EMPTY); + $flags |= (INP_INT); + $var = Input::getVar($name, $flags, $default); + + return ($var >= $min && $var <= $max) ? $var : false; + } +} + +?> diff --git a/web/include/MySmarty.class.php b/web/include/MySmarty.class.php new file mode 100644 index 0000000..eaacc2b --- /dev/null +++ b/web/include/MySmarty.class.php @@ -0,0 +1,21 @@ +template_dir = BASEDIR."smarty/templates/"; + $this->compile_dir = BASEDIR."smarty/templates_c/"; + $this->config_dir = BASEDIR."smarty/configs/"; + $this->cache_dir = BASEDIR."smarty/cache/"; + return $this; + } + + function displaySite($title, $template) { + $this->assign("title", $title); + $this->assign("templatename", $template); + $this->display("siteframe.tpl"); + } +} + +?> diff --git a/web/include/db_Bridge.class.php b/web/include/db_Bridge.class.php new file mode 100644 index 0000000..2394c5c --- /dev/null +++ b/web/include/db_Bridge.class.php @@ -0,0 +1,126 @@ +inDB = true; + $retval->id = (int)$row['id']; + $retval->name = (string)$row['name']; + $retval->ctrlip = (string)$row['ctrlip']; + $retval->basemac = (string)$row['basemac']; + } + return $retval; + } + + private function toSql() { + return "name = '".mysql_real_escape_string($this->name)."', + ctrlip = INET_ATON('".mysql_real_escape_string($this->ctrlip)."'), + basemac = '".mysql_real_escape_string($this->basemac)."'"; + } + + function load($id) { + $dbh = Database::getInstance(); + $sql = "SELECT id, name, INET_NTOA(ctrlip) AS ctrlip, basemac + FROM bridge + WHERE id = '{$id}'"; + + $dbh->query($sql); + return self::fromRow($dbh->fetch_assoc()); + } + + function save() { + $dbh = Database::getInstance(); + + if ($this->inDB) { + $sql = "UPDATE bridge SET ".$this->toSql()." + WHERE id = '{$this->id}'"; + $dbh->query($sql); + + } else { + $sql = "INSERT bridge SET ".$this->toSql(); + + $dbh->query($sql); + $this->iNDB = true; + $this->id = $dbh->insert_id(); + } + } + + function delete($id) { + $dbh = Database::getInstance(); + $sql = "DELETE FROM bridge + WHERE id = '{$id}'"; + + $dbh->query($sql); + + $trunks = Trunk::getAll($id); + foreach ($trunks as $trunk) + Trunk::delete($trunk->id); + } + + function getAll() { + $dbh = Database::getInstance(); + + $sql = "SELECT id, name, INET_NTOA(ctrlip) AS ctrlip, basemac + FROM bridge + ORDER BY name"; + $dbh->query($sql); + + $retval = array(); + while ($row = $dbh->fetch_assoc()) + $retval[$row['id']] = self::fromRow($row); + + return $retval; + } + + private function inc_mac($mac) { + $parts = explode(':', $mac); + foreach ($parts as $num => $part) + $parts[$num] = hexdec($part); + + $inc = true; + for ($i = 5; $i >= 0; $i--) { + if ($inc) + $parts[$i]++; + + if ($parts[$i] >= 0x100) { + $parts[$i] = 0x00; + $inc = true; + } else { + $inc = false; + } + } + + foreach ($parts as $num => $part) { + $parts[$num] = strtoupper(dechex($part)); + + if ($part < 0x10) + $parts[$num] = "0".$parts[$num]; + } + + return implode(':', $parts); + } + + function reorder_macs() { + $mac = $this->basemac; + + $trunks = Trunk::getAll($this->id); + foreach ($trunks as $trunk) { + + $vlans = Vlan::getAll($trunk->id); + foreach ($vlans as $vlan) { + $mac = self::inc_mac($mac); + $vlan->mac = $mac; + $vlan->save(); + } + } + } +} + +?> diff --git a/web/include/db_Forward.class.php b/web/include/db_Forward.class.php new file mode 100644 index 0000000..0c42959 --- /dev/null +++ b/web/include/db_Forward.class.php @@ -0,0 +1,90 @@ +inDB = true; + $retval->id = (int)$row['id']; + $retval->flags = (int)$row['flags']; + $retval->portlo = (int)$row['portlo']; + $retval->porthi = (int)$row['porthi']; + $retval->name = (string)$row['name']; + } + return $retval; + } + + private function toSql() { + return "flags = '{$this->flags}', + portlo = '{$this->portlo}', + porthi = '{$this->porthi}', + name = '".mysql_real_escape_string($this->name)."'"; + } + + function load($id) { + $dbh = Database::getInstance(); + $sql = "SELECT id, flags, portlo, porthi, name + FROM forward + WHERE id = '{$id}'"; + + $dbh->query($sql); + return self::fromRow($dbh->fetch_assoc()); + } + + function save() { + $dbh = Database::getInstance(); + + if ($this->inDB) { + $sql = "UPDATE forward SET ".$this->toSql()." + WHERE id = '{$this->id}'"; + $dbh->query($sql); + + } else { + $sql = "INSERT forward SET ".$this->toSql(); + + $dbh->query($sql); + $this->iNDB = true; + $this->id = $dbh->insert_id(); + } + } + + function delete($id) { + $dbh = Database::getInstance(); + $sql = "DELETE FROM forward + WHERE id = '{$id}'"; + + $dbh->query($sql); + } + + function getAll() { + $dbh = Database::getInstance(); + + $sql = "SELECT id, flags, portlo, porthi, name + FROM forward + ORDER BY portlo, porthi"; + $dbh->query($sql); + + $retval = array(); + while ($row = $dbh->fetch_assoc()) + $retval[$row['id']] = self::fromRow($row); + + return $retval; + } + + function toggle() { + $this->flags ^= 0x01; + } + + function isActive() { + return ($this->flags & 0x01); + } +} + +?> diff --git a/web/include/db_Hlsw.class.php b/web/include/db_Hlsw.class.php new file mode 100644 index 0000000..b5acb8b --- /dev/null +++ b/web/include/db_Hlsw.class.php @@ -0,0 +1,82 @@ +inDB = true; + $retval->id = (int)$row['id']; + $retval->vlanid = (int)$row['vlanid']; + $retval->flags = (int)$row['flags']; + $retval->ip = (string)$row['ip']; + $retval->name = (string)$row['name']; + } + return $retval; + } + + private function toSql() { + return "vlanid = '{$this->vlanid}', + flags = '{$this->flags}', + ip = INET_ATON('".mysql_real_escape_string($this->ip)."'), + name = '".mysql_real_escape_string($this->name)."'"; + } + + function load($id) { + $dbh = Database::getInstance(); + $sql = "SELECT id, vlanid, flags, INET_NTOA(ip) AS ip, name + FROM hlsw + WHERE id = '{$id}'"; + + $dbh->query($sql); + return self::fromRow($dbh->fetch_assoc()); + } + + function save() { + $dbh = Database::getInstance(); + + if ($this->inDB) { + $sql = "UPDATE hlsw SET ".$this->toSql()." + WHERE id = '{$this->id}'"; + $dbh->query($sql); + + } else { + $sql = "INSERT hlsw SET ".$this->toSql(); + + $dbh->query($sql); + $this->iNDB = true; + $this->id = $dbh->insert_id(); + } + } + + function delete($id) { + $dbh = Database::getInstance(); + $sql = "DELETE FROM hlsw + WHERE id = '{$id}'"; + + $dbh->query($sql); + } + + function getAll() { + $dbh = Database::getInstance(); + + $sql = "SELECT id, vlanid, flags, INET_NTOA(ip) AS ip, name + FROM hlsw + ORDER BY ip"; + $dbh->query($sql); + + $retval = array(); + while ($row = $dbh->fetch_assoc()) + $retval[$row['id']] = self::fromRow($row); + + return $retval; + } +} + +?> diff --git a/web/include/db_Trunk.class.php b/web/include/db_Trunk.class.php new file mode 100644 index 0000000..685d89f --- /dev/null +++ b/web/include/db_Trunk.class.php @@ -0,0 +1,85 @@ +inDB = true; + $retval->id = (int)$row['id']; + $retval->bridgeid = (int)$row['bridgeid']; + $retval->flags = (int)$row['flags']; + $retval->name = (string)$row['name']; + } + return $retval; + } + + private function toSql() { + return "bridgeid = '{$this->bridgeid}', + flags = '{$this->flags}', + name = '".mysql_real_escape_string($this->name)."'"; + } + + function load($id) { + $dbh = Database::getInstance(); + $sql = "SELECT id, bridgeid, flags, name + FROM trunk + WHERE id = '{$id}'"; + + $dbh->query($sql); + return self::fromRow($dbh->fetch_assoc()); + } + + function save() { + $dbh = Database::getInstance(); + + if ($this->inDB) { + $sql = "UPDATE trunk SET ".$this->toSql()." + WHERE id = '{$this->id}'"; + $dbh->query($sql); + + } else { + $sql = "INSERT trunk SET ".$this->toSql(); + + $dbh->query($sql); + $this->iNDB = true; + $this->id = $dbh->insert_id(); + } + } + + function delete($id) { + $dbh = Database::getInstance(); + $sql = "DELETE FROM trunk + WHERE id = '{$id}'"; + + $dbh->query($sql); + + $vlans = Vlan::getAll($id); + foreach ($vlans as $vlan) + Vlan::delete($vlan->id); + } + + function getAll($bridgeid = false) { + $dbh = Database::getInstance(); + + $sql = "SELECT id, bridgeid, flags, name + FROM trunk + ".($bridgeid ? "WHERE bridgeid = '{$bridgeid}'" : "")." + ORDER BY name"; + + $dbh->query($sql); + + $retval = array(); + while ($row = $dbh->fetch_assoc()) + $retval[$row['id']] = self::fromRow($row); + + return $retval; + } +} + +?> diff --git a/web/include/db_Vlan.class.php b/web/include/db_Vlan.class.php new file mode 100644 index 0000000..14dc0de --- /dev/null +++ b/web/include/db_Vlan.class.php @@ -0,0 +1,86 @@ +inDB = true; + $retval->id = (int)$row['id']; + $retval->trunkid = (int)$row['trunkid']; + $retval->flags = (int)$row['flags']; + $retval->vlannum = (int)$row['vlannum']; + $retval->bandwidth = (int)$row['bandwidth']; + $retval->mac = (string)$row['mac']; + } + return $retval; + } + + private function toSql() { + return "trunkid = '{$this->trunkid}', + flags = '{$this->flags}', + vlannum = '{$this->vlannum}', + bandwidth = '{$this->bandwidth}', + mac = '".mysql_real_escape_string($this->mac)."'"; + } + + function load($id) { + $dbh = Database::getInstance(); + $sql = "SELECT id, trunkid, flags, vlannum, bandwidth, mac + FROM vlan + WHERE id = '{$id}'"; + + $dbh->query($sql); + return self::fromRow($dbh->fetch_assoc()); + } + + function save() { + $dbh = Database::getInstance(); + + if ($this->inDB) { + $sql = "UPDATE vlan SET ".$this->toSql()." + WHERE id = '{$this->id}'"; + $dbh->query($sql); + + } else { + $sql = "INSERT vlan SET ".$this->toSql(); + + $dbh->query($sql); + $this->iNDB = true; + $this->id = $dbh->insert_id(); + } + } + + function delete($id) { + $dbh = Database::getInstance(); + $sql = "DELETE FROM vlan + WHERE id = '{$id}'"; + + $dbh->query($sql); + } + + function getAll($trunkid = false) { + $dbh = Database::getInstance(); + + $sql = "SELECT id, trunkid, flags, vlannum, bandwidth, mac + FROM vlan + ".($trunkid ? "WHERE trunkid = '{$trunkid}'" : "")." + ORDER BY vlannum"; + $dbh->query($sql); + + $retval = array(); + while ($row = $dbh->fetch_assoc()) + $retval[$row['id']] = self::fromRow($row); + + return $retval; + } +} + +?> diff --git a/web/index.php b/web/index.php new file mode 100644 index 0000000..730c452 --- /dev/null +++ b/web/index.php @@ -0,0 +1,9 @@ +assign('bridges', Bridge::getAll()); + +$smarty->displaySite('Bridge Overview', 'overview.tpl'); + +?> diff --git a/web/smarty/templates/bridge.tpl b/web/smarty/templates/bridge.tpl new file mode 100644 index 0000000..8b15711 --- /dev/null +++ b/web/smarty/templates/bridge.tpl @@ -0,0 +1,109 @@ + + +
+ +{foreach from=$bridges item=bridge} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bridge: {$bridge->name|escape}
Name:IP:
Base MAC:
 
Status:- +    + +

+
+ + + + + +
Interfaces:
+ +
+ + +
+
+
+
+ + + + + +
VLANs:
+ +
+ + + +
+ + + +
+
+
+

+{/foreach} + +
+ + + +
Bridge: -
+
+ +
diff --git a/web/smarty/templates/forward.tpl b/web/smarty/templates/forward.tpl new file mode 100644 index 0000000..3c3ea66 --- /dev/null +++ b/web/smarty/templates/forward.tpl @@ -0,0 +1,39 @@ + +
+ + + + + + + + + +{foreach from=$forwards item=forward} + {cycle values="data1,data2" assign=tdclass} + + {if $forward->isActive()} + + {else} + + {/if} + + + + +{/foreach} + + + + + + + + + +
IP/UDP Forwards
activePort(s)Description
+ + + + {$forward->portlo}{if $forward->porthi != 0} - {$forward->porthi}{/if}{$forward->name|escape}
+
diff --git a/web/smarty/templates/hlsw.tpl b/web/smarty/templates/hlsw.tpl new file mode 100644 index 0000000..7fb7488 --- /dev/null +++ b/web/smarty/templates/hlsw.tpl @@ -0,0 +1,47 @@ + + +
+ +{foreach from=$masters item=hlsw} + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HLSW: {$hlsw->name|escape}
Name:
Source IP:
Interface:{html_options name=hlsw[vlanid] options=$ifarr selected=$hlsw->vlanid}
 
+    + +

[fancy rrdtool stats]
+

+{/foreach} + +
+ + + +
HLSW Master: -
+
+ +
diff --git a/web/smarty/templates/overview.tpl b/web/smarty/templates/overview.tpl new file mode 100644 index 0000000..0e24611 --- /dev/null +++ b/web/smarty/templates/overview.tpl @@ -0,0 +1,13 @@ + +{foreach from=$bridges item=bridge} + +{/foreach} +
+ + + + + + +
Bridge: {$bridge->name|escape}
[fancy rrdtool stats][fancy rrdtool stats]
+
diff --git a/web/smarty/templates/siteframe.tpl b/web/smarty/templates/siteframe.tpl new file mode 100644 index 0000000..d90e6c2 --- /dev/null +++ b/web/smarty/templates/siteframe.tpl @@ -0,0 +1,50 @@ + +Bridge Configuration{if $title} - {$title|escape}{/if} + + + + + + + +
  +

{$title|escape}

+
+ Overview
+
+ + Config:
+ =>  + Bridges +
+ =>  + Forward Ports +
+ =>  + HLSW Master +
+
+{* + Statistics:
+ =>  + Bridges +
+ =>  + Bridge Tunnels +
+ =>  + Bridge VLANs +
+ =>  + Forwarding Ports +
+ =>  + HLSW Server +
+
+*} +


+
+{include file="$templatename"} +
+ diff --git a/web/style.css b/web/style.css new file mode 100644 index 0000000..bf45ac8 --- /dev/null +++ b/web/style.css @@ -0,0 +1,117 @@ +/* Normal Body */ +body { + background-color: #FFFFFF; + color: #000000; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 12px; + text-decoration: none; +} + +/* Input Field Description, right aligned */ +.descra { + font-size: 12px; + font-weight: bold; + text-align: right; +} + +/* Input Field Description, left aligned */ +.descla { + font-size: 12px; + font-weight: bold; + text-align: left; +} + +/* Red Border */ +.redborder { + border: 1px solid #B6334A; +} + +/* all Input Fields */ +select,input,textarea { + border: 1px solid #BBBBBB; + font-size: 12px; + padding: 2px; +} + +/* light gray box */ +.lgraybox { + background-color: #F7F7F7; + border: 1px solid #E0E0E0; + padding: 5px; + text-align: left; + vertical-align: top; + margin: 5; +} + +/* a normal link */ +a { + color: #000000; + font-size: 12px; + text-decoration: none; + font-weight: normal; +} + +/* mouse over link */ +a:hover { + text-decoration: underline; +} + +/* link selected (i am here) */ +a.sel { + font-size: 12px; + font-weight: bold; + text-decoration: none; +} + +/* red marker in front of link */ +.navlink { + color: #FF0000; + font-size: 12px; + font-weight: bold; +} + +/* group caption of links */ +.navgroup { + color: #000000; + font-size: 13px; + font-weight: bold; + text-decoration: underline; +} + +/* small text */ +p { + font-size: 12px; +} + +td.head { + background: #b5b5b5; + color: #FFFFFF; + font-weight: bold; + text-align: center; +} + +td.data { + font-size: 12px; + padding: 1px; +} + +td.data1 { + background-color: #F0F0F0; + color: #000000; + font-size: 12px; + padding: 1px; +} + +td.data2 { + background-color: #E0E0E0; + color: #000000; + font-size: 12px; + padding: 1px; +} + +caption { + color: #C20022; + font-size: 13px; + font-weight: bold; + text-align: left; +}