Project

General

Profile

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

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

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

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

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

    
34
/*
35
	pfSense_BUILDER_BINARIES:	/sbin/ifconfig	/sbin/pfctl	/usr/local/bin/php-cgi /usr/bin/netstat
36
	pfSense_BUILDER_BINARIES:	/bin/df	/usr/bin/grep	/usr/bin/awk	/bin/rm	/usr/sbin/pwd_mkdb	/usr/bin/host
37
	pfSense_BUILDER_BINARIES:	/sbin/kldload
38
	pfSense_MODULE:	utils
39
*/
40

    
41
/****f* pfsense-utils/have_natpfruleint_access
42
 * NAME
43
 *   have_natpfruleint_access
44
 * INPUTS
45
 *	none
46
 * RESULT
47
 *   returns true if user has access to edit a specific firewall nat port forward interface
48
 ******/
49
function have_natpfruleint_access($if) {
50
	$security_url = "firewall_nat_edit.php?if=". strtolower($if);
51
	if (isAllowedPage($security_url, $allowed)) {
52
		return true;
53
	}
54
	return false;
55
}
56

    
57
/****f* pfsense-utils/have_ruleint_access
58
 * NAME
59
 *   have_ruleint_access
60
 * INPUTS
61
 *	none
62
 * RESULT
63
 *   returns true if user has access to edit a specific firewall interface
64
 ******/
65
function have_ruleint_access($if) {
66
	$security_url = "firewall_rules.php?if=". strtolower($if);
67
	if (isAllowedPage($security_url)) {
68
		return true;
69
	}
70
	return false;
71
}
72

    
73
/****f* pfsense-utils/does_url_exist
74
 * NAME
75
 *   does_url_exist
76
 * INPUTS
77
 *	none
78
 * RESULT
79
 *   returns true if a url is available
80
 ******/
81
function does_url_exist($url) {
82
	$fd = fopen("$url", "r");
83
	if ($fd) {
84
		fclose($fd);
85
		return true;
86
	} else {
87
		return false;
88
	}
89
}
90

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

    
115
/****f* pfsense-utils/get_tmp_file
116
 * NAME
117
 *   get_tmp_file
118
 * INPUTS
119
 *	none
120
 * RESULT
121
 *   returns a temporary filename
122
 ******/
123
function get_tmp_file() {
124
	global $g;
125
	return "{$g['tmp_path']}/tmp-" . time();
126
}
127

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

    
152
function hardware_offloading_applyflags($iface) {
153
	global $config;
154

    
155
	$flags_on = 0;
156
	$flags_off = 0;
157
	$options = pfSense_get_interface_addresses($iface);
158

    
159
	if (isset($config['system']['disablechecksumoffloading'])) {
160
		if (isset($options['encaps']['txcsum'])) {
161
			$flags_off |= IFCAP_TXCSUM;
162
		}
163
		if (isset($options['encaps']['rxcsum'])) {
164
			$flags_off |= IFCAP_RXCSUM;
165
		}
166
	} else {
167
		if (isset($options['caps']['txcsum'])) {
168
			$flags_on |= IFCAP_TXCSUM;
169
		}
170
		if (isset($options['caps']['rxcsum'])) {
171
			$flags_on |= IFCAP_RXCSUM;
172
		}
173
	}
174

    
175
	if (isset($config['system']['disablesegmentationoffloading'])) {
176
		$flags_off |= IFCAP_TSO;
177
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
178
		$flags_on |= IFCAP_TSO;
179
	}
180

    
181
	if (isset($config['system']['disablelargereceiveoffloading'])) {
182
		$flags_off |= IFCAP_LRO;
183
	} else if (isset($options['caps']['lro'])) {
184
		$flags_on |= IFCAP_LRO;
185
	}
186

    
187
	/* if the NIC supports polling *AND* it is enabled in the GUI */
188
	if (!isset($config['system']['polling'])) {
189
		$flags_off |= IFCAP_POLLING;
190
	} else if (isset($options['caps']['polling'])) {
191
		$flags_on |= IFCAP_POLLING;
192
	}
193

    
194
	pfSense_interface_capabilities($iface, -$flags_off);
195
	pfSense_interface_capabilities($iface, $flags_on);
196
}
197

    
198
/****f* pfsense-utils/enable_hardware_offloading
199
 * NAME
200
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
201
 * INPUTS
202
 *   $interface	- string containing the physical interface to work on.
203
 * RESULT
204
 *   null
205
 * NOTES
206
 *   This function only supports the fxp driver's loadable microcode.
207
 ******/
208
function enable_hardware_offloading($interface) {
209
	global $g, $config;
210

    
211
	$int = get_real_interface($interface);
212
	if (empty($int)) {
213
		return;
214
	}
215

    
216
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
217
		/* translate wan, lan, opt -> real interface if needed */
218
		$int_family = preg_split("/[0-9]+/", $int);
219
		$supported_ints = array('fxp');
220
		if (in_array($int_family, $supported_ints)) {
221
			if (does_interface_exist($int)) {
222
				pfSense_interface_flags($int, IFF_LINK0);
223
			}
224
		}
225
	}
226

    
227
	/* This is mostly for vlans and ppp types */
228
	$realhwif = get_parent_interface($interface);
229
	if ($realhwif[0] == $int) {
230
		hardware_offloading_applyflags($int);
231
	} else {
232
		hardware_offloading_applyflags($realhwif[0]);
233
		hardware_offloading_applyflags($int);
234
	}
235
}
236

    
237
/****f* pfsense-utils/interface_supports_polling
238
 * NAME
239
 *   checks to see if an interface supports polling according to man polling
240
 * INPUTS
241
 *
242
 * RESULT
243
 *   true or false
244
 * NOTES
245
 *
246
 ******/
247
function interface_supports_polling($iface) {
248
	$opts = pfSense_get_interface_addresses($iface);
249
	if (is_array($opts) && isset($opts['caps']['polling'])) {
250
		return true;
251
	}
252

    
253
	return false;
254
}
255

    
256
/****f* pfsense-utils/is_alias_inuse
257
 * NAME
258
 *   checks to see if an alias is currently in use by a rule
259
 * INPUTS
260
 *
261
 * RESULT
262
 *   true or false
263
 * NOTES
264
 *
265
 ******/
266
function is_alias_inuse($alias) {
267
	global $g, $config;
268

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

    
304
/****f* pfsense-utils/is_schedule_inuse
305
 * NAME
306
 *   checks to see if a schedule is currently in use by a rule
307
 * INPUTS
308
 *
309
 * RESULT
310
 *   true or false
311
 * NOTES
312
 *
313
 ******/
314
function is_schedule_inuse($schedule) {
315
	global $g, $config;
316

    
317
	if ($schedule == "") {
318
		return false;
319
	}
320
	/* loop through firewall rules looking for schedule in use */
321
	if (is_array($config['filter']['rule'])) {
322
		foreach ($config['filter']['rule'] as $rule) {
323
			if ($rule['sched'] == $schedule) {
324
				return true;
325
			}
326
		}
327
	}
328
	return false;
329
}
330

    
331
/****f* pfsense-utils/setup_polling
332
 * NAME
333
 *   sets up polling
334
 * INPUTS
335
 *
336
 * RESULT
337
 *   null
338
 * NOTES
339
 *
340
 ******/
341
function setup_polling() {
342
	global $g, $config;
343

    
344
	if (isset($config['system']['polling'])) {
345
		set_single_sysctl("kern.polling.idle_poll", "1");
346
	} else {
347
		set_single_sysctl("kern.polling.idle_poll", "0");
348
	}
349

    
350
	if ($config['system']['polling_each_burst']) {
351
		set_single_sysctl("kern.polling.each_burst", $config['system']['polling_each_burst']);
352
	}
353
	if ($config['system']['polling_burst_max']) {
354
		set_single_sysctl("kern.polling.burst_max", $config['system']['polling_burst_max']);
355
	}
356
	if ($config['system']['polling_user_frac']) {
357
		set_single_sysctl("kern.polling.user_frac", $config['system']['polling_user_frac']);
358
	}
359
}
360

    
361
/****f* pfsense-utils/setup_microcode
362
 * NAME
363
 *   enumerates all interfaces and calls enable_hardware_offloading which
364
 *   enables a NIC's supported hardware features.
365
 * INPUTS
366
 *
367
 * RESULT
368
 *   null
369
 * NOTES
370
 *   This function only supports the fxp driver's loadable microcode.
371
 ******/
372
function setup_microcode() {
373

    
374
	/* if list */
375
	$iflist = get_configured_interface_list(false, true);
376
	foreach ($iflist as $if => $ifdescr) {
377
		enable_hardware_offloading($if);
378
	}
379
	unset($iflist);
380
}
381

    
382
/****f* pfsense-utils/get_carp_status
383
 * NAME
384
 *   get_carp_status - Return whether CARP is enabled or disabled.
385
 * RESULT
386
 *   boolean	- true if CARP is enabled, false if otherwise.
387
 ******/
388
function get_carp_status() {
389
	/* grab the current status of carp */
390
	$status = get_single_sysctl('net.inet.carp.allow');
391
	return (intval($status) > 0);
392
}
393

    
394
/*
395
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
396

    
397
 */
398
function convert_ip_to_network_format($ip, $subnet) {
399
	$ipsplit = explode('.', $ip);
400
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
401
	return $string;
402
}
403

    
404
/*
405
 * get_carp_interface_status($carpinterface): returns the status of a carp ip
406
 */
407
function get_carp_interface_status($carpinterface) {
408

    
409
	$interface = get_real_interface($interface);
410
	$carp_query = '';
411
	$_gb = exec("/sbin/ifconfig $interface | /usr/bin/grep -v grep | /usr/bin/grep carp: | /usr/bin/head -n 1", $carp_query);
412
	foreach ($carp_query as $int) {
413
		if (stripos($int, "MASTER")) {
414
			return "MASTER";
415
		}
416
		if (stripos($int, "BACKUP")) {
417
			return "BACKUP";
418
		}
419
		if (stripos($int, "INIT")) {
420
			return "INIT";
421
		}
422
	}
423
	return;
424
}
425

    
426
/*
427
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
428
 */
429
function get_pfsync_interface_status($pfsyncinterface) {
430
	if (!does_interface_exist($pfsyncinterface)) {
431
		return;
432
	}
433

    
434
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
435
}
436

    
437
/*
438
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
439
 */
440
function add_rule_to_anchor($anchor, $rule, $label) {
441
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
442
}
443

    
444
/*
445
 * remove_text_from_file
446
 * remove $text from file $file
447
 */
448
function remove_text_from_file($file, $text) {
449
	if (!file_exists($file) && !is_writable($file)) {
450
		return;
451
	}
452
	$filecontents = file_get_contents($file);
453
	$text = str_replace($text, "", $filecontents);
454
	@file_put_contents($file, $text);
455
}
456

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

    
475
/*
476
 * get_filename_from_url($url): converts a url to its filename.
477
 */
478
function get_filename_from_url($url) {
479
	return basename($url);
480
}
481

    
482
/*
483
 *   get_dir: return an array of $dir
484
 */
485
function get_dir($dir) {
486
	$dir_array = array();
487
	$d = dir($dir);
488
	while (false !== ($entry = $d->read())) {
489
		array_push($dir_array, $entry);
490
	}
491
	$d->close();
492
	return $dir_array;
493
}
494

    
495
/****f* pfsense-utils/WakeOnLan
496
 * NAME
497
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
498
 * RESULT
499
 *   true/false - true if the operation was successful
500
 ******/
501
function WakeOnLan($addr, $mac) {
502
	$addr_byte = explode(':', $mac);
503
	$hw_addr = '';
504

    
505
	for ($a = 0; $a < 6; $a++) {
506
		$hw_addr .= chr(hexdec($addr_byte[$a]));
507
	}
508

    
509
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
510

    
511
	for ($a = 1; $a <= 16; $a++) {
512
		$msg .= $hw_addr;
513
	}
514

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

    
532
	return false;
533
}
534

    
535
/*
536
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
537
 *					 Useful for finding paths and stripping file extensions.
538
 */
539
function reverse_strrchr($haystack, $needle) {
540
	if (!is_string($haystack)) {
541
		return;
542
	}
543
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
544
}
545

    
546
/*
547
 *  backup_config_section($section): returns as an xml file string of
548
 *                                   the configuration section
549
 */
550
function backup_config_section($section_name) {
551
	global $config;
552
	$new_section = &$config[$section_name];
553
	/* generate configuration XML */
554
	$xmlconfig = dump_xml_config($new_section, $section_name);
555
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
556
	return $xmlconfig;
557
}
558

    
559
/*
560
 *  restore_config_section($section_name, new_contents): restore a configuration section,
561
 *                                                  and write the configuration out
562
 *                                                  to disk/cf.
563
 */
564
function restore_config_section($section_name, $new_contents) {
565
	global $config, $g;
566
	conf_mount_rw();
567
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
568
	fwrite($fout, $new_contents);
569
	fclose($fout);
570

    
571
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
572
	if ($xml['pfsense']) {
573
		$xml = $xml['pfsense'];
574
	}
575
	else if ($xml['m0n0wall']) {
576
		$xml = $xml['m0n0wall'];
577
	}
578
	if ($xml[$section_name]) {
579
		$section_xml = $xml[$section_name];
580
	} else {
581
		$section_xml = -1;
582
	}
583

    
584
	@unlink($g['tmp_path'] . "/tmpxml");
585
	if ($section_xml === -1) {
586
		return false;
587
	}
588
	$config[$section_name] = &$section_xml;
589
	if (file_exists("{$g['tmp_path']}/config.cache")) {
590
		unlink("{$g['tmp_path']}/config.cache");
591
	}
592
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
593
	disable_security_checks();
594
	conf_mount_ro();
595
	return true;
596
}
597

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

    
620
/*
621
 * http_post($server, $port, $url, $vars): does an http post to a web server
622
 *                                         posting the vars array.
623
 * written by nf@bigpond.net.au
624
 */
625
function http_post($server, $port, $url, $vars) {
626
	$user_agent = "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)";
627
	$urlencoded = "";
628
	while (list($key, $value) = each($vars)) {
629
		$urlencoded .= urlencode($key) . "=" . urlencode($value) . "&";
630
	}
631
	$urlencoded = substr($urlencoded, 0, -1);
632
	$content_length = strlen($urlencoded);
633
	$headers = "POST $url HTTP/1.1
634
Accept: */*
635
Accept-Language: en-au
636
Content-Type: application/x-www-form-urlencoded
637
User-Agent: $user_agent
638
Host: $server
639
Connection: Keep-Alive
640
Cache-Control: no-cache
641
Content-Length: $content_length
642

    
643
";
644

    
645
	$errno = "";
646
	$errstr = "";
647
	$fp = fsockopen($server, $port, $errno, $errstr);
648
	if (!$fp) {
649
		return false;
650
	}
651

    
652
	fputs($fp, $headers);
653
	fputs($fp, $urlencoded);
654

    
655
	$ret = "";
656
	while (!feof($fp)) {
657
		$ret .= fgets($fp, 1024);
658
	}
659
	fclose($fp);
660

    
661
	return $ret;
662
}
663

    
664
/*
665
 *  php_check_syntax($code_tocheck, $errormessage): checks $code_to_check for errors
666
 */
667
if (!function_exists('php_check_syntax')) {
668
	global $g;
669
	function php_check_syntax($code_to_check, &$errormessage) {
670
		return false;
671
		$fout = fopen("{$g['tmp_path']}/codetocheck.php", "w");
672
		$code = $_POST['content'];
673
		$code = str_replace("<?php", "", $code);
674
		$code = str_replace("?>", "", $code);
675
		fwrite($fout, "<?php\n\n");
676
		fwrite($fout, $code_to_check);
677
		fwrite($fout, "\n\n?>\n");
678
		fclose($fout);
679
		$command = "/usr/local/bin/php-cgi -l {$g['tmp_path']}/codetocheck.php";
680
		$output = exec_command($command);
681
		if (stristr($output, "Errors parsing") == false) {
682
			echo "false\n";
683
			$errormessage = '';
684
			return(false);
685
		} else {
686
			$errormessage = $output;
687
			return(true);
688
		}
689
	}
690
}
691

    
692
/*
693
 *  php_check_filename_syntax($filename, $errormessage): checks the file $filename for errors
694
 */
695
if (!function_exists('php_check_syntax')) {
696
	function php_check_syntax($code_to_check, &$errormessage) {
697
		return false;
698
		$command = "/usr/local/bin/php-cgi -l " . escapeshellarg($code_to_check);
699
		$output = exec_command($command);
700
		if (stristr($output, "Errors parsing") == false) {
701
			echo "false\n";
702
			$errormessage = '';
703
			return(false);
704
		} else {
705
			$errormessage = $output;
706
			return(true);
707
		}
708
	}
709
}
710

    
711
/*
712
 * rmdir_recursive($path, $follow_links=false)
713
 * Recursively remove a directory tree (rm -rf path)
714
 * This is for directories _only_
715
 */
716
function rmdir_recursive($path, $follow_links=false) {
717
	$to_do = glob($path);
718
	if (!is_array($to_do)) {
719
		$to_do = array($to_do);
720
	}
721
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
722
		if (file_exists($workingdir)) {
723
			if (is_dir($workingdir)) {
724
				$dir = opendir($workingdir);
725
				while ($entry = readdir($dir)) {
726
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
727
						unlink("$workingdir/$entry");
728
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
729
						rmdir_recursive("$workingdir/$entry");
730
					}
731
				}
732
				closedir($dir);
733
				rmdir($workingdir);
734
			} elseif (is_file($workingdir)) {
735
				unlink($workingdir);
736
			}
737
		}
738
	}
739
	return;
740
}
741

    
742
/*
743
 * host_firmware_version(): Return the versions used in this install
744
 */
745
function host_firmware_version($tocheck = "") {
746
	global $g, $config;
747

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

    
750
	return array(
751
		"firmware" => array("version" => $g['product_version']),
752
		"kernel"   => array("version" => $os_version),
753
		"base"     => array("version" => $os_version),
754
		"platform" => trim(file_get_contents('/etc/platform', " \n")),
755
		"config_version" => $config['version']
756
	);
757
}
758

    
759
function get_disk_info() {
760
	$diskout = "";
761
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
762
	return explode(' ', $diskout[0]);
763
}
764

    
765
/****f* pfsense-utils/strncpy
766
 * NAME
767
 *   strncpy - copy strings
768
 * INPUTS
769
 *   &$dst, $src, $length
770
 * RESULT
771
 *   none
772
 ******/
773
function strncpy(&$dst, $src, $length) {
774
	if (strlen($src) > $length) {
775
		$dst = substr($src, 0, $length);
776
	} else {
777
		$dst = $src;
778
	}
779
}
780

    
781
/****f* pfsense-utils/reload_interfaces_sync
782
 * NAME
783
 *   reload_interfaces - reload all interfaces
784
 * INPUTS
785
 *   none
786
 * RESULT
787
 *   none
788
 ******/
789
function reload_interfaces_sync() {
790
	global $config, $g;
791

    
792
	if ($g['debug']) {
793
		log_error(gettext("reload_interfaces_sync() is starting."));
794
	}
795

    
796
	/* parse config.xml again */
797
	$config = parse_config(true);
798

    
799
	/* enable routing */
800
	system_routing_enable();
801
	if ($g['debug']) {
802
		log_error(gettext("Enabling system routing"));
803
	}
804

    
805
	if ($g['debug']) {
806
		log_error(gettext("Cleaning up Interfaces"));
807
	}
808

    
809
	/* set up interfaces */
810
	interfaces_configure();
811
}
812

    
813
/****f* pfsense-utils/reload_all
814
 * NAME
815
 *   reload_all - triggers a reload of all settings
816
 *   * INPUTS
817
 *   none
818
 * RESULT
819
 *   none
820
 ******/
821
function reload_all() {
822
	send_event("service reload all");
823
}
824

    
825
/****f* pfsense-utils/reload_interfaces
826
 * NAME
827
 *   reload_interfaces - triggers a reload of all interfaces
828
 * INPUTS
829
 *   none
830
 * RESULT
831
 *   none
832
 ******/
833
function reload_interfaces() {
834
	send_event("interface all reload");
835
}
836

    
837
/****f* pfsense-utils/reload_all_sync
838
 * NAME
839
 *   reload_all - reload all settings
840
 *   * INPUTS
841
 *   none
842
 * RESULT
843
 *   none
844
 ******/
845
function reload_all_sync() {
846
	global $config, $g;
847

    
848
	/* parse config.xml again */
849
	$config = parse_config(true);
850

    
851
	/* set up our timezone */
852
	system_timezone_configure();
853

    
854
	/* set up our hostname */
855
	system_hostname_configure();
856

    
857
	/* make hosts file */
858
	system_hosts_generate();
859

    
860
	/* generate resolv.conf */
861
	system_resolvconf_generate();
862

    
863
	/* enable routing */
864
	system_routing_enable();
865

    
866
	/* set up interfaces */
867
	interfaces_configure();
868

    
869
	/* start dyndns service */
870
	services_dyndns_configure();
871

    
872
	/* configure cron service */
873
	configure_cron();
874

    
875
	/* start the NTP client */
876
	system_ntp_configure();
877

    
878
	/* sync pw database */
879
	conf_mount_rw();
880
	unlink_if_exists("/etc/spwd.db.tmp");
881
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
882
	conf_mount_ro();
883

    
884
	/* restart sshd */
885
	send_event("service restart sshd");
886

    
887
	/* restart webConfigurator if needed */
888
	send_event("service restart webgui");
889
}
890

    
891
function setup_serial_port($when = "save", $path = "") {
892
	global $g, $config;
893
	conf_mount_rw();
894
	$ttys_file = "{$path}/etc/ttys";
895
	$boot_config_file = "{$path}/boot.config";
896
	$loader_conf_file = "{$path}/boot/loader.conf";
897
	/* serial console - write out /boot.config */
898
	if (file_exists($boot_config_file)) {
899
		$boot_config = file_get_contents($boot_config_file);
900
	} else {
901
		$boot_config = "";
902
	}
903

    
904
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
905
	if ($g['platform'] != "cdrom") {
906
		$serial_only = false;
907

    
908
		if (($g['platform'] == "nanobsd") && isset($g['enableserial_force'])) {
909
			$serial_only = true;
910
		} else {
911
			$specific_platform = system_identify_specific_platform();
912
			if ($specific_platform['name'] == 'RCC-VE' ||
913
			    $specific_platform['name'] == 'RCC-DFF') {
914
				$serial_only = true;
915
			}
916
		}
917

    
918
		$boot_config_split = explode("\n", $boot_config);
919
		$fd = fopen($boot_config_file, "w");
920
		if ($fd) {
921
			foreach ($boot_config_split as $bcs) {
922
				if (stristr($bcs, "-D") || stristr($bcs, "-h")) {
923
					/* DONT WRITE OUT, WE'LL DO IT LATER */
924
				} else {
925
					if ($bcs <> "") {
926
						fwrite($fd, "{$bcs}\n");
927
					}
928
				}
929
			}
930
			if ($serial_only === true) {
931
				fwrite($fd, "-S{$serialspeed} -h");
932
			} else if (is_serial_enabled()) {
933
				fwrite($fd, "-S{$serialspeed} -D");
934
			}
935
			fclose($fd);
936
		}
937

    
938
		/* serial console - write out /boot/loader.conf */
939
		if ($when == "upgrade") {
940
			system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
941
		}
942
		$boot_config = file_get_contents($loader_conf_file);
943
		$boot_config_split = explode("\n", $boot_config);
944
		if (count($boot_config_split) > 0) {
945
			$new_boot_config = array();
946
			// Loop through and only add lines that are not empty, and which
947
			//  do not contain a console directive.
948
			foreach ($boot_config_split as $bcs) {
949
				if (!empty($bcs) &&
950
				    (stripos($bcs, "console") === false) &&
951
				    (stripos($bcs, "boot_multicons") === false) &&
952
				    (stripos($bcs, "boot_serial") === false) &&
953
				    (stripos($bcs, "hw.usb.no_pf") === false) &&
954
				    (stripos($bcs, "hint.uart.0.flags") === false) &&
955
				    (stripos($bcs, "hint.uart.1.flags") === false)) {
956
					$new_boot_config[] = $bcs;
957
				}
958
			}
959

    
960
			if ($serial_only === true) {
961
				$new_boot_config[] = 'boot_serial="YES"';
962
				$new_boot_config[] = 'console="comconsole"';
963
			} else if (is_serial_enabled()) {
964
				$new_boot_config[] = 'boot_multicons="YES"';
965
				$new_boot_config[] = 'boot_serial="YES"';
966
				$primaryconsole = isset($g['primaryconsole_force']) ? $g['primaryconsole_force'] : $config['system']['primaryconsole'];
967
				switch ($primaryconsole) {
968
					case "video":
969
						$new_boot_config[] = 'console="vidconsole,comconsole"';
970
						break;
971
					case "serial":
972
					default:
973
						$new_boot_config[] = 'console="comconsole,vidconsole"';
974
				}
975
			}
976
			$new_boot_config[] = 'comconsole_speed="' . $serialspeed . '"';
977

    
978
			$specplatform = system_identify_specific_platform();
979
			if ($specplatform['name'] == 'RCC-VE' ||
980
			    $specplatform['name'] == 'RCC-DFF') {
981
				$new_boot_config[] = 'comconsole_port="0x2F8"';
982
				$new_boot_config[] = 'hint.uart.0.flags="0x00"';
983
				$new_boot_config[] = 'hint.uart.1.flags="0x10"';
984
			}
985
			$new_boot_config[] = 'hw.usb.no_pf="1"';
986

    
987
			file_put_contents($loader_conf_file, implode("\n", $new_boot_config) . "\n");
988
		}
989
	}
990
	$ttys = file_get_contents($ttys_file);
991
	$ttys_split = explode("\n", $ttys);
992
	$fd = fopen($ttys_file, "w");
993

    
994
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
995

    
996
	if (isset($config['system']['disableconsolemenu'])) {
997
		$console_type = 'Pc';
998
		$serial_type = 'std.' . $serialspeed;
999
	} else {
1000
		$console_type = 'al.Pc';
1001
		$serial_type = 'al.' . $serialspeed;
1002
	}
1003
	foreach ($ttys_split as $tty) {
1004
		if (stristr($tty, "ttyv0")) {
1005
			fwrite($fd, "ttyv0	\"/usr/libexec/getty {$console_type}\"	cons25	on	secure\n");
1006
		} else if (stristr($tty, "ttyu")) {
1007
			$ttyn = substr($tty, 0, 5);
1008
			fwrite($fd, "{$ttyn}	\"/usr/libexec/getty {$serial_type}\"	cons25	{$on_off}	secure\n");
1009
		} else {
1010
			fwrite($fd, $tty . "\n");
1011
		}
1012
	}
1013
	unset($on_off, $console_type, $serial_type);
1014
	fclose($fd);
1015
	if ($when != "upgrade") {
1016
		reload_ttys();
1017
	}
1018

    
1019
	conf_mount_ro();
1020
	return;
1021
}
1022

    
1023
function is_serial_enabled() {
1024
	global $g, $config;
1025

    
1026
	if (!isset($g['enableserial_force']) &&
1027
	    !isset($config['system']['enableserial']) &&
1028
	    ($g['platform'] == $g['product_name'] || $g['platform'] == "cdrom")) {
1029
		return false;
1030
	}
1031

    
1032
	return true;
1033
}
1034

    
1035
function reload_ttys() {
1036
	// Send a HUP signal to init will make it reload /etc/ttys
1037
	posix_kill(1, SIGHUP);
1038
}
1039

    
1040
function print_value_list($list, $count = 10, $separator = ",") {
1041
	$list = implode($separator, array_slice($list, 0, $count));
1042
	if (count($list) < $count) {
1043
		$list .= ".";
1044
	} else {
1045
		$list .= "...";
1046
	}
1047
	return $list;
1048
}
1049

    
1050
/* DHCP enabled on any interfaces? */
1051
function is_dhcp_server_enabled() {
1052
	global $config;
1053

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

    
1058
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1059
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1060
			return true;
1061
		}
1062
	}
1063

    
1064
	return false;
1065
}
1066

    
1067
/* DHCP enabled on any interfaces? */
1068
function is_dhcpv6_server_enabled() {
1069
	global $config;
1070

    
1071
	if (is_array($config['interfaces'])) {
1072
		foreach ($config['interfaces'] as $ifcfg) {
1073
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1074
				return true;
1075
			}
1076
		}
1077
	}
1078

    
1079
	if (!is_array($config['dhcpdv6'])) {
1080
		return false;
1081
	}
1082

    
1083
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1084
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1085
			return true;
1086
		}
1087
	}
1088

    
1089
	return false;
1090
}
1091

    
1092
/* radvd enabled on any interfaces? */
1093
function is_radvd_enabled() {
1094
	global $config;
1095

    
1096
	if (!is_array($config['dhcpdv6'])) {
1097
		$config['dhcpdv6'] = array();
1098
	}
1099

    
1100
	$dhcpdv6cfg = $config['dhcpdv6'];
1101
	$Iflist = get_configured_interface_list();
1102

    
1103
	/* handle manually configured DHCP6 server settings first */
1104
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1105
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1106
			continue;
1107
		}
1108

    
1109
		if (!isset($dhcpv6ifconf['ramode'])) {
1110
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1111
		}
1112

    
1113
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1114
			continue;
1115
		}
1116

    
1117
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1118
		if (!is_ipaddrv6($ifcfgipv6)) {
1119
			continue;
1120
		}
1121

    
1122
		return true;
1123
	}
1124

    
1125
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1126
	foreach ($Iflist as $if => $ifdescr) {
1127
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1128
			continue;
1129
		}
1130
		if (!isset($config['interfaces'][$if]['enable'])) {
1131
			continue;
1132
		}
1133

    
1134
		$ifcfgipv6 = get_interface_ipv6($if);
1135
		if (!is_ipaddrv6($ifcfgipv6)) {
1136
			continue;
1137
		}
1138

    
1139
		$ifcfgsnv6 = get_interface_subnetv6($if);
1140
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1141

    
1142
		if (!is_ipaddrv6($subnetv6)) {
1143
			continue;
1144
		}
1145

    
1146
		return true;
1147
	}
1148

    
1149
	return false;
1150
}
1151

    
1152
/* Any PPPoE servers enabled? */
1153
function is_pppoe_server_enabled() {
1154
	global $config;
1155

    
1156
	$pppoeenable = false;
1157

    
1158
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1159
		return false;
1160
	}
1161

    
1162
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1163
		if ($pppoes['mode'] == 'server') {
1164
			$pppoeenable = true;
1165
		}
1166
	}
1167

    
1168
	return $pppoeenable;
1169
}
1170

    
1171
function convert_seconds_to_hms($sec) {
1172
	$min = $hrs = 0;
1173
	if ($sec != 0) {
1174
		$min = floor($sec/60);
1175
		$sec %= 60;
1176
	}
1177
	if ($min != 0) {
1178
		$hrs = floor($min/60);
1179
		$min %= 60;
1180
	}
1181
	if ($sec < 10) {
1182
		$sec = "0".$sec;
1183
	}
1184
	if ($min < 10) {
1185
		$min = "0".$min;
1186
	}
1187
	if ($hrs < 10) {
1188
		$hrs = "0".$hrs;
1189
	}
1190
	$result = $hrs.":".$min.":".$sec;
1191
	return $result;
1192
}
1193

    
1194
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1195

    
1196
function get_ppp_uptime($port) {
1197
	if (file_exists("/conf/{$port}.log")) {
1198
		$saved_time = file_get_contents("/conf/{$port}.log");
1199
		$uptime_data = explode("\n", $saved_time);
1200
		$sec = 0;
1201
		foreach ($uptime_data as $upt) {
1202
			$sec += substr($upt, 1 + strpos($upt, " "));
1203
		}
1204
		return convert_seconds_to_hms($sec);
1205
	} else {
1206
		$total_time = gettext("No history data found!");
1207
		return $total_time;
1208
	}
1209
}
1210

    
1211
//returns interface information
1212
function get_interface_info($ifdescr) {
1213
	global $config, $g;
1214

    
1215
	$ifinfo = array();
1216
	if (empty($config['interfaces'][$ifdescr])) {
1217
		return;
1218
	}
1219
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1220
	$ifinfo['if'] = get_real_interface($ifdescr);
1221

    
1222
	$chkif = $ifinfo['if'];
1223
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1224
	$ifinfo['status'] = $ifinfotmp['status'];
1225
	if (empty($ifinfo['status'])) {
1226
		$ifinfo['status'] = "down";
1227
	}
1228
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1229
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1230
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1231
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1232
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1233
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1234
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1235
	if (isset($ifinfotmp['link0'])) {
1236
		$link0 = "down";
1237
	}
1238
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1239
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1240
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1241
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1242
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1243
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1244

    
1245
	/* Use pfctl for non wrapping 64 bit counters */
1246
	/* Pass */
1247
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1248
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1249
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1250
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1251
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1252
	$in4_pass = $pf_in4_pass[5];
1253
	$out4_pass = $pf_out4_pass[5];
1254
	$in4_pass_packets = $pf_in4_pass[3];
1255
	$out4_pass_packets = $pf_out4_pass[3];
1256
	$in6_pass = $pf_in6_pass[5];
1257
	$out6_pass = $pf_out6_pass[5];
1258
	$in6_pass_packets = $pf_in6_pass[3];
1259
	$out6_pass_packets = $pf_out6_pass[3];
1260
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1261
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1262
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1263
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1264

    
1265
	/* Block */
1266
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1267
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1268
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1269
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1270
	$in4_block = $pf_in4_block[5];
1271
	$out4_block = $pf_out4_block[5];
1272
	$in4_block_packets = $pf_in4_block[3];
1273
	$out4_block_packets = $pf_out4_block[3];
1274
	$in6_block = $pf_in6_block[5];
1275
	$out6_block = $pf_out6_block[5];
1276
	$in6_block_packets = $pf_in6_block[3];
1277
	$out6_block_packets = $pf_out6_block[3];
1278
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1279
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1280
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1281
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1282

    
1283
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1284
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1285
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1286
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1287

    
1288
	$ifconfiginfo = "";
1289
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1290
	switch ($link_type) {
1291
		/* DHCP? -> see if dhclient is up */
1292
		case "dhcp":
1293
			/* see if dhclient is up */
1294
			if (find_dhclient_process($ifinfo['if']) != 0) {
1295
				$ifinfo['dhcplink'] = "up";
1296
			} else {
1297
				$ifinfo['dhcplink'] = "down";
1298
			}
1299

    
1300
			break;
1301
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1302
		case "pppoe":
1303
		case "pptp":
1304
		case "l2tp":
1305
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1306
				/* get PPPoE link status for dial on demand */
1307
				$ifinfo["{$link_type}link"] = "up";
1308
			} else {
1309
				$ifinfo["{$link_type}link"] = "down";
1310
			}
1311

    
1312
			break;
1313
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1314
		case "ppp":
1315
			if ($ifinfo['status'] == "up") {
1316
				$ifinfo['ppplink'] = "up";
1317
			} else {
1318
				$ifinfo['ppplink'] = "down" ;
1319
			}
1320

    
1321
			if (empty($ifinfo['status'])) {
1322
				$ifinfo['status'] = "down";
1323
			}
1324

    
1325
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1326
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1327
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1328
						break;
1329
					}
1330
				}
1331
			}
1332
			$dev = $ppp['ports'];
1333
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1334
				break;
1335
			}
1336
			if (!file_exists($dev)) {
1337
				$ifinfo['nodevice'] = 1;
1338
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1339
			}
1340

    
1341
			$usbmodemoutput = array();
1342
			exec("usbconfig", $usbmodemoutput);
1343
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1344
			if (file_exists($mondev)) {
1345
				$cellstats = file($mondev);
1346
				/* skip header */
1347
				$a_cellstats = explode(",", $cellstats[1]);
1348
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1349
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1350
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1351
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1352
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1353
				}
1354
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1355
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1356
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1357
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1358
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1359
				}
1360
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1361
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1362
				$ifinfo['cell_sent'] = $a_cellstats[6];
1363
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1364
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1365
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1366
			}
1367
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1368
			if (isset($ppp['uptime'])) {
1369
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1370
			}
1371
			break;
1372
		default:
1373
			break;
1374
	}
1375

    
1376
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1377
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1378
		$ifinfo['ppp_uptime'] = convert_seconds_to_hms($sec);
1379
	}
1380

    
1381
	if ($ifinfo['status'] == "up") {
1382
		/* try to determine media with ifconfig */
1383
		unset($ifconfiginfo);
1384
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1385
		$wifconfiginfo = array();
1386
		if (is_interface_wireless($ifdescr)) {
1387
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1388
			array_shift($wifconfiginfo);
1389
		}
1390
		$matches = "";
1391
		foreach ($ifconfiginfo as $ici) {
1392

    
1393
			/* don't list media/speed for wireless cards, as it always
1394
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1395
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1396
				$ifinfo['media'] = $matches[1];
1397
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1398
				$ifinfo['media'] = $matches[1];
1399
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1400
				$ifinfo['media'] = $matches[1];
1401
			}
1402

    
1403
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1404
				if ($matches[1] != "active") {
1405
					$ifinfo['status'] = $matches[1];
1406
				}
1407
				if ($ifinfo['status'] == gettext("running")) {
1408
					$ifinfo['status'] = gettext("up");
1409
				}
1410
			}
1411
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1412
				$ifinfo['channel'] = $matches[1];
1413
			}
1414
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1415
				if ($matches[1][0] == '"') {
1416
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1417
				}
1418
				else {
1419
					$ifinfo['ssid'] = $matches[1];
1420
				}
1421
			}
1422
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1423
				$ifinfo['laggproto'] = $matches[1];
1424
			}
1425
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1426
				$ifinfo['laggport'][] = $matches[1];
1427
			}
1428
		}
1429
		foreach ($wifconfiginfo as $ici) {
1430
			$elements = preg_split("/[ ]+/i", $ici);
1431
			if ($elements[0] != "") {
1432
				$ifinfo['bssid'] = $elements[0];
1433
			}
1434
			if ($elements[3] != "") {
1435
				$ifinfo['rate'] = $elements[3];
1436
			}
1437
			if ($elements[4] != "") {
1438
				$ifinfo['rssi'] = $elements[4];
1439
			}
1440
		}
1441
		/* lookup the gateway */
1442
		if (interface_has_gateway($ifdescr)) {
1443
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1444
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1445
		}
1446
	}
1447

    
1448
	$bridge = "";
1449
	$bridge = link_interface_to_bridge($ifdescr);
1450
	if ($bridge) {
1451
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1452
		if (stristr($bridge_text, "blocking") <> false) {
1453
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1454
			$ifinfo['bridgeint'] = $bridge;
1455
		} else if (stristr($bridge_text, "learning") <> false) {
1456
			$ifinfo['bridge'] = gettext("learning");
1457
			$ifinfo['bridgeint'] = $bridge;
1458
		} else if (stristr($bridge_text, "forwarding") <> false) {
1459
			$ifinfo['bridge'] = gettext("forwarding");
1460
			$ifinfo['bridgeint'] = $bridge;
1461
		}
1462
	}
1463

    
1464
	return $ifinfo;
1465
}
1466

    
1467
//returns cpu speed of processor. Good for determining capabilities of machine
1468
function get_cpu_speed() {
1469
	return get_single_sysctl("hw.clockrate");
1470
}
1471

    
1472
function get_uptime_sec() {
1473
	$boottime = "";
1474
	$matches = "";
1475
	$boottime = get_single_sysctl("kern.boottime");
1476
	preg_match("/sec = (\d+)/", $boottime, $matches);
1477
	$boottime = $matches[1];
1478
	if (intval($boottime) == 0) {
1479
		return 0;
1480
	}
1481

    
1482
	$uptime = time() - $boottime;
1483
	return $uptime;
1484
}
1485

    
1486
function add_hostname_to_watch($hostname) {
1487
	if (!is_dir("/var/db/dnscache")) {
1488
		mkdir("/var/db/dnscache");
1489
	}
1490
	$result = array();
1491
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1492
		$domrecords = array();
1493
		$domips = array();
1494
		exec("host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1495
		if ($rethost == 0) {
1496
			foreach ($domrecords as $domr) {
1497
				$doml = explode(" ", $domr);
1498
				$domip = $doml[3];
1499
				/* fill array with domain ip addresses */
1500
				if (is_ipaddr($domip)) {
1501
					$domips[] = $domip;
1502
				}
1503
			}
1504
		}
1505
		sort($domips);
1506
		$contents = "";
1507
		if (!empty($domips)) {
1508
			foreach ($domips as $ip) {
1509
				$contents .= "$ip\n";
1510
			}
1511
		}
1512
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1513
		/* Remove empty elements */
1514
		$result = array_filter(explode("\n", $contents), 'strlen');
1515
	}
1516
	return $result;
1517
}
1518

    
1519
function is_fqdn($fqdn) {
1520
	$hostname = false;
1521
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1522
		$hostname = true;
1523
	}
1524
	if (preg_match("/\.\./", $fqdn)) {
1525
		$hostname = false;
1526
	}
1527
	if (preg_match("/^\./i", $fqdn)) {
1528
		$hostname = false;
1529
	}
1530
	if (preg_match("/\//i", $fqdn)) {
1531
		$hostname = false;
1532
	}
1533
	return($hostname);
1534
}
1535

    
1536
function pfsense_default_state_size() {
1537
	/* get system memory amount */
1538
	$memory = get_memory();
1539
	$physmem = $memory[0];
1540
	/* Be cautious and only allocate 10% of system memory to the state table */
1541
	$max_states = (int) ($physmem/10)*1000;
1542
	return $max_states;
1543
}
1544

    
1545
function pfsense_default_tables_size() {
1546
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1547
	return $current;
1548
}
1549

    
1550
function pfsense_default_table_entries_size() {
1551
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1552
	return $current;
1553
}
1554

    
1555
/* Compare the current hostname DNS to the DNS cache we made
1556
 * if it has changed we return the old records
1557
 * if no change we return false */
1558
function compare_hostname_to_dnscache($hostname) {
1559
	if (!is_dir("/var/db/dnscache")) {
1560
		mkdir("/var/db/dnscache");
1561
	}
1562
	$hostname = trim($hostname);
1563
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1564
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1565
	} else {
1566
		$oldcontents = "";
1567
	}
1568
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1569
		$domrecords = array();
1570
		$domips = array();
1571
		exec("host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1572
		if ($rethost == 0) {
1573
			foreach ($domrecords as $domr) {
1574
				$doml = explode(" ", $domr);
1575
				$domip = $doml[3];
1576
				/* fill array with domain ip addresses */
1577
				if (is_ipaddr($domip)) {
1578
					$domips[] = $domip;
1579
				}
1580
			}
1581
		}
1582
		sort($domips);
1583
		$contents = "";
1584
		if (!empty($domips)) {
1585
			foreach ($domips as $ip) {
1586
				$contents .= "$ip\n";
1587
			}
1588
		}
1589
	}
1590

    
1591
	if (trim($oldcontents) != trim($contents)) {
1592
		if ($g['debug']) {
1593
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1594
		}
1595
		return ($oldcontents);
1596
	} else {
1597
		return false;
1598
	}
1599
}
1600

    
1601
/*
1602
 * load_crypto() - Load crypto modules if enabled in config.
1603
 */
1604
function load_crypto() {
1605
	global $config, $g;
1606
	$crypto_modules = array('glxsb', 'aesni');
1607

    
1608
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1609
		return false;
1610
	}
1611

    
1612
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1613
		log_error("Loading {$config['system']['crypto_hardware']} cryptographic accelerator module.");
1614
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1615
	}
1616
}
1617

    
1618
/*
1619
 * load_thermal_hardware() - Load temperature monitor kernel module
1620
 */
1621
function load_thermal_hardware() {
1622
	global $config, $g;
1623
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1624

    
1625
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1626
		return false;
1627
	}
1628

    
1629
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1630
		log_error("Loading {$config['system']['thermal_hardware']} thermal monitor module.");
1631
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1632
	}
1633
}
1634

    
1635
/****f* pfsense-utils/isvm
1636
 * NAME
1637
 *   isvm
1638
 * INPUTS
1639
 *	none
1640
 * RESULT
1641
 *   returns true if machine is running under a virtual environment
1642
 ******/
1643
function isvm() {
1644
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1645
	$_gb = exec('/bin/kenv smbios.system.product 2>/dev/null', $output, $rc);
1646

    
1647
	if ($rc != 0 || !isset($output[0])) {
1648
		return false;
1649
	}
1650

    
1651
	foreach ($virtualenvs as $virtualenv) {
1652
		if (stripos($output[0], $virtualenv) !== false) {
1653
			return true;
1654
		}
1655
	}
1656

    
1657
	return false;
1658
}
1659

    
1660
function get_freebsd_version() {
1661
	$version = explode(".", php_uname("r"));
1662
	return $version[0];
1663
}
1664

    
1665
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1666
	global $config, $g;
1667

    
1668
	$fp = fopen($destination, "wb");
1669

    
1670
	if (!$fp) {
1671
		return false;
1672
	}
1673

    
1674
	$ch = curl_init();
1675
	curl_setopt($ch, CURLOPT_URL, $url);
1676
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1677
	curl_setopt($ch, CURLOPT_FILE, $fp);
1678
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1679
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1680
	curl_setopt($ch, CURLOPT_HEADER, false);
1681
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1682
	if (!isset($config['system']['host_uuid'])) {
1683
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1684
	} else {
1685
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1686
	}
1687

    
1688
	if (!empty($config['system']['proxyurl'])) {
1689
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1690
		if (!empty($config['system']['proxyport'])) {
1691
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1692
		}
1693
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1694
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1695
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1696
		}
1697
	}
1698

    
1699
	@curl_exec($ch);
1700
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1701
	fclose($fp);
1702
	curl_close($ch);
1703
	return ($http_code == 200) ? true : $http_code;
1704
}
1705

    
1706
function download_file_with_progress_bar($url_file, $destination_file, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1707
	global $config, $g;
1708
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1709
	$file_size = 1;
1710
	$downloaded = 1;
1711
	$first_progress_update = TRUE;
1712
	/* open destination file */
1713
	$fout = fopen($destination_file, "wb");
1714

    
1715
	/*
1716
	 *      Originally by Author: Keyvan Minoukadeh
1717
	 *      Modified by Scott Ullrich to return Content-Length size
1718
	 */
1719

    
1720
	$ch = curl_init();
1721
	curl_setopt($ch, CURLOPT_URL, $url_file);
1722
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
1723
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1724
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
1725
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1726
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1727
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1728
	if (!isset($config['system']['host_uuid'])) {
1729
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1730
	} else {
1731
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1732
	}
1733

    
1734
	if (!empty($config['system']['proxyurl'])) {
1735
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1736
		if (!empty($config['system']['proxyport'])) {
1737
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1738
		}
1739
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1740
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1741
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1742
		}
1743
	}
1744

    
1745
	@curl_exec($ch);
1746
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1747
	if ($fout) {
1748
		fclose($fout);
1749
	}
1750
	curl_close($ch);
1751
	return ($http_code == 200) ? true : $http_code;
1752
}
1753

    
1754
function read_header($ch, $string) {
1755
	global $file_size, $fout;
1756
	$length = strlen($string);
1757
	$regs = "";
1758
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
1759
	if ($regs[2] <> "") {
1760
		$file_size = intval($regs[2]);
1761
	}
1762
	ob_flush();
1763
	return $length;
1764
}
1765

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

    
1818
/*
1819
 *   update_output_window: update bottom textarea dynamically.
1820
 */
1821
function update_output_window($text) {
1822
	global $pkg_interface;
1823
	$log = preg_replace("/\n/", "\\n", $text);
1824
	if ($pkg_interface != "console") {
1825
?>
1826
<script>
1827
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
1828
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
1829
</script>
1830
<?php
1831
	}
1832
	/* ensure that contents are written out */
1833
	ob_flush();
1834
}
1835

    
1836
/*
1837
 *   update_status: update top textarea dynamically.
1838
 */
1839
function update_status($status) {
1840
	global $pkg_interface;
1841
	if ($pkg_interface == "console") {
1842
		echo "\r{$status}";
1843
	} else {
1844
		echo '<script>document.getElementById("status").innerText="'. htmlspecialchars($status).'";</script>';
1845
	}
1846

    
1847
	/* ensure that contents are written out */
1848
	ob_flush();
1849
}
1850

    
1851
/*
1852
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
1853
 */
1854
function update_progress_bar($percent, $first_time) {
1855
	global $pkg_interface;
1856
	if ($percent > 100) {
1857
		$percent = 1;
1858
	}
1859
	if ($pkg_interface <> "console") {
1860
		echo '<script>document.getElementById("progressbar").style.width="'. $percent.'%";</script>';
1861
	} else {
1862
		if (!($first_time)) {
1863
			echo "\x08\x08\x08\x08\x08";
1864
		}
1865
		echo sprintf("%4d%%", $percent);
1866
	}
1867
}
1868

    
1869
/* 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. */
1870
if (!function_exists("split")) {
1871
	function split($separator, $haystack, $limit = null) {
1872
		log_error("deprecated split() call with separator '{$separator}'");
1873
		return preg_split($separator, $haystack, $limit);
1874
	}
1875
}
1876

    
1877
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
1878
	global $g, $config, $pconfig, $debug;
1879
	if (!$origname) {
1880
		return;
1881
	}
1882

    
1883
	$sectionref = &$config;
1884
	foreach ($section as $sectionname) {
1885
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
1886
			$sectionref = &$sectionref[$sectionname];
1887
		} else {
1888
			return;
1889
		}
1890
	}
1891

    
1892
	if ($debug) {
1893
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
1894
		fwrite($fd, print_r($pconfig, true));
1895
	}
1896

    
1897
	if (is_array($sectionref)) {
1898
		foreach ($sectionref as $itemkey => $item) {
1899
			if ($debug) {
1900
				fwrite($fd, "$itemkey\n");
1901
			}
1902

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

    
1922
	if ($debug) {
1923
		fclose($fd);
1924
	}
1925

    
1926
}
1927

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

    
1938
	$fd = @fopen($filename, 'r');
1939
	if (!$fd) {
1940
		log_error(gettext("Could not process aliases from alias: {$alias_url}"));
1941
		return null;
1942
	}
1943
	$items = array();
1944
	/* NOTE: fgetss() is not a typo RTFM before being smart */
1945
	while (($fc = fgetss($fd)) !== FALSE) {
1946
		$tmp = trim($fc, " \t\n\r");
1947
		if (empty($tmp)) {
1948
			continue;
1949
		}
1950
		$tmp_str = strstr($tmp, '#', true);
1951
		if (!empty($tmp_str)) {
1952
			$tmp = $tmp_str;
1953
		}
1954
		$tmp_str = strstr($tmp, ' ', true);
1955
		if (!empty($tmp_str)) {
1956
			$tmp = $tmp_str;
1957
		}
1958
		$valid = ($type == "url" && (is_ipaddr($tmp) || is_subnet($tmp))) ||
1959
			 ($type == "url_ports" && (is_port($tmp) || is_portrange($tmp)));
1960
		if ($valid) {
1961
			$items[] = $tmp;
1962
			if (count($items) == $max_items) {
1963
				break;
1964
			}
1965
		}
1966
	}
1967
	fclose($fd);
1968
	return $items;
1969
}
1970

    
1971
function update_alias_url_data() {
1972
	global $config, $g;
1973

    
1974
	$updated = false;
1975

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

    
1984
			$address = null;
1985
			foreach ($alias['aliasurl'] as $alias_url) {
1986
				/* fetch down and add in */
1987
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
1988
				unlink($temp_filename);
1989
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
1990
				mkdir($temp_filename);
1991
				download_file($alias_url, $temp_filename . "/aliases", $verify_ssl);
1992

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

    
2016
	/* Report status to callers as well */
2017
	return $updated;
2018
}
2019

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

    
2050
	return true;
2051
}
2052

    
2053
function process_alias_tgz($temp_filename) {
2054
	if (!file_exists('/usr/bin/tar')) {
2055
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2056
		return false;
2057
	}
2058
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2059
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2060
	unlink("{$temp_filename}/aliases.tgz");
2061
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2062
	/* foreach through all extracted files and build up aliases file */
2063
	$fd = @fopen("{$temp_filename}/aliases", "w");
2064
	if (!$fd) {
2065
		log_error(gettext("Could not open {$temp_filename}/aliases for writing!"));
2066
		return false;
2067
	}
2068
	foreach ($files_to_process as $f2p) {
2069
		$tmpfd = @fopen($f2p, 'r');
2070
		if (!$tmpfd) {
2071
			log_error(gettext("The following file could not be read {$f2p} from {$temp_filename}"));
2072
			continue;
2073
		}
2074
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2075
			fwrite($fd, $tmpbuf);
2076
		}
2077
		fclose($tmpfd);
2078
		unlink($f2p);
2079
	}
2080
	fclose($fd);
2081
	unset($tmpbuf);
2082

    
2083
	return true;
2084
}
2085

    
2086
function version_compare_dates($a, $b) {
2087
	$a_time = strtotime($a);
2088
	$b_time = strtotime($b);
2089

    
2090
	if ((!$a_time) || (!$b_time)) {
2091
		return FALSE;
2092
	} else {
2093
		if ($a_time < $b_time) {
2094
			return -1;
2095
		} elseif ($a_time == $b_time) {
2096
			return 0;
2097
		} else {
2098
			return 1;
2099
		}
2100
	}
2101
}
2102
function version_get_string_value($a) {
2103
	$strs = array(
2104
		0 => "ALPHA-ALPHA",
2105
		2 => "ALPHA",
2106
		3 => "BETA",
2107
		4 => "B",
2108
		5 => "C",
2109
		6 => "D",
2110
		7 => "RC",
2111
		8 => "RELEASE",
2112
		9 => "*"			// Matches all release levels
2113
	);
2114
	$major = 0;
2115
	$minor = 0;
2116
	foreach ($strs as $num => $str) {
2117
		if (substr($a, 0, strlen($str)) == $str) {
2118
			$major = $num;
2119
			$n = substr($a, strlen($str));
2120
			if (is_numeric($n)) {
2121
				$minor = $n;
2122
			}
2123
			break;
2124
		}
2125
	}
2126
	return "{$major}.{$minor}";
2127
}
2128
function version_compare_string($a, $b) {
2129
	// Only compare string parts if both versions give a specific release
2130
	// (If either version lacks a string part, assume intended to match all release levels)
2131
	if (isset($a) && isset($b)) {
2132
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2133
	} else {
2134
		return 0;
2135
	}
2136
}
2137
function version_compare_numeric($a, $b) {
2138
	$a_arr = explode('.', rtrim($a, '.'));
2139
	$b_arr = explode('.', rtrim($b, '.'));
2140

    
2141
	foreach ($a_arr as $n => $val) {
2142
		if (array_key_exists($n, $b_arr)) {
2143
			// So far so good, both have values at this minor version level. Compare.
2144
			if ($val > $b_arr[$n]) {
2145
				return 1;
2146
			} elseif ($val < $b_arr[$n]) {
2147
				return -1;
2148
			}
2149
		} else {
2150
			// a is greater, since b doesn't have any minor version here.
2151
			return 1;
2152
		}
2153
	}
2154
	if (count($b_arr) > count($a_arr)) {
2155
		// b is longer than a, so it must be greater.
2156
		return -1;
2157
	} else {
2158
		// Both a and b are of equal length and value.
2159
		return 0;
2160
	}
2161
}
2162
function pfs_version_compare($cur_time, $cur_text, $remote) {
2163
	// First try date compare
2164
	$v = version_compare_dates($cur_time, $remote);
2165
	if ($v === FALSE) {
2166
		// If that fails, try to compare by string
2167
		// Before anything else, simply test if the strings are equal
2168
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2169
			return 0;
2170
		}
2171
		list($cur_num, $cur_str) = explode('-', $cur_text);
2172
		list($rem_num, $rem_str) = explode('-', $remote);
2173

    
2174
		// First try to compare the numeric parts of the version string.
2175
		$v = version_compare_numeric($cur_num, $rem_num);
2176

    
2177
		// If the numeric parts are the same, compare the string parts.
2178
		if ($v == 0) {
2179
			return version_compare_string($cur_str, $rem_str);
2180
		}
2181
	}
2182
	return $v;
2183
}
2184
function process_alias_urltable($name, $url, $freq, $forceupdate=false) {
2185
	global $config;
2186

    
2187
	$urltable_prefix = "/var/db/aliastables/";
2188
	$urltable_filename = $urltable_prefix . $name . ".txt";
2189

    
2190
	// Make the aliases directory if it doesn't exist
2191
	if (!file_exists($urltable_prefix)) {
2192
		mkdir($urltable_prefix);
2193
	} elseif (!is_dir($urltable_prefix)) {
2194
		unlink($urltable_prefix);
2195
		mkdir($urltable_prefix);
2196
	}
2197

    
2198
	// If the file doesn't exist or is older than update_freq days, fetch a new copy.
2199
	if (!file_exists($urltable_filename) ||
2200
	    ((time() - filemtime($urltable_filename)) > ($freq * 86400 - 90)) ||
2201
	    $forceupdate) {
2202

    
2203
		// Try to fetch the URL supplied
2204
		conf_mount_rw();
2205
		unlink_if_exists($urltable_filename . ".tmp");
2206
		$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2207
		if (download_file($url, $urltable_filename . ".tmp", $verify_ssl)) {
2208
			mwexec("/usr/bin/sed -E 's/\;.*//g; /^[[:space:]]*($|#)/d' ". escapeshellarg($urltable_filename . ".tmp") . " > " . escapeshellarg($urltable_filename));
2209
			if (alias_get_type($name) == "urltable_ports") {
2210
				$ports = explode("\n", str_replace("\r", "", file_get_contents($urltable_filename)));
2211
				$ports = group_ports($ports);
2212
				file_put_contents($urltable_filename, implode("\n", $ports));
2213
			}
2214
			unlink_if_exists($urltable_filename . ".tmp");
2215
		} else {
2216
			touch($urltable_filename);
2217
		}
2218
		conf_mount_ro();
2219
		return true;
2220
	} else {
2221
		// File exists, and it doesn't need to be updated.
2222
		return -1;
2223
	}
2224
}
2225
function get_real_slice_from_glabel($label) {
2226
	$label = escapeshellarg($label);
2227
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/{$label} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`);
2228
}
2229
function nanobsd_get_boot_slice() {
2230
	return trim(`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`);
2231
}
2232
function nanobsd_get_boot_drive() {
2233
	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`);
2234
}
2235
function nanobsd_get_active_slice() {
2236
	$boot_drive = nanobsd_get_boot_drive();
2237
	$active = trim(`gpart show $boot_drive | grep '\[active\]' | awk '{print $3;}'`);
2238

    
2239
	return "{$boot_drive}s{$active}";
2240
}
2241
function nanobsd_get_size() {
2242
	return strtoupper(file_get_contents("/etc/nanosize.txt"));
2243
}
2244
function nanobsd_switch_boot_slice() {
2245
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2246
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2247
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2248
	nanobsd_detect_slice_info();
2249

    
2250
	if ($BOOTFLASH == $ACTIVE_SLICE) {
2251
		$slice = $TOFLASH;
2252
	} else {
2253
		$slice = $BOOTFLASH;
2254
	}
2255

    
2256
	for ($i = 0; $i < ob_get_level(); $i++) {
2257
		ob_end_flush();
2258
	}
2259
	ob_implicit_flush(1);
2260
	if (strstr($slice, "s2")) {
2261
		$ASLICE = "2";
2262
		$AOLDSLICE = "1";
2263
		$AGLABEL_SLICE = "pfsense1";
2264
		$AUFS_ID = "1";
2265
		$AOLD_UFS_ID = "0";
2266
	} else {
2267
		$ASLICE = "1";
2268
		$AOLDSLICE = "2";
2269
		$AGLABEL_SLICE = "pfsense0";
2270
		$AUFS_ID = "0";
2271
		$AOLD_UFS_ID = "1";
2272
	}
2273
	$ATOFLASH = "{$BOOT_DRIVE}s{$ASLICE}";
2274
	$ACOMPLETE_PATH = "{$BOOT_DRIVE}s{$ASLICE}a";
2275
	$ABOOTFLASH = "{$BOOT_DRIVE}s{$AOLDSLICE}";
2276
	conf_mount_rw();
2277
	set_single_sysctl("kern.geom.debugflags", "16");
2278
	exec("gpart set -a active -i {$ASLICE} {$BOOT_DRIVE}");
2279
	exec("/usr/sbin/boot0cfg -s {$ASLICE} -v /dev/{$BOOT_DRIVE}");
2280
	// We can't update these if they are mounted now.
2281
	if ($BOOTFLASH != $slice) {
2282
		exec("/sbin/tunefs -L ${AGLABEL_SLICE} /dev/$ACOMPLETE_PATH");
2283
		nanobsd_update_fstab($AGLABEL_SLICE, $ACOMPLETE_PATH, $AOLD_UFS_ID, $AUFS_ID);
2284
	}
2285
	set_single_sysctl("kern.geom.debugflags", "0");
2286
	conf_mount_ro();
2287
}
2288
function nanobsd_clone_slice() {
2289
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2290
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2291
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2292
	nanobsd_detect_slice_info();
2293

    
2294
	for ($i = 0; $i < ob_get_level(); $i++) {
2295
		ob_end_flush();
2296
	}
2297
	ob_implicit_flush(1);
2298
	set_single_sysctl("kern.geom.debugflags", "16");
2299
	exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
2300
	exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
2301
	exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
2302
	$status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
2303
	set_single_sysctl("kern.geom.debugflags", "0");
2304
	if ($status) {
2305
		return false;
2306
	} else {
2307
		return true;
2308
	}
2309
}
2310
function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
2311
	$tmppath = "/tmp/{$gslice}";
2312
	$fstabpath = "/tmp/{$gslice}/etc/fstab";
2313

    
2314
	mkdir($tmppath);
2315
	exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
2316
	exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
2317
	copy("/etc/fstab", $fstabpath);
2318

    
2319
	if (!file_exists($fstabpath)) {
2320
		$fstab = <<<EOF
2321
/dev/ufs/{$gslice} / ufs ro,noatime 1 1
2322
/dev/ufs/cf /cf ufs ro,noatime 1 1
2323
EOF;
2324
		if (file_put_contents($fstabpath, $fstab)) {
2325
			$status = true;
2326
		} else {
2327
			$status = false;
2328
		}
2329
	} else {
2330
		$status = exec("sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
2331
	}
2332
	exec("/sbin/umount {$tmppath}");
2333
	rmdir($tmppath);
2334

    
2335
	return $status;
2336
}
2337
function nanobsd_detect_slice_info() {
2338
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2339
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2340
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2341

    
2342
	$BOOT_DEVICE=nanobsd_get_boot_slice();
2343
	$REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
2344
	$BOOT_DRIVE=nanobsd_get_boot_drive();
2345
	$ACTIVE_SLICE=nanobsd_get_active_slice();
2346

    
2347
	// Detect which slice is active and set information.
2348
	if (strstr($REAL_BOOT_DEVICE, "s1")) {
2349
		$SLICE = "2";
2350
		$OLDSLICE = "1";
2351
		$GLABEL_SLICE = "pfsense1";
2352
		$UFS_ID = "1";
2353
		$OLD_UFS_ID = "0";
2354

    
2355
	} else {
2356
		$SLICE = "1";
2357
		$OLDSLICE = "2";
2358
		$GLABEL_SLICE = "pfsense0";
2359
		$UFS_ID = "0";
2360
		$OLD_UFS_ID = "1";
2361
	}
2362
	$TOFLASH = "{$BOOT_DRIVE}s{$SLICE}";
2363
	$COMPLETE_PATH = "{$BOOT_DRIVE}s{$SLICE}a";
2364
	$COMPLETE_BOOT_PATH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2365
	$BOOTFLASH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2366
}
2367

    
2368
function nanobsd_friendly_slice_name($slicename) {
2369
	global $g;
2370
	return strtolower(str_ireplace('pfsense', $g['product_name'], $slicename));
2371
}
2372

    
2373
function get_include_contents($filename) {
2374
	if (is_file($filename)) {
2375
		ob_start();
2376
		include $filename;
2377
		$contents = ob_get_contents();
2378
		ob_end_clean();
2379
		return $contents;
2380
	}
2381
	return false;
2382
}
2383

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

    
2496
function get_country_name($country_code) {
2497
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2498
		return "";
2499
	}
2500

    
2501
	$country_names_xml = "/usr/local/share/mobile-broadband-provider-info/iso_3166-1_list_en.xml";
2502
	$country_names_contents = file_get_contents($country_names_xml);
2503
	$country_names = xml2array($country_names_contents);
2504

    
2505
	if ($country_code == "ALL") {
2506
		$country_list = array();
2507
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2508
			$country_list[] = array(
2509
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2510
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2511
		}
2512
		return $country_list;
2513
	}
2514

    
2515
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2516
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2517
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2518
		}
2519
	}
2520
	return "";
2521
}
2522

    
2523
/* sort by interface only, retain the original order of rules that apply to
2524
   the same interface */
2525
function filter_rules_sort() {
2526
	global $config;
2527

    
2528
	/* mark each rule with the sequence number (to retain the order while sorting) */
2529
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2530
		$config['filter']['rule'][$i]['seq'] = $i;
2531
	}
2532

    
2533
	usort($config['filter']['rule'], "filter_rules_compare");
2534

    
2535
	/* strip the sequence numbers again */
2536
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2537
		unset($config['filter']['rule'][$i]['seq']);
2538
	}
2539
}
2540
function filter_rules_compare($a, $b) {
2541
	if (isset($a['floating']) && isset($b['floating'])) {
2542
		return $a['seq'] - $b['seq'];
2543
	} else if (isset($a['floating'])) {
2544
		return -1;
2545
	} else if (isset($b['floating'])) {
2546
		return 1;
2547
	} else if ($a['interface'] == $b['interface']) {
2548
		return $a['seq'] - $b['seq'];
2549
	} else {
2550
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2551
	}
2552
}
2553

    
2554
function generate_ipv6_from_mac($mac) {
2555
	$elements = explode(":", $mac);
2556
	if (count($elements) <> 6) {
2557
		return false;
2558
	}
2559

    
2560
	$i = 0;
2561
	$ipv6 = "fe80::";
2562
	foreach ($elements as $byte) {
2563
		if ($i == 0) {
2564
			$hexadecimal = substr($byte, 1, 2);
2565
			$bitmap = base_convert($hexadecimal, 16, 2);
2566
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2567
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2568
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2569
		}
2570
		$ipv6 .= $byte;
2571
		if ($i == 1) {
2572
			$ipv6 .= ":";
2573
		}
2574
		if ($i == 3) {
2575
			$ipv6 .= ":";
2576
		}
2577
		if ($i == 2) {
2578
			$ipv6 .= "ff:fe";
2579
		}
2580

    
2581
		$i++;
2582
	}
2583
	return $ipv6;
2584
}
2585

    
2586
/****f* pfsense-utils/load_mac_manufacturer_table
2587
 * NAME
2588
 *   load_mac_manufacturer_table
2589
 * INPUTS
2590
 *   none
2591
 * RESULT
2592
 *   returns associative array with MAC-Manufacturer pairs
2593
 ******/
2594
function load_mac_manufacturer_table() {
2595
	/* load MAC-Manufacture data from the file */
2596
	$macs = false;
2597
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2598
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2599
	}
2600
	if ($macs) {
2601
		foreach ($macs as $line) {
2602
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2603
				/* store values like this $mac_man['000C29']='VMware' */
2604
				$mac_man["$matches[1]"] = $matches[2];
2605
			}
2606
		}
2607
		return $mac_man;
2608
	} else {
2609
		return -1;
2610
	}
2611

    
2612
}
2613

    
2614
/****f* pfsense-utils/is_ipaddr_configured
2615
 * NAME
2616
 *   is_ipaddr_configured
2617
 * INPUTS
2618
 *   IP Address to check.
2619
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2620
 *   check_localip - if true then also check for matches with PPTP and LT2P addresses
2621
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2622
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2623
 *     If check_subnets is true and cidrprefix is specified,
2624
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2625
 * RESULT
2626
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2627
*/
2628
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2629
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2630
		return true;
2631
	}
2632
	return false;
2633
}
2634

    
2635
/****f* pfsense-utils/where_is_ipaddr_configured
2636
 * NAME
2637
 *   where_is_ipaddr_configured
2638
 * INPUTS
2639
 *   IP Address to check.
2640
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2641
 *   check_localip - if true then also check for matches with PPTP and LT2P addresses
2642
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2643
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2644
 *     If check_subnets is true and cidrprefix is specified,
2645
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2646
 * RESULT
2647
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2648
 *   If there are no matches then an empty array is returned.
2649
*/
2650
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2651
	global $config;
2652

    
2653
	$where_configured = array();
2654

    
2655
	$pos = strpos($ignore_if, '_virtualip');
2656
	if ($pos !== false) {
2657
		$ignore_vip_id = substr($ignore_if, $pos+10);
2658
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2659
	} else {
2660
		$ignore_vip_id = -1;
2661
		$ignore_vip_if = $ignore_if;
2662
	}
2663

    
2664
	$isipv6 = is_ipaddrv6($ipaddr);
2665

    
2666
	if ($check_subnets) {
2667
		$cidrprefix = intval($cidrprefix);
2668
		if ($isipv6) {
2669
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2670
				$cidrprefix = 128;
2671
			}
2672
		} else {
2673
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2674
				$cidrprefix = 32;
2675
			}
2676
		}
2677
		$iflist = get_configured_interface_list();
2678
		foreach ($iflist as $if => $ifname) {
2679
			if ($ignore_if == $if) {
2680
				continue;
2681
			}
2682

    
2683
			if ($isipv6) {
2684
				$if_ipv6 = get_interface_ipv6($if);
2685
				$if_snbitsv6 = get_interface_subnetv6($if);
2686
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2687
					$where_entry = array();
2688
					$where_entry['if'] = $if;
2689
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2690
					$where_configured[] = $where_entry;
2691
				}
2692
			} else {
2693
				$if_ipv4 = get_interface_ip($if);
2694
				$if_snbitsv4 = get_interface_subnet($if);
2695
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2696
					$where_entry = array();
2697
					$where_entry['if'] = $if;
2698
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2699
					$where_configured[] = $where_entry;
2700
				}
2701
			}
2702
		}
2703
	} else {
2704
		if ($isipv6) {
2705
			$interface_list_ips = get_configured_ipv6_addresses();
2706
		} else {
2707
			$interface_list_ips = get_configured_ip_addresses();
2708
		}
2709

    
2710
		foreach ($interface_list_ips as $if => $ilips) {
2711
			if ($ignore_if == $if) {
2712
				continue;
2713
			}
2714
			if (strcasecmp($ipaddr, $ilips) == 0) {
2715
				$where_entry = array();
2716
				$where_entry['if'] = $if;
2717
				$where_entry['ip_or_subnet'] = $ilips;
2718
				$where_configured[] = $where_entry;
2719
			}
2720
		}
2721
	}
2722

    
2723
	$interface_list_vips = get_configured_vips_list(true);
2724
	foreach ($interface_list_vips as $id => $vip) {
2725
		/* Skip CARP interfaces here since they were already checked above */
2726
		if ($id == $ignore_vip_id || (substr($ignore_if, 0, 4) == '_vip') && substr($ignore_vip_if, 5) == $vip['uniqdid']) {
2727
			continue;
2728
		}
2729
		if (strcasecmp($ipaddr, $vip['ipaddr']) == 0) {
2730
			$where_entry = array();
2731
			$where_entry['if'] = $vip['if'];
2732
			$where_entry['ip_or_subnet'] = $vip['ipaddr'];
2733
			$where_configured[] = $where_entry;
2734
		}
2735
	}
2736

    
2737
	if ($check_localip) {
2738
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, $config['l2tp']['localip']) == 0)) {
2739
			$where_entry = array();
2740
			$where_entry['if'] = 'l2tp';
2741
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2742
			$where_configured[] = $where_entry;
2743
		}
2744
	}
2745

    
2746
	return $where_configured;
2747
}
2748

    
2749
/****f* pfsense-utils/pfSense_handle_custom_code
2750
 * NAME
2751
 *   pfSense_handle_custom_code
2752
 * INPUTS
2753
 *   directory name to process
2754
 * RESULT
2755
 *   globs the directory and includes the files
2756
 */
2757
function pfSense_handle_custom_code($src_dir) {
2758
	// Allow extending of the nat edit page and include custom input validation
2759
	if (is_dir("$src_dir")) {
2760
		$cf = glob($src_dir . "/*.inc");
2761
		foreach ($cf as $nf) {
2762
			if ($nf == "." || $nf == "..") {
2763
				continue;
2764
			}
2765
			// Include the extra handler
2766
			include("$nf");
2767
		}
2768
	}
2769
}
2770

    
2771
function set_language($lang = 'en_US', $encoding = "UTF-8") {
2772
	putenv("LANG={$lang}.{$encoding}");
2773
	setlocale(LC_ALL, "{$lang}.{$encoding}");
2774
	textdomain("pfSense");
2775
	bindtextdomain("pfSense", "/usr/local/share/locale");
2776
	bind_textdomain_codeset("pfSense", "{$lang}.{$encoding}");
2777
}
2778

    
2779
function get_locale_list() {
2780
	$locales = array(
2781
		"en_US" => gettext("English"),
2782
		"pt_BR" => gettext("Portuguese (Brazil)"),
2783
		"tr" => gettext("Turkish"),
2784
	);
2785
	asort($locales);
2786
	return $locales;
2787
}
2788

    
2789
function system_get_language_code() {
2790
	global $config, $g_languages;
2791

    
2792
	// a language code, as per [RFC3066]
2793
	$language = $config['system']['language'];
2794
	//$code = $g_languages[$language]['code'];
2795
	$code = str_replace("_", "-", $language);
2796

    
2797
	if (empty($code)) {
2798
		$code = "en-US"; // Set default code.
2799
	}
2800

    
2801
	return $code;
2802
}
2803

    
2804
function system_get_language_codeset() {
2805
	global $config, $g_languages;
2806

    
2807
	$language = $config['system']['language'];
2808
	$codeset = $g_languages[$language]['codeset'];
2809

    
2810
	if (empty($codeset)) {
2811
		$codeset = "UTF-8"; // Set default codeset.
2812
	}
2813

    
2814
	return $codeset;
2815
}
2816

    
2817
/* Available languages/locales */
2818
$g_languages = array (
2819
	"sq"    => array("codeset" => "UTF-8", "desc" => gettext("Albanian")),
2820
	"bg"    => array("codeset" => "UTF-8", "desc" => gettext("Bulgarian")),
2821
	"zh_CN" => array("codeset" => "UTF-8", "desc" => gettext("Chinese (Simplified)")),
2822
	"zh_TW" => array("codeset" => "UTF-8", "desc" => gettext("Chinese (Traditional)")),
2823
	"nl"    => array("codeset" => "UTF-8", "desc" => gettext("Dutch")),
2824
	"da"    => array("codeset" => "UTF-8", "desc" => gettext("Danish")),
2825
	"en_US" => array("codeset" => "UTF-8", "desc" => gettext("English")),
2826
	"fi"    => array("codeset" => "UTF-8", "desc" => gettext("Finnish")),
2827
	"fr"    => array("codeset" => "UTF-8", "desc" => gettext("French")),
2828
	"de"    => array("codeset" => "UTF-8", "desc" => gettext("German")),
2829
	"el"    => array("codeset" => "UTF-8", "desc" => gettext("Greek")),
2830
	"hu"    => array("codeset" => "UTF-8", "desc" => gettext("Hungarian")),
2831
	"it"    => array("codeset" => "UTF-8", "desc" => gettext("Italian")),
2832
	"ja"    => array("codeset" => "UTF-8", "desc" => gettext("Japanese")),
2833
	"ko"    => array("codeset" => "UTF-8", "desc" => gettext("Korean")),
2834
	"lv"    => array("codeset" => "UTF-8", "desc" => gettext("Latvian")),
2835
	"nb"    => array("codeset" => "UTF-8", "desc" => gettext("Norwegian (Bokmal)")),
2836
	"pl"    => array("codeset" => "UTF-8", "desc" => gettext("Polish")),
2837
	"pt_BR" => array("codeset" => "UTF-8", "desc" => gettext("Portuguese (Brazil)")),
2838
	"pt"    => array("codeset" => "UTF-8", "desc" => gettext("Portuguese (Portugal)")),
2839
	"ro"    => array("codeset" => "UTF-8", "desc" => gettext("Romanian")),
2840
	"ru"    => array("codeset" => "UTF-8", "desc" => gettext("Russian")),
2841
	"sl"    => array("codeset" => "UTF-8", "desc" => gettext("Slovenian")),
2842
	"tr"    => array("codeset" => "UTF-8", "desc" => gettext("Turkish")),
2843
	"es"    => array("codeset" => "UTF-8", "desc" => gettext("Spanish")),
2844
	"sv"    => array("codeset" => "UTF-8", "desc" => gettext("Swedish")),
2845
	"sk"    => array("codeset" => "UTF-8", "desc" => gettext("Slovak")),
2846
	"cs"    => array("codeset" => "UTF-8", "desc" => gettext("Czech"))
2847
);
2848

    
2849
function return_hex_ipv4($ipv4) {
2850
	if (!is_ipaddrv4($ipv4)) {
2851
		return(false);
2852
	}
2853

    
2854
	/* we need the hex form of the interface IPv4 address */
2855
	$ip4arr = explode(".", $ipv4);
2856
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
2857
}
2858

    
2859
function convert_ipv6_to_128bit($ipv6) {
2860
	if (!is_ipaddrv6($ipv6)) {
2861
		return(false);
2862
	}
2863

    
2864
	$ip6arr = array();
2865
	$ip6prefix = Net_IPv6::uncompress($ipv6);
2866
	$ip6arr = explode(":", $ip6prefix);
2867
	/* binary presentation of the prefix for all 128 bits. */
2868
	$ip6prefixbin = "";
2869
	foreach ($ip6arr as $element) {
2870
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
2871
	}
2872
	return($ip6prefixbin);
2873
}
2874

    
2875
function convert_128bit_to_ipv6($ip6bin) {
2876
	if (strlen($ip6bin) <> 128) {
2877
		return(false);
2878
	}
2879

    
2880
	$ip6arr = array();
2881
	$ip6binarr = array();
2882
	$ip6binarr = str_split($ip6bin, 16);
2883
	foreach ($ip6binarr as $binpart) {
2884
		$ip6arr[] = dechex(bindec($binpart));
2885
	}
2886
	$ip6addr = Net_IPv6::compress(implode(":", $ip6arr));
2887

    
2888
	return($ip6addr);
2889
}
2890

    
2891

    
2892
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
2893
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
2894
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
2895
/* 6to4 is 16 bits, e.g. 65535 */
2896
function calculate_ipv6_delegation_length($if) {
2897
	global $config;
2898

    
2899
	if (!is_array($config['interfaces'][$if])) {
2900
		return false;
2901
	}
2902

    
2903
	switch ($config['interfaces'][$if]['ipaddrv6']) {
2904
		case "6to4":
2905
			$pdlen = 16;
2906
			break;
2907
		case "6rd":
2908
			$rd6cfg = $config['interfaces'][$if];
2909
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
2910
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
2911
			break;
2912
		case "dhcp6":
2913
			$dhcp6cfg = $config['interfaces'][$if];
2914
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
2915
			break;
2916
		default:
2917
			$pdlen = 0;
2918
			break;
2919
	}
2920
	return($pdlen);
2921
}
2922

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3047
}
3048

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

    
3089
?>
(40-40/67)