Project

General

Profile

Download (48.2 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 (file_exists($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 refcount_read($reference) {
252
	/* This function just reads the current value of the refcount for information. */
253
	/* There is no need for locking. */
254
	$shmid = @shmop_open($reference, "a", 0, 0);
255
	if (!$shmid) {
256
		log_error(gettext("Could not open shared memory for read {$reference}"));
257
		return -1;
258
	}
259
	$shm_data = @shmop_read($shmid, 0, 10);
260
	@shmop_close($shmid);
261
	return $shm_data;
262
}
263

    
264
function is_module_loaded($module_name) {
265
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
266
	if (intval($running) >= 1)
267
		return true;
268
	else
269
		return false;
270
}
271

    
272
/* return the subnet address given a host address and a subnet bit count */
273
function gen_subnet($ipaddr, $bits) {
274
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
275
		return "";
276
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
277
}
278

    
279
/* return the subnet address given a host address and a subnet bit count */
280
function gen_subnetv6($ipaddr, $bits) {
281
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
282
		return "";
283

    
284
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
285
	return $address;
286
}
287

    
288
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
289
function gen_subnet_max($ipaddr, $bits) {
290
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
291
		return "";
292

    
293
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
294
}
295

    
296
/* Generate end number for a given ipv6 subnet mask */
297
function gen_subnetv6_max($ipaddr, $bits) {
298
	if(!is_ipaddrv6($ipaddr))
299
		return false;
300
	
301
	$mask = Net_IPv6::getNetmask('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',$bits);
302
	
303
	$inet_ip = (binary)inet_pton($ipaddr);
304
	$inet_mask = (binary)inet_pton($mask);
305

    
306
	$inet_end = $inet_ip | ~$inet_mask;
307

    
308
	return(Net_IPv6::uncompress(inet_ntop($inet_end)));
309
}
310

    
311
/* returns a subnet mask (long given a bit count) */
312
function gen_subnet_mask_long($bits) {
313
	$sm = 0;
314
	for ($i = 0; $i < $bits; $i++) {
315
		$sm >>= 1;
316
		$sm |= 0x80000000;
317
	}
318
	return $sm;
319
}
320

    
321
/* same as above but returns a string */
322
function gen_subnet_mask($bits) {
323
	return long2ip(gen_subnet_mask_long($bits));
324
}
325

    
326
/* Convert long int to IP address, truncating to 32-bits. */
327
function long2ip32($ip) {
328
	return long2ip($ip & 0xFFFFFFFF);
329
}
330

    
331
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
332
function ip2long32($ip) {
333
	return ( ip2long($ip) & 0xFFFFFFFF );
334
}
335

    
336
/* Convert IP address to unsigned long int. */
337
function ip2ulong($ip) {
338
	return sprintf("%u", ip2long32($ip));
339
}
340

    
341
/* Find out how many IPs are contained within a given IP range
342
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
343
 */
344
function ip_range_size($startip, $endip) {
345
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
346
		// Operate as unsigned long because otherwise it wouldn't work
347
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
348
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
349
	}
350
	return -1;
351
}
352

    
353
/* Find the smallest possible subnet mask which can contain a given number of IPs
354
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
355
 */
356
function find_smallest_cidr($number) {
357
	$smallest = 1;
358
	for ($b=32; $b > 0; $b--) {
359
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
360
	}
361
	return (32-$smallest);
362
}
363

    
364
/* Return the previous IP address before the given address */
365
function ip_before($ip) {
366
	return long2ip32(ip2long($ip)-1);
367
}
368

    
369
/* Return the next IP address after the given address */
370
function ip_after($ip) {
371
	return long2ip32(ip2long($ip)+1);
372
}
373

    
374
/* Return true if the first IP is 'before' the second */
375
function ip_less_than($ip1, $ip2) {
376
	// Compare as unsigned long because otherwise it wouldn't work when
377
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
378
	return ip2ulong($ip1) < ip2ulong($ip2);
379
}
380

    
381
/* Return true if the first IP is 'after' the second */
382
function ip_greater_than($ip1, $ip2) {
383
	// Compare as unsigned long because otherwise it wouldn't work
384
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
385
	return ip2ulong($ip1) > ip2ulong($ip2);
386
}
387

    
388
/* Convert a range of IPs to an array of subnets which can contain the range. */
389
function ip_range_to_subnet_array($startip, $endip) {
390
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
391
		return array();
392
	}
393

    
394
	// Container for subnets within this range.
395
	$rangesubnets = array();
396

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

    
400
	// Loop here to reduce subnet size and retest as needed. We need to make sure
401
	//   that the target subnet is wholly contained between $startip and $endip.
402
	for ($cidr; $cidr <= 32; $cidr++) {
403
		// Find the network and broadcast addresses for the subnet being tested.
404
		$targetsub_min = gen_subnet($startip, $cidr);
405
		$targetsub_max = gen_subnet_max($startip, $cidr);
406

    
407
		// Check best case where the range is exactly one subnet.
408
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
409
			// Hooray, the range is exactly this subnet!
410
			return array("{$startip}/{$cidr}");
411
		}
412

    
413
		// These remaining scenarios will find a subnet that uses the largest
414
		//  chunk possible of the range being tested, and leave the rest to be
415
		//  tested recursively after the loop.
416

    
417
		// Check if the subnet begins with $startip and ends before $endip
418
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
419
			break;
420
		}
421

    
422
		// Check if the subnet ends at $endip and starts after $startip
423
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
424
			break;
425
		}
426

    
427
		// Check if the subnet is between $startip and $endip
428
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
429
			break;
430
		}
431
	}
432

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

    
439
	// Add in the subnet we found before, to preserve ordering
440
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
441

    
442
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
443
	if ($endip != $targetsub_max) {
444
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
445
	}
446
	return $rangesubnets;
447
}
448

    
449
function is_iprange($range) {
450
	if (substr_count($range, '-') != 1) {
451
		return false;
452
	}
453
	list($ip1, $ip2) = explode ('-', $range);
454
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
455
}
456

    
457
function is_numericint($arg) {
458
	return (preg_match("/[^0-9]/", $arg) ? false : true);
459
}
460

    
461

    
462
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
463
function is_ipaddr($ipaddr) {
464
	if(is_ipaddrv4($ipaddr)) {
465
		return true;
466
	}
467
	if(is_ipaddrv6($ipaddr)) {
468
		return true;
469
	}
470
	return false;
471
}
472

    
473
/* returns true if $ipaddr is a valid IPv6 address */
474
function is_ipaddrv6($ipaddr) {
475
	$result = Net_IPv6::checkIPv6($ipaddr);
476
	return $result;
477
}
478

    
479
/* returns true if $ipaddr is a valid dotted IPv4 address */
480
function is_ipaddrv4($ipaddr) {
481
	if (!is_string($ipaddr))
482
		return false;
483

    
484
	$ip_long = ip2long($ipaddr);
485
	$ip_reverse = long2ip32($ip_long);
486

    
487
	if ($ipaddr == $ip_reverse)
488
		return true;
489
	else
490
		return false;
491
}
492

    
493

    
494
/* returns true if $ipaddr is a valid literal IPv6 address */
495
function is_literalipaddrv6($ipaddr) {
496
	if(preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match))
497
		$ipaddr = $match[1];
498
	else
499
		return false;
500

    
501
	return is_ipaddrv6($ipaddr);
502
}
503

    
504
function is_ipaddrwithport($ipport) {
505
	$parts = explode(":", $ipport);
506
	$port = array_pop($parts);
507
	if (count($parts) == 1) {
508
		return is_ipaddrv4($parts[0]) && is_port($port);
509
	} elseif (count($parts) > 1) {
510
		return is_literalipaddrv6(implode(":", $parts)) && is_port($port);
511
	} else {
512
		return false;
513
	}
514
}
515

    
516
function is_hostnamewithport($hostport) {
517
	$parts = explode(":", $hostport);
518
	$port = array_pop($parts);
519
	if (count($parts) == 1) {
520
		return is_hostname($parts[0]) && is_port($port);
521
	} else {
522
		return false;
523
	}
524
}
525

    
526
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
527
function is_ipaddroralias($ipaddr) {
528
	global $config;
529

    
530
	if (is_alias($ipaddr)) {
531
		if (is_array($config['aliases']['alias'])) {
532
			foreach ($config['aliases']['alias'] as $alias) {
533
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
534
					return true;
535
			}
536
		}
537
		return false;
538
	} else
539
		return is_ipaddr($ipaddr);
540

    
541
}
542

    
543
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format */
544
function is_subnet($subnet) {
545
	if(is_subnetv4($subnet)) {
546
		return true;
547
	}
548
	if(is_subnetv6($subnet)) {
549
		return true;
550
	}
551
	return false;
552
}
553

    
554
/* returns true if $subnet is a valid IPv4 subnet in CIDR format */
555
function is_subnetv4($subnet) {
556
	if (!is_string($subnet))
557
		return false;
558

    
559
	list($hp,$np) = explode('/', $subnet);
560

    
561
	if (!is_ipaddrv4($hp))
562
		return false;
563

    
564
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
565
		return false;
566

    
567
	return true;
568
}
569

    
570
/* returns true if $subnet is a valid IPv6 subnet in CIDR format */
571
function is_subnetv6($subnet) {
572
	if (!is_string($subnet))
573
		return false;
574

    
575
	list($hp,$np) = explode('/', $subnet);
576

    
577
	if (!is_ipaddrv6($hp))
578
		return false;
579

    
580
	if (!is_numeric($np) || ($np < 1) || ($np > 128))
581
		return false;
582

    
583
	return true;
584
}
585

    
586

    
587
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
588
function is_subnetoralias($subnet) {
589
	global $aliastable;
590

    
591
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
592
		return true;
593
	else
594
		return is_subnet($subnet);
595
}
596

    
597
/* returns true if $hostname is a valid hostname */
598
function is_hostname($hostname) {
599
	if (!is_string($hostname))
600
		return false;
601

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

    
608
/* returns true if $domain is a valid domain name */
609
function is_domain($domain) {
610
	if (!is_string($domain))
611
		return false;
612

    
613
	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))
614
		return true;
615
	else
616
		return false;
617
}
618

    
619
/* returns true if $macaddr is a valid MAC address */
620
function is_macaddr($macaddr, $partial=false) {
621
	$repeat = ($partial) ? '1,5' : '5';
622
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
623
}
624

    
625
/* returns true if $name is a valid name for an alias */
626
/* returns NULL if a reserved word is used */
627
function is_validaliasname($name) {
628
	/* Array of reserved words */
629
	$reserved = array("port", "pass");
630
	if (in_array($name, $reserved, true))
631
		return; /* return NULL */
632
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
633
		return true;
634
	else
635
		return false;
636
}
637

    
638
/* returns true if $port is a valid TCP/UDP port */
639
function is_port($port) {
640
	$tmpports = explode(":", $port);
641
	foreach($tmpports as $tmpport) {
642
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
643
			continue;
644
		if (!ctype_digit($tmpport))
645
			return false;
646
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
647
			return false;
648
	}
649
	return true;
650
}
651

    
652
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
653
function is_portrange($portrange) {
654
	$ports = explode(":", $portrange);
655

    
656
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
657
}
658

    
659
/* returns true if $port is a valid port number or an alias thereof */
660
function is_portoralias($port) {
661
	global $config;
662

    
663
	if (is_alias($port)) {
664
		if (is_array($config['aliases']['alias'])) {
665
			foreach ($config['aliases']['alias'] as $alias) {
666
				if ($alias['name'] == $port && $alias['type'] == "port")
667
					return true;
668
				}
669
			}
670
			return false;
671
	} else
672
		return is_port($port);
673
}
674

    
675
/* returns true if $val is a valid shaper bandwidth value */
676
function is_valid_shaperbw($val) {
677
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
678
}
679

    
680
/* return the configured carp interface list */
681
function get_configured_carp_interface_list() {
682
	global $config;
683

    
684
	$iflist = array();
685

    
686
	if(is_array($config['virtualip']['vip'])) {
687
		$viparr = &$config['virtualip']['vip'];
688
		foreach ($viparr as $vip) {
689
			switch ($vip['mode']) {
690
			case "carp":
691
				$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
692
				$iflist[$vipif] = $vip['subnet'];
693
				break;
694
			}
695
		}
696
	}
697

    
698
	return $iflist;
699
}
700

    
701
/* return the configured IP aliases list */
702
function get_configured_ip_aliases_list($returnfullentry = false) {
703
	global $config;
704

    
705
	$alias_list=array();
706

    
707
	if(is_array($config['virtualip']['vip'])) {
708
		$viparr = &$config['virtualip']['vip'];
709
		foreach ($viparr as $vip) {
710
			if ($vip['mode']=="ipalias") {
711
				if ($returnfullentry)
712
					$alias_list[$vip['subnet']] = $vip;
713
				else
714
					$alias_list[$vip['subnet']] = $vip['interface'];
715
			}
716
		}
717
	}
718

    
719
	return $alias_list;
720
}
721

    
722

    
723
/* comparison function for sorting by the order in which interfaces are normally created */
724
function compare_interface_friendly_names($a, $b) {
725
	if ($a == $b)
726
		return 0;
727
	else if ($a == 'wan')
728
		return -1;
729
	else if ($b == 'wan')
730
		return 1;
731
	else if ($a == 'lan')
732
		return -1;
733
	else if ($b == 'lan')
734
		return 1;
735

    
736
	return strnatcmp($a, $b);
737
}
738

    
739
/* return the configured interfaces list. */
740
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
741
	global $config;
742

    
743
	$iflist = array();
744

    
745
	/* if list */
746
	foreach($config['interfaces'] as $if => $ifdetail) {
747
		if ($only_opt && ($if == "wan" || $if == "lan"))
748
			continue;
749
		if (isset($ifdetail['enable']) || $withdisabled == true)
750
			$iflist[$if] = $if;
751
	}
752

    
753
	return $iflist;
754
}
755

    
756
/* return the configured interfaces list. */
757
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
758
	global $config;
759

    
760
	$iflist = array();
761

    
762
	/* if list */
763
	foreach($config['interfaces'] as $if => $ifdetail) {
764
		if ($only_opt && ($if == "wan" || $if == "lan"))
765
			continue;
766
		if (isset($ifdetail['enable']) || $withdisabled == true) {
767
			$tmpif = get_real_interface($if);
768
			if (!empty($tmpif))
769
				$iflist[$tmpif] = $if;
770
		}
771
	}
772

    
773
	return $iflist;
774
}
775

    
776
/* return the configured interfaces list with their description. */
777
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
778
	global $config;
779

    
780
	$iflist = array();
781

    
782
	/* if list */
783
	foreach($config['interfaces'] as $if => $ifdetail) {
784
		if ($only_opt && ($if == "wan" || $if == "lan"))
785
			continue;
786
		if (isset($ifdetail['enable']) || $withdisabled == true) {
787
			if(empty($ifdetail['descr']))
788
				$iflist[$if] = strtoupper($if);
789
			else
790
				$iflist[$if] = strtoupper($ifdetail['descr']);
791
		}
792
	}
793

    
794
	return $iflist;
795
}
796

    
797
/*
798
 *   get_configured_ip_addresses() - Return a list of all configured
799
 *   interfaces IP Addresses
800
 *
801
 */
802
function get_configured_ip_addresses() {
803
	require_once("interfaces.inc");
804
	$ip_array = array();
805
	$interfaces = get_configured_interface_list();
806
	if(is_array($interfaces)) {
807
		foreach($interfaces as $int) {
808
			$ipaddr = get_interface_ip($int);
809
			$ip_array[$int] = $ipaddr;
810
		}
811
	}
812
	$interfaces = get_configured_carp_interface_list();
813
	if(is_array($interfaces)) 
814
		foreach($interfaces as $int => $ipaddr) 
815
			$ip_array[$int] = $ipaddr;
816
	return $ip_array;
817
}
818

    
819
/*
820
 *   get_configured_ipv6_addresses() - Return a list of all configured
821
 *   interfaces IPv6 Addresses
822
 *
823
 */
824
function get_configured_ipv6_addresses() {
825
	require_once("interfaces.inc");
826
	$ipv6_array = array();
827
	$interfaces = get_configured_interface_list();
828
	if(is_array($interfaces)) {
829
		foreach($interfaces as $int) {
830
			$ipaddrv6 = get_interface_ipv6($int);
831
			$ipv6_array[$int] = $ipaddrv6;
832
		}
833
	}
834
	$interfaces = get_configured_carp_interface_list();
835
	if(is_array($interfaces)) 
836
		foreach($interfaces as $int => $ipaddrv6) 
837
			$ipv6_array[$int] = $ipaddrv6;
838
	return $ipv6_array;
839
}
840

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

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

    
969
/****f* util/log_auth
970
* NAME
971
*   log_auth   - Sends a string to syslog as LOG_AUTH facility
972
* INPUTS
973
*   $error     - string containing the syslog message.
974
* RESULT
975
*   null
976
******/
977
function log_auth($error) {
978
	global $g;
979
	$page = $_SERVER['SCRIPT_NAME'];
980
	syslog(LOG_AUTH, "$page: $error");
981
	if ($g['debug'])
982
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
983
	return;
984
}
985

    
986
/****f* util/exec_command
987
 * NAME
988
 *   exec_command - Execute a command and return a string of the result.
989
 * INPUTS
990
 *   $command   - String of the command to be executed.
991
 * RESULT
992
 *   String containing the command's result.
993
 * NOTES
994
 *   This function returns the command's stdout and stderr.
995
 ******/
996
function exec_command($command) {
997
	$output = array();
998
	exec($command . ' 2>&1 ', $output);
999
	return(implode("\n", $output));
1000
}
1001

    
1002
/* wrapper for exec() */
1003
function mwexec($command, $mute = false, $clearsigmask = false) {
1004
	global $g;
1005

    
1006
	if ($g['debug']) {
1007
		if (!$_SERVER['REMOTE_ADDR'])
1008
			echo "mwexec(): $command\n";
1009
	}
1010
	$oarr = array();
1011
	$retval = 0;
1012

    
1013
	if ($clearsigmask) {
1014
		$oldset = array();
1015
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1016
	}
1017
	$garbage = exec("$command 2>&1", $oarr, $retval);
1018
	if ($clearsigmask) {
1019
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1020
	}
1021

    
1022
	if(isset($config['system']['developerspew']))
1023
		$mute = false;
1024
	if(($retval <> 0) && ($mute === false)) {
1025
		$output = implode(" ", $oarr);
1026
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
1027
	}
1028
	return $retval;
1029
}
1030

    
1031
/* wrapper for exec() in background */
1032
function mwexec_bg($command, $clearsigmask = false) {
1033
	global $g;
1034

    
1035
	if ($g['debug']) {
1036
		if (!$_SERVER['REMOTE_ADDR'])
1037
			echo "mwexec(): $command\n";
1038
	}
1039

    
1040
	if ($clearsigmask) {
1041
		$oldset = array();
1042
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1043
	}
1044
	exec("nohup $command > /dev/null 2>&1 &");
1045
	if ($clearsigmask) {
1046
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1047
	}
1048
}
1049

    
1050
/* unlink a file, if it exists */
1051
function unlink_if_exists($fn) {
1052
	$to_do = glob($fn);
1053
	if(is_array($to_do)) {
1054
		foreach($to_do as $filename)
1055
			@unlink($filename);
1056
	} else {
1057
		@unlink($fn);
1058
	}
1059
}
1060
/* make a global alias table (for faster lookups) */
1061
function alias_make_table($config) {
1062
	global $aliastable;
1063

    
1064
	$aliastable = array();
1065

    
1066
	if (is_array($config['aliases']['alias'])) {
1067
		foreach ($config['aliases']['alias'] as $alias) {
1068
			if ($alias['name'])
1069
				$aliastable[$alias['name']] = $alias['address'];
1070
		}
1071
	}
1072
}
1073

    
1074
/* check if an alias exists */
1075
function is_alias($name) {
1076
	global $aliastable;
1077

    
1078
	return isset($aliastable[$name]);
1079
}
1080

    
1081
function alias_get_type($name) {
1082
        global $config;
1083
        
1084
	if (is_array($config['aliases']['alias'])) {
1085
		foreach ($config['aliases']['alias'] as $alias) {
1086
			if ($name == $alias['name'])
1087
				return $alias['type'];
1088
		}
1089
	}
1090

    
1091
        return "";
1092
}
1093

    
1094
/* expand a host or network alias, if necessary */
1095
function alias_expand($name) {
1096
	global $aliastable;
1097

    
1098
	if (isset($aliastable[$name]))
1099
		return "\${$name}";
1100
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1101
		return "{$name}";
1102
	else
1103
		return null;
1104
}
1105

    
1106
function alias_expand_urltable($name) {
1107
	global $config;
1108
	$urltable_prefix = "/var/db/aliastables/";
1109
	$urltable_filename = $urltable_prefix . $name . ".txt";
1110

    
1111
	if (is_array($config['aliases']['alias'])) {
1112
		foreach ($config['aliases']['alias'] as $alias) {
1113
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
1114
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1115
					return $urltable_filename;
1116
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1117
					return $urltable_filename;
1118
			}
1119
		}
1120
	}
1121
	return null;
1122
}
1123

    
1124
function subnet_size ($subnet) {
1125
	if (is_subnetv4($subnet)) {
1126
		list ($ip, $bits) = explode("/", $subnet);
1127
		return round(exp(log(2) * (32 - $bits)));
1128
	}
1129
	else if (is_subnetv6($subnet)) {
1130
		list ($ip, $bits) = explode("/", $subnet);
1131
		return round(exp(log(2) * (128 - $bits)));
1132
	}
1133
	else {
1134
		return 0;
1135
	}
1136
}
1137

    
1138
function subnet_expand ($subnet) {
1139
	if (is_subnetv4($subnet)) {
1140
		return subnetv4_expand($subnet);
1141
	} else if (is_subnetv6($subnet)) {
1142
		return subnetv6_expand($subnet);
1143
	} else {
1144
		return $subnet;
1145
	}
1146
}
1147

    
1148
function subnetv4_expand ($subnet) {
1149
	$result = array();
1150
	list ($ip, $bits) = explode("/", $subnet);
1151
	$net  = ip2long($ip);
1152
	$mask = (0xffffffff << (32 - $bits));
1153
	$net &= $mask;
1154
	$size = round(exp(log(2) * (32 - $bits)));
1155
	for ($i = 0; $i < $size; $i += 1) {
1156
		$result[] = long2ip($net | $i);
1157
	}
1158
	return $result;
1159
}
1160

    
1161
/* find out whether two subnets overlap */
1162
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1163

    
1164
	if (!is_numeric($bits1))
1165
		$bits1 = 32;
1166
	if (!is_numeric($bits2))
1167
		$bits2 = 32;
1168

    
1169
	if ($bits1 < $bits2)
1170
		$relbits = $bits1;
1171
	else
1172
		$relbits = $bits2;
1173

    
1174
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1175
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1176

    
1177
	return ($sn1 == $sn2);
1178
}
1179

    
1180
/* compare two IP addresses */
1181
function ipcmp($a, $b) {
1182
	if (ip_less_than($a, $b))
1183
		return -1;
1184
	else if (ip_greater_than($a, $b))
1185
		return 1;
1186
	else
1187
		return 0;
1188
}
1189

    
1190
/* return true if $addr is in $subnet, false if not */
1191
function ip_in_subnet($addr,$subnet) {
1192
	if(is_ipaddrv6($addr)) {
1193
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1194
		if($result)
1195
			return true;
1196
		else
1197
			return false;
1198
	}
1199
	list($ip, $mask) = explode('/', $subnet);
1200
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1201
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1202
}
1203

    
1204
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1205
function verify_digital_signature($fname) {
1206
	global $g;
1207

    
1208
	if(!file_exists("/usr/local/sbin/gzsig"))
1209
		return 4;
1210

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

    
1214
/* obtain MAC address given an IP address by looking at the ARP table */
1215
function arp_get_mac_by_ip($ip) {
1216
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1217
	$arpoutput = "";
1218
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1219

    
1220
	if ($arpoutput[0]) {
1221
		$arpi = explode(" ", $arpoutput[0]);
1222
		$macaddr = $arpi[3];
1223
		if (is_macaddr($macaddr))
1224
			return $macaddr;
1225
		else
1226
			return false;
1227
	}
1228

    
1229
	return false;
1230
}
1231

    
1232
/* return a fieldname that is safe for xml usage */
1233
function xml_safe_fieldname($fieldname) {
1234
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1235
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1236
			 ':', ',', '.', '\'', '\\'
1237
		);
1238
	return strtolower(str_replace($replace, "", $fieldname));
1239
}
1240

    
1241
function mac_format($clientmac) {
1242
    global $config, $cpzone;
1243

    
1244
    $mac = explode(":", $clientmac);
1245
    $mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1246

    
1247
    switch($mac_format) {
1248
        case 'singledash':
1249
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1250

    
1251
        case 'ietf':
1252
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1253

    
1254
        case 'cisco':
1255
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1256

    
1257
        case 'unformatted':
1258
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1259

    
1260
        default:
1261
		return $clientmac;
1262
    }
1263
}
1264

    
1265
function resolve_retry($hostname, $retries = 5) {
1266

    
1267
	if (is_ipaddr($hostname))
1268
		return $hostname;
1269

    
1270
       for ($i = 0; $i < $retries; $i++) {
1271
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1272
               $ip = gethostbyname($hostname);
1273

    
1274
		if ($ip && $ip != $hostname) {
1275
			/* success */
1276
			return $ip;
1277
		}
1278

    
1279
		sleep(1);
1280
	}
1281

    
1282
	return false;
1283
}
1284

    
1285
function format_bytes($bytes) {
1286
	if ($bytes >= 1073741824) {
1287
		return sprintf("%.2f GB", $bytes/1073741824);
1288
	} else if ($bytes >= 1048576) {
1289
		return sprintf("%.2f MB", $bytes/1048576);
1290
	} else if ($bytes >= 1024) {
1291
		return sprintf("%.0f KB", $bytes/1024);
1292
	} else {
1293
		return sprintf("%d bytes", $bytes);
1294
	}
1295
}
1296

    
1297
function update_filter_reload_status($text) {
1298
	global $g;
1299

    
1300
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1301
}
1302

    
1303
/****f* util/return_dir_as_array
1304
 * NAME
1305
 *   return_dir_as_array - Return a directory's contents as an array.
1306
 * INPUTS
1307
 *   $dir       - string containing the path to the desired directory.
1308
 * RESULT
1309
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1310
 ******/
1311
function return_dir_as_array($dir) {
1312
	$dir_array = array();
1313
	if (is_dir($dir)) {
1314
		if ($dh = opendir($dir)) {
1315
			while (($file = readdir($dh)) !== false) {
1316
				$canadd = 0;
1317
				if($file == ".") $canadd = 1;
1318
				if($file == "..") $canadd = 1;
1319
				if($canadd == 0)
1320
					array_push($dir_array, $file);
1321
			}
1322
			closedir($dh);
1323
		}
1324
	}
1325
	return $dir_array;
1326
}
1327

    
1328
function run_plugins($directory) {
1329
	global $config, $g;
1330

    
1331
	/* process packager manager custom rules */
1332
	$files = return_dir_as_array($directory);
1333
	if (is_array($files)) {
1334
		foreach ($files as $file) {
1335
			if (stristr($file, ".sh") == true)
1336
				mwexec($directory . $file . " start");
1337
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1338
				require_once($directory . "/" . $file);
1339
		}
1340
	}
1341
}
1342

    
1343
/*
1344
 *    safe_mkdir($path, $mode = 0755)
1345
 *    create directory if it doesn't already exist and isn't a file!
1346
 */
1347
function safe_mkdir($path, $mode=0755) {
1348
	global $g;
1349

    
1350
	if (!is_file($path) && !is_dir($path)) {
1351
		return @mkdir($path, $mode, true);
1352
	} else {
1353
		return false;
1354
	}
1355
}
1356

    
1357
/*
1358
 * make_dirs($path, $mode = 0755)
1359
 * create directory tree recursively (mkdir -p)
1360
 */
1361
function make_dirs($path, $mode = 0755) {
1362
	$base = '';
1363
	foreach (explode('/', $path) as $dir) {
1364
		$base .= "/$dir";
1365
		if (!is_dir($base)) {
1366
			if (!@mkdir($base, $mode))
1367
				return false;
1368
		}
1369
	}
1370
	return true;
1371
}
1372

    
1373
/*
1374
 * get_sysctl($names)
1375
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1376
 * name) and return an array of key/value pairs set for those that exist
1377
 */
1378
function get_sysctl($names) {
1379
	if (empty($names))
1380
		return array();
1381

    
1382
	if (is_array($names)) {
1383
		$name_list = array();
1384
		foreach ($names as $name) {
1385
			$name_list[] = escapeshellarg($name);
1386
		}
1387
	} else
1388
		$name_list = array(escapeshellarg($names));
1389

    
1390
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1391
	$values = array();
1392
	foreach ($output as $line) {
1393
		$line = explode(": ", $line, 2);
1394
		if (count($line) == 2)
1395
			$values[$line[0]] = $line[1];
1396
	}
1397

    
1398
	return $values;
1399
}
1400

    
1401
/*
1402
 * set_sysctl($value_list)
1403
 * Set sysctl OID's listed as key/value pairs and return
1404
 * an array with keys set for those that succeeded
1405
 */
1406
function set_sysctl($values) {
1407
	if (empty($values))
1408
		return array();
1409

    
1410
	$value_list = array();
1411
	foreach ($values as $key => $value) {
1412
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1413
	}
1414

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

    
1417
	/* Retry individually if failed (one or more read-only) */
1418
	if ($success <> 0 && count($value_list) > 1) {
1419
		foreach ($value_list as $value) {
1420
			exec("/sbin/sysctl -i " . $value, $output);
1421
		}
1422
	}
1423

    
1424
	$ret = array();
1425
	foreach ($output as $line) {
1426
		$line = explode(": ", $line, 2);
1427
		if (count($line) == 2)
1428
			$ret[$line[0]] = true;
1429
	}
1430

    
1431
	return $ret;
1432
}
1433

    
1434
/*
1435
 *     get_memory()
1436
 *     returns an array listing the amount of
1437
 *     memory installed in the hardware
1438
 *     [0]real and [1]available
1439
 */
1440
function get_memory() {
1441
	$matches = "";
1442
	if(file_exists("/var/log/dmesg.boot"))
1443
		$mem = `cat /var/log/dmesg.boot | grep memory`;
1444
	else
1445
		$mem = `dmesg -a | grep memory`;			
1446
	if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1447
		return array($matches[1][0], $matches[1][0]);
1448
	if(!$real && !$avail) {
1449
		$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1450
		$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1451
		/* convert from bytes to megabytes */
1452
		return array(($real/1048576),($avail/1048576));
1453
	}
1454
}
1455

    
1456
function mute_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
	if($config['system']['enableserial']) 
1466
		return;			
1467
	exec("/sbin/conscontrol mute on");
1468
}
1469

    
1470
function unmute_kernel_msgs() {
1471
	global $config;
1472
	// Do not mute serial console.  The kernel gets very very cranky
1473
	// and will start dishing you cannot control tty errors.
1474
	switch (trim(file_get_contents("/etc/platform"))) {
1475
		case "nanobsd":
1476
		case "jail":
1477
			return;
1478
	}
1479
	exec("/sbin/conscontrol mute off");
1480
}
1481

    
1482
function start_devd() {
1483
	global $g;
1484

    
1485
	if ($g['platform'] == 'jail')
1486
		return;
1487
	exec("/sbin/devd");
1488
	sleep(1);
1489
}
1490

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

    
1494
	if (is_array($config['vlans']['vlan'])) {
1495
		foreach ($config['vlans']['vlan'] as $vlan) {
1496
			if (does_interface_exist($vlan['if']) == false)
1497
				return true;
1498
		}
1499
	}
1500

    
1501
	return false;
1502
}
1503

    
1504
function is_interface_mismatch() {
1505
	global $config, $g;
1506

    
1507
	$do_assign = false;
1508
	$i = 0;
1509
	$missing_interfaces = array();
1510
	if (is_array($config['interfaces'])) {
1511
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1512
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1513
				// Do not check these interfaces.
1514
				$i++;
1515
				continue;
1516
			}
1517
			else if (does_interface_exist($ifcfg['if']) == false) {
1518
				$missing_interfaces[] = $ifcfg['if'];
1519
				$do_assign = true;
1520
			} else
1521
				$i++;
1522
		}
1523
	}
1524

    
1525
	if ($g['minimum_nic_count'] > $i) {
1526
		$do_assign = true;
1527
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1528
		$do_assign = false;
1529

    
1530
	if (!empty($missing_interfaces) && $do_assign)
1531
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1532
	else
1533
		@unlink("{$g['tmp_path']}/missing_interfaces");
1534

    
1535
	return $do_assign;
1536
}
1537

    
1538
/* sync carp entries to other firewalls */
1539
function carp_sync_client() {
1540
	global $g;
1541
	send_event("filter sync");
1542
}
1543

    
1544
/****f* util/isAjax
1545
 * NAME
1546
 *   isAjax - reports if the request is driven from prototype
1547
 * INPUTS
1548
 *   none
1549
 * RESULT
1550
 *   true/false
1551
 ******/
1552
function isAjax() {
1553
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1554
}
1555

    
1556
/****f* util/timeout
1557
 * NAME
1558
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1559
 * INPUTS
1560
 *   optional, seconds to wait before timeout. Default 9 seconds.
1561
 * RESULT
1562
 *   returns 1 char of user input or null if no input.
1563
 ******/
1564
function timeout($timer = 9) {
1565
	while(!isset($key)) {
1566
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1567
		else { echo chr(8). "{$timer}"; }
1568
		`/bin/stty -icanon min 0 time 25`;
1569
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1570
		`/bin/stty icanon`;
1571
		if ($key == '')
1572
			unset($key);
1573
		$timer--;
1574
		if ($timer == 0)
1575
			break;
1576
	}
1577
	return $key;	
1578
}
1579

    
1580
/****f* util/msort
1581
 * NAME
1582
 *   msort - sort array
1583
 * INPUTS
1584
 *   $array to be sorted, field to sort by, direction of sort
1585
 * RESULT
1586
 *   returns newly sorted array
1587
 ******/
1588
function msort($array, $id="id", $sort_ascending=true) {
1589
	$temp_array = array();
1590
	while(count($array)>0) {
1591
		$lowest_id = 0;
1592
		$index=0;
1593
		foreach ($array as $item) {
1594
			if (isset($item[$id])) {
1595
				if ($array[$lowest_id][$id]) {
1596
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1597
						$lowest_id = $index;
1598
					}
1599
				}
1600
			}
1601
			$index++;
1602
		}
1603
		$temp_array[] = $array[$lowest_id];
1604
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1605
	}
1606
	if ($sort_ascending) {
1607
		return $temp_array;
1608
	} else {
1609
    		return array_reverse($temp_array);
1610
	}
1611
}
1612

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

    
1686
/****f* util/is_URL
1687
 * NAME
1688
 *   is_URL
1689
 * INPUTS
1690
 *   string to check
1691
 * RESULT
1692
 *   Returns true if item is a URL
1693
 ******/
1694
function is_URL($url) {
1695
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1696
	if($match)
1697
		return true;	
1698
	return false;
1699
}
1700

    
1701
function is_file_included($file = "") {
1702
	$files = get_included_files();
1703
	if (in_array($file, $files))
1704
		return true;
1705
	
1706
	return false;
1707
}
1708

    
1709
/*
1710
	This function was borrowed from a comment on PHP.net at the following URL:
1711
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1712
 */
1713
function array_merge_recursive_unique($array0, $array1) {
1714

    
1715
	$arrays = func_get_args();
1716
	$remains = $arrays;
1717

    
1718
	// We walk through each arrays and put value in the results (without
1719
	// considering previous value).
1720
	$result = array();
1721

    
1722
	// loop available array
1723
	foreach($arrays as $array) {
1724

    
1725
		// The first remaining array is $array. We are processing it. So
1726
		// we remove it from remaing arrays.
1727
        array_shift($remains);
1728

    
1729
		// We don't care non array param, like array_merge since PHP 5.0.
1730
		if(is_array($array)) {
1731
			// Loop values
1732
			foreach($array as $key => $value) {
1733
				if(is_array($value)) {
1734
					// we gather all remaining arrays that have such key available
1735
					$args = array();
1736
					foreach($remains as $remain) {
1737
						if(array_key_exists($key, $remain)) {
1738
							array_push($args, $remain[$key]);
1739
						}
1740
					}
1741

    
1742
					if(count($args) > 2) {
1743
						// put the recursion
1744
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1745
					} else {
1746
						foreach($value as $vkey => $vval) {
1747
							$result[$key][$vkey] = $vval;
1748
						}
1749
					}
1750
				} else {
1751
					// simply put the value
1752
					$result[$key] = $value;
1753
				}
1754
			}
1755
		}
1756
	}
1757
	return $result;
1758
}
1759

    
1760

    
1761
/*
1762
 * converts a string like "a,b,c,d"
1763
 * into an array like array("a" => "b", "c" => "d")
1764
 */
1765
function explode_assoc($delimiter, $string) {
1766
	$array = explode($delimiter, $string);
1767
	$result = array();
1768
	$numkeys = floor(count($array) / 2);
1769
	for ($i = 0; $i < $numkeys; $i += 1) {
1770
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1771
	}
1772
	return $result;
1773
}
1774

    
1775
function get_staticroutes($returnsubnetsonly = false) {
1776
	global $config;
1777
	require_once('filter.inc');
1778
	$allstaticroutes = array();
1779
	$allsubnets = array();
1780

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

    
1785
	/* Loop through routes and expand aliases as we find them. */
1786
	foreach ($config['staticroutes']['route'] as $route) {
1787
		if (is_alias($route['network'])) {
1788
			$subnets = filter_expand_alias_array($route['network']);
1789
			foreach ($subnets as $net) {
1790
				if (is_ipaddrv4($net))
1791
					$net .= "/32";
1792
				if (is_ipaddrv6($net) && !is_subnetv6($net))
1793
					$net .= "/128";
1794
				/* This must be a hostname, we can't use it. */
1795
				if (!is_subnet($net))
1796
					continue;
1797
				$temproute = $route;
1798
				$temproute['network'] = $net;
1799
				$allstaticroutes[] = $temproute;
1800
				$allsubnets[] = $net;
1801
			}
1802
		} elseif (is_subnet($route['network'])) {
1803
			$allstaticroutes[] = $route;
1804
			$allsubnets[] = $route['network'];
1805
		}
1806
	}
1807
	if ($returnsubnetsonly) {
1808
		return $allsubnets;
1809
	} else {
1810
		return $allstaticroutes;
1811
	}
1812
}
1813

    
1814
/****f* util/get_alias_list
1815
 * NAME
1816
 *   get_alias_list - Provide a list of aliases.
1817
 * INPUTS
1818
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
1819
 * RESULT
1820
 *   Array containing list of aliases.
1821
 *   If $type is unspecified, all aliases are returned.
1822
 *   If $type is a string, all aliases of the type specified in $type are returned.
1823
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
1824
 */
1825
function get_alias_list($type = null) {
1826
	global $config;
1827
	$result = array();
1828
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
1829
		foreach ($config['aliases']['alias'] as $alias) {
1830
			if ($type === null) {
1831
				$result[] = $alias['name'];
1832
			}
1833
			else if (is_array($type)) {
1834
				if (in_array($alias['type'], $type)) {
1835
					$result[] = $alias['name'];
1836
				}
1837
			}
1838
			else if ($type === $alias['type']) {
1839
				$result[] = $alias['name'];
1840
			}
1841
		}
1842
	}		
1843
	return $result;
1844
}
1845

    
1846
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
1847
function array_exclude($needle, $haystack) {
1848
	$result = array();
1849
	if (is_array($haystack)) {
1850
		foreach ($haystack as $thing) {
1851
			if ($needle !== $thing) {
1852
				$result[] = $thing;
1853
			}
1854
		}
1855
	}
1856
	return $result;
1857
}
1858

    
1859
function setup_library_paths() {
1860
	$current_library_paths = explode(":", exec("/sbin/ldconfig -r | /usr/bin/grep 'search directories' | /usr/bin/awk '{print $3;}'"));
1861
	$pbi_library_paths = array_merge(glob("/usr/pbi/*/lib", GLOB_ONLYDIR), glob("/usr/pbi/*/lib/*", GLOB_ONLYDIR));
1862
	foreach ($pbi_library_paths as $pbilib) {
1863
		if (!in_array($pbilib, $current_library_paths))
1864
			exec("/sbin/ldconfig -m {$pbilib}");
1865
	}
1866
}
1867

    
1868
function get_current_theme() {
1869
	global $config, $g;
1870
	/*
1871
	 *   if user has selected a custom template, use it.
1872
	 *   otherwise default to pfsense tempalte
1873
	 */
1874
	if (($g["disablethemeselection"] === true) && !empty($g["default_theme"]) && (is_dir($g["www_path"].'/themes/'.$g["default_theme"])))
1875
		$theme = $g["default_theme"];
1876
	elseif($config['theme'] <> "" && (is_dir($g["www_path"].'/themes/'.$config['theme'])))
1877
		$theme = $config['theme'];
1878
	else
1879
		$theme = "pfsense";
1880
	/*
1881
	 *  If this device is an apple ipod/iphone
1882
	 *  switch the theme to one that works with it.
1883
	 */
1884
	$lowres_ua = array("iPhone", "iPod", "iPad", "Android", "BlackBerry", "Opera Mini", "Opera Mobi", "PlayBook");
1885
	foreach($lowres_ua as $useragent)
1886
		if(strstr($_SERVER['HTTP_USER_AGENT'], $useragent))
1887
			$theme = (empty($g['theme_lowres']) && (is_dir($g["www_path"].'/themes/'.$g['theme_lowres']))) ? "pfsense" : $g['theme_lowres'];
1888
	return $theme;
1889
}
1890

    
1891
?>
(55-55/67)