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
	$cfglckkeyconsumers++;
123
	if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
124
		if (flock($fp, $op))
125
			return $fp;
126
		else
127
			fclose($fp);
128
	}
129
}
130

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

    
139
function send_event($cmd) {
140
	global $g;
141

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

    
161
function send_multiple_events($cmds) {
162
	global $g;
163

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

    
170
	foreach ($cmds as $cmd)
171
		send_event($cmd);
172
}
173

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

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

    
195
	return $shm_data;
196
}
197

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

    
214
	return $shm_data;
215
}
216

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

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

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

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

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

    
246
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
247
}
248

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

    
259
	$inet_end = $inet_ip | ~$inet_mask;
260

    
261
	return(Net_IPv6::uncompress(inet_ntop($inet_end)));
262
}
263

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
414

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

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

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

    
437
	$ip_long = ip2long($ipaddr);
438
	$ip_reverse = long2ip32($ip_long);
439

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

    
446

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

    
454
	return is_ipaddrv6($ipaddr);
455
}
456

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

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

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

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

    
494
}
495

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

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

    
512
	list($hp,$np) = explode('/', $subnet);
513

    
514
	if (!is_ipaddrv4($hp))
515
		return false;
516

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

    
520
	return true;
521
}
522

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

    
528
	list($hp,$np) = explode('/', $subnet);
529

    
530
	if (!is_ipaddrv6($hp))
531
		return false;
532

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

    
536
	return true;
537
}
538

    
539

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
636
	$iflist = array();
637

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

    
651
	return $iflist;
652
}
653

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

    
658
	$alias_list=array();
659

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

    
672
	return $alias_list;
673
}
674

    
675

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

    
689
	return strnatcmp($a, $b);
690
}
691

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

    
696
	$iflist = array();
697

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

    
706
	return $iflist;
707
}
708

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

    
713
	$iflist = array();
714

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

    
726
	return $iflist;
727
}
728

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

    
733
	$iflist = array();
734

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

    
747
	return $iflist;
748
}
749

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1017
	$aliastable = array();
1018

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

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

    
1031
	return isset($aliastable[$name]);
1032
}
1033

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

    
1044
        return "";
1045
}
1046

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

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

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

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

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

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

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

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

    
1117
	if (!is_numeric($bits1))
1118
		$bits1 = 32;
1119
	if (!is_numeric($bits2))
1120
		$bits2 = 32;
1121

    
1122
	if ($bits1 < $bits2)
1123
		$relbits = $bits1;
1124
	else
1125
		$relbits = $bits2;
1126

    
1127
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1128
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1129

    
1130
	return ($sn1 == $sn2);
1131
}
1132

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

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

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

    
1161
	if(!file_exists("/usr/local/sbin/gzsig"))
1162
		return 4;
1163

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

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

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

    
1182
	return false;
1183
}
1184

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

    
1194
function mac_format($clientmac) {
1195
    global $config;
1196

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

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

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

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

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

    
1213
        default:
1214
		return $clientmac;
1215
    }
1216
}
1217

    
1218
function resolve_retry($hostname, $retries = 5) {
1219

    
1220
	if (is_ipaddr($hostname))
1221
		return $hostname;
1222

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

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

    
1232
		sleep(1);
1233
	}
1234

    
1235
	return false;
1236
}
1237

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

    
1250
function update_filter_reload_status($text) {
1251
	global $g;
1252

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

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

    
1281
function run_plugins($directory) {
1282
	global $config, $g;
1283

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

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

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

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

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

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

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

    
1351
	return $values;
1352
}
1353

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

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

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

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

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

    
1384
	return $ret;
1385
}
1386

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

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

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

    
1435
function start_devd() {
1436
	global $g;
1437

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

    
1444
function is_interface_vlan_mismatch() {
1445
	global $config, $g;
1446

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

    
1454
	return false;
1455
}
1456

    
1457
function is_interface_mismatch() {
1458
	global $config, $g;
1459

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

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

    
1482
	return $do_assign;
1483
}
1484

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

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

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

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

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

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

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

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

    
1662
	$arrays = func_get_args();
1663
	$remains = $arrays;
1664

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

    
1669
	// loop available array
1670
	foreach($arrays as $array) {
1671

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

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

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

    
1707

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

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

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

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

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

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

    
1804
?>
(53-53/65)