Project

General

Profile

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

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

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

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

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

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

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

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

    
44
function isvalidpid($pid) {
45
	$output = "";
46
	exec("/bin/pgrep -nF {$pid}", $output, $retval);
47

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

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

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

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

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

    
68
	return 0;
69
}
70

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

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

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

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

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

    
92
	return false;
93
}
94

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
220
	return $shm_data;
221
}
222

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

    
248
	return $shm_data;
249
}
250

    
251
function is_module_loaded($module_name) {
252
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
253
	if (intval($running) >= 1)
254
		return true;
255
	else
256
		return false;
257
}
258

    
259
/* return the subnet address given a host address and a subnet bit count */
260
function gen_subnet($ipaddr, $bits) {
261
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
262
		return "";
263
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
264
}
265

    
266
/* return the subnet address given a host address and a subnet bit count */
267
function gen_subnetv6($ipaddr, $bits) {
268
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
269
		return "";
270

    
271
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
272
	return $address;
273
}
274

    
275
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
276
function gen_subnet_max($ipaddr, $bits) {
277
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
278
		return "";
279

    
280
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
281
}
282

    
283
/* Generate end number for a given ipv6 subnet mask */
284
function gen_subnetv6_max($ipaddr, $bits) {
285
	if(!is_ipaddrv6($ipaddr))
286
		return false;
287
	
288
	$mask = Net_IPv6::getNetmask('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',$bits);
289
	
290
	$inet_ip = (binary)inet_pton($ipaddr);
291
	$inet_mask = (binary)inet_pton($mask);
292

    
293
	$inet_end = $inet_ip | ~$inet_mask;
294

    
295
	return(Net_IPv6::uncompress(inet_ntop($inet_end)));
296
}
297

    
298
/* returns a subnet mask (long given a bit count) */
299
function gen_subnet_mask_long($bits) {
300
	$sm = 0;
301
	for ($i = 0; $i < $bits; $i++) {
302
		$sm >>= 1;
303
		$sm |= 0x80000000;
304
	}
305
	return $sm;
306
}
307

    
308
/* same as above but returns a string */
309
function gen_subnet_mask($bits) {
310
	return long2ip(gen_subnet_mask_long($bits));
311
}
312

    
313
/* Convert long int to IP address, truncating to 32-bits. */
314
function long2ip32($ip) {
315
	return long2ip($ip & 0xFFFFFFFF);
316
}
317

    
318
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
319
function ip2long32($ip) {
320
	return ( ip2long($ip) & 0xFFFFFFFF );
321
}
322

    
323
/* Convert IP address to unsigned long int. */
324
function ip2ulong($ip) {
325
	return sprintf("%u", ip2long32($ip));
326
}
327

    
328
/* Find out how many IPs are contained within a given IP range
329
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
330
 */
331
function ip_range_size($startip, $endip) {
332
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
333
		// Operate as unsigned long because otherwise it wouldn't work
334
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
335
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
336
	}
337
	return -1;
338
}
339

    
340
/* Find the smallest possible subnet mask which can contain a given number of IPs
341
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
342
 */
343
function find_smallest_cidr($number) {
344
	$smallest = 1;
345
	for ($b=32; $b > 0; $b--) {
346
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
347
	}
348
	return (32-$smallest);
349
}
350

    
351
/* Return the previous IP address before the given address */
352
function ip_before($ip) {
353
	return long2ip32(ip2long($ip)-1);
354
}
355

    
356
/* Return the next IP address after the given address */
357
function ip_after($ip) {
358
	return long2ip32(ip2long($ip)+1);
359
}
360

    
361
/* Return true if the first IP is 'before' the second */
362
function ip_less_than($ip1, $ip2) {
363
	// Compare as unsigned long because otherwise it wouldn't work when
364
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
365
	return ip2ulong($ip1) < ip2ulong($ip2);
366
}
367

    
368
/* Return true if the first IP is 'after' the second */
369
function ip_greater_than($ip1, $ip2) {
370
	// Compare as unsigned long because otherwise it wouldn't work
371
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
372
	return ip2ulong($ip1) > ip2ulong($ip2);
373
}
374

    
375
/* Convert a range of IPs to an array of subnets which can contain the range. */
376
function ip_range_to_subnet_array($startip, $endip) {
377
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
378
		return array();
379
	}
380

    
381
	// Container for subnets within this range.
382
	$rangesubnets = array();
383

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

    
387
	// Loop here to reduce subnet size and retest as needed. We need to make sure
388
	//   that the target subnet is wholly contained between $startip and $endip.
389
	for ($cidr; $cidr <= 32; $cidr++) {
390
		// Find the network and broadcast addresses for the subnet being tested.
391
		$targetsub_min = gen_subnet($startip, $cidr);
392
		$targetsub_max = gen_subnet_max($startip, $cidr);
393

    
394
		// Check best case where the range is exactly one subnet.
395
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
396
			// Hooray, the range is exactly this subnet!
397
			return array("{$startip}/{$cidr}");
398
		}
399

    
400
		// These remaining scenarios will find a subnet that uses the largest
401
		//  chunk possible of the range being tested, and leave the rest to be
402
		//  tested recursively after the loop.
403

    
404
		// Check if the subnet begins with $startip and ends before $endip
405
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
406
			break;
407
		}
408

    
409
		// Check if the subnet ends at $endip and starts after $startip
410
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
411
			break;
412
		}
413

    
414
		// Check if the subnet is between $startip and $endip
415
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
416
			break;
417
		}
418
	}
419

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

    
426
	// Add in the subnet we found before, to preserve ordering
427
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
428

    
429
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
430
	if ($endip != $targetsub_max) {
431
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
432
	}
433
	return $rangesubnets;
434
}
435

    
436
function is_iprange($range) {
437
	if (substr_count($range, '-') != 1) {
438
		return false;
439
	}
440
	list($ip1, $ip2) = explode ('-', $range);
441
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
442
}
443

    
444
function is_numericint($arg) {
445
	return (preg_match("/[^0-9]/", $arg) ? false : true);
446
}
447

    
448

    
449
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
450
function is_ipaddr($ipaddr) {
451
	if(is_ipaddrv4($ipaddr)) {
452
		return true;
453
	}
454
	if(is_ipaddrv6($ipaddr)) {
455
		return true;
456
	}
457
	return false;
458
}
459

    
460
/* returns true if $ipaddr is a valid IPv6 address */
461
function is_ipaddrv6($ipaddr) {
462
	$result = Net_IPv6::checkIPv6($ipaddr);
463
	return $result;
464
}
465

    
466
/* returns true if $ipaddr is a valid dotted IPv4 address */
467
function is_ipaddrv4($ipaddr) {
468
	if (!is_string($ipaddr))
469
		return false;
470

    
471
	$ip_long = ip2long($ipaddr);
472
	$ip_reverse = long2ip32($ip_long);
473

    
474
	if ($ipaddr == $ip_reverse)
475
		return true;
476
	else
477
		return false;
478
}
479

    
480

    
481
/* returns true if $ipaddr is a valid literal IPv6 address */
482
function is_literalipaddrv6($ipaddr) {
483
	if(preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match))
484
		$ipaddr = $match[1];
485
	else
486
		return false;
487

    
488
	return is_ipaddrv6($ipaddr);
489
}
490

    
491
function is_ipaddrwithport($ipport) {
492
	$parts = explode(":", $ipport);
493
	$port = array_pop($parts);
494
	if (count($parts) == 1) {
495
		return is_ipaddrv4($parts[0]) && is_port($port);
496
	} elseif (count($parts) > 1) {
497
		return is_literalipaddrv6(implode(":", $parts)) && is_port($port);
498
	} else {
499
		return false;
500
	}
501
}
502

    
503
function is_hostnamewithport($hostport) {
504
	$parts = explode(":", $hostport);
505
	$port = array_pop($parts);
506
	if (count($parts) == 1) {
507
		return is_hostname($parts[0]) && is_port($port);
508
	} else {
509
		return false;
510
	}
511
}
512

    
513
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
514
function is_ipaddroralias($ipaddr) {
515
	global $config;
516

    
517
	if (is_alias($ipaddr)) {
518
		if (is_array($config['aliases']['alias'])) {
519
			foreach ($config['aliases']['alias'] as $alias) {
520
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
521
					return true;
522
			}
523
		}
524
		return false;
525
	} else
526
		return is_ipaddr($ipaddr);
527

    
528
}
529

    
530
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format */
531
function is_subnet($subnet) {
532
	if(is_subnetv4($subnet)) {
533
		return true;
534
	}
535
	if(is_subnetv6($subnet)) {
536
		return true;
537
	}
538
	return false;
539
}
540

    
541
/* returns true if $subnet is a valid IPv4 subnet in CIDR format */
542
function is_subnetv4($subnet) {
543
	if (!is_string($subnet))
544
		return false;
545

    
546
	list($hp,$np) = explode('/', $subnet);
547

    
548
	if (!is_ipaddrv4($hp))
549
		return false;
550

    
551
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
552
		return false;
553

    
554
	return true;
555
}
556

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

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

    
564
	if (!is_ipaddrv6($hp))
565
		return false;
566

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

    
570
	return true;
571
}
572

    
573

    
574
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
575
function is_subnetoralias($subnet) {
576
	global $aliastable;
577

    
578
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
579
		return true;
580
	else
581
		return is_subnet($subnet);
582
}
583

    
584
/* returns true if $hostname is a valid hostname */
585
function is_hostname($hostname) {
586
	if (!is_string($hostname))
587
		return false;
588

    
589
	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))
590
		return true;
591
	else
592
		return false;
593
}
594

    
595
/* returns true if $domain is a valid domain name */
596
function is_domain($domain) {
597
	if (!is_string($domain))
598
		return false;
599

    
600
	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))
601
		return true;
602
	else
603
		return false;
604
}
605

    
606
/* returns true if $macaddr is a valid MAC address */
607
function is_macaddr($macaddr) {
608
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){5}$/i', $macaddr) == 1 ? true : false;
609
}
610

    
611
/* returns true if $name is a valid name for an alias */
612
/* returns NULL if a reserved word is used */
613
function is_validaliasname($name) {
614
	/* Array of reserved words */
615
	$reserved = array("port", "pass");
616
	if (in_array($name, $reserved, true))
617
		return; /* return NULL */
618
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
619
		return true;
620
	else
621
		return false;
622
}
623

    
624
/* returns true if $port is a valid TCP/UDP port */
625
function is_port($port) {
626
	$tmpports = explode(":", $port);
627
	foreach($tmpports as $tmpport) {
628
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
629
			continue;
630
		if (!ctype_digit($tmpport))
631
			return false;
632
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
633
			return false;
634
	}
635
	return true;
636
}
637

    
638
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
639
function is_portrange($portrange) {
640
	$ports = explode(":", $portrange);
641

    
642
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
643
}
644

    
645
/* returns true if $port is a valid port number or an alias thereof */
646
function is_portoralias($port) {
647
	global $config;
648

    
649
	if (is_alias($port)) {
650
		if (is_array($config['aliases']['alias'])) {
651
			foreach ($config['aliases']['alias'] as $alias) {
652
				if ($alias['name'] == $port && $alias['type'] == "port")
653
					return true;
654
				}
655
			}
656
			return false;
657
	} else
658
		return is_port($port);
659
}
660

    
661
/* returns true if $val is a valid shaper bandwidth value */
662
function is_valid_shaperbw($val) {
663
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
664
}
665

    
666
/* return the configured carp interface list */
667
function get_configured_carp_interface_list() {
668
	global $config;
669

    
670
	$iflist = array();
671

    
672
	if(is_array($config['virtualip']['vip'])) {
673
		$viparr = &$config['virtualip']['vip'];
674
		foreach ($viparr as $vip) {
675
			switch ($vip['mode']) {
676
			case "carp":
677
				$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
678
				$iflist[$vipif] = $vip['subnet'];
679
				break;
680
			}
681
		}
682
	}
683

    
684
	return $iflist;
685
}
686

    
687
/* return the configured IP aliases list */
688
function get_configured_ip_aliases_list($returnfullentry = false) {
689
	global $config;
690

    
691
	$alias_list=array();
692

    
693
	if(is_array($config['virtualip']['vip'])) {
694
		$viparr = &$config['virtualip']['vip'];
695
		foreach ($viparr as $vip) {
696
			if ($vip['mode']=="ipalias") {
697
				if ($returnfullentry)
698
					$alias_list[$vip['subnet']] = $vip;
699
				else
700
					$alias_list[$vip['subnet']] = $vip['interface'];
701
			}
702
		}
703
	}
704

    
705
	return $alias_list;
706
}
707

    
708

    
709
/* comparison function for sorting by the order in which interfaces are normally created */
710
function compare_interface_friendly_names($a, $b) {
711
	if ($a == $b)
712
		return 0;
713
	else if ($a == 'wan')
714
		return -1;
715
	else if ($b == 'wan')
716
		return 1;
717
	else if ($a == 'lan')
718
		return -1;
719
	else if ($b == 'lan')
720
		return 1;
721

    
722
	return strnatcmp($a, $b);
723
}
724

    
725
/* return the configured interfaces list. */
726
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
727
	global $config;
728

    
729
	$iflist = array();
730

    
731
	/* if list */
732
	foreach($config['interfaces'] as $if => $ifdetail) {
733
		if ($only_opt && ($if == "wan" || $if == "lan"))
734
			continue;
735
		if (isset($ifdetail['enable']) || $withdisabled == true)
736
			$iflist[$if] = $if;
737
	}
738

    
739
	return $iflist;
740
}
741

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

    
746
	$iflist = array();
747

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

    
759
	return $iflist;
760
}
761

    
762
/* return the configured interfaces list with their description. */
763
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
764
	global $config;
765

    
766
	$iflist = array();
767

    
768
	/* if list */
769
	foreach($config['interfaces'] as $if => $ifdetail) {
770
		if ($only_opt && ($if == "wan" || $if == "lan"))
771
			continue;
772
		if (isset($ifdetail['enable']) || $withdisabled == true) {
773
			if(empty($ifdetail['descr']))
774
				$iflist[$if] = strtoupper($if);
775
			else
776
				$iflist[$if] = strtoupper($ifdetail['descr']);
777
		}
778
	}
779

    
780
	return $iflist;
781
}
782

    
783
/*
784
 *   get_configured_ip_addresses() - Return a list of all configured
785
 *   interfaces IP Addresses
786
 *
787
 */
788
function get_configured_ip_addresses() {
789
	require_once("interfaces.inc");
790
	$ip_array = array();
791
	$interfaces = get_configured_interface_list();
792
	if(is_array($interfaces)) {
793
		foreach($interfaces as $int) {
794
			$ipaddr = get_interface_ip($int);
795
			$ip_array[$int] = $ipaddr;
796
		}
797
	}
798
	$interfaces = get_configured_carp_interface_list();
799
	if(is_array($interfaces)) 
800
		foreach($interfaces as $int => $ipaddr) 
801
			$ip_array[$int] = $ipaddr;
802
	return $ip_array;
803
}
804

    
805
/*
806
 *   get_configured_ipv6_addresses() - Return a list of all configured
807
 *   interfaces IPv6 Addresses
808
 *
809
 */
810
function get_configured_ipv6_addresses() {
811
	require_once("interfaces.inc");
812
	$ipv6_array = array();
813
	$interfaces = get_configured_interface_list();
814
	if(is_array($interfaces)) {
815
		foreach($interfaces as $int) {
816
			$ipaddrv6 = get_interface_ipv6($int);
817
			$ipv6_array[$int] = $ipaddrv6;
818
		}
819
	}
820
	$interfaces = get_configured_carp_interface_list();
821
	if(is_array($interfaces)) 
822
		foreach($interfaces as $int => $ipaddrv6) 
823
			$ipv6_array[$int] = $ipaddrv6;
824
	return $ipv6_array;
825
}
826

    
827
/*
828
 *   get_interface_list() - Return a list of all physical interfaces
829
 *   along with MAC and status.
830
 *
831
 *   $mode = "active" - use ifconfig -lu
832
 *           "media"  - use ifconfig to check physical connection
833
 *			status (much slower)
834
 */
835
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
836
        global $config;
837
	$upints = array();
838
        /* get a list of virtual interface types */
839
        if(!$vfaces) {
840
		$vfaces = array (
841
				'bridge',
842
				'ppp',
843
				'pppoe',
844
				'pptp',
845
				'l2tp',
846
				'sl',
847
				'gif',
848
				'gre',
849
				'faith',
850
				'lo',
851
				'ng',
852
				'_vlan',
853
				'_wlan',
854
				'pflog',
855
				'plip',
856
				'pfsync',
857
				'enc',
858
				'tun',
859
				'carp',
860
				'lagg',
861
				'vip',
862
				'ipfw'
863
		);
864
	}
865
	switch($mode) {
866
	case "active":
867
                $upints = pfSense_interface_listget(IFF_UP);
868
        	break;
869
	case "media":
870
		$intlist = pfSense_interface_listget();
871
                $ifconfig = "";
872
                exec("/sbin/ifconfig -a", $ifconfig);
873
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
874
                $ifstatus = preg_grep('/status:/', $ifconfig);
875
		foreach($ifstatus as $status) {
876
			$int = array_shift($intlist);
877
			if(stristr($status, "active")) $upints[] = $int;
878
		}
879
		break;
880
	default:
881
		$upints = pfSense_interface_listget();
882
		break;
883
	}
884
        /* build interface list with netstat */
885
        $linkinfo = "";
886
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
887
        array_shift($linkinfo);
888
	/* build ip address list with netstat */
889
	$ipinfo = "";
890
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
891
	array_shift($ipinfo);
892
	foreach($linkinfo as $link) {
893
		$friendly = "";
894
		$alink = explode(" ", $link);
895
		$ifname = rtrim(trim($alink[0]), '*');
896
		/* trim out all numbers before checking for vfaces */
897
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
898
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
899
			$toput = array(
900
					"mac" => trim($alink[1]),
901
					"up" => in_array($ifname, $upints)
902
				);
903
			foreach($ipinfo as $ip) {
904
				$aip = explode(" ", $ip);
905
				if($aip[0] == $ifname) {
906
					$toput['ipaddr'] = $aip[1];
907
				}
908
			}
909
			if (is_array($config['interfaces'])) {
910
				foreach($config['interfaces'] as $name => $int)
911
					if($int['if'] == $ifname) $friendly = $name;
912
			}
913
			switch($keyby) {
914
			case "physical":
915
				if($friendly != "") {
916
					$toput['friendly'] = $friendly;
917
				}
918
				$dmesg_arr = array();
919
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
920
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
921
				$toput['dmesg'] = $dmesg[1][0];
922
				$iflist[$ifname] = $toput;
923
				break;
924
			case "ppp":
925
				
926
			case "friendly":
927
				if($friendly != "") {
928
					$toput['if'] = $ifname;
929
					$iflist[$friendly] = $toput;
930
				}
931
				break;
932
			}
933
		}
934
	}
935
	return $iflist;
936
}
937

    
938
/****f* util/log_error
939
* NAME
940
*   log_error  - Sends a string to syslog.
941
* INPUTS
942
*   $error     - string containing the syslog message.
943
* RESULT
944
*   null
945
******/
946
function log_error($error) {
947
	global $g;
948
	$page = $_SERVER['SCRIPT_NAME'];
949
	syslog(LOG_ERR, "$page: $error");
950
	if ($g['debug'])
951
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
952
	return;
953
}
954

    
955
/****f* util/log_auth
956
* NAME
957
*   log_error  - Sends a string to syslog as LOG_AUTH facility
958
* INPUTS
959
*   $error     - string containing the syslog message.
960
* RESULT
961
*   null
962
******/
963
function log_auth($error) {
964
	global $g;
965
	$page = $_SERVER['SCRIPT_NAME'];
966
	syslog(LOG_AUTH, "$page: $error");
967
	if ($g['debug'])
968
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
969
	return;
970
}
971

    
972
/****f* util/exec_command
973
 * NAME
974
 *   exec_command - Execute a command and return a string of the result.
975
 * INPUTS
976
 *   $command   - String of the command to be executed.
977
 * RESULT
978
 *   String containing the command's result.
979
 * NOTES
980
 *   This function returns the command's stdout and stderr.
981
 ******/
982
function exec_command($command) {
983
	$output = array();
984
	exec($command . ' 2>&1 ', $output);
985
	return(implode("\n", $output));
986
}
987

    
988
/* wrapper for exec() */
989
function mwexec($command, $mute = false, $clearsigmask = false) {
990
	global $g;
991

    
992
	if ($g['debug']) {
993
		if (!$_SERVER['REMOTE_ADDR'])
994
			echo "mwexec(): $command\n";
995
	}
996
	$oarr = array();
997
	$retval = 0;
998

    
999
	if ($clearsigmask) {
1000
		$oldset = array();
1001
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1002
	}
1003
	$garbage = exec("$command 2>&1", $oarr, $retval);
1004
	if ($clearsigmask) {
1005
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1006
	}
1007

    
1008
	if(isset($config['system']['developerspew']))
1009
		$mute = false;
1010
	if(($retval <> 0) && ($mute === false)) {
1011
		$output = implode(" ", $oarr);
1012
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
1013
	}
1014
	return $retval;
1015
}
1016

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

    
1021
	if ($g['debug']) {
1022
		if (!$_SERVER['REMOTE_ADDR'])
1023
			echo "mwexec(): $command\n";
1024
	}
1025

    
1026
	if ($clearsigmask) {
1027
		$oldset = array();
1028
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1029
	}
1030
	exec("nohup $command > /dev/null 2>&1 &");
1031
	if ($clearsigmask) {
1032
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1033
	}
1034
}
1035

    
1036
/* unlink a file, if it exists */
1037
function unlink_if_exists($fn) {
1038
	$to_do = glob($fn);
1039
	if(is_array($to_do)) {
1040
		foreach($to_do as $filename)
1041
			@unlink($filename);
1042
	} else {
1043
		@unlink($fn);
1044
	}
1045
}
1046
/* make a global alias table (for faster lookups) */
1047
function alias_make_table($config) {
1048
	global $aliastable;
1049

    
1050
	$aliastable = array();
1051

    
1052
	if (is_array($config['aliases']['alias'])) {
1053
		foreach ($config['aliases']['alias'] as $alias) {
1054
			if ($alias['name'])
1055
				$aliastable[$alias['name']] = $alias['address'];
1056
		}
1057
	}
1058
}
1059

    
1060
/* check if an alias exists */
1061
function is_alias($name) {
1062
	global $aliastable;
1063

    
1064
	return isset($aliastable[$name]);
1065
}
1066

    
1067
function alias_get_type($name) {
1068
        global $config;
1069
        
1070
	if (is_array($config['aliases']['alias'])) {
1071
		foreach ($config['aliases']['alias'] as $alias) {
1072
			if ($name == $alias['name'])
1073
				return $alias['type'];
1074
		}
1075
	}
1076

    
1077
        return "";
1078
}
1079

    
1080
/* expand a host or network alias, if necessary */
1081
function alias_expand($name) {
1082
	global $aliastable;
1083

    
1084
	if (isset($aliastable[$name]))
1085
		return "\${$name}";
1086
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1087
		return "{$name}";
1088
	else
1089
		return null;
1090
}
1091

    
1092
function alias_expand_urltable($name) {
1093
	global $config;
1094
	$urltable_prefix = "/var/db/aliastables/";
1095
	$urltable_filename = $urltable_prefix . $name . ".txt";
1096

    
1097
	if (is_array($config['aliases']['alias'])) {
1098
		foreach ($config['aliases']['alias'] as $alias) {
1099
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
1100
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1101
					return $urltable_filename;
1102
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1103
					return $urltable_filename;
1104
			}
1105
		}
1106
	}
1107
	return null;
1108
}
1109

    
1110
function subnet_size ($subnet) {
1111
	if (is_subnetv4($subnet)) {
1112
		list ($ip, $bits) = explode("/", $subnet);
1113
		return round(exp(log(2) * (32 - $bits)));
1114
	}
1115
	else if (is_subnetv6($subnet)) {
1116
		list ($ip, $bits) = explode("/", $subnet);
1117
		return round(exp(log(2) * (128 - $bits)));
1118
	}
1119
	else {
1120
		return 0;
1121
	}
1122
}
1123

    
1124
function subnet_expand ($subnet) {
1125
	if (is_subnetv4($subnet)) {
1126
		return subnetv4_expand($subnet);
1127
	} else if (is_subnetv6($subnet)) {
1128
		return subnetv6_expand($subnet);
1129
	} else {
1130
		return $subnet;
1131
	}
1132
}
1133

    
1134
function subnetv4_expand ($subnet) {
1135
	$result = array();
1136
	list ($ip, $bits) = explode("/", $subnet);
1137
	$net  = ip2long($ip);
1138
	$mask = (0xffffffff << (32 - $bits));
1139
	$net &= $mask;
1140
	$size = round(exp(log(2) * (32 - $bits)));
1141
	for ($i = 0; $i < $size; $i += 1) {
1142
		$result[] = long2ip($net | $i);
1143
	}
1144
	return $result;
1145
}
1146

    
1147
/* find out whether two subnets overlap */
1148
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1149

    
1150
	if (!is_numeric($bits1))
1151
		$bits1 = 32;
1152
	if (!is_numeric($bits2))
1153
		$bits2 = 32;
1154

    
1155
	if ($bits1 < $bits2)
1156
		$relbits = $bits1;
1157
	else
1158
		$relbits = $bits2;
1159

    
1160
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1161
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1162

    
1163
	return ($sn1 == $sn2);
1164
}
1165

    
1166
/* compare two IP addresses */
1167
function ipcmp($a, $b) {
1168
	if (ip_less_than($a, $b))
1169
		return -1;
1170
	else if (ip_greater_than($a, $b))
1171
		return 1;
1172
	else
1173
		return 0;
1174
}
1175

    
1176
/* return true if $addr is in $subnet, false if not */
1177
function ip_in_subnet($addr,$subnet) {
1178
	if(is_ipaddrv6($addr)) {
1179
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1180
		if($result)
1181
			return true;
1182
		else
1183
			return false;
1184
	}
1185
	list($ip, $mask) = explode('/', $subnet);
1186
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1187
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1188
}
1189

    
1190
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1191
function verify_digital_signature($fname) {
1192
	global $g;
1193

    
1194
	if(!file_exists("/usr/local/sbin/gzsig"))
1195
		return 4;
1196

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

    
1200
/* obtain MAC address given an IP address by looking at the ARP table */
1201
function arp_get_mac_by_ip($ip) {
1202
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1203
	$arpoutput = "";
1204
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1205

    
1206
	if ($arpoutput[0]) {
1207
		$arpi = explode(" ", $arpoutput[0]);
1208
		$macaddr = $arpi[3];
1209
		if (is_macaddr($macaddr))
1210
			return $macaddr;
1211
		else
1212
			return false;
1213
	}
1214

    
1215
	return false;
1216
}
1217

    
1218
/* return a fieldname that is safe for xml usage */
1219
function xml_safe_fieldname($fieldname) {
1220
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1221
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1222
			 ':', ',', '.', '\'', '\\'
1223
		);
1224
	return strtolower(str_replace($replace, "", $fieldname));
1225
}
1226

    
1227
function mac_format($clientmac) {
1228
    global $config, $cpzone;
1229

    
1230
    $mac = explode(":", $clientmac);
1231
    $mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1232

    
1233
    switch($mac_format) {
1234
        case 'singledash':
1235
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1236

    
1237
        case 'ietf':
1238
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1239

    
1240
        case 'cisco':
1241
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1242

    
1243
        case 'unformatted':
1244
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1245

    
1246
        default:
1247
		return $clientmac;
1248
    }
1249
}
1250

    
1251
function resolve_retry($hostname, $retries = 5) {
1252

    
1253
	if (is_ipaddr($hostname))
1254
		return $hostname;
1255

    
1256
       for ($i = 0; $i < $retries; $i++) {
1257
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1258
               $ip = gethostbyname($hostname);
1259

    
1260
		if ($ip && $ip != $hostname) {
1261
			/* success */
1262
			return $ip;
1263
		}
1264

    
1265
		sleep(1);
1266
	}
1267

    
1268
	return false;
1269
}
1270

    
1271
function format_bytes($bytes) {
1272
	if ($bytes >= 1073741824) {
1273
		return sprintf("%.2f GB", $bytes/1073741824);
1274
	} else if ($bytes >= 1048576) {
1275
		return sprintf("%.2f MB", $bytes/1048576);
1276
	} else if ($bytes >= 1024) {
1277
		return sprintf("%.0f KB", $bytes/1024);
1278
	} else {
1279
		return sprintf("%d bytes", $bytes);
1280
	}
1281
}
1282

    
1283
function update_filter_reload_status($text) {
1284
	global $g;
1285

    
1286
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1287
}
1288

    
1289
/****f* util/return_dir_as_array
1290
 * NAME
1291
 *   return_dir_as_array - Return a directory's contents as an array.
1292
 * INPUTS
1293
 *   $dir       - string containing the path to the desired directory.
1294
 * RESULT
1295
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1296
 ******/
1297
function return_dir_as_array($dir) {
1298
	$dir_array = array();
1299
	if (is_dir($dir)) {
1300
		if ($dh = opendir($dir)) {
1301
			while (($file = readdir($dh)) !== false) {
1302
				$canadd = 0;
1303
				if($file == ".") $canadd = 1;
1304
				if($file == "..") $canadd = 1;
1305
				if($canadd == 0)
1306
					array_push($dir_array, $file);
1307
			}
1308
			closedir($dh);
1309
		}
1310
	}
1311
	return $dir_array;
1312
}
1313

    
1314
function run_plugins($directory) {
1315
	global $config, $g;
1316

    
1317
	/* process packager manager custom rules */
1318
	$files = return_dir_as_array($directory);
1319
	if (is_array($files)) {
1320
		foreach ($files as $file) {
1321
			if (stristr($file, ".sh") == true)
1322
				mwexec($directory . $file . " start");
1323
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1324
				require_once($directory . "/" . $file);
1325
		}
1326
	}
1327
}
1328

    
1329
/*
1330
 *    safe_mkdir($path, $mode = 0755)
1331
 *    create directory if it doesn't already exist and isn't a file!
1332
 */
1333
function safe_mkdir($path, $mode=0755) {
1334
	global $g;
1335

    
1336
	if (!is_file($path) && !is_dir($path)) {
1337
		return @mkdir($path, $mode, true);
1338
	} else {
1339
		return false;
1340
	}
1341
}
1342

    
1343
/*
1344
 * make_dirs($path, $mode = 0755)
1345
 * create directory tree recursively (mkdir -p)
1346
 */
1347
function make_dirs($path, $mode = 0755) {
1348
	$base = '';
1349
	foreach (explode('/', $path) as $dir) {
1350
		$base .= "/$dir";
1351
		if (!is_dir($base)) {
1352
			if (!@mkdir($base, $mode))
1353
				return false;
1354
		}
1355
	}
1356
	return true;
1357
}
1358

    
1359
/*
1360
 * get_sysctl($names)
1361
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1362
 * name) and return an array of key/value pairs set for those that exist
1363
 */
1364
function get_sysctl($names) {
1365
	if (empty($names))
1366
		return array();
1367

    
1368
	if (is_array($names)) {
1369
		$name_list = array();
1370
		foreach ($names as $name) {
1371
			$name_list[] = escapeshellarg($name);
1372
		}
1373
	} else
1374
		$name_list = array(escapeshellarg($names));
1375

    
1376
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1377
	$values = array();
1378
	foreach ($output as $line) {
1379
		$line = explode(": ", $line, 2);
1380
		if (count($line) == 2)
1381
			$values[$line[0]] = $line[1];
1382
	}
1383

    
1384
	return $values;
1385
}
1386

    
1387
/*
1388
 * set_sysctl($value_list)
1389
 * Set sysctl OID's listed as key/value pairs and return
1390
 * an array with keys set for those that succeeded
1391
 */
1392
function set_sysctl($values) {
1393
	if (empty($values))
1394
		return array();
1395

    
1396
	$value_list = array();
1397
	foreach ($values as $key => $value) {
1398
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1399
	}
1400

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

    
1403
	/* Retry individually if failed (one or more read-only) */
1404
	if ($success <> 0 && count($value_list) > 1) {
1405
		foreach ($value_list as $value) {
1406
			exec("/sbin/sysctl -i " . $value, $output);
1407
		}
1408
	}
1409

    
1410
	$ret = array();
1411
	foreach ($output as $line) {
1412
		$line = explode(": ", $line, 2);
1413
		if (count($line) == 2)
1414
			$ret[$line[0]] = true;
1415
	}
1416

    
1417
	return $ret;
1418
}
1419

    
1420
/*
1421
 *     get_memory()
1422
 *     returns an array listing the amount of
1423
 *     memory installed in the hardware
1424
 *     [0]real and [1]available
1425
 */
1426
function get_memory() {
1427
	$matches = "";
1428
	if(file_exists("/var/log/dmesg.boot"))
1429
		$mem = `cat /var/log/dmesg.boot | grep memory`;
1430
	else
1431
		$mem = `dmesg -a | grep memory`;			
1432
	if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1433
		return array($matches[1][0], $matches[1][0]);
1434
	if(!$real && !$avail) {
1435
		$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1436
		$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1437
		/* convert from bytes to megabytes */
1438
		return array(($real/1048576),($avail/1048576));
1439
	}
1440
}
1441

    
1442
function mute_kernel_msgs() {
1443
	global $config;
1444
	// Do not mute serial console.  The kernel gets very very cranky
1445
	// and will start dishing you cannot control tty errors.
1446
	switch (trim(file_get_contents("/etc/platform"))) {
1447
		case "nanobsd":
1448
		case "jail":
1449
			return;
1450
	}
1451
	if($config['system']['enableserial']) 
1452
		return;			
1453
	exec("/sbin/conscontrol mute on");
1454
}
1455

    
1456
function unmute_kernel_msgs() {
1457
	global $config;
1458
	// Do not mute serial console.  The kernel gets very very cranky
1459
	// and will start dishing you cannot control tty errors.
1460
	switch (trim(file_get_contents("/etc/platform"))) {
1461
		case "nanobsd":
1462
		case "jail":
1463
			return;
1464
	}
1465
	exec("/sbin/conscontrol mute off");
1466
}
1467

    
1468
function start_devd() {
1469
	global $g;
1470

    
1471
	if ($g['platform'] == 'jail')
1472
		return;
1473
	exec("/sbin/devd");
1474
	sleep(1);
1475
}
1476

    
1477
function is_interface_vlan_mismatch() {
1478
	global $config, $g;
1479

    
1480
	if (is_array($config['vlans']['vlan'])) {
1481
		foreach ($config['vlans']['vlan'] as $vlan) {
1482
			if (does_interface_exist($vlan['if']) == false)
1483
				return true;
1484
		}
1485
	}
1486

    
1487
	return false;
1488
}
1489

    
1490
function is_interface_mismatch() {
1491
	global $config, $g;
1492

    
1493
	$do_assign = false;
1494
	$i = 0;
1495
	$missing_interfaces = array();
1496
	if (is_array($config['interfaces'])) {
1497
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1498
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1499
				// Do not check these interfaces.
1500
				$i++;
1501
				continue;
1502
			}
1503
			else if (does_interface_exist($ifcfg['if']) == false) {
1504
				$missing_interfaces[] = $ifcfg['if'];
1505
				$do_assign = true;
1506
			} else
1507
				$i++;
1508
		}
1509
	}
1510

    
1511
	if ($g['minimum_nic_count'] > $i) {
1512
		$do_assign = true;
1513
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1514
		$do_assign = false;
1515

    
1516
	if (!empty($missing_interfaces) && $do_assign)
1517
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1518
	else
1519
		@unlink("{$g['tmp_path']}/missing_interfaces");
1520

    
1521
	return $do_assign;
1522
}
1523

    
1524
/* sync carp entries to other firewalls */
1525
function carp_sync_client() {
1526
	global $g;
1527
	send_event("filter sync");
1528
}
1529

    
1530
/****f* util/isAjax
1531
 * NAME
1532
 *   isAjax - reports if the request is driven from prototype
1533
 * INPUTS
1534
 *   none
1535
 * RESULT
1536
 *   true/false
1537
 ******/
1538
function isAjax() {
1539
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1540
}
1541

    
1542
/****f* util/timeout
1543
 * NAME
1544
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1545
 * INPUTS
1546
 *   optional, seconds to wait before timeout. Default 9 seconds.
1547
 * RESULT
1548
 *   returns 1 char of user input or null if no input.
1549
 ******/
1550
function timeout($timer = 9) {
1551
	while(!isset($key)) {
1552
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1553
		else { echo chr(8). "{$timer}"; }
1554
		`/bin/stty -icanon min 0 time 25`;
1555
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1556
		`/bin/stty icanon`;
1557
		if ($key == '')
1558
			unset($key);
1559
		$timer--;
1560
		if ($timer == 0)
1561
			break;
1562
	}
1563
	return $key;	
1564
}
1565

    
1566
/****f* util/msort
1567
 * NAME
1568
 *   msort - sort array
1569
 * INPUTS
1570
 *   $array to be sorted, field to sort by, direction of sort
1571
 * RESULT
1572
 *   returns newly sorted array
1573
 ******/
1574
function msort($array, $id="id", $sort_ascending=true) {
1575
	$temp_array = array();
1576
	while(count($array)>0) {
1577
		$lowest_id = 0;
1578
		$index=0;
1579
		foreach ($array as $item) {
1580
			if (isset($item[$id])) {
1581
				if ($array[$lowest_id][$id]) {
1582
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1583
						$lowest_id = $index;
1584
					}
1585
				}
1586
			}
1587
			$index++;
1588
		}
1589
		$temp_array[] = $array[$lowest_id];
1590
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1591
	}
1592
	if ($sort_ascending) {
1593
		return $temp_array;
1594
	} else {
1595
    		return array_reverse($temp_array);
1596
	}
1597
}
1598

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

    
1672
/****f* util/is_URL
1673
 * NAME
1674
 *   is_URL
1675
 * INPUTS
1676
 *   string to check
1677
 * RESULT
1678
 *   Returns true if item is a URL
1679
 ******/
1680
function is_URL($url) {
1681
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1682
	if($match)
1683
		return true;	
1684
	return false;
1685
}
1686

    
1687
function is_file_included($file = "") {
1688
	$files = get_included_files();
1689
	if (in_array($file, $files))
1690
		return true;
1691
	
1692
	return false;
1693
}
1694

    
1695
/*
1696
	This function was borrowed from a comment on PHP.net at the following URL:
1697
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1698
 */
1699
function array_merge_recursive_unique($array0, $array1) {
1700

    
1701
	$arrays = func_get_args();
1702
	$remains = $arrays;
1703

    
1704
	// We walk through each arrays and put value in the results (without
1705
	// considering previous value).
1706
	$result = array();
1707

    
1708
	// loop available array
1709
	foreach($arrays as $array) {
1710

    
1711
		// The first remaining array is $array. We are processing it. So
1712
		// we remove it from remaing arrays.
1713
        array_shift($remains);
1714

    
1715
		// We don't care non array param, like array_merge since PHP 5.0.
1716
		if(is_array($array)) {
1717
			// Loop values
1718
			foreach($array as $key => $value) {
1719
				if(is_array($value)) {
1720
					// we gather all remaining arrays that have such key available
1721
					$args = array();
1722
					foreach($remains as $remain) {
1723
						if(array_key_exists($key, $remain)) {
1724
							array_push($args, $remain[$key]);
1725
						}
1726
					}
1727

    
1728
					if(count($args) > 2) {
1729
						// put the recursion
1730
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1731
					} else {
1732
						foreach($value as $vkey => $vval) {
1733
							$result[$key][$vkey] = $vval;
1734
						}
1735
					}
1736
				} else {
1737
					// simply put the value
1738
					$result[$key] = $value;
1739
				}
1740
			}
1741
		}
1742
	}
1743
	return $result;
1744
}
1745

    
1746

    
1747
/*
1748
 * converts a string like "a,b,c,d"
1749
 * into an array like array("a" => "b", "c" => "d")
1750
 */
1751
function explode_assoc($delimiter, $string) {
1752
	$array = explode($delimiter, $string);
1753
	$result = array();
1754
	$numkeys = floor(count($array) / 2);
1755
	for ($i = 0; $i < $numkeys; $i += 1) {
1756
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1757
	}
1758
	return $result;
1759
}
1760

    
1761
function get_staticroutes($returnsubnetsonly = false) {
1762
	global $config;
1763
	require_once('filter.inc');
1764
	$allstaticroutes = array();
1765
	$allsubnets = array();
1766

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

    
1771
	/* Loop through routes and expand aliases as we find them. */
1772
	foreach ($config['staticroutes']['route'] as $route) {
1773
		if (is_alias($route['network'])) {
1774
			$subnets = filter_expand_alias_array($route['network']);
1775
			foreach ($subnets as $net) {
1776
				if (is_ipaddrv4($net))
1777
					$net .= "/32";
1778
				if (is_ipaddrv6($net) && !is_subnetv6($net))
1779
					$net .= "/128";
1780
				/* This must be a hostname, we can't use it. */
1781
				if (!is_subnet($net))
1782
					continue;
1783
				$temproute = $route;
1784
				$temproute['network'] = $net;
1785
				$allstaticroutes[] = $temproute;
1786
				$allsubnets[] = $net;
1787
			}
1788
		} elseif (is_subnet($route['network'])) {
1789
			$allstaticroutes[] = $route;
1790
			$allsubnets[] = $route['network'];
1791
		}
1792
	}
1793
	if ($returnsubnetsonly) {
1794
		return $allsubnets;
1795
	} else {
1796
		return $allstaticroutes;
1797
	}
1798
}
1799

    
1800
/****f* util/get_alias_list
1801
 * NAME
1802
 *   get_alias_list - Provide a list of aliases.
1803
 * INPUTS
1804
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
1805
 * RESULT
1806
 *   Array containing list of aliases.
1807
 *   If $type is unspecified, all aliases are returned.
1808
 *   If $type is a string, all aliases of the type specified in $type are returned.
1809
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
1810
 */
1811
function get_alias_list($type = null) {
1812
	global $config;
1813
	$result = array();
1814
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
1815
		foreach ($config['aliases']['alias'] as $alias) {
1816
			if ($type === null) {
1817
				$result[] = $alias['name'];
1818
			}
1819
			else if (is_array($type)) {
1820
				if (in_array($alias['type'], $type)) {
1821
					$result[] = $alias['name'];
1822
				}
1823
			}
1824
			else if ($type === $alias['type']) {
1825
				$result[] = $alias['name'];
1826
			}
1827
		}
1828
	}		
1829
	return $result;
1830
}
1831

    
1832
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
1833
function array_exclude($needle, $haystack) {
1834
	$result = array();
1835
	if (is_array($haystack)) {
1836
		foreach ($haystack as $thing) {
1837
			if ($needle !== $thing) {
1838
				$result[] = $thing;
1839
			}
1840
		}
1841
	}
1842
	return $result;
1843
}
1844

    
1845
function setup_library_paths() {
1846
	$current_library_paths = explode(":", exec("/sbin/ldconfig -r | /usr/bin/grep 'search directories' | /usr/bin/awk '{print $3;}'"));
1847
	$pbi_library_paths = array_merge(glob("/usr/pbi/*/lib", GLOB_ONLYDIR), glob("/usr/pbi/*/lib/*", GLOB_ONLYDIR));
1848
	foreach ($pbi_library_paths as $pbilib) {
1849
		if (!in_array($pbilib, $current_library_paths))
1850
			exec("/sbin/ldconfig -m {$pbilib}");
1851
	}
1852
}
1853

    
1854
?>
(54-54/66)