Project

General

Profile

Download (76.4 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 905bd44e PiBa-NL
function is_v4($ip_or_subnet) {
776
	return is_ipaddrv4($ip_or_subnet) || is_subnetv4($ip_or_subnet);
777
}
778
779
function is_v6($ip_or_subnet) {
780
	return is_ipaddrv6($ip_or_subnet) || is_subnetv6($ip_or_subnet);
781
}
782
783 a5e2a35f stilez
/* same as is_subnet() but accepts IPv4 only */
784 b1b42a06 Warren Baker
function is_subnetv4($subnet) {
785 a5e2a35f stilez
	return (is_subnet($subnet) == 4);
786 5b237745 Scott Ullrich
}
787
788 a5e2a35f stilez
/* same as is_subnet() but accepts IPv6 only */
789 fdb9c1db Warren Baker
function is_subnetv6($subnet) {
790 a5e2a35f stilez
	return (is_subnet($subnet) == 6);
791 fdb9c1db Warren Baker
}
792
793 5b237745 Scott Ullrich
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
794
function is_subnetoralias($subnet) {
795
	global $aliastable;
796 98bbf05a Scott Ullrich
797 751533a2 Phil Davis
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet])) {
798 5b237745 Scott Ullrich
		return true;
799 751533a2 Phil Davis
	} else {
800 5b237745 Scott Ullrich
		return is_subnet($subnet);
801 751533a2 Phil Davis
	}
802 5b237745 Scott Ullrich
}
803
804 cafe9038 stilez
/* Get number of addresses in an IPv4/IPv6 subnet (represented as a string)
805
   optional $exact=true forces error (0) to be returned if it can't be represented exactly
806
   Exact result not possible above PHP_MAX_INT which is about 2^31 addresses on x32 or 2^63 on x64
807 4402b5cb stilez
   Returns 0 for bad data or if cannot represent size as an INT when $exact is set. */
808
function subnet_size($subnet, $exact=false) {
809
	$parts = explode("/", $subnet);
810 0987677a stilez
	$iptype = is_ipaddr($parts[0]);
811
	if (count($parts) == 2 && $iptype) {
812
		return subnet_size_by_netmask($iptype, $parts[1], $exact);
813 4402b5cb stilez
	}
814
	return 0;
815
}
816
817 cafe9038 stilez
/* Get number of addresses in an IPv4/IPv6 subnet (represented numerically as IP type + bits)
818
   optional $exact=true forces error (0) to be returned if it can't be represented exactly
819
   Hard to think where we might need to count exactly a huge subnet but an overflow detection option is probably sensible
820
   Returns 0 for bad data or if cannot represent size as an INT when $exact is set. */
821 4402b5cb stilez
function subnet_size_by_netmask($iptype, $bits, $exact=false) {
822
	if (!is_numericint($bits)) {
823
		return 0;
824
	} elseif ($iptype == 4 && $bits <= 32) {
825
		$snsize = 32 - $bits;
826
	} elseif ($iptype == 6 && $bits <= 128) {
827
		$snsize = 128 - $bits;
828 19b802f4 Phil Davis
	} else {
829 b17ac4f7 stilez
		return 0;
830
	}
831 4402b5cb stilez
832 4f7956ad Steve Beaver
	// 2**N returns an exact result as an INT if possible, and a float/double if not.
833 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
834
	$result = 2 ** $snsize;
835 4f7956ad Steve Beaver
836 4402b5cb stilez
	if ($exact && !is_int($result)) {
837
		//exact required but can't represent result exactly as an INT
838
		return 0;
839
	} else {
840
		// result ok, will be an INT where possible (guaranteed up to 2^31 addresses on x32/x64) and a float for 'huge' subnets
841
		return $result;
842
	}
843 b17ac4f7 stilez
}
844
845 2208be8b Chris Buechler
/* function used by pfblockerng */
846
function subnetv4_expand($subnet) {
847
	$result = array();
848
	list ($ip, $bits) = explode("/", $subnet);
849
	$net = ip2long($ip);
850
	$mask = (0xffffffff << (32 - $bits));
851
	$net &= $mask;
852
	$size = round(exp(log(2) * (32 - $bits)));
853
	for ($i = 0; $i < $size; $i += 1) {
854
		$result[] = long2ip($net | $i);
855
	}
856
	return $result;
857
}
858
859 e8d5be8e stilez
/* find out whether two IPv4/IPv6 CIDR subnets overlap.
860
   Note: CIDR overlap implies one is identical or included so largest sn will be the same */
861 b17ac4f7 stilez
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
862 94eb702f stilez
	if (is_ipaddrv4($subnet1)) {
863 e8d5be8e stilez
		return check_subnetsv4_overlap($subnet1, $bits1, $subnet2, $bits2);
864 751533a2 Phil Davis
	} else {
865 e8d5be8e stilez
		return check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2);
866 751533a2 Phil Davis
	}
867 b17ac4f7 stilez
}
868
869 e8d5be8e stilez
/* find out whether two IPv4 CIDR subnets overlap.
870
   Note: CIDR overlap means sn1/sn2 are identical or one is included in other. So sn using largest $bits will be the same  */
871
function check_subnetsv4_overlap($subnet1, $bits1, $subnet2, $bits2) {
872 62512efa stilez
	$largest_sn = min($bits1, $bits2);
873 e8d5be8e stilez
	$subnetv4_start1 = gen_subnetv4($subnet1, $largest_sn);
874 9f4a788f stilez
	$subnetv4_start2 = gen_subnetv4($subnet2, $largest_sn);
875 4f7956ad Steve Beaver
876 9d3e8723 Phil Davis
	if ($subnetv4_start1 == '' || $subnetv4_start2 == '') {
877 e8d5be8e stilez
		// One or both args is not a valid IPv4 subnet
878
		//FIXME: needs to return "bad data" not true/false if bad. For now return false, best we can do until fixed
879
		return false;
880
	}
881
	return ($subnetv4_start1 == $subnetv4_start2);
882
}
883 b17ac4f7 stilez
884 e8d5be8e stilez
/* find out whether two IPv6 CIDR subnets overlap.
885
   Note: CIDR overlap means sn1/sn2 are identical or one is included in other. So sn using largest $bits will be the same  */
886 9f8266cd stilez
function check_subnetsv6_overlap($subnet1, $bits1, $subnet2, $bits2) {
887 62512efa stilez
	$largest_sn = min($bits1, $bits2);
888 9f8266cd stilez
	$subnetv6_start1 = gen_subnetv6($subnet1, $largest_sn);
889 9f4a788f stilez
	$subnetv6_start2 = gen_subnetv6($subnet2, $largest_sn);
890 4f7956ad Steve Beaver
891 9d3e8723 Phil Davis
	if ($subnetv6_start1 == '' || $subnetv6_start2 == '') {
892 e8d5be8e stilez
		// One or both args is not a valid IPv6 subnet
893
		//FIXME: needs to return "bad data" not true/false if bad. For now return false, best we can do until fixed
894
		return false;
895
	}
896
	return ($subnetv6_start1 == $subnetv6_start2);
897 b17ac4f7 stilez
}
898 4c62c1ff Renato Botelho
899
/* return all PTR zones for a IPv6 network */
900
function get_v6_ptr_zones($subnet, $bits) {
901
	$result = array();
902
903
	if (!is_ipaddrv6($subnet)) {
904
		return $result;
905
	}
906
907
	if (!is_numericint($bits) || $bits > 128) {
908
		return $result;
909
	}
910
911
	/*
912
	 * Find a small nibble boundary subnet mask
913
	 * e.g. a /29 will create 8 /32 PTR zones
914
	 */
915
	$small_sn = $bits;
916
	while ($small_sn % 4 != 0) {
917
		$small_sn++;
918
	}
919
920
	/* Get network prefix */
921
	$small_subnet = Net_IPv6::getNetmask($subnet, $bits);
922
923
	/*
924
	 * While small network is part of bigger one, increase 4-bit in last
925
	 * digit to get next small network
926
	 */
927
	while (Net_IPv6::isInNetmask($small_subnet, $subnet, $bits)) {
928
		/* Get a pure hex value */
929
		$unpacked = unpack('H*hex', inet_pton($small_subnet));
930
		/* Create PTR record using $small_sn / 4 chars */
931
		$result[] = implode('.', array_reverse(str_split(substr(
932
		    $unpacked['hex'], 0, $small_sn / 4)))).'.ip6.arpa';
933
934
		/* Detect what part of IP should be increased */
935
		$change_part = (int) ($small_sn / 16);
936
		if ($small_sn % 16 == 0) {
937
			$change_part--;
938
		}
939
940 53904d09 Renato Botelho
		/* Increase 1 to desired part */
941 4c62c1ff Renato Botelho
		$parts = explode(":", Net_IPv6::uncompress($small_subnet));
942 53904d09 Renato Botelho
		$parts[$change_part]++;
943 4c62c1ff Renato Botelho
		$small_subnet = implode(":", $parts);
944
	}
945
946
	return $result;
947
}
948 b17ac4f7 stilez
949
/* return true if $addr is in $subnet, false if not */
950 086cf944 Phil Davis
function ip_in_subnet($addr, $subnet) {
951 751533a2 Phil Davis
	if (is_ipaddrv6($addr) && is_subnetv6($subnet)) {
952 b17ac4f7 stilez
		return (Net_IPv6::isInNetmask($addr, $subnet));
953 0c5dd854 Renato Botelho
	} else if (is_ipaddrv4($addr) && is_subnetv4($subnet)) {
954 b17ac4f7 stilez
		list($ip, $mask) = explode('/', $subnet);
955
		$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
956
		return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
957
	}
958 0c5dd854 Renato Botelho
	return false;
959 b17ac4f7 stilez
}
960
961 6bcbd862 Phil Davis
/* returns true if $hostname is just a valid hostname (top part without any of the domain part) */
962
function is_unqualified_hostname($hostname) {
963 751533a2 Phil Davis
	if (!is_string($hostname)) {
964 6bcbd862 Phil Davis
		return false;
965 751533a2 Phil Davis
	}
966 6bcbd862 Phil Davis
967 8fdddd51 Chris Buechler
	if (preg_match('/^(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])$/i', $hostname)) {
968 6bcbd862 Phil Davis
		return true;
969 751533a2 Phil Davis
	} else {
970 6bcbd862 Phil Davis
		return false;
971 751533a2 Phil Davis
	}
972 6bcbd862 Phil Davis
}
973
974
/* returns true if $hostname is a valid hostname, with or without being a fully-qualified domain name. */
975 0edcccc3 Daniel Seebald
function is_hostname($hostname, $allow_wildcard=false) {
976 751533a2 Phil Davis
	if (!is_string($hostname)) {
977 5b237745 Scott Ullrich
		return false;
978 751533a2 Phil Davis
	}
979 98bbf05a Scott Ullrich
980 cc882a8b Daniel Seebald
	if (is_domain($hostname, $allow_wildcard)) {
981 5454fd1b Phil Davis
		if ((substr_count($hostname, ".") == 1) && ($hostname[strlen($hostname)-1] == ".")) {
982
			/* Only a single dot at the end like "test." - hosts cannot be directly in the root domain. */
983
			return false;
984
		} else {
985
			return true;
986
		}
987 751533a2 Phil Davis
	} else {
988 5b237745 Scott Ullrich
		return false;
989 751533a2 Phil Davis
	}
990 5b237745 Scott Ullrich
}
991
992
/* returns true if $domain is a valid domain name */
993 0edcccc3 Daniel Seebald
function is_domain($domain, $allow_wildcard=false) {
994 751533a2 Phil Davis
	if (!is_string($domain)) {
995 5b237745 Scott Ullrich
		return false;
996 751533a2 Phil Davis
	}
997 0edcccc3 Daniel Seebald
	if ($allow_wildcard) {
998
		$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';
999
	} else {
1000
		$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';
1001
	}
1002
1003
	if (preg_match($domain_regex, $domain)) {
1004 5b237745 Scott Ullrich
		return true;
1005 751533a2 Phil Davis
	} else {
1006 5b237745 Scott Ullrich
		return false;
1007 751533a2 Phil Davis
	}
1008 5b237745 Scott Ullrich
}
1009
1010
/* returns true if $macaddr is a valid MAC address */
1011 80e7011f jim-p
function is_macaddr($macaddr, $partial=false) {
1012 c982fdbc Luiz Otavio O Souza
	$values = explode(":", $macaddr);
1013 80e7011f jim-p
1014
	/* Verify if the MAC address has a proper amount of parts for either a partial or full match. */
1015
	if ($partial) {
1016
		if ((count($values) < 1) || (count($values) > 6)) {
1017
			return false;
1018
		}
1019
	} elseif (count($values) != 6) {
1020 c982fdbc Luiz Otavio O Souza
		return false;
1021
	}
1022 80e7011f jim-p
	for ($i = 0; $i < count($values); $i++) {
1023 c982fdbc Luiz Otavio O Souza
		if (ctype_xdigit($values[$i]) == false)
1024
			return false;
1025
		if (hexdec($values[$i]) < 0 || hexdec($values[$i]) > 255)
1026
			return false;
1027
	}
1028
1029
	return true;
1030 5b237745 Scott Ullrich
}
1031
1032 e1f5381f Phil Davis
/*
1033
	If $return_message is true then
1034
		returns a text message about the reason that the name is invalid.
1035
		the text includes the type of "thing" that is being checked, passed in $object. (e.g. "alias", "gateway group", "schedule")
1036
	else
1037
		returns true if $name is a valid name for an alias
1038
		returns false if $name is not a valid name for an alias
1039
1040
	Aliases cannot be:
1041
		bad chars: anything except a-z 0-9 and underscore
1042
		bad names: empty string, pure numeric, pure underscore
1043
		reserved words: pre-defined service/protocol/port names which should not be ambiguous, and the words "port" and  "pass" */
1044
1045
function is_validaliasname($name, $return_message = false, $object = "alias") {
1046 beeef1f0 Bill Marquette
	/* Array of reserved words */
1047 0c2badde Colin Smith
	$reserved = array("port", "pass");
1048 4ad9a1e7 stilez
1049 751533a2 Phil Davis
	if (!is_string($name) || strlen($name) >= 32 || preg_match('/(^_*$|^\d*$|[^a-z0-9_])/i', $name)) {
1050 e1f5381f Phil Davis
		if ($return_message) {
1051
			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, _');
1052
		} else {
1053
			return false;
1054
		}
1055 751533a2 Phil Davis
	}
1056 e1f5381f Phil Davis
	if (in_array($name, $reserved, true)) {
1057
		if ($return_message) {
1058
			return sprintf(gettext('The %1$s name must not be either of the reserved words %2$s or %3$s.'), $object, "'port'", "'pass'");
1059
		} else {
1060
			return false;
1061
		}
1062 751533a2 Phil Davis
	}
1063 e1f5381f Phil Davis
	if (getprotobyname($name)) {
1064
		if ($return_message) {
1065 a2405c1a jim-p
			return sprintf(gettext('The %1$s name must not be an IP protocol name such as TCP, UDP, ICMP etc.'), $object);
1066 e1f5381f Phil Davis
		} else {
1067
			return false;
1068
		}
1069
	}
1070
	if (getservbyname($name, "tcp") || getservbyname($name, "udp")) {
1071
		if ($return_message) {
1072 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);
1073 e1f5381f Phil Davis
		} else {
1074
			return false;
1075
		}
1076
	}
1077
	if ($return_message) {
1078
		return sprintf(gettext("The %1$s name is valid."), $object);
1079
	} else {
1080
		return true;
1081
	}
1082
}
1083
1084
/* returns a text message indicating if the alias name is valid, or the reason it is not valid. */
1085
function invalidaliasnamemsg($name, $object = "alias") {
1086
	return is_validaliasname($name, true, $object);
1087 5b237745 Scott Ullrich
}
1088
1089 ee956d19 Renato Botelho
/*
1090
 * returns true if $range is a valid integer range between $min and $max
1091
 * range delimiter can be ':' or '-'
1092
 */
1093
function is_intrange($range, $min, $max) {
1094
	$values = preg_split("/[:-]/", $range);
1095
1096
	if (!is_array($values) || count($values) != 2) {
1097
		return false;
1098
	}
1099
1100
	if (!ctype_digit($values[0]) || !ctype_digit($values[1])) {
1101
		return false;
1102
	}
1103
1104
	$values[0] = intval($values[0]);
1105
	$values[1] = intval($values[1]);
1106
1107
	if ($values[0] >= $values[1]) {
1108
		return false;
1109
	}
1110
1111
	if ($values[0] < $min || $values[1] > $max) {
1112
		return false;
1113
	}
1114
1115
	return true;
1116
}
1117
1118 5b237745 Scott Ullrich
/* returns true if $port is a valid TCP/UDP port */
1119
function is_port($port) {
1120 751533a2 Phil Davis
	if (ctype_digit($port) && ((intval($port) >= 1) && (intval($port) <= 65535))) {
1121 75106235 PiBa-NL
		return true;
1122 751533a2 Phil Davis
	}
1123
	if (getservbyname($port, "tcp") || getservbyname($port, "udp")) {
1124 9060f420 Renato Botelho
		return true;
1125 751533a2 Phil Davis
	}
1126 75106235 PiBa-NL
	return false;
1127 5b237745 Scott Ullrich
}
1128
1129 5a1eebc7 Scott Ullrich
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
1130
function is_portrange($portrange) {
1131 5bbd08e1 Warren Baker
	$ports = explode(":", $portrange);
1132 5a1eebc7 Scott Ullrich
1133 e371f8b9 whjvenyl
	return (count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]));
1134 5a1eebc7 Scott Ullrich
}
1135
1136 4081ecac Phil Davis
/* returns true if $port is a valid TCP/UDP port number or range ("<port>:<port>") */
1137 593e9fe3 Phil Davis
function is_port_or_range($port) {
1138 4081ecac Phil Davis
	return (is_port($port) || is_portrange($port));
1139
}
1140
1141 fe108b67 Phil Davis
/* returns true if $port is an alias that is a port type */
1142
function is_portalias($port) {
1143 1e578a7f Ermal Lu?i
	global $config;
1144
1145 5bbd08e1 Warren Baker
	if (is_alias($port)) {
1146
		if (is_array($config['aliases']['alias'])) {
1147
			foreach ($config['aliases']['alias'] as $alias) {
1148 751533a2 Phil Davis
				if ($alias['name'] == $port && preg_match("/port/i", $alias['type'])) {
1149 5bbd08e1 Warren Baker
					return true;
1150
				}
1151
			}
1152 751533a2 Phil Davis
		}
1153
	}
1154 fe108b67 Phil Davis
	return false;
1155
}
1156
1157
/* returns true if $port is a valid port number or an alias thereof */
1158
function is_port_or_alias($port) {
1159
	return (is_port($port) || is_portalias($port));
1160 1e578a7f Ermal Lu?i
}
1161
1162 4081ecac Phil Davis
/* returns true if $port is a valid TCP/UDP port number or range ("<port>:<port>") or an alias thereof */
1163 593e9fe3 Phil Davis
function is_port_or_range_or_alias($port) {
1164 fe108b67 Phil Davis
	return (is_port($port) || is_portrange($port) || is_portalias($port));
1165 4081ecac Phil Davis
}
1166
1167 d9f33a7f Renato Botelho
/* create ranges of sequential port numbers (200:215) and remove duplicates */
1168 f6622167 NOYB
function group_ports($ports, $kflc = false) {
1169 751533a2 Phil Davis
	if (!is_array($ports) || empty($ports)) {
1170 d9f33a7f Renato Botelho
		return;
1171 751533a2 Phil Davis
	}
1172 d9f33a7f Renato Botelho
1173
	$uniq = array();
1174 f6622167 NOYB
	$comments = array();
1175 d9f33a7f Renato Botelho
	foreach ($ports as $port) {
1176 f6622167 NOYB
		if (($kflc) && (strpos($port, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
1177
			$comments[] = $port;
1178
		} else if (is_portrange($port)) {
1179 d9f33a7f Renato Botelho
			list($begin, $end) = explode(":", $port);
1180
			if ($begin > $end) {
1181
				$aux = $begin;
1182
				$begin = $end;
1183
				$end = $aux;
1184
			}
1185 751533a2 Phil Davis
			for ($i = $begin; $i <= $end; $i++) {
1186
				if (!in_array($i, $uniq)) {
1187 d9f33a7f Renato Botelho
					$uniq[] = $i;
1188 751533a2 Phil Davis
				}
1189
			}
1190 d9f33a7f Renato Botelho
		} else if (is_port($port)) {
1191 751533a2 Phil Davis
			if (!in_array($port, $uniq)) {
1192 d9f33a7f Renato Botelho
				$uniq[] = $port;
1193 751533a2 Phil Davis
			}
1194 d9f33a7f Renato Botelho
		}
1195
	}
1196
	sort($uniq, SORT_NUMERIC);
1197
1198
	$result = array();
1199
	foreach ($uniq as $idx => $port) {
1200
		if ($idx == 0) {
1201
			$result[] = $port;
1202
			continue;
1203
		}
1204
1205
		$last = end($result);
1206 751533a2 Phil Davis
		if (is_portrange($last)) {
1207 d9f33a7f Renato Botelho
			list($begin, $end) = explode(":", $last);
1208 751533a2 Phil Davis
		} else {
1209 d9f33a7f Renato Botelho
			$begin = $end = $last;
1210 751533a2 Phil Davis
		}
1211 d9f33a7f Renato Botelho
1212
		if ($port == ($end+1)) {
1213
			$end++;
1214
			$result[count($result)-1] = "{$begin}:{$end}";
1215
		} else {
1216
			$result[] = $port;
1217
		}
1218
	}
1219
1220 f6622167 NOYB
	return array_merge($comments, $result);
1221 d9f33a7f Renato Botelho
}
1222
1223 b8014f9d Scott Ullrich
/* returns true if $val is a valid shaper bandwidth value */
1224
function is_valid_shaperbw($val) {
1225 eaa37259 Ermal Luçi
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
1226 b8014f9d Scott Ullrich
}
1227
1228 54404519 Renato Botelho
/* returns true if $test is in the range between $start and $end */
1229
function is_inrange_v4($test, $start, $end) {
1230 8c48089f Renato Botelho
	if (!is_ipaddrv4($test) || !is_ipaddrv4($start) || !is_ipaddrv4($end)) {
1231 54404519 Renato Botelho
		return false;
1232 751533a2 Phil Davis
	}
1233 8c48089f Renato Botelho
1234
	if (ip2ulong($test) <= ip2ulong($end) &&
1235
	    ip2ulong($test) >= ip2ulong($start)) {
1236
		return true;
1237
	}
1238
1239
	return false;
1240 54404519 Renato Botelho
}
1241
1242 41b4867e Renato Botelho
/* returns true if $test is in the range between $start and $end */
1243
function is_inrange_v6($test, $start, $end) {
1244 8c48089f Renato Botelho
	if (!is_ipaddrv6($test) || !is_ipaddrv6($start) || !is_ipaddrv6($end)) {
1245 41b4867e Renato Botelho
		return false;
1246 751533a2 Phil Davis
	}
1247 8c48089f Renato Botelho
1248
	if (inet_pton($test) <= inet_pton($end) &&
1249
	    inet_pton($test) >= inet_pton($start)) {
1250
		return true;
1251
	}
1252
1253
	return false;
1254 41b4867e Renato Botelho
}
1255
1256 da6cb29e Renato Botelho
/* returns true if $test is in the range between $start and $end */
1257
function is_inrange($test, $start, $end) {
1258
	return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
1259
}
1260
1261 ce94deb0 Luiz Otavio O Souza
function get_configured_vip_list($family = 'all', $type = VIP_ALL) {
1262 abcb2bed Ermal Lu?i
	global $config;
1263
1264 2a5960b0 Luiz Otavio O Souza
	$list = array();
1265 d9901ff4 Chris Buechler
	if (!is_array($config['virtualip']['vip']) || empty($config['virtualip']['vip'])) {
1266 2a5960b0 Luiz Otavio O Souza
		return ($list);
1267 d9901ff4 Chris Buechler
	}
1268 76153238 Luiz Otavio O Souza
1269
	$viparr = &$config['virtualip']['vip'];
1270
	foreach ($viparr as $vip) {
1271 ce94deb0 Luiz Otavio O Souza
1272
		if ($type == VIP_CARP) {
1273
			if ($vip['mode'] != "carp")
1274
				continue;
1275
		} elseif ($type == VIP_IPALIAS) {
1276
			if ($vip['mode'] != "ipalias")
1277
				continue;
1278
		} else {
1279
			if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
1280
				continue;
1281 d9901ff4 Chris Buechler
		}
1282 2a5960b0 Luiz Otavio O Souza
1283
		if ($family == 'all' ||
1284
		    ($family == 'inet' && is_ipaddrv4($vip['subnet'])) ||
1285
		    ($family == 'inet6' && is_ipaddrv6($vip['subnet']))) {
1286
			$list["_vip{$vip['uniqid']}"] = $vip['subnet'];
1287 4e322e2c Phil Davis
		}
1288 2a5960b0 Luiz Otavio O Souza
	}
1289
	return ($list);
1290
}
1291
1292
function get_configured_vip($vipinterface = '') {
1293
1294
	return (get_configured_vip_detail($vipinterface, 'all', 'vip'));
1295
}
1296
1297
function get_configured_vip_interface($vipinterface = '') {
1298
1299
	return (get_configured_vip_detail($vipinterface, 'all', 'iface'));
1300
}
1301
1302
function get_configured_vip_ipv4($vipinterface = '') {
1303
1304
	return (get_configured_vip_detail($vipinterface, 'inet', 'ip'));
1305
}
1306 76153238 Luiz Otavio O Souza
1307 2a5960b0 Luiz Otavio O Souza
function get_configured_vip_ipv6($vipinterface = '') {
1308
1309
	return (get_configured_vip_detail($vipinterface, 'inet6', 'ip'));
1310
}
1311
1312
function get_configured_vip_subnetv4($vipinterface = '') {
1313
1314
	return (get_configured_vip_detail($vipinterface, 'inet', 'subnet'));
1315
}
1316
1317
function get_configured_vip_subnetv6($vipinterface = '') {
1318
1319
	return (get_configured_vip_detail($vipinterface, 'inet6', 'subnet'));
1320
}
1321
1322
function get_configured_vip_detail($vipinterface = '', $family = 'inet', $what = 'ip') {
1323
	global $config;
1324
1325
	if (empty($vipinterface) || !is_array($config['virtualip']['vip']) ||
1326
	    empty($config['virtualip']['vip'])) {
1327
		return (NULL);
1328
	}
1329
1330
	$viparr = &$config['virtualip']['vip'];
1331
	foreach ($viparr as $vip) {
1332 d9901ff4 Chris Buechler
		if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias") {
1333 76153238 Luiz Otavio O Souza
			continue;
1334 d9901ff4 Chris Buechler
		}
1335 76153238 Luiz Otavio O Souza
1336 d9901ff4 Chris Buechler
		if ($vipinterface != "_vip{$vip['uniqid']}") {
1337 76153238 Luiz Otavio O Souza
			continue;
1338 d9901ff4 Chris Buechler
		}
1339 76153238 Luiz Otavio O Souza
1340
		switch ($what) {
1341
			case 'subnet':
1342 2a5960b0 Luiz Otavio O Souza
				if ($family == 'inet' && is_ipaddrv4($vip['subnet']))
1343
					return ($vip['subnet_bits']);
1344
				else if ($family == 'inet6' && is_ipaddrv6($vip['subnet']))
1345
					return ($vip['subnet_bits']);
1346 76153238 Luiz Otavio O Souza
				break;
1347
			case 'iface':
1348 2a5960b0 Luiz Otavio O Souza
				return ($vip['interface']);
1349 76153238 Luiz Otavio O Souza
				break;
1350
			case 'vip':
1351 2a5960b0 Luiz Otavio O Souza
				return ($vip);
1352 76153238 Luiz Otavio O Souza
				break;
1353
			case 'ip':
1354
			default:
1355 d9901ff4 Chris Buechler
				if ($family == 'inet' && is_ipaddrv4($vip['subnet'])) {
1356 2a5960b0 Luiz Otavio O Souza
					return ($vip['subnet']);
1357 d9901ff4 Chris Buechler
				} else if ($family == 'inet6' && is_ipaddrv6($vip['subnet'])) {
1358 2a5960b0 Luiz Otavio O Souza
					return ($vip['subnet']);
1359 d9901ff4 Chris Buechler
				}
1360 76153238 Luiz Otavio O Souza
				break;
1361 5bbd08e1 Warren Baker
		}
1362 76153238 Luiz Otavio O Souza
		break;
1363 5bbd08e1 Warren Baker
	}
1364 abcb2bed Ermal Lu?i
1365 e0e28fdf Luiz Otavio O Souza
	return (NULL);
1366 e6c60013 Renato Botelho
}
1367 67b0902f pierrepomes
1368 88bc2760 Erik Fonnesbeck
/* comparison function for sorting by the order in which interfaces are normally created */
1369
function compare_interface_friendly_names($a, $b) {
1370 751533a2 Phil Davis
	if ($a == $b) {
1371 88bc2760 Erik Fonnesbeck
		return 0;
1372 751533a2 Phil Davis
	} else if ($a == 'wan') {
1373 88bc2760 Erik Fonnesbeck
		return -1;
1374 751533a2 Phil Davis
	} else if ($b == 'wan') {
1375 88bc2760 Erik Fonnesbeck
		return 1;
1376 751533a2 Phil Davis
	} else if ($a == 'lan') {
1377 88bc2760 Erik Fonnesbeck
		return -1;
1378 751533a2 Phil Davis
	} else if ($b == 'lan') {
1379 88bc2760 Erik Fonnesbeck
		return 1;
1380 751533a2 Phil Davis
	}
1381 88bc2760 Erik Fonnesbeck
1382
	return strnatcmp($a, $b);
1383
}
1384
1385 c8abe1d4 Ermal Luçi
/* return the configured interfaces list. */
1386 80fe8369 Phil Davis
function get_configured_interface_list($withdisabled = false) {
1387 c8abe1d4 Ermal Luçi
	global $config;
1388
1389
	$iflist = array();
1390 14f49fd0 Erik Fonnesbeck
1391 c8abe1d4 Ermal Luçi
	/* if list */
1392 751533a2 Phil Davis
	foreach ($config['interfaces'] as $if => $ifdetail) {
1393
		if (isset($ifdetail['enable']) || $withdisabled == true) {
1394 c8abe1d4 Ermal Luçi
			$iflist[$if] = $if;
1395 751533a2 Phil Davis
		}
1396 42c9d20e Ermal Luçi
	}
1397 c8abe1d4 Ermal Luçi
1398
	return $iflist;
1399
}
1400
1401 bb34737f Ermal Lu?i
/* return the configured interfaces list. */
1402 f625f76c Phil Davis
function get_configured_interface_list_by_realif($withdisabled = false) {
1403 8735afe8 Erik Fonnesbeck
	global $config;
1404 bb34737f Ermal Lu?i
1405 8735afe8 Erik Fonnesbeck
	$iflist = array();
1406 bb34737f Ermal Lu?i
1407 8735afe8 Erik Fonnesbeck
	/* if list */
1408 751533a2 Phil Davis
	foreach ($config['interfaces'] as $if => $ifdetail) {
1409 8735afe8 Erik Fonnesbeck
		if (isset($ifdetail['enable']) || $withdisabled == true) {
1410 bb34737f Ermal Lu?i
			$tmpif = get_real_interface($if);
1411 751533a2 Phil Davis
			if (!empty($tmpif)) {
1412 bb34737f Ermal Lu?i
				$iflist[$tmpif] = $if;
1413 751533a2 Phil Davis
			}
1414 bb34737f Ermal Lu?i
		}
1415 8735afe8 Erik Fonnesbeck
	}
1416 bb34737f Ermal Lu?i
1417 8735afe8 Erik Fonnesbeck
	return $iflist;
1418 bb34737f Ermal Lu?i
}
1419
1420 c8abe1d4 Ermal Luçi
/* return the configured interfaces list with their description. */
1421 f593f80b Phil Davis
function get_configured_interface_with_descr($withdisabled = false) {
1422 1d3510cf Phil Davis
	global $config, $user_settings;
1423 c8abe1d4 Ermal Luçi
1424 a42d1da2 Scott Ullrich
	$iflist = array();
1425 c8abe1d4 Ermal Luçi
1426 a42d1da2 Scott Ullrich
	/* if list */
1427 751533a2 Phil Davis
	foreach ($config['interfaces'] as $if => $ifdetail) {
1428 47c8b036 Ermal Lu?i
		if (isset($ifdetail['enable']) || $withdisabled == true) {
1429 751533a2 Phil Davis
			if (empty($ifdetail['descr'])) {
1430 8e74cb8d Ermal Luçi
				$iflist[$if] = strtoupper($if);
1431 751533a2 Phil Davis
			} else {
1432 44b0ec83 Scott Ullrich
				$iflist[$if] = strtoupper($ifdetail['descr']);
1433 751533a2 Phil Davis
			}
1434 0e218dc1 Ermal Luçi
		}
1435 42c9d20e Ermal Luçi
	}
1436 1d3510cf Phil Davis
1437
	if ($user_settings['webgui']['interfacessort']) {
1438
		asort($iflist);
1439
	}
1440
1441 a42d1da2 Scott Ullrich
	return $iflist;
1442 c8abe1d4 Ermal Luçi
}
1443
1444 4fe9c2dc Scott Ullrich
/*
1445
 *   get_configured_ip_addresses() - Return a list of all configured
1446 2a5960b0 Luiz Otavio O Souza
 *   IPv4 addresses.
1447 4fe9c2dc Scott Ullrich
 *
1448
 */
1449
function get_configured_ip_addresses() {
1450 5dbd619f smos
	global $config;
1451 a1e4e2a7 Ermal
1452 751533a2 Phil Davis
	if (!function_exists('get_interface_ip')) {
1453 a1e4e2a7 Ermal
		require_once("interfaces.inc");
1454 751533a2 Phil Davis
	}
1455 4fe9c2dc Scott Ullrich
	$ip_array = array();
1456
	$interfaces = get_configured_interface_list();
1457 a1e4e2a7 Ermal
	if (is_array($interfaces)) {
1458 751533a2 Phil Davis
		foreach ($interfaces as $int) {
1459 d9114ce0 Scott Ullrich
			$ipaddr = get_interface_ip($int);
1460
			$ip_array[$int] = $ipaddr;
1461
		}
1462 4fe9c2dc Scott Ullrich
	}
1463 2a5960b0 Luiz Otavio O Souza
	$interfaces = get_configured_vip_list('inet');
1464 751533a2 Phil Davis
	if (is_array($interfaces)) {
1465
		foreach ($interfaces as $int => $ipaddr) {
1466 d9114ce0 Scott Ullrich
			$ip_array[$int] = $ipaddr;
1467 751533a2 Phil Davis
		}
1468
	}
1469 5dbd619f smos
1470
	/* pppoe server */
1471 a1e4e2a7 Ermal
	if (is_array($config['pppoes']) && is_array($config['pppoes']['pppoe'])) {
1472 751533a2 Phil Davis
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
1473 5dbd619f smos
			if ($pppoe['mode'] == "server") {
1474 751533a2 Phil Davis
				if (is_ipaddr($pppoe['localip'])) {
1475 5dbd619f smos
					$int = "pppoes". $pppoe['pppoeid'];
1476
					$ip_array[$int] = $pppoe['localip'];
1477
				}
1478
			}
1479
		}
1480
	}
1481 a1e4e2a7 Ermal
1482 4fe9c2dc Scott Ullrich
	return $ip_array;
1483
}
1484 c8abe1d4 Ermal Luçi
1485 e6f7e0be smos
/*
1486
 *   get_configured_ipv6_addresses() - Return a list of all configured
1487 2a5960b0 Luiz Otavio O Souza
 *   IPv6 addresses.
1488 e6f7e0be smos
 *
1489
 */
1490 6a53de6f NewEraCracker
function get_configured_ipv6_addresses($linklocal_fallback = false) {
1491 e6f7e0be smos
	require_once("interfaces.inc");
1492
	$ipv6_array = array();
1493
	$interfaces = get_configured_interface_list();
1494 751533a2 Phil Davis
	if (is_array($interfaces)) {
1495
		foreach ($interfaces as $int) {
1496 cde28bfa Phil Davis
			$ipaddrv6 = text_to_compressed_ip6(get_interface_ipv6($int, false, $linklocal_fallback));
1497 e6f7e0be smos
			$ipv6_array[$int] = $ipaddrv6;
1498
		}
1499
	}
1500 2a5960b0 Luiz Otavio O Souza
	$interfaces = get_configured_vip_list('inet6');
1501 751533a2 Phil Davis
	if (is_array($interfaces)) {
1502
		foreach ($interfaces as $int => $ipaddrv6) {
1503 cde28bfa Phil Davis
			$ipv6_array[$int] = text_to_compressed_ip6($ipaddrv6);
1504 751533a2 Phil Davis
		}
1505
	}
1506 e6f7e0be smos
	return $ipv6_array;
1507
}
1508
1509 36f546e9 Scott Ullrich
/*
1510
 *   get_interface_list() - Return a list of all physical interfaces
1511
 *   along with MAC and status.
1512
 *
1513
 *   $mode = "active" - use ifconfig -lu
1514
 *           "media"  - use ifconfig to check physical connection
1515
 *			status (much slower)
1516
 */
1517
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
1518 86a5e1a8 Renato Botelho
	global $config;
1519 65bed2d2 Scott Ullrich
	$upints = array();
1520 86a5e1a8 Renato Botelho
	/* get a list of virtual interface types */
1521 751533a2 Phil Davis
	if (!$vfaces) {
1522 086cf944 Phil Davis
		$vfaces = array(
1523 9ce38409 Scott Ullrich
				'bridge',
1524
				'ppp',
1525 27c0c7c6 Ermal Lu?i
				'pppoe',
1526
				'pptp',
1527
				'l2tp',
1528 9ce38409 Scott Ullrich
				'sl',
1529
				'gif',
1530 613571ea Ermal Luçi
				'gre',
1531 9ce38409 Scott Ullrich
				'faith',
1532
				'lo',
1533
				'ng',
1534 27616d6e Seth Mos
				'_vlan',
1535 7c53bc7b Erik Fonnesbeck
				'_wlan',
1536 9ce38409 Scott Ullrich
				'pflog',
1537 a42d1da2 Scott Ullrich
				'plip',
1538 9ce38409 Scott Ullrich
				'pfsync',
1539
				'enc',
1540
				'tun',
1541 1fb2bf25 Ermal Lu?i
				'lagg',
1542 1fd35e95 Ermal
				'vip',
1543
				'ipfw'
1544 9ce38409 Scott Ullrich
		);
1545 36f546e9 Scott Ullrich
	}
1546 751533a2 Phil Davis
	switch ($mode) {
1547
		case "active":
1548
			$upints = pfSense_interface_listget(IFF_UP);
1549
			break;
1550
		case "media":
1551
			$intlist = pfSense_interface_listget();
1552
			$ifconfig = "";
1553
			exec("/sbin/ifconfig -a", $ifconfig);
1554
			$regexp = '/(' . implode('|', $intlist) . '):\s/';
1555
			$ifstatus = preg_grep('/status:/', $ifconfig);
1556
			foreach ($ifstatus as $status) {
1557
				$int = array_shift($intlist);
1558
				if (stristr($status, "active")) {
1559
					$upints[] = $int;
1560
				}
1561
			}
1562
			break;
1563
		default:
1564
			$upints = pfSense_interface_listget();
1565
			break;
1566 20203646 Colin Smith
	}
1567 86a5e1a8 Renato Botelho
	/* build interface list with netstat */
1568
	$linkinfo = "";
1569
	exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
1570
	array_shift($linkinfo);
1571 89d1f0f2 Scott Ullrich
	/* build ip address list with netstat */
1572 767a716e Scott Ullrich
	$ipinfo = "";
1573 89d1f0f2 Scott Ullrich
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
1574
	array_shift($ipinfo);
1575 751533a2 Phil Davis
	foreach ($linkinfo as $link) {
1576 89d1f0f2 Scott Ullrich
		$friendly = "";
1577 5bbd08e1 Warren Baker
		$alink = explode(" ", $link);
1578
		$ifname = rtrim(trim($alink[0]), '*');
1579
		/* trim out all numbers before checking for vfaces */
1580 494be6e8 Ermal Lu?i
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
1581 c4865164 Renato Botelho
		    interface_is_vlan($ifname) == NULL &&
1582
		    interface_is_qinq($ifname) == NULL &&
1583 e48ae6f2 Luiz Souza
		    !stristr($ifname, "_wlan")) {
1584 20203646 Colin Smith
			$toput = array(
1585
					"mac" => trim($alink[1]),
1586
					"up" => in_array($ifname, $upints)
1587
				);
1588 751533a2 Phil Davis
			foreach ($ipinfo as $ip) {
1589 89d1f0f2 Scott Ullrich
				$aip = explode(" ", $ip);
1590 751533a2 Phil Davis
				if ($aip[0] == $ifname) {
1591 89d1f0f2 Scott Ullrich
					$toput['ipaddr'] = $aip[1];
1592
				}
1593
			}
1594 72993196 Ermal
			if (is_array($config['interfaces'])) {
1595 751533a2 Phil Davis
				foreach ($config['interfaces'] as $name => $int) {
1596
					if ($int['if'] == $ifname) {
1597
						$friendly = $name;
1598
					}
1599
				}
1600 20203646 Colin Smith
			}
1601 751533a2 Phil Davis
			switch ($keyby) {
1602 20203646 Colin Smith
			case "physical":
1603 751533a2 Phil Davis
				if ($friendly != "") {
1604 89d1f0f2 Scott Ullrich
					$toput['friendly'] = $friendly;
1605
				}
1606 a296c95d Seth Mos
				$dmesg_arr = array();
1607
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
1608
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
1609
				$toput['dmesg'] = $dmesg[1][0];
1610 20203646 Colin Smith
				$iflist[$ifname] = $toput;
1611 3154d7ed Colin Smith
				break;
1612 4aca19b3 Scott Ullrich
			case "ppp":
1613 86a5e1a8 Renato Botelho
1614 20203646 Colin Smith
			case "friendly":
1615 751533a2 Phil Davis
				if ($friendly != "") {
1616 89d1f0f2 Scott Ullrich
					$toput['if'] = $ifname;
1617
					$iflist[$friendly] = $toput;
1618
				}
1619 3154d7ed Colin Smith
				break;
1620
			}
1621 5bbd08e1 Warren Baker
		}
1622
	}
1623
	return $iflist;
1624 5b237745 Scott Ullrich
}
1625
1626 f2286620 Luiz Souza
function get_lagg_interface_list() {
1627
	global $config;
1628
1629
	$plist = array();
1630
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
1631
		foreach ($config['laggs']['lagg'] as $lagg) {
1632
			$lagg['mac'] = get_interface_mac($lagg['laggif']);
1633
			$lagg['islagg'] = true;
1634
			$plist[$lagg['laggif']] = $lagg;
1635
		}
1636
	}
1637
1638
	return ($plist);
1639
}
1640
1641 2b4d37de Ermal Lu?i
/****f* util/log_error
1642
* NAME
1643
*   log_error  - Sends a string to syslog.
1644
* INPUTS
1645
*   $error     - string containing the syslog message.
1646
* RESULT
1647
*   null
1648
******/
1649
function log_error($error) {
1650 5bbd08e1 Warren Baker
	global $g;
1651
	$page = $_SERVER['SCRIPT_NAME'];
1652 866b1d61 jim-p
	if (empty($page)) {
1653
		$files = get_included_files();
1654
		$page = basename($files[0]);
1655
	}
1656 0d0cb047 jim-p
	syslog(LOG_ERR, "$page: $error");
1657 751533a2 Phil Davis
	if ($g['debug']) {
1658 5bbd08e1 Warren Baker
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1659 751533a2 Phil Davis
	}
1660 5bbd08e1 Warren Baker
	return;
1661 2b4d37de Ermal Lu?i
}
1662
1663 3aba1835 Scott Ullrich
/****f* util/log_auth
1664
* NAME
1665 1198abf9 PiBa-NL
*   log_auth   - Sends a string to syslog as LOG_AUTH facility
1666 3aba1835 Scott Ullrich
* INPUTS
1667
*   $error     - string containing the syslog message.
1668
* RESULT
1669
*   null
1670
******/
1671
function log_auth($error) {
1672 5bbd08e1 Warren Baker
	global $g;
1673
	$page = $_SERVER['SCRIPT_NAME'];
1674
	syslog(LOG_AUTH, "$page: $error");
1675 751533a2 Phil Davis
	if ($g['debug']) {
1676 5bbd08e1 Warren Baker
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
1677 751533a2 Phil Davis
	}
1678 5bbd08e1 Warren Baker
	return;
1679 3aba1835 Scott Ullrich
}
1680
1681 83bc3749 Ermal Lu?i
/****f* util/exec_command
1682
 * NAME
1683
 *   exec_command - Execute a command and return a string of the result.
1684
 * INPUTS
1685
 *   $command   - String of the command to be executed.
1686
 * RESULT
1687
 *   String containing the command's result.
1688
 * NOTES
1689
 *   This function returns the command's stdout and stderr.
1690
 ******/
1691
function exec_command($command) {
1692 5bbd08e1 Warren Baker
	$output = array();
1693 873c1701 Renato Botelho
	exec($command . ' 2>&1', $output);
1694 5bbd08e1 Warren Baker
	return(implode("\n", $output));
1695 83bc3749 Ermal Lu?i
}
1696
1697 e00ad357 Renato Botelho
/* wrapper for exec()
1698 f0b41548 stilez
   Executes in background or foreground.
1699
   For background execution, returns PID of background process to allow calling code control */
1700
function mwexec($command, $nologentry = false, $clearsigmask = false, $background = false) {
1701 5b237745 Scott Ullrich
	global $g;
1702 f0b41548 stilez
	$retval = 0;
1703 435a418f Ermal
1704 5b237745 Scott Ullrich
	if ($g['debug']) {
1705 751533a2 Phil Davis
		if (!$_SERVER['REMOTE_ADDR']) {
1706 f0b41548 stilez
			echo "mwexec(): $command" . ($background ? " [BG]":"") . "\n";
1707 751533a2 Phil Davis
		}
1708 f9db3cda Seth Mos
	}
1709 b61e8960 jim-p
	if ($clearsigmask) {
1710
		$oldset = array();
1711
		pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
1712
	}
1713 f0b41548 stilez
1714 2b1f6ed2 stilez
	if ($background) {
1715
		// start background process and return PID
1716
		$retval = exec("/usr/bin/nohup $command > /dev/null 2>&1 & echo $!");
1717
	} else {
1718
		// run in foreground, and (optionally) log if nonzero return
1719
		$outputarray = array();
1720 f0b41548 stilez
		exec("$command 2>&1", $outputarray, $retval);
1721 4e322e2c Phil Davis
		if (($retval <> 0) && (!$nologentry || isset($config['system']['developerspew']))) {
1722 f812b883 stilez
			log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, implode(" ", $outputarray)));
1723 4e322e2c Phil Davis
		}
1724 f0b41548 stilez
	}
1725
1726 b61e8960 jim-p
	if ($clearsigmask) {
1727
		pcntl_sigprocmask(SIG_SETMASK, $oldset);
1728
	}
1729 435a418f Ermal
1730 98bbf05a Scott Ullrich
	return $retval;
1731 5b237745 Scott Ullrich
}
1732
1733
/* wrapper for exec() in background */
1734 b61e8960 jim-p
function mwexec_bg($command, $clearsigmask = false) {
1735 f0b41548 stilez
	return mwexec($command, false, $clearsigmask, true);
1736 5b237745 Scott Ullrich
}
1737
1738 d96a39ba Phil Davis
/*	unlink a file, or pattern-match of a file, if it exists
1739
	if the file/path contains glob() compatible wildcards, all matching files will be unlinked
1740
	any warning/errors are suppressed (e.g. no matching files to delete)
1741
	If there are matching file(s) and they were all unlinked OK, then return true.
1742
	Otherwise return false (the requested file(s) did not exist, or could not be deleted)
1743
	This allows the caller to know if they were the one to successfully delete the file(s).
1744
*/
1745 5b237745 Scott Ullrich
function unlink_if_exists($fn) {
1746 336cb718 Scott Ullrich
	$to_do = glob($fn);
1747 a85ad858 stilez
	if (is_array($to_do) && count($to_do) > 0) {
1748 d96a39ba Phil Davis
		// Returns an array of true/false indicating if each unlink worked
1749
		$results = @array_map("unlink", $to_do);
1750
		// If there is no false in the array, then all went well
1751
		$result = !in_array(false, $results, true);
1752 336cb718 Scott Ullrich
	} else {
1753 d96a39ba Phil Davis
		$result = @unlink($fn);
1754 336cb718 Scott Ullrich
	}
1755 d96a39ba Phil Davis
	return $result;
1756 5b237745 Scott Ullrich
}
1757
/* make a global alias table (for faster lookups) */
1758 918a884d Bill Marquette
function alias_make_table($config) {
1759
	global $aliastable;
1760 98bbf05a Scott Ullrich
1761 5b237745 Scott Ullrich
	$aliastable = array();
1762 98bbf05a Scott Ullrich
1763 5b237745 Scott Ullrich
	if (is_array($config['aliases']['alias'])) {
1764
		foreach ($config['aliases']['alias'] as $alias) {
1765 751533a2 Phil Davis
			if ($alias['name']) {
1766 5b237745 Scott Ullrich
				$aliastable[$alias['name']] = $alias['address'];
1767 751533a2 Phil Davis
			}
1768 5b237745 Scott Ullrich
		}
1769
	}
1770
}
1771 5ffa3389 Ermal
1772 5b237745 Scott Ullrich
/* check if an alias exists */
1773
function is_alias($name) {
1774
	global $aliastable;
1775 98bbf05a Scott Ullrich
1776 5b237745 Scott Ullrich
	return isset($aliastable[$name]);
1777 b8014f9d Scott Ullrich
}
1778 27ff8a3c Scott Ullrich
1779 5ffa3389 Ermal
function alias_get_type($name) {
1780 86a5e1a8 Renato Botelho
	global $config;
1781
1782 5ffa3389 Ermal
	if (is_array($config['aliases']['alias'])) {
1783
		foreach ($config['aliases']['alias'] as $alias) {
1784 751533a2 Phil Davis
			if ($name == $alias['name']) {
1785 5ffa3389 Ermal
				return $alias['type'];
1786 751533a2 Phil Davis
			}
1787 5ffa3389 Ermal
		}
1788
	}
1789
1790 86a5e1a8 Renato Botelho
	return "";
1791 5ffa3389 Ermal
}
1792
1793 5b237745 Scott Ullrich
/* expand a host or network alias, if necessary */
1794
function alias_expand($name) {
1795 2ec7ab35 Chris Buechler
	global $config, $aliastable;
1796
	$urltable_prefix = "/var/db/aliastables/";
1797
	$urltable_filename = $urltable_prefix . $name . ".txt";
1798 98bbf05a Scott Ullrich
1799 751533a2 Phil Davis
	if (isset($aliastable[$name])) {
1800 a97a77a2 Phil Davis
		// alias names cannot be strictly numeric. redmine #4289
1801
		if (is_numericint($name)) {
1802
			return null;
1803
		}
1804 2ec7ab35 Chris Buechler
		// make sure if it's a ports alias, it actually exists. redmine #5845
1805
		foreach ($config['aliases']['alias'] as $alias) {
1806
			if ($alias['name'] == $name) {
1807
				if ($alias['type'] == "urltable_ports") {
1808
					if (is_URL($alias['url']) && file_exists($urltable_filename) && filesize($urltable_filename)) {
1809
						return "\${$name}";
1810
					} else {
1811
						return null;
1812
					}
1813
				}
1814
			}
1815
		}
1816 4335dc87 Bill Marquette
		return "\${$name}";
1817 593e9fe3 Phil Davis
	} else if (is_ipaddr($name) || is_subnet($name) || is_port_or_range($name)) {
1818 57989da5 Scott Ullrich
		return "{$name}";
1819 751533a2 Phil Davis
	} else {
1820 5b237745 Scott Ullrich
		return null;
1821 751533a2 Phil Davis
	}
1822 5b237745 Scott Ullrich
}
1823
1824 c7de8be4 jim-p
function alias_expand_urltable($name) {
1825
	global $config;
1826
	$urltable_prefix = "/var/db/aliastables/";
1827
	$urltable_filename = $urltable_prefix . $name . ".txt";
1828
1829 5ffa3389 Ermal
	if (is_array($config['aliases']['alias'])) {
1830
		foreach ($config['aliases']['alias'] as $alias) {
1831 dd042c51 Renato Botelho
			if (preg_match("/urltable/i", $alias['type']) && ($alias['name'] == $name)) {
1832 e5581024 Chris Buechler
				if (is_URL($alias["url"]) && file_exists($urltable_filename)) {
1833
					if (!filesize($urltable_filename)) {
1834
						// file exists, but is empty, try to sync
1835
						send_event("service sync alias {$name}");
1836
					}
1837 5ffa3389 Ermal
					return $urltable_filename;
1838 5b2b1f4e Ermal LUÇI
				} else {
1839
					send_event("service sync alias {$name}");
1840
					break;
1841 751533a2 Phil Davis
				}
1842 5ffa3389 Ermal
			}
1843 c7de8be4 jim-p
		}
1844
	}
1845
	return null;
1846
}
1847
1848 dd83f869 lukehamburg
/* obtain MAC address given an IP address by looking at the ARP/NDP table */
1849 20cf8d8e lukehamburg
function arp_get_mac_by_ip($ip, $do_ping = true) {
1850 6c2f0930 lukehamburg
	unset($macaddr);
1851
	$retval = 1;
1852 dd83f869 lukehamburg
	switch (is_ipaddr($ip)) {
1853
		case 4:
1854 c516cb28 lukehamburg
			if ($do_ping === true) {
1855
				mwexec("/sbin/ping -c 1 -t 1 " . escapeshellarg($ip), true);
1856
			}
1857 6c2f0930 lukehamburg
			$macaddr = exec("/usr/sbin/arp -n " . escapeshellarg($ip) . " | /usr/bin/awk '{print $4}'", $output, $retval);
1858 dd83f869 lukehamburg
			break;
1859
		case 6:
1860 c516cb28 lukehamburg
			if ($do_ping === true) {
1861
				mwexec("/sbin/ping6 -c 1 -X 1 " . escapeshellarg($ip), true);
1862
			}
1863 6c2f0930 lukehamburg
			$macaddr = exec("/usr/sbin/ndp -n " . escapeshellarg($ip) . " | /usr/bin/awk '{print $2}'", $output, $retval);
1864 dd83f869 lukehamburg
			break;
1865
	}
1866 6c2f0930 lukehamburg
	if ($retval == 0 && is_macaddr($macaddr)) {
1867
		return $macaddr;
1868
	} else {
1869
		return false;
1870 5b237745 Scott Ullrich
	}
1871
}
1872
1873 98bbf05a Scott Ullrich
/* return a fieldname that is safe for xml usage */
1874
function xml_safe_fieldname($fieldname) {
1875 4f3fc80d Renato Botelho
	$replace = array(
1876
	    '/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1877
	    '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1878
	    ':', ',', '.', '\'', '\\'
1879
	);
1880 ddce8ef2 Colin Smith
	return strtolower(str_replace($replace, "", $fieldname));
1881 98bbf05a Scott Ullrich
}
1882
1883 805b9ab6 Ermal
function mac_format($clientmac) {
1884 86a5e1a8 Renato Botelho
	global $config, $cpzone;
1885 4129df39 Scott Ullrich
1886 86a5e1a8 Renato Botelho
	$mac = explode(":", $clientmac);
1887
	$mac_format = $cpzone ? $config['captiveportal'][$cpzone]['radmac_format'] : false;
1888 4129df39 Scott Ullrich
1889 751533a2 Phil Davis
	switch ($mac_format) {
1890
		case 'singledash':
1891
			return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1892 4129df39 Scott Ullrich
1893 751533a2 Phil Davis
		case 'ietf':
1894
			return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1895 4129df39 Scott Ullrich
1896 751533a2 Phil Davis
		case 'cisco':
1897
			return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1898 4129df39 Scott Ullrich
1899 751533a2 Phil Davis
		case 'unformatted':
1900
			return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1901 4129df39 Scott Ullrich
1902 751533a2 Phil Davis
		default:
1903
			return $clientmac;
1904 86a5e1a8 Renato Botelho
	}
1905 4129df39 Scott Ullrich
}
1906
1907 979cd6db Scott Ullrich
function resolve_retry($hostname, $retries = 5) {
1908
1909 751533a2 Phil Davis
	if (is_ipaddr($hostname)) {
1910 5bbd08e1 Warren Baker
		return $hostname;
1911 751533a2 Phil Davis
	}
1912 979cd6db Scott Ullrich
1913 86a5e1a8 Renato Botelho
	for ($i = 0; $i < $retries; $i++) {
1914 6c4f3b54 Seth Mos
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1915 86a5e1a8 Renato Botelho
		$ip = gethostbyname($hostname);
1916 979cd6db Scott Ullrich
1917 5bbd08e1 Warren Baker
		if ($ip && $ip != $hostname) {
1918
			/* success */
1919
			return $ip;
1920
		}
1921 979cd6db Scott Ullrich
1922 5bbd08e1 Warren Baker
		sleep(1);
1923
	}
1924 979cd6db Scott Ullrich
1925 5bbd08e1 Warren Baker
	return false;
1926 979cd6db Scott Ullrich
}
1927
1928 44bfd1fa Scott Ullrich
function format_bytes($bytes) {
1929 4eac105f Phil Davis
	if ($bytes >= 1099511627776) {
1930 7b512ab3 Phil Davis
		return sprintf("%.2f TiB", $bytes/1099511627776);
1931 4eac105f Phil Davis
	} else if ($bytes >= 1073741824) {
1932 7b512ab3 Phil Davis
		return sprintf("%.2f GiB", $bytes/1073741824);
1933 44bfd1fa Scott Ullrich
	} else if ($bytes >= 1048576) {
1934 7b512ab3 Phil Davis
		return sprintf("%.2f MiB", $bytes/1048576);
1935 44bfd1fa Scott Ullrich
	} else if ($bytes >= 1024) {
1936 7b512ab3 Phil Davis
		return sprintf("%.0f KiB", $bytes/1024);
1937 44bfd1fa Scott Ullrich
	} else {
1938 10ae204f Stephen Beaver
		return sprintf("%d B", $bytes);
1939 44bfd1fa Scott Ullrich
	}
1940
}
1941
1942 cc2cff0b Luiz Otavio O Souza
function format_number($num, $precision = 3) {
1943
	$units = array('', 'K', 'M', 'G', 'T');
1944
1945
	$i = 0;
1946
	while ($num > 1000 && $i < count($units)) {
1947
		$num /= 1000;
1948
		$i++;
1949
	}
1950 92130da3 Luiz Otavio O Souza
	$num = round($num, $precision);
1951 cc2cff0b Luiz Otavio O Souza
1952
	return ("$num {$units[$i]}");
1953
}
1954
1955 4f7956ad Steve Beaver
function update_filter_reload_status($text, $new=false) {
1956 5bbd08e1 Warren Baker
	global $g;
1957 2b4d37de Ermal Lu?i
1958 4f7956ad Steve Beaver
	if ($new) {
1959
		file_put_contents("{$g['varrun_path']}/filter_reload_status", $text  . PHP_EOL);
1960
	} else {
1961
		file_put_contents("{$g['varrun_path']}/filter_reload_status", $text  . PHP_EOL, FILE_APPEND);
1962
	}
1963 2b4d37de Ermal Lu?i
}
1964
1965 a2219caf Renato Botelho
/****** util/return_dir_as_array
1966 2b4d37de Ermal Lu?i
 * NAME
1967
 *   return_dir_as_array - Return a directory's contents as an array.
1968
 * INPUTS
1969 a2219caf Renato Botelho
 *   $dir          - string containing the path to the desired directory.
1970
 *   $filter_regex - string containing a regular expression to filter file names. Default empty.
1971 2b4d37de Ermal Lu?i
 * RESULT
1972
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1973
 ******/
1974 a2219caf Renato Botelho
function return_dir_as_array($dir, $filter_regex = '') {
1975 5bbd08e1 Warren Baker
	$dir_array = array();
1976
	if (is_dir($dir)) {
1977
		if ($dh = opendir($dir)) {
1978
			while (($file = readdir($dh)) !== false) {
1979 751533a2 Phil Davis
				if (($file == ".") || ($file == "..")) {
1980 a2219caf Renato Botelho
					continue;
1981 751533a2 Phil Davis
				}
1982 a2219caf Renato Botelho
1983 751533a2 Phil Davis
				if (empty($filter_regex) || preg_match($filter_regex, $file)) {
1984 5bbd08e1 Warren Baker
					array_push($dir_array, $file);
1985 751533a2 Phil Davis
				}
1986 5bbd08e1 Warren Baker
			}
1987
			closedir($dh);
1988
		}
1989
	}
1990
	return $dir_array;
1991 2b4d37de Ermal Lu?i
}
1992
1993
function run_plugins($directory) {
1994 5bbd08e1 Warren Baker
	global $config, $g;
1995
1996
	/* process packager manager custom rules */
1997
	$files = return_dir_as_array($directory);
1998
	if (is_array($files)) {
1999
		foreach ($files as $file) {
2000 751533a2 Phil Davis
			if (stristr($file, ".sh") == true) {
2001 5bbd08e1 Warren Baker
				mwexec($directory . $file . " start");
2002 086cf944 Phil Davis
			} else if (!is_dir($directory . "/" . $file) && stristr($file, ".inc")) {
2003 5bbd08e1 Warren Baker
				require_once($directory . "/" . $file);
2004 751533a2 Phil Davis
			}
2005 2990acf8 Scott Ullrich
		}
2006 5bbd08e1 Warren Baker
	}
2007 2b4d37de Ermal Lu?i
}
2008
2009
/*
2010
 *    safe_mkdir($path, $mode = 0755)
2011
 *    create directory if it doesn't already exist and isn't a file!
2012
 */
2013 6c07db48 Phil Davis
function safe_mkdir($path, $mode = 0755) {
2014 5bbd08e1 Warren Baker
	global $g;
2015 2b4d37de Ermal Lu?i
2016 5bbd08e1 Warren Baker
	if (!is_file($path) && !is_dir($path)) {
2017
		return @mkdir($path, $mode, true);
2018
	} else {
2019
		return false;
2020
	}
2021 2b4d37de Ermal Lu?i
}
2022
2023 aa4f498d Erik Fonnesbeck
/*
2024
 * get_sysctl($names)
2025
 * Get values of sysctl OID's listed in $names (accepts an array or a single
2026
 * name) and return an array of key/value pairs set for those that exist
2027
 */
2028
function get_sysctl($names) {
2029 751533a2 Phil Davis
	if (empty($names)) {
2030 aa4f498d Erik Fonnesbeck
		return array();
2031 751533a2 Phil Davis
	}
2032 aa4f498d Erik Fonnesbeck
2033
	if (is_array($names)) {
2034
		$name_list = array();
2035
		foreach ($names as $name) {
2036
			$name_list[] = escapeshellarg($name);
2037
		}
2038 751533a2 Phil Davis
	} else {
2039 aa4f498d Erik Fonnesbeck
		$name_list = array(escapeshellarg($names));
2040 751533a2 Phil Davis
	}
2041 aa4f498d Erik Fonnesbeck
2042 3c44c845 Luiz Souza
	exec("/sbin/sysctl -iq " . implode(" ", $name_list), $output);
2043 aa4f498d Erik Fonnesbeck
	$values = array();
2044
	foreach ($output as $line) {
2045
		$line = explode(": ", $line, 2);
2046 751533a2 Phil Davis
		if (count($line) == 2) {
2047 aa4f498d Erik Fonnesbeck
			$values[$line[0]] = $line[1];
2048 751533a2 Phil Davis
		}
2049 aa4f498d Erik Fonnesbeck
	}
2050
2051
	return $values;
2052
}
2053
2054 ff23363d Renato Botelho
/*
2055
 * get_single_sysctl($name)
2056
 * Wrapper for get_sysctl() to simplify read of a single sysctl value
2057
 * return the value for sysctl $name or empty string if it doesn't exist
2058
 */
2059
function get_single_sysctl($name) {
2060 751533a2 Phil Davis
	if (empty($name)) {
2061 ff23363d Renato Botelho
		return "";
2062 751533a2 Phil Davis
	}
2063 ff23363d Renato Botelho
2064
	$value = get_sysctl($name);
2065 751533a2 Phil Davis
	if (empty($value) || !isset($value[$name])) {
2066 ff23363d Renato Botelho
		return "";
2067 751533a2 Phil Davis
	}
2068 ff23363d Renato Botelho
2069
	return $value[$name];
2070
}
2071
2072 aa4f498d Erik Fonnesbeck
/*
2073
 * set_sysctl($value_list)
2074
 * Set sysctl OID's listed as key/value pairs and return
2075
 * an array with keys set for those that succeeded
2076
 */
2077
function set_sysctl($values) {
2078 751533a2 Phil Davis
	if (empty($values)) {
2079 aa4f498d Erik Fonnesbeck
		return array();
2080 751533a2 Phil Davis
	}
2081 aa4f498d Erik Fonnesbeck
2082
	$value_list = array();
2083
	foreach ($values as $key => $value) {
2084
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
2085
	}
2086
2087 3c44c845 Luiz Souza
	exec("/sbin/sysctl -iq " . implode(" ", $value_list), $output, $success);
2088 aa4f498d Erik Fonnesbeck
2089
	/* Retry individually if failed (one or more read-only) */
2090
	if ($success <> 0 && count($value_list) > 1) {
2091
		foreach ($value_list as $value) {
2092 3c44c845 Luiz Souza
			exec("/sbin/sysctl -iq " . $value, $output);
2093 aa4f498d Erik Fonnesbeck
		}
2094
	}
2095
2096
	$ret = array();
2097
	foreach ($output as $line) {
2098
		$line = explode(": ", $line, 2);
2099 751533a2 Phil Davis
		if (count($line) == 2) {
2100 aa4f498d Erik Fonnesbeck
			$ret[$line[0]] = true;
2101 751533a2 Phil Davis
		}
2102 aa4f498d Erik Fonnesbeck
	}
2103
2104
	return $ret;
2105
}
2106
2107 82f75815 Renato Botelho
/*
2108
 * set_single_sysctl($name, $value)
2109
 * Wrapper to set_sysctl() to make it simple to set only one sysctl
2110 751533a2 Phil Davis
 * returns boolean meaning if it succeeded
2111 82f75815 Renato Botelho
 */
2112
function set_single_sysctl($name, $value) {
2113 751533a2 Phil Davis
	if (empty($name)) {
2114 82f75815 Renato Botelho
		return false;
2115 751533a2 Phil Davis
	}
2116 82f75815 Renato Botelho
2117
	$result = set_sysctl(array($name => $value));
2118
2119 751533a2 Phil Davis
	if (!isset($result[$name]) || $result[$name] != $value) {
2120 82f75815 Renato Botelho
		return false;
2121 751533a2 Phil Davis
	}
2122 82f75815 Renato Botelho
2123
	return true;
2124
}
2125
2126 2b4d37de Ermal Lu?i
/*
2127
 *     get_memory()
2128
 *     returns an array listing the amount of
2129
 *     memory installed in the hardware
2130 517fb89e Phil Davis
 *     [0] net memory available for the OS (FreeBSD) after some is taken by BIOS, video or whatever - e.g. 235 MBytes
2131
 *     [1] real (actual) memory of the system, should be the size of the RAM card/s - e.g. 256 MBytes
2132 2b4d37de Ermal Lu?i
 */
2133
function get_memory() {
2134 971de1f9 Renato Botelho
	$physmem = get_single_sysctl("hw.physmem");
2135
	$realmem = get_single_sysctl("hw.realmem");
2136 5cd73772 Ermal
	/* convert from bytes to megabytes */
2137 086cf944 Phil Davis
	return array(($physmem/1048576), ($realmem/1048576));
2138 2b4d37de Ermal Lu?i
}
2139
2140
function mute_kernel_msgs() {
2141 6fa9f38c Renato Botelho
	global $g, $config;
2142 dc61252a Renato Botelho
2143 751533a2 Phil Davis
	if ($config['system']['enableserial']) {
2144 86a5e1a8 Renato Botelho
		return;
2145 751533a2 Phil Davis
	}
2146 5bbd08e1 Warren Baker
	exec("/sbin/conscontrol mute on");
2147 2b4d37de Ermal Lu?i
}
2148
2149
function unmute_kernel_msgs() {
2150 6fa9f38c Renato Botelho
	global $g;
2151 dc61252a Renato Botelho
2152 5bbd08e1 Warren Baker
	exec("/sbin/conscontrol mute off");
2153 2b4d37de Ermal Lu?i
}
2154
2155
function start_devd() {
2156 505e3e0e Renato Botelho
	global $g;
2157
2158 751533a2 Phil Davis
	/* Use the undocumented -q options of devd to quiet its log spamming */
2159 505e3e0e Renato Botelho
	$_gb = exec("/sbin/devd -q -f /etc/{$g['product_name']}-devd.conf");
2160 5bbd08e1 Warren Baker
	sleep(1);
2161 a7f79eda Ermal LUÇI
	unset($_gb);
2162 2b4d37de Ermal Lu?i
}
2163
2164 66bcba1b Ermal
function is_interface_vlan_mismatch() {
2165 5bbd08e1 Warren Baker
	global $config, $g;
2166 66bcba1b Ermal
2167 5bbd08e1 Warren Baker
	if (is_array($config['vlans']['vlan'])) {
2168
		foreach ($config['vlans']['vlan'] as $vlan) {
2169 2915acf8 Chris Buechler
			if (substr($vlan['if'], 0, 4) == "lagg") {
2170
				return false;
2171
			}
2172 751533a2 Phil Davis
			if (does_interface_exist($vlan['if']) == false) {
2173 66bcba1b Ermal
				return true;
2174 751533a2 Phil Davis
			}
2175 5bbd08e1 Warren Baker
		}
2176
	}
2177 66bcba1b Ermal
2178
	return false;
2179
}
2180
2181 2b4d37de Ermal Lu?i
function is_interface_mismatch() {
2182 857da904 Scott Ullrich
	global $config, $g;
2183 2b4d37de Ermal Lu?i
2184 857da904 Scott Ullrich
	$do_assign = false;
2185
	$i = 0;
2186 e0a45ce0 Erik Fonnesbeck
	$missing_interfaces = array();
2187 72993196 Ermal
	if (is_array($config['interfaces'])) {
2188 857da904 Scott Ullrich
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
2189 12bcf7e9 Luiz Souza
			if (interface_is_vlan($ifcfg['if']) != NULL ||
2190 0793de1a Luiz Souza
			    interface_is_qinq($ifcfg['if']) != NULL ||
2191 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'])) {
2192 857da904 Scott Ullrich
				// Do not check these interfaces.
2193
				$i++;
2194
				continue;
2195 751533a2 Phil Davis
			} else if (does_interface_exist($ifcfg['if']) == false) {
2196 e0a45ce0 Erik Fonnesbeck
				$missing_interfaces[] = $ifcfg['if'];
2197 72993196 Ermal
				$do_assign = true;
2198 751533a2 Phil Davis
			} else {
2199 857da904 Scott Ullrich
				$i++;
2200 751533a2 Phil Davis
			}
2201 857da904 Scott Ullrich
		}
2202 72993196 Ermal
	}
2203 2b4d37de Ermal Lu?i
2204 751533a2 Phil Davis
	if (file_exists("{$g['tmp_path']}/assign_complete")) {
2205 e0a45ce0 Erik Fonnesbeck
		$do_assign = false;
2206 751533a2 Phil Davis
	}
2207 e0a45ce0 Erik Fonnesbeck
2208 751533a2 Phil Davis
	if (!empty($missing_interfaces) && $do_assign) {
2209 e0a45ce0 Erik Fonnesbeck
		file_put_contents("{$g['tmp_path']}/missing_interfaces", implode(' ', $missing_interfaces));
2210 751533a2 Phil Davis
	} else {
2211 e0a45ce0 Erik Fonnesbeck
		@unlink("{$g['tmp_path']}/missing_interfaces");
2212 751533a2 Phil Davis
	}
2213 2b4d37de Ermal Lu?i
2214 857da904 Scott Ullrich
	return $do_assign;
2215 2b4d37de Ermal Lu?i
}
2216
2217 6e8f7b53 Ermal Lu?i
/* sync carp entries to other firewalls */
2218
function carp_sync_client() {
2219 e14d1c01 Ermal Lu?i
	global $g;
2220 0ae6daf8 Ermal
	send_event("filter sync");
2221 6e8f7b53 Ermal Lu?i
}
2222
2223 6dc88d53 Ermal Luci
/****f* util/isAjax
2224
 * NAME
2225
 *   isAjax - reports if the request is driven from prototype
2226
 * INPUTS
2227
 *   none
2228
 * RESULT
2229
 *   true/false
2230
 ******/
2231
function isAjax() {
2232 5bbd08e1 Warren Baker
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
2233 6dc88d53 Ermal Luci
}
2234
2235 dad2b40e Tim Allender
/****f* util/timeout
2236
 * NAME
2237
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
2238
 * INPUTS
2239
 *   optional, seconds to wait before timeout. Default 9 seconds.
2240
 * RESULT
2241
 *   returns 1 char of user input or null if no input.
2242
 ******/
2243
function timeout($timer = 9) {
2244 751533a2 Phil Davis
	while (!isset($key)) {
2245
		if ($timer >= 9) {
2246 6c07db48 Phil Davis
			echo chr(8) . chr(8) . ($timer == 9 ? chr(32) : null) . "{$timer}";
2247 751533a2 Phil Davis
		} else {
2248
			echo chr(8). "{$timer}";
2249
		}
2250 dad2b40e Tim Allender
		`/bin/stty -icanon min 0 time 25`;
2251
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
2252
		`/bin/stty icanon`;
2253 751533a2 Phil Davis
		if ($key == '') {
2254 dad2b40e Tim Allender
			unset($key);
2255 751533a2 Phil Davis
		}
2256 dad2b40e Tim Allender
		$timer--;
2257 751533a2 Phil Davis
		if ($timer == 0) {
2258 dad2b40e Tim Allender
			break;
2259 751533a2 Phil Davis
		}
2260 dad2b40e Tim Allender
	}
2261 86a5e1a8 Renato Botelho
	return $key;
2262 dad2b40e Tim Allender
}
2263 6dc88d53 Ermal Luci
2264 fdf3af3f Scott Ullrich
/****f* util/msort
2265
 * NAME
2266
 *   msort - sort array
2267
 * INPUTS
2268
 *   $array to be sorted, field to sort by, direction of sort
2269
 * RESULT
2270
 *   returns newly sorted array
2271
 ******/
2272 6c07db48 Phil Davis
function msort($array, $id = "id", $sort_ascending = true) {
2273 4a8bc5a2 Scott Ullrich
	$temp_array = array();
2274 a47598aa Renato Botelho
	if (!is_array($array)) {
2275
		return $temp_array;
2276
	}
2277 751533a2 Phil Davis
	while (count($array)>0) {
2278 4a8bc5a2 Scott Ullrich
		$lowest_id = 0;
2279 6c07db48 Phil Davis
		$index = 0;
2280 4a8bc5a2 Scott Ullrich
		foreach ($array as $item) {
2281
			if (isset($item[$id])) {
2282
				if ($array[$lowest_id][$id]) {
2283
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
2284
						$lowest_id = $index;
2285
					}
2286
				}
2287
			}
2288
			$index++;
2289
		}
2290
		$temp_array[] = $array[$lowest_id];
2291 086cf944 Phil Davis
		$array = array_merge(array_slice($array, 0, $lowest_id), array_slice($array, $lowest_id + 1));
2292 4a8bc5a2 Scott Ullrich
	}
2293
	if ($sort_ascending) {
2294
		return $temp_array;
2295
	} else {
2296 86a5e1a8 Renato Botelho
		return array_reverse($temp_array);
2297 4a8bc5a2 Scott Ullrich
	}
2298
}
2299
2300 5e9dd72a sullrich
/****f* util/is_URL
2301
 * NAME
2302
 *   is_URL
2303
 * INPUTS
2304
 *   string to check
2305
 * RESULT
2306
 *   Returns true if item is a URL
2307
 ******/
2308
function is_URL($url) {
2309
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
2310 751533a2 Phil Davis
	if ($match) {
2311 86a5e1a8 Renato Botelho
		return true;
2312 751533a2 Phil Davis
	}
2313 5e9dd72a sullrich
	return false;
2314
}
2315
2316 ab94ba00 Ermal Lu?i
function is_file_included($file = "") {
2317
	$files = get_included_files();
2318 751533a2 Phil Davis
	if (in_array($file, $files)) {
2319 ab94ba00 Ermal Lu?i
		return true;
2320 751533a2 Phil Davis
	}
2321 86a5e1a8 Renato Botelho
2322 ab94ba00 Ermal Lu?i
	return false;
2323
}
2324
2325 f2cc3344 Renato Botelho
/*
2326
 * Replace a value on a deep associative array using regex
2327
 */
2328
function array_replace_values_recursive($data, $match, $replace) {
2329 751533a2 Phil Davis
	if (empty($data)) {
2330 f2cc3344 Renato Botelho
		return $data;
2331 751533a2 Phil Davis
	}
2332 f2cc3344 Renato Botelho
2333 751533a2 Phil Davis
	if (is_string($data)) {
2334 f2cc3344 Renato Botelho
		$data = preg_replace("/{$match}/", $replace, $data);
2335 751533a2 Phil Davis
	} else if (is_array($data)) {
2336
		foreach ($data as $k => $v) {
2337 f2cc3344 Renato Botelho
			$data[$k] = array_replace_values_recursive($v, $match, $replace);
2338 751533a2 Phil Davis
		}
2339
	}
2340 f2cc3344 Renato Botelho
2341
	return $data;
2342
}
2343
2344 0d90fcaf jim-p
/*
2345
	This function was borrowed from a comment on PHP.net at the following URL:
2346
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
2347
 */
2348 5bbd08e1 Warren Baker
function array_merge_recursive_unique($array0, $array1) {
2349
2350
	$arrays = func_get_args();
2351
	$remains = $arrays;
2352 0d90fcaf jim-p
2353 5bbd08e1 Warren Baker
	// We walk through each arrays and put value in the results (without
2354
	// considering previous value).
2355
	$result = array();
2356 0d90fcaf jim-p
2357 5bbd08e1 Warren Baker
	// loop available array
2358 751533a2 Phil Davis
	foreach ($arrays as $array) {
2359 0d90fcaf jim-p
2360 5bbd08e1 Warren Baker
		// The first remaining array is $array. We are processing it. So
2361 751533a2 Phil Davis
		// we remove it from remaining arrays.
2362 86a5e1a8 Renato Botelho
		array_shift($remains);
2363 0d90fcaf jim-p
2364 5bbd08e1 Warren Baker
		// We don't care non array param, like array_merge since PHP 5.0.
2365 751533a2 Phil Davis
		if (is_array($array)) {
2366 5bbd08e1 Warren Baker
			// Loop values
2367 751533a2 Phil Davis
			foreach ($array as $key => $value) {
2368
				if (is_array($value)) {
2369 5bbd08e1 Warren Baker
					// we gather all remaining arrays that have such key available
2370
					$args = array();
2371 751533a2 Phil Davis
					foreach ($remains as $remain) {
2372
						if (array_key_exists($key, $remain)) {
2373 5bbd08e1 Warren Baker
							array_push($args, $remain[$key]);
2374
						}
2375
					}
2376
2377 751533a2 Phil Davis
					if (count($args) > 2) {
2378 5bbd08e1 Warren Baker
						// put the recursion
2379
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
2380
					} else {
2381 751533a2 Phil Davis
						foreach ($value as $vkey => $vval) {
2382 b2c97ede jim-p
							if (!is_array($result[$key])) {
2383
								$result[$key] = array();
2384
							}
2385 5bbd08e1 Warren Baker
							$result[$key][$vkey] = $vval;
2386
						}
2387
					}
2388
				} else {
2389
					// simply put the value
2390
					$result[$key] = $value;
2391
				}
2392
			}
2393
		}
2394
	}
2395
	return $result;
2396 0d90fcaf jim-p
}
2397
2398 f898c1a9 jim-p
2399 9a456170 Darren Embry
/*
2400
 * converts a string like "a,b,c,d"
2401
 * into an array like array("a" => "b", "c" => "d")
2402
 */
2403
function explode_assoc($delimiter, $string) {
2404
	$array = explode($delimiter, $string);
2405
	$result = array();
2406
	$numkeys = floor(count($array) / 2);
2407
	for ($i = 0; $i < $numkeys; $i += 1) {
2408
		$result[$array[$i * 2]] = $array[$i * 2 + 1];
2409
	}
2410
	return $result;
2411
}
2412
2413 bea18841 Phil Davis
/*
2414
 * Given a string of text with some delimiter, look for occurrences
2415
 * of some string and replace all of those.
2416
 * $text - the text string (e.g. "abc,defg,x123,ipv4,xyz")
2417
 * $delimiter - the delimiter (e.g. ",")
2418
 * $element - the element to match (e.g. "defg")
2419
 * $replacement - the string to replace it with (e.g. "42")
2420
 * Returns the resulting delimited string (e.g. "abc,42,x123,ipv4,xyz")
2421
 */
2422
function replace_element_in_list($text, $delimiter, $element, $replacement) {
2423
	$textArray = explode($delimiter, $text);
2424
	while (($entry = array_search($element, $textArray)) !== false) {
2425
		$textArray[$entry] = $replacement;
2426
	}
2427
	return implode(',', $textArray);
2428
}
2429
2430 94bd7fb3 Renato Botelho
/* Try to change a static route, if it doesn't exist, add it */
2431
function route_add_or_change($args) {
2432
	global $config;
2433
2434
	if (empty($args)) {
2435
		return false;
2436
	}
2437
2438
	/* First, try to add it */
2439
	$_gb = exec(escapeshellcmd("/sbin/route add " . $args), $output, $rc);
2440 43a9b03d PiBa-NL
		
2441 94bd7fb3 Renato Botelho
	if (isset($config['system']['route-debug'])) {
2442 43a9b03d PiBa-NL
		$add_change = 'add';
2443 94bd7fb3 Renato Botelho
		$mt = microtime();
2444
		log_error("ROUTING debug: $mt - ADD RC={$rc} - $args");
2445
	}
2446
2447
	if ($rc != 0) {
2448
		/* If it fails, try to change it */
2449
		$_gb = exec(escapeshellcmd("/sbin/route change " . $args),
2450
		    $output, $rc);
2451
2452
		if (isset($config['system']['route-debug'])) {
2453 43a9b03d PiBa-NL
			$add_change = 'change';
2454 94bd7fb3 Renato Botelho
			$mt = microtime();
2455
			log_error("ROUTING debug: $mt - CHG RC={$rc} - $args");
2456
		}
2457
	}
2458 43a9b03d PiBa-NL
	if (isset($config['system']['route-debug'])) {
2459
		file_put_contents("/dev/console", "\n[".getmypid()."] ROUTE: {$add_change} {$args} result: {$rc}");
2460
	}
2461 94bd7fb3 Renato Botelho
2462
	return ($rc == 0);
2463
}
2464
2465 71f0623e PiBa-NL
function alias_to_subnets_recursive($name, $returnhostnames = false) {
2466
	global $aliastable;
2467
	$result = array();
2468
	if (!isset($aliastable[$name])) {
2469
		return $result;
2470
	}
2471
	$subnets = preg_split('/\s+/', $aliastable[$name]);
2472
	foreach ($subnets as $net) {
2473
		if (is_alias($net)) {
2474
			$sub = alias_to_subnets_recursive($net, $returnhostnames);
2475
			$result = array_merge($result, $sub);
2476
			continue;
2477
		} elseif (!is_subnet($net)) {
2478
			if (is_ipaddrv4($net)) {
2479
				$net .= "/32";
2480
			} else if (is_ipaddrv6($net)) {
2481
				$net .= "/128";
2482
			} else if ($returnhostnames === false || !is_fqdn($net)) {
2483
				continue;
2484
			}
2485
		}
2486
		$result[] = $net;
2487
	}
2488
	return $result;
2489
}
2490
2491 cf08b49e Phil Davis
function get_staticroutes($returnsubnetsonly = false, $returnhostnames = false, $returnenabledroutesonly = false) {
2492 1901463c Renato Botelho
	global $config, $aliastable;
2493 f898c1a9 jim-p
2494
	/* Bail if there are no routes, but return an array always so callers don't have to check. */
2495 751533a2 Phil Davis
	if (!is_array($config['staticroutes']['route'])) {
2496 f898c1a9 jim-p
		return array();
2497 751533a2 Phil Davis
	}
2498 f898c1a9 jim-p
2499 bcab1b07 Ermal
	$allstaticroutes = array();
2500
	$allsubnets = array();
2501 f898c1a9 jim-p
	/* Loop through routes and expand aliases as we find them. */
2502
	foreach ($config['staticroutes']['route'] as $route) {
2503 cf08b49e Phil Davis
		if ($returnenabledroutesonly && isset($route['disabled'])) {
2504
			continue;
2505
		}
2506
2507 f898c1a9 jim-p
		if (is_alias($route['network'])) {
2508 71f0623e PiBa-NL
			foreach (alias_to_subnets_recursive($route['network'], $returnhostnames) as $net) {
2509 f898c1a9 jim-p
				$temproute = $route;
2510
				$temproute['network'] = $net;
2511
				$allstaticroutes[] = $temproute;
2512
				$allsubnets[] = $net;
2513
			}
2514
		} elseif (is_subnet($route['network'])) {
2515
			$allstaticroutes[] = $route;
2516
			$allsubnets[] = $route['network'];
2517
		}
2518
	}
2519 751533a2 Phil Davis
	if ($returnsubnetsonly) {
2520 f898c1a9 jim-p
		return $allsubnets;
2521 751533a2 Phil Davis
	} else {
2522 f898c1a9 jim-p
		return $allstaticroutes;
2523 751533a2 Phil Davis
	}
2524 f898c1a9 jim-p
}
2525 a0539faa Darren Embry
2526
/****f* util/get_alias_list
2527
 * NAME
2528
 *   get_alias_list - Provide a list of aliases.
2529
 * INPUTS
2530
 *   $type          - Optional, can be a string or array specifying what type(s) of aliases you need.
2531
 * RESULT
2532
 *   Array containing list of aliases.
2533
 *   If $type is unspecified, all aliases are returned.
2534
 *   If $type is a string, all aliases of the type specified in $type are returned.
2535
 *   If $type is an array, all aliases of any type specified in any element of $type are returned.
2536
 */
2537
function get_alias_list($type = null) {
2538
	global $config;
2539
	$result = array();
2540
	if ($config['aliases']['alias'] <> "" && is_array($config['aliases']['alias'])) {
2541
		foreach ($config['aliases']['alias'] as $alias) {
2542
			if ($type === null) {
2543
				$result[] = $alias['name'];
2544 751533a2 Phil Davis
			} else if (is_array($type)) {
2545 a0539faa Darren Embry
				if (in_array($alias['type'], $type)) {
2546
					$result[] = $alias['name'];
2547
				}
2548 751533a2 Phil Davis
			} else if ($type === $alias['type']) {
2549 a0539faa Darren Embry
				$result[] = $alias['name'];
2550
			}
2551
		}
2552 86a5e1a8 Renato Botelho
	}
2553 a0539faa Darren Embry
	return $result;
2554
}
2555
2556 4dfd930e Darren Embry
/* returns an array consisting of every element of $haystack that is not equal to $needle. */
2557
function array_exclude($needle, $haystack) {
2558
	$result = array();
2559
	if (is_array($haystack)) {
2560
		foreach ($haystack as $thing) {
2561
			if ($needle !== $thing) {
2562
				$result[] = $thing;
2563
			}
2564
		}
2565
	}
2566
	return $result;
2567
}
2568
2569 77a341a4 Renato Botelho
/* Define what is preferred, IPv4 or IPv6 */
2570
function prefer_ipv4_or_ipv6() {
2571
	global $config;
2572
2573 751533a2 Phil Davis
	if (isset($config['system']['prefer_ipv4'])) {
2574 77a341a4 Renato Botelho
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv4");
2575 751533a2 Phil Davis
	} else {
2576 77a341a4 Renato Botelho
		mwexec("/etc/rc.d/ip6addrctl prefer_ipv6");
2577 751533a2 Phil Davis
	}
2578 77a341a4 Renato Botelho
}
2579
2580 111bea0d Renato Botelho
/* Redirect to page passing parameters via POST */
2581
function post_redirect($page, $params) {
2582 751533a2 Phil Davis
	if (!is_array($params)) {
2583 111bea0d Renato Botelho
		return;
2584 751533a2 Phil Davis
	}
2585 111bea0d Renato Botelho
2586
	print "<html><body><form action=\"{$page}\" name=\"formredir\" method=\"post\">\n";
2587
	foreach ($params as $key => $value) {
2588
		print "<input type=\"hidden\" name=\"{$key}\" value=\"{$value}\" />\n";
2589
	}
2590 8fd9052f Colin Fleming
	print "</form>\n";
2591
	print "<script type=\"text/javascript\">\n";
2592
	print "//<![CDATA[\n";
2593
	print "document.formredir.submit();\n";
2594
	print "//]]>\n";
2595
	print "</script>\n";
2596 111bea0d Renato Botelho
	print "</body></html>\n";
2597
}
2598
2599 ea20169a jim-p
/* Locate disks that can be queried for S.M.A.R.T. data. */
2600
function get_smart_drive_list() {
2601
	$disk_list = explode(" ", get_single_sysctl("kern.disks"));
2602
	foreach ($disk_list as $id => $disk) {
2603
		// We only want certain kinds of disks for S.M.A.R.T.
2604 a68c6785 Phil Davis
		// 1 is a match, 0 is no match, False is any problem processing the regex
2605
		if (preg_match("/^(ad|da|ada).*[0-9]{1,2}$/", $disk) !== 1) {
2606 ea20169a jim-p
			unset($disk_list[$id]);
2607
		}
2608
	}
2609
	sort($disk_list);
2610
	return $disk_list;
2611
}
2612
2613 77a8a7d6 Steve Beaver
// Validate a network address
2614
//	$addr: the address to validate
2615
//	$type: IPV4|IPV6|IPV4V6
2616 c393f1d1 Steve Beaver
//	$label: the label used by the GUI to display this value. Required to compose an error message
2617 77a8a7d6 Steve Beaver
//	$err_msg: pointer to the callers error message array so that error messages can be added to it here
2618
//	$alias: are aliases permitted for this address?
2619 24eb39e2 Phil Davis
// Returns:
2620 74999ad8 Phil Davis
//	IPV4 - if $addr is a valid IPv4 address
2621
//	IPV6 - if $addr is a valid IPv6 address
2622
//	ALIAS - if $alias=true and $addr is an alias
2623 24eb39e2 Phil Davis
//	false - otherwise
2624
2625 77a8a7d6 Steve Beaver
function validateipaddr(&$addr, $type, $label, &$err_msg, $alias=false) {
2626
	switch ($type) {
2627
		case IPV4:
2628
			if (is_ipaddrv4($addr)) {
2629 dc938839 Phil Davis
				return IPV4;
2630 77a8a7d6 Steve Beaver
			} else if ($alias) {
2631
				if (is_alias($addr)) {
2632 dc938839 Phil Davis
					return ALIAS;
2633 77a8a7d6 Steve Beaver
				} else {
2634 bb9747b2 Phil Davis
					$err_msg[] = sprintf(gettext("%s must be a valid IPv4 address or alias."), $label);
2635 77a8a7d6 Steve Beaver
					return false;
2636
				}
2637
			} else {
2638 bb9747b2 Phil Davis
				$err_msg[] = sprintf(gettext("%s must be a valid IPv4 address."), $label);
2639 77a8a7d6 Steve Beaver
				return false;
2640
			}
2641
		break;
2642
		case IPV6:
2643
			if (is_ipaddrv6($addr)) {
2644
				$addr = strtolower($addr);
2645 dc938839 Phil Davis
				return IPV6;
2646 aa2b8133 Phil Davis
			} else if ($alias) {
2647 77a8a7d6 Steve Beaver
				if (is_alias($addr)) {
2648 dc938839 Phil Davis
					return ALIAS;
2649 77a8a7d6 Steve Beaver
				} else {
2650 bb9747b2 Phil Davis
					$err_msg[] = sprintf(gettext("%s must be a valid IPv6 address or alias."), $label);
2651 77a8a7d6 Steve Beaver
					return false;
2652
				}
2653
			} else {
2654 bb9747b2 Phil Davis
				$err_msg[] = sprintf(gettext("%s must be a valid IPv6 address."), $label);
2655 77a8a7d6 Steve Beaver
				return false;
2656
			}
2657
		break;
2658
		case IPV4V6:
2659
			if (is_ipaddrv6($addr)) {
2660
				$addr = strtolower($addr);
2661 dc938839 Phil Davis
				return IPV6;
2662 77a8a7d6 Steve Beaver
			} else if (is_ipaddrv4($addr)) {
2663 dc938839 Phil Davis
				return IPV4;
2664 aa2b8133 Phil Davis
			} else if ($alias) {
2665 77a8a7d6 Steve Beaver
				if (is_alias($addr)) {
2666 dc938839 Phil Davis
					return ALIAS;
2667 77a8a7d6 Steve Beaver
				} else {
2668 bb9747b2 Phil Davis
					$err_msg[] = sprintf(gettext("%s must be a valid IPv4 or IPv6 address or alias."), $label);
2669 77a8a7d6 Steve Beaver
					return false;
2670
				}
2671
			} else {
2672 bb9747b2 Phil Davis
				$err_msg[] = sprintf(gettext("%s must be a valid IPv4 or IPv6 address."), $label);
2673 77a8a7d6 Steve Beaver
				return false;
2674
			}
2675
		break;
2676
	}
2677
2678
	return false;
2679
}
2680 7be23d53 marjohn56
2681 64b9d133 kangtastic
/* From DUID configuration inputs, format a string that looks (more) like the expected raw DUID format:
2682 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:
2683
 *     a) For DUID-LLT and DUID-EN, convert the time/enterprise ID input to hex and append the link-layer address/identifier input.
2684
 *     b) For DUID-LLT and DUID-LL, prepend a hardware type of 1.
2685
 *     c) For DUID-UUID, remove any "-".
2686
 * 2) Replace any remaining "-" with ":".
2687 f4bbec8b Phil Davis
 * 3) If any components are input with just a single char (hex digit hopefully), put a "0" in front.
2688 fffb9eed kangtastic
 * 4) The first two components should be a 16-bit integer (little- or big-endian, depending on the current machine type) that
2689 7955bcce kangtastic
 *    is equal to the number of other components. If not, prepend this as "nn:00" (all pfSense builds are little-endian).
2690 fffb9eed kangtastic
 *    This is convenience, because the DUID reported by dhcp6c in logs does not include this count, which corresponds to the
2691
 *    option-len field of DHCPv6's OPTION_CLIENTID option.
2692 f4bbec8b Phil Davis
 *
2693
 * The final result should be closer to:
2694
 *
2695 7955bcce kangtastic
 * "nn:00:00:0n:nn:nn:nn:..."
2696 f4bbec8b Phil Davis
 *
2697
 * This function does not validate the input. is_duid() will do validation.
2698 64b9d133 kangtastic
 */
2699
function format_duid($duidtype, $duidpt1, $duidpt2=null) {
2700 fffb9eed kangtastic
	if ($duidpt2)
2701
		$duidpt1 = implode(':', str_split(str_pad(dechex($duidpt1), 8, '0', STR_PAD_LEFT), 2)) . ':' . $duidpt2;
2702 64b9d133 kangtastic
2703 fffb9eed kangtastic
	/* Make hexstrings */
2704
	if ($duidtype) {
2705
		switch ($duidtype) {
2706
		/* Add a hardware type to DUID-LLT and DUID-LL; assume Ethernet */
2707
		case 1:
2708
		case 3:
2709
			$duidpt1 = '00:01:' . $duidpt1;
2710
			break;
2711
		/* Remove '-' from given UUID and insert ':' every 2 characters */
2712
		case 4:
2713
			$duidpt1 = implode(':', str_split(str_replace('-', '', $duidpt1), 2));
2714
			break;
2715
		default:
2716
		}
2717
		$duidpt1 = '00:0' . $duidtype . ':' . $duidpt1;
2718 f4bbec8b Phil Davis
	}
2719 fd2e503a Phil Davis
2720 fffb9eed kangtastic
	$values = explode(':', strtolower(str_replace('-', ':', $duidpt1)));
2721
2722 7955bcce kangtastic
	if (hexdec($values[0]) != count($values) - 2)
2723 64b9d133 kangtastic
		array_unshift($values, dechex(count($values)), '00');
2724 fd2e503a Phil Davis
2725
	array_walk($values, function(&$value) {
2726 4f3fc80d Renato Botelho
		$value = str_pad($value, 2, '0', STR_PAD_LEFT);
2727 fd2e503a Phil Davis
	});
2728
2729 febfd592 Phil Davis
	return implode(":", $values);
2730 f4bbec8b Phil Davis
}
2731
2732 64b9d133 kangtastic
/* Returns true if $dhcp6duid is a valid DUID entry.
2733 7955bcce kangtastic
 * Parse the entry to check for valid length according to known DUID types.
2734 64b9d133 kangtastic
 */
2735 7be23d53 marjohn56
function is_duid($dhcp6duid) {
2736
	$values = explode(":", $dhcp6duid);
2737 7955bcce kangtastic
	if (hexdec($values[0]) == count($values) - 2) {
2738 64b9d133 kangtastic
		switch (hexdec($values[2] . $values[3])) {
2739 fffb9eed kangtastic
		case 0:
2740
			return false;
2741
			break;
2742 64b9d133 kangtastic
		case 1:
2743 fffb9eed kangtastic
			if (count($values) != 16 || strlen($dhcp6duid) != 47)
2744 64b9d133 kangtastic
				return false;
2745
			break;
2746
		case 3:
2747 fffb9eed kangtastic
			if (count($values) != 12 || strlen($dhcp6duid) != 35)
2748 64b9d133 kangtastic
				return false;
2749
			break;
2750
		case 4:
2751 fffb9eed kangtastic
			if (count($values) != 20 || strlen($dhcp6duid) != 59)
2752 64b9d133 kangtastic
				return false;
2753
			break;
2754 fffb9eed kangtastic
		/* DUID is up to 128 octets; allow 2 octets for type code, 2 more for option-len */
2755 64b9d133 kangtastic
		default:
2756 fffb9eed kangtastic
			if (count($values) > 132 || strlen($dhcp6duid) != count($values) * 3 - 1)
2757 64b9d133 kangtastic
				return false;
2758
		}
2759 fffb9eed kangtastic
	} else
2760 7be23d53 marjohn56
		return false;
2761 fffb9eed kangtastic
2762 64b9d133 kangtastic
	for ($i = 0; $i < count($values); $i++) {
2763 7be23d53 marjohn56
		if (ctype_xdigit($values[$i]) == false)
2764
			return false;
2765
		if (hexdec($values[$i]) < 0 || hexdec($values[$i]) > 255)
2766
			return false;
2767
	}
2768 fffb9eed kangtastic
2769 7be23d53 marjohn56
	return true;
2770
}
2771
2772
/* Write the DHCP6 DUID file */
2773
function write_dhcp6_duid($duidstring) {
2774
	// Create the hex array from the dhcp6duid config entry and write to file
2775
	global $g;
2776 4f3fc80d Renato Botelho
2777
	if(!is_duid($duidstring)) {
2778 7be23d53 marjohn56
		log_error(gettext("Error: attempting to write DUID file - Invalid DUID detected"));
2779
		return false;
2780
	}
2781
	$temp = str_replace(":","",$duidstring);
2782
	$duid_binstring = pack("H*",$temp);
2783
	if ($fd = fopen("{$g['vardb_path']}/dhcp6c_duid", "wb")) {
2784
		fwrite($fd, $duid_binstring);
2785
		fclose($fd);
2786
		return true;
2787
	}
2788
	log_error(gettext("Error: attempting to write DUID file - File write error"));
2789
	return false;
2790
}
2791 2acedbbf marjohn56
2792 9e08a2bd marjohn56
/* returns duid string from 'vardb_path']}/dhcp6c_duid' */
2793 4f3fc80d Renato Botelho
function get_duid_from_file() {
2794 9e08a2bd marjohn56
	global $g;
2795 4f3fc80d Renato Botelho
2796 2acedbbf marjohn56
	$duid_ASCII = "";
2797 9e08a2bd marjohn56
	$count = 0;
2798 a271ed3d Renato Botelho
2799
	if (file_exists("{$g['vardb_path']}/dhcp6c_duid") &&
2800
	    ($fd = fopen("{$g['vardb_path']}/dhcp6c_duid", "r"))) {
2801 64b9d133 kangtastic
		$fsize = filesize("{$g['vardb_path']}/dhcp6c_duid");
2802
		if ($fsize <= 132) {
2803
			$buffer = fread($fd, $fsize);
2804
			while($count < $fsize) {
2805 2acedbbf marjohn56
				$duid_ASCII .= bin2hex($buffer[$count]);
2806 9e08a2bd marjohn56
				$count++;
2807 64b9d133 kangtastic
				if($count < $fsize) {
2808 9e08a2bd marjohn56
					$duid_ASCII .= ":";
2809
				}
2810
			}
2811
		}
2812
		fclose($fd);
2813
	}
2814
	//if no file or error with read then the string returns blanked DUID string
2815 2acedbbf marjohn56
	if(!is_duid($duid_ASCII)) {
2816 9e08a2bd marjohn56
		return "--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--";
2817
	}
2818 4f3fc80d Renato Botelho
	return($duid_ASCII);
2819 9e08a2bd marjohn56
}
2820 117776e0 doktornotor
2821
/* Replaces the Mac OS 9 and earlier (\r) and DOS/Windows (\r\n) newlines with the Unix equivalent (\n). */
2822
function unixnewlines($text) {
2823
	return preg_replace('/\r\n?/', "\n", $text);
2824
}
2825
2826 eb295a1b Ermal
?>