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
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");
// 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>
<?php
}
?>
function echoln($str) {
echo("$str\n");
}

View File

@ -24,11 +24,8 @@ header("Cache-Control: no-cache");
header("Pragma: no-cache");
require_once("config.php");
require_once("lib/util.php");
require_once("lib/trans.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", ]
require_once("lib/macs.php");
function translator($mac) {
global $mac_translation_table;
@ -37,65 +34,7 @@ function translator($mac) {
return $mac;
}
class Macs {
private $macs;
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();
$macs = macs_get();
$macs = array_map("translator", $macs);
echo '["'.implode('", "', $macs).'"]';
macs_purge();

View File

@ -34,8 +34,7 @@ USER=''
PASSWORD=''
function usage {
echo "Usage: pamela-scanner [OPTIONS]
echo "Usage: pamela-scanner [OPTIONS]
-i INTERFACE Interface to arp-scan. Defaults to [$IF].
-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
server, where all results are agregated. In short, pamela gives you an overview
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 {
check_if_root
check_if_arpscan_installed
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"
exit 0
}
function unregister {
check_if_root
echo "Unregistering pamela in cron: $PAM_CRON"
rm "$PAM_CRON"
exit 0
}
TEMP=$(getopt -o 'hrqi:o:s:u:p:-n' "pamela arp scanner" -- "$@")
if [ $? != 0 ] ; then echo "Could not parse parameters..." >&2 ; exit 1 ; fi
eval set "$TEMP"
while true
do
shift;
[ -z "$1" ] && break;
case "$1" in
-i) IF="$2"; shift;;
-o) OUT="$2"; shift;;
-s) SLEEP="$2"; shift;;
-u) USER="$2"; shift;;
-p) PASSWORD="$2"; shift;;
-r) REGISTER='r';;
-q) unregister; break;;
-h|'-?') usage; break;;
*) echo "Unknown param: [$1]"; usage; exit 1;
esac
done
function parse_params {
TEMP=$(getopt -o 'hrqi:o:s:u:p:-n' "pamela arp scanner" -- "$@")
if [ $? != 0 ] ; then echo "Could not parse parameters..." >&2 ; exit 1 ; fi
eval set "$TEMP"
while true
do
shift;
[ -z "$1" ] && break;
case "$1" in
-i) IF="$2"; shift;;
-o) OUT="$2"; shift;;
-s) SLEEP="$2"; shift;;
-u) USER="$2"; shift;;
-p) PASSWORD="$2"; shift;;
-r) REGISTER='r';;
-q) unregister; exit 0;;
-h|'-?') usage; exit 1;;
*) echo "Unknown param: [$1]"; usage; exit 1;;
esac
done
# Register only after parsing all args
if [ -n "$REGISTER" ]; then
register
exit 0
fi
}
#register only after parsing all args
[ -n "$REGISTER" ] && register
function scan_and_upload {
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" ]
then
echo "Must be root to run pamela-scanner"
exit 1
fi
parse_params $@
check_if_root
check_if_arpscan_installed
scan_and_upload
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");
require_once("config.php");
require_once("lib/util.php");
function echoln($str) {
echo("$str\n");
}
require_once("lib/macs.php");
class Upload {
private $subnet;
private $macs;
function __construct() {
$this->subnet = getPost("sn");
$this->macs = getPost("macs");
}
private function parseAndValidate() {
if ($this->subnet == NULL) {
echoln("Missing or bad sn param");
return false;
}
if ($this->macs == NULL) {
echoln("Missing macs param");
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);
foreach($mcs as $mac) {
if (preg_match("/^(([\dABCDEF]){2}:){5}([\dABCDEF]){2}$/i", $mac) == 1)
@ -72,7 +47,10 @@ class Upload {
}
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() {