Project

General

Profile

Download (55.6 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 (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))
690
		return true;
691
	else
692
		return false;
693
}
694

    
695
/* returns true if $domain is a valid domain name */
696
function is_domain($domain) {
697
	if (!is_string($domain))
698
		return false;
699

    
700
	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))
701
		return true;
702
	else
703
		return false;
704
}
705

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

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

    
720
function is_validaliasname($name) {
721
	/* Array of reserved words */
722
	$reserved = array("port", "pass");
723

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

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

    
742
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
743
function is_portrange($portrange) {
744
	$ports = explode(":", $portrange);
745

    
746
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
747
}
748

    
749
/* returns true if $port is a valid port number or an alias thereof */
750
function is_portoralias($port) {
751
	global $config;
752

    
753
	if (is_alias($port)) {
754
		if (is_array($config['aliases']['alias'])) {
755
			foreach ($config['aliases']['alias'] as $alias) {
756
				if ($alias['name'] == $port && preg_match("/port/i", $alias['type']))
757
					return true;
758
				}
759
			}
760
			return false;
761
	} else
762
		return is_port($port);
763
}
764

    
765
/* create ranges of sequential port numbers (200:215) and remove duplicates */
766
function group_ports($ports) {
767
	if (!is_array($ports) || empty($ports))
768
		return;
769

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

    
789
	$result = array();
790
	foreach ($uniq as $idx => $port) {
791
		if ($idx == 0) {
792
			$result[] = $port;
793
			continue;
794
		}
795

    
796
		$last = end($result);
797
		if (is_portrange($last))
798
			list($begin, $end) = explode(":", $last);
799
		else
800
			$begin = $end = $last;
801

    
802
		if ($port == ($end+1)) {
803
			$end++;
804
			$result[count($result)-1] = "{$begin}:{$end}";
805
		} else {
806
			$result[] = $port;
807
		}
808
	}
809

    
810
	return $result;
811
}
812

    
813
/* returns true if $val is a valid shaper bandwidth value */
814
function is_valid_shaperbw($val) {
815
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
816
}
817

    
818
/* returns true if $test is in the range between $start and $end */
819
function is_inrange_v4($test, $start, $end) {
820
	if ( (ip2ulong($test) <= ip2ulong($end)) && (ip2ulong($test) >= ip2ulong($start)) )
821
		return true;
822
	else
823
		return false;
824
}
825

    
826
/* returns true if $test is in the range between $start and $end */
827
function is_inrange_v6($test, $start, $end) {
828
	if ( (inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start)) )
829
		return true;
830
	else
831
		return false;
832
}
833

    
834
/* returns true if $test is in the range between $start and $end */
835
function is_inrange($test, $start, $end) {
836
	return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
837
}
838

    
839
/* XXX: return the configured carp interface list */
840
function get_configured_carp_interface_list($carpinterface = '', $family = 'inet', $what = 'ip') {
841
	global $config;
842

    
843
	$iflist = array();
844

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

    
888
	return $iflist;
889
}
890

    
891
/* return the configured IP aliases list */
892
function get_configured_ip_aliases_list($returnfullentry = false) {
893
	global $config;
894

    
895
	$alias_list=array();
896

    
897
	if(is_array($config['virtualip']['vip'])) {
898
		$viparr = &$config['virtualip']['vip'];
899
		foreach ($viparr as $vip) {
900
			if ($vip['mode']=="ipalias") {
901
				if ($returnfullentry)
902
					$alias_list[$vip['subnet']] = $vip;
903
				else
904
					$alias_list[$vip['subnet']] = $vip['interface'];
905
			}
906
		}
907
	}
908

    
909
	return $alias_list;
910
}
911

    
912
/* return all configured aliases list (IP, carp, proxyarp and other) */
913
function get_configured_vips_list() {
914
	global $config;
915

    
916
	$alias_list=array();
917

    
918
	if(is_array($config['virtualip']['vip'])) {
919
		$viparr = &$config['virtualip']['vip'];
920
		foreach ($viparr as $vip) {
921
			if ($vip['mode'] == "carp")
922
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => "{$vip['interface']}_vip{$vip['vhid']}");
923
			else
924
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
925
		}
926
	}
927

    
928
	return $alias_list;
929
}
930

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

    
944
	return strnatcmp($a, $b);
945
}
946

    
947
/* return the configured interfaces list. */
948
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
949
	global $config;
950

    
951
	$iflist = array();
952

    
953
	/* if list */
954
	foreach($config['interfaces'] as $if => $ifdetail) {
955
		if ($only_opt && ($if == "wan" || $if == "lan"))
956
			continue;
957
		if (isset($ifdetail['enable']) || $withdisabled == true)
958
			$iflist[$if] = $if;
959
	}
960

    
961
	return $iflist;
962
}
963

    
964
/* return the configured interfaces list. */
965
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
966
	global $config;
967

    
968
	$iflist = array();
969

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

    
981
	return $iflist;
982
}
983

    
984
/* return the configured interfaces list with their description. */
985
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
986
	global $config;
987

    
988
	$iflist = array();
989

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

    
1002
	return $iflist;
1003
}
1004

    
1005
/*
1006
 *   get_configured_ip_addresses() - Return a list of all configured
1007
 *   interfaces IP Addresses
1008
 *
1009
 */
1010
function get_configured_ip_addresses() {
1011
	global $config;
1012

    
1013
	if (!function_exists('get_interface_ip'))
1014
		require_once("interfaces.inc");
1015
	$ip_array = array();
1016
	$interfaces = get_configured_interface_list();
1017
	if (is_array($interfaces)) {
1018
		foreach($interfaces as $int) {
1019
			$ipaddr = get_interface_ip($int);
1020
			$ip_array[$int] = $ipaddr;
1021
		}
1022
	}
1023
	$interfaces = get_configured_carp_interface_list();
1024
	if (is_array($interfaces))
1025
		foreach($interfaces as $int => $ipaddr)
1026
			$ip_array[$int] = $ipaddr;
1027

    
1028
	/* pppoe server */
1029
	if (is_array($config['pppoes']) && is_array($config['pppoes']['pppoe'])) {
1030
		foreach($config['pppoes']['pppoe'] as $pppoe) {
1031
			if ($pppoe['mode'] == "server") {
1032
				if(is_ipaddr($pppoe['localip'])) {
1033
					$int = "pppoes". $pppoe['pppoeid'];
1034
					$ip_array[$int] = $pppoe['localip'];
1035
				}
1036
			}
1037
		}
1038
	}
1039

    
1040
	return $ip_array;
1041
}
1042

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

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

    
1164
			case "friendly":
1165
				if($friendly != "") {
1166
					$toput['if'] = $ifname;
1167
					$iflist[$friendly] = $toput;
1168
				}
1169
				break;
1170
			}
1171
		}
1172
	}
1173
	return $iflist;
1174
}
1175

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

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

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

    
1230
/* wrapper for exec() */
1231
function mwexec($command, $mute = false, $clearsigmask = false) {
1232
	global $g;
1233

    
1234
	if ($g['debug']) {
1235
		if (!$_SERVER['REMOTE_ADDR'])
1236
			echo "mwexec(): $command\n";
1237
	}
1238
	$oarr = array();
1239
	$retval = 0;
1240

    
1241
	if ($clearsigmask) {
1242
		$oldset = array();
1243
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1244
	}
1245
	$garbage = exec("$command 2>&1", $oarr, $retval);
1246
	if ($clearsigmask) {
1247
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1248
	}
1249

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

    
1261
/* wrapper for exec() in background */
1262
function mwexec_bg($command, $clearsigmask = false) {
1263
	global $g;
1264

    
1265
	if ($g['debug']) {
1266
		if (!$_SERVER['REMOTE_ADDR'])
1267
			echo "mwexec(): $command\n";
1268
	}
1269

    
1270
	if ($clearsigmask) {
1271
		$oldset = array();
1272
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1273
	}
1274
	$_gb = exec("/usr/bin/nohup $command > /dev/null 2>&1 &");
1275
	if ($clearsigmask) {
1276
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1277
	}
1278
	unset($_gb);
1279
}
1280

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

    
1295
	$aliastable = array();
1296

    
1297
	if (is_array($config['aliases']['alias'])) {
1298
		foreach ($config['aliases']['alias'] as $alias) {
1299
			if ($alias['name'])
1300
				$aliastable[$alias['name']] = $alias['address'];
1301
		}
1302
	}
1303
}
1304

    
1305
/* check if an alias exists */
1306
function is_alias($name) {
1307
	global $aliastable;
1308

    
1309
	return isset($aliastable[$name]);
1310
}
1311

    
1312
function alias_get_type($name) {
1313
	global $config;
1314

    
1315
	if (is_array($config['aliases']['alias'])) {
1316
		foreach ($config['aliases']['alias'] as $alias) {
1317
			if ($name == $alias['name'])
1318
				return $alias['type'];
1319
		}
1320
	}
1321

    
1322
	return "";
1323
}
1324

    
1325
/* expand a host or network alias, if necessary */
1326
function alias_expand($name) {
1327
	global $aliastable;
1328

    
1329
	if (isset($aliastable[$name]))
1330
		return "\${$name}";
1331
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name) || is_portrange($name))
1332
		return "{$name}";
1333
	else
1334
		return null;
1335
}
1336

    
1337
function alias_expand_urltable($name) {
1338
	global $config;
1339
	$urltable_prefix = "/var/db/aliastables/";
1340
	$urltable_filename = $urltable_prefix . $name . ".txt";
1341

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

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

    
1369
function subnet_expand($subnet) {
1370
	if (is_subnetv4($subnet)) {
1371
		return subnetv4_expand($subnet);
1372
	} else if (is_subnetv6($subnet)) {
1373
		return subnetv6_expand($subnet);
1374
	} else {
1375
		return $subnet;
1376
	}
1377
}
1378

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

    
1392
/* find out whether two subnets overlap */
1393
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1394

    
1395
	if (!is_numeric($bits1))
1396
		$bits1 = 32;
1397
	if (!is_numeric($bits2))
1398
		$bits2 = 32;
1399

    
1400
	if ($bits1 < $bits2)
1401
		$relbits = $bits1;
1402
	else
1403
		$relbits = $bits2;
1404

    
1405
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1406
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1407

    
1408
	return ($sn1 == $sn2);
1409
}
1410

    
1411
/* find out whether two IPv6 subnets overlap */
1412
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
1413
	$sub1_min = gen_subnetv6($subnet1, $bits1);
1414
	$sub1_max = gen_subnetv6_max($subnet1, $bits1);
1415
	$sub2_min = gen_subnetv6($subnet2, $bits2);
1416
	$sub2_max = gen_subnetv6_max($subnet2, $bits2);
1417

    
1418
	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));
1419
}
1420

    
1421
/* compare two IP addresses */
1422
function ipcmp($a, $b) {
1423
	if (ip_less_than($a, $b))
1424
		return -1;
1425
	else if (ip_greater_than($a, $b))
1426
		return 1;
1427
	else
1428
		return 0;
1429
}
1430

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

    
1442
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1443
function verify_digital_signature($fname) {
1444
	global $g;
1445

    
1446
	if(!file_exists("/usr/local/sbin/gzsig"))
1447
		return 4;
1448

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

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

    
1458
	if ($arpoutput[0]) {
1459
		$arpi = explode(" ", $arpoutput[0]);
1460
		$macaddr = $arpi[3];
1461
		if (is_macaddr($macaddr))
1462
			return $macaddr;
1463
		else
1464
			return false;
1465
	}
1466

    
1467
	return false;
1468
}
1469

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

    
1479
function mac_format($clientmac) {
1480
	global $config, $cpzone;
1481

    
1482
	$mac = explode(":", $clientmac);
1483
	$mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1484

    
1485
	switch($mac_format) {
1486
	case 'singledash':
1487
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1488

    
1489
	case 'ietf':
1490
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1491

    
1492
	case 'cisco':
1493
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1494

    
1495
	case 'unformatted':
1496
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1497

    
1498
	default:
1499
		return $clientmac;
1500
	}
1501
}
1502

    
1503
function resolve_retry($hostname, $retries = 5) {
1504

    
1505
	if (is_ipaddr($hostname))
1506
		return $hostname;
1507

    
1508
	for ($i = 0; $i < $retries; $i++) {
1509
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1510
		$ip = gethostbyname($hostname);
1511

    
1512
		if ($ip && $ip != $hostname) {
1513
			/* success */
1514
			return $ip;
1515
		}
1516

    
1517
		sleep(1);
1518
	}
1519

    
1520
	return false;
1521
}
1522

    
1523
function format_bytes($bytes) {
1524
	if ($bytes >= 1073741824) {
1525
		return sprintf("%.2f GB", $bytes/1073741824);
1526
	} else if ($bytes >= 1048576) {
1527
		return sprintf("%.2f MB", $bytes/1048576);
1528
	} else if ($bytes >= 1024) {
1529
		return sprintf("%.0f KB", $bytes/1024);
1530
	} else {
1531
		return sprintf("%d bytes", $bytes);
1532
	}
1533
}
1534

    
1535
function update_filter_reload_status($text) {
1536
	global $g;
1537

    
1538
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1539
}
1540

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

    
1558
				if (empty($filter_regex) || preg_match($filter_regex, $file))
1559
					array_push($dir_array, $file);
1560
			}
1561
			closedir($dh);
1562
		}
1563
	}
1564
	return $dir_array;
1565
}
1566

    
1567
function run_plugins($directory) {
1568
	global $config, $g;
1569

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

    
1582
/*
1583
 *    safe_mkdir($path, $mode = 0755)
1584
 *    create directory if it doesn't already exist and isn't a file!
1585
 */
1586
function safe_mkdir($path, $mode=0755) {
1587
	global $g;
1588

    
1589
	if (!is_file($path) && !is_dir($path)) {
1590
		return @mkdir($path, $mode, true);
1591
	} else {
1592
		return false;
1593
	}
1594
}
1595

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

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

    
1621
	if (is_array($names)) {
1622
		$name_list = array();
1623
		foreach ($names as $name) {
1624
			$name_list[] = escapeshellarg($name);
1625
		}
1626
	} else
1627
		$name_list = array(escapeshellarg($names));
1628

    
1629
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1630
	$values = array();
1631
	foreach ($output as $line) {
1632
		$line = explode(": ", $line, 2);
1633
		if (count($line) == 2)
1634
			$values[$line[0]] = $line[1];
1635
	}
1636

    
1637
	return $values;
1638
}
1639

    
1640
/*
1641
 * get_single_sysctl($name)
1642
 * Wrapper for get_sysctl() to simplify read of a single sysctl value
1643
 * return the value for sysctl $name or empty string if it doesn't exist
1644
 */
1645
function get_single_sysctl($name) {
1646
	if (empty($name))
1647
		return "";
1648

    
1649
	$value = get_sysctl($name);
1650
	if (empty($value) || !isset($value[$name]))
1651
		return "";
1652

    
1653
	return $value[$name];
1654
}
1655

    
1656
/*
1657
 * set_sysctl($value_list)
1658
 * Set sysctl OID's listed as key/value pairs and return
1659
 * an array with keys set for those that succeeded
1660
 */
1661
function set_sysctl($values) {
1662
	if (empty($values))
1663
		return array();
1664

    
1665
	$value_list = array();
1666
	foreach ($values as $key => $value) {
1667
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1668
	}
1669

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

    
1672
	/* Retry individually if failed (one or more read-only) */
1673
	if ($success <> 0 && count($value_list) > 1) {
1674
		foreach ($value_list as $value) {
1675
			exec("/sbin/sysctl -i " . $value, $output);
1676
		}
1677
	}
1678

    
1679
	$ret = array();
1680
	foreach ($output as $line) {
1681
		$line = explode(": ", $line, 2);
1682
		if (count($line) == 2)
1683
			$ret[$line[0]] = true;
1684
	}
1685

    
1686
	return $ret;
1687
}
1688

    
1689
/*
1690
 * set_single_sysctl($name, $value)
1691
 * Wrapper to set_sysctl() to make it simple to set only one sysctl
1692
 * returns boolean meaning if it suceed
1693
 */
1694
function set_single_sysctl($name, $value) {
1695
	if (empty($name))
1696
		return false;
1697

    
1698
	$result = set_sysctl(array($name => $value));
1699

    
1700
	if (!isset($result[$name]) || $result[$name] != $value)
1701
		return false;
1702

    
1703
	return true;
1704
}
1705

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

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

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

    
1746
function start_devd() {
1747
	global $g;
1748

    
1749
	if ($g['platform'] == 'jail')
1750
		return;
1751
	exec("/sbin/devd");
1752
	sleep(1);
1753
}
1754

    
1755
function is_interface_vlan_mismatch() {
1756
	global $config, $g;
1757

    
1758
	if (is_array($config['vlans']['vlan'])) {
1759
		foreach ($config['vlans']['vlan'] as $vlan) {
1760
			if (does_interface_exist($vlan['if']) == false)
1761
				return true;
1762
		}
1763
	}
1764

    
1765
	return false;
1766
}
1767

    
1768
function is_interface_mismatch() {
1769
	global $config, $g;
1770

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

    
1789
	if (file_exists("{$g['tmp_path']}/assign_complete"))
1790
		$do_assign = false;
1791

    
1792
	if (!empty($missing_interfaces) && $do_assign)
1793
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1794
	else
1795
		@unlink("{$g['tmp_path']}/missing_interfaces");
1796

    
1797
	return $do_assign;
1798
}
1799

    
1800
/* sync carp entries to other firewalls */
1801
function carp_sync_client() {
1802
	global $g;
1803
	send_event("filter sync");
1804
}
1805

    
1806
/****f* util/isAjax
1807
 * NAME
1808
 *   isAjax - reports if the request is driven from prototype
1809
 * INPUTS
1810
 *   none
1811
 * RESULT
1812
 *   true/false
1813
 ******/
1814
function isAjax() {
1815
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1816
}
1817

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

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

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

    
1890
function is_file_included($file = "") {
1891
	$files = get_included_files();
1892
	if (in_array($file, $files))
1893
		return true;
1894

    
1895
	return false;
1896
}
1897

    
1898
/*
1899
 * Replace a value on a deep associative array using regex
1900
 */
1901
function array_replace_values_recursive($data, $match, $replace) {
1902
	if (empty($data))
1903
		return $data;
1904

    
1905
	if (is_string($data))
1906
		$data = preg_replace("/{$match}/", $replace, $data);
1907
	else if (is_array($data))
1908
		foreach ($data as $k => $v)
1909
			$data[$k] = array_replace_values_recursive($v, $match, $replace);
1910

    
1911
	return $data;
1912
}
1913

    
1914
/*
1915
	This function was borrowed from a comment on PHP.net at the following URL:
1916
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1917
 */
1918
function array_merge_recursive_unique($array0, $array1) {
1919

    
1920
	$arrays = func_get_args();
1921
	$remains = $arrays;
1922

    
1923
	// We walk through each arrays and put value in the results (without
1924
	// considering previous value).
1925
	$result = array();
1926

    
1927
	// loop available array
1928
	foreach($arrays as $array) {
1929

    
1930
		// The first remaining array is $array. We are processing it. So
1931
		// we remove it from remaing arrays.
1932
		array_shift($remains);
1933

    
1934
		// We don't care non array param, like array_merge since PHP 5.0.
1935
		if(is_array($array)) {
1936
			// Loop values
1937
			foreach($array as $key => $value) {
1938
				if(is_array($value)) {
1939
					// we gather all remaining arrays that have such key available
1940
					$args = array();
1941
					foreach($remains as $remain) {
1942
						if(array_key_exists($key, $remain)) {
1943
							array_push($args, $remain[$key]);
1944
						}
1945
					}
1946

    
1947
					if(count($args) > 2) {
1948
						// put the recursion
1949
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1950
					} else {
1951
						foreach($value as $vkey => $vval) {
1952
							$result[$key][$vkey] = $vval;
1953
						}
1954
					}
1955
				} else {
1956
					// simply put the value
1957
					$result[$key] = $value;
1958
				}
1959
			}
1960
		}
1961
	}
1962
	return $result;
1963
}
1964

    
1965

    
1966
/*
1967
 * converts a string like "a,b,c,d"
1968
 * into an array like array("a" => "b", "c" => "d")
1969
 */
1970
function explode_assoc($delimiter, $string) {
1971
	$array = explode($delimiter, $string);
1972
	$result = array();
1973
	$numkeys = floor(count($array) / 2);
1974
	for ($i = 0; $i < $numkeys; $i += 1) {
1975
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1976
	}
1977
	return $result;
1978
}
1979

    
1980
function get_staticroutes($returnsubnetsonly = false, $returnhostnames = false) {
1981
	global $config, $aliastable;
1982

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

    
1987
	$allstaticroutes = array();
1988
	$allsubnets = array();
1989
	/* Loop through routes and expand aliases as we find them. */
1990
	foreach ($config['staticroutes']['route'] as $route) {
1991
		if (is_alias($route['network'])) {
1992
			if (!isset($aliastable[$route['network']]))
1993
				continue;
1994

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

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

    
2053
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
2054
function array_exclude($needle, $haystack) {
2055
	$result = array();
2056
	if (is_array($haystack)) {
2057
		foreach ($haystack as $thing) {
2058
			if ($needle !== $thing) {
2059
				$result[] = $thing;
2060
			}
2061
		}
2062
	}
2063
	return $result;
2064
}
2065

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

    
2089
/* Define what is preferred, IPv4 or IPv6 */
2090
function prefer_ipv4_or_ipv6() {
2091
	global $config;
2092

    
2093
	if (isset($config['system']['prefer_ipv4']))
2094
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv4");
2095
	else
2096
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv6");
2097
}
2098

    
2099
/* Redirect to page passing parameters via POST */
2100
function post_redirect($page, $params) {
2101
	if (!is_array($params))
2102
		return;
2103

    
2104
	print "<html><body><form action=\"{$page}\" name=\"formredir\" method=\"post\">\n";
2105
	foreach ($params as $key => $value) {
2106
		print "<input type=\"hidden\" name=\"{$key}\" value=\"{$value}\" />\n";
2107
	}
2108
	print "</form><script type=\"text/javascript\">document.formredir.submit();</script>\n";
2109
	print "</body></html>\n";
2110
}
2111

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

    
2126
?>
(56-56/68)