Project

General

Profile

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