Project

General

Profile

Download (61.8 KB) Statistics
| Branch: | Tag: | Revision:
1 86a5e1a8 Renato Botelho
<?php
2 417fc5c4 Scott Ullrich
/*
3 5b237745 Scott Ullrich
	util.inc
4
*/
5 995df6c3 Stephen Beaver
/* ====================================================================
6
 *	Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
7 ba360ed7 Stephen Beaver
 *
8
 *  Some or all of this file is based on the m0n0wall project which is
9
 *  Copyright (c)  2004 Manuel Kasper (BSD 2 clause)
10 995df6c3 Stephen Beaver
 *
11
 *	Redistribution and use in source and binary forms, with or without modification,
12
 *	are permitted provided that the following conditions are met:
13
 *
14
 *	1. Redistributions of source code must retain the above copyright notice,
15
 *		this list of conditions and the following disclaimer.
16
 *
17
 *	2. Redistributions in binary form must reproduce the above copyright
18
 *		notice, this list of conditions and the following disclaimer in
19
 *		the documentation and/or other materials provided with the
20
 *		distribution.
21
 *
22
 *	3. All advertising materials mentioning features or use of this software
23
 *		must display the following acknowledgment:
24
 *		"This product includes software developed by the pfSense Project
25
 *		 for use in the pfSense software distribution. (http://www.pfsense.org/).
26
 *
27
 *	4. The names "pfSense" and "pfSense Project" must not be used to
28
 *		 endorse or promote products derived from this software without
29
 *		 prior written permission. For written permission, please contact
30
 *		 coreteam@pfsense.org.
31
 *
32
 *	5. Products derived from this software may not be called "pfSense"
33
 *		nor may "pfSense" appear in their names without prior written
34
 *		permission of the Electric Sheep Fencing, LLC.
35
 *
36
 *	6. Redistributions of any form whatsoever must retain the following
37
 *		acknowledgment:
38
 *
39
 *	"This product includes software developed by the pfSense Project
40
 *	for use in the pfSense software distribution (http://www.pfsense.org/).
41
 *
42
 *	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
43
 *	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44
 *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
45
 *	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
46
 *	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47
 *	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48
 *	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
49
 *	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50
 *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
51
 *	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52
 *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
53
 *	OF THE POSSIBILITY OF SUCH DAMAGE.
54
 *
55
 *	====================================================================
56
 *
57
 */
58 523855b0 Scott Ullrich
59 5b237745 Scott Ullrich
/* kill a process by pid file */
60
function killbypid($pidfile) {
61 435a418f Ermal
	return sigkillbypid($pidfile, "TERM");
62 5b237745 Scott Ullrich
}
63
64 c4594e36 Phil Davis
function isvalidpid($pidfile) {
65 0e604b3a Ermal
	$output = "";
66 c4594e36 Phil Davis
	if (file_exists($pidfile)) {
67
		exec("/bin/pgrep -nF {$pidfile}", $output, $retval);
68
		return (intval($retval) == 0);
69
	}
70
	return false;
71 53aca1fd Scott Ullrich
}
72
73 6dc3a5c2 Ermal Lu?i
function is_process_running($process) {
74 01d4b621 Ermal
	$output = "";
75 873c1701 Renato Botelho
	exec("/bin/pgrep -anx " . escapeshellarg($process), $output, $retval);
76 6dc3a5c2 Ermal Lu?i
77 5bbd08e1 Warren Baker
	return (intval($retval) == 0);
78 6dc3a5c2 Ermal Lu?i
}
79
80 53aca1fd Scott Ullrich
function isvalidproc($proc) {
81 ba8495f0 Ermal
	return is_process_running($proc);
82 53aca1fd Scott Ullrich
}
83
84 5b237745 Scott Ullrich
/* sigkill a process by pid file */
85 53aca1fd Scott Ullrich
/* return 1 for success and 0 for a failure */
86 5b237745 Scott Ullrich
function sigkillbypid($pidfile, $sig) {
87 751533a2 Phil Davis
	if (file_exists($pidfile)) {
88 873c1701 Renato Botelho
		return mwexec("/bin/pkill " . escapeshellarg("-{$sig}") . " -F {$pidfile}", true);
89 751533a2 Phil Davis
	}
90 ba8495f0 Ermal
91 53aca1fd Scott Ullrich
	return 0;
92
}
93
94
/* kill a process by name */
95
function sigkillbyname($procname, $sig) {
96 751533a2 Phil Davis
	if (isvalidproc($procname)) {
97 873c1701 Renato Botelho
		return mwexec("/usr/bin/killall " . escapeshellarg("-{$sig}") . " " . escapeshellarg($procname), true);
98 751533a2 Phil Davis
	}
99 5b237745 Scott Ullrich
}
100
101
/* kill a process by name */
102
function killbyname($procname) {
103 751533a2 Phil Davis
	if (isvalidproc($procname)) {
104 53aca1fd Scott Ullrich
		mwexec("/usr/bin/killall " . escapeshellarg($procname));
105 751533a2 Phil Davis
	}
106 5b237745 Scott Ullrich
}
107
108 a368a026 Ermal Lu?i
function is_subsystem_dirty($subsystem = "") {
109
	global $g;
110
111 751533a2 Phil Davis
	if ($subsystem == "") {
112 a368a026 Ermal Lu?i
		return false;
113 751533a2 Phil Davis
	}
114 a368a026 Ermal Lu?i
115 751533a2 Phil Davis
	if (file_exists("{$g['varrun_path']}/{$subsystem}.dirty")) {
116 a368a026 Ermal Lu?i
		return true;
117 751533a2 Phil Davis
	}
118 a368a026 Ermal Lu?i
119
	return false;
120
}
121
122
function mark_subsystem_dirty($subsystem = "") {
123
	global $g;
124
125 751533a2 Phil Davis
	if (!file_put_contents("{$g['varrun_path']}/{$subsystem}.dirty", "DIRTY")) {
126 fd7b47b6 Renato Botelho
		log_error(sprintf(gettext("WARNING: Could not mark subsystem: %s dirty"), $subsystem));
127 751533a2 Phil Davis
	}
128 a368a026 Ermal Lu?i
}
129
130
function clear_subsystem_dirty($subsystem = "") {
131
	global $g;
132
133
	@unlink("{$g['varrun_path']}/{$subsystem}.dirty");
134
}
135
136 0027de0a Ermal Lu?i
function config_lock() {
137
	return;
138
}
139
function config_unlock() {
140
	return;
141
}
142
143
/* lock configuration file */
144 b6c34bfc Ermal
function lock($lock, $op = LOCK_SH) {
145 9e7ef1a5 Scott Ullrich
	global $g, $cfglckkeyconsumers;
146 751533a2 Phil Davis
	if (!$lock) {
147 fd7b47b6 Renato Botelho
		die(gettext("WARNING: You must give a name as parameter to lock() function."));
148 751533a2 Phil Davis
	}
149 6bee76d5 Ermal
	if (!file_exists("{$g['tmp_path']}/{$lock}.lock")) {
150 9e7ef1a5 Scott Ullrich
		@touch("{$g['tmp_path']}/{$lock}.lock");
151 6bee76d5 Ermal
		@chmod("{$g['tmp_path']}/{$lock}.lock", 0666);
152
	}
153 9e7ef1a5 Scott Ullrich
	$cfglckkeyconsumers++;
154 b6c34bfc Ermal
	if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
155 751533a2 Phil Davis
		if (flock($fp, $op)) {
156 9e7ef1a5 Scott Ullrich
			return $fp;
157 751533a2 Phil Davis
		} else {
158 b6c34bfc Ermal
			fclose($fp);
159 751533a2 Phil Davis
		}
160 9e7ef1a5 Scott Ullrich
	}
161 0027de0a Ermal Lu?i
}
162
163 8171a2c2 Ermal
function try_lock($lock, $timeout = 5) {
164
	global $g, $cfglckkeyconsumers;
165 751533a2 Phil Davis
	if (!$lock) {
166 8171a2c2 Ermal
		die(gettext("WARNING: You must give a name as parameter to try_lock() function."));
167 751533a2 Phil Davis
	}
168 8171a2c2 Ermal
	if (!file_exists("{$g['tmp_path']}/{$lock}.lock")) {
169
		@touch("{$g['tmp_path']}/{$lock}.lock");
170
		@chmod("{$g['tmp_path']}/{$lock}.lock", 0666);
171
	}
172
	$cfglckkeyconsumers++;
173
	if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
174
		$trycounter = 0;
175 751533a2 Phil Davis
		while (!flock($fp, LOCK_EX | LOCK_NB)) {
176 8171a2c2 Ermal
			if ($trycounter >= $timeout) {
177
				fclose($fp);
178
				return NULL;
179
			}
180
			sleep(1);
181
			$trycounter++;
182
		}
183
184
		return $fp;
185
	}
186
187
	return NULL;
188
}
189
190 0027de0a Ermal Lu?i
/* unlock configuration file */
191
function unlock($cfglckkey = 0) {
192 9e7ef1a5 Scott Ullrich
	global $g, $cfglckkeyconsumers;
193
	flock($cfglckkey, LOCK_UN);
194 cb6fd90b Ermal Lu?i
	fclose($cfglckkey);
195 9e7ef1a5 Scott Ullrich
	return;
196 0027de0a Ermal Lu?i
}
197
198 8171a2c2 Ermal
/* unlock forcefully configuration file */
199
function unlock_force($lock) {
200
	global $g;
201
202
	@unlink("{$g['tmp_path']}/{$lock}.lock");
203
}
204
205 0ae6daf8 Ermal
function send_event($cmd) {
206
	global $g;
207
208 751533a2 Phil Davis
	if (!isset($g['event_address'])) {
209 1015b3a9 Warren Baker
		$g['event_address'] = "unix:///var/run/check_reload_status";
210 751533a2 Phil Davis
	}
211 86a5e1a8 Renato Botelho
212 838feb14 Ermal
	$try = 0;
213
	while ($try < 3) {
214
		$fd = @fsockopen($g['event_address']);
215
		if ($fd) {
216
			fwrite($fd, $cmd);
217
			$resp = fread($fd, 4096);
218 751533a2 Phil Davis
			if ($resp != "OK\n") {
219 838feb14 Ermal
				log_error("send_event: sent {$cmd} got {$resp}");
220 751533a2 Phil Davis
			}
221 838feb14 Ermal
			fclose($fd);
222
			$try = 3;
223 751533a2 Phil Davis
		} else if (!is_process_running("check_reload_status")) {
224 838feb14 Ermal
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
225 751533a2 Phil Davis
		}
226 838feb14 Ermal
		$try++;
227 0ae6daf8 Ermal
	}
228
}
229
230
function send_multiple_events($cmds) {
231 1015b3a9 Warren Baker
	global $g;
232 0ae6daf8 Ermal
233 751533a2 Phil Davis
	if (!isset($g['event_address'])) {
234 1015b3a9 Warren Baker
		$g['event_address'] = "unix:///var/run/check_reload_status";
235 751533a2 Phil Davis
	}
236 86a5e1a8 Renato Botelho
237 751533a2 Phil Davis
	if (!is_array($cmds)) {
238 0ae6daf8 Ermal
		return;
239 751533a2 Phil Davis
	}
240 6e1f456f Ermal
241 915089b7 Ermal
	while ($try < 3) {
242
		$fd = @fsockopen($g['event_address']);
243
		if ($fd) {
244
			foreach ($cmds as $cmd) {
245
				fwrite($fd, $cmd);
246
				$resp = fread($fd, 4096);
247 751533a2 Phil Davis
				if ($resp != "OK\n") {
248 915089b7 Ermal
					log_error("send_event: sent {$cmd} got {$resp}");
249 751533a2 Phil Davis
				}
250 915089b7 Ermal
			}
251
			fclose($fd);
252
			$try = 3;
253 751533a2 Phil Davis
		} else if (!is_process_running("check_reload_status")) {
254 915089b7 Ermal
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
255 751533a2 Phil Davis
		}
256 915089b7 Ermal
		$try++;
257
	}
258 0ae6daf8 Ermal
}
259
260 ef3af02e Ermal Lu?i
function refcount_init($reference) {
261 eb295a1b Ermal
	$shmid = @shmop_open($reference, "c", 0644, 10);
262
	@shmop_write($shmid, str_pad("0", 10, "\x0", STR_PAD_RIGHT), 0);
263
	@shmop_close($shmid);
264 ef3af02e Ermal Lu?i
}
265
266
function refcount_reference($reference) {
267 eb295a1b Ermal
	/* Take out a lock across the shared memory read, increment, write sequence to make it atomic. */
268
	$shm_lck = lock("shm{$reference}", LOCK_EX);
269 e15e9c6b Ermal
	try {
270 eb295a1b Ermal
		/* NOTE: A warning is generated when shared memory does not exist */
271 7074a89a Phil Davis
		$shmid = @shmop_open($reference, "w", 0, 0);
272 e15e9c6b Ermal
		if (!$shmid) {
273
			refcount_init($reference);
274 eb295a1b Ermal
			$shmid = @shmop_open($reference, "w", 0, 0);
275
			if (!$shmid) {
276
				log_error(gettext("Could not open shared memory {$reference}"));
277 712eb769 Ermal
				unlock($shm_lck);
278 eb295a1b Ermal
				return;
279
			}
280 e15e9c6b Ermal
		}
281 eb295a1b Ermal
		$shm_data = @shmop_read($shmid, 0, 10);
282 7074a89a Phil Davis
		$shm_data = intval($shm_data) + 1;
283 eb295a1b Ermal
		@shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
284
		@shmop_close($shmid);
285 7074a89a Phil Davis
		unlock($shm_lck);
286 e15e9c6b Ermal
	} catch (Exception $e) {
287
		log_error($e->getMessage());
288 eb295a1b Ermal
		unlock($shm_lck);
289 a45e27ba Ermal
	}
290 e15e9c6b Ermal
291 ef3af02e Ermal Lu?i
	return $shm_data;
292
}
293
294
function refcount_unreference($reference) {
295 eb295a1b Ermal
	/* Take out a lock across the shared memory read, decrement, write sequence to make it atomic. */
296
	$shm_lck = lock("shm{$reference}", LOCK_EX);
297 e15e9c6b Ermal
	try {
298
		$shmid = @shmop_open($reference, "w", 0, 0);
299 eb295a1b Ermal
		if (!$shmid) {
300
			refcount_init($reference);
301
			log_error(gettext("Could not open shared memory {$reference}"));
302 712eb769 Ermal
			unlock($shm_lck);
303 eb295a1b Ermal
			return;
304
		}
305
		$shm_data = @shmop_read($shmid, 0, 10);
306 780705e9 jim-p
		$shm_data = intval($shm_data) - 1;
307 e15e9c6b Ermal
		if ($shm_data < 0) {
308
			//debug_backtrace();
309
			log_error(sprintf(gettext("Reference %s is going negative, not doing unreference."), $reference));
310 751533a2 Phil Davis
		} else {
311 eb295a1b Ermal
			@shmop_write($shmid, str_pad($shm_data, 10, "\x0", STR_PAD_RIGHT), 0);
312 751533a2 Phil Davis
		}
313 eb295a1b Ermal
		@shmop_close($shmid);
314 7074a89a Phil Davis
		unlock($shm_lck);
315 e15e9c6b Ermal
	} catch (Exception $e) {
316
		log_error($e->getMessage());
317 eb295a1b Ermal
		unlock($shm_lck);
318 e15e9c6b Ermal
	}
319
320 f2f0a748 Ermal Lu?i
	return $shm_data;
321 96cecadb Phil Davis
}
322
323
function refcount_read($reference) {
324
	/* This function just reads the current value of the refcount for information. */
325
	/* There is no need for locking. */
326
	$shmid = @shmop_open($reference, "a", 0, 0);
327
	if (!$shmid) {
328
		log_error(gettext("Could not open shared memory for read {$reference}"));
329
		return -1;
330
	}
331
	$shm_data = @shmop_read($shmid, 0, 10);
332
	@shmop_close($shmid);
333
	return $shm_data;
334 ef3af02e Ermal Lu?i
}
335
336 1ab56363 Ermal Lu?i
function is_module_loaded($module_name) {
337 302c005e Ermal
	$module_name = str_replace(".ko", "", $module_name);
338
	$running = 0;
339 ec25f18a Renato Botelho
	$_gb = exec("/sbin/kldstat -qn {$module_name} 2>&1", $_gb, $running);
340 751533a2 Phil Davis
	if (intval($running) == 0) {
341 1ab56363 Ermal Lu?i
		return true;
342 751533a2 Phil Davis
	} else {
343 1ab56363 Ermal Lu?i
		return false;
344 751533a2 Phil Davis
	}
345 1ab56363 Ermal Lu?i
}
346
347 4caa9574 stilez
/* validate non-negative numeric string, or equivalent numeric variable */
348
function is_numericint($arg) {
349 751533a2 Phil Davis
	return (((is_int($arg) && $arg >= 0) || (is_string($arg) && strlen($arg) > 0 && ctype_digit($arg))) ? true : false);
350 4caa9574 stilez
}
351
352 751533a2 Phil Davis
/* Generate the (human readable) ipv4 or ipv6 subnet address (i.e., netmask, or subnet start IP)
353 e89d2995 stilez
   given an (human readable) ipv4 or ipv6 host address and subnet bit count */
354 5b237745 Scott Ullrich
function gen_subnet($ipaddr, $bits) {
355 751533a2 Phil Davis
	if (($sn = gen_subnetv6($ipaddr, $bits)) == '') {
356 e89d2995 stilez
		$sn = gen_subnetv4($ipaddr, $bits);  // try to avoid rechecking IPv4/v6
357 751533a2 Phil Davis
	}
358 e89d2995 stilez
	return $sn;
359
}
360 3bad4691 Renato Botelho
361 e89d2995 stilez
/* same as gen_subnet() but accepts IPv4 only */
362
function gen_subnetv4($ipaddr, $bits) {
363
	if (is_ipaddrv4($ipaddr) && is_numericint($bits) && $bits <= 32) {
364 751533a2 Phil Davis
		if ($bits == 0) {
365 e89d2995 stilez
			return '0.0.0.0';  // avoids <<32
366 751533a2 Phil Davis
		}
367 e89d2995 stilez
		return long2ip(ip2long($ipaddr) & ((0xFFFFFFFF << (32 - $bits)) & 0xFFFFFFFF));
368
	}
369
	return "";
370 22b5abac Seth Mos
}
371
372 e89d2995 stilez
/* same as gen_subnet() but accepts IPv6 only */
373 22b5abac Seth Mos
function gen_subnetv6($ipaddr, $bits) {
374 751533a2 Phil Davis
	if (is_ipaddrv6($ipaddr) && is_numericint($bits) && $bits <= 128) {
375 e89d2995 stilez
		return Net_IPv6::compress(Net_IPv6::getNetmask($ipaddr, $bits));
376 751533a2 Phil Davis
	}
377 e89d2995 stilez
	return "";
378 5b237745 Scott Ullrich
}
379
380 3bad4691 Renato Botelho
/* Generate the (human readable) ipv4 or ipv6 subnet end address (i.e., highest address, end IP, or IPv4 broadcast address)
381 e89d2995 stilez
   given an (human readable) ipv4 or ipv6 host address and subnet bit count. */
382 5b237745 Scott Ullrich
function gen_subnet_max($ipaddr, $bits) {
383 751533a2 Phil Davis
	if (($sn = gen_subnetv6_max($ipaddr, $bits)) == '') {
384 e89d2995 stilez
		$sn = gen_subnetv4_max($ipaddr, $bits);  // try to avoid rechecking IPv4/v6
385 751533a2 Phil Davis
	}
386 e89d2995 stilez
	return $sn;
387
}
388 98bbf05a Scott Ullrich
389 e89d2995 stilez
/* same as gen_subnet_max() but validates IPv4 only */
390
function gen_subnetv4_max($ipaddr, $bits) {
391
	if (is_ipaddrv4($ipaddr) && is_numericint($bits) && $bits <= 32) {
392 751533a2 Phil Davis
		if ($bits == 32) {
393 e89d2995 stilez
			return $ipaddr;
394 751533a2 Phil Davis
		}
395 c18ba6bf Phil Davis
		return long2ip32(ip2long($ipaddr) | (~gen_subnet_mask_long($bits) & 0xFFFFFFFF));
396 e89d2995 stilez
	}
397
	return "";
398 5b237745 Scott Ullrich
}
399
400 e89d2995 stilez
/* same as gen_subnet_max() but validates IPv6 only */
401 c75a8185 Seth Mos
function gen_subnetv6_max($ipaddr, $bits) {
402 e89d2995 stilez
	if (is_ipaddrv6($ipaddr) && is_numericint($bits) && $bits <= 128) {
403 3f499654 Renato Botelho
		$endip_bin = substr(Net_IPv6::_ip2Bin($ipaddr), 0, $bits) . str_repeat('1', 128 - $bits);
404 e89d2995 stilez
		return Net_IPv6::compress(Net_IPv6::_bin2Ip($endip_bin));
405
	}
406
	return "";
407 c75a8185 Seth Mos
}
408
409 5b237745 Scott Ullrich
/* returns a subnet mask (long given a bit count) */
410
function gen_subnet_mask_long($bits) {
411
	$sm = 0;
412
	for ($i = 0; $i < $bits; $i++) {
413
		$sm >>= 1;
414
		$sm |= 0x80000000;
415
	}
416
	return $sm;
417
}
418
419
/* same as above but returns a string */
420
function gen_subnet_mask($bits) {
421
	return long2ip(gen_subnet_mask_long($bits));
422
}
423
424 ce9dc198 stilez
/* Convert long int to IPv4 address
425 f8a6c824 Chris Buechler
   Returns '' if not valid IPv4 (including if any bits >32 are non-zero) */
426 96033063 Erik Fonnesbeck
function long2ip32($ip) {
427 f8a6c824 Chris Buechler
	return long2ip($ip & 0xFFFFFFFF);
428
}
429 96033063 Erik Fonnesbeck
430 ce9dc198 stilez
/* Convert IPv4 address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms.
431
   Returns '' if not valid IPv4. */
432 96033063 Erik Fonnesbeck
function ip2long32($ip) {
433 f8a6c824 Chris Buechler
	return (ip2long($ip) & 0xFFFFFFFF);
434 96033063 Erik Fonnesbeck
}
435
436 ce9dc198 stilez
/* Convert IPv4 address to unsigned long int.
437
   Returns '' if not valid IPv4. */
438 ecd1f2d9 jim-p
function ip2ulong($ip) {
439 f8a6c824 Chris Buechler
	return sprintf("%u", ip2long32($ip));
440 ecd1f2d9 jim-p
}
441
442
/* Find out how many IPs are contained within a given IP range
443
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
444
 */
445 bb67ac32 Phil Davis
function ip_range_size_v4($startip, $endip) {
446
	if (is_ipaddrv4($startip) && is_ipaddrv4($endip)) {
447 ecd1f2d9 jim-p
		// Operate as unsigned long because otherwise it wouldn't work
448
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
449
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
450
	}
451
	return -1;
452
}
453
454
/* Find the smallest possible subnet mask which can contain a given number of IPs
455
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
456
 */
457 bb67ac32 Phil Davis
function find_smallest_cidr_v4($number) {
458 ecd1f2d9 jim-p
	$smallest = 1;
459
	for ($b=32; $b > 0; $b--) {
460 086cf944 Phil Davis
		$smallest = ($number <= pow(2, $b)) ? $b : $smallest;
461 ecd1f2d9 jim-p
	}
462
	return (32-$smallest);
463
}
464
465
/* Return the previous IP address before the given address */
466 aa181833 Phil Davis
function ip_before($ip, $offset = 1) {
467
	return long2ip32(ip2long($ip) - $offset);
468 ecd1f2d9 jim-p
}
469
470
/* Return the next IP address after the given address */
471 aa181833 Phil Davis
function ip_after($ip, $offset = 1) {
472
	return long2ip32(ip2long($ip) + $offset);
473 ecd1f2d9 jim-p
}
474
475
/* Return true if the first IP is 'before' the second */
476
function ip_less_than($ip1, $ip2) {
477
	// Compare as unsigned long because otherwise it wouldn't work when
478
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
479
	return ip2ulong($ip1) < ip2ulong($ip2);
480
}
481
482
/* Return true if the first IP is 'after' the second */
483
function ip_greater_than($ip1, $ip2) {
484
	// Compare as unsigned long because otherwise it wouldn't work
485
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
486
	return ip2ulong($ip1) > ip2ulong($ip2);
487
}
488
489 b17ac4f7 stilez
/* compare two IP addresses */
490
function ipcmp($a, $b) {
491 751533a2 Phil Davis
	if (ip_less_than($a, $b)) {
492 b17ac4f7 stilez
		return -1;
493 751533a2 Phil Davis
	} else if (ip_greater_than($a, $b)) {
494 b17ac4f7 stilez
		return 1;
495 751533a2 Phil Davis
	} else {
496 b17ac4f7 stilez
		return 0;
497 751533a2 Phil Davis
	}
498 b17ac4f7 stilez
}
499
500 bb67ac32 Phil Davis
/* Convert a range of IPv4 addresses to an array of individual addresses. */
501
/* Note: IPv6 ranges are not yet supported here. */
502
function ip_range_to_address_array($startip, $endip, $max_size = 5000) {
503
	if (!is_ipaddrv4($startip) || !is_ipaddrv4($endip)) {
504
		return false;
505
	}
506
507
	if (ip_greater_than($startip, $endip)) {
508
		// Swap start and end so we can process sensibly.
509
		$temp = $startip;
510
		$startip = $endip;
511
		$endip = $temp;
512
	}
513
514 751533a2 Phil Davis
	if (ip_range_size_v4($startip, $endip) > $max_size) {
515 bb67ac32 Phil Davis
		return false;
516 751533a2 Phil Davis
	}
517
518 bb67ac32 Phil Davis
	// Container for IP addresses within this range.
519
	$rangeaddresses = array();
520
	$end_int = ip2ulong($endip);
521
	for ($ip_int = ip2ulong($startip); $ip_int <= $end_int; $ip_int++) {
522
		$rangeaddresses[] = long2ip($ip_int);
523
	}
524
525
	return $rangeaddresses;
526
}
527
528 ed516fa7 stilez
/* 	Convert an IPv4 or IPv6 IP range to an array of subnets which can contain the range.
529
	Algorithm and embodying code PD'ed by Stilez - enjoy as you like :-)
530
531
	Documented on pfsense dev list 19-20 May 2013. Summary:
532
533
	The algorithm looks at patterns of 0's and 1's in the least significant bit(s), whether IPv4 or IPv6.
534
	These are all that needs checking to identify a _guaranteed_ correct, minimal and optimal subnet array.
535 19b802f4 Phil Davis
536
	As a result, string/binary pattern matching of the binary IP is very efficient. It uses just 2 pattern-matching rules
537 ed516fa7 stilez
	to chop off increasingly larger subnets at both ends that can't be part of larger subnets, until nothing's left.
538
539 19b802f4 Phil Davis
	(a) If any range has EITHER low bit 1 (in startip) or 0 (in endip), that end-point is _always guaranteed_ to be optimally
540
	represented by its own 'single IP' CIDR; the remaining range then shrinks by one IP up or down, causing the new end-point's
541
	low bit to change from 1->0 (startip) or 0->1 (endip). Only one edge case needs checking: if a range contains exactly 2
542 ed516fa7 stilez
	adjacent IPs of this format, then the two IPs themselves are required to span it, and we're done.
543 19b802f4 Phil Davis
	Once this rule is applied, the remaining range is _guaranteed_ to end in 0's and 1's so rule (b) can now be used, and its
544 ed516fa7 stilez
	low bits can now be ignored.
545 19b802f4 Phil Davis
546
	(b) If any range has BOTH startip and endip ending in some number of 0's and 1's respectively, these low bits can
547
	*always* be ignored and "bit-shifted" for subnet spanning. So provided we remember the bits we've place-shifted, we can
548
	_always_ right-shift and chop off those bits, leaving a smaller range that has EITHER startip ending in 1 or endip ending
549
	in 0 (ie can now apply (a) again) or the entire range has vanished and we're done.
550
	We then loop to redo (a) again on the remaining (place shifted) range until after a few loops, the remaining (place shifted)
551 ed516fa7 stilez
	range 'vanishes' by meeting the exit criteria of (a) or (b), and we're done.
552
*/
553 ecd1f2d9 jim-p
554 ed516fa7 stilez
function ip_range_to_subnet_array($ip1, $ip2) {
555 bb67ac32 Phil Davis
556 ed516fa7 stilez
	if (is_ipaddrv4($ip1) && is_ipaddrv4($ip2)) {
557
		$proto = 'ipv4';  // for clarity
558
		$bits = 32;
559
		$ip1bin = decbin(ip2long32($ip1));
560
		$ip2bin = decbin(ip2long32($ip2));
561
	} elseif (is_ipaddrv6($ip1) && is_ipaddrv6($ip2)) {
562
		$proto = 'ipv6';
563
		$bits = 128;
564
		$ip1bin = Net_IPv6::_ip2Bin($ip1);
565
		$ip2bin = Net_IPv6::_ip2Bin($ip2);
566 19b802f4 Phil Davis
	} else {
567 ed516fa7 stilez
		return array();
568 19b802f4 Phil Davis
	}
569 ecd1f2d9 jim-p
570 ed516fa7 stilez
	// it's *crucial* that binary strings are guaranteed the expected length;  do this for certainty even though for IPv6 it's redundant
571
	$ip1bin = str_pad($ip1bin, $bits, '0', STR_PAD_LEFT);
572
	$ip2bin = str_pad($ip2bin, $bits, '0', STR_PAD_LEFT);
573 ecd1f2d9 jim-p
574 19b802f4 Phil Davis
	if ($ip1bin == $ip2bin) {
575 ed516fa7 stilez
		return array($ip1 . '/' . $bits); // exit if ip1=ip2 (trivial case)
576 19b802f4 Phil Davis
	}
577
578
	if ($ip1bin > $ip2bin) {
579 ed516fa7 stilez
		list ($ip1bin, $ip2bin) = array($ip2bin, $ip1bin);  // swap if needed (ensures ip1 < ip2)
580 19b802f4 Phil Davis
	}
581 ecd1f2d9 jim-p
582 ed516fa7 stilez
	$rangesubnets = array();
583
	$netsize = 0;
584
585
	do {
586
		// at loop start, $ip1 is guaranteed strictly less than $ip2 (important for edge case trapping and preventing accidental binary wrapround)
587
		// which means the assignments $ip1 += 1 and $ip2 -= 1 will always be "binary-wrapround-safe"
588
589
		// step #1 if start ip (as shifted) ends in any '1's, then it must have a single cidr to itself (any cidr would include the '0' below it)
590 19b802f4 Phil Davis
591 ed516fa7 stilez
		if (substr($ip1bin, -1, 1) == '1') {
592
			// the start ip must be in a separate one-IP cidr range
593
			$new_subnet_ip = substr($ip1bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize);
594
			$rangesubnets[$new_subnet_ip] = $bits - $netsize;
595
			$n = strrpos($ip1bin, '0');  //can't be all 1's
596
			$ip1bin = ($n == 0 ? '' : substr($ip1bin, 0, $n)) . '1' . str_repeat('0', $bits - $n - 1);  // BINARY VERSION OF $ip1 += 1
597 19b802f4 Phil Davis
		}
598 ed516fa7 stilez
599
		// step #2, if end ip (as shifted) ends in any zeros then that must have a cidr to itself (as cidr cant span the 1->0 gap)
600 19b802f4 Phil Davis
601 ed516fa7 stilez
		if (substr($ip2bin, -1, 1) == '0') {
602
			// the end ip must be in a separate one-IP cidr range
603
			$new_subnet_ip = substr($ip2bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize);
604
			$rangesubnets[$new_subnet_ip] = $bits - $netsize;
605
			$n = strrpos($ip2bin, '1');  //can't be all 0's
606
			$ip2bin = ($n == 0 ? '' : substr($ip2bin, 0, $n)) . '0' . str_repeat('1', $bits - $n - 1);  // BINARY VERSION OF $ip2 -= 1
607
			// already checked for the edge case where end = start+1 and start ends in 0x1, above, so it's safe
608 ecd1f2d9 jim-p
		}
609
610 19b802f4 Phil Davis
		// this is the only edge case arising from increment/decrement.
611 ed516fa7 stilez
		// it happens if the range at start of loop is exactly 2 adjacent ips, that spanned the 1->0 gap. (we will have enumerated both by now)
612 19b802f4 Phil Davis
613
		if ($ip2bin < $ip1bin) {
614 ed516fa7 stilez
			continue;
615 19b802f4 Phil Davis
		}
616 ed516fa7 stilez
617
		// step #3 the start and end ip MUST now end in '0's and '1's respectively
618
		// so we have a non-trivial range AND the last N bits are no longer important for CIDR purposes.
619
620
		$shift = $bits - max(strrpos($ip1bin, '0'), strrpos($ip2bin, '1'));  // num of low bits which are '0' in ip1 and '1' in ip2
621
		$ip1bin = str_repeat('0', $shift) . substr($ip1bin, 0, $bits - $shift);
622
		$ip2bin = str_repeat('0', $shift) . substr($ip2bin, 0, $bits - $shift);
623
		$netsize += $shift;
624
		if ($ip1bin == $ip2bin) {
625
			// we're done.
626
			$new_subnet_ip = substr($ip1bin, $netsize, $bits - $netsize) . str_repeat('0', $netsize);
627
			$rangesubnets[$new_subnet_ip] = $bits - $netsize;
628
			continue;
629 ecd1f2d9 jim-p
		}
630 19b802f4 Phil Davis
631 ed516fa7 stilez
		// at this point there's still a remaining range, and either startip ends with '1', or endip ends with '0'. So repeat cycle.
632
	} while ($ip1bin < $ip2bin);
633 ecd1f2d9 jim-p
634 ed516fa7 stilez
	// subnets are ordered by bit size. Re sort by IP ("naturally") and convert back to IPv4/IPv6
635 ecd1f2d9 jim-p
636 ed516fa7 stilez
	ksort($rangesubnets, SORT_STRING);
637
	$out = array();
638 ecd1f2d9 jim-p
639 ed516fa7 stilez
	foreach ($rangesubnets as $ip => $netmask) {
640
		if ($proto == 'ipv4') {
641
			$i = str_split($ip, 8);
642 19b802f4 Phil Davis
			$out[] = implode('.', array(bindec($i[0]), bindec($i[1]), bindec($i[2]), bindec($i[3]))) . '/' . $netmask;
643
		} else {
644 ed516fa7 stilez
			$out[] = Net_IPv6::compress(Net_IPv6::_bin2Ip($ip)) . '/' . $netmask;
645 19b802f4 Phil Davis
		}
646 ecd1f2d9 jim-p
	}
647
648 ed516fa7 stilez
	return $out;
649 ecd1f2d9 jim-p
}
650
651 bb67ac32 Phil Davis
/* returns true if $range is a valid pair of IPv4 or IPv6 addresses separated by a "-"
652 751533a2 Phil Davis
	false - if not a valid pair
653
	true (numeric 4 or 6) - if valid, gives type of addresses */
654 ecd1f2d9 jim-p
function is_iprange($range) {
655
	if (substr_count($range, '-') != 1) {
656
		return false;
657
	}
658
	list($ip1, $ip2) = explode ('-', $range);
659 751533a2 Phil Davis
	if (is_ipaddrv4($ip1) && is_ipaddrv4($ip2)) {
660 bb67ac32 Phil Davis
		return 4;
661 751533a2 Phil Davis
	}
662
	if (is_ipaddrv6($ip1) && is_ipaddrv6($ip2)) {
663 bb67ac32 Phil Davis
		return 6;
664 751533a2 Phil Davis
	}
665 bb67ac32 Phil Davis
	return false;
666 ecd1f2d9 jim-p
}
667
668 31495068 stilez
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6
669 751533a2 Phil Davis
	false - not valid
670
	true (numeric 4 or 6) - if valid, gives type of address */
671 5b237745 Scott Ullrich
function is_ipaddr($ipaddr) {
672 751533a2 Phil Davis
	if (is_ipaddrv4($ipaddr)) {
673 31495068 stilez
		return 4;
674 47593ac6 Seth Mos
	}
675 751533a2 Phil Davis
	if (is_ipaddrv6($ipaddr)) {
676 31495068 stilez
		return 6;
677 47593ac6 Seth Mos
	}
678
	return false;
679
}
680
681 22b5abac Seth Mos
/* returns true if $ipaddr is a valid IPv6 address */
682 47593ac6 Seth Mos
function is_ipaddrv6($ipaddr) {
683 751533a2 Phil Davis
	if (!is_string($ipaddr) || empty($ipaddr)) {
684 b5b5bcc0 Ermal
		return false;
685 751533a2 Phil Davis
	}
686 55909a9a Ermal
	if (strstr($ipaddr, "%") && is_linklocal($ipaddr)) {
687
		$tmpip = explode("%", $ipaddr);
688
		$ipaddr = $tmpip[0];
689
	}
690 1e5da31d Ermal
	return Net_IPv6::checkIPv6($ipaddr);
691 47593ac6 Seth Mos
}
692
693
/* returns true if $ipaddr is a valid dotted IPv4 address */
694
function is_ipaddrv4($ipaddr) {
695 c3b3e9c7 stilez
	if (!is_string($ipaddr) || empty($ipaddr) || ip2long($ipaddr) === FALSE) {
696 5b237745 Scott Ullrich
		return false;
697 751533a2 Phil Davis
	}
698 c3b3e9c7 stilez
	return true;
699 5b237745 Scott Ullrich
}
700
701 31495068 stilez
/* returns true if $ipaddr is a valid IPv6 linklocal address */
702 19341491 Renato Botelho
function is_linklocal($ipaddr) {
703 04f5393f Renato Botelho
	return (strtolower(substr($ipaddr, 0, 5)) == "fe80:");
704 19341491 Renato Botelho
}
705 3f5f7ad3 smos
706 bd6ff328 Renato Botelho
/* returns scope of a linklocal address */
707
function get_ll_scope($addr) {
708 751533a2 Phil Davis
	if (!is_linklocal($addr) || !strstr($addr, "%")) {
709 bd6ff328 Renato Botelho
		return "";
710 751533a2 Phil Davis
	}
711 bd6ff328 Renato Botelho
	list ($ll, $scope) = explode("%", $addr);
712
	return $scope;
713
}
714
715 3f5f7ad3 smos
/* returns true if $ipaddr is a valid literal IPv6 address */
716
function is_literalipaddrv6($ipaddr) {
717 751533a2 Phil Davis
	if (preg_match("/\[([0-9a-f:]+)\]/i", $ipaddr, $match)) {
718 3f5f7ad3 smos
		$ipaddr = $match[1];
719 751533a2 Phil Davis
	} else {
720 3f5f7ad3 smos
		return false;
721 751533a2 Phil Davis
	}
722 3f5f7ad3 smos
723
	return is_ipaddrv6($ipaddr);
724
}
725
726 31495068 stilez
/* returns true if $iport is a valid IPv4/IPv6 address + port
727 751533a2 Phil Davis
	false - not valid
728
	true (numeric 4 or 6) - if valid, gives type of address */
729 4a8a90ff jim-p
function is_ipaddrwithport($ipport) {
730 31495068 stilez
	$c = strrpos($ipport, ":");
731 751533a2 Phil Davis
	if ($c === false) {
732 31495068 stilez
		return false;  // can't split at final colon if no colon exists
733 751533a2 Phil Davis
	}
734
735
	if (!is_port(substr($ipport, $c + 1))) {
736 31495068 stilez
		return false;  // no valid port after last colon
737 751533a2 Phil Davis
	}
738 31495068 stilez
739
	$ip = substr($ipport, 0, $c);  // else is text before last colon a valid IP
740 751533a2 Phil Davis
	if (is_literalipaddrv6($ip)) {
741 31495068 stilez
		return 6;
742 751533a2 Phil Davis
	} elseif (is_ipaddrv4($ip)) {
743 31495068 stilez
		return 4;
744 751533a2 Phil Davis
	} else {
745 4a8a90ff jim-p
		return false;
746 751533a2 Phil Davis
	}
747 4a8a90ff jim-p
}
748
749 d3a2337a jim-p
function is_hostnamewithport($hostport) {
750
	$parts = explode(":", $hostport);
751
	$port = array_pop($parts);
752
	if (count($parts) == 1) {
753
		return is_hostname($parts[0]) && is_port($port);
754
	} else {
755
		return false;
756
	}
757
}
758
759 87f0be87 Chris Buechler
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
760 5b237745 Scott Ullrich
function is_ipaddroralias($ipaddr) {
761 1e578a7f Ermal Lu?i
	global $config;
762 87f0be87 Chris Buechler
763 1e578a7f Ermal Lu?i
	if (is_alias($ipaddr)) {
764
		if (is_array($config['aliases']['alias'])) {
765
			foreach ($config['aliases']['alias'] as $alias) {
766 751533a2 Phil Davis
				if ($alias['name'] == $ipaddr && !preg_match("/port/i", $alias['type'])) {
767 1e578a7f Ermal Lu?i
					return true;
768 751533a2 Phil Davis
				}
769 1e578a7f Ermal Lu?i
			}
770 5bbd08e1 Warren Baker
		}
771 1e578a7f Ermal Lu?i
		return false;
772 751533a2 Phil Davis
	} else {
773 87f0be87 Chris Buechler
		return is_ipaddr($ipaddr);
774 751533a2 Phil Davis
	}
775 87f0be87 Chris Buechler
776 5b237745 Scott Ullrich
}
777
778 a5e2a35f stilez
/* returns true if $subnet is a valid IPv4 or IPv6 subnet in CIDR format
779 751533a2 Phil Davis
	false - if not a valid subnet
780
	true (numeric 4 or 6) - if valid, gives type of subnet */
781 5b237745 Scott Ullrich
function is_subnet($subnet) {
782 a5e2a35f stilez
	if (is_string($subnet) && preg_match('/^(?:([0-9.]{7,15})|([0-9a-f:]{2,39}))\/(\d{1,3})$/i', $subnet, $parts)) {
783 751533a2 Phil Davis
		if (is_ipaddrv4($parts[1]) && $parts[3] <= 32) {
784 a5e2a35f stilez
			return 4;
785 751533a2 Phil Davis
		}
786
		if (is_ipaddrv6($parts[2]) && $parts[3] <= 128) {
787 a5e2a35f stilez
			return 6;
788 751533a2 Phil Davis
		}
789 b1b42a06 Warren Baker
	}
790
	return false;
791
}
792
793 a5e2a35f stilez
/* same as is_subnet() but accepts IPv4 only */
794 b1b42a06 Warren Baker
function is_subnetv4($subnet) {
795 a5e2a35f stilez
	return (is_subnet($subnet) == 4);
796 5b237745 Scott Ullrich
}
797
798 a5e2a35f stilez
/* same as is_subnet() but accepts IPv6 only */
799 fdb9c1db Warren Baker
function is_subnetv6($subnet) {
800 a5e2a35f stilez
	return (is_subnet($subnet) == 6);
801 fdb9c1db Warren Baker
}
802
803 5b237745 Scott Ullrich
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
804
function is_subnetoralias($subnet) {
805
	global $aliastable;
806 98bbf05a Scott Ullrich
807 751533a2 Phil Davis
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet])) {
808 5b237745 Scott Ullrich
		return true;
809 751533a2 Phil Davis
	} else {
810 5b237745 Scott Ullrich
		return is_subnet($subnet);
811 751533a2 Phil Davis
	}
812 5b237745 Scott Ullrich
}
813
814 b17ac4f7 stilez
function subnet_size($subnet) {
815
	if (is_subnetv4($subnet)) {
816
		list ($ip, $bits) = explode("/", $subnet);
817
		return round(exp(log(2) * (32 - $bits)));
818 19b802f4 Phil Davis
	} else if (is_subnetv6($subnet)) {
819 b17ac4f7 stilez
		list ($ip, $bits) = explode("/", $subnet);
820
		return round(exp(log(2) * (128 - $bits)));
821 19b802f4 Phil Davis
	} else {
822 b17ac4f7 stilez
		return 0;
823
	}
824
}
825
826
827
function subnet_expand($subnet) {
828
	if (is_subnetv4($subnet)) {
829
		return subnetv4_expand($subnet);
830
	} else if (is_subnetv6($subnet)) {
831
		return subnetv6_expand($subnet);
832
	} else {
833
		return $subnet;
834
	}
835
}
836
837
function subnetv4_expand($subnet) {
838
	$result = array();
839
	list ($ip, $bits) = explode("/", $subnet);
840 6c07db48 Phil Davis
	$net = ip2long($ip);
841 b17ac4f7 stilez
	$mask = (0xffffffff << (32 - $bits));
842
	$net &= $mask;
843
	$size = round(exp(log(2) * (32 - $bits)));
844
	for ($i = 0; $i < $size; $i += 1) {
845
		$result[] = long2ip($net | $i);
846
	}
847
	return $result;
848
}
849
850 e8d5be8e stilez
/* find out whether two IPv4/IPv6 CIDR subnets overlap.
851
   Note: CIDR overlap implies one is identical or included so largest sn will be the same */
852 b17ac4f7 stilez
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
853 94eb702f stilez
	if (is_ipaddrv4($subnet1)) {
854 e8d5be8e stilez
		return check_subnetsv4_overlap($subnet1, $bits1, $subnet2, $bits2);
855 751533a2 Phil Davis
	} else {
856 e8d5be8e stilez
		return check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2);
857 751533a2 Phil Davis
	}
858 b17ac4f7 stilez
}
859
860 e8d5be8e stilez
/* find out whether two IPv4 CIDR subnets overlap.
861
   Note: CIDR overlap means sn1/sn2 are identical or one is included in other. So sn using largest $bits will be the same  */
862
function check_subnetsv4_overlap($subnet1, $bits1, $subnet2, $bits2) {
863 62512efa stilez
	$largest_sn = min($bits1, $bits2);
864 e8d5be8e stilez
	$subnetv4_start1 = gen_subnetv4($subnet1, $largest_sn);
865 9f4a788f stilez
	$subnetv4_start2 = gen_subnetv4($subnet2, $largest_sn);
866 e8d5be8e stilez
	
867
	if($subnetv4_start1 == '' || $subnetv4_start2 == '') {
868
		// One or both args is not a valid IPv4 subnet
869
		//FIXME: needs to return "bad data" not true/false if bad. For now return false, best we can do until fixed
870
		return false;
871
	}
872
	return ($subnetv4_start1 == $subnetv4_start2);
873
}
874 b17ac4f7 stilez
875 e8d5be8e stilez
/* find out whether two IPv6 CIDR subnets overlap.
876
   Note: CIDR overlap means sn1/sn2 are identical or one is included in other. So sn using largest $bits will be the same  */
877 9f8266cd stilez
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
878 62512efa stilez
	$largest_sn = min($bits1, $bits2);
879 9f8266cd stilez
	$subnetv6_start1 = gen_subnetv6($subnet1, $largest_sn);
880 9f4a788f stilez
	$subnetv6_start2 = gen_subnetv6($subnet2, $largest_sn);
881 e8d5be8e stilez
	
882
	if($subnetv6_start1 == '' || $subnetv6_start2 == '') {
883
		// One or both args is not a valid IPv6 subnet
884
		//FIXME: needs to return "bad data" not true/false if bad. For now return false, best we can do until fixed
885
		return false;
886
	}
887
	return ($subnetv6_start1 == $subnetv6_start2);
888 b17ac4f7 stilez
}
889
890
/* return true if $addr is in $subnet, false if not */
891 086cf944 Phil Davis
function ip_in_subnet($addr, $subnet) {
892 751533a2 Phil Davis
	if (is_ipaddrv6($addr) && is_subnetv6($subnet)) {
893 b17ac4f7 stilez
		return (Net_IPv6::isInNetmask($addr, $subnet));
894 0c5dd854 Renato Botelho
	} else if (is_ipaddrv4($addr) && is_subnetv4($subnet)) {
895 b17ac4f7 stilez
		list($ip, $mask) = explode('/', $subnet);
896
		$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
897
		return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
898
	}
899 0c5dd854 Renato Botelho
	return false;
900 b17ac4f7 stilez
}
901
902 6bcbd862 Phil Davis
/* returns true if $hostname is just a valid hostname (top part without any of the domain part) */
903
function is_unqualified_hostname($hostname) {
904 751533a2 Phil Davis
	if (!is_string($hostname)) {
905 6bcbd862 Phil Davis
		return false;
906 751533a2 Phil Davis
	}
907 6bcbd862 Phil Davis
908 751533a2 Phil Davis
	if (preg_match('/^(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])$/i', $hostname)) {
909 6bcbd862 Phil Davis
		return true;
910 751533a2 Phil Davis
	} else {
911 6bcbd862 Phil Davis
		return false;
912 751533a2 Phil Davis
	}
913 6bcbd862 Phil Davis
}
914
915
/* returns true if $hostname is a valid hostname, with or without being a fully-qualified domain name. */
916 0edcccc3 Daniel Seebald
function is_hostname($hostname, $allow_wildcard=false) {
917 751533a2 Phil Davis
	if (!is_string($hostname)) {
918 5b237745 Scott Ullrich
		return false;
919 751533a2 Phil Davis
	}
920 98bbf05a Scott Ullrich
921 cc882a8b Daniel Seebald
	if (is_domain($hostname, $allow_wildcard)) {
922 5454fd1b Phil Davis
		if ((substr_count($hostname, ".") == 1) && ($hostname[strlen($hostname)-1] == ".")) {
923
			/* Only a single dot at the end like "test." - hosts cannot be directly in the root domain. */
924
			return false;
925
		} else {
926
			return true;
927
		}
928 751533a2 Phil Davis
	} else {
929 5b237745 Scott Ullrich
		return false;
930 751533a2 Phil Davis
	}
931 5b237745 Scott Ullrich
}
932
933
/* returns true if $domain is a valid domain name */
934 0edcccc3 Daniel Seebald
function is_domain($domain, $allow_wildcard=false) {
935 751533a2 Phil Davis
	if (!is_string($domain)) {
936 5b237745 Scott Ullrich
		return false;
937 751533a2 Phil Davis
	}
938 0edcccc3 Daniel Seebald
	if ($allow_wildcard) {
939
		$domain_regex = '/^(?:(?:[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';
940
	} else {
941
		$domain_regex = '/^(?:(?:[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';
942
	}
943
944
	if (preg_match($domain_regex, $domain)) {
945 5b237745 Scott Ullrich
		return true;
946 751533a2 Phil Davis
	} else {
947 5b237745 Scott Ullrich
		return false;
948 751533a2 Phil Davis
	}
949 5b237745 Scott Ullrich
}
950
951
/* returns true if $macaddr is a valid MAC address */
952 1f1a08c8 jim-p
function is_macaddr($macaddr, $partial=false) {
953
	$repeat = ($partial) ? '1,5' : '5';
954
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){'.$repeat.'}$/i', $macaddr) == 1 ? true : false;
955 5b237745 Scott Ullrich
}
956
957 4ad9a1e7 stilez
/* returns true if $name is a valid name for an alias
958
   returns NULL if a reserved word is used
959
   returns FALSE for bad chars in the name - this allows calling code to determine what the problem was.
960
   aliases cannot be:
961 751533a2 Phil Davis
	bad chars: anything except a-z 0-9 and underscore
962
	bad names: empty string, pure numeric, pure underscore
963
	reserved words: pre-defined service/protocol/port names which should not be ambiguous, and the words "port" and  "pass" */
964 4ad9a1e7 stilez
965 5b237745 Scott Ullrich
function is_validaliasname($name) {
966 beeef1f0 Bill Marquette
	/* Array of reserved words */
967 0c2badde Colin Smith
	$reserved = array("port", "pass");
968 4ad9a1e7 stilez
969 751533a2 Phil Davis
	if (!is_string($name) || strlen($name) >= 32 || preg_match('/(^_*$|^\d*$|[^a-z0-9_])/i', $name)) {
970 5b237745 Scott Ullrich
		return false;
971 751533a2 Phil Davis
	}
972
	if (in_array($name, $reserved, true) || getservbyname($name, "tcp") || getservbyname($name, "udp") || getprotobyname($name)) {
973 4ad9a1e7 stilez
		return; /* return NULL */
974 751533a2 Phil Davis
	}
975 4ad9a1e7 stilez
	return true;
976 5b237745 Scott Ullrich
}
977
978
/* returns true if $port is a valid TCP/UDP port */
979
function is_port($port) {
980 751533a2 Phil Davis
	if (ctype_digit($port) && ((intval($port) >= 1) && (intval($port) <= 65535))) {
981 75106235 PiBa-NL
		return true;
982 751533a2 Phil Davis
	}
983
	if (getservbyname($port, "tcp") || getservbyname($port, "udp")) {
984 9060f420 Renato Botelho
		return true;
985 751533a2 Phil Davis
	}
986 75106235 PiBa-NL
	return false;
987 5b237745 Scott Ullrich
}
988
989 5a1eebc7 Scott Ullrich
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
990
function is_portrange($portrange) {
991 5bbd08e1 Warren Baker
	$ports = explode(":", $portrange);
992 5a1eebc7 Scott Ullrich
993 e371f8b9 whjvenyl
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
994 5a1eebc7 Scott Ullrich
}
995
996 1e578a7f Ermal Lu?i
/* returns true if $port is a valid port number or an alias thereof */
997
function is_portoralias($port) {
998
	global $config;
999
1000 5bbd08e1 Warren Baker
	if (is_alias($port)) {
1001
		if (is_array($config['aliases']['alias'])) {
1002
			foreach ($config['aliases']['alias'] as $alias) {
1003 751533a2 Phil Davis
				if ($alias['name'] == $port && preg_match("/port/i", $alias['type'])) {
1004 5bbd08e1 Warren Baker
					return true;
1005
				}
1006
			}
1007 751533a2 Phil Davis
		}
1008
		return false;
1009
	} else {
1010 5bbd08e1 Warren Baker
		return is_port($port);
1011 751533a2 Phil Davis
	}
1012 1e578a7f Ermal Lu?i
}
1013
1014 d9f33a7f Renato Botelho
/* create ranges of sequential port numbers (200:215) and remove duplicates */
1015
function group_ports($ports) {
1016 751533a2 Phil Davis
	if (!is_array($ports) || empty($ports)) {
1017 d9f33a7f Renato Botelho
		return;
1018 751533a2 Phil Davis
	}
1019 d9f33a7f Renato Botelho
1020
	$uniq = array();
1021
	foreach ($ports as $port) {
1022
		if (is_portrange($port)) {
1023
			list($begin, $end) = explode(":", $port);
1024
			if ($begin > $end) {
1025
				$aux = $begin;
1026
				$begin = $end;
1027
				$end = $aux;
1028
			}
1029 751533a2 Phil Davis
			for ($i = $begin; $i <= $end; $i++) {
1030
				if (!in_array($i, $uniq)) {
1031 d9f33a7f Renato Botelho
					$uniq[] = $i;
1032 751533a2 Phil Davis
				}
1033
			}
1034 d9f33a7f Renato Botelho
		} else if (is_port($port)) {
1035 751533a2 Phil Davis
			if (!in_array($port, $uniq)) {
1036 d9f33a7f Renato Botelho
				$uniq[] = $port;
1037 751533a2 Phil Davis
			}
1038 d9f33a7f Renato Botelho
		}
1039
	}
1040
	sort($uniq, SORT_NUMERIC);
1041
1042
	$result = array();
1043
	foreach ($uniq as $idx => $port) {
1044
		if ($idx == 0) {
1045
			$result[] = $port;
1046
			continue;
1047
		}
1048
1049
		$last = end($result);
1050 751533a2 Phil Davis
		if (is_portrange($last)) {
1051 d9f33a7f Renato Botelho
			list($begin, $end) = explode(":", $last);
1052 751533a2 Phil Davis
		} else {
1053 d9f33a7f Renato Botelho
			$begin = $end = $last;
1054 751533a2 Phil Davis
		}
1055 d9f33a7f Renato Botelho
1056
		if ($port == ($end+1)) {
1057
			$end++;
1058
			$result[count($result)-1] = "{$begin}:{$end}";
1059
		} else {
1060
			$result[] = $port;
1061
		}
1062
	}
1063
1064
	return $result;
1065
}
1066
1067 b8014f9d Scott Ullrich
/* returns true if $val is a valid shaper bandwidth value */
1068
function is_valid_shaperbw($val) {
1069 eaa37259 Ermal Luçi
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
1070 b8014f9d Scott Ullrich
}
1071
1072 54404519 Renato Botelho
/* returns true if $test is in the range between $start and $end */
1073
function is_inrange_v4($test, $start, $end) {
1074 751533a2 Phil Davis
	if ((ip2ulong($test) <= ip2ulong($end)) && (ip2ulong($test) >= ip2ulong($start))) {
1075 54404519 Renato Botelho
		return true;
1076 751533a2 Phil Davis
	} else {
1077 54404519 Renato Botelho
		return false;
1078 751533a2 Phil Davis
	}
1079 54404519 Renato Botelho
}
1080
1081 41b4867e Renato Botelho
/* returns true if $test is in the range between $start and $end */
1082
function is_inrange_v6($test, $start, $end) {
1083 751533a2 Phil Davis
	if ((inet_pton($test) <= inet_pton($end)) && (inet_pton($test) >= inet_pton($start))) {
1084 41b4867e Renato Botelho
		return true;
1085 751533a2 Phil Davis
	} else {
1086 41b4867e Renato Botelho
		return false;
1087 751533a2 Phil Davis
	}
1088 41b4867e Renato Botelho
}
1089
1090 da6cb29e Renato Botelho
/* returns true if $test is in the range between $start and $end */
1091
function is_inrange($test, $start, $end) {
1092
	return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
1093
}
1094
1095 7238e0cf Ermal
/* XXX: return the configured carp interface list */
1096 b0d054ca Ermal
function get_configured_carp_interface_list($carpinterface = '', $family = 'inet', $what = 'ip') {
1097 abcb2bed Ermal Lu?i
	global $config;
1098
1099
	$iflist = array();
1100
1101 4e322e2c Phil Davis
	if (!is_array($config['virtualip']['vip']) || empty($config['virtualip']['vip'])) {
1102 76153238 Luiz Otavio O Souza
		return $iflist;
1103 4e322e2c Phil Davis
	}
1104 76153238 Luiz Otavio O Souza
1105
	$viparr = &$config['virtualip']['vip'];
1106
	foreach ($viparr as $vip) {
1107 4e322e2c Phil Davis
		if ($vip['mode'] != "carp") {
1108 76153238 Luiz Otavio O Souza
			continue;
1109 4e322e2c Phil Davis
		}
1110 76153238 Luiz Otavio O Souza
1111
		if (empty($carpinterface)) {
1112
			$iflist["_vip{$vip['uniqid']}"] = $vip['subnet'];
1113
			continue;
1114
		}
1115
1116 4e322e2c Phil Davis
		if ($carpinterface != "_vip{$vip['uniqid']}") {
1117 76153238 Luiz Otavio O Souza
			continue;
1118 4e322e2c Phil Davis
		}
1119 76153238 Luiz Otavio O Souza
1120
		switch ($what) {
1121
			case 'subnet':
1122
				if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
1123
					return $vip['subnet_bits'];
1124
				} else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
1125
					return $vip['subnet_bits'];
1126
				}
1127
				break;
1128
			case 'iface':
1129
				if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
1130
					return $vip['interface'];
1131
				} else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
1132
					return $vip['interface'];
1133
				}
1134
				break;
1135
			case 'vip':
1136
				if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
1137
					return $vip;
1138
				} else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
1139
					return $vip;
1140
				}
1141
				break;
1142
			case 'ip':
1143
			default:
1144
				if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
1145
					return $vip['subnet'];
1146
				} else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
1147
					return $vip['subnet'];
1148
				}
1149
				break;
1150 5bbd08e1 Warren Baker
		}
1151 76153238 Luiz Otavio O Souza
		break;
1152 5bbd08e1 Warren Baker
	}
1153 abcb2bed Ermal Lu?i
1154
	return $iflist;
1155
}
1156
1157 67b0902f pierrepomes
/* return the configured IP aliases list */
1158 a119ecf8 Erik Fonnesbeck
function get_configured_ip_aliases_list($returnfullentry = false) {
1159 5bbd08e1 Warren Baker
	global $config;
1160 67b0902f pierrepomes
1161 6c07db48 Phil Davis
	$alias_list = array();
1162 67b0902f pierrepomes
1163 751533a2 Phil Davis
	if (is_array($config['virtualip']['vip'])) {
1164 5bbd08e1 Warren Baker
		$viparr = &$config['virtualip']['vip'];
1165
		foreach ($viparr as $vip) {
1166 086cf944 Phil Davis
			if ($vip['mode'] == "ipalias") {
1167 751533a2 Phil Davis
				if ($returnfullentry) {
1168 a119ecf8 Erik Fonnesbeck
					$alias_list[$vip['subnet']] = $vip;
1169 751533a2 Phil Davis
				} else {
1170 a119ecf8 Erik Fonnesbeck
					$alias_list[$vip['subnet']] = $vip['interface'];
1171 751533a2 Phil Davis
				}
1172 5bbd08e1 Warren Baker
			}
1173
		}
1174
	}
1175 67b0902f pierrepomes
1176 5bbd08e1 Warren Baker
	return $alias_list;
1177 67b0902f pierrepomes
}
1178
1179 e6c60013 Renato Botelho
/* return all configured aliases list (IP, carp, proxyarp and other) */
1180
function get_configured_vips_list() {
1181
	global $config;
1182
1183 6c07db48 Phil Davis
	$alias_list = array();
1184 e6c60013 Renato Botelho
1185 751533a2 Phil Davis
	if (is_array($config['virtualip']['vip'])) {
1186 e6c60013 Renato Botelho
		$viparr = &$config['virtualip']['vip'];
1187 0c21eb70 Ermal
		foreach ($viparr as $vip) {
1188 751533a2 Phil Davis
			if ($vip['mode'] == "carp") {
1189 a5bed5a2 Luiz Otavio O Souza
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => "_vip{$vip['uniqid']}");
1190 751533a2 Phil Davis
			} else {
1191 0c21eb70 Ermal
				$alias_list[] = array("ipaddr" => $vip['subnet'], "if" => $vip['interface']);
1192 751533a2 Phil Davis
			}
1193 7a7ba89a Ermal
		}
1194 e6c60013 Renato Botelho
	}
1195
1196
	return $alias_list;
1197
}
1198 67b0902f pierrepomes
1199 88bc2760 Erik Fonnesbeck
/* comparison function for sorting by the order in which interfaces are normally created */
1200
function compare_interface_friendly_names($a, $b) {
1201 751533a2 Phil Davis
	if ($a == $b) {
1202 88bc2760 Erik Fonnesbeck
		return 0;
1203 751533a2 Phil Davis
	} else if ($a == 'wan') {
1204 88bc2760 Erik Fonnesbeck
		return -1;
1205 751533a2 Phil Davis
	} else if ($b == 'wan') {
1206 88bc2760 Erik Fonnesbeck
		return 1;
1207 751533a2 Phil Davis
	} else if ($a == 'lan') {
1208 88bc2760 Erik Fonnesbeck
		return -1;
1209 751533a2 Phil Davis
	} else if ($b == 'lan') {
1210 88bc2760 Erik Fonnesbeck
		return 1;
1211 751533a2 Phil Davis
	}
1212 88bc2760 Erik Fonnesbeck
1213
	return strnatcmp($a, $b);
1214
}
1215
1216 c8abe1d4 Ermal Luçi
/* return the configured interfaces list. */
1217 3ad5e089 Ermal Luçi
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
1218 c8abe1d4 Ermal Luçi
	global $config;
1219
1220
	$iflist = array();
1221 14f49fd0 Erik Fonnesbeck
1222 c8abe1d4 Ermal Luçi
	/* if list */
1223 751533a2 Phil Davis
	foreach ($config['interfaces'] as $if => $ifdetail) {
1224
		if ($only_opt && ($if == "wan" || $if == "lan")) {
1225 42c9d20e Ermal Luçi
			continue;
1226 751533a2 Phil Davis
		}
1227
		if (isset($ifdetail['enable']) || $withdisabled == true) {
1228 c8abe1d4 Ermal Luçi
			$iflist[$if] = $if;
1229 751533a2 Phil Davis
		}
1230 42c9d20e Ermal Luçi
	}
1231 c8abe1d4 Ermal Luçi
1232
	return $iflist;
1233
}
1234
1235 bb34737f Ermal Lu?i
/* return the configured interfaces list. */
1236
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
1237 8735afe8 Erik Fonnesbeck
	global $config;
1238 bb34737f Ermal Lu?i
1239 8735afe8 Erik Fonnesbeck
	$iflist = array();
1240 bb34737f Ermal Lu?i
1241 8735afe8 Erik Fonnesbeck
	/* if list */
1242 751533a2 Phil Davis
	foreach ($config['interfaces'] as $if => $ifdetail) {
1243
		if ($only_opt && ($if == "wan" || $if == "lan")) {
1244 8735afe8 Erik Fonnesbeck
			continue;
1245 751533a2 Phil Davis
		}
1246 8735afe8 Erik Fonnesbeck
		if (isset($ifdetail['enable']) || $withdisabled == true) {
1247 bb34737f Ermal Lu?i
			$tmpif = get_real_interface($if);
1248 751533a2 Phil Davis
			if (!empty($tmpif)) {
1249 bb34737f Ermal Lu?i
				$iflist[$tmpif] = $if;
1250 751533a2 Phil Davis
			}
1251 bb34737f Ermal Lu?i
		}
1252 8735afe8 Erik Fonnesbeck
	}
1253 bb34737f Ermal Lu?i
1254 8735afe8 Erik Fonnesbeck
	return $iflist;
1255 bb34737f Ermal Lu?i
}
1256
1257 c8abe1d4 Ermal Luçi
/* return the configured interfaces list with their description. */
1258 3ad5e089 Ermal Luçi
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
1259 a42d1da2 Scott Ullrich
	global $config;
1260 c8abe1d4 Ermal Luçi
1261 a42d1da2 Scott Ullrich
	$iflist = array();
1262 c8abe1d4 Ermal Luçi
1263 a42d1da2 Scott Ullrich
	/* if list */
1264 751533a2 Phil Davis
	foreach ($config['interfaces'] as $if => $ifdetail) {
1265
		if ($only_opt && ($if == "wan" || $if == "lan")) {
1266 8735afe8 Erik Fonnesbeck
			continue;
1267 751533a2 Phil Davis
		}
1268 47c8b036 Ermal Lu?i
		if (isset($ifdetail['enable']) || $withdisabled == true) {
1269 751533a2 Phil Davis
			if (empty($ifdetail['descr'])) {
1270 8e74cb8d Ermal Luçi
				$iflist[$if] = strtoupper($if);
1271 751533a2 Phil Davis
			} else {
1272 44b0ec83 Scott Ullrich
				$iflist[$if] = strtoupper($ifdetail['descr']);
1273 751533a2 Phil Davis
			}
1274 0e218dc1 Ermal Luçi
		}
1275 42c9d20e Ermal Luçi
	}
1276 c8abe1d4 Ermal Luçi
1277 a42d1da2 Scott Ullrich
	return $iflist;
1278 c8abe1d4 Ermal Luçi
}
1279
1280 4fe9c2dc Scott Ullrich
/*
1281
 *   get_configured_ip_addresses() - Return a list of all configured
1282
 *   interfaces IP Addresses
1283
 *
1284
 */
1285
function get_configured_ip_addresses() {
1286 5dbd619f smos
	global $config;
1287 a1e4e2a7 Ermal
1288 751533a2 Phil Davis
	if (!function_exists('get_interface_ip')) {
1289 a1e4e2a7 Ermal
		require_once("interfaces.inc");
1290 751533a2 Phil Davis
	}
1291 4fe9c2dc Scott Ullrich
	$ip_array = array();
1292
	$interfaces = get_configured_interface_list();
1293 a1e4e2a7 Ermal
	if (is_array($interfaces)) {
1294 751533a2 Phil Davis
		foreach ($interfaces as $int) {
1295 d9114ce0 Scott Ullrich
			$ipaddr = get_interface_ip($int);
1296
			$ip_array[$int] = $ipaddr;
1297
		}
1298 4fe9c2dc Scott Ullrich
	}
1299 19f101d7 Scott Ullrich
	$interfaces = get_configured_carp_interface_list();
1300 751533a2 Phil Davis
	if (is_array($interfaces)) {
1301
		foreach ($interfaces as $int => $ipaddr) {
1302 d9114ce0 Scott Ullrich
			$ip_array[$int] = $ipaddr;
1303 751533a2 Phil Davis
		}
1304
	}
1305 5dbd619f smos
1306
	/* pppoe server */
1307 a1e4e2a7 Ermal
	if (is_array($config['pppoes']) && is_array($config['pppoes']['pppoe'])) {
1308 751533a2 Phil Davis
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
1309 5dbd619f smos
			if ($pppoe['mode'] == "server") {
1310 751533a2 Phil Davis
				if (is_ipaddr($pppoe['localip'])) {
1311 5dbd619f smos
					$int = "pppoes". $pppoe['pppoeid'];
1312
					$ip_array[$int] = $pppoe['localip'];
1313
				}
1314
			}
1315
		}
1316
	}
1317 a1e4e2a7 Ermal
1318 4fe9c2dc Scott Ullrich
	return $ip_array;
1319
}
1320 c8abe1d4 Ermal Luçi
1321 e6f7e0be smos
/*
1322
 *   get_configured_ipv6_addresses() - Return a list of all configured
1323
 *   interfaces IPv6 Addresses
1324
 *
1325
 */
1326
function get_configured_ipv6_addresses() {
1327
	require_once("interfaces.inc");
1328
	$ipv6_array = array();
1329
	$interfaces = get_configured_interface_list();
1330 751533a2 Phil Davis
	if (is_array($interfaces)) {
1331
		foreach ($interfaces as $int) {
1332 e6f7e0be smos
			$ipaddrv6 = get_interface_ipv6($int);
1333
			$ipv6_array[$int] = $ipaddrv6;
1334
		}
1335
	}
1336
	$interfaces = get_configured_carp_interface_list();
1337 751533a2 Phil Davis
	if (is_array($interfaces)) {
1338
		foreach ($interfaces as $int => $ipaddrv6) {
1339 e6f7e0be smos
			$ipv6_array[$int] = $ipaddrv6;
1340 751533a2 Phil Davis
		}
1341
	}
1342 e6f7e0be smos
	return $ipv6_array;
1343
}
1344
1345 36f546e9 Scott Ullrich
/*
1346
 *   get_interface_list() - Return a list of all physical interfaces
1347
 *   along with MAC and status.
1348
 *
1349
 *   $mode = "active" - use ifconfig -lu
1350
 *           "media"  - use ifconfig to check physical connection
1351
 *			status (much slower)
1352
 */
1353
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
1354 86a5e1a8 Renato Botelho
	global $config;
1355 65bed2d2 Scott Ullrich
	$upints = array();
1356 86a5e1a8 Renato Botelho
	/* get a list of virtual interface types */
1357 751533a2 Phil Davis
	if (!$vfaces) {
1358 086cf944 Phil Davis
		$vfaces = array(
1359 9ce38409 Scott Ullrich
				'bridge',
1360
				'ppp',
1361 27c0c7c6 Ermal Lu?i
				'pppoe',
1362
				'pptp',
1363
				'l2tp',
1364 9ce38409 Scott Ullrich
				'sl',
1365
				'gif',
1366 613571ea Ermal Luçi
				'gre',
1367 9ce38409 Scott Ullrich
				'faith',
1368
				'lo',
1369
				'ng',
1370 27616d6e Seth Mos
				'_vlan',
1371 7c53bc7b Erik Fonnesbeck
				'_wlan',
1372 9ce38409 Scott Ullrich
				'pflog',
1373 a42d1da2 Scott Ullrich
				'plip',
1374 9ce38409 Scott Ullrich
				'pfsync',
1375
				'enc',
1376
				'tun',
1377 0a140d2e Ermal Luçi
				'carp',
1378 1fb2bf25 Ermal Lu?i
				'lagg',
1379 1fd35e95 Ermal
				'vip',
1380
				'ipfw'
1381 9ce38409 Scott Ullrich
		);
1382 36f546e9 Scott Ullrich
	}
1383 751533a2 Phil Davis
	switch ($mode) {
1384
		case "active":
1385
			$upints = pfSense_interface_listget(IFF_UP);
1386
			break;
1387
		case "media":
1388
			$intlist = pfSense_interface_listget();
1389
			$ifconfig = "";
1390
			exec("/sbin/ifconfig -a", $ifconfig);
1391
			$regexp = '/(' . implode('|', $intlist) . '):\s/';
1392
			$ifstatus = preg_grep('/status:/', $ifconfig);
1393
			foreach ($ifstatus as $status) {
1394
				$int = array_shift($intlist);
1395
				if (stristr($status, "active")) {
1396
					$upints[] = $int;
1397
				}
1398
			}
1399
			break;
1400
		default:
1401
			$upints = pfSense_interface_listget();
1402
			break;
1403 20203646 Colin Smith
	}
1404 86a5e1a8 Renato Botelho
	/* build interface list with netstat */
1405
	$linkinfo = "";
1406
	exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
1407
	array_shift($linkinfo);
1408 89d1f0f2 Scott Ullrich
	/* build ip address list with netstat */
1409 767a716e Scott Ullrich
	$ipinfo = "";
1410 89d1f0f2 Scott Ullrich
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
1411
	array_shift($ipinfo);
1412 751533a2 Phil Davis
	foreach ($linkinfo as $link) {
1413 89d1f0f2 Scott Ullrich
		$friendly = "";
1414 5bbd08e1 Warren Baker
		$alink = explode(" ", $link);
1415
		$ifname = rtrim(trim($alink[0]), '*');
1416
		/* trim out all numbers before checking for vfaces */
1417 494be6e8 Ermal Lu?i
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
1418 751533a2 Phil Davis
		    !stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
1419 20203646 Colin Smith
			$toput = array(
1420
					"mac" => trim($alink[1]),
1421
					"up" => in_array($ifname, $upints)
1422
				);
1423 751533a2 Phil Davis
			foreach ($ipinfo as $ip) {
1424 89d1f0f2 Scott Ullrich
				$aip = explode(" ", $ip);
1425 751533a2 Phil Davis
				if ($aip[0] == $ifname) {
1426 89d1f0f2 Scott Ullrich
					$toput['ipaddr'] = $aip[1];
1427
				}
1428
			}
1429 72993196 Ermal
			if (is_array($config['interfaces'])) {
1430 751533a2 Phil Davis
				foreach ($config['interfaces'] as $name => $int) {
1431
					if ($int['if'] == $ifname) {
1432
						$friendly = $name;
1433
					}
1434
				}
1435 20203646 Colin Smith
			}
1436 751533a2 Phil Davis
			switch ($keyby) {
1437 20203646 Colin Smith
			case "physical":
1438 751533a2 Phil Davis
				if ($friendly != "") {
1439 89d1f0f2 Scott Ullrich
					$toput['friendly'] = $friendly;
1440
				}
1441 a296c95d Seth Mos
				$dmesg_arr = array();
1442
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
1443
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
1444
				$toput['dmesg'] = $dmesg[1][0];
1445 20203646 Colin Smith
				$iflist[$ifname] = $toput;
1446 3154d7ed Colin Smith
				break;
1447 4aca19b3 Scott Ullrich
			case "ppp":
1448 86a5e1a8 Renato Botelho
1449 20203646 Colin Smith
			case "friendly":
1450 751533a2 Phil Davis
				if ($friendly != "") {
1451 89d1f0f2 Scott Ullrich
					$toput['if'] = $ifname;
1452
					$iflist[$friendly] = $toput;
1453
				}
1454 3154d7ed Colin Smith
				break;
1455
			}
1456 5bbd08e1 Warren Baker
		}
1457
	}
1458
	return $iflist;
1459 5b237745 Scott Ullrich
}
1460
1461 2b4d37de Ermal Lu?i
/****f* util/log_error
1462
* NAME
1463
*   log_error  - Sends a string to syslog.
1464
* INPUTS
1465
*   $error     - string containing the syslog message.
1466
* RESULT
1467
*   null
1468
******/
1469
function log_error($error) {
1470 5bbd08e1 Warren Baker
	global $g;
1471
	$page = $_SERVER['SCRIPT_NAME'];
1472 866b1d61 jim-p
	if (empty($page)) {
1473
		$files = get_included_files();
1474
		$page = basename($files[0]);
1475
	}
1476 0d0cb047 jim-p
	syslog(LOG_ERR, "$page: $error");
1477 751533a2 Phil Davis
	if ($g['debug']) {
1478 5bbd08e1 Warren Baker
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1479 751533a2 Phil Davis
	}
1480 5bbd08e1 Warren Baker
	return;
1481 2b4d37de Ermal Lu?i
}
1482
1483 3aba1835 Scott Ullrich
/****f* util/log_auth
1484
* NAME
1485 1198abf9 PiBa-NL
*   log_auth   - Sends a string to syslog as LOG_AUTH facility
1486 3aba1835 Scott Ullrich
* INPUTS
1487
*   $error     - string containing the syslog message.
1488
* RESULT
1489
*   null
1490
******/
1491
function log_auth($error) {
1492 5bbd08e1 Warren Baker
	global $g;
1493
	$page = $_SERVER['SCRIPT_NAME'];
1494
	syslog(LOG_AUTH, "$page: $error");
1495 751533a2 Phil Davis
	if ($g['debug']) {
1496 5bbd08e1 Warren Baker
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1497 751533a2 Phil Davis
	}
1498 5bbd08e1 Warren Baker
	return;
1499 3aba1835 Scott Ullrich
}
1500
1501 83bc3749 Ermal Lu?i
/****f* util/exec_command
1502
 * NAME
1503
 *   exec_command - Execute a command and return a string of the result.
1504
 * INPUTS
1505
 *   $command   - String of the command to be executed.
1506
 * RESULT
1507
 *   String containing the command's result.
1508
 * NOTES
1509
 *   This function returns the command's stdout and stderr.
1510
 ******/
1511
function exec_command($command) {
1512 5bbd08e1 Warren Baker
	$output = array();
1513 873c1701 Renato Botelho
	exec($command . ' 2>&1', $output);
1514 5bbd08e1 Warren Baker
	return(implode("\n", $output));
1515 83bc3749 Ermal Lu?i
}
1516
1517 e00ad357 Renato Botelho
/* wrapper for exec()
1518 f0b41548 stilez
   Executes in background or foreground.
1519
   For background execution, returns PID of background process to allow calling code control */
1520
function mwexec($command, $nologentry = false, $clearsigmask = false, $background = false) {
1521 5b237745 Scott Ullrich
	global $g;
1522 f0b41548 stilez
	$retval = 0;
1523 435a418f Ermal
1524 5b237745 Scott Ullrich
	if ($g['debug']) {
1525 751533a2 Phil Davis
		if (!$_SERVER['REMOTE_ADDR']) {
1526 f0b41548 stilez
			echo "mwexec(): $command" . ($background ? " [BG]":"") . "\n";
1527 751533a2 Phil Davis
		}
1528 f9db3cda Seth Mos
	}
1529 b61e8960 jim-p
	if ($clearsigmask) {
1530
		$oldset = array();
1531
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1532
	}
1533 f0b41548 stilez
1534 2b1f6ed2 stilez
	if ($background) {
1535
		// start background process and return PID
1536
		$retval = exec("/usr/bin/nohup $command > /dev/null 2>&1 & echo $!");
1537
	} else {
1538
		// run in foreground, and (optionally) log if nonzero return
1539
		$outputarray = array();
1540 f0b41548 stilez
		exec("$command 2>&1", $outputarray, $retval);
1541 4e322e2c Phil Davis
		if (($retval <> 0) && (!$nologentry || isset($config['system']['developerspew']))) {
1542 f812b883 stilez
			log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, implode(" ", $outputarray)));
1543 4e322e2c Phil Davis
		}
1544 f0b41548 stilez
	}
1545
1546 b61e8960 jim-p
	if ($clearsigmask) {
1547
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1548
	}
1549 435a418f Ermal
1550 98bbf05a Scott Ullrich
	return $retval;
1551 5b237745 Scott Ullrich
}
1552
1553
/* wrapper for exec() in background */
1554 b61e8960 jim-p
function mwexec_bg($command, $clearsigmask = false) {
1555 f0b41548 stilez
	return mwexec($command, false, $clearsigmask, true);
1556 5b237745 Scott Ullrich
}
1557
1558 a85ad858 stilez
/* unlink a file, or pattern-match of a file, if it exists
1559 4e322e2c Phil Davis
   if the file/path contains glob() compatible wildcards, all matching files will be unlinked
1560 a85ad858 stilez
   if no matches, no error occurs */
1561 5b237745 Scott Ullrich
function unlink_if_exists($fn) {
1562 336cb718 Scott Ullrich
	$to_do = glob($fn);
1563 a85ad858 stilez
	if (is_array($to_do) && count($to_do) > 0) {
1564 4bc0cbc3 Renato Botelho
		@array_map("unlink", $to_do);
1565 336cb718 Scott Ullrich
	} else {
1566 9ff926a2 Colin Smith
		@unlink($fn);
1567 336cb718 Scott Ullrich
	}
1568 5b237745 Scott Ullrich
}
1569
/* make a global alias table (for faster lookups) */
1570 918a884d Bill Marquette
function alias_make_table($config) {
1571
	global $aliastable;
1572 98bbf05a Scott Ullrich
1573 5b237745 Scott Ullrich
	$aliastable = array();
1574 98bbf05a Scott Ullrich
1575 5b237745 Scott Ullrich
	if (is_array($config['aliases']['alias'])) {
1576
		foreach ($config['aliases']['alias'] as $alias) {
1577 751533a2 Phil Davis
			if ($alias['name']) {
1578 5b237745 Scott Ullrich
				$aliastable[$alias['name']] = $alias['address'];
1579 751533a2 Phil Davis
			}
1580 5b237745 Scott Ullrich
		}
1581
	}
1582
}
1583 5ffa3389 Ermal
1584 5b237745 Scott Ullrich
/* check if an alias exists */
1585
function is_alias($name) {
1586
	global $aliastable;
1587 98bbf05a Scott Ullrich
1588 5b237745 Scott Ullrich
	return isset($aliastable[$name]);
1589 b8014f9d Scott Ullrich
}
1590 27ff8a3c Scott Ullrich
1591 5ffa3389 Ermal
function alias_get_type($name) {
1592 86a5e1a8 Renato Botelho
	global $config;
1593
1594 5ffa3389 Ermal
	if (is_array($config['aliases']['alias'])) {
1595
		foreach ($config['aliases']['alias'] as $alias) {
1596 751533a2 Phil Davis
			if ($name == $alias['name']) {
1597 5ffa3389 Ermal
				return $alias['type'];
1598 751533a2 Phil Davis
			}
1599 5ffa3389 Ermal
		}
1600
	}
1601
1602 86a5e1a8 Renato Botelho
	return "";
1603 5ffa3389 Ermal
}
1604
1605 5b237745 Scott Ullrich
/* expand a host or network alias, if necessary */
1606
function alias_expand($name) {
1607
	global $aliastable;
1608 98bbf05a Scott Ullrich
1609 751533a2 Phil Davis
	if (isset($aliastable[$name])) {
1610 a97a77a2 Phil Davis
		// alias names cannot be strictly numeric. redmine #4289
1611
		if (is_numericint($name)) {
1612
			return null;
1613
		}
1614 4335dc87 Bill Marquette
		return "\${$name}";
1615 751533a2 Phil Davis
	} else if (is_ipaddr($name) || is_subnet($name) || is_port($name) || is_portrange($name)) {
1616 57989da5 Scott Ullrich
		return "{$name}";
1617 751533a2 Phil Davis
	} else {
1618 5b237745 Scott Ullrich
		return null;
1619 751533a2 Phil Davis
	}
1620 5b237745 Scott Ullrich
}
1621
1622 c7de8be4 jim-p
function alias_expand_urltable($name) {
1623
	global $config;
1624
	$urltable_prefix = "/var/db/aliastables/";
1625
	$urltable_filename = $urltable_prefix . $name . ".txt";
1626
1627 5ffa3389 Ermal
	if (is_array($config['aliases']['alias'])) {
1628
		foreach ($config['aliases']['alias'] as $alias) {
1629 dd042c51 Renato Botelho
			if (preg_match("/urltable/i", $alias['type']) && ($alias['name'] == $name)) {
1630 751533a2 Phil Davis
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename)) {
1631 5ffa3389 Ermal
					return $urltable_filename;
1632 5b2b1f4e Ermal LUÇI
				} else {
1633
					send_event("service sync alias {$name}");
1634
					break;
1635 751533a2 Phil Davis
				}
1636 5ffa3389 Ermal
			}
1637 c7de8be4 jim-p
		}
1638
	}
1639
	return null;
1640
}
1641
1642 5b237745 Scott Ullrich
/* obtain MAC address given an IP address by looking at the ARP table */
1643
function arp_get_mac_by_ip($ip) {
1644 873c1701 Renato Botelho
	mwexec("/sbin/ping -c 1 -t 1 " . escapeshellarg($ip), true);
1645 767a716e Scott Ullrich
	$arpoutput = "";
1646 873c1701 Renato Botelho
	exec("/usr/sbin/arp -n " . escapeshellarg($ip), $arpoutput);
1647 98bbf05a Scott Ullrich
1648 5b237745 Scott Ullrich
	if ($arpoutput[0]) {
1649
		$arpi = explode(" ", $arpoutput[0]);
1650
		$macaddr = $arpi[3];
1651 751533a2 Phil Davis
		if (is_macaddr($macaddr)) {
1652 5b237745 Scott Ullrich
			return $macaddr;
1653 751533a2 Phil Davis
		} else {
1654 5b237745 Scott Ullrich
			return false;
1655 751533a2 Phil Davis
		}
1656 5b237745 Scott Ullrich
	}
1657 98bbf05a Scott Ullrich
1658 5b237745 Scott Ullrich
	return false;
1659
}
1660
1661 98bbf05a Scott Ullrich
/* return a fieldname that is safe for xml usage */
1662
function xml_safe_fieldname($fieldname) {
1663 87f0be87 Chris Buechler
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1664
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1665 ddce8ef2 Colin Smith
			 ':', ',', '.', '\'', '\\'
1666
		);
1667
	return strtolower(str_replace($replace, "", $fieldname));
1668 98bbf05a Scott Ullrich
}
1669
1670 805b9ab6 Ermal
function mac_format($clientmac) {
1671 86a5e1a8 Renato Botelho
	global $config, $cpzone;
1672 4129df39 Scott Ullrich
1673 86a5e1a8 Renato Botelho
	$mac = explode(":", $clientmac);
1674
	$mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1675 4129df39 Scott Ullrich
1676 751533a2 Phil Davis
	switch ($mac_format) {
1677
		case 'singledash':
1678
			return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1679 4129df39 Scott Ullrich
1680 751533a2 Phil Davis
		case 'ietf':
1681
			return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1682 4129df39 Scott Ullrich
1683 751533a2 Phil Davis
		case 'cisco':
1684
			return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1685 4129df39 Scott Ullrich
1686 751533a2 Phil Davis
		case 'unformatted':
1687
			return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1688 4129df39 Scott Ullrich
1689 751533a2 Phil Davis
		default:
1690
			return $clientmac;
1691 86a5e1a8 Renato Botelho
	}
1692 4129df39 Scott Ullrich
}
1693
1694 979cd6db Scott Ullrich
function resolve_retry($hostname, $retries = 5) {
1695
1696 751533a2 Phil Davis
	if (is_ipaddr($hostname)) {
1697 5bbd08e1 Warren Baker
		return $hostname;
1698 751533a2 Phil Davis
	}
1699 979cd6db Scott Ullrich
1700 86a5e1a8 Renato Botelho
	for ($i = 0; $i < $retries; $i++) {
1701 6c4f3b54 Seth Mos
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1702 86a5e1a8 Renato Botelho
		$ip = gethostbyname($hostname);
1703 979cd6db Scott Ullrich
1704 5bbd08e1 Warren Baker
		if ($ip && $ip != $hostname) {
1705
			/* success */
1706
			return $ip;
1707
		}
1708 979cd6db Scott Ullrich
1709 5bbd08e1 Warren Baker
		sleep(1);
1710
	}
1711 979cd6db Scott Ullrich
1712 5bbd08e1 Warren Baker
	return false;
1713 979cd6db Scott Ullrich
}
1714
1715 44bfd1fa Scott Ullrich
function format_bytes($bytes) {
1716
	if ($bytes >= 1073741824) {
1717
		return sprintf("%.2f GB", $bytes/1073741824);
1718
	} else if ($bytes >= 1048576) {
1719
		return sprintf("%.2f MB", $bytes/1048576);
1720
	} else if ($bytes >= 1024) {
1721
		return sprintf("%.0f KB", $bytes/1024);
1722
	} else {
1723 10ae204f Stephen Beaver
		return sprintf("%d B", $bytes);
1724 44bfd1fa Scott Ullrich
	}
1725
}
1726
1727 cc2cff0b Luiz Otavio O Souza
function format_number($num, $precision = 3) {
1728
	$units = array('', 'K', 'M', 'G', 'T');
1729
1730
	$i = 0;
1731
	while ($num > 1000 && $i < count($units)) {
1732
		$num /= 1000;
1733
		$i++;
1734
	}
1735
	round($num, $precision);
1736
1737
	return ("$num {$units[$i]}");
1738
}
1739
1740 2b4d37de Ermal Lu?i
function update_filter_reload_status($text) {
1741 5bbd08e1 Warren Baker
	global $g;
1742 2b4d37de Ermal Lu?i
1743 5bbd08e1 Warren Baker
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1744 2b4d37de Ermal Lu?i
}
1745
1746 a2219caf Renato Botelho
/****** util/return_dir_as_array
1747 2b4d37de Ermal Lu?i
 * NAME
1748
 *   return_dir_as_array - Return a directory's contents as an array.
1749
 * INPUTS
1750 a2219caf Renato Botelho
 *   $dir          - string containing the path to the desired directory.
1751
 *   $filter_regex - string containing a regular expression to filter file names. Default empty.
1752 2b4d37de Ermal Lu?i
 * RESULT
1753
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1754
 ******/
1755 a2219caf Renato Botelho
function return_dir_as_array($dir, $filter_regex = '') {
1756 5bbd08e1 Warren Baker
	$dir_array = array();
1757
	if (is_dir($dir)) {
1758
		if ($dh = opendir($dir)) {
1759
			while (($file = readdir($dh)) !== false) {
1760 751533a2 Phil Davis
				if (($file == ".") || ($file == "..")) {
1761 a2219caf Renato Botelho
					continue;
1762 751533a2 Phil Davis
				}
1763 a2219caf Renato Botelho
1764 751533a2 Phil Davis
				if (empty($filter_regex) || preg_match($filter_regex, $file)) {
1765 5bbd08e1 Warren Baker
					array_push($dir_array, $file);
1766 751533a2 Phil Davis
				}
1767 5bbd08e1 Warren Baker
			}
1768
			closedir($dh);
1769
		}
1770
	}
1771
	return $dir_array;
1772 2b4d37de Ermal Lu?i
}
1773
1774
function run_plugins($directory) {
1775 5bbd08e1 Warren Baker
	global $config, $g;
1776
1777
	/* process packager manager custom rules */
1778
	$files = return_dir_as_array($directory);
1779
	if (is_array($files)) {
1780
		foreach ($files as $file) {
1781 751533a2 Phil Davis
			if (stristr($file, ".sh") == true) {
1782 5bbd08e1 Warren Baker
				mwexec($directory . $file . " start");
1783 086cf944 Phil Davis
			} else if (!is_dir($directory . "/" . $file) && stristr($file, ".inc")) {
1784 5bbd08e1 Warren Baker
				require_once($directory . "/" . $file);
1785 751533a2 Phil Davis
			}
1786 2990acf8 Scott Ullrich
		}
1787 5bbd08e1 Warren Baker
	}
1788 2b4d37de Ermal Lu?i
}
1789
1790
/*
1791
 *    safe_mkdir($path, $mode = 0755)
1792
 *    create directory if it doesn't already exist and isn't a file!
1793
 */
1794 6c07db48 Phil Davis
function safe_mkdir($path, $mode = 0755) {
1795 5bbd08e1 Warren Baker
	global $g;
1796 2b4d37de Ermal Lu?i
1797 5bbd08e1 Warren Baker
	if (!is_file($path) && !is_dir($path)) {
1798
		return @mkdir($path, $mode, true);
1799
	} else {
1800
		return false;
1801
	}
1802 2b4d37de Ermal Lu?i
}
1803
1804 aa4f498d Erik Fonnesbeck
/*
1805
 * get_sysctl($names)
1806
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1807
 * name) and return an array of key/value pairs set for those that exist
1808
 */
1809
function get_sysctl($names) {
1810 751533a2 Phil Davis
	if (empty($names)) {
1811 aa4f498d Erik Fonnesbeck
		return array();
1812 751533a2 Phil Davis
	}
1813 aa4f498d Erik Fonnesbeck
1814
	if (is_array($names)) {
1815
		$name_list = array();
1816
		foreach ($names as $name) {
1817
			$name_list[] = escapeshellarg($name);
1818
		}
1819 751533a2 Phil Davis
	} else {
1820 aa4f498d Erik Fonnesbeck
		$name_list = array(escapeshellarg($names));
1821 751533a2 Phil Davis
	}
1822 aa4f498d Erik Fonnesbeck
1823
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1824
	$values = array();
1825
	foreach ($output as $line) {
1826
		$line = explode(": ", $line, 2);
1827 751533a2 Phil Davis
		if (count($line) == 2) {
1828 aa4f498d Erik Fonnesbeck
			$values[$line[0]] = $line[1];
1829 751533a2 Phil Davis
		}
1830 aa4f498d Erik Fonnesbeck
	}
1831
1832
	return $values;
1833
}
1834
1835 ff23363d Renato Botelho
/*
1836
 * get_single_sysctl($name)
1837
 * Wrapper for get_sysctl() to simplify read of a single sysctl value
1838
 * return the value for sysctl $name or empty string if it doesn't exist
1839
 */
1840
function get_single_sysctl($name) {
1841 751533a2 Phil Davis
	if (empty($name)) {
1842 ff23363d Renato Botelho
		return "";
1843 751533a2 Phil Davis
	}
1844 ff23363d Renato Botelho
1845
	$value = get_sysctl($name);
1846 751533a2 Phil Davis
	if (empty($value) || !isset($value[$name])) {
1847 ff23363d Renato Botelho
		return "";
1848 751533a2 Phil Davis
	}
1849 ff23363d Renato Botelho
1850
	return $value[$name];
1851
}
1852
1853 aa4f498d Erik Fonnesbeck
/*
1854
 * set_sysctl($value_list)
1855
 * Set sysctl OID's listed as key/value pairs and return
1856
 * an array with keys set for those that succeeded
1857
 */
1858
function set_sysctl($values) {
1859 751533a2 Phil Davis
	if (empty($values)) {
1860 aa4f498d Erik Fonnesbeck
		return array();
1861 751533a2 Phil Davis
	}
1862 aa4f498d Erik Fonnesbeck
1863
	$value_list = array();
1864
	foreach ($values as $key => $value) {
1865
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1866
	}
1867
1868
	exec("/sbin/sysctl -i " . implode(" ", $value_list), $output, $success);
1869
1870
	/* Retry individually if failed (one or more read-only) */
1871
	if ($success <> 0 && count($value_list) > 1) {
1872
		foreach ($value_list as $value) {
1873
			exec("/sbin/sysctl -i " . $value, $output);
1874
		}
1875
	}
1876
1877
	$ret = array();
1878
	foreach ($output as $line) {
1879
		$line = explode(": ", $line, 2);
1880 751533a2 Phil Davis
		if (count($line) == 2) {
1881 aa4f498d Erik Fonnesbeck
			$ret[$line[0]] = true;
1882 751533a2 Phil Davis
		}
1883 aa4f498d Erik Fonnesbeck
	}
1884
1885
	return $ret;
1886
}
1887
1888 82f75815 Renato Botelho
/*
1889
 * set_single_sysctl($name, $value)
1890
 * Wrapper to set_sysctl() to make it simple to set only one sysctl
1891 751533a2 Phil Davis
 * returns boolean meaning if it succeeded
1892 82f75815 Renato Botelho
 */
1893
function set_single_sysctl($name, $value) {
1894 751533a2 Phil Davis
	if (empty($name)) {
1895 82f75815 Renato Botelho
		return false;
1896 751533a2 Phil Davis
	}
1897 82f75815 Renato Botelho
1898
	$result = set_sysctl(array($name => $value));
1899
1900 751533a2 Phil Davis
	if (!isset($result[$name]) || $result[$name] != $value) {
1901 82f75815 Renato Botelho
		return false;
1902 751533a2 Phil Davis
	}
1903 82f75815 Renato Botelho
1904
	return true;
1905
}
1906
1907 2b4d37de Ermal Lu?i
/*
1908
 *     get_memory()
1909
 *     returns an array listing the amount of
1910
 *     memory installed in the hardware
1911 517fb89e Phil Davis
 *     [0] net memory available for the OS (FreeBSD) after some is taken by BIOS, video or whatever - e.g. 235 MBytes
1912
 *     [1] real (actual) memory of the system, should be the size of the RAM card/s - e.g. 256 MBytes
1913 2b4d37de Ermal Lu?i
 */
1914
function get_memory() {
1915 971de1f9 Renato Botelho
	$physmem = get_single_sysctl("hw.physmem");
1916
	$realmem = get_single_sysctl("hw.realmem");
1917 5cd73772 Ermal
	/* convert from bytes to megabytes */
1918 086cf944 Phil Davis
	return array(($physmem/1048576), ($realmem/1048576));
1919 2b4d37de Ermal Lu?i
}
1920
1921
function mute_kernel_msgs() {
1922 6fa9f38c Renato Botelho
	global $g, $config;
1923 5bbd08e1 Warren Baker
	// Do not mute serial console.  The kernel gets very very cranky
1924
	// and will start dishing you cannot control tty errors.
1925 6fa9f38c Renato Botelho
	if ($g['platform'] == 'nanobsd') {
1926
		return;
1927 7734aea6 Andrew Thompson
	}
1928 751533a2 Phil Davis
	if ($config['system']['enableserial']) {
1929 86a5e1a8 Renato Botelho
		return;
1930 751533a2 Phil Davis
	}
1931 5bbd08e1 Warren Baker
	exec("/sbin/conscontrol mute on");
1932 2b4d37de Ermal Lu?i
}
1933
1934
function unmute_kernel_msgs() {
1935 6fa9f38c Renato Botelho
	global $g;
1936 5bbd08e1 Warren Baker
	// Do not mute serial console.  The kernel gets very very cranky
1937
	// and will start dishing you cannot control tty errors.
1938 6fa9f38c Renato Botelho
	if ($g['platform'] == 'nanobsd') {
1939
		return;
1940 7734aea6 Andrew Thompson
	}
1941 5bbd08e1 Warren Baker
	exec("/sbin/conscontrol mute off");
1942 2b4d37de Ermal Lu?i
}
1943
1944
function start_devd() {
1945 751533a2 Phil Davis
	/* Use the undocumented -q options of devd to quiet its log spamming */
1946 a7f79eda Ermal LUÇI
	$_gb = exec("/sbin/devd -q");
1947 5bbd08e1 Warren Baker
	sleep(1);
1948 a7f79eda Ermal LUÇI
	unset($_gb);
1949 2b4d37de Ermal Lu?i
}
1950
1951 66bcba1b Ermal
function is_interface_vlan_mismatch() {
1952 5bbd08e1 Warren Baker
	global $config, $g;
1953 66bcba1b Ermal
1954 5bbd08e1 Warren Baker
	if (is_array($config['vlans']['vlan'])) {
1955
		foreach ($config['vlans']['vlan'] as $vlan) {
1956 751533a2 Phil Davis
			if (does_interface_exist($vlan['if']) == false) {
1957 66bcba1b Ermal
				return true;
1958 751533a2 Phil Davis
			}
1959 5bbd08e1 Warren Baker
		}
1960
	}
1961 66bcba1b Ermal
1962
	return false;
1963
}
1964
1965 2b4d37de Ermal Lu?i
function is_interface_mismatch() {
1966 857da904 Scott Ullrich
	global $config, $g;
1967 2b4d37de Ermal Lu?i
1968 857da904 Scott Ullrich
	$do_assign = false;
1969
	$i = 0;
1970 e0a45ce0 Erik Fonnesbeck
	$missing_interfaces = array();
1971 72993196 Ermal
	if (is_array($config['interfaces'])) {
1972 857da904 Scott Ullrich
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1973 fd863e5c Erik Fonnesbeck
			if (preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1974 857da904 Scott Ullrich
				// Do not check these interfaces.
1975
				$i++;
1976
				continue;
1977 751533a2 Phil Davis
			} else if (does_interface_exist($ifcfg['if']) == false) {
1978 e0a45ce0 Erik Fonnesbeck
				$missing_interfaces[] = $ifcfg['if'];
1979 72993196 Ermal
				$do_assign = true;
1980 751533a2 Phil Davis
			} else {
1981 857da904 Scott Ullrich
				$i++;
1982 751533a2 Phil Davis
			}
1983 857da904 Scott Ullrich
		}
1984 72993196 Ermal
	}
1985 2b4d37de Ermal Lu?i
1986 751533a2 Phil Davis
	if (file_exists("{$g['tmp_path']}/assign_complete")) {
1987 e0a45ce0 Erik Fonnesbeck
		$do_assign = false;
1988 751533a2 Phil Davis
	}
1989 e0a45ce0 Erik Fonnesbeck
1990 751533a2 Phil Davis
	if (!empty($missing_interfaces) && $do_assign) {
1991 e0a45ce0 Erik Fonnesbeck
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
1992 751533a2 Phil Davis
	} else {
1993 e0a45ce0 Erik Fonnesbeck
		@unlink("{$g['tmp_path']}/missing_interfaces");
1994 751533a2 Phil Davis
	}
1995 2b4d37de Ermal Lu?i
1996 857da904 Scott Ullrich
	return $do_assign;
1997 2b4d37de Ermal Lu?i
}
1998
1999 6e8f7b53 Ermal Lu?i
/* sync carp entries to other firewalls */
2000
function carp_sync_client() {
2001 e14d1c01 Ermal Lu?i
	global $g;
2002 0ae6daf8 Ermal
	send_event("filter sync");
2003 6e8f7b53 Ermal Lu?i
}
2004
2005 6dc88d53 Ermal Luci
/****f* util/isAjax
2006
 * NAME
2007
 *   isAjax - reports if the request is driven from prototype
2008
 * INPUTS
2009
 *   none
2010
 * RESULT
2011
 *   true/false
2012
 ******/
2013
function isAjax() {
2014 5bbd08e1 Warren Baker
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
2015 6dc88d53 Ermal Luci
}
2016
2017 dad2b40e Tim Allender
/****f* util/timeout
2018
 * NAME
2019
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
2020
 * INPUTS
2021
 *   optional, seconds to wait before timeout. Default 9 seconds.
2022
 * RESULT
2023
 *   returns 1 char of user input or null if no input.
2024
 ******/
2025
function timeout($timer = 9) {
2026 751533a2 Phil Davis
	while (!isset($key)) {
2027
		if ($timer >= 9) {
2028 6c07db48 Phil Davis
			echo chr(8) . chr(8) . ($timer == 9 ? chr(32) : null) . "{$timer}";
2029 751533a2 Phil Davis
		} else {
2030
			echo chr(8). "{$timer}";
2031
		}
2032 dad2b40e Tim Allender
		`/bin/stty -icanon min 0 time 25`;
2033
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
2034
		`/bin/stty icanon`;
2035 751533a2 Phil Davis
		if ($key == '') {
2036 dad2b40e Tim Allender
			unset($key);
2037 751533a2 Phil Davis
		}
2038 dad2b40e Tim Allender
		$timer--;
2039 751533a2 Phil Davis
		if ($timer == 0) {
2040 dad2b40e Tim Allender
			break;
2041 751533a2 Phil Davis
		}
2042 dad2b40e Tim Allender
	}
2043 86a5e1a8 Renato Botelho
	return $key;
2044 dad2b40e Tim Allender
}
2045 6dc88d53 Ermal Luci
2046 fdf3af3f Scott Ullrich
/****f* util/msort
2047
 * NAME
2048
 *   msort - sort array
2049
 * INPUTS
2050
 *   $array to be sorted, field to sort by, direction of sort
2051
 * RESULT
2052
 *   returns newly sorted array
2053
 ******/
2054 6c07db48 Phil Davis
function msort($array, $id = "id", $sort_ascending = true) {
2055 4a8bc5a2 Scott Ullrich
	$temp_array = array();
2056 751533a2 Phil Davis
	while (count($array)>0) {
2057 4a8bc5a2 Scott Ullrich
		$lowest_id = 0;
2058 6c07db48 Phil Davis
		$index = 0;
2059 4a8bc5a2 Scott Ullrich
		foreach ($array as $item) {
2060
			if (isset($item[$id])) {
2061
				if ($array[$lowest_id][$id]) {
2062
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
2063
						$lowest_id = $index;
2064
					}
2065
				}
2066
			}
2067
			$index++;
2068
		}
2069
		$temp_array[] = $array[$lowest_id];
2070 086cf944 Phil Davis
		$array = array_merge(array_slice($array, 0, $lowest_id), array_slice($array, $lowest_id + 1));
2071 4a8bc5a2 Scott Ullrich
	}
2072
	if ($sort_ascending) {
2073
		return $temp_array;
2074
	} else {
2075 86a5e1a8 Renato Botelho
		return array_reverse($temp_array);
2076 4a8bc5a2 Scott Ullrich
	}
2077
}
2078
2079 5e9dd72a sullrich
/****f* util/is_URL
2080
 * NAME
2081
 *   is_URL
2082
 * INPUTS
2083
 *   string to check
2084
 * RESULT
2085
 *   Returns true if item is a URL
2086
 ******/
2087
function is_URL($url) {
2088
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
2089 751533a2 Phil Davis
	if ($match) {
2090 86a5e1a8 Renato Botelho
		return true;
2091 751533a2 Phil Davis
	}
2092 5e9dd72a sullrich
	return false;
2093
}
2094
2095 ab94ba00 Ermal Lu?i
function is_file_included($file = "") {
2096
	$files = get_included_files();
2097 751533a2 Phil Davis
	if (in_array($file, $files)) {
2098 ab94ba00 Ermal Lu?i
		return true;
2099 751533a2 Phil Davis
	}
2100 86a5e1a8 Renato Botelho
2101 ab94ba00 Ermal Lu?i
	return false;
2102
}
2103
2104 f2cc3344 Renato Botelho
/*
2105
 * Replace a value on a deep associative array using regex
2106
 */
2107
function array_replace_values_recursive($data, $match, $replace) {
2108 751533a2 Phil Davis
	if (empty($data)) {
2109 f2cc3344 Renato Botelho
		return $data;
2110 751533a2 Phil Davis
	}
2111 f2cc3344 Renato Botelho
2112 751533a2 Phil Davis
	if (is_string($data)) {
2113 f2cc3344 Renato Botelho
		$data = preg_replace("/{$match}/", $replace, $data);
2114 751533a2 Phil Davis
	} else if (is_array($data)) {
2115
		foreach ($data as $k => $v) {
2116 f2cc3344 Renato Botelho
			$data[$k] = array_replace_values_recursive($v, $match, $replace);
2117 751533a2 Phil Davis
		}
2118
	}
2119 f2cc3344 Renato Botelho
2120
	return $data;
2121
}
2122
2123 0d90fcaf jim-p
/*
2124
	This function was borrowed from a comment on PHP.net at the following URL:
2125
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
2126
 */
2127 5bbd08e1 Warren Baker
function array_merge_recursive_unique($array0, $array1) {
2128
2129
	$arrays = func_get_args();
2130
	$remains = $arrays;
2131 0d90fcaf jim-p
2132 5bbd08e1 Warren Baker
	// We walk through each arrays and put value in the results (without
2133
	// considering previous value).
2134
	$result = array();
2135 0d90fcaf jim-p
2136 5bbd08e1 Warren Baker
	// loop available array
2137 751533a2 Phil Davis
	foreach ($arrays as $array) {
2138 0d90fcaf jim-p
2139 5bbd08e1 Warren Baker
		// The first remaining array is $array. We are processing it. So
2140 751533a2 Phil Davis
		// we remove it from remaining arrays.
2141 86a5e1a8 Renato Botelho
		array_shift($remains);
2142 0d90fcaf jim-p
2143 5bbd08e1 Warren Baker
		// We don't care non array param, like array_merge since PHP 5.0.
2144 751533a2 Phil Davis
		if (is_array($array)) {
2145 5bbd08e1 Warren Baker
			// Loop values
2146 751533a2 Phil Davis
			foreach ($array as $key => $value) {
2147
				if (is_array($value)) {
2148 5bbd08e1 Warren Baker
					// we gather all remaining arrays that have such key available
2149
					$args = array();
2150 751533a2 Phil Davis
					foreach ($remains as $remain) {
2151
						if (array_key_exists($key, $remain)) {
2152 5bbd08e1 Warren Baker
							array_push($args, $remain[$key]);
2153
						}
2154
					}
2155
2156 751533a2 Phil Davis
					if (count($args) > 2) {
2157 5bbd08e1 Warren Baker
						// put the recursion
2158
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
2159
					} else {
2160 751533a2 Phil Davis
						foreach ($value as $vkey => $vval) {
2161 5bbd08e1 Warren Baker
							$result[$key][$vkey] = $vval;
2162
						}
2163
					}
2164
				} else {
2165
					// simply put the value
2166
					$result[$key] = $value;
2167
				}
2168
			}
2169
		}
2170
	}
2171
	return $result;
2172 0d90fcaf jim-p
}
2173
2174 f898c1a9 jim-p
2175 9a456170 Darren Embry
/*
2176
 * converts a string like "a,b,c,d"
2177
 * into an array like array("a" => "b", "c" => "d")
2178
 */
2179
function explode_assoc($delimiter, $string) {
2180
	$array = explode($delimiter, $string);
2181
	$result = array();
2182
	$numkeys = floor(count($array) / 2);
2183
	for ($i = 0; $i < $numkeys; $i += 1) {
2184
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
2185
	}
2186
	return $result;
2187
}
2188
2189 1901463c Renato Botelho
function get_staticroutes($returnsubnetsonly = false, $returnhostnames = false) {
2190
	global $config, $aliastable;
2191 f898c1a9 jim-p
2192
	/* Bail if there are no routes, but return an array always so callers don't have to check. */
2193 751533a2 Phil Davis
	if (!is_array($config['staticroutes']['route'])) {
2194 f898c1a9 jim-p
		return array();
2195 751533a2 Phil Davis
	}
2196 f898c1a9 jim-p
2197 bcab1b07 Ermal
	$allstaticroutes = array();
2198
	$allsubnets = array();
2199 f898c1a9 jim-p
	/* Loop through routes and expand aliases as we find them. */
2200
	foreach ($config['staticroutes']['route'] as $route) {
2201
		if (is_alias($route['network'])) {
2202 751533a2 Phil Davis
			if (!isset($aliastable[$route['network']])) {
2203 1901463c Renato Botelho
				continue;
2204 751533a2 Phil Davis
			}
2205 1901463c Renato Botelho
2206
			$subnets = preg_split('/\s+/', $aliastable[$route['network']]);
2207 f898c1a9 jim-p
			foreach ($subnets as $net) {
2208 bcab1b07 Ermal
				if (!is_subnet($net)) {
2209 751533a2 Phil Davis
					if (is_ipaddrv4($net)) {
2210 bcab1b07 Ermal
						$net .= "/32";
2211 751533a2 Phil Davis
					} else if (is_ipaddrv6($net)) {
2212 bcab1b07 Ermal
						$net .= "/128";
2213 751533a2 Phil Davis
					} else if ($returnhostnames === false || !is_fqdn($net)) {
2214 bcab1b07 Ermal
						continue;
2215 751533a2 Phil Davis
					}
2216 bcab1b07 Ermal
				}
2217 f898c1a9 jim-p
				$temproute = $route;
2218
				$temproute['network'] = $net;
2219
				$allstaticroutes[] = $temproute;
2220
				$allsubnets[] = $net;
2221
			}
2222
		} elseif (is_subnet($route['network'])) {
2223
			$allstaticroutes[] = $route;
2224
			$allsubnets[] = $route['network'];
2225
		}
2226
	}
2227 751533a2 Phil Davis
	if ($returnsubnetsonly) {
2228 f898c1a9 jim-p
		return $allsubnets;
2229 751533a2 Phil Davis
	} else {
2230 f898c1a9 jim-p
		return $allstaticroutes;
2231 751533a2 Phil Davis
	}
2232 f898c1a9 jim-p
}
2233 a0539faa Darren Embry
2234
/****f* util/get_alias_list
2235
 * NAME
2236
 *   get_alias_list - Provide a list of aliases.
2237
 * INPUTS
2238
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
2239
 * RESULT
2240
 *   Array containing list of aliases.
2241
 *   If $type is unspecified, all aliases are returned.
2242
 *   If $type is a string, all aliases of the type specified in $type are returned.
2243
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
2244
 */
2245
function get_alias_list($type = null) {
2246
	global $config;
2247
	$result = array();
2248
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
2249
		foreach ($config['aliases']['alias'] as $alias) {
2250
			if ($type === null) {
2251
				$result[] = $alias['name'];
2252 751533a2 Phil Davis
			} else if (is_array($type)) {
2253 a0539faa Darren Embry
				if (in_array($alias['type'], $type)) {
2254
					$result[] = $alias['name'];
2255
				}
2256 751533a2 Phil Davis
			} else if ($type === $alias['type']) {
2257 a0539faa Darren Embry
				$result[] = $alias['name'];
2258
			}
2259
		}
2260 86a5e1a8 Renato Botelho
	}
2261 a0539faa Darren Embry
	return $result;
2262
}
2263
2264 4dfd930e Darren Embry
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
2265
function array_exclude($needle, $haystack) {
2266
	$result = array();
2267
	if (is_array($haystack)) {
2268
		foreach ($haystack as $thing) {
2269
			if ($needle !== $thing) {
2270
				$result[] = $thing;
2271
			}
2272
		}
2273
	}
2274
	return $result;
2275
}
2276
2277 77a341a4 Renato Botelho
/* Define what is preferred, IPv4 or IPv6 */
2278
function prefer_ipv4_or_ipv6() {
2279
	global $config;
2280
2281 751533a2 Phil Davis
	if (isset($config['system']['prefer_ipv4'])) {
2282 77a341a4 Renato Botelho
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv4");
2283 751533a2 Phil Davis
	} else {
2284 77a341a4 Renato Botelho
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv6");
2285 751533a2 Phil Davis
	}
2286 77a341a4 Renato Botelho
}
2287
2288 111bea0d Renato Botelho
/* Redirect to page passing parameters via POST */
2289
function post_redirect($page, $params) {
2290 751533a2 Phil Davis
	if (!is_array($params)) {
2291 111bea0d Renato Botelho
		return;
2292 751533a2 Phil Davis
	}
2293 111bea0d Renato Botelho
2294
	print "<html><body><form action=\"{$page}\" name=\"formredir\" method=\"post\">\n";
2295
	foreach ($params as $key => $value) {
2296
		print "<input type=\"hidden\" name=\"{$key}\" value=\"{$value}\" />\n";
2297
	}
2298 8fd9052f Colin Fleming
	print "</form>\n";
2299
	print "<script type=\"text/javascript\">\n";
2300
	print "//<![CDATA[\n";
2301
	print "document.formredir.submit();\n";
2302
	print "//]]>\n";
2303
	print "</script>\n";
2304 111bea0d Renato Botelho
	print "</body></html>\n";
2305
}
2306
2307 ea20169a jim-p
/* Locate disks that can be queried for S.M.A.R.T. data. */
2308
function get_smart_drive_list() {
2309
	$disk_list = explode(" ", get_single_sysctl("kern.disks"));
2310
	foreach ($disk_list as $id => $disk) {
2311
		// We only want certain kinds of disks for S.M.A.R.T.
2312 a68c6785 Phil Davis
		// 1 is a match, 0 is no match, False is any problem processing the regex
2313
		if (preg_match("/^(ad|da|ada).*[0-9]{1,2}$/", $disk) !== 1) {
2314 ea20169a jim-p
			unset($disk_list[$id]);
2315
		}
2316
	}
2317
	sort($disk_list);
2318
	return $disk_list;
2319
}
2320
2321 eb295a1b Ermal
?>