Project

General

Profile

Download (47.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, $partial=false) {
608
	$repeat = ($partial) ? '1,5' : '5';
609
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
610
}
611

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

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

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

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

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

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

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

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

    
671
	$iflist = array();
672

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

    
685
	return $iflist;
686
}
687

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

    
692
	$alias_list=array();
693

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

    
706
	return $alias_list;
707
}
708

    
709

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

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

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

    
730
	$iflist = array();
731

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

    
740
	return $iflist;
741
}
742

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

    
747
	$iflist = array();
748

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

    
760
	return $iflist;
761
}
762

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

    
767
	$iflist = array();
768

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

    
781
	return $iflist;
782
}
783

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1051
	$aliastable = array();
1052

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

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

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

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

    
1078
        return "";
1079
}
1080

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1216
	return false;
1217
}
1218

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

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

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

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

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

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

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

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

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

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

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

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

    
1266
		sleep(1);
1267
	}
1268

    
1269
	return false;
1270
}
1271

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

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

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

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

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

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

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

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

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

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

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

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

    
1385
	return $values;
1386
}
1387

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

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

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

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

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

    
1418
	return $ret;
1419
}
1420

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

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

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

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

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

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

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

    
1488
	return false;
1489
}
1490

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

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

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

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

    
1522
	return $do_assign;
1523
}
1524

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1747

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

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

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

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

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

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

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

    
1855
function get_current_theme() {
1856
	global $config, $g;
1857
	/*
1858
	 *   if user has selected a custom template, use it.
1859
	 *   otherwise default to pfsense tempalte
1860
	 */
1861
	if (($g["disablethemeselection"] === true) && !empty($g["default_theme"]) && (is_dir($g["www_path"].'/themes/'.$g["default_theme"])))
1862
		$theme = $g["default_theme"];
1863
	elseif($config['theme'] <> "" && (is_dir($g["www_path"].'/themes/'.$config['theme'])))
1864
		$theme = $config['theme'];
1865
	else
1866
		$theme = "pfsense";
1867
	/*
1868
	 *  If this device is an apple ipod/iphone
1869
	 *  switch the theme to one that works with it.
1870
	 */
1871
	$lowres_ua = array("iPhone", "iPod", "iPad", "Android", "BlackBerry", "Opera Mini", "Opera Mobi", "PlayBook");
1872
	foreach($lowres_ua as $useragent)
1873
		if(strstr($_SERVER['HTTP_USER_AGENT'], $useragent))
1874
			$theme = (empty($g['theme_lowres']) && (is_dir($g["www_path"].'/themes/'.$g['theme_lowres']))) ? "pfsense" : $g['theme_lowres'];
1875
	return $theme;
1876
}
1877

    
1878
?>
(54-54/66)