Project

General

Profile

Download (54.1 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 (strtolower(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
   returns FALSE for bad chars in the name - this allows calling code to determine what the problem was.
660
   aliases cannot be:
661
   	bad chars: anything except a-z 0-9 and underscore
662
   	bad names: empty string, pure numeric, pure underscore
663
   	reserved words: pre-defined service/protocol/port names which should not be ambiguous, and the words "port" and  "pass" */
664

    
665
function is_validaliasname($name) {
666
	/* Array of reserved words */
667
	$reserved = array("port", "pass");
668

    
669
	if (!is_string($name) || strlen($name) >= 32 || preg_match('/(^_*$|^\d*$|[^a-z0-9_])/i', $name))
670
		return false;
671
	if (in_array($name, $reserved, true) || getservbyname($name, "tcp") || getservbyname($name, "udp") || getprotobyname($name))
672
		return; /* return NULL */
673
	return true;
674
}
675

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

    
690
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
691
function is_portrange($portrange) {
692
	$ports = explode(":", $portrange);
693

    
694
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
695
}
696

    
697
/* returns true if $port is a valid port number or an alias thereof */
698
function is_portoralias($port) {
699
	global $config;
700

    
701
	if (is_alias($port)) {
702
		if (is_array($config['aliases']['alias'])) {
703
			foreach ($config['aliases']['alias'] as $alias) {
704
				if ($alias['name'] == $port && preg_match("/port/i", $alias['type']))
705
					return true;
706
				}
707
			}
708
			return false;
709
	} else
710
		return is_port($port);
711
}
712

    
713
/* create ranges of sequential port numbers (200:215) and remove duplicates */
714
function group_ports($ports) {
715
	if (!is_array($ports) || empty($ports))
716
		return;
717

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

    
737
	$result = array();
738
	foreach ($uniq as $idx => $port) {
739
		if ($idx == 0) {
740
			$result[] = $port;
741
			continue;
742
		}
743

    
744
		$last = end($result);
745
		if (is_portrange($last))
746
			list($begin, $end) = explode(":", $last);
747
		else
748
			$begin = $end = $last;
749

    
750
		if ($port == ($end+1)) {
751
			$end++;
752
			$result[count($result)-1] = "{$begin}:{$end}";
753
		} else {
754
			$result[] = $port;
755
		}
756
	}
757

    
758
	return $result;
759
}
760

    
761
/* returns true if $val is a valid shaper bandwidth value */
762
function is_valid_shaperbw($val) {
763
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
764
}
765

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

    
774
/* returns true if $test is in the range between $start and $end */
775
function is_inrange_v6($test, $start, $end) {
776
	if ( (inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start)) )
777
		return true;
778
	else
779
		return false;
780
}
781

    
782
/* returns true if $test is in the range between $start and $end */
783
function is_inrange($test, $start, $end) {
784
	return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
785
}
786

    
787
/* XXX: return the configured carp interface list */
788
function get_configured_carp_interface_list($carpinterface = "", $family = "inet") {
789
	global $config;
790

    
791
	$iflist = array();
792

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

    
813
	return $iflist;
814
}
815

    
816
/* return the configured IP aliases list */
817
function get_configured_ip_aliases_list($returnfullentry = false) {
818
	global $config;
819

    
820
	$alias_list=array();
821

    
822
	if(is_array($config['virtualip']['vip'])) {
823
		$viparr = &$config['virtualip']['vip'];
824
		foreach ($viparr as $vip) {
825
			if ($vip['mode']=="ipalias") {
826
				if ($returnfullentry)
827
					$alias_list[$vip['subnet']] = $vip;
828
				else
829
					$alias_list[$vip['subnet']] = $vip['interface'];
830
			}
831
		}
832
	}
833

    
834
	return $alias_list;
835
}
836

    
837
/* return all configured aliases list (IP, carp, proxyarp and other) */
838
function get_configured_vips_list() {
839
	global $config;
840

    
841
	$alias_list=array();
842

    
843
	if(is_array($config['virtualip']['vip'])) {
844
		$viparr = &$config['virtualip']['vip'];
845
		foreach ($viparr as $vip) {
846
			if ($vip['mode'] == "carp")
847
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => "{$vip['interface']}_vip{$vip['vhid']}");
848
			else
849
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
850
		}
851
	}
852

    
853
	return $alias_list;
854
}
855

    
856
/* comparison function for sorting by the order in which interfaces are normally created */
857
function compare_interface_friendly_names($a, $b) {
858
	if ($a == $b)
859
		return 0;
860
	else if ($a == 'wan')
861
		return -1;
862
	else if ($b == 'wan')
863
		return 1;
864
	else if ($a == 'lan')
865
		return -1;
866
	else if ($b == 'lan')
867
		return 1;
868

    
869
	return strnatcmp($a, $b);
870
}
871

    
872
/* return the configured interfaces list. */
873
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
874
	global $config;
875

    
876
	$iflist = array();
877

    
878
	/* if list */
879
	foreach($config['interfaces'] as $if => $ifdetail) {
880
		if ($only_opt && ($if == "wan" || $if == "lan"))
881
			continue;
882
		if (isset($ifdetail['enable']) || $withdisabled == true)
883
			$iflist[$if] = $if;
884
	}
885

    
886
	return $iflist;
887
}
888

    
889
/* return the configured interfaces list. */
890
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
891
	global $config;
892

    
893
	$iflist = array();
894

    
895
	/* if list */
896
	foreach($config['interfaces'] as $if => $ifdetail) {
897
		if ($only_opt && ($if == "wan" || $if == "lan"))
898
			continue;
899
		if (isset($ifdetail['enable']) || $withdisabled == true) {
900
			$tmpif = get_real_interface($if);
901
			if (!empty($tmpif))
902
				$iflist[$tmpif] = $if;
903
		}
904
	}
905

    
906
	return $iflist;
907
}
908

    
909
/* return the configured interfaces list with their description. */
910
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
911
	global $config;
912

    
913
	$iflist = array();
914

    
915
	/* if list */
916
	foreach($config['interfaces'] as $if => $ifdetail) {
917
		if ($only_opt && ($if == "wan" || $if == "lan"))
918
			continue;
919
		if (isset($ifdetail['enable']) || $withdisabled == true) {
920
			if(empty($ifdetail['descr']))
921
				$iflist[$if] = strtoupper($if);
922
			else
923
				$iflist[$if] = strtoupper($ifdetail['descr']);
924
		}
925
	}
926

    
927
	return $iflist;
928
}
929

    
930
/*
931
 *   get_configured_ip_addresses() - Return a list of all configured
932
 *   interfaces IP Addresses
933
 *
934
 */
935
function get_configured_ip_addresses() {
936
	global $config;
937

    
938
	if (!function_exists('get_interface_ip'))
939
		require_once("interfaces.inc");
940
	$ip_array = array();
941
	$interfaces = get_configured_interface_list();
942
	if (is_array($interfaces)) {
943
		foreach($interfaces as $int) {
944
			$ipaddr = get_interface_ip($int);
945
			$ip_array[$int] = $ipaddr;
946
		}
947
	}
948
	$interfaces = get_configured_carp_interface_list();
949
	if (is_array($interfaces))
950
		foreach($interfaces as $int => $ipaddr)
951
			$ip_array[$int] = $ipaddr;
952

    
953
	/* pppoe server */
954
	if (is_array($config['pppoes']) && is_array($config['pppoes']['pppoe'])) {
955
		foreach($config['pppoes']['pppoe'] as $pppoe) {
956
			if ($pppoe['mode'] == "server") {
957
				if(is_ipaddr($pppoe['localip'])) {
958
					$int = "pppoes". $pppoe['pppoeid'];
959
					$ip_array[$int] = $pppoe['localip'];
960
				}
961
			}
962
		}
963
	}
964

    
965
	return $ip_array;
966
}
967

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

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

    
1089
			case "friendly":
1090
				if($friendly != "") {
1091
					$toput['if'] = $ifname;
1092
					$iflist[$friendly] = $toput;
1093
				}
1094
				break;
1095
			}
1096
		}
1097
	}
1098
	return $iflist;
1099
}
1100

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

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

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

    
1155
/* wrapper for exec() */
1156
function mwexec($command, $mute = false, $clearsigmask = false) {
1157
	global $g;
1158

    
1159
	if ($g['debug']) {
1160
		if (!$_SERVER['REMOTE_ADDR'])
1161
			echo "mwexec(): $command\n";
1162
	}
1163
	$oarr = array();
1164
	$retval = 0;
1165

    
1166
	if ($clearsigmask) {
1167
		$oldset = array();
1168
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1169
	}
1170
	$garbage = exec("$command 2>&1", $oarr, $retval);
1171
	if ($clearsigmask) {
1172
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1173
	}
1174

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

    
1186
/* wrapper for exec() in background */
1187
function mwexec_bg($command, $clearsigmask = false) {
1188
	global $g;
1189

    
1190
	if ($g['debug']) {
1191
		if (!$_SERVER['REMOTE_ADDR'])
1192
			echo "mwexec(): $command\n";
1193
	}
1194

    
1195
	if ($clearsigmask) {
1196
		$oldset = array();
1197
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1198
	}
1199
	$_gb = exec("/usr/bin/nohup $command > /dev/null 2>&1 &");
1200
	if ($clearsigmask) {
1201
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1202
	}
1203
	unset($_gb);
1204
}
1205

    
1206
/* unlink a file, if it exists */
1207
function unlink_if_exists($fn) {
1208
	$to_do = glob($fn);
1209
	if(is_array($to_do)) {
1210
		foreach($to_do as $filename)
1211
			@unlink($filename);
1212
	} else {
1213
		@unlink($fn);
1214
	}
1215
}
1216
/* make a global alias table (for faster lookups) */
1217
function alias_make_table($config) {
1218
	global $aliastable;
1219

    
1220
	$aliastable = array();
1221

    
1222
	if (is_array($config['aliases']['alias'])) {
1223
		foreach ($config['aliases']['alias'] as $alias) {
1224
			if ($alias['name'])
1225
				$aliastable[$alias['name']] = $alias['address'];
1226
		}
1227
	}
1228
}
1229

    
1230
/* check if an alias exists */
1231
function is_alias($name) {
1232
	global $aliastable;
1233

    
1234
	return isset($aliastable[$name]);
1235
}
1236

    
1237
function alias_get_type($name) {
1238
	global $config;
1239

    
1240
	if (is_array($config['aliases']['alias'])) {
1241
		foreach ($config['aliases']['alias'] as $alias) {
1242
			if ($name == $alias['name'])
1243
				return $alias['type'];
1244
		}
1245
	}
1246

    
1247
	return "";
1248
}
1249

    
1250
/* expand a host or network alias, if necessary */
1251
function alias_expand($name) {
1252
	global $aliastable;
1253

    
1254
	if (isset($aliastable[$name]))
1255
		return "\${$name}";
1256
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1257
		return "{$name}";
1258
	else
1259
		return null;
1260
}
1261

    
1262
function alias_expand_urltable($name) {
1263
	global $config;
1264
	$urltable_prefix = "/var/db/aliastables/";
1265
	$urltable_filename = $urltable_prefix . $name . ".txt";
1266

    
1267
	if (is_array($config['aliases']['alias'])) {
1268
		foreach ($config['aliases']['alias'] as $alias) {
1269
			if (preg_match("/urltable/i", $alias['type']) && ($alias['name'] == $name)) {
1270
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1271
					return $urltable_filename;
1272
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1273
					return $urltable_filename;
1274
			}
1275
		}
1276
	}
1277
	return null;
1278
}
1279

    
1280
function subnet_size($subnet) {
1281
	if (is_subnetv4($subnet)) {
1282
		list ($ip, $bits) = explode("/", $subnet);
1283
		return round(exp(log(2) * (32 - $bits)));
1284
	}
1285
	else if (is_subnetv6($subnet)) {
1286
		list ($ip, $bits) = explode("/", $subnet);
1287
		return round(exp(log(2) * (128 - $bits)));
1288
	}
1289
	else {
1290
		return 0;
1291
	}
1292
}
1293

    
1294
function subnet_expand($subnet) {
1295
	if (is_subnetv4($subnet)) {
1296
		return subnetv4_expand($subnet);
1297
	} else if (is_subnetv6($subnet)) {
1298
		return subnetv6_expand($subnet);
1299
	} else {
1300
		return $subnet;
1301
	}
1302
}
1303

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

    
1317
/* find out whether two subnets overlap */
1318
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1319

    
1320
	if (!is_numeric($bits1))
1321
		$bits1 = 32;
1322
	if (!is_numeric($bits2))
1323
		$bits2 = 32;
1324

    
1325
	if ($bits1 < $bits2)
1326
		$relbits = $bits1;
1327
	else
1328
		$relbits = $bits2;
1329

    
1330
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1331
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1332

    
1333
	return ($sn1 == $sn2);
1334
}
1335

    
1336
/* find out whether two IPv6 subnets overlap */
1337
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
1338
	$sub1_min = gen_subnetv6($subnet1, $bits1);
1339
	$sub1_max = gen_subnetv6_max($subnet1, $bits1);
1340
	$sub2_min = gen_subnetv6($subnet2, $bits2);
1341
	$sub2_max = gen_subnetv6_max($subnet2, $bits2);
1342

    
1343
	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));
1344
}
1345

    
1346
/* compare two IP addresses */
1347
function ipcmp($a, $b) {
1348
	if (ip_less_than($a, $b))
1349
		return -1;
1350
	else if (ip_greater_than($a, $b))
1351
		return 1;
1352
	else
1353
		return 0;
1354
}
1355

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

    
1367
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1368
function verify_digital_signature($fname) {
1369
	global $g;
1370

    
1371
	if(!file_exists("/usr/local/sbin/gzsig"))
1372
		return 4;
1373

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

    
1377
/* obtain MAC address given an IP address by looking at the ARP table */
1378
function arp_get_mac_by_ip($ip) {
1379
	mwexec("/sbin/ping -c 1 -t 1 " . escapeshellarg($ip), true);
1380
	$arpoutput = "";
1381
	exec("/usr/sbin/arp -n " . escapeshellarg($ip), $arpoutput);
1382

    
1383
	if ($arpoutput[0]) {
1384
		$arpi = explode(" ", $arpoutput[0]);
1385
		$macaddr = $arpi[3];
1386
		if (is_macaddr($macaddr))
1387
			return $macaddr;
1388
		else
1389
			return false;
1390
	}
1391

    
1392
	return false;
1393
}
1394

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

    
1404
function mac_format($clientmac) {
1405
	global $config, $cpzone;
1406

    
1407
	$mac = explode(":", $clientmac);
1408
	$mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1409

    
1410
	switch($mac_format) {
1411
	case 'singledash':
1412
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1413

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

    
1417
	case 'cisco':
1418
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1419

    
1420
	case 'unformatted':
1421
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1422

    
1423
	default:
1424
		return $clientmac;
1425
	}
1426
}
1427

    
1428
function resolve_retry($hostname, $retries = 5) {
1429

    
1430
	if (is_ipaddr($hostname))
1431
		return $hostname;
1432

    
1433
	for ($i = 0; $i < $retries; $i++) {
1434
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1435
		$ip = gethostbyname($hostname);
1436

    
1437
		if ($ip && $ip != $hostname) {
1438
			/* success */
1439
			return $ip;
1440
		}
1441

    
1442
		sleep(1);
1443
	}
1444

    
1445
	return false;
1446
}
1447

    
1448
function format_bytes($bytes) {
1449
	if ($bytes >= 1073741824) {
1450
		return sprintf("%.2f GB", $bytes/1073741824);
1451
	} else if ($bytes >= 1048576) {
1452
		return sprintf("%.2f MB", $bytes/1048576);
1453
	} else if ($bytes >= 1024) {
1454
		return sprintf("%.0f KB", $bytes/1024);
1455
	} else {
1456
		return sprintf("%d bytes", $bytes);
1457
	}
1458
}
1459

    
1460
function update_filter_reload_status($text) {
1461
	global $g;
1462

    
1463
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1464
}
1465

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

    
1483
				if (empty($filter_regex) || preg_match($filter_regex, $file))
1484
					array_push($dir_array, $file);
1485
			}
1486
			closedir($dh);
1487
		}
1488
	}
1489
	return $dir_array;
1490
}
1491

    
1492
function run_plugins($directory) {
1493
	global $config, $g;
1494

    
1495
	/* process packager manager custom rules */
1496
	$files = return_dir_as_array($directory);
1497
	if (is_array($files)) {
1498
		foreach ($files as $file) {
1499
			if (stristr($file, ".sh") == true)
1500
				mwexec($directory . $file . " start");
1501
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc"))
1502
				require_once($directory . "/" . $file);
1503
		}
1504
	}
1505
}
1506

    
1507
/*
1508
 *    safe_mkdir($path, $mode = 0755)
1509
 *    create directory if it doesn't already exist and isn't a file!
1510
 */
1511
function safe_mkdir($path, $mode=0755) {
1512
	global $g;
1513

    
1514
	if (!is_file($path) && !is_dir($path)) {
1515
		return @mkdir($path, $mode, true);
1516
	} else {
1517
		return false;
1518
	}
1519
}
1520

    
1521
/*
1522
 * make_dirs($path, $mode = 0755)
1523
 * create directory tree recursively (mkdir -p)
1524
 */
1525
function make_dirs($path, $mode = 0755) {
1526
	$base = '';
1527
	foreach (explode('/', $path) as $dir) {
1528
		$base .= "/$dir";
1529
		if (!is_dir($base)) {
1530
			if (!@mkdir($base, $mode))
1531
				return false;
1532
		}
1533
	}
1534
	return true;
1535
}
1536

    
1537
/*
1538
 * get_sysctl($names)
1539
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1540
 * name) and return an array of key/value pairs set for those that exist
1541
 */
1542
function get_sysctl($names) {
1543
	if (empty($names))
1544
		return array();
1545

    
1546
	if (is_array($names)) {
1547
		$name_list = array();
1548
		foreach ($names as $name) {
1549
			$name_list[] = escapeshellarg($name);
1550
		}
1551
	} else
1552
		$name_list = array(escapeshellarg($names));
1553

    
1554
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1555
	$values = array();
1556
	foreach ($output as $line) {
1557
		$line = explode(": ", $line, 2);
1558
		if (count($line) == 2)
1559
			$values[$line[0]] = $line[1];
1560
	}
1561

    
1562
	return $values;
1563
}
1564

    
1565
/*
1566
 * set_sysctl($value_list)
1567
 * Set sysctl OID's listed as key/value pairs and return
1568
 * an array with keys set for those that succeeded
1569
 */
1570
function set_sysctl($values) {
1571
	if (empty($values))
1572
		return array();
1573

    
1574
	$value_list = array();
1575
	foreach ($values as $key => $value) {
1576
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1577
	}
1578

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

    
1581
	/* Retry individually if failed (one or more read-only) */
1582
	if ($success <> 0 && count($value_list) > 1) {
1583
		foreach ($value_list as $value) {
1584
			exec("/sbin/sysctl -i " . $value, $output);
1585
		}
1586
	}
1587

    
1588
	$ret = array();
1589
	foreach ($output as $line) {
1590
		$line = explode(": ", $line, 2);
1591
		if (count($line) == 2)
1592
			$ret[$line[0]] = true;
1593
	}
1594

    
1595
	return $ret;
1596
}
1597

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

    
1607
	$output = "";
1608
	$_gb = exec("/sbin/sysctl -n hw.physmem", $output);
1609
	$physmem = trim($output[0], " \n");
1610
	unset($output);
1611
	$_gb = exec("/sbin/sysctl -n hw.physmem", $output);
1612
	$realmem = trim($output[0], " \n");
1613
	unset($output, $_gb);
1614
	/* convert from bytes to megabytes */
1615
	return array(($physmem/1048576),($realmem/1048576));
1616
}
1617

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

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

    
1644
function start_devd() {
1645
	global $g;
1646

    
1647
	if ($g['platform'] == 'jail')
1648
		return;
1649
	exec("/sbin/devd");
1650
	sleep(1);
1651
}
1652

    
1653
function is_interface_vlan_mismatch() {
1654
	global $config, $g;
1655

    
1656
	if (is_array($config['vlans']['vlan'])) {
1657
		foreach ($config['vlans']['vlan'] as $vlan) {
1658
			if (does_interface_exist($vlan['if']) == false)
1659
				return true;
1660
		}
1661
	}
1662

    
1663
	return false;
1664
}
1665

    
1666
function is_interface_mismatch() {
1667
	global $config, $g;
1668

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

    
1687
	if ($g['minimum_nic_count'] > $i) {
1688
		$do_assign = true;
1689
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1690
		$do_assign = false;
1691

    
1692
	if (!empty($missing_interfaces) && $do_assign)
1693
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1694
	else
1695
		@unlink("{$g['tmp_path']}/missing_interfaces");
1696

    
1697
	return $do_assign;
1698
}
1699

    
1700
/* sync carp entries to other firewalls */
1701
function carp_sync_client() {
1702
	global $g;
1703
	send_event("filter sync");
1704
}
1705

    
1706
/****f* util/isAjax
1707
 * NAME
1708
 *   isAjax - reports if the request is driven from prototype
1709
 * INPUTS
1710
 *   none
1711
 * RESULT
1712
 *   true/false
1713
 ******/
1714
function isAjax() {
1715
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1716
}
1717

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

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

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

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

    
1863
function is_file_included($file = "") {
1864
	$files = get_included_files();
1865
	if (in_array($file, $files))
1866
		return true;
1867

    
1868
	return false;
1869
}
1870

    
1871
/*
1872
 * Replace a value on a deep associative array using regex
1873
 */
1874
function array_replace_values_recursive($data, $match, $replace) {
1875
	if (empty($data))
1876
		return $data;
1877

    
1878
	if (is_string($data))
1879
		$data = preg_replace("/{$match}/", $replace, $data);
1880
	else if (is_array($data))
1881
		foreach ($data as $k => $v)
1882
			$data[$k] = array_replace_values_recursive($v, $match, $replace);
1883

    
1884
	return $data;
1885
}
1886

    
1887
/*
1888
	This function was borrowed from a comment on PHP.net at the following URL:
1889
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1890
 */
1891
function array_merge_recursive_unique($array0, $array1) {
1892

    
1893
	$arrays = func_get_args();
1894
	$remains = $arrays;
1895

    
1896
	// We walk through each arrays and put value in the results (without
1897
	// considering previous value).
1898
	$result = array();
1899

    
1900
	// loop available array
1901
	foreach($arrays as $array) {
1902

    
1903
		// The first remaining array is $array. We are processing it. So
1904
		// we remove it from remaing arrays.
1905
		array_shift($remains);
1906

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

    
1920
					if(count($args) > 2) {
1921
						// put the recursion
1922
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1923
					} else {
1924
						foreach($value as $vkey => $vval) {
1925
							$result[$key][$vkey] = $vval;
1926
						}
1927
					}
1928
				} else {
1929
					// simply put the value
1930
					$result[$key] = $value;
1931
				}
1932
			}
1933
		}
1934
	}
1935
	return $result;
1936
}
1937

    
1938

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

    
1953
function get_staticroutes($returnsubnetsonly = false, $returnhostnames = false) {
1954
	global $config, $aliastable;
1955

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

    
1960
	$allstaticroutes = array();
1961
	$allsubnets = array();
1962
	/* Loop through routes and expand aliases as we find them. */
1963
	foreach ($config['staticroutes']['route'] as $route) {
1964
		if (is_alias($route['network'])) {
1965
			if (!isset($aliastable[$route['network']]))
1966
				continue;
1967

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

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

    
2026
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
2027
function array_exclude($needle, $haystack) {
2028
	$result = array();
2029
	if (is_array($haystack)) {
2030
		foreach ($haystack as $thing) {
2031
			if ($needle !== $thing) {
2032
				$result[] = $thing;
2033
			}
2034
		}
2035
	}
2036
	return $result;
2037
}
2038

    
2039
function setup_library_paths() {
2040
	$current_library_paths = explode(":", exec("/sbin/ldconfig -r | /usr/bin/grep 'search directories' | /usr/bin/awk '{print $3;}'"));
2041
	$pbi_library_paths = array_merge(glob("/usr/pbi/*/lib", GLOB_ONLYDIR), glob("/usr/pbi/*/lib/*", GLOB_ONLYDIR));
2042
	foreach ($pbi_library_paths as $pbilib) {
2043
		if (!in_array($pbilib, $current_library_paths))
2044
			exec("/sbin/ldconfig -m {$pbilib}");
2045
	}
2046
}
2047

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

    
2071
/* Define what is preferred, IPv4 or IPv6 */
2072
function prefer_ipv4_or_ipv6() {
2073
	global $config;
2074

    
2075
	if (isset($config['system']['prefer_ipv4']))
2076
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv4");
2077
	else
2078
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv6");
2079
}
2080

    
2081
?>
(55-55/67)