Project

General

Profile

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