Project

General

Profile

Download (45 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($pid) {
45
	$output = "";
46
	exec("/bin/pgrep -nF {$pid}", $output, $retval);
47

    
48
	return (intval($retval) == 0);
49
}
50

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

    
55
	return (intval($retval) == 0);
56
}
57

    
58
function isvalidproc($proc) {
59
	return is_process_running($proc);
60
}
61

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

    
68
	return 0;
69
}
70

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

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

    
83
function is_subsystem_dirty($subsystem = "") {
84
	global $g;
85

    
86
	if ($subsystem == "")
87
		return false;
88

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

    
92
	return false;
93
}
94

    
95
function mark_subsystem_dirty($subsystem = "") {
96
	global $g;
97

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

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

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

    
108
function config_lock() {
109
	return;
110
}
111
function config_unlock() {
112
	return;
113
}
114

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

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

    
141
function send_event($cmd) {
142
	global $g;
143

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

    
163
function send_multiple_events($cmds) {
164
	global $g;
165

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

    
172
	foreach ($cmds as $cmd)
173
		send_event($cmd);
174
}
175

    
176
function refcount_init($reference) {
177
	$shmid = @shmop_open($reference, "c", 0644, 10);
178
	@shmop_write($shmid, 0, 0);
179
	@shmop_close($shmid);
180
}
181

    
182
function refcount_reference($reference) {
183
	try {
184
		$shmid = @shmop_open($reference, "w", 0644, 10);
185
		if (!$shmid) {
186
			refcount_init($reference);
187
			$shmid = @shmop_open($reference, "w", 0, 0);
188
		}
189
		$shm_data = @shmop_read($shmid, 0, 10);
190
		$shm_data = intval($shm_data) + 1;
191
		@shmop_write($shmid, $shm_data, 0);
192
		@shmop_close($shmid);
193
	} catch (Exception $e) {
194
		log_error($e->getMessage());
195
	}
196

    
197
	return $shm_data;
198
}
199

    
200
function refcount_unreference($reference) {
201
	try {
202
		/* We assume that the shared memory exists. */
203
		$shmid = @shmop_open($reference, "w", 0, 0);
204
		$shm_data = @shmop_read($shmid, 0, 10);
205
		$shm_data = intval($shm_data) - 1;
206
		if ($shm_data < 0) {
207
			//debug_backtrace();
208
			log_error(sprintf(gettext("Reference %s is going negative, not doing unreference."), $reference));
209
		} else
210
			@shmop_write($shmid, $shm_data, 0);
211
		@shmop_close($shmid);
212
	} catch (Exception $e) {
213
		log_error($e->getMessage());
214
	}
215

    
216
	return $shm_data;
217
}
218

    
219
function is_module_loaded($module_name) {
220
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
221
	if (intval($running) >= 1)
222
		return true;
223
	else
224
		return false;
225
}
226

    
227
/* return the subnet address given a host address and a subnet bit count */
228
function gen_subnet($ipaddr, $bits) {
229
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
230
		return "";
231
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
232
}
233

    
234
/* return the subnet address given a host address and a subnet bit count */
235
function gen_subnetv6($ipaddr, $bits) {
236
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
237
		return "";
238

    
239
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
240
	return $address;
241
}
242

    
243
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
244
function gen_subnet_max($ipaddr, $bits) {
245
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
246
		return "";
247

    
248
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
249
}
250

    
251
/* Generate end number for a given ipv6 subnet mask */
252
function gen_subnetv6_max($ipaddr, $bits) {
253
	if(!is_ipaddrv6($ipaddr))
254
		return false;
255
	
256
	$mask = Net_IPv6::getNetmask('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',$bits);
257
	
258
	$inet_ip = (binary)inet_pton($ipaddr);
259
	$inet_mask = (binary)inet_pton($mask);
260

    
261
	$inet_end = $inet_ip | ~$inet_mask;
262

    
263
	return(Net_IPv6::uncompress(inet_ntop($inet_end)));
264
}
265

    
266
/* returns a subnet mask (long given a bit count) */
267
function gen_subnet_mask_long($bits) {
268
	$sm = 0;
269
	for ($i = 0; $i < $bits; $i++) {
270
		$sm >>= 1;
271
		$sm |= 0x80000000;
272
	}
273
	return $sm;
274
}
275

    
276
/* same as above but returns a string */
277
function gen_subnet_mask($bits) {
278
	return long2ip(gen_subnet_mask_long($bits));
279
}
280

    
281
/* Convert long int to IP address, truncating to 32-bits. */
282
function long2ip32($ip) {
283
	return long2ip($ip & 0xFFFFFFFF);
284
}
285

    
286
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
287
function ip2long32($ip) {
288
	return ( ip2long($ip) & 0xFFFFFFFF );
289
}
290

    
291
/* Convert IP address to unsigned long int. */
292
function ip2ulong($ip) {
293
	return sprintf("%u", ip2long32($ip));
294
}
295

    
296
/* Find out how many IPs are contained within a given IP range
297
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
298
 */
299
function ip_range_size($startip, $endip) {
300
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
301
		// Operate as unsigned long because otherwise it wouldn't work
302
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
303
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
304
	}
305
	return -1;
306
}
307

    
308
/* Find the smallest possible subnet mask which can contain a given number of IPs
309
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
310
 */
311
function find_smallest_cidr($number) {
312
	$smallest = 1;
313
	for ($b=32; $b > 0; $b--) {
314
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
315
	}
316
	return (32-$smallest);
317
}
318

    
319
/* Return the previous IP address before the given address */
320
function ip_before($ip) {
321
	return long2ip32(ip2long($ip)-1);
322
}
323

    
324
/* Return the next IP address after the given address */
325
function ip_after($ip) {
326
	return long2ip32(ip2long($ip)+1);
327
}
328

    
329
/* Return true if the first IP is 'before' the second */
330
function ip_less_than($ip1, $ip2) {
331
	// Compare as unsigned long because otherwise it wouldn't work when
332
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
333
	return ip2ulong($ip1) < ip2ulong($ip2);
334
}
335

    
336
/* Return true if the first IP is 'after' the second */
337
function ip_greater_than($ip1, $ip2) {
338
	// Compare as unsigned long because otherwise it wouldn't work
339
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
340
	return ip2ulong($ip1) > ip2ulong($ip2);
341
}
342

    
343
/* Convert a range of IPs to an array of subnets which can contain the range. */
344
function ip_range_to_subnet_array($startip, $endip) {
345
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
346
		return array();
347
	}
348

    
349
	// Container for subnets within this range.
350
	$rangesubnets = array();
351

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

    
355
	// Loop here to reduce subnet size and retest as needed. We need to make sure
356
	//   that the target subnet is wholly contained between $startip and $endip.
357
	for ($cidr; $cidr <= 32; $cidr++) {
358
		// Find the network and broadcast addresses for the subnet being tested.
359
		$targetsub_min = gen_subnet($startip, $cidr);
360
		$targetsub_max = gen_subnet_max($startip, $cidr);
361

    
362
		// Check best case where the range is exactly one subnet.
363
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
364
			// Hooray, the range is exactly this subnet!
365
			return array("{$startip}/{$cidr}");
366
		}
367

    
368
		// These remaining scenarios will find a subnet that uses the largest
369
		//  chunk possible of the range being tested, and leave the rest to be
370
		//  tested recursively after the loop.
371

    
372
		// Check if the subnet begins with $startip and ends before $endip
373
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
374
			break;
375
		}
376

    
377
		// Check if the subnet ends at $endip and starts after $startip
378
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
379
			break;
380
		}
381

    
382
		// Check if the subnet is between $startip and $endip
383
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
384
			break;
385
		}
386
	}
387

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

    
394
	// Add in the subnet we found before, to preserve ordering
395
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
396

    
397
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
398
	if ($endip != $targetsub_max) {
399
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
400
	}
401
	return $rangesubnets;
402
}
403

    
404
function is_iprange($range) {
405
	if (substr_count($range, '-') != 1) {
406
		return false;
407
	}
408
	list($ip1, $ip2) = explode ('-', $range);
409
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
410
}
411

    
412
function is_numericint($arg) {
413
	return (preg_match("/[^0-9]/", $arg) ? false : true);
414
}
415

    
416

    
417
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
418
function is_ipaddr($ipaddr) {
419
	if(is_ipaddrv4($ipaddr)) {
420
		return true;
421
	}
422
	if(is_ipaddrv6($ipaddr)) {
423
		return true;
424
	}
425
	return false;
426
}
427

    
428
/* returns true if $ipaddr is a valid IPv6 address */
429
function is_ipaddrv6($ipaddr) {
430
	$result = Net_IPv6::checkIPv6($ipaddr);
431
	return $result;
432
}
433

    
434
/* returns true if $ipaddr is a valid dotted IPv4 address */
435
function is_ipaddrv4($ipaddr) {
436
	if (!is_string($ipaddr))
437
		return false;
438

    
439
	$ip_long = ip2long($ipaddr);
440
	$ip_reverse = long2ip32($ip_long);
441

    
442
	if ($ipaddr == $ip_reverse)
443
		return true;
444
	else
445
		return false;
446
}
447

    
448

    
449
/* returns true if $ipaddr is a valid literal IPv6 address */
450
function is_literalipaddrv6($ipaddr) {
451
	if(preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match))
452
		$ipaddr = $match[1];
453
	else
454
		return false;
455

    
456
	return is_ipaddrv6($ipaddr);
457
}
458

    
459
function is_ipaddrwithport($ipport) {
460
	$parts = explode(":", $ipport);
461
	$port = array_pop($parts);
462
	if (count($parts) == 1) {
463
		return is_ipaddrv4($parts[0]) && is_port($port);
464
	} elseif (count($parts) > 1) {
465
		return is_literalipaddrv6(implode(":", $parts)) && is_port($port);
466
	} else {
467
		return false;
468
	}
469
}
470

    
471
function is_hostnamewithport($hostport) {
472
	$parts = explode(":", $hostport);
473
	$port = array_pop($parts);
474
	if (count($parts) == 1) {
475
		return is_hostname($parts[0]) && is_port($port);
476
	} else {
477
		return false;
478
	}
479
}
480

    
481
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
482
function is_ipaddroralias($ipaddr) {
483
	global $config;
484

    
485
	if (is_alias($ipaddr)) {
486
		if (is_array($config['aliases']['alias'])) {
487
			foreach ($config['aliases']['alias'] as $alias) {
488
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
489
					return true;
490
			}
491
		}
492
		return false;
493
	} else
494
		return is_ipaddr($ipaddr);
495

    
496
}
497

    
498
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format */
499
function is_subnet($subnet) {
500
	if(is_subnetv4($subnet)) {
501
		return true;
502
	}
503
	if(is_subnetv6($subnet)) {
504
		return true;
505
	}
506
	return false;
507
}
508

    
509
/* returns true if $subnet is a valid IPv4 subnet in CIDR format */
510
function is_subnetv4($subnet) {
511
	if (!is_string($subnet))
512
		return false;
513

    
514
	list($hp,$np) = explode('/', $subnet);
515

    
516
	if (!is_ipaddrv4($hp))
517
		return false;
518

    
519
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
520
		return false;
521

    
522
	return true;
523
}
524

    
525
/* returns true if $subnet is a valid IPv6 subnet in CIDR format */
526
function is_subnetv6($subnet) {
527
	if (!is_string($subnet))
528
		return false;
529

    
530
	list($hp,$np) = explode('/', $subnet);
531

    
532
	if (!is_ipaddrv6($hp))
533
		return false;
534

    
535
	if (!is_numeric($np) || ($np < 1) || ($np > 128))
536
		return false;
537

    
538
	return true;
539
}
540

    
541

    
542
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
543
function is_subnetoralias($subnet) {
544
	global $aliastable;
545

    
546
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
547
		return true;
548
	else
549
		return is_subnet($subnet);
550
}
551

    
552
/* returns true if $hostname is a valid hostname */
553
function is_hostname($hostname) {
554
	if (!is_string($hostname))
555
		return false;
556

    
557
	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))
558
		return true;
559
	else
560
		return false;
561
}
562

    
563
/* returns true if $domain is a valid domain name */
564
function is_domain($domain) {
565
	if (!is_string($domain))
566
		return false;
567

    
568
	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))
569
		return true;
570
	else
571
		return false;
572
}
573

    
574
/* returns true if $macaddr is a valid MAC address */
575
function is_macaddr($macaddr) {
576
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){5}$/i', $macaddr) == 1 ? true : false;
577
}
578

    
579
/* returns true if $name is a valid name for an alias */
580
/* returns NULL if a reserved word is used */
581
function is_validaliasname($name) {
582
	/* Array of reserved words */
583
	$reserved = array("port", "pass");
584
	if (in_array($name, $reserved, true))
585
		return; /* return NULL */
586
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
587
		return true;
588
	else
589
		return false;
590
}
591

    
592
/* returns true if $port is a valid TCP/UDP port */
593
function is_port($port) {
594
	$tmpports = explode(":", $port);
595
	foreach($tmpports as $tmpport) {
596
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
597
			continue;
598
		if (!ctype_digit($tmpport))
599
			return false;
600
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
601
			return false;
602
	}
603
	return true;
604
}
605

    
606
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
607
function is_portrange($portrange) {
608
	$ports = explode(":", $portrange);
609

    
610
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
611
}
612

    
613
/* returns true if $port is a valid port number or an alias thereof */
614
function is_portoralias($port) {
615
	global $config;
616

    
617
	if (is_alias($port)) {
618
		if (is_array($config['aliases']['alias'])) {
619
			foreach ($config['aliases']['alias'] as $alias) {
620
				if ($alias['name'] == $port && $alias['type'] == "port")
621
					return true;
622
				}
623
			}
624
			return false;
625
	} else
626
		return is_port($port);
627
}
628

    
629
/* returns true if $val is a valid shaper bandwidth value */
630
function is_valid_shaperbw($val) {
631
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
632
}
633

    
634
/* return the configured carp interface list */
635
function get_configured_carp_interface_list() {
636
	global $config;
637

    
638
	$iflist = array();
639

    
640
	if(is_array($config['virtualip']['vip'])) {
641
		$viparr = &$config['virtualip']['vip'];
642
		foreach ($viparr as $vip) {
643
			switch ($vip['mode']) {
644
			case "carp":
645
			case "carpdev-dhcp":
646
				$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
647
				$iflist[$vipif] = $vip['subnet'];
648
				break;
649
			}
650
		}
651
	}
652

    
653
	return $iflist;
654
}
655

    
656
/* return the configured IP aliases list */
657
function get_configured_ip_aliases_list($returnfullentry = false) {
658
	global $config;
659

    
660
	$alias_list=array();
661

    
662
	if(is_array($config['virtualip']['vip'])) {
663
		$viparr = &$config['virtualip']['vip'];
664
		foreach ($viparr as $vip) {
665
			if ($vip['mode']=="ipalias") {
666
				if ($returnfullentry)
667
					$alias_list[$vip['subnet']] = $vip;
668
				else
669
					$alias_list[$vip['subnet']] = $vip['interface'];
670
			}
671
		}
672
	}
673

    
674
	return $alias_list;
675
}
676

    
677

    
678
/* comparison function for sorting by the order in which interfaces are normally created */
679
function compare_interface_friendly_names($a, $b) {
680
	if ($a == $b)
681
		return 0;
682
	else if ($a == 'wan')
683
		return -1;
684
	else if ($b == 'wan')
685
		return 1;
686
	else if ($a == 'lan')
687
		return -1;
688
	else if ($b == 'lan')
689
		return 1;
690

    
691
	return strnatcmp($a, $b);
692
}
693

    
694
/* return the configured interfaces list. */
695
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
696
	global $config;
697

    
698
	$iflist = array();
699

    
700
	/* if list */
701
	foreach($config['interfaces'] as $if => $ifdetail) {
702
		if ($only_opt && ($if == "wan" || $if == "lan"))
703
			continue;
704
		if (isset($ifdetail['enable']) || $withdisabled == true)
705
			$iflist[$if] = $if;
706
	}
707

    
708
	return $iflist;
709
}
710

    
711
/* return the configured interfaces list. */
712
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
713
	global $config;
714

    
715
	$iflist = array();
716

    
717
	/* if list */
718
	foreach($config['interfaces'] as $if => $ifdetail) {
719
		if ($only_opt && ($if == "wan" || $if == "lan"))
720
			continue;
721
		if (isset($ifdetail['enable']) || $withdisabled == true) {
722
			$tmpif = get_real_interface($if);
723
			if (!empty($tmpif))
724
				$iflist[$tmpif] = $if;
725
		}
726
	}
727

    
728
	return $iflist;
729
}
730

    
731
/* return the configured interfaces list with their description. */
732
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
733
	global $config;
734

    
735
	$iflist = array();
736

    
737
	/* if list */
738
	foreach($config['interfaces'] as $if => $ifdetail) {
739
		if ($only_opt && ($if == "wan" || $if == "lan"))
740
			continue;
741
		if (isset($ifdetail['enable']) || $withdisabled == true) {
742
			if(empty($ifdetail['descr']))
743
				$iflist[$if] = strtoupper($if);
744
			else
745
				$iflist[$if] = strtoupper($ifdetail['descr']);
746
		}
747
	}
748

    
749
	return $iflist;
750
}
751

    
752
/*
753
 *   get_configured_ip_addresses() - Return a list of all configured
754
 *   interfaces IP Addresses
755
 *
756
 */
757
function get_configured_ip_addresses() {
758
	require_once("interfaces.inc");
759
	$ip_array = array();
760
	$interfaces = get_configured_interface_list();
761
	if(is_array($interfaces)) {
762
		foreach($interfaces as $int) {
763
			$ipaddr = get_interface_ip($int);
764
			$ip_array[$int] = $ipaddr;
765
		}
766
	}
767
	$interfaces = get_configured_carp_interface_list();
768
	if(is_array($interfaces)) 
769
		foreach($interfaces as $int => $ipaddr) 
770
			$ip_array[$int] = $ipaddr;
771
	return $ip_array;
772
}
773

    
774
/*
775
 *   get_configured_ipv6_addresses() - Return a list of all configured
776
 *   interfaces IPv6 Addresses
777
 *
778
 */
779
function get_configured_ipv6_addresses() {
780
	require_once("interfaces.inc");
781
	$ipv6_array = array();
782
	$interfaces = get_configured_interface_list();
783
	if(is_array($interfaces)) {
784
		foreach($interfaces as $int) {
785
			$ipaddrv6 = get_interface_ipv6($int);
786
			$ipv6_array[$int] = $ipaddrv6;
787
		}
788
	}
789
	$interfaces = get_configured_carp_interface_list();
790
	if(is_array($interfaces)) 
791
		foreach($interfaces as $int => $ipaddrv6) 
792
			$ipv6_array[$int] = $ipaddrv6;
793
	return $ipv6_array;
794
}
795

    
796
/*
797
 *   get_interface_list() - Return a list of all physical interfaces
798
 *   along with MAC and status.
799
 *
800
 *   $mode = "active" - use ifconfig -lu
801
 *           "media"  - use ifconfig to check physical connection
802
 *			status (much slower)
803
 */
804
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
805
        global $config;
806
	$upints = array();
807
        /* get a list of virtual interface types */
808
        if(!$vfaces) {
809
		$vfaces = array (
810
				'bridge',
811
				'ppp',
812
				'pppoe',
813
				'pptp',
814
				'l2tp',
815
				'sl',
816
				'gif',
817
				'gre',
818
				'faith',
819
				'lo',
820
				'ng',
821
				'_vlan',
822
				'_wlan',
823
				'pflog',
824
				'plip',
825
				'pfsync',
826
				'enc',
827
				'tun',
828
				'carp',
829
				'lagg',
830
				'vip',
831
				'ipfw'
832
		);
833
	}
834
	switch($mode) {
835
	case "active":
836
                $upints = pfSense_interface_listget(IFF_UP);
837
        	break;
838
	case "media":
839
		$intlist = pfSense_interface_listget();
840
                $ifconfig = "";
841
                exec("/sbin/ifconfig -a", $ifconfig);
842
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
843
                $ifstatus = preg_grep('/status:/', $ifconfig);
844
		foreach($ifstatus as $status) {
845
			$int = array_shift($intlist);
846
			if(stristr($status, "active")) $upints[] = $int;
847
		}
848
		break;
849
	default:
850
		$upints = pfSense_interface_listget();
851
		break;
852
	}
853
        /* build interface list with netstat */
854
        $linkinfo = "";
855
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
856
        array_shift($linkinfo);
857
	/* build ip address list with netstat */
858
	$ipinfo = "";
859
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
860
	array_shift($ipinfo);
861
	foreach($linkinfo as $link) {
862
		$friendly = "";
863
		$alink = explode(" ", $link);
864
		$ifname = rtrim(trim($alink[0]), '*');
865
		/* trim out all numbers before checking for vfaces */
866
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
867
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
868
			$toput = array(
869
					"mac" => trim($alink[1]),
870
					"up" => in_array($ifname, $upints)
871
				);
872
			foreach($ipinfo as $ip) {
873
				$aip = explode(" ", $ip);
874
				if($aip[0] == $ifname) {
875
					$toput['ipaddr'] = $aip[1];
876
				}
877
			}
878
			if (is_array($config['interfaces'])) {
879
				foreach($config['interfaces'] as $name => $int)
880
					if($int['if'] == $ifname) $friendly = $name;
881
			}
882
			switch($keyby) {
883
			case "physical":
884
				if($friendly != "") {
885
					$toput['friendly'] = $friendly;
886
				}
887
				$dmesg_arr = array();
888
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
889
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
890
				$toput['dmesg'] = $dmesg[1][0];
891
				$iflist[$ifname] = $toput;
892
				break;
893
			case "ppp":
894
				
895
			case "friendly":
896
				if($friendly != "") {
897
					$toput['if'] = $ifname;
898
					$iflist[$friendly] = $toput;
899
				}
900
				break;
901
			}
902
		}
903
	}
904
	return $iflist;
905
}
906

    
907
/****f* util/log_error
908
* NAME
909
*   log_error  - Sends a string to syslog.
910
* INPUTS
911
*   $error     - string containing the syslog message.
912
* RESULT
913
*   null
914
******/
915
function log_error($error) {
916
	global $g;
917
	$page = $_SERVER['SCRIPT_NAME'];
918
	syslog(LOG_ERR, "$page: $error");
919
	if ($g['debug'])
920
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
921
	return;
922
}
923

    
924
/****f* util/log_auth
925
* NAME
926
*   log_error  - Sends a string to syslog as LOG_AUTH facility
927
* INPUTS
928
*   $error     - string containing the syslog message.
929
* RESULT
930
*   null
931
******/
932
function log_auth($error) {
933
	global $g;
934
	$page = $_SERVER['SCRIPT_NAME'];
935
	syslog(LOG_AUTH, "$page: $error");
936
	if ($g['debug'])
937
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
938
	return;
939
}
940

    
941
/****f* util/exec_command
942
 * NAME
943
 *   exec_command - Execute a command and return a string of the result.
944
 * INPUTS
945
 *   $command   - String of the command to be executed.
946
 * RESULT
947
 *   String containing the command's result.
948
 * NOTES
949
 *   This function returns the command's stdout and stderr.
950
 ******/
951
function exec_command($command) {
952
	$output = array();
953
	exec($command . ' 2>&1 ', $output);
954
	return(implode("\n", $output));
955
}
956

    
957
/* wrapper for exec() */
958
function mwexec($command, $mute = false, $clearsigmask = false) {
959
	global $g;
960

    
961
	if ($g['debug']) {
962
		if (!$_SERVER['REMOTE_ADDR'])
963
			echo "mwexec(): $command\n";
964
	}
965
	$oarr = array();
966
	$retval = 0;
967

    
968
	if ($clearsigmask) {
969
		$oldset = array();
970
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
971
	}
972
	$garbage = exec("$command 2>&1", $oarr, $retval);
973
	if ($clearsigmask) {
974
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
975
	}
976

    
977
	if(isset($config['system']['developerspew']))
978
		$mute = false;
979
	if(($retval <> 0) && ($mute === false)) {
980
		$output = implode(" ", $oarr);
981
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
982
	}
983
	return $retval;
984
}
985

    
986
/* wrapper for exec() in background */
987
function mwexec_bg($command, $clearsigmask = false) {
988
	global $g;
989

    
990
	if ($g['debug']) {
991
		if (!$_SERVER['REMOTE_ADDR'])
992
			echo "mwexec(): $command\n";
993
	}
994

    
995
	if ($clearsigmask) {
996
		$oldset = array();
997
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
998
	}
999
	exec("nohup $command > /dev/null 2>&1 &");
1000
	if ($clearsigmask) {
1001
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1002
	}
1003
}
1004

    
1005
/* unlink a file, if it exists */
1006
function unlink_if_exists($fn) {
1007
	$to_do = glob($fn);
1008
	if(is_array($to_do)) {
1009
		foreach($to_do as $filename)
1010
			@unlink($filename);
1011
	} else {
1012
		@unlink($fn);
1013
	}
1014
}
1015
/* make a global alias table (for faster lookups) */
1016
function alias_make_table($config) {
1017
	global $aliastable;
1018

    
1019
	$aliastable = array();
1020

    
1021
	if (is_array($config['aliases']['alias'])) {
1022
		foreach ($config['aliases']['alias'] as $alias) {
1023
			if ($alias['name'])
1024
				$aliastable[$alias['name']] = $alias['address'];
1025
		}
1026
	}
1027
}
1028

    
1029
/* check if an alias exists */
1030
function is_alias($name) {
1031
	global $aliastable;
1032

    
1033
	return isset($aliastable[$name]);
1034
}
1035

    
1036
function alias_get_type($name) {
1037
        global $config;
1038
        
1039
	if (is_array($config['aliases']['alias'])) {
1040
		foreach ($config['aliases']['alias'] as $alias) {
1041
			if ($name == $alias['name'])
1042
				return $alias['type'];
1043
		}
1044
	}
1045

    
1046
        return "";
1047
}
1048

    
1049
/* expand a host or network alias, if necessary */
1050
function alias_expand($name) {
1051
	global $aliastable;
1052

    
1053
	if (isset($aliastable[$name]))
1054
		return "\${$name}";
1055
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1056
		return "{$name}";
1057
	else
1058
		return null;
1059
}
1060

    
1061
function alias_expand_urltable($name) {
1062
	global $config;
1063
	$urltable_prefix = "/var/db/aliastables/";
1064
	$urltable_filename = $urltable_prefix . $name . ".txt";
1065

    
1066
	if (is_array($config['aliases']['alias'])) {
1067
		foreach ($config['aliases']['alias'] as $alias) {
1068
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
1069
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1070
					return $urltable_filename;
1071
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1072
					return $urltable_filename;
1073
			}
1074
		}
1075
	}
1076
	return null;
1077
}
1078

    
1079
function subnet_size ($subnet) {
1080
	if (is_subnetv4($subnet)) {
1081
		list ($ip, $bits) = explode("/", $subnet);
1082
		return round(exp(log(2) * (32 - $bits)));
1083
	}
1084
	else if (is_subnetv6($subnet)) {
1085
		list ($ip, $bits) = explode("/", $subnet);
1086
		return round(exp(log(2) * (128 - $bits)));
1087
	}
1088
	else {
1089
		return 0;
1090
	}
1091
}
1092

    
1093
function subnet_expand ($subnet) {
1094
	if (is_subnetv4($subnet)) {
1095
		return subnetv4_expand($subnet);
1096
	} else if (is_subnetv6($subnet)) {
1097
		return subnetv6_expand($subnet);
1098
	} else {
1099
		return $subnet;
1100
	}
1101
}
1102

    
1103
function subnetv4_expand ($subnet) {
1104
	$result = array();
1105
	list ($ip, $bits) = explode("/", $subnet);
1106
	$net  = ip2long($ip);
1107
	$mask = (0xffffffff << (32 - $bits));
1108
	$net &= $mask;
1109
	$size = round(exp(log(2) * (32 - $bits)));
1110
	for ($i = 0; $i < $size; $i += 1) {
1111
		$result[] = long2ip($net | $i);
1112
	}
1113
	return $result;
1114
}
1115

    
1116
/* find out whether two subnets overlap */
1117
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1118

    
1119
	if (!is_numeric($bits1))
1120
		$bits1 = 32;
1121
	if (!is_numeric($bits2))
1122
		$bits2 = 32;
1123

    
1124
	if ($bits1 < $bits2)
1125
		$relbits = $bits1;
1126
	else
1127
		$relbits = $bits2;
1128

    
1129
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1130
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1131

    
1132
	return ($sn1 == $sn2);
1133
}
1134

    
1135
/* compare two IP addresses */
1136
function ipcmp($a, $b) {
1137
	if (ip_less_than($a, $b))
1138
		return -1;
1139
	else if (ip_greater_than($a, $b))
1140
		return 1;
1141
	else
1142
		return 0;
1143
}
1144

    
1145
/* return true if $addr is in $subnet, false if not */
1146
function ip_in_subnet($addr,$subnet) {
1147
	if(is_ipaddrv6($addr)) {
1148
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1149
		if($result)
1150
			return true;
1151
		else
1152
			return false;
1153
	}
1154
	list($ip, $mask) = explode('/', $subnet);
1155
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1156
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1157
}
1158

    
1159
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1160
function verify_digital_signature($fname) {
1161
	global $g;
1162

    
1163
	if(!file_exists("/usr/local/sbin/gzsig"))
1164
		return 4;
1165

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

    
1169
/* obtain MAC address given an IP address by looking at the ARP table */
1170
function arp_get_mac_by_ip($ip) {
1171
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1172
	$arpoutput = "";
1173
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1174

    
1175
	if ($arpoutput[0]) {
1176
		$arpi = explode(" ", $arpoutput[0]);
1177
		$macaddr = $arpi[3];
1178
		if (is_macaddr($macaddr))
1179
			return $macaddr;
1180
		else
1181
			return false;
1182
	}
1183

    
1184
	return false;
1185
}
1186

    
1187
/* return a fieldname that is safe for xml usage */
1188
function xml_safe_fieldname($fieldname) {
1189
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1190
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1191
			 ':', ',', '.', '\'', '\\'
1192
		);
1193
	return strtolower(str_replace($replace, "", $fieldname));
1194
}
1195

    
1196
function mac_format($clientmac) {
1197
    global $config;
1198

    
1199
    $mac = explode(":", $clientmac);
1200
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
1201

    
1202
    switch($mac_format) {
1203
        case 'singledash':
1204
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1205

    
1206
        case 'ietf':
1207
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1208

    
1209
        case 'cisco':
1210
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1211

    
1212
        case 'unformatted':
1213
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1214

    
1215
        default:
1216
		return $clientmac;
1217
    }
1218
}
1219

    
1220
function resolve_retry($hostname, $retries = 5) {
1221

    
1222
	if (is_ipaddr($hostname))
1223
		return $hostname;
1224

    
1225
       for ($i = 0; $i < $retries; $i++) {
1226
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1227
               $ip = gethostbyname($hostname);
1228

    
1229
		if ($ip && $ip != $hostname) {
1230
			/* success */
1231
			return $ip;
1232
		}
1233

    
1234
		sleep(1);
1235
	}
1236

    
1237
	return false;
1238
}
1239

    
1240
function format_bytes($bytes) {
1241
	if ($bytes >= 1073741824) {
1242
		return sprintf("%.2f GB", $bytes/1073741824);
1243
	} else if ($bytes >= 1048576) {
1244
		return sprintf("%.2f MB", $bytes/1048576);
1245
	} else if ($bytes >= 1024) {
1246
		return sprintf("%.0f KB", $bytes/1024);
1247
	} else {
1248
		return sprintf("%d bytes", $bytes);
1249
	}
1250
}
1251

    
1252
function update_filter_reload_status($text) {
1253
	global $g;
1254

    
1255
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1256
}
1257

    
1258
/****f* util/return_dir_as_array
1259
 * NAME
1260
 *   return_dir_as_array - Return a directory's contents as an array.
1261
 * INPUTS
1262
 *   $dir       - string containing the path to the desired directory.
1263
 * RESULT
1264
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1265
 ******/
1266
function return_dir_as_array($dir) {
1267
	$dir_array = array();
1268
	if (is_dir($dir)) {
1269
		if ($dh = opendir($dir)) {
1270
			while (($file = readdir($dh)) !== false) {
1271
				$canadd = 0;
1272
				if($file == ".") $canadd = 1;
1273
				if($file == "..") $canadd = 1;
1274
				if($canadd == 0)
1275
					array_push($dir_array, $file);
1276
			}
1277
			closedir($dh);
1278
		}
1279
	}
1280
	return $dir_array;
1281
}
1282

    
1283
function run_plugins($directory) {
1284
	global $config, $g;
1285

    
1286
	/* process packager manager custom rules */
1287
	$files = return_dir_as_array($directory);
1288
	if (is_array($files)) {
1289
		foreach ($files as $file) {
1290
			if (stristr($file, ".sh") == true)
1291
				mwexec($directory . $file . " start");
1292
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1293
				require_once($directory . "/" . $file);
1294
		}
1295
	}
1296
}
1297

    
1298
/*
1299
 *    safe_mkdir($path, $mode = 0755)
1300
 *    create directory if it doesn't already exist and isn't a file!
1301
 */
1302
function safe_mkdir($path, $mode=0755) {
1303
	global $g;
1304

    
1305
	if (!is_file($path) && !is_dir($path)) {
1306
		return @mkdir($path, $mode, true);
1307
	} else {
1308
		return false;
1309
	}
1310
}
1311

    
1312
/*
1313
 * make_dirs($path, $mode = 0755)
1314
 * create directory tree recursively (mkdir -p)
1315
 */
1316
function make_dirs($path, $mode = 0755) {
1317
	$base = '';
1318
	foreach (explode('/', $path) as $dir) {
1319
		$base .= "/$dir";
1320
		if (!is_dir($base)) {
1321
			if (!@mkdir($base, $mode))
1322
				return false;
1323
		}
1324
	}
1325
	return true;
1326
}
1327

    
1328
/*
1329
 * get_sysctl($names)
1330
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1331
 * name) and return an array of key/value pairs set for those that exist
1332
 */
1333
function get_sysctl($names) {
1334
	if (empty($names))
1335
		return array();
1336

    
1337
	if (is_array($names)) {
1338
		$name_list = array();
1339
		foreach ($names as $name) {
1340
			$name_list[] = escapeshellarg($name);
1341
		}
1342
	} else
1343
		$name_list = array(escapeshellarg($names));
1344

    
1345
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1346
	$values = array();
1347
	foreach ($output as $line) {
1348
		$line = explode(": ", $line, 2);
1349
		if (count($line) == 2)
1350
			$values[$line[0]] = $line[1];
1351
	}
1352

    
1353
	return $values;
1354
}
1355

    
1356
/*
1357
 * set_sysctl($value_list)
1358
 * Set sysctl OID's listed as key/value pairs and return
1359
 * an array with keys set for those that succeeded
1360
 */
1361
function set_sysctl($values) {
1362
	if (empty($values))
1363
		return array();
1364

    
1365
	$value_list = array();
1366
	foreach ($values as $key => $value) {
1367
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1368
	}
1369

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

    
1372
	/* Retry individually if failed (one or more read-only) */
1373
	if ($success <> 0 && count($value_list) > 1) {
1374
		foreach ($value_list as $value) {
1375
			exec("/sbin/sysctl -i " . $value, $output);
1376
		}
1377
	}
1378

    
1379
	$ret = array();
1380
	foreach ($output as $line) {
1381
		$line = explode(": ", $line, 2);
1382
		if (count($line) == 2)
1383
			$ret[$line[0]] = true;
1384
	}
1385

    
1386
	return $ret;
1387
}
1388

    
1389
/*
1390
 *     get_memory()
1391
 *     returns an array listing the amount of
1392
 *     memory installed in the hardware
1393
 *     [0]real and [1]available
1394
 */
1395
function get_memory() {
1396
	$matches = "";
1397
	if(file_exists("/var/log/dmesg.boot"))
1398
		$mem = `cat /var/log/dmesg.boot | grep memory`;
1399
	else
1400
		$mem = `dmesg -a | grep memory`;			
1401
	if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1402
		return array($matches[1][0], $matches[1][0]);
1403
	if(!$real && !$avail) {
1404
		$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1405
		$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1406
		/* convert from bytes to megabytes */
1407
		return array(($real/1048576),($avail/1048576));
1408
	}
1409
}
1410

    
1411
function mute_kernel_msgs() {
1412
	global $config;
1413
	// Do not mute serial console.  The kernel gets very very cranky
1414
	// and will start dishing you cannot control tty errors.
1415
	switch (trim(file_get_contents("/etc/platform"))) {
1416
		case "nanobsd":
1417
		case "jail":
1418
			return;
1419
	}
1420
	if($config['system']['enableserial']) 
1421
		return;			
1422
	exec("/sbin/conscontrol mute on");
1423
}
1424

    
1425
function unmute_kernel_msgs() {
1426
	global $config;
1427
	// Do not mute serial console.  The kernel gets very very cranky
1428
	// and will start dishing you cannot control tty errors.
1429
	switch (trim(file_get_contents("/etc/platform"))) {
1430
		case "nanobsd":
1431
		case "jail":
1432
			return;
1433
	}
1434
	exec("/sbin/conscontrol mute off");
1435
}
1436

    
1437
function start_devd() {
1438
	global $g;
1439

    
1440
	if ($g['platform'] == 'jail')
1441
		return;
1442
	exec("/sbin/devd");
1443
	sleep(1);
1444
}
1445

    
1446
function is_interface_vlan_mismatch() {
1447
	global $config, $g;
1448

    
1449
	if (is_array($config['vlans']['vlan'])) {
1450
		foreach ($config['vlans']['vlan'] as $vlan) {
1451
			if (does_interface_exist($vlan['if']) == false)
1452
				return true;
1453
		}
1454
	}
1455

    
1456
	return false;
1457
}
1458

    
1459
function is_interface_mismatch() {
1460
	global $config, $g;
1461

    
1462
	$do_assign = false;
1463
	$i = 0;
1464
	if (is_array($config['interfaces'])) {
1465
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1466
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1467
				// Do not check these interfaces.
1468
				$i++;
1469
				continue;
1470
			}
1471
			else if (does_interface_exist($ifcfg['if']) == false) {
1472
				echo "Warning: Interface '{$ifcfg['if']}' does not exist.\n";
1473
				$do_assign = true;
1474
			} else
1475
				$i++;
1476
		}
1477
	}
1478

    
1479
	if ($g['minimum_nic_count'] > $i) {
1480
		$do_assign = true;
1481
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1482
	$do_assign = false;
1483

    
1484
	return $do_assign;
1485
}
1486

    
1487
/* sync carp entries to other firewalls */
1488
function carp_sync_client() {
1489
	global $g;
1490
	send_event("filter sync");
1491
}
1492

    
1493
/****f* util/isAjax
1494
 * NAME
1495
 *   isAjax - reports if the request is driven from prototype
1496
 * INPUTS
1497
 *   none
1498
 * RESULT
1499
 *   true/false
1500
 ******/
1501
function isAjax() {
1502
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1503
}
1504

    
1505
/****f* util/timeout
1506
 * NAME
1507
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1508
 * INPUTS
1509
 *   optional, seconds to wait before timeout. Default 9 seconds.
1510
 * RESULT
1511
 *   returns 1 char of user input or null if no input.
1512
 ******/
1513
function timeout($timer = 9) {
1514
	while(!isset($key)) {
1515
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1516
		else { echo chr(8). "{$timer}"; }
1517
		`/bin/stty -icanon min 0 time 25`;
1518
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1519
		`/bin/stty icanon`;
1520
		if ($key == '')
1521
			unset($key);
1522
		$timer--;
1523
		if ($timer == 0)
1524
			break;
1525
	}
1526
	return $key;	
1527
}
1528

    
1529
/****f* util/msort
1530
 * NAME
1531
 *   msort - sort array
1532
 * INPUTS
1533
 *   $array to be sorted, field to sort by, direction of sort
1534
 * RESULT
1535
 *   returns newly sorted array
1536
 ******/
1537
function msort($array, $id="id", $sort_ascending=true) {
1538
	$temp_array = array();
1539
	while(count($array)>0) {
1540
		$lowest_id = 0;
1541
		$index=0;
1542
		foreach ($array as $item) {
1543
			if (isset($item[$id])) {
1544
				if ($array[$lowest_id][$id]) {
1545
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1546
						$lowest_id = $index;
1547
					}
1548
				}
1549
			}
1550
			$index++;
1551
		}
1552
		$temp_array[] = $array[$lowest_id];
1553
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1554
	}
1555
	if ($sort_ascending) {
1556
		return $temp_array;
1557
	} else {
1558
    		return array_reverse($temp_array);
1559
	}
1560
}
1561

    
1562
/****f* util/color
1563
 * NAME
1564
 *   color - outputs a color code to the ansi terminal if supported
1565
 * INPUTS
1566
 *   color code or color name
1567
 * RESULT
1568
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1569
 ******/
1570
function color($color = "0m") {
1571
	/*
1572
		Color codes available:
1573
		 0m reset; clears all colors and styles (to white on black)
1574
		 1m bold on (see below)
1575
		 3m italics on
1576
		 4m underline on
1577
		 7m inverse on; reverses foreground & background colors
1578
		 9m strikethrough on
1579
		 22m bold off (see below)
1580
		 23m italics off
1581
		 24m underline off
1582
		 27m inverse off
1583
		 29m strikethrough off
1584
		 30m set foreground color to black
1585
		 31m set foreground color to red
1586
		 32m set foreground color to green
1587
		 33m set foreground color to yellow
1588
		 34m set foreground color to blue
1589
		 35m set foreground color to magenta (purple)
1590
		 36m set foreground color to cyan
1591
		 37m set foreground color to white
1592
		 40m  set background color to black
1593
		 41m set background color to red
1594
		 42m set background color to green
1595
		 43m set background color to yellow
1596
		 44m set background color to blue
1597
		 45m set background color to magenta (purple)
1598
		 46m set background color to cyan
1599
		 47m set background color to white
1600
		 49m set background color to default (black)
1601
	*/	
1602
	// Allow caching of TERM to 
1603
	// speedup subequence requests.
1604
	global $TERM;
1605
	if(!$TERM) 
1606
		$TERM=`/usr/bin/env | grep color`;
1607
	if(!$TERM)
1608
		$TERM=`/usr/bin/env | grep cons25`;
1609
	if($TERM) {
1610
		$ESCAPE=chr(27);
1611
		switch ($color) {
1612
			case "black":
1613
				return "{$ESCAPE}[30m"; 
1614
			case "red":
1615
				return "{$ESCAPE}[31m"; 
1616
			case "green":
1617
				return "{$ESCAPE}[32m"; 
1618
			case "yellow":
1619
				return "{$ESCAPE}[33m"; 
1620
			case "blue":
1621
				return "{$ESCAPE}[34m"; 
1622
			case "magenta":
1623
				return "{$ESCAPE}[35m"; 
1624
			case "cyan":
1625
				return "{$ESCAPE}[36m"; 
1626
			case "white":
1627
				return "{$ESCAPE}[37m"; 
1628
			case "default":
1629
				return "{$ESCAPE}[39m"; 
1630
		}
1631
		return "{$ESCAPE}[{$color}";
1632
	}
1633
}
1634

    
1635
/****f* util/is_URL
1636
 * NAME
1637
 *   is_URL
1638
 * INPUTS
1639
 *   string to check
1640
 * RESULT
1641
 *   Returns true if item is a URL
1642
 ******/
1643
function is_URL($url) {
1644
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1645
	if($match)
1646
		return true;	
1647
	return false;
1648
}
1649

    
1650
function is_file_included($file = "") {
1651
	$files = get_included_files();
1652
	if (in_array($file, $files))
1653
		return true;
1654
	
1655
	return false;
1656
}
1657

    
1658
/*
1659
	This function was borrowed from a comment on PHP.net at the following URL:
1660
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1661
 */
1662
function array_merge_recursive_unique($array0, $array1) {
1663

    
1664
	$arrays = func_get_args();
1665
	$remains = $arrays;
1666

    
1667
	// We walk through each arrays and put value in the results (without
1668
	// considering previous value).
1669
	$result = array();
1670

    
1671
	// loop available array
1672
	foreach($arrays as $array) {
1673

    
1674
		// The first remaining array is $array. We are processing it. So
1675
		// we remove it from remaing arrays.
1676
        array_shift($remains);
1677

    
1678
		// We don't care non array param, like array_merge since PHP 5.0.
1679
		if(is_array($array)) {
1680
			// Loop values
1681
			foreach($array as $key => $value) {
1682
				if(is_array($value)) {
1683
					// we gather all remaining arrays that have such key available
1684
					$args = array();
1685
					foreach($remains as $remain) {
1686
						if(array_key_exists($key, $remain)) {
1687
							array_push($args, $remain[$key]);
1688
						}
1689
					}
1690

    
1691
					if(count($args) > 2) {
1692
						// put the recursion
1693
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1694
					} else {
1695
						foreach($value as $vkey => $vval) {
1696
							$result[$key][$vkey] = $vval;
1697
						}
1698
					}
1699
				} else {
1700
					// simply put the value
1701
					$result[$key] = $value;
1702
				}
1703
			}
1704
		}
1705
	}
1706
	return $result;
1707
}
1708

    
1709

    
1710
/*
1711
 * converts a string like "a,b,c,d"
1712
 * into an array like array("a" => "b", "c" => "d")
1713
 */
1714
function explode_assoc($delimiter, $string) {
1715
	$array = explode($delimiter, $string);
1716
	$result = array();
1717
	$numkeys = floor(count($array) / 2);
1718
	for ($i = 0; $i < $numkeys; $i += 1) {
1719
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1720
	}
1721
	return $result;
1722
}
1723

    
1724
function get_staticroutes($returnsubnetsonly = false) {
1725
	global $config;
1726
	require_once('filter.inc');
1727
	$allstaticroutes = array();
1728
	$allsubnets = array();
1729

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

    
1734
	/* Loop through routes and expand aliases as we find them. */
1735
	foreach ($config['staticroutes']['route'] as $route) {
1736
		if (is_alias($route['network'])) {
1737
			$subnets = filter_expand_alias_array($route['network']);
1738
			foreach ($subnets as $net) {
1739
				if (is_ipaddr($net))
1740
					$net .= "/32";
1741
				/* This must be a hostname, we can't use it. */
1742
				if (!is_subnet($net))
1743
					continue;
1744
				$temproute = $route;
1745
				$temproute['network'] = $net;
1746
				$allstaticroutes[] = $temproute;
1747
				$allsubnets[] = $net;
1748
			}
1749
		} elseif (is_subnet($route['network'])) {
1750
			$allstaticroutes[] = $route;
1751
			$allsubnets[] = $route['network'];
1752
		}
1753
	}
1754
	if ($returnsubnetsonly) {
1755
		return $allsubnets;
1756
	} else {
1757
		return $allstaticroutes;
1758
	}
1759
}
1760

    
1761
/****f* util/get_alias_list
1762
 * NAME
1763
 *   get_alias_list - Provide a list of aliases.
1764
 * INPUTS
1765
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
1766
 * RESULT
1767
 *   Array containing list of aliases.
1768
 *   If $type is unspecified, all aliases are returned.
1769
 *   If $type is a string, all aliases of the type specified in $type are returned.
1770
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
1771
 */
1772
function get_alias_list($type = null) {
1773
	global $config;
1774
	$result = array();
1775
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
1776
		foreach ($config['aliases']['alias'] as $alias) {
1777
			if ($type === null) {
1778
				$result[] = $alias['name'];
1779
			}
1780
			else if (is_array($type)) {
1781
				if (in_array($alias['type'], $type)) {
1782
					$result[] = $alias['name'];
1783
				}
1784
			}
1785
			else if ($type === $alias['type']) {
1786
				$result[] = $alias['name'];
1787
			}
1788
		}
1789
	}		
1790
	return $result;
1791
}
1792

    
1793
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
1794
function array_exclude($needle, $haystack) {
1795
	$result = array();
1796
	if (is_array($haystack)) {
1797
		foreach ($haystack as $thing) {
1798
			if ($needle !== $thing) {
1799
				$result[] = $thing;
1800
			}
1801
		}
1802
	}
1803
	return $result;
1804
}
1805

    
1806
?>
(54-54/66)