Project

General

Profile

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

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

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

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

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

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

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

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

    
44
function isvalidpid($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
	syslog(LOG_ERR, "$page: $error");
1018
	if ($g['debug'])
1019
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1020
	return;
1021
}
1022

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

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

    
1056
/* wrapper for exec() */
1057
function mwexec($command, $mute = false, $clearsigmask = false) {
1058
	global $g;
1059

    
1060
	if ($g['debug']) {
1061
		if (!$_SERVER['REMOTE_ADDR'])
1062
			echo "mwexec(): $command\n";
1063
	}
1064
	$oarr = array();
1065
	$retval = 0;
1066

    
1067
	if ($clearsigmask) {
1068
		$oldset = array();
1069
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1070
	}
1071
	$garbage = exec("$command 2>&1", $oarr, $retval);
1072
	if ($clearsigmask) {
1073
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1074
	}
1075

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

    
1085
/* wrapper for exec() in background */
1086
function mwexec_bg($command, $clearsigmask = false) {
1087
	global $g;
1088

    
1089
	if ($g['debug']) {
1090
		if (!$_SERVER['REMOTE_ADDR'])
1091
			echo "mwexec(): $command\n";
1092
	}
1093

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

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

    
1119
	$aliastable = array();
1120

    
1121
	if (is_array($config['aliases']['alias'])) {
1122
		foreach ($config['aliases']['alias'] as $alias) {
1123
			if ($alias['name'])
1124
				$aliastable[$alias['name']] = $alias['address'];
1125
		}
1126
	}
1127
}
1128

    
1129
/* check if an alias exists */
1130
function is_alias($name) {
1131
	global $aliastable;
1132

    
1133
	return isset($aliastable[$name]);
1134
}
1135

    
1136
function alias_get_type($name) {
1137
	global $config;
1138

    
1139
	if (is_array($config['aliases']['alias'])) {
1140
		foreach ($config['aliases']['alias'] as $alias) {
1141
			if ($name == $alias['name'])
1142
				return $alias['type'];
1143
		}
1144
	}
1145

    
1146
	return "";
1147
}
1148

    
1149
/* expand a host or network alias, if necessary */
1150
function alias_expand($name) {
1151
	global $aliastable;
1152

    
1153
	if (isset($aliastable[$name]))
1154
		return "\${$name}";
1155
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1156
		return "{$name}";
1157
	else
1158
		return null;
1159
}
1160

    
1161
function alias_expand_urltable($name) {
1162
	global $config;
1163
	$urltable_prefix = "/var/db/aliastables/";
1164
	$urltable_filename = $urltable_prefix . $name . ".txt";
1165

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

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

    
1193
function subnet_expand($subnet) {
1194
	if (is_subnetv4($subnet)) {
1195
		return subnetv4_expand($subnet);
1196
	} else if (is_subnetv6($subnet)) {
1197
		return subnetv6_expand($subnet);
1198
	} else {
1199
		return $subnet;
1200
	}
1201
}
1202

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

    
1216
/* find out whether two subnets overlap */
1217
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1218

    
1219
	if (!is_numeric($bits1))
1220
		$bits1 = 32;
1221
	if (!is_numeric($bits2))
1222
		$bits2 = 32;
1223

    
1224
	if ($bits1 < $bits2)
1225
		$relbits = $bits1;
1226
	else
1227
		$relbits = $bits2;
1228

    
1229
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1230
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1231

    
1232
	return ($sn1 == $sn2);
1233
}
1234

    
1235
/* find out whether two IPv6 subnets overlap */
1236
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
1237
	$sub1_min = gen_subnetv6($subnet1, $bits1);
1238
	$sub1_max = gen_subnetv6_max($subnet1, $bits1);
1239
	$sub2_min = gen_subnetv6($subnet2, $bits2);
1240
	$sub2_max = gen_subnetv6_max($subnet2, $bits2);
1241

    
1242
	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));
1243
}
1244

    
1245
/* compare two IP addresses */
1246
function ipcmp($a, $b) {
1247
	if (ip_less_than($a, $b))
1248
		return -1;
1249
	else if (ip_greater_than($a, $b))
1250
		return 1;
1251
	else
1252
		return 0;
1253
}
1254

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

    
1266
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1267
function verify_digital_signature($fname) {
1268
	global $g;
1269

    
1270
	if(!file_exists("/usr/local/sbin/gzsig"))
1271
		return 4;
1272

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

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

    
1282
	if ($arpoutput[0]) {
1283
		$arpi = explode(" ", $arpoutput[0]);
1284
		$macaddr = $arpi[3];
1285
		if (is_macaddr($macaddr))
1286
			return $macaddr;
1287
		else
1288
			return false;
1289
	}
1290

    
1291
	return false;
1292
}
1293

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

    
1303
function mac_format($clientmac) {
1304
	global $config, $cpzone;
1305

    
1306
	$mac = explode(":", $clientmac);
1307
	$mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1308

    
1309
	switch($mac_format) {
1310
	case 'singledash':
1311
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1312

    
1313
	case 'ietf':
1314
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1315

    
1316
	case 'cisco':
1317
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1318

    
1319
	case 'unformatted':
1320
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1321

    
1322
	default:
1323
		return $clientmac;
1324
	}
1325
}
1326

    
1327
function resolve_retry($hostname, $retries = 5) {
1328

    
1329
	if (is_ipaddr($hostname))
1330
		return $hostname;
1331

    
1332
	for ($i = 0; $i < $retries; $i++) {
1333
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1334
		$ip = gethostbyname($hostname);
1335

    
1336
		if ($ip && $ip != $hostname) {
1337
			/* success */
1338
			return $ip;
1339
		}
1340

    
1341
		sleep(1);
1342
	}
1343

    
1344
	return false;
1345
}
1346

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

    
1359
function update_filter_reload_status($text) {
1360
	global $g;
1361

    
1362
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1363
}
1364

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

    
1382
				if (empty($filter_regex) || preg_match($filter_regex, $file))
1383
					array_push($dir_array, $file);
1384
			}
1385
			closedir($dh);
1386
		}
1387
	}
1388
	return $dir_array;
1389
}
1390

    
1391
function run_plugins($directory) {
1392
	global $config, $g;
1393

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

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

    
1413
	if (!is_file($path) && !is_dir($path)) {
1414
		return @mkdir($path, $mode, true);
1415
	} else {
1416
		return false;
1417
	}
1418
}
1419

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

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

    
1445
	if (is_array($names)) {
1446
		$name_list = array();
1447
		foreach ($names as $name) {
1448
			$name_list[] = escapeshellarg($name);
1449
		}
1450
	} else
1451
		$name_list = array(escapeshellarg($names));
1452

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

    
1461
	return $values;
1462
}
1463

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

    
1473
	$value_list = array();
1474
	foreach ($values as $key => $value) {
1475
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1476
	}
1477

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

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

    
1487
	$ret = array();
1488
	foreach ($output as $line) {
1489
		$line = explode(": ", $line, 2);
1490
		if (count($line) == 2)
1491
			$ret[$line[0]] = true;
1492
	}
1493

    
1494
	return $ret;
1495
}
1496

    
1497
/*
1498
 *     get_memory()
1499
 *     returns an array listing the amount of
1500
 *     memory installed in the hardware
1501
 *     [0]real and [1]available
1502
 */
1503
function get_memory() {
1504

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

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

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

    
1537
function start_devd() {
1538
	global $g;
1539

    
1540
	if ($g['platform'] == 'jail')
1541
		return;
1542
	exec("/sbin/devd");
1543
	sleep(1);
1544
}
1545

    
1546
function is_interface_vlan_mismatch() {
1547
	global $config, $g;
1548

    
1549
	if (is_array($config['vlans']['vlan'])) {
1550
		foreach ($config['vlans']['vlan'] as $vlan) {
1551
			if (does_interface_exist($vlan['if']) == false)
1552
				return true;
1553
		}
1554
	}
1555

    
1556
	return false;
1557
}
1558

    
1559
function is_interface_mismatch() {
1560
	global $config, $g;
1561

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

    
1580
	if ($g['minimum_nic_count'] > $i) {
1581
		$do_assign = true;
1582
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1583
		$do_assign = false;
1584

    
1585
	if (!empty($missing_interfaces) && $do_assign)
1586
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1587
	else
1588
		@unlink("{$g['tmp_path']}/missing_interfaces");
1589

    
1590
	return $do_assign;
1591
}
1592

    
1593
/* sync carp entries to other firewalls */
1594
function carp_sync_client() {
1595
	global $g;
1596
	send_event("filter sync");
1597
}
1598

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

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

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

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

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

    
1756
function is_file_included($file = "") {
1757
	$files = get_included_files();
1758
	if (in_array($file, $files))
1759
		return true;
1760

    
1761
	return false;
1762
}
1763

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

    
1770
	$arrays = func_get_args();
1771
	$remains = $arrays;
1772

    
1773
	// We walk through each arrays and put value in the results (without
1774
	// considering previous value).
1775
	$result = array();
1776

    
1777
	// loop available array
1778
	foreach($arrays as $array) {
1779

    
1780
		// The first remaining array is $array. We are processing it. So
1781
		// we remove it from remaing arrays.
1782
		array_shift($remains);
1783

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

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

    
1815

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

    
1830
function get_staticroutes($returnsubnetsonly = false, $returnhostnames = false) {
1831
	global $config, $aliastable;
1832

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

    
1837
	$allstaticroutes = array();
1838
	$allsubnets = array();
1839
	/* Loop through routes and expand aliases as we find them. */
1840
	foreach ($config['staticroutes']['route'] as $route) {
1841
		if (is_alias($route['network'])) {
1842
			if (!isset($aliastable[$route['network']]))
1843
				continue;
1844

    
1845
			$subnets = preg_split('/\s+/', $aliastable[$route['network']]);
1846
			foreach ($subnets as $net) {
1847
				if (!is_subnet($net)) {
1848
					if (is_ipaddrv4($net))
1849
						$net .= "/32";
1850
					else if (is_ipaddrv6($net))
1851
						$net .= "/128";
1852
					else if ($returnhostnames === false || !is_fqdn($net))
1853
						continue;
1854
				}
1855
				$temproute = $route;
1856
				$temproute['network'] = $net;
1857
				$allstaticroutes[] = $temproute;
1858
				$allsubnets[] = $net;
1859
			}
1860
		} elseif (is_subnet($route['network'])) {
1861
			$allstaticroutes[] = $route;
1862
			$allsubnets[] = $route['network'];
1863
		}
1864
	}
1865
	if ($returnsubnetsonly)
1866
		return $allsubnets;
1867
	else
1868
		return $allstaticroutes;
1869
}
1870

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

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

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

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

    
1948
?>
(54-54/66)