Skip to content

Instantly share code, notes, and snippets.

@jkoop
Created April 11, 2023 02:30
Show Gist options
  • Save jkoop/50fc6a8de111470296719da8e5b30f6f to your computer and use it in GitHub Desktop.
Save jkoop/50fc6a8de111470296719da8e5b30f6f to your computer and use it in GitHub Desktop.
Get a list of all Wifi clients from AeroHive APs
#!/usr/bin/php
<?php
/**
* This script SSHes into all of my AeroHive Wifi APs, gets a list of current
* connected clients from each if them, assembles the list into one, and writes
* that list to a JSON file.
*
* This is intended to be run as a minutely `cron` job. As such, the path of the
* output file is the date, formatted to not put a million files in one folder:
* E.g.: 2023/0411/122303.json // 2023-04-11 12:23:03 UTC
*/
if (!isset($GLOBALS['argv'])) die("FATAL: Refusing to run from web request.\n");
const SSH_PASS = '/path/to/password/file'; // file contains password for AeroHive APs
const AP_IPS = ['192.168.0.1', '192.168.0.2', etc]; // array of IP addresses of AeroHive APs
$stderr = fopen('php://stderr', 'a');
$clients = [];
foreach (AP_IPS as $apIp) {
// connect to the AP
$process = proc_open(['sshpass', '-f', SSH_PASS, 'ssh', '-tt', "admin@$apIp"], [
0 => ["pipe", "r"],
1 => ["pipe", "w"],
], $pipes);
if (!is_resource($process)) die('FATAL: Error at line ' . __LINE__ . "\n");
$output = '';
$state = 'waiting-for-answer';
while (true) {
$output .= $char = fgetc($pipes[1]);
fwrite($stderr, $char);
if ($state == 'waiting-for-answer' && $char == '#') { // wait for the AP to answer
$state = 'waiting-for-end-of-data';
$prompt = substr($output, strrpos($output, "\r\n"), -1);
fwrite($pipes[0], "show _client detail information\r\r\n"); // send the command
} else if ($state == 'waiting-for-end-of-data' && str_ends_with($output, " --More-- ")) { // the AP might want us to press enter for the next page
fwrite($pipes[0], "\r\n");
} else if ($state == 'waiting-for-end-of-data' && str_ends_with($output, $prompt)) { // the AP is done sending data
proc_terminate($process);
break;
}
}
$output = str_replace(" --More-- \x08\x08\x08\x08\x08\x08\x08\x08\x08\x08 \x08\x08\x08\x08\x08\x08\x08\x08\x08\x08", '', $output); // remove the page breaks
$output = substr($output, strpos($output, $prompt) + strlen($prompt)); // remove the welcome blurb and first prompt
$output = substr($output, strpos($output, "\n") + 1); // remove the line with the command we sent earlier
while (str_contains($output, $prompt)) {
$output = substr($output, 0, strrpos($output, $prompt));
}
$output = "[$output]"; // *now* it's valid JSON
array_push($clients, ...json_decode($output));
unset($output);
}
chdir(__DIR__);
date_default_timezone_set('Etc/UTC');
$folderPath = date('Y/md');
if (!is_dir($folderPath)) mkdir($folderPath, recursive: true);
file_put_contents(date('Y/md/His') . '.json', json_encode($clients, JSON_PRETTY_PRINT));
fwrite($stderr, "\n\n\e[30;42mSuccess!\e[0m\n"); // black text on a bright green background "Success!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment