PHP - Ping exec on Linux hangs script - php

I have a simple PHP script setup to check the status of my servers. It uses a standard ping command, run via exec().
On Windows, the script works fine both when a server is online and
when down.
On Linux, the script works when the server is online, but hangs when
the server is down. Timeout seems to have no effect on the latter.
Pinging with the same command via console works fine and times out correctly.
What's the cause, and how would this be fixed?
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$exec_string = 'ping -n 1 -i 255 -w 2 ' . $host;
} else {
$exec_string = 'ping -n -c 1 -t 255 -w 2 ' . $host;
}
exec($exec_string, $output, $return);

I would avoid pinging directly using an exec(). I use this script, found here, you can also setup port and timeout:
function ping($host, $port = 80, $timeout = 6) {
$fsock = fsockopen($host, $port, $errno, $errstr, $timeout);
if (!$fsock) {
return false;
} else {
return true;
}
}
$host = 'www.example.com';
if(ping($host)) {
echo "HOST UP";
} else {
echo "HOST DOWN";
}

I'm unsure why, but switching from suPHP to fastCGI (both with suEXEC enabled) seemed to resolve the issue and the ping properly times out as expected.
If anyone has an explanation for this, I would love to know, in either comment or answer format.

Related

Get MAC address from client's machine

I'm new to this, and I did some searching, but most of the answers have the same results: the MAC address output is shown as "Found."
My code is below:
$ip = $_SERVER['REMOTE_ADDR'];
$mac=shell_exec("arp -a ".$ip);
$mac_string = shell_exec("arp -a $ip");
$mac_array = explode(" ",$mac_string);
$mac = $mac_array[3];
if(empty($mac)) {
die("No mac address for $ip not found");
}
echo($ip." - ".$mac);
Ah, the old exec() vs shell_exec() vs passthru() question.
To see what command is actually being run, and what the system is actually returning, use exec(), and pass it an int and an array as its 2nd and 3rd params respectively, then var_dump() them both after running the command.
For example:
$cmd = "arp -a " . $ip;
$status = 0;
$return = [];
exec($cmd, $return, $status);
var_dump($status, $return);
die;
If everything went OK, then $status should be zero and $return may or may not be empty. However if $status is non-zero then pay attention to what the value of $return is, as this will be what your system is telling you is happening when it tries to run your command.
Protip: Pass exec() the full path to arp as-in:
#> which arp
/usr/sbin/arp
$cmd = "/usr/sbin/arp -a" . $ip;
Also, bear in mind, depending on where the command is being run, REMOTE_ADDR may not return anything useful. There are several other ways of obtaining an IP address, which are especially useful if the IP address you need is behind some sort of proxy.
Guess I could take this script a step further.. remember, only works on your local network. will return false if not able to get.
function GetMAC() {
$cmd = "arp -a " . $_SERVER["REMOTE_ADDR"];
$status = 0;
$return = [];
exec($cmd, $return, $status);
if(isset($return[3])) return strtoupper(str_replace("-",":",substr($return[3],24,17)));
return false;
}

How to capture telnet session/scoket output(fread) continuously?

I am executing commands(fputs) on socket/telnet console and getting output/result(fread) by below code and it's working perfectly fine.
//open socket let's say ip = 192.168.10.5 and port = 21
$this->socketResource = fsockopen($this->nodeIp,$this->portNumber);
//execute some commands, for example "ipconfig"
fputs($this->socketResource,$command);
//get output string
$output = fread($this->socketResource,30000);
Now my requirement is to get all console/socket output without executing any command by fputs. For example, Cisco routers give continuous debug messages/prints on the telnet console/socket without executing any command by fputs.
How can i capture(fread) any telnet session output continuously for some duration without executing any command(fputs)?
If i capture in discrete fashion like every x seconds, i will definitely miss some console output.
For this, I would would switch over to the stream_* family. There is a huge improvement when trying to accomplish the above with performance and extending.
$stream = stream_socket_client("tcp://10.1.1.1:23", $errno, $errstr, 30);
if (!$stream ) {
echo "$errstr ($errno)<br />\n";
} else {
fwrite($stream , "sh run" . PHP_EOL);
// Set Blocking Mode - Wait For A Response On The Stream
stream_set_blocking( $stream , true );
while( true ){
// This is your response
echo stream_get_contents( $stream );
}
}
You will need to add something above to break the while(true) loop, or the script will run forever, but this is an approach I use to do something similar.

php ping a range ip address

well i'm new of php and i have this problem....
<?php
$RANGE = 192.168.1.1/254;
for in $RANGE
do
count=$(ping -c $COUNT $myHost | grep 'received' | awk -F',' '{ print $2 }' | awk '{ print $1 }')
if ! ping -c $COUNT $myhost; then
# 100% failed
fi
fi
done
echo "Host : $myHost is down (ping failed) at $(date)" | mail -s "$SUBJECT" $EMAILID
the idea is :
1: ping the Range
2: mount an eventually server (if is alive)
3: send me an email
4: put all host alive in db
anyone can help me?!
tnx in advance
You can check hosts and ports of hosts with fsockopen function
$hosts = array(/* array of hosts list */)
foreach ($hosts as $host) {
$hostname = $host;
$port = 80;
$timeout = 3;
$fp = fsockopen ($hostname, $port ,$errno ,$errstr, $timeout);
if($fp) {
// Port is alive
// Mount, send an email, insert to db
} else {
// Port is dead. Reason : $errstr
}
}
Guess you could try something like this. Be warned though, I have not tested this code.
$mainpart = "192.168.1.";
$errors = array();
foreach(range(1, 254) as $ip) {
$adr = $main . $ip;
$msg = exec("ping {$adr} blablabla");
if($msg == "bad error") {
$errors[$adr] = $msg;
}
}
Might need some sort of timeout for each loop. At the end you can loop through the errors-array to handle each error given. If possible I would consider using fsockopen to check on ports instead of pingcommands like Osaman recommends.

PHP Socket and proc_open

I am trying to create a inetd-like service for Windows in PHP for future use with my other application.
So all I can think of is to use Steam Server and proc_open to pipe the stream directly to the process (like inetd). Because on Windows there is no pcntl_fork(), and PHP doesn't support threading.
So far, here is my code. The inetdtest program is a simple program with single printf (written in C). But the problem is that when I connected to my server (via netcat), I got no response message.
<?php
define ('SERVICE_COMMAND', 'inetdtest');
define ('SERVICE_PORT', 35123);
function main() {
echo "Simple inetd starting...\n";
$socket = stream_socket_server('tcp://0.0.0.0:' . SERVICE_PORT, $errno, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN);
if ($socket === false) {
echo "Can't bind to service port.\n";
echo "[$errno] $errstr";
die(1);
}
$processes = array();
while (true) {
$current = #stream_socket_accept($socket, 5, $host);
if ($current !== false) {
echo 'Incomming connection from client ' . $host . "\n";
echo "Lunching child process... ";
$io = array(
0 => $current,
1 => $current,
2 => array('file', 'stderr.log', 'a')
);
$proc = proc_open(SERVICE_COMMAND, $io, $pipes, NULL, NULL, array('bypass_shell'));
$status = proc_get_status($proc);
echo " DONE! PID : {$status['pid']}\n";
$processes[] = array($current, $proc);
}
foreach ($processes as $k=>$v) {
$status = proc_get_status($v[1]);
if (false === $status['running']) {
echo "Finalizing process {$status['pid']}... ";
fflush($v[0]);
fclose($v[0]);
proc_close($v[1]);
unset($processes[$k]);
echo "DONE!\n";
}
}
}
}
main();
The code justs works as it stands here (using cat as program and on linux), so the problem lies somewhere in the windows side of things.
For one thing, the option you are passing, to bypass the shell, should be given as
array('bypass_shell'=>true)
This may fix things already. The tricky part with these things, is that you're passing a socket fd to a process, which may or may not be expected to handle that properly. I don't know how these things are done in windows, but cutting cmd out of the equation can only help.
If it still doesn't work, you should create a loop which waits for data (either from network or child processes) and sends data from the network socket to the process pipe, and vice versa.

Empty PHP SSH2 stream contents, even with stream_set_blocking?

I am working on a tool that reads an iptables configuration from a remote host over SSH2 using the PECL SSH2 extension. I am able to successfully make the connection to the host, authenticate, and execute commands. The trouble I am having is sometimes the stream doesn't contain any data.
/**
* Load the current firewall configuration
* #return bool
*/
public function loadRules() {
$stream = ssh2_exec($this->connection,"~/iptsave;");
stream_set_blocking($stream,true);
$iptablesSave = stream_get_contents($stream);
if(empty($iptablesSave)) {
return false;
}
parent::restore($iptablesSave);
return true;
}
About 25% of the time, loadRules() returns false, even when connecting to locahost instead of the remote system. I was able to work around the problem by changing the ssh2_exec call to
$stream = ssh2_exec($this->connection,"~/iptsave; sleep .5");
but I am concerned that something is wrong.
phpSecLib may be able to help:
According to this post, it always returns the output, unlike ssh2.so.
I've got the same issue here. Somehow you need to set a delay for getting the result of the stream.
The way you've done it is possible, but you could also set a sleep(1) after the stream_set_block($stream, true) function.
You could try the usleep() function. Haven't tried it yet
May be this will solve the issue:
$stream = ssh2_exec($this->connection,"~/iptsave;");
stream_set_blocking($stream,true);
$stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
$iptablesSave = stream_get_contents($stream);
With some severs you have to use 'interactive shell'. And sometimes you have to set the delay / sleep manually. A working example:
$connection = ssh2_connect($IP, 22);
$auth = ssh2_auth_password($connection, $User, $Pass);
$cmd = "help" . PHP_EOL;
if (!$auth) {
echo "Login Failed;
exit(1);
}
$shell = ssh2_shell($connection);
stream_set_blocking($shell, false); // we will use manual sleep
sleep(1); // This sleep to make sure that you get the prompt back
fwrite ($shell, $cmd . ";" . PHP_EOL);
sleep(1); // This to make sure that the command executes and we get the prompt back again!
while($output = fgets($shell)){
echo $output;
}
fwrite ($shell, "exit;" . PHP_EOL); // If needed
sleep(1);
ssh2_disconnect($connection);
unset($shell);
unset($connection);

Categories