Project

General

Profile

Download (49.9 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

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

    
505
	return is_ipaddrv6($ipaddr);
506
}
507

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

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

    
530
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
531
function is_ipaddroralias($ipaddr) {
532
	global $config;
533

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

    
545
}
546

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

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

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

    
565
	if (!is_ipaddrv4($hp))
566
		return false;
567

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

    
571
	return true;
572
}
573

    
574
/* returns true if $subnet is a valid IPv6 subnet in CIDR format */
575
function is_subnetv6($subnet) {
576
	if (!is_string($subnet))
577
		return false;
578

    
579
	list($hp,$np) = explode('/', $subnet);
580

    
581
	if (!is_ipaddrv6($hp))
582
		return false;
583

    
584
	if (!is_numeric($np) || ($np < 1) || ($np > 128))
585
		return false;
586

    
587
	return true;
588
}
589

    
590

    
591
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
592
function is_subnetoralias($subnet) {
593
	global $aliastable;
594

    
595
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
596
		return true;
597
	else
598
		return is_subnet($subnet);
599
}
600

    
601
/* returns true if $hostname is a valid hostname */
602
function is_hostname($hostname) {
603
	if (!is_string($hostname))
604
		return false;
605

    
606
	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))
607
		return true;
608
	else
609
		return false;
610
}
611

    
612
/* returns true if $domain is a valid domain name */
613
function is_domain($domain) {
614
	if (!is_string($domain))
615
		return false;
616

    
617
	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))
618
		return true;
619
	else
620
		return false;
621
}
622

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

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

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

    
656
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
657
function is_portrange($portrange) {
658
	$ports = explode(":", $portrange);
659

    
660
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
661
}
662

    
663
/* returns true if $port is a valid port number or an alias thereof */
664
function is_portoralias($port) {
665
	global $config;
666

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

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

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

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

    
700
/* return the configured carp interface list */
701
function get_configured_carp_interface_list() {
702
	global $config;
703

    
704
	$iflist = array();
705

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

    
718
	return $iflist;
719
}
720

    
721
/* return the configured IP aliases list */
722
function get_configured_ip_aliases_list($returnfullentry = false) {
723
	global $config;
724

    
725
	$alias_list=array();
726

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

    
739
	return $alias_list;
740
}
741

    
742
/* return all configured aliases list (IP, carp, proxyarp and other) */
743
function get_configured_vips_list() {
744
	global $config;
745

    
746
	$alias_list=array();
747

    
748
	if(is_array($config['virtualip']['vip'])) {
749
		$viparr = &$config['virtualip']['vip'];
750
		foreach ($viparr as $vip)
751
			$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
752
	}
753

    
754
	return $alias_list;
755
}
756

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

    
770
	return strnatcmp($a, $b);
771
}
772

    
773
/* return the configured interfaces list. */
774
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
775
	global $config;
776

    
777
	$iflist = array();
778

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

    
787
	return $iflist;
788
}
789

    
790
/* return the configured interfaces list. */
791
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
792
	global $config;
793

    
794
	$iflist = array();
795

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

    
807
	return $iflist;
808
}
809

    
810
/* return the configured interfaces list with their description. */
811
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
812
	global $config;
813

    
814
	$iflist = array();
815

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

    
828
	return $iflist;
829
}
830

    
831
/*
832
 *   get_configured_ip_addresses() - Return a list of all configured
833
 *   interfaces IP Addresses
834
 *
835
 */
836
function get_configured_ip_addresses() {
837
	global $config;
838

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

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

    
866
	return $ip_array;
867
}
868

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

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

    
1002
/****f* util/log_error
1003
* NAME
1004
*   log_error  - Sends a string to syslog.
1005
* INPUTS
1006
*   $error     - string containing the syslog message.
1007
* RESULT
1008
*   null
1009
******/
1010
function log_error($error) {
1011
	global $g;
1012
	$page = $_SERVER['SCRIPT_NAME'];
1013
	syslog(LOG_ERR, "$page: $error");
1014
	if ($g['debug'])
1015
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1016
	return;
1017
}
1018

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

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

    
1052
/* wrapper for exec() */
1053
function mwexec($command, $mute = false, $clearsigmask = false) {
1054
	global $g;
1055

    
1056
	if ($g['debug']) {
1057
		if (!$_SERVER['REMOTE_ADDR'])
1058
			echo "mwexec(): $command\n";
1059
	}
1060
	$oarr = array();
1061
	$retval = 0;
1062

    
1063
	if ($clearsigmask) {
1064
		$oldset = array();
1065
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1066
	}
1067
	$garbage = exec("$command 2>&1", $oarr, $retval);
1068
	if ($clearsigmask) {
1069
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1070
	}
1071

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

    
1081
/* wrapper for exec() in background */
1082
function mwexec_bg($command, $clearsigmask = false) {
1083
	global $g;
1084

    
1085
	if ($g['debug']) {
1086
		if (!$_SERVER['REMOTE_ADDR'])
1087
			echo "mwexec(): $command\n";
1088
	}
1089

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

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

    
1115
	$aliastable = array();
1116

    
1117
	if (is_array($config['aliases']['alias'])) {
1118
		foreach ($config['aliases']['alias'] as $alias) {
1119
			if ($alias['name'])
1120
				$aliastable[$alias['name']] = $alias['address'];
1121
		}
1122
	}
1123
}
1124

    
1125
/* check if an alias exists */
1126
function is_alias($name) {
1127
	global $aliastable;
1128

    
1129
	return isset($aliastable[$name]);
1130
}
1131

    
1132
function alias_get_type($name) {
1133
        global $config;
1134
        
1135
	if (is_array($config['aliases']['alias'])) {
1136
		foreach ($config['aliases']['alias'] as $alias) {
1137
			if ($name == $alias['name'])
1138
				return $alias['type'];
1139
		}
1140
	}
1141

    
1142
        return "";
1143
}
1144

    
1145
/* expand a host or network alias, if necessary */
1146
function alias_expand($name) {
1147
	global $aliastable;
1148

    
1149
	if (isset($aliastable[$name]))
1150
		return "\${$name}";
1151
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
1152
		return "{$name}";
1153
	else
1154
		return null;
1155
}
1156

    
1157
function alias_expand_urltable($name) {
1158
	global $config;
1159
	$urltable_prefix = "/var/db/aliastables/";
1160
	$urltable_filename = $urltable_prefix . $name . ".txt";
1161

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

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

    
1189
function subnet_expand($subnet) {
1190
	if (is_subnetv4($subnet)) {
1191
		return subnetv4_expand($subnet);
1192
	} else if (is_subnetv6($subnet)) {
1193
		return subnetv6_expand($subnet);
1194
	} else {
1195
		return $subnet;
1196
	}
1197
}
1198

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

    
1212
/* find out whether two subnets overlap */
1213
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1214

    
1215
	if (!is_numeric($bits1))
1216
		$bits1 = 32;
1217
	if (!is_numeric($bits2))
1218
		$bits2 = 32;
1219

    
1220
	if ($bits1 < $bits2)
1221
		$relbits = $bits1;
1222
	else
1223
		$relbits = $bits2;
1224

    
1225
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1226
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1227

    
1228
	return ($sn1 == $sn2);
1229
}
1230

    
1231
/* find out whether two IPv6 subnets overlap */
1232
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
1233
	$sub1_min = gen_subnetv6($subnet1, $bits1);
1234
	$sub1_max = gen_subnetv6_max($subnet1, $bits1);
1235
	$sub2_min = gen_subnetv6($subnet2, $bits2);
1236
	$sub2_max = gen_subnetv6_max($subnet2, $bits2);
1237
	
1238
	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));
1239
}
1240

    
1241
/* compare two IP addresses */
1242
function ipcmp($a, $b) {
1243
	if (ip_less_than($a, $b))
1244
		return -1;
1245
	else if (ip_greater_than($a, $b))
1246
		return 1;
1247
	else
1248
		return 0;
1249
}
1250

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

    
1262
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1263
function verify_digital_signature($fname) {
1264
	global $g;
1265

    
1266
	if(!file_exists("/usr/local/sbin/gzsig"))
1267
		return 4;
1268

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

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

    
1278
	if ($arpoutput[0]) {
1279
		$arpi = explode(" ", $arpoutput[0]);
1280
		$macaddr = $arpi[3];
1281
		if (is_macaddr($macaddr))
1282
			return $macaddr;
1283
		else
1284
			return false;
1285
	}
1286

    
1287
	return false;
1288
}
1289

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

    
1299
function mac_format($clientmac) {
1300
    global $config, $cpzone;
1301

    
1302
    $mac = explode(":", $clientmac);
1303
    $mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1304

    
1305
    switch($mac_format) {
1306
        case 'singledash':
1307
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1308

    
1309
        case 'ietf':
1310
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1311

    
1312
        case 'cisco':
1313
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1314

    
1315
        case 'unformatted':
1316
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1317

    
1318
        default:
1319
		return $clientmac;
1320
    }
1321
}
1322

    
1323
function resolve_retry($hostname, $retries = 5) {
1324

    
1325
	if (is_ipaddr($hostname))
1326
		return $hostname;
1327

    
1328
       for ($i = 0; $i < $retries; $i++) {
1329
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1330
               $ip = gethostbyname($hostname);
1331

    
1332
		if ($ip && $ip != $hostname) {
1333
			/* success */
1334
			return $ip;
1335
		}
1336

    
1337
		sleep(1);
1338
	}
1339

    
1340
	return false;
1341
}
1342

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

    
1355
function update_filter_reload_status($text) {
1356
	global $g;
1357

    
1358
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1359
}
1360

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

    
1378
				if (empty($filter_regex) || preg_match($filter_regex, $file))
1379
					array_push($dir_array, $file);
1380
			}
1381
			closedir($dh);
1382
		}
1383
	}
1384
	return $dir_array;
1385
}
1386

    
1387
function run_plugins($directory) {
1388
	global $config, $g;
1389

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

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

    
1409
	if (!is_file($path) && !is_dir($path)) {
1410
		return @mkdir($path, $mode, true);
1411
	} else {
1412
		return false;
1413
	}
1414
}
1415

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

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

    
1441
	if (is_array($names)) {
1442
		$name_list = array();
1443
		foreach ($names as $name) {
1444
			$name_list[] = escapeshellarg($name);
1445
		}
1446
	} else
1447
		$name_list = array(escapeshellarg($names));
1448

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

    
1457
	return $values;
1458
}
1459

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

    
1469
	$value_list = array();
1470
	foreach ($values as $key => $value) {
1471
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1472
	}
1473

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

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

    
1483
	$ret = array();
1484
	foreach ($output as $line) {
1485
		$line = explode(": ", $line, 2);
1486
		if (count($line) == 2)
1487
			$ret[$line[0]] = true;
1488
	}
1489

    
1490
	return $ret;
1491
}
1492

    
1493
/*
1494
 *     get_memory()
1495
 *     returns an array listing the amount of
1496
 *     memory installed in the hardware
1497
 *     [0]real and [1]available
1498
 */
1499
function get_memory() {
1500

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

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

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

    
1533
function start_devd() {
1534
	global $g;
1535

    
1536
	if ($g['platform'] == 'jail')
1537
		return;
1538
	exec("/sbin/devd");
1539
	sleep(1);
1540
}
1541

    
1542
function is_interface_vlan_mismatch() {
1543
	global $config, $g;
1544

    
1545
	if (is_array($config['vlans']['vlan'])) {
1546
		foreach ($config['vlans']['vlan'] as $vlan) {
1547
			if (does_interface_exist($vlan['if']) == false)
1548
				return true;
1549
		}
1550
	}
1551

    
1552
	return false;
1553
}
1554

    
1555
function is_interface_mismatch() {
1556
	global $config, $g;
1557

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

    
1576
	if ($g['minimum_nic_count'] > $i) {
1577
		$do_assign = true;
1578
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1579
		$do_assign = false;
1580

    
1581
	if (!empty($missing_interfaces) && $do_assign)
1582
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1583
	else
1584
		@unlink("{$g['tmp_path']}/missing_interfaces");
1585

    
1586
	return $do_assign;
1587
}
1588

    
1589
/* sync carp entries to other firewalls */
1590
function carp_sync_client() {
1591
	global $g;
1592
	send_event("filter sync");
1593
}
1594

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

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

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

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

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

    
1752
function is_file_included($file = "") {
1753
	$files = get_included_files();
1754
	if (in_array($file, $files))
1755
		return true;
1756
	
1757
	return false;
1758
}
1759

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

    
1766
	$arrays = func_get_args();
1767
	$remains = $arrays;
1768

    
1769
	// We walk through each arrays and put value in the results (without
1770
	// considering previous value).
1771
	$result = array();
1772

    
1773
	// loop available array
1774
	foreach($arrays as $array) {
1775

    
1776
		// The first remaining array is $array. We are processing it. So
1777
		// we remove it from remaing arrays.
1778
        array_shift($remains);
1779

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

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

    
1811

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

    
1826
function get_staticroutes($returnsubnetsonly = false) {
1827
	global $config;
1828

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

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

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

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

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

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

    
1944
?>
(54-54/66)