Project

General

Profile

Download (43 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
function is_ipaddrwithport($ipport) {
447
	$parts = explode(":", $ipport);
448
	$port = array_pop($parts);
449
	if (count($parts) == 1) {
450
		return is_ipaddrv4($parts[0]) && is_port($port);
451
	} elseif (count($parts) > 1) {
452
		return is_ipaddrv6(implode(":", $parts)) && is_port($port);
453
	} else {
454
		return false;
455
	}
456
}
457

    
458
function is_hostnamewithport($hostport) {
459
	$parts = explode(":", $hostport);
460
	$port = array_pop($parts);
461
	if (count($parts) == 1) {
462
		return is_hostname($parts[0]) && is_port($port);
463
	} else {
464
		return false;
465
	}
466
}
467

    
468
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
469
function is_ipaddroralias($ipaddr) {
470
	global $config;
471

    
472
	if (is_alias($ipaddr)) {
473
		if (is_array($config['aliases']['alias'])) {
474
			foreach ($config['aliases']['alias'] as $alias) {
475
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
476
					return true;
477
			}
478
		}
479
		return false;
480
	} else
481
		return is_ipaddr($ipaddr);
482

    
483
}
484

    
485
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format */
486
function is_subnet($subnet) {
487
	if(is_subnetv4($subnet)) {
488
		return true;
489
	}
490
	if(is_subnetv6($subnet)) {
491
		return true;
492
	}
493
	return false;
494
}
495

    
496
/* returns true if $subnet is a valid IPv4 subnet in CIDR format */
497
function is_subnetv4($subnet) {
498
	if (!is_string($subnet))
499
		return false;
500

    
501
	list($hp,$np) = explode('/', $subnet);
502

    
503
	if (!is_ipaddrv4($hp))
504
		return false;
505

    
506
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
507
		return false;
508

    
509
	return true;
510
}
511

    
512
/* returns true if $subnet is a valid IPv6 subnet in CIDR format */
513
function is_subnetv6($subnet) {
514
	if (!is_string($subnet))
515
		return false;
516

    
517
	list($hp,$np) = explode('/', $subnet);
518

    
519
	if (!is_ipaddrv6($hp))
520
		return false;
521

    
522
	if (!is_numeric($np) || ($np < 1) || ($np > 128))
523
		return false;
524

    
525
	return true;
526
}
527

    
528

    
529
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
530
function is_subnetoralias($subnet) {
531
	global $aliastable;
532

    
533
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
534
		return true;
535
	else
536
		return is_subnet($subnet);
537
}
538

    
539
/* returns true if $hostname is a valid hostname */
540
function is_hostname($hostname) {
541
	if (!is_string($hostname))
542
		return false;
543

    
544
	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))
545
		return true;
546
	else
547
		return false;
548
}
549

    
550
/* returns true if $domain is a valid domain name */
551
function is_domain($domain) {
552
	if (!is_string($domain))
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', $domain))
556
		return true;
557
	else
558
		return false;
559
}
560

    
561
/* returns true if $macaddr is a valid MAC address */
562
function is_macaddr($macaddr) {
563
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){5}$/i', $macaddr) == 1 ? true : false;
564
}
565

    
566
/* returns true if $name is a valid name for an alias */
567
/* returns NULL if a reserved word is used */
568
function is_validaliasname($name) {
569
	/* Array of reserved words */
570
	$reserved = array("port", "pass");
571
	if (in_array($name, $reserved, true))
572
		return; /* return NULL */
573
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
574
		return true;
575
	else
576
		return false;
577
}
578

    
579
/* returns true if $port is a valid TCP/UDP port */
580
function is_port($port) {
581
	$tmpports = explode(":", $port);
582
	foreach($tmpports as $tmpport) {
583
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
584
			continue;
585
		if (!ctype_digit($tmpport))
586
			return false;
587
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
588
			return false;
589
	}
590
	return true;
591
}
592

    
593
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
594
function is_portrange($portrange) {
595
	$ports = explode(":", $portrange);
596

    
597
	if(count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]))
598
		return true;
599
	else
600
		return false;
601
}
602

    
603
/* returns true if $port is a valid port number or an alias thereof */
604
function is_portoralias($port) {
605
	global $config;
606

    
607
	if (is_alias($port)) {
608
		if (is_array($config['aliases']['alias'])) {
609
			foreach ($config['aliases']['alias'] as $alias) {
610
				if ($alias['name'] == $port && $alias['type'] == "port")
611
					return true;
612
				}
613
			}
614
			return false;
615
	} else
616
		return is_port($port);
617
}
618

    
619
/* returns true if $val is a valid shaper bandwidth value */
620
function is_valid_shaperbw($val) {
621
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
622
}
623

    
624
/* return the configured carp interface list */
625
function get_configured_carp_interface_list() {
626
	global $config;
627

    
628
	$iflist = array();
629

    
630
	if(is_array($config['virtualip']['vip'])) {
631
		$viparr = &$config['virtualip']['vip'];
632
		foreach ($viparr as $vip) {
633
			switch ($vip['mode']) {
634
			case "carp":
635
			case "carpdev-dhcp":
636
				$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
637
				$iflist[$vipif] = $vip['subnet'];
638
				break;
639
			}
640
		}
641
	}
642

    
643
	return $iflist;
644
}
645

    
646
/* return the configured IP aliases list */
647
function get_configured_ip_aliases_list() {
648
	global $config;
649

    
650
	$alias_list=array();
651

    
652
	if(is_array($config['virtualip']['vip'])) {
653
		$viparr = &$config['virtualip']['vip'];
654
		foreach ($viparr as $vip) {
655
			if ($vip['mode']=="ipalias") {
656
				$alias_list[$vip['subnet']] = $vip['interface'];
657
			}
658
		}
659
	}
660

    
661
	return $alias_list;
662
}
663

    
664

    
665
/* comparison function for sorting by the order in which interfaces are normally created */
666
function compare_interface_friendly_names($a, $b) {
667
	if ($a == $b)
668
		return 0;
669
	else if ($a == 'wan')
670
		return -1;
671
	else if ($b == 'wan')
672
		return 1;
673
	else if ($a == 'lan')
674
		return -1;
675
	else if ($b == 'lan')
676
		return 1;
677

    
678
	return strnatcmp($a, $b);
679
}
680

    
681
/* return the configured interfaces list. */
682
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
683
	global $config;
684

    
685
	$iflist = array();
686

    
687
	/* if list */
688
	foreach($config['interfaces'] as $if => $ifdetail) {
689
		if ($only_opt && ($if == "wan" || $if == "lan"))
690
			continue;
691
		if (isset($ifdetail['enable']) || $withdisabled == true)
692
			$iflist[$if] = $if;
693
	}
694

    
695
	return $iflist;
696
}
697

    
698
/* return the configured interfaces list. */
699
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
700
	global $config;
701

    
702
	$iflist = array();
703

    
704
	/* if list */
705
	foreach($config['interfaces'] as $if => $ifdetail) {
706
		if ($only_opt && ($if == "wan" || $if == "lan"))
707
			continue;
708
		if (isset($ifdetail['enable']) || $withdisabled == true) {
709
			$tmpif = get_real_interface($if);
710
			if (!empty($tmpif))
711
				$iflist[$tmpif] = $if;
712
		}
713
	}
714

    
715
	return $iflist;
716
}
717

    
718
/* return the configured interfaces list with their description. */
719
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
720
	global $config;
721

    
722
	$iflist = array();
723

    
724
	/* if list */
725
	foreach($config['interfaces'] as $if => $ifdetail) {
726
		if ($only_opt && ($if == "wan" || $if == "lan"))
727
			continue;
728
		if (isset($ifdetail['enable']) || $withdisabled == true) {
729
			if(empty($ifdetail['descr']))
730
				$iflist[$if] = strtoupper($if);
731
			else
732
				$iflist[$if] = strtoupper($ifdetail['descr']);
733
		}
734
	}
735

    
736
	return $iflist;
737
}
738

    
739
/*
740
 *   get_configured_ip_addresses() - Return a list of all configured
741
 *   interfaces IP Addresses
742
 *
743
 */
744
function get_configured_ip_addresses() {
745
	require_once("interfaces.inc");
746
	$ip_array = array();
747
	$interfaces = get_configured_interface_list();
748
	if(is_array($interfaces)) {
749
		foreach($interfaces as $int) {
750
			$ipaddr = get_interface_ip($int);
751
			$ip_array[$int] = $ipaddr;
752
		}
753
	}
754
	$interfaces = get_configured_carp_interface_list();
755
	if(is_array($interfaces)) 
756
		foreach($interfaces as $int => $ipaddr) 
757
			$ip_array[$int] = $ipaddr;
758
	return $ip_array;
759
}
760

    
761
/*
762
 *   get_configured_ipv6_addresses() - Return a list of all configured
763
 *   interfaces IPv6 Addresses
764
 *
765
 */
766
function get_configured_ipv6_addresses() {
767
	require_once("interfaces.inc");
768
	$ipv6_array = array();
769
	$interfaces = get_configured_interface_list();
770
	if(is_array($interfaces)) {
771
		foreach($interfaces as $int) {
772
			$ipaddrv6 = get_interface_ipv6($int);
773
			$ipv6_array[$int] = $ipaddrv6;
774
		}
775
	}
776
	$interfaces = get_configured_carp_interface_list();
777
	if(is_array($interfaces)) 
778
		foreach($interfaces as $int => $ipaddrv6) 
779
			$ipv6_array[$int] = $ipaddrv6;
780
	return $ipv6_array;
781
}
782

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

    
894
/****f* util/log_error
895
* NAME
896
*   log_error  - Sends a string to syslog.
897
* INPUTS
898
*   $error     - string containing the syslog message.
899
* RESULT
900
*   null
901
******/
902
function log_error($error) {
903
	global $g;
904
	$page = $_SERVER['SCRIPT_NAME'];
905
	syslog(LOG_WARNING, "$page: $error");
906
	if ($g['debug'])
907
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
908
	return;
909
}
910

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

    
928
/****f* util/exec_command
929
 * NAME
930
 *   exec_command - Execute a command and return a string of the result.
931
 * INPUTS
932
 *   $command   - String of the command to be executed.
933
 * RESULT
934
 *   String containing the command's result.
935
 * NOTES
936
 *   This function returns the command's stdout and stderr.
937
 ******/
938
function exec_command($command) {
939
	$output = array();
940
	exec($command . ' 2>&1 ', $output);
941
	return(implode("\n", $output));
942
}
943

    
944
/* wrapper for exec() */
945
function mwexec($command, $mute = false) {
946
	global $g;
947

    
948
	if ($g['debug']) {
949
		if (!$_SERVER['REMOTE_ADDR'])
950
			echo "mwexec(): $command\n";
951
	}
952
	$oarr = array();
953
	$retval = 0;
954
	$garbage = exec("$command 2>&1", $oarr, $retval);
955

    
956
	if(isset($config['system']['developerspew']))
957
		$mute = false;
958
	if(($retval <> 0) && ($mute === false)) {
959
		$output = implode(" ", $oarr);
960
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
961
	}
962
	return $retval;
963
}
964

    
965
/* wrapper for exec() in background */
966
function mwexec_bg($command) {
967
	global $g;
968

    
969
	if ($g['debug']) {
970
		if (!$_SERVER['REMOTE_ADDR'])
971
			echo "mwexec(): $command\n";
972
	}
973

    
974
	exec("nohup $command > /dev/null 2>&1 &");
975
}
976

    
977
/* unlink a file, if it exists */
978
function unlink_if_exists($fn) {
979
	$to_do = glob($fn);
980
	if(is_array($to_do)) {
981
		foreach($to_do as $filename)
982
			@unlink($filename);
983
	} else {
984
		@unlink($fn);
985
	}
986
}
987
/* make a global alias table (for faster lookups) */
988
function alias_make_table($config) {
989
	global $aliastable;
990

    
991
	$aliastable = array();
992

    
993
	if (is_array($config['aliases']['alias'])) {
994
		foreach ($config['aliases']['alias'] as $alias) {
995
			if ($alias['name'])
996
				$aliastable[$alias['name']] = $alias['address'];
997
		}
998
	}
999
}
1000

    
1001
/* check if an alias exists */
1002
function is_alias($name) {
1003
	global $aliastable;
1004

    
1005
	return isset($aliastable[$name]);
1006
}
1007

    
1008
function alias_get_type($name) {
1009
        global $config;
1010
        
1011
	if (is_array($config['aliases']['alias'])) {
1012
		foreach ($config['aliases']['alias'] as $alias) {
1013
			if ($name == $alias['name'])
1014
				return $alias['type'];
1015
		}
1016
	}
1017

    
1018
        return "";
1019
}
1020

    
1021
/* expand a host or network alias, if necessary */
1022
function alias_expand($name) {
1023
	global $aliastable;
1024

    
1025
	if (isset($aliastable[$name]))
1026
		return "\${$name}";
1027
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1028
		return "{$name}";
1029
	else
1030
		return null;
1031
}
1032

    
1033
function alias_expand_urltable($name) {
1034
	global $config;
1035
	$urltable_prefix = "/var/db/aliastables/";
1036
	$urltable_filename = $urltable_prefix . $name . ".txt";
1037

    
1038
	if (is_array($config['aliases']['alias'])) {
1039
		foreach ($config['aliases']['alias'] as $alias) {
1040
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
1041
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1042
					return $urltable_filename;
1043
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1044
					return $urltable_filename;
1045
			}
1046
		}
1047
	}
1048
	return null;
1049
}
1050

    
1051
function subnet_size ($subnet) {
1052
	if (is_subnetv4($subnet)) {
1053
		list ($ip, $bits) = explode("/", $subnet);
1054
		return round(exp(log(2) * (32 - $bits)));
1055
	}
1056
	else if (is_subnetv6($subnet)) {
1057
		list ($ip, $bits) = explode("/", $subnet);
1058
		return round(exp(log(2) * (128 - $bits)));
1059
	}
1060
	else {
1061
		return 0;
1062
	}
1063
}
1064

    
1065
function subnet_expand ($subnet) {
1066
	if (is_subnetv4($subnet)) {
1067
		return subnetv4_expand($subnet);
1068
	} else if (is_subnetv6($subnet)) {
1069
		return subnetv6_expand($subnet);
1070
	} else {
1071
		return $subnet;
1072
	}
1073
}
1074

    
1075
function subnetv4_expand ($subnet) {
1076
	$result = array();
1077
	list ($ip, $bits) = explode("/", $subnet);
1078
	$net  = ip2long($ip);
1079
	$mask = (0xffffffff << (32 - $bits));
1080
	$net &= $mask;
1081
	$size = round(exp(log(2) * (32 - $bits)));
1082
	for ($i = 0; $i < $size; $i += 1) {
1083
		$result[] = long2ip($net | $i);
1084
	}
1085
	return $result;
1086
}
1087

    
1088
/* find out whether two subnets overlap */
1089
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1090

    
1091
	if (!is_numeric($bits1))
1092
		$bits1 = 32;
1093
	if (!is_numeric($bits2))
1094
		$bits2 = 32;
1095

    
1096
	if ($bits1 < $bits2)
1097
		$relbits = $bits1;
1098
	else
1099
		$relbits = $bits2;
1100

    
1101
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1102
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1103

    
1104
	if ($sn1 == $sn2)
1105
		return true;
1106
	else
1107
		return false;
1108
}
1109

    
1110
/* compare two IP addresses */
1111
function ipcmp($a, $b) {
1112
	if (ip_less_than($a, $b))
1113
		return -1;
1114
	else if (ip_greater_than($a, $b))
1115
		return 1;
1116
	else
1117
		return 0;
1118
}
1119

    
1120
/* return true if $addr is in $subnet, false if not */
1121
function ip_in_subnet($addr,$subnet) {
1122
	if(is_ipaddrv6($addr)) {
1123
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1124
		if($result)
1125
			return true;
1126
		else
1127
			return false;
1128
	}
1129
	list($ip, $mask) = explode('/', $subnet);
1130
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1131
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1132
}
1133

    
1134
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1135
function verify_digital_signature($fname) {
1136
	global $g;
1137

    
1138
	if(!file_exists("/usr/local/sbin/gzsig"))
1139
		return 4;
1140

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

    
1144
/* obtain MAC address given an IP address by looking at the ARP table */
1145
function arp_get_mac_by_ip($ip) {
1146
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1147
	$arpoutput = "";
1148
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1149

    
1150
	if ($arpoutput[0]) {
1151
		$arpi = explode(" ", $arpoutput[0]);
1152
		$macaddr = $arpi[3];
1153
		if (is_macaddr($macaddr))
1154
			return $macaddr;
1155
		else
1156
			return false;
1157
	}
1158

    
1159
	return false;
1160
}
1161

    
1162
/* return a fieldname that is safe for xml usage */
1163
function xml_safe_fieldname($fieldname) {
1164
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1165
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1166
			 ':', ',', '.', '\'', '\\'
1167
		);
1168
	return strtolower(str_replace($replace, "", $fieldname));
1169
}
1170

    
1171
function mac_format($clientmac) {
1172
    global $config;
1173

    
1174
    $mac = explode(":", $clientmac);
1175
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
1176

    
1177
    switch($mac_format) {
1178
        case 'singledash':
1179
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1180

    
1181
        case 'ietf':
1182
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1183

    
1184
        case 'cisco':
1185
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1186

    
1187
        case 'unformatted':
1188
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1189

    
1190
        default:
1191
		return $clientmac;
1192
    }
1193
}
1194

    
1195
function resolve_retry($hostname, $retries = 5) {
1196

    
1197
	if (is_ipaddr($hostname))
1198
		return $hostname;
1199

    
1200
       for ($i = 0; $i < $retries; $i++) {
1201
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1202
               $ip = gethostbyname($hostname);
1203

    
1204
		if ($ip && $ip != $hostname) {
1205
			/* success */
1206
			return $ip;
1207
		}
1208

    
1209
		sleep(1);
1210
	}
1211

    
1212
	return false;
1213
}
1214

    
1215
function format_bytes($bytes) {
1216
	if ($bytes >= 1073741824) {
1217
		return sprintf("%.2f GB", $bytes/1073741824);
1218
	} else if ($bytes >= 1048576) {
1219
		return sprintf("%.2f MB", $bytes/1048576);
1220
	} else if ($bytes >= 1024) {
1221
		return sprintf("%.0f KB", $bytes/1024);
1222
	} else {
1223
		return sprintf("%d bytes", $bytes);
1224
	}
1225
}
1226

    
1227
function update_filter_reload_status($text) {
1228
	global $g;
1229

    
1230
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1231
}
1232

    
1233
/****f* util/return_dir_as_array
1234
 * NAME
1235
 *   return_dir_as_array - Return a directory's contents as an array.
1236
 * INPUTS
1237
 *   $dir       - string containing the path to the desired directory.
1238
 * RESULT
1239
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1240
 ******/
1241
function return_dir_as_array($dir) {
1242
	$dir_array = array();
1243
	if (is_dir($dir)) {
1244
		if ($dh = opendir($dir)) {
1245
			while (($file = readdir($dh)) !== false) {
1246
				$canadd = 0;
1247
				if($file == ".") $canadd = 1;
1248
				if($file == "..") $canadd = 1;
1249
				if($canadd == 0)
1250
					array_push($dir_array, $file);
1251
			}
1252
			closedir($dh);
1253
		}
1254
	}
1255
	return $dir_array;
1256
}
1257

    
1258
function run_plugins($directory) {
1259
	global $config, $g;
1260

    
1261
	/* process packager manager custom rules */
1262
	$files = return_dir_as_array($directory);
1263
	if (is_array($files)) {
1264
		foreach ($files as $file) {
1265
			if (stristr($file, ".sh") == true)
1266
				mwexec($directory . $file . " start");
1267
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1268
				require_once($directory . "/" . $file);
1269
		}
1270
	}
1271
}
1272

    
1273
/*
1274
 *    safe_mkdir($path, $mode = 0755)
1275
 *    create directory if it doesn't already exist and isn't a file!
1276
 */
1277
function safe_mkdir($path, $mode=0755) {
1278
	global $g;
1279

    
1280
	if (!is_file($path) && !is_dir($path)) {
1281
		return @mkdir($path, $mode, true);
1282
	} else {
1283
		return false;
1284
	}
1285
}
1286

    
1287
/*
1288
 * make_dirs($path, $mode = 0755)
1289
 * create directory tree recursively (mkdir -p)
1290
 */
1291
function make_dirs($path, $mode = 0755) {
1292
	$base = '';
1293
	foreach (explode('/', $path) as $dir) {
1294
		$base .= "/$dir";
1295
		if (!is_dir($base)) {
1296
			if (!@mkdir($base, $mode))
1297
				return false;
1298
		}
1299
	}
1300
	return true;
1301
}
1302

    
1303
/*
1304
 * get_sysctl($names)
1305
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1306
 * name) and return an array of key/value pairs set for those that exist
1307
 */
1308
function get_sysctl($names) {
1309
	if (empty($names))
1310
		return array();
1311

    
1312
	if (is_array($names)) {
1313
		$name_list = array();
1314
		foreach ($names as $name) {
1315
			$name_list[] = escapeshellarg($name);
1316
		}
1317
	} else
1318
		$name_list = array(escapeshellarg($names));
1319

    
1320
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1321
	$values = array();
1322
	foreach ($output as $line) {
1323
		$line = explode(": ", $line, 2);
1324
		if (count($line) == 2)
1325
			$values[$line[0]] = $line[1];
1326
	}
1327

    
1328
	return $values;
1329
}
1330

    
1331
/*
1332
 * set_sysctl($value_list)
1333
 * Set sysctl OID's listed as key/value pairs and return
1334
 * an array with keys set for those that succeeded
1335
 */
1336
function set_sysctl($values) {
1337
	if (empty($values))
1338
		return array();
1339

    
1340
	$value_list = array();
1341
	foreach ($values as $key => $value) {
1342
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1343
	}
1344

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

    
1347
	/* Retry individually if failed (one or more read-only) */
1348
	if ($success <> 0 && count($value_list) > 1) {
1349
		foreach ($value_list as $value) {
1350
			exec("/sbin/sysctl -i " . $value, $output);
1351
		}
1352
	}
1353

    
1354
	$ret = array();
1355
	foreach ($output as $line) {
1356
		$line = explode(": ", $line, 2);
1357
		if (count($line) == 2)
1358
			$ret[$line[0]] = true;
1359
	}
1360

    
1361
	return $ret;
1362
}
1363

    
1364
/*
1365
 *     get_memory()
1366
 *     returns an array listing the amount of
1367
 *     memory installed in the hardware
1368
 *     [0]real and [1]available
1369
 */
1370
function get_memory() {
1371
	$matches = "";
1372
	if(file_exists("/var/log/dmesg.boot"))
1373
		$mem = `cat /var/log/dmesg.boot | grep memory`;
1374
	else
1375
		$mem = `dmesg -a | grep memory`;			
1376
	if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1377
		return array($matches[1][0], $matches[1][0]);
1378
	if(!$real && !$avail) {
1379
		$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1380
		$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1381
		/* convert from bytes to megabytes */
1382
		return array(($real/1048576),($avail/1048576));
1383
	}
1384
}
1385

    
1386
function mute_kernel_msgs() {
1387
	global $config;
1388
	// Do not mute serial console.  The kernel gets very very cranky
1389
	// and will start dishing you cannot control tty errors.
1390
	switch (trim(file_get_contents("/etc/platform"))) {
1391
		case "nanobsd":
1392
		case "jail":
1393
			return;
1394
	}
1395
	if($config['system']['enableserial']) 
1396
		return;			
1397
	exec("/sbin/conscontrol mute on");
1398
}
1399

    
1400
function unmute_kernel_msgs() {
1401
	global $config;
1402
	// Do not mute serial console.  The kernel gets very very cranky
1403
	// and will start dishing you cannot control tty errors.
1404
	switch (trim(file_get_contents("/etc/platform"))) {
1405
		case "nanobsd":
1406
		case "jail":
1407
			return;
1408
	}
1409
	exec("/sbin/conscontrol mute off");
1410
}
1411

    
1412
function start_devd() {
1413
	global $g;
1414

    
1415
	if ($g['platform'] == 'jail')
1416
		return;
1417
	exec("/sbin/devd");
1418
	sleep(1);
1419
}
1420

    
1421
function is_interface_vlan_mismatch() {
1422
	global $config, $g;
1423

    
1424
	if (is_array($config['vlans']['vlan'])) {
1425
		foreach ($config['vlans']['vlan'] as $vlan) {
1426
			if (does_interface_exist($vlan['if']) == false)
1427
				return true;
1428
		}
1429
	}
1430

    
1431
	return false;
1432
}
1433

    
1434
function is_interface_mismatch() {
1435
	global $config, $g;
1436

    
1437
	$do_assign = false;
1438
	$i = 0;
1439
	if (is_array($config['interfaces'])) {
1440
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1441
			if (preg_match("/^enc|^cua|^tun|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1442
				// Do not check these interfaces.
1443
				$i++;
1444
				continue;
1445
			}
1446
			else if (does_interface_exist($ifcfg['if']) == false) {
1447
				$do_assign = true;
1448
			} else
1449
				$i++;
1450
		}
1451
	}
1452

    
1453
	if ($g['minimum_nic_count'] > $i) {
1454
		$do_assign = true;
1455
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1456
	$do_assign = false;
1457

    
1458
	return $do_assign;
1459
}
1460

    
1461
/* sync carp entries to other firewalls */
1462
function carp_sync_client() {
1463
	global $g;
1464
	send_event("filter sync");
1465
}
1466

    
1467
/****f* util/isAjax
1468
 * NAME
1469
 *   isAjax - reports if the request is driven from prototype
1470
 * INPUTS
1471
 *   none
1472
 * RESULT
1473
 *   true/false
1474
 ******/
1475
function isAjax() {
1476
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1477
}
1478

    
1479
/****f* util/timeout
1480
 * NAME
1481
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1482
 * INPUTS
1483
 *   optional, seconds to wait before timeout. Default 9 seconds.
1484
 * RESULT
1485
 *   returns 1 char of user input or null if no input.
1486
 ******/
1487
function timeout($timer = 9) {
1488
	while(!isset($key)) {
1489
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1490
		else { echo chr(8). "{$timer}"; }
1491
		`/bin/stty -icanon min 0 time 25`;
1492
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1493
		`/bin/stty icanon`;
1494
		if ($key == '')
1495
			unset($key);
1496
		$timer--;
1497
		if ($timer == 0)
1498
			break;
1499
	}
1500
	return $key;	
1501
}
1502

    
1503
/****f* util/msort
1504
 * NAME
1505
 *   msort - sort array
1506
 * INPUTS
1507
 *   $array to be sorted, field to sort by, direction of sort
1508
 * RESULT
1509
 *   returns newly sorted array
1510
 ******/
1511
function msort($array, $id="id", $sort_ascending=true) {
1512
	$temp_array = array();
1513
	while(count($array)>0) {
1514
		$lowest_id = 0;
1515
		$index=0;
1516
		foreach ($array as $item) {
1517
			if (isset($item[$id])) {
1518
				if ($array[$lowest_id][$id]) {
1519
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1520
						$lowest_id = $index;
1521
					}
1522
				}
1523
			}
1524
			$index++;
1525
		}
1526
		$temp_array[] = $array[$lowest_id];
1527
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1528
	}
1529
	if ($sort_ascending) {
1530
		return $temp_array;
1531
	} else {
1532
    	return array_reverse($temp_array);
1533
	}
1534
}
1535

    
1536
/****f* util/color
1537
 * NAME
1538
 *   color - outputs a color code to the ansi terminal if supported
1539
 * INPUTS
1540
 *   color code or color name
1541
 * RESULT
1542
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1543
 ******/
1544
function color($color = "0m") {
1545
	/*
1546
		Color codes available:
1547
		 0m reset; clears all colors and styles (to white on black)
1548
		 1m bold on (see below)
1549
		 3m italics on
1550
		 4m underline on
1551
		 7m inverse on; reverses foreground & background colors
1552
		 9m strikethrough on
1553
		 22m bold off (see below)
1554
		 23m italics off
1555
		 24m underline off
1556
		 27m inverse off
1557
		 29m strikethrough off
1558
		 30m set foreground color to black
1559
		 31m set foreground color to red
1560
		 32m set foreground color to green
1561
		 33m set foreground color to yellow
1562
		 34m set foreground color to blue
1563
		 35m set foreground color to magenta (purple)
1564
		 36m set foreground color to cyan
1565
		 37m set foreground color to white
1566
		 40m  set background color to black
1567
		 41m set background color to red
1568
		 42m set background color to green
1569
		 43m set background color to yellow
1570
		 44m set background color to blue
1571
		 45m set background color to magenta (purple)
1572
		 46m set background color to cyan
1573
		 47m set background color to white
1574
		 49m set background color to default (black)
1575
	*/	
1576
	// Allow caching of TERM to 
1577
	// speedup subequence requests.
1578
	global $TERM;
1579
	if(!$TERM) 
1580
		$TERM=`/usr/bin/env | grep color`;
1581
	if(!$TERM)
1582
		$TERM=`/usr/bin/env | grep cons25`;
1583
	if($TERM) {
1584
		$ESCAPE=chr(27);
1585
		switch ($color) {
1586
			case "black":
1587
				return "{$ESCAPE}[30m"; 
1588
			case "red":
1589
				return "{$ESCAPE}[31m"; 
1590
			case "green":
1591
				return "{$ESCAPE}[32m"; 
1592
			case "yellow":
1593
				return "{$ESCAPE}[33m"; 
1594
			case "blue":
1595
				return "{$ESCAPE}[34m"; 
1596
			case "magenta":
1597
				return "{$ESCAPE}[35m"; 
1598
			case "cyan":
1599
				return "{$ESCAPE}[36m"; 
1600
			case "white":
1601
				return "{$ESCAPE}[37m"; 
1602
			case "default":
1603
				return "{$ESCAPE}[39m"; 
1604
		}
1605
		return "{$ESCAPE}[{$color}";
1606
	}
1607
}
1608

    
1609
/****f* util/is_URL
1610
 * NAME
1611
 *   is_URL
1612
 * INPUTS
1613
 *   string to check
1614
 * RESULT
1615
 *   Returns true if item is a URL
1616
 ******/
1617
function is_URL($url) {
1618
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1619
	if($match)
1620
		return true;	
1621
	return false;
1622
}
1623

    
1624
function is_file_included($file = "") {
1625
	$files = get_included_files();
1626
	if (in_array($file, $files))
1627
		return true;
1628
	
1629
	return false;
1630
}
1631

    
1632
/*
1633
	This function was borrowed from a comment on PHP.net at the following URL:
1634
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1635
 */
1636
function array_merge_recursive_unique($array0, $array1) {
1637

    
1638
	$arrays = func_get_args();
1639
	$remains = $arrays;
1640

    
1641
	// We walk through each arrays and put value in the results (without
1642
	// considering previous value).
1643
	$result = array();
1644

    
1645
	// loop available array
1646
	foreach($arrays as $array) {
1647

    
1648
		// The first remaining array is $array. We are processing it. So
1649
		// we remove it from remaing arrays.
1650
        array_shift($remains);
1651

    
1652
		// We don't care non array param, like array_merge since PHP 5.0.
1653
		if(is_array($array)) {
1654
			// Loop values
1655
			foreach($array as $key => $value) {
1656
				if(is_array($value)) {
1657
					// we gather all remaining arrays that have such key available
1658
					$args = array();
1659
					foreach($remains as $remain) {
1660
						if(array_key_exists($key, $remain)) {
1661
							array_push($args, $remain[$key]);
1662
						}
1663
					}
1664

    
1665
					if(count($args) > 2) {
1666
						// put the recursion
1667
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1668
					} else {
1669
						foreach($value as $vkey => $vval) {
1670
							$result[$key][$vkey] = $vval;
1671
						}
1672
					}
1673
				} else {
1674
					// simply put the value
1675
					$result[$key] = $value;
1676
				}
1677
			}
1678
		}
1679
	}
1680
	return $result;
1681
}
1682

    
1683

    
1684
/*
1685
 * converts a string like "a,b,c,d"
1686
 * into an array like array("a" => "b", "c" => "d")
1687
 */
1688
function explode_assoc($delimiter, $string) {
1689
	$array = explode($delimiter, $string);
1690
	$result = array();
1691
	$numkeys = floor(count($array) / 2);
1692
	for ($i = 0; $i < $numkeys; $i += 1) {
1693
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1694
	}
1695
	return $result;
1696
}
1697

    
1698
function get_staticroutes($returnsubnetsonly = false) {
1699
	global $config;
1700
	require_once('filter.inc');
1701
	$allstaticroutes = array();
1702
	$allsubnets = array();
1703

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

    
1708
	/* Loop through routes and expand aliases as we find them. */
1709
	foreach ($config['staticroutes']['route'] as $route) {
1710
		if (is_alias($route['network'])) {
1711
			$subnets = filter_expand_alias_array($route['network']);
1712
			foreach ($subnets as $net) {
1713
				if (is_ipaddr($net))
1714
					$net .= "/32";
1715
				/* This must be a hostname, we can't use it. */
1716
				if (!is_subnet($net))
1717
					continue;
1718
				$temproute = $route;
1719
				$temproute['network'] = $net;
1720
				$allstaticroutes[] = $temproute;
1721
				$allsubnets[] = $net;
1722
			}
1723
		} elseif (is_subnet($route['network'])) {
1724
			$allstaticroutes[] = $route;
1725
			$allsubnets[] = $route['network'];
1726
		}
1727
	}
1728
	if ($returnsubnetsonly) {
1729
		return $allsubnets;
1730
	} else {
1731
		return $allstaticroutes;
1732
	}
1733
}
1734
?>
(53-53/65)