Project

General

Profile

Download (40.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php 
2
/*
3
	util.inc
4
	part of the pfSense project (http://www.pfsense.com)
5

    
6
	originally part of m0n0wall (http://m0n0.ch/wall)
7
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
8
	All rights reserved.
9

    
10
	Redistribution and use in source and binary forms, with or without
11
	modification, are permitted provided that the following conditions are met:
12

    
13
	1. Redistributions of source code must retain the above copyright notice,
14
	   this list of conditions and the following disclaimer.
15

    
16
	2. Redistributions in binary form must reproduce the above copyright
17
	   notice, this list of conditions and the following disclaimer in the
18
	   documentation and/or other materials provided with the distribution.
19

    
20
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
	POSSIBILITY OF SUCH DAMAGE.
30
*/
31

    
32
/*
33
	pfSense_BUILDER_BINARIES:	/bin/ps	/bin/kill	/usr/bin/killall	/sbin/ifconfig	/usr/bin/netstat
34
	pfSense_BUILDER_BINARIES:	/usr/bin/awk	/sbin/dmesg		/sbin/ping /usr/local/sbin/gzsig	/usr/sbin/arp
35
	pfSense_BUILDER_BINARIES:	/sbin/conscontrol	/sbin/devd	/bin/ps
36
	pfSense_MODULE:	utils
37
*/
38

    
39
/* kill a process by pid file */
40
function killbypid($pidfile) {
41
	return sigkillbypid($pidfile, "TERM");
42
}
43

    
44
function isvalidpid($pid) {
45
	$output = "";
46
	exec("/bin/pgrep -F {$pid}", $output, $retval);
47

    
48
	return (intval($retval) == 0);
49
}
50

    
51
function is_process_running($process) {
52
	$output = "";
53
	exec("/bin/pgrep -ax {$process}", $output, $retval);
54

    
55
	return (intval($retval) == 0);
56
}
57

    
58
function isvalidproc($proc) {
59
	return is_process_running($proc);
60
}
61

    
62
/* sigkill a process by pid file */
63
/* return 1 for success and 0 for a failure */
64
function sigkillbypid($pidfile, $sig) {
65
	if (is_file($pidfile))
66
		return mwexec("/bin/pkill -{$sig} -F {$pidfile}", true);
67

    
68
	return 0;
69
}
70

    
71
/* kill a process by name */
72
function sigkillbyname($procname, $sig) {
73
	if(isvalidproc($procname))
74
		return mwexec("/usr/bin/killall -{$sig} " . escapeshellarg($procname), true);
75
}
76

    
77
/* kill a process by name */
78
function killbyname($procname) {
79
	if(isvalidproc($procname)) 
80
		mwexec("/usr/bin/killall " . escapeshellarg($procname));
81
}
82

    
83
function is_subsystem_dirty($subsystem = "") {
84
	global $g;
85

    
86
	if ($subsystem == "")
87
		return false;
88

    
89
	if (file_exists("{$g['varrun_path']}/{$subsystem}.dirty"))
90
		return true;
91

    
92
	return false;
93
}
94

    
95
function mark_subsystem_dirty($subsystem = "") {
96
	global $g;
97

    
98
	if (!file_put_contents("{$g['varrun_path']}/{$subsystem}.dirty", "DIRTY"))
99
		log_error(sprintf(gettext("WARNING: Could not mark subsystem: %s dirty"), $subsystem));
100
}
101

    
102
function clear_subsystem_dirty($subsystem = "") {
103
	global $g;
104

    
105
	@unlink("{$g['varrun_path']}/{$subsystem}.dirty");
106
}
107

    
108
function config_lock() {
109
	return;
110
}
111
function config_unlock() {
112
	return;
113
}
114

    
115
/* lock configuration file */
116
function lock($lock, $op = LOCK_SH) {
117
	global $g, $cfglckkeyconsumers;
118
	if (!$lock)
119
		die(gettext("WARNING: You must give a name as parameter to lock() function."));
120
	if (!file_exists("{$g['tmp_path']}/{$lock}.lock"))
121
		@touch("{$g['tmp_path']}/{$lock}.lock");
122
	$cfglckkeyconsumers++;
123
	if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
124
		if (flock($fp, $op))
125
			return $fp;
126
		else
127
			fclose($fp);
128
	}
129
}
130

    
131
/* unlock configuration file */
132
function unlock($cfglckkey = 0) {
133
	global $g, $cfglckkeyconsumers;
134
	flock($cfglckkey, LOCK_UN);
135
	fclose($cfglckkey);
136
	return;
137
}
138

    
139
function send_event($cmd) {
140
	global $g;
141

    
142
	if(!isset($g['event_address']))
143
		$g['event_address'] = "unix:///var/run/check_reload_status";
144
		
145
	$try = 0;
146
	while ($try < 3) {
147
		$fd = @fsockopen($g['event_address']);
148
		if ($fd) {
149
			fwrite($fd, $cmd);
150
			$resp = fread($fd, 4096);
151
			if ($resp != "OK\n")
152
				log_error("send_event: sent {$cmd} got {$resp}");
153
			fclose($fd);
154
			$try = 3;
155
		} else
156
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
157
		$try++;
158
	}
159
}
160

    
161
function send_multiple_events($cmds) {
162
	global $g;
163

    
164
	if(!isset($g['event_address']))
165
		$g['event_address'] = "unix:///var/run/check_reload_status";
166
			
167
	if (!is_array($cmds))
168
		return;
169
	$fd = fsockopen($g['event_address']);
170
	if ($fd) {
171
		foreach ($cmds as $cmd) {
172
			fwrite($fd, $cmd);
173
			$resp = fread($fd, 4096);
174
			if ($resp != "OK\n")
175
				log_error("send_event: sent {$cmd} got {$resp}");
176
		}
177
		fclose($fd);
178
	}
179
}
180

    
181
function refcount_init($reference) {
182
	$shmid = @shmop_open($reference, "c", 0644, 10);
183
	@shmop_write($shmid, 0, 0);
184
	@shmop_close($shmid);
185
}
186

    
187
function refcount_reference($reference) {
188
	try {
189
		$shmid = @shmop_open($reference, "w", 0644, 10);
190
		if (!$shmid) {
191
			refcount_init($reference);
192
			$shmid = @shmop_open($reference, "w", 0, 0);
193
		}
194
		$shm_data = @shmop_read($shmid, 0, 10);
195
		$shm_data = intval($shm_data) + 1;
196
		@shmop_write($shmid, $shm_data, 0);
197
		@shmop_close($shmid);
198
	} catch (Exception $e) {
199
		log_error($e->getMessage());
200
	}
201

    
202
	return $shm_data;
203
}
204

    
205
function refcount_unreference($reference) {
206
	try {
207
		/* We assume that the shared memory exists. */
208
		$shmid = @shmop_open($reference, "w", 0, 0);
209
		$shm_data = @shmop_read($shmid, 0, 10);
210
		$shm_data = intval($shm_data) - 1;
211
		if ($shm_data < 0) {
212
			//debug_backtrace();
213
			log_error(sprintf(gettext("Reference %s is going negative, not doing unreference."), $reference));
214
		} else
215
			@shmop_write($shmid, $shm_data, 0);
216
		@shmop_close($shmid);
217
	} catch (Exception $e) {
218
		log_error($e->getMessage());
219
	}
220

    
221
	return $shm_data;
222
}
223

    
224
function is_module_loaded($module_name) {
225
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
226
	if (intval($running) >= 1)
227
		return true;
228
	else
229
		return false;
230
}
231

    
232
/* return the subnet address given a host address and a subnet bit count */
233
function gen_subnet($ipaddr, $bits) {
234
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
235
		return "";
236
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
237
}
238

    
239
/* return the subnet address given a host address and a subnet bit count */
240
function gen_subnetv6($ipaddr, $bits) {
241
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
242
		return "";
243

    
244
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
245
	return $address;
246
}
247

    
248
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
249
function gen_subnet_max($ipaddr, $bits) {
250
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
251
		return "";
252

    
253
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
254
}
255

    
256
/* Generate end number for a given ipv6 subnet mask
257
 * no, it does not perform math */
258
function gen_subnetv6_max($ipaddr, $bits) {
259
	if(!is_ipaddrv6($ipaddr))
260
		return false;
261
	
262
	$subnetstart = gen_subnetv6($ipaddr, $bits);
263
	/* we should have a expanded full ipv6 subnet starting at 0.
264
	 * Now split those by the semicolon so we can do 16 bit math */
265
	$parts = explode(":", $subnetstart);
266
	if(count($parts) <> 8)
267
		return false;
268
	
269
	$result = array();
270
	/* set the itteration count properly */
271
	$bitsleft = $bits;
272
	$i = 0;
273
	foreach($parts as $part) {
274
		/* if we have more then 16 bits we just append the part to the result */
275
		if($bitsleft >= 16) {
276
			$result[$i] = $parts[$i];
277
			$bitsleft = $bitsleft - 16;
278
			$i++;
279
			continue;
280
		}
281
		/* if we have less then 16 bits we need to calculate the other bits */
282
		if(($bitsleft < 16) && ($bitsleft > 0)) {
283
			$result[$i] = dechex(pow(2, (16 - $bitsleft)) -1) ;
284
			$integer = pow(2, (16 - $bitsleft));
285
			$strlen = strlen($result[$i]);
286
			while($strlen < 4) {
287
				$result[$i] = 0 . $result[$i];
288
				$strlen++;
289
			}
290
			$bitsleft = 0;
291
			$i++;
292
			continue;
293
		}
294
		/* counter is zero, append quad F */
295
		if($bitsleft == 0) {
296
			$result[$i] = "ffff";
297
			$i++;
298
			continue;
299
		}
300
		$i++;
301
	}
302
	$subnet_end = implode(":", $result);
303
	return $subnet_end;
304
}
305

    
306
/* returns a subnet mask (long given a bit count) */
307
function gen_subnet_mask_long($bits) {
308
	$sm = 0;
309
	for ($i = 0; $i < $bits; $i++) {
310
		$sm >>= 1;
311
		$sm |= 0x80000000;
312
	}
313
	return $sm;
314
}
315

    
316
/* same as above but returns a string */
317
function gen_subnet_mask($bits) {
318
	return long2ip(gen_subnet_mask_long($bits));
319
}
320

    
321
/* Convert long int to IP address, truncating to 32-bits. */
322
function long2ip32($ip) {
323
	return long2ip($ip & 0xFFFFFFFF);
324
}
325

    
326
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
327
function ip2long32($ip) {
328
	return ( ip2long($ip) & 0xFFFFFFFF );
329
}
330

    
331
/* Convert IP address to unsigned long int. */
332
function ip2ulong($ip) {
333
	return sprintf("%u", ip2long32($ip));
334
}
335

    
336
/* Find out how many IPs are contained within a given IP range
337
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
338
 */
339
function ip_range_size($startip, $endip) {
340
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
341
		// Operate as unsigned long because otherwise it wouldn't work
342
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
343
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
344
	}
345
	return -1;
346
}
347

    
348
/* Find the smallest possible subnet mask which can contain a given number of IPs
349
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
350
 */
351
function find_smallest_cidr($number) {
352
	$smallest = 1;
353
	for ($b=32; $b > 0; $b--) {
354
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
355
	}
356
	return (32-$smallest);
357
}
358

    
359
/* Return the previous IP address before the given address */
360
function ip_before($ip) {
361
	return long2ip32(ip2long($ip)-1);
362
}
363

    
364
/* Return the next IP address after the given address */
365
function ip_after($ip) {
366
	return long2ip32(ip2long($ip)+1);
367
}
368

    
369
/* Return true if the first IP is 'before' the second */
370
function ip_less_than($ip1, $ip2) {
371
	// Compare as unsigned long because otherwise it wouldn't work when
372
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
373
	return ip2ulong($ip1) < ip2ulong($ip2);
374
}
375

    
376
/* Return true if the first IP is 'after' the second */
377
function ip_greater_than($ip1, $ip2) {
378
	// Compare as unsigned long because otherwise it wouldn't work
379
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
380
	return ip2ulong($ip1) > ip2ulong($ip2);
381
}
382

    
383
/* Convert a range of IPs to an array of subnets which can contain the range. */
384
function ip_range_to_subnet_array($startip, $endip) {
385
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
386
		return array();
387
	}
388

    
389
	// Container for subnets within this range.
390
	$rangesubnets = array();
391

    
392
	// Figure out what the smallest subnet is that holds the number of IPs in the given range.
393
	$cidr = find_smallest_cidr(ip_range_size($startip, $endip));
394

    
395
	// Loop here to reduce subnet size and retest as needed. We need to make sure
396
	//   that the target subnet is wholly contained between $startip and $endip.
397
	for ($cidr; $cidr <= 32; $cidr++) {
398
		// Find the network and broadcast addresses for the subnet being tested.
399
		$targetsub_min = gen_subnet($startip, $cidr);
400
		$targetsub_max = gen_subnet_max($startip, $cidr);
401

    
402
		// Check best case where the range is exactly one subnet.
403
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
404
			// Hooray, the range is exactly this subnet!
405
			return array("{$startip}/{$cidr}");
406
		}
407

    
408
		// These remaining scenarios will find a subnet that uses the largest
409
		//  chunk possible of the range being tested, and leave the rest to be
410
		//  tested recursively after the loop.
411

    
412
		// Check if the subnet begins with $startip and ends before $endip
413
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
414
			break;
415
		}
416

    
417
		// Check if the subnet ends at $endip and starts after $startip
418
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
419
			break;
420
		}
421

    
422
		// Check if the subnet is between $startip and $endip
423
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
424
			break;
425
		}
426
	}
427

    
428
	// Some logic that will recursivly search from $startip to the first IP before the start of the subnet we just found.
429
	// NOTE: This may never be hit, the way the above algo turned out, but is left for completeness.
430
	if ($startip != $targetsub_min) {
431
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array($startip, ip_before($targetsub_min)));
432
	}
433

    
434
	// Add in the subnet we found before, to preserve ordering
435
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
436

    
437
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
438
	if ($endip != $targetsub_max) {
439
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
440
	}
441
	return $rangesubnets;
442
}
443

    
444
function is_iprange($range) {
445
	if (substr_count($range, '-') != 1) {
446
		return false;
447
	}
448
	list($ip1, $ip2) = explode ('-', $range);
449
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
450
}
451

    
452
function is_numericint($arg) {
453
	return (preg_match("/[^0-9]/", $arg) ? false : true);
454
}
455

    
456

    
457
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
458
function is_ipaddr($ipaddr) {
459
	if(is_ipaddrv4($ipaddr)) {
460
		return true;
461
	}
462
	if(is_ipaddrv6($ipaddr)) {
463
		return true;
464
	}
465
	return false;
466
}
467

    
468
/* returns true if $ipaddr is a valid IPv6 address */
469
function is_ipaddrv6($ipaddr) {
470
	$result = Net_IPv6::checkIPv6($ipaddr);
471
	return $result;
472
}
473

    
474
/* returns true if $ipaddr is a valid dotted IPv4 address */
475
function is_ipaddrv4($ipaddr) {
476
	if (!is_string($ipaddr))
477
		return false;
478

    
479
	$ip_long = ip2long($ipaddr);
480
	$ip_reverse = long2ip32($ip_long);
481

    
482
	if ($ipaddr == $ip_reverse)
483
		return true;
484
	else
485
		return false;
486
}
487

    
488
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
489
function is_ipaddroralias($ipaddr) {
490
	global $config;
491

    
492
	if (is_alias($ipaddr)) {
493
		if (is_array($config['aliases']['alias'])) {
494
			foreach ($config['aliases']['alias'] as $alias) {
495
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
496
					return true;
497
			}
498
		}
499
		return false;
500
	} else
501
		return is_ipaddr($ipaddr);
502

    
503
}
504

    
505
/* returns true if $subnet is a valid subnet in CIDR format */
506
function is_subnet($subnet) {
507
	if (!is_string($subnet))
508
		return false;
509

    
510
	list($hp,$np) = explode('/', $subnet);
511

    
512
	if (!is_ipaddr($hp))
513
		return false;
514

    
515
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
516
		return false;
517

    
518
	return true;
519
}
520

    
521
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
522
function is_subnetoralias($subnet) {
523
	global $aliastable;
524

    
525
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
526
		return true;
527
	else
528
		return is_subnet($subnet);
529
}
530

    
531
/* returns true if $hostname is a valid hostname */
532
function is_hostname($hostname) {
533
	if (!is_string($hostname))
534
		return false;
535

    
536
	if (preg_match('/^(?:(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])\.)*(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])$/i', $hostname))
537
		return true;
538
	else
539
		return false;
540
}
541

    
542
/* returns true if $domain is a valid domain name */
543
function is_domain($domain) {
544
	if (!is_string($domain))
545
		return false;
546

    
547
	if (preg_match('/^(?:(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$/i', $domain))
548
		return true;
549
	else
550
		return false;
551
}
552

    
553
/* returns true if $macaddr is a valid MAC address */
554
function is_macaddr($macaddr) {
555
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){5}$/i', $macaddr) == 1 ? true : false;
556
}
557

    
558
/* returns true if $name is a valid name for an alias */
559
/* returns NULL if a reserved word is used */
560
function is_validaliasname($name) {
561
	/* Array of reserved words */
562
	$reserved = array("port", "pass");
563
	if (in_array($name, $reserved, true))
564
		return; /* return NULL */
565
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
566
		return true;
567
	else
568
		return false;
569
}
570

    
571
/* returns true if $port is a valid TCP/UDP port */
572
function is_port($port) {
573
	$tmpports = explode(":", $port);
574
	foreach($tmpports as $tmpport) {
575
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
576
			continue;
577
		if (!ctype_digit($tmpport))
578
			return false;
579
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
580
			return false;
581
	}
582
	return true;
583
}
584

    
585
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
586
function is_portrange($portrange) {
587
	$ports = explode(":", $portrange);
588

    
589
	if(count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]))
590
		return true;
591
	else
592
		return false;
593
}
594

    
595
/* returns true if $port is a valid port number or an alias thereof */
596
function is_portoralias($port) {
597
	global $config;
598

    
599
	if (is_alias($port)) {
600
		if (is_array($config['aliases']['alias'])) {
601
			foreach ($config['aliases']['alias'] as $alias) {
602
				if ($alias['name'] == $port && $alias['type'] == "port")
603
					return true;
604
				}
605
			}
606
			return false;
607
	} else
608
		return is_port($port);
609
}
610

    
611
/* returns true if $val is a valid shaper bandwidth value */
612
function is_valid_shaperbw($val) {
613
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
614
}
615

    
616
/* return the configured carp interface list */
617
function get_configured_carp_interface_list() {
618
	global $config;
619

    
620
	$iflist = array();
621

    
622
	if(is_array($config['virtualip']['vip'])) {
623
		$viparr = &$config['virtualip']['vip'];
624
		foreach ($viparr as $vip) {
625
			switch ($vip['mode']) {
626
				case "carp":
627
				case "carpdev-dhcp":
628
					$vipif = "vip" . $vip['vhid'];
629
					$iflist[$vipif] = $vip['subnet'];
630
					break;
631
			}
632
		}
633
	}
634

    
635
	return $iflist;
636
}
637

    
638
/* return the configured IP aliases list */
639
function get_configured_ip_aliases_list() {
640
	global $config;
641

    
642
	$alias_list=array();
643

    
644
	if(is_array($config['virtualip']['vip'])) {
645
		$viparr = &$config['virtualip']['vip'];
646
		foreach ($viparr as $vip) {
647
			if ($vip['mode']=="ipalias") {
648
				$alias_list[$vip['subnet']] = $vip['interface'];
649
			}
650
		}
651
	}
652

    
653
	return $alias_list;
654
}
655

    
656

    
657
/* comparison function for sorting by the order in which interfaces are normally created */
658
function compare_interface_friendly_names($a, $b) {
659
	if ($a == $b)
660
		return 0;
661
	else if ($a == 'wan')
662
		return -1;
663
	else if ($b == 'wan')
664
		return 1;
665
	else if ($a == 'lan')
666
		return -1;
667
	else if ($b == 'lan')
668
		return 1;
669

    
670
	return strnatcmp($a, $b);
671
}
672

    
673
/* return the configured interfaces list. */
674
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
675
	global $config;
676

    
677
	$iflist = array();
678

    
679
	/* if list */
680
	foreach($config['interfaces'] as $if => $ifdetail) {
681
		if ($only_opt && ($if == "wan" || $if == "lan"))
682
			continue;
683
		if (isset($ifdetail['enable']) || $withdisabled == true)
684
			$iflist[$if] = $if;
685
	}
686

    
687
	return $iflist;
688
}
689

    
690
/* return the configured interfaces list. */
691
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
692
	global $config;
693

    
694
	$iflist = array();
695

    
696
	/* if list */
697
	foreach($config['interfaces'] as $if => $ifdetail) {
698
		if ($only_opt && ($if == "wan" || $if == "lan"))
699
			continue;
700
		if (isset($ifdetail['enable']) || $withdisabled == true) {
701
			$tmpif = get_real_interface($if);
702
			if (!empty($tmpif))
703
				$iflist[$tmpif] = $if;
704
		}
705
	}
706

    
707
	return $iflist;
708
}
709

    
710
/* return the configured interfaces list with their description. */
711
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
712
	global $config;
713

    
714
	$iflist = array();
715

    
716
	/* if list */
717
	foreach($config['interfaces'] as $if => $ifdetail) {
718
		if ($only_opt && ($if == "wan" || $if == "lan"))
719
			continue;
720
		if (isset($ifdetail['enable']) || $withdisabled == true) {
721
			if(empty($ifdetail['descr']))
722
				$iflist[$if] = strtoupper($if);
723
			else
724
				$iflist[$if] = strtoupper($ifdetail['descr']);
725
		}
726
	}
727

    
728
	return $iflist;
729
}
730

    
731
/*
732
 *   get_configured_ip_addresses() - Return a list of all configured
733
 *   interfaces IP Addresses
734
 *
735
 */
736
function get_configured_ip_addresses() {
737
	require_once("interfaces.inc");
738
	$ip_array = array();
739
	$interfaces = get_configured_interface_list();
740
	if(is_array($interfaces)) {
741
		foreach($interfaces as $int) {
742
			$ipaddr = get_interface_ip($int);
743
			$ip_array[$int] = $ipaddr;
744
		}
745
	}
746
	$interfaces = get_configured_carp_interface_list();
747
	if(is_array($interfaces)) 
748
		foreach($interfaces as $int => $ipaddr) 
749
			$ip_array[$int] = $ipaddr;
750
	return $ip_array;
751
}
752

    
753
/*
754
 *   get_configured_ipv6_addresses() - Return a list of all configured
755
 *   interfaces IPv6 Addresses
756
 *
757
 */
758
function get_configured_ipv6_addresses() {
759
	require_once("interfaces.inc");
760
	$ipv6_array = array();
761
	$interfaces = get_configured_interface_list();
762
	if(is_array($interfaces)) {
763
		foreach($interfaces as $int) {
764
			$ipaddrv6 = get_interface_ipv6($int);
765
			$ipv6_array[$int] = $ipaddrv6;
766
		}
767
	}
768
	$interfaces = get_configured_carp_interface_list();
769
	if(is_array($interfaces)) 
770
		foreach($interfaces as $int => $ipaddrv6) 
771
			$ipv6_array[$int] = $ipaddrv6;
772
	return $ipv6_array;
773
}
774

    
775
/*
776
 *   get_interface_list() - Return a list of all physical interfaces
777
 *   along with MAC and status.
778
 *
779
 *   $mode = "active" - use ifconfig -lu
780
 *           "media"  - use ifconfig to check physical connection
781
 *			status (much slower)
782
 */
783
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
784
        global $config;
785
	$upints = array();
786
        /* get a list of virtual interface types */
787
        if(!$vfaces) {
788
		$vfaces = array (
789
				'bridge',
790
				'ppp',
791
				'pppoe',
792
				'pptp',
793
				'l2tp',
794
				'sl',
795
				'gif',
796
				'gre',
797
				'faith',
798
				'lo',
799
				'ng',
800
				'_vlan',
801
				'_wlan',
802
				'pflog',
803
				'plip',
804
				'pfsync',
805
				'enc',
806
				'tun',
807
				'carp',
808
				'lagg',
809
				'vip',
810
				'ipfw'
811
		);
812
	}
813
	switch($mode) {
814
	case "active":
815
                $upints = explode(" ", trim(shell_exec("/sbin/ifconfig -lu")));
816
        	break;
817
	case "media":
818
                $intlist = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
819
                $ifconfig = "";
820
                exec("/sbin/ifconfig -a", $ifconfig);
821
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
822
                $ifstatus = preg_grep('/status:/', $ifconfig);
823
		foreach($ifstatus as $status) {
824
			$int = array_shift($intlist);
825
			if(stristr($status, "active")) $upints[] = $int;
826
		}
827
		break;
828
	default:
829
		$upints = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
830
		break;
831
	}
832
        /* build interface list with netstat */
833
        $linkinfo = "";
834
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
835
        array_shift($linkinfo);
836
	/* build ip address list with netstat */
837
	$ipinfo = "";
838
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
839
	array_shift($ipinfo);
840
	foreach($linkinfo as $link) {
841
		$friendly = "";
842
		$alink = explode(" ", $link);
843
		$ifname = rtrim(trim($alink[0]), '*');
844
		/* trim out all numbers before checking for vfaces */
845
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
846
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
847
			$toput = array(
848
					"mac" => trim($alink[1]),
849
					"up" => in_array($ifname, $upints)
850
				);
851
			foreach($ipinfo as $ip) {
852
				$aip = explode(" ", $ip);
853
				if($aip[0] == $ifname) {
854
					$toput['ipaddr'] = $aip[1];
855
				}
856
			}
857
			if (is_array($config['interfaces'])) {
858
				foreach($config['interfaces'] as $name => $int)
859
					if($int['if'] == $ifname) $friendly = $name;
860
			}
861
			switch($keyby) {
862
			case "physical":
863
				if($friendly != "") {
864
					$toput['friendly'] = $friendly;
865
				}
866
				$dmesg_arr = array();
867
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
868
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
869
				$toput['dmesg'] = $dmesg[1][0];
870
				$iflist[$ifname] = $toput;
871
				break;
872
			case "ppp":
873
				
874
			case "friendly":
875
				if($friendly != "") {
876
					$toput['if'] = $ifname;
877
					$iflist[$friendly] = $toput;
878
				}
879
				break;
880
			}
881
		}
882
	}
883
	return $iflist;
884
}
885

    
886
/****f* util/log_error
887
* NAME
888
*   log_error  - Sends a string to syslog.
889
* INPUTS
890
*   $error     - string containing the syslog message.
891
* RESULT
892
*   null
893
******/
894
function log_error($error) {
895
	global $g;
896
	$page = $_SERVER['SCRIPT_NAME'];
897
	syslog(LOG_WARNING, "$page: $error");
898
	if ($g['debug'])
899
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
900
	return;
901
}
902

    
903
/****f* util/log_auth
904
* NAME
905
*   log_error  - Sends a string to syslog as LOG_AUTH facility
906
* INPUTS
907
*   $error     - string containing the syslog message.
908
* RESULT
909
*   null
910
******/
911
function log_auth($error) {
912
	global $g;
913
	$page = $_SERVER['SCRIPT_NAME'];
914
	syslog(LOG_AUTH, "$page: $error");
915
	if ($g['debug'])
916
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
917
	return;
918
}
919

    
920
/****f* util/exec_command
921
 * NAME
922
 *   exec_command - Execute a command and return a string of the result.
923
 * INPUTS
924
 *   $command   - String of the command to be executed.
925
 * RESULT
926
 *   String containing the command's result.
927
 * NOTES
928
 *   This function returns the command's stdout and stderr.
929
 ******/
930
function exec_command($command) {
931
	$output = array();
932
	exec($command . ' 2>&1 ', $output);
933
	return(implode("\n", $output));
934
}
935

    
936
/* wrapper for exec() */
937
function mwexec($command, $mute = false) {
938
	global $g;
939

    
940
	if ($g['debug']) {
941
		if (!$_SERVER['REMOTE_ADDR'])
942
			echo "mwexec(): $command\n";
943
	}
944
	$oarr = array();
945
	$retval = 0;
946
	$garbage = exec("$command 2>&1", $oarr, $retval);
947

    
948
	if(isset($config['system']['developerspew']))
949
		$mute = false;
950
	if(($retval <> 0) && ($mute === false)) {
951
		$output = implode(" ", $oarr);
952
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
953
	}
954
	return $retval;
955
}
956

    
957
/* wrapper for exec() in background */
958
function mwexec_bg($command) {
959
	global $g;
960

    
961
	if ($g['debug']) {
962
		if (!$_SERVER['REMOTE_ADDR'])
963
			echo "mwexec(): $command\n";
964
	}
965

    
966
	exec("nohup $command > /dev/null 2>&1 &");
967
}
968

    
969
/* unlink a file, if it exists */
970
function unlink_if_exists($fn) {
971
	$to_do = glob($fn);
972
	if(is_array($to_do)) {
973
		foreach($to_do as $filename)
974
			@unlink($filename);
975
	} else {
976
		@unlink($fn);
977
	}
978
}
979
/* make a global alias table (for faster lookups) */
980
function alias_make_table($config) {
981
	global $aliastable;
982

    
983
	$aliastable = array();
984

    
985
	if (is_array($config['aliases']['alias'])) {
986
		foreach ($config['aliases']['alias'] as $alias) {
987
			if ($alias['name'])
988
				$aliastable[$alias['name']] = $alias['address'];
989
		}
990
	}
991
}
992

    
993
/* check if an alias exists */
994
function is_alias($name) {
995
	global $aliastable;
996

    
997
	return isset($aliastable[$name]);
998
}
999

    
1000
function alias_get_type($name) {
1001
        global $config;
1002
        
1003
	if (is_array($config['aliases']['alias'])) {
1004
		foreach ($config['aliases']['alias'] as $alias) {
1005
			if ($name == $alias['name'])
1006
				return $alias['type'];
1007
		}
1008
	}
1009

    
1010
        return "";
1011
}
1012

    
1013
/* expand a host or network alias, if necessary */
1014
function alias_expand($name) {
1015
	global $aliastable;
1016

    
1017
	if (isset($aliastable[$name]))
1018
		return "\${$name}";
1019
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1020
		return "{$name}";
1021
	else
1022
		return null;
1023
}
1024

    
1025
function alias_expand_urltable($name) {
1026
	global $config;
1027
	$urltable_prefix = "/var/db/aliastables/";
1028
	$urltable_filename = $urltable_prefix . $name . ".txt";
1029

    
1030
	if (is_array($config['aliases']['alias'])) {
1031
		foreach ($config['aliases']['alias'] as $alias) {
1032
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
1033
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1034
					return $urltable_filename;
1035
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1036
					return $urltable_filename;
1037
			}
1038
		}
1039
	}
1040
	return null;
1041
}
1042

    
1043
/* find out whether two subnets overlap */
1044
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1045

    
1046
	if (!is_numeric($bits1))
1047
		$bits1 = 32;
1048
	if (!is_numeric($bits2))
1049
		$bits2 = 32;
1050

    
1051
	if ($bits1 < $bits2)
1052
		$relbits = $bits1;
1053
	else
1054
		$relbits = $bits2;
1055

    
1056
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1057
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1058

    
1059
	if ($sn1 == $sn2)
1060
		return true;
1061
	else
1062
		return false;
1063
}
1064

    
1065
/* compare two IP addresses */
1066
function ipcmp($a, $b) {
1067
	if (ip_less_than($a, $b))
1068
		return -1;
1069
	else if (ip_greater_than($a, $b))
1070
		return 1;
1071
	else
1072
		return 0;
1073
}
1074

    
1075
/* return true if $addr is in $subnet, false if not */
1076
function ip_in_subnet($addr,$subnet) {
1077
	if(is_ipaddrv6($addr)) {
1078
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1079
		if($result)
1080
			return true;
1081
		else
1082
			return false;
1083
	}
1084
	list($ip, $mask) = explode('/', $subnet);
1085
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1086
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1087
}
1088

    
1089
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1090
function verify_digital_signature($fname) {
1091
	global $g;
1092

    
1093
	if(!file_exists("/usr/local/sbin/gzsig"))
1094
		return 4;
1095

    
1096
	return mwexec("/usr/local/sbin/gzsig verify {$g['etc_path']}/pubkey.pem < " . escapeshellarg($fname));
1097
}
1098

    
1099
/* obtain MAC address given an IP address by looking at the ARP table */
1100
function arp_get_mac_by_ip($ip) {
1101
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1102
	$arpoutput = "";
1103
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1104

    
1105
	if ($arpoutput[0]) {
1106
		$arpi = explode(" ", $arpoutput[0]);
1107
		$macaddr = $arpi[3];
1108
		if (is_macaddr($macaddr))
1109
			return $macaddr;
1110
		else
1111
			return false;
1112
	}
1113

    
1114
	return false;
1115
}
1116

    
1117
/* return a fieldname that is safe for xml usage */
1118
function xml_safe_fieldname($fieldname) {
1119
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1120
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1121
			 ':', ',', '.', '\'', '\\'
1122
		);
1123
	return strtolower(str_replace($replace, "", $fieldname));
1124
}
1125

    
1126
function mac_format($clientmac) {
1127
    $mac =explode(":", $clientmac);
1128

    
1129
    global $config;
1130

    
1131
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
1132

    
1133
    switch($mac_format) {
1134

    
1135
        case 'singledash':
1136
        return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1137

    
1138
        case 'ietf':
1139
        return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1140

    
1141
        case 'cisco':
1142
        return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1143

    
1144
        case 'unformatted':
1145
        return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1146

    
1147
        default:
1148
        return $clientmac;
1149
    }
1150
}
1151

    
1152
function resolve_retry($hostname, $retries = 5) {
1153

    
1154
	if (is_ipaddr($hostname))
1155
		return $hostname;
1156

    
1157
       for ($i = 0; $i < $retries; $i++) {
1158
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1159
               $ip = gethostbyname($hostname);
1160

    
1161
		if ($ip && $ip != $hostname) {
1162
			/* success */
1163
			return $ip;
1164
		}
1165

    
1166
		sleep(1);
1167
	}
1168

    
1169
	return false;
1170
}
1171

    
1172
function format_bytes($bytes) {
1173
	if ($bytes >= 1073741824) {
1174
		return sprintf("%.2f GB", $bytes/1073741824);
1175
	} else if ($bytes >= 1048576) {
1176
		return sprintf("%.2f MB", $bytes/1048576);
1177
	} else if ($bytes >= 1024) {
1178
		return sprintf("%.0f KB", $bytes/1024);
1179
	} else {
1180
		return sprintf("%d bytes", $bytes);
1181
	}
1182
}
1183

    
1184
function update_filter_reload_status($text) {
1185
	global $g;
1186

    
1187
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1188
}
1189

    
1190
/****f* util/return_dir_as_array
1191
 * NAME
1192
 *   return_dir_as_array - Return a directory's contents as an array.
1193
 * INPUTS
1194
 *   $dir       - string containing the path to the desired directory.
1195
 * RESULT
1196
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1197
 ******/
1198
function return_dir_as_array($dir) {
1199
	$dir_array = array();
1200
	if (is_dir($dir)) {
1201
		if ($dh = opendir($dir)) {
1202
			while (($file = readdir($dh)) !== false) {
1203
				$canadd = 0;
1204
				if($file == ".") $canadd = 1;
1205
				if($file == "..") $canadd = 1;
1206
				if($canadd == 0)
1207
					array_push($dir_array, $file);
1208
			}
1209
			closedir($dh);
1210
		}
1211
	}
1212
	return $dir_array;
1213
}
1214

    
1215
function run_plugins($directory) {
1216
	global $config, $g;
1217

    
1218
	/* process packager manager custom rules */
1219
	$files = return_dir_as_array($directory);
1220
	if (is_array($files)) {
1221
		foreach ($files as $file) {
1222
			if (stristr($file, ".sh") == true)
1223
				mwexec($directory . $file . " start");
1224
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1225
				require_once($directory . "/" . $file);
1226
		}
1227
	}
1228
}
1229

    
1230
/*
1231
 *    safe_mkdir($path, $mode = 0755)
1232
 *    create directory if it doesn't already exist and isn't a file!
1233
 */
1234
function safe_mkdir($path, $mode=0755) {
1235
	global $g;
1236

    
1237
	if (!is_file($path) && !is_dir($path)) {
1238
		return @mkdir($path, $mode, true);
1239
	} else {
1240
		return false;
1241
	}
1242
}
1243

    
1244
/*
1245
 * make_dirs($path, $mode = 0755)
1246
 * create directory tree recursively (mkdir -p)
1247
 */
1248
function make_dirs($path, $mode = 0755) {
1249
	$base = '';
1250
	foreach (explode('/', $path) as $dir) {
1251
		$base .= "/$dir";
1252
		if (!is_dir($base)) {
1253
			if (!@mkdir($base, $mode))
1254
				return false;
1255
		}
1256
	}
1257
	return true;
1258
}
1259

    
1260
/*
1261
 * get_sysctl($names)
1262
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1263
 * name) and return an array of key/value pairs set for those that exist
1264
 */
1265
function get_sysctl($names) {
1266
	if (empty($names))
1267
		return array();
1268

    
1269
	if (is_array($names)) {
1270
		$name_list = array();
1271
		foreach ($names as $name) {
1272
			$name_list[] = escapeshellarg($name);
1273
		}
1274
	} else
1275
		$name_list = array(escapeshellarg($names));
1276

    
1277
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1278
	$values = array();
1279
	foreach ($output as $line) {
1280
		$line = explode(": ", $line, 2);
1281
		if (count($line) == 2)
1282
			$values[$line[0]] = $line[1];
1283
	}
1284

    
1285
	return $values;
1286
}
1287

    
1288
/*
1289
 * set_sysctl($value_list)
1290
 * Set sysctl OID's listed as key/value pairs and return
1291
 * an array with keys set for those that succeeded
1292
 */
1293
function set_sysctl($values) {
1294
	if (empty($values))
1295
		return array();
1296

    
1297
	$value_list = array();
1298
	foreach ($values as $key => $value) {
1299
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1300
	}
1301

    
1302
	exec("/sbin/sysctl -i " . implode(" ", $value_list), $output, $success);
1303

    
1304
	/* Retry individually if failed (one or more read-only) */
1305
	if ($success <> 0 && count($value_list) > 1) {
1306
		foreach ($value_list as $value) {
1307
			exec("/sbin/sysctl -i " . $value, $output);
1308
		}
1309
	}
1310

    
1311
	$ret = array();
1312
	foreach ($output as $line) {
1313
		$line = explode(": ", $line, 2);
1314
		if (count($line) == 2)
1315
			$ret[$line[0]] = true;
1316
	}
1317

    
1318
	return $ret;
1319
}
1320

    
1321
/*
1322
 *     get_memory()
1323
 *     returns an array listing the amount of
1324
 *     memory installed in the hardware
1325
 *     [0]real and [1]available
1326
 */
1327
function get_memory() {
1328
	$matches = "";
1329
	if(file_exists("/var/log/dmesg.boot"))
1330
		$mem = `cat /var/log/dmesg.boot | grep memory`;
1331
	else
1332
		$mem = `dmesg -a | grep memory`;			
1333
	if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1334
		return array($matches[1][0], $matches[1][0]);
1335
	if(!$real && !$avail) {
1336
		$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1337
		$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1338
		/* convert from bytes to megabytes */
1339
		return array(($real/1048576),($avail/1048576));
1340
	}
1341
}
1342

    
1343
function mute_kernel_msgs() {
1344
	global $config;
1345
	// Do not mute serial console.  The kernel gets very very cranky
1346
	// and will start dishing you cannot control tty errors.
1347
	switch (trim(file_get_contents("/etc/platform"))) {
1348
		case "nanobsd":
1349
		case "jail":
1350
			return;
1351
	}
1352
	if($config['system']['enableserial']) 
1353
		return;			
1354
	exec("/sbin/conscontrol mute on");
1355
}
1356

    
1357
function unmute_kernel_msgs() {
1358
	global $config;
1359
	// Do not mute serial console.  The kernel gets very very cranky
1360
	// and will start dishing you cannot control tty errors.
1361
	switch (trim(file_get_contents("/etc/platform"))) {
1362
		case "nanobsd":
1363
		case "jail":
1364
			return;
1365
	}
1366
	exec("/sbin/conscontrol mute off");
1367
}
1368

    
1369
function start_devd() {
1370
	global $g;
1371

    
1372
	if ($g['platform'] == 'jail')
1373
		return;
1374
	exec("/sbin/devd");
1375
	sleep(1);
1376
}
1377

    
1378
function is_interface_vlan_mismatch() {
1379
	global $config, $g;
1380

    
1381
	if (is_array($config['vlans']['vlan'])) {
1382
		foreach ($config['vlans']['vlan'] as $vlan) {
1383
			if (does_interface_exist($vlan['if']) == false)
1384
				return true;
1385
		}
1386
	}
1387

    
1388
	return false;
1389
}
1390

    
1391
function is_interface_mismatch() {
1392
	global $config, $g;
1393

    
1394
	$do_assign = false;
1395
	$i = 0;
1396
	if (is_array($config['interfaces'])) {
1397
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1398
			if (preg_match("/^enc|^cua|^tun|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1399
				// Do not check these interfaces.
1400
				$i++;
1401
				continue;
1402
			}
1403
			else if (does_interface_exist($ifcfg['if']) == false) {
1404
				$do_assign = true;
1405
			} else
1406
				$i++;
1407
		}
1408
	}
1409

    
1410
	if ($g['minimum_nic_count'] > $i) {
1411
		$do_assign = true;
1412
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1413
	$do_assign = false;
1414

    
1415
	return $do_assign;
1416
}
1417

    
1418
/* sync carp entries to other firewalls */
1419
function carp_sync_client() {
1420
	global $g;
1421
	send_event("filter sync");
1422
}
1423

    
1424
/****f* util/isAjax
1425
 * NAME
1426
 *   isAjax - reports if the request is driven from prototype
1427
 * INPUTS
1428
 *   none
1429
 * RESULT
1430
 *   true/false
1431
 ******/
1432
function isAjax() {
1433
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1434
}
1435

    
1436
/****f* util/timeout
1437
 * NAME
1438
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1439
 * INPUTS
1440
 *   optional, seconds to wait before timeout. Default 9 seconds.
1441
 * RESULT
1442
 *   returns 1 char of user input or null if no input.
1443
 ******/
1444
function timeout($timer = 9) {
1445
	while(!isset($key)) {
1446
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1447
		else { echo chr(8). "{$timer}"; }
1448
		`/bin/stty -icanon min 0 time 25`;
1449
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1450
		`/bin/stty icanon`;
1451
		if ($key == '')
1452
			unset($key);
1453
		$timer--;
1454
		if ($timer == 0)
1455
			break;
1456
	}
1457
	return $key;	
1458
}
1459

    
1460
/****f* util/msort
1461
 * NAME
1462
 *   msort - sort array
1463
 * INPUTS
1464
 *   $array to be sorted, field to sort by, direction of sort
1465
 * RESULT
1466
 *   returns newly sorted array
1467
 ******/
1468
function msort($array, $id="id", $sort_ascending=true) {
1469
	$temp_array = array();
1470
	while(count($array)>0) {
1471
		$lowest_id = 0;
1472
		$index=0;
1473
		foreach ($array as $item) {
1474
			if (isset($item[$id])) {
1475
				if ($array[$lowest_id][$id]) {
1476
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1477
						$lowest_id = $index;
1478
					}
1479
				}
1480
			}
1481
			$index++;
1482
		}
1483
		$temp_array[] = $array[$lowest_id];
1484
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1485
	}
1486
	if ($sort_ascending) {
1487
		return $temp_array;
1488
	} else {
1489
    	return array_reverse($temp_array);
1490
	}
1491
}
1492

    
1493
/****f* util/color
1494
 * NAME
1495
 *   color - outputs a color code to the ansi terminal if supported
1496
 * INPUTS
1497
 *   color code or color name
1498
 * RESULT
1499
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1500
 ******/
1501
function color($color = "0m") {
1502
	/*
1503
		Color codes available:
1504
		 0m reset; clears all colors and styles (to white on black)
1505
		 1m bold on (see below)
1506
		 3m italics on
1507
		 4m underline on
1508
		 7m inverse on; reverses foreground & background colors
1509
		 9m strikethrough on
1510
		 22m bold off (see below)
1511
		 23m italics off
1512
		 24m underline off
1513
		 27m inverse off
1514
		 29m strikethrough off
1515
		 30m set foreground color to black
1516
		 31m set foreground color to red
1517
		 32m set foreground color to green
1518
		 33m set foreground color to yellow
1519
		 34m set foreground color to blue
1520
		 35m set foreground color to magenta (purple)
1521
		 36m set foreground color to cyan
1522
		 37m set foreground color to white
1523
		 40m  set background color to black
1524
		 41m set background color to red
1525
		 42m set background color to green
1526
		 43m set background color to yellow
1527
		 44m set background color to blue
1528
		 45m set background color to magenta (purple)
1529
		 46m set background color to cyan
1530
		 47m set background color to white
1531
		 49m set background color to default (black)
1532
	*/	
1533
	// Allow caching of TERM to 
1534
	// speedup subequence requests.
1535
	global $TERM;
1536
	if(!$TERM) 
1537
		$TERM=`/usr/bin/env | grep color`;
1538
	if(!$TERM)
1539
		$TERM=`/usr/bin/env | grep cons25`;
1540
	if($TERM) {
1541
		$ESCAPE=chr(27);
1542
		switch ($color) {
1543
			case "black":
1544
				return "{$ESCAPE}[30m"; 
1545
			case "red":
1546
				return "{$ESCAPE}[31m"; 
1547
			case "green":
1548
				return "{$ESCAPE}[32m"; 
1549
			case "yellow":
1550
				return "{$ESCAPE}[33m"; 
1551
			case "blue":
1552
				return "{$ESCAPE}[34m"; 
1553
			case "magenta":
1554
				return "{$ESCAPE}[35m"; 
1555
			case "cyan":
1556
				return "{$ESCAPE}[36m"; 
1557
			case "white":
1558
				return "{$ESCAPE}[37m"; 
1559
			case "default":
1560
				return "{$ESCAPE}[39m"; 
1561
		}
1562
		return "{$ESCAPE}[{$color}";
1563
	}
1564
}
1565

    
1566
/****f* util/is_URL
1567
 * NAME
1568
 *   is_URL
1569
 * INPUTS
1570
 *   string to check
1571
 * RESULT
1572
 *   Returns true if item is a URL
1573
 ******/
1574
function is_URL($url) {
1575
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1576
	if($match)
1577
		return true;	
1578
	return false;
1579
}
1580

    
1581
function is_file_included($file = "") {
1582
	$files = get_included_files();
1583
	if (in_array($file, $files))
1584
		return true;
1585
	
1586
	return false;
1587
}
1588

    
1589
/*
1590
	This function was borrowed from a comment on PHP.net at the following URL:
1591
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1592
 */
1593
function array_merge_recursive_unique($array0, $array1) {
1594

    
1595
	$arrays = func_get_args();
1596
	$remains = $arrays;
1597

    
1598
	// We walk through each arrays and put value in the results (without
1599
	// considering previous value).
1600
	$result = array();
1601

    
1602
	// loop available array
1603
	foreach($arrays as $array) {
1604

    
1605
		// The first remaining array is $array. We are processing it. So
1606
		// we remove it from remaing arrays.
1607
        array_shift($remains);
1608

    
1609
		// We don't care non array param, like array_merge since PHP 5.0.
1610
		if(is_array($array)) {
1611
			// Loop values
1612
			foreach($array as $key => $value) {
1613
				if(is_array($value)) {
1614
					// we gather all remaining arrays that have such key available
1615
					$args = array();
1616
					foreach($remains as $remain) {
1617
						if(array_key_exists($key, $remain)) {
1618
							array_push($args, $remain[$key]);
1619
						}
1620
					}
1621

    
1622
					if(count($args) > 2) {
1623
						// put the recursion
1624
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1625
					} else {
1626
						foreach($value as $vkey => $vval) {
1627
							$result[$key][$vkey] = $vval;
1628
						}
1629
					}
1630
				} else {
1631
					// simply put the value
1632
					$result[$key] = $value;
1633
				}
1634
			}
1635
		}
1636
	}
1637
	return $result;
1638
}
1639

    
1640
?>
(49-49/61)