742 lines
18 KiB
PHP
742 lines
18 KiB
PHP
|
#!/usr/bin/php
|
||
|
<?php
|
||
|
|
||
|
// file positionen
|
||
|
define('NEWFILE', 'http://10.10.254.100/bridge/config.php?bridgeid=22');
|
||
|
define('OLDFILE', '/etc/bridge/.config.old');
|
||
|
|
||
|
// rrdsrv on 5001/tcp
|
||
|
define('RRDSRV', "10.10.254.100");
|
||
|
|
||
|
class Cmd {
|
||
|
function run($args) {
|
||
|
echo "$args\n";
|
||
|
exec($args, $tmp);
|
||
|
return $tmp;
|
||
|
}
|
||
|
|
||
|
function ebtables($args) {
|
||
|
return self::run("/sbin/ebtables {$args}");
|
||
|
}
|
||
|
|
||
|
function brctl($args) {
|
||
|
return self::run("/usr/sbin/brctl {$args}");
|
||
|
}
|
||
|
|
||
|
function vconfig($args) {
|
||
|
return self::run("/sbin/vconfig {$args}");
|
||
|
}
|
||
|
|
||
|
function ifconfig($args) {
|
||
|
return self::run("/sbin/ifconfig {$args}");
|
||
|
}
|
||
|
|
||
|
function route($args) {
|
||
|
return self::run("/sbin/route {$args}");
|
||
|
}
|
||
|
|
||
|
function tc($args) {
|
||
|
return self::run("/sbin/tc {$args}");
|
||
|
}
|
||
|
|
||
|
function vtund($args) {
|
||
|
return self::run("/usr/sbin/vtund {$args}");
|
||
|
}
|
||
|
|
||
|
function ip($args) {
|
||
|
return self::run("/sbin/ip {$args}");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Config {
|
||
|
function fetch() {
|
||
|
$data = @file_get_contents(NEWFILE);
|
||
|
if (empty($data))
|
||
|
return false;
|
||
|
|
||
|
$arr = @unserialize($data);
|
||
|
if (!is_array($arr))
|
||
|
return false;
|
||
|
|
||
|
return $arr;
|
||
|
}
|
||
|
|
||
|
function getOld() {
|
||
|
if (!file_exists(OLDFILE))
|
||
|
return false;
|
||
|
|
||
|
$data = @file_get_contents(OLDFILE);
|
||
|
$arr = @unserialize($data);
|
||
|
if (!is_array($arr))
|
||
|
return false;
|
||
|
|
||
|
return $arr;
|
||
|
}
|
||
|
|
||
|
function getEmpty() {
|
||
|
return array(
|
||
|
'bridge' => 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);
|
||
|
|
||
|
?>
|