Project

General

Profile

Download (50.1 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($pidfile) {
45
	$output = "";
46
	if (file_exists($pidfile)) {
47
		exec("/bin/pgrep -nF {$pidfile}", $output, $retval);
48
		return (intval($retval) == 0);
49
	}
50
	return false;
51
}
52

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

    
57
	return (intval($retval) == 0);
58
}
59

    
60
function isvalidproc($proc) {
61
	return is_process_running($proc);
62
}
63

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

    
70
	return 0;
71
}
72

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

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

    
85
function is_subsystem_dirty($subsystem = "") {
86
	global $g;
87

    
88
	if ($subsystem == "")
89
		return false;
90

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

    
94
	return false;
95
}
96

    
97
function mark_subsystem_dirty($subsystem = "") {
98
	global $g;
99

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

    
104
function clear_subsystem_dirty($subsystem = "") {
105
	global $g;
106

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

    
110
function config_lock() {
111
	return;
112
}
113
function config_unlock() {
114
	return;
115
}
116

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

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

    
143
function send_event($cmd) {
144
	global $g;
145

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

    
165
function send_multiple_events($cmds) {
166
	global $g;
167

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

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

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

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

    
222
	return $shm_data;
223
}
224

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

    
250
	return $shm_data;
251
}
252

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

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

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

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

    
286
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
287
	$address = Net_IPv6::compress($address);
288
	return $address;
289
}
290

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

    
296
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
297
}
298

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

    
309
	$inet_end = $inet_ip | ~$inet_mask;
310

    
311
	return (inet_ntop($inet_end));
312
}
313

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

    
324
/* same as above but returns a string */
325
function gen_subnet_mask($bits) {
326
	return long2ip(gen_subnet_mask_long($bits));
327
}
328

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

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

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

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

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

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

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

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

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

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

    
397
	// Container for subnets within this range.
398
	$rangesubnets = array();
399

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

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

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

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

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

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

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

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

    
442
	// Add in the subnet we found before, to preserve ordering
443
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
444

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

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

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

    
464

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

    
476
/* returns true if $ipaddr is a valid IPv6 address */
477
function is_ipaddrv6($ipaddr) {
478
	if (!is_string($ipaddr) || empty($ipaddr))
479
		return false;
480
	return Net_IPv6::checkIPv6($ipaddr);
481
}
482

    
483
/* returns true if $ipaddr is a valid dotted IPv4 address */
484
function is_ipaddrv4($ipaddr) {
485
	if (!is_string($ipaddr) || empty($ipaddr))
486
		return false;
487

    
488
	$ip_long = ip2long($ipaddr);
489
	$ip_reverse = long2ip32($ip_long);
490

    
491
	if ($ipaddr == $ip_reverse)
492
		return true;
493
	else
494
		return false;
495
}
496

    
497
/* returns true if $ipaddr is a valid linklocal address */
498
function is_linklocal($ipaddr) {
499
	return preg_match('/^fe80:/i', $ipaddr);
500
}
501

    
502
/* returns true if $ipaddr is a valid literal IPv6 address */
503
function is_literalipaddrv6($ipaddr) {
504
	if(preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match))
505
		$ipaddr = $match[1];
506
	else
507
		return false;
508

    
509
	return is_ipaddrv6($ipaddr);
510
}
511

    
512
function is_ipaddrwithport($ipport) {
513
	$parts = explode(":", $ipport);
514
	$port = array_pop($parts);
515
	if (count($parts) == 1) {
516
		return is_ipaddrv4($parts[0]) && is_port($port);
517
	} elseif (count($parts) > 1) {
518
		return is_literalipaddrv6(implode(":", $parts)) && is_port($port);
519
	} else {
520
		return false;
521
	}
522
}
523

    
524
function is_hostnamewithport($hostport) {
525
	$parts = explode(":", $hostport);
526
	$port = array_pop($parts);
527
	if (count($parts) == 1) {
528
		return is_hostname($parts[0]) && is_port($port);
529
	} else {
530
		return false;
531
	}
532
}
533

    
534
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
535
function is_ipaddroralias($ipaddr) {
536
	global $config;
537

    
538
	if (is_alias($ipaddr)) {
539
		if (is_array($config['aliases']['alias'])) {
540
			foreach ($config['aliases']['alias'] as $alias) {
541
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
542
					return true;
543
			}
544
		}
545
		return false;
546
	} else
547
		return is_ipaddr($ipaddr);
548

    
549
}
550

    
551
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format */
552
function is_subnet($subnet) {
553
	if(is_subnetv4($subnet)) {
554
		return true;
555
	}
556
	if(is_subnetv6($subnet)) {
557
		return true;
558
	}
559
	return false;
560
}
561

    
562
/* returns true if $subnet is a valid IPv4 subnet in CIDR format */
563
function is_subnetv4($subnet) {
564
	if (!is_string($subnet))
565
		return false;
566

    
567
	list($hp,$np) = explode('/', $subnet);
568

    
569
	if (!is_ipaddrv4($hp))
570
		return false;
571

    
572
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
573
		return false;
574

    
575
	return true;
576
}
577

    
578
/* returns true if $subnet is a valid IPv6 subnet in CIDR format */
579
function is_subnetv6($subnet) {
580
	if (!is_string($subnet))
581
		return false;
582

    
583
	list($hp,$np) = explode('/', $subnet);
584

    
585
	if (!is_ipaddrv6($hp))
586
		return false;
587

    
588
	if (!is_numeric($np) || ($np < 1) || ($np > 128))
589
		return false;
590

    
591
	return true;
592
}
593

    
594

    
595
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
596
function is_subnetoralias($subnet) {
597
	global $aliastable;
598

    
599
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
600
		return true;
601
	else
602
		return is_subnet($subnet);
603
}
604

    
605
/* returns true if $hostname is a valid hostname */
606
function is_hostname($hostname) {
607
	if (!is_string($hostname))
608
		return false;
609

    
610
	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))
611
		return true;
612
	else
613
		return false;
614
}
615

    
616
/* returns true if $domain is a valid domain name */
617
function is_domain($domain) {
618
	if (!is_string($domain))
619
		return false;
620

    
621
	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))
622
		return true;
623
	else
624
		return false;
625
}
626

    
627
/* returns true if $macaddr is a valid MAC address */
628
function is_macaddr($macaddr, $partial=false) {
629
	$repeat = ($partial) ? '1,5' : '5';
630
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
631
}
632

    
633
/* returns true if $name is a valid name for an alias */
634
/* returns NULL if a reserved word is used */
635
function is_validaliasname($name) {
636
	/* Array of reserved words */
637
	$reserved = array("port", "pass");
638
	if (in_array($name, $reserved, true))
639
		return; /* return NULL */
640
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
641
		return true;
642
	else
643
		return false;
644
}
645

    
646
/* returns true if $port is a valid TCP/UDP port */
647
function is_port($port) {
648
	$tmpports = explode(":", $port);
649
	foreach($tmpports as $tmpport) {
650
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
651
			continue;
652
		if (!ctype_digit($tmpport))
653
			return false;
654
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
655
			return false;
656
	}
657
	return true;
658
}
659

    
660
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
661
function is_portrange($portrange) {
662
	$ports = explode(":", $portrange);
663

    
664
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
665
}
666

    
667
/* returns true if $port is a valid port number or an alias thereof */
668
function is_portoralias($port) {
669
	global $config;
670

    
671
	if (is_alias($port)) {
672
		if (is_array($config['aliases']['alias'])) {
673
			foreach ($config['aliases']['alias'] as $alias) {
674
				if ($alias['name'] == $port && $alias['type'] == "port")
675
					return true;
676
				}
677
			}
678
			return false;
679
	} else
680
		return is_port($port);
681
}
682

    
683
/* returns true if $val is a valid shaper bandwidth value */
684
function is_valid_shaperbw($val) {
685
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
686
}
687

    
688
/* returns true if $test is in the range between $start and $end */
689
function is_inrange_v4($test, $start, $end) {
690
	if ( (ip2ulong($test) <= ip2ulong($end)) && (ip2ulong($test) >= ip2ulong($start)) )
691
		return true;
692
	else
693
		return false;
694
}
695

    
696
/* returns true if $test is in the range between $start and $end */
697
function is_inrange_v6($test, $start, $end) {
698
	if ( (inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start)) )
699
		return true;
700
	else
701
		return false;
702
}
703

    
704
/* return the configured carp interface list */
705
function get_configured_carp_interface_list() {
706
	global $config;
707

    
708
	$iflist = array();
709

    
710
	if(is_array($config['virtualip']['vip'])) {
711
		$viparr = &$config['virtualip']['vip'];
712
		foreach ($viparr as $vip) {
713
			switch ($vip['mode']) {
714
			case "carp":
715
				$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
716
				$iflist[$vipif] = $vip['subnet'];
717
				break;
718
			}
719
		}
720
	}
721

    
722
	return $iflist;
723
}
724

    
725
/* return the configured IP aliases list */
726
function get_configured_ip_aliases_list($returnfullentry = false) {
727
	global $config;
728

    
729
	$alias_list=array();
730

    
731
	if(is_array($config['virtualip']['vip'])) {
732
		$viparr = &$config['virtualip']['vip'];
733
		foreach ($viparr as $vip) {
734
			if ($vip['mode']=="ipalias") {
735
				if ($returnfullentry)
736
					$alias_list[$vip['subnet']] = $vip;
737
				else
738
					$alias_list[$vip['subnet']] = $vip['interface'];
739
			}
740
		}
741
	}
742

    
743
	return $alias_list;
744
}
745

    
746
/* return all configured aliases list (IP, carp, proxyarp and other) */
747
function get_configured_vips_list() {
748
	global $config;
749

    
750
	$alias_list=array();
751

    
752
	if(is_array($config['virtualip']['vip'])) {
753
		$viparr = &$config['virtualip']['vip'];
754
		foreach ($viparr as $vip)
755
			$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
756
	}
757

    
758
	return $alias_list;
759
}
760

    
761
/* comparison function for sorting by the order in which interfaces are normally created */
762
function compare_interface_friendly_names($a, $b) {
763
	if ($a == $b)
764
		return 0;
765
	else if ($a == 'wan')
766
		return -1;
767
	else if ($b == 'wan')
768
		return 1;
769
	else if ($a == 'lan')
770
		return -1;
771
	else if ($b == 'lan')
772
		return 1;
773

    
774
	return strnatcmp($a, $b);
775
}
776

    
777
/* return the configured interfaces list. */
778
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
779
	global $config;
780

    
781
	$iflist = array();
782

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

    
791
	return $iflist;
792
}
793

    
794
/* return the configured interfaces list. */
795
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
796
	global $config;
797

    
798
	$iflist = array();
799

    
800
	/* if list */
801
	foreach($config['interfaces'] as $if => $ifdetail) {
802
		if ($only_opt && ($if == "wan" || $if == "lan"))
803
			continue;
804
		if (isset($ifdetail['enable']) || $withdisabled == true) {
805
			$tmpif = get_real_interface($if);
806
			if (!empty($tmpif))
807
				$iflist[$tmpif] = $if;
808
		}
809
	}
810

    
811
	return $iflist;
812
}
813

    
814
/* return the configured interfaces list with their description. */
815
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
816
	global $config;
817

    
818
	$iflist = array();
819

    
820
	/* if list */
821
	foreach($config['interfaces'] as $if => $ifdetail) {
822
		if ($only_opt && ($if == "wan" || $if == "lan"))
823
			continue;
824
		if (isset($ifdetail['enable']) || $withdisabled == true) {
825
			if(empty($ifdetail['descr']))
826
				$iflist[$if] = strtoupper($if);
827
			else
828
				$iflist[$if] = strtoupper($ifdetail['descr']);
829
		}
830
	}
831

    
832
	return $iflist;
833
}
834

    
835
/*
836
 *   get_configured_ip_addresses() - Return a list of all configured
837
 *   interfaces IP Addresses
838
 *
839
 */
840
function get_configured_ip_addresses() {
841
	global $config;
842

    
843
	if (!function_exists('get_interface_ip'))
844
		require_once("interfaces.inc");
845
	$ip_array = array();
846
	$interfaces = get_configured_interface_list();
847
	if (is_array($interfaces)) {
848
		foreach($interfaces as $int) {
849
			$ipaddr = get_interface_ip($int);
850
			$ip_array[$int] = $ipaddr;
851
		}
852
	}
853
	$interfaces = get_configured_carp_interface_list();
854
	if (is_array($interfaces)) 
855
		foreach($interfaces as $int => $ipaddr) 
856
			$ip_array[$int] = $ipaddr;
857

    
858
	/* pppoe server */
859
	if (is_array($config['pppoes']) && is_array($config['pppoes']['pppoe'])) {
860
		foreach($config['pppoes']['pppoe'] as $pppoe) {
861
			if ($pppoe['mode'] == "server") {
862
				if(is_ipaddr($pppoe['localip'])) {
863
					$int = "pppoes". $pppoe['pppoeid'];
864
					$ip_array[$int] = $pppoe['localip'];
865
				}
866
			}
867
		}
868
	}
869

    
870
	return $ip_array;
871
}
872

    
873
/*
874
 *   get_configured_ipv6_addresses() - Return a list of all configured
875
 *   interfaces IPv6 Addresses
876
 *
877
 */
878
function get_configured_ipv6_addresses() {
879
	require_once("interfaces.inc");
880
	$ipv6_array = array();
881
	$interfaces = get_configured_interface_list();
882
	if(is_array($interfaces)) {
883
		foreach($interfaces as $int) {
884
			$ipaddrv6 = get_interface_ipv6($int);
885
			$ipv6_array[$int] = $ipaddrv6;
886
		}
887
	}
888
	$interfaces = get_configured_carp_interface_list();
889
	if(is_array($interfaces)) 
890
		foreach($interfaces as $int => $ipaddrv6) 
891
			$ipv6_array[$int] = $ipaddrv6;
892
	return $ipv6_array;
893
}
894

    
895
/*
896
 *   get_interface_list() - Return a list of all physical interfaces
897
 *   along with MAC and status.
898
 *
899
 *   $mode = "active" - use ifconfig -lu
900
 *           "media"  - use ifconfig to check physical connection
901
 *			status (much slower)
902
 */
903
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
904
        global $config;
905
	$upints = array();
906
        /* get a list of virtual interface types */
907
        if(!$vfaces) {
908
		$vfaces = array (
909
				'bridge',
910
				'ppp',
911
				'pppoe',
912
				'pptp',
913
				'l2tp',
914
				'sl',
915
				'gif',
916
				'gre',
917
				'faith',
918
				'lo',
919
				'ng',
920
				'_vlan',
921
				'_wlan',
922
				'pflog',
923
				'plip',
924
				'pfsync',
925
				'enc',
926
				'tun',
927
				'carp',
928
				'lagg',
929
				'vip',
930
				'ipfw'
931
		);
932
	}
933
	switch($mode) {
934
	case "active":
935
                $upints = pfSense_interface_listget(IFF_UP);
936
        	break;
937
	case "media":
938
		$intlist = pfSense_interface_listget();
939
                $ifconfig = "";
940
                exec("/sbin/ifconfig -a", $ifconfig);
941
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
942
                $ifstatus = preg_grep('/status:/', $ifconfig);
943
		foreach($ifstatus as $status) {
944
			$int = array_shift($intlist);
945
			if(stristr($status, "active")) $upints[] = $int;
946
		}
947
		break;
948
	default:
949
		$upints = pfSense_interface_listget();
950
		break;
951
	}
952
        /* build interface list with netstat */
953
        $linkinfo = "";
954
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
955
        array_shift($linkinfo);
956
	/* build ip address list with netstat */
957
	$ipinfo = "";
958
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
959
	array_shift($ipinfo);
960
	foreach($linkinfo as $link) {
961
		$friendly = "";
962
		$alink = explode(" ", $link);
963
		$ifname = rtrim(trim($alink[0]), '*');
964
		/* trim out all numbers before checking for vfaces */
965
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
966
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
967
			$toput = array(
968
					"mac" => trim($alink[1]),
969
					"up" => in_array($ifname, $upints)
970
				);
971
			foreach($ipinfo as $ip) {
972
				$aip = explode(" ", $ip);
973
				if($aip[0] == $ifname) {
974
					$toput['ipaddr'] = $aip[1];
975
				}
976
			}
977
			if (is_array($config['interfaces'])) {
978
				foreach($config['interfaces'] as $name => $int)
979
					if($int['if'] == $ifname) $friendly = $name;
980
			}
981
			switch($keyby) {
982
			case "physical":
983
				if($friendly != "") {
984
					$toput['friendly'] = $friendly;
985
				}
986
				$dmesg_arr = array();
987
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
988
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
989
				$toput['dmesg'] = $dmesg[1][0];
990
				$iflist[$ifname] = $toput;
991
				break;
992
			case "ppp":
993
				
994
			case "friendly":
995
				if($friendly != "") {
996
					$toput['if'] = $ifname;
997
					$iflist[$friendly] = $toput;
998
				}
999
				break;
1000
			}
1001
		}
1002
	}
1003
	return $iflist;
1004
}
1005

    
1006
/****f* util/log_error
1007
* NAME
1008
*   log_error  - Sends a string to syslog.
1009
* INPUTS
1010
*   $error     - string containing the syslog message.
1011
* RESULT
1012
*   null
1013
******/
1014
function log_error($error) {
1015
	global $g;
1016
	$page = $_SERVER['SCRIPT_NAME'];
1017
	if (empty($page)) {
1018
		$files = get_included_files();
1019
		$page = basename($files[0]);
1020
	}
1021
	syslog(LOG_ERR, "$page: $error");
1022
	if ($g['debug'])
1023
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1024
	return;
1025
}
1026

    
1027
/****f* util/log_auth
1028
* NAME
1029
*   log_auth   - Sends a string to syslog as LOG_AUTH facility
1030
* INPUTS
1031
*   $error     - string containing the syslog message.
1032
* RESULT
1033
*   null
1034
******/
1035
function log_auth($error) {
1036
	global $g;
1037
	$page = $_SERVER['SCRIPT_NAME'];
1038
	syslog(LOG_AUTH, "$page: $error");
1039
	if ($g['debug'])
1040
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1041
	return;
1042
}
1043

    
1044
/****f* util/exec_command
1045
 * NAME
1046
 *   exec_command - Execute a command and return a string of the result.
1047
 * INPUTS
1048
 *   $command   - String of the command to be executed.
1049
 * RESULT
1050
 *   String containing the command's result.
1051
 * NOTES
1052
 *   This function returns the command's stdout and stderr.
1053
 ******/
1054
function exec_command($command) {
1055
	$output = array();
1056
	exec($command . ' 2>&1 ', $output);
1057
	return(implode("\n", $output));
1058
}
1059

    
1060
/* wrapper for exec() */
1061
function mwexec($command, $mute = false, $clearsigmask = false) {
1062
	global $g;
1063

    
1064
	if ($g['debug']) {
1065
		if (!$_SERVER['REMOTE_ADDR'])
1066
			echo "mwexec(): $command\n";
1067
	}
1068
	$oarr = array();
1069
	$retval = 0;
1070

    
1071
	if ($clearsigmask) {
1072
		$oldset = array();
1073
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1074
	}
1075
	$garbage = exec("$command 2>&1", $oarr, $retval);
1076
	if ($clearsigmask) {
1077
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1078
	}
1079

    
1080
	if(isset($config['system']['developerspew']))
1081
		$mute = false;
1082
	if(($retval <> 0) && ($mute === false)) {
1083
		$output = implode(" ", $oarr);
1084
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
1085
	}
1086
	return $retval;
1087
}
1088

    
1089
/* wrapper for exec() in background */
1090
function mwexec_bg($command, $clearsigmask = false) {
1091
	global $g;
1092

    
1093
	if ($g['debug']) {
1094
		if (!$_SERVER['REMOTE_ADDR'])
1095
			echo "mwexec(): $command\n";
1096
	}
1097

    
1098
	if ($clearsigmask) {
1099
		$oldset = array();
1100
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1101
	}
1102
	$_gb = exec("/usr/bin/nohup $command > /dev/null 2>&1 &");
1103
	if ($clearsigmask) {
1104
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1105
	}
1106
	unset($_gb);
1107
}
1108

    
1109
/* unlink a file, if it exists */
1110
function unlink_if_exists($fn) {
1111
	$to_do = glob($fn);
1112
	if(is_array($to_do)) {
1113
		foreach($to_do as $filename)
1114
			@unlink($filename);
1115
	} else {
1116
		@unlink($fn);
1117
	}
1118
}
1119
/* make a global alias table (for faster lookups) */
1120
function alias_make_table($config) {
1121
	global $aliastable;
1122

    
1123
	$aliastable = array();
1124

    
1125
	if (is_array($config['aliases']['alias'])) {
1126
		foreach ($config['aliases']['alias'] as $alias) {
1127
			if ($alias['name'])
1128
				$aliastable[$alias['name']] = $alias['address'];
1129
		}
1130
	}
1131
}
1132

    
1133
/* check if an alias exists */
1134
function is_alias($name) {
1135
	global $aliastable;
1136

    
1137
	return isset($aliastable[$name]);
1138
}
1139

    
1140
function alias_get_type($name) {
1141
        global $config;
1142
        
1143
	if (is_array($config['aliases']['alias'])) {
1144
		foreach ($config['aliases']['alias'] as $alias) {
1145
			if ($name == $alias['name'])
1146
				return $alias['type'];
1147
		}
1148
	}
1149

    
1150
        return "";
1151
}
1152

    
1153
/* expand a host or network alias, if necessary */
1154
function alias_expand($name) {
1155
	global $aliastable;
1156

    
1157
	if (isset($aliastable[$name]))
1158
		return "\${$name}";
1159
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1160
		return "{$name}";
1161
	else
1162
		return null;
1163
}
1164

    
1165
function alias_expand_urltable($name) {
1166
	global $config;
1167
	$urltable_prefix = "/var/db/aliastables/";
1168
	$urltable_filename = $urltable_prefix . $name . ".txt";
1169

    
1170
	if (is_array($config['aliases']['alias'])) {
1171
		foreach ($config['aliases']['alias'] as $alias) {
1172
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
1173
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1174
					return $urltable_filename;
1175
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1176
					return $urltable_filename;
1177
			}
1178
		}
1179
	}
1180
	return null;
1181
}
1182

    
1183
function subnet_size($subnet) {
1184
	if (is_subnetv4($subnet)) {
1185
		list ($ip, $bits) = explode("/", $subnet);
1186
		return round(exp(log(2) * (32 - $bits)));
1187
	}
1188
	else if (is_subnetv6($subnet)) {
1189
		list ($ip, $bits) = explode("/", $subnet);
1190
		return round(exp(log(2) * (128 - $bits)));
1191
	}
1192
	else {
1193
		return 0;
1194
	}
1195
}
1196

    
1197
function subnet_expand($subnet) {
1198
	if (is_subnetv4($subnet)) {
1199
		return subnetv4_expand($subnet);
1200
	} else if (is_subnetv6($subnet)) {
1201
		return subnetv6_expand($subnet);
1202
	} else {
1203
		return $subnet;
1204
	}
1205
}
1206

    
1207
function subnetv4_expand($subnet) {
1208
	$result = array();
1209
	list ($ip, $bits) = explode("/", $subnet);
1210
	$net  = ip2long($ip);
1211
	$mask = (0xffffffff << (32 - $bits));
1212
	$net &= $mask;
1213
	$size = round(exp(log(2) * (32 - $bits)));
1214
	for ($i = 0; $i < $size; $i += 1) {
1215
		$result[] = long2ip($net | $i);
1216
	}
1217
	return $result;
1218
}
1219

    
1220
/* find out whether two subnets overlap */
1221
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1222

    
1223
	if (!is_numeric($bits1))
1224
		$bits1 = 32;
1225
	if (!is_numeric($bits2))
1226
		$bits2 = 32;
1227

    
1228
	if ($bits1 < $bits2)
1229
		$relbits = $bits1;
1230
	else
1231
		$relbits = $bits2;
1232

    
1233
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1234
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1235

    
1236
	return ($sn1 == $sn2);
1237
}
1238

    
1239
/* find out whether two IPv6 subnets overlap */
1240
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
1241
	$sub1_min = gen_subnetv6($subnet1, $bits1);
1242
	$sub1_max = gen_subnetv6_max($subnet1, $bits1);
1243
	$sub2_min = gen_subnetv6($subnet2, $bits2);
1244
	$sub2_max = gen_subnetv6_max($subnet2, $bits2);
1245
	
1246
	return (is_inrange_v6($sub1_min, $sub2_min, $sub2_max) || is_inrange_v6($sub1_max, $sub2_min, $sub2_max) || is_inrange_v6($sub2_min, $sub1_min, $sub1_max));
1247
}
1248

    
1249
/* compare two IP addresses */
1250
function ipcmp($a, $b) {
1251
	if (ip_less_than($a, $b))
1252
		return -1;
1253
	else if (ip_greater_than($a, $b))
1254
		return 1;
1255
	else
1256
		return 0;
1257
}
1258

    
1259
/* return true if $addr is in $subnet, false if not */
1260
function ip_in_subnet($addr,$subnet) {
1261
	if(is_ipaddrv6($addr)) {
1262
		return (Net_IPv6::isInNetmask($addr, $subnet));
1263
	} else { /* XXX: Maybe check for IPv4 */
1264
		list($ip, $mask) = explode('/', $subnet);
1265
		$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1266
		return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1267
	}
1268
}
1269

    
1270
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1271
function verify_digital_signature($fname) {
1272
	global $g;
1273

    
1274
	if(!file_exists("/usr/local/sbin/gzsig"))
1275
		return 4;
1276

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

    
1280
/* obtain MAC address given an IP address by looking at the ARP table */
1281
function arp_get_mac_by_ip($ip) {
1282
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1283
	$arpoutput = "";
1284
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1285

    
1286
	if ($arpoutput[0]) {
1287
		$arpi = explode(" ", $arpoutput[0]);
1288
		$macaddr = $arpi[3];
1289
		if (is_macaddr($macaddr))
1290
			return $macaddr;
1291
		else
1292
			return false;
1293
	}
1294

    
1295
	return false;
1296
}
1297

    
1298
/* return a fieldname that is safe for xml usage */
1299
function xml_safe_fieldname($fieldname) {
1300
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1301
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1302
			 ':', ',', '.', '\'', '\\'
1303
		);
1304
	return strtolower(str_replace($replace, "", $fieldname));
1305
}
1306

    
1307
function mac_format($clientmac) {
1308
    global $config, $cpzone;
1309

    
1310
    $mac = explode(":", $clientmac);
1311
    $mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1312

    
1313
    switch($mac_format) {
1314
        case 'singledash':
1315
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1316

    
1317
        case 'ietf':
1318
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1319

    
1320
        case 'cisco':
1321
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1322

    
1323
        case 'unformatted':
1324
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1325

    
1326
        default:
1327
		return $clientmac;
1328
    }
1329
}
1330

    
1331
function resolve_retry($hostname, $retries = 5) {
1332

    
1333
	if (is_ipaddr($hostname))
1334
		return $hostname;
1335

    
1336
       for ($i = 0; $i < $retries; $i++) {
1337
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1338
               $ip = gethostbyname($hostname);
1339

    
1340
		if ($ip && $ip != $hostname) {
1341
			/* success */
1342
			return $ip;
1343
		}
1344

    
1345
		sleep(1);
1346
	}
1347

    
1348
	return false;
1349
}
1350

    
1351
function format_bytes($bytes) {
1352
	if ($bytes >= 1073741824) {
1353
		return sprintf("%.2f GB", $bytes/1073741824);
1354
	} else if ($bytes >= 1048576) {
1355
		return sprintf("%.2f MB", $bytes/1048576);
1356
	} else if ($bytes >= 1024) {
1357
		return sprintf("%.0f KB", $bytes/1024);
1358
	} else {
1359
		return sprintf("%d bytes", $bytes);
1360
	}
1361
}
1362

    
1363
function update_filter_reload_status($text) {
1364
	global $g;
1365

    
1366
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1367
}
1368

    
1369
/****** util/return_dir_as_array
1370
 * NAME
1371
 *   return_dir_as_array - Return a directory's contents as an array.
1372
 * INPUTS
1373
 *   $dir          - string containing the path to the desired directory.
1374
 *   $filter_regex - string containing a regular expression to filter file names. Default empty.
1375
 * RESULT
1376
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1377
 ******/
1378
function return_dir_as_array($dir, $filter_regex = '') {
1379
	$dir_array = array();
1380
	if (is_dir($dir)) {
1381
		if ($dh = opendir($dir)) {
1382
			while (($file = readdir($dh)) !== false) {
1383
				if (($file == ".") || ($file == ".."))
1384
					continue;
1385

    
1386
				if (empty($filter_regex) || preg_match($filter_regex, $file))
1387
					array_push($dir_array, $file);
1388
			}
1389
			closedir($dh);
1390
		}
1391
	}
1392
	return $dir_array;
1393
}
1394

    
1395
function run_plugins($directory) {
1396
	global $config, $g;
1397

    
1398
	/* process packager manager custom rules */
1399
	$files = return_dir_as_array($directory);
1400
	if (is_array($files)) {
1401
		foreach ($files as $file) {
1402
			if (stristr($file, ".sh") == true)
1403
				mwexec($directory . $file . " start");
1404
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1405
				require_once($directory . "/" . $file);
1406
		}
1407
	}
1408
}
1409

    
1410
/*
1411
 *    safe_mkdir($path, $mode = 0755)
1412
 *    create directory if it doesn't already exist and isn't a file!
1413
 */
1414
function safe_mkdir($path, $mode=0755) {
1415
	global $g;
1416

    
1417
	if (!is_file($path) && !is_dir($path)) {
1418
		return @mkdir($path, $mode, true);
1419
	} else {
1420
		return false;
1421
	}
1422
}
1423

    
1424
/*
1425
 * make_dirs($path, $mode = 0755)
1426
 * create directory tree recursively (mkdir -p)
1427
 */
1428
function make_dirs($path, $mode = 0755) {
1429
	$base = '';
1430
	foreach (explode('/', $path) as $dir) {
1431
		$base .= "/$dir";
1432
		if (!is_dir($base)) {
1433
			if (!@mkdir($base, $mode))
1434
				return false;
1435
		}
1436
	}
1437
	return true;
1438
}
1439

    
1440
/*
1441
 * get_sysctl($names)
1442
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1443
 * name) and return an array of key/value pairs set for those that exist
1444
 */
1445
function get_sysctl($names) {
1446
	if (empty($names))
1447
		return array();
1448

    
1449
	if (is_array($names)) {
1450
		$name_list = array();
1451
		foreach ($names as $name) {
1452
			$name_list[] = escapeshellarg($name);
1453
		}
1454
	} else
1455
		$name_list = array(escapeshellarg($names));
1456

    
1457
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1458
	$values = array();
1459
	foreach ($output as $line) {
1460
		$line = explode(": ", $line, 2);
1461
		if (count($line) == 2)
1462
			$values[$line[0]] = $line[1];
1463
	}
1464

    
1465
	return $values;
1466
}
1467

    
1468
/*
1469
 * set_sysctl($value_list)
1470
 * Set sysctl OID's listed as key/value pairs and return
1471
 * an array with keys set for those that succeeded
1472
 */
1473
function set_sysctl($values) {
1474
	if (empty($values))
1475
		return array();
1476

    
1477
	$value_list = array();
1478
	foreach ($values as $key => $value) {
1479
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1480
	}
1481

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

    
1484
	/* Retry individually if failed (one or more read-only) */
1485
	if ($success <> 0 && count($value_list) > 1) {
1486
		foreach ($value_list as $value) {
1487
			exec("/sbin/sysctl -i " . $value, $output);
1488
		}
1489
	}
1490

    
1491
	$ret = array();
1492
	foreach ($output as $line) {
1493
		$line = explode(": ", $line, 2);
1494
		if (count($line) == 2)
1495
			$ret[$line[0]] = true;
1496
	}
1497

    
1498
	return $ret;
1499
}
1500

    
1501
/*
1502
 *     get_memory()
1503
 *     returns an array listing the amount of
1504
 *     memory installed in the hardware
1505
 *     [0]real and [1]available
1506
 */
1507
function get_memory() {
1508

    
1509
	$real = trim(`sysctl -n hw.physmem`, " \n");
1510
	$avail = trim(`sysctl -n hw.realmem`, " \n");
1511
	/* convert from bytes to megabytes */
1512
	return array(($real/1048576),($avail/1048576));
1513
}
1514

    
1515
function mute_kernel_msgs() {
1516
	global $config;
1517
	// Do not mute serial console.  The kernel gets very very cranky
1518
	// and will start dishing you cannot control tty errors.
1519
	switch (trim(file_get_contents("/etc/platform"))) {
1520
		case "nanobsd":
1521
		case "jail":
1522
			return;
1523
	}
1524
	if($config['system']['enableserial']) 
1525
		return;			
1526
	exec("/sbin/conscontrol mute on");
1527
}
1528

    
1529
function unmute_kernel_msgs() {
1530
	global $config;
1531
	// Do not mute serial console.  The kernel gets very very cranky
1532
	// and will start dishing you cannot control tty errors.
1533
	switch (trim(file_get_contents("/etc/platform"))) {
1534
		case "nanobsd":
1535
		case "jail":
1536
			return;
1537
	}
1538
	exec("/sbin/conscontrol mute off");
1539
}
1540

    
1541
function start_devd() {
1542
	global $g;
1543

    
1544
	if ($g['platform'] == 'jail')
1545
		return;
1546
	exec("/sbin/devd");
1547
	sleep(1);
1548
}
1549

    
1550
function is_interface_vlan_mismatch() {
1551
	global $config, $g;
1552

    
1553
	if (is_array($config['vlans']['vlan'])) {
1554
		foreach ($config['vlans']['vlan'] as $vlan) {
1555
			if (does_interface_exist($vlan['if']) == false)
1556
				return true;
1557
		}
1558
	}
1559

    
1560
	return false;
1561
}
1562

    
1563
function is_interface_mismatch() {
1564
	global $config, $g;
1565

    
1566
	$do_assign = false;
1567
	$i = 0;
1568
	$missing_interfaces = array();
1569
	if (is_array($config['interfaces'])) {
1570
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1571
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1572
				// Do not check these interfaces.
1573
				$i++;
1574
				continue;
1575
			}
1576
			else if (does_interface_exist($ifcfg['if']) == false) {
1577
				$missing_interfaces[] = $ifcfg['if'];
1578
				$do_assign = true;
1579
			} else
1580
				$i++;
1581
		}
1582
	}
1583

    
1584
	if ($g['minimum_nic_count'] > $i) {
1585
		$do_assign = true;
1586
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1587
		$do_assign = false;
1588

    
1589
	if (!empty($missing_interfaces) && $do_assign)
1590
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1591
	else
1592
		@unlink("{$g['tmp_path']}/missing_interfaces");
1593

    
1594
	return $do_assign;
1595
}
1596

    
1597
/* sync carp entries to other firewalls */
1598
function carp_sync_client() {
1599
	global $g;
1600
	send_event("filter sync");
1601
}
1602

    
1603
/****f* util/isAjax
1604
 * NAME
1605
 *   isAjax - reports if the request is driven from prototype
1606
 * INPUTS
1607
 *   none
1608
 * RESULT
1609
 *   true/false
1610
 ******/
1611
function isAjax() {
1612
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1613
}
1614

    
1615
/****f* util/timeout
1616
 * NAME
1617
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1618
 * INPUTS
1619
 *   optional, seconds to wait before timeout. Default 9 seconds.
1620
 * RESULT
1621
 *   returns 1 char of user input or null if no input.
1622
 ******/
1623
function timeout($timer = 9) {
1624
	while(!isset($key)) {
1625
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1626
		else { echo chr(8). "{$timer}"; }
1627
		`/bin/stty -icanon min 0 time 25`;
1628
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1629
		`/bin/stty icanon`;
1630
		if ($key == '')
1631
			unset($key);
1632
		$timer--;
1633
		if ($timer == 0)
1634
			break;
1635
	}
1636
	return $key;	
1637
}
1638

    
1639
/****f* util/msort
1640
 * NAME
1641
 *   msort - sort array
1642
 * INPUTS
1643
 *   $array to be sorted, field to sort by, direction of sort
1644
 * RESULT
1645
 *   returns newly sorted array
1646
 ******/
1647
function msort($array, $id="id", $sort_ascending=true) {
1648
	$temp_array = array();
1649
	while(count($array)>0) {
1650
		$lowest_id = 0;
1651
		$index=0;
1652
		foreach ($array as $item) {
1653
			if (isset($item[$id])) {
1654
				if ($array[$lowest_id][$id]) {
1655
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1656
						$lowest_id = $index;
1657
					}
1658
				}
1659
			}
1660
			$index++;
1661
		}
1662
		$temp_array[] = $array[$lowest_id];
1663
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1664
	}
1665
	if ($sort_ascending) {
1666
		return $temp_array;
1667
	} else {
1668
    		return array_reverse($temp_array);
1669
	}
1670
}
1671

    
1672
/****f* util/color
1673
 * NAME
1674
 *   color - outputs a color code to the ansi terminal if supported
1675
 * INPUTS
1676
 *   color code or color name
1677
 * RESULT
1678
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1679
 ******/
1680
function color($color = "0m") {
1681
	/*
1682
		Color codes available:
1683
		 0m reset; clears all colors and styles (to white on black)
1684
		 1m bold on (see below)
1685
		 3m italics on
1686
		 4m underline on
1687
		 7m inverse on; reverses foreground & background colors
1688
		 9m strikethrough on
1689
		 22m bold off (see below)
1690
		 23m italics off
1691
		 24m underline off
1692
		 27m inverse off
1693
		 29m strikethrough off
1694
		 30m set foreground color to black
1695
		 31m set foreground color to red
1696
		 32m set foreground color to green
1697
		 33m set foreground color to yellow
1698
		 34m set foreground color to blue
1699
		 35m set foreground color to magenta (purple)
1700
		 36m set foreground color to cyan
1701
		 37m set foreground color to white
1702
		 40m  set background color to black
1703
		 41m set background color to red
1704
		 42m set background color to green
1705
		 43m set background color to yellow
1706
		 44m set background color to blue
1707
		 45m set background color to magenta (purple)
1708
		 46m set background color to cyan
1709
		 47m set background color to white
1710
		 49m set background color to default (black)
1711
	*/	
1712
	// Allow caching of TERM to 
1713
	// speedup subequence requests.
1714
	global $TERM;
1715
	if(!$TERM) 
1716
		$TERM=`/usr/bin/env | grep color`;
1717
	if(!$TERM)
1718
		$TERM=`/usr/bin/env | grep cons25`;
1719
	if($TERM) {
1720
		$ESCAPE=chr(27);
1721
		switch ($color) {
1722
			case "black":
1723
				return "{$ESCAPE}[30m"; 
1724
			case "red":
1725
				return "{$ESCAPE}[31m"; 
1726
			case "green":
1727
				return "{$ESCAPE}[32m"; 
1728
			case "yellow":
1729
				return "{$ESCAPE}[33m"; 
1730
			case "blue":
1731
				return "{$ESCAPE}[34m"; 
1732
			case "magenta":
1733
				return "{$ESCAPE}[35m"; 
1734
			case "cyan":
1735
				return "{$ESCAPE}[36m"; 
1736
			case "white":
1737
				return "{$ESCAPE}[37m"; 
1738
			case "default":
1739
				return "{$ESCAPE}[39m"; 
1740
		}
1741
		return "{$ESCAPE}[{$color}";
1742
	}
1743
}
1744

    
1745
/****f* util/is_URL
1746
 * NAME
1747
 *   is_URL
1748
 * INPUTS
1749
 *   string to check
1750
 * RESULT
1751
 *   Returns true if item is a URL
1752
 ******/
1753
function is_URL($url) {
1754
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1755
	if($match)
1756
		return true;	
1757
	return false;
1758
}
1759

    
1760
function is_file_included($file = "") {
1761
	$files = get_included_files();
1762
	if (in_array($file, $files))
1763
		return true;
1764
	
1765
	return false;
1766
}
1767

    
1768
/*
1769
	This function was borrowed from a comment on PHP.net at the following URL:
1770
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1771
 */
1772
function array_merge_recursive_unique($array0, $array1) {
1773

    
1774
	$arrays = func_get_args();
1775
	$remains = $arrays;
1776

    
1777
	// We walk through each arrays and put value in the results (without
1778
	// considering previous value).
1779
	$result = array();
1780

    
1781
	// loop available array
1782
	foreach($arrays as $array) {
1783

    
1784
		// The first remaining array is $array. We are processing it. So
1785
		// we remove it from remaing arrays.
1786
        array_shift($remains);
1787

    
1788
		// We don't care non array param, like array_merge since PHP 5.0.
1789
		if(is_array($array)) {
1790
			// Loop values
1791
			foreach($array as $key => $value) {
1792
				if(is_array($value)) {
1793
					// we gather all remaining arrays that have such key available
1794
					$args = array();
1795
					foreach($remains as $remain) {
1796
						if(array_key_exists($key, $remain)) {
1797
							array_push($args, $remain[$key]);
1798
						}
1799
					}
1800

    
1801
					if(count($args) > 2) {
1802
						// put the recursion
1803
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1804
					} else {
1805
						foreach($value as $vkey => $vval) {
1806
							$result[$key][$vkey] = $vval;
1807
						}
1808
					}
1809
				} else {
1810
					// simply put the value
1811
					$result[$key] = $value;
1812
				}
1813
			}
1814
		}
1815
	}
1816
	return $result;
1817
}
1818

    
1819

    
1820
/*
1821
 * converts a string like "a,b,c,d"
1822
 * into an array like array("a" => "b", "c" => "d")
1823
 */
1824
function explode_assoc($delimiter, $string) {
1825
	$array = explode($delimiter, $string);
1826
	$result = array();
1827
	$numkeys = floor(count($array) / 2);
1828
	for ($i = 0; $i < $numkeys; $i += 1) {
1829
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1830
	}
1831
	return $result;
1832
}
1833

    
1834
function get_staticroutes($returnsubnetsonly = false) {
1835
	global $config;
1836

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

    
1841
	$allstaticroutes = array();
1842
	$allsubnets = array();
1843
	/* Loop through routes and expand aliases as we find them. */
1844
	foreach ($config['staticroutes']['route'] as $route) {
1845
		if (is_alias($route['network'])) {
1846
			if (!function_exists('filter_expand_alias_array'))
1847
				require_once('filter.inc');
1848
			$subnets = filter_expand_alias_array($route['network']);
1849
			foreach ($subnets as $net) {
1850
				if (!is_subnet($net)) {
1851
					if (is_ipaddrv4($net))
1852
						$net .= "/32";
1853
					else if (is_ipaddrv6($net))
1854
						$net .= "/128";
1855
					/* This must be a hostname, we can't use it. */
1856
					else
1857
						continue;
1858
				}
1859
				$temproute = $route;
1860
				$temproute['network'] = $net;
1861
				$allstaticroutes[] = $temproute;
1862
				$allsubnets[] = $net;
1863
			}
1864
		} elseif (is_subnet($route['network'])) {
1865
			$allstaticroutes[] = $route;
1866
			$allsubnets[] = $route['network'];
1867
		}
1868
	}
1869
	if ($returnsubnetsonly)
1870
		return $allsubnets;
1871
	else
1872
		return $allstaticroutes;
1873
}
1874

    
1875
/****f* util/get_alias_list
1876
 * NAME
1877
 *   get_alias_list - Provide a list of aliases.
1878
 * INPUTS
1879
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
1880
 * RESULT
1881
 *   Array containing list of aliases.
1882
 *   If $type is unspecified, all aliases are returned.
1883
 *   If $type is a string, all aliases of the type specified in $type are returned.
1884
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
1885
 */
1886
function get_alias_list($type = null) {
1887
	global $config;
1888
	$result = array();
1889
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
1890
		foreach ($config['aliases']['alias'] as $alias) {
1891
			if ($type === null) {
1892
				$result[] = $alias['name'];
1893
			}
1894
			else if (is_array($type)) {
1895
				if (in_array($alias['type'], $type)) {
1896
					$result[] = $alias['name'];
1897
				}
1898
			}
1899
			else if ($type === $alias['type']) {
1900
				$result[] = $alias['name'];
1901
			}
1902
		}
1903
	}		
1904
	return $result;
1905
}
1906

    
1907
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
1908
function array_exclude($needle, $haystack) {
1909
	$result = array();
1910
	if (is_array($haystack)) {
1911
		foreach ($haystack as $thing) {
1912
			if ($needle !== $thing) {
1913
				$result[] = $thing;
1914
			}
1915
		}
1916
	}
1917
	return $result;
1918
}
1919

    
1920
function setup_library_paths() {
1921
	$current_library_paths = explode(":", exec("/sbin/ldconfig -r | /usr/bin/grep 'search directories' | /usr/bin/awk '{print $3;}'"));
1922
	$pbi_library_paths = array_merge(glob("/usr/pbi/*/lib", GLOB_ONLYDIR), glob("/usr/pbi/*/lib/*", GLOB_ONLYDIR));
1923
	foreach ($pbi_library_paths as $pbilib) {
1924
		if (!in_array($pbilib, $current_library_paths))
1925
			exec("/sbin/ldconfig -m {$pbilib}");
1926
	}
1927
}
1928

    
1929
function get_current_theme() {
1930
	global $config, $g;
1931
	/*
1932
	 *   if user has selected a custom template, use it.
1933
	 *   otherwise default to pfsense tempalte
1934
	 */
1935
	if (($g["disablethemeselection"] === true) && !empty($g["default_theme"]) && (is_dir($g["www_path"].'/themes/'.$g["default_theme"])))
1936
		$theme = $g["default_theme"];
1937
	elseif($config['theme'] <> "" && (is_dir($g["www_path"].'/themes/'.$config['theme'])))
1938
		$theme = $config['theme'];
1939
	else
1940
		$theme = "pfsense";
1941
	/*
1942
	 *  If this device is an apple ipod/iphone
1943
	 *  switch the theme to one that works with it.
1944
	 */
1945
	$lowres_ua = array("iPhone", "iPod", "iPad", "Android", "BlackBerry", "Opera Mini", "Opera Mobi", "PlayBook", "IEMobile");
1946
	foreach($lowres_ua as $useragent)
1947
		if(strstr($_SERVER['HTTP_USER_AGENT'], $useragent))
1948
			$theme = (empty($g['theme_lowres']) && (is_dir($g["www_path"].'/themes/'.$g['theme_lowres']))) ? "pfsense" : $g['theme_lowres'];
1949
	return $theme;
1950
}
1951

    
1952
?>
(54-54/66)