Project

General

Profile

Download (41.2 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 -nF {$pid}", $output, $retval);
47

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

    
51
function is_process_running($process) {
52
	$output = "";
53
	exec("/bin/pgrep -anx {$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

    
170
	foreach ($cmds as $cmd)
171
		send_event($cmd);
172
}
173

    
174
function refcount_init($reference) {
175
	$shmid = @shmop_open($reference, "c", 0644, 10);
176
	@shmop_write($shmid, 0, 0);
177
	@shmop_close($shmid);
178
}
179

    
180
function refcount_reference($reference) {
181
	try {
182
		$shmid = @shmop_open($reference, "w", 0644, 10);
183
		if (!$shmid) {
184
			refcount_init($reference);
185
			$shmid = @shmop_open($reference, "w", 0, 0);
186
		}
187
		$shm_data = @shmop_read($shmid, 0, 10);
188
		$shm_data = intval($shm_data) + 1;
189
		@shmop_write($shmid, $shm_data, 0);
190
		@shmop_close($shmid);
191
	} catch (Exception $e) {
192
		log_error($e->getMessage());
193
	}
194

    
195
	return $shm_data;
196
}
197

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

    
214
	return $shm_data;
215
}
216

    
217
function is_module_loaded($module_name) {
218
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
219
	if (intval($running) >= 1)
220
		return true;
221
	else
222
		return false;
223
}
224

    
225
/* return the subnet address given a host address and a subnet bit count */
226
function gen_subnet($ipaddr, $bits) {
227
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
228
		return "";
229
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
230
}
231

    
232
/* return the subnet address given a host address and a subnet bit count */
233
function gen_subnetv6($ipaddr, $bits) {
234
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
235
		return "";
236

    
237
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
238
	return $address;
239
}
240

    
241
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
242
function gen_subnet_max($ipaddr, $bits) {
243
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
244
		return "";
245

    
246
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
247
}
248

    
249
/* Generate end number for a given ipv6 subnet mask */
250
function gen_subnetv6_max($ipaddr, $bits) {
251
	if(!is_ipaddrv6($ipaddr))
252
		return false;
253
	
254
	$mask = Net_IPv6::getNetmask('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',$bits);
255
	
256
	$inet_ip = (binary)inet_pton($ipaddr);
257
	$inet_mask = (binary)inet_pton($mask);
258

    
259
	$inet_end = $inet_ip | ~$inet_mask;
260

    
261
	return(Net_IPv6::uncompress(inet_ntop($inet_end)));
262
}
263

    
264
/* returns a subnet mask (long given a bit count) */
265
function gen_subnet_mask_long($bits) {
266
	$sm = 0;
267
	for ($i = 0; $i < $bits; $i++) {
268
		$sm >>= 1;
269
		$sm |= 0x80000000;
270
	}
271
	return $sm;
272
}
273

    
274
/* same as above but returns a string */
275
function gen_subnet_mask($bits) {
276
	return long2ip(gen_subnet_mask_long($bits));
277
}
278

    
279
/* Convert long int to IP address, truncating to 32-bits. */
280
function long2ip32($ip) {
281
	return long2ip($ip & 0xFFFFFFFF);
282
}
283

    
284
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
285
function ip2long32($ip) {
286
	return ( ip2long($ip) & 0xFFFFFFFF );
287
}
288

    
289
/* Convert IP address to unsigned long int. */
290
function ip2ulong($ip) {
291
	return sprintf("%u", ip2long32($ip));
292
}
293

    
294
/* Find out how many IPs are contained within a given IP range
295
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
296
 */
297
function ip_range_size($startip, $endip) {
298
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
299
		// Operate as unsigned long because otherwise it wouldn't work
300
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
301
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
302
	}
303
	return -1;
304
}
305

    
306
/* Find the smallest possible subnet mask which can contain a given number of IPs
307
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
308
 */
309
function find_smallest_cidr($number) {
310
	$smallest = 1;
311
	for ($b=32; $b > 0; $b--) {
312
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
313
	}
314
	return (32-$smallest);
315
}
316

    
317
/* Return the previous IP address before the given address */
318
function ip_before($ip) {
319
	return long2ip32(ip2long($ip)-1);
320
}
321

    
322
/* Return the next IP address after the given address */
323
function ip_after($ip) {
324
	return long2ip32(ip2long($ip)+1);
325
}
326

    
327
/* Return true if the first IP is 'before' the second */
328
function ip_less_than($ip1, $ip2) {
329
	// Compare as unsigned long because otherwise it wouldn't work when
330
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
331
	return ip2ulong($ip1) < ip2ulong($ip2);
332
}
333

    
334
/* Return true if the first IP is 'after' the second */
335
function ip_greater_than($ip1, $ip2) {
336
	// Compare as unsigned long because otherwise it wouldn't work
337
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
338
	return ip2ulong($ip1) > ip2ulong($ip2);
339
}
340

    
341
/* Convert a range of IPs to an array of subnets which can contain the range. */
342
function ip_range_to_subnet_array($startip, $endip) {
343
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
344
		return array();
345
	}
346

    
347
	// Container for subnets within this range.
348
	$rangesubnets = array();
349

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

    
353
	// Loop here to reduce subnet size and retest as needed. We need to make sure
354
	//   that the target subnet is wholly contained between $startip and $endip.
355
	for ($cidr; $cidr <= 32; $cidr++) {
356
		// Find the network and broadcast addresses for the subnet being tested.
357
		$targetsub_min = gen_subnet($startip, $cidr);
358
		$targetsub_max = gen_subnet_max($startip, $cidr);
359

    
360
		// Check best case where the range is exactly one subnet.
361
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
362
			// Hooray, the range is exactly this subnet!
363
			return array("{$startip}/{$cidr}");
364
		}
365

    
366
		// These remaining scenarios will find a subnet that uses the largest
367
		//  chunk possible of the range being tested, and leave the rest to be
368
		//  tested recursively after the loop.
369

    
370
		// Check if the subnet begins with $startip and ends before $endip
371
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
372
			break;
373
		}
374

    
375
		// Check if the subnet ends at $endip and starts after $startip
376
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
377
			break;
378
		}
379

    
380
		// Check if the subnet is between $startip and $endip
381
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
382
			break;
383
		}
384
	}
385

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

    
392
	// Add in the subnet we found before, to preserve ordering
393
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
394

    
395
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
396
	if ($endip != $targetsub_max) {
397
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
398
	}
399
	return $rangesubnets;
400
}
401

    
402
function is_iprange($range) {
403
	if (substr_count($range, '-') != 1) {
404
		return false;
405
	}
406
	list($ip1, $ip2) = explode ('-', $range);
407
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
408
}
409

    
410
function is_numericint($arg) {
411
	return (preg_match("/[^0-9]/", $arg) ? false : true);
412
}
413

    
414

    
415
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
416
function is_ipaddr($ipaddr) {
417
	if(is_ipaddrv4($ipaddr)) {
418
		return true;
419
	}
420
	if(is_ipaddrv6($ipaddr)) {
421
		return true;
422
	}
423
	return false;
424
}
425

    
426
/* returns true if $ipaddr is a valid IPv6 address */
427
function is_ipaddrv6($ipaddr) {
428
	$result = Net_IPv6::checkIPv6($ipaddr);
429
	return $result;
430
}
431

    
432
/* returns true if $ipaddr is a valid dotted IPv4 address */
433
function is_ipaddrv4($ipaddr) {
434
	if (!is_string($ipaddr))
435
		return false;
436

    
437
	$ip_long = ip2long($ipaddr);
438
	$ip_reverse = long2ip32($ip_long);
439

    
440
	if ($ipaddr == $ip_reverse)
441
		return true;
442
	else
443
		return false;
444
}
445

    
446
function is_ipaddrwithport($ipport) {
447
	$parts = explode(":", $ipport);
448
	$port = array_pop($parts);
449
	if (count($parts) == 1) {
450
		return is_ipaddrv4($parts[0]) && is_port($port);
451
	} elseif (count($parts) > 1) {
452
		return is_ipaddrv6(implode(":", $parts)) && is_port($port);
453
	} else {
454
		return false;
455
	}
456
}
457

    
458
function is_hostnamewithport($hostport) {
459
	$parts = explode(":", $hostport);
460
	$port = array_pop($parts);
461
	if (count($parts) == 1) {
462
		return is_hostname($parts[0]) && is_port($port);
463
	} else {
464
		return false;
465
	}
466
}
467

    
468
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
469
function is_ipaddroralias($ipaddr) {
470
	global $config;
471

    
472
	if (is_alias($ipaddr)) {
473
		if (is_array($config['aliases']['alias'])) {
474
			foreach ($config['aliases']['alias'] as $alias) {
475
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
476
					return true;
477
			}
478
		}
479
		return false;
480
	} else
481
		return is_ipaddr($ipaddr);
482

    
483
}
484

    
485
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format */
486
function is_subnet($subnet) {
487
	if(is_subnetv4($subnet)) {
488
		return true;
489
	}
490
	if(is_subnetv6($subnet)) {
491
		return true;
492
	}
493
	return false;
494
}
495

    
496
/* returns true if $subnet is a valid IPv4 subnet in CIDR format */
497
function is_subnetv4($subnet) {
498
	if (!is_string($subnet))
499
		return false;
500

    
501
	list($hp,$np) = explode('/', $subnet);
502

    
503
	if (!is_ipaddrv4($hp))
504
		return false;
505

    
506
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
507
		return false;
508

    
509
	return true;
510
}
511

    
512
/* returns true if $subnet is a valid IPv6 subnet in CIDR format */
513
function is_subnetv6($subnet) {
514
	if (!is_string($subnet))
515
		return false;
516

    
517
	list($hp,$np) = explode('/', $subnet);
518

    
519
	if (!is_ipaddrv6($hp))
520
		return false;
521

    
522
	if (!is_numeric($np) || ($np < 1) || ($np > 128))
523
		return false;
524

    
525
	return true;
526
}
527

    
528

    
529
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
530
function is_subnetoralias($subnet) {
531
	global $aliastable;
532

    
533
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
534
		return true;
535
	else
536
		return is_subnet($subnet);
537
}
538

    
539
/* returns true if $hostname is a valid hostname */
540
function is_hostname($hostname) {
541
	if (!is_string($hostname))
542
		return false;
543

    
544
	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))
545
		return true;
546
	else
547
		return false;
548
}
549

    
550
/* returns true if $domain is a valid domain name */
551
function is_domain($domain) {
552
	if (!is_string($domain))
553
		return false;
554

    
555
	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))
556
		return true;
557
	else
558
		return false;
559
}
560

    
561
/* returns true if $macaddr is a valid MAC address */
562
function is_macaddr($macaddr) {
563
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){5}$/i', $macaddr) == 1 ? true : false;
564
}
565

    
566
/* returns true if $name is a valid name for an alias */
567
/* returns NULL if a reserved word is used */
568
function is_validaliasname($name) {
569
	/* Array of reserved words */
570
	$reserved = array("port", "pass");
571
	if (in_array($name, $reserved, true))
572
		return; /* return NULL */
573
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
574
		return true;
575
	else
576
		return false;
577
}
578

    
579
/* returns true if $port is a valid TCP/UDP port */
580
function is_port($port) {
581
	$tmpports = explode(":", $port);
582
	foreach($tmpports as $tmpport) {
583
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
584
			continue;
585
		if (!ctype_digit($tmpport))
586
			return false;
587
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
588
			return false;
589
	}
590
	return true;
591
}
592

    
593
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
594
function is_portrange($portrange) {
595
	$ports = explode(":", $portrange);
596

    
597
	if(count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]))
598
		return true;
599
	else
600
		return false;
601
}
602

    
603
/* returns true if $port is a valid port number or an alias thereof */
604
function is_portoralias($port) {
605
	global $config;
606

    
607
	if (is_alias($port)) {
608
		if (is_array($config['aliases']['alias'])) {
609
			foreach ($config['aliases']['alias'] as $alias) {
610
				if ($alias['name'] == $port && $alias['type'] == "port")
611
					return true;
612
				}
613
			}
614
			return false;
615
	} else
616
		return is_port($port);
617
}
618

    
619
/* returns true if $val is a valid shaper bandwidth value */
620
function is_valid_shaperbw($val) {
621
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
622
}
623

    
624
/* return the configured carp interface list */
625
function get_configured_carp_interface_list() {
626
	global $config;
627

    
628
	$iflist = array();
629

    
630
	if(is_array($config['virtualip']['vip'])) {
631
		$viparr = &$config['virtualip']['vip'];
632
		foreach ($viparr as $vip) {
633
			switch ($vip['mode']) {
634
				case "carp":
635
				case "carpdev-dhcp":
636
					$vipif = "vip" . $vip['vhid'];
637
					$iflist[$vipif] = $vip['subnet'];
638
					break;
639
			}
640
		}
641
	}
642

    
643
	return $iflist;
644
}
645

    
646
/* return the configured IP aliases list */
647
function get_configured_ip_aliases_list() {
648
	global $config;
649

    
650
	$alias_list=array();
651

    
652
	if(is_array($config['virtualip']['vip'])) {
653
		$viparr = &$config['virtualip']['vip'];
654
		foreach ($viparr as $vip) {
655
			if ($vip['mode']=="ipalias") {
656
				$alias_list[$vip['subnet']] = $vip['interface'];
657
			}
658
		}
659
	}
660

    
661
	return $alias_list;
662
}
663

    
664

    
665
/* comparison function for sorting by the order in which interfaces are normally created */
666
function compare_interface_friendly_names($a, $b) {
667
	if ($a == $b)
668
		return 0;
669
	else if ($a == 'wan')
670
		return -1;
671
	else if ($b == 'wan')
672
		return 1;
673
	else if ($a == 'lan')
674
		return -1;
675
	else if ($b == 'lan')
676
		return 1;
677

    
678
	return strnatcmp($a, $b);
679
}
680

    
681
/* return the configured interfaces list. */
682
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
683
	global $config;
684

    
685
	$iflist = array();
686

    
687
	/* if list */
688
	foreach($config['interfaces'] as $if => $ifdetail) {
689
		if ($only_opt && ($if == "wan" || $if == "lan"))
690
			continue;
691
		if (isset($ifdetail['enable']) || $withdisabled == true)
692
			$iflist[$if] = $if;
693
	}
694

    
695
	return $iflist;
696
}
697

    
698
/* return the configured interfaces list. */
699
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
700
	global $config;
701

    
702
	$iflist = array();
703

    
704
	/* if list */
705
	foreach($config['interfaces'] as $if => $ifdetail) {
706
		if ($only_opt && ($if == "wan" || $if == "lan"))
707
			continue;
708
		if (isset($ifdetail['enable']) || $withdisabled == true) {
709
			$tmpif = get_real_interface($if);
710
			if (!empty($tmpif))
711
				$iflist[$tmpif] = $if;
712
		}
713
	}
714

    
715
	return $iflist;
716
}
717

    
718
/* return the configured interfaces list with their description. */
719
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
720
	global $config;
721

    
722
	$iflist = array();
723

    
724
	/* if list */
725
	foreach($config['interfaces'] as $if => $ifdetail) {
726
		if ($only_opt && ($if == "wan" || $if == "lan"))
727
			continue;
728
		if (isset($ifdetail['enable']) || $withdisabled == true) {
729
			if(empty($ifdetail['descr']))
730
				$iflist[$if] = strtoupper($if);
731
			else
732
				$iflist[$if] = strtoupper($ifdetail['descr']);
733
		}
734
	}
735

    
736
	return $iflist;
737
}
738

    
739
/*
740
 *   get_configured_ip_addresses() - Return a list of all configured
741
 *   interfaces IP Addresses
742
 *
743
 */
744
function get_configured_ip_addresses() {
745
	require_once("interfaces.inc");
746
	$ip_array = array();
747
	$interfaces = get_configured_interface_list();
748
	if(is_array($interfaces)) {
749
		foreach($interfaces as $int) {
750
			$ipaddr = get_interface_ip($int);
751
			$ip_array[$int] = $ipaddr;
752
		}
753
	}
754
	$interfaces = get_configured_carp_interface_list();
755
	if(is_array($interfaces)) 
756
		foreach($interfaces as $int => $ipaddr) 
757
			$ip_array[$int] = $ipaddr;
758
	return $ip_array;
759
}
760

    
761
/*
762
 *   get_configured_ipv6_addresses() - Return a list of all configured
763
 *   interfaces IPv6 Addresses
764
 *
765
 */
766
function get_configured_ipv6_addresses() {
767
	require_once("interfaces.inc");
768
	$ipv6_array = array();
769
	$interfaces = get_configured_interface_list();
770
	if(is_array($interfaces)) {
771
		foreach($interfaces as $int) {
772
			$ipaddrv6 = get_interface_ipv6($int);
773
			$ipv6_array[$int] = $ipaddrv6;
774
		}
775
	}
776
	$interfaces = get_configured_carp_interface_list();
777
	if(is_array($interfaces)) 
778
		foreach($interfaces as $int => $ipaddrv6) 
779
			$ipv6_array[$int] = $ipaddrv6;
780
	return $ipv6_array;
781
}
782

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

    
894
/****f* util/log_error
895
* NAME
896
*   log_error  - Sends a string to syslog.
897
* INPUTS
898
*   $error     - string containing the syslog message.
899
* RESULT
900
*   null
901
******/
902
function log_error($error) {
903
	global $g;
904
	$page = $_SERVER['SCRIPT_NAME'];
905
	syslog(LOG_WARNING, "$page: $error");
906
	if ($g['debug'])
907
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
908
	return;
909
}
910

    
911
/****f* util/log_auth
912
* NAME
913
*   log_error  - Sends a string to syslog as LOG_AUTH facility
914
* INPUTS
915
*   $error     - string containing the syslog message.
916
* RESULT
917
*   null
918
******/
919
function log_auth($error) {
920
	global $g;
921
	$page = $_SERVER['SCRIPT_NAME'];
922
	syslog(LOG_AUTH, "$page: $error");
923
	if ($g['debug'])
924
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
925
	return;
926
}
927

    
928
/****f* util/exec_command
929
 * NAME
930
 *   exec_command - Execute a command and return a string of the result.
931
 * INPUTS
932
 *   $command   - String of the command to be executed.
933
 * RESULT
934
 *   String containing the command's result.
935
 * NOTES
936
 *   This function returns the command's stdout and stderr.
937
 ******/
938
function exec_command($command) {
939
	$output = array();
940
	exec($command . ' 2>&1 ', $output);
941
	return(implode("\n", $output));
942
}
943

    
944
/* wrapper for exec() */
945
function mwexec($command, $mute = false) {
946
	global $g;
947

    
948
	if ($g['debug']) {
949
		if (!$_SERVER['REMOTE_ADDR'])
950
			echo "mwexec(): $command\n";
951
	}
952
	$oarr = array();
953
	$retval = 0;
954
	$garbage = exec("$command 2>&1", $oarr, $retval);
955

    
956
	if(isset($config['system']['developerspew']))
957
		$mute = false;
958
	if(($retval <> 0) && ($mute === false)) {
959
		$output = implode(" ", $oarr);
960
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
961
	}
962
	return $retval;
963
}
964

    
965
/* wrapper for exec() in background */
966
function mwexec_bg($command) {
967
	global $g;
968

    
969
	if ($g['debug']) {
970
		if (!$_SERVER['REMOTE_ADDR'])
971
			echo "mwexec(): $command\n";
972
	}
973

    
974
	exec("nohup $command > /dev/null 2>&1 &");
975
}
976

    
977
/* unlink a file, if it exists */
978
function unlink_if_exists($fn) {
979
	$to_do = glob($fn);
980
	if(is_array($to_do)) {
981
		foreach($to_do as $filename)
982
			@unlink($filename);
983
	} else {
984
		@unlink($fn);
985
	}
986
}
987
/* make a global alias table (for faster lookups) */
988
function alias_make_table($config) {
989
	global $aliastable;
990

    
991
	$aliastable = array();
992

    
993
	if (is_array($config['aliases']['alias'])) {
994
		foreach ($config['aliases']['alias'] as $alias) {
995
			if ($alias['name'])
996
				$aliastable[$alias['name']] = $alias['address'];
997
		}
998
	}
999
}
1000

    
1001
/* check if an alias exists */
1002
function is_alias($name) {
1003
	global $aliastable;
1004

    
1005
	return isset($aliastable[$name]);
1006
}
1007

    
1008
function alias_get_type($name) {
1009
        global $config;
1010
        
1011
	if (is_array($config['aliases']['alias'])) {
1012
		foreach ($config['aliases']['alias'] as $alias) {
1013
			if ($name == $alias['name'])
1014
				return $alias['type'];
1015
		}
1016
	}
1017

    
1018
        return "";
1019
}
1020

    
1021
/* expand a host or network alias, if necessary */
1022
function alias_expand($name) {
1023
	global $aliastable;
1024

    
1025
	if (isset($aliastable[$name]))
1026
		return "\${$name}";
1027
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1028
		return "{$name}";
1029
	else
1030
		return null;
1031
}
1032

    
1033
function alias_expand_urltable($name) {
1034
	global $config;
1035
	$urltable_prefix = "/var/db/aliastables/";
1036
	$urltable_filename = $urltable_prefix . $name . ".txt";
1037

    
1038
	if (is_array($config['aliases']['alias'])) {
1039
		foreach ($config['aliases']['alias'] as $alias) {
1040
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
1041
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1042
					return $urltable_filename;
1043
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1044
					return $urltable_filename;
1045
			}
1046
		}
1047
	}
1048
	return null;
1049
}
1050

    
1051
/* find out whether two subnets overlap */
1052
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1053

    
1054
	if (!is_numeric($bits1))
1055
		$bits1 = 32;
1056
	if (!is_numeric($bits2))
1057
		$bits2 = 32;
1058

    
1059
	if ($bits1 < $bits2)
1060
		$relbits = $bits1;
1061
	else
1062
		$relbits = $bits2;
1063

    
1064
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1065
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1066

    
1067
	if ($sn1 == $sn2)
1068
		return true;
1069
	else
1070
		return false;
1071
}
1072

    
1073
/* compare two IP addresses */
1074
function ipcmp($a, $b) {
1075
	if (ip_less_than($a, $b))
1076
		return -1;
1077
	else if (ip_greater_than($a, $b))
1078
		return 1;
1079
	else
1080
		return 0;
1081
}
1082

    
1083
/* return true if $addr is in $subnet, false if not */
1084
function ip_in_subnet($addr,$subnet) {
1085
	if(is_ipaddrv6($addr)) {
1086
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1087
		if($result)
1088
			return true;
1089
		else
1090
			return false;
1091
	}
1092
	list($ip, $mask) = explode('/', $subnet);
1093
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1094
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1095
}
1096

    
1097
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1098
function verify_digital_signature($fname) {
1099
	global $g;
1100

    
1101
	if(!file_exists("/usr/local/sbin/gzsig"))
1102
		return 4;
1103

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

    
1107
/* obtain MAC address given an IP address by looking at the ARP table */
1108
function arp_get_mac_by_ip($ip) {
1109
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1110
	$arpoutput = "";
1111
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1112

    
1113
	if ($arpoutput[0]) {
1114
		$arpi = explode(" ", $arpoutput[0]);
1115
		$macaddr = $arpi[3];
1116
		if (is_macaddr($macaddr))
1117
			return $macaddr;
1118
		else
1119
			return false;
1120
	}
1121

    
1122
	return false;
1123
}
1124

    
1125
/* return a fieldname that is safe for xml usage */
1126
function xml_safe_fieldname($fieldname) {
1127
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1128
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1129
			 ':', ',', '.', '\'', '\\'
1130
		);
1131
	return strtolower(str_replace($replace, "", $fieldname));
1132
}
1133

    
1134
function mac_format($clientmac) {
1135
    $mac =explode(":", $clientmac);
1136

    
1137
    global $config;
1138

    
1139
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
1140

    
1141
    switch($mac_format) {
1142

    
1143
        case 'singledash':
1144
        return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1145

    
1146
        case 'ietf':
1147
        return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1148

    
1149
        case 'cisco':
1150
        return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1151

    
1152
        case 'unformatted':
1153
        return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1154

    
1155
        default:
1156
        return $clientmac;
1157
    }
1158
}
1159

    
1160
function resolve_retry($hostname, $retries = 5) {
1161

    
1162
	if (is_ipaddr($hostname))
1163
		return $hostname;
1164

    
1165
       for ($i = 0; $i < $retries; $i++) {
1166
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1167
               $ip = gethostbyname($hostname);
1168

    
1169
		if ($ip && $ip != $hostname) {
1170
			/* success */
1171
			return $ip;
1172
		}
1173

    
1174
		sleep(1);
1175
	}
1176

    
1177
	return false;
1178
}
1179

    
1180
function format_bytes($bytes) {
1181
	if ($bytes >= 1073741824) {
1182
		return sprintf("%.2f GB", $bytes/1073741824);
1183
	} else if ($bytes >= 1048576) {
1184
		return sprintf("%.2f MB", $bytes/1048576);
1185
	} else if ($bytes >= 1024) {
1186
		return sprintf("%.0f KB", $bytes/1024);
1187
	} else {
1188
		return sprintf("%d bytes", $bytes);
1189
	}
1190
}
1191

    
1192
function update_filter_reload_status($text) {
1193
	global $g;
1194

    
1195
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1196
}
1197

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

    
1223
function run_plugins($directory) {
1224
	global $config, $g;
1225

    
1226
	/* process packager manager custom rules */
1227
	$files = return_dir_as_array($directory);
1228
	if (is_array($files)) {
1229
		foreach ($files as $file) {
1230
			if (stristr($file, ".sh") == true)
1231
				mwexec($directory . $file . " start");
1232
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1233
				require_once($directory . "/" . $file);
1234
		}
1235
	}
1236
}
1237

    
1238
/*
1239
 *    safe_mkdir($path, $mode = 0755)
1240
 *    create directory if it doesn't already exist and isn't a file!
1241
 */
1242
function safe_mkdir($path, $mode=0755) {
1243
	global $g;
1244

    
1245
	if (!is_file($path) && !is_dir($path)) {
1246
		return @mkdir($path, $mode, true);
1247
	} else {
1248
		return false;
1249
	}
1250
}
1251

    
1252
/*
1253
 * make_dirs($path, $mode = 0755)
1254
 * create directory tree recursively (mkdir -p)
1255
 */
1256
function make_dirs($path, $mode = 0755) {
1257
	$base = '';
1258
	foreach (explode('/', $path) as $dir) {
1259
		$base .= "/$dir";
1260
		if (!is_dir($base)) {
1261
			if (!@mkdir($base, $mode))
1262
				return false;
1263
		}
1264
	}
1265
	return true;
1266
}
1267

    
1268
/*
1269
 * get_sysctl($names)
1270
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1271
 * name) and return an array of key/value pairs set for those that exist
1272
 */
1273
function get_sysctl($names) {
1274
	if (empty($names))
1275
		return array();
1276

    
1277
	if (is_array($names)) {
1278
		$name_list = array();
1279
		foreach ($names as $name) {
1280
			$name_list[] = escapeshellarg($name);
1281
		}
1282
	} else
1283
		$name_list = array(escapeshellarg($names));
1284

    
1285
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1286
	$values = array();
1287
	foreach ($output as $line) {
1288
		$line = explode(": ", $line, 2);
1289
		if (count($line) == 2)
1290
			$values[$line[0]] = $line[1];
1291
	}
1292

    
1293
	return $values;
1294
}
1295

    
1296
/*
1297
 * set_sysctl($value_list)
1298
 * Set sysctl OID's listed as key/value pairs and return
1299
 * an array with keys set for those that succeeded
1300
 */
1301
function set_sysctl($values) {
1302
	if (empty($values))
1303
		return array();
1304

    
1305
	$value_list = array();
1306
	foreach ($values as $key => $value) {
1307
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1308
	}
1309

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

    
1312
	/* Retry individually if failed (one or more read-only) */
1313
	if ($success <> 0 && count($value_list) > 1) {
1314
		foreach ($value_list as $value) {
1315
			exec("/sbin/sysctl -i " . $value, $output);
1316
		}
1317
	}
1318

    
1319
	$ret = array();
1320
	foreach ($output as $line) {
1321
		$line = explode(": ", $line, 2);
1322
		if (count($line) == 2)
1323
			$ret[$line[0]] = true;
1324
	}
1325

    
1326
	return $ret;
1327
}
1328

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

    
1351
function mute_kernel_msgs() {
1352
	global $config;
1353
	// Do not mute serial console.  The kernel gets very very cranky
1354
	// and will start dishing you cannot control tty errors.
1355
	switch (trim(file_get_contents("/etc/platform"))) {
1356
		case "nanobsd":
1357
		case "jail":
1358
			return;
1359
	}
1360
	if($config['system']['enableserial']) 
1361
		return;			
1362
	exec("/sbin/conscontrol mute on");
1363
}
1364

    
1365
function unmute_kernel_msgs() {
1366
	global $config;
1367
	// Do not mute serial console.  The kernel gets very very cranky
1368
	// and will start dishing you cannot control tty errors.
1369
	switch (trim(file_get_contents("/etc/platform"))) {
1370
		case "nanobsd":
1371
		case "jail":
1372
			return;
1373
	}
1374
	exec("/sbin/conscontrol mute off");
1375
}
1376

    
1377
function start_devd() {
1378
	global $g;
1379

    
1380
	if ($g['platform'] == 'jail')
1381
		return;
1382
	exec("/sbin/devd");
1383
	sleep(1);
1384
}
1385

    
1386
function is_interface_vlan_mismatch() {
1387
	global $config, $g;
1388

    
1389
	if (is_array($config['vlans']['vlan'])) {
1390
		foreach ($config['vlans']['vlan'] as $vlan) {
1391
			if (does_interface_exist($vlan['if']) == false)
1392
				return true;
1393
		}
1394
	}
1395

    
1396
	return false;
1397
}
1398

    
1399
function is_interface_mismatch() {
1400
	global $config, $g;
1401

    
1402
	$do_assign = false;
1403
	$i = 0;
1404
	if (is_array($config['interfaces'])) {
1405
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1406
			if (preg_match("/^enc|^cua|^tun|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1407
				// Do not check these interfaces.
1408
				$i++;
1409
				continue;
1410
			}
1411
			else if (does_interface_exist($ifcfg['if']) == false) {
1412
				$do_assign = true;
1413
			} else
1414
				$i++;
1415
		}
1416
	}
1417

    
1418
	if ($g['minimum_nic_count'] > $i) {
1419
		$do_assign = true;
1420
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1421
	$do_assign = false;
1422

    
1423
	return $do_assign;
1424
}
1425

    
1426
/* sync carp entries to other firewalls */
1427
function carp_sync_client() {
1428
	global $g;
1429
	send_event("filter sync");
1430
}
1431

    
1432
/****f* util/isAjax
1433
 * NAME
1434
 *   isAjax - reports if the request is driven from prototype
1435
 * INPUTS
1436
 *   none
1437
 * RESULT
1438
 *   true/false
1439
 ******/
1440
function isAjax() {
1441
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1442
}
1443

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

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

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

    
1574
/****f* util/is_URL
1575
 * NAME
1576
 *   is_URL
1577
 * INPUTS
1578
 *   string to check
1579
 * RESULT
1580
 *   Returns true if item is a URL
1581
 ******/
1582
function is_URL($url) {
1583
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1584
	if($match)
1585
		return true;	
1586
	return false;
1587
}
1588

    
1589
function is_file_included($file = "") {
1590
	$files = get_included_files();
1591
	if (in_array($file, $files))
1592
		return true;
1593
	
1594
	return false;
1595
}
1596

    
1597
/*
1598
	This function was borrowed from a comment on PHP.net at the following URL:
1599
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1600
 */
1601
function array_merge_recursive_unique($array0, $array1) {
1602

    
1603
	$arrays = func_get_args();
1604
	$remains = $arrays;
1605

    
1606
	// We walk through each arrays and put value in the results (without
1607
	// considering previous value).
1608
	$result = array();
1609

    
1610
	// loop available array
1611
	foreach($arrays as $array) {
1612

    
1613
		// The first remaining array is $array. We are processing it. So
1614
		// we remove it from remaing arrays.
1615
        array_shift($remains);
1616

    
1617
		// We don't care non array param, like array_merge since PHP 5.0.
1618
		if(is_array($array)) {
1619
			// Loop values
1620
			foreach($array as $key => $value) {
1621
				if(is_array($value)) {
1622
					// we gather all remaining arrays that have such key available
1623
					$args = array();
1624
					foreach($remains as $remain) {
1625
						if(array_key_exists($key, $remain)) {
1626
							array_push($args, $remain[$key]);
1627
						}
1628
					}
1629

    
1630
					if(count($args) > 2) {
1631
						// put the recursion
1632
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1633
					} else {
1634
						foreach($value as $vkey => $vval) {
1635
							$result[$key][$vkey] = $vval;
1636
						}
1637
					}
1638
				} else {
1639
					// simply put the value
1640
					$result[$key] = $value;
1641
				}
1642
			}
1643
		}
1644
	}
1645
	return $result;
1646
}
1647

    
1648
/*
1649
 * converts a string like "a,b,c,d"
1650
 * into an array like array("a" => "b", "c" => "d")
1651
 */
1652
function explode_assoc($delimiter, $string) {
1653
	$array = explode($delimiter, $string);
1654
	$result = array();
1655
	$numkeys = floor(count($array) / 2);
1656
	for ($i = 0; $i < $numkeys; $i += 1) {
1657
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1658
	}
1659
	return $result;
1660
}
1661

    
1662
?>
(52-52/64)