Project

General

Profile

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