Project

General

Profile

Download (57.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

    
71
	return 0;
72
}
73

    
74
/* kill a process by name */
75
function sigkillbyname($procname, $sig) {
76
	if (isvalidproc($procname)) {
77
		return mwexec("/usr/bin/killall " . escapeshellarg("-{$sig}") . " " . escapeshellarg($procname), true);
78
	}
79
}
80

    
81
/* kill a process by name */
82
function killbyname($procname) {
83
	if (isvalidproc($procname)) {
84
		mwexec("/usr/bin/killall " . escapeshellarg($procname));
85
	}
86
}
87

    
88
function is_subsystem_dirty($subsystem = "") {
89
	global $g;
90

    
91
	if ($subsystem == "") {
92
		return false;
93
	}
94

    
95
	if (file_exists("{$g['varrun_path']}/{$subsystem}.dirty")) {
96
		return true;
97
	}
98

    
99
	return false;
100
}
101

    
102
function mark_subsystem_dirty($subsystem = "") {
103
	global $g;
104

    
105
	if (!file_put_contents("{$g['varrun_path']}/{$subsystem}.dirty", "DIRTY")) {
106
		log_error(sprintf(gettext("WARNING: Could not mark subsystem: %s dirty"), $subsystem));
107
	}
108
}
109

    
110
function clear_subsystem_dirty($subsystem = "") {
111
	global $g;
112

    
113
	@unlink("{$g['varrun_path']}/{$subsystem}.dirty");
114
}
115

    
116
function config_lock() {
117
	return;
118
}
119
function config_unlock() {
120
	return;
121
}
122

    
123
/* lock configuration file */
124
function lock($lock, $op = LOCK_SH) {
125
	global $g, $cfglckkeyconsumers;
126
	if (!$lock) {
127
		die(gettext("WARNING: You must give a name as parameter to lock() function."));
128
	}
129
	if (!file_exists("{$g['tmp_path']}/{$lock}.lock")) {
130
		@touch("{$g['tmp_path']}/{$lock}.lock");
131
		@chmod("{$g['tmp_path']}/{$lock}.lock", 0666);
132
	}
133
	$cfglckkeyconsumers++;
134
	if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
135
		if (flock($fp, $op)) {
136
			return $fp;
137
		} else {
138
			fclose($fp);
139
		}
140
	}
141
}
142

    
143
function try_lock($lock, $timeout = 5) {
144
	global $g, $cfglckkeyconsumers;
145
	if (!$lock) {
146
		die(gettext("WARNING: You must give a name as parameter to try_lock() function."));
147
	}
148
	if (!file_exists("{$g['tmp_path']}/{$lock}.lock")) {
149
		@touch("{$g['tmp_path']}/{$lock}.lock");
150
		@chmod("{$g['tmp_path']}/{$lock}.lock", 0666);
151
	}
152
	$cfglckkeyconsumers++;
153
	if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
154
		$trycounter = 0;
155
		while (!flock($fp, LOCK_EX | LOCK_NB)) {
156
			if ($trycounter >= $timeout) {
157
				fclose($fp);
158
				return NULL;
159
			}
160
			sleep(1);
161
			$trycounter++;
162
		}
163

    
164
		return $fp;
165
	}
166

    
167
	return NULL;
168
}
169

    
170
/* unlock configuration file */
171
function unlock($cfglckkey = 0) {
172
	global $g, $cfglckkeyconsumers;
173
	flock($cfglckkey, LOCK_UN);
174
	fclose($cfglckkey);
175
	return;
176
}
177

    
178
/* unlock forcefully configuration file */
179
function unlock_force($lock) {
180
	global $g;
181

    
182
	@unlink("{$g['tmp_path']}/{$lock}.lock");
183
}
184

    
185
function send_event($cmd) {
186
	global $g;
187

    
188
	if (!isset($g['event_address'])) {
189
		$g['event_address'] = "unix:///var/run/check_reload_status";
190
	}
191

    
192
	$try = 0;
193
	while ($try < 3) {
194
		$fd = @fsockopen($g['event_address']);
195
		if ($fd) {
196
			fwrite($fd, $cmd);
197
			$resp = fread($fd, 4096);
198
			if ($resp != "OK\n") {
199
				log_error("send_event: sent {$cmd} got {$resp}");
200
			}
201
			fclose($fd);
202
			$try = 3;
203
		} else if (!is_process_running("check_reload_status")) {
204
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
205
		}
206
		$try++;
207
	}
208
}
209

    
210
function send_multiple_events($cmds) {
211
	global $g;
212

    
213
	if (!isset($g['event_address'])) {
214
		$g['event_address'] = "unix:///var/run/check_reload_status";
215
	}
216

    
217
	if (!is_array($cmds)) {
218
		return;
219
	}
220

    
221
	while ($try < 3) {
222
		$fd = @fsockopen($g['event_address']);
223
		if ($fd) {
224
			foreach ($cmds as $cmd) {
225
				fwrite($fd, $cmd);
226
				$resp = fread($fd, 4096);
227
				if ($resp != "OK\n") {
228
					log_error("send_event: sent {$cmd} got {$resp}");
229
				}
230
			}
231
			fclose($fd);
232
			$try = 3;
233
		} else if (!is_process_running("check_reload_status")) {
234
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
235
		}
236
		$try++;
237
	}
238
}
239

    
240
function refcount_init($reference) {
241
	$shmid = @shmop_open($reference, "c", 0644, 10);
242
	@shmop_write($shmid, str_pad("0", 10, "\x0", STR_PAD_RIGHT), 0);
243
	@shmop_close($shmid);
244
}
245

    
246
function refcount_reference($reference) {
247
	/* Take out a lock across the shared memory read, increment, write sequence to make it atomic. */
248
	$shm_lck = lock("shm{$reference}", LOCK_EX);
249
	try {
250
		/* NOTE: A warning is generated when shared memory does not exist */
251
		$shmid = @shmop_open($reference, "w", 0, 0);
252
		if (!$shmid) {
253
			refcount_init($reference);
254
			$shmid = @shmop_open($reference, "w", 0, 0);
255
			if (!$shmid) {
256
				log_error(gettext("Could not open shared memory {$reference}"));
257
				unlock($shm_lck);
258
				return;
259
			}
260
		}
261
		$shm_data = @shmop_read($shmid, 0, 10);
262
		$shm_data = intval($shm_data) + 1;
263
		@shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
264
		@shmop_close($shmid);
265
		unlock($shm_lck);
266
	} catch (Exception $e) {
267
		log_error($e->getMessage());
268
		unlock($shm_lck);
269
	}
270

    
271
	return $shm_data;
272
}
273

    
274
function refcount_unreference($reference) {
275
	/* Take out a lock across the shared memory read, decrement, write sequence to make it atomic. */
276
	$shm_lck = lock("shm{$reference}", LOCK_EX);
277
	try {
278
		$shmid = @shmop_open($reference, "w", 0, 0);
279
		if (!$shmid) {
280
			refcount_init($reference);
281
			log_error(gettext("Could not open shared memory {$reference}"));
282
			unlock($shm_lck);
283
			return;
284
		}
285
		$shm_data = @shmop_read($shmid, 0, 10);
286
		$shm_data = intval($shm_data) - 1;
287
		if ($shm_data < 0) {
288
			//debug_backtrace();
289
			log_error(sprintf(gettext("Reference %s is going negative, not doing unreference."), $reference));
290
		} else {
291
			@shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
292
		}
293
		@shmop_close($shmid);
294
		unlock($shm_lck);
295
	} catch (Exception $e) {
296
		log_error($e->getMessage());
297
		unlock($shm_lck);
298
	}
299

    
300
	return $shm_data;
301
}
302

    
303
function refcount_read($reference) {
304
	/* This function just reads the current value of the refcount for information. */
305
	/* There is no need for locking. */
306
	$shmid = @shmop_open($reference, "a", 0, 0);
307
	if (!$shmid) {
308
		log_error(gettext("Could not open shared memory for read {$reference}"));
309
		return -1;
310
	}
311
	$shm_data = @shmop_read($shmid, 0, 10);
312
	@shmop_close($shmid);
313
	return $shm_data;
314
}
315

    
316
function is_module_loaded($module_name) {
317
	$module_name = str_replace(".ko", "", $module_name);
318
	$running = 0;
319
	$_gb = exec("/sbin/kldstat -qn {$module_name} 2>&1", $_gb, $running);
320
	if (intval($running) == 0) {
321
		return true;
322
	} else {
323
		return false;
324
	}
325
}
326

    
327
/* validate non-negative numeric string, or equivalent numeric variable */
328
function is_numericint($arg) {
329
	return (((is_int($arg) && $arg >= 0) || (is_string($arg) && strlen($arg) > 0 && ctype_digit($arg))) ? true : false);
330
}
331

    
332
/* Generate the (human readable) ipv4 or ipv6 subnet address (i.e., netmask, or subnet start IP)
333
   given an (human readable) ipv4 or ipv6 host address and subnet bit count */
334
function gen_subnet($ipaddr, $bits) {
335
	if (($sn = gen_subnetv6($ipaddr, $bits)) == '') {
336
		$sn = gen_subnetv4($ipaddr, $bits);  // try to avoid rechecking IPv4/v6
337
	}
338
	return $sn;
339
}
340

    
341
/* same as gen_subnet() but accepts IPv4 only */
342
function gen_subnetv4($ipaddr, $bits) {
343
	if (is_ipaddrv4($ipaddr) && is_numericint($bits) && $bits <= 32) {
344
		if ($bits == 0) {
345
			return '0.0.0.0';  // avoids <<32
346
		}
347
		return long2ip(ip2long($ipaddr) & ((0xFFFFFFFF << (32 - $bits)) & 0xFFFFFFFF));
348
	}
349
	return "";
350
}
351

    
352
/* same as gen_subnet() but accepts IPv6 only */
353
function gen_subnetv6($ipaddr, $bits) {
354
	if (is_ipaddrv6($ipaddr) && is_numericint($bits) && $bits <= 128) {
355
		return Net_IPv6::compress(Net_IPv6::getNetmask($ipaddr, $bits));
356
	}
357
	return "";
358
}
359

    
360
/* Generate the (human readable) ipv4 or ipv6 subnet end address (i.e., highest address, end IP, or IPv4 broadcast address)
361
   given an (human readable) ipv4 or ipv6 host address and subnet bit count. */
362
function gen_subnet_max($ipaddr, $bits) {
363
	if (($sn = gen_subnetv6_max($ipaddr, $bits)) == '') {
364
		$sn = gen_subnetv4_max($ipaddr, $bits);  // try to avoid rechecking IPv4/v6
365
	}
366
	return $sn;
367
}
368

    
369
/* same as gen_subnet_max() but validates IPv4 only */
370
function gen_subnetv4_max($ipaddr, $bits) {
371
	if (is_ipaddrv4($ipaddr) && is_numericint($bits) && $bits <= 32) {
372
		if ($bits == 32) {
373
			return $ipaddr;
374
		}
375
		return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
376
	}
377
	return "";
378
}
379

    
380
/* same as gen_subnet_max() but validates IPv6 only */
381
function gen_subnetv6_max($ipaddr, $bits) {
382
	if (is_ipaddrv6($ipaddr) && is_numericint($bits) && $bits <= 128) {
383
		$endip_bin = substr(Net_IPv6::_ip2Bin($ipaddr), 0, $bits) . str_repeat('1', 128 - $bits);
384
		return Net_IPv6::compress(Net_IPv6::_bin2Ip($endip_bin));
385
	}
386
	return "";
387
}
388

    
389
/* returns a subnet mask (long given a bit count) */
390
function gen_subnet_mask_long($bits) {
391
	$sm = 0;
392
	for ($i = 0; $i < $bits; $i++) {
393
		$sm >>= 1;
394
		$sm |= 0x80000000;
395
	}
396
	return $sm;
397
}
398

    
399
/* same as above but returns a string */
400
function gen_subnet_mask($bits) {
401
	return long2ip(gen_subnet_mask_long($bits));
402
}
403

    
404
/* Convert long int to IP address, truncating to 32-bits. */
405
function long2ip32($ip) {
406
	return long2ip($ip & 0xFFFFFFFF);
407
}
408

    
409
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
410
function ip2long32($ip) {
411
	return (ip2long($ip) & 0xFFFFFFFF);
412
}
413

    
414
/* Convert IP address to unsigned long int. */
415
function ip2ulong($ip) {
416
	return sprintf("%u", ip2long32($ip));
417
}
418

    
419
/* Find out how many IPs are contained within a given IP range
420
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
421
 */
422
function ip_range_size_v4($startip, $endip) {
423
	if (is_ipaddrv4($startip) && is_ipaddrv4($endip)) {
424
		// Operate as unsigned long because otherwise it wouldn't work
425
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
426
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
427
	}
428
	return -1;
429
}
430

    
431
/* Find the smallest possible subnet mask which can contain a given number of IPs
432
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
433
 */
434
function find_smallest_cidr_v4($number) {
435
	$smallest = 1;
436
	for ($b=32; $b > 0; $b--) {
437
		$smallest = ($number <= pow(2, $b)) ? $b : $smallest;
438
	}
439
	return (32-$smallest);
440
}
441

    
442
/* Return the previous IP address before the given address */
443
function ip_before($ip, $offset = 1) {
444
	return long2ip32(ip2long($ip) - $offset);
445
}
446

    
447
/* Return the next IP address after the given address */
448
function ip_after($ip, $offset = 1) {
449
	return long2ip32(ip2long($ip) + $offset);
450
}
451

    
452
/* Return true if the first IP is 'before' the second */
453
function ip_less_than($ip1, $ip2) {
454
	// Compare as unsigned long because otherwise it wouldn't work when
455
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
456
	return ip2ulong($ip1) < ip2ulong($ip2);
457
}
458

    
459
/* Return true if the first IP is 'after' the second */
460
function ip_greater_than($ip1, $ip2) {
461
	// Compare as unsigned long because otherwise it wouldn't work
462
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
463
	return ip2ulong($ip1) > ip2ulong($ip2);
464
}
465

    
466
/* compare two IP addresses */
467
function ipcmp($a, $b) {
468
	if (ip_less_than($a, $b)) {
469
		return -1;
470
	} else if (ip_greater_than($a, $b)) {
471
		return 1;
472
	} else {
473
		return 0;
474
	}
475
}
476

    
477
/* Convert a range of IPv4 addresses to an array of individual addresses. */
478
/* Note: IPv6 ranges are not yet supported here. */
479
function ip_range_to_address_array($startip, $endip, $max_size = 5000) {
480
	if (!is_ipaddrv4($startip) || !is_ipaddrv4($endip)) {
481
		return false;
482
	}
483

    
484
	if (ip_greater_than($startip, $endip)) {
485
		// Swap start and end so we can process sensibly.
486
		$temp = $startip;
487
		$startip = $endip;
488
		$endip = $temp;
489
	}
490

    
491
	if (ip_range_size_v4($startip, $endip) > $max_size) {
492
		return false;
493
	}
494

    
495
	// Container for IP addresses within this range.
496
	$rangeaddresses = array();
497
	$end_int = ip2ulong($endip);
498
	for ($ip_int = ip2ulong($startip); $ip_int <= $end_int; $ip_int++) {
499
		$rangeaddresses[] = long2ip($ip_int);
500
	}
501

    
502
	return $rangeaddresses;
503
}
504

    
505
/* Convert a range of IPv4 addresses to an array of subnets which can contain the range. */
506
/* Note: IPv6 ranges are not yet supported here. */
507
function ip_range_to_subnet_array($startip, $endip) {
508
	if (!is_ipaddrv4($startip) || !is_ipaddrv4($endip)) {
509
		return array();
510
	}
511

    
512
	if (ip_greater_than($startip, $endip)) {
513
		// Swap start and end so we can process sensibly.
514
		$temp = $startip;
515
		$startip = $endip;
516
		$endip = $temp;
517
	}
518

    
519
	// Container for subnets within this range.
520
	$rangesubnets = array();
521

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

    
525
	// Loop here to reduce subnet size and retest as needed. We need to make sure
526
	//   that the target subnet is wholly contained between $startip and $endip.
527
	for ($cidr; $cidr <= 32; $cidr++) {
528
		// Find the network and broadcast addresses for the subnet being tested.
529
		$targetsub_min = gen_subnet($startip, $cidr);
530
		$targetsub_max = gen_subnet_max($startip, $cidr);
531

    
532
		// Check best case where the range is exactly one subnet.
533
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
534
			// Hooray, the range is exactly this subnet!
535
			return array("{$startip}/{$cidr}");
536
		}
537

    
538
		// These remaining scenarios will find a subnet that uses the largest
539
		//  chunk possible of the range being tested, and leave the rest to be
540
		//  tested recursively after the loop.
541

    
542
		// Check if the subnet begins with $startip and ends before $endip
543
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
544
			break;
545
		}
546

    
547
		// Check if the subnet ends at $endip and starts after $startip
548
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
549
			break;
550
		}
551

    
552
		// Check if the subnet is between $startip and $endip
553
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
554
			break;
555
		}
556
	}
557

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

    
564
	// Add in the subnet we found before, to preserve ordering
565
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
566

    
567
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
568
	if ($endip != $targetsub_max) {
569
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
570
	}
571
	return $rangesubnets;
572
}
573

    
574
/* returns true if $range is a valid pair of IPv4 or IPv6 addresses separated by a "-"
575
	false - if not a valid pair
576
	true (numeric 4 or 6) - if valid, gives type of addresses */
577
function is_iprange($range) {
578
	if (substr_count($range, '-') != 1) {
579
		return false;
580
	}
581
	list($ip1, $ip2) = explode ('-', $range);
582
	if (is_ipaddrv4($ip1) && is_ipaddrv4($ip2)) {
583
		return 4;
584
	}
585
	if (is_ipaddrv6($ip1) && is_ipaddrv6($ip2)) {
586
		return 6;
587
	}
588
	return false;
589
}
590

    
591
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6
592
	false - not valid
593
	true (numeric 4 or 6) - if valid, gives type of address */
594
function is_ipaddr($ipaddr) {
595
	if (is_ipaddrv4($ipaddr)) {
596
		return 4;
597
	}
598
	if (is_ipaddrv6($ipaddr)) {
599
		return 6;
600
	}
601
	return false;
602
}
603

    
604
/* returns true if $ipaddr is a valid IPv6 address */
605
function is_ipaddrv6($ipaddr) {
606
	if (!is_string($ipaddr) || empty($ipaddr)) {
607
		return false;
608
	}
609
	if (strstr($ipaddr, "%") && is_linklocal($ipaddr)) {
610
		$tmpip = explode("%", $ipaddr);
611
		$ipaddr = $tmpip[0];
612
	}
613
	return Net_IPv6::checkIPv6($ipaddr);
614
}
615

    
616
/* returns true if $ipaddr is a valid dotted IPv4 address */
617
function is_ipaddrv4($ipaddr) {
618
	if (!is_string($ipaddr) || empty($ipaddr) || ip2long($ipaddr) === FALSE) {
619
		return false;
620
	}
621
	return true;
622
}
623

    
624
/* returns true if $ipaddr is a valid IPv6 linklocal address */
625
function is_linklocal($ipaddr) {
626
	return (strtolower(substr($ipaddr, 0, 5)) == "fe80:");
627
}
628

    
629
/* returns scope of a linklocal address */
630
function get_ll_scope($addr) {
631
	if (!is_linklocal($addr) || !strstr($addr, "%")) {
632
		return "";
633
	}
634
	list ($ll, $scope) = explode("%", $addr);
635
	return $scope;
636
}
637

    
638
/* returns true if $ipaddr is a valid literal IPv6 address */
639
function is_literalipaddrv6($ipaddr) {
640
	if (preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match)) {
641
		$ipaddr = $match[1];
642
	} else {
643
		return false;
644
	}
645

    
646
	return is_ipaddrv6($ipaddr);
647
}
648

    
649
/* returns true if $iport is a valid IPv4/IPv6 address + port
650
	false - not valid
651
	true (numeric 4 or 6) - if valid, gives type of address */
652
function is_ipaddrwithport($ipport) {
653
	$c = strrpos($ipport, ":");
654
	if ($c === false) {
655
		return false;  // can't split at final colon if no colon exists
656
	}
657

    
658
	if (!is_port(substr($ipport, $c + 1))) {
659
		return false;  // no valid port after last colon
660
	}
661

    
662
	$ip = substr($ipport, 0, $c);  // else is text before last colon a valid IP
663
	if (is_literalipaddrv6($ip)) {
664
		return 6;
665
	} elseif (is_ipaddrv4($ip)) {
666
		return 4;
667
	} else {
668
		return false;
669
	}
670
}
671

    
672
function is_hostnamewithport($hostport) {
673
	$parts = explode(":", $hostport);
674
	$port = array_pop($parts);
675
	if (count($parts) == 1) {
676
		return is_hostname($parts[0]) && is_port($port);
677
	} else {
678
		return false;
679
	}
680
}
681

    
682
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
683
function is_ipaddroralias($ipaddr) {
684
	global $config;
685

    
686
	if (is_alias($ipaddr)) {
687
		if (is_array($config['aliases']['alias'])) {
688
			foreach ($config['aliases']['alias'] as $alias) {
689
				if ($alias['name'] == $ipaddr && !preg_match("/port/i", $alias['type'])) {
690
					return true;
691
				}
692
			}
693
		}
694
		return false;
695
	} else {
696
		return is_ipaddr($ipaddr);
697
	}
698

    
699
}
700

    
701
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format
702
	false - if not a valid subnet
703
	true (numeric 4 or 6) - if valid, gives type of subnet */
704
function is_subnet($subnet) {
705
	if (is_string($subnet) && preg_match('/^(?:([0-9.]{7,15})|([0-9a-f:]{2,39}))\/(\d{1,3})$/i', $subnet, $parts)) {
706
		if (is_ipaddrv4($parts[1]) && $parts[3] <= 32) {
707
			return 4;
708
		}
709
		if (is_ipaddrv6($parts[2]) && $parts[3] <= 128) {
710
			return 6;
711
		}
712
	}
713
	return false;
714
}
715

    
716
/* same as is_subnet() but accepts IPv4 only */
717
function is_subnetv4($subnet) {
718
	return (is_subnet($subnet) == 4);
719
}
720

    
721
/* same as is_subnet() but accepts IPv6 only */
722
function is_subnetv6($subnet) {
723
	return (is_subnet($subnet) == 6);
724
}
725

    
726
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
727
function is_subnetoralias($subnet) {
728
	global $aliastable;
729

    
730
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet])) {
731
		return true;
732
	} else {
733
		return is_subnet($subnet);
734
	}
735
}
736

    
737
function subnet_size($subnet) {
738
	if (is_subnetv4($subnet)) {
739
		list ($ip, $bits) = explode("/", $subnet);
740
		return round(exp(log(2) * (32 - $bits)));
741
	}
742
	else if (is_subnetv6($subnet)) {
743
		list ($ip, $bits) = explode("/", $subnet);
744
		return round(exp(log(2) * (128 - $bits)));
745
	}
746
	else {
747
		return 0;
748
	}
749
}
750

    
751

    
752
function subnet_expand($subnet) {
753
	if (is_subnetv4($subnet)) {
754
		return subnetv4_expand($subnet);
755
	} else if (is_subnetv6($subnet)) {
756
		return subnetv6_expand($subnet);
757
	} else {
758
		return $subnet;
759
	}
760
}
761

    
762
function subnetv4_expand($subnet) {
763
	$result = array();
764
	list ($ip, $bits) = explode("/", $subnet);
765
	$net  = ip2long($ip);
766
	$mask = (0xffffffff << (32 - $bits));
767
	$net &= $mask;
768
	$size = round(exp(log(2) * (32 - $bits)));
769
	for ($i = 0; $i < $size; $i += 1) {
770
		$result[] = long2ip($net | $i);
771
	}
772
	return $result;
773
}
774

    
775
/* find out whether two subnets overlap */
776
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
777

    
778
	if (!is_numeric($bits1)) {
779
		$bits1 = 32;
780
	}
781
	if (!is_numeric($bits2)) {
782
		$bits2 = 32;
783
	}
784

    
785
	if ($bits1 < $bits2) {
786
		$relbits = $bits1;
787
	} else {
788
		$relbits = $bits2;
789
	}
790

    
791
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
792
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
793

    
794
	return ($sn1 == $sn2);
795
}
796

    
797
/* find out whether two IPv6 subnets overlap */
798
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
799
	$sub1_min = gen_subnetv6($subnet1, $bits1);
800
	$sub1_max = gen_subnetv6_max($subnet1, $bits1);
801
	$sub2_min = gen_subnetv6($subnet2, $bits2);
802
	$sub2_max = gen_subnetv6_max($subnet2, $bits2);
803

    
804
	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));
805
}
806

    
807
/* return true if $addr is in $subnet, false if not */
808
function ip_in_subnet($addr, $subnet) {
809
	if (is_ipaddrv6($addr) && is_subnetv6($subnet)) {
810
		return (Net_IPv6::isInNetmask($addr, $subnet));
811
	} else if (is_ipaddrv4($addr) && is_subnetv4($subnet)) {
812
		list($ip, $mask) = explode('/', $subnet);
813
		$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
814
		return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
815
	}
816
	return false;
817
}
818

    
819
/* returns true if $hostname is just a valid hostname (top part without any of the domain part) */
820
function is_unqualified_hostname($hostname) {
821
	if (!is_string($hostname)) {
822
		return false;
823
	}
824

    
825
	if (preg_match('/^(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])$/i', $hostname)) {
826
		return true;
827
	} else {
828
		return false;
829
	}
830
}
831

    
832
/* returns true if $hostname is a valid hostname, with or without being a fully-qualified domain name. */
833
function is_hostname($hostname) {
834
	if (!is_string($hostname)) {
835
		return false;
836
	}
837

    
838
	if (is_domain($hostname)) {
839
		if ((substr_count($hostname, ".") == 1) && ($hostname[strlen($hostname)-1] == ".")) {
840
			/* Only a single dot at the end like "test." - hosts cannot be directly in the root domain. */
841
			return false;
842
		} else {
843
			return true;
844
		}
845
	} else {
846
		return false;
847
	}
848
}
849

    
850
/* returns true if $domain is a valid domain name */
851
function is_domain($domain) {
852
	if (!is_string($domain)) {
853
		return false;
854
	}
855

    
856
	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)) {
857
		return true;
858
	} else {
859
		return false;
860
	}
861
}
862

    
863
/* returns true if $macaddr is a valid MAC address */
864
function is_macaddr($macaddr, $partial=false) {
865
	$repeat = ($partial) ? '1,5' : '5';
866
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
867
}
868

    
869
/* returns true if $name is a valid name for an alias
870
   returns NULL if a reserved word is used
871
   returns FALSE for bad chars in the name - this allows calling code to determine what the problem was.
872
   aliases cannot be:
873
	bad chars: anything except a-z 0-9 and underscore
874
	bad names: empty string, pure numeric, pure underscore
875
	reserved words: pre-defined service/protocol/port names which should not be ambiguous, and the words "port" and  "pass" */
876

    
877
function is_validaliasname($name) {
878
	/* Array of reserved words */
879
	$reserved = array("port", "pass");
880

    
881
	if (!is_string($name) || strlen($name) >= 32 || preg_match('/(^_*$|^\d*$|[^a-z0-9_])/i', $name)) {
882
		return false;
883
	}
884
	if (in_array($name, $reserved, true) || getservbyname($name, "tcp") || getservbyname($name, "udp") || getprotobyname($name)) {
885
		return; /* return NULL */
886
	}
887
	return true;
888
}
889

    
890
/* returns true if $port is a valid TCP/UDP port */
891
function is_port($port) {
892
	if (ctype_digit($port) && ((intval($port) >= 1) && (intval($port) <= 65535))) {
893
		return true;
894
	}
895
	if (getservbyname($port, "tcp") || getservbyname($port, "udp")) {
896
		return true;
897
	}
898
	return false;
899
}
900

    
901
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
902
function is_portrange($portrange) {
903
	$ports = explode(":", $portrange);
904

    
905
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
906
}
907

    
908
/* returns true if $port is a valid port number or an alias thereof */
909
function is_portoralias($port) {
910
	global $config;
911

    
912
	if (is_alias($port)) {
913
		if (is_array($config['aliases']['alias'])) {
914
			foreach ($config['aliases']['alias'] as $alias) {
915
				if ($alias['name'] == $port && preg_match("/port/i", $alias['type'])) {
916
					return true;
917
				}
918
			}
919
		}
920
		return false;
921
	} else {
922
		return is_port($port);
923
	}
924
}
925

    
926
/* create ranges of sequential port numbers (200:215) and remove duplicates */
927
function group_ports($ports) {
928
	if (!is_array($ports) || empty($ports)) {
929
		return;
930
	}
931

    
932
	$uniq = array();
933
	foreach ($ports as $port) {
934
		if (is_portrange($port)) {
935
			list($begin, $end) = explode(":", $port);
936
			if ($begin > $end) {
937
				$aux = $begin;
938
				$begin = $end;
939
				$end = $aux;
940
			}
941
			for ($i = $begin; $i <= $end; $i++) {
942
				if (!in_array($i, $uniq)) {
943
					$uniq[] = $i;
944
				}
945
			}
946
		} else if (is_port($port)) {
947
			if (!in_array($port, $uniq)) {
948
				$uniq[] = $port;
949
			}
950
		}
951
	}
952
	sort($uniq, SORT_NUMERIC);
953

    
954
	$result = array();
955
	foreach ($uniq as $idx => $port) {
956
		if ($idx == 0) {
957
			$result[] = $port;
958
			continue;
959
		}
960

    
961
		$last = end($result);
962
		if (is_portrange($last)) {
963
			list($begin, $end) = explode(":", $last);
964
		} else {
965
			$begin = $end = $last;
966
		}
967

    
968
		if ($port == ($end+1)) {
969
			$end++;
970
			$result[count($result)-1] = "{$begin}:{$end}";
971
		} else {
972
			$result[] = $port;
973
		}
974
	}
975

    
976
	return $result;
977
}
978

    
979
/* returns true if $val is a valid shaper bandwidth value */
980
function is_valid_shaperbw($val) {
981
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
982
}
983

    
984
/* returns true if $test is in the range between $start and $end */
985
function is_inrange_v4($test, $start, $end) {
986
	if ((ip2ulong($test) <= ip2ulong($end)) && (ip2ulong($test) >= ip2ulong($start))) {
987
		return true;
988
	} else {
989
		return false;
990
	}
991
}
992

    
993
/* returns true if $test is in the range between $start and $end */
994
function is_inrange_v6($test, $start, $end) {
995
	if ((inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start))) {
996
		return true;
997
	} else {
998
		return false;
999
	}
1000
}
1001

    
1002
/* returns true if $test is in the range between $start and $end */
1003
function is_inrange($test, $start, $end) {
1004
	return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
1005
}
1006

    
1007
/* XXX: return the configured carp interface list */
1008
function get_configured_carp_interface_list($carpinterface = '', $family = 'inet', $what = 'ip') {
1009
	global $config;
1010

    
1011
	$iflist = array();
1012

    
1013
	if (is_array($config['virtualip']['vip'])) {
1014
		$viparr = &$config['virtualip']['vip'];
1015
		foreach ($viparr as $vip) {
1016
			switch ($vip['mode']) {
1017
				case "carp":
1018
					if (!empty($carpinterface)) {
1019
						if ($carpinterface == "_vip{$vip['uniqid']}") {
1020
							switch ($what) {
1021
								case 'subnet':
1022
									if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
1023
										return $vip['subnet_bits'];
1024
									} else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
1025
										return $vip['subnet_bits'];
1026
									}
1027
									break;
1028
								case 'iface':
1029
									if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
1030
										return $vip['interface'];
1031
									} else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
1032
										return $vip['interface'];
1033
									}
1034
									break;
1035
								case 'vip':
1036
									if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
1037
										return $vip;
1038
									} else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
1039
										return $vip;
1040
									}
1041
									break;
1042
								case 'ip':
1043
								default:
1044
									if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
1045
										return $vip['subnet'];
1046
									} else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
1047
										return $vip['subnet'];
1048
									}
1049
									break;
1050
							}
1051
						}
1052
					} else {
1053
						$iflist["_vip{$vip['uniqid']}"] = $vip['subnet'];
1054
					}
1055
					break;
1056
			}
1057
		}
1058
	}
1059

    
1060
	return $iflist;
1061
}
1062

    
1063
/* return the configured IP aliases list */
1064
function get_configured_ip_aliases_list($returnfullentry = false) {
1065
	global $config;
1066

    
1067
	$alias_list=array();
1068

    
1069
	if (is_array($config['virtualip']['vip'])) {
1070
		$viparr = &$config['virtualip']['vip'];
1071
		foreach ($viparr as $vip) {
1072
			if ($vip['mode'] == "ipalias") {
1073
				if ($returnfullentry) {
1074
					$alias_list[$vip['subnet']] = $vip;
1075
				} else {
1076
					$alias_list[$vip['subnet']] = $vip['interface'];
1077
				}
1078
			}
1079
		}
1080
	}
1081

    
1082
	return $alias_list;
1083
}
1084

    
1085
/* return all configured aliases list (IP, carp, proxyarp and other) */
1086
function get_configured_vips_list() {
1087
	global $config;
1088

    
1089
	$alias_list=array();
1090

    
1091
	if (is_array($config['virtualip']['vip'])) {
1092
		$viparr = &$config['virtualip']['vip'];
1093
		foreach ($viparr as $vip) {
1094
			if ($vip['mode'] == "carp") {
1095
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => "{$vip['interface']}_vip{$vip['vhid']}");
1096
			} else {
1097
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
1098
			}
1099
		}
1100
	}
1101

    
1102
	return $alias_list;
1103
}
1104

    
1105
/* comparison function for sorting by the order in which interfaces are normally created */
1106
function compare_interface_friendly_names($a, $b) {
1107
	if ($a == $b) {
1108
		return 0;
1109
	} else if ($a == 'wan') {
1110
		return -1;
1111
	} else if ($b == 'wan') {
1112
		return 1;
1113
	} else if ($a == 'lan') {
1114
		return -1;
1115
	} else if ($b == 'lan') {
1116
		return 1;
1117
	}
1118

    
1119
	return strnatcmp($a, $b);
1120
}
1121

    
1122
/* return the configured interfaces list. */
1123
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
1124
	global $config;
1125

    
1126
	$iflist = array();
1127

    
1128
	/* if list */
1129
	foreach ($config['interfaces'] as $if => $ifdetail) {
1130
		if ($only_opt && ($if == "wan" || $if == "lan")) {
1131
			continue;
1132
		}
1133
		if (isset($ifdetail['enable']) || $withdisabled == true) {
1134
			$iflist[$if] = $if;
1135
		}
1136
	}
1137

    
1138
	return $iflist;
1139
}
1140

    
1141
/* return the configured interfaces list. */
1142
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
1143
	global $config;
1144

    
1145
	$iflist = array();
1146

    
1147
	/* if list */
1148
	foreach ($config['interfaces'] as $if => $ifdetail) {
1149
		if ($only_opt && ($if == "wan" || $if == "lan")) {
1150
			continue;
1151
		}
1152
		if (isset($ifdetail['enable']) || $withdisabled == true) {
1153
			$tmpif = get_real_interface($if);
1154
			if (!empty($tmpif)) {
1155
				$iflist[$tmpif] = $if;
1156
			}
1157
		}
1158
	}
1159

    
1160
	return $iflist;
1161
}
1162

    
1163
/* return the configured interfaces list with their description. */
1164
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
1165
	global $config;
1166

    
1167
	$iflist = array();
1168

    
1169
	/* if list */
1170
	foreach ($config['interfaces'] as $if => $ifdetail) {
1171
		if ($only_opt && ($if == "wan" || $if == "lan")) {
1172
			continue;
1173
		}
1174
		if (isset($ifdetail['enable']) || $withdisabled == true) {
1175
			if (empty($ifdetail['descr'])) {
1176
				$iflist[$if] = strtoupper($if);
1177
			} else {
1178
				$iflist[$if] = strtoupper($ifdetail['descr']);
1179
			}
1180
		}
1181
	}
1182

    
1183
	return $iflist;
1184
}
1185

    
1186
/*
1187
 *   get_configured_ip_addresses() - Return a list of all configured
1188
 *   interfaces IP Addresses
1189
 *
1190
 */
1191
function get_configured_ip_addresses() {
1192
	global $config;
1193

    
1194
	if (!function_exists('get_interface_ip')) {
1195
		require_once("interfaces.inc");
1196
	}
1197
	$ip_array = array();
1198
	$interfaces = get_configured_interface_list();
1199
	if (is_array($interfaces)) {
1200
		foreach ($interfaces as $int) {
1201
			$ipaddr = get_interface_ip($int);
1202
			$ip_array[$int] = $ipaddr;
1203
		}
1204
	}
1205
	$interfaces = get_configured_carp_interface_list();
1206
	if (is_array($interfaces)) {
1207
		foreach ($interfaces as $int => $ipaddr) {
1208
			$ip_array[$int] = $ipaddr;
1209
		}
1210
	}
1211

    
1212
	/* pppoe server */
1213
	if (is_array($config['pppoes']) && is_array($config['pppoes']['pppoe'])) {
1214
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
1215
			if ($pppoe['mode'] == "server") {
1216
				if (is_ipaddr($pppoe['localip'])) {
1217
					$int = "pppoes". $pppoe['pppoeid'];
1218
					$ip_array[$int] = $pppoe['localip'];
1219
				}
1220
			}
1221
		}
1222
	}
1223

    
1224
	return $ip_array;
1225
}
1226

    
1227
/*
1228
 *   get_configured_ipv6_addresses() - Return a list of all configured
1229
 *   interfaces IPv6 Addresses
1230
 *
1231
 */
1232
function get_configured_ipv6_addresses() {
1233
	require_once("interfaces.inc");
1234
	$ipv6_array = array();
1235
	$interfaces = get_configured_interface_list();
1236
	if (is_array($interfaces)) {
1237
		foreach ($interfaces as $int) {
1238
			$ipaddrv6 = get_interface_ipv6($int);
1239
			$ipv6_array[$int] = $ipaddrv6;
1240
		}
1241
	}
1242
	$interfaces = get_configured_carp_interface_list();
1243
	if (is_array($interfaces)) {
1244
		foreach ($interfaces as $int => $ipaddrv6) {
1245
			$ipv6_array[$int] = $ipaddrv6;
1246
		}
1247
	}
1248
	return $ipv6_array;
1249
}
1250

    
1251
/*
1252
 *   get_interface_list() - Return a list of all physical interfaces
1253
 *   along with MAC and status.
1254
 *
1255
 *   $mode = "active" - use ifconfig -lu
1256
 *           "media"  - use ifconfig to check physical connection
1257
 *			status (much slower)
1258
 */
1259
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
1260
	global $config;
1261
	$upints = array();
1262
	/* get a list of virtual interface types */
1263
	if (!$vfaces) {
1264
		$vfaces = array(
1265
				'bridge',
1266
				'ppp',
1267
				'pppoe',
1268
				'pptp',
1269
				'l2tp',
1270
				'sl',
1271
				'gif',
1272
				'gre',
1273
				'faith',
1274
				'lo',
1275
				'ng',
1276
				'_vlan',
1277
				'_wlan',
1278
				'pflog',
1279
				'plip',
1280
				'pfsync',
1281
				'enc',
1282
				'tun',
1283
				'carp',
1284
				'lagg',
1285
				'vip',
1286
				'ipfw'
1287
		);
1288
	}
1289
	switch ($mode) {
1290
		case "active":
1291
			$upints = pfSense_interface_listget(IFF_UP);
1292
			break;
1293
		case "media":
1294
			$intlist = pfSense_interface_listget();
1295
			$ifconfig = "";
1296
			exec("/sbin/ifconfig -a", $ifconfig);
1297
			$regexp = '/(' . implode('|', $intlist) . '):\s/';
1298
			$ifstatus = preg_grep('/status:/', $ifconfig);
1299
			foreach ($ifstatus as $status) {
1300
				$int = array_shift($intlist);
1301
				if (stristr($status, "active")) {
1302
					$upints[] = $int;
1303
				}
1304
			}
1305
			break;
1306
		default:
1307
			$upints = pfSense_interface_listget();
1308
			break;
1309
	}
1310
	/* build interface list with netstat */
1311
	$linkinfo = "";
1312
	exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
1313
	array_shift($linkinfo);
1314
	/* build ip address list with netstat */
1315
	$ipinfo = "";
1316
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
1317
	array_shift($ipinfo);
1318
	foreach ($linkinfo as $link) {
1319
		$friendly = "";
1320
		$alink = explode(" ", $link);
1321
		$ifname = rtrim(trim($alink[0]), '*');
1322
		/* trim out all numbers before checking for vfaces */
1323
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
1324
		    !stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
1325
			$toput = array(
1326
					"mac" => trim($alink[1]),
1327
					"up" => in_array($ifname, $upints)
1328
				);
1329
			foreach ($ipinfo as $ip) {
1330
				$aip = explode(" ", $ip);
1331
				if ($aip[0] == $ifname) {
1332
					$toput['ipaddr'] = $aip[1];
1333
				}
1334
			}
1335
			if (is_array($config['interfaces'])) {
1336
				foreach ($config['interfaces'] as $name => $int) {
1337
					if ($int['if'] == $ifname) {
1338
						$friendly = $name;
1339
					}
1340
				}
1341
			}
1342
			switch ($keyby) {
1343
			case "physical":
1344
				if ($friendly != "") {
1345
					$toput['friendly'] = $friendly;
1346
				}
1347
				$dmesg_arr = array();
1348
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
1349
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
1350
				$toput['dmesg'] = $dmesg[1][0];
1351
				$iflist[$ifname] = $toput;
1352
				break;
1353
			case "ppp":
1354

    
1355
			case "friendly":
1356
				if ($friendly != "") {
1357
					$toput['if'] = $ifname;
1358
					$iflist[$friendly] = $toput;
1359
				}
1360
				break;
1361
			}
1362
		}
1363
	}
1364
	return $iflist;
1365
}
1366

    
1367
/****f* util/log_error
1368
* NAME
1369
*   log_error  - Sends a string to syslog.
1370
* INPUTS
1371
*   $error     - string containing the syslog message.
1372
* RESULT
1373
*   null
1374
******/
1375
function log_error($error) {
1376
	global $g;
1377
	$page = $_SERVER['SCRIPT_NAME'];
1378
	if (empty($page)) {
1379
		$files = get_included_files();
1380
		$page = basename($files[0]);
1381
	}
1382
	syslog(LOG_ERR, "$page: $error");
1383
	if ($g['debug']) {
1384
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1385
	}
1386
	return;
1387
}
1388

    
1389
/****f* util/log_auth
1390
* NAME
1391
*   log_auth   - Sends a string to syslog as LOG_AUTH facility
1392
* INPUTS
1393
*   $error     - string containing the syslog message.
1394
* RESULT
1395
*   null
1396
******/
1397
function log_auth($error) {
1398
	global $g;
1399
	$page = $_SERVER['SCRIPT_NAME'];
1400
	syslog(LOG_AUTH, "$page: $error");
1401
	if ($g['debug']) {
1402
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1403
	}
1404
	return;
1405
}
1406

    
1407
/****f* util/exec_command
1408
 * NAME
1409
 *   exec_command - Execute a command and return a string of the result.
1410
 * INPUTS
1411
 *   $command   - String of the command to be executed.
1412
 * RESULT
1413
 *   String containing the command's result.
1414
 * NOTES
1415
 *   This function returns the command's stdout and stderr.
1416
 ******/
1417
function exec_command($command) {
1418
	$output = array();
1419
	exec($command . ' 2>&1', $output);
1420
	return(implode("\n", $output));
1421
}
1422

    
1423
/* wrapper for exec() */
1424
function mwexec($command, $mute = false, $clearsigmask = false) {
1425
	global $g;
1426

    
1427
	if ($g['debug']) {
1428
		if (!$_SERVER['REMOTE_ADDR']) {
1429
			echo "mwexec(): $command\n";
1430
		}
1431
	}
1432
	$oarr = array();
1433
	$retval = 0;
1434

    
1435
	if ($clearsigmask) {
1436
		$oldset = array();
1437
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1438
	}
1439
	$garbage = exec("$command 2>&1", $oarr, $retval);
1440
	if ($clearsigmask) {
1441
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1442
	}
1443

    
1444
	if (isset($config['system']['developerspew'])) {
1445
		$mute = false;
1446
	}
1447
	if (($retval <> 0) && ($mute === false)) {
1448
		$output = implode(" ", $oarr);
1449
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
1450
		unset($output);
1451
	}
1452
	unset($oarr);
1453
	return $retval;
1454
}
1455

    
1456
/* wrapper for exec() in background */
1457
function mwexec_bg($command, $clearsigmask = false) {
1458
	global $g;
1459

    
1460
	if ($g['debug']) {
1461
		if (!$_SERVER['REMOTE_ADDR']) {
1462
			echo "mwexec(): $command\n";
1463
		}
1464
	}
1465

    
1466
	if ($clearsigmask) {
1467
		$oldset = array();
1468
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1469
	}
1470
	$_gb = exec("/usr/bin/nohup $command > /dev/null 2>&1 &");
1471
	if ($clearsigmask) {
1472
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1473
	}
1474
	unset($_gb);
1475
}
1476

    
1477
/* unlink a file, if it exists */
1478
function unlink_if_exists($fn) {
1479
	$to_do = glob($fn);
1480
	if (is_array($to_do)) {
1481
		foreach ($to_do as $filename) {
1482
			@unlink($filename);
1483
		}
1484
	} else {
1485
		@unlink($fn);
1486
	}
1487
}
1488
/* make a global alias table (for faster lookups) */
1489
function alias_make_table($config) {
1490
	global $aliastable;
1491

    
1492
	$aliastable = array();
1493

    
1494
	if (is_array($config['aliases']['alias'])) {
1495
		foreach ($config['aliases']['alias'] as $alias) {
1496
			if ($alias['name']) {
1497
				$aliastable[$alias['name']] = $alias['address'];
1498
			}
1499
		}
1500
	}
1501
}
1502

    
1503
/* check if an alias exists */
1504
function is_alias($name) {
1505
	global $aliastable;
1506

    
1507
	return isset($aliastable[$name]);
1508
}
1509

    
1510
function alias_get_type($name) {
1511
	global $config;
1512

    
1513
	if (is_array($config['aliases']['alias'])) {
1514
		foreach ($config['aliases']['alias'] as $alias) {
1515
			if ($name == $alias['name']) {
1516
				return $alias['type'];
1517
			}
1518
		}
1519
	}
1520

    
1521
	return "";
1522
}
1523

    
1524
/* expand a host or network alias, if necessary */
1525
function alias_expand($name) {
1526
	global $aliastable;
1527

    
1528
	if (isset($aliastable[$name])) {
1529
		// alias names cannot be strictly numeric. redmine #4289
1530
		if (is_numericint($name)) {
1531
			return null;
1532
		}
1533
		return "\${$name}";
1534
	} else if (is_ipaddr($name) || is_subnet($name) || is_port($name) || is_portrange($name)) {
1535
		return "{$name}";
1536
	} else {
1537
		return null;
1538
	}
1539
}
1540

    
1541
function alias_expand_urltable($name) {
1542
	global $config;
1543
	$urltable_prefix = "/var/db/aliastables/";
1544
	$urltable_filename = $urltable_prefix . $name . ".txt";
1545

    
1546
	if (is_array($config['aliases']['alias'])) {
1547
		foreach ($config['aliases']['alias'] as $alias) {
1548
			if (preg_match("/urltable/i", $alias['type']) && ($alias['name'] == $name)) {
1549
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename)) {
1550
					return $urltable_filename;
1551
				} else if (process_alias_urltable($name, $alias["url"], 0, true)) {
1552
					return $urltable_filename;
1553
				}
1554
			}
1555
		}
1556
	}
1557
	return null;
1558
}
1559

    
1560
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1561
function verify_digital_signature($fname) {
1562
	global $g;
1563

    
1564
	if (!file_exists("/usr/local/sbin/gzsig")) {
1565
		return 4;
1566
	}
1567

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

    
1571
/* obtain MAC address given an IP address by looking at the ARP table */
1572
function arp_get_mac_by_ip($ip) {
1573
	mwexec("/sbin/ping -c 1 -t 1 " . escapeshellarg($ip), true);
1574
	$arpoutput = "";
1575
	exec("/usr/sbin/arp -n " . escapeshellarg($ip), $arpoutput);
1576

    
1577
	if ($arpoutput[0]) {
1578
		$arpi = explode(" ", $arpoutput[0]);
1579
		$macaddr = $arpi[3];
1580
		if (is_macaddr($macaddr)) {
1581
			return $macaddr;
1582
		} else {
1583
			return false;
1584
		}
1585
	}
1586

    
1587
	return false;
1588
}
1589

    
1590
/* return a fieldname that is safe for xml usage */
1591
function xml_safe_fieldname($fieldname) {
1592
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1593
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1594
			 ':', ',', '.', '\'', '\\'
1595
		);
1596
	return strtolower(str_replace($replace, "", $fieldname));
1597
}
1598

    
1599
function mac_format($clientmac) {
1600
	global $config, $cpzone;
1601

    
1602
	$mac = explode(":", $clientmac);
1603
	$mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1604

    
1605
	switch ($mac_format) {
1606
		case 'singledash':
1607
			return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1608

    
1609
		case 'ietf':
1610
			return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1611

    
1612
		case 'cisco':
1613
			return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1614

    
1615
		case 'unformatted':
1616
			return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1617

    
1618
		default:
1619
			return $clientmac;
1620
	}
1621
}
1622

    
1623
function resolve_retry($hostname, $retries = 5) {
1624

    
1625
	if (is_ipaddr($hostname)) {
1626
		return $hostname;
1627
	}
1628

    
1629
	for ($i = 0; $i < $retries; $i++) {
1630
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1631
		$ip = gethostbyname($hostname);
1632

    
1633
		if ($ip && $ip != $hostname) {
1634
			/* success */
1635
			return $ip;
1636
		}
1637

    
1638
		sleep(1);
1639
	}
1640

    
1641
	return false;
1642
}
1643

    
1644
function format_bytes($bytes) {
1645
	if ($bytes >= 1073741824) {
1646
		return sprintf("%.2f GB", $bytes/1073741824);
1647
	} else if ($bytes >= 1048576) {
1648
		return sprintf("%.2f MB", $bytes/1048576);
1649
	} else if ($bytes >= 1024) {
1650
		return sprintf("%.0f KB", $bytes/1024);
1651
	} else {
1652
		return sprintf("%d bytes", $bytes);
1653
	}
1654
}
1655

    
1656
function update_filter_reload_status($text) {
1657
	global $g;
1658

    
1659
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1660
}
1661

    
1662
/****** util/return_dir_as_array
1663
 * NAME
1664
 *   return_dir_as_array - Return a directory's contents as an array.
1665
 * INPUTS
1666
 *   $dir          - string containing the path to the desired directory.
1667
 *   $filter_regex - string containing a regular expression to filter file names. Default empty.
1668
 * RESULT
1669
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1670
 ******/
1671
function return_dir_as_array($dir, $filter_regex = '') {
1672
	$dir_array = array();
1673
	if (is_dir($dir)) {
1674
		if ($dh = opendir($dir)) {
1675
			while (($file = readdir($dh)) !== false) {
1676
				if (($file == ".") || ($file == "..")) {
1677
					continue;
1678
				}
1679

    
1680
				if (empty($filter_regex) || preg_match($filter_regex, $file)) {
1681
					array_push($dir_array, $file);
1682
				}
1683
			}
1684
			closedir($dh);
1685
		}
1686
	}
1687
	return $dir_array;
1688
}
1689

    
1690
function run_plugins($directory) {
1691
	global $config, $g;
1692

    
1693
	/* process packager manager custom rules */
1694
	$files = return_dir_as_array($directory);
1695
	if (is_array($files)) {
1696
		foreach ($files as $file) {
1697
			if (stristr($file, ".sh") == true) {
1698
				mwexec($directory . $file . " start");
1699
			} else if (!is_dir($directory . "/" . $file) && stristr($file, ".inc")) {
1700
				require_once($directory . "/" . $file);
1701
			}
1702
		}
1703
	}
1704
}
1705

    
1706
/*
1707
 *    safe_mkdir($path, $mode = 0755)
1708
 *    create directory if it doesn't already exist and isn't a file!
1709
 */
1710
function safe_mkdir($path, $mode=0755) {
1711
	global $g;
1712

    
1713
	if (!is_file($path) && !is_dir($path)) {
1714
		return @mkdir($path, $mode, true);
1715
	} else {
1716
		return false;
1717
	}
1718
}
1719

    
1720
/*
1721
 * get_sysctl($names)
1722
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1723
 * name) and return an array of key/value pairs set for those that exist
1724
 */
1725
function get_sysctl($names) {
1726
	if (empty($names)) {
1727
		return array();
1728
	}
1729

    
1730
	if (is_array($names)) {
1731
		$name_list = array();
1732
		foreach ($names as $name) {
1733
			$name_list[] = escapeshellarg($name);
1734
		}
1735
	} else {
1736
		$name_list = array(escapeshellarg($names));
1737
	}
1738

    
1739
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1740
	$values = array();
1741
	foreach ($output as $line) {
1742
		$line = explode(": ", $line, 2);
1743
		if (count($line) == 2) {
1744
			$values[$line[0]] = $line[1];
1745
		}
1746
	}
1747

    
1748
	return $values;
1749
}
1750

    
1751
/*
1752
 * get_single_sysctl($name)
1753
 * Wrapper for get_sysctl() to simplify read of a single sysctl value
1754
 * return the value for sysctl $name or empty string if it doesn't exist
1755
 */
1756
function get_single_sysctl($name) {
1757
	if (empty($name)) {
1758
		return "";
1759
	}
1760

    
1761
	$value = get_sysctl($name);
1762
	if (empty($value) || !isset($value[$name])) {
1763
		return "";
1764
	}
1765

    
1766
	return $value[$name];
1767
}
1768

    
1769
/*
1770
 * set_sysctl($value_list)
1771
 * Set sysctl OID's listed as key/value pairs and return
1772
 * an array with keys set for those that succeeded
1773
 */
1774
function set_sysctl($values) {
1775
	if (empty($values)) {
1776
		return array();
1777
	}
1778

    
1779
	$value_list = array();
1780
	foreach ($values as $key => $value) {
1781
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1782
	}
1783

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

    
1786
	/* Retry individually if failed (one or more read-only) */
1787
	if ($success <> 0 && count($value_list) > 1) {
1788
		foreach ($value_list as $value) {
1789
			exec("/sbin/sysctl -i " . $value, $output);
1790
		}
1791
	}
1792

    
1793
	$ret = array();
1794
	foreach ($output as $line) {
1795
		$line = explode(": ", $line, 2);
1796
		if (count($line) == 2) {
1797
			$ret[$line[0]] = true;
1798
		}
1799
	}
1800

    
1801
	return $ret;
1802
}
1803

    
1804
/*
1805
 * set_single_sysctl($name, $value)
1806
 * Wrapper to set_sysctl() to make it simple to set only one sysctl
1807
 * returns boolean meaning if it succeeded
1808
 */
1809
function set_single_sysctl($name, $value) {
1810
	if (empty($name)) {
1811
		return false;
1812
	}
1813

    
1814
	$result = set_sysctl(array($name => $value));
1815

    
1816
	if (!isset($result[$name]) || $result[$name] != $value) {
1817
		return false;
1818
	}
1819

    
1820
	return true;
1821
}
1822

    
1823
/*
1824
 *     get_memory()
1825
 *     returns an array listing the amount of
1826
 *     memory installed in the hardware
1827
 *     [0] net memory available for the OS (FreeBSD) after some is taken by BIOS, video or whatever - e.g. 235 MBytes
1828
 *     [1] real (actual) memory of the system, should be the size of the RAM card/s - e.g. 256 MBytes
1829
 */
1830
function get_memory() {
1831
	$physmem = get_single_sysctl("hw.physmem");
1832
	$realmem = get_single_sysctl("hw.realmem");
1833
	/* convert from bytes to megabytes */
1834
	return array(($physmem/1048576), ($realmem/1048576));
1835
}
1836

    
1837
function mute_kernel_msgs() {
1838
	global $config;
1839
	// Do not mute serial console.  The kernel gets very very cranky
1840
	// and will start dishing you cannot control tty errors.
1841
	switch (trim(file_get_contents("/etc/platform"))) {
1842
		case "nanobsd":
1843
		case "jail":
1844
			return;
1845
	}
1846
	if ($config['system']['enableserial']) {
1847
		return;
1848
	}
1849
	exec("/sbin/conscontrol mute on");
1850
}
1851

    
1852
function unmute_kernel_msgs() {
1853
	global $config;
1854
	// Do not mute serial console.  The kernel gets very very cranky
1855
	// and will start dishing you cannot control tty errors.
1856
	switch (trim(file_get_contents("/etc/platform"))) {
1857
		case "nanobsd":
1858
		case "jail":
1859
			return;
1860
	}
1861
	exec("/sbin/conscontrol mute off");
1862
}
1863

    
1864
function start_devd() {
1865
	global $g;
1866

    
1867
	if ($g['platform'] == 'jail') {
1868
		return;
1869
	}
1870
	/* Use the undocumented -q options of devd to quiet its log spamming */
1871
	$_gb = exec("/sbin/devd -q");
1872
	sleep(1);
1873
	unset($_gb);
1874
}
1875

    
1876
function is_interface_vlan_mismatch() {
1877
	global $config, $g;
1878

    
1879
	if (is_array($config['vlans']['vlan'])) {
1880
		foreach ($config['vlans']['vlan'] as $vlan) {
1881
			if (does_interface_exist($vlan['if']) == false) {
1882
				return true;
1883
			}
1884
		}
1885
	}
1886

    
1887
	return false;
1888
}
1889

    
1890
function is_interface_mismatch() {
1891
	global $config, $g;
1892

    
1893
	$do_assign = false;
1894
	$i = 0;
1895
	$missing_interfaces = array();
1896
	if (is_array($config['interfaces'])) {
1897
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1898
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1899
				// Do not check these interfaces.
1900
				$i++;
1901
				continue;
1902
			} else if (does_interface_exist($ifcfg['if']) == false) {
1903
				$missing_interfaces[] = $ifcfg['if'];
1904
				$do_assign = true;
1905
			} else {
1906
				$i++;
1907
			}
1908
		}
1909
	}
1910

    
1911
	if (file_exists("{$g['tmp_path']}/assign_complete")) {
1912
		$do_assign = false;
1913
	}
1914

    
1915
	if (!empty($missing_interfaces) && $do_assign) {
1916
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1917
	} else {
1918
		@unlink("{$g['tmp_path']}/missing_interfaces");
1919
	}
1920

    
1921
	return $do_assign;
1922
}
1923

    
1924
/* sync carp entries to other firewalls */
1925
function carp_sync_client() {
1926
	global $g;
1927
	send_event("filter sync");
1928
}
1929

    
1930
/****f* util/isAjax
1931
 * NAME
1932
 *   isAjax - reports if the request is driven from prototype
1933
 * INPUTS
1934
 *   none
1935
 * RESULT
1936
 *   true/false
1937
 ******/
1938
function isAjax() {
1939
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1940
}
1941

    
1942
/****f* util/timeout
1943
 * NAME
1944
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1945
 * INPUTS
1946
 *   optional, seconds to wait before timeout. Default 9 seconds.
1947
 * RESULT
1948
 *   returns 1 char of user input or null if no input.
1949
 ******/
1950
function timeout($timer = 9) {
1951
	while (!isset($key)) {
1952
		if ($timer >= 9) {
1953
			echo chr(8) . chr(8) . ($timer == 9 ? chr(32) : null)  . "{$timer}";
1954
		} else {
1955
			echo chr(8). "{$timer}";
1956
		}
1957
		`/bin/stty -icanon min 0 time 25`;
1958
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1959
		`/bin/stty icanon`;
1960
		if ($key == '') {
1961
			unset($key);
1962
		}
1963
		$timer--;
1964
		if ($timer == 0) {
1965
			break;
1966
		}
1967
	}
1968
	return $key;
1969
}
1970

    
1971
/****f* util/msort
1972
 * NAME
1973
 *   msort - sort array
1974
 * INPUTS
1975
 *   $array to be sorted, field to sort by, direction of sort
1976
 * RESULT
1977
 *   returns newly sorted array
1978
 ******/
1979
function msort($array, $id="id", $sort_ascending=true) {
1980
	$temp_array = array();
1981
	while (count($array)>0) {
1982
		$lowest_id = 0;
1983
		$index=0;
1984
		foreach ($array as $item) {
1985
			if (isset($item[$id])) {
1986
				if ($array[$lowest_id][$id]) {
1987
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1988
						$lowest_id = $index;
1989
					}
1990
				}
1991
			}
1992
			$index++;
1993
		}
1994
		$temp_array[] = $array[$lowest_id];
1995
		$array = array_merge(array_slice($array, 0, $lowest_id), array_slice($array, $lowest_id + 1));
1996
	}
1997
	if ($sort_ascending) {
1998
		return $temp_array;
1999
	} else {
2000
		return array_reverse($temp_array);
2001
	}
2002
}
2003

    
2004
/****f* util/is_URL
2005
 * NAME
2006
 *   is_URL
2007
 * INPUTS
2008
 *   string to check
2009
 * RESULT
2010
 *   Returns true if item is a URL
2011
 ******/
2012
function is_URL($url) {
2013
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
2014
	if ($match) {
2015
		return true;
2016
	}
2017
	return false;
2018
}
2019

    
2020
function is_file_included($file = "") {
2021
	$files = get_included_files();
2022
	if (in_array($file, $files)) {
2023
		return true;
2024
	}
2025

    
2026
	return false;
2027
}
2028

    
2029
/*
2030
 * Replace a value on a deep associative array using regex
2031
 */
2032
function array_replace_values_recursive($data, $match, $replace) {
2033
	if (empty($data)) {
2034
		return $data;
2035
	}
2036

    
2037
	if (is_string($data)) {
2038
		$data = preg_replace("/{$match}/", $replace, $data);
2039
	} else if (is_array($data)) {
2040
		foreach ($data as $k => $v) {
2041
			$data[$k] = array_replace_values_recursive($v, $match, $replace);
2042
		}
2043
	}
2044

    
2045
	return $data;
2046
}
2047

    
2048
/*
2049
	This function was borrowed from a comment on PHP.net at the following URL:
2050
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
2051
 */
2052
function array_merge_recursive_unique($array0, $array1) {
2053

    
2054
	$arrays = func_get_args();
2055
	$remains = $arrays;
2056

    
2057
	// We walk through each arrays and put value in the results (without
2058
	// considering previous value).
2059
	$result = array();
2060

    
2061
	// loop available array
2062
	foreach ($arrays as $array) {
2063

    
2064
		// The first remaining array is $array. We are processing it. So
2065
		// we remove it from remaining arrays.
2066
		array_shift($remains);
2067

    
2068
		// We don't care non array param, like array_merge since PHP 5.0.
2069
		if (is_array($array)) {
2070
			// Loop values
2071
			foreach ($array as $key => $value) {
2072
				if (is_array($value)) {
2073
					// we gather all remaining arrays that have such key available
2074
					$args = array();
2075
					foreach ($remains as $remain) {
2076
						if (array_key_exists($key, $remain)) {
2077
							array_push($args, $remain[$key]);
2078
						}
2079
					}
2080

    
2081
					if (count($args) > 2) {
2082
						// put the recursion
2083
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
2084
					} else {
2085
						foreach ($value as $vkey => $vval) {
2086
							$result[$key][$vkey] = $vval;
2087
						}
2088
					}
2089
				} else {
2090
					// simply put the value
2091
					$result[$key] = $value;
2092
				}
2093
			}
2094
		}
2095
	}
2096
	return $result;
2097
}
2098

    
2099

    
2100
/*
2101
 * converts a string like "a,b,c,d"
2102
 * into an array like array("a" => "b", "c" => "d")
2103
 */
2104
function explode_assoc($delimiter, $string) {
2105
	$array = explode($delimiter, $string);
2106
	$result = array();
2107
	$numkeys = floor(count($array) / 2);
2108
	for ($i = 0; $i < $numkeys; $i += 1) {
2109
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
2110
	}
2111
	return $result;
2112
}
2113

    
2114
function get_staticroutes($returnsubnetsonly = false, $returnhostnames = false) {
2115
	global $config, $aliastable;
2116

    
2117
	/* Bail if there are no routes, but return an array always so callers don't have to check. */
2118
	if (!is_array($config['staticroutes']['route'])) {
2119
		return array();
2120
	}
2121

    
2122
	$allstaticroutes = array();
2123
	$allsubnets = array();
2124
	/* Loop through routes and expand aliases as we find them. */
2125
	foreach ($config['staticroutes']['route'] as $route) {
2126
		if (is_alias($route['network'])) {
2127
			if (!isset($aliastable[$route['network']])) {
2128
				continue;
2129
			}
2130

    
2131
			$subnets = preg_split('/\s+/', $aliastable[$route['network']]);
2132
			foreach ($subnets as $net) {
2133
				if (!is_subnet($net)) {
2134
					if (is_ipaddrv4($net)) {
2135
						$net .= "/32";
2136
					} else if (is_ipaddrv6($net)) {
2137
						$net .= "/128";
2138
					} else if ($returnhostnames === false || !is_fqdn($net)) {
2139
						continue;
2140
					}
2141
				}
2142
				$temproute = $route;
2143
				$temproute['network'] = $net;
2144
				$allstaticroutes[] = $temproute;
2145
				$allsubnets[] = $net;
2146
			}
2147
		} elseif (is_subnet($route['network'])) {
2148
			$allstaticroutes[] = $route;
2149
			$allsubnets[] = $route['network'];
2150
		}
2151
	}
2152
	if ($returnsubnetsonly) {
2153
		return $allsubnets;
2154
	} else {
2155
		return $allstaticroutes;
2156
	}
2157
}
2158

    
2159
/****f* util/get_alias_list
2160
 * NAME
2161
 *   get_alias_list - Provide a list of aliases.
2162
 * INPUTS
2163
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
2164
 * RESULT
2165
 *   Array containing list of aliases.
2166
 *   If $type is unspecified, all aliases are returned.
2167
 *   If $type is a string, all aliases of the type specified in $type are returned.
2168
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
2169
 */
2170
function get_alias_list($type = null) {
2171
	global $config;
2172
	$result = array();
2173
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
2174
		foreach ($config['aliases']['alias'] as $alias) {
2175
			if ($type === null) {
2176
				$result[] = $alias['name'];
2177
			} else if (is_array($type)) {
2178
				if (in_array($alias['type'], $type)) {
2179
					$result[] = $alias['name'];
2180
				}
2181
			} else if ($type === $alias['type']) {
2182
				$result[] = $alias['name'];
2183
			}
2184
		}
2185
	}
2186
	return $result;
2187
}
2188

    
2189
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
2190
function array_exclude($needle, $haystack) {
2191
	$result = array();
2192
	if (is_array($haystack)) {
2193
		foreach ($haystack as $thing) {
2194
			if ($needle !== $thing) {
2195
				$result[] = $thing;
2196
			}
2197
		}
2198
	}
2199
	return $result;
2200
}
2201

    
2202
function get_current_theme() {
2203
	global $config, $g;
2204
	/*
2205
	 *   if user has selected a custom template, use it.
2206
	 *   otherwise default to pfsense template
2207
	 */
2208
	if (($g["disablethemeselection"] === true) && !empty($g["default_theme"]) && (is_dir($g["www_path"].'/themes/'.$g["default_theme"]))) {
2209
		$theme = $g["default_theme"];
2210
	} elseif ($config['theme'] <> "" && (is_dir($g["www_path"].'/themes/'.$config['theme']))) {
2211
		$theme = $config['theme'];
2212
	} else {
2213
		$theme = "pfsense";
2214
	}
2215
	/*
2216
	 *  If this device is an apple ipod/iphone
2217
	 *  switch the theme to one that works with it.
2218
	 */
2219
	$lowres_ua = array("iPhone", "iPod", "iPad", "Android", "BlackBerry", "Opera Mini", "Opera Mobi", "PlayBook", "IEMobile");
2220
	foreach ($lowres_ua as $useragent) {
2221
		if (strstr($_SERVER['HTTP_USER_AGENT'], $useragent)) {
2222
			$theme = (empty($g['theme_lowres']) && (is_dir($g["www_path"].'/themes/'.$g['theme_lowres']))) ? "pfsense" : $g['theme_lowres'];
2223
		}
2224
	}
2225
	return $theme;
2226
}
2227

    
2228
/* Define what is preferred, IPv4 or IPv6 */
2229
function prefer_ipv4_or_ipv6() {
2230
	global $config;
2231

    
2232
	if (isset($config['system']['prefer_ipv4'])) {
2233
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv4");
2234
	} else {
2235
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv6");
2236
	}
2237
}
2238

    
2239
/* Redirect to page passing parameters via POST */
2240
function post_redirect($page, $params) {
2241
	if (!is_array($params)) {
2242
		return;
2243
	}
2244

    
2245
	print "<html><body><form action=\"{$page}\" name=\"formredir\" method=\"post\">\n";
2246
	foreach ($params as $key => $value) {
2247
		print "<input type=\"hidden\" name=\"{$key}\" value=\"{$value}\" />\n";
2248
	}
2249
	print "</form><script type=\"text/javascript\">document.formredir.submit();</script>\n";
2250
	print "</body></html>\n";
2251
}
2252

    
2253
/* Locate disks that can be queried for S.M.A.R.T. data. */
2254
function get_smart_drive_list() {
2255
	$disk_list = explode(" ", get_single_sysctl("kern.disks"));
2256
	foreach ($disk_list as $id => $disk) {
2257
		// We only want certain kinds of disks for S.M.A.R.T.
2258
		// 1 is a match, 0 is no match, False is any problem processing the regex
2259
		if (preg_match("/^(ad|da|ada).*[0-9]{1,2}$/", $disk) !== 1) {
2260
			unset($disk_list[$id]);
2261
		}
2262
	}
2263
	sort($disk_list);
2264
	return $disk_list;
2265
}
2266

    
2267
?>
(55-55/67)