Projet

Général

Profil

Télécharger (55,2 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / util.inc @ 340ce958

1
<?php
2
/*
3
	util.inc
4
	part of the pfSense project (https://www.pfsense.org)
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 " . escapeshellarg($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 " . escapeshellarg("-{$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 " . escapeshellarg("-{$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
function try_lock($lock, $timeout = 5) {
136
	global $g, $cfglckkeyconsumers;
137
	if (!$lock)
138
		die(gettext("WARNING: You must give a name as parameter to try_lock() function."));
139
	if (!file_exists("{$g['tmp_path']}/{$lock}.lock")) {
140
		@touch("{$g['tmp_path']}/{$lock}.lock");
141
		@chmod("{$g['tmp_path']}/{$lock}.lock", 0666);
142
	}
143
	$cfglckkeyconsumers++;
144
	if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
145
		$trycounter = 0;
146
		while(!flock($fp, LOCK_EX | LOCK_NB)) {
147
			if ($trycounter >= $timeout) {
148
				fclose($fp);
149
				return NULL;
150
			}
151
			sleep(1);
152
			$trycounter++;
153
		}
154

    
155
		return $fp;
156
	}
157

    
158
	return NULL;
159
}
160

    
161
/* unlock configuration file */
162
function unlock($cfglckkey = 0) {
163
	global $g, $cfglckkeyconsumers;
164
	flock($cfglckkey, LOCK_UN);
165
	fclose($cfglckkey);
166
	return;
167
}
168

    
169
/* unlock forcefully configuration file */
170
function unlock_force($lock) {
171
	global $g;
172

    
173
	@unlink("{$g['tmp_path']}/{$lock}.lock");
174
}
175

    
176
function send_event($cmd) {
177
	global $g;
178

    
179
	if(!isset($g['event_address']))
180
		$g['event_address'] = "unix:///var/run/check_reload_status";
181

    
182
	$try = 0;
183
	while ($try < 3) {
184
		$fd = @fsockopen($g['event_address']);
185
		if ($fd) {
186
			fwrite($fd, $cmd);
187
			$resp = fread($fd, 4096);
188
			if ($resp != "OK\n")
189
				log_error("send_event: sent {$cmd} got {$resp}");
190
			fclose($fd);
191
			$try = 3;
192
		} else if (!is_process_running("check_reload_status"))
193
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
194
		$try++;
195
	}
196
}
197

    
198
function send_multiple_events($cmds) {
199
	global $g;
200

    
201
	if(!isset($g['event_address']))
202
		$g['event_address'] = "unix:///var/run/check_reload_status";
203

    
204
	if (!is_array($cmds))
205
		return;
206

    
207
	while ($try < 3) {
208
		$fd = @fsockopen($g['event_address']);
209
		if ($fd) {
210
			foreach ($cmds as $cmd) {
211
				fwrite($fd, $cmd);
212
				$resp = fread($fd, 4096);
213
				if ($resp != "OK\n")
214
					log_error("send_event: sent {$cmd} got {$resp}");
215
			}
216
			fclose($fd);
217
			$try = 3;
218
		} else if (!is_process_running("check_reload_status"))
219
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
220
		$try++;
221
	}
222
}
223

    
224
function refcount_init($reference) {
225
	$shmid = @shmop_open($reference, "c", 0644, 10);
226
	@shmop_write($shmid, str_pad("0", 10, "\x0", STR_PAD_RIGHT), 0);
227
	@shmop_close($shmid);
228
}
229

    
230
function refcount_reference($reference) {
231
	/* Take out a lock across the shared memory read, increment, write sequence to make it atomic. */
232
	$shm_lck = lock("shm{$reference}", LOCK_EX);
233
	try {
234
		/* NOTE: A warning is generated when shared memory does not exist */
235
		$shmid = @shmop_open($reference, "w", 0, 0);
236
		if (!$shmid) {
237
			refcount_init($reference);
238
			$shmid = @shmop_open($reference, "w", 0, 0);
239
			if (!$shmid) {
240
				log_error(gettext("Could not open shared memory {$reference}"));
241
				unlock($shm_lck);
242
				return;
243
			}
244
		}
245
		$shm_data = @shmop_read($shmid, 0, 10);
246
		$shm_data = intval($shm_data) + 1;
247
		@shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
248
		@shmop_close($shmid);
249
		unlock($shm_lck);
250
	} catch (Exception $e) {
251
		log_error($e->getMessage());
252
		unlock($shm_lck);
253
	}
254

    
255
	return $shm_data;
256
}
257

    
258
function refcount_unreference($reference) {
259
	/* Take out a lock across the shared memory read, decrement, write sequence to make it atomic. */
260
	$shm_lck = lock("shm{$reference}", LOCK_EX);
261
	try {
262
		$shmid = @shmop_open($reference, "w", 0, 0);
263
		if (!$shmid) {
264
			refcount_init($reference);
265
			log_error(gettext("Could not open shared memory {$reference}"));
266
			unlock($shm_lck);
267
			return;
268
		}
269
		$shm_data = @shmop_read($shmid, 0, 10);
270
		$shm_data = intval($shm_data) - 1;
271
		if ($shm_data < 0) {
272
			//debug_backtrace();
273
			log_error(sprintf(gettext("Reference %s is going negative, not doing unreference."), $reference));
274
		} else
275
			@shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
276
		@shmop_close($shmid);
277
		unlock($shm_lck);
278
	} catch (Exception $e) {
279
		log_error($e->getMessage());
280
		unlock($shm_lck);
281
	}
282

    
283
	return $shm_data;
284
}
285

    
286
function refcount_read($reference) {
287
	/* This function just reads the current value of the refcount for information. */
288
	/* There is no need for locking. */
289
	$shmid = @shmop_open($reference, "a", 0, 0);
290
	if (!$shmid) {
291
		log_error(gettext("Could not open shared memory for read {$reference}"));
292
		return -1;
293
	}
294
	$shm_data = @shmop_read($shmid, 0, 10);
295
	@shmop_close($shmid);
296
	return $shm_data;
297
}
298

    
299
function is_module_loaded($module_name) {
300
	$module_name = str_replace(".ko", "", $module_name);
301
	$running = 0;
302
	$_gb = exec("/sbin/kldstat -qn {$module_name} 2>&1", $_gb, $running);
303
	if (intval($running) == 0)
304
		return true;
305
	else
306
		return false;
307
}
308

    
309
/* validate non-negative numeric string, or equivalent numeric variable */
310
function is_numericint($arg) {
311
	return (((is_int($arg) && $arg >= 0) || (is_string($arg) && strlen($arg) > 0 && ctype_digit($arg))) ? true : false);  
312
}
313

    
314
/* return the subnet address given a host address and a subnet bit count */
315
function gen_subnet($ipaddr, $bits) {
316
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
317
		return "";
318
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
319
}
320

    
321
/* return the subnet address given a host address and a subnet bit count */
322
function gen_subnetv6($ipaddr, $bits) {
323
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
324
		return "";
325

    
326
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
327
	$address = Net_IPv6::compress($address);
328
	return $address;
329
}
330

    
331
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
332
function gen_subnet_max($ipaddr, $bits) {
333
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
334
		return "";
335

    
336
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
337
}
338

    
339
/* Generate end number for a given ipv6 subnet mask */
340
function gen_subnetv6_max($ipaddr, $bits) {
341
	if(!is_ipaddrv6($ipaddr))
342
		return false;
343

    
344
	$mask = Net_IPv6::getNetmask('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',$bits);
345

    
346
	$inet_ip = (binary)inet_pton($ipaddr);
347
	$inet_mask = (binary)inet_pton($mask);
348

    
349
	$inet_end = $inet_ip | ~$inet_mask;
350

    
351
	return (inet_ntop($inet_end));
352
}
353

    
354
/* returns a subnet mask (long given a bit count) */
355
function gen_subnet_mask_long($bits) {
356
	$sm = 0;
357
	for ($i = 0; $i < $bits; $i++) {
358
		$sm >>= 1;
359
		$sm |= 0x80000000;
360
	}
361
	return $sm;
362
}
363

    
364
/* same as above but returns a string */
365
function gen_subnet_mask($bits) {
366
	return long2ip(gen_subnet_mask_long($bits));
367
}
368

    
369
/* Convert long int to IP address, truncating to 32-bits. */
370
function long2ip32($ip) {
371
	return long2ip($ip & 0xFFFFFFFF);
372
}
373

    
374
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
375
function ip2long32($ip) {
376
	return ( ip2long($ip) & 0xFFFFFFFF );
377
}
378

    
379
/* Convert IP address to unsigned long int. */
380
function ip2ulong($ip) {
381
	return sprintf("%u", ip2long32($ip));
382
}
383

    
384
/* Find out how many IPs are contained within a given IP range
385
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
386
 */
387
function ip_range_size_v4($startip, $endip) {
388
	if (is_ipaddrv4($startip) && is_ipaddrv4($endip)) {
389
		// Operate as unsigned long because otherwise it wouldn't work
390
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
391
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
392
	}
393
	return -1;
394
}
395

    
396
/* Find the smallest possible subnet mask which can contain a given number of IPs
397
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
398
 */
399
function find_smallest_cidr_v4($number) {
400
	$smallest = 1;
401
	for ($b=32; $b > 0; $b--) {
402
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
403
	}
404
	return (32-$smallest);
405
}
406

    
407
/* Return the previous IP address before the given address */
408
function ip_before($ip) {
409
	return long2ip32(ip2long($ip)-1);
410
}
411

    
412
/* Return the next IP address after the given address */
413
function ip_after($ip) {
414
	return long2ip32(ip2long($ip)+1);
415
}
416

    
417
/* Return true if the first IP is 'before' the second */
418
function ip_less_than($ip1, $ip2) {
419
	// Compare as unsigned long because otherwise it wouldn't work when
420
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
421
	return ip2ulong($ip1) < ip2ulong($ip2);
422
}
423

    
424
/* Return true if the first IP is 'after' the second */
425
function ip_greater_than($ip1, $ip2) {
426
	// Compare as unsigned long because otherwise it wouldn't work
427
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
428
	return ip2ulong($ip1) > ip2ulong($ip2);
429
}
430

    
431
/* Convert a range of IPv4 addresses to an array of individual addresses. */
432
/* Note: IPv6 ranges are not yet supported here. */
433
function ip_range_to_address_array($startip, $endip, $max_size = 5000) {
434
	if (!is_ipaddrv4($startip) || !is_ipaddrv4($endip)) {
435
		return false;
436
	}
437

    
438
	if (ip_greater_than($startip, $endip)) {
439
		// Swap start and end so we can process sensibly.
440
		$temp = $startip;
441
		$startip = $endip;
442
		$endip = $temp;
443
	}
444

    
445
	if (ip_range_size_v4($startip, $endip) > $max_size)
446
		return false;
447
	
448
	// Container for IP addresses within this range.
449
	$rangeaddresses = array();
450
	$end_int = ip2ulong($endip);
451
	for ($ip_int = ip2ulong($startip); $ip_int <= $end_int; $ip_int++) {
452
		$rangeaddresses[] = long2ip($ip_int);
453
	}
454

    
455
	return $rangeaddresses;
456
}
457

    
458
/* Convert a range of IPv4 addresses to an array of subnets which can contain the range. */
459
/* Note: IPv6 ranges are not yet supported here. */
460
function ip_range_to_subnet_array($startip, $endip) {
461
	if (!is_ipaddrv4($startip) || !is_ipaddrv4($endip)) {
462
		return array();
463
	}
464

    
465
	if (ip_greater_than($startip, $endip)) {
466
		// Swap start and end so we can process sensibly.
467
		$temp = $startip;
468
		$startip = $endip;
469
		$endip = $temp;
470
	}
471

    
472
	// Container for subnets within this range.
473
	$rangesubnets = array();
474

    
475
	// Figure out what the smallest subnet is that holds the number of IPs in the given range.
476
	$cidr = find_smallest_cidr_v4(ip_range_size_v4($startip, $endip));
477

    
478
	// Loop here to reduce subnet size and retest as needed. We need to make sure
479
	//   that the target subnet is wholly contained between $startip and $endip.
480
	for ($cidr; $cidr <= 32; $cidr++) {
481
		// Find the network and broadcast addresses for the subnet being tested.
482
		$targetsub_min = gen_subnet($startip, $cidr);
483
		$targetsub_max = gen_subnet_max($startip, $cidr);
484

    
485
		// Check best case where the range is exactly one subnet.
486
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
487
			// Hooray, the range is exactly this subnet!
488
			return array("{$startip}/{$cidr}");
489
		}
490

    
491
		// These remaining scenarios will find a subnet that uses the largest
492
		//  chunk possible of the range being tested, and leave the rest to be
493
		//  tested recursively after the loop.
494

    
495
		// Check if the subnet begins with $startip and ends before $endip
496
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
497
			break;
498
		}
499

    
500
		// Check if the subnet ends at $endip and starts after $startip
501
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
502
			break;
503
		}
504

    
505
		// Check if the subnet is between $startip and $endip
506
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
507
			break;
508
		}
509
	}
510

    
511
	// Some logic that will recursively search from $startip to the first IP before the start of the subnet we just found.
512
	// NOTE: This may never be hit, the way the above algo turned out, but is left for completeness.
513
	if ($startip != $targetsub_min) {
514
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array($startip, ip_before($targetsub_min)));
515
	}
516

    
517
	// Add in the subnet we found before, to preserve ordering
518
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
519

    
520
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
521
	if ($endip != $targetsub_max) {
522
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
523
	}
524
	return $rangesubnets;
525
}
526

    
527
/* returns true if $range is a valid pair of IPv4 or IPv6 addresses separated by a "-"
528
   	false - if not a valid pair
529
   	true (numeric 4 or 6) - if valid, gives type of addresses */
530
function is_iprange($range) {
531
	if (substr_count($range, '-') != 1) {
532
		return false;
533
	}
534
	list($ip1, $ip2) = explode ('-', $range);
535
	if (is_ipaddrv4($ip1) && is_ipaddrv4($ip2))
536
		return 4;
537
	if (is_ipaddrv6($ip1) && is_ipaddrv6($ip2))
538
		return 6;
539
	return false;
540
}
541

    
542
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
543
function is_ipaddr($ipaddr) {
544
	if(is_ipaddrv4($ipaddr)) {
545
		return true;
546
	}
547
	if(is_ipaddrv6($ipaddr)) {
548
		return true;
549
	}
550
	return false;
551
}
552

    
553
/* returns true if $ipaddr is a valid IPv6 address */
554
function is_ipaddrv6($ipaddr) {
555
	if (!is_string($ipaddr) || empty($ipaddr))
556
		return false;
557
	if (strstr($ipaddr, "%") && is_linklocal($ipaddr)) {
558
		$tmpip = explode("%", $ipaddr);
559
		$ipaddr = $tmpip[0];
560
	}
561
	return Net_IPv6::checkIPv6($ipaddr);
562
}
563

    
564
/* returns true if $ipaddr is a valid dotted IPv4 address */
565
function is_ipaddrv4($ipaddr) {
566
	if (!is_string($ipaddr) || empty($ipaddr))
567
		return false;
568

    
569
	$ip_long = ip2long($ipaddr);
570
	$ip_reverse = long2ip32($ip_long);
571

    
572
	if ($ipaddr == $ip_reverse)
573
		return true;
574
	else
575
		return false;
576
}
577

    
578
/* returns true if $ipaddr is a valid linklocal address */
579
function is_linklocal($ipaddr) {
580
	return (strtolower(substr($ipaddr, 0, 5)) == "fe80:");
581
}
582

    
583
/* returns scope of a linklocal address */
584
function get_ll_scope($addr) {
585
	if (!is_linklocal($addr) || !strstr($addr, "%"))
586
		return "";
587
	list ($ll, $scope) = explode("%", $addr);
588
	return $scope;
589
}
590

    
591
/* returns true if $ipaddr is a valid literal IPv6 address */
592
function is_literalipaddrv6($ipaddr) {
593
	if(preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match))
594
		$ipaddr = $match[1];
595
	else
596
		return false;
597

    
598
	return is_ipaddrv6($ipaddr);
599
}
600

    
601
function is_ipaddrwithport($ipport) {
602
	$parts = explode(":", $ipport);
603
	$port = array_pop($parts);
604
	if (count($parts) == 1) {
605
		return is_ipaddrv4($parts[0]) && is_port($port);
606
	} elseif (count($parts) > 1) {
607
		return is_literalipaddrv6(implode(":", $parts)) && is_port($port);
608
	} else {
609
		return false;
610
	}
611
}
612

    
613
function is_hostnamewithport($hostport) {
614
	$parts = explode(":", $hostport);
615
	$port = array_pop($parts);
616
	if (count($parts) == 1) {
617
		return is_hostname($parts[0]) && is_port($port);
618
	} else {
619
		return false;
620
	}
621
}
622

    
623
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
624
function is_ipaddroralias($ipaddr) {
625
	global $config;
626

    
627
	if (is_alias($ipaddr)) {
628
		if (is_array($config['aliases']['alias'])) {
629
			foreach ($config['aliases']['alias'] as $alias) {
630
				if ($alias['name'] == $ipaddr && !preg_match("/port/i", $alias['type']))
631
					return true;
632
			}
633
		}
634
		return false;
635
	} else
636
		return is_ipaddr($ipaddr);
637

    
638
}
639

    
640
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format
641
   	false - if not a valid subnet
642
   	true (numeric 4 or 6) - if valid, gives type of subnet */
643
function is_subnet($subnet) {
644
	if (is_string($subnet) && preg_match('/^(?:([0-9.]{7,15})|([0-9a-f:]{2,39}))\/(\d{1,3})$/i', $subnet, $parts)) {
645
		if (is_ipaddrv4($parts[1]) && $parts[3] <= 32)
646
			return 4;
647
		if (is_ipaddrv6($parts[2]) && $parts[3] <= 128)
648
			return 6;
649
	}
650
	return false;
651
}
652

    
653
/* same as is_subnet() but accepts IPv4 only */
654
function is_subnetv4($subnet) {
655
	return (is_subnet($subnet) == 4);
656
}
657

    
658
/* same as is_subnet() but accepts IPv6 only */
659
function is_subnetv6($subnet) {
660
	return (is_subnet($subnet) == 6);
661
}
662

    
663
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
664
function is_subnetoralias($subnet) {
665
	global $aliastable;
666

    
667
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
668
		return true;
669
	else
670
		return is_subnet($subnet);
671
}
672

    
673
/* returns true if $hostname is a valid hostname */
674
function is_hostname($hostname) {
675
	if (!is_string($hostname))
676
		return false;
677

    
678
	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))
679
		return true;
680
	else
681
		return false;
682
}
683

    
684
/* returns true if $domain is a valid domain name */
685
function is_domain($domain) {
686
	if (!is_string($domain))
687
		return false;
688

    
689
	if (preg_match('/^(?:(?:[a-z_0-9]|[a-z_0-9][a-z_0-9\-]*[a-z_0-9])\.)*(?:[a-z_0-9]|[a-z_0-9][a-z_0-9\-]*[a-z_0-9\.])$/i', $domain))
690
		return true;
691
	else
692
		return false;
693
}
694

    
695
/* returns true if $macaddr is a valid MAC address */
696
function is_macaddr($macaddr, $partial=false) {
697
	$repeat = ($partial) ? '1,5' : '5';
698
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
699
}
700

    
701
/* returns true if $name is a valid name for an alias
702
   returns NULL if a reserved word is used
703
   returns FALSE for bad chars in the name - this allows calling code to determine what the problem was.
704
   aliases cannot be:
705
   	bad chars: anything except a-z 0-9 and underscore
706
   	bad names: empty string, pure numeric, pure underscore
707
   	reserved words: pre-defined service/protocol/port names which should not be ambiguous, and the words "port" and  "pass" */
708

    
709
function is_validaliasname($name) {
710
	/* Array of reserved words */
711
	$reserved = array("port", "pass");
712

    
713
	if (!is_string($name) || strlen($name) >= 32 || preg_match('/(^_*$|^\d*$|[^a-z0-9_])/i', $name))
714
		return false;
715
	if (in_array($name, $reserved, true) || getservbyname($name, "tcp") || getservbyname($name, "udp") || getprotobyname($name))
716
		return; /* return NULL */
717
	return true;
718
}
719

    
720
/* returns true if $port is a valid TCP/UDP port */
721
function is_port($port) {
722
	if (getservbyname($port, "tcp") || getservbyname($port, "udp"))
723
		return true;
724
	if (!ctype_digit($port))
725
		return false;
726
	else if ((intval($port) < 1) || (intval($port) > 65535))
727
		return false;
728
	return true;
729
}
730

    
731
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
732
function is_portrange($portrange) {
733
	$ports = explode(":", $portrange);
734

    
735
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
736
}
737

    
738
/* returns true if $port is a valid port number or an alias thereof */
739
function is_portoralias($port) {
740
	global $config;
741

    
742
	if (is_alias($port)) {
743
		if (is_array($config['aliases']['alias'])) {
744
			foreach ($config['aliases']['alias'] as $alias) {
745
				if ($alias['name'] == $port && preg_match("/port/i", $alias['type']))
746
					return true;
747
				}
748
			}
749
			return false;
750
	} else
751
		return is_port($port);
752
}
753

    
754
/* create ranges of sequential port numbers (200:215) and remove duplicates */
755
function group_ports($ports) {
756
	if (!is_array($ports) || empty($ports))
757
		return;
758

    
759
	$uniq = array();
760
	foreach ($ports as $port) {
761
		if (is_portrange($port)) {
762
			list($begin, $end) = explode(":", $port);
763
			if ($begin > $end) {
764
				$aux = $begin;
765
				$begin = $end;
766
				$end = $aux;
767
			}
768
			for ($i = $begin; $i <= $end; $i++)
769
				if (!in_array($i, $uniq))
770
					$uniq[] = $i;
771
		} else if (is_port($port)) {
772
			if (!in_array($port, $uniq))
773
				$uniq[] = $port;
774
		}
775
	}
776
	sort($uniq, SORT_NUMERIC);
777

    
778
	$result = array();
779
	foreach ($uniq as $idx => $port) {
780
		if ($idx == 0) {
781
			$result[] = $port;
782
			continue;
783
		}
784

    
785
		$last = end($result);
786
		if (is_portrange($last))
787
			list($begin, $end) = explode(":", $last);
788
		else
789
			$begin = $end = $last;
790

    
791
		if ($port == ($end+1)) {
792
			$end++;
793
			$result[count($result)-1] = "{$begin}:{$end}";
794
		} else {
795
			$result[] = $port;
796
		}
797
	}
798

    
799
	return $result;
800
}
801

    
802
/* returns true if $val is a valid shaper bandwidth value */
803
function is_valid_shaperbw($val) {
804
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
805
}
806

    
807
/* returns true if $test is in the range between $start and $end */
808
function is_inrange_v4($test, $start, $end) {
809
	if ( (ip2ulong($test) <= ip2ulong($end)) && (ip2ulong($test) >= ip2ulong($start)) )
810
		return true;
811
	else
812
		return false;
813
}
814

    
815
/* returns true if $test is in the range between $start and $end */
816
function is_inrange_v6($test, $start, $end) {
817
	if ( (inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start)) )
818
		return true;
819
	else
820
		return false;
821
}
822

    
823
/* returns true if $test is in the range between $start and $end */
824
function is_inrange($test, $start, $end) {
825
	return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
826
}
827

    
828
/* XXX: return the configured carp interface list */
829
function get_configured_carp_interface_list($carpinterface = '', $family = 'inet', $what = 'ip') {
830
	global $config;
831

    
832
	$iflist = array();
833

    
834
	if(is_array($config['virtualip']['vip'])) {
835
		$viparr = &$config['virtualip']['vip'];
836
		foreach ($viparr as $vip) {
837
			switch ($vip['mode']) {
838
			case "carp":
839
				if (!empty($carpinterface)) {
840
					if ($carpinterface == "{$vip['interface']}_vip{$vip['vhid']}") {
841
						switch ($what) {
842
						case 'subnet':
843
							if ($family == 'inet' && is_ipaddrv4($vip['subnet']))
844
								return "{$vip['subnet']}/{$vip['subnet_bits']}";
845
							else if ($family == 'inet6' && is_ipaddrv6($vip['subnet']))
846
								return "{$vip['subnet']}/{$vip['subnet_bits']}";
847
							break;
848
						case 'iface':
849
							if ($family == 'inet' && is_ipaddrv4($vip['subnet']))
850
								return $vip['interface'];
851
							else if ($family == 'inet6' && is_ipaddrv6($vip['subnet']))
852
								return $vip['interface'];
853
							break;
854
						case 'vip':
855
							if ($family == 'inet' && is_ipaddrv4($vip['subnet']))
856
								return $vip;
857
							else if ($family == 'inet6' && is_ipaddrv6($vip['subnet']))
858
								return $vip;
859
							break;
860
						case 'ip':
861
						default:
862
							if ($family == 'inet' && is_ipaddrv4($vip['subnet']))
863
								return $vip['subnet'];
864
							else if ($family == 'inet6' && is_ipaddrv6($vip['subnet']))
865
								return $vip['subnet'];
866
							break;
867
						}
868
					}
869
				} else {
870
					$iflist["{$vip['interface']}_vip{$vip['vhid']}"] = $vip['subnet'];
871
				}
872
				break;
873
			}
874
		}
875
	}
876

    
877
	return $iflist;
878
}
879

    
880
/* return the configured IP aliases list */
881
function get_configured_ip_aliases_list($returnfullentry = false) {
882
	global $config;
883

    
884
	$alias_list=array();
885

    
886
	if(is_array($config['virtualip']['vip'])) {
887
		$viparr = &$config['virtualip']['vip'];
888
		foreach ($viparr as $vip) {
889
			if ($vip['mode']=="ipalias") {
890
				if ($returnfullentry)
891
					$alias_list[$vip['subnet']] = $vip;
892
				else
893
					$alias_list[$vip['subnet']] = $vip['interface'];
894
			}
895
		}
896
	}
897

    
898
	return $alias_list;
899
}
900

    
901
/* return all configured aliases list (IP, carp, proxyarp and other) */
902
function get_configured_vips_list() {
903
	global $config;
904

    
905
	$alias_list=array();
906

    
907
	if(is_array($config['virtualip']['vip'])) {
908
		$viparr = &$config['virtualip']['vip'];
909
		foreach ($viparr as $vip) {
910
			if ($vip['mode'] == "carp")
911
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => "{$vip['interface']}_vip{$vip['vhid']}");
912
			else
913
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
914
		}
915
	}
916

    
917
	return $alias_list;
918
}
919

    
920
/* comparison function for sorting by the order in which interfaces are normally created */
921
function compare_interface_friendly_names($a, $b) {
922
	if ($a == $b)
923
		return 0;
924
	else if ($a == 'wan')
925
		return -1;
926
	else if ($b == 'wan')
927
		return 1;
928
	else if ($a == 'lan')
929
		return -1;
930
	else if ($b == 'lan')
931
		return 1;
932

    
933
	return strnatcmp($a, $b);
934
}
935

    
936
/* return the configured interfaces list. */
937
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
938
	global $config;
939

    
940
	$iflist = array();
941

    
942
	/* if list */
943
	foreach($config['interfaces'] as $if => $ifdetail) {
944
		if ($only_opt && ($if == "wan" || $if == "lan"))
945
			continue;
946
		if (isset($ifdetail['enable']) || $withdisabled == true)
947
			$iflist[$if] = $if;
948
	}
949

    
950
	return $iflist;
951
}
952

    
953
/* return the configured interfaces list. */
954
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
955
	global $config;
956

    
957
	$iflist = array();
958

    
959
	/* if list */
960
	foreach($config['interfaces'] as $if => $ifdetail) {
961
		if ($only_opt && ($if == "wan" || $if == "lan"))
962
			continue;
963
		if (isset($ifdetail['enable']) || $withdisabled == true) {
964
			$tmpif = get_real_interface($if);
965
			if (!empty($tmpif))
966
				$iflist[$tmpif] = $if;
967
		}
968
	}
969

    
970
	return $iflist;
971
}
972

    
973
/* return the configured interfaces list with their description. */
974
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
975
	global $config;
976

    
977
	$iflist = array();
978

    
979
	/* if list */
980
	foreach($config['interfaces'] as $if => $ifdetail) {
981
		if ($only_opt && ($if == "wan" || $if == "lan"))
982
			continue;
983
		if (isset($ifdetail['enable']) || $withdisabled == true) {
984
			if(empty($ifdetail['descr']))
985
				$iflist[$if] = strtoupper($if);
986
			else
987
				$iflist[$if] = strtoupper($ifdetail['descr']);
988
		}
989
	}
990

    
991
	return $iflist;
992
}
993

    
994
/*
995
 *   get_configured_ip_addresses() - Return a list of all configured
996
 *   interfaces IP Addresses
997
 *
998
 */
999
function get_configured_ip_addresses() {
1000
	global $config;
1001

    
1002
	if (!function_exists('get_interface_ip'))
1003
		require_once("interfaces.inc");
1004
	$ip_array = array();
1005
	$interfaces = get_configured_interface_list();
1006
	if (is_array($interfaces)) {
1007
		foreach($interfaces as $int) {
1008
			$ipaddr = get_interface_ip($int);
1009
			$ip_array[$int] = $ipaddr;
1010
		}
1011
	}
1012
	$interfaces = get_configured_carp_interface_list();
1013
	if (is_array($interfaces))
1014
		foreach($interfaces as $int => $ipaddr)
1015
			$ip_array[$int] = $ipaddr;
1016

    
1017
	/* pppoe server */
1018
	if (is_array($config['pppoes']) && is_array($config['pppoes']['pppoe'])) {
1019
		foreach($config['pppoes']['pppoe'] as $pppoe) {
1020
			if ($pppoe['mode'] == "server") {
1021
				if(is_ipaddr($pppoe['localip'])) {
1022
					$int = "pppoes". $pppoe['pppoeid'];
1023
					$ip_array[$int] = $pppoe['localip'];
1024
				}
1025
			}
1026
		}
1027
	}
1028

    
1029
	return $ip_array;
1030
}
1031

    
1032
/*
1033
 *   get_configured_ipv6_addresses() - Return a list of all configured
1034
 *   interfaces IPv6 Addresses
1035
 *
1036
 */
1037
function get_configured_ipv6_addresses() {
1038
	require_once("interfaces.inc");
1039
	$ipv6_array = array();
1040
	$interfaces = get_configured_interface_list();
1041
	if(is_array($interfaces)) {
1042
		foreach($interfaces as $int) {
1043
			$ipaddrv6 = get_interface_ipv6($int);
1044
			$ipv6_array[$int] = $ipaddrv6;
1045
		}
1046
	}
1047
	$interfaces = get_configured_carp_interface_list();
1048
	if(is_array($interfaces))
1049
		foreach($interfaces as $int => $ipaddrv6)
1050
			$ipv6_array[$int] = $ipaddrv6;
1051
	return $ipv6_array;
1052
}
1053

    
1054
/*
1055
 *   get_interface_list() - Return a list of all physical interfaces
1056
 *   along with MAC and status.
1057
 *
1058
 *   $mode = "active" - use ifconfig -lu
1059
 *           "media"  - use ifconfig to check physical connection
1060
 *			status (much slower)
1061
 */
1062
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
1063
	global $config;
1064
	$upints = array();
1065
	/* get a list of virtual interface types */
1066
	if(!$vfaces) {
1067
		$vfaces = array (
1068
				'bridge',
1069
				'ppp',
1070
				'pppoe',
1071
				'pptp',
1072
				'l2tp',
1073
				'sl',
1074
				'gif',
1075
				'gre',
1076
				'faith',
1077
				'lo',
1078
				'ng',
1079
				'_vlan',
1080
				'_wlan',
1081
				'pflog',
1082
				'plip',
1083
				'pfsync',
1084
				'enc',
1085
				'tun',
1086
				'carp',
1087
				'lagg',
1088
				'vip',
1089
				'ipfw'
1090
		);
1091
	}
1092
	switch($mode) {
1093
	case "active":
1094
		$upints = pfSense_interface_listget(IFF_UP);
1095
		break;
1096
	case "media":
1097
		$intlist = pfSense_interface_listget();
1098
		$ifconfig = "";
1099
		exec("/sbin/ifconfig -a", $ifconfig);
1100
		$regexp = '/(' . implode('|', $intlist) . '):\s/';
1101
		$ifstatus = preg_grep('/status:/', $ifconfig);
1102
		foreach($ifstatus as $status) {
1103
			$int = array_shift($intlist);
1104
			if(stristr($status, "active")) $upints[] = $int;
1105
		}
1106
		break;
1107
	default:
1108
		$upints = pfSense_interface_listget();
1109
		break;
1110
	}
1111
	/* build interface list with netstat */
1112
	$linkinfo = "";
1113
	exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
1114
	array_shift($linkinfo);
1115
	/* build ip address list with netstat */
1116
	$ipinfo = "";
1117
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
1118
	array_shift($ipinfo);
1119
	foreach($linkinfo as $link) {
1120
		$friendly = "";
1121
		$alink = explode(" ", $link);
1122
		$ifname = rtrim(trim($alink[0]), '*');
1123
		/* trim out all numbers before checking for vfaces */
1124
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
1125
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
1126
			$toput = array(
1127
					"mac" => trim($alink[1]),
1128
					"up" => in_array($ifname, $upints)
1129
				);
1130
			foreach($ipinfo as $ip) {
1131
				$aip = explode(" ", $ip);
1132
				if($aip[0] == $ifname) {
1133
					$toput['ipaddr'] = $aip[1];
1134
				}
1135
			}
1136
			if (is_array($config['interfaces'])) {
1137
				foreach($config['interfaces'] as $name => $int)
1138
					if($int['if'] == $ifname) $friendly = $name;
1139
			}
1140
			switch($keyby) {
1141
			case "physical":
1142
				if($friendly != "") {
1143
					$toput['friendly'] = $friendly;
1144
				}
1145
				$dmesg_arr = array();
1146
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
1147
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
1148
				$toput['dmesg'] = $dmesg[1][0];
1149
				$iflist[$ifname] = $toput;
1150
				break;
1151
			case "ppp":
1152

    
1153
			case "friendly":
1154
				if($friendly != "") {
1155
					$toput['if'] = $ifname;
1156
					$iflist[$friendly] = $toput;
1157
				}
1158
				break;
1159
			}
1160
		}
1161
	}
1162
	return $iflist;
1163
}
1164

    
1165
/****f* util/log_error
1166
* NAME
1167
*   log_error  - Sends a string to syslog.
1168
* INPUTS
1169
*   $error     - string containing the syslog message.
1170
* RESULT
1171
*   null
1172
******/
1173
function log_error($error) {
1174
	global $g;
1175
	$page = $_SERVER['SCRIPT_NAME'];
1176
	if (empty($page)) {
1177
		$files = get_included_files();
1178
		$page = basename($files[0]);
1179
	}
1180
	syslog(LOG_ERR, "$page: $error");
1181
	if ($g['debug'])
1182
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1183
	return;
1184
}
1185

    
1186
/****f* util/log_auth
1187
* NAME
1188
*   log_auth   - Sends a string to syslog as LOG_AUTH facility
1189
* INPUTS
1190
*   $error     - string containing the syslog message.
1191
* RESULT
1192
*   null
1193
******/
1194
function log_auth($error) {
1195
	global $g;
1196
	$page = $_SERVER['SCRIPT_NAME'];
1197
	syslog(LOG_AUTH, "$page: $error");
1198
	if ($g['debug'])
1199
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1200
	return;
1201
}
1202

    
1203
/****f* util/exec_command
1204
 * NAME
1205
 *   exec_command - Execute a command and return a string of the result.
1206
 * INPUTS
1207
 *   $command   - String of the command to be executed.
1208
 * RESULT
1209
 *   String containing the command's result.
1210
 * NOTES
1211
 *   This function returns the command's stdout and stderr.
1212
 ******/
1213
function exec_command($command) {
1214
	$output = array();
1215
	exec($command . ' 2>&1', $output);
1216
	return(implode("\n", $output));
1217
}
1218

    
1219
/* wrapper for exec() */
1220
function mwexec($command, $mute = false, $clearsigmask = false) {
1221
	global $g;
1222

    
1223
	if ($g['debug']) {
1224
		if (!$_SERVER['REMOTE_ADDR'])
1225
			echo "mwexec(): $command\n";
1226
	}
1227
	$oarr = array();
1228
	$retval = 0;
1229

    
1230
	if ($clearsigmask) {
1231
		$oldset = array();
1232
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1233
	}
1234
	$garbage = exec("$command 2>&1", $oarr, $retval);
1235
	if ($clearsigmask) {
1236
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1237
	}
1238

    
1239
	if(isset($config['system']['developerspew']))
1240
		$mute = false;
1241
	if(($retval <> 0) && ($mute === false)) {
1242
		$output = implode(" ", $oarr);
1243
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
1244
		unset($output);
1245
	}
1246
	unset($oarr);
1247
	return $retval;
1248
}
1249

    
1250
/* wrapper for exec() in background */
1251
function mwexec_bg($command, $clearsigmask = false) {
1252
	global $g;
1253

    
1254
	if ($g['debug']) {
1255
		if (!$_SERVER['REMOTE_ADDR'])
1256
			echo "mwexec(): $command\n";
1257
	}
1258

    
1259
	if ($clearsigmask) {
1260
		$oldset = array();
1261
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1262
	}
1263
	$_gb = exec("/usr/bin/nohup $command > /dev/null 2>&1 &");
1264
	if ($clearsigmask) {
1265
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1266
	}
1267
	unset($_gb);
1268
}
1269

    
1270
/* unlink a file, if it exists */
1271
function unlink_if_exists($fn) {
1272
	$to_do = glob($fn);
1273
	if(is_array($to_do)) {
1274
		foreach($to_do as $filename)
1275
			@unlink($filename);
1276
	} else {
1277
		@unlink($fn);
1278
	}
1279
}
1280
/* make a global alias table (for faster lookups) */
1281
function alias_make_table($config) {
1282
	global $aliastable;
1283

    
1284
	$aliastable = array();
1285

    
1286
	if (is_array($config['aliases']['alias'])) {
1287
		foreach ($config['aliases']['alias'] as $alias) {
1288
			if ($alias['name'])
1289
				$aliastable[$alias['name']] = $alias['address'];
1290
		}
1291
	}
1292
}
1293

    
1294
/* check if an alias exists */
1295
function is_alias($name) {
1296
	global $aliastable;
1297

    
1298
	return isset($aliastable[$name]);
1299
}
1300

    
1301
function alias_get_type($name) {
1302
	global $config;
1303

    
1304
	if (is_array($config['aliases']['alias'])) {
1305
		foreach ($config['aliases']['alias'] as $alias) {
1306
			if ($name == $alias['name'])
1307
				return $alias['type'];
1308
		}
1309
	}
1310

    
1311
	return "";
1312
}
1313

    
1314
/* expand a host or network alias, if necessary */
1315
function alias_expand($name) {
1316
	global $aliastable;
1317

    
1318
	if (isset($aliastable[$name]))
1319
		return "\${$name}";
1320
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name) || is_portrange($name))
1321
		return "{$name}";
1322
	else
1323
		return null;
1324
}
1325

    
1326
function alias_expand_urltable($name) {
1327
	global $config;
1328
	$urltable_prefix = "/var/db/aliastables/";
1329
	$urltable_filename = $urltable_prefix . $name . ".txt";
1330

    
1331
	if (is_array($config['aliases']['alias'])) {
1332
		foreach ($config['aliases']['alias'] as $alias) {
1333
			if (preg_match("/urltable/i", $alias['type']) && ($alias['name'] == $name)) {
1334
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1335
					return $urltable_filename;
1336
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1337
					return $urltable_filename;
1338
			}
1339
		}
1340
	}
1341
	return null;
1342
}
1343

    
1344
function subnet_size($subnet) {
1345
	if (is_subnetv4($subnet)) {
1346
		list ($ip, $bits) = explode("/", $subnet);
1347
		return round(exp(log(2) * (32 - $bits)));
1348
	}
1349
	else if (is_subnetv6($subnet)) {
1350
		list ($ip, $bits) = explode("/", $subnet);
1351
		return round(exp(log(2) * (128 - $bits)));
1352
	}
1353
	else {
1354
		return 0;
1355
	}
1356
}
1357

    
1358
function subnet_expand($subnet) {
1359
	if (is_subnetv4($subnet)) {
1360
		return subnetv4_expand($subnet);
1361
	} else if (is_subnetv6($subnet)) {
1362
		return subnetv6_expand($subnet);
1363
	} else {
1364
		return $subnet;
1365
	}
1366
}
1367

    
1368
function subnetv4_expand($subnet) {
1369
	$result = array();
1370
	list ($ip, $bits) = explode("/", $subnet);
1371
	$net  = ip2long($ip);
1372
	$mask = (0xffffffff << (32 - $bits));
1373
	$net &= $mask;
1374
	$size = round(exp(log(2) * (32 - $bits)));
1375
	for ($i = 0; $i < $size; $i += 1) {
1376
		$result[] = long2ip($net | $i);
1377
	}
1378
	return $result;
1379
}
1380

    
1381
/* find out whether two subnets overlap */
1382
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1383

    
1384
	if (!is_numeric($bits1))
1385
		$bits1 = 32;
1386
	if (!is_numeric($bits2))
1387
		$bits2 = 32;
1388

    
1389
	if ($bits1 < $bits2)
1390
		$relbits = $bits1;
1391
	else
1392
		$relbits = $bits2;
1393

    
1394
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1395
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1396

    
1397
	return ($sn1 == $sn2);
1398
}
1399

    
1400
/* find out whether two IPv6 subnets overlap */
1401
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
1402
	$sub1_min = gen_subnetv6($subnet1, $bits1);
1403
	$sub1_max = gen_subnetv6_max($subnet1, $bits1);
1404
	$sub2_min = gen_subnetv6($subnet2, $bits2);
1405
	$sub2_max = gen_subnetv6_max($subnet2, $bits2);
1406

    
1407
	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));
1408
}
1409

    
1410
/* compare two IP addresses */
1411
function ipcmp($a, $b) {
1412
	if (ip_less_than($a, $b))
1413
		return -1;
1414
	else if (ip_greater_than($a, $b))
1415
		return 1;
1416
	else
1417
		return 0;
1418
}
1419

    
1420
/* return true if $addr is in $subnet, false if not */
1421
function ip_in_subnet($addr,$subnet) {
1422
	if(is_ipaddrv6($addr)) {
1423
		return (Net_IPv6::isInNetmask($addr, $subnet));
1424
	} else { /* XXX: Maybe check for IPv4 */
1425
		list($ip, $mask) = explode('/', $subnet);
1426
		$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1427
		return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1428
	}
1429
}
1430

    
1431
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1432
function verify_digital_signature($fname) {
1433
	global $g;
1434

    
1435
	if(!file_exists("/usr/local/sbin/gzsig"))
1436
		return 4;
1437

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

    
1441
/* obtain MAC address given an IP address by looking at the ARP table */
1442
function arp_get_mac_by_ip($ip) {
1443
	mwexec("/sbin/ping -c 1 -t 1 " . escapeshellarg($ip), true);
1444
	$arpoutput = "";
1445
	exec("/usr/sbin/arp -n " . escapeshellarg($ip), $arpoutput);
1446

    
1447
	if ($arpoutput[0]) {
1448
		$arpi = explode(" ", $arpoutput[0]);
1449
		$macaddr = $arpi[3];
1450
		if (is_macaddr($macaddr))
1451
			return $macaddr;
1452
		else
1453
			return false;
1454
	}
1455

    
1456
	return false;
1457
}
1458

    
1459
/* return a fieldname that is safe for xml usage */
1460
function xml_safe_fieldname($fieldname) {
1461
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1462
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1463
			 ':', ',', '.', '\'', '\\'
1464
		);
1465
	return strtolower(str_replace($replace, "", $fieldname));
1466
}
1467

    
1468
function mac_format($clientmac) {
1469
	global $config, $cpzone;
1470

    
1471
	$mac = explode(":", $clientmac);
1472
	$mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1473

    
1474
	switch($mac_format) {
1475
	case 'singledash':
1476
		return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1477

    
1478
	case 'ietf':
1479
		return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1480

    
1481
	case 'cisco':
1482
		return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1483

    
1484
	case 'unformatted':
1485
		return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1486

    
1487
	default:
1488
		return $clientmac;
1489
	}
1490
}
1491

    
1492
function resolve_retry($hostname, $retries = 5) {
1493

    
1494
	if (is_ipaddr($hostname))
1495
		return $hostname;
1496

    
1497
	for ($i = 0; $i < $retries; $i++) {
1498
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1499
		$ip = gethostbyname($hostname);
1500

    
1501
		if ($ip && $ip != $hostname) {
1502
			/* success */
1503
			return $ip;
1504
		}
1505

    
1506
		sleep(1);
1507
	}
1508

    
1509
	return false;
1510
}
1511

    
1512
function format_bytes($bytes) {
1513
	if ($bytes >= 1073741824) {
1514
		return sprintf("%.2f GB", $bytes/1073741824);
1515
	} else if ($bytes >= 1048576) {
1516
		return sprintf("%.2f MB", $bytes/1048576);
1517
	} else if ($bytes >= 1024) {
1518
		return sprintf("%.0f KB", $bytes/1024);
1519
	} else {
1520
		return sprintf("%d bytes", $bytes);
1521
	}
1522
}
1523

    
1524
function update_filter_reload_status($text) {
1525
	global $g;
1526

    
1527
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1528
}
1529

    
1530
/****** util/return_dir_as_array
1531
 * NAME
1532
 *   return_dir_as_array - Return a directory's contents as an array.
1533
 * INPUTS
1534
 *   $dir          - string containing the path to the desired directory.
1535
 *   $filter_regex - string containing a regular expression to filter file names. Default empty.
1536
 * RESULT
1537
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1538
 ******/
1539
function return_dir_as_array($dir, $filter_regex = '') {
1540
	$dir_array = array();
1541
	if (is_dir($dir)) {
1542
		if ($dh = opendir($dir)) {
1543
			while (($file = readdir($dh)) !== false) {
1544
				if (($file == ".") || ($file == ".."))
1545
					continue;
1546

    
1547
				if (empty($filter_regex) || preg_match($filter_regex, $file))
1548
					array_push($dir_array, $file);
1549
			}
1550
			closedir($dh);
1551
		}
1552
	}
1553
	return $dir_array;
1554
}
1555

    
1556
function run_plugins($directory) {
1557
	global $config, $g;
1558

    
1559
	/* process packager manager custom rules */
1560
	$files = return_dir_as_array($directory);
1561
	if (is_array($files)) {
1562
		foreach ($files as $file) {
1563
			if (stristr($file, ".sh") == true)
1564
				mwexec($directory . $file . " start");
1565
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc"))
1566
				require_once($directory . "/" . $file);
1567
		}
1568
	}
1569
}
1570

    
1571
/*
1572
 *    safe_mkdir($path, $mode = 0755)
1573
 *    create directory if it doesn't already exist and isn't a file!
1574
 */
1575
function safe_mkdir($path, $mode=0755) {
1576
	global $g;
1577

    
1578
	if (!is_file($path) && !is_dir($path)) {
1579
		return @mkdir($path, $mode, true);
1580
	} else {
1581
		return false;
1582
	}
1583
}
1584

    
1585
/*
1586
 * make_dirs($path, $mode = 0755)
1587
 * create directory tree recursively (mkdir -p)
1588
 */
1589
function make_dirs($path, $mode = 0755) {
1590
	$base = '';
1591
	foreach (explode('/', $path) as $dir) {
1592
		$base .= "/$dir";
1593
		if (!is_dir($base)) {
1594
			if (!@mkdir($base, $mode))
1595
				return false;
1596
		}
1597
	}
1598
	return true;
1599
}
1600

    
1601
/*
1602
 * get_sysctl($names)
1603
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1604
 * name) and return an array of key/value pairs set for those that exist
1605
 */
1606
function get_sysctl($names) {
1607
	if (empty($names))
1608
		return array();
1609

    
1610
	if (is_array($names)) {
1611
		$name_list = array();
1612
		foreach ($names as $name) {
1613
			$name_list[] = escapeshellarg($name);
1614
		}
1615
	} else
1616
		$name_list = array(escapeshellarg($names));
1617

    
1618
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1619
	$values = array();
1620
	foreach ($output as $line) {
1621
		$line = explode(": ", $line, 2);
1622
		if (count($line) == 2)
1623
			$values[$line[0]] = $line[1];
1624
	}
1625

    
1626
	return $values;
1627
}
1628

    
1629
/*
1630
 * get_single_sysctl($name)
1631
 * Wrapper for get_sysctl() to simplify read of a single sysctl value
1632
 * return the value for sysctl $name or empty string if it doesn't exist
1633
 */
1634
function get_single_sysctl($name) {
1635
	if (empty($name))
1636
		return "";
1637

    
1638
	$value = get_sysctl($name);
1639
	if (empty($value) || !isset($value[$name]))
1640
		return "";
1641

    
1642
	return $value[$name];
1643
}
1644

    
1645
/*
1646
 * set_sysctl($value_list)
1647
 * Set sysctl OID's listed as key/value pairs and return
1648
 * an array with keys set for those that succeeded
1649
 */
1650
function set_sysctl($values) {
1651
	if (empty($values))
1652
		return array();
1653

    
1654
	$value_list = array();
1655
	foreach ($values as $key => $value) {
1656
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1657
	}
1658

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

    
1661
	/* Retry individually if failed (one or more read-only) */
1662
	if ($success <> 0 && count($value_list) > 1) {
1663
		foreach ($value_list as $value) {
1664
			exec("/sbin/sysctl -i " . $value, $output);
1665
		}
1666
	}
1667

    
1668
	$ret = array();
1669
	foreach ($output as $line) {
1670
		$line = explode(": ", $line, 2);
1671
		if (count($line) == 2)
1672
			$ret[$line[0]] = true;
1673
	}
1674

    
1675
	return $ret;
1676
}
1677

    
1678
/*
1679
 * set_single_sysctl($name, $value)
1680
 * Wrapper to set_sysctl() to make it simple to set only one sysctl
1681
 * returns boolean meaning if it suceed
1682
 */
1683
function set_single_sysctl($name, $value) {
1684
	if (empty($name))
1685
		return false;
1686

    
1687
	$result = set_sysctl(array($name => $value));
1688

    
1689
	if (!isset($result[$name]) || $result[$name] != $value)
1690
		return false;
1691

    
1692
	return true;
1693
}
1694

    
1695
/*
1696
 *     get_memory()
1697
 *     returns an array listing the amount of
1698
 *     memory installed in the hardware
1699
 *     [0] net memory available for the OS (FreeBSD) after some is taken by BIOS, video or whatever - e.g. 235 MBytes
1700
 *     [1] real (actual) memory of the system, should be the size of the RAM card/s - e.g. 256 MBytes
1701
 */
1702
function get_memory() {
1703
	$physmem = get_single_sysctl("hw.physmem");
1704
	$realmem = get_single_sysctl("hw.realmem");
1705
	/* convert from bytes to megabytes */
1706
	return array(($physmem/1048576),($realmem/1048576));
1707
}
1708

    
1709
function mute_kernel_msgs() {
1710
	global $config;
1711
	// Do not mute serial console.  The kernel gets very very cranky
1712
	// and will start dishing you cannot control tty errors.
1713
	switch (trim(file_get_contents("/etc/platform"))) {
1714
		case "nanobsd":
1715
		case "jail":
1716
			return;
1717
	}
1718
	if($config['system']['enableserial'])
1719
		return;
1720
	exec("/sbin/conscontrol mute on");
1721
}
1722

    
1723
function unmute_kernel_msgs() {
1724
	global $config;
1725
	// Do not mute serial console.  The kernel gets very very cranky
1726
	// and will start dishing you cannot control tty errors.
1727
	switch (trim(file_get_contents("/etc/platform"))) {
1728
		case "nanobsd":
1729
		case "jail":
1730
			return;
1731
	}
1732
	exec("/sbin/conscontrol mute off");
1733
}
1734

    
1735
function start_devd() {
1736
	global $g;
1737

    
1738
	if ($g['platform'] == 'jail')
1739
		return;
1740
	exec("/sbin/devd");
1741
	sleep(1);
1742
}
1743

    
1744
function is_interface_vlan_mismatch() {
1745
	global $config, $g;
1746

    
1747
	if (is_array($config['vlans']['vlan'])) {
1748
		foreach ($config['vlans']['vlan'] as $vlan) {
1749
			if (does_interface_exist($vlan['if']) == false)
1750
				return true;
1751
		}
1752
	}
1753

    
1754
	return false;
1755
}
1756

    
1757
function is_interface_mismatch() {
1758
	global $config, $g;
1759

    
1760
	$do_assign = false;
1761
	$i = 0;
1762
	$missing_interfaces = array();
1763
	if (is_array($config['interfaces'])) {
1764
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1765
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1766
				// Do not check these interfaces.
1767
				$i++;
1768
				continue;
1769
			}
1770
			else if (does_interface_exist($ifcfg['if']) == false) {
1771
				$missing_interfaces[] = $ifcfg['if'];
1772
				$do_assign = true;
1773
			} else
1774
				$i++;
1775
		}
1776
	}
1777

    
1778
	if (file_exists("{$g['tmp_path']}/assign_complete"))
1779
		$do_assign = false;
1780

    
1781
	if (!empty($missing_interfaces) && $do_assign)
1782
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1783
	else
1784
		@unlink("{$g['tmp_path']}/missing_interfaces");
1785

    
1786
	return $do_assign;
1787
}
1788

    
1789
/* sync carp entries to other firewalls */
1790
function carp_sync_client() {
1791
	global $g;
1792
	send_event("filter sync");
1793
}
1794

    
1795
/****f* util/isAjax
1796
 * NAME
1797
 *   isAjax - reports if the request is driven from prototype
1798
 * INPUTS
1799
 *   none
1800
 * RESULT
1801
 *   true/false
1802
 ******/
1803
function isAjax() {
1804
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1805
}
1806

    
1807
/****f* util/timeout
1808
 * NAME
1809
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1810
 * INPUTS
1811
 *   optional, seconds to wait before timeout. Default 9 seconds.
1812
 * RESULT
1813
 *   returns 1 char of user input or null if no input.
1814
 ******/
1815
function timeout($timer = 9) {
1816
	while(!isset($key)) {
1817
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1818
		else { echo chr(8). "{$timer}"; }
1819
		`/bin/stty -icanon min 0 time 25`;
1820
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1821
		`/bin/stty icanon`;
1822
		if ($key == '')
1823
			unset($key);
1824
		$timer--;
1825
		if ($timer == 0)
1826
			break;
1827
	}
1828
	return $key;
1829
}
1830

    
1831
/****f* util/msort
1832
 * NAME
1833
 *   msort - sort array
1834
 * INPUTS
1835
 *   $array to be sorted, field to sort by, direction of sort
1836
 * RESULT
1837
 *   returns newly sorted array
1838
 ******/
1839
function msort($array, $id="id", $sort_ascending=true) {
1840
	$temp_array = array();
1841
	while(count($array)>0) {
1842
		$lowest_id = 0;
1843
		$index=0;
1844
		foreach ($array as $item) {
1845
			if (isset($item[$id])) {
1846
				if ($array[$lowest_id][$id]) {
1847
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1848
						$lowest_id = $index;
1849
					}
1850
				}
1851
			}
1852
			$index++;
1853
		}
1854
		$temp_array[] = $array[$lowest_id];
1855
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1856
	}
1857
	if ($sort_ascending) {
1858
		return $temp_array;
1859
	} else {
1860
		return array_reverse($temp_array);
1861
	}
1862
}
1863

    
1864
/****f* util/is_URL
1865
 * NAME
1866
 *   is_URL
1867
 * INPUTS
1868
 *   string to check
1869
 * RESULT
1870
 *   Returns true if item is a URL
1871
 ******/
1872
function is_URL($url) {
1873
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1874
	if($match)
1875
		return true;
1876
	return false;
1877
}
1878

    
1879
function is_file_included($file = "") {
1880
	$files = get_included_files();
1881
	if (in_array($file, $files))
1882
		return true;
1883

    
1884
	return false;
1885
}
1886

    
1887
/*
1888
 * Replace a value on a deep associative array using regex
1889
 */
1890
function array_replace_values_recursive($data, $match, $replace) {
1891
	if (empty($data))
1892
		return $data;
1893

    
1894
	if (is_string($data))
1895
		$data = preg_replace("/{$match}/", $replace, $data);
1896
	else if (is_array($data))
1897
		foreach ($data as $k => $v)
1898
			$data[$k] = array_replace_values_recursive($v, $match, $replace);
1899

    
1900
	return $data;
1901
}
1902

    
1903
/*
1904
	This function was borrowed from a comment on PHP.net at the following URL:
1905
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1906
 */
1907
function array_merge_recursive_unique($array0, $array1) {
1908

    
1909
	$arrays = func_get_args();
1910
	$remains = $arrays;
1911

    
1912
	// We walk through each arrays and put value in the results (without
1913
	// considering previous value).
1914
	$result = array();
1915

    
1916
	// loop available array
1917
	foreach($arrays as $array) {
1918

    
1919
		// The first remaining array is $array. We are processing it. So
1920
		// we remove it from remaing arrays.
1921
		array_shift($remains);
1922

    
1923
		// We don't care non array param, like array_merge since PHP 5.0.
1924
		if(is_array($array)) {
1925
			// Loop values
1926
			foreach($array as $key => $value) {
1927
				if(is_array($value)) {
1928
					// we gather all remaining arrays that have such key available
1929
					$args = array();
1930
					foreach($remains as $remain) {
1931
						if(array_key_exists($key, $remain)) {
1932
							array_push($args, $remain[$key]);
1933
						}
1934
					}
1935

    
1936
					if(count($args) > 2) {
1937
						// put the recursion
1938
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1939
					} else {
1940
						foreach($value as $vkey => $vval) {
1941
							$result[$key][$vkey] = $vval;
1942
						}
1943
					}
1944
				} else {
1945
					// simply put the value
1946
					$result[$key] = $value;
1947
				}
1948
			}
1949
		}
1950
	}
1951
	return $result;
1952
}
1953

    
1954

    
1955
/*
1956
 * converts a string like "a,b,c,d"
1957
 * into an array like array("a" => "b", "c" => "d")
1958
 */
1959
function explode_assoc($delimiter, $string) {
1960
	$array = explode($delimiter, $string);
1961
	$result = array();
1962
	$numkeys = floor(count($array) / 2);
1963
	for ($i = 0; $i < $numkeys; $i += 1) {
1964
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
1965
	}
1966
	return $result;
1967
}
1968

    
1969
function get_staticroutes($returnsubnetsonly = false, $returnhostnames = false) {
1970
	global $config, $aliastable;
1971

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

    
1976
	$allstaticroutes = array();
1977
	$allsubnets = array();
1978
	/* Loop through routes and expand aliases as we find them. */
1979
	foreach ($config['staticroutes']['route'] as $route) {
1980
		if (is_alias($route['network'])) {
1981
			if (!isset($aliastable[$route['network']]))
1982
				continue;
1983

    
1984
			$subnets = preg_split('/\s+/', $aliastable[$route['network']]);
1985
			foreach ($subnets as $net) {
1986
				if (!is_subnet($net)) {
1987
					if (is_ipaddrv4($net))
1988
						$net .= "/32";
1989
					else if (is_ipaddrv6($net))
1990
						$net .= "/128";
1991
					else if ($returnhostnames === false || !is_fqdn($net))
1992
						continue;
1993
				}
1994
				$temproute = $route;
1995
				$temproute['network'] = $net;
1996
				$allstaticroutes[] = $temproute;
1997
				$allsubnets[] = $net;
1998
			}
1999
		} elseif (is_subnet($route['network'])) {
2000
			$allstaticroutes[] = $route;
2001
			$allsubnets[] = $route['network'];
2002
		}
2003
	}
2004
	if ($returnsubnetsonly)
2005
		return $allsubnets;
2006
	else
2007
		return $allstaticroutes;
2008
}
2009

    
2010
/****f* util/get_alias_list
2011
 * NAME
2012
 *   get_alias_list - Provide a list of aliases.
2013
 * INPUTS
2014
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
2015
 * RESULT
2016
 *   Array containing list of aliases.
2017
 *   If $type is unspecified, all aliases are returned.
2018
 *   If $type is a string, all aliases of the type specified in $type are returned.
2019
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
2020
 */
2021
function get_alias_list($type = null) {
2022
	global $config;
2023
	$result = array();
2024
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
2025
		foreach ($config['aliases']['alias'] as $alias) {
2026
			if ($type === null) {
2027
				$result[] = $alias['name'];
2028
			}
2029
			else if (is_array($type)) {
2030
				if (in_array($alias['type'], $type)) {
2031
					$result[] = $alias['name'];
2032
				}
2033
			}
2034
			else if ($type === $alias['type']) {
2035
				$result[] = $alias['name'];
2036
			}
2037
		}
2038
	}
2039
	return $result;
2040
}
2041

    
2042
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
2043
function array_exclude($needle, $haystack) {
2044
	$result = array();
2045
	if (is_array($haystack)) {
2046
		foreach ($haystack as $thing) {
2047
			if ($needle !== $thing) {
2048
				$result[] = $thing;
2049
			}
2050
		}
2051
	}
2052
	return $result;
2053
}
2054

    
2055
function get_current_theme() {
2056
	global $config, $g;
2057
	/*
2058
	 *   if user has selected a custom template, use it.
2059
	 *   otherwise default to pfsense tempalte
2060
	 */
2061
	if (($g["disablethemeselection"] === true) && !empty($g["default_theme"]) && (is_dir($g["www_path"].'/themes/'.$g["default_theme"])))
2062
		$theme = $g["default_theme"];
2063
	elseif($config['theme'] <> "" && (is_dir($g["www_path"].'/themes/'.$config['theme'])))
2064
		$theme = $config['theme'];
2065
	else
2066
		$theme = "pfsense";
2067
	/*
2068
	 *  If this device is an apple ipod/iphone
2069
	 *  switch the theme to one that works with it.
2070
	 */
2071
	$lowres_ua = array("iPhone", "iPod", "iPad", "Android", "BlackBerry", "Opera Mini", "Opera Mobi", "PlayBook", "IEMobile");
2072
	foreach($lowres_ua as $useragent)
2073
		if(strstr($_SERVER['HTTP_USER_AGENT'], $useragent))
2074
			$theme = (empty($g['theme_lowres']) && (is_dir($g["www_path"].'/themes/'.$g['theme_lowres']))) ? "pfsense" : $g['theme_lowres'];
2075
	return $theme;
2076
}
2077

    
2078
/* Define what is preferred, IPv4 or IPv6 */
2079
function prefer_ipv4_or_ipv6() {
2080
	global $config;
2081

    
2082
	if (isset($config['system']['prefer_ipv4']))
2083
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv4");
2084
	else
2085
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv6");
2086
}
2087

    
2088
/* Redirect to page passing parameters via POST */
2089
function post_redirect($page, $params) {
2090
	if (!is_array($params))
2091
		return;
2092

    
2093
	print "<html><body><form action=\"{$page}\" name=\"formredir\" method=\"post\">\n";
2094
	foreach ($params as $key => $value) {
2095
		print "<input type=\"hidden\" name=\"{$key}\" value=\"{$value}\" />\n";
2096
	}
2097
	print "</form><script type=\"text/javascript\">document.formredir.submit();</script>\n";
2098
	print "</body></html>\n";
2099
}
2100

    
2101
/* Locate disks that can be queried for S.M.A.R.T. data. */
2102
function get_smart_drive_list() {
2103
	$disk_list = explode(" ", get_single_sysctl("kern.disks"));
2104
	foreach ($disk_list as $id => $disk) {
2105
		// We only want certain kinds of disks for S.M.A.R.T.
2106
		// 1 is a match, 0 is no match, False is any problem processing the regex
2107
		if (preg_match("/^(ad|da|ada).*[0-9]{1,2}$/", $disk) !== 1) {
2108
			unset($disk_list[$id]);
2109
		}
2110
	}
2111
	sort($disk_list);
2112
	return $disk_list;
2113
}
2114

    
2115
?>
(56-56/68)