Commit 1852d5d0 authored by Marc Ariberti's avatar Marc Ariberti

* added miniVLANserver that has been quicly developed for the Ecole

Centrale Paris.

* see included documentation for more information about configuration,
    installations...

* yuo will need to install apache, postgresql, and compile php for
snmp support
parent da7de258
* Installer postgresql
* Installer apache et apache-dev
* Configurer APACHE pour qu'il tourne en USER www-data (httpd.conf)
* Compiler PHP :
- ./configure --with-pgsql --with-snmp --enable-ucd-snmp-hack --without-mysql
- make && make install
* Compiler le module PHP pour apache :
- ./configure --with-pgsql --with-snmp --enable-ucd-snmp-hack --without-mysql --with-apxs
- make
- mkdir /usr/local/lib/apache
- cp .libs/libphp4.so /usr/local/lib/apache
- rajouter la ligne suivante dans /etc/apache/httpd.conf :
LoadModule php4_module /usr/local/lib/apache/libphp4.so
* ne pas hésiter à relancer apache
* rajouter un lien du genre :
ln -s /home/diff/vlcs/htdocs /var/www/vlcs
* Créer les users postgres suivant : diff et www-data (createuser)
- NB: etre en USER postgres
- diff avec tous les droits
- www-data avec le minimum de droits lors de la création
* Créer la db vlcs : createdb vlcs
* Editer le network.conf pour qu'il reflète la config du réseau
* Lancer le script gensql.sh
* lancer psql vlcs (en compte diff dans le répertoire conf)
* lancer create_db.sh
* lancer les scripts init_switches.php updatedb.php
* mettre les scripts d'admin dans la cron 'crontab crontab'
* dans le répertoire vlcs : faire make && make install
* mettre les lignes suivantes dans visudo :
diff ALL = NOPASSWD: /usr/sbin/arp -d *
videolan ALL = (diff) /home/diff/nvlcs/bin/restart_vlcs.sh
* lancer le vlcs dans un screen : screen ./vlcs
* si j'ai rien oublié çà devrait marcher
****************************************************
* DISCLAIMER DISCLAIMER *
****************************************************
* I must remind that this program is NOT SAFE at all. Use it at your
own risk. You can crush down your network. If you do not know what
a VLAN exactly is, please do not use it.
* I strongly advise you to read the vlb-linux documentation
because you will probably need it
****************************************************
* DISCLAIMER DISCLAIMER *
****************************************************
* To know what are VLANs, and what has the VLANserver been designed for,
please refer to the FAQ that has been written for the VLANserver :
http://www.videolan.org/
* this miniVLANserver is a simplified VLANserver that has been designed
to fit the needs at our school. It has been designed to be very simple
and not optimized at all (because the numbers of request made by vlc
did not urge it).
* Switch that are supported are 3com switches : 1100 33OO 1000 Desktop
SNMP requests to change VLAN do not work on our HP procurve 2524 switch
* parts are :
vlcs/ contains the source of the program that dialogs with the vlc
bin/ contains main program and different scripts
vlcs program that dialogs with the vlc
updatedb.php sends request to all switches in order to update
the vlcs' database
go_vlan2.php script that send request to put back all the ports
to the VLAN 2
several others...
conf/ contains configuration files :
network.conf the network topology (network.conf)
create.sql the database definition
vlcs.conf the list of channels
network.sql generated by gensql.sh using network.conf, do NOT edit
htdocs/ contains php files for administration/audimat through http
README this file
INSTALL installation instruction
TODO a plain todolist
crontab the crontab to be inserted in the system's crontab
to run updating scripts
* build a complete web site for administration
* 802.1Q handling
* split vlcs.c (for GPA)
* make a beautiful makefile
* add a debug mode
* proprification (indent, names...)
* dynamically change channels number and description
* remove the channel2vlan kludge
* add comments everywhere
* make a clean logger system (reuse marcari's one :)
* put more logs (with a configurable verbosity)
* put back to channel 0 people that have not been seen for a while
* lock switches if there are simultaneous request on the same switch
* rewrite change_channel.php in language C
* find a way to change cleanly channel on switch-hp
#!/home/diff/bin/php -q
<?
/*****************************************************************************
* change_channel.php: PostgreSQL and SNMP queries for VLCS
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: change_channel.php,v 1.1 2002/01/27 22:00:38 marcari Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/* change_channel.php <channel> <MAC address>
*
* Return values :
* 0 : OK
* 1 : Machine not found
* 2 : Protected port
* 3 : SNMP failed
*/
if( $argv[1] == "-h" || $argv[1] == "--help" )
{
echo "Usage : change_channel.php <channel> <MAC address> <ip>\n";
exit( -1 );
}
$channel = $argv[1];
$mac_ad = $argv[2];
$ip = $argv[3];
//exec("host $ip",$result);
//list($dummy, $dns_l)=explode(" ",$result[0]);
//list($dns, $j1, $j2, $j3)=explode(".",$dns_l);
include( "database.inc" );
include( "snmp.inc" );
openlog( "VLCS/PHP", 0, LOG_DAEMON );
syslog(LOG_INFO,"$ip asked for channel $channel");
base_Init();
echo date("d/M H:i:s")." $ip asked for channel $channel\n";
$query = base_Check( $mac_ad, Channel2VLAN( $channel ) );
if( !$query )
{
base_Close();
closelog();
exit( 1 );
}
if( $query["port_protection"] )
{
base_Close();
closelog();
exit( 2 );
}
syslog(LOG_INFO,"Sending SNMP request");
/* Do SNMP request */
$var_name = "vlan".Channel2VLAN( $channel )."_id";
if( !snmp_set_vlan( $query["switch_ip"], $query["port_internal_id"],
$query[$var_name], $query["community_string"] ) )
{
syslog( LOG_CRIT, "SNMP failed (".$query["switch_ip"].":"
.$query["port_internal_id"].")\n" );
base_Close();
closelog();
exit( 3 );
}
syslog(LOG_INFO,"SNMP request sent");
base_Change( $query["port_id"], Channel2VLAN( $channel ) );
// remove the ARP entry because we know that now, the client
// has changed vlan and so changed visible MAC address (cf vlanbridge)
// system("sudo arp -d $ip");
syslog(LOG_INFO,"Changed in DB");
base_Close();
closelog();
exit( 0 );
#!/bin/sh
psql -f ../conf/create.sql vlcs
psql -f ../conf/network.sql vlcs
<?
/* Configuration */
$pg_host = "localhost";
$pg_port = 5432;
$pg_db = "vlcs";
/*
* Database management functions
*/
function base_Init( )
{
global $pg_handle, $pg_host, $pg_port, $pg_db;
$pg_handle = pg_connect($pg_host, $pg_port, $pg_db);
if( !$pg_handle )
{
syslog( LOG_ALERT, "Error : Cannot open database !\n" );
exit(-1);
}
}
function base_Close( )
{
global $pg_handle;
pg_close( $pg_handle );
}
function base_Check( $mac_ad, $vlan )
{
global $pg_handle;
$request = pg_exec( $pg_handle, "select port.port_id, port.port_internal_id, port.port_protection, switch.switch_ip, switch.community_string, switch.vlan".$vlan."_id from machine, port, switch where machine.mac_ad='$mac_ad' and machine.port_id=port.port_id and port.switch_id=switch.switch_id" );
if( !$request )
{
syslog( LOG_ALERT, "Error : PostgreSQL database has gone fishing !\n" );
return;
}
$num = pg_numrows( $request );
if( $num == 0 )
{
syslog( LOG_NOTICE, "Warning : $mac_ad doesn't exist in the database\n" );
return;
}
elseif( $num > 1 )
{
syslog( LOG_NOTICE, "Warning : duplicate entries for $mac_ad\n" );
}
return pg_fetch_array( $request, 0 );
}
function base_AllPorts( $channel )
{
global $pg_handle;
$request = pg_exec( $pg_handle, "select port.port_id, port.port_internal_id, port.port_protection, switch.switch_ip, switch.community_string, switch.vlan".$channel."_id from port, switch where port.switch_id=switch.switch_id" );
if( !$request )
{
syslog( LOG_ALERT, "Error : PostgreSQL database has gone fishing !\n" );
return;
}
$num = pg_numrows( $request );
$result = array();
for( $i = 0; $i < $num; $i++ )
{
$result[] = pg_fetch_array( $request, $i );
}
return( $result );
}
function base_Change( $port_id, $channel )
{
/* No error checks because it's been done in base_Check() */
global $pg_handle;
$request = pg_exec($pg_handle, "update port set vlan_num=$channel where port_id=$port_id" );
if( !$request )
{
syslog( LOG_ALERT, "Error : PostgreSQL database has gone fishing !\n");
}
if( ($num = pg_cmdtuples( $request )) != 1 )
{
syslog( LOG_CRIT, "Error : Update made weird things (cmdtuples=$num)");
}
}
function base_Expire()
{
global $pg_handle;
// 172800=2*24*3600secondes=48heures de aging time
$request = pg_exec($pg_handle,
"delete from machine where age(now(), expires)>172800");
if( !$request )
{
echo "Error : PostgreSQL database has gone fishing !\n";
return;
}
syslog( LOG_NOTICE, "Maintenance : Expired ".pg_cmdtuples($request)." machine entries\n" );
}
function base_IncreaseUnseen()
{
global $pg_handle;
// pg_exec($pg_handle, "update machine, port set port.unseen_count = port.unseen_count + 1 where machine.port_id = port.port_id");
}
// returns all macs that have not been seen for a while (4 times for eg.)
function base_UnseenLimit()
{
global $pg_handle;
/* $request=pg_exec($pg_handle, "select switch.switch_ip, port.port_internal_id, switch.vlan2_id, switch.community_string from machine, port, switch where unseen_count>4 and port.port_id=machine.port_id and port.vlan_num>2");
if( !$request )
{
syslog( LOG_ALERT, "Error : PostgreSQL database has gone fishing !\n" );
return;
}
$num = pg_numrows( $request );
$result = array();
for( $i = 0; $i < $num; $i++ )
{
$row = pg_fetch_array( $request, $i );
$result[]=$row["mac_ad"];
}
return( $result );
*/
}
// insert machine in db or update info if machine already exists
// return 0 if everything is OK
function set_Machine( $port_id, $mac_addr )
{
global $pg_handle;
$request = pg_exec($pg_handle, "select machine_id from machine where mac_ad='$mac_addr';" );
if( !$request )
{
syslog(LOG_ERR,"Error : PostgreSQL database has gone fishing !\n");
return;
}
$num = pg_numrows( $request );
if( $num == 0 )
{
$request=pg_exec($pg_handle, "select nextval('machine_seq');");
$row=pg_fetch_row($request, 0);
$machine_id=$row[0];
$timestamp=time()+3600*24*48;
$res=pg_exec($pg_handle, "insert into machine values ($machine_id, $port_id, '$mac_addr', now());");
if ($res==FALSE)
{
syslog(LOG_ERR, "Insert machine query could not be executed\n");
return 1;
}
return 0;
}
else if ($num == 1)
{
$row=pg_fetch_array($request, 0);
$machine_id=$row[0];
$res=pg_exec($pg_handle, "update machine set port_id=$port_id, mac_ad='$mac_addr',expires=now() where machine_id=$machine_id");
if ($res==FALSE)
{
syslog(LOG_ERR, "Update machine query could not be executed\n");
return 1;
}
return 0;
}
else
{
syslog(LOG_WARNING, "Warning machine $mac_addr is more than once in DB");
return 2;
}
}
function update_Vlan( $switch_id, $port_number, $vlan_num )
{
global $pg_handle;
$request = pg_exec($pg_handle, "update port set vlan_num=$vlan_num where switch_id=$switch_id and port_number=$port_number" );
if( !$request )
{
syslog( LOG_ALERT, "Error : PostgreSQL database has gone fishing !\n");
}
if( ($num = pg_cmdtuples( $request )) != 1 )
{
syslog( LOG_CRIT, "Error : Update made weird things (cmdtuples=$num)");
}
}
function set_PortInternalId( $switch_id, $port_number, $port_internal_id )
{
global $pg_handle;
$request = pg_exec($pg_handle, "select port_id from port where port_number=$port_number and switch_id=$switch_id" );
if( !$request )
{
echo "Error : PostgreSQL database has gone fishing !\n";
return 1;
}
$num = pg_numrows( $request );
if( $num == 0 )
{
syslog(LOG_ERR, "Error : port number $port_number not found on switch n$switch_id");
}
else
{
$row=pg_fetch_row($request, 0);
$port_id=$row[0];
$res=pg_exec($pg_handle, "update port set port_internal_id=$port_internal_id where port_id=$port_id and port_protection=0;");
if ($res==FALSE)
{
syslog(LOG_ERR, "Update port query could not be executed\n");
return 1;
}
}
}
function set_vlanId($switch_id, $number, $id)
{
global $pg_handle;
$res=pg_exec($pg_handle, "update switch set vlan".$number."_id=$id where switch_id=$switch_id;");
if ($res==FALSE)
{
syslog(LOG_ERR, "Update vlan_id query could not be executed\n");
return 1;
}
return 0;
}
function Channel2VLAN( $channel )
{
if( $channel == 0 )
{
return( 2 );
}
else
{
return( $channel + 3 );
}
}
?>
#!/bin/sh
psql -f ../conf/destroy.sql vlcs
#!/home/diff/bin/php -q
<?
/*****************************************************************************
* expire_entries.php: Expires old machines
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: expire_entries.php,v 1.1 2002/01/27 22:00:38 marcari Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
if( $argv[1] == "-h" || $argv[1] == "--help" )
{
echo "Usage : expire_entries.php\n";
exit( -1 );
}
include( "database.inc" );
openlog( "VLCS/PHP", LOG_PERROR, LOG_DAEMON );
base_Init();
base_Expire();
base_Close();
closelog();
exit( 0 );
?>
#!/bin/bash
cat ../conf/network.conf | grep -v '^#' | grep -v '^ *$' |
{
switch_num=1;
port_id=1;
while read nom ip unit type community nports liste
do
echo "INSERT INTO switch VALUES ($switch_num, '$nom', '$ip', $unit, $type, '$community',";
echo " -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);"
for port_num in `seq 1 $nports`
do
if echo $liste | grep "\<$port_num\>" > /dev/null
then
echo "INSERT INTO port VALUES ( $port_id, $switch_num, $port_num, -1, 2, 2, -1);"
elif echo $liste | grep "\<r$port_num\>" > /dev/null
then
echo "INSERT INTO port VALUES ( $port_id, $switch_num, $port_num, -1, 1, 2, -1);"
else
echo "INSERT INTO port VALUES ( $port_id, $switch_num, $port_num, -1, 0, 2, -1);"
fi
port_id=$(($port_id+1))
done
switch_num=$(($switch_num+1))
echo
echo
done
port_id=$(($port_id+1))
switch_num=$(($switch_num+1))
echo "SELECT setval('switch_seq',$switch_num);";
echo "SELECT setval('port_seq',$port_id);";
} > ../conf/network.sql
#!/home/diff/bin/php -q
<?
/*****************************************************************************
* go_vlan2.php: Place ALL machines in VLAN 2
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: go_vlan2.php,v 1.1 2002/01/27 22:00:38 marcari Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
if( $argv[1] == "-h" || $argv[1] == "--help" )
{
echo "Usage : go_vlan2.php\n";
exit( -1 );
}
include( "database.inc" );
include( "snmp.inc" );
openlog( "VLCS/PHP", LOG_PERROR, LOG_DAEMON );
base_Init();
$ports = base_AllPorts( 2 );
if( !$ports )
{
base_Close();
closelog();
exit( 1 );
}
foreach ($ports as $query)
{
if( $query["port_protection"] )
{
continue;
}
/* Do SNMP request */
if( !snmp_set_vlan( $query["switch_ip"], $query["port_internal_id"],
$query["vlan2_id"], $query["community_string"] ) )
{
syslog( LOG_CRIT, "SNMP failed (".$query["switch_ip"].":"
.$query["port_internal_id"].")\n" );
continue;
}
base_Change( $query["port_id"], 2 );
}
base_Close();
closelog();
exit( 0 );
?>
#!/bin/sh
# usage : hp_change_vlan .sh port vlan
echo "Changing vlan on switch-HP !!!"
cat cmds | sed "s/%VLAN/$2/" | sed "s/%PORT/$1/" | netcat switch-h3 23 > /dev/null 2> /dev/null
#!/home/diff/bin/php -q
<?
// This script lauches walk on switch in order to get vlanIds an portIds
// of all the switches and stores them into the DB
include("snmp.inc");
include("database.inc");
base_Init();
$request=pg_exec($pg_handle,
"select switch_id, switch_name, switch_ip, unit_number, switch_type, community_string from switch;");
// "select switch_id, switch_name, switch_ip, unit_number, switch_type, community_string from switch where switch_name = 'switch-i3';");
$nb_switches=pg_numrows($request);
for($num_switch=0 ; $num_switch<$nb_switches ; $num_switch++)
{
$row=pg_fetch_array($request, $num_switch);
echo $row["switch_name"]."\n";
$switch_id=$row["switch_id"];
/* gets the portIds and vlanIds of the switch */
$id_list=snmp_walk_switch_ids( $row["switch_ip"],
$row["unit_number"],
$row['switch_type'],
$row["community_string"]);
foreach ( $id_list as $key => $id)
{
list($type, $number)=explode(" ",$key);
if ($type=="Port")
{
set_PortInternalId($switch_id, $number, $id);
}
else if ($type=="Vlan")
{
set_VlanId($switch_id, $number, $id);
}
else
{
syslog(LOG_WARNING, "warning : unknown type of id");
}
}
}
base_Close();
?>
#!/bin/bash
# usage : kill_vlcs.sh signal
# stop the previous instance of vlcs
killall $1 vlcs
#!/bin/bash
./kill_vlcs.sh
./run_vlcs.sh