Project

General

Profile

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