Project

General

Profile

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

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

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

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

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

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

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

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

    
44
function isvalidpid($pidfile) {
45
	$output = "";
46
	if (file_exists($pidfile)) {
47
		exec("/bin/pgrep -nF {$pidfile}", $output, $retval);
48
		return (intval($retval) == 0);
49
	}
50
	return false;
51
}
52

    
53
function is_process_running($process) {
54
	$output = "";
55
	exec("/bin/pgrep -anx {$process}", $output, $retval);
56

    
57
	return (intval($retval) == 0);
58
}
59

    
60
function isvalidproc($proc) {
61
	return is_process_running($proc);
62
}
63

    
64
/* sigkill a process by pid file */
65
/* return 1 for success and 0 for a failure */
66
function sigkillbypid($pidfile, $sig) {
67
	if (file_exists($pidfile))
68
		return mwexec("/bin/pkill -{$sig} -F {$pidfile}", true);
69

    
70
	return 0;
71
}
72

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

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

    
85
function is_subsystem_dirty($subsystem = "") {
86
	global $g;
87

    
88
	if ($subsystem == "")
89
		return false;
90

    
91
	if (file_exists("{$g['varrun_path']}/{$subsystem}.dirty"))
92
		return true;
93

    
94
	return false;
95
}
96

    
97
function mark_subsystem_dirty($subsystem = "") {
98
	global $g;
99

    
100
	if (!file_put_contents("{$g['varrun_path']}/{$subsystem}.dirty", "DIRTY"))
101
		log_error(sprintf(gettext("WARNING: Could not mark subsystem: %s dirty"), $subsystem));
102
}
103

    
104
function clear_subsystem_dirty($subsystem = "") {
105
	global $g;
106

    
107
	@unlink("{$g['varrun_path']}/{$subsystem}.dirty");
108
}
109

    
110
function config_lock() {
111
	return;
112
}
113
function config_unlock() {
114
	return;
115
}
116

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

    
135
/* unlock configuration file */
136
function unlock($cfglckkey = 0) {
137
	global $g, $cfglckkeyconsumers;
138
	flock($cfglckkey, LOCK_UN);
139
	fclose($cfglckkey);
140
	return;
141
}
142

    
143
function send_event($cmd) {
144
	global $g;
145

    
146
	if(!isset($g['event_address']))
147
		$g['event_address'] = "unix:///var/run/check_reload_status";
148
		
149
	$try = 0;
150
	while ($try < 3) {
151
		$fd = @fsockopen($g['event_address']);
152
		if ($fd) {
153
			fwrite($fd, $cmd);
154
			$resp = fread($fd, 4096);
155
			if ($resp != "OK\n")
156
				log_error("send_event: sent {$cmd} got {$resp}");
157
			fclose($fd);
158
			$try = 3;
159
		} else if (!is_process_running("check_reload_status"))
160
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
161
		$try++;
162
	}
163
}
164

    
165
function send_multiple_events($cmds) {
166
	global $g;
167

    
168
	if(!isset($g['event_address']))
169
		$g['event_address'] = "unix:///var/run/check_reload_status";
170
			
171
	if (!is_array($cmds))
172
		return;
173

    
174
	while ($try < 3) {
175
		$fd = @fsockopen($g['event_address']);
176
		if ($fd) {
177
			foreach ($cmds as $cmd) {
178
				fwrite($fd, $cmd);
179
				$resp = fread($fd, 4096);
180
				if ($resp != "OK\n")
181
					log_error("send_event: sent {$cmd} got {$resp}");
182
			}
183
			fclose($fd);
184
			$try = 3;
185
		} else if (!is_process_running("check_reload_status"))
186
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
187
		$try++;
188
	}
189
}
190

    
191
function refcount_init($reference) {
192
	$shmid = @shmop_open($reference, "c", 0644, 10);
193
	@shmop_write($shmid, str_pad("0", 10, "\x0", STR_PAD_RIGHT), 0);
194
	@shmop_close($shmid);
195
}
196

    
197
function refcount_reference($reference) {
198
	/* Take out a lock across the shared memory read, increment, write sequence to make it atomic. */
199
	$shm_lck = lock("shm{$reference}", LOCK_EX);
200
	try {
201
		/* NOTE: A warning is generated when shared memory does not exist */
202
		$shmid = @shmop_open($reference, "w", 0, 0);
203
		if (!$shmid) {
204
			refcount_init($reference);
205
			$shmid = @shmop_open($reference, "w", 0, 0);
206
			if (!$shmid) {
207
				log_error(gettext("Could not open shared memory {$reference}"));
208
				unlock($shm_lck);
209
				return;
210
			}
211
		}
212
		$shm_data = @shmop_read($shmid, 0, 10);
213
		$shm_data = intval($shm_data) + 1;
214
		@shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
215
		@shmop_close($shmid);
216
		unlock($shm_lck);
217
	} catch (Exception $e) {
218
		log_error($e->getMessage());
219
		unlock($shm_lck);
220
	}
221

    
222
	return $shm_data;
223
}
224

    
225
function refcount_unreference($reference) {
226
	/* Take out a lock across the shared memory read, decrement, write sequence to make it atomic. */
227
	$shm_lck = lock("shm{$reference}", LOCK_EX);
228
	try {
229
		$shmid = @shmop_open($reference, "w", 0, 0);
230
		if (!$shmid) {
231
			refcount_init($reference);
232
			log_error(gettext("Could not open shared memory {$reference}"));
233
			unlock($shm_lck);
234
			return;
235
		}
236
		$shm_data = @shmop_read($shmid, 0, 10);
237
		$shm_data = intval($shm_data) - 1;
238
		if ($shm_data < 0) {
239
			//debug_backtrace();
240
			log_error(sprintf(gettext("Reference %s is going negative, not doing unreference."), $reference));
241
		} else
242
			@shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
243
		@shmop_close($shmid);
244
		unlock($shm_lck);
245
	} catch (Exception $e) {
246
		log_error($e->getMessage());
247
		unlock($shm_lck);
248
	}
249

    
250
	return $shm_data;
251
}
252

    
253
function refcount_read($reference) {
254
	/* This function just reads the current value of the refcount for information. */
255
	/* There is no need for locking. */
256
	$shmid = @shmop_open($reference, "a", 0, 0);
257
	if (!$shmid) {
258
		log_error(gettext("Could not open shared memory for read {$reference}"));
259
		return -1;
260
	}
261
	$shm_data = @shmop_read($shmid, 0, 10);
262
	@shmop_close($shmid);
263
	return $shm_data;
264
}
265

    
266
function is_module_loaded($module_name) {
267
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
268
	if (intval($running) >= 1)
269
		return true;
270
	else
271
		return false;
272
}
273

    
274
/* return the subnet address given a host address and a subnet bit count */
275
function gen_subnet($ipaddr, $bits) {
276
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
277
		return "";
278
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
279
}
280

    
281
/* return the subnet address given a host address and a subnet bit count */
282
function gen_subnetv6($ipaddr, $bits) {
283
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
284
		return "";
285

    
286
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
287
	return $address;
288
}
289

    
290
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
291
function gen_subnet_max($ipaddr, $bits) {
292
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
293
		return "";
294

    
295
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
296
}
297

    
298
/* Generate end number for a given ipv6 subnet mask */
299
function gen_subnetv6_max($ipaddr, $bits) {
300
	if(!is_ipaddrv6($ipaddr))
301
		return false;
302
	
303
	$mask = Net_IPv6::getNetmask('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',$bits);
304
	
305
	$inet_ip = (binary)inet_pton($ipaddr);
306
	$inet_mask = (binary)inet_pton($mask);
307

    
308
	$inet_end = $inet_ip | ~$inet_mask;
309

    
310
	return(Net_IPv6::uncompress(inet_ntop($inet_end)));
311
}
312

    
313
/* returns a subnet mask (long given a bit count) */
314
function gen_subnet_mask_long($bits) {
315
	$sm = 0;
316
	for ($i = 0; $i < $bits; $i++) {
317
		$sm >>= 1;
318
		$sm |= 0x80000000;
319
	}
320
	return $sm;
321
}
322

    
323
/* same as above but returns a string */
324
function gen_subnet_mask($bits) {
325
	return long2ip(gen_subnet_mask_long($bits));
326
}
327

    
328
/* Convert long int to IP address, truncating to 32-bits. */
329
function long2ip32($ip) {
330
	return long2ip($ip & 0xFFFFFFFF);
331
}
332

    
333
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
334
function ip2long32($ip) {
335
	return ( ip2long($ip) & 0xFFFFFFFF );
336
}
337

    
338
/* Convert IP address to unsigned long int. */
339
function ip2ulong($ip) {
340
	return sprintf("%u", ip2long32($ip));
341
}
342

    
343
/* Find out how many IPs are contained within a given IP range
344
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
345
 */
346
function ip_range_size($startip, $endip) {
347
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
348
		// Operate as unsigned long because otherwise it wouldn't work
349
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
350
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
351
	}
352
	return -1;
353
}
354

    
355
/* Find the smallest possible subnet mask which can contain a given number of IPs
356
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
357
 */
358
function find_smallest_cidr($number) {
359
	$smallest = 1;
360
	for ($b=32; $b > 0; $b--) {
361
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
362
	}
363
	return (32-$smallest);
364
}
365

    
366
/* Return the previous IP address before the given address */
367
function ip_before($ip) {
368
	return long2ip32(ip2long($ip)-1);
369
}
370

    
371
/* Return the next IP address after the given address */
372
function ip_after($ip) {
373
	return long2ip32(ip2long($ip)+1);
374
}
375

    
376
/* Return true if the first IP is 'before' the second */
377
function ip_less_than($ip1, $ip2) {
378
	// Compare as unsigned long because otherwise it wouldn't work when
379
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
380
	return ip2ulong($ip1) < ip2ulong($ip2);
381
}
382

    
383
/* Return true if the first IP is 'after' the second */
384
function ip_greater_than($ip1, $ip2) {
385
	// Compare as unsigned long because otherwise it wouldn't work
386
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
387
	return ip2ulong($ip1) > ip2ulong($ip2);
388
}
389

    
390
/* Convert a range of IPs to an array of subnets which can contain the range. */
391
function ip_range_to_subnet_array($startip, $endip) {
392
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
393
		return array();
394
	}
395

    
396
	// Container for subnets within this range.
397
	$rangesubnets = array();
398

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

    
402
	// Loop here to reduce subnet size and retest as needed. We need to make sure
403
	//   that the target subnet is wholly contained between $startip and $endip.
404
	for ($cidr; $cidr <= 32; $cidr++) {
405
		// Find the network and broadcast addresses for the subnet being tested.
406
		$targetsub_min = gen_subnet($startip, $cidr);
407
		$targetsub_max = gen_subnet_max($startip, $cidr);
408

    
409
		// Check best case where the range is exactly one subnet.
410
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
411
			// Hooray, the range is exactly this subnet!
412
			return array("{$startip}/{$cidr}");
413
		}
414

    
415
		// These remaining scenarios will find a subnet that uses the largest
416
		//  chunk possible of the range being tested, and leave the rest to be
417
		//  tested recursively after the loop.
418

    
419
		// Check if the subnet begins with $startip and ends before $endip
420
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
421
			break;
422
		}
423

    
424
		// Check if the subnet ends at $endip and starts after $startip
425
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
426
			break;
427
		}
428

    
429
		// Check if the subnet is between $startip and $endip
430
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
431
			break;
432
		}
433
	}
434

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

    
441
	// Add in the subnet we found before, to preserve ordering
442
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
443

    
444
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
445
	if ($endip != $targetsub_max) {
446
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
447
	}
448
	return $rangesubnets;
449
}
450

    
451
function is_iprange($range) {
452
	if (substr_count($range, '-') != 1) {
453
		return false;
454
	}
455
	list($ip1, $ip2) = explode ('-', $range);
456
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
457
}
458

    
459
function is_numericint($arg) {
460
	return (preg_match("/[^0-9]/", $arg) ? false : true);
461
}
462

    
463

    
464
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
465
function is_ipaddr($ipaddr) {
466
	if(is_ipaddrv4($ipaddr)) {
467
		return true;
468
	}
469
	if(is_ipaddrv6($ipaddr)) {
470
		return true;
471
	}
472
	return false;
473
}
474

    
475
/* returns true if $ipaddr is a valid IPv6 address */
476
function is_ipaddrv6($ipaddr) {
477
	$result = Net_IPv6::checkIPv6($ipaddr);
478
	return $result;
479
}
480

    
481
/* returns true if $ipaddr is a valid dotted IPv4 address */
482
function is_ipaddrv4($ipaddr) {
483
	if (!is_string($ipaddr))
484
		return false;
485

    
486
	$ip_long = ip2long($ipaddr);
487
	$ip_reverse = long2ip32($ip_long);
488

    
489
	if ($ipaddr == $ip_reverse)
490
		return true;
491
	else
492
		return false;
493
}
494

    
495

    
496
/* returns true if $ipaddr is a valid literal IPv6 address */
497
function is_literalipaddrv6($ipaddr) {
498
	if(preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match))
499
		$ipaddr = $match[1];
500
	else
501
		return false;
502

    
503
	return is_ipaddrv6($ipaddr);
504
}
505

    
506
function is_ipaddrwithport($ipport) {
507
	$parts = explode(":", $ipport);
508
	$port = array_pop($parts);
509
	if (count($parts) == 1) {
510
		return is_ipaddrv4($parts[0]) && is_port($port);
511
	} elseif (count($parts) > 1) {
512
		return is_literalipaddrv6(implode(":", $parts)) && is_port($port);
513
	} else {
514
		return false;
515
	}
516
}
517

    
518
function is_hostnamewithport($hostport) {
519
	$parts = explode(":", $hostport);
520
	$port = array_pop($parts);
521
	if (count($parts) == 1) {
522
		return is_hostname($parts[0]) && is_port($port);
523
	} else {
524
		return false;
525
	}
526
}
527

    
528
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
529
function is_ipaddroralias($ipaddr) {
530
	global $config;
531

    
532
	if (is_alias($ipaddr)) {
533
		if (is_array($config['aliases']['alias'])) {
534
			foreach ($config['aliases']['alias'] as $alias) {
535
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
536
					return true;
537
			}
538
		}
539
		return false;
540
	} else
541
		return is_ipaddr($ipaddr);
542

    
543
}
544

    
545
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format */
546
function is_subnet($subnet) {
547
	if(is_subnetv4($subnet)) {
548
		return true;
549
	}
550
	if(is_subnetv6($subnet)) {
551
		return true;
552
	}
553
	return false;
554
}
555

    
556
/* returns true if $subnet is a valid IPv4 subnet in CIDR format */
557
function is_subnetv4($subnet) {
558
	if (!is_string($subnet))
559
		return false;
560

    
561
	list($hp,$np) = explode('/', $subnet);
562

    
563
	if (!is_ipaddrv4($hp))
564
		return false;
565

    
566
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
567
		return false;
568

    
569
	return true;
570
}
571

    
572
/* returns true if $subnet is a valid IPv6 subnet in CIDR format */
573
function is_subnetv6($subnet) {
574
	if (!is_string($subnet))
575
		return false;
576

    
577
	list($hp,$np) = explode('/', $subnet);
578

    
579
	if (!is_ipaddrv6($hp))
580
		return false;
581

    
582
	if (!is_numeric($np) || ($np < 1) || ($np > 128))
583
		return false;
584

    
585
	return true;
586
}
587

    
588

    
589
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
590
function is_subnetoralias($subnet) {
591
	global $aliastable;
592

    
593
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
594
		return true;
595
	else
596
		return is_subnet($subnet);
597
}
598

    
599
/* returns true if $hostname is a valid hostname */
600
function is_hostname($hostname) {
601
	if (!is_string($hostname))
602
		return false;
603

    
604
	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))
605
		return true;
606
	else
607
		return false;
608
}
609

    
610
/* returns true if $domain is a valid domain name */
611
function is_domain($domain) {
612
	if (!is_string($domain))
613
		return false;
614

    
615
	if (preg_match('/^(?:(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$/i', $domain))
616
		return true;
617
	else
618
		return false;
619
}
620

    
621
/* returns true if $macaddr is a valid MAC address */
622
function is_macaddr($macaddr, $partial=false) {
623
	$repeat = ($partial) ? '1,5' : '5';
624
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
625
}
626

    
627
/* returns true if $name is a valid name for an alias */
628
/* returns NULL if a reserved word is used */
629
function is_validaliasname($name) {
630
	/* Array of reserved words */
631
	$reserved = array("port", "pass");
632
	if (in_array($name, $reserved, true))
633
		return; /* return NULL */
634
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
635
		return true;
636
	else
637
		return false;
638
}
639

    
640
/* returns true if $port is a valid TCP/UDP port */
641
function is_port($port) {
642
	$tmpports = explode(":", $port);
643
	foreach($tmpports as $tmpport) {
644
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
645
			continue;
646
		if (!ctype_digit($tmpport))
647
			return false;
648
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
649
			return false;
650
	}
651
	return true;
652
}
653

    
654
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
655
function is_portrange($portrange) {
656
	$ports = explode(":", $portrange);
657

    
658
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
659
}
660

    
661
/* returns true if $port is a valid port number or an alias thereof */
662
function is_portoralias($port) {
663
	global $config;
664

    
665
	if (is_alias($port)) {
666
		if (is_array($config['aliases']['alias'])) {
667
			foreach ($config['aliases']['alias'] as $alias) {
668
				if ($alias['name'] == $port && $alias['type'] == "port")
669
					return true;
670
				}
671
			}
672
			return false;
673
	} else
674
		return is_port($port);
675
}
676

    
677
/* returns true if $val is a valid shaper bandwidth value */
678
function is_valid_shaperbw($val) {
679
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
680
}
681

    
682
/* return the configured carp interface list */
683
function get_configured_carp_interface_list() {
684
	global $config;
685

    
686
	$iflist = array();
687

    
688
	if(is_array($config['virtualip']['vip'])) {
689
		$viparr = &$config['virtualip']['vip'];
690
		foreach ($viparr as $vip) {
691
			switch ($vip['mode']) {
692
			case "carp":
693
				$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
694
				$iflist[$vipif] = $vip['subnet'];
695
				break;
696
			}
697
		}
698
	}
699

    
700
	return $iflist;
701
}
702

    
703
/* return the configured IP aliases list */
704
function get_configured_ip_aliases_list($returnfullentry = false) {
705
	global $config;
706

    
707
	$alias_list=array();
708

    
709
	if(is_array($config['virtualip']['vip'])) {
710
		$viparr = &$config['virtualip']['vip'];
711
		foreach ($viparr as $vip) {
712
			if ($vip['mode']=="ipalias") {
713
				if ($returnfullentry)
714
					$alias_list[$vip['subnet']] = $vip;
715
				else
716
					$alias_list[$vip['subnet']] = $vip['interface'];
717
			}
718
		}
719
	}
720

    
721
	return $alias_list;
722
}
723

    
724

    
725
/* comparison function for sorting by the order in which interfaces are normally created */
726
function compare_interface_friendly_names($a, $b) {
727
	if ($a == $b)
728
		return 0;
729
	else if ($a == 'wan')
730
		return -1;
731
	else if ($b == 'wan')
732
		return 1;
733
	else if ($a == 'lan')
734
		return -1;
735
	else if ($b == 'lan')
736
		return 1;
737

    
738
	return strnatcmp($a, $b);
739
}
740

    
741
/* return the configured interfaces list. */
742
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
743
	global $config;
744

    
745
	$iflist = array();
746

    
747
	/* if list */
748
	foreach($config['interfaces'] as $if => $ifdetail) {
749
		if ($only_opt && ($if == "wan" || $if == "lan"))
750
			continue;
751
		if (isset($ifdetail['enable']) || $withdisabled == true)
752
			$iflist[$if] = $if;
753
	}
754

    
755
	return $iflist;
756
}
757

    
758
/* return the configured interfaces list. */
759
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
760
	global $config;
761

    
762
	$iflist = array();
763

    
764
	/* if list */
765
	foreach($config['interfaces'] as $if => $ifdetail) {
766
		if ($only_opt && ($if == "wan" || $if == "lan"))
767
			continue;
768
		if (isset($ifdetail['enable']) || $withdisabled == true) {
769
			$tmpif = get_real_interface($if);
770
			if (!empty($tmpif))
771
				$iflist[$tmpif] = $if;
772
		}
773
	}
774

    
775
	return $iflist;
776
}
777

    
778
/* return the configured interfaces list with their description. */
779
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
780
	global $config;
781

    
782
	$iflist = array();
783

    
784
	/* if list */
785
	foreach($config['interfaces'] as $if => $ifdetail) {
786
		if ($only_opt && ($if == "wan" || $if == "lan"))
787
			continue;
788
		if (isset($ifdetail['enable']) || $withdisabled == true) {
789
			if(empty($ifdetail['descr']))
790
				$iflist[$if] = strtoupper($if);
791
			else
792
				$iflist[$if] = strtoupper($ifdetail['descr']);
793
		}
794
	}
795

    
796
	return $iflist;
797
}
798

    
799
/*
800
 *   get_configured_ip_addresses() - Return a list of all configured
801
 *   interfaces IP Addresses
802
 *
803
 */
804
function get_configured_ip_addresses() {
805
	global $config;
806
	require_once("interfaces.inc");
807
	$ip_array = array();
808
	$interfaces = get_configured_interface_list();
809
	if(is_array($interfaces)) {
810
		foreach($interfaces as $int) {
811
			$ipaddr = get_interface_ip($int);
812
			$ip_array[$int] = $ipaddr;
813
		}
814
	}
815
	$interfaces = get_configured_carp_interface_list();
816
	if(is_array($interfaces)) 
817
		foreach($interfaces as $int => $ipaddr) 
818
			$ip_array[$int] = $ipaddr;
819

    
820
	/* pppoe server */
821
	if (is_array($config['pppoes']['pppoe'])) {
822
		foreach($config['pppoes']['pppoe'] as $pppoe) {
823
			if ($pppoe['mode'] == "server") {
824
				if(is_ipaddr($pppoe['localip'])) {
825
					$int = "pppoes". $pppoe['pppoeid'];
826
					$ip_array[$int] = $pppoe['localip'];
827
				}
828
			}
829
		}
830
	}
831
	return $ip_array;
832
}
833

    
834
/*
835
 *   get_configured_ipv6_addresses() - Return a list of all configured
836
 *   interfaces IPv6 Addresses
837
 *
838
 */
839
function get_configured_ipv6_addresses() {
840
	require_once("interfaces.inc");
841
	$ipv6_array = array();
842
	$interfaces = get_configured_interface_list();
843
	if(is_array($interfaces)) {
844
		foreach($interfaces as $int) {
845
			$ipaddrv6 = get_interface_ipv6($int);
846
			$ipv6_array[$int] = $ipaddrv6;
847
		}
848
	}
849
	$interfaces = get_configured_carp_interface_list();
850
	if(is_array($interfaces)) 
851
		foreach($interfaces as $int => $ipaddrv6) 
852
			$ipv6_array[$int] = $ipaddrv6;
853
	return $ipv6_array;
854
}
855

    
856
/*
857
 *   get_interface_list() - Return a list of all physical interfaces
858
 *   along with MAC and status.
859
 *
860
 *   $mode = "active" - use ifconfig -lu
861
 *           "media"  - use ifconfig to check physical connection
862
 *			status (much slower)
863
 */
864
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
865
        global $config;
866
	$upints = array();
867
        /* get a list of virtual interface types */
868
        if(!$vfaces) {
869
		$vfaces = array (
870
				'bridge',
871
				'ppp',
872
				'pppoe',
873
				'pptp',
874
				'l2tp',
875
				'sl',
876
				'gif',
877
				'gre',
878
				'faith',
879
				'lo',
880
				'ng',
881
				'_vlan',
882
				'_wlan',
883
				'pflog',
884
				'plip',
885
				'pfsync',
886
				'enc',
887
				'tun',
888
				'carp',
889
				'lagg',
890
				'vip',
891
				'ipfw'
892
		);
893
	}
894
	switch($mode) {
895
	case "active":
896
                $upints = pfSense_interface_listget(IFF_UP);
897
        	break;
898
	case "media":
899
		$intlist = pfSense_interface_listget();
900
                $ifconfig = "";
901
                exec("/sbin/ifconfig -a", $ifconfig);
902
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
903
                $ifstatus = preg_grep('/status:/', $ifconfig);
904
		foreach($ifstatus as $status) {
905
			$int = array_shift($intlist);
906
			if(stristr($status, "active")) $upints[] = $int;
907
		}
908
		break;
909
	default:
910
		$upints = pfSense_interface_listget();
911
		break;
912
	}
913
        /* build interface list with netstat */
914
        $linkinfo = "";
915
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
916
        array_shift($linkinfo);
917
	/* build ip address list with netstat */
918
	$ipinfo = "";
919
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
920
	array_shift($ipinfo);
921
	foreach($linkinfo as $link) {
922
		$friendly = "";
923
		$alink = explode(" ", $link);
924
		$ifname = rtrim(trim($alink[0]), '*');
925
		/* trim out all numbers before checking for vfaces */
926
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
927
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
928
			$toput = array(
929
					"mac" => trim($alink[1]),
930
					"up" => in_array($ifname, $upints)
931
				);
932
			foreach($ipinfo as $ip) {
933
				$aip = explode(" ", $ip);
934
				if($aip[0] == $ifname) {
935
					$toput['ipaddr'] = $aip[1];
936
				}
937
			}
938
			if (is_array($config['interfaces'])) {
939
				foreach($config['interfaces'] as $name => $int)
940
					if($int['if'] == $ifname) $friendly = $name;
941
			}
942
			switch($keyby) {
943
			case "physical":
944
				if($friendly != "") {
945
					$toput['friendly'] = $friendly;
946
				}
947
				$dmesg_arr = array();
948
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
949
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
950
				$toput['dmesg'] = $dmesg[1][0];
951
				$iflist[$ifname] = $toput;
952
				break;
953
			case "ppp":
954
				
955
			case "friendly":
956
				if($friendly != "") {
957
					$toput['if'] = $ifname;
958
					$iflist[$friendly] = $toput;
959
				}
960
				break;
961
			}
962
		}
963
	}
964
	return $iflist;
965
}
966

    
967
/****f* util/log_error
968
* NAME
969
*   log_error  - Sends a string to syslog.
970
* INPUTS
971
*   $error     - string containing the syslog message.
972
* RESULT
973
*   null
974
******/
975
function log_error($error) {
976
	global $g;
977
	$page = $_SERVER['SCRIPT_NAME'];
978
	syslog(LOG_ERR, "$page: $error");
979
	if ($g['debug'])
980
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
981
	return;
982
}
983

    
984
/****f* util/log_auth
985
* NAME
986
*   log_auth   - Sends a string to syslog as LOG_AUTH facility
987
* INPUTS
988
*   $error     - string containing the syslog message.
989
* RESULT
990
*   null
991
******/
992
function log_auth($error) {
993
	global $g;
994
	$page = $_SERVER['SCRIPT_NAME'];
995
	syslog(LOG_AUTH, "$page: $error");
996
	if ($g['debug'])
997
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
998
	return;
999
}
1000

    
1001
/****f* util/exec_command
1002
 * NAME
1003
 *   exec_command - Execute a command and return a string of the result.
1004
 * INPUTS
1005
 *   $command   - String of the command to be executed.
1006
 * RESULT
1007
 *   String containing the command's result.
1008
 * NOTES
1009
 *   This function returns the command's stdout and stderr.
1010
 ******/
1011
function exec_command($command) {
1012
	$output = array();
1013
	exec($command . ' 2>&1 ', $output);
1014
	return(implode("\n", $output));
1015
}
1016

    
1017
/* wrapper for exec() */
1018
function mwexec($command, $mute = false, $clearsigmask = false) {
1019
	global $g;
1020

    
1021
	if ($g['debug']) {
1022
		if (!$_SERVER['REMOTE_ADDR'])
1023
			echo "mwexec(): $command\n";
1024
	}
1025
	$oarr = array();
1026
	$retval = 0;
1027

    
1028
	if ($clearsigmask) {
1029
		$oldset = array();
1030
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1031
	}
1032
	$garbage = exec("$command 2>&1", $oarr, $retval);
1033
	if ($clearsigmask) {
1034
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1035
	}
1036

    
1037
	if(isset($config['system']['developerspew']))
1038
		$mute = false;
1039
	if(($retval <> 0) && ($mute === false)) {
1040
		$output = implode(" ", $oarr);
1041
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
1042
	}
1043
	return $retval;
1044
}
1045

    
1046
/* wrapper for exec() in background */
1047
function mwexec_bg($command, $clearsigmask = false) {
1048
	global $g;
1049

    
1050
	if ($g['debug']) {
1051
		if (!$_SERVER['REMOTE_ADDR'])
1052
			echo "mwexec(): $command\n";
1053
	}
1054

    
1055
	if ($clearsigmask) {
1056
		$oldset = array();
1057
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1058
	}
1059
	exec("nohup $command > /dev/null 2>&1 &");
1060
	if ($clearsigmask) {
1061
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1062
	}
1063
}
1064

    
1065
/* unlink a file, if it exists */
1066
function unlink_if_exists($fn) {
1067
	$to_do = glob($fn);
1068
	if(is_array($to_do)) {
1069
		foreach($to_do as $filename)
1070
			@unlink($filename);
1071
	} else {
1072
		@unlink($fn);
1073
	}
1074
}
1075
/* make a global alias table (for faster lookups) */
1076
function alias_make_table($config) {
1077
	global $aliastable;
1078

    
1079
	$aliastable = array();
1080

    
1081
	if (is_array($config['aliases']['alias'])) {
1082
		foreach ($config['aliases']['alias'] as $alias) {
1083
			if ($alias['name'])
1084
				$aliastable[$alias['name']] = $alias['address'];
1085
		}
1086
	}
1087
}
1088

    
1089
/* check if an alias exists */
1090
function is_alias($name) {
1091
	global $aliastable;
1092

    
1093
	return isset($aliastable[$name]);
1094
}
1095

    
1096
function alias_get_type($name) {
1097
        global $config;
1098
        
1099
	if (is_array($config['aliases']['alias'])) {
1100
		foreach ($config['aliases']['alias'] as $alias) {
1101
			if ($name == $alias['name'])
1102
				return $alias['type'];
1103
		}
1104
	}
1105

    
1106
        return "";
1107
}
1108

    
1109
/* expand a host or network alias, if necessary */
1110
function alias_expand($name) {
1111
	global $aliastable;
1112

    
1113
	if (isset($aliastable[$name]))
1114
		return "\${$name}";
1115
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1116
		return "{$name}";
1117
	else
1118
		return null;
1119
}
1120

    
1121
function alias_expand_urltable($name) {
1122
	global $config;
1123
	$urltable_prefix = "/var/db/aliastables/";
1124
	$urltable_filename = $urltable_prefix . $name . ".txt";
1125

    
1126
	if (is_array($config['aliases']['alias'])) {
1127
		foreach ($config['aliases']['alias'] as $alias) {
1128
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
1129
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1130
					return $urltable_filename;
1131
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1132
					return $urltable_filename;
1133
			}
1134
		}
1135
	}
1136
	return null;
1137
}
1138

    
1139
function subnet_size ($subnet) {
1140
	if (is_subnetv4($subnet)) {
1141
		list ($ip, $bits) = explode("/", $subnet);
1142
		return round(exp(log(2) * (32 - $bits)));
1143
	}
1144
	else if (is_subnetv6($subnet)) {
1145
		list ($ip, $bits) = explode("/", $subnet);
1146
		return round(exp(log(2) * (128 - $bits)));
1147
	}
1148
	else {
1149
		return 0;
1150
	}
1151
}
1152

    
1153
function subnet_expand ($subnet) {
1154
	if (is_subnetv4($subnet)) {
1155
		return subnetv4_expand($subnet);
1156
	} else if (is_subnetv6($subnet)) {
1157
		return subnetv6_expand($subnet);
1158
	} else {
1159
		return $subnet;
1160
	}
1161
}
1162

    
1163
function subnetv4_expand ($subnet) {
1164
	$result = array();
1165
	list ($ip, $bits) = explode("/", $subnet);
1166
	$net  = ip2long($ip);
1167
	$mask = (0xffffffff << (32 - $bits));
1168
	$net &= $mask;
1169
	$size = round(exp(log(2) * (32 - $bits)));
1170
	for ($i = 0; $i < $size; $i += 1) {
1171
		$result[] = long2ip($net | $i);
1172
	}
1173
	return $result;
1174
}
1175

    
1176
/* find out whether two subnets overlap */
1177
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1178

    
1179
	if (!is_numeric($bits1))
1180
		$bits1 = 32;
1181
	if (!is_numeric($bits2))
1182
		$bits2 = 32;
1183

    
1184
	if ($bits1 < $bits2)
1185
		$relbits = $bits1;
1186
	else
1187
		$relbits = $bits2;
1188

    
1189
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1190
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1191

    
1192
	return ($sn1 == $sn2);
1193
}
1194

    
1195
/* compare two IP addresses */
1196
function ipcmp($a, $b) {
1197
	if (ip_less_than($a, $b))
1198
		return -1;
1199
	else if (ip_greater_than($a, $b))
1200
		return 1;
1201
	else
1202
		return 0;
1203
}
1204

    
1205
/* return true if $addr is in $subnet, false if not */
1206
function ip_in_subnet($addr,$subnet) {
1207
	if(is_ipaddrv6($addr)) {
1208
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1209
		if($result)
1210
			return true;
1211
		else
1212
			return false;
1213
	}
1214
	list($ip, $mask) = explode('/', $subnet);
1215
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1216
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1217
}
1218

    
1219
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1220
function verify_digital_signature($fname) {
1221
	global $g;
1222

    
1223
	if(!file_exists("/usr/local/sbin/gzsig"))
1224
		return 4;
1225

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

    
1229
/* obtain MAC address given an IP address by looking at the ARP table */
1230
function arp_get_mac_by_ip($ip) {
1231
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1232
	$arpoutput = "";
1233
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1234

    
1235
	if ($arpoutput[0]) {
1236
		$arpi = explode(" ", $arpoutput[0]);
1237
		$macaddr = $arpi[3];
1238
		if (is_macaddr($macaddr))
1239
			return $macaddr;
1240
		else
1241
			return false;
1242
	}
1243

    
1244
	return false;
1245
}
1246

    
1247
/* return a fieldname that is safe for xml usage */
1248
function xml_safe_fieldname($fieldname) {
1249
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1250
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1251
			 ':', ',', '.', '\'', '\\'
1252
		);
1253
	return strtolower(str_replace($replace, "", $fieldname));
1254
}
1255

    
1256
function mac_format($clientmac) {
1257
    global $config, $cpzone;
1258

    
1259
    $mac = explode(":", $clientmac);
1260
    $mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1261

    
1262
    switch($mac_format) {
1263
        case 'singledash':
1264
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1265

    
1266
        case 'ietf':
1267
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1268

    
1269
        case 'cisco':
1270
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1271

    
1272
        case 'unformatted':
1273
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1274

    
1275
        default:
1276
		return $clientmac;
1277
    }
1278
}
1279

    
1280
function resolve_retry($hostname, $retries = 5) {
1281

    
1282
	if (is_ipaddr($hostname))
1283
		return $hostname;
1284

    
1285
       for ($i = 0; $i < $retries; $i++) {
1286
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1287
               $ip = gethostbyname($hostname);
1288

    
1289
		if ($ip && $ip != $hostname) {
1290
			/* success */
1291
			return $ip;
1292
		}
1293

    
1294
		sleep(1);
1295
	}
1296

    
1297
	return false;
1298
}
1299

    
1300
function format_bytes($bytes) {
1301
	if ($bytes >= 1073741824) {
1302
		return sprintf("%.2f GB", $bytes/1073741824);
1303
	} else if ($bytes >= 1048576) {
1304
		return sprintf("%.2f MB", $bytes/1048576);
1305
	} else if ($bytes >= 1024) {
1306
		return sprintf("%.0f KB", $bytes/1024);
1307
	} else {
1308
		return sprintf("%d bytes", $bytes);
1309
	}
1310
}
1311

    
1312
function update_filter_reload_status($text) {
1313
	global $g;
1314

    
1315
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1316
}
1317

    
1318
/****f* util/return_dir_as_array
1319
 * NAME
1320
 *   return_dir_as_array - Return a directory's contents as an array.
1321
 * INPUTS
1322
 *   $dir       - string containing the path to the desired directory.
1323
 * RESULT
1324
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1325
 ******/
1326
function return_dir_as_array($dir) {
1327
	$dir_array = array();
1328
	if (is_dir($dir)) {
1329
		if ($dh = opendir($dir)) {
1330
			while (($file = readdir($dh)) !== false) {
1331
				$canadd = 0;
1332
				if($file == ".") $canadd = 1;
1333
				if($file == "..") $canadd = 1;
1334
				if($canadd == 0)
1335
					array_push($dir_array, $file);
1336
			}
1337
			closedir($dh);
1338
		}
1339
	}
1340
	return $dir_array;
1341
}
1342

    
1343
function run_plugins($directory) {
1344
	global $config, $g;
1345

    
1346
	/* process packager manager custom rules */
1347
	$files = return_dir_as_array($directory);
1348
	if (is_array($files)) {
1349
		foreach ($files as $file) {
1350
			if (stristr($file, ".sh") == true)
1351
				mwexec($directory . $file . " start");
1352
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1353
				require_once($directory . "/" . $file);
1354
		}
1355
	}
1356
}
1357

    
1358
/*
1359
 *    safe_mkdir($path, $mode = 0755)
1360
 *    create directory if it doesn't already exist and isn't a file!
1361
 */
1362
function safe_mkdir($path, $mode=0755) {
1363
	global $g;
1364

    
1365
	if (!is_file($path) && !is_dir($path)) {
1366
		return @mkdir($path, $mode, true);
1367
	} else {
1368
		return false;
1369
	}
1370
}
1371

    
1372
/*
1373
 * make_dirs($path, $mode = 0755)
1374
 * create directory tree recursively (mkdir -p)
1375
 */
1376
function make_dirs($path, $mode = 0755) {
1377
	$base = '';
1378
	foreach (explode('/', $path) as $dir) {
1379
		$base .= "/$dir";
1380
		if (!is_dir($base)) {
1381
			if (!@mkdir($base, $mode))
1382
				return false;
1383
		}
1384
	}
1385
	return true;
1386
}
1387

    
1388
/*
1389
 * get_sysctl($names)
1390
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1391
 * name) and return an array of key/value pairs set for those that exist
1392
 */
1393
function get_sysctl($names) {
1394
	if (empty($names))
1395
		return array();
1396

    
1397
	if (is_array($names)) {
1398
		$name_list = array();
1399
		foreach ($names as $name) {
1400
			$name_list[] = escapeshellarg($name);
1401
		}
1402
	} else
1403
		$name_list = array(escapeshellarg($names));
1404

    
1405
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1406
	$values = array();
1407
	foreach ($output as $line) {
1408
		$line = explode(": ", $line, 2);
1409
		if (count($line) == 2)
1410
			$values[$line[0]] = $line[1];
1411
	}
1412

    
1413
	return $values;
1414
}
1415

    
1416
/*
1417
 * set_sysctl($value_list)
1418
 * Set sysctl OID's listed as key/value pairs and return
1419
 * an array with keys set for those that succeeded
1420
 */
1421
function set_sysctl($values) {
1422
	if (empty($values))
1423
		return array();
1424

    
1425
	$value_list = array();
1426
	foreach ($values as $key => $value) {
1427
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1428
	}
1429

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

    
1432
	/* Retry individually if failed (one or more read-only) */
1433
	if ($success <> 0 && count($value_list) > 1) {
1434
		foreach ($value_list as $value) {
1435
			exec("/sbin/sysctl -i " . $value, $output);
1436
		}
1437
	}
1438

    
1439
	$ret = array();
1440
	foreach ($output as $line) {
1441
		$line = explode(": ", $line, 2);
1442
		if (count($line) == 2)
1443
			$ret[$line[0]] = true;
1444
	}
1445

    
1446
	return $ret;
1447
}
1448

    
1449
/*
1450
 *     get_memory()
1451
 *     returns an array listing the amount of
1452
 *     memory installed in the hardware
1453
 *     [0]real and [1]available
1454
 */
1455
function get_memory() {
1456

    
1457
	$real = trim(`sysctl -n hw.physmem`, " \n");
1458
	$avail = trim(`sysctl -n hw.realmem`, " \n");
1459
	/* convert from bytes to megabytes */
1460
	return array(($real/1048576),($avail/1048576));
1461
}
1462

    
1463
function mute_kernel_msgs() {
1464
	global $config;
1465
	// Do not mute serial console.  The kernel gets very very cranky
1466
	// and will start dishing you cannot control tty errors.
1467
	switch (trim(file_get_contents("/etc/platform"))) {
1468
		case "nanobsd":
1469
		case "jail":
1470
			return;
1471
	}
1472
	if($config['system']['enableserial']) 
1473
		return;			
1474
	exec("/sbin/conscontrol mute on");
1475
}
1476

    
1477
function unmute_kernel_msgs() {
1478
	global $config;
1479
	// Do not mute serial console.  The kernel gets very very cranky
1480
	// and will start dishing you cannot control tty errors.
1481
	switch (trim(file_get_contents("/etc/platform"))) {
1482
		case "nanobsd":
1483
		case "jail":
1484
			return;
1485
	}
1486
	exec("/sbin/conscontrol mute off");
1487
}
1488

    
1489
function start_devd() {
1490
	global $g;
1491

    
1492
	if ($g['platform'] == 'jail')
1493
		return;
1494
	exec("/sbin/devd");
1495
	sleep(1);
1496
}
1497

    
1498
function is_interface_vlan_mismatch() {
1499
	global $config, $g;
1500

    
1501
	if (is_array($config['vlans']['vlan'])) {
1502
		foreach ($config['vlans']['vlan'] as $vlan) {
1503
			if (does_interface_exist($vlan['if']) == false)
1504
				return true;
1505
		}
1506
	}
1507

    
1508
	return false;
1509
}
1510

    
1511
function is_interface_mismatch() {
1512
	global $config, $g;
1513

    
1514
	$do_assign = false;
1515
	$i = 0;
1516
	$missing_interfaces = array();
1517
	if (is_array($config['interfaces'])) {
1518
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1519
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1520
				// Do not check these interfaces.
1521
				$i++;
1522
				continue;
1523
			}
1524
			else if (does_interface_exist($ifcfg['if']) == false) {
1525
				$missing_interfaces[] = $ifcfg['if'];
1526
				$do_assign = true;
1527
			} else
1528
				$i++;
1529
		}
1530
	}
1531

    
1532
	if ($g['minimum_nic_count'] > $i) {
1533
		$do_assign = true;
1534
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1535
		$do_assign = false;
1536

    
1537
	if (!empty($missing_interfaces) && $do_assign)
1538
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1539
	else
1540
		@unlink("{$g['tmp_path']}/missing_interfaces");
1541

    
1542
	return $do_assign;
1543
}
1544

    
1545
/* sync carp entries to other firewalls */
1546
function carp_sync_client() {
1547
	global $g;
1548
	send_event("filter sync");
1549
}
1550

    
1551
/****f* util/isAjax
1552
 * NAME
1553
 *   isAjax - reports if the request is driven from prototype
1554
 * INPUTS
1555
 *   none
1556
 * RESULT
1557
 *   true/false
1558
 ******/
1559
function isAjax() {
1560
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1561
}
1562

    
1563
/****f* util/timeout
1564
 * NAME
1565
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1566
 * INPUTS
1567
 *   optional, seconds to wait before timeout. Default 9 seconds.
1568
 * RESULT
1569
 *   returns 1 char of user input or null if no input.
1570
 ******/
1571
function timeout($timer = 9) {
1572
	while(!isset($key)) {
1573
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1574
		else { echo chr(8). "{$timer}"; }
1575
		`/bin/stty -icanon min 0 time 25`;
1576
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1577
		`/bin/stty icanon`;
1578
		if ($key == '')
1579
			unset($key);
1580
		$timer--;
1581
		if ($timer == 0)
1582
			break;
1583
	}
1584
	return $key;	
1585
}
1586

    
1587
/****f* util/msort
1588
 * NAME
1589
 *   msort - sort array
1590
 * INPUTS
1591
 *   $array to be sorted, field to sort by, direction of sort
1592
 * RESULT
1593
 *   returns newly sorted array
1594
 ******/
1595
function msort($array, $id="id", $sort_ascending=true) {
1596
	$temp_array = array();
1597
	while(count($array)>0) {
1598
		$lowest_id = 0;
1599
		$index=0;
1600
		foreach ($array as $item) {
1601
			if (isset($item[$id])) {
1602
				if ($array[$lowest_id][$id]) {
1603
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1604
						$lowest_id = $index;
1605
					}
1606
				}
1607
			}
1608
			$index++;
1609
		}
1610
		$temp_array[] = $array[$lowest_id];
1611
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1612
	}
1613
	if ($sort_ascending) {
1614
		return $temp_array;
1615
	} else {
1616
    		return array_reverse($temp_array);
1617
	}
1618
}
1619

    
1620
/****f* util/color
1621
 * NAME
1622
 *   color - outputs a color code to the ansi terminal if supported
1623
 * INPUTS
1624
 *   color code or color name
1625
 * RESULT
1626
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1627
 ******/
1628
function color($color = "0m") {
1629
	/*
1630
		Color codes available:
1631
		 0m reset; clears all colors and styles (to white on black)
1632
		 1m bold on (see below)
1633
		 3m italics on
1634
		 4m underline on
1635
		 7m inverse on; reverses foreground & background colors
1636
		 9m strikethrough on
1637
		 22m bold off (see below)
1638
		 23m italics off
1639
		 24m underline off
1640
		 27m inverse off
1641
		 29m strikethrough off
1642
		 30m set foreground color to black
1643
		 31m set foreground color to red
1644
		 32m set foreground color to green
1645
		 33m set foreground color to yellow
1646
		 34m set foreground color to blue
1647
		 35m set foreground color to magenta (purple)
1648
		 36m set foreground color to cyan
1649
		 37m set foreground color to white
1650
		 40m  set background color to black
1651
		 41m set background color to red
1652
		 42m set background color to green
1653
		 43m set background color to yellow
1654
		 44m set background color to blue
1655
		 45m set background color to magenta (purple)
1656
		 46m set background color to cyan
1657
		 47m set background color to white
1658
		 49m set background color to default (black)
1659
	*/	
1660
	// Allow caching of TERM to 
1661
	// speedup subequence requests.
1662
	global $TERM;
1663
	if(!$TERM) 
1664
		$TERM=`/usr/bin/env | grep color`;
1665
	if(!$TERM)
1666
		$TERM=`/usr/bin/env | grep cons25`;
1667
	if($TERM) {
1668
		$ESCAPE=chr(27);
1669
		switch ($color) {
1670
			case "black":
1671
				return "{$ESCAPE}[30m"; 
1672
			case "red":
1673
				return "{$ESCAPE}[31m"; 
1674
			case "green":
1675
				return "{$ESCAPE}[32m"; 
1676
			case "yellow":
1677
				return "{$ESCAPE}[33m"; 
1678
			case "blue":
1679
				return "{$ESCAPE}[34m"; 
1680
			case "magenta":
1681
				return "{$ESCAPE}[35m"; 
1682
			case "cyan":
1683
				return "{$ESCAPE}[36m"; 
1684
			case "white":
1685
				return "{$ESCAPE}[37m"; 
1686
			case "default":
1687
				return "{$ESCAPE}[39m"; 
1688
		}
1689
		return "{$ESCAPE}[{$color}";
1690
	}
1691
}
1692

    
1693
/****f* util/is_URL
1694
 * NAME
1695
 *   is_URL
1696
 * INPUTS
1697
 *   string to check
1698
 * RESULT
1699
 *   Returns true if item is a URL
1700
 ******/
1701
function is_URL($url) {
1702
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1703
	if($match)
1704
		return true;	
1705
	return false;
1706
}
1707

    
1708
function is_file_included($file = "") {
1709
	$files = get_included_files();
1710
	if (in_array($file, $files))
1711
		return true;
1712
	
1713
	return false;
1714
}
1715

    
1716
/*
1717
	This function was borrowed from a comment on PHP.net at the following URL:
1718
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1719
 */
1720
function array_merge_recursive_unique($array0, $array1) {
1721

    
1722
	$arrays = func_get_args();
1723
	$remains = $arrays;
1724

    
1725
	// We walk through each arrays and put value in the results (without
1726
	// considering previous value).
1727
	$result = array();
1728

    
1729
	// loop available array
1730
	foreach($arrays as $array) {
1731

    
1732
		// The first remaining array is $array. We are processing it. So
1733
		// we remove it from remaing arrays.
1734
        array_shift($remains);
1735

    
1736
		// We don't care non array param, like array_merge since PHP 5.0.
1737
		if(is_array($array)) {
1738
			// Loop values
1739
			foreach($array as $key => $value) {
1740
				if(is_array($value)) {
1741
					// we gather all remaining arrays that have such key available
1742
					$args = array();
1743
					foreach($remains as $remain) {
1744
						if(array_key_exists($key, $remain)) {
1745
							array_push($args, $remain[$key]);
1746
						}
1747
					}
1748

    
1749
					if(count($args) > 2) {
1750
						// put the recursion
1751
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1752
					} else {
1753
						foreach($value as $vkey => $vval) {
1754
							$result[$key][$vkey] = $vval;
1755
						}
1756
					}
1757
				} else {
1758
					// simply put the value
1759
					$result[$key] = $value;
1760
				}
1761
			}
1762
		}
1763
	}
1764
	return $result;
1765
}
1766

    
1767

    
1768
/*
1769
 * converts a string like "a,b,c,d"
1770
 * into an array like array("a" => "b", "c" => "d")
1771
 */
1772
function explode_assoc($delimiter, $string) {
1773
	$array = explode($delimiter, $string);
1774
	$result = array();
1775
	$numkeys = floor(count($array) / 2);
1776
	for ($i = 0; $i < $numkeys; $i += 1) {
1777
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1778
	}
1779
	return $result;
1780
}
1781

    
1782
function get_staticroutes($returnsubnetsonly = false) {
1783
	global $config;
1784
	require_once('filter.inc');
1785
	$allstaticroutes = array();
1786
	$allsubnets = array();
1787

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

    
1792
	/* Loop through routes and expand aliases as we find them. */
1793
	foreach ($config['staticroutes']['route'] as $route) {
1794
		if (is_alias($route['network'])) {
1795
			$subnets = filter_expand_alias_array($route['network']);
1796
			foreach ($subnets as $net) {
1797
				if (is_ipaddrv4($net))
1798
					$net .= "/32";
1799
				if (is_ipaddrv6($net) && !is_subnetv6($net))
1800
					$net .= "/128";
1801
				/* This must be a hostname, we can't use it. */
1802
				if (!is_subnet($net))
1803
					continue;
1804
				$temproute = $route;
1805
				$temproute['network'] = $net;
1806
				$allstaticroutes[] = $temproute;
1807
				$allsubnets[] = $net;
1808
			}
1809
		} elseif (is_subnet($route['network'])) {
1810
			$allstaticroutes[] = $route;
1811
			$allsubnets[] = $route['network'];
1812
		}
1813
	}
1814
	if ($returnsubnetsonly) {
1815
		return $allsubnets;
1816
	} else {
1817
		return $allstaticroutes;
1818
	}
1819
}
1820

    
1821
/****f* util/get_alias_list
1822
 * NAME
1823
 *   get_alias_list - Provide a list of aliases.
1824
 * INPUTS
1825
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
1826
 * RESULT
1827
 *   Array containing list of aliases.
1828
 *   If $type is unspecified, all aliases are returned.
1829
 *   If $type is a string, all aliases of the type specified in $type are returned.
1830
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
1831
 */
1832
function get_alias_list($type = null) {
1833
	global $config;
1834
	$result = array();
1835
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
1836
		foreach ($config['aliases']['alias'] as $alias) {
1837
			if ($type === null) {
1838
				$result[] = $alias['name'];
1839
			}
1840
			else if (is_array($type)) {
1841
				if (in_array($alias['type'], $type)) {
1842
					$result[] = $alias['name'];
1843
				}
1844
			}
1845
			else if ($type === $alias['type']) {
1846
				$result[] = $alias['name'];
1847
			}
1848
		}
1849
	}		
1850
	return $result;
1851
}
1852

    
1853
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
1854
function array_exclude($needle, $haystack) {
1855
	$result = array();
1856
	if (is_array($haystack)) {
1857
		foreach ($haystack as $thing) {
1858
			if ($needle !== $thing) {
1859
				$result[] = $thing;
1860
			}
1861
		}
1862
	}
1863
	return $result;
1864
}
1865

    
1866
function setup_library_paths() {
1867
	$current_library_paths = explode(":", exec("/sbin/ldconfig -r | /usr/bin/grep 'search directories' | /usr/bin/awk '{print $3;}'"));
1868
	$pbi_library_paths = array_merge(glob("/usr/pbi/*/lib", GLOB_ONLYDIR), glob("/usr/pbi/*/lib/*", GLOB_ONLYDIR));
1869
	foreach ($pbi_library_paths as $pbilib) {
1870
		if (!in_array($pbilib, $current_library_paths))
1871
			exec("/sbin/ldconfig -m {$pbilib}");
1872
	}
1873
}
1874

    
1875
function get_current_theme() {
1876
	global $config, $g;
1877
	/*
1878
	 *   if user has selected a custom template, use it.
1879
	 *   otherwise default to pfsense tempalte
1880
	 */
1881
	if (($g["disablethemeselection"] === true) && !empty($g["default_theme"]) && (is_dir($g["www_path"].'/themes/'.$g["default_theme"])))
1882
		$theme = $g["default_theme"];
1883
	elseif($config['theme'] <> "" && (is_dir($g["www_path"].'/themes/'.$config['theme'])))
1884
		$theme = $config['theme'];
1885
	else
1886
		$theme = "pfsense";
1887
	/*
1888
	 *  If this device is an apple ipod/iphone
1889
	 *  switch the theme to one that works with it.
1890
	 */
1891
	$lowres_ua = array("iPhone", "iPod", "iPad", "Android", "BlackBerry", "Opera Mini", "Opera Mobi", "PlayBook");
1892
	foreach($lowres_ua as $useragent)
1893
		if(strstr($_SERVER['HTTP_USER_AGENT'], $useragent))
1894
			$theme = (empty($g['theme_lowres']) && (is_dir($g["www_path"].'/themes/'.$g['theme_lowres']))) ? "pfsense" : $g['theme_lowres'];
1895
	return $theme;
1896
}
1897

    
1898
?>
(55-55/67)