sqlite instead of file system to store macs

This commit is contained in:
sandb 2010-02-22 01:38:28 +01:00
parent ebff21147c
commit b08f87e9e5
9 changed files with 130 additions and 148 deletions

6
.htaccess Normal file
View File

@ -0,0 +1,6 @@
Addtype application/octet-stream .ttf .otf
AddType application/vnd.ms-fontobject .eot
RewriteRule (.*).php $1
RewriteRule (.*).hmtl $1

View File

@ -1,6 +1,11 @@
<?php <?php
define("OUTPUT_SERVER_DIRECTORY", "/home/sandbender/www/pamela-trans/uploads"); // Number of seconds a mac address file is valid. If it's older it will be removed.
define("MACFILE_TTL", "3600"); define("MACFILE_TTL", "3600");
// Where the db is located for the sqlite db. The file does not have to exist.
// The directory does need to exist though, and the directory must be writable.
define("SQLITE_DB", "/home/sandbender/www/pamela/db/pamela.sql");
// sql create statement for mac table
define("CREATE_MAC_TABLE_SQL", "create table macs (mac text unique on conflict replace, committime integer);");

11
lib/db.php Normal file
View File

@ -0,0 +1,11 @@
<?php
require_once("config.php");
function get_db() {
static $db = NULL;
if ($db == NULL) {
$db = sqlite_open(SQLITE_DB);
}
return $db;
}

26
lib/macs.php Normal file
View File

@ -0,0 +1,26 @@
<?php
require_once("lib/db.php");
function macs_get() {
$results = array();
$db = get_db();
$q = sqlite_query($db, "select mac from macs where committime > strftime('%s','now') - ".MACFILE_TTL);
if (!$q) return $results;
while(sqlite_has_more($q)) {
$row = sqlite_fetch_array($q, SQLITE_ASSOC);
$results[] = $row['mac'];
}
return $results;
}
function macs_add($mac) {
$db = get_db();
$mac = sqlite_escape_string($mac);
$q = sqlite_exec($db, "insert into macs values (\"$mac\", strftime('%s','now'))");
if (!$q) return $results;
}
function macs_purge() {
$db = get_db();
return sqlite_exec($db, "delete from macs where committime <= strftime('%s','now') - ".MACFILE_TTL);
}

View File

@ -95,4 +95,8 @@ function script($source) {
<script type="text/javascript" src="<?=$source?>"></script> <script type="text/javascript" src="<?=$source?>"></script>
<?php <?php
} }
?>
function echoln($str) {
echo("$str\n");
}

View File

@ -24,11 +24,8 @@ header("Cache-Control: no-cache");
header("Pragma: no-cache"); header("Pragma: no-cache");
require_once("config.php"); require_once("config.php");
require_once("lib/util.php");
require_once("lib/trans.php"); require_once("lib/trans.php");
require_once("lib/macs.php");
// [ "00:01:e8:04:99:be", "00:05:4e:40:1e:97", "00:0c:f1:16:10:ba", "00:0c:f1:1d:dc:70", "00:0e:35:96:c7:ff", "00:11:85:6a:1f:ec", ]
function translator($mac) { function translator($mac) {
global $mac_translation_table; global $mac_translation_table;
@ -37,65 +34,7 @@ function translator($mac) {
return $mac; return $mac;
} }
$macs = macs_get();
class Macs { $macs = array_map("translator", $macs);
echo '["'.implode('", "', $macs).'"]';
private $macs; macs_purge();
function __construct() {
$this->macs = array();
}
private function readFile($filename) {
$mcs = file_get_contents($filename);
$this->macs = array_merge($this->macs, explode(',', $mcs));
}
private function readFiles($directory) {
$macFiles = scandir($directory);
foreach ($macFiles as $macFile) {
if (preg_match("/.+\.macs$/", $macFile) != 1)
continue;
$filename = "$directory/$macFile";
// data is too old, remove
if (filemtime($filename) + MACFILE_TTL < time()) {
unlink($filename);
continue;
}
$this->readFile($filename);
}
}
private function cleanUp() {
$this->macs = array_unique($this->macs);
}
private function translate() {
$this->macs = array_map("translator", $this->macs);
}
private function createJson() {
if (count($this->macs) < 1) {
echo '[]';
return;
}
echo '["';
echo implode('", "', $this->macs);
echo '"]';
}
public function run() {
$this->readFiles(OUTPUT_SERVER_DIRECTORY);
$this->cleanUp();
$this->translate();
$this->createJson();
}
}
$macs = new Macs();
$macs->run();

View File

@ -34,8 +34,7 @@ USER=''
PASSWORD='' PASSWORD=''
function usage { function usage {
echo "Usage: pamela-scanner [OPTIONS]
echo "Usage: pamela-scanner [OPTIONS]
-i INTERFACE Interface to arp-scan. Defaults to [$IF]. -i INTERFACE Interface to arp-scan. Defaults to [$IF].
-o URL The url of the pamela upload script (including /upload.php). -o URL The url of the pamela upload script (including /upload.php).
@ -51,71 +50,85 @@ webserver where you get a visual representation of the mac addresses present.
Multiple people on multiple lans can run pamela together against the same Multiple people on multiple lans can run pamela together against the same
server, where all results are agregated. In short, pamela gives you an overview server, where all results are agregated. In short, pamela gives you an overview
of how big the shared network is." of how big the shared network is."
}
exit 1 function check_if_root {
if [ "$(id -ru)" != "0" ]
then
echo "Must be root to run pamela-scanner"
exit 1
fi
}
function check_if_arpscan_installed {
if [ -z "$(which arp-scan)" ]
then
echo "ENOARPSCAN: Could not find arp-scan, please install it"
fi
} }
function register { function register {
check_if_root
check_if_arpscan_installed
echo "Registering pamela in cron: $PAM_CRON" echo "Registering pamela in cron: $PAM_CRON"
echo "*/2 * * * * root [ -x \"$PAM_SCRIPT\" ] && \"$PAM_SCRIPT\" -i \"$IF\" -o \"$OUT\" -u \"$USER\" -p \"$PASSWORD\" >> \"$PAM_LOG\"" > "$PAM_CRON" echo "*/2 * * * * root [ -x \"$PAM_SCRIPT\" ] && \"$PAM_SCRIPT\" -i \"$IF\" -o \"$OUT\" -u \"$USER\" -p \"$PASSWORD\" >> \"$PAM_LOG\"" > "$PAM_CRON"
exit 0
} }
function unregister { function unregister {
check_if_root
echo "Unregistering pamela in cron: $PAM_CRON" echo "Unregistering pamela in cron: $PAM_CRON"
rm "$PAM_CRON" rm "$PAM_CRON"
exit 0
} }
TEMP=$(getopt -o 'hrqi:o:s:u:p:-n' "pamela arp scanner" -- "$@") function parse_params {
if [ $? != 0 ] ; then echo "Could not parse parameters..." >&2 ; exit 1 ; fi TEMP=$(getopt -o 'hrqi:o:s:u:p:-n' "pamela arp scanner" -- "$@")
eval set "$TEMP" if [ $? != 0 ] ; then echo "Could not parse parameters..." >&2 ; exit 1 ; fi
while true eval set "$TEMP"
do while true
shift; do
[ -z "$1" ] && break; shift;
case "$1" in [ -z "$1" ] && break;
-i) IF="$2"; shift;; case "$1" in
-o) OUT="$2"; shift;; -i) IF="$2"; shift;;
-s) SLEEP="$2"; shift;; -o) OUT="$2"; shift;;
-u) USER="$2"; shift;; -s) SLEEP="$2"; shift;;
-p) PASSWORD="$2"; shift;; -u) USER="$2"; shift;;
-r) REGISTER='r';; -p) PASSWORD="$2"; shift;;
-q) unregister; break;; -r) REGISTER='r';;
-h|'-?') usage; break;; -q) unregister; exit 0;;
*) echo "Unknown param: [$1]"; usage; exit 1; -h|'-?') usage; exit 1;;
esac *) echo "Unknown param: [$1]"; usage; exit 1;;
done esac
done
# Register only after parsing all args
if [ -n "$REGISTER" ]; then
register
exit 0
fi
}
#register only after parsing all args function scan_and_upload {
[ -n "$REGISTER" ] && register echo $(date)" scanning..."
NETMASK="$(ip -4 addr show "$IF" | egrep -o "brd [0-9\.]+" | egrep -o "[0-9\.]+")"
MACS=""
NUM_MACS=0
for M in $(arp-scan -R -i 10 --interface "$IF" --localnet | awk '{ print $2 }' | grep :.*: | sort | uniq)
do
[ -n "$MACS" ] && MACS="$MACS,$M" || MACS="$M";
let "NUM_MACS=NUM_MACS+1"
done
POST="sn=$NETMASK&macs=$MACS"
RESULT=$(wget "$OUT" -O - --quiet --post-data "$POST" --user "$USER" --password "$PASSWORD" || echo "wget error: $?")
if [ -n "$RESULT" ]
then
echo Error uploading results:
echo "$RESULT"
fi
echo $(date)" Uploaded $NUM_MACS mac addresses..."
}
if [ "$(id -ru)" != "0" ] parse_params $@
then check_if_root
echo "Must be root to run pamela-scanner" check_if_arpscan_installed
exit 1 scan_and_upload
fi
if [ -z "$(which arp-scan)" ]
then
echo "ENOARPSCAN: Could not find arp-scan, please install it"
fi
echo $(date)" scanning..."
NETMASK="$(ip -4 addr show "$IF" | egrep -o "brd [0-9\.]+" | egrep -o "[0-9\.]+")"
MACS=""
NUM_MACS=0
for M in $(arp-scan -R -i 10 --interface "$IF" --localnet | awk '{ print $2 }' | grep :.*: | sort | uniq)
do
[ -n "$MACS" ] && MACS="$MACS,$M" || MACS="$M";
let "NUM_MACS=NUM_MACS+1"
done
POST="sn=$NETMASK&macs=$MACS"
RESULT=$(wget "$OUT" -O - --quiet --post-data "$POST" --user "$USER" --password "$PASSWORD" || echo "wget error: $?")
if [ -n "$RESULT" ]
then
echo Error uploading results:
echo "$RESULT"
fi
echo $(date)" Uploaded $NUM_MACS mac addresses..."

View File

@ -19,48 +19,23 @@
*/ */
header("Content-type: text/plain"); header("Content-type: text/plain");
require_once("config.php");
require_once("lib/util.php"); require_once("lib/util.php");
require_once("lib/macs.php");
function echoln($str) {
echo("$str\n");
}
class Upload { class Upload {
private $subnet;
private $macs; private $macs;
function __construct() { function __construct() {
$this->subnet = getPost("sn");
$this->macs = getPost("macs"); $this->macs = getPost("macs");
} }
private function parseAndValidate() { private function parseAndValidate() {
if ($this->subnet == NULL) {
echoln("Missing or bad sn param");
return false;
}
if ($this->macs == NULL) { if ($this->macs == NULL) {
echoln("Missing macs param"); echoln("Missing macs param");
return false; return false;
} }
if (preg_match("/^(\d{1,3}\.){3}\d{1,3}$/", $this->subnet) != 1) {
echoln("subnet ($this->subnet) is not valid");
return false;
}
$snParts = explode('.', $this->subnet);
foreach($snParts as $part) {
$i = intvaldef($part, -1);
if (($i >= 0) && ($i <= 255))
continue;
echoln("subnet ($this->subnet) contains invalid parts ($part)");
return false;
}
$mcs = explode(',', $this->macs); $mcs = explode(',', $this->macs);
foreach($mcs as $mac) { foreach($mcs as $mac) {
if (preg_match("/^(([\dABCDEF]){2}:){5}([\dABCDEF]){2}$/i", $mac) == 1) if (preg_match("/^(([\dABCDEF]){2}:){5}([\dABCDEF]){2}$/i", $mac) == 1)
@ -72,7 +47,10 @@ class Upload {
} }
private function writeMacs() { private function writeMacs() {
file_put_contents(OUTPUT_SERVER_DIRECTORY."/$this->subnet.macs", $this->macs); $mcs = explode(',', $this->macs);
foreach($mcs as $mac) {
macs_add($mac);
}
} }
public function run() { public function run() {