Project

General

Profile

Download (48.8 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
/* returns true if $test is in the range between $start and $end */
683
function is_inrange_v4($test, $start, $end) {
684
	if ( (ip2ulong($test) <= ip2ulong($end)) && (ip2ulong($test) >= ip2ulong($start)) )
685
		return true;
686
	else
687
		return false;
688
}
689

    
690
/* returns true if $test is in the range between $start and $end */
691
function is_inrange_v6($test, $start, $end) {
692
	if ( (inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start)) )
693
		return true;
694
	else
695
		return false;
696
}
697

    
698
/* return the configured carp interface list */
699
function get_configured_carp_interface_list() {
700
	global $config;
701

    
702
	$iflist = array();
703

    
704
	if(is_array($config['virtualip']['vip'])) {
705
		$viparr = &$config['virtualip']['vip'];
706
		foreach ($viparr as $vip) {
707
			switch ($vip['mode']) {
708
			case "carp":
709
				$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
710
				$iflist[$vipif] = $vip['subnet'];
711
				break;
712
			}
713
		}
714
	}
715

    
716
	return $iflist;
717
}
718

    
719
/* return the configured IP aliases list */
720
function get_configured_ip_aliases_list($returnfullentry = false) {
721
	global $config;
722

    
723
	$alias_list=array();
724

    
725
	if(is_array($config['virtualip']['vip'])) {
726
		$viparr = &$config['virtualip']['vip'];
727
		foreach ($viparr as $vip) {
728
			if ($vip['mode']=="ipalias") {
729
				if ($returnfullentry)
730
					$alias_list[$vip['subnet']] = $vip;
731
				else
732
					$alias_list[$vip['subnet']] = $vip['interface'];
733
			}
734
		}
735
	}
736

    
737
	return $alias_list;
738
}
739

    
740

    
741
/* comparison function for sorting by the order in which interfaces are normally created */
742
function compare_interface_friendly_names($a, $b) {
743
	if ($a == $b)
744
		return 0;
745
	else if ($a == 'wan')
746
		return -1;
747
	else if ($b == 'wan')
748
		return 1;
749
	else if ($a == 'lan')
750
		return -1;
751
	else if ($b == 'lan')
752
		return 1;
753

    
754
	return strnatcmp($a, $b);
755
}
756

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

    
761
	$iflist = array();
762

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

    
771
	return $iflist;
772
}
773

    
774
/* return the configured interfaces list. */
775
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
776
	global $config;
777

    
778
	$iflist = array();
779

    
780
	/* if list */
781
	foreach($config['interfaces'] as $if => $ifdetail) {
782
		if ($only_opt && ($if == "wan" || $if == "lan"))
783
			continue;
784
		if (isset($ifdetail['enable']) || $withdisabled == true) {
785
			$tmpif = get_real_interface($if);
786
			if (!empty($tmpif))
787
				$iflist[$tmpif] = $if;
788
		}
789
	}
790

    
791
	return $iflist;
792
}
793

    
794
/* return the configured interfaces list with their description. */
795
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
796
	global $config;
797

    
798
	$iflist = array();
799

    
800
	/* if list */
801
	foreach($config['interfaces'] as $if => $ifdetail) {
802
		if ($only_opt && ($if == "wan" || $if == "lan"))
803
			continue;
804
		if (isset($ifdetail['enable']) || $withdisabled == true) {
805
			if(empty($ifdetail['descr']))
806
				$iflist[$if] = strtoupper($if);
807
			else
808
				$iflist[$if] = strtoupper($ifdetail['descr']);
809
		}
810
	}
811

    
812
	return $iflist;
813
}
814

    
815
/*
816
 *   get_configured_ip_addresses() - Return a list of all configured
817
 *   interfaces IP Addresses
818
 *
819
 */
820
function get_configured_ip_addresses() {
821
	global $config;
822
	require_once("interfaces.inc");
823
	$ip_array = array();
824
	$interfaces = get_configured_interface_list();
825
	if(is_array($interfaces)) {
826
		foreach($interfaces as $int) {
827
			$ipaddr = get_interface_ip($int);
828
			$ip_array[$int] = $ipaddr;
829
		}
830
	}
831
	$interfaces = get_configured_carp_interface_list();
832
	if(is_array($interfaces)) 
833
		foreach($interfaces as $int => $ipaddr) 
834
			$ip_array[$int] = $ipaddr;
835

    
836
	/* pppoe server */
837
	if (is_array($config['pppoes']['pppoe'])) {
838
		foreach($config['pppoes']['pppoe'] as $pppoe) {
839
			if ($pppoe['mode'] == "server") {
840
				if(is_ipaddr($pppoe['localip'])) {
841
					$int = "pppoes". $pppoe['pppoeid'];
842
					$ip_array[$int] = $pppoe['localip'];
843
				}
844
			}
845
		}
846
	}
847
	return $ip_array;
848
}
849

    
850
/*
851
 *   get_configured_ipv6_addresses() - Return a list of all configured
852
 *   interfaces IPv6 Addresses
853
 *
854
 */
855
function get_configured_ipv6_addresses() {
856
	require_once("interfaces.inc");
857
	$ipv6_array = array();
858
	$interfaces = get_configured_interface_list();
859
	if(is_array($interfaces)) {
860
		foreach($interfaces as $int) {
861
			$ipaddrv6 = get_interface_ipv6($int);
862
			$ipv6_array[$int] = $ipaddrv6;
863
		}
864
	}
865
	$interfaces = get_configured_carp_interface_list();
866
	if(is_array($interfaces)) 
867
		foreach($interfaces as $int => $ipaddrv6) 
868
			$ipv6_array[$int] = $ipaddrv6;
869
	return $ipv6_array;
870
}
871

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

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

    
1000
/****f* util/log_auth
1001
* NAME
1002
*   log_auth   - Sends a string to syslog as LOG_AUTH facility
1003
* INPUTS
1004
*   $error     - string containing the syslog message.
1005
* RESULT
1006
*   null
1007
******/
1008
function log_auth($error) {
1009
	global $g;
1010
	$page = $_SERVER['SCRIPT_NAME'];
1011
	syslog(LOG_AUTH, "$page: $error");
1012
	if ($g['debug'])
1013
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1014
	return;
1015
}
1016

    
1017
/****f* util/exec_command
1018
 * NAME
1019
 *   exec_command - Execute a command and return a string of the result.
1020
 * INPUTS
1021
 *   $command   - String of the command to be executed.
1022
 * RESULT
1023
 *   String containing the command's result.
1024
 * NOTES
1025
 *   This function returns the command's stdout and stderr.
1026
 ******/
1027
function exec_command($command) {
1028
	$output = array();
1029
	exec($command . ' 2>&1 ', $output);
1030
	return(implode("\n", $output));
1031
}
1032

    
1033
/* wrapper for exec() */
1034
function mwexec($command, $mute = false, $clearsigmask = false) {
1035
	global $g;
1036

    
1037
	if ($g['debug']) {
1038
		if (!$_SERVER['REMOTE_ADDR'])
1039
			echo "mwexec(): $command\n";
1040
	}
1041
	$oarr = array();
1042
	$retval = 0;
1043

    
1044
	if ($clearsigmask) {
1045
		$oldset = array();
1046
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1047
	}
1048
	$garbage = exec("$command 2>&1", $oarr, $retval);
1049
	if ($clearsigmask) {
1050
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1051
	}
1052

    
1053
	if(isset($config['system']['developerspew']))
1054
		$mute = false;
1055
	if(($retval <> 0) && ($mute === false)) {
1056
		$output = implode(" ", $oarr);
1057
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
1058
	}
1059
	return $retval;
1060
}
1061

    
1062
/* wrapper for exec() in background */
1063
function mwexec_bg($command, $clearsigmask = false) {
1064
	global $g;
1065

    
1066
	if ($g['debug']) {
1067
		if (!$_SERVER['REMOTE_ADDR'])
1068
			echo "mwexec(): $command\n";
1069
	}
1070

    
1071
	if ($clearsigmask) {
1072
		$oldset = array();
1073
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1074
	}
1075
	exec("nohup $command > /dev/null 2>&1 &");
1076
	if ($clearsigmask) {
1077
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1078
	}
1079
}
1080

    
1081
/* unlink a file, if it exists */
1082
function unlink_if_exists($fn) {
1083
	$to_do = glob($fn);
1084
	if(is_array($to_do)) {
1085
		foreach($to_do as $filename)
1086
			@unlink($filename);
1087
	} else {
1088
		@unlink($fn);
1089
	}
1090
}
1091
/* make a global alias table (for faster lookups) */
1092
function alias_make_table($config) {
1093
	global $aliastable;
1094

    
1095
	$aliastable = array();
1096

    
1097
	if (is_array($config['aliases']['alias'])) {
1098
		foreach ($config['aliases']['alias'] as $alias) {
1099
			if ($alias['name'])
1100
				$aliastable[$alias['name']] = $alias['address'];
1101
		}
1102
	}
1103
}
1104

    
1105
/* check if an alias exists */
1106
function is_alias($name) {
1107
	global $aliastable;
1108

    
1109
	return isset($aliastable[$name]);
1110
}
1111

    
1112
function alias_get_type($name) {
1113
        global $config;
1114
        
1115
	if (is_array($config['aliases']['alias'])) {
1116
		foreach ($config['aliases']['alias'] as $alias) {
1117
			if ($name == $alias['name'])
1118
				return $alias['type'];
1119
		}
1120
	}
1121

    
1122
        return "";
1123
}
1124

    
1125
/* expand a host or network alias, if necessary */
1126
function alias_expand($name) {
1127
	global $aliastable;
1128

    
1129
	if (isset($aliastable[$name]))
1130
		return "\${$name}";
1131
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1132
		return "{$name}";
1133
	else
1134
		return null;
1135
}
1136

    
1137
function alias_expand_urltable($name) {
1138
	global $config;
1139
	$urltable_prefix = "/var/db/aliastables/";
1140
	$urltable_filename = $urltable_prefix . $name . ".txt";
1141

    
1142
	if (is_array($config['aliases']['alias'])) {
1143
		foreach ($config['aliases']['alias'] as $alias) {
1144
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
1145
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1146
					return $urltable_filename;
1147
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1148
					return $urltable_filename;
1149
			}
1150
		}
1151
	}
1152
	return null;
1153
}
1154

    
1155
function subnet_size ($subnet) {
1156
	if (is_subnetv4($subnet)) {
1157
		list ($ip, $bits) = explode("/", $subnet);
1158
		return round(exp(log(2) * (32 - $bits)));
1159
	}
1160
	else if (is_subnetv6($subnet)) {
1161
		list ($ip, $bits) = explode("/", $subnet);
1162
		return round(exp(log(2) * (128 - $bits)));
1163
	}
1164
	else {
1165
		return 0;
1166
	}
1167
}
1168

    
1169
function subnet_expand ($subnet) {
1170
	if (is_subnetv4($subnet)) {
1171
		return subnetv4_expand($subnet);
1172
	} else if (is_subnetv6($subnet)) {
1173
		return subnetv6_expand($subnet);
1174
	} else {
1175
		return $subnet;
1176
	}
1177
}
1178

    
1179
function subnetv4_expand ($subnet) {
1180
	$result = array();
1181
	list ($ip, $bits) = explode("/", $subnet);
1182
	$net  = ip2long($ip);
1183
	$mask = (0xffffffff << (32 - $bits));
1184
	$net &= $mask;
1185
	$size = round(exp(log(2) * (32 - $bits)));
1186
	for ($i = 0; $i < $size; $i += 1) {
1187
		$result[] = long2ip($net | $i);
1188
	}
1189
	return $result;
1190
}
1191

    
1192
/* find out whether two subnets overlap */
1193
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1194

    
1195
	if (!is_numeric($bits1))
1196
		$bits1 = 32;
1197
	if (!is_numeric($bits2))
1198
		$bits2 = 32;
1199

    
1200
	if ($bits1 < $bits2)
1201
		$relbits = $bits1;
1202
	else
1203
		$relbits = $bits2;
1204

    
1205
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1206
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1207

    
1208
	return ($sn1 == $sn2);
1209
}
1210

    
1211
/* compare two IP addresses */
1212
function ipcmp($a, $b) {
1213
	if (ip_less_than($a, $b))
1214
		return -1;
1215
	else if (ip_greater_than($a, $b))
1216
		return 1;
1217
	else
1218
		return 0;
1219
}
1220

    
1221
/* return true if $addr is in $subnet, false if not */
1222
function ip_in_subnet($addr,$subnet) {
1223
	if(is_ipaddrv6($addr)) {
1224
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1225
		if($result)
1226
			return true;
1227
		else
1228
			return false;
1229
	}
1230
	list($ip, $mask) = explode('/', $subnet);
1231
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1232
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1233
}
1234

    
1235
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1236
function verify_digital_signature($fname) {
1237
	global $g;
1238

    
1239
	if(!file_exists("/usr/local/sbin/gzsig"))
1240
		return 4;
1241

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

    
1245
/* obtain MAC address given an IP address by looking at the ARP table */
1246
function arp_get_mac_by_ip($ip) {
1247
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1248
	$arpoutput = "";
1249
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1250

    
1251
	if ($arpoutput[0]) {
1252
		$arpi = explode(" ", $arpoutput[0]);
1253
		$macaddr = $arpi[3];
1254
		if (is_macaddr($macaddr))
1255
			return $macaddr;
1256
		else
1257
			return false;
1258
	}
1259

    
1260
	return false;
1261
}
1262

    
1263
/* return a fieldname that is safe for xml usage */
1264
function xml_safe_fieldname($fieldname) {
1265
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1266
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1267
			 ':', ',', '.', '\'', '\\'
1268
		);
1269
	return strtolower(str_replace($replace, "", $fieldname));
1270
}
1271

    
1272
function mac_format($clientmac) {
1273
    global $config, $cpzone;
1274

    
1275
    $mac = explode(":", $clientmac);
1276
    $mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1277

    
1278
    switch($mac_format) {
1279
        case 'singledash':
1280
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1281

    
1282
        case 'ietf':
1283
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1284

    
1285
        case 'cisco':
1286
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1287

    
1288
        case 'unformatted':
1289
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1290

    
1291
        default:
1292
		return $clientmac;
1293
    }
1294
}
1295

    
1296
function resolve_retry($hostname, $retries = 5) {
1297

    
1298
	if (is_ipaddr($hostname))
1299
		return $hostname;
1300

    
1301
       for ($i = 0; $i < $retries; $i++) {
1302
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1303
               $ip = gethostbyname($hostname);
1304

    
1305
		if ($ip && $ip != $hostname) {
1306
			/* success */
1307
			return $ip;
1308
		}
1309

    
1310
		sleep(1);
1311
	}
1312

    
1313
	return false;
1314
}
1315

    
1316
function format_bytes($bytes) {
1317
	if ($bytes >= 1073741824) {
1318
		return sprintf("%.2f GB", $bytes/1073741824);
1319
	} else if ($bytes >= 1048576) {
1320
		return sprintf("%.2f MB", $bytes/1048576);
1321
	} else if ($bytes >= 1024) {
1322
		return sprintf("%.0f KB", $bytes/1024);
1323
	} else {
1324
		return sprintf("%d bytes", $bytes);
1325
	}
1326
}
1327

    
1328
function update_filter_reload_status($text) {
1329
	global $g;
1330

    
1331
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1332
}
1333

    
1334
/****** util/return_dir_as_array
1335
 * NAME
1336
 *   return_dir_as_array - Return a directory's contents as an array.
1337
 * INPUTS
1338
 *   $dir          - string containing the path to the desired directory.
1339
 *   $filter_regex - string containing a regular expression to filter file names. Default empty.
1340
 * RESULT
1341
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1342
 ******/
1343
function return_dir_as_array($dir, $filter_regex = '') {
1344
	$dir_array = array();
1345
	if (is_dir($dir)) {
1346
		if ($dh = opendir($dir)) {
1347
			while (($file = readdir($dh)) !== false) {
1348
				if (($file == ".") || ($file == ".."))
1349
					continue;
1350

    
1351
				if (empty($filter_regex) || preg_match($filter_regex, $file))
1352
					array_push($dir_array, $file);
1353
			}
1354
			closedir($dh);
1355
		}
1356
	}
1357
	return $dir_array;
1358
}
1359

    
1360
function run_plugins($directory) {
1361
	global $config, $g;
1362

    
1363
	/* process packager manager custom rules */
1364
	$files = return_dir_as_array($directory);
1365
	if (is_array($files)) {
1366
		foreach ($files as $file) {
1367
			if (stristr($file, ".sh") == true)
1368
				mwexec($directory . $file . " start");
1369
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1370
				require_once($directory . "/" . $file);
1371
		}
1372
	}
1373
}
1374

    
1375
/*
1376
 *    safe_mkdir($path, $mode = 0755)
1377
 *    create directory if it doesn't already exist and isn't a file!
1378
 */
1379
function safe_mkdir($path, $mode=0755) {
1380
	global $g;
1381

    
1382
	if (!is_file($path) && !is_dir($path)) {
1383
		return @mkdir($path, $mode, true);
1384
	} else {
1385
		return false;
1386
	}
1387
}
1388

    
1389
/*
1390
 * make_dirs($path, $mode = 0755)
1391
 * create directory tree recursively (mkdir -p)
1392
 */
1393
function make_dirs($path, $mode = 0755) {
1394
	$base = '';
1395
	foreach (explode('/', $path) as $dir) {
1396
		$base .= "/$dir";
1397
		if (!is_dir($base)) {
1398
			if (!@mkdir($base, $mode))
1399
				return false;
1400
		}
1401
	}
1402
	return true;
1403
}
1404

    
1405
/*
1406
 * get_sysctl($names)
1407
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1408
 * name) and return an array of key/value pairs set for those that exist
1409
 */
1410
function get_sysctl($names) {
1411
	if (empty($names))
1412
		return array();
1413

    
1414
	if (is_array($names)) {
1415
		$name_list = array();
1416
		foreach ($names as $name) {
1417
			$name_list[] = escapeshellarg($name);
1418
		}
1419
	} else
1420
		$name_list = array(escapeshellarg($names));
1421

    
1422
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1423
	$values = array();
1424
	foreach ($output as $line) {
1425
		$line = explode(": ", $line, 2);
1426
		if (count($line) == 2)
1427
			$values[$line[0]] = $line[1];
1428
	}
1429

    
1430
	return $values;
1431
}
1432

    
1433
/*
1434
 * set_sysctl($value_list)
1435
 * Set sysctl OID's listed as key/value pairs and return
1436
 * an array with keys set for those that succeeded
1437
 */
1438
function set_sysctl($values) {
1439
	if (empty($values))
1440
		return array();
1441

    
1442
	$value_list = array();
1443
	foreach ($values as $key => $value) {
1444
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1445
	}
1446

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

    
1449
	/* Retry individually if failed (one or more read-only) */
1450
	if ($success <> 0 && count($value_list) > 1) {
1451
		foreach ($value_list as $value) {
1452
			exec("/sbin/sysctl -i " . $value, $output);
1453
		}
1454
	}
1455

    
1456
	$ret = array();
1457
	foreach ($output as $line) {
1458
		$line = explode(": ", $line, 2);
1459
		if (count($line) == 2)
1460
			$ret[$line[0]] = true;
1461
	}
1462

    
1463
	return $ret;
1464
}
1465

    
1466
/*
1467
 *     get_memory()
1468
 *     returns an array listing the amount of
1469
 *     memory installed in the hardware
1470
 *     [0]real and [1]available
1471
 */
1472
function get_memory() {
1473

    
1474
	$real = trim(`sysctl -n hw.physmem`, " \n");
1475
	$avail = trim(`sysctl -n hw.realmem`, " \n");
1476
	/* convert from bytes to megabytes */
1477
	return array(($real/1048576),($avail/1048576));
1478
}
1479

    
1480
function mute_kernel_msgs() {
1481
	global $config;
1482
	// Do not mute serial console.  The kernel gets very very cranky
1483
	// and will start dishing you cannot control tty errors.
1484
	switch (trim(file_get_contents("/etc/platform"))) {
1485
		case "nanobsd":
1486
		case "jail":
1487
			return;
1488
	}
1489
	if($config['system']['enableserial']) 
1490
		return;			
1491
	exec("/sbin/conscontrol mute on");
1492
}
1493

    
1494
function unmute_kernel_msgs() {
1495
	global $config;
1496
	// Do not mute serial console.  The kernel gets very very cranky
1497
	// and will start dishing you cannot control tty errors.
1498
	switch (trim(file_get_contents("/etc/platform"))) {
1499
		case "nanobsd":
1500
		case "jail":
1501
			return;
1502
	}
1503
	exec("/sbin/conscontrol mute off");
1504
}
1505

    
1506
function start_devd() {
1507
	global $g;
1508

    
1509
	if ($g['platform'] == 'jail')
1510
		return;
1511
	exec("/sbin/devd");
1512
	sleep(1);
1513
}
1514

    
1515
function is_interface_vlan_mismatch() {
1516
	global $config, $g;
1517

    
1518
	if (is_array($config['vlans']['vlan'])) {
1519
		foreach ($config['vlans']['vlan'] as $vlan) {
1520
			if (does_interface_exist($vlan['if']) == false)
1521
				return true;
1522
		}
1523
	}
1524

    
1525
	return false;
1526
}
1527

    
1528
function is_interface_mismatch() {
1529
	global $config, $g;
1530

    
1531
	$do_assign = false;
1532
	$i = 0;
1533
	$missing_interfaces = array();
1534
	if (is_array($config['interfaces'])) {
1535
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1536
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1537
				// Do not check these interfaces.
1538
				$i++;
1539
				continue;
1540
			}
1541
			else if (does_interface_exist($ifcfg['if']) == false) {
1542
				$missing_interfaces[] = $ifcfg['if'];
1543
				$do_assign = true;
1544
			} else
1545
				$i++;
1546
		}
1547
	}
1548

    
1549
	if ($g['minimum_nic_count'] > $i) {
1550
		$do_assign = true;
1551
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1552
		$do_assign = false;
1553

    
1554
	if (!empty($missing_interfaces) && $do_assign)
1555
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1556
	else
1557
		@unlink("{$g['tmp_path']}/missing_interfaces");
1558

    
1559
	return $do_assign;
1560
}
1561

    
1562
/* sync carp entries to other firewalls */
1563
function carp_sync_client() {
1564
	global $g;
1565
	send_event("filter sync");
1566
}
1567

    
1568
/****f* util/isAjax
1569
 * NAME
1570
 *   isAjax - reports if the request is driven from prototype
1571
 * INPUTS
1572
 *   none
1573
 * RESULT
1574
 *   true/false
1575
 ******/
1576
function isAjax() {
1577
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1578
}
1579

    
1580
/****f* util/timeout
1581
 * NAME
1582
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1583
 * INPUTS
1584
 *   optional, seconds to wait before timeout. Default 9 seconds.
1585
 * RESULT
1586
 *   returns 1 char of user input or null if no input.
1587
 ******/
1588
function timeout($timer = 9) {
1589
	while(!isset($key)) {
1590
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1591
		else { echo chr(8). "{$timer}"; }
1592
		`/bin/stty -icanon min 0 time 25`;
1593
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1594
		`/bin/stty icanon`;
1595
		if ($key == '')
1596
			unset($key);
1597
		$timer--;
1598
		if ($timer == 0)
1599
			break;
1600
	}
1601
	return $key;	
1602
}
1603

    
1604
/****f* util/msort
1605
 * NAME
1606
 *   msort - sort array
1607
 * INPUTS
1608
 *   $array to be sorted, field to sort by, direction of sort
1609
 * RESULT
1610
 *   returns newly sorted array
1611
 ******/
1612
function msort($array, $id="id", $sort_ascending=true) {
1613
	$temp_array = array();
1614
	while(count($array)>0) {
1615
		$lowest_id = 0;
1616
		$index=0;
1617
		foreach ($array as $item) {
1618
			if (isset($item[$id])) {
1619
				if ($array[$lowest_id][$id]) {
1620
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1621
						$lowest_id = $index;
1622
					}
1623
				}
1624
			}
1625
			$index++;
1626
		}
1627
		$temp_array[] = $array[$lowest_id];
1628
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1629
	}
1630
	if ($sort_ascending) {
1631
		return $temp_array;
1632
	} else {
1633
    		return array_reverse($temp_array);
1634
	}
1635
}
1636

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

    
1710
/****f* util/is_URL
1711
 * NAME
1712
 *   is_URL
1713
 * INPUTS
1714
 *   string to check
1715
 * RESULT
1716
 *   Returns true if item is a URL
1717
 ******/
1718
function is_URL($url) {
1719
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1720
	if($match)
1721
		return true;	
1722
	return false;
1723
}
1724

    
1725
function is_file_included($file = "") {
1726
	$files = get_included_files();
1727
	if (in_array($file, $files))
1728
		return true;
1729
	
1730
	return false;
1731
}
1732

    
1733
/*
1734
	This function was borrowed from a comment on PHP.net at the following URL:
1735
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1736
 */
1737
function array_merge_recursive_unique($array0, $array1) {
1738

    
1739
	$arrays = func_get_args();
1740
	$remains = $arrays;
1741

    
1742
	// We walk through each arrays and put value in the results (without
1743
	// considering previous value).
1744
	$result = array();
1745

    
1746
	// loop available array
1747
	foreach($arrays as $array) {
1748

    
1749
		// The first remaining array is $array. We are processing it. So
1750
		// we remove it from remaing arrays.
1751
        array_shift($remains);
1752

    
1753
		// We don't care non array param, like array_merge since PHP 5.0.
1754
		if(is_array($array)) {
1755
			// Loop values
1756
			foreach($array as $key => $value) {
1757
				if(is_array($value)) {
1758
					// we gather all remaining arrays that have such key available
1759
					$args = array();
1760
					foreach($remains as $remain) {
1761
						if(array_key_exists($key, $remain)) {
1762
							array_push($args, $remain[$key]);
1763
						}
1764
					}
1765

    
1766
					if(count($args) > 2) {
1767
						// put the recursion
1768
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1769
					} else {
1770
						foreach($value as $vkey => $vval) {
1771
							$result[$key][$vkey] = $vval;
1772
						}
1773
					}
1774
				} else {
1775
					// simply put the value
1776
					$result[$key] = $value;
1777
				}
1778
			}
1779
		}
1780
	}
1781
	return $result;
1782
}
1783

    
1784

    
1785
/*
1786
 * converts a string like "a,b,c,d"
1787
 * into an array like array("a" => "b", "c" => "d")
1788
 */
1789
function explode_assoc($delimiter, $string) {
1790
	$array = explode($delimiter, $string);
1791
	$result = array();
1792
	$numkeys = floor(count($array) / 2);
1793
	for ($i = 0; $i < $numkeys; $i += 1) {
1794
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1795
	}
1796
	return $result;
1797
}
1798

    
1799
function get_staticroutes($returnsubnetsonly = false) {
1800
	global $config;
1801
	require_once('filter.inc');
1802
	$allstaticroutes = array();
1803
	$allsubnets = array();
1804

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

    
1809
	/* Loop through routes and expand aliases as we find them. */
1810
	foreach ($config['staticroutes']['route'] as $route) {
1811
		if (is_alias($route['network'])) {
1812
			$subnets = filter_expand_alias_array($route['network']);
1813
			foreach ($subnets as $net) {
1814
				if (is_ipaddrv4($net))
1815
					$net .= "/32";
1816
				if (is_ipaddrv6($net) && !is_subnetv6($net))
1817
					$net .= "/128";
1818
				/* This must be a hostname, we can't use it. */
1819
				if (!is_subnet($net))
1820
					continue;
1821
				$temproute = $route;
1822
				$temproute['network'] = $net;
1823
				$allstaticroutes[] = $temproute;
1824
				$allsubnets[] = $net;
1825
			}
1826
		} elseif (is_subnet($route['network'])) {
1827
			$allstaticroutes[] = $route;
1828
			$allsubnets[] = $route['network'];
1829
		}
1830
	}
1831
	if ($returnsubnetsonly) {
1832
		return $allsubnets;
1833
	} else {
1834
		return $allstaticroutes;
1835
	}
1836
}
1837

    
1838
/****f* util/get_alias_list
1839
 * NAME
1840
 *   get_alias_list - Provide a list of aliases.
1841
 * INPUTS
1842
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
1843
 * RESULT
1844
 *   Array containing list of aliases.
1845
 *   If $type is unspecified, all aliases are returned.
1846
 *   If $type is a string, all aliases of the type specified in $type are returned.
1847
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
1848
 */
1849
function get_alias_list($type = null) {
1850
	global $config;
1851
	$result = array();
1852
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
1853
		foreach ($config['aliases']['alias'] as $alias) {
1854
			if ($type === null) {
1855
				$result[] = $alias['name'];
1856
			}
1857
			else if (is_array($type)) {
1858
				if (in_array($alias['type'], $type)) {
1859
					$result[] = $alias['name'];
1860
				}
1861
			}
1862
			else if ($type === $alias['type']) {
1863
				$result[] = $alias['name'];
1864
			}
1865
		}
1866
	}		
1867
	return $result;
1868
}
1869

    
1870
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
1871
function array_exclude($needle, $haystack) {
1872
	$result = array();
1873
	if (is_array($haystack)) {
1874
		foreach ($haystack as $thing) {
1875
			if ($needle !== $thing) {
1876
				$result[] = $thing;
1877
			}
1878
		}
1879
	}
1880
	return $result;
1881
}
1882

    
1883
function setup_library_paths() {
1884
	$current_library_paths = explode(":", exec("/sbin/ldconfig -r | /usr/bin/grep 'search directories' | /usr/bin/awk '{print $3;}'"));
1885
	$pbi_library_paths = array_merge(glob("/usr/pbi/*/lib", GLOB_ONLYDIR), glob("/usr/pbi/*/lib/*", GLOB_ONLYDIR));
1886
	foreach ($pbi_library_paths as $pbilib) {
1887
		if (!in_array($pbilib, $current_library_paths))
1888
			exec("/sbin/ldconfig -m {$pbilib}");
1889
	}
1890
}
1891

    
1892
function get_current_theme() {
1893
	global $config, $g;
1894
	/*
1895
	 *   if user has selected a custom template, use it.
1896
	 *   otherwise default to pfsense tempalte
1897
	 */
1898
	if (($g["disablethemeselection"] === true) && !empty($g["default_theme"]) && (is_dir($g["www_path"].'/themes/'.$g["default_theme"])))
1899
		$theme = $g["default_theme"];
1900
	elseif($config['theme'] <> "" && (is_dir($g["www_path"].'/themes/'.$config['theme'])))
1901
		$theme = $config['theme'];
1902
	else
1903
		$theme = "pfsense";
1904
	/*
1905
	 *  If this device is an apple ipod/iphone
1906
	 *  switch the theme to one that works with it.
1907
	 */
1908
	$lowres_ua = array("iPhone", "iPod", "iPad", "Android", "BlackBerry", "Opera Mini", "Opera Mobi", "PlayBook");
1909
	foreach($lowres_ua as $useragent)
1910
		if(strstr($_SERVER['HTTP_USER_AGENT'], $useragent))
1911
			$theme = (empty($g['theme_lowres']) && (is_dir($g["www_path"].'/themes/'.$g['theme_lowres']))) ? "pfsense" : $g['theme_lowres'];
1912
	return $theme;
1913
}
1914

    
1915
?>
(55-55/67)