Projet

Général

Profil

Télécharger (53,8 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / util.inc @ ec25f18a

1
<?php
2
/*
3
	util.inc
4
	part of the pfSense project (https://www.pfsense.org)
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
	$module_name = str_replace(".ko", "", $module_name);
301
	$running = 0;
302
	$_gb = exec("/sbin/kldstat -qn {$module_name} 2>&1", $_gb, $running);
303
	if (intval($running) == 0)
304
		return true;
305
	else
306
		return false;
307
}
308

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

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

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

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

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

    
336
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
337
}
338

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

    
344
	$mask = Net_IPv6::getNetmask('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',$bits);
345

    
346
	$inet_ip = (binary)inet_pton($ipaddr);
347
	$inet_mask = (binary)inet_pton($mask);
348

    
349
	$inet_end = $inet_ip | ~$inet_mask;
350

    
351
	return (inet_ntop($inet_end));
352
}
353

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
527
	$ip_long = ip2long($ipaddr);
528
	$ip_reverse = long2ip32($ip_long);
529

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

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

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

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

    
556
	return is_ipaddrv6($ipaddr);
557
}
558

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

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

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

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

    
596
}
597

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

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

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

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

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

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

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

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

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

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

    
659
/* returns true if $name is a valid name for an alias
660
   returns NULL if a reserved word is used
661
   returns FALSE for bad chars in the name - this allows calling code to determine what the problem was.
662
   aliases cannot be:
663
   	bad chars: anything except a-z 0-9 and underscore
664
   	bad names: empty string, pure numeric, pure underscore
665
   	reserved words: pre-defined service/protocol/port names which should not be ambiguous, and the words "port" and  "pass" */
666

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

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

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

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

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

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

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

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

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

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

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

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

    
760
	return $result;
761
}
762

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

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

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

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

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

    
793
	$iflist = array();
794

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

    
815
	return $iflist;
816
}
817

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

    
822
	$alias_list=array();
823

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

    
836
	return $alias_list;
837
}
838

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

    
843
	$alias_list=array();
844

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

    
855
	return $alias_list;
856
}
857

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

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

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

    
878
	$iflist = array();
879

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

    
888
	return $iflist;
889
}
890

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

    
895
	$iflist = array();
896

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

    
908
	return $iflist;
909
}
910

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

    
915
	$iflist = array();
916

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

    
929
	return $iflist;
930
}
931

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

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

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

    
967
	return $ip_array;
968
}
969

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1222
	$aliastable = array();
1223

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

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

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

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

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

    
1249
	return "";
1250
}
1251

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1394
	return false;
1395
}
1396

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

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

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

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

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

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

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

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

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

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

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

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

    
1444
		sleep(1);
1445
	}
1446

    
1447
	return false;
1448
}
1449

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1564
	return $values;
1565
}
1566

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

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

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

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

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

    
1597
	return $ret;
1598
}
1599

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

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

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

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

    
1646
function start_devd() {
1647
	global $g;
1648

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

    
1655
function is_interface_vlan_mismatch() {
1656
	global $config, $g;
1657

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

    
1665
	return false;
1666
}
1667

    
1668
function is_interface_mismatch() {
1669
	global $config, $g;
1670

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

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

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

    
1699
	return $do_assign;
1700
}
1701

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

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

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

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

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

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

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

    
1870
	return false;
1871
}
1872

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

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

    
1886
	return $data;
1887
}
1888

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

    
1895
	$arrays = func_get_args();
1896
	$remains = $arrays;
1897

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

    
1902
	// loop available array
1903
	foreach($arrays as $array) {
1904

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

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

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

    
1940

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

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

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

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

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

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

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

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

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

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

    
2074
?>
(55-55/67)