Project

General

Profile

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

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

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

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

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

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

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

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

    
44
function isvalidpid($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 {$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 -{$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 -{$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
/* return the subnet address given a host address and a subnet bit count */
308
function gen_subnet($ipaddr, $bits) {
309
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
310
		return "";
311
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
312
}
313

    
314
/* return the subnet address given a host address and a subnet bit count */
315
function gen_subnetv6($ipaddr, $bits) {
316
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
317
		return "";
318

    
319
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
320
	$address = Net_IPv6::compress($address);
321
	return $address;
322
}
323

    
324
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
325
function gen_subnet_max($ipaddr, $bits) {
326
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
327
		return "";
328

    
329
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
330
}
331

    
332
/* Generate end number for a given ipv6 subnet mask */
333
function gen_subnetv6_max($ipaddr, $bits) {
334
	if(!is_ipaddrv6($ipaddr))
335
		return false;
336

    
337
	$mask = Net_IPv6::getNetmask('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',$bits);
338

    
339
	$inet_ip = (binary)inet_pton($ipaddr);
340
	$inet_mask = (binary)inet_pton($mask);
341

    
342
	$inet_end = $inet_ip | ~$inet_mask;
343

    
344
	return (inet_ntop($inet_end));
345
}
346

    
347
/* returns a subnet mask (long given a bit count) */
348
function gen_subnet_mask_long($bits) {
349
	$sm = 0;
350
	for ($i = 0; $i < $bits; $i++) {
351
		$sm >>= 1;
352
		$sm |= 0x80000000;
353
	}
354
	return $sm;
355
}
356

    
357
/* same as above but returns a string */
358
function gen_subnet_mask($bits) {
359
	return long2ip(gen_subnet_mask_long($bits));
360
}
361

    
362
/* Convert long int to IP address, truncating to 32-bits. */
363
function long2ip32($ip) {
364
	return long2ip($ip & 0xFFFFFFFF);
365
}
366

    
367
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
368
function ip2long32($ip) {
369
	return ( ip2long($ip) & 0xFFFFFFFF );
370
}
371

    
372
/* Convert IP address to unsigned long int. */
373
function ip2ulong($ip) {
374
	return sprintf("%u", ip2long32($ip));
375
}
376

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

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

    
400
/* Return the previous IP address before the given address */
401
function ip_before($ip) {
402
	return long2ip32(ip2long($ip)-1);
403
}
404

    
405
/* Return the next IP address after the given address */
406
function ip_after($ip) {
407
	return long2ip32(ip2long($ip)+1);
408
}
409

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

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

    
424
/* Convert a range of IPs to an array of subnets which can contain the range. */
425
function ip_range_to_subnet_array($startip, $endip) {
426
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
427
		return array();
428
	}
429

    
430
	// Container for subnets within this range.
431
	$rangesubnets = array();
432

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

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

    
443
		// Check best case where the range is exactly one subnet.
444
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
445
			// Hooray, the range is exactly this subnet!
446
			return array("{$startip}/{$cidr}");
447
		}
448

    
449
		// These remaining scenarios will find a subnet that uses the largest
450
		//  chunk possible of the range being tested, and leave the rest to be
451
		//  tested recursively after the loop.
452

    
453
		// Check if the subnet begins with $startip and ends before $endip
454
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
455
			break;
456
		}
457

    
458
		// Check if the subnet ends at $endip and starts after $startip
459
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
460
			break;
461
		}
462

    
463
		// Check if the subnet is between $startip and $endip
464
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
465
			break;
466
		}
467
	}
468

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

    
475
	// Add in the subnet we found before, to preserve ordering
476
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
477

    
478
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
479
	if ($endip != $targetsub_max) {
480
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
481
	}
482
	return $rangesubnets;
483
}
484

    
485
function is_iprange($range) {
486
	if (substr_count($range, '-') != 1) {
487
		return false;
488
	}
489
	list($ip1, $ip2) = explode ('-', $range);
490
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
491
}
492

    
493
function is_numericint($arg) {
494
	return (preg_match("/[^0-9]/", $arg) ? false : true);
495
}
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
function is_subnet($subnet) {
598
	if(is_subnetv4($subnet)) {
599
		return true;
600
	}
601
	if(is_subnetv6($subnet)) {
602
		return true;
603
	}
604
	return false;
605
}
606

    
607
/* returns true if $subnet is a valid IPv4 subnet in CIDR format */
608
function is_subnetv4($subnet) {
609
	if (!is_string($subnet))
610
		return false;
611

    
612
	list($hp,$np) = explode('/', $subnet);
613

    
614
	if (!is_ipaddrv4($hp))
615
		return false;
616

    
617
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
618
		return false;
619

    
620
	return true;
621
}
622

    
623
/* returns true if $subnet is a valid IPv6 subnet in CIDR format */
624
function is_subnetv6($subnet) {
625
	if (!is_string($subnet))
626
		return false;
627

    
628
	list($hp,$np) = explode('/', $subnet);
629

    
630
	if (!is_ipaddrv6($hp))
631
		return false;
632

    
633
	if (!is_numeric($np) || ($np < 1) || ($np > 128))
634
		return false;
635

    
636
	return true;
637
}
638

    
639

    
640
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
641
function is_subnetoralias($subnet) {
642
	global $aliastable;
643

    
644
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
645
		return true;
646
	else
647
		return is_subnet($subnet);
648
}
649

    
650
/* returns true if $hostname is a valid hostname */
651
function is_hostname($hostname) {
652
	if (!is_string($hostname))
653
		return false;
654

    
655
	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))
656
		return true;
657
	else
658
		return false;
659
}
660

    
661
/* returns true if $domain is a valid domain name */
662
function is_domain($domain) {
663
	if (!is_string($domain))
664
		return false;
665

    
666
	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))
667
		return true;
668
	else
669
		return false;
670
}
671

    
672
/* returns true if $macaddr is a valid MAC address */
673
function is_macaddr($macaddr, $partial=false) {
674
	$repeat = ($partial) ? '1,5' : '5';
675
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
676
}
677

    
678
/* returns true if $name is a valid name for an alias */
679
/* returns NULL if a reserved word is used */
680
function is_validaliasname($name) {
681
	/* Array of reserved words */
682
	$reserved = array("port", "pass");
683
	if (in_array($name, $reserved, true))
684
		return; /* return NULL */
685
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
686
		return true;
687
	else
688
		return false;
689
}
690

    
691
/* returns true if $port is a valid TCP/UDP port */
692
function is_port($port) {
693
	$tmpports = explode(":", $port);
694
	foreach($tmpports as $tmpport) {
695
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
696
			continue;
697
		if (!ctype_digit($tmpport))
698
			return false;
699
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
700
			return false;
701
	}
702
	return true;
703
}
704

    
705
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
706
function is_portrange($portrange) {
707
	$ports = explode(":", $portrange);
708

    
709
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
710
}
711

    
712
/* returns true if $port is a valid port number or an alias thereof */
713
function is_portoralias($port) {
714
	global $config;
715

    
716
	if (is_alias($port)) {
717
		if (is_array($config['aliases']['alias'])) {
718
			foreach ($config['aliases']['alias'] as $alias) {
719
				if ($alias['name'] == $port && preg_match("/port/i", $alias['type']))
720
					return true;
721
				}
722
			}
723
			return false;
724
	} else
725
		return is_port($port);
726
}
727

    
728
/* create ranges of sequential port numbers (200:215) and remove duplicates */
729
function group_ports($ports) {
730
	if (!is_array($ports) || empty($ports))
731
		return;
732

    
733
	$uniq = array();
734
	foreach ($ports as $port) {
735
		if (is_portrange($port)) {
736
			list($begin, $end) = explode(":", $port);
737
			if ($begin > $end) {
738
				$aux = $begin;
739
				$begin = $end;
740
				$end = $aux;
741
			}
742
			for ($i = $begin; $i <= $end; $i++)
743
				if (!in_array($i, $uniq))
744
					$uniq[] = $i;
745
		} else if (is_port($port)) {
746
			if (!in_array($port, $uniq))
747
				$uniq[] = $port;
748
		}
749
	}
750
	sort($uniq, SORT_NUMERIC);
751

    
752
	$result = array();
753
	foreach ($uniq as $idx => $port) {
754
		if ($idx == 0) {
755
			$result[] = $port;
756
			continue;
757
		}
758

    
759
		$last = end($result);
760
		if (is_portrange($last))
761
			list($begin, $end) = explode(":", $last);
762
		else
763
			$begin = $end = $last;
764

    
765
		if ($port == ($end+1)) {
766
			$end++;
767
			$result[count($result)-1] = "{$begin}:{$end}";
768
		} else {
769
			$result[] = $port;
770
		}
771
	}
772

    
773
	return $result;
774
}
775

    
776
/* returns true if $val is a valid shaper bandwidth value */
777
function is_valid_shaperbw($val) {
778
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
779
}
780

    
781
/* returns true if $test is in the range between $start and $end */
782
function is_inrange_v4($test, $start, $end) {
783
	if ( (ip2ulong($test) <= ip2ulong($end)) && (ip2ulong($test) >= ip2ulong($start)) )
784
		return true;
785
	else
786
		return false;
787
}
788

    
789
/* returns true if $test is in the range between $start and $end */
790
function is_inrange_v6($test, $start, $end) {
791
	if ( (inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start)) )
792
		return true;
793
	else
794
		return false;
795
}
796

    
797
/* returns true if $test is in the range between $start and $end */
798
function is_inrange($test, $start, $end) {
799
	return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
800
}
801

    
802
/* XXX: return the configured carp interface list */
803
function get_configured_carp_interface_list() {
804
	global $config;
805

    
806
	$iflist = array();
807

    
808
	if(is_array($config['virtualip']['vip'])) {
809
		$viparr = &$config['virtualip']['vip'];
810
		foreach ($viparr as $vip) {
811
			switch ($vip['mode']) {
812
			case "carp":
813
				$vipif = get_real_interface($vip['interface']) . "@{$vip['vhid']}";
814
				$iflist[$vipif] = $vip['subnet'];
815
				break;
816
			}
817
		}
818
	}
819

    
820
	return $iflist;
821
}
822

    
823
/* return the configured IP aliases list */
824
function get_configured_ip_aliases_list($returnfullentry = false) {
825
	global $config;
826

    
827
	$alias_list=array();
828

    
829
	if(is_array($config['virtualip']['vip'])) {
830
		$viparr = &$config['virtualip']['vip'];
831
		foreach ($viparr as $vip) {
832
			if ($vip['mode']=="ipalias") {
833
				if ($returnfullentry)
834
					$alias_list[$vip['subnet']] = $vip;
835
				else
836
					$alias_list[$vip['subnet']] = $vip['interface'];
837
			}
838
		}
839
	}
840

    
841
	return $alias_list;
842
}
843

    
844
/* return all configured aliases list (IP, carp, proxyarp and other) */
845
function get_configured_vips_list() {
846
	global $config;
847

    
848
	$alias_list=array();
849

    
850
	if(is_array($config['virtualip']['vip'])) {
851
		$viparr = &$config['virtualip']['vip'];
852
		foreach ($viparr as $vip)
853
			$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
854
	}
855

    
856
	return $alias_list;
857
}
858

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

    
872
	return strnatcmp($a, $b);
873
}
874

    
875
/* return the configured interfaces list. */
876
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
877
	global $config;
878

    
879
	$iflist = array();
880

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

    
889
	return $iflist;
890
}
891

    
892
/* return the configured interfaces list. */
893
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
894
	global $config;
895

    
896
	$iflist = array();
897

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

    
909
	return $iflist;
910
}
911

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

    
916
	$iflist = array();
917

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

    
930
	return $iflist;
931
}
932

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

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

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

    
968
	return $ip_array;
969
}
970

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

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

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

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

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

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

    
1158
/* wrapper for exec() */
1159
function mwexec($command, $mute = false, $clearsigmask = false) {
1160
	global $g;
1161

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

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

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

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

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

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

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

    
1221
	$aliastable = array();
1222

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

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

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

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

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

    
1248
	return "";
1249
}
1250

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1393
	return false;
1394
}
1395

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

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

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

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

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

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

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

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

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

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

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

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

    
1443
		sleep(1);
1444
	}
1445

    
1446
	return false;
1447
}
1448

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1563
	return $values;
1564
}
1565

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

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

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

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

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

    
1596
	return $ret;
1597
}
1598

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

    
1608
	$physmem = trim(`sysctl -n hw.physmem`, " \n");
1609
	$realmem = trim(`sysctl -n hw.realmem`, " \n");
1610
	/* convert from bytes to megabytes */
1611
	return array(($physmem/1048576),($realmem/1048576));
1612
}
1613

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

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

    
1640
function start_devd() {
1641
	global $g;
1642

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

    
1649
function is_interface_vlan_mismatch() {
1650
	global $config, $g;
1651

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

    
1659
	return false;
1660
}
1661

    
1662
function is_interface_mismatch() {
1663
	global $config, $g;
1664

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

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

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

    
1693
	return $do_assign;
1694
}
1695

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

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

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

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

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

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

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

    
1864
	return false;
1865
}
1866

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

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

    
1880
	return $data;
1881
}
1882

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

    
1889
	$arrays = func_get_args();
1890
	$remains = $arrays;
1891

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

    
1896
	// loop available array
1897
	foreach($arrays as $array) {
1898

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

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

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

    
1934

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

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

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

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

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

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

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

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

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

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

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

    
2077
?>
(54-54/66)