Project

General

Profile

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