File: 1.00.4a/server/base/tests.inc.php (View as HTML)

  1: <?php // tests.inc.php
  2: /* -------------------------------------------------------------
  3: This file is part of FreeNATS
  4: 
  5: FreeNATS is (C) Copyright 2008 PurplePixie Systems
  6: 
  7: FreeNATS is free software: you can redistribute it and/or modify
  8: it under the terms of the GNU General Public License as published by
  9: the Free Software Foundation, either version 3 of the License, or
 10: (at your option) any later version.
 11: 
 12: FreeNATS is distributed in the hope that it will be useful,
 13: but WITHOUT ANY WARRANTY; without even the implied warranty of
 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15: GNU General Public License for more details.
 16: 
 17: You should have received a copy of the GNU General Public License
 18: along with FreeNATS.  If not, see www.gnu.org/licenses
 19: 
 20: For more information see www.purplepixie.org/freenats
 21: -------------------------------------------------------------- */
 22: 
 23: if (!isset($BaseDir)) $BaseDir="../base/"; // 
 24: require_once($BaseDir."timer.inc.php"); // just in case standalone
 25: 
 26: // FreeNATS_Local_Test Base Class - Local Tests (run from FreeNATS server) must extend from this
 27: 
 28: class FreeNATS_Local_Test
 29: {
 30: function DoTest($testname,$param,$hostname="",$timeout=-1,$params=false)
 31: 	{
 32: 	return 0;
 33: 	}
 34: 	
 35: function Evaluate($result)
 36: 	{
 37: 	return -1;
 38: 	}
 39: 	
 40: function DisplayForm(&$row)
 41: 	{
 42: 	return false;
 43: 	}
 44: 	
 45: function ProtectOutput(&$row)
 46: 	{
 47: 	return false;
 48: 	}
 49: }
 50: 
 51: // ------------------------------------------------------------------------------------------------
 52: 
 53: require($BaseDir."tests/mysql.inc.php");
 54: require($BaseDir."tests/imap.inc.php");
 55: require($BaseDir."tests/smtp.inc.php");
 56: 
 57: require($BaseDir."tests/dns.inc.php");
 58: require($BaseDir."tests/nats-dns.inc.php"); // the wrapper module
 59: 
 60: require($BaseDir."tests/smb.inc.php");
 61: 
 62: function ip_lookup($hostname) // "safe" DNS lookup function to call with a hostname, URL or IP - returns 0 if unsuccessful
 63: {
 64: // Is it already an IP adress?
 65: $out=str_replace(".","",$hostname);
 66: if (is_numeric($out)) return $hostname; // yes it is
 67: 
 68: // No it is not
 69: $ip=@gethostbyname($hostname);
 70: if ($ip==$hostname) return 0; // unmodified host - lookup failed
 71: 
 72: return $ip;
 73: }
 74: 
 75: function next_run_x($interval)
 76: {
 77: if ($interval<1) return time();
 78: return time()+(($interval)*60)-30;
 79: }
 80: 
 81: function test_sleep()
 82: {
 83: global $NATS;
 84: if (!isset($NATS)) return false;
 85: $sleep=$NATS->Cfg->Get("test.interval",0);
 86: if ($sleep<=0) return false;
 87: $sleep=$sleep*1000000; // convert to usec
 88: usleep($sleep);
 89: return true;
 90: }
 91: 	
 92: function url_lookup($url)
 93: {
 94: // Sod regular expressions here as we'd have to do it twice or with cleverness I lack
 95: // Is it a URL?
 96: $colon=strpos($url,":");
 97: if ($colon != 0) // exists so it a URL
 98: 	{
 99: 	$out=preg_match("@^(?:http[s]*://)?([^/|\?|:]+)@i",$url,$matches);
100: 	$hostname=$matches[1];
101: 	}
102: else $hostname=$url; // try direct
103: 	
104: return ip_lookup($hostname);
105: }
106: 	
107: 	
108: 
109: 
110: 
111: 
112: 
113:  function icmpChecksum($data)
114:     {
115:     if (strlen($data)%2)
116:     $data .= "\x00";
117:     
118:     $bit = unpack('n*', $data);
119:     $sum = array_sum($bit);
120:     
121:     while ($sum >> 16)
122:     $sum = ($sum >> 16) + ($sum & 0xffff);
123:     
124:     return pack('n*', ~$sum);
125:     }
126:    
127: function PingTest($host,$ctimeout=-1)
128: 	{
129: 	global $NATS;
130: 	$FreeNATS_Timer=new TFNTimer();
131:     // Make Package
132:     $type= "\x08";
133:     $code= "\x00";
134:     $checksum= "\x00\x00";
135:     $identifier = "\x00\x00";
136:     $seqNumber = "\x00\x00";
137:     $data= "FreeNATS";
138:     $package = $type.$code.$checksum.$identifier.$seqNumber.$data;
139:     $checksum = icmpChecksum($package); // Calculate the checksum
140:     $package = $type.$code.$checksum.$identifier.$seqNumber.$data;
141:     
142:     // Return s or ms(s*1000)
143:     $returnsecs=true;
144:     if (isset($NATS))
145:     	{
146: 	    if ($NATS->Cfg->Get("test.icmp.returnms",0)==1) $returnsecs=false;
147:     	}
148: 
149: 	// Timeout Values
150:     if (isset($NATS)) $timeout=$NATS->Cfg->Get("test.icmp.timeout",10);
151:     else $timeout=10;
152:     if ($ctimeout>0) $timeout=$ctimeout; // use custom timeout if passed
153:     if ($timeout<=0) $timeout=10; // catch-all for defaults bug
154:     
155:     // Create Socket
156:     $socket = @socket_create(AF_INET, SOCK_RAW, 1);
157:     	//or die(socket_strerror(socket_last_error()));
158:     if (!$socket) return 0;
159:     
160:     // Set Non-Blocking
161:     @socket_set_nonblock($socket);
162:     	
163:     // Connect Socket
164:     $sconn=@socket_connect($socket, $host, null);
165:     if (!$sconn) return 0;
166:     
167:     // Send Data
168:     @socket_send($socket, $package, strLen($package), 0);
169:         
170:     // Start Timer
171:     $FreeNATS_Timer->Start();
172:     $startTime = microtime(true); // need this for the looping section
173:     
174: 
175:     // Read Data
176:     $keepon=true;
177: 
178:     while( (!(@socket_read($socket, 255))) && $keepon)
179:     	{ // basically just kill time
180:     	// consider putting some sort of sleepy thing here to lower load but would f* with figures!
181:     	
182:     	if ( (microtime(true) - $startTime) > $timeout )
183:     		$keepon=false;
184: 		}
185:     	
186: 	if ($keepon) // didn't time out - read data
187:     	{
188: 	    $elapsed=$FreeNATS_Timer->Stop();
189: 	    if ($returnsecs) $elapsed=round($elapsed,4);
190: 	    else $elapsed=round( ($elapsed*1000),4 );
191: 	    @socket_close($socket);
192:     	// $ret=round(microtime(true) - $startTime, 4); -- old method
193:     	if ($elapsed<=0) $elapsed="0.0001"; // safety catch-all
194:     	return $elapsed;
195:     	/*
196:     	if ($ret==0) return "0.0001";
197:     	else 
198:     		{
199: 	    	if ($ret<=0) return "0.0001";
200: 	    	else return $ret;
201:     		}
202:     	*/
203:     	}
204:     	
205:     // Socket timed out
206:     @socket_close($socket);
207:     return 0;
208: 	}
209: 
210: function WebTest($url,$timeout=-1)
211: 	{
212: 	global $NATS;
213: 	if ($timeout<=0) // use NATS or env
214: 		{
215: 		if (isset($NATS))
216: 			{
217: 			$nto=$NATS->Cfg->Get("test.http.timeout",-1);
218: 			if ($nto>0) $timeout=$nto; // use NATS timeout
219: 			}
220: 		}
221: 	if ($timeout>0) // use the set timeout
222: 		$oldtimeout=ini_set("default_socket_timeout",$timeout);
223: 		
224: 	if (function_exists("curl_getinfo")) // use CURL if present
225: 		{
226: 		$ch=curl_init();
227: 		curl_setopt($ch,CURLOPT_URL,$url);
228: 		curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
229: 		curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
230: 		curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
231: 		curl_setopt($ch,CURLOPT_HEADER,1);
232: 		if ($timeout>0) curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
233: 		if ($timeout>0) curl_setopt($ch,CURLOPT_TIMEOUT,$timeout);
234: 		if (!$output=curl_exec($ch))
235: 			{
236: 			$ctr=-1; // failed
237: 			}
238: 		else $ctr=round(curl_getinfo($ch,CURLINFO_SIZE_DOWNLOAD)/1024,2);
239: 		curl_close($ch);
240: 		
241: 		if ($ctr==0) $ctr="0.0001";
242: 		
243: 		}
244: 	else
245: 		{	// no CURL - use fopen()	
246: 		$fp=@fopen($url,"r");
247: 		if ($fp<=0)
248: 			{
249: 			if ($timeout>0) ini_set("default_socket_timeout",$oldtimeout);
250: 			return -1;
251: 			}
252: 		$ctr=0;
253: 		while ($body=@fgets($fp,1024)) $ctr+=sizeof($body);
254: 		@fclose($fp);
255: 		}
256: 	
257: 	
258: 	
259: 	if ($timeout>0) ini_set("default_socket_timeout",$oldtimeout);
260: 	return $ctr;
261: 	}
262: 	
263: function DoTest($test,$param,$hostname="",$timeout=-1,$params=0,$nodeid="")
264: {
265: global $NATS;
266: if (!is_array($params))
267: 	{
268: 	$params=array();
269: 	for ($a=0; $a<10; $a++) $params[$a]="";
270: 	}
271: 	
272: switch ($test)
273: 	{
274: 	case "web": case "wsize":
275: 		// Don't bother with pre-resolution as size only
276: 		return WebTest($param,$timeout);
277: 		break;
278: 	case "tcp": // nb TCP does not support timeouts currently
279: 		$ip=ip_lookup($hostname);
280: 		if ($ip=="0") return 0;
281: 		$fp=@fsockopen($ip,$param);
282: 		if ($fp<=0) return 0;
283: 		@fclose($fp);
284: 		return 1;
285: 		break;
286: 	case "wtime":
287: 		$timer=new TFNTimer();
288: 		// Do a pre-lookup
289: 		$ip=url_lookup($param);
290: 		if ($ip=="0") return -1; // dns lookup failed
291: 		$timer->Start();
292: 		$r=WebTest($param,$timeout);
293: 		$elapsedTime=$timer->Stop();
294: 		$elapsedTime=round($elapsedTime,4);
295: 		if ($r<0) return -1; // open failed
296: 		if ($r==0) return -2; // no chars shown as returned
297: 		if ($elapsedTime<=0) return 0.0001;
298: 		return $elapsedTime;
299: 		break;
300: 		
301: 	case "host":
302: 		$timer=new TFNTimer();
303: 		if (preg_match("/[a-zA-Z]/",$param)>0) $is_ip=false;
304: 		else $is_ip=true;
305: 		
306: 		$timer->Start();
307: 		if ($is_ip) $result=gethostbyaddr($param);
308: 		else $result=gethostbyname($param);
309: 		$elapsedTime=$timer->Stop();
310: 		
311: 		if ($result==$param) // lookup failed
312: 			return -1;
313: 			
314: 		if ($result=="")	// lookup failed
315: 			return -1;
316: 			
317: 		$elapsedTime=round($elapsedTime,4);
318: 		if ($elapsedTime<=0) return 0.0001;
319: 		return $elapsedTime;
320: 		break;
321: 		/*
322: 	case "dns":
323: 		$timer=new TFNTimer();
324: 		if ($param=="") $dnsserver=$hostname;
325: 		else $dnsserver=$param;
326: 		if ($dnsserver=="") return -3;
327: 		if ($timeout<=0) $timeout=60;
328: 		if ($params[4]==1) $udp=false; // use TCP
329: 		else $udp=true;
330: 		if (($params[3]=="")||($params[3]==0)) $port=53;
331: 		else $port=$params[3];
332: 		
333: 		$dns_query=new DNSQuery($dnsserver,$port,$timeout,$udp,false); // run with debug off
334: 		$type=$params[2];
335: 		$query=$params[1];
336: 		
337: 		$timer->Start();
338: 		$answer=$dns_query->Query($query,$type);
339: 		$elapsedTime=$timer->Stop();
340: 		
341: 		if ( ($answer===false) || ($dns_query->error) ) return -2; // query error
342: 		if ($answer->count<=0) return -1; // no records returned
343: 		
344: 		// otherwise we've got some results ok
345: 		$elapsedTime=round($elapsedTime,4);
346: 		if ($elapsedTime<=0) return 0.0001;
347: 		return $elapsedTime;
348: 		break;
349: 		*/
350: 	case "testloop":
351: 		return $param;
352: 		break;
353: 		
354: 	case "testrand":
355: 		mt_srand(microtime()*1000000);
356: 		if ( ($param=="") || ($param==0) ) $param=100;
357: 		return mt_rand(0,$param);
358: 		break;
359: 		
360: 	case "ping":
361: 		return PingTest($param,$timeout);
362: 		break;
363: /* // now handled as a module		
364: 	case "smtp":
365: 		$ip=ip_lookup($param);
366: 		if ($ip=="0") return -1;
367: 		return smtp_test_time($ip,$params[1],$timeout);
368: 		break;
369: */
370: /* // now handled as a module
371: 	case "imap":
372: 		if ($params[5]==1) $ssl=true;
373: 		else $ssl=false;
374: 		
375: 		$ip=ip_lookup($param);
376: 		if ($ip=="0") return -1;
377: 		
378: 		return imap_test_time($ip,$params[1],$params[2],$timeout,$params[3],$params[4],$ssl);
379: 		break;
380: */
381: /* // now handled as a module
382: 	case "mysql":
383: 		$ip=ip_lookup($param);
384: 		if ($ip=="0") return -1; // cache only as 127.0.0.1 is not the same connection as localhost for MySQL auth!
385: 
386: 		return mysql_test_time($param,$params[1],$params[2],$params[3],$timeout,$params[4]);
387: 		break;
388: 		
389: 	case "mysqlrows":
390: 		$ip=ip_lookup($param);
391: 		if ($ip=="0") return -1; // cache only - see above
392: 		return mysql_test_rows($param,$params[1],$params[2],$params[3],$timeout,$params[4]);
393: 		break;
394: */
395: 	default:
396: 		if (isset($NATS)) // try and see if a test is registered
397: 			{
398: 			if (isset($NATS->Tests->QuickList[$test])) // exists
399: 				{
400: 				$NATS->Tests->Tests[$test]->Create();
401: 				return $NATS->Tests->Tests[$test]->instance->DoTest($test,$param,$hostname,$timeout,$params);
402: 				}
403: 			}
404: 		
405: 	}
406: return -1; // did not run any test so untested
407: }
408: 
409: function SimpleEval($test,$result)
410: {
411: global $NATS;
412: switch($test)
413: 	{
414: 	case "ping": // handles both types of simple evaluation (inbuilt ICMP and remote ping)
415: 		if ($result<=0) return 2;
416: 		return 0;
417: 	case "web": case "wsize":
418: 		if ($result<=0) return 2;
419: 		return 0;
420: 	case "tcp":
421: 		if ($result==1) return 0;
422: 		return 2;
423: 	case "wtime":
424: 		if ($result<0) return 2;
425: 		return 0;
426: 	/*
427: 	case "imap":
428: 		if ($result<=0) return 2;
429: 		return 0;
430: 	*/
431: 	/*
432: 	case "smtp":
433: 		if ($result<=0) return 2;
434: 		return 0;
435: 	*/	
436: 	case "mysql":
437: 		if ($result<=0) return 2;
438: 		return 0;
439: 		
440: 	case "mysqlrows":
441: 		if ($result<=0) return 2; // no rows returned or error
442: 		return 0;
443: 		
444: 	case "host": case "dns":
445: 		if ($result<=0) return 2; // no records returned or error
446: 		
447: 	case "testloop":
448: 		return 0;
449: 	case "testrand":
450: 		return 0;
451: 		
452: 	default:
453: 	if (isset($NATS))
454: 		{
455: 		if (isset($NATS->Tests->QuickList[$test]))
456: 			{
457: 			$NATS->Tests->Tests[$test]->Create();
458: 			return $NATS->Tests->Tests[$test]->instance->Evaluate($result);
459: 			}
460: 		}
461: 	}
462: return -1; // untested if we don't know WTF the result was
463: }
464: 
465: function aText($al)
466: {
467: return oText($al); // uses function in tests.inc.php with site config support	
468: /* -- depreciated
469: switch($al)
470: 	{
471: 	case -1: return "Untested";
472: 	case 0: return "Passed";
473: 	case 1: return "Warning";
474: 	case 2: return "Failed";
475: 	default: return "Unknown";
476: 	}
477: */
478: }
479: ?>