Project

General

Profile

Download (82.7 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/****h* pfSense/pfsense-utils
3
	NAME
4
		pfsense-utils.inc - Utilities specific to pfSense
5
	DESCRIPTION
6
		This include contains various pfSense specific functions.
7
	HISTORY
8
		$Id$
9

    
10
	Copyright (C) 2004-2007 Scott Ullrich (sullrich@gmail.com)
11
	All rights reserved.
12
	Redistribution and use in source and binary forms, with or without
13
	modification, are permitted provided that the following conditions are met:
14

    
15
	1. Redistributions of source code must retain the above copyright notice,
16
	   this list of conditions and the following disclaimer.
17

    
18
	2. Redistributions in binary form must reproduce the above copyright
19
	   notice, this list of conditions and the following disclaimer in the
20
	   documentation and/or other materials provided with the distribution.
21

    
22
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
24
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
	POSSIBILITY OF SUCH DAMAGE.
32
*/
33

    
34
/****f* pfsense-utils/have_natpfruleint_access
35
 * NAME
36
 *   have_natpfruleint_access
37
 * INPUTS
38
 *	none
39
 * RESULT
40
 *   returns true if user has access to edit a specific firewall nat port forward interface
41
 ******/
42
function have_natpfruleint_access($if) {
43
	$security_url = "firewall_nat_edit.php?if=". strtolower($if);
44
	if (isAllowedPage($security_url, $allowed)) {
45
		return true;
46
	}
47
	return false;
48
}
49

    
50
/****f* pfsense-utils/have_ruleint_access
51
 * NAME
52
 *   have_ruleint_access
53
 * INPUTS
54
 *	none
55
 * RESULT
56
 *   returns true if user has access to edit a specific firewall interface
57
 ******/
58
function have_ruleint_access($if) {
59
	$security_url = "firewall_rules.php?if=". strtolower($if);
60
	if (isAllowedPage($security_url)) {
61
		return true;
62
	}
63
	return false;
64
}
65

    
66
/****f* pfsense-utils/does_url_exist
67
 * NAME
68
 *   does_url_exist
69
 * INPUTS
70
 *	none
71
 * RESULT
72
 *   returns true if a url is available
73
 ******/
74
function does_url_exist($url) {
75
	$fd = fopen("$url", "r");
76
	if ($fd) {
77
		fclose($fd);
78
		return true;
79
	} else {
80
		return false;
81
	}
82
}
83

    
84
/****f* pfsense-utils/is_private_ip
85
 * NAME
86
 *   is_private_ip
87
 * INPUTS
88
 *	none
89
 * RESULT
90
 *   returns true if an ip address is in a private range
91
 ******/
92
function is_private_ip($iptocheck) {
93
	$isprivate = false;
94
	$ip_private_list = array(
95
		"10.0.0.0/8",
96
		"100.64.0.0/10",
97
		"172.16.0.0/12",
98
		"192.168.0.0/16",
99
	);
100
	foreach ($ip_private_list as $private) {
101
		if (ip_in_subnet($iptocheck, $private) == true) {
102
			$isprivate = true;
103
		}
104
	}
105
	return $isprivate;
106
}
107

    
108
/****f* pfsense-utils/get_tmp_file
109
 * NAME
110
 *   get_tmp_file
111
 * INPUTS
112
 *	none
113
 * RESULT
114
 *   returns a temporary filename
115
 ******/
116
function get_tmp_file() {
117
	global $g;
118
	return "{$g['tmp_path']}/tmp-" . time();
119
}
120

    
121
/****f* pfsense-utils/get_dns_servers
122
 * NAME
123
 *   get_dns_servers - get system dns servers
124
 * INPUTS
125
 *   none
126
 * RESULT
127
 *   $dns_servers - an array of the dns servers
128
 ******/
129
function get_dns_servers() {
130
	$dns_servers = array();
131
	if (file_exists("/etc/resolv.conf")) {
132
		$dns_s = file("/etc/resolv.conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
133
	}
134
	if (is_array($dns_s)) {
135
		foreach ($dns_s as $dns) {
136
			$matches = "";
137
			if (preg_match("/nameserver (.*)/", $dns, $matches)) {
138
				$dns_servers[] = $matches[1];
139
			}
140
		}
141
	}
142
	return array_unique($dns_servers);
143
}
144

    
145
function hardware_offloading_applyflags($iface) {
146
	global $config;
147

    
148
	$flags_on = 0;
149
	$flags_off = 0;
150
	$options = pfSense_get_interface_addresses($iface);
151

    
152
	if (isset($config['system']['disablechecksumoffloading'])) {
153
		if (isset($options['encaps']['txcsum'])) {
154
			$flags_off |= IFCAP_TXCSUM;
155
		}
156
		if (isset($options['encaps']['rxcsum'])) {
157
			$flags_off |= IFCAP_RXCSUM;
158
		}
159
	} else {
160
		if (isset($options['caps']['txcsum'])) {
161
			$flags_on |= IFCAP_TXCSUM;
162
		}
163
		if (isset($options['caps']['rxcsum'])) {
164
			$flags_on |= IFCAP_RXCSUM;
165
		}
166
	}
167

    
168
	if (isset($config['system']['disablesegmentationoffloading'])) {
169
		$flags_off |= IFCAP_TSO;
170
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
171
		$flags_on |= IFCAP_TSO;
172
	}
173

    
174
	if (isset($config['system']['disablelargereceiveoffloading'])) {
175
		$flags_off |= IFCAP_LRO;
176
	} else if (isset($options['caps']['lro'])) {
177
		$flags_on |= IFCAP_LRO;
178
	}
179

    
180
	/* if the NIC supports polling *AND* it is enabled in the GUI */
181
	if (!isset($config['system']['polling'])) {
182
		$flags_off |= IFCAP_POLLING;
183
	} else if (isset($options['caps']['polling'])) {
184
		$flags_on |= IFCAP_POLLING;
185
	}
186

    
187
	pfSense_interface_capabilities($iface, -$flags_off);
188
	pfSense_interface_capabilities($iface, $flags_on);
189
}
190

    
191
/****f* pfsense-utils/enable_hardware_offloading
192
 * NAME
193
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
194
 * INPUTS
195
 *   $interface	- string containing the physical interface to work on.
196
 * RESULT
197
 *   null
198
 * NOTES
199
 *   This function only supports the fxp driver's loadable microcode.
200
 ******/
201
function enable_hardware_offloading($interface) {
202
	global $g, $config;
203

    
204
	$int = get_real_interface($interface);
205
	if (empty($int)) {
206
		return;
207
	}
208

    
209
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
210
		/* translate wan, lan, opt -> real interface if needed */
211
		$int_family = preg_split("/[0-9]+/", $int);
212
		$supported_ints = array('fxp');
213
		if (in_array($int_family, $supported_ints)) {
214
			if (does_interface_exist($int)) {
215
				pfSense_interface_flags($int, IFF_LINK0);
216
			}
217
		}
218
	}
219

    
220
	/* This is mostly for vlans and ppp types */
221
	$realhwif = get_parent_interface($interface);
222
	if ($realhwif[0] == $int) {
223
		hardware_offloading_applyflags($int);
224
	} else {
225
		hardware_offloading_applyflags($realhwif[0]);
226
		hardware_offloading_applyflags($int);
227
	}
228
}
229

    
230
/****f* pfsense-utils/interface_supports_polling
231
 * NAME
232
 *   checks to see if an interface supports polling according to man polling
233
 * INPUTS
234
 *
235
 * RESULT
236
 *   true or false
237
 * NOTES
238
 *
239
 ******/
240
function interface_supports_polling($iface) {
241
	$opts = pfSense_get_interface_addresses($iface);
242
	if (is_array($opts) && isset($opts['caps']['polling'])) {
243
		return true;
244
	}
245

    
246
	return false;
247
}
248

    
249
/****f* pfsense-utils/is_alias_inuse
250
 * NAME
251
 *   checks to see if an alias is currently in use by a rule
252
 * INPUTS
253
 *
254
 * RESULT
255
 *   true or false
256
 * NOTES
257
 *
258
 ******/
259
function is_alias_inuse($alias) {
260
	global $g, $config;
261

    
262
	if ($alias == "") {
263
		return false;
264
	}
265
	/* loop through firewall rules looking for alias in use */
266
	if (is_array($config['filter']['rule'])) {
267
		foreach ($config['filter']['rule'] as $rule) {
268
			if ($rule['source']['address']) {
269
				if ($rule['source']['address'] == $alias) {
270
					return true;
271
				}
272
			}
273
			if ($rule['destination']['address']) {
274
				if ($rule['destination']['address'] == $alias) {
275
					return true;
276
				}
277
			}
278
		}
279
	}
280
	/* loop through nat rules looking for alias in use */
281
	if (is_array($config['nat']['rule'])) {
282
		foreach ($config['nat']['rule'] as $rule) {
283
			if ($rule['target'] && $rule['target'] == $alias) {
284
				return true;
285
			}
286
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
287
				return true;
288
			}
289
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
290
				return true;
291
			}
292
		}
293
	}
294
	return false;
295
}
296

    
297
/****f* pfsense-utils/is_schedule_inuse
298
 * NAME
299
 *   checks to see if a schedule is currently in use by a rule
300
 * INPUTS
301
 *
302
 * RESULT
303
 *   true or false
304
 * NOTES
305
 *
306
 ******/
307
function is_schedule_inuse($schedule) {
308
	global $g, $config;
309

    
310
	if ($schedule == "") {
311
		return false;
312
	}
313
	/* loop through firewall rules looking for schedule in use */
314
	if (is_array($config['filter']['rule'])) {
315
		foreach ($config['filter']['rule'] as $rule) {
316
			if ($rule['sched'] == $schedule) {
317
				return true;
318
			}
319
		}
320
	}
321
	return false;
322
}
323

    
324
/****f* pfsense-utils/setup_polling
325
 * NAME
326
 *   sets up polling
327
 * INPUTS
328
 *
329
 * RESULT
330
 *   null
331
 * NOTES
332
 *
333
 ******/
334
function setup_polling() {
335
	global $g, $config;
336

    
337
	if (isset($config['system']['polling'])) {
338
		set_single_sysctl("kern.polling.idle_poll", "1");
339
	} else {
340
		set_single_sysctl("kern.polling.idle_poll", "0");
341
	}
342

    
343
	if ($config['system']['polling_each_burst']) {
344
		set_single_sysctl("kern.polling.each_burst", $config['system']['polling_each_burst']);
345
	}
346
	if ($config['system']['polling_burst_max']) {
347
		set_single_sysctl("kern.polling.burst_max", $config['system']['polling_burst_max']);
348
	}
349
	if ($config['system']['polling_user_frac']) {
350
		set_single_sysctl("kern.polling.user_frac", $config['system']['polling_user_frac']);
351
	}
352
}
353

    
354
/****f* pfsense-utils/setup_microcode
355
 * NAME
356
 *   enumerates all interfaces and calls enable_hardware_offloading which
357
 *   enables a NIC's supported hardware features.
358
 * INPUTS
359
 *
360
 * RESULT
361
 *   null
362
 * NOTES
363
 *   This function only supports the fxp driver's loadable microcode.
364
 ******/
365
function setup_microcode() {
366

    
367
	/* if list */
368
	$iflist = get_configured_interface_list(false, true);
369
	foreach ($iflist as $if => $ifdescr) {
370
		enable_hardware_offloading($if);
371
	}
372
	unset($iflist);
373
}
374

    
375
/****f* pfsense-utils/get_carp_status
376
 * NAME
377
 *   get_carp_status - Return whether CARP is enabled or disabled.
378
 * RESULT
379
 *   boolean	- true if CARP is enabled, false if otherwise.
380
 ******/
381
function get_carp_status() {
382
	/* grab the current status of carp */
383
	$status = get_single_sysctl('net.inet.carp.allow');
384
	return (intval($status) > 0);
385
}
386

    
387
/*
388
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
389

    
390
 */
391
function convert_ip_to_network_format($ip, $subnet) {
392
	$ipsplit = explode('.', $ip);
393
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
394
	return $string;
395
}
396

    
397
/*
398
 * get_carp_interface_status($carpinterface): returns the status of a carp ip
399
 */
400
function get_carp_interface_status($carpinterface) {
401
	global $config;
402

    
403
	foreach ($config['virtualip']['vip'] as $carp) {
404
		if ($carp['mode'] != "carp") {
405
			continue;
406
		}
407
		$carpif = "_vip{$carp['uniqid']}";
408
		if ($carpinterface !== $carpif) {
409
			continue;
410
		}
411

    
412
		$interface = get_real_interface($carp['interface']);
413
		$vhid = $carp['vhid'];
414
		$carp_query = '';
415
		$_gb = exec("/sbin/ifconfig $interface | /usr/bin/grep carp: | /usr/bin/grep \"vhid $vhid\"", $carp_query);
416
		foreach ($carp_query as $int) {
417
			if (stripos($int, "MASTER")) {
418
				return "MASTER";
419
			}
420
			if (stripos($int, "BACKUP")) {
421
				return "BACKUP";
422
			}
423
			if (stripos($int, "INIT")) {
424
				return "INIT";
425
			}
426
		}
427
		break;
428
	}
429

    
430
	return;
431
}
432

    
433
/*
434
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
435
 */
436
function get_pfsync_interface_status($pfsyncinterface) {
437
	if (!does_interface_exist($pfsyncinterface)) {
438
		return;
439
	}
440

    
441
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
442
}
443

    
444
/*
445
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
446
 */
447
function add_rule_to_anchor($anchor, $rule, $label) {
448
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
449
}
450

    
451
/*
452
 * remove_text_from_file
453
 * remove $text from file $file
454
 */
455
function remove_text_from_file($file, $text) {
456
	if (!file_exists($file) && !is_writable($file)) {
457
		return;
458
	}
459
	$filecontents = file_get_contents($file);
460
	$text = str_replace($text, "", $filecontents);
461
	@file_put_contents($file, $text);
462
}
463

    
464
/*
465
 *   after_sync_bump_adv_skew(): create skew values by 1S
466
 */
467
function after_sync_bump_adv_skew() {
468
	global $config, $g;
469
	$processed_skew = 1;
470
	$a_vip = &$config['virtualip']['vip'];
471
	foreach ($a_vip as $vipent) {
472
		if ($vipent['advskew'] <> "") {
473
			$processed_skew = 1;
474
			$vipent['advskew'] = $vipent['advskew']+1;
475
		}
476
	}
477
	if ($processed_skew == 1) {
478
		write_config(gettext("After synch increase advertising skew"));
479
	}
480
}
481

    
482
/*
483
 * get_filename_from_url($url): converts a url to its filename.
484
 */
485
function get_filename_from_url($url) {
486
	return basename($url);
487
}
488

    
489
/*
490
 *   get_dir: return an array of $dir
491
 */
492
function get_dir($dir) {
493
	$dir_array = array();
494
	$d = dir($dir);
495
	while (false !== ($entry = $d->read())) {
496
		array_push($dir_array, $entry);
497
	}
498
	$d->close();
499
	return $dir_array;
500
}
501

    
502
/****f* pfsense-utils/WakeOnLan
503
 * NAME
504
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
505
 * RESULT
506
 *   true/false - true if the operation was successful
507
 ******/
508
function WakeOnLan($addr, $mac) {
509
	$addr_byte = explode(':', $mac);
510
	$hw_addr = '';
511

    
512
	for ($a = 0; $a < 6; $a++) {
513
		$hw_addr .= chr(hexdec($addr_byte[$a]));
514
	}
515

    
516
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
517

    
518
	for ($a = 1; $a <= 16; $a++) {
519
		$msg .= $hw_addr;
520
	}
521

    
522
	// send it to the broadcast address using UDP
523
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
524
	if ($s == false) {
525
		log_error(gettext("Error creating socket!"));
526
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
527
	} else {
528
		// setting a broadcast option to socket:
529
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
530
		if ($opt_ret < 0) {
531
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
532
		}
533
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
534
		socket_close($s);
535
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to {%2$s} MAC=%3$s'), $e, $addr, $mac));
536
		return true;
537
	}
538

    
539
	return false;
540
}
541

    
542
/*
543
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
544
 *					 Useful for finding paths and stripping file extensions.
545
 */
546
function reverse_strrchr($haystack, $needle) {
547
	if (!is_string($haystack)) {
548
		return;
549
	}
550
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
551
}
552

    
553
/*
554
 *  backup_config_section($section): returns as an xml file string of
555
 *                                   the configuration section
556
 */
557
function backup_config_section($section_name) {
558
	global $config;
559
	$new_section = &$config[$section_name];
560
	/* generate configuration XML */
561
	$xmlconfig = dump_xml_config($new_section, $section_name);
562
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
563
	return $xmlconfig;
564
}
565

    
566
/*
567
 *  restore_config_section($section_name, new_contents): restore a configuration section,
568
 *                                                  and write the configuration out
569
 *                                                  to disk/cf.
570
 */
571
function restore_config_section($section_name, $new_contents) {
572
	global $config, $g;
573
	conf_mount_rw();
574
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
575
	fwrite($fout, $new_contents);
576
	fclose($fout);
577

    
578
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
579
	if ($xml['pfsense']) {
580
		$xml = $xml['pfsense'];
581
	}
582
	else if ($xml['m0n0wall']) {
583
		$xml = $xml['m0n0wall'];
584
	}
585
	if ($xml[$section_name]) {
586
		$section_xml = $xml[$section_name];
587
	} else {
588
		$section_xml = -1;
589
	}
590

    
591
	@unlink($g['tmp_path'] . "/tmpxml");
592
	if ($section_xml === -1) {
593
		return false;
594
	}
595
	$config[$section_name] = &$section_xml;
596
	if (file_exists("{$g['tmp_path']}/config.cache")) {
597
		unlink("{$g['tmp_path']}/config.cache");
598
	}
599
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
600
	disable_security_checks();
601
	conf_mount_ro();
602
	return true;
603
}
604

    
605
/*
606
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
607
 *                                                  and write the configuration out
608
 *                                                  to disk/cf.  But preserve the prior
609
 * 													structure if needed
610
 */
611
function merge_config_section($section_name, $new_contents) {
612
	global $config;
613
	conf_mount_rw();
614
	$fname = get_tmp_filename();
615
	$fout = fopen($fname, "w");
616
	fwrite($fout, $new_contents);
617
	fclose($fout);
618
	$section_xml = parse_xml_config($fname, $section_name);
619
	$config[$section_name] = $section_xml;
620
	unlink($fname);
621
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
622
	disable_security_checks();
623
	conf_mount_ro();
624
	return;
625
}
626

    
627
/*
628
 *  php_check_syntax($code_tocheck, $errormessage): checks $code_to_check for errors
629
 */
630
if (!function_exists('php_check_syntax')) {
631
	global $g;
632
	function php_check_syntax($code_to_check, &$errormessage) {
633
		return false;
634
		$fout = fopen("{$g['tmp_path']}/codetocheck.php", "w");
635
		$code = $_POST['content'];
636
		$code = str_replace("<?php", "", $code);
637
		$code = str_replace("?>", "", $code);
638
		fwrite($fout, "<?php\n\n");
639
		fwrite($fout, $code_to_check);
640
		fwrite($fout, "\n\n?>\n");
641
		fclose($fout);
642
		$command = "/usr/local/bin/php-cgi -l {$g['tmp_path']}/codetocheck.php";
643
		$output = exec_command($command);
644
		if (stristr($output, "Errors parsing") == false) {
645
			echo "false\n";
646
			$errormessage = '';
647
			return(false);
648
		} else {
649
			$errormessage = $output;
650
			return(true);
651
		}
652
	}
653
}
654

    
655
/*
656
 *  php_check_filename_syntax($filename, $errormessage): checks the file $filename for errors
657
 */
658
if (!function_exists('php_check_syntax')) {
659
	function php_check_syntax($code_to_check, &$errormessage) {
660
		return false;
661
		$command = "/usr/local/bin/php-cgi -l " . escapeshellarg($code_to_check);
662
		$output = exec_command($command);
663
		if (stristr($output, "Errors parsing") == false) {
664
			echo "false\n";
665
			$errormessage = '';
666
			return(false);
667
		} else {
668
			$errormessage = $output;
669
			return(true);
670
		}
671
	}
672
}
673

    
674
/*
675
 * rmdir_recursive($path, $follow_links=false)
676
 * Recursively remove a directory tree (rm -rf path)
677
 * This is for directories _only_
678
 */
679
function rmdir_recursive($path, $follow_links=false) {
680
	$to_do = glob($path);
681
	if (!is_array($to_do)) {
682
		$to_do = array($to_do);
683
	}
684
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
685
		if (file_exists($workingdir)) {
686
			if (is_dir($workingdir)) {
687
				$dir = opendir($workingdir);
688
				while ($entry = readdir($dir)) {
689
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
690
						unlink("$workingdir/$entry");
691
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
692
						rmdir_recursive("$workingdir/$entry");
693
					}
694
				}
695
				closedir($dir);
696
				rmdir($workingdir);
697
			} elseif (is_file($workingdir)) {
698
				unlink($workingdir);
699
			}
700
		}
701
	}
702
	return;
703
}
704

    
705
/*
706
 * host_firmware_version(): Return the versions used in this install
707
 */
708
function host_firmware_version($tocheck = "") {
709
	global $g, $config;
710

    
711
	$os_version = trim(substr(php_uname("r"), 0, strpos(php_uname("r"), '-')));
712

    
713
	return array(
714
		"firmware" => array("version" => $g['product_version']),
715
		"kernel"   => array("version" => $os_version),
716
		"base"     => array("version" => $os_version),
717
		"platform" => trim(file_get_contents('/etc/platform', " \n")),
718
		"config_version" => $config['version']
719
	);
720
}
721

    
722
function get_disk_info() {
723
	$diskout = "";
724
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
725
	return explode(' ', $diskout[0]);
726
}
727

    
728
/****f* pfsense-utils/strncpy
729
 * NAME
730
 *   strncpy - copy strings
731
 * INPUTS
732
 *   &$dst, $src, $length
733
 * RESULT
734
 *   none
735
 ******/
736
function strncpy(&$dst, $src, $length) {
737
	if (strlen($src) > $length) {
738
		$dst = substr($src, 0, $length);
739
	} else {
740
		$dst = $src;
741
	}
742
}
743

    
744
/****f* pfsense-utils/reload_interfaces_sync
745
 * NAME
746
 *   reload_interfaces - reload all interfaces
747
 * INPUTS
748
 *   none
749
 * RESULT
750
 *   none
751
 ******/
752
function reload_interfaces_sync() {
753
	global $config, $g;
754

    
755
	if ($g['debug']) {
756
		log_error(gettext("reload_interfaces_sync() is starting."));
757
	}
758

    
759
	/* parse config.xml again */
760
	$config = parse_config(true);
761

    
762
	/* enable routing */
763
	system_routing_enable();
764
	if ($g['debug']) {
765
		log_error(gettext("Enabling system routing"));
766
	}
767

    
768
	if ($g['debug']) {
769
		log_error(gettext("Cleaning up Interfaces"));
770
	}
771

    
772
	/* set up interfaces */
773
	interfaces_configure();
774
}
775

    
776
/****f* pfsense-utils/reload_all
777
 * NAME
778
 *   reload_all - triggers a reload of all settings
779
 *   * INPUTS
780
 *   none
781
 * RESULT
782
 *   none
783
 ******/
784
function reload_all() {
785
	send_event("service reload all");
786
}
787

    
788
/****f* pfsense-utils/reload_interfaces
789
 * NAME
790
 *   reload_interfaces - triggers a reload of all interfaces
791
 * INPUTS
792
 *   none
793
 * RESULT
794
 *   none
795
 ******/
796
function reload_interfaces() {
797
	send_event("interface all reload");
798
}
799

    
800
/****f* pfsense-utils/reload_all_sync
801
 * NAME
802
 *   reload_all - reload all settings
803
 *   * INPUTS
804
 *   none
805
 * RESULT
806
 *   none
807
 ******/
808
function reload_all_sync() {
809
	global $config, $g;
810

    
811
	/* parse config.xml again */
812
	$config = parse_config(true);
813

    
814
	/* set up our timezone */
815
	system_timezone_configure();
816

    
817
	/* set up our hostname */
818
	system_hostname_configure();
819

    
820
	/* make hosts file */
821
	system_hosts_generate();
822

    
823
	/* generate resolv.conf */
824
	system_resolvconf_generate();
825

    
826
	/* enable routing */
827
	system_routing_enable();
828

    
829
	/* set up interfaces */
830
	interfaces_configure();
831

    
832
	/* start dyndns service */
833
	services_dyndns_configure();
834

    
835
	/* configure cron service */
836
	configure_cron();
837

    
838
	/* start the NTP client */
839
	system_ntp_configure();
840

    
841
	/* sync pw database */
842
	conf_mount_rw();
843
	unlink_if_exists("/etc/spwd.db.tmp");
844
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
845
	conf_mount_ro();
846

    
847
	/* restart sshd */
848
	send_event("service restart sshd");
849

    
850
	/* restart webConfigurator if needed */
851
	send_event("service restart webgui");
852
}
853

    
854
function setup_serial_port($when = "save", $path = "") {
855
	global $g, $config;
856
	conf_mount_rw();
857
	$ttys_file = "{$path}/etc/ttys";
858
	$boot_config_file = "{$path}/boot.config";
859
	$loader_conf_file = "{$path}/boot/loader.conf";
860
	/* serial console - write out /boot.config */
861
	if (file_exists($boot_config_file)) {
862
		$boot_config = file_get_contents($boot_config_file);
863
	} else {
864
		$boot_config = "";
865
	}
866

    
867
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
868
	if ($g['platform'] != "cdrom") {
869
		$serial_only = false;
870

    
871
		if (($g['platform'] == "nanobsd") && isset($g['enableserial_force'])) {
872
			$serial_only = true;
873
		} else {
874
			$specific_platform = system_identify_specific_platform();
875
			if ($specific_platform['name'] == 'RCC-VE' ||
876
			    $specific_platform['name'] == 'RCC-DFF') {
877
				$serial_only = true;
878
			}
879
		}
880

    
881
		$boot_config_split = explode("\n", $boot_config);
882
		$fd = fopen($boot_config_file, "w");
883
		if ($fd) {
884
			foreach ($boot_config_split as $bcs) {
885
				if (stristr($bcs, "-D") || stristr($bcs, "-h")) {
886
					/* DONT WRITE OUT, WE'LL DO IT LATER */
887
				} else {
888
					if ($bcs <> "") {
889
						fwrite($fd, "{$bcs}\n");
890
					}
891
				}
892
			}
893
			if ($serial_only === true) {
894
				fwrite($fd, "-S{$serialspeed} -h");
895
			} else if (is_serial_enabled()) {
896
				fwrite($fd, "-S{$serialspeed} -D");
897
			}
898
			fclose($fd);
899
		}
900

    
901
		/* serial console - write out /boot/loader.conf */
902
		if ($when == "upgrade") {
903
			system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
904
		}
905
		$boot_config = file_get_contents($loader_conf_file);
906
		$boot_config_split = explode("\n", $boot_config);
907
		if (count($boot_config_split) > 0) {
908
			$new_boot_config = array();
909
			// Loop through and only add lines that are not empty, and which
910
			//  do not contain a console directive.
911
			foreach ($boot_config_split as $bcs) {
912
				if (!empty($bcs) &&
913
				    (stripos($bcs, "console") === false) &&
914
				    (stripos($bcs, "boot_multicons") === false) &&
915
				    (stripos($bcs, "boot_serial") === false) &&
916
				    (stripos($bcs, "hw.usb.no_pf") === false) &&
917
				    (stripos($bcs, "hint.uart.0.flags") === false) &&
918
				    (stripos($bcs, "hint.uart.1.flags") === false)) {
919
					$new_boot_config[] = $bcs;
920
				}
921
			}
922

    
923
			if ($serial_only === true) {
924
				$new_boot_config[] = 'boot_serial="YES"';
925
				$new_boot_config[] = 'console="comconsole"';
926
			} else if (is_serial_enabled()) {
927
				$new_boot_config[] = 'boot_multicons="YES"';
928
				$new_boot_config[] = 'boot_serial="YES"';
929
				$primaryconsole = isset($g['primaryconsole_force']) ? $g['primaryconsole_force'] : $config['system']['primaryconsole'];
930
				switch ($primaryconsole) {
931
					case "video":
932
						$new_boot_config[] = 'console="vidconsole,comconsole"';
933
						break;
934
					case "serial":
935
					default:
936
						$new_boot_config[] = 'console="comconsole,vidconsole"';
937
				}
938
			}
939
			$new_boot_config[] = 'comconsole_speed="' . $serialspeed . '"';
940

    
941
			$specplatform = system_identify_specific_platform();
942
			if ($specplatform['name'] == 'RCC-VE' ||
943
			    $specplatform['name'] == 'RCC-DFF') {
944
				$new_boot_config[] = 'comconsole_port="0x2F8"';
945
				$new_boot_config[] = 'hint.uart.0.flags="0x00"';
946
				$new_boot_config[] = 'hint.uart.1.flags="0x10"';
947
			}
948
			$new_boot_config[] = 'hw.usb.no_pf="1"';
949

    
950
			file_put_contents($loader_conf_file, implode("\n", $new_boot_config) . "\n");
951
		}
952
	}
953
	$ttys = file_get_contents($ttys_file);
954
	$ttys_split = explode("\n", $ttys);
955
	$fd = fopen($ttys_file, "w");
956

    
957
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
958

    
959
	if (isset($config['system']['disableconsolemenu'])) {
960
		$console_type = 'Pc';
961
		$serial_type = 'std.' . $serialspeed;
962
	} else {
963
		$console_type = 'al.Pc';
964
		$serial_type = 'al.' . $serialspeed;
965
	}
966
	foreach ($ttys_split as $tty) {
967
		if (stristr($tty, "ttyv0")) {
968
			fwrite($fd, "ttyv0	\"/usr/libexec/getty {$console_type}\"	cons25	on	secure\n");
969
		} else if (stristr($tty, "ttyu")) {
970
			$ttyn = substr($tty, 0, 5);
971
			fwrite($fd, "{$ttyn}	\"/usr/libexec/getty {$serial_type}\"	cons25	{$on_off}	secure\n");
972
		} else {
973
			fwrite($fd, $tty . "\n");
974
		}
975
	}
976
	unset($on_off, $console_type, $serial_type);
977
	fclose($fd);
978
	if ($when != "upgrade") {
979
		reload_ttys();
980
	}
981

    
982
	conf_mount_ro();
983
	return;
984
}
985

    
986
function is_serial_enabled() {
987
	global $g, $config;
988

    
989
	if (!isset($g['enableserial_force']) &&
990
	    !isset($config['system']['enableserial']) &&
991
	    ($g['platform'] == $g['product_name'] || $g['platform'] == "cdrom")) {
992
		return false;
993
	}
994

    
995
	return true;
996
}
997

    
998
function reload_ttys() {
999
	// Send a HUP signal to init will make it reload /etc/ttys
1000
	posix_kill(1, SIGHUP);
1001
}
1002

    
1003
function print_value_list($list, $count = 10, $separator = ",") {
1004
	$list = implode($separator, array_slice($list, 0, $count));
1005
	if (count($list) < $count) {
1006
		$list .= ".";
1007
	} else {
1008
		$list .= "...";
1009
	}
1010
	return $list;
1011
}
1012

    
1013
/* DHCP enabled on any interfaces? */
1014
function is_dhcp_server_enabled() {
1015
	global $config;
1016

    
1017
	if (!is_array($config['dhcpd'])) {
1018
		return false;
1019
	}
1020

    
1021
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1022
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1023
			return true;
1024
		}
1025
	}
1026

    
1027
	return false;
1028
}
1029

    
1030
/* DHCP enabled on any interfaces? */
1031
function is_dhcpv6_server_enabled() {
1032
	global $config;
1033

    
1034
	if (is_array($config['interfaces'])) {
1035
		foreach ($config['interfaces'] as $ifcfg) {
1036
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1037
				return true;
1038
			}
1039
		}
1040
	}
1041

    
1042
	if (!is_array($config['dhcpdv6'])) {
1043
		return false;
1044
	}
1045

    
1046
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1047
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1048
			return true;
1049
		}
1050
	}
1051

    
1052
	return false;
1053
}
1054

    
1055
/* radvd enabled on any interfaces? */
1056
function is_radvd_enabled() {
1057
	global $config;
1058

    
1059
	if (!is_array($config['dhcpdv6'])) {
1060
		$config['dhcpdv6'] = array();
1061
	}
1062

    
1063
	$dhcpdv6cfg = $config['dhcpdv6'];
1064
	$Iflist = get_configured_interface_list();
1065

    
1066
	/* handle manually configured DHCP6 server settings first */
1067
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1068
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1069
			continue;
1070
		}
1071

    
1072
		if (!isset($dhcpv6ifconf['ramode'])) {
1073
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1074
		}
1075

    
1076
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1077
			continue;
1078
		}
1079

    
1080
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1081
		if (!is_ipaddrv6($ifcfgipv6)) {
1082
			continue;
1083
		}
1084

    
1085
		return true;
1086
	}
1087

    
1088
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1089
	foreach ($Iflist as $if => $ifdescr) {
1090
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1091
			continue;
1092
		}
1093
		if (!isset($config['interfaces'][$if]['enable'])) {
1094
			continue;
1095
		}
1096

    
1097
		$ifcfgipv6 = get_interface_ipv6($if);
1098
		if (!is_ipaddrv6($ifcfgipv6)) {
1099
			continue;
1100
		}
1101

    
1102
		$ifcfgsnv6 = get_interface_subnetv6($if);
1103
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1104

    
1105
		if (!is_ipaddrv6($subnetv6)) {
1106
			continue;
1107
		}
1108

    
1109
		return true;
1110
	}
1111

    
1112
	return false;
1113
}
1114

    
1115
/* Any PPPoE servers enabled? */
1116
function is_pppoe_server_enabled() {
1117
	global $config;
1118

    
1119
	$pppoeenable = false;
1120

    
1121
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1122
		return false;
1123
	}
1124

    
1125
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1126
		if ($pppoes['mode'] == 'server') {
1127
			$pppoeenable = true;
1128
		}
1129
	}
1130

    
1131
	return $pppoeenable;
1132
}
1133

    
1134
function convert_seconds_to_hms($sec) {
1135
	$min = $hrs = 0;
1136
	if ($sec != 0) {
1137
		$min = floor($sec/60);
1138
		$sec %= 60;
1139
	}
1140
	if ($min != 0) {
1141
		$hrs = floor($min/60);
1142
		$min %= 60;
1143
	}
1144
	if ($sec < 10) {
1145
		$sec = "0".$sec;
1146
	}
1147
	if ($min < 10) {
1148
		$min = "0".$min;
1149
	}
1150
	if ($hrs < 10) {
1151
		$hrs = "0".$hrs;
1152
	}
1153
	$result = $hrs.":".$min.":".$sec;
1154
	return $result;
1155
}
1156

    
1157
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1158

    
1159
function get_ppp_uptime($port) {
1160
	if (file_exists("/conf/{$port}.log")) {
1161
		$saved_time = file_get_contents("/conf/{$port}.log");
1162
		$uptime_data = explode("\n", $saved_time);
1163
		$sec = 0;
1164
		foreach ($uptime_data as $upt) {
1165
			$sec += substr($upt, 1 + strpos($upt, " "));
1166
		}
1167
		return convert_seconds_to_hms($sec);
1168
	} else {
1169
		$total_time = gettext("No history data found!");
1170
		return $total_time;
1171
	}
1172
}
1173

    
1174
//returns interface information
1175
function get_interface_info($ifdescr) {
1176
	global $config, $g;
1177

    
1178
	$ifinfo = array();
1179
	if (empty($config['interfaces'][$ifdescr])) {
1180
		return;
1181
	}
1182
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1183
	$ifinfo['if'] = get_real_interface($ifdescr);
1184

    
1185
	$chkif = $ifinfo['if'];
1186
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1187
	$ifinfo['status'] = $ifinfotmp['status'];
1188
	if (empty($ifinfo['status'])) {
1189
		$ifinfo['status'] = "down";
1190
	}
1191
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1192
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1193
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1194
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1195
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1196
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1197
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1198
	if (isset($ifinfotmp['link0'])) {
1199
		$link0 = "down";
1200
	}
1201
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1202
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1203
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1204
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1205
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1206
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1207

    
1208
	/* Use pfctl for non wrapping 64 bit counters */
1209
	/* Pass */
1210
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1211
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1212
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1213
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1214
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1215
	$in4_pass = $pf_in4_pass[5];
1216
	$out4_pass = $pf_out4_pass[5];
1217
	$in4_pass_packets = $pf_in4_pass[3];
1218
	$out4_pass_packets = $pf_out4_pass[3];
1219
	$in6_pass = $pf_in6_pass[5];
1220
	$out6_pass = $pf_out6_pass[5];
1221
	$in6_pass_packets = $pf_in6_pass[3];
1222
	$out6_pass_packets = $pf_out6_pass[3];
1223
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1224
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1225
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1226
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1227

    
1228
	/* Block */
1229
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1230
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1231
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1232
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1233
	$in4_block = $pf_in4_block[5];
1234
	$out4_block = $pf_out4_block[5];
1235
	$in4_block_packets = $pf_in4_block[3];
1236
	$out4_block_packets = $pf_out4_block[3];
1237
	$in6_block = $pf_in6_block[5];
1238
	$out6_block = $pf_out6_block[5];
1239
	$in6_block_packets = $pf_in6_block[3];
1240
	$out6_block_packets = $pf_out6_block[3];
1241
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1242
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1243
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1244
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1245

    
1246
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1247
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1248
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1249
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1250

    
1251
	$ifconfiginfo = "";
1252
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1253
	switch ($link_type) {
1254
		/* DHCP? -> see if dhclient is up */
1255
		case "dhcp":
1256
			/* see if dhclient is up */
1257
			if (find_dhclient_process($ifinfo['if']) != 0) {
1258
				$ifinfo['dhcplink'] = "up";
1259
			} else {
1260
				$ifinfo['dhcplink'] = "down";
1261
			}
1262

    
1263
			break;
1264
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1265
		case "pppoe":
1266
		case "pptp":
1267
		case "l2tp":
1268
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1269
				/* get PPPoE link status for dial on demand */
1270
				$ifinfo["{$link_type}link"] = "up";
1271
			} else {
1272
				$ifinfo["{$link_type}link"] = "down";
1273
			}
1274

    
1275
			break;
1276
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1277
		case "ppp":
1278
			if ($ifinfo['status'] == "up") {
1279
				$ifinfo['ppplink'] = "up";
1280
			} else {
1281
				$ifinfo['ppplink'] = "down" ;
1282
			}
1283

    
1284
			if (empty($ifinfo['status'])) {
1285
				$ifinfo['status'] = "down";
1286
			}
1287

    
1288
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1289
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1290
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1291
						break;
1292
					}
1293
				}
1294
			}
1295
			$dev = $ppp['ports'];
1296
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1297
				break;
1298
			}
1299
			if (!file_exists($dev)) {
1300
				$ifinfo['nodevice'] = 1;
1301
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1302
			}
1303

    
1304
			$usbmodemoutput = array();
1305
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1306
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1307
			if (file_exists($mondev)) {
1308
				$cellstats = file($mondev);
1309
				/* skip header */
1310
				$a_cellstats = explode(",", $cellstats[1]);
1311
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1312
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1313
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1314
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1315
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1316
				}
1317
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1318
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1319
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1320
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1321
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1322
				}
1323
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1324
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1325
				$ifinfo['cell_sent'] = $a_cellstats[6];
1326
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1327
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1328
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1329
			}
1330
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1331
			if (isset($ppp['uptime'])) {
1332
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1333
			}
1334
			break;
1335
		default:
1336
			break;
1337
	}
1338

    
1339
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1340
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1341
		$ifinfo['ppp_uptime'] = convert_seconds_to_hms($sec);
1342
	}
1343

    
1344
	if ($ifinfo['status'] == "up") {
1345
		/* try to determine media with ifconfig */
1346
		unset($ifconfiginfo);
1347
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1348
		$wifconfiginfo = array();
1349
		if (is_interface_wireless($ifdescr)) {
1350
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1351
			array_shift($wifconfiginfo);
1352
		}
1353
		$matches = "";
1354
		foreach ($ifconfiginfo as $ici) {
1355

    
1356
			/* don't list media/speed for wireless cards, as it always
1357
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1358
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1359
				$ifinfo['media'] = $matches[1];
1360
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1361
				$ifinfo['media'] = $matches[1];
1362
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1363
				$ifinfo['media'] = $matches[1];
1364
			}
1365

    
1366
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1367
				if ($matches[1] != "active") {
1368
					$ifinfo['status'] = $matches[1];
1369
				}
1370
				if ($ifinfo['status'] == gettext("running")) {
1371
					$ifinfo['status'] = gettext("up");
1372
				}
1373
			}
1374
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1375
				$ifinfo['channel'] = $matches[1];
1376
			}
1377
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1378
				if ($matches[1][0] == '"') {
1379
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1380
				}
1381
				else {
1382
					$ifinfo['ssid'] = $matches[1];
1383
				}
1384
			}
1385
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1386
				$ifinfo['laggproto'] = $matches[1];
1387
			}
1388
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1389
				$ifinfo['laggport'][] = $matches[1];
1390
			}
1391
		}
1392
		foreach ($wifconfiginfo as $ici) {
1393
			$elements = preg_split("/[ ]+/i", $ici);
1394
			if ($elements[0] != "") {
1395
				$ifinfo['bssid'] = $elements[0];
1396
			}
1397
			if ($elements[3] != "") {
1398
				$ifinfo['rate'] = $elements[3];
1399
			}
1400
			if ($elements[4] != "") {
1401
				$ifinfo['rssi'] = $elements[4];
1402
			}
1403
		}
1404
		/* lookup the gateway */
1405
		if (interface_has_gateway($ifdescr)) {
1406
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1407
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1408
		}
1409
	}
1410

    
1411
	$bridge = "";
1412
	$bridge = link_interface_to_bridge($ifdescr);
1413
	if ($bridge) {
1414
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1415
		if (stristr($bridge_text, "blocking") <> false) {
1416
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1417
			$ifinfo['bridgeint'] = $bridge;
1418
		} else if (stristr($bridge_text, "learning") <> false) {
1419
			$ifinfo['bridge'] = gettext("learning");
1420
			$ifinfo['bridgeint'] = $bridge;
1421
		} else if (stristr($bridge_text, "forwarding") <> false) {
1422
			$ifinfo['bridge'] = gettext("forwarding");
1423
			$ifinfo['bridgeint'] = $bridge;
1424
		}
1425
	}
1426

    
1427
	return $ifinfo;
1428
}
1429

    
1430
//returns cpu speed of processor. Good for determining capabilities of machine
1431
function get_cpu_speed() {
1432
	return get_single_sysctl("hw.clockrate");
1433
}
1434

    
1435
function get_uptime_sec() {
1436
	$boottime = "";
1437
	$matches = "";
1438
	$boottime = get_single_sysctl("kern.boottime");
1439
	preg_match("/sec = (\d+)/", $boottime, $matches);
1440
	$boottime = $matches[1];
1441
	if (intval($boottime) == 0) {
1442
		return 0;
1443
	}
1444

    
1445
	$uptime = time() - $boottime;
1446
	return $uptime;
1447
}
1448

    
1449
function add_hostname_to_watch($hostname) {
1450
	if (!is_dir("/var/db/dnscache")) {
1451
		mkdir("/var/db/dnscache");
1452
	}
1453
	$result = array();
1454
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1455
		$domrecords = array();
1456
		$domips = array();
1457
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1458
		if ($rethost == 0) {
1459
			foreach ($domrecords as $domr) {
1460
				$doml = explode(" ", $domr);
1461
				$domip = $doml[3];
1462
				/* fill array with domain ip addresses */
1463
				if (is_ipaddr($domip)) {
1464
					$domips[] = $domip;
1465
				}
1466
			}
1467
		}
1468
		sort($domips);
1469
		$contents = "";
1470
		if (!empty($domips)) {
1471
			foreach ($domips as $ip) {
1472
				$contents .= "$ip\n";
1473
			}
1474
		}
1475
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1476
		/* Remove empty elements */
1477
		$result = array_filter(explode("\n", $contents), 'strlen');
1478
	}
1479
	return $result;
1480
}
1481

    
1482
function is_fqdn($fqdn) {
1483
	$hostname = false;
1484
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1485
		$hostname = true;
1486
	}
1487
	if (preg_match("/\.\./", $fqdn)) {
1488
		$hostname = false;
1489
	}
1490
	if (preg_match("/^\./i", $fqdn)) {
1491
		$hostname = false;
1492
	}
1493
	if (preg_match("/\//i", $fqdn)) {
1494
		$hostname = false;
1495
	}
1496
	return($hostname);
1497
}
1498

    
1499
function pfsense_default_state_size() {
1500
	/* get system memory amount */
1501
	$memory = get_memory();
1502
	$physmem = $memory[0];
1503
	/* Be cautious and only allocate 10% of system memory to the state table */
1504
	$max_states = (int) ($physmem/10)*1000;
1505
	return $max_states;
1506
}
1507

    
1508
function pfsense_default_tables_size() {
1509
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1510
	return $current;
1511
}
1512

    
1513
function pfsense_default_table_entries_size() {
1514
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1515
	return (trim($current));
1516
}
1517

    
1518
/* Compare the current hostname DNS to the DNS cache we made
1519
 * if it has changed we return the old records
1520
 * if no change we return false */
1521
function compare_hostname_to_dnscache($hostname) {
1522
	if (!is_dir("/var/db/dnscache")) {
1523
		mkdir("/var/db/dnscache");
1524
	}
1525
	$hostname = trim($hostname);
1526
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1527
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1528
	} else {
1529
		$oldcontents = "";
1530
	}
1531
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1532
		$domrecords = array();
1533
		$domips = array();
1534
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1535
		if ($rethost == 0) {
1536
			foreach ($domrecords as $domr) {
1537
				$doml = explode(" ", $domr);
1538
				$domip = $doml[3];
1539
				/* fill array with domain ip addresses */
1540
				if (is_ipaddr($domip)) {
1541
					$domips[] = $domip;
1542
				}
1543
			}
1544
		}
1545
		sort($domips);
1546
		$contents = "";
1547
		if (!empty($domips)) {
1548
			foreach ($domips as $ip) {
1549
				$contents .= "$ip\n";
1550
			}
1551
		}
1552
	}
1553

    
1554
	if (trim($oldcontents) != trim($contents)) {
1555
		if ($g['debug']) {
1556
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1557
		}
1558
		return ($oldcontents);
1559
	} else {
1560
		return false;
1561
	}
1562
}
1563

    
1564
/*
1565
 * load_crypto() - Load crypto modules if enabled in config.
1566
 */
1567
function load_crypto() {
1568
	global $config, $g;
1569
	$crypto_modules = array('glxsb', 'aesni');
1570

    
1571
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1572
		return false;
1573
	}
1574

    
1575
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1576
		log_error("Loading {$config['system']['crypto_hardware']} cryptographic accelerator module.");
1577
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1578
	}
1579
}
1580

    
1581
/*
1582
 * load_thermal_hardware() - Load temperature monitor kernel module
1583
 */
1584
function load_thermal_hardware() {
1585
	global $config, $g;
1586
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1587

    
1588
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1589
		return false;
1590
	}
1591

    
1592
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1593
		log_error("Loading {$config['system']['thermal_hardware']} thermal monitor module.");
1594
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1595
	}
1596
}
1597

    
1598
/****f* pfsense-utils/isvm
1599
 * NAME
1600
 *   isvm
1601
 * INPUTS
1602
 *	none
1603
 * RESULT
1604
 *   returns true if machine is running under a virtual environment
1605
 ******/
1606
function isvm() {
1607
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1608
	$_gb = exec('/bin/kenv smbios.system.product 2>/dev/null', $output, $rc);
1609

    
1610
	if ($rc != 0 || !isset($output[0])) {
1611
		return false;
1612
	}
1613

    
1614
	foreach ($virtualenvs as $virtualenv) {
1615
		if (stripos($output[0], $virtualenv) !== false) {
1616
			return true;
1617
		}
1618
	}
1619

    
1620
	return false;
1621
}
1622

    
1623
function get_freebsd_version() {
1624
	$version = explode(".", php_uname("r"));
1625
	return $version[0];
1626
}
1627

    
1628
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1629
	global $config, $g;
1630

    
1631
	$fp = fopen($destination, "wb");
1632

    
1633
	if (!$fp) {
1634
		return false;
1635
	}
1636

    
1637
	$ch = curl_init();
1638
	curl_setopt($ch, CURLOPT_URL, $url);
1639
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1640
	curl_setopt($ch, CURLOPT_FILE, $fp);
1641
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1642
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1643
	curl_setopt($ch, CURLOPT_HEADER, false);
1644
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1645
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1646
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1647
	} else {
1648
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1649
	}
1650

    
1651
	if (!empty($config['system']['proxyurl'])) {
1652
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1653
		if (!empty($config['system']['proxyport'])) {
1654
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1655
		}
1656
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1657
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1658
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1659
		}
1660
	}
1661

    
1662
	@curl_exec($ch);
1663
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1664
	fclose($fp);
1665
	curl_close($ch);
1666
	return ($http_code == 200) ? true : $http_code;
1667
}
1668

    
1669
function download_file_with_progress_bar($url_file, $destination_file, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1670
	global $config, $g;
1671
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1672
	$file_size = 1;
1673
	$downloaded = 1;
1674
	$first_progress_update = TRUE;
1675
	/* open destination file */
1676
	$fout = fopen($destination_file, "wb");
1677

    
1678
	/*
1679
	 *      Originally by Author: Keyvan Minoukadeh
1680
	 *      Modified by Scott Ullrich to return Content-Length size
1681
	 */
1682

    
1683
	$ch = curl_init();
1684
	curl_setopt($ch, CURLOPT_URL, $url_file);
1685
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
1686
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1687
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
1688
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1689
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1690
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1691
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1692
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1693
	} else {
1694
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1695
	}
1696

    
1697
	if (!empty($config['system']['proxyurl'])) {
1698
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1699
		if (!empty($config['system']['proxyport'])) {
1700
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1701
		}
1702
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1703
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1704
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1705
		}
1706
	}
1707

    
1708
	@curl_exec($ch);
1709
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1710
	if ($fout) {
1711
		fclose($fout);
1712
	}
1713
	curl_close($ch);
1714
	return ($http_code == 200) ? true : $http_code;
1715
}
1716

    
1717
function read_header($ch, $string) {
1718
	global $file_size, $fout;
1719
	$length = strlen($string);
1720
	$regs = "";
1721
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
1722
	if ($regs[2] <> "") {
1723
		$file_size = intval($regs[2]);
1724
	}
1725
	ob_flush();
1726
	return $length;
1727
}
1728

    
1729
function read_body($ch, $string) {
1730
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
1731
	global $pkg_interface;
1732
	$length = strlen($string);
1733
	$downloaded += intval($length);
1734
	if ($file_size > 0) {
1735
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
1736
		$downloadProgress = 100 - $downloadProgress;
1737
	} else {
1738
		$downloadProgress = 0;
1739
	}
1740
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
1741
		if ($sendto == "status") {
1742
			if ($pkg_interface == "console") {
1743
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
1744
					$tostatus = $static_status . $downloadProgress . "%";
1745
					if ($downloadProgress == 100) {
1746
						$tostatus = $tostatus . "\r";
1747
					}
1748
					update_status($tostatus);
1749
				}
1750
			} else {
1751
				$tostatus = $static_status . $downloadProgress . "%";
1752
				update_status($tostatus);
1753
			}
1754
		} else {
1755
			if ($pkg_interface == "console") {
1756
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
1757
					$tooutput = $static_output . $downloadProgress . "%";
1758
					if ($downloadProgress == 100) {
1759
						$tooutput = $tooutput . "\r";
1760
					}
1761
					update_output_window($tooutput);
1762
				}
1763
			} else {
1764
				$tooutput = $static_output . $downloadProgress . "%";
1765
				update_output_window($tooutput);
1766
			}
1767
		}
1768
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
1769
			update_progress_bar($downloadProgress, $first_progress_update);
1770
			$first_progress_update = FALSE;
1771
		}
1772
		$lastseen = $downloadProgress;
1773
	}
1774
	if ($fout) {
1775
		fwrite($fout, $string);
1776
	}
1777
	ob_flush();
1778
	return $length;
1779
}
1780

    
1781
/*
1782
 *   update_output_window: update bottom textarea dynamically.
1783
 */
1784
function update_output_window($text) {
1785
	global $pkg_interface;
1786
	$log = preg_replace("/\n/", "\\n", $text);
1787
	if ($pkg_interface != "console") {
1788
?>
1789
<script type="text/javascript">
1790
//<![CDATA[
1791
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
1792
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
1793
//]]>
1794
</script>
1795
<?php
1796
	}
1797
	/* ensure that contents are written out */
1798
	ob_flush();
1799
}
1800

    
1801
/*
1802
 *   update_status: update top textarea dynamically.
1803
 */
1804
function update_status($status) {
1805
	global $pkg_interface;
1806

    
1807
	if ($pkg_interface == "console") {
1808
		print ("{$status}");
1809
	}
1810

    
1811
	/* ensure that contents are written out */
1812
	ob_flush();
1813
}
1814

    
1815
/*
1816
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
1817
 */
1818
function update_progress_bar($percent, $first_time) {
1819
	global $pkg_interface;
1820
	if ($percent > 100) {
1821
		$percent = 1;
1822
	}
1823
	if ($pkg_interface <> "console") {
1824
		echo '<script type="text/javascript">';
1825
		echo "\n//<![CDATA[\n";
1826
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
1827
		echo "\n//]]>\n";
1828
		echo '</script>';
1829
	} else {
1830
		if (!($first_time)) {
1831
			echo "\x08\x08\x08\x08\x08";
1832
		}
1833
		echo sprintf("%4d%%", $percent);
1834
	}
1835
}
1836

    
1837
/* Split() is being DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 6.0.0. Relying on this feature is highly discouraged. */
1838
if (!function_exists("split")) {
1839
	function split($separator, $haystack, $limit = null) {
1840
		log_error("deprecated split() call with separator '{$separator}'");
1841
		return preg_split($separator, $haystack, $limit);
1842
	}
1843
}
1844

    
1845
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
1846
	global $g, $config, $pconfig, $debug;
1847
	if (!$origname) {
1848
		return;
1849
	}
1850

    
1851
	$sectionref = &$config;
1852
	foreach ($section as $sectionname) {
1853
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
1854
			$sectionref = &$sectionref[$sectionname];
1855
		} else {
1856
			return;
1857
		}
1858
	}
1859

    
1860
	if ($debug) {
1861
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
1862
		fwrite($fd, print_r($pconfig, true));
1863
	}
1864

    
1865
	if (is_array($sectionref)) {
1866
		foreach ($sectionref as $itemkey => $item) {
1867
			if ($debug) {
1868
				fwrite($fd, "$itemkey\n");
1869
			}
1870

    
1871
			$fieldfound = true;
1872
			$fieldref = &$sectionref[$itemkey];
1873
			foreach ($field as $fieldname) {
1874
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
1875
					$fieldref = &$fieldref[$fieldname];
1876
				} else {
1877
					$fieldfound = false;
1878
					break;
1879
				}
1880
			}
1881
			if ($fieldfound && $fieldref == $origname) {
1882
				if ($debug) {
1883
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
1884
				}
1885
				$fieldref = $new_alias_name;
1886
			}
1887
		}
1888
	}
1889

    
1890
	if ($debug) {
1891
		fclose($fd);
1892
	}
1893

    
1894
}
1895

    
1896
function parse_aliases_file($filename, $type = "url", $max_items = -1) {
1897
	/*
1898
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
1899
	 * $type = if set to 'url' then subnets and ips will be returned,
1900
	 *         if set to 'url_ports' port-ranges and ports will be returned
1901
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
1902
	 *
1903
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
1904
	 */
1905

    
1906
	$fd = @fopen($filename, 'r');
1907
	if (!$fd) {
1908
		log_error(gettext("Could not process aliases from alias: {$alias_url}"));
1909
		return null;
1910
	}
1911
	$items = array();
1912
	/* NOTE: fgetss() is not a typo RTFM before being smart */
1913
	while (($fc = fgetss($fd)) !== FALSE) {
1914
		$tmp = trim($fc, " \t\n\r");
1915
		if (empty($tmp)) {
1916
			continue;
1917
		}
1918
		$tmp_str = strstr($tmp, '#', true);
1919
		if (!empty($tmp_str)) {
1920
			$tmp = $tmp_str;
1921
		}
1922
		$tmp_str = strstr($tmp, ' ', true);
1923
		if (!empty($tmp_str)) {
1924
			$tmp = $tmp_str;
1925
		}
1926
		$valid = ($type == "url" && (is_ipaddr($tmp) || is_subnet($tmp))) ||
1927
			 ($type == "url_ports" && (is_port($tmp) || is_portrange($tmp)));
1928
		if ($valid) {
1929
			$items[] = $tmp;
1930
			if (count($items) == $max_items) {
1931
				break;
1932
			}
1933
		}
1934
	}
1935
	fclose($fd);
1936
	return $items;
1937
}
1938

    
1939
function update_alias_url_data() {
1940
	global $config, $g;
1941

    
1942
	$updated = false;
1943

    
1944
	/* item is a url type */
1945
	$lockkey = lock('aliasurl');
1946
	if (is_array($config['aliases']['alias'])) {
1947
		foreach ($config['aliases']['alias'] as $x => $alias) {
1948
			if (empty($alias['aliasurl'])) {
1949
				continue;
1950
			}
1951

    
1952
			$address = null;
1953
			foreach ($alias['aliasurl'] as $alias_url) {
1954
				/* fetch down and add in */
1955
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
1956
				unlink($temp_filename);
1957
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
1958
				mkdir($temp_filename);
1959
				download_file($alias_url, $temp_filename . "/aliases", $verify_ssl);
1960

    
1961
				/* if the item is tar gzipped then extract */
1962
				if (stripos($alias_url, '.tgz')) {
1963
					if (!process_alias_tgz($temp_filename)) {
1964
						continue;
1965
					}
1966
				} else if (stripos($alias_url, '.zip')) {
1967
					if (!process_alias_unzip($temp_filename)) {
1968
						continue;
1969
					}
1970
				}
1971
				if (file_exists("{$temp_filename}/aliases")) {
1972
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 3000);
1973
					mwexec("/bin/rm -rf {$temp_filename}");
1974
				}
1975
			}
1976
			if ($address != null) {
1977
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
1978
				$updated = true;
1979
			}
1980
		}
1981
	}
1982
	unlock($lockkey);
1983

    
1984
	/* Report status to callers as well */
1985
	return $updated;
1986
}
1987

    
1988
function process_alias_unzip($temp_filename) {
1989
	if (!file_exists("/usr/local/bin/unzip")) {
1990
		log_error(gettext("Alias archive is a .zip file which cannot be decompressed because utility is missing!"));
1991
		return false;
1992
	}
1993
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.zip");
1994
	mwexec("/usr/local/bin/unzip {$temp_filename}/aliases.tgz -d {$temp_filename}/aliases/");
1995
	unlink("{$temp_filename}/aliases.zip");
1996
	$files_to_process = return_dir_as_array("{$temp_filename}/");
1997
	/* foreach through all extracted files and build up aliases file */
1998
	$fd = @fopen("{$temp_filename}/aliases", "w");
1999
	if (!$fd) {
2000
		log_error(gettext("Could not open {$temp_filename}/aliases for writing!"));
2001
		return false;
2002
	}
2003
	foreach ($files_to_process as $f2p) {
2004
		$tmpfd = @fopen($f2p, 'r');
2005
		if (!$tmpfd) {
2006
			log_error(gettext("The following file could not be read {$f2p} from {$temp_filename}"));
2007
			continue;
2008
		}
2009
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2010
			fwrite($fd, $tmpbuf);
2011
		}
2012
		fclose($tmpfd);
2013
		unlink($f2p);
2014
	}
2015
	fclose($fd);
2016
	unset($tmpbuf);
2017

    
2018
	return true;
2019
}
2020

    
2021
function process_alias_tgz($temp_filename) {
2022
	if (!file_exists('/usr/bin/tar')) {
2023
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2024
		return false;
2025
	}
2026
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2027
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2028
	unlink("{$temp_filename}/aliases.tgz");
2029
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2030
	/* foreach through all extracted files and build up aliases file */
2031
	$fd = @fopen("{$temp_filename}/aliases", "w");
2032
	if (!$fd) {
2033
		log_error(gettext("Could not open {$temp_filename}/aliases for writing!"));
2034
		return false;
2035
	}
2036
	foreach ($files_to_process as $f2p) {
2037
		$tmpfd = @fopen($f2p, 'r');
2038
		if (!$tmpfd) {
2039
			log_error(gettext("The following file could not be read {$f2p} from {$temp_filename}"));
2040
			continue;
2041
		}
2042
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2043
			fwrite($fd, $tmpbuf);
2044
		}
2045
		fclose($tmpfd);
2046
		unlink($f2p);
2047
	}
2048
	fclose($fd);
2049
	unset($tmpbuf);
2050

    
2051
	return true;
2052
}
2053

    
2054
function version_compare_dates($a, $b) {
2055
	$a_time = strtotime($a);
2056
	$b_time = strtotime($b);
2057

    
2058
	if ((!$a_time) || (!$b_time)) {
2059
		return FALSE;
2060
	} else {
2061
		if ($a_time < $b_time) {
2062
			return -1;
2063
		} elseif ($a_time == $b_time) {
2064
			return 0;
2065
		} else {
2066
			return 1;
2067
		}
2068
	}
2069
}
2070
function version_get_string_value($a) {
2071
	$strs = array(
2072
		0 => "ALPHA-ALPHA",
2073
		2 => "ALPHA",
2074
		3 => "BETA",
2075
		4 => "B",
2076
		5 => "C",
2077
		6 => "D",
2078
		7 => "RC",
2079
		8 => "RELEASE",
2080
		9 => "*"			// Matches all release levels
2081
	);
2082
	$major = 0;
2083
	$minor = 0;
2084
	foreach ($strs as $num => $str) {
2085
		if (substr($a, 0, strlen($str)) == $str) {
2086
			$major = $num;
2087
			$n = substr($a, strlen($str));
2088
			if (is_numeric($n)) {
2089
				$minor = $n;
2090
			}
2091
			break;
2092
		}
2093
	}
2094
	return "{$major}.{$minor}";
2095
}
2096
function version_compare_string($a, $b) {
2097
	// Only compare string parts if both versions give a specific release
2098
	// (If either version lacks a string part, assume intended to match all release levels)
2099
	if (isset($a) && isset($b)) {
2100
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2101
	} else {
2102
		return 0;
2103
	}
2104
}
2105
function version_compare_numeric($a, $b) {
2106
	$a_arr = explode('.', rtrim($a, '.'));
2107
	$b_arr = explode('.', rtrim($b, '.'));
2108

    
2109
	foreach ($a_arr as $n => $val) {
2110
		if (array_key_exists($n, $b_arr)) {
2111
			// So far so good, both have values at this minor version level. Compare.
2112
			if ($val > $b_arr[$n]) {
2113
				return 1;
2114
			} elseif ($val < $b_arr[$n]) {
2115
				return -1;
2116
			}
2117
		} else {
2118
			// a is greater, since b doesn't have any minor version here.
2119
			return 1;
2120
		}
2121
	}
2122
	if (count($b_arr) > count($a_arr)) {
2123
		// b is longer than a, so it must be greater.
2124
		return -1;
2125
	} else {
2126
		// Both a and b are of equal length and value.
2127
		return 0;
2128
	}
2129
}
2130
function pfs_version_compare($cur_time, $cur_text, $remote) {
2131
	// First try date compare
2132
	$v = version_compare_dates($cur_time, $remote);
2133
	if ($v === FALSE) {
2134
		// If that fails, try to compare by string
2135
		// Before anything else, simply test if the strings are equal
2136
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2137
			return 0;
2138
		}
2139
		list($cur_num, $cur_str) = explode('-', $cur_text);
2140
		list($rem_num, $rem_str) = explode('-', $remote);
2141

    
2142
		// First try to compare the numeric parts of the version string.
2143
		$v = version_compare_numeric($cur_num, $rem_num);
2144

    
2145
		// If the numeric parts are the same, compare the string parts.
2146
		if ($v == 0) {
2147
			return version_compare_string($cur_str, $rem_str);
2148
		}
2149
	}
2150
	return $v;
2151
}
2152
function process_alias_urltable($name, $url, $freq, $forceupdate=false) {
2153
	global $config;
2154

    
2155
	$urltable_prefix = "/var/db/aliastables/";
2156
	$urltable_filename = $urltable_prefix . $name . ".txt";
2157

    
2158
	// Make the aliases directory if it doesn't exist
2159
	if (!file_exists($urltable_prefix)) {
2160
		mkdir($urltable_prefix);
2161
	} elseif (!is_dir($urltable_prefix)) {
2162
		unlink($urltable_prefix);
2163
		mkdir($urltable_prefix);
2164
	}
2165

    
2166
	// If the file doesn't exist or is older than update_freq days, fetch a new copy.
2167
	if (!file_exists($urltable_filename) ||
2168
	    ((time() - filemtime($urltable_filename)) > ($freq * 86400 - 90)) ||
2169
	    $forceupdate) {
2170

    
2171
		// Try to fetch the URL supplied
2172
		conf_mount_rw();
2173
		unlink_if_exists($urltable_filename . ".tmp");
2174
		$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2175
		if (download_file($url, $urltable_filename . ".tmp", $verify_ssl)) {
2176
			mwexec("/usr/bin/sed -E 's/\;.*//g; /^[[:space:]]*($|#)/d' ". escapeshellarg($urltable_filename . ".tmp") . " > " . escapeshellarg($urltable_filename));
2177
			if (alias_get_type($name) == "urltable_ports") {
2178
				$ports = explode("\n", str_replace("\r", "", file_get_contents($urltable_filename)));
2179
				$ports = group_ports($ports);
2180
				file_put_contents($urltable_filename, implode("\n", $ports));
2181
			}
2182
			unlink_if_exists($urltable_filename . ".tmp");
2183
		} else {
2184
			touch($urltable_filename);
2185
		}
2186
		conf_mount_ro();
2187
		return true;
2188
	} else {
2189
		// File exists, and it doesn't need to be updated.
2190
		return -1;
2191
	}
2192
}
2193
function get_real_slice_from_glabel($label) {
2194
	$label = escapeshellarg($label);
2195
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/{$label} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`);
2196
}
2197
function nanobsd_get_boot_slice() {
2198
	return trim(`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`);
2199
}
2200
function nanobsd_get_boot_drive() {
2201
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/pfsense | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' ' | /usr/bin/cut -d's' -f1`);
2202
}
2203
function nanobsd_get_active_slice() {
2204
	$boot_drive = nanobsd_get_boot_drive();
2205
	$active = trim(`gpart show $boot_drive | grep '\[active\]' | awk '{print $3;}'`);
2206

    
2207
	return "{$boot_drive}s{$active}";
2208
}
2209
function nanobsd_get_size() {
2210
	return strtoupper(file_get_contents("/etc/nanosize.txt"));
2211
}
2212
function nanobsd_switch_boot_slice() {
2213
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2214
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2215
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2216
	nanobsd_detect_slice_info();
2217

    
2218
	if ($BOOTFLASH == $ACTIVE_SLICE) {
2219
		$slice = $TOFLASH;
2220
	} else {
2221
		$slice = $BOOTFLASH;
2222
	}
2223

    
2224
	for ($i = 0; $i < ob_get_level(); $i++) {
2225
		ob_end_flush();
2226
	}
2227
	ob_implicit_flush(1);
2228
	if (strstr($slice, "s2")) {
2229
		$ASLICE = "2";
2230
		$AOLDSLICE = "1";
2231
		$AGLABEL_SLICE = "pfsense1";
2232
		$AUFS_ID = "1";
2233
		$AOLD_UFS_ID = "0";
2234
	} else {
2235
		$ASLICE = "1";
2236
		$AOLDSLICE = "2";
2237
		$AGLABEL_SLICE = "pfsense0";
2238
		$AUFS_ID = "0";
2239
		$AOLD_UFS_ID = "1";
2240
	}
2241
	$ATOFLASH = "{$BOOT_DRIVE}s{$ASLICE}";
2242
	$ACOMPLETE_PATH = "{$BOOT_DRIVE}s{$ASLICE}a";
2243
	$ABOOTFLASH = "{$BOOT_DRIVE}s{$AOLDSLICE}";
2244
	conf_mount_rw();
2245
	set_single_sysctl("kern.geom.debugflags", "16");
2246
	exec("/sbin/gpart set -a active -i {$ASLICE} {$BOOT_DRIVE}");
2247
	exec("/usr/sbin/boot0cfg -s {$ASLICE} -v /dev/{$BOOT_DRIVE}");
2248
	// We can't update these if they are mounted now.
2249
	if ($BOOTFLASH != $slice) {
2250
		exec("/sbin/tunefs -L ${AGLABEL_SLICE} /dev/$ACOMPLETE_PATH");
2251
		nanobsd_update_fstab($AGLABEL_SLICE, $ACOMPLETE_PATH, $AOLD_UFS_ID, $AUFS_ID);
2252
	}
2253
	set_single_sysctl("kern.geom.debugflags", "0");
2254
	conf_mount_ro();
2255
}
2256
function nanobsd_clone_slice() {
2257
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2258
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2259
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2260
	nanobsd_detect_slice_info();
2261

    
2262
	for ($i = 0; $i < ob_get_level(); $i++) {
2263
		ob_end_flush();
2264
	}
2265
	ob_implicit_flush(1);
2266
	set_single_sysctl("kern.geom.debugflags", "16");
2267
	exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
2268
	exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
2269
	exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
2270
	$status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
2271
	set_single_sysctl("kern.geom.debugflags", "0");
2272
	if ($status) {
2273
		return false;
2274
	} else {
2275
		return true;
2276
	}
2277
}
2278
function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
2279
	$tmppath = "/tmp/{$gslice}";
2280
	$fstabpath = "/tmp/{$gslice}/etc/fstab";
2281

    
2282
	mkdir($tmppath);
2283
	exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
2284
	exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
2285
	copy("/etc/fstab", $fstabpath);
2286

    
2287
	if (!file_exists($fstabpath)) {
2288
		$fstab = <<<EOF
2289
/dev/ufs/{$gslice} / ufs ro,noatime 1 1
2290
/dev/ufs/cf /cf ufs ro,noatime 1 1
2291
EOF;
2292
		if (file_put_contents($fstabpath, $fstab)) {
2293
			$status = true;
2294
		} else {
2295
			$status = false;
2296
		}
2297
	} else {
2298
		$status = exec("/usr/bin/sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
2299
	}
2300
	exec("/sbin/umount {$tmppath}");
2301
	rmdir($tmppath);
2302

    
2303
	return $status;
2304
}
2305
function nanobsd_detect_slice_info() {
2306
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2307
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2308
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2309

    
2310
	$BOOT_DEVICE=nanobsd_get_boot_slice();
2311
	$REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
2312
	$BOOT_DRIVE=nanobsd_get_boot_drive();
2313
	$ACTIVE_SLICE=nanobsd_get_active_slice();
2314

    
2315
	// Detect which slice is active and set information.
2316
	if (strstr($REAL_BOOT_DEVICE, "s1")) {
2317
		$SLICE = "2";
2318
		$OLDSLICE = "1";
2319
		$GLABEL_SLICE = "pfsense1";
2320
		$UFS_ID = "1";
2321
		$OLD_UFS_ID = "0";
2322

    
2323
	} else {
2324
		$SLICE = "1";
2325
		$OLDSLICE = "2";
2326
		$GLABEL_SLICE = "pfsense0";
2327
		$UFS_ID = "0";
2328
		$OLD_UFS_ID = "1";
2329
	}
2330
	$TOFLASH = "{$BOOT_DRIVE}s{$SLICE}";
2331
	$COMPLETE_PATH = "{$BOOT_DRIVE}s{$SLICE}a";
2332
	$COMPLETE_BOOT_PATH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2333
	$BOOTFLASH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2334
}
2335

    
2336
function nanobsd_friendly_slice_name($slicename) {
2337
	global $g;
2338
	return strtolower(str_ireplace('pfsense', $g['product_name'], $slicename));
2339
}
2340

    
2341
function get_include_contents($filename) {
2342
	if (is_file($filename)) {
2343
		ob_start();
2344
		include $filename;
2345
		$contents = ob_get_contents();
2346
		ob_end_clean();
2347
		return $contents;
2348
	}
2349
	return false;
2350
}
2351

    
2352
/* This xml 2 array function is courtesy of the php.net comment section on xml_parse.
2353
 * it is roughly 4 times faster then our existing pfSense parser but due to the large
2354
 * size of the RRD xml dumps this is required.
2355
 * The reason we do not use it for pfSense is that it does not know about array fields
2356
 * which causes it to fail on array fields with single items. Possible Todo?
2357
 */
2358
function xml2array($contents, $get_attributes = 1, $priority = 'tag') {
2359
	if (!function_exists('xml_parser_create')) {
2360
		return array ();
2361
	}
2362
	$parser = xml_parser_create('');
2363
	xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
2364
	xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2365
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2366
	xml_parse_into_struct($parser, trim($contents), $xml_values);
2367
	xml_parser_free($parser);
2368
	if (!$xml_values) {
2369
		return; //Hmm...
2370
	}
2371
	$xml_array = array ();
2372
	$parents = array ();
2373
	$opened_tags = array ();
2374
	$arr = array ();
2375
	$current = & $xml_array;
2376
	$repeated_tag_index = array ();
2377
	foreach ($xml_values as $data) {
2378
		unset ($attributes, $value);
2379
		extract($data);
2380
		$result = array ();
2381
		$attributes_data = array ();
2382
		if (isset ($value)) {
2383
			if ($priority == 'tag') {
2384
				$result = $value;
2385
			} else {
2386
				$result['value'] = $value;
2387
			}
2388
		}
2389
		if (isset ($attributes) and $get_attributes) {
2390
			foreach ($attributes as $attr => $val) {
2391
				if ($priority == 'tag') {
2392
					$attributes_data[$attr] = $val;
2393
				} else {
2394
					$result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
2395
				}
2396
			}
2397
		}
2398
		if ($type == "open") {
2399
			$parent[$level -1] = & $current;
2400
			if (!is_array($current) or (!in_array($tag, array_keys($current)))) {
2401
				$current[$tag] = $result;
2402
				if ($attributes_data) {
2403
					$current[$tag . '_attr'] = $attributes_data;
2404
				}
2405
				$repeated_tag_index[$tag . '_' . $level] = 1;
2406
				$current = & $current[$tag];
2407
			} else {
2408
				if (isset ($current[$tag][0])) {
2409
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2410
					$repeated_tag_index[$tag . '_' . $level]++;
2411
				} else {
2412
					$current[$tag] = array (
2413
						$current[$tag],
2414
						$result
2415
						);
2416
					$repeated_tag_index[$tag . '_' . $level] = 2;
2417
					if (isset ($current[$tag . '_attr'])) {
2418
						$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2419
						unset ($current[$tag . '_attr']);
2420
					}
2421
				}
2422
				$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
2423
				$current = & $current[$tag][$last_item_index];
2424
			}
2425
		} elseif ($type == "complete") {
2426
			if (!isset ($current[$tag])) {
2427
				$current[$tag] = $result;
2428
				$repeated_tag_index[$tag . '_' . $level] = 1;
2429
				if ($priority == 'tag' and $attributes_data) {
2430
					$current[$tag . '_attr'] = $attributes_data;
2431
				}
2432
			} else {
2433
				if (isset ($current[$tag][0]) and is_array($current[$tag])) {
2434
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2435
					if ($priority == 'tag' and $get_attributes and $attributes_data) {
2436
						$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2437
					}
2438
					$repeated_tag_index[$tag . '_' . $level]++;
2439
				} else {
2440
					$current[$tag] = array (
2441
						$current[$tag],
2442
						$result
2443
						);
2444
					$repeated_tag_index[$tag . '_' . $level] = 1;
2445
					if ($priority == 'tag' and $get_attributes) {
2446
						if (isset ($current[$tag . '_attr'])) {
2447
							$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2448
							unset ($current[$tag . '_attr']);
2449
						}
2450
						if ($attributes_data) {
2451
							$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2452
						}
2453
					}
2454
					$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
2455
				}
2456
			}
2457
		} elseif ($type == 'close') {
2458
			$current = & $parent[$level -1];
2459
		}
2460
	}
2461
	return ($xml_array);
2462
}
2463

    
2464
function get_country_name($country_code) {
2465
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2466
		return "";
2467
	}
2468

    
2469
	$country_names_xml = "/usr/local/share/mobile-broadband-provider-info/iso_3166-1_list_en.xml";
2470
	$country_names_contents = file_get_contents($country_names_xml);
2471
	$country_names = xml2array($country_names_contents);
2472

    
2473
	if ($country_code == "ALL") {
2474
		$country_list = array();
2475
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2476
			$country_list[] = array(
2477
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2478
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2479
		}
2480
		return $country_list;
2481
	}
2482

    
2483
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2484
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2485
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2486
		}
2487
	}
2488
	return "";
2489
}
2490

    
2491
/* sort by interface only, retain the original order of rules that apply to
2492
   the same interface */
2493
function filter_rules_sort() {
2494
	global $config;
2495

    
2496
	/* mark each rule with the sequence number (to retain the order while sorting) */
2497
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2498
		$config['filter']['rule'][$i]['seq'] = $i;
2499
	}
2500

    
2501
	usort($config['filter']['rule'], "filter_rules_compare");
2502

    
2503
	/* strip the sequence numbers again */
2504
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2505
		unset($config['filter']['rule'][$i]['seq']);
2506
	}
2507
}
2508
function filter_rules_compare($a, $b) {
2509
	if (isset($a['floating']) && isset($b['floating'])) {
2510
		return $a['seq'] - $b['seq'];
2511
	} else if (isset($a['floating'])) {
2512
		return -1;
2513
	} else if (isset($b['floating'])) {
2514
		return 1;
2515
	} else if ($a['interface'] == $b['interface']) {
2516
		return $a['seq'] - $b['seq'];
2517
	} else {
2518
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2519
	}
2520
}
2521

    
2522
function generate_ipv6_from_mac($mac) {
2523
	$elements = explode(":", $mac);
2524
	if (count($elements) <> 6) {
2525
		return false;
2526
	}
2527

    
2528
	$i = 0;
2529
	$ipv6 = "fe80::";
2530
	foreach ($elements as $byte) {
2531
		if ($i == 0) {
2532
			$hexadecimal = substr($byte, 1, 2);
2533
			$bitmap = base_convert($hexadecimal, 16, 2);
2534
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2535
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2536
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2537
		}
2538
		$ipv6 .= $byte;
2539
		if ($i == 1) {
2540
			$ipv6 .= ":";
2541
		}
2542
		if ($i == 3) {
2543
			$ipv6 .= ":";
2544
		}
2545
		if ($i == 2) {
2546
			$ipv6 .= "ff:fe";
2547
		}
2548

    
2549
		$i++;
2550
	}
2551
	return $ipv6;
2552
}
2553

    
2554
/****f* pfsense-utils/load_mac_manufacturer_table
2555
 * NAME
2556
 *   load_mac_manufacturer_table
2557
 * INPUTS
2558
 *   none
2559
 * RESULT
2560
 *   returns associative array with MAC-Manufacturer pairs
2561
 ******/
2562
function load_mac_manufacturer_table() {
2563
	/* load MAC-Manufacture data from the file */
2564
	$macs = false;
2565
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2566
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2567
	}
2568
	if ($macs) {
2569
		foreach ($macs as $line) {
2570
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2571
				/* store values like this $mac_man['000C29']='VMware' */
2572
				$mac_man["$matches[1]"] = $matches[2];
2573
			}
2574
		}
2575
		return $mac_man;
2576
	} else {
2577
		return -1;
2578
	}
2579

    
2580
}
2581

    
2582
/****f* pfsense-utils/is_ipaddr_configured
2583
 * NAME
2584
 *   is_ipaddr_configured
2585
 * INPUTS
2586
 *   IP Address to check.
2587
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2588
 *   check_localip - if true then also check for matches with PPTP and LT2P addresses
2589
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2590
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2591
 *     If check_subnets is true and cidrprefix is specified,
2592
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2593
 * RESULT
2594
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2595
*/
2596
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2597
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2598
		return true;
2599
	}
2600
	return false;
2601
}
2602

    
2603
/****f* pfsense-utils/where_is_ipaddr_configured
2604
 * NAME
2605
 *   where_is_ipaddr_configured
2606
 * INPUTS
2607
 *   IP Address to check.
2608
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2609
 *   check_localip - if true then also check for matches with PPTP and LT2P addresses
2610
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2611
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2612
 *     If check_subnets is true and cidrprefix is specified,
2613
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2614
 * RESULT
2615
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2616
 *   If there are no matches then an empty array is returned.
2617
*/
2618
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2619
	global $config;
2620

    
2621
	$where_configured = array();
2622

    
2623
	$pos = strpos($ignore_if, '_virtualip');
2624
	if ($pos !== false) {
2625
		$ignore_vip_id = substr($ignore_if, $pos+10);
2626
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2627
	} else {
2628
		$ignore_vip_id = -1;
2629
		$ignore_vip_if = $ignore_if;
2630
	}
2631

    
2632
	$isipv6 = is_ipaddrv6($ipaddr);
2633

    
2634
	if ($check_subnets) {
2635
		$cidrprefix = intval($cidrprefix);
2636
		if ($isipv6) {
2637
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2638
				$cidrprefix = 128;
2639
			}
2640
		} else {
2641
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2642
				$cidrprefix = 32;
2643
			}
2644
		}
2645
		$iflist = get_configured_interface_list();
2646
		foreach ($iflist as $if => $ifname) {
2647
			if ($ignore_if == $if) {
2648
				continue;
2649
			}
2650

    
2651
			if ($isipv6) {
2652
				$if_ipv6 = get_interface_ipv6($if);
2653
				$if_snbitsv6 = get_interface_subnetv6($if);
2654
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2655
					$where_entry = array();
2656
					$where_entry['if'] = $if;
2657
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2658
					$where_configured[] = $where_entry;
2659
				}
2660
			} else {
2661
				$if_ipv4 = get_interface_ip($if);
2662
				$if_snbitsv4 = get_interface_subnet($if);
2663
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2664
					$where_entry = array();
2665
					$where_entry['if'] = $if;
2666
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2667
					$where_configured[] = $where_entry;
2668
				}
2669
			}
2670
		}
2671
	} else {
2672
		if ($isipv6) {
2673
			$interface_list_ips = get_configured_ipv6_addresses();
2674
		} else {
2675
			$interface_list_ips = get_configured_ip_addresses();
2676
		}
2677

    
2678
		foreach ($interface_list_ips as $if => $ilips) {
2679
			if ($ignore_if == $if) {
2680
				continue;
2681
			}
2682
			if (strcasecmp($ipaddr, $ilips) == 0) {
2683
				$where_entry = array();
2684
				$where_entry['if'] = $if;
2685
				$where_entry['ip_or_subnet'] = $ilips;
2686
				$where_configured[] = $where_entry;
2687
			}
2688
		}
2689
	}
2690

    
2691
	$interface_list_vips = get_configured_vips_list(true);
2692
	foreach ($interface_list_vips as $id => $vip) {
2693
		/* Skip CARP interfaces here since they were already checked above */
2694
		if ($id == $ignore_vip_id || (substr($ignore_if, 0, 4) == '_vip') && $ignore_vip_if === $vip['if']) {
2695
			continue;
2696
		}
2697
		if (strcasecmp($ipaddr, $vip['ipaddr']) == 0) {
2698
			$where_entry = array();
2699
			$where_entry['if'] = $vip['if'];
2700
			$where_entry['ip_or_subnet'] = $vip['ipaddr'];
2701
			$where_configured[] = $where_entry;
2702
		}
2703
	}
2704

    
2705
	if ($check_localip) {
2706
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, $config['l2tp']['localip']) == 0)) {
2707
			$where_entry = array();
2708
			$where_entry['if'] = 'l2tp';
2709
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2710
			$where_configured[] = $where_entry;
2711
		}
2712
	}
2713

    
2714
	return $where_configured;
2715
}
2716

    
2717
/****f* pfsense-utils/pfSense_handle_custom_code
2718
 * NAME
2719
 *   pfSense_handle_custom_code
2720
 * INPUTS
2721
 *   directory name to process
2722
 * RESULT
2723
 *   globs the directory and includes the files
2724
 */
2725
function pfSense_handle_custom_code($src_dir) {
2726
	// Allow extending of the nat edit page and include custom input validation
2727
	if (is_dir("$src_dir")) {
2728
		$cf = glob($src_dir . "/*.inc");
2729
		foreach ($cf as $nf) {
2730
			if ($nf == "." || $nf == "..") {
2731
				continue;
2732
			}
2733
			// Include the extra handler
2734
			include("$nf");
2735
		}
2736
	}
2737
}
2738

    
2739
function set_language($lang = 'en_US', $encoding = "UTF-8") {
2740
	setlocale(LC_ALL, "{$lang}.{$encoding}");
2741
	textdomain("pfSense");
2742
	bindtextdomain("pfSense", "/usr/local/share/locale");
2743
	bind_textdomain_codeset("pfSense", "{$lang}.{$encoding}");
2744
}
2745

    
2746
function get_locale_list() {
2747
	$locales = array(
2748
		"en_US" => gettext("English"),
2749
		"pt_BR" => gettext("Portuguese (Brazil)"),
2750
		"tr" => gettext("Turkish"),
2751
	);
2752
	asort($locales);
2753
	return $locales;
2754
}
2755

    
2756
function return_hex_ipv4($ipv4) {
2757
	if (!is_ipaddrv4($ipv4)) {
2758
		return(false);
2759
	}
2760

    
2761
	/* we need the hex form of the interface IPv4 address */
2762
	$ip4arr = explode(".", $ipv4);
2763
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
2764
}
2765

    
2766
function convert_ipv6_to_128bit($ipv6) {
2767
	if (!is_ipaddrv6($ipv6)) {
2768
		return(false);
2769
	}
2770

    
2771
	$ip6arr = array();
2772
	$ip6prefix = Net_IPv6::uncompress($ipv6);
2773
	$ip6arr = explode(":", $ip6prefix);
2774
	/* binary presentation of the prefix for all 128 bits. */
2775
	$ip6prefixbin = "";
2776
	foreach ($ip6arr as $element) {
2777
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
2778
	}
2779
	return($ip6prefixbin);
2780
}
2781

    
2782
function convert_128bit_to_ipv6($ip6bin) {
2783
	if (strlen($ip6bin) <> 128) {
2784
		return(false);
2785
	}
2786

    
2787
	$ip6arr = array();
2788
	$ip6binarr = array();
2789
	$ip6binarr = str_split($ip6bin, 16);
2790
	foreach ($ip6binarr as $binpart) {
2791
		$ip6arr[] = dechex(bindec($binpart));
2792
	}
2793
	$ip6addr = Net_IPv6::compress(implode(":", $ip6arr));
2794

    
2795
	return($ip6addr);
2796
}
2797

    
2798

    
2799
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
2800
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
2801
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
2802
/* 6to4 is 16 bits, e.g. 65535 */
2803
function calculate_ipv6_delegation_length($if) {
2804
	global $config;
2805

    
2806
	if (!is_array($config['interfaces'][$if])) {
2807
		return false;
2808
	}
2809

    
2810
	switch ($config['interfaces'][$if]['ipaddrv6']) {
2811
		case "6to4":
2812
			$pdlen = 16;
2813
			break;
2814
		case "6rd":
2815
			$rd6cfg = $config['interfaces'][$if];
2816
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
2817
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
2818
			break;
2819
		case "dhcp6":
2820
			$dhcp6cfg = $config['interfaces'][$if];
2821
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
2822
			break;
2823
		default:
2824
			$pdlen = 0;
2825
			break;
2826
	}
2827
	return($pdlen);
2828
}
2829

    
2830
function huawei_rssi_to_string($rssi) {
2831
	$dbm = array();
2832
	$i = 0;
2833
	$dbstart = -113;
2834
	while ($i < 32) {
2835
		$dbm[$i] = $dbstart + ($i * 2);
2836
		$i++;
2837
	}
2838
	$percent = round(($rssi / 31) * 100);
2839
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
2840
	return $string;
2841
}
2842

    
2843
function huawei_mode_to_string($mode, $submode) {
2844
	$modes[0] = "None";
2845
	$modes[1] = "AMPS";
2846
	$modes[2] = "CDMA";
2847
	$modes[3] = "GSM/GPRS";
2848
	$modes[4] = "HDR";
2849
	$modes[5] = "WCDMA";
2850
	$modes[6] = "GPS";
2851

    
2852
	$submodes[0] = "No Service";
2853
	$submodes[1] = "GSM";
2854
	$submodes[2] = "GPRS";
2855
	$submodes[3] = "EDGE";
2856
	$submodes[4] = "WCDMA";
2857
	$submodes[5] = "HSDPA";
2858
	$submodes[6] = "HSUPA";
2859
	$submodes[7] = "HSDPA+HSUPA";
2860
	$submodes[8] = "TD-SCDMA";
2861
	$submodes[9] = "HSPA+";
2862
	$string = "{$modes[$mode]}, {$submodes[$submode]} Mode";
2863
	return $string;
2864
}
2865

    
2866
function huawei_service_to_string($state) {
2867
	$modes[0] = "No";
2868
	$modes[1] = "Restricted";
2869
	$modes[2] = "Valid";
2870
	$modes[3] = "Restricted Regional";
2871
	$modes[4] = "Powersaving";
2872
	$string = "{$modes[$state]} Service";
2873
	return $string;
2874
}
2875

    
2876
function huawei_simstate_to_string($state) {
2877
	$modes[0] = "Invalid SIM/locked";
2878
	$modes[1] = "Valid SIM";
2879
	$modes[2] = "Invalid SIM CS";
2880
	$modes[3] = "Invalid SIM PS";
2881
	$modes[4] = "Invalid SIM CS/PS";
2882
	$modes[255] = "Missing SIM";
2883
	$string = "{$modes[$state]} State";
2884
	return $string;
2885
}
2886

    
2887
function zte_rssi_to_string($rssi) {
2888
	return huawei_rssi_to_string($rssi);
2889
}
2890

    
2891
function zte_mode_to_string($mode, $submode) {
2892
	$modes[0] = "No Service";
2893
	$modes[1] = "Limited Service";
2894
	$modes[2] = "GPRS";
2895
	$modes[3] = "GSM";
2896
	$modes[4] = "UMTS";
2897
	$modes[5] = "EDGE";
2898
	$modes[6] = "HSDPA";
2899

    
2900
	$submodes[0] = "CS_ONLY";
2901
	$submodes[1] = "PS_ONLY";
2902
	$submodes[2] = "CS_PS";
2903
	$submodes[3] = "CAMPED";
2904
	$string = "{$modes[$mode]}, {$submodes[$submode]} Mode";
2905
	return $string;
2906
}
2907

    
2908
function zte_service_to_string($state) {
2909
	$modes[0] = "Initializing";
2910
	$modes[1] = "Network Lock error";
2911
	$modes[2] = "Network Locked";
2912
	$modes[3] = "Unlocked or correct MCC/MNC";
2913
	$string = "{$modes[$state]} Service";
2914
	return $string;
2915
}
2916

    
2917
function zte_simstate_to_string($state) {
2918
	$modes[0] = "No action";
2919
	$modes[1] = "Network lock";
2920
	$modes[2] = "(U)SIM card lock";
2921
	$modes[3] = "Network Lock and (U)SIM card Lock";
2922
	$string = "{$modes[$state]} State";
2923
	return $string;
2924
}
2925

    
2926
function get_configured_pppoe_server_interfaces() {
2927
	global $config;
2928
	$iflist = array();
2929
	if (is_array($config['pppoes']['pppoe'])) {
2930
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
2931
			if ($pppoe['mode'] == "server") {
2932
				$int = "poes". $pppoe['pppoeid'];
2933
				$iflist[$int] = strtoupper($int);
2934
			}
2935
		}
2936
	}
2937
	return $iflist;
2938
}
2939

    
2940
function get_pppoes_child_interfaces($ifpattern) {
2941
	$if_arr = array();
2942
	if ($ifpattern == "") {
2943
		return;
2944
	}
2945

    
2946
	exec("/sbin/ifconfig", $out, $ret);
2947
	foreach ($out as $line) {
2948
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
2949
			$if_arr[] = $match[1];
2950
		}
2951
	}
2952
	return $if_arr;
2953

    
2954
}
2955

    
2956
/****f* pfsense-utils/pkg_call_plugins
2957
 * NAME
2958
 *   pkg_call_plugins
2959
 * INPUTS
2960
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
2961
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
2962
 * RESULT
2963
 *   returns associative array results from the plugin calls for each package
2964
 * NOTES
2965
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
2966
 ******/
2967
function pkg_call_plugins($plugin_type, $plugin_params) {
2968
	global $g, $config;
2969
	$results = array();
2970
	if (!is_array($config['installedpackages']['package'])) {
2971
		return $results;
2972
	}
2973
	foreach ($config['installedpackages']['package'] as $package) {
2974
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
2975
			continue;
2976
		}
2977
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
2978
		$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
2979
		if (is_array($pkg_config['plugins']['item'])) {
2980
			foreach ($pkg_config['plugins']['item'] as $plugin) {
2981
				if ($plugin['type'] == $plugin_type) {
2982
					if (file_exists($pkg_config['include_file'])) {
2983
						require_once($pkg_config['include_file']);
2984
					} else {
2985
						continue;
2986
					}
2987
					$plugin_function = $pkgname . '_'. $plugin_type;
2988
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
2989
				}
2990
			}
2991
		}
2992
	}
2993
	return $results;
2994
}
2995

    
2996
?>
(39-39/65)