Project

General

Profile

Download (55.8 KB) Statistics
| Branch: | Tag: | Revision:
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_v4($startip, $endip) {
388
	if (is_ipaddrv4($startip) && is_ipaddrv4($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_v4($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 IPv4 addresses to an array of individual addresses. */
432
/* Note: IPv6 ranges are not yet supported here. */
433
function ip_range_to_address_array($startip, $endip, $max_size = 5000) {
434
	if (!is_ipaddrv4($startip) || !is_ipaddrv4($endip)) {
435
		return false;
436
	}
437

    
438
	if (ip_greater_than($startip, $endip)) {
439
		// Swap start and end so we can process sensibly.
440
		$temp = $startip;
441
		$startip = $endip;
442
		$endip = $temp;
443
	}
444

    
445
	if (ip_range_size_v4($startip, $endip) > $max_size)
446
		return false;
447
	
448
	// Container for IP addresses within this range.
449
	$rangeaddresses = array();
450
	$end_int = ip2ulong($endip);
451
	for ($ip_int = ip2ulong($startip); $ip_int <= $end_int; $ip_int++) {
452
		$rangeaddresses[] = long2ip($ip_int);
453
	}
454

    
455
	return $rangeaddresses;
456
}
457

    
458
/* Convert a range of IPv4 addresses to an array of subnets which can contain the range. */
459
/* Note: IPv6 ranges are not yet supported here. */
460
function ip_range_to_subnet_array($startip, $endip) {
461
	if (!is_ipaddrv4($startip) || !is_ipaddrv4($endip)) {
462
		return array();
463
	}
464

    
465
	if (ip_greater_than($startip, $endip)) {
466
		// Swap start and end so we can process sensibly.
467
		$temp = $startip;
468
		$startip = $endip;
469
		$endip = $temp;
470
	}
471

    
472
	// Container for subnets within this range.
473
	$rangesubnets = array();
474

    
475
	// Figure out what the smallest subnet is that holds the number of IPs in the given range.
476
	$cidr = find_smallest_cidr_v4(ip_range_size_v4($startip, $endip));
477

    
478
	// Loop here to reduce subnet size and retest as needed. We need to make sure
479
	//   that the target subnet is wholly contained between $startip and $endip.
480
	for ($cidr; $cidr <= 32; $cidr++) {
481
		// Find the network and broadcast addresses for the subnet being tested.
482
		$targetsub_min = gen_subnet($startip, $cidr);
483
		$targetsub_max = gen_subnet_max($startip, $cidr);
484

    
485
		// Check best case where the range is exactly one subnet.
486
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
487
			// Hooray, the range is exactly this subnet!
488
			return array("{$startip}/{$cidr}");
489
		}
490

    
491
		// These remaining scenarios will find a subnet that uses the largest
492
		//  chunk possible of the range being tested, and leave the rest to be
493
		//  tested recursively after the loop.
494

    
495
		// Check if the subnet begins with $startip and ends before $endip
496
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
497
			break;
498
		}
499

    
500
		// Check if the subnet ends at $endip and starts after $startip
501
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
502
			break;
503
		}
504

    
505
		// Check if the subnet is between $startip and $endip
506
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
507
			break;
508
		}
509
	}
510

    
511
	// Some logic that will recursively search from $startip to the first IP before the start of the subnet we just found.
512
	// NOTE: This may never be hit, the way the above algo turned out, but is left for completeness.
513
	if ($startip != $targetsub_min) {
514
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array($startip, ip_before($targetsub_min)));
515
	}
516

    
517
	// Add in the subnet we found before, to preserve ordering
518
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
519

    
520
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
521
	if ($endip != $targetsub_max) {
522
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
523
	}
524
	return $rangesubnets;
525
}
526

    
527
/* returns true if $range is a valid pair of IPv4 or IPv6 addresses separated by a "-"
528
   	false - if not a valid pair
529
   	true (numeric 4 or 6) - if valid, gives type of addresses */
530
function is_iprange($range) {
531
	if (substr_count($range, '-') != 1) {
532
		return false;
533
	}
534
	list($ip1, $ip2) = explode ('-', $range);
535
	if (is_ipaddrv4($ip1) && is_ipaddrv4($ip2))
536
		return 4;
537
	if (is_ipaddrv6($ip1) && is_ipaddrv6($ip2))
538
		return 6;
539
	return false;
540
}
541

    
542
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
543
function is_ipaddr($ipaddr) {
544
	if(is_ipaddrv4($ipaddr)) {
545
		return true;
546
	}
547
	if(is_ipaddrv6($ipaddr)) {
548
		return true;
549
	}
550
	return false;
551
}
552

    
553
/* returns true if $ipaddr is a valid IPv6 address */
554
function is_ipaddrv6($ipaddr) {
555
	if (!is_string($ipaddr) || empty($ipaddr))
556
		return false;
557
	if (strstr($ipaddr, "%") && is_linklocal($ipaddr)) {
558
		$tmpip = explode("%", $ipaddr);
559
		$ipaddr = $tmpip[0];
560
	}
561
	return Net_IPv6::checkIPv6($ipaddr);
562
}
563

    
564
/* returns true if $ipaddr is a valid dotted IPv4 address */
565
function is_ipaddrv4($ipaddr) {
566
	if (!is_string($ipaddr) || empty($ipaddr))
567
		return false;
568

    
569
	$ip_long = ip2long($ipaddr);
570
	$ip_reverse = long2ip32($ip_long);
571

    
572
	if ($ipaddr == $ip_reverse)
573
		return true;
574
	else
575
		return false;
576
}
577

    
578
/* returns true if $ipaddr is a valid linklocal address */
579
function is_linklocal($ipaddr) {
580
	return (strtolower(substr($ipaddr, 0, 5)) == "fe80:");
581
}
582

    
583
/* returns scope of a linklocal address */
584
function get_ll_scope($addr) {
585
	if (!is_linklocal($addr) || !strstr($addr, "%"))
586
		return "";
587
	list ($ll, $scope) = explode("%", $addr);
588
	return $scope;
589
}
590

    
591
/* returns true if $ipaddr is a valid literal IPv6 address */
592
function is_literalipaddrv6($ipaddr) {
593
	if(preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match))
594
		$ipaddr = $match[1];
595
	else
596
		return false;
597

    
598
	return is_ipaddrv6($ipaddr);
599
}
600

    
601
function is_ipaddrwithport($ipport) {
602
	$parts = explode(":", $ipport);
603
	$port = array_pop($parts);
604
	if (count($parts) == 1) {
605
		return is_ipaddrv4($parts[0]) && is_port($port);
606
	} elseif (count($parts) > 1) {
607
		return is_literalipaddrv6(implode(":", $parts)) && is_port($port);
608
	} else {
609
		return false;
610
	}
611
}
612

    
613
function is_hostnamewithport($hostport) {
614
	$parts = explode(":", $hostport);
615
	$port = array_pop($parts);
616
	if (count($parts) == 1) {
617
		return is_hostname($parts[0]) && is_port($port);
618
	} else {
619
		return false;
620
	}
621
}
622

    
623
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
624
function is_ipaddroralias($ipaddr) {
625
	global $config;
626

    
627
	if (is_alias($ipaddr)) {
628
		if (is_array($config['aliases']['alias'])) {
629
			foreach ($config['aliases']['alias'] as $alias) {
630
				if ($alias['name'] == $ipaddr && !preg_match("/port/i", $alias['type']))
631
					return true;
632
			}
633
		}
634
		return false;
635
	} else
636
		return is_ipaddr($ipaddr);
637

    
638
}
639

    
640
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format
641
   	false - if not a valid subnet
642
   	true (numeric 4 or 6) - if valid, gives type of subnet */
643
function is_subnet($subnet) {
644
	if (is_string($subnet) && preg_match('/^(?:([0-9.]{7,15})|([0-9a-f:]{2,39}))\/(\d{1,3})$/i', $subnet, $parts)) {
645
		if (is_ipaddrv4($parts[1]) && $parts[3] <= 32)
646
			return 4;
647
		if (is_ipaddrv6($parts[2]) && $parts[3] <= 128)
648
			return 6;
649
	}
650
	return false;
651
}
652

    
653
/* same as is_subnet() but accepts IPv4 only */
654
function is_subnetv4($subnet) {
655
	return (is_subnet($subnet) == 4);
656
}
657

    
658
/* same as is_subnet() but accepts IPv6 only */
659
function is_subnetv6($subnet) {
660
	return (is_subnet($subnet) == 6);
661
}
662

    
663
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
664
function is_subnetoralias($subnet) {
665
	global $aliastable;
666

    
667
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
668
		return true;
669
	else
670
		return is_subnet($subnet);
671
}
672

    
673
/* returns true if $hostname is just a valid hostname (top part without any of the domain part) */
674
function is_unqualified_hostname($hostname) {
675
	if (!is_string($hostname))
676
		return false;
677

    
678
	if (preg_match('/^(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])$/i', $hostname))
679
		return true;
680
	else
681
		return false;
682
}
683

    
684
/* returns true if $hostname is a valid hostname, with or without being a fully-qualified domain name. */
685
function is_hostname($hostname) {
686
	if (!is_string($hostname))
687
		return false;
688

    
689
	if (is_domain($hostname))
690
		if ((substr_count($hostname, ".") == 1) && ($hostname[strlen($hostname)-1] == ".")) {
691
			/* Only a single dot at the end like "test." - hosts cannot be directly in the root domain. */
692
			return false;
693
		} else {
694
			return true;
695
		}
696
	else
697
		return false;
698
}
699

    
700
/* returns true if $domain is a valid domain name */
701
function is_domain($domain) {
702
	if (!is_string($domain))
703
		return false;
704

    
705
	if (preg_match('/^(?:(?:[a-z_0-9]|[a-z_0-9][a-z_0-9\-]*[a-z_0-9])\.)*(?:[a-z_0-9]|[a-z_0-9][a-z_0-9\-]*[a-z_0-9\.])$/i', $domain))
706
		return true;
707
	else
708
		return false;
709
}
710

    
711
/* returns true if $macaddr is a valid MAC address */
712
function is_macaddr($macaddr, $partial=false) {
713
	$repeat = ($partial) ? '1,5' : '5';
714
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
715
}
716

    
717
/* returns true if $name is a valid name for an alias
718
   returns NULL if a reserved word is used
719
   returns FALSE for bad chars in the name - this allows calling code to determine what the problem was.
720
   aliases cannot be:
721
   	bad chars: anything except a-z 0-9 and underscore
722
   	bad names: empty string, pure numeric, pure underscore
723
   	reserved words: pre-defined service/protocol/port names which should not be ambiguous, and the words "port" and  "pass" */
724

    
725
function is_validaliasname($name) {
726
	/* Array of reserved words */
727
	$reserved = array("port", "pass");
728

    
729
	if (!is_string($name) || strlen($name) >= 32 || preg_match('/(^_*$|^\d*$|[^a-z0-9_])/i', $name))
730
		return false;
731
	if (in_array($name, $reserved, true) || getservbyname($name, "tcp") || getservbyname($name, "udp") || getprotobyname($name))
732
		return; /* return NULL */
733
	return true;
734
}
735

    
736
/* returns true if $port is a valid TCP/UDP port */
737
function is_port($port) {
738
	if (getservbyname($port, "tcp") || getservbyname($port, "udp"))
739
		return true;
740
	if (!ctype_digit($port))
741
		return false;
742
	else if ((intval($port) < 1) || (intval($port) > 65535))
743
		return false;
744
	return true;
745
}
746

    
747
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
748
function is_portrange($portrange) {
749
	$ports = explode(":", $portrange);
750

    
751
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
752
}
753

    
754
/* returns true if $port is a valid port number or an alias thereof */
755
function is_portoralias($port) {
756
	global $config;
757

    
758
	if (is_alias($port)) {
759
		if (is_array($config['aliases']['alias'])) {
760
			foreach ($config['aliases']['alias'] as $alias) {
761
				if ($alias['name'] == $port && preg_match("/port/i", $alias['type']))
762
					return true;
763
				}
764
			}
765
			return false;
766
	} else
767
		return is_port($port);
768
}
769

    
770
/* create ranges of sequential port numbers (200:215) and remove duplicates */
771
function group_ports($ports) {
772
	if (!is_array($ports) || empty($ports))
773
		return;
774

    
775
	$uniq = array();
776
	foreach ($ports as $port) {
777
		if (is_portrange($port)) {
778
			list($begin, $end) = explode(":", $port);
779
			if ($begin > $end) {
780
				$aux = $begin;
781
				$begin = $end;
782
				$end = $aux;
783
			}
784
			for ($i = $begin; $i <= $end; $i++)
785
				if (!in_array($i, $uniq))
786
					$uniq[] = $i;
787
		} else if (is_port($port)) {
788
			if (!in_array($port, $uniq))
789
				$uniq[] = $port;
790
		}
791
	}
792
	sort($uniq, SORT_NUMERIC);
793

    
794
	$result = array();
795
	foreach ($uniq as $idx => $port) {
796
		if ($idx == 0) {
797
			$result[] = $port;
798
			continue;
799
		}
800

    
801
		$last = end($result);
802
		if (is_portrange($last))
803
			list($begin, $end) = explode(":", $last);
804
		else
805
			$begin = $end = $last;
806

    
807
		if ($port == ($end+1)) {
808
			$end++;
809
			$result[count($result)-1] = "{$begin}:{$end}";
810
		} else {
811
			$result[] = $port;
812
		}
813
	}
814

    
815
	return $result;
816
}
817

    
818
/* returns true if $val is a valid shaper bandwidth value */
819
function is_valid_shaperbw($val) {
820
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
821
}
822

    
823
/* returns true if $test is in the range between $start and $end */
824
function is_inrange_v4($test, $start, $end) {
825
	if ( (ip2ulong($test) <= ip2ulong($end)) && (ip2ulong($test) >= ip2ulong($start)) )
826
		return true;
827
	else
828
		return false;
829
}
830

    
831
/* returns true if $test is in the range between $start and $end */
832
function is_inrange_v6($test, $start, $end) {
833
	if ( (inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start)) )
834
		return true;
835
	else
836
		return false;
837
}
838

    
839
/* returns true if $test is in the range between $start and $end */
840
function is_inrange($test, $start, $end) {
841
	return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
842
}
843

    
844
/* XXX: return the configured carp interface list */
845
function get_configured_carp_interface_list($carpinterface = '', $family = 'inet', $what = 'ip') {
846
	global $config;
847

    
848
	$iflist = array();
849

    
850
	if(is_array($config['virtualip']['vip'])) {
851
		$viparr = &$config['virtualip']['vip'];
852
		foreach ($viparr as $vip) {
853
			switch ($vip['mode']) {
854
			case "carp":
855
				if (!empty($carpinterface)) {
856
					if ($carpinterface == "{$vip['interface']}_vip{$vip['vhid']}") {
857
						switch ($what) {
858
						case 'subnet':
859
							if ($family == 'inet' && is_ipaddrv4($vip['subnet']))
860
								return "{$vip['subnet']}/{$vip['subnet_bits']}";
861
							else if ($family == 'inet6' && is_ipaddrv6($vip['subnet']))
862
								return "{$vip['subnet']}/{$vip['subnet_bits']}";
863
							break;
864
						case 'iface':
865
							if ($family == 'inet' && is_ipaddrv4($vip['subnet']))
866
								return $vip['interface'];
867
							else if ($family == 'inet6' && is_ipaddrv6($vip['subnet']))
868
								return $vip['interface'];
869
							break;
870
						case 'vip':
871
							if ($family == 'inet' && is_ipaddrv4($vip['subnet']))
872
								return $vip;
873
							else if ($family == 'inet6' && is_ipaddrv6($vip['subnet']))
874
								return $vip;
875
							break;
876
						case 'ip':
877
						default:
878
							if ($family == 'inet' && is_ipaddrv4($vip['subnet']))
879
								return $vip['subnet'];
880
							else if ($family == 'inet6' && is_ipaddrv6($vip['subnet']))
881
								return $vip['subnet'];
882
							break;
883
						}
884
					}
885
				} else {
886
					$iflist["{$vip['interface']}_vip{$vip['vhid']}"] = $vip['subnet'];
887
				}
888
				break;
889
			}
890
		}
891
	}
892

    
893
	return $iflist;
894
}
895

    
896
/* return the configured IP aliases list */
897
function get_configured_ip_aliases_list($returnfullentry = false) {
898
	global $config;
899

    
900
	$alias_list=array();
901

    
902
	if(is_array($config['virtualip']['vip'])) {
903
		$viparr = &$config['virtualip']['vip'];
904
		foreach ($viparr as $vip) {
905
			if ($vip['mode']=="ipalias") {
906
				if ($returnfullentry)
907
					$alias_list[$vip['subnet']] = $vip;
908
				else
909
					$alias_list[$vip['subnet']] = $vip['interface'];
910
			}
911
		}
912
	}
913

    
914
	return $alias_list;
915
}
916

    
917
/* return all configured aliases list (IP, carp, proxyarp and other) */
918
function get_configured_vips_list() {
919
	global $config;
920

    
921
	$alias_list=array();
922

    
923
	if(is_array($config['virtualip']['vip'])) {
924
		$viparr = &$config['virtualip']['vip'];
925
		foreach ($viparr as $vip) {
926
			if ($vip['mode'] == "carp")
927
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => "{$vip['interface']}_vip{$vip['vhid']}");
928
			else
929
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
930
		}
931
	}
932

    
933
	return $alias_list;
934
}
935

    
936
/* comparison function for sorting by the order in which interfaces are normally created */
937
function compare_interface_friendly_names($a, $b) {
938
	if ($a == $b)
939
		return 0;
940
	else if ($a == 'wan')
941
		return -1;
942
	else if ($b == 'wan')
943
		return 1;
944
	else if ($a == 'lan')
945
		return -1;
946
	else if ($b == 'lan')
947
		return 1;
948

    
949
	return strnatcmp($a, $b);
950
}
951

    
952
/* return the configured interfaces list. */
953
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
954
	global $config;
955

    
956
	$iflist = array();
957

    
958
	/* if list */
959
	foreach($config['interfaces'] as $if => $ifdetail) {
960
		if ($only_opt && ($if == "wan" || $if == "lan"))
961
			continue;
962
		if (isset($ifdetail['enable']) || $withdisabled == true)
963
			$iflist[$if] = $if;
964
	}
965

    
966
	return $iflist;
967
}
968

    
969
/* return the configured interfaces list. */
970
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
971
	global $config;
972

    
973
	$iflist = array();
974

    
975
	/* if list */
976
	foreach($config['interfaces'] as $if => $ifdetail) {
977
		if ($only_opt && ($if == "wan" || $if == "lan"))
978
			continue;
979
		if (isset($ifdetail['enable']) || $withdisabled == true) {
980
			$tmpif = get_real_interface($if);
981
			if (!empty($tmpif))
982
				$iflist[$tmpif] = $if;
983
		}
984
	}
985

    
986
	return $iflist;
987
}
988

    
989
/* return the configured interfaces list with their description. */
990
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
991
	global $config;
992

    
993
	$iflist = array();
994

    
995
	/* if list */
996
	foreach($config['interfaces'] as $if => $ifdetail) {
997
		if ($only_opt && ($if == "wan" || $if == "lan"))
998
			continue;
999
		if (isset($ifdetail['enable']) || $withdisabled == true) {
1000
			if(empty($ifdetail['descr']))
1001
				$iflist[$if] = strtoupper($if);
1002
			else
1003
				$iflist[$if] = strtoupper($ifdetail['descr']);
1004
		}
1005
	}
1006

    
1007
	return $iflist;
1008
}
1009

    
1010
/*
1011
 *   get_configured_ip_addresses() - Return a list of all configured
1012
 *   interfaces IP Addresses
1013
 *
1014
 */
1015
function get_configured_ip_addresses() {
1016
	global $config;
1017

    
1018
	if (!function_exists('get_interface_ip'))
1019
		require_once("interfaces.inc");
1020
	$ip_array = array();
1021
	$interfaces = get_configured_interface_list();
1022
	if (is_array($interfaces)) {
1023
		foreach($interfaces as $int) {
1024
			$ipaddr = get_interface_ip($int);
1025
			$ip_array[$int] = $ipaddr;
1026
		}
1027
	}
1028
	$interfaces = get_configured_carp_interface_list();
1029
	if (is_array($interfaces))
1030
		foreach($interfaces as $int => $ipaddr)
1031
			$ip_array[$int] = $ipaddr;
1032

    
1033
	/* pppoe server */
1034
	if (is_array($config['pppoes']) && is_array($config['pppoes']['pppoe'])) {
1035
		foreach($config['pppoes']['pppoe'] as $pppoe) {
1036
			if ($pppoe['mode'] == "server") {
1037
				if(is_ipaddr($pppoe['localip'])) {
1038
					$int = "pppoes". $pppoe['pppoeid'];
1039
					$ip_array[$int] = $pppoe['localip'];
1040
				}
1041
			}
1042
		}
1043
	}
1044

    
1045
	return $ip_array;
1046
}
1047

    
1048
/*
1049
 *   get_configured_ipv6_addresses() - Return a list of all configured
1050
 *   interfaces IPv6 Addresses
1051
 *
1052
 */
1053
function get_configured_ipv6_addresses() {
1054
	require_once("interfaces.inc");
1055
	$ipv6_array = array();
1056
	$interfaces = get_configured_interface_list();
1057
	if(is_array($interfaces)) {
1058
		foreach($interfaces as $int) {
1059
			$ipaddrv6 = get_interface_ipv6($int);
1060
			$ipv6_array[$int] = $ipaddrv6;
1061
		}
1062
	}
1063
	$interfaces = get_configured_carp_interface_list();
1064
	if(is_array($interfaces))
1065
		foreach($interfaces as $int => $ipaddrv6)
1066
			$ipv6_array[$int] = $ipaddrv6;
1067
	return $ipv6_array;
1068
}
1069

    
1070
/*
1071
 *   get_interface_list() - Return a list of all physical interfaces
1072
 *   along with MAC and status.
1073
 *
1074
 *   $mode = "active" - use ifconfig -lu
1075
 *           "media"  - use ifconfig to check physical connection
1076
 *			status (much slower)
1077
 */
1078
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
1079
	global $config;
1080
	$upints = array();
1081
	/* get a list of virtual interface types */
1082
	if(!$vfaces) {
1083
		$vfaces = array (
1084
				'bridge',
1085
				'ppp',
1086
				'pppoe',
1087
				'pptp',
1088
				'l2tp',
1089
				'sl',
1090
				'gif',
1091
				'gre',
1092
				'faith',
1093
				'lo',
1094
				'ng',
1095
				'_vlan',
1096
				'_wlan',
1097
				'pflog',
1098
				'plip',
1099
				'pfsync',
1100
				'enc',
1101
				'tun',
1102
				'carp',
1103
				'lagg',
1104
				'vip',
1105
				'ipfw'
1106
		);
1107
	}
1108
	switch($mode) {
1109
	case "active":
1110
		$upints = pfSense_interface_listget(IFF_UP);
1111
		break;
1112
	case "media":
1113
		$intlist = pfSense_interface_listget();
1114
		$ifconfig = "";
1115
		exec("/sbin/ifconfig -a", $ifconfig);
1116
		$regexp = '/(' . implode('|', $intlist) . '):\s/';
1117
		$ifstatus = preg_grep('/status:/', $ifconfig);
1118
		foreach($ifstatus as $status) {
1119
			$int = array_shift($intlist);
1120
			if(stristr($status, "active")) $upints[] = $int;
1121
		}
1122
		break;
1123
	default:
1124
		$upints = pfSense_interface_listget();
1125
		break;
1126
	}
1127
	/* build interface list with netstat */
1128
	$linkinfo = "";
1129
	exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
1130
	array_shift($linkinfo);
1131
	/* build ip address list with netstat */
1132
	$ipinfo = "";
1133
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
1134
	array_shift($ipinfo);
1135
	foreach($linkinfo as $link) {
1136
		$friendly = "";
1137
		$alink = explode(" ", $link);
1138
		$ifname = rtrim(trim($alink[0]), '*');
1139
		/* trim out all numbers before checking for vfaces */
1140
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
1141
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
1142
			$toput = array(
1143
					"mac" => trim($alink[1]),
1144
					"up" => in_array($ifname, $upints)
1145
				);
1146
			foreach($ipinfo as $ip) {
1147
				$aip = explode(" ", $ip);
1148
				if($aip[0] == $ifname) {
1149
					$toput['ipaddr'] = $aip[1];
1150
				}
1151
			}
1152
			if (is_array($config['interfaces'])) {
1153
				foreach($config['interfaces'] as $name => $int)
1154
					if($int['if'] == $ifname) $friendly = $name;
1155
			}
1156
			switch($keyby) {
1157
			case "physical":
1158
				if($friendly != "") {
1159
					$toput['friendly'] = $friendly;
1160
				}
1161
				$dmesg_arr = array();
1162
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
1163
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
1164
				$toput['dmesg'] = $dmesg[1][0];
1165
				$iflist[$ifname] = $toput;
1166
				break;
1167
			case "ppp":
1168

    
1169
			case "friendly":
1170
				if($friendly != "") {
1171
					$toput['if'] = $ifname;
1172
					$iflist[$friendly] = $toput;
1173
				}
1174
				break;
1175
			}
1176
		}
1177
	}
1178
	return $iflist;
1179
}
1180

    
1181
/****f* util/log_error
1182
* NAME
1183
*   log_error  - Sends a string to syslog.
1184
* INPUTS
1185
*   $error     - string containing the syslog message.
1186
* RESULT
1187
*   null
1188
******/
1189
function log_error($error) {
1190
	global $g;
1191
	$page = $_SERVER['SCRIPT_NAME'];
1192
	if (empty($page)) {
1193
		$files = get_included_files();
1194
		$page = basename($files[0]);
1195
	}
1196
	syslog(LOG_ERR, "$page: $error");
1197
	if ($g['debug'])
1198
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1199
	return;
1200
}
1201

    
1202
/****f* util/log_auth
1203
* NAME
1204
*   log_auth   - Sends a string to syslog as LOG_AUTH facility
1205
* INPUTS
1206
*   $error     - string containing the syslog message.
1207
* RESULT
1208
*   null
1209
******/
1210
function log_auth($error) {
1211
	global $g;
1212
	$page = $_SERVER['SCRIPT_NAME'];
1213
	syslog(LOG_AUTH, "$page: $error");
1214
	if ($g['debug'])
1215
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1216
	return;
1217
}
1218

    
1219
/****f* util/exec_command
1220
 * NAME
1221
 *   exec_command - Execute a command and return a string of the result.
1222
 * INPUTS
1223
 *   $command   - String of the command to be executed.
1224
 * RESULT
1225
 *   String containing the command's result.
1226
 * NOTES
1227
 *   This function returns the command's stdout and stderr.
1228
 ******/
1229
function exec_command($command) {
1230
	$output = array();
1231
	exec($command . ' 2>&1', $output);
1232
	return(implode("\n", $output));
1233
}
1234

    
1235
/* wrapper for exec() */
1236
function mwexec($command, $mute = false, $clearsigmask = false) {
1237
	global $g;
1238

    
1239
	if ($g['debug']) {
1240
		if (!$_SERVER['REMOTE_ADDR'])
1241
			echo "mwexec(): $command\n";
1242
	}
1243
	$oarr = array();
1244
	$retval = 0;
1245

    
1246
	if ($clearsigmask) {
1247
		$oldset = array();
1248
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1249
	}
1250
	$garbage = exec("$command 2>&1", $oarr, $retval);
1251
	if ($clearsigmask) {
1252
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1253
	}
1254

    
1255
	if(isset($config['system']['developerspew']))
1256
		$mute = false;
1257
	if(($retval <> 0) && ($mute === false)) {
1258
		$output = implode(" ", $oarr);
1259
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
1260
		unset($output);
1261
	}
1262
	unset($oarr);
1263
	return $retval;
1264
}
1265

    
1266
/* wrapper for exec() in background */
1267
function mwexec_bg($command, $clearsigmask = false) {
1268
	global $g;
1269

    
1270
	if ($g['debug']) {
1271
		if (!$_SERVER['REMOTE_ADDR'])
1272
			echo "mwexec(): $command\n";
1273
	}
1274

    
1275
	if ($clearsigmask) {
1276
		$oldset = array();
1277
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1278
	}
1279
	$_gb = exec("/usr/bin/nohup $command > /dev/null 2>&1 &");
1280
	if ($clearsigmask) {
1281
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1282
	}
1283
	unset($_gb);
1284
}
1285

    
1286
/* unlink a file, if it exists */
1287
function unlink_if_exists($fn) {
1288
	$to_do = glob($fn);
1289
	if(is_array($to_do)) {
1290
		foreach($to_do as $filename)
1291
			@unlink($filename);
1292
	} else {
1293
		@unlink($fn);
1294
	}
1295
}
1296
/* make a global alias table (for faster lookups) */
1297
function alias_make_table($config) {
1298
	global $aliastable;
1299

    
1300
	$aliastable = array();
1301

    
1302
	if (is_array($config['aliases']['alias'])) {
1303
		foreach ($config['aliases']['alias'] as $alias) {
1304
			if ($alias['name'])
1305
				$aliastable[$alias['name']] = $alias['address'];
1306
		}
1307
	}
1308
}
1309

    
1310
/* check if an alias exists */
1311
function is_alias($name) {
1312
	global $aliastable;
1313

    
1314
	return isset($aliastable[$name]);
1315
}
1316

    
1317
function alias_get_type($name) {
1318
	global $config;
1319

    
1320
	if (is_array($config['aliases']['alias'])) {
1321
		foreach ($config['aliases']['alias'] as $alias) {
1322
			if ($name == $alias['name'])
1323
				return $alias['type'];
1324
		}
1325
	}
1326

    
1327
	return "";
1328
}
1329

    
1330
/* expand a host or network alias, if necessary */
1331
function alias_expand($name) {
1332
	global $aliastable;
1333

    
1334
	if (isset($aliastable[$name]))
1335
		return "\${$name}";
1336
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name) || is_portrange($name))
1337
		return "{$name}";
1338
	else
1339
		return null;
1340
}
1341

    
1342
function alias_expand_urltable($name) {
1343
	global $config;
1344
	$urltable_prefix = "/var/db/aliastables/";
1345
	$urltable_filename = $urltable_prefix . $name . ".txt";
1346

    
1347
	if (is_array($config['aliases']['alias'])) {
1348
		foreach ($config['aliases']['alias'] as $alias) {
1349
			if (preg_match("/urltable/i", $alias['type']) && ($alias['name'] == $name)) {
1350
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1351
					return $urltable_filename;
1352
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1353
					return $urltable_filename;
1354
			}
1355
		}
1356
	}
1357
	return null;
1358
}
1359

    
1360
function subnet_size($subnet) {
1361
	if (is_subnetv4($subnet)) {
1362
		list ($ip, $bits) = explode("/", $subnet);
1363
		return round(exp(log(2) * (32 - $bits)));
1364
	}
1365
	else if (is_subnetv6($subnet)) {
1366
		list ($ip, $bits) = explode("/", $subnet);
1367
		return round(exp(log(2) * (128 - $bits)));
1368
	}
1369
	else {
1370
		return 0;
1371
	}
1372
}
1373

    
1374
function subnet_expand($subnet) {
1375
	if (is_subnetv4($subnet)) {
1376
		return subnetv4_expand($subnet);
1377
	} else if (is_subnetv6($subnet)) {
1378
		return subnetv6_expand($subnet);
1379
	} else {
1380
		return $subnet;
1381
	}
1382
}
1383

    
1384
function subnetv4_expand($subnet) {
1385
	$result = array();
1386
	list ($ip, $bits) = explode("/", $subnet);
1387
	$net  = ip2long($ip);
1388
	$mask = (0xffffffff << (32 - $bits));
1389
	$net &= $mask;
1390
	$size = round(exp(log(2) * (32 - $bits)));
1391
	for ($i = 0; $i < $size; $i += 1) {
1392
		$result[] = long2ip($net | $i);
1393
	}
1394
	return $result;
1395
}
1396

    
1397
/* find out whether two subnets overlap */
1398
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1399

    
1400
	if (!is_numeric($bits1))
1401
		$bits1 = 32;
1402
	if (!is_numeric($bits2))
1403
		$bits2 = 32;
1404

    
1405
	if ($bits1 < $bits2)
1406
		$relbits = $bits1;
1407
	else
1408
		$relbits = $bits2;
1409

    
1410
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1411
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1412

    
1413
	return ($sn1 == $sn2);
1414
}
1415

    
1416
/* find out whether two IPv6 subnets overlap */
1417
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
1418
	$sub1_min = gen_subnetv6($subnet1, $bits1);
1419
	$sub1_max = gen_subnetv6_max($subnet1, $bits1);
1420
	$sub2_min = gen_subnetv6($subnet2, $bits2);
1421
	$sub2_max = gen_subnetv6_max($subnet2, $bits2);
1422

    
1423
	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));
1424
}
1425

    
1426
/* compare two IP addresses */
1427
function ipcmp($a, $b) {
1428
	if (ip_less_than($a, $b))
1429
		return -1;
1430
	else if (ip_greater_than($a, $b))
1431
		return 1;
1432
	else
1433
		return 0;
1434
}
1435

    
1436
/* return true if $addr is in $subnet, false if not */
1437
function ip_in_subnet($addr,$subnet) {
1438
	if(is_ipaddrv6($addr)) {
1439
		return (Net_IPv6::isInNetmask($addr, $subnet));
1440
	} else { /* XXX: Maybe check for IPv4 */
1441
		list($ip, $mask) = explode('/', $subnet);
1442
		$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1443
		return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1444
	}
1445
}
1446

    
1447
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1448
function verify_digital_signature($fname) {
1449
	global $g;
1450

    
1451
	if(!file_exists("/usr/local/sbin/gzsig"))
1452
		return 4;
1453

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

    
1457
/* obtain MAC address given an IP address by looking at the ARP table */
1458
function arp_get_mac_by_ip($ip) {
1459
	mwexec("/sbin/ping -c 1 -t 1 " . escapeshellarg($ip), true);
1460
	$arpoutput = "";
1461
	exec("/usr/sbin/arp -n " . escapeshellarg($ip), $arpoutput);
1462

    
1463
	if ($arpoutput[0]) {
1464
		$arpi = explode(" ", $arpoutput[0]);
1465
		$macaddr = $arpi[3];
1466
		if (is_macaddr($macaddr))
1467
			return $macaddr;
1468
		else
1469
			return false;
1470
	}
1471

    
1472
	return false;
1473
}
1474

    
1475
/* return a fieldname that is safe for xml usage */
1476
function xml_safe_fieldname($fieldname) {
1477
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1478
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1479
			 ':', ',', '.', '\'', '\\'
1480
		);
1481
	return strtolower(str_replace($replace, "", $fieldname));
1482
}
1483

    
1484
function mac_format($clientmac) {
1485
	global $config, $cpzone;
1486

    
1487
	$mac = explode(":", $clientmac);
1488
	$mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1489

    
1490
	switch($mac_format) {
1491
	case 'singledash':
1492
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1493

    
1494
	case 'ietf':
1495
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1496

    
1497
	case 'cisco':
1498
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1499

    
1500
	case 'unformatted':
1501
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1502

    
1503
	default:
1504
		return $clientmac;
1505
	}
1506
}
1507

    
1508
function resolve_retry($hostname, $retries = 5) {
1509

    
1510
	if (is_ipaddr($hostname))
1511
		return $hostname;
1512

    
1513
	for ($i = 0; $i < $retries; $i++) {
1514
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1515
		$ip = gethostbyname($hostname);
1516

    
1517
		if ($ip && $ip != $hostname) {
1518
			/* success */
1519
			return $ip;
1520
		}
1521

    
1522
		sleep(1);
1523
	}
1524

    
1525
	return false;
1526
}
1527

    
1528
function format_bytes($bytes) {
1529
	if ($bytes >= 1073741824) {
1530
		return sprintf("%.2f GB", $bytes/1073741824);
1531
	} else if ($bytes >= 1048576) {
1532
		return sprintf("%.2f MB", $bytes/1048576);
1533
	} else if ($bytes >= 1024) {
1534
		return sprintf("%.0f KB", $bytes/1024);
1535
	} else {
1536
		return sprintf("%d bytes", $bytes);
1537
	}
1538
}
1539

    
1540
function update_filter_reload_status($text) {
1541
	global $g;
1542

    
1543
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1544
}
1545

    
1546
/****** util/return_dir_as_array
1547
 * NAME
1548
 *   return_dir_as_array - Return a directory's contents as an array.
1549
 * INPUTS
1550
 *   $dir          - string containing the path to the desired directory.
1551
 *   $filter_regex - string containing a regular expression to filter file names. Default empty.
1552
 * RESULT
1553
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1554
 ******/
1555
function return_dir_as_array($dir, $filter_regex = '') {
1556
	$dir_array = array();
1557
	if (is_dir($dir)) {
1558
		if ($dh = opendir($dir)) {
1559
			while (($file = readdir($dh)) !== false) {
1560
				if (($file == ".") || ($file == ".."))
1561
					continue;
1562

    
1563
				if (empty($filter_regex) || preg_match($filter_regex, $file))
1564
					array_push($dir_array, $file);
1565
			}
1566
			closedir($dh);
1567
		}
1568
	}
1569
	return $dir_array;
1570
}
1571

    
1572
function run_plugins($directory) {
1573
	global $config, $g;
1574

    
1575
	/* process packager manager custom rules */
1576
	$files = return_dir_as_array($directory);
1577
	if (is_array($files)) {
1578
		foreach ($files as $file) {
1579
			if (stristr($file, ".sh") == true)
1580
				mwexec($directory . $file . " start");
1581
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc"))
1582
				require_once($directory . "/" . $file);
1583
		}
1584
	}
1585
}
1586

    
1587
/*
1588
 *    safe_mkdir($path, $mode = 0755)
1589
 *    create directory if it doesn't already exist and isn't a file!
1590
 */
1591
function safe_mkdir($path, $mode=0755) {
1592
	global $g;
1593

    
1594
	if (!is_file($path) && !is_dir($path)) {
1595
		return @mkdir($path, $mode, true);
1596
	} else {
1597
		return false;
1598
	}
1599
}
1600

    
1601
/*
1602
 * make_dirs($path, $mode = 0755)
1603
 * create directory tree recursively (mkdir -p)
1604
 */
1605
function make_dirs($path, $mode = 0755) {
1606
	$base = '';
1607
	foreach (explode('/', $path) as $dir) {
1608
		$base .= "/$dir";
1609
		if (!is_dir($base)) {
1610
			if (!@mkdir($base, $mode))
1611
				return false;
1612
		}
1613
	}
1614
	return true;
1615
}
1616

    
1617
/*
1618
 * get_sysctl($names)
1619
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1620
 * name) and return an array of key/value pairs set for those that exist
1621
 */
1622
function get_sysctl($names) {
1623
	if (empty($names))
1624
		return array();
1625

    
1626
	if (is_array($names)) {
1627
		$name_list = array();
1628
		foreach ($names as $name) {
1629
			$name_list[] = escapeshellarg($name);
1630
		}
1631
	} else
1632
		$name_list = array(escapeshellarg($names));
1633

    
1634
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1635
	$values = array();
1636
	foreach ($output as $line) {
1637
		$line = explode(": ", $line, 2);
1638
		if (count($line) == 2)
1639
			$values[$line[0]] = $line[1];
1640
	}
1641

    
1642
	return $values;
1643
}
1644

    
1645
/*
1646
 * get_single_sysctl($name)
1647
 * Wrapper for get_sysctl() to simplify read of a single sysctl value
1648
 * return the value for sysctl $name or empty string if it doesn't exist
1649
 */
1650
function get_single_sysctl($name) {
1651
	if (empty($name))
1652
		return "";
1653

    
1654
	$value = get_sysctl($name);
1655
	if (empty($value) || !isset($value[$name]))
1656
		return "";
1657

    
1658
	return $value[$name];
1659
}
1660

    
1661
/*
1662
 * set_sysctl($value_list)
1663
 * Set sysctl OID's listed as key/value pairs and return
1664
 * an array with keys set for those that succeeded
1665
 */
1666
function set_sysctl($values) {
1667
	if (empty($values))
1668
		return array();
1669

    
1670
	$value_list = array();
1671
	foreach ($values as $key => $value) {
1672
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1673
	}
1674

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

    
1677
	/* Retry individually if failed (one or more read-only) */
1678
	if ($success <> 0 && count($value_list) > 1) {
1679
		foreach ($value_list as $value) {
1680
			exec("/sbin/sysctl -i " . $value, $output);
1681
		}
1682
	}
1683

    
1684
	$ret = array();
1685
	foreach ($output as $line) {
1686
		$line = explode(": ", $line, 2);
1687
		if (count($line) == 2)
1688
			$ret[$line[0]] = true;
1689
	}
1690

    
1691
	return $ret;
1692
}
1693

    
1694
/*
1695
 * set_single_sysctl($name, $value)
1696
 * Wrapper to set_sysctl() to make it simple to set only one sysctl
1697
 * returns boolean meaning if it suceed
1698
 */
1699
function set_single_sysctl($name, $value) {
1700
	if (empty($name))
1701
		return false;
1702

    
1703
	$result = set_sysctl(array($name => $value));
1704

    
1705
	if (!isset($result[$name]) || $result[$name] != $value)
1706
		return false;
1707

    
1708
	return true;
1709
}
1710

    
1711
/*
1712
 *     get_memory()
1713
 *     returns an array listing the amount of
1714
 *     memory installed in the hardware
1715
 *     [0] net memory available for the OS (FreeBSD) after some is taken by BIOS, video or whatever - e.g. 235 MBytes
1716
 *     [1] real (actual) memory of the system, should be the size of the RAM card/s - e.g. 256 MBytes
1717
 */
1718
function get_memory() {
1719
	$physmem = get_single_sysctl("hw.physmem");
1720
	$realmem = get_single_sysctl("hw.realmem");
1721
	/* convert from bytes to megabytes */
1722
	return array(($physmem/1048576),($realmem/1048576));
1723
}
1724

    
1725
function mute_kernel_msgs() {
1726
	global $config;
1727
	// Do not mute serial console.  The kernel gets very very cranky
1728
	// and will start dishing you cannot control tty errors.
1729
	switch (trim(file_get_contents("/etc/platform"))) {
1730
		case "nanobsd":
1731
		case "jail":
1732
			return;
1733
	}
1734
	if($config['system']['enableserial'])
1735
		return;
1736
	exec("/sbin/conscontrol mute on");
1737
}
1738

    
1739
function unmute_kernel_msgs() {
1740
	global $config;
1741
	// Do not mute serial console.  The kernel gets very very cranky
1742
	// and will start dishing you cannot control tty errors.
1743
	switch (trim(file_get_contents("/etc/platform"))) {
1744
		case "nanobsd":
1745
		case "jail":
1746
			return;
1747
	}
1748
	exec("/sbin/conscontrol mute off");
1749
}
1750

    
1751
function start_devd() {
1752
	global $g;
1753

    
1754
	if ($g['platform'] == 'jail')
1755
		return;
1756
	/* Use the undocumented -q options of devd to quite its log spamming */
1757
	$_gb = exec("/sbin/devd -q");
1758
	sleep(1);
1759
	unset($_gb);
1760
}
1761

    
1762
function is_interface_vlan_mismatch() {
1763
	global $config, $g;
1764

    
1765
	if (is_array($config['vlans']['vlan'])) {
1766
		foreach ($config['vlans']['vlan'] as $vlan) {
1767
			if (does_interface_exist($vlan['if']) == false)
1768
				return true;
1769
		}
1770
	}
1771

    
1772
	return false;
1773
}
1774

    
1775
function is_interface_mismatch() {
1776
	global $config, $g;
1777

    
1778
	$do_assign = false;
1779
	$i = 0;
1780
	$missing_interfaces = array();
1781
	if (is_array($config['interfaces'])) {
1782
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1783
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1784
				// Do not check these interfaces.
1785
				$i++;
1786
				continue;
1787
			}
1788
			else if (does_interface_exist($ifcfg['if']) == false) {
1789
				$missing_interfaces[] = $ifcfg['if'];
1790
				$do_assign = true;
1791
			} else
1792
				$i++;
1793
		}
1794
	}
1795

    
1796
	if (file_exists("{$g['tmp_path']}/assign_complete"))
1797
		$do_assign = false;
1798

    
1799
	if (!empty($missing_interfaces) && $do_assign)
1800
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1801
	else
1802
		@unlink("{$g['tmp_path']}/missing_interfaces");
1803

    
1804
	return $do_assign;
1805
}
1806

    
1807
/* sync carp entries to other firewalls */
1808
function carp_sync_client() {
1809
	global $g;
1810
	send_event("filter sync");
1811
}
1812

    
1813
/****f* util/isAjax
1814
 * NAME
1815
 *   isAjax - reports if the request is driven from prototype
1816
 * INPUTS
1817
 *   none
1818
 * RESULT
1819
 *   true/false
1820
 ******/
1821
function isAjax() {
1822
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1823
}
1824

    
1825
/****f* util/timeout
1826
 * NAME
1827
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1828
 * INPUTS
1829
 *   optional, seconds to wait before timeout. Default 9 seconds.
1830
 * RESULT
1831
 *   returns 1 char of user input or null if no input.
1832
 ******/
1833
function timeout($timer = 9) {
1834
	while(!isset($key)) {
1835
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1836
		else { echo chr(8). "{$timer}"; }
1837
		`/bin/stty -icanon min 0 time 25`;
1838
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1839
		`/bin/stty icanon`;
1840
		if ($key == '')
1841
			unset($key);
1842
		$timer--;
1843
		if ($timer == 0)
1844
			break;
1845
	}
1846
	return $key;
1847
}
1848

    
1849
/****f* util/msort
1850
 * NAME
1851
 *   msort - sort array
1852
 * INPUTS
1853
 *   $array to be sorted, field to sort by, direction of sort
1854
 * RESULT
1855
 *   returns newly sorted array
1856
 ******/
1857
function msort($array, $id="id", $sort_ascending=true) {
1858
	$temp_array = array();
1859
	while(count($array)>0) {
1860
		$lowest_id = 0;
1861
		$index=0;
1862
		foreach ($array as $item) {
1863
			if (isset($item[$id])) {
1864
				if ($array[$lowest_id][$id]) {
1865
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1866
						$lowest_id = $index;
1867
					}
1868
				}
1869
			}
1870
			$index++;
1871
		}
1872
		$temp_array[] = $array[$lowest_id];
1873
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1874
	}
1875
	if ($sort_ascending) {
1876
		return $temp_array;
1877
	} else {
1878
		return array_reverse($temp_array);
1879
	}
1880
}
1881

    
1882
/****f* util/is_URL
1883
 * NAME
1884
 *   is_URL
1885
 * INPUTS
1886
 *   string to check
1887
 * RESULT
1888
 *   Returns true if item is a URL
1889
 ******/
1890
function is_URL($url) {
1891
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1892
	if($match)
1893
		return true;
1894
	return false;
1895
}
1896

    
1897
function is_file_included($file = "") {
1898
	$files = get_included_files();
1899
	if (in_array($file, $files))
1900
		return true;
1901

    
1902
	return false;
1903
}
1904

    
1905
/*
1906
 * Replace a value on a deep associative array using regex
1907
 */
1908
function array_replace_values_recursive($data, $match, $replace) {
1909
	if (empty($data))
1910
		return $data;
1911

    
1912
	if (is_string($data))
1913
		$data = preg_replace("/{$match}/", $replace, $data);
1914
	else if (is_array($data))
1915
		foreach ($data as $k => $v)
1916
			$data[$k] = array_replace_values_recursive($v, $match, $replace);
1917

    
1918
	return $data;
1919
}
1920

    
1921
/*
1922
	This function was borrowed from a comment on PHP.net at the following URL:
1923
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1924
 */
1925
function array_merge_recursive_unique($array0, $array1) {
1926

    
1927
	$arrays = func_get_args();
1928
	$remains = $arrays;
1929

    
1930
	// We walk through each arrays and put value in the results (without
1931
	// considering previous value).
1932
	$result = array();
1933

    
1934
	// loop available array
1935
	foreach($arrays as $array) {
1936

    
1937
		// The first remaining array is $array. We are processing it. So
1938
		// we remove it from remaing arrays.
1939
		array_shift($remains);
1940

    
1941
		// We don't care non array param, like array_merge since PHP 5.0.
1942
		if(is_array($array)) {
1943
			// Loop values
1944
			foreach($array as $key => $value) {
1945
				if(is_array($value)) {
1946
					// we gather all remaining arrays that have such key available
1947
					$args = array();
1948
					foreach($remains as $remain) {
1949
						if(array_key_exists($key, $remain)) {
1950
							array_push($args, $remain[$key]);
1951
						}
1952
					}
1953

    
1954
					if(count($args) > 2) {
1955
						// put the recursion
1956
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1957
					} else {
1958
						foreach($value as $vkey => $vval) {
1959
							$result[$key][$vkey] = $vval;
1960
						}
1961
					}
1962
				} else {
1963
					// simply put the value
1964
					$result[$key] = $value;
1965
				}
1966
			}
1967
		}
1968
	}
1969
	return $result;
1970
}
1971

    
1972

    
1973
/*
1974
 * converts a string like "a,b,c,d"
1975
 * into an array like array("a" => "b", "c" => "d")
1976
 */
1977
function explode_assoc($delimiter, $string) {
1978
	$array = explode($delimiter, $string);
1979
	$result = array();
1980
	$numkeys = floor(count($array) / 2);
1981
	for ($i = 0; $i < $numkeys; $i += 1) {
1982
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1983
	}
1984
	return $result;
1985
}
1986

    
1987
function get_staticroutes($returnsubnetsonly = false, $returnhostnames = false) {
1988
	global $config, $aliastable;
1989

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

    
1994
	$allstaticroutes = array();
1995
	$allsubnets = array();
1996
	/* Loop through routes and expand aliases as we find them. */
1997
	foreach ($config['staticroutes']['route'] as $route) {
1998
		if (is_alias($route['network'])) {
1999
			if (!isset($aliastable[$route['network']]))
2000
				continue;
2001

    
2002
			$subnets = preg_split('/\s+/', $aliastable[$route['network']]);
2003
			foreach ($subnets as $net) {
2004
				if (!is_subnet($net)) {
2005
					if (is_ipaddrv4($net))
2006
						$net .= "/32";
2007
					else if (is_ipaddrv6($net))
2008
						$net .= "/128";
2009
					else if ($returnhostnames === false || !is_fqdn($net))
2010
						continue;
2011
				}
2012
				$temproute = $route;
2013
				$temproute['network'] = $net;
2014
				$allstaticroutes[] = $temproute;
2015
				$allsubnets[] = $net;
2016
			}
2017
		} elseif (is_subnet($route['network'])) {
2018
			$allstaticroutes[] = $route;
2019
			$allsubnets[] = $route['network'];
2020
		}
2021
	}
2022
	if ($returnsubnetsonly)
2023
		return $allsubnets;
2024
	else
2025
		return $allstaticroutes;
2026
}
2027

    
2028
/****f* util/get_alias_list
2029
 * NAME
2030
 *   get_alias_list - Provide a list of aliases.
2031
 * INPUTS
2032
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
2033
 * RESULT
2034
 *   Array containing list of aliases.
2035
 *   If $type is unspecified, all aliases are returned.
2036
 *   If $type is a string, all aliases of the type specified in $type are returned.
2037
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
2038
 */
2039
function get_alias_list($type = null) {
2040
	global $config;
2041
	$result = array();
2042
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
2043
		foreach ($config['aliases']['alias'] as $alias) {
2044
			if ($type === null) {
2045
				$result[] = $alias['name'];
2046
			}
2047
			else if (is_array($type)) {
2048
				if (in_array($alias['type'], $type)) {
2049
					$result[] = $alias['name'];
2050
				}
2051
			}
2052
			else if ($type === $alias['type']) {
2053
				$result[] = $alias['name'];
2054
			}
2055
		}
2056
	}
2057
	return $result;
2058
}
2059

    
2060
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
2061
function array_exclude($needle, $haystack) {
2062
	$result = array();
2063
	if (is_array($haystack)) {
2064
		foreach ($haystack as $thing) {
2065
			if ($needle !== $thing) {
2066
				$result[] = $thing;
2067
			}
2068
		}
2069
	}
2070
	return $result;
2071
}
2072

    
2073
function get_current_theme() {
2074
	global $config, $g;
2075
	/*
2076
	 *   if user has selected a custom template, use it.
2077
	 *   otherwise default to pfsense tempalte
2078
	 */
2079
	if (($g["disablethemeselection"] === true) && !empty($g["default_theme"]) && (is_dir($g["www_path"].'/themes/'.$g["default_theme"])))
2080
		$theme = $g["default_theme"];
2081
	elseif($config['theme'] <> "" && (is_dir($g["www_path"].'/themes/'.$config['theme'])))
2082
		$theme = $config['theme'];
2083
	else
2084
		$theme = "pfsense";
2085
	/*
2086
	 *  If this device is an apple ipod/iphone
2087
	 *  switch the theme to one that works with it.
2088
	 */
2089
	$lowres_ua = array("iPhone", "iPod", "iPad", "Android", "BlackBerry", "Opera Mini", "Opera Mobi", "PlayBook", "IEMobile");
2090
	foreach($lowres_ua as $useragent)
2091
		if(strstr($_SERVER['HTTP_USER_AGENT'], $useragent))
2092
			$theme = (empty($g['theme_lowres']) && (is_dir($g["www_path"].'/themes/'.$g['theme_lowres']))) ? "pfsense" : $g['theme_lowres'];
2093
	return $theme;
2094
}
2095

    
2096
/* Define what is preferred, IPv4 or IPv6 */
2097
function prefer_ipv4_or_ipv6() {
2098
	global $config;
2099

    
2100
	if (isset($config['system']['prefer_ipv4']))
2101
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv4");
2102
	else
2103
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv6");
2104
}
2105

    
2106
/* Redirect to page passing parameters via POST */
2107
function post_redirect($page, $params) {
2108
	if (!is_array($params))
2109
		return;
2110

    
2111
	print "<html><body><form action=\"{$page}\" name=\"formredir\" method=\"post\">\n";
2112
	foreach ($params as $key => $value) {
2113
		print "<input type=\"hidden\" name=\"{$key}\" value=\"{$value}\" />\n";
2114
	}
2115
	print "</form><script type=\"text/javascript\">document.formredir.submit();</script>\n";
2116
	print "</body></html>\n";
2117
}
2118

    
2119
/* Locate disks that can be queried for S.M.A.R.T. data. */
2120
function get_smart_drive_list() {
2121
	$disk_list = explode(" ", get_single_sysctl("kern.disks"));
2122
	foreach ($disk_list as $id => $disk) {
2123
		// We only want certain kinds of disks for S.M.A.R.T.
2124
		// 1 is a match, 0 is no match, False is any problem processing the regex
2125
		if (preg_match("/^(ad|da|ada).*[0-9]{1,2}$/", $disk) !== 1) {
2126
			unset($disk_list[$id]);
2127
		}
2128
	}
2129
	sort($disk_list);
2130
	return $disk_list;
2131
}
2132

    
2133
?>
(56-56/68)