Project

General

Profile

Download (85.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	pfsense-utils.inc
4

    
5
	part of pfSense (https://www.pfsense.org)
6
	Copyright (c) 2004-2016 Electric Sheep Fencing, LLC.
7
	All rights reserved.
8

    
9
	Redistribution and use in source and binary forms, with or without
10
	modification, are permitted provided that the following conditions are met:
11

    
12
	1. Redistributions of source code must retain the above copyright notice,
13
	   this list of conditions and the following disclaimer.
14

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

    
20
	3. All advertising materials mentioning features or use of this software
21
	   must display the following acknowledgment:
22
	   "This product includes software developed by the pfSense Project
23
	   for use in the pfSense® software distribution. (http://www.pfsense.org/).
24

    
25
	4. The names "pfSense" and "pfSense Project" must not be used to
26
	   endorse or promote products derived from this software without
27
	   prior written permission. For written permission, please contact
28
	   coreteam@pfsense.org.
29

    
30
	5. Products derived from this software may not be called "pfSense"
31
	   nor may "pfSense" appear in their names without prior written
32
	   permission of the Electric Sheep Fencing, LLC.
33

    
34
	6. Redistributions of any form whatsoever must retain the following
35
	   acknowledgment:
36

    
37
	"This product includes software developed by the pfSense Project
38
	for use in the pfSense software distribution (http://www.pfsense.org/).
39

    
40
	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
41
	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43
	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
44
	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45
	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49
	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51
	OF THE POSSIBILITY OF SUCH DAMAGE.
52
*/
53

    
54
/****f* pfsense-utils/have_natpfruleint_access
55
 * NAME
56
 *   have_natpfruleint_access
57
 * INPUTS
58
 *	none
59
 * RESULT
60
 *   returns true if user has access to edit a specific firewall nat port forward interface
61
 ******/
62
function have_natpfruleint_access($if) {
63
	$security_url = "firewall_nat_edit.php?if=". strtolower($if);
64
	if (isAllowedPage($security_url, $allowed)) {
65
		return true;
66
	}
67
	return false;
68
}
69

    
70
/****f* pfsense-utils/have_ruleint_access
71
 * NAME
72
 *   have_ruleint_access
73
 * INPUTS
74
 *	none
75
 * RESULT
76
 *   returns true if user has access to edit a specific firewall interface
77
 ******/
78
function have_ruleint_access($if) {
79
	$security_url = "firewall_rules.php?if=". strtolower($if);
80
	if (isAllowedPage($security_url)) {
81
		return true;
82
	}
83
	return false;
84
}
85

    
86
/****f* pfsense-utils/does_url_exist
87
 * NAME
88
 *   does_url_exist
89
 * INPUTS
90
 *	none
91
 * RESULT
92
 *   returns true if a url is available
93
 ******/
94
function does_url_exist($url) {
95
	$fd = fopen("$url", "r");
96
	if ($fd) {
97
		fclose($fd);
98
		return true;
99
	} else {
100
		return false;
101
	}
102
}
103

    
104
/****f* pfsense-utils/is_private_ip
105
 * NAME
106
 *   is_private_ip
107
 * INPUTS
108
 *	none
109
 * RESULT
110
 *   returns true if an ip address is in a private range
111
 ******/
112
function is_private_ip($iptocheck) {
113
	$isprivate = false;
114
	$ip_private_list = array(
115
		"10.0.0.0/8",
116
		"100.64.0.0/10",
117
		"172.16.0.0/12",
118
		"192.168.0.0/16",
119
	);
120
	foreach ($ip_private_list as $private) {
121
		if (ip_in_subnet($iptocheck, $private) == true) {
122
			$isprivate = true;
123
		}
124
	}
125
	return $isprivate;
126
}
127

    
128
/****f* pfsense-utils/get_tmp_file
129
 * NAME
130
 *   get_tmp_file
131
 * INPUTS
132
 *	none
133
 * RESULT
134
 *   returns a temporary filename
135
 ******/
136
function get_tmp_file() {
137
	global $g;
138
	return "{$g['tmp_path']}/tmp-" . time();
139
}
140

    
141
/****f* pfsense-utils/get_dns_servers
142
 * NAME
143
 *   get_dns_servers - get system dns servers
144
 * INPUTS
145
 *   none
146
 * RESULT
147
 *   $dns_servers - an array of the dns servers
148
 ******/
149
function get_dns_servers() {
150
	$dns_servers = array();
151
	if (file_exists("/etc/resolv.conf")) {
152
		$dns_s = file("/etc/resolv.conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
153
	}
154
	if (is_array($dns_s)) {
155
		foreach ($dns_s as $dns) {
156
			$matches = "";
157
			if (preg_match("/nameserver (.*)/", $dns, $matches)) {
158
				$dns_servers[] = $matches[1];
159
			}
160
		}
161
	}
162
	return array_unique($dns_servers);
163
}
164

    
165
function hardware_offloading_applyflags($iface) {
166
	global $config;
167

    
168
	$flags_on = 0;
169
	$flags_off = 0;
170
	$options = pfSense_get_interface_addresses($iface);
171

    
172
	if (isset($config['system']['disablechecksumoffloading'])) {
173
		if (isset($options['encaps']['txcsum'])) {
174
			$flags_off |= IFCAP_TXCSUM;
175
		}
176
		if (isset($options['encaps']['rxcsum'])) {
177
			$flags_off |= IFCAP_RXCSUM;
178
		}
179
	} else {
180
		if (isset($options['caps']['txcsum'])) {
181
			$flags_on |= IFCAP_TXCSUM;
182
		}
183
		if (isset($options['caps']['rxcsum'])) {
184
			$flags_on |= IFCAP_RXCSUM;
185
		}
186
	}
187

    
188
	if (isset($config['system']['disablesegmentationoffloading'])) {
189
		$flags_off |= IFCAP_TSO;
190
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
191
		$flags_on |= IFCAP_TSO;
192
	}
193

    
194
	if (isset($config['system']['disablelargereceiveoffloading'])) {
195
		$flags_off |= IFCAP_LRO;
196
	} else if (isset($options['caps']['lro'])) {
197
		$flags_on |= IFCAP_LRO;
198
	}
199

    
200
	/* if the NIC supports polling *AND* it is enabled in the GUI */
201
	if (!isset($config['system']['polling'])) {
202
		$flags_off |= IFCAP_POLLING;
203
	} else if (isset($options['caps']['polling'])) {
204
		$flags_on |= IFCAP_POLLING;
205
	}
206

    
207
	pfSense_interface_capabilities($iface, -$flags_off);
208
	pfSense_interface_capabilities($iface, $flags_on);
209
}
210

    
211
/****f* pfsense-utils/enable_hardware_offloading
212
 * NAME
213
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
214
 * INPUTS
215
 *   $interface	- string containing the physical interface to work on.
216
 * RESULT
217
 *   null
218
 * NOTES
219
 *   This function only supports the fxp driver's loadable microcode.
220
 ******/
221
function enable_hardware_offloading($interface) {
222
	global $g, $config;
223

    
224
	$int = get_real_interface($interface);
225
	if (empty($int)) {
226
		return;
227
	}
228

    
229
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
230
		/* translate wan, lan, opt -> real interface if needed */
231
		$int_family = preg_split("/[0-9]+/", $int);
232
		$supported_ints = array('fxp');
233
		if (in_array($int_family, $supported_ints)) {
234
			if (does_interface_exist($int)) {
235
				pfSense_interface_flags($int, IFF_LINK0);
236
			}
237
		}
238
	}
239

    
240
	/* This is mostly for vlans and ppp types */
241
	$realhwif = get_parent_interface($interface);
242
	if ($realhwif[0] == $int) {
243
		hardware_offloading_applyflags($int);
244
	} else {
245
		hardware_offloading_applyflags($realhwif[0]);
246
		hardware_offloading_applyflags($int);
247
	}
248
}
249

    
250
/****f* pfsense-utils/interface_supports_polling
251
 * NAME
252
 *   checks to see if an interface supports polling according to man polling
253
 * INPUTS
254
 *
255
 * RESULT
256
 *   true or false
257
 * NOTES
258
 *
259
 ******/
260
function interface_supports_polling($iface) {
261
	$opts = pfSense_get_interface_addresses($iface);
262
	if (is_array($opts) && isset($opts['caps']['polling'])) {
263
		return true;
264
	}
265

    
266
	return false;
267
}
268

    
269
/****f* pfsense-utils/is_alias_inuse
270
 * NAME
271
 *   checks to see if an alias is currently in use by a rule
272
 * INPUTS
273
 *
274
 * RESULT
275
 *   true or false
276
 * NOTES
277
 *
278
 ******/
279
function is_alias_inuse($alias) {
280
	global $g, $config;
281

    
282
	if ($alias == "") {
283
		return false;
284
	}
285
	/* loop through firewall rules looking for alias in use */
286
	if (is_array($config['filter']['rule'])) {
287
		foreach ($config['filter']['rule'] as $rule) {
288
			if ($rule['source']['address']) {
289
				if ($rule['source']['address'] == $alias) {
290
					return true;
291
				}
292
			}
293
			if ($rule['destination']['address']) {
294
				if ($rule['destination']['address'] == $alias) {
295
					return true;
296
				}
297
			}
298
		}
299
	}
300
	/* loop through nat rules looking for alias in use */
301
	if (is_array($config['nat']['rule'])) {
302
		foreach ($config['nat']['rule'] as $rule) {
303
			if ($rule['target'] && $rule['target'] == $alias) {
304
				return true;
305
			}
306
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
307
				return true;
308
			}
309
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
310
				return true;
311
			}
312
		}
313
	}
314
	return false;
315
}
316

    
317
/****f* pfsense-utils/is_schedule_inuse
318
 * NAME
319
 *   checks to see if a schedule is currently in use by a rule
320
 * INPUTS
321
 *
322
 * RESULT
323
 *   true or false
324
 * NOTES
325
 *
326
 ******/
327
function is_schedule_inuse($schedule) {
328
	global $g, $config;
329

    
330
	if ($schedule == "") {
331
		return false;
332
	}
333
	/* loop through firewall rules looking for schedule in use */
334
	if (is_array($config['filter']['rule'])) {
335
		foreach ($config['filter']['rule'] as $rule) {
336
			if ($rule['sched'] == $schedule) {
337
				return true;
338
			}
339
		}
340
	}
341
	return false;
342
}
343

    
344
/****f* pfsense-utils/setup_polling
345
 * NAME
346
 *   sets up polling
347
 * INPUTS
348
 *
349
 * RESULT
350
 *   null
351
 * NOTES
352
 *
353
 ******/
354
function setup_polling() {
355
	global $g, $config;
356

    
357
	if (isset($config['system']['polling'])) {
358
		set_single_sysctl("kern.polling.idle_poll", "1");
359
	} else {
360
		set_single_sysctl("kern.polling.idle_poll", "0");
361
	}
362

    
363
	if ($config['system']['polling_each_burst']) {
364
		set_single_sysctl("kern.polling.each_burst", $config['system']['polling_each_burst']);
365
	}
366
	if ($config['system']['polling_burst_max']) {
367
		set_single_sysctl("kern.polling.burst_max", $config['system']['polling_burst_max']);
368
	}
369
	if ($config['system']['polling_user_frac']) {
370
		set_single_sysctl("kern.polling.user_frac", $config['system']['polling_user_frac']);
371
	}
372
}
373

    
374
/****f* pfsense-utils/setup_microcode
375
 * NAME
376
 *   enumerates all interfaces and calls enable_hardware_offloading which
377
 *   enables a NIC's supported hardware features.
378
 * INPUTS
379
 *
380
 * RESULT
381
 *   null
382
 * NOTES
383
 *   This function only supports the fxp driver's loadable microcode.
384
 ******/
385
function setup_microcode() {
386

    
387
	/* if list */
388
	$iflist = get_configured_interface_list(false, true);
389
	foreach ($iflist as $if => $ifdescr) {
390
		enable_hardware_offloading($if);
391
	}
392
	unset($iflist);
393
}
394

    
395
/****f* pfsense-utils/get_carp_status
396
 * NAME
397
 *   get_carp_status - Return whether CARP is enabled or disabled.
398
 * RESULT
399
 *   boolean	- true if CARP is enabled, false if otherwise.
400
 ******/
401
function get_carp_status() {
402
	/* grab the current status of carp */
403
	$status = get_single_sysctl('net.inet.carp.allow');
404
	return (intval($status) > 0);
405
}
406

    
407
/*
408
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
409

    
410
 */
411
function convert_ip_to_network_format($ip, $subnet) {
412
	$ipsplit = explode('.', $ip);
413
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
414
	return $string;
415
}
416

    
417
/*
418
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
419
 */
420
function get_carp_interface_status($carpid) {
421

    
422
	$carpiface = get_configured_vip_interface($carpid);
423
	if ($carpiface == NULL)
424
		return "";
425
	$interface = get_real_interface($carpiface);
426
	if ($interface == NULL)
427
		return "";
428

    
429
	$vhid = $carp['vhid'];
430
	$carp_query = '';
431
	$_gb = exec("/sbin/ifconfig $interface | /usr/bin/grep carp: | /usr/bin/grep \"vhid $vhid\"", $carp_query);
432
	foreach ($carp_query as $int) {
433
		if (stripos($int, "MASTER"))
434
			return "MASTER";
435
		elseif (stripos($int, "BACKUP"))
436
			return "BACKUP";
437
		elseif (stripos($int, "INIT"))
438
			return "INIT";
439
	}
440

    
441
	return "";
442
}
443

    
444
/*
445
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
446
 */
447
function get_pfsync_interface_status($pfsyncinterface) {
448
	if (!does_interface_exist($pfsyncinterface)) {
449
		return;
450
	}
451

    
452
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
453
}
454

    
455
/*
456
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
457
 */
458
function add_rule_to_anchor($anchor, $rule, $label) {
459
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
460
}
461

    
462
/*
463
 * remove_text_from_file
464
 * remove $text from file $file
465
 */
466
function remove_text_from_file($file, $text) {
467
	if (!file_exists($file) && !is_writable($file)) {
468
		return;
469
	}
470
	$filecontents = file_get_contents($file);
471
	$text = str_replace($text, "", $filecontents);
472
	@file_put_contents($file, $text);
473
}
474

    
475
/*
476
 *   after_sync_bump_adv_skew(): create skew values by 1S
477
 */
478
function after_sync_bump_adv_skew() {
479
	global $config, $g;
480
	$processed_skew = 1;
481
	$a_vip = &$config['virtualip']['vip'];
482
	foreach ($a_vip as $vipent) {
483
		if ($vipent['advskew'] <> "") {
484
			$processed_skew = 1;
485
			$vipent['advskew'] = $vipent['advskew']+1;
486
		}
487
	}
488
	if ($processed_skew == 1) {
489
		write_config(gettext("After synch increase advertising skew"));
490
	}
491
}
492

    
493
/*
494
 * get_filename_from_url($url): converts a url to its filename.
495
 */
496
function get_filename_from_url($url) {
497
	return basename($url);
498
}
499

    
500
/*
501
 *   get_dir: return an array of $dir
502
 */
503
function get_dir($dir) {
504
	$dir_array = array();
505
	$d = dir($dir);
506
	while (false !== ($entry = $d->read())) {
507
		array_push($dir_array, $entry);
508
	}
509
	$d->close();
510
	return $dir_array;
511
}
512

    
513
/****f* pfsense-utils/WakeOnLan
514
 * NAME
515
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
516
 * RESULT
517
 *   true/false - true if the operation was successful
518
 ******/
519
function WakeOnLan($addr, $mac) {
520
	$addr_byte = explode(':', $mac);
521
	$hw_addr = '';
522

    
523
	for ($a = 0; $a < 6; $a++) {
524
		$hw_addr .= chr(hexdec($addr_byte[$a]));
525
	}
526

    
527
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
528

    
529
	for ($a = 1; $a <= 16; $a++) {
530
		$msg .= $hw_addr;
531
	}
532

    
533
	// send it to the broadcast address using UDP
534
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
535
	if ($s == false) {
536
		log_error(gettext("Error creating socket!"));
537
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
538
	} else {
539
		// setting a broadcast option to socket:
540
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
541
		if ($opt_ret < 0) {
542
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
543
		}
544
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
545
		socket_close($s);
546
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
547
		return true;
548
	}
549

    
550
	return false;
551
}
552

    
553
/*
554
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
555
 *					 Useful for finding paths and stripping file extensions.
556
 */
557
function reverse_strrchr($haystack, $needle) {
558
	if (!is_string($haystack)) {
559
		return;
560
	}
561
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
562
}
563

    
564
/*
565
 *  backup_config_section($section): returns as an xml file string of
566
 *                                   the configuration section
567
 */
568
function backup_config_section($section_name) {
569
	global $config;
570
	$new_section = &$config[$section_name];
571
	/* generate configuration XML */
572
	$xmlconfig = dump_xml_config($new_section, $section_name);
573
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
574
	return $xmlconfig;
575
}
576

    
577
/*
578
 *  restore_config_section($section_name, new_contents): restore a configuration section,
579
 *                                                  and write the configuration out
580
 *                                                  to disk/cf.
581
 */
582
function restore_config_section($section_name, $new_contents) {
583
	global $config, $g;
584
	conf_mount_rw();
585
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
586
	fwrite($fout, $new_contents);
587
	fclose($fout);
588

    
589
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
590
	if ($xml['pfsense']) {
591
		$xml = $xml['pfsense'];
592
	}
593
	else if ($xml['m0n0wall']) {
594
		$xml = $xml['m0n0wall'];
595
	}
596
	if ($xml[$section_name]) {
597
		$section_xml = $xml[$section_name];
598
	} else {
599
		$section_xml = -1;
600
	}
601

    
602
	@unlink($g['tmp_path'] . "/tmpxml");
603
	if ($section_xml === -1) {
604
		return false;
605
	}
606
	$config[$section_name] = &$section_xml;
607
	if (file_exists("{$g['tmp_path']}/config.cache")) {
608
		unlink("{$g['tmp_path']}/config.cache");
609
	}
610
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
611
	disable_security_checks();
612
	conf_mount_ro();
613
	return true;
614
}
615

    
616
/*
617
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
618
 *                                                  and write the configuration out
619
 *                                                  to disk/cf.  But preserve the prior
620
 * 													structure if needed
621
 */
622
function merge_config_section($section_name, $new_contents) {
623
	global $config;
624
	conf_mount_rw();
625
	$fname = get_tmp_filename();
626
	$fout = fopen($fname, "w");
627
	fwrite($fout, $new_contents);
628
	fclose($fout);
629
	$section_xml = parse_xml_config($fname, $section_name);
630
	$config[$section_name] = $section_xml;
631
	unlink($fname);
632
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
633
	disable_security_checks();
634
	conf_mount_ro();
635
	return;
636
}
637

    
638
/*
639
 *  php_check_syntax($code_tocheck, $errormessage): checks $code_to_check for errors
640
 */
641
if (!function_exists('php_check_syntax')) {
642
	global $g;
643
	function php_check_syntax($code_to_check, &$errormessage) {
644
		return false;
645
		$fout = fopen("{$g['tmp_path']}/codetocheck.php", "w");
646
		$code = $_POST['content'];
647
		$code = str_replace("<?php", "", $code);
648
		$code = str_replace("?>", "", $code);
649
		fwrite($fout, "<?php\n\n");
650
		fwrite($fout, $code_to_check);
651
		fwrite($fout, "\n\n?>\n");
652
		fclose($fout);
653
		$command = "/usr/local/bin/php-cgi -l {$g['tmp_path']}/codetocheck.php";
654
		$output = exec_command($command);
655
		if (stristr($output, "Errors parsing") == false) {
656
			echo "false\n";
657
			$errormessage = '';
658
			return(false);
659
		} else {
660
			$errormessage = $output;
661
			return(true);
662
		}
663
	}
664
}
665

    
666
/*
667
 *  php_check_filename_syntax($filename, $errormessage): checks the file $filename for errors
668
 */
669
if (!function_exists('php_check_syntax')) {
670
	function php_check_syntax($code_to_check, &$errormessage) {
671
		return false;
672
		$command = "/usr/local/bin/php-cgi -l " . escapeshellarg($code_to_check);
673
		$output = exec_command($command);
674
		if (stristr($output, "Errors parsing") == false) {
675
			echo "false\n";
676
			$errormessage = '';
677
			return(false);
678
		} else {
679
			$errormessage = $output;
680
			return(true);
681
		}
682
	}
683
}
684

    
685
/*
686
 * rmdir_recursive($path, $follow_links=false)
687
 * Recursively remove a directory tree (rm -rf path)
688
 * This is for directories _only_
689
 */
690
function rmdir_recursive($path, $follow_links=false) {
691
	$to_do = glob($path);
692
	if (!is_array($to_do)) {
693
		$to_do = array($to_do);
694
	}
695
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
696
		if (file_exists($workingdir)) {
697
			if (is_dir($workingdir)) {
698
				$dir = opendir($workingdir);
699
				while ($entry = readdir($dir)) {
700
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
701
						unlink("$workingdir/$entry");
702
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
703
						rmdir_recursive("$workingdir/$entry");
704
					}
705
				}
706
				closedir($dir);
707
				rmdir($workingdir);
708
			} elseif (is_file($workingdir)) {
709
				unlink($workingdir);
710
			}
711
		}
712
	}
713
	return;
714
}
715

    
716
/*
717
 * host_firmware_version(): Return the versions used in this install
718
 */
719
function host_firmware_version($tocheck = "") {
720
	global $g, $config;
721

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

    
724
	return array(
725
		"firmware" => array("version" => $g['product_version']),
726
		"kernel"   => array("version" => $os_version),
727
		"base"     => array("version" => $os_version),
728
		"platform" => trim(file_get_contents('/etc/platform', " \n")),
729
		"config_version" => $config['version']
730
	);
731
}
732

    
733
function get_disk_info() {
734
	$diskout = "";
735
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
736
	return explode(' ', $diskout[0]);
737
}
738

    
739
/****f* pfsense-utils/strncpy
740
 * NAME
741
 *   strncpy - copy strings
742
 * INPUTS
743
 *   &$dst, $src, $length
744
 * RESULT
745
 *   none
746
 ******/
747
function strncpy(&$dst, $src, $length) {
748
	if (strlen($src) > $length) {
749
		$dst = substr($src, 0, $length);
750
	} else {
751
		$dst = $src;
752
	}
753
}
754

    
755
/****f* pfsense-utils/reload_interfaces_sync
756
 * NAME
757
 *   reload_interfaces - reload all interfaces
758
 * INPUTS
759
 *   none
760
 * RESULT
761
 *   none
762
 ******/
763
function reload_interfaces_sync() {
764
	global $config, $g;
765

    
766
	if ($g['debug']) {
767
		log_error(gettext("reload_interfaces_sync() is starting."));
768
	}
769

    
770
	/* parse config.xml again */
771
	$config = parse_config(true);
772

    
773
	/* enable routing */
774
	system_routing_enable();
775
	if ($g['debug']) {
776
		log_error(gettext("Enabling system routing"));
777
	}
778

    
779
	if ($g['debug']) {
780
		log_error(gettext("Cleaning up Interfaces"));
781
	}
782

    
783
	/* set up interfaces */
784
	interfaces_configure();
785
}
786

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

    
799
/****f* pfsense-utils/reload_interfaces
800
 * NAME
801
 *   reload_interfaces - triggers a reload of all interfaces
802
 * INPUTS
803
 *   none
804
 * RESULT
805
 *   none
806
 ******/
807
function reload_interfaces() {
808
	send_event("interface all reload");
809
}
810

    
811
/****f* pfsense-utils/reload_all_sync
812
 * NAME
813
 *   reload_all - reload all settings
814
 *   * INPUTS
815
 *   none
816
 * RESULT
817
 *   none
818
 ******/
819
function reload_all_sync() {
820
	global $config, $g;
821

    
822
	/* parse config.xml again */
823
	$config = parse_config(true);
824

    
825
	/* set up our timezone */
826
	system_timezone_configure();
827

    
828
	/* set up our hostname */
829
	system_hostname_configure();
830

    
831
	/* make hosts file */
832
	system_hosts_generate();
833

    
834
	/* generate resolv.conf */
835
	system_resolvconf_generate();
836

    
837
	/* enable routing */
838
	system_routing_enable();
839

    
840
	/* set up interfaces */
841
	interfaces_configure();
842

    
843
	/* start dyndns service */
844
	services_dyndns_configure();
845

    
846
	/* configure cron service */
847
	configure_cron();
848

    
849
	/* start the NTP client */
850
	system_ntp_configure();
851

    
852
	/* sync pw database */
853
	conf_mount_rw();
854
	unlink_if_exists("/etc/spwd.db.tmp");
855
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
856
	conf_mount_ro();
857

    
858
	/* restart sshd */
859
	send_event("service restart sshd");
860

    
861
	/* restart webConfigurator if needed */
862
	send_event("service restart webgui");
863
}
864

    
865
function setup_serial_port($when = "save", $path = "") {
866
	global $g, $config;
867
	conf_mount_rw();
868
	$ttys_file = "{$path}/etc/ttys";
869
	$boot_config_file = "{$path}/boot.config";
870
	$loader_conf_file = "{$path}/boot/loader.conf";
871
	/* serial console - write out /boot.config */
872
	if (file_exists($boot_config_file)) {
873
		$boot_config = file_get_contents($boot_config_file);
874
	} else {
875
		$boot_config = "";
876
	}
877

    
878
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
879
	if ($g['platform'] != "cdrom") {
880
		$serial_only = false;
881

    
882
		if (($g['platform'] == "nanobsd") && isset($g['enableserial_force'])) {
883
			$serial_only = true;
884
		} else {
885
			$specific_platform = system_identify_specific_platform();
886
			if ($specific_platform['name'] == 'RCC-VE' ||
887
			    $specific_platform['name'] == 'RCC' ||
888
			    $specific_platform['name'] == 'RCC-DFF') {
889
				$serial_only = true;
890
			}
891
		}
892

    
893
		$boot_config_split = explode("\n", $boot_config);
894
		$fd = fopen($boot_config_file, "w");
895
		if ($fd) {
896
			foreach ($boot_config_split as $bcs) {
897
				if (stristr($bcs, "-D") || stristr($bcs, "-h")) {
898
					/* DONT WRITE OUT, WE'LL DO IT LATER */
899
				} else {
900
					if ($bcs <> "") {
901
						fwrite($fd, "{$bcs}\n");
902
					}
903
				}
904
			}
905
			if ($serial_only === true) {
906
				fwrite($fd, "-S{$serialspeed} -h");
907
			} else if (is_serial_enabled()) {
908
				fwrite($fd, "-S{$serialspeed} -D");
909
			}
910
			fclose($fd);
911
		}
912

    
913
		/* serial console - write out /boot/loader.conf */
914
		if ($when == "upgrade") {
915
			system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
916
		}
917
		$boot_config = file_get_contents($loader_conf_file);
918
		$boot_config_split = explode("\n", $boot_config);
919
		if (count($boot_config_split) > 0) {
920
			$new_boot_config = array();
921
			// Loop through and only add lines that are not empty, and which
922
			//  do not contain a console directive.
923
			foreach ($boot_config_split as $bcs) {
924
				if (!empty($bcs) &&
925
				    (stripos($bcs, "console") === false) &&
926
				    (stripos($bcs, "boot_multicons") === false) &&
927
				    (stripos($bcs, "boot_serial") === false) &&
928
				    (stripos($bcs, "hw.usb.no_pf") === false) &&
929
				    (stripos($bcs, "hint.uart.0.flags") === false) &&
930
				    (stripos($bcs, "hint.uart.1.flags") === false)) {
931
					$new_boot_config[] = $bcs;
932
				}
933
			}
934

    
935
			if ($serial_only === true) {
936
				$new_boot_config[] = 'boot_serial="YES"';
937
				$new_boot_config[] = 'console="comconsole"';
938
			} else if (is_serial_enabled()) {
939
				$new_boot_config[] = 'boot_multicons="YES"';
940
				$new_boot_config[] = 'boot_serial="YES"';
941
				$primaryconsole = isset($g['primaryconsole_force']) ? $g['primaryconsole_force'] : $config['system']['primaryconsole'];
942
				switch ($primaryconsole) {
943
					case "video":
944
						$new_boot_config[] = 'console="vidconsole,comconsole"';
945
						break;
946
					case "serial":
947
					default:
948
						$new_boot_config[] = 'console="comconsole,vidconsole"';
949
				}
950
			}
951
			$new_boot_config[] = 'comconsole_speed="' . $serialspeed . '"';
952

    
953
			$specplatform = system_identify_specific_platform();
954
			if ($specplatform['name'] == 'RCC-VE' ||
955
			    $specplatform['name'] == 'RCC' ||
956
			    $specplatform['name'] == 'RCC-DFF') {
957
				$new_boot_config[] = 'comconsole_port="0x2F8"';
958
				$new_boot_config[] = 'hint.uart.0.flags="0x00"';
959
				$new_boot_config[] = 'hint.uart.1.flags="0x10"';
960
			}
961
			$new_boot_config[] = 'hw.usb.no_pf="1"';
962

    
963
			file_put_contents($loader_conf_file, implode("\n", $new_boot_config) . "\n");
964
		}
965
	}
966
	$ttys = file_get_contents($ttys_file);
967
	$ttys_split = explode("\n", $ttys);
968
	$fd = fopen($ttys_file, "w");
969

    
970
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
971

    
972
	if (isset($config['system']['disableconsolemenu'])) {
973
		$console_type = 'Pc';
974
		$serial_type = 'std.' . $serialspeed;
975
	} else {
976
		$console_type = 'al.Pc';
977
		$serial_type = 'al.' . $serialspeed;
978
	}
979
	foreach ($ttys_split as $tty) {
980
		if (stristr($tty, "ttyv0")) {
981
			fwrite($fd, "ttyv0	\"/usr/libexec/getty {$console_type}\"	cons25	on	secure\n");
982
		} else if (stristr($tty, "ttyu")) {
983
			$ttyn = substr($tty, 0, 5);
984
			fwrite($fd, "{$ttyn}	\"/usr/libexec/getty {$serial_type}\"	cons25	{$on_off}	secure\n");
985
		} else {
986
			fwrite($fd, $tty . "\n");
987
		}
988
	}
989
	unset($on_off, $console_type, $serial_type);
990
	fclose($fd);
991
	if ($when != "upgrade") {
992
		reload_ttys();
993
	}
994

    
995
	conf_mount_ro();
996
	return;
997
}
998

    
999
function is_serial_enabled() {
1000
	global $g, $config;
1001

    
1002
	if (!isset($g['enableserial_force']) &&
1003
	    !isset($config['system']['enableserial']) &&
1004
	    ($g['platform'] == $g['product_name'] || $g['platform'] == "cdrom")) {
1005
		return false;
1006
	}
1007

    
1008
	return true;
1009
}
1010

    
1011
function reload_ttys() {
1012
	// Send a HUP signal to init will make it reload /etc/ttys
1013
	posix_kill(1, SIGHUP);
1014
}
1015

    
1016
function print_value_list($list, $count = 10, $separator = ",") {
1017
	$list = implode($separator, array_slice($list, 0, $count));
1018
	if (count($list) < $count) {
1019
		$list .= ".";
1020
	} else {
1021
		$list .= "...";
1022
	}
1023
	return $list;
1024
}
1025

    
1026
/* DHCP enabled on any interfaces? */
1027
function is_dhcp_server_enabled() {
1028
	global $config;
1029

    
1030
	if (!is_array($config['dhcpd'])) {
1031
		return false;
1032
	}
1033

    
1034
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1035
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1036
			return true;
1037
		}
1038
	}
1039

    
1040
	return false;
1041
}
1042

    
1043
/* DHCP enabled on any interfaces? */
1044
function is_dhcpv6_server_enabled() {
1045
	global $config;
1046

    
1047
	if (is_array($config['interfaces'])) {
1048
		foreach ($config['interfaces'] as $ifcfg) {
1049
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1050
				return true;
1051
			}
1052
		}
1053
	}
1054

    
1055
	if (!is_array($config['dhcpdv6'])) {
1056
		return false;
1057
	}
1058

    
1059
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1060
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1061
			return true;
1062
		}
1063
	}
1064

    
1065
	return false;
1066
}
1067

    
1068
/* radvd enabled on any interfaces? */
1069
function is_radvd_enabled() {
1070
	global $config;
1071

    
1072
	if (!is_array($config['dhcpdv6'])) {
1073
		$config['dhcpdv6'] = array();
1074
	}
1075

    
1076
	$dhcpdv6cfg = $config['dhcpdv6'];
1077
	$Iflist = get_configured_interface_list();
1078

    
1079
	/* handle manually configured DHCP6 server settings first */
1080
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1081
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1082
			continue;
1083
		}
1084

    
1085
		if (!isset($dhcpv6ifconf['ramode'])) {
1086
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1087
		}
1088

    
1089
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1090
			continue;
1091
		}
1092

    
1093
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1094
		if (!is_ipaddrv6($ifcfgipv6)) {
1095
			continue;
1096
		}
1097

    
1098
		return true;
1099
	}
1100

    
1101
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1102
	foreach ($Iflist as $if => $ifdescr) {
1103
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1104
			continue;
1105
		}
1106
		if (!isset($config['interfaces'][$if]['enable'])) {
1107
			continue;
1108
		}
1109

    
1110
		$ifcfgipv6 = get_interface_ipv6($if);
1111
		if (!is_ipaddrv6($ifcfgipv6)) {
1112
			continue;
1113
		}
1114

    
1115
		$ifcfgsnv6 = get_interface_subnetv6($if);
1116
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1117

    
1118
		if (!is_ipaddrv6($subnetv6)) {
1119
			continue;
1120
		}
1121

    
1122
		return true;
1123
	}
1124

    
1125
	return false;
1126
}
1127

    
1128
/* Any PPPoE servers enabled? */
1129
function is_pppoe_server_enabled() {
1130
	global $config;
1131

    
1132
	$pppoeenable = false;
1133

    
1134
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1135
		return false;
1136
	}
1137

    
1138
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1139
		if ($pppoes['mode'] == 'server') {
1140
			$pppoeenable = true;
1141
		}
1142
	}
1143

    
1144
	return $pppoeenable;
1145
}
1146

    
1147
function convert_seconds_to_hms($sec) {
1148
	$min = $hrs = 0;
1149
	if ($sec != 0) {
1150
		$min = floor($sec/60);
1151
		$sec %= 60;
1152
	}
1153
	if ($min != 0) {
1154
		$hrs = floor($min/60);
1155
		$min %= 60;
1156
	}
1157
	if ($sec < 10) {
1158
		$sec = "0".$sec;
1159
	}
1160
	if ($min < 10) {
1161
		$min = "0".$min;
1162
	}
1163
	if ($hrs < 10) {
1164
		$hrs = "0".$hrs;
1165
	}
1166
	$result = $hrs.":".$min.":".$sec;
1167
	return $result;
1168
}
1169

    
1170
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1171

    
1172
function get_ppp_uptime($port) {
1173
	if (file_exists("/conf/{$port}.log")) {
1174
		$saved_time = file_get_contents("/conf/{$port}.log");
1175
		$uptime_data = explode("\n", $saved_time);
1176
		$sec = 0;
1177
		foreach ($uptime_data as $upt) {
1178
			$sec += substr($upt, 1 + strpos($upt, " "));
1179
		}
1180
		return convert_seconds_to_hms($sec);
1181
	} else {
1182
		$total_time = gettext("No history data found!");
1183
		return $total_time;
1184
	}
1185
}
1186

    
1187
//returns interface information
1188
function get_interface_info($ifdescr) {
1189
	global $config, $g;
1190

    
1191
	$ifinfo = array();
1192
	if (empty($config['interfaces'][$ifdescr])) {
1193
		return;
1194
	}
1195
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1196
	$ifinfo['if'] = get_real_interface($ifdescr);
1197

    
1198
	$chkif = $ifinfo['if'];
1199
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1200
	$ifinfo['status'] = $ifinfotmp['status'];
1201
	if (empty($ifinfo['status'])) {
1202
		$ifinfo['status'] = "down";
1203
	}
1204
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1205
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1206
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1207
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1208
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1209
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1210
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1211
	if (isset($ifinfotmp['link0'])) {
1212
		$link0 = "down";
1213
	}
1214
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1215
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1216
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1217
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1218
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1219
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1220

    
1221
	/* Use pfctl for non wrapping 64 bit counters */
1222
	/* Pass */
1223
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1224
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1225
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1226
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1227
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1228
	$in4_pass = $pf_in4_pass[5];
1229
	$out4_pass = $pf_out4_pass[5];
1230
	$in4_pass_packets = $pf_in4_pass[3];
1231
	$out4_pass_packets = $pf_out4_pass[3];
1232
	$in6_pass = $pf_in6_pass[5];
1233
	$out6_pass = $pf_out6_pass[5];
1234
	$in6_pass_packets = $pf_in6_pass[3];
1235
	$out6_pass_packets = $pf_out6_pass[3];
1236
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1237
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1238
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1239
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1240

    
1241
	/* Block */
1242
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1243
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1244
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1245
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1246
	$in4_block = $pf_in4_block[5];
1247
	$out4_block = $pf_out4_block[5];
1248
	$in4_block_packets = $pf_in4_block[3];
1249
	$out4_block_packets = $pf_out4_block[3];
1250
	$in6_block = $pf_in6_block[5];
1251
	$out6_block = $pf_out6_block[5];
1252
	$in6_block_packets = $pf_in6_block[3];
1253
	$out6_block_packets = $pf_out6_block[3];
1254
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1255
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1256
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1257
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1258

    
1259
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1260
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1261
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1262
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1263

    
1264
	$ifconfiginfo = "";
1265
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1266
	switch ($link_type) {
1267
		/* DHCP? -> see if dhclient is up */
1268
		case "dhcp":
1269
			/* see if dhclient is up */
1270
			if (find_dhclient_process($ifinfo['if']) != 0) {
1271
				$ifinfo['dhcplink'] = "up";
1272
			} else {
1273
				$ifinfo['dhcplink'] = "down";
1274
			}
1275

    
1276
			break;
1277
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1278
		case "pppoe":
1279
		case "pptp":
1280
		case "l2tp":
1281
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1282
				/* get PPPoE link status for dial on demand */
1283
				$ifinfo["{$link_type}link"] = "up";
1284
			} else {
1285
				$ifinfo["{$link_type}link"] = "down";
1286
			}
1287

    
1288
			break;
1289
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1290
		case "ppp":
1291
			if ($ifinfo['status'] == "up") {
1292
				$ifinfo['ppplink'] = "up";
1293
			} else {
1294
				$ifinfo['ppplink'] = "down" ;
1295
			}
1296

    
1297
			if (empty($ifinfo['status'])) {
1298
				$ifinfo['status'] = "down";
1299
			}
1300

    
1301
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1302
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1303
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1304
						break;
1305
					}
1306
				}
1307
			}
1308
			$dev = $ppp['ports'];
1309
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1310
				break;
1311
			}
1312
			if (!file_exists($dev)) {
1313
				$ifinfo['nodevice'] = 1;
1314
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1315
			}
1316

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

    
1352
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1353
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1354
		$ifinfo['ppp_uptime'] = convert_seconds_to_hms($sec);
1355
	}
1356

    
1357
	if ($ifinfo['status'] == "up") {
1358
		/* try to determine media with ifconfig */
1359
		unset($ifconfiginfo);
1360
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1361
		$wifconfiginfo = array();
1362
		if (is_interface_wireless($ifdescr)) {
1363
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1364
			array_shift($wifconfiginfo);
1365
		}
1366
		$matches = "";
1367
		foreach ($ifconfiginfo as $ici) {
1368

    
1369
			/* don't list media/speed for wireless cards, as it always
1370
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1371
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1372
				$ifinfo['media'] = $matches[1];
1373
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1374
				$ifinfo['media'] = $matches[1];
1375
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1376
				$ifinfo['media'] = $matches[1];
1377
			}
1378

    
1379
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1380
				if ($matches[1] != "active") {
1381
					$ifinfo['status'] = $matches[1];
1382
				}
1383
				if ($ifinfo['status'] == gettext("running")) {
1384
					$ifinfo['status'] = gettext("up");
1385
				}
1386
			}
1387
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1388
				$ifinfo['channel'] = $matches[1];
1389
			}
1390
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1391
				if ($matches[1][0] == '"') {
1392
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1393
				}
1394
				else {
1395
					$ifinfo['ssid'] = $matches[1];
1396
				}
1397
			}
1398
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1399
				$ifinfo['laggproto'] = $matches[1];
1400
			}
1401
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1402
				$ifinfo['laggport'][] = $matches[1];
1403
			}
1404
		}
1405
		foreach ($wifconfiginfo as $ici) {
1406
			$elements = preg_split("/[ ]+/i", $ici);
1407
			if ($elements[0] != "") {
1408
				$ifinfo['bssid'] = $elements[0];
1409
			}
1410
			if ($elements[3] != "") {
1411
				$ifinfo['rate'] = $elements[3];
1412
			}
1413
			if ($elements[4] != "") {
1414
				$ifinfo['rssi'] = $elements[4];
1415
			}
1416
		}
1417
		/* lookup the gateway */
1418
		if (interface_has_gateway($ifdescr)) {
1419
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1420
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1421
		}
1422
	}
1423

    
1424
	$bridge = "";
1425
	$bridge = link_interface_to_bridge($ifdescr);
1426
	if ($bridge) {
1427
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1428
		if (stristr($bridge_text, "blocking") <> false) {
1429
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1430
			$ifinfo['bridgeint'] = $bridge;
1431
		} else if (stristr($bridge_text, "learning") <> false) {
1432
			$ifinfo['bridge'] = gettext("learning");
1433
			$ifinfo['bridgeint'] = $bridge;
1434
		} else if (stristr($bridge_text, "forwarding") <> false) {
1435
			$ifinfo['bridge'] = gettext("forwarding");
1436
			$ifinfo['bridgeint'] = $bridge;
1437
		}
1438
	}
1439

    
1440
	return $ifinfo;
1441
}
1442

    
1443
//returns cpu speed of processor. Good for determining capabilities of machine
1444
function get_cpu_speed() {
1445
	return get_single_sysctl("hw.clockrate");
1446
}
1447

    
1448
function get_uptime_sec() {
1449
	$boottime = "";
1450
	$matches = "";
1451
	$boottime = get_single_sysctl("kern.boottime");
1452
	preg_match("/sec = (\d+)/", $boottime, $matches);
1453
	$boottime = $matches[1];
1454
	if (intval($boottime) == 0) {
1455
		return 0;
1456
	}
1457

    
1458
	$uptime = time() - $boottime;
1459
	return $uptime;
1460
}
1461

    
1462
function add_hostname_to_watch($hostname) {
1463
	if (!is_dir("/var/db/dnscache")) {
1464
		mkdir("/var/db/dnscache");
1465
	}
1466
	$result = array();
1467
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1468
		$domrecords = array();
1469
		$domips = array();
1470
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1471
		if ($rethost == 0) {
1472
			foreach ($domrecords as $domr) {
1473
				$doml = explode(" ", $domr);
1474
				$domip = $doml[3];
1475
				/* fill array with domain ip addresses */
1476
				if (is_ipaddr($domip)) {
1477
					$domips[] = $domip;
1478
				}
1479
			}
1480
		}
1481
		sort($domips);
1482
		$contents = "";
1483
		if (!empty($domips)) {
1484
			foreach ($domips as $ip) {
1485
				$contents .= "$ip\n";
1486
			}
1487
		}
1488
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1489
		/* Remove empty elements */
1490
		$result = array_filter(explode("\n", $contents), 'strlen');
1491
	}
1492
	return $result;
1493
}
1494

    
1495
function is_fqdn($fqdn) {
1496
	$hostname = false;
1497
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1498
		$hostname = true;
1499
	}
1500
	if (preg_match("/\.\./", $fqdn)) {
1501
		$hostname = false;
1502
	}
1503
	if (preg_match("/^\./i", $fqdn)) {
1504
		$hostname = false;
1505
	}
1506
	if (preg_match("/\//i", $fqdn)) {
1507
		$hostname = false;
1508
	}
1509
	return($hostname);
1510
}
1511

    
1512
function pfsense_default_state_size() {
1513
	/* get system memory amount */
1514
	$memory = get_memory();
1515
	$physmem = $memory[0];
1516
	/* Be cautious and only allocate 10% of system memory to the state table */
1517
	$max_states = (int) ($physmem/10)*1000;
1518
	return $max_states;
1519
}
1520

    
1521
function pfsense_default_tables_size() {
1522
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1523
	return $current;
1524
}
1525

    
1526
function pfsense_default_table_entries_size() {
1527
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1528
	return (trim($current));
1529
}
1530

    
1531
/* Compare the current hostname DNS to the DNS cache we made
1532
 * if it has changed we return the old records
1533
 * if no change we return false */
1534
function compare_hostname_to_dnscache($hostname) {
1535
	if (!is_dir("/var/db/dnscache")) {
1536
		mkdir("/var/db/dnscache");
1537
	}
1538
	$hostname = trim($hostname);
1539
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1540
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1541
	} else {
1542
		$oldcontents = "";
1543
	}
1544
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1545
		$domrecords = array();
1546
		$domips = array();
1547
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1548
		if ($rethost == 0) {
1549
			foreach ($domrecords as $domr) {
1550
				$doml = explode(" ", $domr);
1551
				$domip = $doml[3];
1552
				/* fill array with domain ip addresses */
1553
				if (is_ipaddr($domip)) {
1554
					$domips[] = $domip;
1555
				}
1556
			}
1557
		}
1558
		sort($domips);
1559
		$contents = "";
1560
		if (!empty($domips)) {
1561
			foreach ($domips as $ip) {
1562
				$contents .= "$ip\n";
1563
			}
1564
		}
1565
	}
1566

    
1567
	if (trim($oldcontents) != trim($contents)) {
1568
		if ($g['debug']) {
1569
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1570
		}
1571
		return ($oldcontents);
1572
	} else {
1573
		return false;
1574
	}
1575
}
1576

    
1577
/*
1578
 * load_crypto() - Load crypto modules if enabled in config.
1579
 */
1580
function load_crypto() {
1581
	global $config, $g;
1582
	$crypto_modules = array('glxsb', 'aesni');
1583

    
1584
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1585
		return false;
1586
	}
1587

    
1588
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1589
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1590
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1591
	}
1592
}
1593

    
1594
/*
1595
 * load_thermal_hardware() - Load temperature monitor kernel module
1596
 */
1597
function load_thermal_hardware() {
1598
	global $config, $g;
1599
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1600

    
1601
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1602
		return false;
1603
	}
1604

    
1605
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1606
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1607
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1608
	}
1609
}
1610

    
1611
/****f* pfsense-utils/isvm
1612
 * NAME
1613
 *   isvm
1614
 * INPUTS
1615
 *	none
1616
 * RESULT
1617
 *   returns true if machine is running under a virtual environment
1618
 ******/
1619
function isvm() {
1620
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1621
	$_gb = exec('/bin/kenv smbios.system.product 2>/dev/null', $output, $rc);
1622

    
1623
	if ($rc != 0 || !isset($output[0])) {
1624
		return false;
1625
	}
1626

    
1627
	foreach ($virtualenvs as $virtualenv) {
1628
		if (stripos($output[0], $virtualenv) !== false) {
1629
			return true;
1630
		}
1631
	}
1632

    
1633
	return false;
1634
}
1635

    
1636
function get_freebsd_version() {
1637
	$version = explode(".", php_uname("r"));
1638
	return $version[0];
1639
}
1640

    
1641
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1642
	global $config, $g;
1643

    
1644
	$fp = fopen($destination, "wb");
1645

    
1646
	if (!$fp) {
1647
		return false;
1648
	}
1649

    
1650
	$ch = curl_init();
1651
	curl_setopt($ch, CURLOPT_URL, $url);
1652
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1653
	curl_setopt($ch, CURLOPT_FILE, $fp);
1654
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1655
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1656
	curl_setopt($ch, CURLOPT_HEADER, false);
1657
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1658
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1659
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1660
	} else {
1661
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1662
	}
1663

    
1664
	if (!empty($config['system']['proxyurl'])) {
1665
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1666
		if (!empty($config['system']['proxyport'])) {
1667
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1668
		}
1669
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1670
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1671
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1672
		}
1673
	}
1674

    
1675
	@curl_exec($ch);
1676
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1677
	fclose($fp);
1678
	curl_close($ch);
1679
	if ($http_code == 200) {
1680
		return true;
1681
	} else {
1682
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1683
		unlink_if_exists($destination);
1684
		return false;
1685
	}
1686
}
1687

    
1688
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1689
	global $config, $g;
1690
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1691
	$file_size = 1;
1692
	$downloaded = 1;
1693
	$first_progress_update = TRUE;
1694
	/* open destination file */
1695
	$fout = fopen($destination, "wb");
1696

    
1697
	if (!$fout) {
1698
		return false;
1699
	}
1700
	/*
1701
	 *      Originally by Author: Keyvan Minoukadeh
1702
	 *      Modified by Scott Ullrich to return Content-Length size
1703
	 */
1704
	$ch = curl_init();
1705
	curl_setopt($ch, CURLOPT_URL, $url);
1706
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1707
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
1708
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1709
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
1710
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1711
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1712
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1713
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1714
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1715
	} else {
1716
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1717
	}
1718

    
1719
	if (!empty($config['system']['proxyurl'])) {
1720
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1721
		if (!empty($config['system']['proxyport'])) {
1722
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1723
		}
1724
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1725
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1726
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1727
		}
1728
	}
1729

    
1730
	@curl_exec($ch);
1731
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1732
	fclose($fout);
1733
	curl_close($ch);
1734
	if ($http_code == 200) {
1735
		return true;
1736
	} else {
1737
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1738
		unlink_if_exists($destination);
1739
		return false;
1740
	}
1741
}
1742

    
1743
function read_header($ch, $string) {
1744
	global $file_size, $fout;
1745
	$length = strlen($string);
1746
	$regs = "";
1747
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
1748
	if ($regs[2] <> "") {
1749
		$file_size = intval($regs[2]);
1750
	}
1751
	ob_flush();
1752
	return $length;
1753
}
1754

    
1755
function read_body($ch, $string) {
1756
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
1757
	global $pkg_interface;
1758
	$length = strlen($string);
1759
	$downloaded += intval($length);
1760
	if ($file_size > 0) {
1761
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
1762
		$downloadProgress = 100 - $downloadProgress;
1763
	} else {
1764
		$downloadProgress = 0;
1765
	}
1766
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
1767
		if ($sendto == "status") {
1768
			if ($pkg_interface == "console") {
1769
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
1770
					$tostatus = $static_status . $downloadProgress . "%";
1771
					if ($downloadProgress == 100) {
1772
						$tostatus = $tostatus . "\r";
1773
					}
1774
					update_status($tostatus);
1775
				}
1776
			} else {
1777
				$tostatus = $static_status . $downloadProgress . "%";
1778
				update_status($tostatus);
1779
			}
1780
		} else {
1781
			if ($pkg_interface == "console") {
1782
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
1783
					$tooutput = $static_output . $downloadProgress . "%";
1784
					if ($downloadProgress == 100) {
1785
						$tooutput = $tooutput . "\r";
1786
					}
1787
					update_output_window($tooutput);
1788
				}
1789
			} else {
1790
				$tooutput = $static_output . $downloadProgress . "%";
1791
				update_output_window($tooutput);
1792
			}
1793
		}
1794
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
1795
			update_progress_bar($downloadProgress, $first_progress_update);
1796
			$first_progress_update = FALSE;
1797
		}
1798
		$lastseen = $downloadProgress;
1799
	}
1800
	if ($fout) {
1801
		fwrite($fout, $string);
1802
	}
1803
	ob_flush();
1804
	return $length;
1805
}
1806

    
1807
/*
1808
 *   update_output_window: update bottom textarea dynamically.
1809
 */
1810
function update_output_window($text) {
1811
	global $pkg_interface;
1812
	$log = preg_replace("/\n/", "\\n", $text);
1813
	if ($pkg_interface != "console") {
1814
?>
1815
<script type="text/javascript">
1816
//<![CDATA[
1817
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
1818
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
1819
//]]>
1820
</script>
1821
<?php
1822
	}
1823
	/* ensure that contents are written out */
1824
	ob_flush();
1825
}
1826

    
1827
/*
1828
 *   update_status: update top textarea dynamically.
1829
 */
1830
function update_status($status) {
1831
	global $pkg_interface;
1832

    
1833
	if ($pkg_interface == "console") {
1834
		print ("{$status}");
1835
	}
1836

    
1837
	/* ensure that contents are written out */
1838
	ob_flush();
1839
}
1840

    
1841
/*
1842
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
1843
 */
1844
function update_progress_bar($percent, $first_time) {
1845
	global $pkg_interface;
1846
	if ($percent > 100) {
1847
		$percent = 1;
1848
	}
1849
	if ($pkg_interface <> "console") {
1850
		echo '<script type="text/javascript">';
1851
		echo "\n//<![CDATA[\n";
1852
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
1853
		echo "\n//]]>\n";
1854
		echo '</script>';
1855
	} else {
1856
		if (!($first_time)) {
1857
			echo "\x08\x08\x08\x08\x08";
1858
		}
1859
		echo sprintf("%4d%%", $percent);
1860
	}
1861
}
1862

    
1863
/* 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. */
1864
if (!function_exists("split")) {
1865
	function split($separator, $haystack, $limit = null) {
1866
		log_error("deprecated split() call with separator '{$separator}'");
1867
		return preg_split($separator, $haystack, $limit);
1868
	}
1869
}
1870

    
1871
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
1872
	global $g, $config, $pconfig, $debug;
1873
	if (!$origname) {
1874
		return;
1875
	}
1876

    
1877
	$sectionref = &$config;
1878
	foreach ($section as $sectionname) {
1879
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
1880
			$sectionref = &$sectionref[$sectionname];
1881
		} else {
1882
			return;
1883
		}
1884
	}
1885

    
1886
	if ($debug) {
1887
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
1888
		fwrite($fd, print_r($pconfig, true));
1889
	}
1890

    
1891
	if (is_array($sectionref)) {
1892
		foreach ($sectionref as $itemkey => $item) {
1893
			if ($debug) {
1894
				fwrite($fd, "$itemkey\n");
1895
			}
1896

    
1897
			$fieldfound = true;
1898
			$fieldref = &$sectionref[$itemkey];
1899
			foreach ($field as $fieldname) {
1900
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
1901
					$fieldref = &$fieldref[$fieldname];
1902
				} else {
1903
					$fieldfound = false;
1904
					break;
1905
				}
1906
			}
1907
			if ($fieldfound && $fieldref == $origname) {
1908
				if ($debug) {
1909
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
1910
				}
1911
				$fieldref = $new_alias_name;
1912
			}
1913
		}
1914
	}
1915

    
1916
	if ($debug) {
1917
		fclose($fd);
1918
	}
1919

    
1920
}
1921

    
1922
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
1923
	/*
1924
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
1925
	 * $type = if set to 'url' then subnets and ips will be returned,
1926
	 *         if set to 'url_ports' port-ranges and ports will be returned
1927
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
1928
	 *
1929
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
1930
	 */
1931

    
1932
	if (filesize($filename) == 0) {
1933
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
1934
		return null;
1935
	}
1936
	$fd = @fopen($filename, 'r');
1937
	if (!$fd) {
1938
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
1939
		return null;
1940
	}
1941
	$items = array();
1942
	$comments = array();
1943
	/* NOTE: fgetss() is not a typo RTFM before being smart */
1944
	while (($fc = fgetss($fd)) !== FALSE) {
1945
		$tmp = trim($fc, " \t\n\r");
1946
		if (empty($tmp)) {
1947
			continue;
1948
		}
1949
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
1950
			$comments[] = $tmp;
1951
		} else {
1952
			$tmp_str = strstr($tmp, '#', true);
1953
			if (!empty($tmp_str)) {
1954
				$tmp = $tmp_str;
1955
			}
1956
			$tmp_str = strstr($tmp, ' ', true);
1957
			if (!empty($tmp_str)) {
1958
				$tmp = $tmp_str;
1959
			}
1960
			$valid = ($type == "url" && (is_ipaddr($tmp) || is_subnet($tmp))) ||
1961
				($type == "url_ports" && (is_port($tmp) || is_portrange($tmp)));
1962
			if ($valid) {
1963
				$items[] = $tmp;
1964
				if (count($items) == $max_items) {
1965
					break;
1966
				}
1967
			}
1968
		}
1969
	}
1970
	fclose($fd);
1971
	return array_merge($comments, $items);
1972
}
1973

    
1974
function update_alias_url_data() {
1975
	global $config, $g;
1976

    
1977
	$updated = false;
1978

    
1979
	/* item is a url type */
1980
	$lockkey = lock('aliasurl');
1981
	if (is_array($config['aliases']['alias'])) {
1982
		foreach ($config['aliases']['alias'] as $x => $alias) {
1983
			if (empty($alias['aliasurl'])) {
1984
				continue;
1985
			}
1986

    
1987
			$address = null;
1988
			foreach ($alias['aliasurl'] as $alias_url) {
1989
				/* fetch down and add in */
1990
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
1991
				unlink($temp_filename);
1992
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
1993
				mkdir($temp_filename);
1994
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
1995
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
1996
					continue;
1997
				}
1998

    
1999
				/* if the item is tar gzipped then extract */
2000
				if (stripos($alias_url, '.tgz')) {
2001
					if (!process_alias_tgz($temp_filename)) {
2002
						continue;
2003
					}
2004
				}
2005
				if (file_exists("{$temp_filename}/aliases")) {
2006
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2007
					mwexec("/bin/rm -rf {$temp_filename}");
2008
				}
2009
			}
2010
			if ($address != null) {
2011
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2012
				$updated = true;
2013
			}
2014
		}
2015
	}
2016
	unlock($lockkey);
2017

    
2018
	/* Report status to callers as well */
2019
	return $updated;
2020
}
2021

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

    
2052
	return true;
2053
}
2054

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

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

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

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

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

    
2156
	$urltable_prefix = "/var/db/aliastables/";
2157
	$urltable_filename = $urltable_prefix . $name . ".txt";
2158
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2159

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

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

    
2173
		// Try to fetch the URL supplied
2174
		conf_mount_rw();
2175
		unlink_if_exists($tmp_urltable_filename);
2176
		$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2177
		if (download_file($url, $tmp_urltable_filename, $verify_ssl)) {
2178
			// Convert lines that begin with '$' or ';' to comments '#' instead of deleting them.
2179
			mwexec("/usr/bin/sed -i \"\" -E 's/^[[:space:]]*($|#|;)/#/g; /^#/!s/\;.*//g;' ". escapeshellarg($tmp_urltable_filename));
2180
			if (alias_get_type($name) == "urltable_ports") {
2181
				$ports = parse_aliases_file($tmp_urltable_filename, "url_ports", "-1", true);
2182
				$ports = group_ports($ports, true);
2183
				file_put_contents($urltable_filename, implode("\n", $ports));
2184
			} else {
2185
				$urltable = parse_aliases_file($tmp_urltable_filename, "url", "-1", true);
2186
				if (is_array($urltable)) {
2187
					file_put_contents($urltable_filename, implode("\n", $urltable));
2188
				}
2189
			}
2190
			unlink_if_exists($tmp_urltable_filename);
2191
		} else {
2192
			if (!$validateonly) {
2193
				touch($urltable_filename);
2194
			}
2195
			conf_mount_ro();
2196
			return false;
2197
		}
2198
		conf_mount_ro();
2199
		return true;
2200
	} else {
2201
		// File exists, and it doesn't need to be updated.
2202
		return -1;
2203
	}
2204
}
2205
function get_real_slice_from_glabel($label) {
2206
	$label = escapeshellarg($label);
2207
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/{$label} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`);
2208
}
2209
function nanobsd_get_boot_slice() {
2210
	return trim(`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`);
2211
}
2212
function nanobsd_get_boot_drive() {
2213
	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`);
2214
}
2215
function nanobsd_get_active_slice() {
2216
	$boot_drive = nanobsd_get_boot_drive();
2217
	$active = trim(`gpart show $boot_drive | grep '\[active\]' | awk '{print $3;}'`);
2218

    
2219
	return "{$boot_drive}s{$active}";
2220
}
2221
function nanobsd_get_size() {
2222
	return strtoupper(file_get_contents("/etc/nanosize.txt"));
2223
}
2224
function nanobsd_switch_boot_slice() {
2225
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2226
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2227
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2228
	nanobsd_detect_slice_info();
2229

    
2230
	if ($BOOTFLASH == $ACTIVE_SLICE) {
2231
		$slice = $TOFLASH;
2232
	} else {
2233
		$slice = $BOOTFLASH;
2234
	}
2235

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

    
2274
	for ($i = 0; $i < ob_get_level(); $i++) {
2275
		ob_end_flush();
2276
	}
2277
	ob_implicit_flush(1);
2278
	set_single_sysctl("kern.geom.debugflags", "16");
2279
	exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
2280
	exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
2281
	exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
2282
	$status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
2283
	set_single_sysctl("kern.geom.debugflags", "0");
2284
	if ($status) {
2285
		return false;
2286
	} else {
2287
		return true;
2288
	}
2289
}
2290
function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
2291
	$tmppath = "/tmp/{$gslice}";
2292
	$fstabpath = "/tmp/{$gslice}/etc/fstab";
2293

    
2294
	mkdir($tmppath);
2295
	exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
2296
	exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
2297
	copy("/etc/fstab", $fstabpath);
2298

    
2299
	if (!file_exists($fstabpath)) {
2300
		$fstab = <<<EOF
2301
/dev/ufs/{$gslice} / ufs ro,noatime 1 1
2302
/dev/ufs/cf /cf ufs ro,noatime 1 1
2303
EOF;
2304
		if (file_put_contents($fstabpath, $fstab)) {
2305
			$status = true;
2306
		} else {
2307
			$status = false;
2308
		}
2309
	} else {
2310
		$status = exec("/usr/bin/sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
2311
	}
2312
	exec("/sbin/umount {$tmppath}");
2313
	rmdir($tmppath);
2314

    
2315
	return $status;
2316
}
2317
function nanobsd_detect_slice_info() {
2318
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2319
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2320
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2321

    
2322
	$BOOT_DEVICE=nanobsd_get_boot_slice();
2323
	$REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
2324
	$BOOT_DRIVE=nanobsd_get_boot_drive();
2325
	$ACTIVE_SLICE=nanobsd_get_active_slice();
2326

    
2327
	// Detect which slice is active and set information.
2328
	if (strstr($REAL_BOOT_DEVICE, "s1")) {
2329
		$SLICE = "2";
2330
		$OLDSLICE = "1";
2331
		$GLABEL_SLICE = "pfsense1";
2332
		$UFS_ID = "1";
2333
		$OLD_UFS_ID = "0";
2334

    
2335
	} else {
2336
		$SLICE = "1";
2337
		$OLDSLICE = "2";
2338
		$GLABEL_SLICE = "pfsense0";
2339
		$UFS_ID = "0";
2340
		$OLD_UFS_ID = "1";
2341
	}
2342
	$TOFLASH = "{$BOOT_DRIVE}s{$SLICE}";
2343
	$COMPLETE_PATH = "{$BOOT_DRIVE}s{$SLICE}a";
2344
	$COMPLETE_BOOT_PATH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2345
	$BOOTFLASH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2346
}
2347

    
2348
function nanobsd_friendly_slice_name($slicename) {
2349
	global $g;
2350
	return strtolower(str_ireplace('pfsense', $g['product_name'], $slicename));
2351
}
2352

    
2353
function get_include_contents($filename) {
2354
	if (is_file($filename)) {
2355
		ob_start();
2356
		include $filename;
2357
		$contents = ob_get_contents();
2358
		ob_end_clean();
2359
		return $contents;
2360
	}
2361
	return false;
2362
}
2363

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

    
2476
function get_country_name($country_code) {
2477
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2478
		return "";
2479
	}
2480

    
2481
	$country_names_xml = "/usr/local/share/mobile-broadband-provider-info/iso_3166-1_list_en.xml";
2482
	$country_names_contents = file_get_contents($country_names_xml);
2483
	$country_names = xml2array($country_names_contents);
2484

    
2485
	if ($country_code == "ALL") {
2486
		$country_list = array();
2487
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2488
			$country_list[] = array(
2489
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2490
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2491
		}
2492
		return $country_list;
2493
	}
2494

    
2495
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2496
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2497
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2498
		}
2499
	}
2500
	return "";
2501
}
2502

    
2503
/* sort by interface only, retain the original order of rules that apply to
2504
   the same interface */
2505
function filter_rules_sort() {
2506
	global $config;
2507

    
2508
	/* mark each rule with the sequence number (to retain the order while sorting) */
2509
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2510
		$config['filter']['rule'][$i]['seq'] = $i;
2511
	}
2512

    
2513
	usort($config['filter']['rule'], "filter_rules_compare");
2514

    
2515
	/* strip the sequence numbers again */
2516
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2517
		unset($config['filter']['rule'][$i]['seq']);
2518
	}
2519
}
2520
function filter_rules_compare($a, $b) {
2521
	if (isset($a['floating']) && isset($b['floating'])) {
2522
		return $a['seq'] - $b['seq'];
2523
	} else if (isset($a['floating'])) {
2524
		return -1;
2525
	} else if (isset($b['floating'])) {
2526
		return 1;
2527
	} else if ($a['interface'] == $b['interface']) {
2528
		return $a['seq'] - $b['seq'];
2529
	} else {
2530
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2531
	}
2532
}
2533

    
2534
function generate_ipv6_from_mac($mac) {
2535
	$elements = explode(":", $mac);
2536
	if (count($elements) <> 6) {
2537
		return false;
2538
	}
2539

    
2540
	$i = 0;
2541
	$ipv6 = "fe80::";
2542
	foreach ($elements as $byte) {
2543
		if ($i == 0) {
2544
			$hexadecimal = substr($byte, 1, 2);
2545
			$bitmap = base_convert($hexadecimal, 16, 2);
2546
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2547
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2548
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2549
		}
2550
		$ipv6 .= $byte;
2551
		if ($i == 1) {
2552
			$ipv6 .= ":";
2553
		}
2554
		if ($i == 3) {
2555
			$ipv6 .= ":";
2556
		}
2557
		if ($i == 2) {
2558
			$ipv6 .= "ff:fe";
2559
		}
2560

    
2561
		$i++;
2562
	}
2563
	return $ipv6;
2564
}
2565

    
2566
/****f* pfsense-utils/load_mac_manufacturer_table
2567
 * NAME
2568
 *   load_mac_manufacturer_table
2569
 * INPUTS
2570
 *   none
2571
 * RESULT
2572
 *   returns associative array with MAC-Manufacturer pairs
2573
 ******/
2574
function load_mac_manufacturer_table() {
2575
	/* load MAC-Manufacture data from the file */
2576
	$macs = false;
2577
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2578
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2579
	}
2580
	if ($macs) {
2581
		foreach ($macs as $line) {
2582
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2583
				/* store values like this $mac_man['000C29']='VMware' */
2584
				$mac_man["$matches[1]"] = $matches[2];
2585
			}
2586
		}
2587
		return $mac_man;
2588
	} else {
2589
		return -1;
2590
	}
2591

    
2592
}
2593

    
2594
/****f* pfsense-utils/is_ipaddr_configured
2595
 * NAME
2596
 *   is_ipaddr_configured
2597
 * INPUTS
2598
 *   IP Address to check.
2599
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2600
 *   check_localip - if true then also check for matches with PPTP and LT2P addresses
2601
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2602
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2603
 *     If check_subnets is true and cidrprefix is specified,
2604
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2605
 * RESULT
2606
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2607
*/
2608
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2609
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2610
		return true;
2611
	}
2612
	return false;
2613
}
2614

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

    
2633
	$where_configured = array();
2634

    
2635
	$pos = strpos($ignore_if, '_virtualip');
2636
	if ($pos !== false) {
2637
		$ignore_vip_id = substr($ignore_if, $pos+10);
2638
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2639
	} else {
2640
		$ignore_vip_id = -1;
2641
		$ignore_vip_if = $ignore_if;
2642
	}
2643

    
2644
	$isipv6 = is_ipaddrv6($ipaddr);
2645

    
2646
	if ($check_subnets) {
2647
		$cidrprefix = intval($cidrprefix);
2648
		if ($isipv6) {
2649
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2650
				$cidrprefix = 128;
2651
			}
2652
		} else {
2653
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2654
				$cidrprefix = 32;
2655
			}
2656
		}
2657
		$iflist = get_configured_interface_list();
2658
		foreach ($iflist as $if => $ifname) {
2659
			if ($ignore_if == $if) {
2660
				continue;
2661
			}
2662

    
2663
			if ($isipv6) {
2664
				$if_ipv6 = get_interface_ipv6($if);
2665
				$if_snbitsv6 = get_interface_subnetv6($if);
2666
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2667
					$where_entry = array();
2668
					$where_entry['if'] = $if;
2669
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2670
					$where_configured[] = $where_entry;
2671
				}
2672
			} else {
2673
				$if_ipv4 = get_interface_ip($if);
2674
				$if_snbitsv4 = get_interface_subnet($if);
2675
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2676
					$where_entry = array();
2677
					$where_entry['if'] = $if;
2678
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2679
					$where_configured[] = $where_entry;
2680
				}
2681
			}
2682
		}
2683
	} else {
2684
		if ($isipv6) {
2685
			$interface_list_ips = get_configured_ipv6_addresses();
2686
		} else {
2687
			$interface_list_ips = get_configured_ip_addresses();
2688
		}
2689

    
2690
		foreach ($interface_list_ips as $if => $ilips) {
2691
			if ($ignore_if == $if) {
2692
				continue;
2693
			}
2694
			if (strcasecmp($ipaddr, $ilips) == 0) {
2695
				$where_entry = array();
2696
				$where_entry['if'] = $if;
2697
				$where_entry['ip_or_subnet'] = $ilips;
2698
				$where_configured[] = $where_entry;
2699
			}
2700
		}
2701
	}
2702

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

    
2712
	return $where_configured;
2713
}
2714

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

    
2737
function set_language() {
2738
	global $config, $g;
2739

    
2740
	if (!empty($config['system']['language'])) {
2741
		$lang = $config['system']['language'];
2742
	} elseif (!empty($g['language'])) {
2743
		$lang = $g['language'];
2744
	}
2745
	$lang .= ".UTF-8";
2746

    
2747
	putenv("LANG={$lang}");
2748
	setlocale(LC_ALL, $lang);
2749
	textdomain("pfSense");
2750
	bindtextdomain("pfSense", "/usr/local/share/locale");
2751
	bind_textdomain_codeset("pfSense", $lang);
2752
}
2753

    
2754
function get_locale_list() {
2755
	$locales = array(
2756
		"en_US" => gettext("English"),
2757
		"pt_BR" => gettext("Portuguese (Brazil)"),
2758
		"tr" => gettext("Turkish"),
2759
	);
2760
	asort($locales);
2761
	return $locales;
2762
}
2763

    
2764
function return_hex_ipv4($ipv4) {
2765
	if (!is_ipaddrv4($ipv4)) {
2766
		return(false);
2767
	}
2768

    
2769
	/* we need the hex form of the interface IPv4 address */
2770
	$ip4arr = explode(".", $ipv4);
2771
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
2772
}
2773

    
2774
function convert_ipv6_to_128bit($ipv6) {
2775
	if (!is_ipaddrv6($ipv6)) {
2776
		return(false);
2777
	}
2778

    
2779
	$ip6arr = array();
2780
	$ip6prefix = Net_IPv6::uncompress($ipv6);
2781
	$ip6arr = explode(":", $ip6prefix);
2782
	/* binary presentation of the prefix for all 128 bits. */
2783
	$ip6prefixbin = "";
2784
	foreach ($ip6arr as $element) {
2785
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
2786
	}
2787
	return($ip6prefixbin);
2788
}
2789

    
2790
function convert_128bit_to_ipv6($ip6bin) {
2791
	if (strlen($ip6bin) <> 128) {
2792
		return(false);
2793
	}
2794

    
2795
	$ip6arr = array();
2796
	$ip6binarr = array();
2797
	$ip6binarr = str_split($ip6bin, 16);
2798
	foreach ($ip6binarr as $binpart) {
2799
		$ip6arr[] = dechex(bindec($binpart));
2800
	}
2801
	$ip6addr = Net_IPv6::compress(implode(":", $ip6arr));
2802

    
2803
	return($ip6addr);
2804
}
2805

    
2806

    
2807
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
2808
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
2809
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
2810
/* 6to4 is 16 bits, e.g. 65535 */
2811
function calculate_ipv6_delegation_length($if) {
2812
	global $config;
2813

    
2814
	if (!is_array($config['interfaces'][$if])) {
2815
		return false;
2816
	}
2817

    
2818
	switch ($config['interfaces'][$if]['ipaddrv6']) {
2819
		case "6to4":
2820
			$pdlen = 16;
2821
			break;
2822
		case "6rd":
2823
			$rd6cfg = $config['interfaces'][$if];
2824
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
2825
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
2826
			break;
2827
		case "dhcp6":
2828
			$dhcp6cfg = $config['interfaces'][$if];
2829
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
2830
			break;
2831
		default:
2832
			$pdlen = 0;
2833
			break;
2834
	}
2835
	return($pdlen);
2836
}
2837

    
2838
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
2839
	$prefix = Net_IPv6::uncompress($prefix, true);
2840
	$suffix = Net_IPv6::uncompress($suffix, true);
2841

    
2842
	/*
2843
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
2844
	 *                ^^^^ ^
2845
	 *                |||| \-> 64
2846
	 *                |||\---> 63, 62, 61, 60
2847
	 *                ||\----> 56
2848
	 *                |\-----> 52
2849
	 *                \------> 48
2850
	 */
2851

    
2852
	switch ($len) {
2853
	case 48:
2854
		$prefix_len = 15;
2855
		break;
2856
	case 52:
2857
		$prefix_len = 16;
2858
		break;
2859
	case 56:
2860
		$prefix_len = 17;
2861
		break;
2862
	case 60:
2863
		$prefix_len = 18;
2864
		break;
2865
	/*
2866
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
2867
	 * we let user chose this bit it can end up out of PD network
2868
	 *
2869
	 * Leave this with 20 for now until we find a way to let user
2870
	 * chose it. The side-effect is users with PD with one of these
2871
	 * lengths will not be able to setup DHCP server range for full
2872
	 * PD size, only for last /64 network
2873
	 */
2874
	case 63:
2875
	case 62:
2876
	case 61:
2877
	default:
2878
		$prefix_len = 20;
2879
		break;
2880
	}
2881

    
2882
	return Net_IPv6::compress(substr($prefix, 0, $prefix_len) .
2883
	    substr($suffix, $prefix_len));
2884
}
2885

    
2886
function dhcpv6_pd_str_help($pdlen) {
2887
	$result = '';
2888

    
2889
	switch ($pdlen) {
2890
	case 48:
2891
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
2892
		break;
2893
	case 52:
2894
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
2895
		break;
2896
	case 56:
2897
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
2898
		break;
2899
	case 60:
2900
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
2901
		break;
2902
	/*
2903
	 * XXX 63, 62 and 61 should use same mask of 60 but it would
2904
	 * we let user chose this bit it can end up out of PD network
2905
	 *
2906
	 * Leave this with the same of 64 for now until we find a way to
2907
	 * let user chose it. The side-effect is users with PD with one
2908
	 * of these lengths will not be able to setup DHCP server range
2909
	 * for full PD size, only for last /64 network
2910
	 */
2911
	case 61:
2912
	case 62:
2913
	case 63:
2914
	case 64:
2915
		$result = '::xxxx:xxxx:xxxx:xxxx';
2916
		break;
2917
	}
2918

    
2919
	return $result;
2920
}
2921

    
2922
function huawei_rssi_to_string($rssi) {
2923
	$dbm = array();
2924
	$i = 0;
2925
	$dbstart = -113;
2926
	while ($i < 32) {
2927
		$dbm[$i] = $dbstart + ($i * 2);
2928
		$i++;
2929
	}
2930
	$percent = round(($rssi / 31) * 100);
2931
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
2932
	return $string;
2933
}
2934

    
2935
function huawei_mode_to_string($mode, $submode) {
2936
	$modes[0] = gettext("None");
2937
	$modes[1] = "AMPS";
2938
	$modes[2] = "CDMA";
2939
	$modes[3] = "GSM/GPRS";
2940
	$modes[4] = "HDR";
2941
	$modes[5] = "WCDMA";
2942
	$modes[6] = "GPS";
2943

    
2944
	$submodes[0] = gettext("No Service");
2945
	$submodes[1] = "GSM";
2946
	$submodes[2] = "GPRS";
2947
	$submodes[3] = "EDGE";
2948
	$submodes[4] = "WCDMA";
2949
	$submodes[5] = "HSDPA";
2950
	$submodes[6] = "HSUPA";
2951
	$submodes[7] = "HSDPA+HSUPA";
2952
	$submodes[8] = "TD-SCDMA";
2953
	$submodes[9] = "HSPA+";
2954
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
2955
	return $string;
2956
}
2957

    
2958
function huawei_service_to_string($state) {
2959
	$modes[0] = gettext("No Service");
2960
	$modes[1] = gettext("Restricted Service");
2961
	$modes[2] = gettext("Valid Service");
2962
	$modes[3] = gettext("Restricted Regional Service");
2963
	$modes[4] = gettext("Powersaving Service");
2964
	$string = $modes[$state];
2965
	return $string;
2966
}
2967

    
2968
function huawei_simstate_to_string($state) {
2969
	$modes[0] = gettext("Invalid SIM/locked State");
2970
	$modes[1] = gettext("Valid SIM State");
2971
	$modes[2] = gettext("Invalid SIM CS State");
2972
	$modes[3] = gettext("Invalid SIM PS State");
2973
	$modes[4] = gettext("Invalid SIM CS/PS State");
2974
	$modes[255] = gettext("Missing SIM State");
2975
	$string = $modes[$state];
2976
	return $string;
2977
}
2978

    
2979
function zte_rssi_to_string($rssi) {
2980
	return huawei_rssi_to_string($rssi);
2981
}
2982

    
2983
function zte_mode_to_string($mode, $submode) {
2984
	$modes[0] = gettext("No Service");
2985
	$modes[1] = gettext("Limited Service");
2986
	$modes[2] = "GPRS";
2987
	$modes[3] = "GSM";
2988
	$modes[4] = "UMTS";
2989
	$modes[5] = "EDGE";
2990
	$modes[6] = "HSDPA";
2991

    
2992
	$submodes[0] = "CS_ONLY";
2993
	$submodes[1] = "PS_ONLY";
2994
	$submodes[2] = "CS_PS";
2995
	$submodes[3] = "CAMPED";
2996
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
2997
	return $string;
2998
}
2999

    
3000
function zte_service_to_string($service) {
3001
	$modes[0] = gettext("Initializing Service");
3002
	$modes[1] = gettext("Network Lock error Service");
3003
	$modes[2] = gettext("Network Locked Service");
3004
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3005
	$string = $modes[$service];
3006
	return $string;
3007
}
3008

    
3009
function zte_simstate_to_string($state) {
3010
	$modes[0] = gettext("No action State");
3011
	$modes[1] = gettext("Network lock State");
3012
	$modes[2] = gettext("(U)SIM card lock State");
3013
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3014
	$string = $modes[$state];
3015
	return $string;
3016
}
3017

    
3018
function get_configured_pppoe_server_interfaces() {
3019
	global $config;
3020
	$iflist = array();
3021
	if (is_array($config['pppoes']['pppoe'])) {
3022
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3023
			if ($pppoe['mode'] == "server") {
3024
				$int = "poes". $pppoe['pppoeid'];
3025
				$iflist[$int] = strtoupper($int);
3026
			}
3027
		}
3028
	}
3029
	return $iflist;
3030
}
3031

    
3032
function get_pppoes_child_interfaces($ifpattern) {
3033
	$if_arr = array();
3034
	if ($ifpattern == "") {
3035
		return;
3036
	}
3037

    
3038
	exec("/sbin/ifconfig", $out, $ret);
3039
	foreach ($out as $line) {
3040
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3041
			$if_arr[] = $match[1];
3042
		}
3043
	}
3044
	return $if_arr;
3045

    
3046
}
3047

    
3048
/****f* pfsense-utils/pkg_call_plugins
3049
 * NAME
3050
 *   pkg_call_plugins
3051
 * INPUTS
3052
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3053
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3054
 * RESULT
3055
 *   returns associative array results from the plugin calls for each package
3056
 * NOTES
3057
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3058
 ******/
3059
function pkg_call_plugins($plugin_type, $plugin_params) {
3060
	global $g, $config;
3061
	$results = array();
3062
	if (!is_array($config['installedpackages']['package'])) {
3063
		return $results;
3064
	}
3065
	foreach ($config['installedpackages']['package'] as $package) {
3066
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
3067
			continue;
3068
		}
3069
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
3070
		$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3071
		if (is_array($pkg_config['plugins']['item'])) {
3072
			foreach ($pkg_config['plugins']['item'] as $plugin) {
3073
				if ($plugin['type'] == $plugin_type) {
3074
					if (file_exists($pkg_config['include_file'])) {
3075
						require_once($pkg_config['include_file']);
3076
					} else {
3077
						continue;
3078
					}
3079
					$plugin_function = $pkgname . '_'. $plugin_type;
3080
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3081
				}
3082
			}
3083
		}
3084
	}
3085
	return $results;
3086
}
3087

    
3088
?>
(39-39/65)