Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
165
/****f* pfsense-utils/get_css_files
166
 * NAME
167
 *   get_css_files - get a list of the available CSS files (themes)
168
 * INPUTS
169
 *   none
170
 * RESULT
171
 *   $csslist - an array of the CSS files
172
 ******/
173
function get_css_files() {
174
	$csslist = array();
175

    
176
	// List pfSense files, then any BETA files followed by any user-contributed files
177
	$cssfiles = glob("/usr/local/www/css/*.css");
178

    
179
	if (is_array($cssfiles)) {
180
		arsort($cssfiles);
181
		$usrcss = $pfscss = $betacss = array();
182

    
183
		foreach ($cssfiles as $css) {
184
			if (strpos($css, "BETA") != 0) {
185
				array_push($betacss, $css);
186
			} else if (strpos($css, "pfSense") != 0) {
187
				array_push($pfscss, $css);
188
			} else {
189
				array_push($usrcss, $css);
190
			}
191
		}
192

    
193
		$css = array_merge($pfscss, $betacss, $usrcss);
194

    
195
		foreach ($css as $file) {
196
			$file = basename($file);
197
			$csslist[$file] = pathinfo($file, PATHINFO_FILENAME);
198
		}
199
	}
200
	return $csslist;
201
}
202

    
203
/****f* pfsense-utils/gen_webguicss_field
204
 * NAME
205
 *   gen_webguicss_field
206
 * INPUTS
207
 *   Pointer to section object
208
 *   Initial value for the field
209
 * RESULT
210
 *   no return value, section object is updated
211
 ******/
212
function gen_webguicss_field(&$section, $value) {
213

    
214
	$csslist = get_css_files();
215

    
216
	if (!isset($csslist[$value])) {
217
		$value = "pfSense.css";
218
	}
219

    
220
	$section->addInput(new Form_Select(
221
		'webguicss',
222
		'Theme',
223
		$value,
224
		$csslist
225
	))->setHelp(sprintf(gettext('Choose an alternative css file (if installed) to change the appearance of the webConfigurator. css files are located in /usr/local/www/css/%s'), '<span id="csstxt"></span>'));
226
}
227

    
228
/****f* pfsense-utils/gen_webguifixedmenu_field
229
 * NAME
230
 *   gen_webguifixedmenu_field
231
 * INPUTS
232
 *   Pointer to section object
233
 *   Initial value for the field
234
 * RESULT
235
 *   no return value, section object is updated
236
 ******/
237
function gen_webguifixedmenu_field(&$section, $value) {
238

    
239
	$section->addInput(new Form_Select(
240
		'webguifixedmenu',
241
		'Top Navigation',
242
		$value,
243
		["" => gettext("Scrolls with page"), "fixed" => gettext("Fixed (Remains visible at top of page)")]
244
	))->setHelp("The fixed option is intended for large screens only.");
245
}
246

    
247
/****f* pfsense-utils/gen_webguihostnamemenu_field
248
 * NAME
249
 *   gen_webguihostnamemenu_field
250
 * INPUTS
251
 *   Pointer to section object
252
 *   Initial value for the field
253
 * RESULT
254
 *   no return value, section object is updated
255
 ******/
256
function gen_webguihostnamemenu_field(&$section, $value) {
257

    
258
	$section->addInput(new Form_Select(
259
		'webguihostnamemenu',
260
		'Hostname in Menu',
261
		$value,
262
		["" => gettext("Default (No hostname)"), "hostonly" => gettext("Hostname only"), "fqdn" => gettext("Fully Qualified Domain Name")]
263
	))->setHelp("Replaces the Help menu title in the Navbar with the system hostname or FQDN.");
264
}
265

    
266
/****f* pfsense-utils/gen_dashboardcolumns_field
267
 * NAME
268
 *   gen_dashboardcolumns_field
269
 * INPUTS
270
 *   Pointer to section object
271
 *   Initial value for the field
272
 * RESULT
273
 *   no return value, section object is updated
274
 ******/
275
function gen_dashboardcolumns_field(&$section, $value) {
276

    
277
	if (($value < 1) || ($value > 4)) {
278
		$value = 2;
279
	}
280

    
281
	$section->addInput(new Form_Input(
282
		'dashboardcolumns',
283
		'Dashboard Columns',
284
		'number',
285
		$value,
286
		[min => 1, max => 4]
287
	));
288
}
289

    
290
/****f* pfsense-utils/gen_associatedpanels_fields
291
 * NAME
292
 *   gen_associatedpanels_fields
293
 * INPUTS
294
 *   Pointer to section object
295
 *   Initial value for each of the fields
296
 * RESULT
297
 *   no return value, section object is updated
298
 ******/
299
function gen_associatedpanels_fields(&$section, $value1, $value2, $value3, $value4) {
300

    
301
	$group = new Form_Group('Associated Panels Show/Hide');
302

    
303
	$group->add(new Form_Checkbox(
304
		'dashboardavailablewidgetspanel',
305
		null,
306
		'Available Widgets',
307
		$value1
308
		))->setHelp('Show the Available Widgets panel on the Dashboard.');
309

    
310
	$group->add(new Form_Checkbox(
311
		'systemlogsfilterpanel',
312
		null,
313
		'Log Filter',
314
		$value2
315
	))->setHelp('Show the Log Filter panel in System Logs.');
316

    
317
	$group->add(new Form_Checkbox(
318
		'systemlogsmanagelogpanel',
319
		null,
320
		'Manage Log',
321
		$value3
322
	))->setHelp('Show the Manage Log panel in System Logs.');
323

    
324
	$group->add(new Form_Checkbox(
325
		'statusmonitoringsettingspanel',
326
		null,
327
		'Monitoring Settings',
328
		$value4
329
	))->setHelp('Show the Settings panel in Status Monitoring.');
330

    
331
	$group->setHelp('These options allow certain panels to be automatically hidden on page load. A control is provided in the title bar to un-hide the panel.');
332

    
333
	$section->add($group);
334
}
335

    
336
/****f* pfsense-utils/gen_webguileftcolumnhyper_field
337
 * NAME
338
 *   gen_webguileftcolumnhyper_field
339
 * INPUTS
340
 *   Pointer to section object
341
 *   Initial value for the field
342
 * RESULT
343
 *   no return value, section object is updated
344
 ******/
345
function gen_webguileftcolumnhyper_field(&$section, $value) {
346

    
347
	$section->addInput(new Form_Checkbox(
348
		'webguileftcolumnhyper',
349
		'Left Column Labels',
350
		'Active',
351
		$value
352
	))->setHelp('If selected, clicking a label in the left column will select/toggle the first item of the group.');
353
}
354

    
355
/****f* pfsense-utils/gen_pagenamefirst_field
356
 * NAME
357
 *   gen_pagenamefirst_field
358
 * INPUTS
359
 *   Pointer to section object
360
 *   Initial value for the field
361
 * RESULT
362
 *   no return value, section object is updated
363
 ******/
364
function gen_pagenamefirst_field(&$section, $value) {
365

    
366
	$section->addInput(new Form_Checkbox(
367
		'pagenamefirst',
368
		'Browser tab text',
369
		'Display page name first in browser tab',
370
		$value
371
	))->setHelp('When this is unchecked, the browser tab shows the host name followed '.
372
		'by the current page. Check this box to display the current page followed by the '.
373
		'host name.');
374
}
375

    
376
/****f* pfsense-utils/gen_user_settings_fields
377
 * NAME
378
 *   gen_user_settings_fields
379
 * INPUTS
380
 *   Pointer to section object
381
 *   Array of initial values for the fields
382
 * RESULT
383
 *   no return value, section object is updated
384
 ******/
385
function gen_user_settings_fields(&$section, $pconfig) {
386

    
387
	gen_webguicss_field($section, $pconfig['webguicss']);
388
	gen_webguifixedmenu_field($section, $pconfig['webguifixedmenu']);
389
	gen_webguihostnamemenu_field($section, $pconfig['webguihostnamemenu']);
390
	gen_dashboardcolumns_field($section, $pconfig['dashboardcolumns']);
391
	gen_associatedpanels_fields(
392
		$section,
393
		$pconfig['dashboardavailablewidgetspanel'],
394
		$pconfig['systemlogsfilterpanel'],
395
		$pconfig['systemlogsmanagelogpanel'],
396
		$pconfig['statusmonitoringsettingspanel']);
397
	gen_webguileftcolumnhyper_field($section, $pconfig['webguileftcolumnhyper']);
398
	gen_pagenamefirst_field($section, $pconfig['pagenamefirst']);
399
}
400

    
401
function hardware_offloading_applyflags($iface) {
402
	global $config;
403

    
404
	$flags_on = 0;
405
	$flags_off = 0;
406
	$options = pfSense_get_interface_addresses($iface);
407

    
408
	if (isset($config['system']['disablechecksumoffloading'])) {
409
		if (isset($options['encaps']['txcsum'])) {
410
			$flags_off |= IFCAP_TXCSUM;
411
		}
412
		if (isset($options['encaps']['rxcsum'])) {
413
			$flags_off |= IFCAP_RXCSUM;
414
		}
415
	} else {
416
		if (isset($options['caps']['txcsum'])) {
417
			$flags_on |= IFCAP_TXCSUM;
418
		}
419
		if (isset($options['caps']['rxcsum'])) {
420
			$flags_on |= IFCAP_RXCSUM;
421
		}
422
	}
423

    
424
	if (isset($config['system']['disablesegmentationoffloading'])) {
425
		$flags_off |= IFCAP_TSO;
426
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
427
		$flags_on |= IFCAP_TSO;
428
	}
429

    
430
	if (isset($config['system']['disablelargereceiveoffloading'])) {
431
		$flags_off |= IFCAP_LRO;
432
	} else if (isset($options['caps']['lro'])) {
433
		$flags_on |= IFCAP_LRO;
434
	}
435

    
436
	/* if the NIC supports polling *AND* it is enabled in the GUI */
437
	if (!isset($config['system']['polling'])) {
438
		$flags_off |= IFCAP_POLLING;
439
	} else if (isset($options['caps']['polling'])) {
440
		$flags_on |= IFCAP_POLLING;
441
	}
442

    
443
	pfSense_interface_capabilities($iface, -$flags_off);
444
	pfSense_interface_capabilities($iface, $flags_on);
445
}
446

    
447
/****f* pfsense-utils/enable_hardware_offloading
448
 * NAME
449
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
450
 * INPUTS
451
 *   $interface	- string containing the physical interface to work on.
452
 * RESULT
453
 *   null
454
 * NOTES
455
 *   This function only supports the fxp driver's loadable microcode.
456
 ******/
457
function enable_hardware_offloading($interface) {
458
	global $g, $config;
459

    
460
	$int = get_real_interface($interface);
461
	if (empty($int)) {
462
		return;
463
	}
464

    
465
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
466
		/* translate wan, lan, opt -> real interface if needed */
467
		$int_family = preg_split("/[0-9]+/", $int);
468
		$supported_ints = array('fxp');
469
		if (in_array($int_family, $supported_ints)) {
470
			if (does_interface_exist($int)) {
471
				pfSense_interface_flags($int, IFF_LINK0);
472
			}
473
		}
474
	}
475

    
476
	/* This is mostly for vlans and ppp types */
477
	$realhwif = get_parent_interface($interface);
478
	if ($realhwif[0] == $int) {
479
		hardware_offloading_applyflags($int);
480
	} else {
481
		hardware_offloading_applyflags($realhwif[0]);
482
		hardware_offloading_applyflags($int);
483
	}
484
}
485

    
486
/****f* pfsense-utils/interface_supports_polling
487
 * NAME
488
 *   checks to see if an interface supports polling according to man polling
489
 * INPUTS
490
 *
491
 * RESULT
492
 *   true or false
493
 * NOTES
494
 *
495
 ******/
496
function interface_supports_polling($iface) {
497
	$opts = pfSense_get_interface_addresses($iface);
498
	if (is_array($opts) && isset($opts['caps']['polling'])) {
499
		return true;
500
	}
501

    
502
	return false;
503
}
504

    
505
/****f* pfsense-utils/is_alias_inuse
506
 * NAME
507
 *   checks to see if an alias is currently in use by a rule
508
 * INPUTS
509
 *
510
 * RESULT
511
 *   true or false
512
 * NOTES
513
 *
514
 ******/
515
function is_alias_inuse($alias) {
516
	global $g, $config;
517

    
518
	if ($alias == "") {
519
		return false;
520
	}
521
	/* loop through firewall rules looking for alias in use */
522
	if (is_array($config['filter']['rule'])) {
523
		foreach ($config['filter']['rule'] as $rule) {
524
			if ($rule['source']['address']) {
525
				if ($rule['source']['address'] == $alias) {
526
					return true;
527
				}
528
			}
529
			if ($rule['destination']['address']) {
530
				if ($rule['destination']['address'] == $alias) {
531
					return true;
532
				}
533
			}
534
		}
535
	}
536
	/* loop through nat rules looking for alias in use */
537
	if (is_array($config['nat']['rule'])) {
538
		foreach ($config['nat']['rule'] as $rule) {
539
			if ($rule['target'] && $rule['target'] == $alias) {
540
				return true;
541
			}
542
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
543
				return true;
544
			}
545
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
546
				return true;
547
			}
548
		}
549
	}
550
	return false;
551
}
552

    
553
/****f* pfsense-utils/is_schedule_inuse
554
 * NAME
555
 *   checks to see if a schedule is currently in use by a rule
556
 * INPUTS
557
 *
558
 * RESULT
559
 *   true or false
560
 * NOTES
561
 *
562
 ******/
563
function is_schedule_inuse($schedule) {
564
	global $g, $config;
565

    
566
	if ($schedule == "") {
567
		return false;
568
	}
569
	/* loop through firewall rules looking for schedule in use */
570
	if (is_array($config['filter']['rule'])) {
571
		foreach ($config['filter']['rule'] as $rule) {
572
			if ($rule['sched'] == $schedule) {
573
				return true;
574
			}
575
		}
576
	}
577
	return false;
578
}
579

    
580
/****f* pfsense-utils/setup_polling
581
 * NAME
582
 *   sets up polling
583
 * INPUTS
584
 *
585
 * RESULT
586
 *   null
587
 * NOTES
588
 *
589
 ******/
590
function setup_polling() {
591
	global $g, $config;
592

    
593
	if (isset($config['system']['polling'])) {
594
		set_single_sysctl("kern.polling.idle_poll", "1");
595
	} else {
596
		set_single_sysctl("kern.polling.idle_poll", "0");
597
	}
598

    
599
	if ($config['system']['polling_each_burst']) {
600
		set_single_sysctl("kern.polling.each_burst", $config['system']['polling_each_burst']);
601
	}
602
	if ($config['system']['polling_burst_max']) {
603
		set_single_sysctl("kern.polling.burst_max", $config['system']['polling_burst_max']);
604
	}
605
	if ($config['system']['polling_user_frac']) {
606
		set_single_sysctl("kern.polling.user_frac", $config['system']['polling_user_frac']);
607
	}
608
}
609

    
610
/****f* pfsense-utils/setup_microcode
611
 * NAME
612
 *   enumerates all interfaces and calls enable_hardware_offloading which
613
 *   enables a NIC's supported hardware features.
614
 * INPUTS
615
 *
616
 * RESULT
617
 *   null
618
 * NOTES
619
 *   This function only supports the fxp driver's loadable microcode.
620
 ******/
621
function setup_microcode() {
622

    
623
	/* if list */
624
	$iflist = get_configured_interface_list(false, true);
625
	foreach ($iflist as $if => $ifdescr) {
626
		enable_hardware_offloading($if);
627
	}
628
	unset($iflist);
629
}
630

    
631
/****f* pfsense-utils/get_carp_status
632
 * NAME
633
 *   get_carp_status - Return whether CARP is enabled or disabled.
634
 * RESULT
635
 *   boolean	- true if CARP is enabled, false if otherwise.
636
 ******/
637
function get_carp_status() {
638
	/* grab the current status of carp */
639
	$status = get_single_sysctl('net.inet.carp.allow');
640
	return (intval($status) > 0);
641
}
642

    
643
/*
644
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
645

    
646
 */
647
function convert_ip_to_network_format($ip, $subnet) {
648
	$ipsplit = explode('.', $ip);
649
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
650
	return $string;
651
}
652

    
653
/*
654
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
655
 */
656
function get_carp_interface_status($carpid) {
657

    
658
	$carpiface = get_configured_vip_interface($carpid);
659
	if ($carpiface == NULL)
660
		return "";
661
	$interface = get_real_interface($carpiface);
662
	if ($interface == NULL)
663
		return "";
664

    
665
	$vhid = $carp['vhid'];
666
	$carp_query = '';
667
	$_gb = exec("/sbin/ifconfig $interface | /usr/bin/grep carp: | /usr/bin/grep \"vhid $vhid\"", $carp_query);
668
	foreach ($carp_query as $int) {
669
		if (stripos($int, "MASTER"))
670
			return "MASTER";
671
		elseif (stripos($int, "BACKUP"))
672
			return "BACKUP";
673
		elseif (stripos($int, "INIT"))
674
			return "INIT";
675
	}
676

    
677
	return "";
678
}
679

    
680
/*
681
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
682
 */
683
function get_pfsync_interface_status($pfsyncinterface) {
684
	if (!does_interface_exist($pfsyncinterface)) {
685
		return;
686
	}
687

    
688
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
689
}
690

    
691
/*
692
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
693
 */
694
function add_rule_to_anchor($anchor, $rule, $label) {
695
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
696
}
697

    
698
/*
699
 * remove_text_from_file
700
 * remove $text from file $file
701
 */
702
function remove_text_from_file($file, $text) {
703
	if (!file_exists($file) && !is_writable($file)) {
704
		return;
705
	}
706
	$filecontents = file_get_contents($file);
707
	$text = str_replace($text, "", $filecontents);
708
	@file_put_contents($file, $text);
709
}
710

    
711
/*
712
 *   after_sync_bump_adv_skew(): create skew values by 1S
713
 */
714
function after_sync_bump_adv_skew() {
715
	global $config, $g;
716
	$processed_skew = 1;
717
	$a_vip = &$config['virtualip']['vip'];
718
	foreach ($a_vip as $vipent) {
719
		if ($vipent['advskew'] <> "") {
720
			$processed_skew = 1;
721
			$vipent['advskew'] = $vipent['advskew']+1;
722
		}
723
	}
724
	if ($processed_skew == 1) {
725
		write_config(gettext("After synch increase advertising skew"));
726
	}
727
}
728

    
729
/*
730
 * get_filename_from_url($url): converts a url to its filename.
731
 */
732
function get_filename_from_url($url) {
733
	return basename($url);
734
}
735

    
736
/*
737
 *   get_dir: return an array of $dir
738
 */
739
function get_dir($dir) {
740
	$dir_array = array();
741
	$d = dir($dir);
742
	while (false !== ($entry = $d->read())) {
743
		array_push($dir_array, $entry);
744
	}
745
	$d->close();
746
	return $dir_array;
747
}
748

    
749
/****f* pfsense-utils/WakeOnLan
750
 * NAME
751
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
752
 * RESULT
753
 *   true/false - true if the operation was successful
754
 ******/
755
function WakeOnLan($addr, $mac) {
756
	$addr_byte = explode(':', $mac);
757
	$hw_addr = '';
758

    
759
	for ($a = 0; $a < 6; $a++) {
760
		$hw_addr .= chr(hexdec($addr_byte[$a]));
761
	}
762

    
763
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
764

    
765
	for ($a = 1; $a <= 16; $a++) {
766
		$msg .= $hw_addr;
767
	}
768

    
769
	// send it to the broadcast address using UDP
770
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
771
	if ($s == false) {
772
		log_error(gettext("Error creating socket!"));
773
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
774
	} else {
775
		// setting a broadcast option to socket:
776
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
777
		if ($opt_ret < 0) {
778
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
779
		}
780
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
781
		socket_close($s);
782
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
783
		return true;
784
	}
785

    
786
	return false;
787
}
788

    
789
/*
790
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
791
 *					 Useful for finding paths and stripping file extensions.
792
 */
793
function reverse_strrchr($haystack, $needle) {
794
	if (!is_string($haystack)) {
795
		return;
796
	}
797
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
798
}
799

    
800
/*
801
 *  backup_config_section($section): returns as an xml file string of
802
 *                                   the configuration section
803
 */
804
function backup_config_section($section_name) {
805
	global $config;
806
	$new_section = &$config[$section_name];
807
	/* generate configuration XML */
808
	$xmlconfig = dump_xml_config($new_section, $section_name);
809
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
810
	return $xmlconfig;
811
}
812

    
813
/*
814
 *  restore_config_section($section_name, new_contents): restore a configuration section,
815
 *                                                  and write the configuration out
816
 *                                                  to disk/cf.
817
 */
818
function restore_config_section($section_name, $new_contents) {
819
	global $config, $g;
820
	conf_mount_rw();
821
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
822
	fwrite($fout, $new_contents);
823
	fclose($fout);
824

    
825
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
826
	if ($xml['pfsense']) {
827
		$xml = $xml['pfsense'];
828
	}
829
	else if ($xml['m0n0wall']) {
830
		$xml = $xml['m0n0wall'];
831
	}
832
	if ($xml[$section_name]) {
833
		$section_xml = $xml[$section_name];
834
	} else {
835
		$section_xml = -1;
836
	}
837

    
838
	@unlink($g['tmp_path'] . "/tmpxml");
839
	if ($section_xml === -1) {
840
		return false;
841
	}
842
	$config[$section_name] = &$section_xml;
843
	if (file_exists("{$g['tmp_path']}/config.cache")) {
844
		unlink("{$g['tmp_path']}/config.cache");
845
	}
846
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
847
	disable_security_checks();
848
	conf_mount_ro();
849
	return true;
850
}
851

    
852
/*
853
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
854
 *                                                  and write the configuration out
855
 *                                                  to disk/cf.  But preserve the prior
856
 * 													structure if needed
857
 */
858
function merge_config_section($section_name, $new_contents) {
859
	global $config;
860
	conf_mount_rw();
861
	$fname = get_tmp_filename();
862
	$fout = fopen($fname, "w");
863
	fwrite($fout, $new_contents);
864
	fclose($fout);
865
	$section_xml = parse_xml_config($fname, $section_name);
866
	$config[$section_name] = $section_xml;
867
	unlink($fname);
868
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
869
	disable_security_checks();
870
	conf_mount_ro();
871
	return;
872
}
873

    
874
/*
875
 *  php_check_syntax($code_tocheck, $errormessage): checks $code_to_check for errors
876
 */
877
if (!function_exists('php_check_syntax')) {
878
	global $g;
879
	function php_check_syntax($code_to_check, &$errormessage) {
880
		return false;
881
		$fout = fopen("{$g['tmp_path']}/codetocheck.php", "w");
882
		$code = $_POST['content'];
883
		$code = str_replace("<?php", "", $code);
884
		$code = str_replace("?>", "", $code);
885
		fwrite($fout, "<?php\n\n");
886
		fwrite($fout, $code_to_check);
887
		fwrite($fout, "\n\n?>\n");
888
		fclose($fout);
889
		$command = "/usr/local/bin/php-cgi -l {$g['tmp_path']}/codetocheck.php";
890
		$output = exec_command($command);
891
		if (stristr($output, "Errors parsing") == false) {
892
			echo "false\n";
893
			$errormessage = '';
894
			return(false);
895
		} else {
896
			$errormessage = $output;
897
			return(true);
898
		}
899
	}
900
}
901

    
902
/*
903
 *  php_check_filename_syntax($filename, $errormessage): checks the file $filename for errors
904
 */
905
if (!function_exists('php_check_syntax')) {
906
	function php_check_syntax($code_to_check, &$errormessage) {
907
		return false;
908
		$command = "/usr/local/bin/php-cgi -l " . escapeshellarg($code_to_check);
909
		$output = exec_command($command);
910
		if (stristr($output, "Errors parsing") == false) {
911
			echo "false\n";
912
			$errormessage = '';
913
			return(false);
914
		} else {
915
			$errormessage = $output;
916
			return(true);
917
		}
918
	}
919
}
920

    
921
/*
922
 * rmdir_recursive($path, $follow_links=false)
923
 * Recursively remove a directory tree (rm -rf path)
924
 * This is for directories _only_
925
 */
926
function rmdir_recursive($path, $follow_links=false) {
927
	$to_do = glob($path);
928
	if (!is_array($to_do)) {
929
		$to_do = array($to_do);
930
	}
931
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
932
		if (file_exists($workingdir)) {
933
			if (is_dir($workingdir)) {
934
				$dir = opendir($workingdir);
935
				while ($entry = readdir($dir)) {
936
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
937
						unlink("$workingdir/$entry");
938
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
939
						rmdir_recursive("$workingdir/$entry");
940
					}
941
				}
942
				closedir($dir);
943
				rmdir($workingdir);
944
			} elseif (is_file($workingdir)) {
945
				unlink($workingdir);
946
			}
947
		}
948
	}
949
	return;
950
}
951

    
952
/*
953
 * host_firmware_version(): Return the versions used in this install
954
 */
955
function host_firmware_version($tocheck = "") {
956
	global $g, $config;
957

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

    
960
	return array(
961
		"firmware" => array("version" => $g['product_version']),
962
		"kernel"   => array("version" => $os_version),
963
		"base"     => array("version" => $os_version),
964
		"platform" => trim(file_get_contents('/etc/platform', " \n")),
965
		"config_version" => $config['version']
966
	);
967
}
968

    
969
function get_disk_info() {
970
	$diskout = "";
971
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
972
	return explode(' ', $diskout[0]);
973
}
974

    
975
/****f* pfsense-utils/strncpy
976
 * NAME
977
 *   strncpy - copy strings
978
 * INPUTS
979
 *   &$dst, $src, $length
980
 * RESULT
981
 *   none
982
 ******/
983
function strncpy(&$dst, $src, $length) {
984
	if (strlen($src) > $length) {
985
		$dst = substr($src, 0, $length);
986
	} else {
987
		$dst = $src;
988
	}
989
}
990

    
991
/****f* pfsense-utils/reload_interfaces_sync
992
 * NAME
993
 *   reload_interfaces - reload all interfaces
994
 * INPUTS
995
 *   none
996
 * RESULT
997
 *   none
998
 ******/
999
function reload_interfaces_sync() {
1000
	global $config, $g;
1001

    
1002
	if ($g['debug']) {
1003
		log_error(gettext("reload_interfaces_sync() is starting."));
1004
	}
1005

    
1006
	/* parse config.xml again */
1007
	$config = parse_config(true);
1008

    
1009
	/* enable routing */
1010
	system_routing_enable();
1011
	if ($g['debug']) {
1012
		log_error(gettext("Enabling system routing"));
1013
	}
1014

    
1015
	if ($g['debug']) {
1016
		log_error(gettext("Cleaning up Interfaces"));
1017
	}
1018

    
1019
	/* set up interfaces */
1020
	interfaces_configure();
1021
}
1022

    
1023
/****f* pfsense-utils/reload_all
1024
 * NAME
1025
 *   reload_all - triggers a reload of all settings
1026
 *   * INPUTS
1027
 *   none
1028
 * RESULT
1029
 *   none
1030
 ******/
1031
function reload_all() {
1032
	send_event("service reload all");
1033
}
1034

    
1035
/****f* pfsense-utils/reload_interfaces
1036
 * NAME
1037
 *   reload_interfaces - triggers a reload of all interfaces
1038
 * INPUTS
1039
 *   none
1040
 * RESULT
1041
 *   none
1042
 ******/
1043
function reload_interfaces() {
1044
	send_event("interface all reload");
1045
}
1046

    
1047
/****f* pfsense-utils/reload_all_sync
1048
 * NAME
1049
 *   reload_all - reload all settings
1050
 *   * INPUTS
1051
 *   none
1052
 * RESULT
1053
 *   none
1054
 ******/
1055
function reload_all_sync() {
1056
	global $config, $g;
1057

    
1058
	/* parse config.xml again */
1059
	$config = parse_config(true);
1060

    
1061
	/* set up our timezone */
1062
	system_timezone_configure();
1063

    
1064
	/* set up our hostname */
1065
	system_hostname_configure();
1066

    
1067
	/* make hosts file */
1068
	system_hosts_generate();
1069

    
1070
	/* generate resolv.conf */
1071
	system_resolvconf_generate();
1072

    
1073
	/* enable routing */
1074
	system_routing_enable();
1075

    
1076
	/* set up interfaces */
1077
	interfaces_configure();
1078

    
1079
	/* start dyndns service */
1080
	services_dyndns_configure();
1081

    
1082
	/* configure cron service */
1083
	configure_cron();
1084

    
1085
	/* start the NTP client */
1086
	system_ntp_configure();
1087

    
1088
	/* sync pw database */
1089
	conf_mount_rw();
1090
	unlink_if_exists("/etc/spwd.db.tmp");
1091
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1092
	conf_mount_ro();
1093

    
1094
	/* restart sshd */
1095
	send_event("service restart sshd");
1096

    
1097
	/* restart webConfigurator if needed */
1098
	send_event("service restart webgui");
1099
}
1100

    
1101
function setup_serial_port($when = "save", $path = "") {
1102
	global $g, $config;
1103
	conf_mount_rw();
1104
	$ttys_file = "{$path}/etc/ttys";
1105
	$boot_config_file = "{$path}/boot.config";
1106
	$loader_conf_file = "{$path}/boot/loader.conf";
1107
	/* serial console - write out /boot.config */
1108
	if (file_exists($boot_config_file)) {
1109
		$boot_config = file_get_contents($boot_config_file);
1110
	} else {
1111
		$boot_config = "";
1112
	}
1113

    
1114
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1115
	if ($g['platform'] != "cdrom") {
1116
		$serial_only = false;
1117

    
1118
		if (($g['platform'] == "nanobsd") && isset($g['enableserial_force'])) {
1119
			$serial_only = true;
1120
		} else {
1121
			$specific_platform = system_identify_specific_platform();
1122
			if ($specific_platform['name'] == 'RCC-VE' ||
1123
			    $specific_platform['name'] == 'RCC' ||
1124
			    $specific_platform['name'] == 'RCC-DFF') {
1125
				$serial_only = true;
1126
			}
1127
		}
1128

    
1129
		$boot_config_split = explode("\n", $boot_config);
1130
		$fd = fopen($boot_config_file, "w");
1131
		if ($fd) {
1132
			foreach ($boot_config_split as $bcs) {
1133
				if (stristr($bcs, "-D") || stristr($bcs, "-h")) {
1134
					/* DONT WRITE OUT, WE'LL DO IT LATER */
1135
				} else {
1136
					if ($bcs <> "") {
1137
						fwrite($fd, "{$bcs}\n");
1138
					}
1139
				}
1140
			}
1141
			if ($serial_only === true) {
1142
				fwrite($fd, "-S{$serialspeed} -h");
1143
			} else if (is_serial_enabled()) {
1144
				fwrite($fd, "-S{$serialspeed} -D");
1145
			}
1146
			fclose($fd);
1147
		}
1148

    
1149
		/* serial console - write out /boot/loader.conf */
1150
		if ($when == "upgrade") {
1151
			system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1152
		}
1153
		$boot_config = file_get_contents($loader_conf_file);
1154
		$boot_config_split = explode("\n", $boot_config);
1155
		if (count($boot_config_split) > 0) {
1156
			$new_boot_config = array();
1157
			// Loop through and only add lines that are not empty, and which
1158
			//  do not contain a console directive.
1159
			foreach ($boot_config_split as $bcs) {
1160
				if (!empty($bcs) &&
1161
				    (stripos($bcs, "console") === false) &&
1162
				    (stripos($bcs, "boot_multicons") === false) &&
1163
				    (stripos($bcs, "boot_serial") === false) &&
1164
				    (stripos($bcs, "hw.usb.no_pf") === false) &&
1165
				    (stripos($bcs, "hint.uart.0.flags") === false) &&
1166
				    (stripos($bcs, "hint.uart.1.flags") === false)) {
1167
					$new_boot_config[] = $bcs;
1168
				}
1169
			}
1170

    
1171
			if ($serial_only === true) {
1172
				$new_boot_config[] = 'boot_serial="YES"';
1173
				$new_boot_config[] = 'console="comconsole"';
1174
			} else if (is_serial_enabled()) {
1175
				$new_boot_config[] = 'boot_multicons="YES"';
1176
				$new_boot_config[] = 'boot_serial="YES"';
1177
				$primaryconsole = isset($g['primaryconsole_force']) ? $g['primaryconsole_force'] : $config['system']['primaryconsole'];
1178
				switch ($primaryconsole) {
1179
					case "video":
1180
						$new_boot_config[] = 'console="vidconsole,comconsole"';
1181
						break;
1182
					case "serial":
1183
					default:
1184
						$new_boot_config[] = 'console="comconsole,vidconsole"';
1185
				}
1186
			}
1187
			$new_boot_config[] = 'comconsole_speed="' . $serialspeed . '"';
1188

    
1189
			$specplatform = system_identify_specific_platform();
1190
			if ($specplatform['name'] == 'RCC-VE' ||
1191
			    $specplatform['name'] == 'RCC' ||
1192
			    $specplatform['name'] == 'RCC-DFF') {
1193
				$new_boot_config[] = 'comconsole_port="0x2F8"';
1194
				$new_boot_config[] = 'hint.uart.0.flags="0x00"';
1195
				$new_boot_config[] = 'hint.uart.1.flags="0x10"';
1196
			}
1197
			$new_boot_config[] = 'hw.usb.no_pf="1"';
1198

    
1199
			file_put_contents($loader_conf_file, implode("\n", $new_boot_config) . "\n");
1200
		}
1201
	}
1202
	$ttys = file_get_contents($ttys_file);
1203
	$ttys_split = explode("\n", $ttys);
1204
	$fd = fopen($ttys_file, "w");
1205

    
1206
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1207

    
1208
	if (isset($config['system']['disableconsolemenu'])) {
1209
		$console_type = 'Pc';
1210
		$serial_type = '3wire';
1211
	} else {
1212
		$console_type = 'al.Pc';
1213
		$serial_type = 'al.3wire';
1214
	}
1215
	foreach ($ttys_split as $tty) {
1216
		if (stristr($tty, "ttyv0")) {
1217
			fwrite($fd, "ttyv0	\"/usr/libexec/getty {$console_type}\"	xterm	on	secure\n");
1218
		} else if (stristr($tty, "ttyu")) {
1219
			$ttyn = substr($tty, 0, 5);
1220
			fwrite($fd, "{$ttyn}	\"/usr/libexec/getty {$serial_type}\"	vt100	{$on_off}	secure\n");
1221
		} else {
1222
			fwrite($fd, $tty . "\n");
1223
		}
1224
	}
1225
	unset($on_off, $console_type, $serial_type);
1226
	fclose($fd);
1227
	if ($when != "upgrade") {
1228
		reload_ttys();
1229
	}
1230

    
1231
	conf_mount_ro();
1232
	return;
1233
}
1234

    
1235
function is_serial_enabled() {
1236
	global $g, $config;
1237

    
1238
	if (!isset($g['enableserial_force']) &&
1239
	    !isset($config['system']['enableserial']) &&
1240
	    ($g['platform'] == $g['product_name'] || $g['platform'] == "cdrom")) {
1241
		return false;
1242
	}
1243

    
1244
	return true;
1245
}
1246

    
1247
function reload_ttys() {
1248
	// Send a HUP signal to init will make it reload /etc/ttys
1249
	posix_kill(1, SIGHUP);
1250
}
1251

    
1252
function print_value_list($list, $count = 10, $separator = ",") {
1253
	$list = implode($separator, array_slice($list, 0, $count));
1254
	if (count($list) < $count) {
1255
		$list .= ".";
1256
	} else {
1257
		$list .= "...";
1258
	}
1259
	return $list;
1260
}
1261

    
1262
/* DHCP enabled on any interfaces? */
1263
function is_dhcp_server_enabled() {
1264
	global $config;
1265

    
1266
	if (!is_array($config['dhcpd'])) {
1267
		return false;
1268
	}
1269

    
1270
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1271
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1272
			return true;
1273
		}
1274
	}
1275

    
1276
	return false;
1277
}
1278

    
1279
/* DHCP enabled on any interfaces? */
1280
function is_dhcpv6_server_enabled() {
1281
	global $config;
1282

    
1283
	if (is_array($config['interfaces'])) {
1284
		foreach ($config['interfaces'] as $ifcfg) {
1285
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1286
				return true;
1287
			}
1288
		}
1289
	}
1290

    
1291
	if (!is_array($config['dhcpdv6'])) {
1292
		return false;
1293
	}
1294

    
1295
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1296
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1297
			return true;
1298
		}
1299
	}
1300

    
1301
	return false;
1302
}
1303

    
1304
/* radvd enabled on any interfaces? */
1305
function is_radvd_enabled() {
1306
	global $config;
1307

    
1308
	if (!is_array($config['dhcpdv6'])) {
1309
		$config['dhcpdv6'] = array();
1310
	}
1311

    
1312
	$dhcpdv6cfg = $config['dhcpdv6'];
1313
	$Iflist = get_configured_interface_list();
1314

    
1315
	/* handle manually configured DHCP6 server settings first */
1316
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1317
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1318
			continue;
1319
		}
1320

    
1321
		if (!isset($dhcpv6ifconf['ramode'])) {
1322
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1323
		}
1324

    
1325
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1326
			continue;
1327
		}
1328

    
1329
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1330
		if (!is_ipaddrv6($ifcfgipv6)) {
1331
			continue;
1332
		}
1333

    
1334
		return true;
1335
	}
1336

    
1337
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1338
	foreach ($Iflist as $if => $ifdescr) {
1339
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1340
			continue;
1341
		}
1342
		if (!isset($config['interfaces'][$if]['enable'])) {
1343
			continue;
1344
		}
1345

    
1346
		$ifcfgipv6 = get_interface_ipv6($if);
1347
		if (!is_ipaddrv6($ifcfgipv6)) {
1348
			continue;
1349
		}
1350

    
1351
		$ifcfgsnv6 = get_interface_subnetv6($if);
1352
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1353

    
1354
		if (!is_ipaddrv6($subnetv6)) {
1355
			continue;
1356
		}
1357

    
1358
		return true;
1359
	}
1360

    
1361
	return false;
1362
}
1363

    
1364
/* Any PPPoE servers enabled? */
1365
function is_pppoe_server_enabled() {
1366
	global $config;
1367

    
1368
	$pppoeenable = false;
1369

    
1370
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1371
		return false;
1372
	}
1373

    
1374
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1375
		if ($pppoes['mode'] == 'server') {
1376
			$pppoeenable = true;
1377
		}
1378
	}
1379

    
1380
	return $pppoeenable;
1381
}
1382

    
1383
/* Optional arg forces hh:mm:ss without days */
1384
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1385
	if (!is_numericint($sec)) {
1386
		return '-';
1387
	}
1388
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1389
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1390
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1391
					(int)(($sec % 3600)/60),
1392
					$sec % 60
1393
				);
1394
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1395
}
1396

    
1397
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1398

    
1399
function get_ppp_uptime($port) {
1400
	if (file_exists("/conf/{$port}.log")) {
1401
		$saved_time = file_get_contents("/conf/{$port}.log");
1402
		$uptime_data = explode("\n", $saved_time);
1403
		$sec = 0;
1404
		foreach ($uptime_data as $upt) {
1405
			$sec += substr($upt, 1 + strpos($upt, " "));
1406
		}
1407
		return convert_seconds_to_dhms($sec);
1408
	} else {
1409
		$total_time = gettext("No history data found!");
1410
		return $total_time;
1411
	}
1412
}
1413

    
1414
//returns interface information
1415
function get_interface_info($ifdescr) {
1416
	global $config, $g;
1417

    
1418
	$ifinfo = array();
1419
	if (empty($config['interfaces'][$ifdescr])) {
1420
		return;
1421
	}
1422
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1423
	$ifinfo['if'] = get_real_interface($ifdescr);
1424

    
1425
	$chkif = $ifinfo['if'];
1426
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1427
	$ifinfo['status'] = $ifinfotmp['status'];
1428
	if (empty($ifinfo['status'])) {
1429
		$ifinfo['status'] = "down";
1430
	}
1431
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1432
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1433
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1434
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1435
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1436
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1437
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1438
	if (isset($ifinfotmp['link0'])) {
1439
		$link0 = "down";
1440
	}
1441
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1442
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1443
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1444
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1445
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1446
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1447

    
1448
	/* Use pfctl for non wrapping 64 bit counters */
1449
	/* Pass */
1450
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1451
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1452
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1453
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1454
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1455
	$in4_pass = $pf_in4_pass[5];
1456
	$out4_pass = $pf_out4_pass[5];
1457
	$in4_pass_packets = $pf_in4_pass[3];
1458
	$out4_pass_packets = $pf_out4_pass[3];
1459
	$in6_pass = $pf_in6_pass[5];
1460
	$out6_pass = $pf_out6_pass[5];
1461
	$in6_pass_packets = $pf_in6_pass[3];
1462
	$out6_pass_packets = $pf_out6_pass[3];
1463
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1464
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1465
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1466
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1467

    
1468
	/* Block */
1469
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1470
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1471
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1472
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1473
	$in4_block = $pf_in4_block[5];
1474
	$out4_block = $pf_out4_block[5];
1475
	$in4_block_packets = $pf_in4_block[3];
1476
	$out4_block_packets = $pf_out4_block[3];
1477
	$in6_block = $pf_in6_block[5];
1478
	$out6_block = $pf_out6_block[5];
1479
	$in6_block_packets = $pf_in6_block[3];
1480
	$out6_block_packets = $pf_out6_block[3];
1481
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1482
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1483
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1484
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1485

    
1486
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1487
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1488
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1489
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1490

    
1491
	$ifconfiginfo = "";
1492
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1493
	switch ($link_type) {
1494
		/* DHCP? -> see if dhclient is up */
1495
		case "dhcp":
1496
			/* see if dhclient is up */
1497
			if (find_dhclient_process($ifinfo['if']) != 0) {
1498
				$ifinfo['dhcplink'] = "up";
1499
			} else {
1500
				$ifinfo['dhcplink'] = "down";
1501
			}
1502

    
1503
			break;
1504
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1505
		case "pppoe":
1506
		case "pptp":
1507
		case "l2tp":
1508
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1509
				/* get PPPoE link status for dial on demand */
1510
				$ifinfo["{$link_type}link"] = "up";
1511
			} else {
1512
				$ifinfo["{$link_type}link"] = "down";
1513
			}
1514

    
1515
			break;
1516
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1517
		case "ppp":
1518
			if ($ifinfo['status'] == "up") {
1519
				$ifinfo['ppplink'] = "up";
1520
			} else {
1521
				$ifinfo['ppplink'] = "down" ;
1522
			}
1523

    
1524
			if (empty($ifinfo['status'])) {
1525
				$ifinfo['status'] = "down";
1526
			}
1527

    
1528
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1529
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1530
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1531
						break;
1532
					}
1533
				}
1534
			}
1535
			$dev = $ppp['ports'];
1536
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1537
				break;
1538
			}
1539
			if (!file_exists($dev)) {
1540
				$ifinfo['nodevice'] = 1;
1541
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1542
			}
1543

    
1544
			$usbmodemoutput = array();
1545
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1546
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1547
			if (file_exists($mondev)) {
1548
				$cellstats = file($mondev);
1549
				/* skip header */
1550
				$a_cellstats = explode(",", $cellstats[1]);
1551
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1552
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1553
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1554
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1555
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1556
				}
1557
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1558
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1559
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1560
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1561
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1562
				}
1563
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1564
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1565
				$ifinfo['cell_sent'] = $a_cellstats[6];
1566
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1567
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1568
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1569
			}
1570
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1571
			if (isset($ppp['uptime'])) {
1572
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1573
			}
1574
			break;
1575
		default:
1576
			break;
1577
	}
1578

    
1579
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1580
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1581
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1582
	}
1583

    
1584
	if ($ifinfo['status'] == "up") {
1585
		/* try to determine media with ifconfig */
1586
		unset($ifconfiginfo);
1587
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1588
		$wifconfiginfo = array();
1589
		if (is_interface_wireless($ifdescr)) {
1590
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1591
			array_shift($wifconfiginfo);
1592
		}
1593
		$matches = "";
1594
		foreach ($ifconfiginfo as $ici) {
1595

    
1596
			/* don't list media/speed for wireless cards, as it always
1597
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1598
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1599
				$ifinfo['media'] = $matches[1];
1600
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1601
				$ifinfo['media'] = $matches[1];
1602
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1603
				$ifinfo['media'] = $matches[1];
1604
			}
1605

    
1606
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1607
				if ($matches[1] != "active") {
1608
					$ifinfo['status'] = $matches[1];
1609
				}
1610
				if ($ifinfo['status'] == gettext("running")) {
1611
					$ifinfo['status'] = gettext("up");
1612
				}
1613
			}
1614
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1615
				$ifinfo['channel'] = $matches[1];
1616
			}
1617
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1618
				if ($matches[1][0] == '"') {
1619
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1620
				}
1621
				else {
1622
					$ifinfo['ssid'] = $matches[1];
1623
				}
1624
			}
1625
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1626
				$ifinfo['laggproto'] = $matches[1];
1627
			}
1628
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1629
				$ifinfo['laggport'][] = $matches[1];
1630
			}
1631
		}
1632
		foreach ($wifconfiginfo as $ici) {
1633
			$elements = preg_split("/[ ]+/i", $ici);
1634
			if ($elements[0] != "") {
1635
				$ifinfo['bssid'] = $elements[0];
1636
			}
1637
			if ($elements[3] != "") {
1638
				$ifinfo['rate'] = $elements[3];
1639
			}
1640
			if ($elements[4] != "") {
1641
				$ifinfo['rssi'] = $elements[4];
1642
			}
1643
		}
1644
		/* lookup the gateway */
1645
		if (interface_has_gateway($ifdescr)) {
1646
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1647
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1648
		}
1649
	}
1650

    
1651
	$bridge = "";
1652
	$bridge = link_interface_to_bridge($ifdescr);
1653
	if ($bridge) {
1654
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1655
		if (stristr($bridge_text, "blocking") <> false) {
1656
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1657
			$ifinfo['bridgeint'] = $bridge;
1658
		} else if (stristr($bridge_text, "learning") <> false) {
1659
			$ifinfo['bridge'] = gettext("learning");
1660
			$ifinfo['bridgeint'] = $bridge;
1661
		} else if (stristr($bridge_text, "forwarding") <> false) {
1662
			$ifinfo['bridge'] = gettext("forwarding");
1663
			$ifinfo['bridgeint'] = $bridge;
1664
		}
1665
	}
1666

    
1667
	return $ifinfo;
1668
}
1669

    
1670
//returns cpu speed of processor. Good for determining capabilities of machine
1671
function get_cpu_speed() {
1672
	return get_single_sysctl("hw.clockrate");
1673
}
1674

    
1675
function get_uptime_sec() {
1676
	$boottime = "";
1677
	$matches = "";
1678
	$boottime = get_single_sysctl("kern.boottime");
1679
	preg_match("/sec = (\d+)/", $boottime, $matches);
1680
	$boottime = $matches[1];
1681
	if (intval($boottime) == 0) {
1682
		return 0;
1683
	}
1684

    
1685
	$uptime = time() - $boottime;
1686
	return $uptime;
1687
}
1688

    
1689
function add_hostname_to_watch($hostname) {
1690
	if (!is_dir("/var/db/dnscache")) {
1691
		mkdir("/var/db/dnscache");
1692
	}
1693
	$result = array();
1694
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1695
		$domrecords = array();
1696
		$domips = array();
1697
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1698
		if ($rethost == 0) {
1699
			foreach ($domrecords as $domr) {
1700
				$doml = explode(" ", $domr);
1701
				$domip = $doml[3];
1702
				/* fill array with domain ip addresses */
1703
				if (is_ipaddr($domip)) {
1704
					$domips[] = $domip;
1705
				}
1706
			}
1707
		}
1708
		sort($domips);
1709
		$contents = "";
1710
		if (!empty($domips)) {
1711
			foreach ($domips as $ip) {
1712
				$contents .= "$ip\n";
1713
			}
1714
		}
1715
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1716
		/* Remove empty elements */
1717
		$result = array_filter(explode("\n", $contents), 'strlen');
1718
	}
1719
	return $result;
1720
}
1721

    
1722
function is_fqdn($fqdn) {
1723
	$hostname = false;
1724
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1725
		$hostname = true;
1726
	}
1727
	if (preg_match("/\.\./", $fqdn)) {
1728
		$hostname = false;
1729
	}
1730
	if (preg_match("/^\./i", $fqdn)) {
1731
		$hostname = false;
1732
	}
1733
	if (preg_match("/\//i", $fqdn)) {
1734
		$hostname = false;
1735
	}
1736
	return($hostname);
1737
}
1738

    
1739
function pfsense_default_state_size() {
1740
	/* get system memory amount */
1741
	$memory = get_memory();
1742
	$physmem = $memory[0];
1743
	/* Be cautious and only allocate 10% of system memory to the state table */
1744
	$max_states = (int) ($physmem/10)*1000;
1745
	return $max_states;
1746
}
1747

    
1748
function pfsense_default_tables_size() {
1749
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1750
	return $current;
1751
}
1752

    
1753
function pfsense_default_table_entries_size() {
1754
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1755
	return (trim($current));
1756
}
1757

    
1758
/* Compare the current hostname DNS to the DNS cache we made
1759
 * if it has changed we return the old records
1760
 * if no change we return false */
1761
function compare_hostname_to_dnscache($hostname) {
1762
	if (!is_dir("/var/db/dnscache")) {
1763
		mkdir("/var/db/dnscache");
1764
	}
1765
	$hostname = trim($hostname);
1766
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1767
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1768
	} else {
1769
		$oldcontents = "";
1770
	}
1771
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1772
		$domrecords = array();
1773
		$domips = array();
1774
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1775
		if ($rethost == 0) {
1776
			foreach ($domrecords as $domr) {
1777
				$doml = explode(" ", $domr);
1778
				$domip = $doml[3];
1779
				/* fill array with domain ip addresses */
1780
				if (is_ipaddr($domip)) {
1781
					$domips[] = $domip;
1782
				}
1783
			}
1784
		}
1785
		sort($domips);
1786
		$contents = "";
1787
		if (!empty($domips)) {
1788
			foreach ($domips as $ip) {
1789
				$contents .= "$ip\n";
1790
			}
1791
		}
1792
	}
1793

    
1794
	if (trim($oldcontents) != trim($contents)) {
1795
		if ($g['debug']) {
1796
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1797
		}
1798
		return ($oldcontents);
1799
	} else {
1800
		return false;
1801
	}
1802
}
1803

    
1804
/*
1805
 * load_crypto() - Load crypto modules if enabled in config.
1806
 */
1807
function load_crypto() {
1808
	global $config, $g;
1809
	$crypto_modules = array('glxsb', 'aesni');
1810

    
1811
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1812
		return false;
1813
	}
1814

    
1815
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1816
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1817
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1818
	}
1819
}
1820

    
1821
/*
1822
 * load_thermal_hardware() - Load temperature monitor kernel module
1823
 */
1824
function load_thermal_hardware() {
1825
	global $config, $g;
1826
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1827

    
1828
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1829
		return false;
1830
	}
1831

    
1832
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1833
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1834
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1835
	}
1836
}
1837

    
1838
/****f* pfsense-utils/isvm
1839
 * NAME
1840
 *   isvm
1841
 * INPUTS
1842
 *	none
1843
 * RESULT
1844
 *   returns true if machine is running under a virtual environment
1845
 ******/
1846
function isvm() {
1847
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1848
	$_gb = exec('/bin/kenv smbios.system.product 2>/dev/null', $output, $rc);
1849

    
1850
	if ($rc != 0 || !isset($output[0])) {
1851
		return false;
1852
	}
1853

    
1854
	foreach ($virtualenvs as $virtualenv) {
1855
		if (stripos($output[0], $virtualenv) !== false) {
1856
			return true;
1857
		}
1858
	}
1859

    
1860
	return false;
1861
}
1862

    
1863
function get_freebsd_version() {
1864
	$version = explode(".", php_uname("r"));
1865
	return $version[0];
1866
}
1867

    
1868
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1869
	global $config, $g;
1870

    
1871
	$fp = fopen($destination, "wb");
1872

    
1873
	if (!$fp) {
1874
		return false;
1875
	}
1876

    
1877
	$ch = curl_init();
1878
	curl_setopt($ch, CURLOPT_URL, $url);
1879
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1880
	curl_setopt($ch, CURLOPT_FILE, $fp);
1881
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1882
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1883
	curl_setopt($ch, CURLOPT_HEADER, false);
1884
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1885
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1886
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1887
	} else {
1888
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1889
	}
1890

    
1891
	if (!empty($config['system']['proxyurl'])) {
1892
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1893
		if (!empty($config['system']['proxyport'])) {
1894
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1895
		}
1896
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1897
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1898
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1899
		}
1900
	}
1901

    
1902
	@curl_exec($ch);
1903
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1904
	fclose($fp);
1905
	curl_close($ch);
1906
	if ($http_code == 200) {
1907
		return true;
1908
	} else {
1909
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1910
		unlink_if_exists($destination);
1911
		return false;
1912
	}
1913
}
1914

    
1915
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1916
	global $config, $g;
1917
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1918
	$file_size = 1;
1919
	$downloaded = 1;
1920
	$first_progress_update = TRUE;
1921
	/* open destination file */
1922
	$fout = fopen($destination, "wb");
1923

    
1924
	if (!$fout) {
1925
		return false;
1926
	}
1927
	/*
1928
	 *      Originally by Author: Keyvan Minoukadeh
1929
	 *      Modified by Scott Ullrich to return Content-Length size
1930
	 */
1931
	$ch = curl_init();
1932
	curl_setopt($ch, CURLOPT_URL, $url);
1933
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1934
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
1935
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1936
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
1937
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1938
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1939
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1940
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1941
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1942
	} else {
1943
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1944
	}
1945

    
1946
	if (!empty($config['system']['proxyurl'])) {
1947
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1948
		if (!empty($config['system']['proxyport'])) {
1949
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1950
		}
1951
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1952
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1953
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1954
		}
1955
	}
1956

    
1957
	@curl_exec($ch);
1958
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1959
	fclose($fout);
1960
	curl_close($ch);
1961
	if ($http_code == 200) {
1962
		return true;
1963
	} else {
1964
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1965
		unlink_if_exists($destination);
1966
		return false;
1967
	}
1968
}
1969

    
1970
function read_header($ch, $string) {
1971
	global $file_size, $fout;
1972
	$length = strlen($string);
1973
	$regs = "";
1974
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
1975
	if ($regs[2] <> "") {
1976
		$file_size = intval($regs[2]);
1977
	}
1978
	ob_flush();
1979
	return $length;
1980
}
1981

    
1982
function read_body($ch, $string) {
1983
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
1984
	global $pkg_interface;
1985
	$length = strlen($string);
1986
	$downloaded += intval($length);
1987
	if ($file_size > 0) {
1988
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
1989
		$downloadProgress = 100 - $downloadProgress;
1990
	} else {
1991
		$downloadProgress = 0;
1992
	}
1993
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
1994
		if ($sendto == "status") {
1995
			if ($pkg_interface == "console") {
1996
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
1997
					$tostatus = $static_status . $downloadProgress . "%";
1998
					if ($downloadProgress == 100) {
1999
						$tostatus = $tostatus . "\r";
2000
					}
2001
					update_status($tostatus);
2002
				}
2003
			} else {
2004
				$tostatus = $static_status . $downloadProgress . "%";
2005
				update_status($tostatus);
2006
			}
2007
		} else {
2008
			if ($pkg_interface == "console") {
2009
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2010
					$tooutput = $static_output . $downloadProgress . "%";
2011
					if ($downloadProgress == 100) {
2012
						$tooutput = $tooutput . "\r";
2013
					}
2014
					update_output_window($tooutput);
2015
				}
2016
			} else {
2017
				$tooutput = $static_output . $downloadProgress . "%";
2018
				update_output_window($tooutput);
2019
			}
2020
		}
2021
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2022
			update_progress_bar($downloadProgress, $first_progress_update);
2023
			$first_progress_update = FALSE;
2024
		}
2025
		$lastseen = $downloadProgress;
2026
	}
2027
	if ($fout) {
2028
		fwrite($fout, $string);
2029
	}
2030
	ob_flush();
2031
	return $length;
2032
}
2033

    
2034
/*
2035
 *   update_output_window: update bottom textarea dynamically.
2036
 */
2037
function update_output_window($text) {
2038
	global $pkg_interface;
2039
	$log = preg_replace("/\n/", "\\n", $text);
2040
	if ($pkg_interface != "console") {
2041
?>
2042
<script type="text/javascript">
2043
//<![CDATA[
2044
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2045
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2046
//]]>
2047
</script>
2048
<?php
2049
	}
2050
	/* ensure that contents are written out */
2051
	ob_flush();
2052
}
2053

    
2054
/*
2055
 *   update_status: update top textarea dynamically.
2056
 */
2057
function update_status($status) {
2058
	global $pkg_interface;
2059

    
2060
	if ($pkg_interface == "console") {
2061
		print ("{$status}");
2062
	}
2063

    
2064
	/* ensure that contents are written out */
2065
	ob_flush();
2066
}
2067

    
2068
/*
2069
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2070
 */
2071
function update_progress_bar($percent, $first_time) {
2072
	global $pkg_interface;
2073
	if ($percent > 100) {
2074
		$percent = 1;
2075
	}
2076
	if ($pkg_interface <> "console") {
2077
		echo '<script type="text/javascript">';
2078
		echo "\n//<![CDATA[\n";
2079
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2080
		echo "\n//]]>\n";
2081
		echo '</script>';
2082
	} else {
2083
		if (!($first_time)) {
2084
			echo "\x08\x08\x08\x08\x08";
2085
		}
2086
		echo sprintf("%4d%%", $percent);
2087
	}
2088
}
2089

    
2090
/* 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. */
2091
if (!function_exists("split")) {
2092
	function split($separator, $haystack, $limit = null) {
2093
		log_error("deprecated split() call with separator '{$separator}'");
2094
		return preg_split($separator, $haystack, $limit);
2095
	}
2096
}
2097

    
2098
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2099
	global $g, $config, $pconfig, $debug;
2100
	if (!$origname) {
2101
		return;
2102
	}
2103

    
2104
	$sectionref = &$config;
2105
	foreach ($section as $sectionname) {
2106
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2107
			$sectionref = &$sectionref[$sectionname];
2108
		} else {
2109
			return;
2110
		}
2111
	}
2112

    
2113
	if ($debug) {
2114
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2115
		fwrite($fd, print_r($pconfig, true));
2116
	}
2117

    
2118
	if (is_array($sectionref)) {
2119
		foreach ($sectionref as $itemkey => $item) {
2120
			if ($debug) {
2121
				fwrite($fd, "$itemkey\n");
2122
			}
2123

    
2124
			$fieldfound = true;
2125
			$fieldref = &$sectionref[$itemkey];
2126
			foreach ($field as $fieldname) {
2127
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2128
					$fieldref = &$fieldref[$fieldname];
2129
				} else {
2130
					$fieldfound = false;
2131
					break;
2132
				}
2133
			}
2134
			if ($fieldfound && $fieldref == $origname) {
2135
				if ($debug) {
2136
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2137
				}
2138
				$fieldref = $new_alias_name;
2139
			}
2140
		}
2141
	}
2142

    
2143
	if ($debug) {
2144
		fclose($fd);
2145
	}
2146

    
2147
}
2148

    
2149
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2150
	/*
2151
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2152
	 * $type = if set to 'url' then subnets and ips will be returned,
2153
	 *         if set to 'url_ports' port-ranges and ports will be returned
2154
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2155
	 *
2156
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2157
	 */
2158

    
2159
	if (!file_exists($filename)) {
2160
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2161
		return null;
2162
	}
2163

    
2164
	if (filesize($filename) == 0) {
2165
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2166
		return null;
2167
	}
2168
	$fd = @fopen($filename, 'r');
2169
	if (!$fd) {
2170
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2171
		return null;
2172
	}
2173
	$items = array();
2174
	$comments = array();
2175
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2176
	while (($fc = fgetss($fd)) !== FALSE) {
2177
		$tmp = trim($fc, " \t\n\r");
2178
		if (empty($tmp)) {
2179
			continue;
2180
		}
2181
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2182
			$comments[] = $tmp;
2183
		} else {
2184
			$tmp_str = strstr($tmp, '#', true);
2185
			if (!empty($tmp_str)) {
2186
				$tmp = $tmp_str;
2187
			}
2188
			$tmp_str = strstr($tmp, ' ', true);
2189
			if (!empty($tmp_str)) {
2190
				$tmp = $tmp_str;
2191
			}
2192
			$valid = (($type == "url" || $type == "urltable") && (is_ipaddr($tmp) || is_subnet($tmp))) ||
2193
				(($type == "url_ports" || $type == "urltable_ports") && (is_port($tmp) || is_portrange($tmp)));
2194
			if ($valid) {
2195
				$items[] = $tmp;
2196
				if (count($items) == $max_items) {
2197
					break;
2198
				}
2199
			}
2200
		}
2201
	}
2202
	fclose($fd);
2203
	return array_merge($comments, $items);
2204
}
2205

    
2206
function update_alias_url_data() {
2207
	global $config, $g;
2208

    
2209
	$updated = false;
2210

    
2211
	/* item is a url type */
2212
	$lockkey = lock('aliasurl');
2213
	if (is_array($config['aliases']['alias'])) {
2214
		foreach ($config['aliases']['alias'] as $x => $alias) {
2215
			if (empty($alias['aliasurl'])) {
2216
				continue;
2217
			}
2218

    
2219
			$address = null;
2220
			foreach ($alias['aliasurl'] as $alias_url) {
2221
				/* fetch down and add in */
2222
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2223
				unlink($temp_filename);
2224
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2225
				mkdir($temp_filename);
2226
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2227
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2228
					continue;
2229
				}
2230

    
2231
				/* if the item is tar gzipped then extract */
2232
				if (stripos($alias_url, '.tgz')) {
2233
					if (!process_alias_tgz($temp_filename)) {
2234
						continue;
2235
					}
2236
				}
2237
				if (file_exists("{$temp_filename}/aliases")) {
2238
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2239
					mwexec("/bin/rm -rf {$temp_filename}");
2240
				}
2241
			}
2242
			if ($address != null) {
2243
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2244
				$updated = true;
2245
			}
2246
		}
2247
	}
2248
	unlock($lockkey);
2249

    
2250
	/* Report status to callers as well */
2251
	return $updated;
2252
}
2253

    
2254
function process_alias_tgz($temp_filename) {
2255
	if (!file_exists('/usr/bin/tar')) {
2256
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2257
		return false;
2258
	}
2259
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2260
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2261
	unlink("{$temp_filename}/aliases.tgz");
2262
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2263
	/* foreach through all extracted files and build up aliases file */
2264
	$fd = @fopen("{$temp_filename}/aliases", "w");
2265
	if (!$fd) {
2266
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2267
		return false;
2268
	}
2269
	foreach ($files_to_process as $f2p) {
2270
		$tmpfd = @fopen($f2p, 'r');
2271
		if (!$tmpfd) {
2272
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2273
			continue;
2274
		}
2275
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2276
			fwrite($fd, $tmpbuf);
2277
		}
2278
		fclose($tmpfd);
2279
		unlink($f2p);
2280
	}
2281
	fclose($fd);
2282
	unset($tmpbuf);
2283

    
2284
	return true;
2285
}
2286

    
2287
function version_compare_dates($a, $b) {
2288
	$a_time = strtotime($a);
2289
	$b_time = strtotime($b);
2290

    
2291
	if ((!$a_time) || (!$b_time)) {
2292
		return FALSE;
2293
	} else {
2294
		if ($a_time < $b_time) {
2295
			return -1;
2296
		} elseif ($a_time == $b_time) {
2297
			return 0;
2298
		} else {
2299
			return 1;
2300
		}
2301
	}
2302
}
2303
function version_get_string_value($a) {
2304
	$strs = array(
2305
		0 => "ALPHA-ALPHA",
2306
		2 => "ALPHA",
2307
		3 => "BETA",
2308
		4 => "B",
2309
		5 => "C",
2310
		6 => "D",
2311
		7 => "RC",
2312
		8 => "RELEASE",
2313
		9 => "*"			// Matches all release levels
2314
	);
2315
	$major = 0;
2316
	$minor = 0;
2317
	foreach ($strs as $num => $str) {
2318
		if (substr($a, 0, strlen($str)) == $str) {
2319
			$major = $num;
2320
			$n = substr($a, strlen($str));
2321
			if (is_numeric($n)) {
2322
				$minor = $n;
2323
			}
2324
			break;
2325
		}
2326
	}
2327
	return "{$major}.{$minor}";
2328
}
2329
function version_compare_string($a, $b) {
2330
	// Only compare string parts if both versions give a specific release
2331
	// (If either version lacks a string part, assume intended to match all release levels)
2332
	if (isset($a) && isset($b)) {
2333
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2334
	} else {
2335
		return 0;
2336
	}
2337
}
2338
function version_compare_numeric($a, $b) {
2339
	$a_arr = explode('.', rtrim($a, '.'));
2340
	$b_arr = explode('.', rtrim($b, '.'));
2341

    
2342
	foreach ($a_arr as $n => $val) {
2343
		if (array_key_exists($n, $b_arr)) {
2344
			// So far so good, both have values at this minor version level. Compare.
2345
			if ($val > $b_arr[$n]) {
2346
				return 1;
2347
			} elseif ($val < $b_arr[$n]) {
2348
				return -1;
2349
			}
2350
		} else {
2351
			// a is greater, since b doesn't have any minor version here.
2352
			return 1;
2353
		}
2354
	}
2355
	if (count($b_arr) > count($a_arr)) {
2356
		// b is longer than a, so it must be greater.
2357
		return -1;
2358
	} else {
2359
		// Both a and b are of equal length and value.
2360
		return 0;
2361
	}
2362
}
2363
function pfs_version_compare($cur_time, $cur_text, $remote) {
2364
	// First try date compare
2365
	$v = version_compare_dates($cur_time, $remote);
2366
	if ($v === FALSE) {
2367
		// If that fails, try to compare by string
2368
		// Before anything else, simply test if the strings are equal
2369
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2370
			return 0;
2371
		}
2372
		list($cur_num, $cur_str) = explode('-', $cur_text);
2373
		list($rem_num, $rem_str) = explode('-', $remote);
2374

    
2375
		// First try to compare the numeric parts of the version string.
2376
		$v = version_compare_numeric($cur_num, $rem_num);
2377

    
2378
		// If the numeric parts are the same, compare the string parts.
2379
		if ($v == 0) {
2380
			return version_compare_string($cur_str, $rem_str);
2381
		}
2382
	}
2383
	return $v;
2384
}
2385
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2386
	global $g, $config;
2387

    
2388
	$urltable_prefix = "/var/db/aliastables/";
2389
	$urltable_filename = $urltable_prefix . $name . ".txt";
2390
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2391

    
2392
	// Make the aliases directory if it doesn't exist
2393
	if (!file_exists($urltable_prefix)) {
2394
		mkdir($urltable_prefix);
2395
	} elseif (!is_dir($urltable_prefix)) {
2396
		unlink($urltable_prefix);
2397
		mkdir($urltable_prefix);
2398
	}
2399

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

    
2405
		// Try to fetch the URL supplied
2406
		conf_mount_rw();
2407
		unlink_if_exists($tmp_urltable_filename);
2408
		$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2409
		if (download_file($url, $tmp_urltable_filename, $verify_ssl)) {
2410
			// Convert lines that begin with '$' or ';' to comments '#' instead of deleting them.
2411
			mwexec("/usr/bin/sed -i \"\" -E 's/^[[:space:]]*($|#|;)/#/g; /^#/!s/\;.*//g;' ". escapeshellarg($tmp_urltable_filename));
2412

    
2413
			$type = ($type) ? $type : alias_get_type($name);	// If empty type passed, try to get it from config.
2414

    
2415
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2416
			if ($type == "urltable_ports") {
2417
				$parsed_contents = group_ports($parsed_contents, true);
2418
			}
2419
			if (is_array($parsed_contents)) {
2420
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2421
			}
2422

    
2423
			/* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */
2424
			if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
2425
				unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz");
2426
			} else {
2427
				/* Update the RAM disk store with the new/updated table file. */
2428
				mwexec("cd / && /usr/bin/tar -czf \"{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz\" -C / \"{$urltable_filename}\"");
2429
			}
2430
			unlink_if_exists($tmp_urltable_filename);
2431
		} else {
2432
			if (!$validateonly) {
2433
				touch($urltable_filename);
2434
			}
2435
			conf_mount_ro();
2436
			return false;
2437
		}
2438
		conf_mount_ro();
2439
		return true;
2440
	} else {
2441
		// File exists, and it doesn't need to be updated.
2442
		return -1;
2443
	}
2444
}
2445
function get_real_slice_from_glabel($label) {
2446
	$label = escapeshellarg($label);
2447
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/{$label} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`);
2448
}
2449
function nanobsd_get_boot_slice() {
2450
	return trim(`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`);
2451
}
2452
function nanobsd_get_boot_drive() {
2453
	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`);
2454
}
2455
function nanobsd_get_active_slice() {
2456
	$boot_drive = nanobsd_get_boot_drive();
2457
	$active = trim(`gpart show $boot_drive | grep '\[active\]' | awk '{print $3;}'`);
2458

    
2459
	return "{$boot_drive}s{$active}";
2460
}
2461
function nanobsd_get_size() {
2462
	return strtoupper(file_get_contents("/etc/nanosize.txt"));
2463
}
2464
function nanobsd_switch_boot_slice() {
2465
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2466
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2467
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2468
	nanobsd_detect_slice_info();
2469

    
2470
	if ($BOOTFLASH == $ACTIVE_SLICE) {
2471
		$slice = $TOFLASH;
2472
	} else {
2473
		$slice = $BOOTFLASH;
2474
	}
2475

    
2476
	for ($i = 0; $i < ob_get_level(); $i++) {
2477
		ob_end_flush();
2478
	}
2479
	ob_implicit_flush(1);
2480
	if (strstr($slice, "s2")) {
2481
		$ASLICE = "2";
2482
		$AOLDSLICE = "1";
2483
		$AGLABEL_SLICE = "pfsense1";
2484
		$AUFS_ID = "1";
2485
		$AOLD_UFS_ID = "0";
2486
	} else {
2487
		$ASLICE = "1";
2488
		$AOLDSLICE = "2";
2489
		$AGLABEL_SLICE = "pfsense0";
2490
		$AUFS_ID = "0";
2491
		$AOLD_UFS_ID = "1";
2492
	}
2493
	$ATOFLASH = "{$BOOT_DRIVE}s{$ASLICE}";
2494
	$ACOMPLETE_PATH = "{$BOOT_DRIVE}s{$ASLICE}a";
2495
	$ABOOTFLASH = "{$BOOT_DRIVE}s{$AOLDSLICE}";
2496
	conf_mount_rw();
2497
	set_single_sysctl("kern.geom.debugflags", "16");
2498
	exec("/sbin/gpart set -a active -i {$ASLICE} {$BOOT_DRIVE}");
2499
	exec("/usr/sbin/boot0cfg -s {$ASLICE} -v /dev/{$BOOT_DRIVE}");
2500
	// We can't update these if they are mounted now.
2501
	if ($BOOTFLASH != $slice) {
2502
		exec("/sbin/tunefs -L ${AGLABEL_SLICE} /dev/$ACOMPLETE_PATH");
2503
		nanobsd_update_fstab($AGLABEL_SLICE, $ACOMPLETE_PATH, $AOLD_UFS_ID, $AUFS_ID);
2504
	}
2505
	set_single_sysctl("kern.geom.debugflags", "0");
2506
	conf_mount_ro();
2507
}
2508
function nanobsd_clone_slice() {
2509
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2510
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2511
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2512
	nanobsd_detect_slice_info();
2513

    
2514
	for ($i = 0; $i < ob_get_level(); $i++) {
2515
		ob_end_flush();
2516
	}
2517
	ob_implicit_flush(1);
2518
	set_single_sysctl("kern.geom.debugflags", "16");
2519
	exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
2520
	exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
2521
	exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
2522
	$status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
2523
	set_single_sysctl("kern.geom.debugflags", "0");
2524
	if ($status) {
2525
		return false;
2526
	} else {
2527
		return true;
2528
	}
2529
}
2530
function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
2531
	$tmppath = "/tmp/{$gslice}";
2532
	$fstabpath = "/tmp/{$gslice}/etc/fstab";
2533

    
2534
	mkdir($tmppath);
2535
	exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
2536
	exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
2537
	copy("/etc/fstab", $fstabpath);
2538

    
2539
	if (!file_exists($fstabpath)) {
2540
		$fstab = <<<EOF
2541
/dev/ufs/{$gslice} / ufs ro,noatime 1 1
2542
/dev/ufs/cf /cf ufs ro,noatime 1 1
2543
EOF;
2544
		if (file_put_contents($fstabpath, $fstab)) {
2545
			$status = true;
2546
		} else {
2547
			$status = false;
2548
		}
2549
	} else {
2550
		$status = exec("/usr/bin/sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
2551
	}
2552
	exec("/sbin/umount {$tmppath}");
2553
	rmdir($tmppath);
2554

    
2555
	return $status;
2556
}
2557
function nanobsd_detect_slice_info() {
2558
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2559
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2560
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2561

    
2562
	$BOOT_DEVICE=nanobsd_get_boot_slice();
2563
	$REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
2564
	$BOOT_DRIVE=nanobsd_get_boot_drive();
2565
	$ACTIVE_SLICE=nanobsd_get_active_slice();
2566

    
2567
	// Detect which slice is active and set information.
2568
	if (strstr($REAL_BOOT_DEVICE, "s1")) {
2569
		$SLICE = "2";
2570
		$OLDSLICE = "1";
2571
		$GLABEL_SLICE = "pfsense1";
2572
		$UFS_ID = "1";
2573
		$OLD_UFS_ID = "0";
2574

    
2575
	} else {
2576
		$SLICE = "1";
2577
		$OLDSLICE = "2";
2578
		$GLABEL_SLICE = "pfsense0";
2579
		$UFS_ID = "0";
2580
		$OLD_UFS_ID = "1";
2581
	}
2582
	$TOFLASH = "{$BOOT_DRIVE}s{$SLICE}";
2583
	$COMPLETE_PATH = "{$BOOT_DRIVE}s{$SLICE}a";
2584
	$COMPLETE_BOOT_PATH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2585
	$BOOTFLASH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2586
}
2587

    
2588
function nanobsd_friendly_slice_name($slicename) {
2589
	global $g;
2590
	return strtolower(str_ireplace('pfsense', $g['product_name'], $slicename));
2591
}
2592

    
2593
function get_include_contents($filename) {
2594
	if (is_file($filename)) {
2595
		ob_start();
2596
		include $filename;
2597
		$contents = ob_get_contents();
2598
		ob_end_clean();
2599
		return $contents;
2600
	}
2601
	return false;
2602
}
2603

    
2604
/* This xml 2 array function is courtesy of the php.net comment section on xml_parse.
2605
 * it is roughly 4 times faster then our existing pfSense parser but due to the large
2606
 * size of the RRD xml dumps this is required.
2607
 * The reason we do not use it for pfSense is that it does not know about array fields
2608
 * which causes it to fail on array fields with single items. Possible Todo?
2609
 */
2610
function xml2array($contents, $get_attributes = 1, $priority = 'tag') {
2611
	if (!function_exists('xml_parser_create')) {
2612
		return array ();
2613
	}
2614
	$parser = xml_parser_create('');
2615
	xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
2616
	xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2617
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2618
	xml_parse_into_struct($parser, trim($contents), $xml_values);
2619
	xml_parser_free($parser);
2620
	if (!$xml_values) {
2621
		return; //Hmm...
2622
	}
2623
	$xml_array = array ();
2624
	$parents = array ();
2625
	$opened_tags = array ();
2626
	$arr = array ();
2627
	$current = & $xml_array;
2628
	$repeated_tag_index = array ();
2629
	foreach ($xml_values as $data) {
2630
		unset ($attributes, $value);
2631
		extract($data);
2632
		$result = array ();
2633
		$attributes_data = array ();
2634
		if (isset ($value)) {
2635
			if ($priority == 'tag') {
2636
				$result = $value;
2637
			} else {
2638
				$result['value'] = $value;
2639
			}
2640
		}
2641
		if (isset ($attributes) and $get_attributes) {
2642
			foreach ($attributes as $attr => $val) {
2643
				if ($priority == 'tag') {
2644
					$attributes_data[$attr] = $val;
2645
				} else {
2646
					$result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
2647
				}
2648
			}
2649
		}
2650
		if ($type == "open") {
2651
			$parent[$level -1] = & $current;
2652
			if (!is_array($current) or (!in_array($tag, array_keys($current)))) {
2653
				$current[$tag] = $result;
2654
				if ($attributes_data) {
2655
					$current[$tag . '_attr'] = $attributes_data;
2656
				}
2657
				$repeated_tag_index[$tag . '_' . $level] = 1;
2658
				$current = & $current[$tag];
2659
			} else {
2660
				if (isset ($current[$tag][0])) {
2661
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2662
					$repeated_tag_index[$tag . '_' . $level]++;
2663
				} else {
2664
					$current[$tag] = array (
2665
						$current[$tag],
2666
						$result
2667
						);
2668
					$repeated_tag_index[$tag . '_' . $level] = 2;
2669
					if (isset ($current[$tag . '_attr'])) {
2670
						$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2671
						unset ($current[$tag . '_attr']);
2672
					}
2673
				}
2674
				$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
2675
				$current = & $current[$tag][$last_item_index];
2676
			}
2677
		} elseif ($type == "complete") {
2678
			if (!isset ($current[$tag])) {
2679
				$current[$tag] = $result;
2680
				$repeated_tag_index[$tag . '_' . $level] = 1;
2681
				if ($priority == 'tag' and $attributes_data) {
2682
					$current[$tag . '_attr'] = $attributes_data;
2683
				}
2684
			} else {
2685
				if (isset ($current[$tag][0]) and is_array($current[$tag])) {
2686
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2687
					if ($priority == 'tag' and $get_attributes and $attributes_data) {
2688
						$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2689
					}
2690
					$repeated_tag_index[$tag . '_' . $level]++;
2691
				} else {
2692
					$current[$tag] = array (
2693
						$current[$tag],
2694
						$result
2695
						);
2696
					$repeated_tag_index[$tag . '_' . $level] = 1;
2697
					if ($priority == 'tag' and $get_attributes) {
2698
						if (isset ($current[$tag . '_attr'])) {
2699
							$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2700
							unset ($current[$tag . '_attr']);
2701
						}
2702
						if ($attributes_data) {
2703
							$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2704
						}
2705
					}
2706
					$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
2707
				}
2708
			}
2709
		} elseif ($type == 'close') {
2710
			$current = & $parent[$level -1];
2711
		}
2712
	}
2713
	return ($xml_array);
2714
}
2715

    
2716
function get_country_name($country_code) {
2717
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2718
		return "";
2719
	}
2720

    
2721
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2722
	$country_names_contents = file_get_contents($country_names_xml);
2723
	$country_names = xml2array($country_names_contents);
2724

    
2725
	if ($country_code == "ALL") {
2726
		$country_list = array();
2727
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2728
			$country_list[] = array(
2729
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2730
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2731
		}
2732
		return $country_list;
2733
	}
2734

    
2735
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2736
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2737
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2738
		}
2739
	}
2740
	return "";
2741
}
2742

    
2743
/* sort by interface only, retain the original order of rules that apply to
2744
   the same interface */
2745
function filter_rules_sort() {
2746
	global $config;
2747

    
2748
	/* mark each rule with the sequence number (to retain the order while sorting) */
2749
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2750
		$config['filter']['rule'][$i]['seq'] = $i;
2751
	}
2752

    
2753
	usort($config['filter']['rule'], "filter_rules_compare");
2754

    
2755
	/* strip the sequence numbers again */
2756
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2757
		unset($config['filter']['rule'][$i]['seq']);
2758
	}
2759
}
2760
function filter_rules_compare($a, $b) {
2761
	if (isset($a['floating']) && isset($b['floating'])) {
2762
		return $a['seq'] - $b['seq'];
2763
	} else if (isset($a['floating'])) {
2764
		return -1;
2765
	} else if (isset($b['floating'])) {
2766
		return 1;
2767
	} else if ($a['interface'] == $b['interface']) {
2768
		return $a['seq'] - $b['seq'];
2769
	} else {
2770
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2771
	}
2772
}
2773

    
2774
function generate_ipv6_from_mac($mac) {
2775
	$elements = explode(":", $mac);
2776
	if (count($elements) <> 6) {
2777
		return false;
2778
	}
2779

    
2780
	$i = 0;
2781
	$ipv6 = "fe80::";
2782
	foreach ($elements as $byte) {
2783
		if ($i == 0) {
2784
			$hexadecimal = substr($byte, 1, 2);
2785
			$bitmap = base_convert($hexadecimal, 16, 2);
2786
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2787
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2788
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2789
		}
2790
		$ipv6 .= $byte;
2791
		if ($i == 1) {
2792
			$ipv6 .= ":";
2793
		}
2794
		if ($i == 3) {
2795
			$ipv6 .= ":";
2796
		}
2797
		if ($i == 2) {
2798
			$ipv6 .= "ff:fe";
2799
		}
2800

    
2801
		$i++;
2802
	}
2803
	return $ipv6;
2804
}
2805

    
2806
/****f* pfsense-utils/load_mac_manufacturer_table
2807
 * NAME
2808
 *   load_mac_manufacturer_table
2809
 * INPUTS
2810
 *   none
2811
 * RESULT
2812
 *   returns associative array with MAC-Manufacturer pairs
2813
 ******/
2814
function load_mac_manufacturer_table() {
2815
	/* load MAC-Manufacture data from the file */
2816
	$macs = false;
2817
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2818
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2819
	}
2820
	if ($macs) {
2821
		foreach ($macs as $line) {
2822
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2823
				/* store values like this $mac_man['000C29']='VMware' */
2824
				$mac_man["$matches[1]"] = $matches[2];
2825
			}
2826
		}
2827
		return $mac_man;
2828
	} else {
2829
		return -1;
2830
	}
2831

    
2832
}
2833

    
2834
/****f* pfsense-utils/is_ipaddr_configured
2835
 * NAME
2836
 *   is_ipaddr_configured
2837
 * INPUTS
2838
 *   IP Address to check.
2839
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2840
 *   check_localip - if true then also check for matches with PPTP and LT2P addresses
2841
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2842
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2843
 *     If check_subnets is true and cidrprefix is specified,
2844
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2845
 * RESULT
2846
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2847
*/
2848
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2849
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2850
		return true;
2851
	}
2852
	return false;
2853
}
2854

    
2855
/****f* pfsense-utils/where_is_ipaddr_configured
2856
 * NAME
2857
 *   where_is_ipaddr_configured
2858
 * INPUTS
2859
 *   IP Address to check.
2860
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2861
 *   check_localip - if true then also check for matches with PPTP and LT2P addresses
2862
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2863
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2864
 *     If check_subnets is true and cidrprefix is specified,
2865
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2866
 * RESULT
2867
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2868
 *   If there are no matches then an empty array is returned.
2869
*/
2870
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2871
	global $config;
2872

    
2873
	$where_configured = array();
2874

    
2875
	$pos = strpos($ignore_if, '_virtualip');
2876
	if ($pos !== false) {
2877
		$ignore_vip_id = substr($ignore_if, $pos+10);
2878
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2879
	} else {
2880
		$ignore_vip_id = -1;
2881
		$ignore_vip_if = $ignore_if;
2882
	}
2883

    
2884
	$isipv6 = is_ipaddrv6($ipaddr);
2885

    
2886
	if ($check_subnets) {
2887
		$cidrprefix = intval($cidrprefix);
2888
		if ($isipv6) {
2889
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2890
				$cidrprefix = 128;
2891
			}
2892
		} else {
2893
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2894
				$cidrprefix = 32;
2895
			}
2896
		}
2897
		$iflist = get_configured_interface_list();
2898
		foreach ($iflist as $if => $ifname) {
2899
			if ($ignore_if == $if) {
2900
				continue;
2901
			}
2902

    
2903
			if ($isipv6) {
2904
				$if_ipv6 = get_interface_ipv6($if);
2905
				$if_snbitsv6 = get_interface_subnetv6($if);
2906
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2907
					$where_entry = array();
2908
					$where_entry['if'] = $if;
2909
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2910
					$where_configured[] = $where_entry;
2911
				}
2912
			} else {
2913
				$if_ipv4 = get_interface_ip($if);
2914
				$if_snbitsv4 = get_interface_subnet($if);
2915
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2916
					$where_entry = array();
2917
					$where_entry['if'] = $if;
2918
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2919
					$where_configured[] = $where_entry;
2920
				}
2921
			}
2922
		}
2923
	} else {
2924
		if ($isipv6) {
2925
			$interface_list_ips = get_configured_ipv6_addresses();
2926
		} else {
2927
			$interface_list_ips = get_configured_ip_addresses();
2928
		}
2929

    
2930
		foreach ($interface_list_ips as $if => $ilips) {
2931
			if ($ignore_if == $if) {
2932
				continue;
2933
			}
2934
			if (strcasecmp($ipaddr, $ilips) == 0) {
2935
				$where_entry = array();
2936
				$where_entry['if'] = $if;
2937
				$where_entry['ip_or_subnet'] = $ilips;
2938
				$where_configured[] = $where_entry;
2939
			}
2940
		}
2941
	}
2942

    
2943
	if ($check_localip) {
2944
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, $config['l2tp']['localip']) == 0)) {
2945
			$where_entry = array();
2946
			$where_entry['if'] = 'l2tp';
2947
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2948
			$where_configured[] = $where_entry;
2949
		}
2950
	}
2951

    
2952
	return $where_configured;
2953
}
2954

    
2955
/****f* pfsense-utils/pfSense_handle_custom_code
2956
 * NAME
2957
 *   pfSense_handle_custom_code
2958
 * INPUTS
2959
 *   directory name to process
2960
 * RESULT
2961
 *   globs the directory and includes the files
2962
 */
2963
function pfSense_handle_custom_code($src_dir) {
2964
	// Allow extending of the nat edit page and include custom input validation
2965
	if (is_dir("$src_dir")) {
2966
		$cf = glob($src_dir . "/*.inc");
2967
		foreach ($cf as $nf) {
2968
			if ($nf == "." || $nf == "..") {
2969
				continue;
2970
			}
2971
			// Include the extra handler
2972
			include_once("$nf");
2973
		}
2974
	}
2975
}
2976

    
2977
function set_language() {
2978
	global $config, $g;
2979

    
2980
	if (!empty($config['system']['language'])) {
2981
		$lang = $config['system']['language'];
2982
	} elseif (!empty($g['language'])) {
2983
		$lang = $g['language'];
2984
	}
2985
	$lang .= ".UTF-8";
2986

    
2987
	putenv("LANG={$lang}");
2988
	setlocale(LC_ALL, $lang);
2989
	textdomain("pfSense");
2990
	bindtextdomain("pfSense", "/usr/local/share/locale");
2991
	bind_textdomain_codeset("pfSense", $lang);
2992
}
2993

    
2994
function get_locale_list() {
2995
	$locales = array(
2996
		"en_US" => gettext("English"),
2997
		"pt_BR" => gettext("Portuguese (Brazil)"),
2998
		"tr" => gettext("Turkish"),
2999
	);
3000
	asort($locales);
3001
	return $locales;
3002
}
3003

    
3004
function return_hex_ipv4($ipv4) {
3005
	if (!is_ipaddrv4($ipv4)) {
3006
		return(false);
3007
	}
3008

    
3009
	/* we need the hex form of the interface IPv4 address */
3010
	$ip4arr = explode(".", $ipv4);
3011
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3012
}
3013

    
3014
function convert_ipv6_to_128bit($ipv6) {
3015
	if (!is_ipaddrv6($ipv6)) {
3016
		return(false);
3017
	}
3018

    
3019
	$ip6arr = array();
3020
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3021
	$ip6arr = explode(":", $ip6prefix);
3022
	/* binary presentation of the prefix for all 128 bits. */
3023
	$ip6prefixbin = "";
3024
	foreach ($ip6arr as $element) {
3025
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3026
	}
3027
	return($ip6prefixbin);
3028
}
3029

    
3030
function convert_128bit_to_ipv6($ip6bin) {
3031
	if (strlen($ip6bin) <> 128) {
3032
		return(false);
3033
	}
3034

    
3035
	$ip6arr = array();
3036
	$ip6binarr = array();
3037
	$ip6binarr = str_split($ip6bin, 16);
3038
	foreach ($ip6binarr as $binpart) {
3039
		$ip6arr[] = dechex(bindec($binpart));
3040
	}
3041
	$ip6addr = Net_IPv6::compress(implode(":", $ip6arr));
3042

    
3043
	return($ip6addr);
3044
}
3045

    
3046

    
3047
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3048
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3049
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3050
/* 6to4 is 16 bits, e.g. 65535 */
3051
function calculate_ipv6_delegation_length($if) {
3052
	global $config;
3053

    
3054
	if (!is_array($config['interfaces'][$if])) {
3055
		return false;
3056
	}
3057

    
3058
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3059
		case "6to4":
3060
			$pdlen = 16;
3061
			break;
3062
		case "6rd":
3063
			$rd6cfg = $config['interfaces'][$if];
3064
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3065
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
3066
			break;
3067
		case "dhcp6":
3068
			$dhcp6cfg = $config['interfaces'][$if];
3069
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3070
			break;
3071
		default:
3072
			$pdlen = 0;
3073
			break;
3074
	}
3075
	return($pdlen);
3076
}
3077

    
3078
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3079
	$prefix = Net_IPv6::uncompress($prefix, true);
3080
	$suffix = Net_IPv6::uncompress($suffix, true);
3081

    
3082
	/*
3083
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3084
	 *                ^^^^ ^
3085
	 *                |||| \-> 64
3086
	 *                |||\---> 63, 62, 61, 60
3087
	 *                ||\----> 56
3088
	 *                |\-----> 52
3089
	 *                \------> 48
3090
	 */
3091

    
3092
	switch ($len) {
3093
	case 48:
3094
		$prefix_len = 15;
3095
		break;
3096
	case 52:
3097
		$prefix_len = 16;
3098
		break;
3099
	case 56:
3100
		$prefix_len = 17;
3101
		break;
3102
	case 60:
3103
		$prefix_len = 18;
3104
		break;
3105
	/*
3106
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3107
	 * we let user chose this bit it can end up out of PD network
3108
	 *
3109
	 * Leave this with 20 for now until we find a way to let user
3110
	 * chose it. The side-effect is users with PD with one of these
3111
	 * lengths will not be able to setup DHCP server range for full
3112
	 * PD size, only for last /64 network
3113
	 */
3114
	case 63:
3115
	case 62:
3116
	case 61:
3117
	default:
3118
		$prefix_len = 20;
3119
		break;
3120
	}
3121

    
3122
	return Net_IPv6::compress(substr($prefix, 0, $prefix_len) .
3123
	    substr($suffix, $prefix_len));
3124
}
3125

    
3126
function dhcpv6_pd_str_help($pdlen) {
3127
	$result = '';
3128

    
3129
	switch ($pdlen) {
3130
	case 48:
3131
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3132
		break;
3133
	case 52:
3134
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3135
		break;
3136
	case 56:
3137
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3138
		break;
3139
	case 60:
3140
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3141
		break;
3142
	/*
3143
	 * XXX 63, 62 and 61 should use same mask of 60 but it would
3144
	 * we let user chose this bit it can end up out of PD network
3145
	 *
3146
	 * Leave this with the same of 64 for now until we find a way to
3147
	 * let user chose it. The side-effect is users with PD with one
3148
	 * of these lengths will not be able to setup DHCP server range
3149
	 * for full PD size, only for last /64 network
3150
	 */
3151
	case 61:
3152
	case 62:
3153
	case 63:
3154
	case 64:
3155
		$result = '::xxxx:xxxx:xxxx:xxxx';
3156
		break;
3157
	}
3158

    
3159
	return $result;
3160
}
3161

    
3162
function huawei_rssi_to_string($rssi) {
3163
	$dbm = array();
3164
	$i = 0;
3165
	$dbstart = -113;
3166
	while ($i < 32) {
3167
		$dbm[$i] = $dbstart + ($i * 2);
3168
		$i++;
3169
	}
3170
	$percent = round(($rssi / 31) * 100);
3171
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3172
	return $string;
3173
}
3174

    
3175
function huawei_mode_to_string($mode, $submode) {
3176
	$modes[0] = gettext("None");
3177
	$modes[1] = "AMPS";
3178
	$modes[2] = "CDMA";
3179
	$modes[3] = "GSM/GPRS";
3180
	$modes[4] = "HDR";
3181
	$modes[5] = "WCDMA";
3182
	$modes[6] = "GPS";
3183

    
3184
	$submodes[0] = gettext("No Service");
3185
	$submodes[1] = "GSM";
3186
	$submodes[2] = "GPRS";
3187
	$submodes[3] = "EDGE";
3188
	$submodes[4] = "WCDMA";
3189
	$submodes[5] = "HSDPA";
3190
	$submodes[6] = "HSUPA";
3191
	$submodes[7] = "HSDPA+HSUPA";
3192
	$submodes[8] = "TD-SCDMA";
3193
	$submodes[9] = "HSPA+";
3194
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3195
	return $string;
3196
}
3197

    
3198
function huawei_service_to_string($state) {
3199
	$modes[0] = gettext("No Service");
3200
	$modes[1] = gettext("Restricted Service");
3201
	$modes[2] = gettext("Valid Service");
3202
	$modes[3] = gettext("Restricted Regional Service");
3203
	$modes[4] = gettext("Powersaving Service");
3204
	$string = $modes[$state];
3205
	return $string;
3206
}
3207

    
3208
function huawei_simstate_to_string($state) {
3209
	$modes[0] = gettext("Invalid SIM/locked State");
3210
	$modes[1] = gettext("Valid SIM State");
3211
	$modes[2] = gettext("Invalid SIM CS State");
3212
	$modes[3] = gettext("Invalid SIM PS State");
3213
	$modes[4] = gettext("Invalid SIM CS/PS State");
3214
	$modes[255] = gettext("Missing SIM State");
3215
	$string = $modes[$state];
3216
	return $string;
3217
}
3218

    
3219
function zte_rssi_to_string($rssi) {
3220
	return huawei_rssi_to_string($rssi);
3221
}
3222

    
3223
function zte_mode_to_string($mode, $submode) {
3224
	$modes[0] = gettext("No Service");
3225
	$modes[1] = gettext("Limited Service");
3226
	$modes[2] = "GPRS";
3227
	$modes[3] = "GSM";
3228
	$modes[4] = "UMTS";
3229
	$modes[5] = "EDGE";
3230
	$modes[6] = "HSDPA";
3231

    
3232
	$submodes[0] = "CS_ONLY";
3233
	$submodes[1] = "PS_ONLY";
3234
	$submodes[2] = "CS_PS";
3235
	$submodes[3] = "CAMPED";
3236
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3237
	return $string;
3238
}
3239

    
3240
function zte_service_to_string($service) {
3241
	$modes[0] = gettext("Initializing Service");
3242
	$modes[1] = gettext("Network Lock error Service");
3243
	$modes[2] = gettext("Network Locked Service");
3244
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3245
	$string = $modes[$service];
3246
	return $string;
3247
}
3248

    
3249
function zte_simstate_to_string($state) {
3250
	$modes[0] = gettext("No action State");
3251
	$modes[1] = gettext("Network lock State");
3252
	$modes[2] = gettext("(U)SIM card lock State");
3253
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3254
	$string = $modes[$state];
3255
	return $string;
3256
}
3257

    
3258
function get_configured_pppoe_server_interfaces() {
3259
	global $config;
3260
	$iflist = array();
3261
	if (is_array($config['pppoes']['pppoe'])) {
3262
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3263
			if ($pppoe['mode'] == "server") {
3264
				$int = "poes". $pppoe['pppoeid'];
3265
				$iflist[$int] = strtoupper($int);
3266
			}
3267
		}
3268
	}
3269
	return $iflist;
3270
}
3271

    
3272
function get_pppoes_child_interfaces($ifpattern) {
3273
	$if_arr = array();
3274
	if ($ifpattern == "") {
3275
		return;
3276
	}
3277

    
3278
	exec("/sbin/ifconfig", $out, $ret);
3279
	foreach ($out as $line) {
3280
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3281
			$if_arr[] = $match[1];
3282
		}
3283
	}
3284
	return $if_arr;
3285

    
3286
}
3287

    
3288
/****f* pfsense-utils/pkg_call_plugins
3289
 * NAME
3290
 *   pkg_call_plugins
3291
 * INPUTS
3292
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3293
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3294
 * RESULT
3295
 *   returns associative array results from the plugin calls for each package
3296
 * NOTES
3297
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3298
 ******/
3299
function pkg_call_plugins($plugin_type, $plugin_params) {
3300
	global $g, $config;
3301
	$results = array();
3302
	if (!is_array($config['installedpackages']['package'])) {
3303
		return $results;
3304
	}
3305
	foreach ($config['installedpackages']['package'] as $package) {
3306
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
3307
			continue;
3308
		}
3309
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
3310
		$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3311
		if (is_array($pkg_config['plugins']['item'])) {
3312
			foreach ($pkg_config['plugins']['item'] as $plugin) {
3313
				if ($plugin['type'] == $plugin_type) {
3314
					if (file_exists($pkg_config['include_file'])) {
3315
						require_once($pkg_config['include_file']);
3316
					} else {
3317
						continue;
3318
					}
3319
					$plugin_function = $pkgname . '_'. $plugin_type;
3320
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3321
				}
3322
			}
3323
		}
3324
	}
3325
	return $results;
3326
}
3327

    
3328
function restore_aliastables() {
3329
	global $g, $config;
3330

    
3331
	$dbpath = "{$g['vardb_path']}/aliastables/";
3332

    
3333
	/* restore the alias tables, if we have them */
3334
	$files = glob("{$g['cf_conf_path']}/RAM_Disk_Store{$dbpath}*.tgz");
3335
	if (count($files)) {
3336
		echo "Restoring alias tables...";
3337
		foreach ($files as $file) {
3338
			if (file_exists($file)) {
3339
				$aliastablesrestore = "";
3340
				$aliastablesreturn = "";
3341
				exec("cd /;LANG=C /usr/bin/tar -xzf {$file} 2>&1", $aliastablesrestore, $aliastablesreturn);
3342
				$aliastablesrestore = implode(" ", $aliastablesrestore);
3343
				if ($aliastablesreturn <> 0) {
3344
					log_error(sprintf(gettext('Alias table restore failed exited with %1$s, the error is: %2$s %3$s%4$s'), $aliastablesreturn, $aliastablesrestore, $file, "\n"));
3345
				} else {
3346
					log_error(sprintf(gettext('Alias table restore succeeded exited with %1$s, the result is: %2$s %3$s%4$s'), $aliastablesreturn, $aliastablesrestore, $dbpath.basename($file, ".tgz"), "\n"));
3347
				}
3348
			}
3349
			/* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */
3350
			if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
3351
				unlink_if_exists("{$file}");
3352
			}
3353
		}
3354
		echo "done.\n";
3355
		return true;
3356
	}
3357
	return false;
3358
}
3359

    
3360
?>
(39-39/65)