Project

General

Profile

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