Project

General

Profile

Download (53.7 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($pidfile) {
45
	$output = "";
46
	if (file_exists($pidfile)) {
47
		exec("/bin/pgrep -nF {$pidfile}", $output, $retval);
48
		return (intval($retval) == 0);
49
	}
50
	return false;
51
}
52

    
53
function is_process_running($process) {
54
	$output = "";
55
	exec("/bin/pgrep -anx " . escapeshellarg($process), $output, $retval);
56

    
57
	return (intval($retval) == 0);
58
}
59

    
60
function isvalidproc($proc) {
61
	return is_process_running($proc);
62
}
63

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

    
70
	return 0;
71
}
72

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

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

    
85
function is_subsystem_dirty($subsystem = "") {
86
	global $g;
87

    
88
	if ($subsystem == "")
89
		return false;
90

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

    
94
	return false;
95
}
96

    
97
function mark_subsystem_dirty($subsystem = "") {
98
	global $g;
99

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

    
104
function clear_subsystem_dirty($subsystem = "") {
105
	global $g;
106

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

    
110
function config_lock() {
111
	return;
112
}
113
function config_unlock() {
114
	return;
115
}
116

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

    
135
function try_lock($lock, $timeout = 5) {
136
	global $g, $cfglckkeyconsumers;
137
	if (!$lock)
138
		die(gettext("WARNING: You must give a name as parameter to try_lock() function."));
139
	if (!file_exists("{$g['tmp_path']}/{$lock}.lock")) {
140
		@touch("{$g['tmp_path']}/{$lock}.lock");
141
		@chmod("{$g['tmp_path']}/{$lock}.lock", 0666);
142
	}
143
	$cfglckkeyconsumers++;
144
	if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
145
		$trycounter = 0;
146
		while(!flock($fp, LOCK_EX | LOCK_NB)) {
147
			if ($trycounter >= $timeout) {
148
				fclose($fp);
149
				return NULL;
150
			}
151
			sleep(1);
152
			$trycounter++;
153
		}
154

    
155
		return $fp;
156
	}
157

    
158
	return NULL;
159
}
160

    
161
/* unlock configuration file */
162
function unlock($cfglckkey = 0) {
163
	global $g, $cfglckkeyconsumers;
164
	flock($cfglckkey, LOCK_UN);
165
	fclose($cfglckkey);
166
	return;
167
}
168

    
169
/* unlock forcefully configuration file */
170
function unlock_force($lock) {
171
	global $g;
172

    
173
	@unlink("{$g['tmp_path']}/{$lock}.lock");
174
}
175

    
176
function send_event($cmd) {
177
	global $g;
178

    
179
	if(!isset($g['event_address']))
180
		$g['event_address'] = "unix:///var/run/check_reload_status";
181

    
182
	$try = 0;
183
	while ($try < 3) {
184
		$fd = @fsockopen($g['event_address']);
185
		if ($fd) {
186
			fwrite($fd, $cmd);
187
			$resp = fread($fd, 4096);
188
			if ($resp != "OK\n")
189
				log_error("send_event: sent {$cmd} got {$resp}");
190
			fclose($fd);
191
			$try = 3;
192
		} else if (!is_process_running("check_reload_status"))
193
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
194
		$try++;
195
	}
196
}
197

    
198
function send_multiple_events($cmds) {
199
	global $g;
200

    
201
	if(!isset($g['event_address']))
202
		$g['event_address'] = "unix:///var/run/check_reload_status";
203

    
204
	if (!is_array($cmds))
205
		return;
206

    
207
	while ($try < 3) {
208
		$fd = @fsockopen($g['event_address']);
209
		if ($fd) {
210
			foreach ($cmds as $cmd) {
211
				fwrite($fd, $cmd);
212
				$resp = fread($fd, 4096);
213
				if ($resp != "OK\n")
214
					log_error("send_event: sent {$cmd} got {$resp}");
215
			}
216
			fclose($fd);
217
			$try = 3;
218
		} else if (!is_process_running("check_reload_status"))
219
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
220
		$try++;
221
	}
222
}
223

    
224
function refcount_init($reference) {
225
	$shmid = @shmop_open($reference, "c", 0644, 10);
226
	@shmop_write($shmid, str_pad("0", 10, "\x0", STR_PAD_RIGHT), 0);
227
	@shmop_close($shmid);
228
}
229

    
230
function refcount_reference($reference) {
231
	/* Take out a lock across the shared memory read, increment, write sequence to make it atomic. */
232
	$shm_lck = lock("shm{$reference}", LOCK_EX);
233
	try {
234
		/* NOTE: A warning is generated when shared memory does not exist */
235
		$shmid = @shmop_open($reference, "w", 0, 0);
236
		if (!$shmid) {
237
			refcount_init($reference);
238
			$shmid = @shmop_open($reference, "w", 0, 0);
239
			if (!$shmid) {
240
				log_error(gettext("Could not open shared memory {$reference}"));
241
				unlock($shm_lck);
242
				return;
243
			}
244
		}
245
		$shm_data = @shmop_read($shmid, 0, 10);
246
		$shm_data = intval($shm_data) + 1;
247
		@shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
248
		@shmop_close($shmid);
249
		unlock($shm_lck);
250
	} catch (Exception $e) {
251
		log_error($e->getMessage());
252
		unlock($shm_lck);
253
	}
254

    
255
	return $shm_data;
256
}
257

    
258
function refcount_unreference($reference) {
259
	/* Take out a lock across the shared memory read, decrement, write sequence to make it atomic. */
260
	$shm_lck = lock("shm{$reference}", LOCK_EX);
261
	try {
262
		$shmid = @shmop_open($reference, "w", 0, 0);
263
		if (!$shmid) {
264
			refcount_init($reference);
265
			log_error(gettext("Could not open shared memory {$reference}"));
266
			unlock($shm_lck);
267
			return;
268
		}
269
		$shm_data = @shmop_read($shmid, 0, 10);
270
		$shm_data = intval($shm_data) - 1;
271
		if ($shm_data < 0) {
272
			//debug_backtrace();
273
			log_error(sprintf(gettext("Reference %s is going negative, not doing unreference."), $reference));
274
		} else
275
			@shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
276
		@shmop_close($shmid);
277
		unlock($shm_lck);
278
	} catch (Exception $e) {
279
		log_error($e->getMessage());
280
		unlock($shm_lck);
281
	}
282

    
283
	return $shm_data;
284
}
285

    
286
function refcount_read($reference) {
287
	/* This function just reads the current value of the refcount for information. */
288
	/* There is no need for locking. */
289
	$shmid = @shmop_open($reference, "a", 0, 0);
290
	if (!$shmid) {
291
		log_error(gettext("Could not open shared memory for read {$reference}"));
292
		return -1;
293
	}
294
	$shm_data = @shmop_read($shmid, 0, 10);
295
	@shmop_close($shmid);
296
	return $shm_data;
297
}
298

    
299
function is_module_loaded($module_name) {
300
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
301
	if (intval($running) >= 1)
302
		return true;
303
	else
304
		return false;
305
}
306

    
307
/* validate non-negative numeric string, or equivalent numeric variable */
308
function is_numericint($arg) {
309
	return (((is_int($arg) && $arg >= 0) || (is_string($arg) && strlen($arg) > 0 && ctype_digit($arg))) ? true : false);  
310
}
311

    
312
/* return the subnet address given a host address and a subnet bit count */
313
function gen_subnet($ipaddr, $bits) {
314
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
315
		return "";
316
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
317
}
318

    
319
/* return the subnet address given a host address and a subnet bit count */
320
function gen_subnetv6($ipaddr, $bits) {
321
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
322
		return "";
323

    
324
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
325
	$address = Net_IPv6::compress($address);
326
	return $address;
327
}
328

    
329
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
330
function gen_subnet_max($ipaddr, $bits) {
331
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
332
		return "";
333

    
334
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
335
}
336

    
337
/* Generate end number for a given ipv6 subnet mask */
338
function gen_subnetv6_max($ipaddr, $bits) {
339
	if(!is_ipaddrv6($ipaddr))
340
		return false;
341

    
342
	$mask = Net_IPv6::getNetmask('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',$bits);
343

    
344
	$inet_ip = (binary)inet_pton($ipaddr);
345
	$inet_mask = (binary)inet_pton($mask);
346

    
347
	$inet_end = $inet_ip | ~$inet_mask;
348

    
349
	return (inet_ntop($inet_end));
350
}
351

    
352
/* returns a subnet mask (long given a bit count) */
353
function gen_subnet_mask_long($bits) {
354
	$sm = 0;
355
	for ($i = 0; $i < $bits; $i++) {
356
		$sm >>= 1;
357
		$sm |= 0x80000000;
358
	}
359
	return $sm;
360
}
361

    
362
/* same as above but returns a string */
363
function gen_subnet_mask($bits) {
364
	return long2ip(gen_subnet_mask_long($bits));
365
}
366

    
367
/* Convert long int to IP address, truncating to 32-bits. */
368
function long2ip32($ip) {
369
	return long2ip($ip & 0xFFFFFFFF);
370
}
371

    
372
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
373
function ip2long32($ip) {
374
	return ( ip2long($ip) & 0xFFFFFFFF );
375
}
376

    
377
/* Convert IP address to unsigned long int. */
378
function ip2ulong($ip) {
379
	return sprintf("%u", ip2long32($ip));
380
}
381

    
382
/* Find out how many IPs are contained within a given IP range
383
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
384
 */
385
function ip_range_size($startip, $endip) {
386
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
387
		// Operate as unsigned long because otherwise it wouldn't work
388
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
389
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
390
	}
391
	return -1;
392
}
393

    
394
/* Find the smallest possible subnet mask which can contain a given number of IPs
395
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
396
 */
397
function find_smallest_cidr($number) {
398
	$smallest = 1;
399
	for ($b=32; $b > 0; $b--) {
400
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
401
	}
402
	return (32-$smallest);
403
}
404

    
405
/* Return the previous IP address before the given address */
406
function ip_before($ip) {
407
	return long2ip32(ip2long($ip)-1);
408
}
409

    
410
/* Return the next IP address after the given address */
411
function ip_after($ip) {
412
	return long2ip32(ip2long($ip)+1);
413
}
414

    
415
/* Return true if the first IP is 'before' the second */
416
function ip_less_than($ip1, $ip2) {
417
	// Compare as unsigned long because otherwise it wouldn't work when
418
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
419
	return ip2ulong($ip1) < ip2ulong($ip2);
420
}
421

    
422
/* Return true if the first IP is 'after' the second */
423
function ip_greater_than($ip1, $ip2) {
424
	// Compare as unsigned long because otherwise it wouldn't work
425
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
426
	return ip2ulong($ip1) > ip2ulong($ip2);
427
}
428

    
429
/* Convert a range of IPs to an array of subnets which can contain the range. */
430
function ip_range_to_subnet_array($startip, $endip) {
431
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
432
		return array();
433
	}
434

    
435
	// Container for subnets within this range.
436
	$rangesubnets = array();
437

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

    
441
	// Loop here to reduce subnet size and retest as needed. We need to make sure
442
	//   that the target subnet is wholly contained between $startip and $endip.
443
	for ($cidr; $cidr <= 32; $cidr++) {
444
		// Find the network and broadcast addresses for the subnet being tested.
445
		$targetsub_min = gen_subnet($startip, $cidr);
446
		$targetsub_max = gen_subnet_max($startip, $cidr);
447

    
448
		// Check best case where the range is exactly one subnet.
449
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
450
			// Hooray, the range is exactly this subnet!
451
			return array("{$startip}/{$cidr}");
452
		}
453

    
454
		// These remaining scenarios will find a subnet that uses the largest
455
		//  chunk possible of the range being tested, and leave the rest to be
456
		//  tested recursively after the loop.
457

    
458
		// Check if the subnet begins with $startip and ends before $endip
459
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
460
			break;
461
		}
462

    
463
		// Check if the subnet ends at $endip and starts after $startip
464
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
465
			break;
466
		}
467

    
468
		// Check if the subnet is between $startip and $endip
469
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
470
			break;
471
		}
472
	}
473

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

    
480
	// Add in the subnet we found before, to preserve ordering
481
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
482

    
483
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
484
	if ($endip != $targetsub_max) {
485
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
486
	}
487
	return $rangesubnets;
488
}
489

    
490
function is_iprange($range) {
491
	if (substr_count($range, '-') != 1) {
492
		return false;
493
	}
494
	list($ip1, $ip2) = explode ('-', $range);
495
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
496
}
497

    
498
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
499
function is_ipaddr($ipaddr) {
500
	if(is_ipaddrv4($ipaddr)) {
501
		return true;
502
	}
503
	if(is_ipaddrv6($ipaddr)) {
504
		return true;
505
	}
506
	return false;
507
}
508

    
509
/* returns true if $ipaddr is a valid IPv6 address */
510
function is_ipaddrv6($ipaddr) {
511
	if (!is_string($ipaddr) || empty($ipaddr))
512
		return false;
513
	if (strstr($ipaddr, "%") && is_linklocal($ipaddr)) {
514
		$tmpip = explode("%", $ipaddr);
515
		$ipaddr = $tmpip[0];
516
	}
517
	return Net_IPv6::checkIPv6($ipaddr);
518
}
519

    
520
/* returns true if $ipaddr is a valid dotted IPv4 address */
521
function is_ipaddrv4($ipaddr) {
522
	if (!is_string($ipaddr) || empty($ipaddr))
523
		return false;
524

    
525
	$ip_long = ip2long($ipaddr);
526
	$ip_reverse = long2ip32($ip_long);
527

    
528
	if ($ipaddr == $ip_reverse)
529
		return true;
530
	else
531
		return false;
532
}
533

    
534
/* returns true if $ipaddr is a valid linklocal address */
535
function is_linklocal($ipaddr) {
536
	return (substr($ipaddr, 0, 5) == "fe80:");
537
}
538

    
539
/* returns scope of a linklocal address */
540
function get_ll_scope($addr) {
541
	if (!is_linklocal($addr) || !strstr($addr, "%"))
542
		return "";
543
	list ($ll, $scope) = explode("%", $addr);
544
	return $scope;
545
}
546

    
547
/* returns true if $ipaddr is a valid literal IPv6 address */
548
function is_literalipaddrv6($ipaddr) {
549
	if(preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match))
550
		$ipaddr = $match[1];
551
	else
552
		return false;
553

    
554
	return is_ipaddrv6($ipaddr);
555
}
556

    
557
function is_ipaddrwithport($ipport) {
558
	$parts = explode(":", $ipport);
559
	$port = array_pop($parts);
560
	if (count($parts) == 1) {
561
		return is_ipaddrv4($parts[0]) && is_port($port);
562
	} elseif (count($parts) > 1) {
563
		return is_literalipaddrv6(implode(":", $parts)) && is_port($port);
564
	} else {
565
		return false;
566
	}
567
}
568

    
569
function is_hostnamewithport($hostport) {
570
	$parts = explode(":", $hostport);
571
	$port = array_pop($parts);
572
	if (count($parts) == 1) {
573
		return is_hostname($parts[0]) && is_port($port);
574
	} else {
575
		return false;
576
	}
577
}
578

    
579
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
580
function is_ipaddroralias($ipaddr) {
581
	global $config;
582

    
583
	if (is_alias($ipaddr)) {
584
		if (is_array($config['aliases']['alias'])) {
585
			foreach ($config['aliases']['alias'] as $alias) {
586
				if ($alias['name'] == $ipaddr && !preg_match("/port/i", $alias['type']))
587
					return true;
588
			}
589
		}
590
		return false;
591
	} else
592
		return is_ipaddr($ipaddr);
593

    
594
}
595

    
596
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format
597
   	false - if not a valid subnet
598
   	true (numeric 4 or 6) - if valid, gives type of subnet */
599
function is_subnet($subnet) {
600
	if (is_string($subnet) && preg_match('/^(?:([0-9.]{7,15})|([0-9a-f:]{2,39}))\/(\d{1,3})$/i', $subnet, $parts)) {
601
		if (is_ipaddrv4($parts[1]) && $parts[3] <= 32)
602
			return 4;
603
		if (is_ipaddrv6($parts[2]) && $parts[3] <= 128)
604
			return 6;
605
	}
606
	return false;
607
}
608

    
609
/* same as is_subnet() but accepts IPv4 only */
610
function is_subnetv4($subnet) {
611
	return (is_subnet($subnet) == 4);
612
}
613

    
614
/* same as is_subnet() but accepts IPv6 only */
615
function is_subnetv6($subnet) {
616
	return (is_subnet($subnet) == 6);
617
}
618

    
619
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
620
function is_subnetoralias($subnet) {
621
	global $aliastable;
622

    
623
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
624
		return true;
625
	else
626
		return is_subnet($subnet);
627
}
628

    
629
/* returns true if $hostname is a valid hostname */
630
function is_hostname($hostname) {
631
	if (!is_string($hostname))
632
		return false;
633

    
634
	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))
635
		return true;
636
	else
637
		return false;
638
}
639

    
640
/* returns true if $domain is a valid domain name */
641
function is_domain($domain) {
642
	if (!is_string($domain))
643
		return false;
644

    
645
	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))
646
		return true;
647
	else
648
		return false;
649
}
650

    
651
/* returns true if $macaddr is a valid MAC address */
652
function is_macaddr($macaddr, $partial=false) {
653
	$repeat = ($partial) ? '1,5' : '5';
654
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
655
}
656

    
657
/* returns true if $name is a valid name for an alias */
658
/* returns NULL if a reserved word is used */
659
function is_validaliasname($name) {
660
	/* Array of reserved words */
661
	$reserved = array("port", "pass");
662
	if (in_array($name, $reserved, true))
663
		return; /* return NULL */
664
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
665
		return true;
666
	else
667
		return false;
668
}
669

    
670
/* returns true if $port is a valid TCP/UDP port */
671
function is_port($port) {
672
	$tmpports = explode(":", $port);
673
	foreach($tmpports as $tmpport) {
674
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
675
			continue;
676
		if (!ctype_digit($tmpport))
677
			return false;
678
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
679
			return false;
680
	}
681
	return true;
682
}
683

    
684
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
685
function is_portrange($portrange) {
686
	$ports = explode(":", $portrange);
687

    
688
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
689
}
690

    
691
/* returns true if $port is a valid port number or an alias thereof */
692
function is_portoralias($port) {
693
	global $config;
694

    
695
	if (is_alias($port)) {
696
		if (is_array($config['aliases']['alias'])) {
697
			foreach ($config['aliases']['alias'] as $alias) {
698
				if ($alias['name'] == $port && preg_match("/port/i", $alias['type']))
699
					return true;
700
				}
701
			}
702
			return false;
703
	} else
704
		return is_port($port);
705
}
706

    
707
/* create ranges of sequential port numbers (200:215) and remove duplicates */
708
function group_ports($ports) {
709
	if (!is_array($ports) || empty($ports))
710
		return;
711

    
712
	$uniq = array();
713
	foreach ($ports as $port) {
714
		if (is_portrange($port)) {
715
			list($begin, $end) = explode(":", $port);
716
			if ($begin > $end) {
717
				$aux = $begin;
718
				$begin = $end;
719
				$end = $aux;
720
			}
721
			for ($i = $begin; $i <= $end; $i++)
722
				if (!in_array($i, $uniq))
723
					$uniq[] = $i;
724
		} else if (is_port($port)) {
725
			if (!in_array($port, $uniq))
726
				$uniq[] = $port;
727
		}
728
	}
729
	sort($uniq, SORT_NUMERIC);
730

    
731
	$result = array();
732
	foreach ($uniq as $idx => $port) {
733
		if ($idx == 0) {
734
			$result[] = $port;
735
			continue;
736
		}
737

    
738
		$last = end($result);
739
		if (is_portrange($last))
740
			list($begin, $end) = explode(":", $last);
741
		else
742
			$begin = $end = $last;
743

    
744
		if ($port == ($end+1)) {
745
			$end++;
746
			$result[count($result)-1] = "{$begin}:{$end}";
747
		} else {
748
			$result[] = $port;
749
		}
750
	}
751

    
752
	return $result;
753
}
754

    
755
/* returns true if $val is a valid shaper bandwidth value */
756
function is_valid_shaperbw($val) {
757
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
758
}
759

    
760
/* returns true if $test is in the range between $start and $end */
761
function is_inrange_v4($test, $start, $end) {
762
	if ( (ip2ulong($test) <= ip2ulong($end)) && (ip2ulong($test) >= ip2ulong($start)) )
763
		return true;
764
	else
765
		return false;
766
}
767

    
768
/* returns true if $test is in the range between $start and $end */
769
function is_inrange_v6($test, $start, $end) {
770
	if ( (inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start)) )
771
		return true;
772
	else
773
		return false;
774
}
775

    
776
/* returns true if $test is in the range between $start and $end */
777
function is_inrange($test, $start, $end) {
778
	return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
779
}
780

    
781
/* XXX: return the configured carp interface list */
782
function get_configured_carp_interface_list($carpinterface = "", $family = "inet") {
783
	global $config;
784

    
785
	$iflist = array();
786

    
787
	if(is_array($config['virtualip']['vip'])) {
788
		$viparr = &$config['virtualip']['vip'];
789
		foreach ($viparr as $vip) {
790
			switch ($vip['mode']) {
791
			case "carp":
792
				if (!empty($carpinterface)) {
793
					if ($carpinterface == "{$vip['interface']}_vip{$vip['vhid']}") {
794
						if ($family == "inet" && is_ipaddrv4($vip['subnet']))
795
							return $vip['subnet'];
796
						else if ($family == "inet6" && is_ipaddrv6($vip['subnet']))
797
							return $vip['subnet'];
798
					}
799
				} else {
800
					$iflist["{$vip['interface']}_vip{$vip['vhid']}"] = $vip['subnet'];
801
				}
802
				break;
803
			}
804
		}
805
	}
806

    
807
	return $iflist;
808
}
809

    
810
/* return the configured IP aliases list */
811
function get_configured_ip_aliases_list($returnfullentry = false) {
812
	global $config;
813

    
814
	$alias_list=array();
815

    
816
	if(is_array($config['virtualip']['vip'])) {
817
		$viparr = &$config['virtualip']['vip'];
818
		foreach ($viparr as $vip) {
819
			if ($vip['mode']=="ipalias") {
820
				if ($returnfullentry)
821
					$alias_list[$vip['subnet']] = $vip;
822
				else
823
					$alias_list[$vip['subnet']] = $vip['interface'];
824
			}
825
		}
826
	}
827

    
828
	return $alias_list;
829
}
830

    
831
/* return all configured aliases list (IP, carp, proxyarp and other) */
832
function get_configured_vips_list() {
833
	global $config;
834

    
835
	$alias_list=array();
836

    
837
	if(is_array($config['virtualip']['vip'])) {
838
		$viparr = &$config['virtualip']['vip'];
839
		foreach ($viparr as $vip) {
840
			if ($vip['mode'] == "carp")
841
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => "{$vip['interface']}_vip{$vip['vhid']}");
842
			else
843
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
844
		}
845
	}
846

    
847
	return $alias_list;
848
}
849

    
850
/* comparison function for sorting by the order in which interfaces are normally created */
851
function compare_interface_friendly_names($a, $b) {
852
	if ($a == $b)
853
		return 0;
854
	else if ($a == 'wan')
855
		return -1;
856
	else if ($b == 'wan')
857
		return 1;
858
	else if ($a == 'lan')
859
		return -1;
860
	else if ($b == 'lan')
861
		return 1;
862

    
863
	return strnatcmp($a, $b);
864
}
865

    
866
/* return the configured interfaces list. */
867
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
868
	global $config;
869

    
870
	$iflist = array();
871

    
872
	/* if list */
873
	foreach($config['interfaces'] as $if => $ifdetail) {
874
		if ($only_opt && ($if == "wan" || $if == "lan"))
875
			continue;
876
		if (isset($ifdetail['enable']) || $withdisabled == true)
877
			$iflist[$if] = $if;
878
	}
879

    
880
	return $iflist;
881
}
882

    
883
/* return the configured interfaces list. */
884
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
885
	global $config;
886

    
887
	$iflist = array();
888

    
889
	/* if list */
890
	foreach($config['interfaces'] as $if => $ifdetail) {
891
		if ($only_opt && ($if == "wan" || $if == "lan"))
892
			continue;
893
		if (isset($ifdetail['enable']) || $withdisabled == true) {
894
			$tmpif = get_real_interface($if);
895
			if (!empty($tmpif))
896
				$iflist[$tmpif] = $if;
897
		}
898
	}
899

    
900
	return $iflist;
901
}
902

    
903
/* return the configured interfaces list with their description. */
904
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
905
	global $config;
906

    
907
	$iflist = array();
908

    
909
	/* if list */
910
	foreach($config['interfaces'] as $if => $ifdetail) {
911
		if ($only_opt && ($if == "wan" || $if == "lan"))
912
			continue;
913
		if (isset($ifdetail['enable']) || $withdisabled == true) {
914
			if(empty($ifdetail['descr']))
915
				$iflist[$if] = strtoupper($if);
916
			else
917
				$iflist[$if] = strtoupper($ifdetail['descr']);
918
		}
919
	}
920

    
921
	return $iflist;
922
}
923

    
924
/*
925
 *   get_configured_ip_addresses() - Return a list of all configured
926
 *   interfaces IP Addresses
927
 *
928
 */
929
function get_configured_ip_addresses() {
930
	global $config;
931

    
932
	if (!function_exists('get_interface_ip'))
933
		require_once("interfaces.inc");
934
	$ip_array = array();
935
	$interfaces = get_configured_interface_list();
936
	if (is_array($interfaces)) {
937
		foreach($interfaces as $int) {
938
			$ipaddr = get_interface_ip($int);
939
			$ip_array[$int] = $ipaddr;
940
		}
941
	}
942
	$interfaces = get_configured_carp_interface_list();
943
	if (is_array($interfaces))
944
		foreach($interfaces as $int => $ipaddr)
945
			$ip_array[$int] = $ipaddr;
946

    
947
	/* pppoe server */
948
	if (is_array($config['pppoes']) && is_array($config['pppoes']['pppoe'])) {
949
		foreach($config['pppoes']['pppoe'] as $pppoe) {
950
			if ($pppoe['mode'] == "server") {
951
				if(is_ipaddr($pppoe['localip'])) {
952
					$int = "pppoes". $pppoe['pppoeid'];
953
					$ip_array[$int] = $pppoe['localip'];
954
				}
955
			}
956
		}
957
	}
958

    
959
	return $ip_array;
960
}
961

    
962
/*
963
 *   get_configured_ipv6_addresses() - Return a list of all configured
964
 *   interfaces IPv6 Addresses
965
 *
966
 */
967
function get_configured_ipv6_addresses() {
968
	require_once("interfaces.inc");
969
	$ipv6_array = array();
970
	$interfaces = get_configured_interface_list();
971
	if(is_array($interfaces)) {
972
		foreach($interfaces as $int) {
973
			$ipaddrv6 = get_interface_ipv6($int);
974
			$ipv6_array[$int] = $ipaddrv6;
975
		}
976
	}
977
	$interfaces = get_configured_carp_interface_list();
978
	if(is_array($interfaces))
979
		foreach($interfaces as $int => $ipaddrv6)
980
			$ipv6_array[$int] = $ipaddrv6;
981
	return $ipv6_array;
982
}
983

    
984
/*
985
 *   get_interface_list() - Return a list of all physical interfaces
986
 *   along with MAC and status.
987
 *
988
 *   $mode = "active" - use ifconfig -lu
989
 *           "media"  - use ifconfig to check physical connection
990
 *			status (much slower)
991
 */
992
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
993
	global $config;
994
	$upints = array();
995
	/* get a list of virtual interface types */
996
	if(!$vfaces) {
997
		$vfaces = array (
998
				'bridge',
999
				'ppp',
1000
				'pppoe',
1001
				'pptp',
1002
				'l2tp',
1003
				'sl',
1004
				'gif',
1005
				'gre',
1006
				'faith',
1007
				'lo',
1008
				'ng',
1009
				'_vlan',
1010
				'_wlan',
1011
				'pflog',
1012
				'plip',
1013
				'pfsync',
1014
				'enc',
1015
				'tun',
1016
				'carp',
1017
				'lagg',
1018
				'vip',
1019
				'ipfw'
1020
		);
1021
	}
1022
	switch($mode) {
1023
	case "active":
1024
		$upints = pfSense_interface_listget(IFF_UP);
1025
		break;
1026
	case "media":
1027
		$intlist = pfSense_interface_listget();
1028
		$ifconfig = "";
1029
		exec("/sbin/ifconfig -a", $ifconfig);
1030
		$regexp = '/(' . implode('|', $intlist) . '):\s/';
1031
		$ifstatus = preg_grep('/status:/', $ifconfig);
1032
		foreach($ifstatus as $status) {
1033
			$int = array_shift($intlist);
1034
			if(stristr($status, "active")) $upints[] = $int;
1035
		}
1036
		break;
1037
	default:
1038
		$upints = pfSense_interface_listget();
1039
		break;
1040
	}
1041
	/* build interface list with netstat */
1042
	$linkinfo = "";
1043
	exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
1044
	array_shift($linkinfo);
1045
	/* build ip address list with netstat */
1046
	$ipinfo = "";
1047
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
1048
	array_shift($ipinfo);
1049
	foreach($linkinfo as $link) {
1050
		$friendly = "";
1051
		$alink = explode(" ", $link);
1052
		$ifname = rtrim(trim($alink[0]), '*');
1053
		/* trim out all numbers before checking for vfaces */
1054
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
1055
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
1056
			$toput = array(
1057
					"mac" => trim($alink[1]),
1058
					"up" => in_array($ifname, $upints)
1059
				);
1060
			foreach($ipinfo as $ip) {
1061
				$aip = explode(" ", $ip);
1062
				if($aip[0] == $ifname) {
1063
					$toput['ipaddr'] = $aip[1];
1064
				}
1065
			}
1066
			if (is_array($config['interfaces'])) {
1067
				foreach($config['interfaces'] as $name => $int)
1068
					if($int['if'] == $ifname) $friendly = $name;
1069
			}
1070
			switch($keyby) {
1071
			case "physical":
1072
				if($friendly != "") {
1073
					$toput['friendly'] = $friendly;
1074
				}
1075
				$dmesg_arr = array();
1076
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
1077
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
1078
				$toput['dmesg'] = $dmesg[1][0];
1079
				$iflist[$ifname] = $toput;
1080
				break;
1081
			case "ppp":
1082

    
1083
			case "friendly":
1084
				if($friendly != "") {
1085
					$toput['if'] = $ifname;
1086
					$iflist[$friendly] = $toput;
1087
				}
1088
				break;
1089
			}
1090
		}
1091
	}
1092
	return $iflist;
1093
}
1094

    
1095
/****f* util/log_error
1096
* NAME
1097
*   log_error  - Sends a string to syslog.
1098
* INPUTS
1099
*   $error     - string containing the syslog message.
1100
* RESULT
1101
*   null
1102
******/
1103
function log_error($error) {
1104
	global $g;
1105
	$page = $_SERVER['SCRIPT_NAME'];
1106
	if (empty($page)) {
1107
		$files = get_included_files();
1108
		$page = basename($files[0]);
1109
	}
1110
	syslog(LOG_ERR, "$page: $error");
1111
	if ($g['debug'])
1112
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1113
	return;
1114
}
1115

    
1116
/****f* util/log_auth
1117
* NAME
1118
*   log_auth   - Sends a string to syslog as LOG_AUTH facility
1119
* INPUTS
1120
*   $error     - string containing the syslog message.
1121
* RESULT
1122
*   null
1123
******/
1124
function log_auth($error) {
1125
	global $g;
1126
	$page = $_SERVER['SCRIPT_NAME'];
1127
	syslog(LOG_AUTH, "$page: $error");
1128
	if ($g['debug'])
1129
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1130
	return;
1131
}
1132

    
1133
/****f* util/exec_command
1134
 * NAME
1135
 *   exec_command - Execute a command and return a string of the result.
1136
 * INPUTS
1137
 *   $command   - String of the command to be executed.
1138
 * RESULT
1139
 *   String containing the command's result.
1140
 * NOTES
1141
 *   This function returns the command's stdout and stderr.
1142
 ******/
1143
function exec_command($command) {
1144
	$output = array();
1145
	exec($command . ' 2>&1', $output);
1146
	return(implode("\n", $output));
1147
}
1148

    
1149
/* wrapper for exec() */
1150
function mwexec($command, $mute = false, $clearsigmask = false) {
1151
	global $g;
1152

    
1153
	if ($g['debug']) {
1154
		if (!$_SERVER['REMOTE_ADDR'])
1155
			echo "mwexec(): $command\n";
1156
	}
1157
	$oarr = array();
1158
	$retval = 0;
1159

    
1160
	if ($clearsigmask) {
1161
		$oldset = array();
1162
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1163
	}
1164
	$garbage = exec("$command 2>&1", $oarr, $retval);
1165
	if ($clearsigmask) {
1166
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1167
	}
1168

    
1169
	if(isset($config['system']['developerspew']))
1170
		$mute = false;
1171
	if(($retval <> 0) && ($mute === false)) {
1172
		$output = implode(" ", $oarr);
1173
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
1174
		unset($output);
1175
	}
1176
	unset($oarr);
1177
	return $retval;
1178
}
1179

    
1180
/* wrapper for exec() in background */
1181
function mwexec_bg($command, $clearsigmask = false) {
1182
	global $g;
1183

    
1184
	if ($g['debug']) {
1185
		if (!$_SERVER['REMOTE_ADDR'])
1186
			echo "mwexec(): $command\n";
1187
	}
1188

    
1189
	if ($clearsigmask) {
1190
		$oldset = array();
1191
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1192
	}
1193
	$_gb = exec("/usr/bin/nohup $command > /dev/null 2>&1 &");
1194
	if ($clearsigmask) {
1195
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1196
	}
1197
	unset($_gb);
1198
}
1199

    
1200
/* unlink a file, if it exists */
1201
function unlink_if_exists($fn) {
1202
	$to_do = glob($fn);
1203
	if(is_array($to_do)) {
1204
		foreach($to_do as $filename)
1205
			@unlink($filename);
1206
	} else {
1207
		@unlink($fn);
1208
	}
1209
}
1210
/* make a global alias table (for faster lookups) */
1211
function alias_make_table($config) {
1212
	global $aliastable;
1213

    
1214
	$aliastable = array();
1215

    
1216
	if (is_array($config['aliases']['alias'])) {
1217
		foreach ($config['aliases']['alias'] as $alias) {
1218
			if ($alias['name'])
1219
				$aliastable[$alias['name']] = $alias['address'];
1220
		}
1221
	}
1222
}
1223

    
1224
/* check if an alias exists */
1225
function is_alias($name) {
1226
	global $aliastable;
1227

    
1228
	return isset($aliastable[$name]);
1229
}
1230

    
1231
function alias_get_type($name) {
1232
	global $config;
1233

    
1234
	if (is_array($config['aliases']['alias'])) {
1235
		foreach ($config['aliases']['alias'] as $alias) {
1236
			if ($name == $alias['name'])
1237
				return $alias['type'];
1238
		}
1239
	}
1240

    
1241
	return "";
1242
}
1243

    
1244
/* expand a host or network alias, if necessary */
1245
function alias_expand($name) {
1246
	global $aliastable;
1247

    
1248
	if (isset($aliastable[$name]))
1249
		return "\${$name}";
1250
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1251
		return "{$name}";
1252
	else
1253
		return null;
1254
}
1255

    
1256
function alias_expand_urltable($name) {
1257
	global $config;
1258
	$urltable_prefix = "/var/db/aliastables/";
1259
	$urltable_filename = $urltable_prefix . $name . ".txt";
1260

    
1261
	if (is_array($config['aliases']['alias'])) {
1262
		foreach ($config['aliases']['alias'] as $alias) {
1263
			if (preg_match("/urltable/i", $alias['type']) && ($alias['name'] == $name)) {
1264
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1265
					return $urltable_filename;
1266
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1267
					return $urltable_filename;
1268
			}
1269
		}
1270
	}
1271
	return null;
1272
}
1273

    
1274
function subnet_size($subnet) {
1275
	if (is_subnetv4($subnet)) {
1276
		list ($ip, $bits) = explode("/", $subnet);
1277
		return round(exp(log(2) * (32 - $bits)));
1278
	}
1279
	else if (is_subnetv6($subnet)) {
1280
		list ($ip, $bits) = explode("/", $subnet);
1281
		return round(exp(log(2) * (128 - $bits)));
1282
	}
1283
	else {
1284
		return 0;
1285
	}
1286
}
1287

    
1288
function subnet_expand($subnet) {
1289
	if (is_subnetv4($subnet)) {
1290
		return subnetv4_expand($subnet);
1291
	} else if (is_subnetv6($subnet)) {
1292
		return subnetv6_expand($subnet);
1293
	} else {
1294
		return $subnet;
1295
	}
1296
}
1297

    
1298
function subnetv4_expand($subnet) {
1299
	$result = array();
1300
	list ($ip, $bits) = explode("/", $subnet);
1301
	$net  = ip2long($ip);
1302
	$mask = (0xffffffff << (32 - $bits));
1303
	$net &= $mask;
1304
	$size = round(exp(log(2) * (32 - $bits)));
1305
	for ($i = 0; $i < $size; $i += 1) {
1306
		$result[] = long2ip($net | $i);
1307
	}
1308
	return $result;
1309
}
1310

    
1311
/* find out whether two subnets overlap */
1312
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1313

    
1314
	if (!is_numeric($bits1))
1315
		$bits1 = 32;
1316
	if (!is_numeric($bits2))
1317
		$bits2 = 32;
1318

    
1319
	if ($bits1 < $bits2)
1320
		$relbits = $bits1;
1321
	else
1322
		$relbits = $bits2;
1323

    
1324
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1325
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1326

    
1327
	return ($sn1 == $sn2);
1328
}
1329

    
1330
/* find out whether two IPv6 subnets overlap */
1331
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
1332
	$sub1_min = gen_subnetv6($subnet1, $bits1);
1333
	$sub1_max = gen_subnetv6_max($subnet1, $bits1);
1334
	$sub2_min = gen_subnetv6($subnet2, $bits2);
1335
	$sub2_max = gen_subnetv6_max($subnet2, $bits2);
1336

    
1337
	return (is_inrange_v6($sub1_min, $sub2_min, $sub2_max) || is_inrange_v6($sub1_max, $sub2_min, $sub2_max) || is_inrange_v6($sub2_min, $sub1_min, $sub1_max));
1338
}
1339

    
1340
/* compare two IP addresses */
1341
function ipcmp($a, $b) {
1342
	if (ip_less_than($a, $b))
1343
		return -1;
1344
	else if (ip_greater_than($a, $b))
1345
		return 1;
1346
	else
1347
		return 0;
1348
}
1349

    
1350
/* return true if $addr is in $subnet, false if not */
1351
function ip_in_subnet($addr,$subnet) {
1352
	if(is_ipaddrv6($addr)) {
1353
		return (Net_IPv6::isInNetmask($addr, $subnet));
1354
	} else { /* XXX: Maybe check for IPv4 */
1355
		list($ip, $mask) = explode('/', $subnet);
1356
		$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1357
		return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1358
	}
1359
}
1360

    
1361
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1362
function verify_digital_signature($fname) {
1363
	global $g;
1364

    
1365
	if(!file_exists("/usr/local/sbin/gzsig"))
1366
		return 4;
1367

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

    
1371
/* obtain MAC address given an IP address by looking at the ARP table */
1372
function arp_get_mac_by_ip($ip) {
1373
	mwexec("/sbin/ping -c 1 -t 1 " . escapeshellarg($ip), true);
1374
	$arpoutput = "";
1375
	exec("/usr/sbin/arp -n " . escapeshellarg($ip), $arpoutput);
1376

    
1377
	if ($arpoutput[0]) {
1378
		$arpi = explode(" ", $arpoutput[0]);
1379
		$macaddr = $arpi[3];
1380
		if (is_macaddr($macaddr))
1381
			return $macaddr;
1382
		else
1383
			return false;
1384
	}
1385

    
1386
	return false;
1387
}
1388

    
1389
/* return a fieldname that is safe for xml usage */
1390
function xml_safe_fieldname($fieldname) {
1391
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1392
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1393
			 ':', ',', '.', '\'', '\\'
1394
		);
1395
	return strtolower(str_replace($replace, "", $fieldname));
1396
}
1397

    
1398
function mac_format($clientmac) {
1399
	global $config, $cpzone;
1400

    
1401
	$mac = explode(":", $clientmac);
1402
	$mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1403

    
1404
	switch($mac_format) {
1405
	case 'singledash':
1406
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1407

    
1408
	case 'ietf':
1409
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1410

    
1411
	case 'cisco':
1412
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1413

    
1414
	case 'unformatted':
1415
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1416

    
1417
	default:
1418
		return $clientmac;
1419
	}
1420
}
1421

    
1422
function resolve_retry($hostname, $retries = 5) {
1423

    
1424
	if (is_ipaddr($hostname))
1425
		return $hostname;
1426

    
1427
	for ($i = 0; $i < $retries; $i++) {
1428
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1429
		$ip = gethostbyname($hostname);
1430

    
1431
		if ($ip && $ip != $hostname) {
1432
			/* success */
1433
			return $ip;
1434
		}
1435

    
1436
		sleep(1);
1437
	}
1438

    
1439
	return false;
1440
}
1441

    
1442
function format_bytes($bytes) {
1443
	if ($bytes >= 1073741824) {
1444
		return sprintf("%.2f GB", $bytes/1073741824);
1445
	} else if ($bytes >= 1048576) {
1446
		return sprintf("%.2f MB", $bytes/1048576);
1447
	} else if ($bytes >= 1024) {
1448
		return sprintf("%.0f KB", $bytes/1024);
1449
	} else {
1450
		return sprintf("%d bytes", $bytes);
1451
	}
1452
}
1453

    
1454
function update_filter_reload_status($text) {
1455
	global $g;
1456

    
1457
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1458
}
1459

    
1460
/****** util/return_dir_as_array
1461
 * NAME
1462
 *   return_dir_as_array - Return a directory's contents as an array.
1463
 * INPUTS
1464
 *   $dir          - string containing the path to the desired directory.
1465
 *   $filter_regex - string containing a regular expression to filter file names. Default empty.
1466
 * RESULT
1467
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1468
 ******/
1469
function return_dir_as_array($dir, $filter_regex = '') {
1470
	$dir_array = array();
1471
	if (is_dir($dir)) {
1472
		if ($dh = opendir($dir)) {
1473
			while (($file = readdir($dh)) !== false) {
1474
				if (($file == ".") || ($file == ".."))
1475
					continue;
1476

    
1477
				if (empty($filter_regex) || preg_match($filter_regex, $file))
1478
					array_push($dir_array, $file);
1479
			}
1480
			closedir($dh);
1481
		}
1482
	}
1483
	return $dir_array;
1484
}
1485

    
1486
function run_plugins($directory) {
1487
	global $config, $g;
1488

    
1489
	/* process packager manager custom rules */
1490
	$files = return_dir_as_array($directory);
1491
	if (is_array($files)) {
1492
		foreach ($files as $file) {
1493
			if (stristr($file, ".sh") == true)
1494
				mwexec($directory . $file . " start");
1495
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc"))
1496
				require_once($directory . "/" . $file);
1497
		}
1498
	}
1499
}
1500

    
1501
/*
1502
 *    safe_mkdir($path, $mode = 0755)
1503
 *    create directory if it doesn't already exist and isn't a file!
1504
 */
1505
function safe_mkdir($path, $mode=0755) {
1506
	global $g;
1507

    
1508
	if (!is_file($path) && !is_dir($path)) {
1509
		return @mkdir($path, $mode, true);
1510
	} else {
1511
		return false;
1512
	}
1513
}
1514

    
1515
/*
1516
 * make_dirs($path, $mode = 0755)
1517
 * create directory tree recursively (mkdir -p)
1518
 */
1519
function make_dirs($path, $mode = 0755) {
1520
	$base = '';
1521
	foreach (explode('/', $path) as $dir) {
1522
		$base .= "/$dir";
1523
		if (!is_dir($base)) {
1524
			if (!@mkdir($base, $mode))
1525
				return false;
1526
		}
1527
	}
1528
	return true;
1529
}
1530

    
1531
/*
1532
 * get_sysctl($names)
1533
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1534
 * name) and return an array of key/value pairs set for those that exist
1535
 */
1536
function get_sysctl($names) {
1537
	if (empty($names))
1538
		return array();
1539

    
1540
	if (is_array($names)) {
1541
		$name_list = array();
1542
		foreach ($names as $name) {
1543
			$name_list[] = escapeshellarg($name);
1544
		}
1545
	} else
1546
		$name_list = array(escapeshellarg($names));
1547

    
1548
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1549
	$values = array();
1550
	foreach ($output as $line) {
1551
		$line = explode(": ", $line, 2);
1552
		if (count($line) == 2)
1553
			$values[$line[0]] = $line[1];
1554
	}
1555

    
1556
	return $values;
1557
}
1558

    
1559
/*
1560
 * set_sysctl($value_list)
1561
 * Set sysctl OID's listed as key/value pairs and return
1562
 * an array with keys set for those that succeeded
1563
 */
1564
function set_sysctl($values) {
1565
	if (empty($values))
1566
		return array();
1567

    
1568
	$value_list = array();
1569
	foreach ($values as $key => $value) {
1570
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1571
	}
1572

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

    
1575
	/* Retry individually if failed (one or more read-only) */
1576
	if ($success <> 0 && count($value_list) > 1) {
1577
		foreach ($value_list as $value) {
1578
			exec("/sbin/sysctl -i " . $value, $output);
1579
		}
1580
	}
1581

    
1582
	$ret = array();
1583
	foreach ($output as $line) {
1584
		$line = explode(": ", $line, 2);
1585
		if (count($line) == 2)
1586
			$ret[$line[0]] = true;
1587
	}
1588

    
1589
	return $ret;
1590
}
1591

    
1592
/*
1593
 *     get_memory()
1594
 *     returns an array listing the amount of
1595
 *     memory installed in the hardware
1596
 *     [0] net memory available for the OS (FreeBSD) after some is taken by BIOS, video or whatever - e.g. 235 MBytes
1597
 *     [1] real (actual) memory of the system, should be the size of the RAM card/s - e.g. 256 MBytes
1598
 */
1599
function get_memory() {
1600

    
1601
	$output = "";
1602
	$_gb = exec("/sbin/sysctl -n hw.physmem", $output);
1603
	$physmem = trim($output[0], " \n");
1604
	unset($output);
1605
	$_gb = exec("/sbin/sysctl -n hw.physmem", $output);
1606
	$realmem = trim($output[0], " \n");
1607
	unset($output, $_gb);
1608
	/* convert from bytes to megabytes */
1609
	return array(($physmem/1048576),($realmem/1048576));
1610
}
1611

    
1612
function mute_kernel_msgs() {
1613
	global $config;
1614
	// Do not mute serial console.  The kernel gets very very cranky
1615
	// and will start dishing you cannot control tty errors.
1616
	switch (trim(file_get_contents("/etc/platform"))) {
1617
		case "nanobsd":
1618
		case "jail":
1619
			return;
1620
	}
1621
	if($config['system']['enableserial'])
1622
		return;
1623
	exec("/sbin/conscontrol mute on");
1624
}
1625

    
1626
function unmute_kernel_msgs() {
1627
	global $config;
1628
	// Do not mute serial console.  The kernel gets very very cranky
1629
	// and will start dishing you cannot control tty errors.
1630
	switch (trim(file_get_contents("/etc/platform"))) {
1631
		case "nanobsd":
1632
		case "jail":
1633
			return;
1634
	}
1635
	exec("/sbin/conscontrol mute off");
1636
}
1637

    
1638
function start_devd() {
1639
	global $g;
1640

    
1641
	if ($g['platform'] == 'jail')
1642
		return;
1643
	exec("/sbin/devd");
1644
	sleep(1);
1645
}
1646

    
1647
function is_interface_vlan_mismatch() {
1648
	global $config, $g;
1649

    
1650
	if (is_array($config['vlans']['vlan'])) {
1651
		foreach ($config['vlans']['vlan'] as $vlan) {
1652
			if (does_interface_exist($vlan['if']) == false)
1653
				return true;
1654
		}
1655
	}
1656

    
1657
	return false;
1658
}
1659

    
1660
function is_interface_mismatch() {
1661
	global $config, $g;
1662

    
1663
	$do_assign = false;
1664
	$i = 0;
1665
	$missing_interfaces = array();
1666
	if (is_array($config['interfaces'])) {
1667
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1668
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1669
				// Do not check these interfaces.
1670
				$i++;
1671
				continue;
1672
			}
1673
			else if (does_interface_exist($ifcfg['if']) == false) {
1674
				$missing_interfaces[] = $ifcfg['if'];
1675
				$do_assign = true;
1676
			} else
1677
				$i++;
1678
		}
1679
	}
1680

    
1681
	if ($g['minimum_nic_count'] > $i) {
1682
		$do_assign = true;
1683
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1684
		$do_assign = false;
1685

    
1686
	if (!empty($missing_interfaces) && $do_assign)
1687
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1688
	else
1689
		@unlink("{$g['tmp_path']}/missing_interfaces");
1690

    
1691
	return $do_assign;
1692
}
1693

    
1694
/* sync carp entries to other firewalls */
1695
function carp_sync_client() {
1696
	global $g;
1697
	send_event("filter sync");
1698
}
1699

    
1700
/****f* util/isAjax
1701
 * NAME
1702
 *   isAjax - reports if the request is driven from prototype
1703
 * INPUTS
1704
 *   none
1705
 * RESULT
1706
 *   true/false
1707
 ******/
1708
function isAjax() {
1709
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1710
}
1711

    
1712
/****f* util/timeout
1713
 * NAME
1714
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1715
 * INPUTS
1716
 *   optional, seconds to wait before timeout. Default 9 seconds.
1717
 * RESULT
1718
 *   returns 1 char of user input or null if no input.
1719
 ******/
1720
function timeout($timer = 9) {
1721
	while(!isset($key)) {
1722
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1723
		else { echo chr(8). "{$timer}"; }
1724
		`/bin/stty -icanon min 0 time 25`;
1725
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1726
		`/bin/stty icanon`;
1727
		if ($key == '')
1728
			unset($key);
1729
		$timer--;
1730
		if ($timer == 0)
1731
			break;
1732
	}
1733
	return $key;
1734
}
1735

    
1736
/****f* util/msort
1737
 * NAME
1738
 *   msort - sort array
1739
 * INPUTS
1740
 *   $array to be sorted, field to sort by, direction of sort
1741
 * RESULT
1742
 *   returns newly sorted array
1743
 ******/
1744
function msort($array, $id="id", $sort_ascending=true) {
1745
	$temp_array = array();
1746
	while(count($array)>0) {
1747
		$lowest_id = 0;
1748
		$index=0;
1749
		foreach ($array as $item) {
1750
			if (isset($item[$id])) {
1751
				if ($array[$lowest_id][$id]) {
1752
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1753
						$lowest_id = $index;
1754
					}
1755
				}
1756
			}
1757
			$index++;
1758
		}
1759
		$temp_array[] = $array[$lowest_id];
1760
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1761
	}
1762
	if ($sort_ascending) {
1763
		return $temp_array;
1764
	} else {
1765
		return array_reverse($temp_array);
1766
	}
1767
}
1768

    
1769
/****f* util/color
1770
 * NAME
1771
 *   color - outputs a color code to the ansi terminal if supported
1772
 * INPUTS
1773
 *   color code or color name
1774
 * RESULT
1775
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1776
 ******/
1777
function color($color = "0m") {
1778
	/*
1779
		Color codes available:
1780
		 0m reset; clears all colors and styles (to white on black)
1781
		 1m bold on (see below)
1782
		 3m italics on
1783
		 4m underline on
1784
		 7m inverse on; reverses foreground & background colors
1785
		 9m strikethrough on
1786
		 22m bold off (see below)
1787
		 23m italics off
1788
		 24m underline off
1789
		 27m inverse off
1790
		 29m strikethrough off
1791
		 30m set foreground color to black
1792
		 31m set foreground color to red
1793
		 32m set foreground color to green
1794
		 33m set foreground color to yellow
1795
		 34m set foreground color to blue
1796
		 35m set foreground color to magenta (purple)
1797
		 36m set foreground color to cyan
1798
		 37m set foreground color to white
1799
		 40m  set background color to black
1800
		 41m set background color to red
1801
		 42m set background color to green
1802
		 43m set background color to yellow
1803
		 44m set background color to blue
1804
		 45m set background color to magenta (purple)
1805
		 46m set background color to cyan
1806
		 47m set background color to white
1807
		 49m set background color to default (black)
1808
	*/
1809
	// Allow caching of TERM to
1810
	// speedup subequence requests.
1811
	global $TERM;
1812
	if(!$TERM)
1813
		$TERM=`/usr/bin/env | grep color`;
1814
	if(!$TERM)
1815
		$TERM=`/usr/bin/env | grep cons25`;
1816
	if($TERM) {
1817
		$ESCAPE=chr(27);
1818
		switch ($color) {
1819
			case "black":
1820
				return "{$ESCAPE}[30m";
1821
			case "red":
1822
				return "{$ESCAPE}[31m";
1823
			case "green":
1824
				return "{$ESCAPE}[32m";
1825
			case "yellow":
1826
				return "{$ESCAPE}[33m";
1827
			case "blue":
1828
				return "{$ESCAPE}[34m";
1829
			case "magenta":
1830
				return "{$ESCAPE}[35m";
1831
			case "cyan":
1832
				return "{$ESCAPE}[36m";
1833
			case "white":
1834
				return "{$ESCAPE}[37m";
1835
			case "default":
1836
				return "{$ESCAPE}[39m";
1837
		}
1838
		return "{$ESCAPE}[{$color}";
1839
	}
1840
}
1841

    
1842
/****f* util/is_URL
1843
 * NAME
1844
 *   is_URL
1845
 * INPUTS
1846
 *   string to check
1847
 * RESULT
1848
 *   Returns true if item is a URL
1849
 ******/
1850
function is_URL($url) {
1851
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1852
	if($match)
1853
		return true;
1854
	return false;
1855
}
1856

    
1857
function is_file_included($file = "") {
1858
	$files = get_included_files();
1859
	if (in_array($file, $files))
1860
		return true;
1861

    
1862
	return false;
1863
}
1864

    
1865
/*
1866
 * Replace a value on a deep associative array using regex
1867
 */
1868
function array_replace_values_recursive($data, $match, $replace) {
1869
	if (empty($data))
1870
		return $data;
1871

    
1872
	if (is_string($data))
1873
		$data = preg_replace("/{$match}/", $replace, $data);
1874
	else if (is_array($data))
1875
		foreach ($data as $k => $v)
1876
			$data[$k] = array_replace_values_recursive($v, $match, $replace);
1877

    
1878
	return $data;
1879
}
1880

    
1881
/*
1882
	This function was borrowed from a comment on PHP.net at the following URL:
1883
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1884
 */
1885
function array_merge_recursive_unique($array0, $array1) {
1886

    
1887
	$arrays = func_get_args();
1888
	$remains = $arrays;
1889

    
1890
	// We walk through each arrays and put value in the results (without
1891
	// considering previous value).
1892
	$result = array();
1893

    
1894
	// loop available array
1895
	foreach($arrays as $array) {
1896

    
1897
		// The first remaining array is $array. We are processing it. So
1898
		// we remove it from remaing arrays.
1899
		array_shift($remains);
1900

    
1901
		// We don't care non array param, like array_merge since PHP 5.0.
1902
		if(is_array($array)) {
1903
			// Loop values
1904
			foreach($array as $key => $value) {
1905
				if(is_array($value)) {
1906
					// we gather all remaining arrays that have such key available
1907
					$args = array();
1908
					foreach($remains as $remain) {
1909
						if(array_key_exists($key, $remain)) {
1910
							array_push($args, $remain[$key]);
1911
						}
1912
					}
1913

    
1914
					if(count($args) > 2) {
1915
						// put the recursion
1916
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1917
					} else {
1918
						foreach($value as $vkey => $vval) {
1919
							$result[$key][$vkey] = $vval;
1920
						}
1921
					}
1922
				} else {
1923
					// simply put the value
1924
					$result[$key] = $value;
1925
				}
1926
			}
1927
		}
1928
	}
1929
	return $result;
1930
}
1931

    
1932

    
1933
/*
1934
 * converts a string like "a,b,c,d"
1935
 * into an array like array("a" => "b", "c" => "d")
1936
 */
1937
function explode_assoc($delimiter, $string) {
1938
	$array = explode($delimiter, $string);
1939
	$result = array();
1940
	$numkeys = floor(count($array) / 2);
1941
	for ($i = 0; $i < $numkeys; $i += 1) {
1942
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1943
	}
1944
	return $result;
1945
}
1946

    
1947
function get_staticroutes($returnsubnetsonly = false, $returnhostnames = false) {
1948
	global $config, $aliastable;
1949

    
1950
	/* Bail if there are no routes, but return an array always so callers don't have to check. */
1951
	if (!is_array($config['staticroutes']['route']))
1952
		return array();
1953

    
1954
	$allstaticroutes = array();
1955
	$allsubnets = array();
1956
	/* Loop through routes and expand aliases as we find them. */
1957
	foreach ($config['staticroutes']['route'] as $route) {
1958
		if (is_alias($route['network'])) {
1959
			if (!isset($aliastable[$route['network']]))
1960
				continue;
1961

    
1962
			$subnets = preg_split('/\s+/', $aliastable[$route['network']]);
1963
			foreach ($subnets as $net) {
1964
				if (!is_subnet($net)) {
1965
					if (is_ipaddrv4($net))
1966
						$net .= "/32";
1967
					else if (is_ipaddrv6($net))
1968
						$net .= "/128";
1969
					else if ($returnhostnames === false || !is_fqdn($net))
1970
						continue;
1971
				}
1972
				$temproute = $route;
1973
				$temproute['network'] = $net;
1974
				$allstaticroutes[] = $temproute;
1975
				$allsubnets[] = $net;
1976
			}
1977
		} elseif (is_subnet($route['network'])) {
1978
			$allstaticroutes[] = $route;
1979
			$allsubnets[] = $route['network'];
1980
		}
1981
	}
1982
	if ($returnsubnetsonly)
1983
		return $allsubnets;
1984
	else
1985
		return $allstaticroutes;
1986
}
1987

    
1988
/****f* util/get_alias_list
1989
 * NAME
1990
 *   get_alias_list - Provide a list of aliases.
1991
 * INPUTS
1992
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
1993
 * RESULT
1994
 *   Array containing list of aliases.
1995
 *   If $type is unspecified, all aliases are returned.
1996
 *   If $type is a string, all aliases of the type specified in $type are returned.
1997
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
1998
 */
1999
function get_alias_list($type = null) {
2000
	global $config;
2001
	$result = array();
2002
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
2003
		foreach ($config['aliases']['alias'] as $alias) {
2004
			if ($type === null) {
2005
				$result[] = $alias['name'];
2006
			}
2007
			else if (is_array($type)) {
2008
				if (in_array($alias['type'], $type)) {
2009
					$result[] = $alias['name'];
2010
				}
2011
			}
2012
			else if ($type === $alias['type']) {
2013
				$result[] = $alias['name'];
2014
			}
2015
		}
2016
	}
2017
	return $result;
2018
}
2019

    
2020
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
2021
function array_exclude($needle, $haystack) {
2022
	$result = array();
2023
	if (is_array($haystack)) {
2024
		foreach ($haystack as $thing) {
2025
			if ($needle !== $thing) {
2026
				$result[] = $thing;
2027
			}
2028
		}
2029
	}
2030
	return $result;
2031
}
2032

    
2033
function setup_library_paths() {
2034
	$current_library_paths = explode(":", exec("/sbin/ldconfig -r | /usr/bin/grep 'search directories' | /usr/bin/awk '{print $3;}'"));
2035
	$pbi_library_paths = array_merge(glob("/usr/pbi/*/lib", GLOB_ONLYDIR), glob("/usr/pbi/*/lib/*", GLOB_ONLYDIR));
2036
	foreach ($pbi_library_paths as $pbilib) {
2037
		if (!in_array($pbilib, $current_library_paths))
2038
			exec("/sbin/ldconfig -m {$pbilib}");
2039
	}
2040
}
2041

    
2042
function get_current_theme() {
2043
	global $config, $g;
2044
	/*
2045
	 *   if user has selected a custom template, use it.
2046
	 *   otherwise default to pfsense tempalte
2047
	 */
2048
	if (($g["disablethemeselection"] === true) && !empty($g["default_theme"]) && (is_dir($g["www_path"].'/themes/'.$g["default_theme"])))
2049
		$theme = $g["default_theme"];
2050
	elseif($config['theme'] <> "" && (is_dir($g["www_path"].'/themes/'.$config['theme'])))
2051
		$theme = $config['theme'];
2052
	else
2053
		$theme = "pfsense";
2054
	/*
2055
	 *  If this device is an apple ipod/iphone
2056
	 *  switch the theme to one that works with it.
2057
	 */
2058
	$lowres_ua = array("iPhone", "iPod", "iPad", "Android", "BlackBerry", "Opera Mini", "Opera Mobi", "PlayBook", "IEMobile");
2059
	foreach($lowres_ua as $useragent)
2060
		if(strstr($_SERVER['HTTP_USER_AGENT'], $useragent))
2061
			$theme = (empty($g['theme_lowres']) && (is_dir($g["www_path"].'/themes/'.$g['theme_lowres']))) ? "pfsense" : $g['theme_lowres'];
2062
	return $theme;
2063
}
2064

    
2065
/* Define what is preferred, IPv4 or IPv6 */
2066
function prefer_ipv4_or_ipv6() {
2067
	global $config;
2068

    
2069
	if (isset($config['system']['prefer_ipv4']))
2070
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv4");
2071
	else
2072
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv6");
2073
}
2074

    
2075
?>
(55-55/67)