Project

General

Profile

Download (95 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 Rubicon Communications, LLC (Netgate)
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
/****f* pfsense-utils/gen_requirestatefilter_field
402
 * NAME
403
 *   gen_requirestatefilter_field
404
 * INPUTS
405
 *   Pointer to section object
406
 *   Initial value for the field
407
 * RESULT
408
 *   no return value, section object is updated
409
 ******/
410
function gen_requirestatefilter_field(&$section, $value) {
411
	$section->addInput(new Form_Checkbox(
412
		'requirestatefilter',
413
		'Require State Filter',
414
		'Do not display state table without a filter',
415
		$value
416
	))->setHelp('By default, the entire state table is displayed when entering '.
417
		'Diagnostics > States. This option requires a filter to be entered '.
418
		'before the states are displayed. Useful for systems with large state tables.');
419
}
420

    
421
function hardware_offloading_applyflags($iface) {
422
	global $config;
423

    
424
	$flags_on = 0;
425
	$flags_off = 0;
426
	$options = pfSense_get_interface_addresses($iface);
427

    
428
	if (isset($config['system']['disablechecksumoffloading'])) {
429
		if (isset($options['encaps']['txcsum'])) {
430
			$flags_off |= IFCAP_TXCSUM;
431
		}
432
		if (isset($options['encaps']['rxcsum'])) {
433
			$flags_off |= IFCAP_RXCSUM;
434
		}
435
		if (isset($options['encaps']['txcsum6'])) {
436
			$flags_off |= IFCAP_TXCSUM_IPV6;
437
		}
438
		if (isset($options['encaps']['rxcsum6'])) {
439
			$flags_off |= IFCAP_RXCSUM_IPV6;
440
		}
441
	} else {
442
		if (isset($options['caps']['txcsum'])) {
443
			$flags_on |= IFCAP_TXCSUM;
444
		}
445
		if (isset($options['caps']['rxcsum'])) {
446
			$flags_on |= IFCAP_RXCSUM;
447
		}
448
		if (isset($options['caps']['txcsum6'])) {
449
			$flags_on |= IFCAP_TXCSUM_IPV6;
450
		}
451
		if (isset($options['caps']['rxcsum6'])) {
452
			$flags_on |= IFCAP_RXCSUM_IPV6;
453
		}
454
	}
455

    
456
	if (isset($config['system']['disablesegmentationoffloading'])) {
457
		$flags_off |= IFCAP_TSO;
458
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
459
		$flags_on |= IFCAP_TSO;
460
	}
461

    
462
	if (isset($config['system']['disablelargereceiveoffloading'])) {
463
		$flags_off |= IFCAP_LRO;
464
	} else if (isset($options['caps']['lro'])) {
465
		$flags_on |= IFCAP_LRO;
466
	}
467

    
468
	/* if the NIC supports polling *AND* it is enabled in the GUI */
469
	if (!isset($config['system']['polling'])) {
470
		$flags_off |= IFCAP_POLLING;
471
	} else if (isset($options['caps']['polling'])) {
472
		$flags_on |= IFCAP_POLLING;
473
	}
474

    
475
	pfSense_interface_capabilities($iface, -$flags_off);
476
	pfSense_interface_capabilities($iface, $flags_on);
477
}
478

    
479
/****f* pfsense-utils/enable_hardware_offloading
480
 * NAME
481
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
482
 * INPUTS
483
 *   $interface	- string containing the physical interface to work on.
484
 * RESULT
485
 *   null
486
 * NOTES
487
 *   This function only supports the fxp driver's loadable microcode.
488
 ******/
489
function enable_hardware_offloading($interface) {
490
	global $g, $config;
491

    
492
	$int = get_real_interface($interface);
493
	if (empty($int)) {
494
		return;
495
	}
496

    
497
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
498
		/* translate wan, lan, opt -> real interface if needed */
499
		$int_family = preg_split("/[0-9]+/", $int);
500
		$supported_ints = array('fxp');
501
		if (in_array($int_family, $supported_ints)) {
502
			if (does_interface_exist($int)) {
503
				pfSense_interface_flags($int, IFF_LINK0);
504
			}
505
		}
506
	}
507

    
508
	/* This is mostly for vlans and ppp types */
509
	$realhwif = get_parent_interface($interface);
510
	if ($realhwif[0] == $int) {
511
		hardware_offloading_applyflags($int);
512
	} else {
513
		hardware_offloading_applyflags($realhwif[0]);
514
		hardware_offloading_applyflags($int);
515
	}
516
}
517

    
518
/****f* pfsense-utils/interface_supports_polling
519
 * NAME
520
 *   checks to see if an interface supports polling according to man polling
521
 * INPUTS
522
 *
523
 * RESULT
524
 *   true or false
525
 * NOTES
526
 *
527
 ******/
528
function interface_supports_polling($iface) {
529
	$opts = pfSense_get_interface_addresses($iface);
530
	if (is_array($opts) && isset($opts['caps']['polling'])) {
531
		return true;
532
	}
533

    
534
	return false;
535
}
536

    
537
/****f* pfsense-utils/is_alias_inuse
538
 * NAME
539
 *   checks to see if an alias is currently in use by a rule
540
 * INPUTS
541
 *
542
 * RESULT
543
 *   true or false
544
 * NOTES
545
 *
546
 ******/
547
function is_alias_inuse($alias) {
548
	global $g, $config;
549

    
550
	if ($alias == "") {
551
		return false;
552
	}
553
	/* loop through firewall rules looking for alias in use */
554
	if (is_array($config['filter']['rule'])) {
555
		foreach ($config['filter']['rule'] as $rule) {
556
			if ($rule['source']['address']) {
557
				if ($rule['source']['address'] == $alias) {
558
					return true;
559
				}
560
			}
561
			if ($rule['destination']['address']) {
562
				if ($rule['destination']['address'] == $alias) {
563
					return true;
564
				}
565
			}
566
		}
567
	}
568
	/* loop through nat rules looking for alias in use */
569
	if (is_array($config['nat']['rule'])) {
570
		foreach ($config['nat']['rule'] as $rule) {
571
			if ($rule['target'] && $rule['target'] == $alias) {
572
				return true;
573
			}
574
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
575
				return true;
576
			}
577
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
578
				return true;
579
			}
580
		}
581
	}
582
	return false;
583
}
584

    
585
/****f* pfsense-utils/is_schedule_inuse
586
 * NAME
587
 *   checks to see if a schedule is currently in use by a rule
588
 * INPUTS
589
 *
590
 * RESULT
591
 *   true or false
592
 * NOTES
593
 *
594
 ******/
595
function is_schedule_inuse($schedule) {
596
	global $g, $config;
597

    
598
	if ($schedule == "") {
599
		return false;
600
	}
601
	/* loop through firewall rules looking for schedule in use */
602
	if (is_array($config['filter']['rule'])) {
603
		foreach ($config['filter']['rule'] as $rule) {
604
			if ($rule['sched'] == $schedule) {
605
				return true;
606
			}
607
		}
608
	}
609
	return false;
610
}
611

    
612
/****f* pfsense-utils/setup_polling
613
 * NAME
614
 *   sets up polling
615
 * INPUTS
616
 *
617
 * RESULT
618
 *   null
619
 * NOTES
620
 *
621
 ******/
622
function setup_polling() {
623
	global $g, $config;
624

    
625
	if (isset($config['system']['polling'])) {
626
		set_single_sysctl("kern.polling.idle_poll", "1");
627
	} else {
628
		set_single_sysctl("kern.polling.idle_poll", "0");
629
	}
630

    
631
	if ($config['system']['polling_each_burst']) {
632
		set_single_sysctl("kern.polling.each_burst", $config['system']['polling_each_burst']);
633
	}
634
	if ($config['system']['polling_burst_max']) {
635
		set_single_sysctl("kern.polling.burst_max", $config['system']['polling_burst_max']);
636
	}
637
	if ($config['system']['polling_user_frac']) {
638
		set_single_sysctl("kern.polling.user_frac", $config['system']['polling_user_frac']);
639
	}
640
}
641

    
642
/****f* pfsense-utils/setup_microcode
643
 * NAME
644
 *   enumerates all interfaces and calls enable_hardware_offloading which
645
 *   enables a NIC's supported hardware features.
646
 * INPUTS
647
 *
648
 * RESULT
649
 *   null
650
 * NOTES
651
 *   This function only supports the fxp driver's loadable microcode.
652
 ******/
653
function setup_microcode() {
654

    
655
	/* if list */
656
	$iflist = get_configured_interface_list(false, true);
657
	foreach ($iflist as $if => $ifdescr) {
658
		enable_hardware_offloading($if);
659
	}
660
	unset($iflist);
661
}
662

    
663
/****f* pfsense-utils/get_carp_status
664
 * NAME
665
 *   get_carp_status - Return whether CARP is enabled or disabled.
666
 * RESULT
667
 *   boolean	- true if CARP is enabled, false if otherwise.
668
 ******/
669
function get_carp_status() {
670
	/* grab the current status of carp */
671
	$status = get_single_sysctl('net.inet.carp.allow');
672
	return (intval($status) > 0);
673
}
674

    
675
/*
676
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
677

    
678
 */
679
function convert_ip_to_network_format($ip, $subnet) {
680
	$ipsplit = explode('.', $ip);
681
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
682
	return $string;
683
}
684

    
685
/*
686
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
687
 */
688
function get_carp_interface_status($carpid) {
689

    
690
	$carpiface = get_configured_vip_interface($carpid);
691
	if ($carpiface == NULL)
692
		return "";
693
	$interface = get_real_interface($carpiface);
694
	if ($interface == NULL)
695
		return "";
696
	$vip = get_configured_vip($carpid);
697
	if ($vip == NULL || !isset($vip['vhid']))
698
		return "";
699

    
700
	$vhid = $vip['vhid'];
701
	$carp_query = '';
702
	$_gb = exec("/sbin/ifconfig $interface | /usr/bin/grep carp: | /usr/bin/grep \"vhid $vhid\"", $carp_query);
703
	foreach ($carp_query as $int) {
704
		if (stripos($int, "MASTER"))
705
			return "MASTER";
706
		elseif (stripos($int, "BACKUP"))
707
			return "BACKUP";
708
		elseif (stripos($int, "INIT"))
709
			return "INIT";
710
	}
711

    
712
	return "";
713
}
714

    
715
/*
716
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
717
 */
718
function get_pfsync_interface_status($pfsyncinterface) {
719
	if (!does_interface_exist($pfsyncinterface)) {
720
		return;
721
	}
722

    
723
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
724
}
725

    
726
/*
727
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
728
 */
729
function add_rule_to_anchor($anchor, $rule, $label) {
730
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
731
}
732

    
733
/*
734
 * remove_text_from_file
735
 * remove $text from file $file
736
 */
737
function remove_text_from_file($file, $text) {
738
	if (!file_exists($file) && !is_writable($file)) {
739
		return;
740
	}
741
	$filecontents = file_get_contents($file);
742
	$text = str_replace($text, "", $filecontents);
743
	@file_put_contents($file, $text);
744
}
745

    
746
/*
747
 *   after_sync_bump_adv_skew(): create skew values by 1S
748
 */
749
function after_sync_bump_adv_skew() {
750
	global $config, $g;
751
	$processed_skew = 1;
752
	$a_vip = &$config['virtualip']['vip'];
753
	foreach ($a_vip as $vipent) {
754
		if ($vipent['advskew'] <> "") {
755
			$processed_skew = 1;
756
			$vipent['advskew'] = $vipent['advskew']+1;
757
		}
758
	}
759
	if ($processed_skew == 1) {
760
		write_config(gettext("After synch increase advertising skew"));
761
	}
762
}
763

    
764
/*
765
 * get_filename_from_url($url): converts a url to its filename.
766
 */
767
function get_filename_from_url($url) {
768
	return basename($url);
769
}
770

    
771
/*
772
 *   get_dir: return an array of $dir
773
 */
774
function get_dir($dir) {
775
	$dir_array = array();
776
	$d = dir($dir);
777
	if (!is_object($d)) {
778
		return array();
779
	}
780
	while (false !== ($entry = $d->read())) {
781
		array_push($dir_array, $entry);
782
	}
783
	$d->close();
784
	return $dir_array;
785
}
786

    
787
/****f* pfsense-utils/WakeOnLan
788
 * NAME
789
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
790
 * RESULT
791
 *   true/false - true if the operation was successful
792
 ******/
793
function WakeOnLan($addr, $mac) {
794
	$addr_byte = explode(':', $mac);
795
	$hw_addr = '';
796

    
797
	for ($a = 0; $a < 6; $a++) {
798
		$hw_addr .= chr(hexdec($addr_byte[$a]));
799
	}
800

    
801
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
802

    
803
	for ($a = 1; $a <= 16; $a++) {
804
		$msg .= $hw_addr;
805
	}
806

    
807
	// send it to the broadcast address using UDP
808
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
809
	if ($s == false) {
810
		log_error(gettext("Error creating socket!"));
811
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
812
	} else {
813
		// setting a broadcast option to socket:
814
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
815
		if ($opt_ret < 0) {
816
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
817
		}
818
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
819
		socket_close($s);
820
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
821
		return true;
822
	}
823

    
824
	return false;
825
}
826

    
827
/*
828
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
829
 *					 Useful for finding paths and stripping file extensions.
830
 */
831
function reverse_strrchr($haystack, $needle) {
832
	if (!is_string($haystack)) {
833
		return;
834
	}
835
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
836
}
837

    
838
/*
839
 *  backup_config_section($section): returns as an xml file string of
840
 *                                   the configuration section
841
 */
842
function backup_config_section($section_name) {
843
	global $config;
844
	$new_section = &$config[$section_name];
845
	/* generate configuration XML */
846
	$xmlconfig = dump_xml_config($new_section, $section_name);
847
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
848
	return $xmlconfig;
849
}
850

    
851
/*
852
 *  restore_config_section($section_name, new_contents): restore a configuration section,
853
 *                                                  and write the configuration out
854
 *                                                  to disk/cf.
855
 */
856
function restore_config_section($section_name, $new_contents) {
857
	global $config, $g;
858
	conf_mount_rw();
859
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
860
	fwrite($fout, $new_contents);
861
	fclose($fout);
862

    
863
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
864
	if ($xml['pfsense']) {
865
		$xml = $xml['pfsense'];
866
	}
867
	else if ($xml['m0n0wall']) {
868
		$xml = $xml['m0n0wall'];
869
	}
870
	if ($xml[$section_name]) {
871
		$section_xml = $xml[$section_name];
872
	} else {
873
		$section_xml = -1;
874
	}
875

    
876
	@unlink($g['tmp_path'] . "/tmpxml");
877
	if ($section_xml === -1) {
878
		return false;
879
	}
880
	$config[$section_name] = &$section_xml;
881
	if (file_exists("{$g['tmp_path']}/config.cache")) {
882
		unlink("{$g['tmp_path']}/config.cache");
883
	}
884
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
885
	disable_security_checks();
886
	conf_mount_ro();
887
	return true;
888
}
889

    
890
/*
891
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
892
 *                                                  and write the configuration out
893
 *                                                  to disk/cf.  But preserve the prior
894
 * 													structure if needed
895
 */
896
function merge_config_section($section_name, $new_contents) {
897
	global $config;
898
	conf_mount_rw();
899
	$fname = get_tmp_filename();
900
	$fout = fopen($fname, "w");
901
	fwrite($fout, $new_contents);
902
	fclose($fout);
903
	$section_xml = parse_xml_config($fname, $section_name);
904
	$config[$section_name] = $section_xml;
905
	unlink($fname);
906
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
907
	disable_security_checks();
908
	conf_mount_ro();
909
	return;
910
}
911

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

    
943
/*
944
 * host_firmware_version(): Return the versions used in this install
945
 */
946
function host_firmware_version($tocheck = "") {
947
	global $g, $config;
948

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

    
951
	return array(
952
		"firmware" => array("version" => $g['product_version']),
953
		"kernel"   => array("version" => $os_version),
954
		"base"     => array("version" => $os_version),
955
		"platform" => trim(file_get_contents('/etc/platform', " \n")),
956
		"config_version" => $config['version']
957
	);
958
}
959

    
960
function get_disk_info() {
961
	$diskout = "";
962
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
963
	return explode(' ', $diskout[0]);
964
}
965

    
966
/****f* pfsense-utils/strncpy
967
 * NAME
968
 *   strncpy - copy strings
969
 * INPUTS
970
 *   &$dst, $src, $length
971
 * RESULT
972
 *   none
973
 ******/
974
function strncpy(&$dst, $src, $length) {
975
	if (strlen($src) > $length) {
976
		$dst = substr($src, 0, $length);
977
	} else {
978
		$dst = $src;
979
	}
980
}
981

    
982
/****f* pfsense-utils/reload_interfaces_sync
983
 * NAME
984
 *   reload_interfaces - reload all interfaces
985
 * INPUTS
986
 *   none
987
 * RESULT
988
 *   none
989
 ******/
990
function reload_interfaces_sync() {
991
	global $config, $g;
992

    
993
	if ($g['debug']) {
994
		log_error(gettext("reload_interfaces_sync() is starting."));
995
	}
996

    
997
	/* parse config.xml again */
998
	$config = parse_config(true);
999

    
1000
	/* enable routing */
1001
	system_routing_enable();
1002
	if ($g['debug']) {
1003
		log_error(gettext("Enabling system routing"));
1004
	}
1005

    
1006
	if ($g['debug']) {
1007
		log_error(gettext("Cleaning up Interfaces"));
1008
	}
1009

    
1010
	/* set up interfaces */
1011
	interfaces_configure();
1012
}
1013

    
1014
/****f* pfsense-utils/reload_all
1015
 * NAME
1016
 *   reload_all - triggers a reload of all settings
1017
 *   * INPUTS
1018
 *   none
1019
 * RESULT
1020
 *   none
1021
 ******/
1022
function reload_all() {
1023
	send_event("service reload all");
1024
}
1025

    
1026
/****f* pfsense-utils/reload_interfaces
1027
 * NAME
1028
 *   reload_interfaces - triggers a reload of all interfaces
1029
 * INPUTS
1030
 *   none
1031
 * RESULT
1032
 *   none
1033
 ******/
1034
function reload_interfaces() {
1035
	send_event("interface all reload");
1036
}
1037

    
1038
/****f* pfsense-utils/reload_all_sync
1039
 * NAME
1040
 *   reload_all - reload all settings
1041
 *   * INPUTS
1042
 *   none
1043
 * RESULT
1044
 *   none
1045
 ******/
1046
function reload_all_sync() {
1047
	global $config, $g;
1048

    
1049
	/* parse config.xml again */
1050
	$config = parse_config(true);
1051

    
1052
	/* set up our timezone */
1053
	system_timezone_configure();
1054

    
1055
	/* set up our hostname */
1056
	system_hostname_configure();
1057

    
1058
	/* make hosts file */
1059
	system_hosts_generate();
1060

    
1061
	/* generate resolv.conf */
1062
	system_resolvconf_generate();
1063

    
1064
	/* enable routing */
1065
	system_routing_enable();
1066

    
1067
	/* set up interfaces */
1068
	interfaces_configure();
1069

    
1070
	/* start dyndns service */
1071
	services_dyndns_configure();
1072

    
1073
	/* configure cron service */
1074
	configure_cron();
1075

    
1076
	/* start the NTP client */
1077
	system_ntp_configure();
1078

    
1079
	/* sync pw database */
1080
	conf_mount_rw();
1081
	unlink_if_exists("/etc/spwd.db.tmp");
1082
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1083
	conf_mount_ro();
1084

    
1085
	/* restart sshd */
1086
	send_event("service restart sshd");
1087

    
1088
	/* restart webConfigurator if needed */
1089
	send_event("service restart webgui");
1090
}
1091

    
1092
function setup_serial_port($when = "save", $path = "") {
1093
	global $g, $config;
1094
	conf_mount_rw();
1095
	$ttys_file = "{$path}/etc/ttys";
1096
	$boot_config_file = "{$path}/boot.config";
1097
	$loader_conf_file = "{$path}/boot/loader.conf";
1098
	/* serial console - write out /boot.config */
1099
	if (file_exists($boot_config_file)) {
1100
		$boot_config = file_get_contents($boot_config_file);
1101
	} else {
1102
		$boot_config = "";
1103
	}
1104

    
1105
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1106
	if ($g['platform'] != "cdrom") {
1107
		$serial_only = false;
1108

    
1109
		if (($g['platform'] == "nanobsd") && isset($g['enableserial_force'])) {
1110
			$serial_only = true;
1111
		} else {
1112
			$specific_platform = system_identify_specific_platform();
1113
			if ($specific_platform['name'] == 'RCC-VE' ||
1114
			    $specific_platform['name'] == 'RCC' ||
1115
			    $specific_platform['name'] == 'RCC-DFF' ||
1116
			    $specific_platform['name'] == 'apu2') {
1117
				$serial_only = true;
1118
			}
1119
		}
1120

    
1121
		$boot_config_split = explode("\n", $boot_config);
1122
		$data = array();
1123
		foreach ($boot_config_split as $bcs) {
1124
			/* Ignore -D and -h lines now */
1125
			if (!empty($bcs) && !stristr($bcs, "-D") &&
1126
			    !stristr($bcs, "-h")) {
1127
				$data[] = $bcs;
1128
			}
1129
		}
1130
		if ($serial_only === true) {
1131
			$data[] = "-S{$serialspeed} -h";
1132
		} elseif (is_serial_enabled()) {
1133
			$data[] = "-S{$serialspeed} -D";
1134
		}
1135

    
1136
		if (empty($data)) {
1137
			@unlink($boot_conf_file);
1138
		} else {
1139
			safe_write_file($boot_config_file, $data);
1140
		}
1141

    
1142
		unset($boot_config, $boot_config_file, $boot_config_split);
1143

    
1144
		/* serial console - write out /boot/loader.conf */
1145
		if ($when == "upgrade") {
1146
			system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1147
		}
1148

    
1149
		$loader_conf = file_get_contents($loader_conf_file);
1150
		$loader_conf_split = explode("\n", $loader_conf);
1151

    
1152
		$data = array();
1153
		// Loop through and only add lines that are not empty, and which
1154
		//  do not contain a console directive.
1155
		foreach ($loader_conf_split as $bcs) {
1156
			if (!empty($bcs) &&
1157
			    (stripos($bcs, "console") === false) &&
1158
			    (stripos($bcs, "boot_multicons") === false) &&
1159
			    (stripos($bcs, "boot_serial") === false) &&
1160
			    (stripos($bcs, "hw.usb.no_pf") === false) &&
1161
			    (stripos($bcs, "hint.uart.0.flags") === false) &&
1162
			    (stripos($bcs, "hint.uart.1.flags") === false)) {
1163
				$data[] = $bcs;
1164
			}
1165
		}
1166

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

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

    
1197
		safe_write_file($loader_conf_file, $data);
1198

    
1199
		unset($loader_conf, $loader_conf_split, $loader_config_file);
1200
	}
1201

    
1202
	$ttys = file_get_contents($ttys_file);
1203
	$ttys_split = explode("\n", $ttys);
1204

    
1205
	$data = array();
1206

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

    
1209
	if (isset($config['system']['disableconsolemenu'])) {
1210
		$console_type = 'Pc';
1211
		$serial_type = 'std.' . $serialspeed;
1212
	} else {
1213
		$console_type = 'al.Pc';
1214
		$serial_type = 'al.' . $serialspeed;
1215
	}
1216

    
1217
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1218
	$ttyv0_line =
1219
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\tcons25\ton\tsecure";
1220
	$ttyu_line =
1221
	    "\"/usr/libexec/getty {$serial_type}\"\tcons25\t{$on_off}\tsecure";
1222

    
1223
	$found = array();
1224

    
1225
	foreach ($ttys_split as $tty) {
1226
		/* Ignore blank lines */
1227
		if (empty($tty)) {
1228
			continue;
1229
		}
1230

    
1231
		if (stristr($tty, "ttyv0")) {
1232
			$found['ttyv0'] = 1;
1233
			$data[] = $ttyv0_line;
1234
		} elseif (stristr($tty, "ttyu")) {
1235
			$ttyn = substr($tty, 0, 5);
1236
			$found[$ttyn] = 1;
1237
			$data[] = "{$ttyn}\t{$ttyu_line}";
1238
		} elseif (substr($tty, 0, 7) == 'console') {
1239
			$found['console'] = 1;
1240
			$data[] = $tty;
1241
		} else {
1242
			$data[] = $tty;
1243
		}
1244
	}
1245
	unset($on_off, $console_type, $serial_type);
1246

    
1247
	/* Detect missing main lines on original file and try to rebuild it */
1248
	$items = array(
1249
		'console',
1250
		'ttyv0',
1251
		'ttyu0',
1252
		'ttyu1',
1253
		'ttyu2',
1254
		'ttyu3'
1255
	);
1256

    
1257
	foreach ($items as $item) {
1258
		if (isset($found[$item])) {
1259
			continue;
1260
		}
1261

    
1262
		if ($item == 'console') {
1263
			$data[] = $console_line;
1264
		} elseif ($item == 'ttyv0') {
1265
			$data[] = $ttyv0_line;
1266
		} else {
1267
			$data[] = "{$item}\t{$ttyu_line}";
1268
		}
1269
	}
1270

    
1271
	safe_write_file($ttys_file, $data);
1272

    
1273
	unset($ttys, $ttys_file, $ttys_split, $data);
1274

    
1275
	if ($when != "upgrade") {
1276
		reload_ttys();
1277
	}
1278

    
1279
	conf_mount_ro();
1280
	return;
1281
}
1282

    
1283
function is_serial_enabled() {
1284
	global $g, $config;
1285

    
1286
	if (!isset($g['enableserial_force']) &&
1287
	    !isset($config['system']['enableserial']) &&
1288
	    ($g['platform'] == $g['product_name'] || $g['platform'] == "cdrom")) {
1289
		return false;
1290
	}
1291

    
1292
	return true;
1293
}
1294

    
1295
function reload_ttys() {
1296
	// Send a HUP signal to init will make it reload /etc/ttys
1297
	posix_kill(1, SIGHUP);
1298
}
1299

    
1300
function print_value_list($list, $count = 10, $separator = ",") {
1301
	$list = implode($separator, array_slice($list, 0, $count));
1302
	if (count($list) < $count) {
1303
		$list .= ".";
1304
	} else {
1305
		$list .= "...";
1306
	}
1307
	return $list;
1308
}
1309

    
1310
/* DHCP enabled on any interfaces? */
1311
function is_dhcp_server_enabled() {
1312
	global $config;
1313

    
1314
	if (!is_array($config['dhcpd'])) {
1315
		return false;
1316
	}
1317

    
1318
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1319
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1320
			return true;
1321
		}
1322
	}
1323

    
1324
	return false;
1325
}
1326

    
1327
/* DHCP enabled on any interfaces? */
1328
function is_dhcpv6_server_enabled() {
1329
	global $config;
1330

    
1331
	if (is_array($config['interfaces'])) {
1332
		foreach ($config['interfaces'] as $ifcfg) {
1333
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1334
				return true;
1335
			}
1336
		}
1337
	}
1338

    
1339
	if (!is_array($config['dhcpdv6'])) {
1340
		return false;
1341
	}
1342

    
1343
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1344
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1345
			return true;
1346
		}
1347
	}
1348

    
1349
	return false;
1350
}
1351

    
1352
/* radvd enabled on any interfaces? */
1353
function is_radvd_enabled() {
1354
	global $config;
1355

    
1356
	if (!is_array($config['dhcpdv6'])) {
1357
		$config['dhcpdv6'] = array();
1358
	}
1359

    
1360
	$dhcpdv6cfg = $config['dhcpdv6'];
1361
	$Iflist = get_configured_interface_list();
1362

    
1363
	/* handle manually configured DHCP6 server settings first */
1364
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1365
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1366
			continue;
1367
		}
1368

    
1369
		if (!isset($dhcpv6ifconf['ramode'])) {
1370
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1371
		}
1372

    
1373
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1374
			continue;
1375
		}
1376

    
1377
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1378
		if (!is_ipaddrv6($ifcfgipv6)) {
1379
			continue;
1380
		}
1381

    
1382
		return true;
1383
	}
1384

    
1385
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1386
	foreach ($Iflist as $if => $ifdescr) {
1387
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1388
			continue;
1389
		}
1390
		if (!isset($config['interfaces'][$if]['enable'])) {
1391
			continue;
1392
		}
1393

    
1394
		$ifcfgipv6 = get_interface_ipv6($if);
1395
		if (!is_ipaddrv6($ifcfgipv6)) {
1396
			continue;
1397
		}
1398

    
1399
		$ifcfgsnv6 = get_interface_subnetv6($if);
1400
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1401

    
1402
		if (!is_ipaddrv6($subnetv6)) {
1403
			continue;
1404
		}
1405

    
1406
		return true;
1407
	}
1408

    
1409
	return false;
1410
}
1411

    
1412
/* Any PPPoE servers enabled? */
1413
function is_pppoe_server_enabled() {
1414
	global $config;
1415

    
1416
	$pppoeenable = false;
1417

    
1418
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1419
		return false;
1420
	}
1421

    
1422
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1423
		if ($pppoes['mode'] == 'server') {
1424
			$pppoeenable = true;
1425
		}
1426
	}
1427

    
1428
	return $pppoeenable;
1429
}
1430

    
1431
/* Optional arg forces hh:mm:ss without days */
1432
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1433
	if (!is_numericint($sec)) {
1434
		return '-';
1435
	}
1436
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1437
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1438
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1439
					(int)(($sec % 3600)/60),
1440
					$sec % 60
1441
				);
1442
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1443
}
1444

    
1445
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1446

    
1447
function get_ppp_uptime($port) {
1448
	if (file_exists("/conf/{$port}.log")) {
1449
		$saved_time = file_get_contents("/conf/{$port}.log");
1450
		$uptime_data = explode("\n", $saved_time);
1451
		$sec = 0;
1452
		foreach ($uptime_data as $upt) {
1453
			$sec += substr($upt, 1 + strpos($upt, " "));
1454
		}
1455
		return convert_seconds_to_dhms($sec);
1456
	} else {
1457
		$total_time = gettext("No history data found!");
1458
		return $total_time;
1459
	}
1460
}
1461

    
1462
//returns interface information
1463
function get_interface_info($ifdescr) {
1464
	global $config, $g;
1465

    
1466
	$ifinfo = array();
1467
	if (empty($config['interfaces'][$ifdescr])) {
1468
		return;
1469
	}
1470
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1471
	$ifinfo['if'] = get_real_interface($ifdescr);
1472

    
1473
	$chkif = $ifinfo['if'];
1474
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1475
	$ifinfo['status'] = $ifinfotmp['status'];
1476
	if (empty($ifinfo['status'])) {
1477
		$ifinfo['status'] = "down";
1478
	}
1479
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1480
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1481
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1482
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1483
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1484
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1485
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1486
	if (isset($ifinfotmp['link0'])) {
1487
		$link0 = "down";
1488
	}
1489
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1490
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1491
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1492
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1493
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1494
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1495

    
1496
	/* Use pfctl for non wrapping 64 bit counters */
1497
	/* Pass */
1498
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1499
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1500
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1501
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1502
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1503
	$in4_pass = $pf_in4_pass[5];
1504
	$out4_pass = $pf_out4_pass[5];
1505
	$in4_pass_packets = $pf_in4_pass[3];
1506
	$out4_pass_packets = $pf_out4_pass[3];
1507
	$in6_pass = $pf_in6_pass[5];
1508
	$out6_pass = $pf_out6_pass[5];
1509
	$in6_pass_packets = $pf_in6_pass[3];
1510
	$out6_pass_packets = $pf_out6_pass[3];
1511
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1512
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1513
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1514
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1515

    
1516
	/* Block */
1517
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1518
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1519
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1520
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1521
	$in4_block = $pf_in4_block[5];
1522
	$out4_block = $pf_out4_block[5];
1523
	$in4_block_packets = $pf_in4_block[3];
1524
	$out4_block_packets = $pf_out4_block[3];
1525
	$in6_block = $pf_in6_block[5];
1526
	$out6_block = $pf_out6_block[5];
1527
	$in6_block_packets = $pf_in6_block[3];
1528
	$out6_block_packets = $pf_out6_block[3];
1529
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1530
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1531
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1532
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1533

    
1534
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1535
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1536
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1537
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1538

    
1539
	$ifconfiginfo = "";
1540
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1541
	switch ($link_type) {
1542
		/* DHCP? -> see if dhclient is up */
1543
		case "dhcp":
1544
			/* see if dhclient is up */
1545
			if (find_dhclient_process($ifinfo['if']) != 0) {
1546
				$ifinfo['dhcplink'] = "up";
1547
			} else {
1548
				$ifinfo['dhcplink'] = "down";
1549
			}
1550

    
1551
			break;
1552
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1553
		case "pppoe":
1554
		case "pptp":
1555
		case "l2tp":
1556
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1557
				/* get PPPoE link status for dial on demand */
1558
				$ifinfo["{$link_type}link"] = "up";
1559
			} else {
1560
				$ifinfo["{$link_type}link"] = "down";
1561
			}
1562

    
1563
			break;
1564
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1565
		case "ppp":
1566
			if ($ifinfo['status'] == "up") {
1567
				$ifinfo['ppplink'] = "up";
1568
			} else {
1569
				$ifinfo['ppplink'] = "down" ;
1570
			}
1571

    
1572
			if (empty($ifinfo['status'])) {
1573
				$ifinfo['status'] = "down";
1574
			}
1575

    
1576
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1577
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1578
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1579
						break;
1580
					}
1581
				}
1582
			}
1583
			$dev = $ppp['ports'];
1584
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1585
				break;
1586
			}
1587
			if (!file_exists($dev)) {
1588
				$ifinfo['nodevice'] = 1;
1589
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1590
			}
1591

    
1592
			$usbmodemoutput = array();
1593
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1594
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1595
			if (file_exists($mondev)) {
1596
				$cellstats = file($mondev);
1597
				/* skip header */
1598
				$a_cellstats = explode(",", $cellstats[1]);
1599
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1600
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1601
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1602
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1603
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1604
				}
1605
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1606
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1607
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1608
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1609
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1610
				}
1611
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1612
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1613
				$ifinfo['cell_sent'] = $a_cellstats[6];
1614
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1615
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1616
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1617
			}
1618
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1619
			if (isset($ppp['uptime'])) {
1620
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1621
			}
1622
			break;
1623
		default:
1624
			break;
1625
	}
1626

    
1627
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1628
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1629
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1630
	}
1631

    
1632
	if ($ifinfo['status'] == "up") {
1633
		/* try to determine media with ifconfig */
1634
		unset($ifconfiginfo);
1635
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1636
		$wifconfiginfo = array();
1637
		if (is_interface_wireless($ifdescr)) {
1638
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1639
			array_shift($wifconfiginfo);
1640
		}
1641
		$matches = "";
1642
		foreach ($ifconfiginfo as $ici) {
1643

    
1644
			/* don't list media/speed for wireless cards, as it always
1645
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1646
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1647
				$ifinfo['media'] = $matches[1];
1648
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1649
				$ifinfo['media'] = $matches[1];
1650
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1651
				$ifinfo['media'] = $matches[1];
1652
			}
1653

    
1654
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1655
				if ($matches[1] != "active") {
1656
					$ifinfo['status'] = $matches[1];
1657
				}
1658
				if ($ifinfo['status'] == gettext("running")) {
1659
					$ifinfo['status'] = gettext("up");
1660
				}
1661
			}
1662
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1663
				$ifinfo['channel'] = $matches[1];
1664
			}
1665
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1666
				if ($matches[1][0] == '"') {
1667
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1668
				}
1669
				else {
1670
					$ifinfo['ssid'] = $matches[1];
1671
				}
1672
			}
1673
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1674
				$ifinfo['laggproto'] = $matches[1];
1675
			}
1676
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1677
				$ifinfo['laggport'][] = $matches[1];
1678
			}
1679
		}
1680
		foreach ($wifconfiginfo as $ici) {
1681
			$elements = preg_split("/[ ]+/i", $ici);
1682
			if ($elements[0] != "") {
1683
				$ifinfo['bssid'] = $elements[0];
1684
			}
1685
			if ($elements[3] != "") {
1686
				$ifinfo['rate'] = $elements[3];
1687
			}
1688
			if ($elements[4] != "") {
1689
				$ifinfo['rssi'] = $elements[4];
1690
			}
1691
		}
1692
		/* lookup the gateway */
1693
		if (interface_has_gateway($ifdescr)) {
1694
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1695
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1696
		}
1697
	}
1698

    
1699
	$bridge = "";
1700
	$bridge = link_interface_to_bridge($ifdescr);
1701
	if ($bridge) {
1702
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1703
		if (stristr($bridge_text, "blocking") <> false) {
1704
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1705
			$ifinfo['bridgeint'] = $bridge;
1706
		} else if (stristr($bridge_text, "learning") <> false) {
1707
			$ifinfo['bridge'] = gettext("learning");
1708
			$ifinfo['bridgeint'] = $bridge;
1709
		} else if (stristr($bridge_text, "forwarding") <> false) {
1710
			$ifinfo['bridge'] = gettext("forwarding");
1711
			$ifinfo['bridgeint'] = $bridge;
1712
		}
1713
	}
1714

    
1715
	return $ifinfo;
1716
}
1717

    
1718
//returns cpu speed of processor. Good for determining capabilities of machine
1719
function get_cpu_speed() {
1720
	return get_single_sysctl("hw.clockrate");
1721
}
1722

    
1723
function get_uptime_sec() {
1724
	$boottime = "";
1725
	$matches = "";
1726
	$boottime = get_single_sysctl("kern.boottime");
1727
	preg_match("/sec = (\d+)/", $boottime, $matches);
1728
	$boottime = $matches[1];
1729
	if (intval($boottime) == 0) {
1730
		return 0;
1731
	}
1732

    
1733
	$uptime = time() - $boottime;
1734
	return $uptime;
1735
}
1736

    
1737
function add_hostname_to_watch($hostname) {
1738
	if (!is_dir("/var/db/dnscache")) {
1739
		mkdir("/var/db/dnscache");
1740
	}
1741
	$result = array();
1742
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1743
		$domrecords = array();
1744
		$domips = array();
1745
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1746
		if ($rethost == 0) {
1747
			foreach ($domrecords as $domr) {
1748
				$doml = explode(" ", $domr);
1749
				$domip = $doml[3];
1750
				/* fill array with domain ip addresses */
1751
				if (is_ipaddr($domip)) {
1752
					$domips[] = $domip;
1753
				}
1754
			}
1755
		}
1756
		sort($domips);
1757
		$contents = "";
1758
		if (!empty($domips)) {
1759
			foreach ($domips as $ip) {
1760
				$contents .= "$ip\n";
1761
			}
1762
		}
1763
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1764
		/* Remove empty elements */
1765
		$result = array_filter(explode("\n", $contents), 'strlen');
1766
	}
1767
	return $result;
1768
}
1769

    
1770
function is_fqdn($fqdn) {
1771
	$hostname = false;
1772
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1773
		$hostname = true;
1774
	}
1775
	if (preg_match("/\.\./", $fqdn)) {
1776
		$hostname = false;
1777
	}
1778
	if (preg_match("/^\./i", $fqdn)) {
1779
		$hostname = false;
1780
	}
1781
	if (preg_match("/\//i", $fqdn)) {
1782
		$hostname = false;
1783
	}
1784
	return($hostname);
1785
}
1786

    
1787
function pfsense_default_state_size() {
1788
	/* get system memory amount */
1789
	$memory = get_memory();
1790
	$physmem = $memory[0];
1791
	/* Be cautious and only allocate 10% of system memory to the state table */
1792
	$max_states = (int) ($physmem/10)*1000;
1793
	return $max_states;
1794
}
1795

    
1796
function pfsense_default_tables_size() {
1797
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1798
	return $current;
1799
}
1800

    
1801
function pfsense_default_table_entries_size() {
1802
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1803
	return (trim($current));
1804
}
1805

    
1806
/* Compare the current hostname DNS to the DNS cache we made
1807
 * if it has changed we return the old records
1808
 * if no change we return false */
1809
function compare_hostname_to_dnscache($hostname) {
1810
	if (!is_dir("/var/db/dnscache")) {
1811
		mkdir("/var/db/dnscache");
1812
	}
1813
	$hostname = trim($hostname);
1814
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1815
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1816
	} else {
1817
		$oldcontents = "";
1818
	}
1819
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1820
		$domrecords = array();
1821
		$domips = array();
1822
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1823
		if ($rethost == 0) {
1824
			foreach ($domrecords as $domr) {
1825
				$doml = explode(" ", $domr);
1826
				$domip = $doml[3];
1827
				/* fill array with domain ip addresses */
1828
				if (is_ipaddr($domip)) {
1829
					$domips[] = $domip;
1830
				}
1831
			}
1832
		}
1833
		sort($domips);
1834
		$contents = "";
1835
		if (!empty($domips)) {
1836
			foreach ($domips as $ip) {
1837
				$contents .= "$ip\n";
1838
			}
1839
		}
1840
	}
1841

    
1842
	if (trim($oldcontents) != trim($contents)) {
1843
		if ($g['debug']) {
1844
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1845
		}
1846
		return ($oldcontents);
1847
	} else {
1848
		return false;
1849
	}
1850
}
1851

    
1852
/*
1853
 * load_crypto() - Load crypto modules if enabled in config.
1854
 */
1855
function load_crypto() {
1856
	global $config, $g;
1857
	$crypto_modules = array('glxsb', 'aesni');
1858

    
1859
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1860
		return false;
1861
	}
1862

    
1863
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1864
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1865
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1866
	}
1867
}
1868

    
1869
/*
1870
 * load_thermal_hardware() - Load temperature monitor kernel module
1871
 */
1872
function load_thermal_hardware() {
1873
	global $config, $g;
1874
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1875

    
1876
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1877
		return false;
1878
	}
1879

    
1880
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1881
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1882
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1883
	}
1884
}
1885

    
1886
/****f* pfsense-utils/isvm
1887
 * NAME
1888
 *   isvm
1889
 * INPUTS
1890
 *	none
1891
 * RESULT
1892
 *   returns true if machine is running under a virtual environment
1893
 ******/
1894
function isvm() {
1895
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1896
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
1897

    
1898
	if ($rc != 0 || !isset($output[0])) {
1899
		return false;
1900
	}
1901

    
1902
	foreach ($virtualenvs as $virtualenv) {
1903
		if (stripos($output[0], $virtualenv) !== false) {
1904
			return true;
1905
		}
1906
	}
1907

    
1908
	return false;
1909
}
1910

    
1911
function get_freebsd_version() {
1912
	$version = explode(".", php_uname("r"));
1913
	return $version[0];
1914
}
1915

    
1916
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1917
	global $config, $g;
1918

    
1919
	$fp = fopen($destination, "wb");
1920

    
1921
	if (!$fp) {
1922
		return false;
1923
	}
1924

    
1925
	$ch = curl_init();
1926
	curl_setopt($ch, CURLOPT_URL, $url);
1927
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1928
	curl_setopt($ch, CURLOPT_FILE, $fp);
1929
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1930
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1931
	curl_setopt($ch, CURLOPT_HEADER, false);
1932
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1933
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1934
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1935
	} else {
1936
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1937
	}
1938

    
1939
	if (!empty($config['system']['proxyurl'])) {
1940
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1941
		if (!empty($config['system']['proxyport'])) {
1942
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1943
		}
1944
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1945
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1946
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1947
		}
1948
	}
1949

    
1950
	@curl_exec($ch);
1951
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1952
	fclose($fp);
1953
	curl_close($ch);
1954
	if ($http_code == 200) {
1955
		return true;
1956
	} else {
1957
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1958
		unlink_if_exists($destination);
1959
		return false;
1960
	}
1961
}
1962

    
1963
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1964
	global $config, $g;
1965
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1966
	$file_size = 1;
1967
	$downloaded = 1;
1968
	$first_progress_update = TRUE;
1969
	/* open destination file */
1970
	$fout = fopen($destination, "wb");
1971

    
1972
	if (!$fout) {
1973
		return false;
1974
	}
1975
	/*
1976
	 *      Originally by Author: Keyvan Minoukadeh
1977
	 *      Modified by Scott Ullrich to return Content-Length size
1978
	 */
1979
	$ch = curl_init();
1980
	curl_setopt($ch, CURLOPT_URL, $url);
1981
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1982
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
1983
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1984
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
1985
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1986
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1987
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1988
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1989
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1990
	} else {
1991
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1992
	}
1993

    
1994
	if (!empty($config['system']['proxyurl'])) {
1995
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1996
		if (!empty($config['system']['proxyport'])) {
1997
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1998
		}
1999
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2000
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2001
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2002
		}
2003
	}
2004

    
2005
	@curl_exec($ch);
2006
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2007
	fclose($fout);
2008
	curl_close($ch);
2009
	if ($http_code == 200) {
2010
		return true;
2011
	} else {
2012
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2013
		unlink_if_exists($destination);
2014
		return false;
2015
	}
2016
}
2017

    
2018
function read_header($ch, $string) {
2019
	global $file_size, $fout;
2020
	$length = strlen($string);
2021
	$regs = "";
2022
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2023
	if ($regs[2] <> "") {
2024
		$file_size = intval($regs[2]);
2025
	}
2026
	ob_flush();
2027
	return $length;
2028
}
2029

    
2030
function read_body($ch, $string) {
2031
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2032
	global $pkg_interface;
2033
	$length = strlen($string);
2034
	$downloaded += intval($length);
2035
	if ($file_size > 0) {
2036
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2037
		$downloadProgress = 100 - $downloadProgress;
2038
	} else {
2039
		$downloadProgress = 0;
2040
	}
2041
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2042
		if ($sendto == "status") {
2043
			if ($pkg_interface == "console") {
2044
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2045
					$tostatus = $static_status . $downloadProgress . "%";
2046
					if ($downloadProgress == 100) {
2047
						$tostatus = $tostatus . "\r";
2048
					}
2049
					update_status($tostatus);
2050
				}
2051
			} else {
2052
				$tostatus = $static_status . $downloadProgress . "%";
2053
				update_status($tostatus);
2054
			}
2055
		} else {
2056
			if ($pkg_interface == "console") {
2057
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2058
					$tooutput = $static_output . $downloadProgress . "%";
2059
					if ($downloadProgress == 100) {
2060
						$tooutput = $tooutput . "\r";
2061
					}
2062
					update_output_window($tooutput);
2063
				}
2064
			} else {
2065
				$tooutput = $static_output . $downloadProgress . "%";
2066
				update_output_window($tooutput);
2067
			}
2068
		}
2069
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2070
			update_progress_bar($downloadProgress, $first_progress_update);
2071
			$first_progress_update = FALSE;
2072
		}
2073
		$lastseen = $downloadProgress;
2074
	}
2075
	if ($fout) {
2076
		fwrite($fout, $string);
2077
	}
2078
	ob_flush();
2079
	return $length;
2080
}
2081

    
2082
/*
2083
 *   update_output_window: update bottom textarea dynamically.
2084
 */
2085
function update_output_window($text) {
2086
	global $pkg_interface;
2087
	$log = preg_replace("/\n/", "\\n", $text);
2088
	if ($pkg_interface != "console") {
2089
?>
2090
<script type="text/javascript">
2091
//<![CDATA[
2092
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2093
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2094
//]]>
2095
</script>
2096
<?php
2097
	}
2098
	/* ensure that contents are written out */
2099
	ob_flush();
2100
}
2101

    
2102
/*
2103
 *   update_status: update top textarea dynamically.
2104
 */
2105
function update_status($status) {
2106
	global $pkg_interface;
2107

    
2108
	if ($pkg_interface == "console") {
2109
		print ("{$status}");
2110
	}
2111

    
2112
	/* ensure that contents are written out */
2113
	ob_flush();
2114
}
2115

    
2116
/*
2117
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2118
 */
2119
function update_progress_bar($percent, $first_time) {
2120
	global $pkg_interface;
2121
	if ($percent > 100) {
2122
		$percent = 1;
2123
	}
2124
	if ($pkg_interface <> "console") {
2125
		echo '<script type="text/javascript">';
2126
		echo "\n//<![CDATA[\n";
2127
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2128
		echo "\n//]]>\n";
2129
		echo '</script>';
2130
	} else {
2131
		if (!($first_time)) {
2132
			echo "\x08\x08\x08\x08\x08";
2133
		}
2134
		echo sprintf("%4d%%", $percent);
2135
	}
2136
}
2137

    
2138
/* 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. */
2139
if (!function_exists("split")) {
2140
	function split($separator, $haystack, $limit = null) {
2141
		log_error("deprecated split() call with separator '{$separator}'");
2142
		return preg_split($separator, $haystack, $limit);
2143
	}
2144
}
2145

    
2146
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2147
	global $g, $config, $pconfig, $debug;
2148
	if (!$origname) {
2149
		return;
2150
	}
2151

    
2152
	$sectionref = &$config;
2153
	foreach ($section as $sectionname) {
2154
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2155
			$sectionref = &$sectionref[$sectionname];
2156
		} else {
2157
			return;
2158
		}
2159
	}
2160

    
2161
	if ($debug) {
2162
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2163
		fwrite($fd, print_r($pconfig, true));
2164
	}
2165

    
2166
	if (is_array($sectionref)) {
2167
		foreach ($sectionref as $itemkey => $item) {
2168
			if ($debug) {
2169
				fwrite($fd, "$itemkey\n");
2170
			}
2171

    
2172
			$fieldfound = true;
2173
			$fieldref = &$sectionref[$itemkey];
2174
			foreach ($field as $fieldname) {
2175
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2176
					$fieldref = &$fieldref[$fieldname];
2177
				} else {
2178
					$fieldfound = false;
2179
					break;
2180
				}
2181
			}
2182
			if ($fieldfound && $fieldref == $origname) {
2183
				if ($debug) {
2184
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2185
				}
2186
				$fieldref = $new_alias_name;
2187
			}
2188
		}
2189
	}
2190

    
2191
	if ($debug) {
2192
		fclose($fd);
2193
	}
2194

    
2195
}
2196

    
2197
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2198
	/*
2199
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2200
	 * $type = if set to 'url' then subnets and ips will be returned,
2201
	 *         if set to 'url_ports' port-ranges and ports will be returned
2202
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2203
	 *
2204
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2205
	 */
2206

    
2207
	if (!file_exists($filename)) {
2208
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2209
		return null;
2210
	}
2211

    
2212
	if (filesize($filename) == 0) {
2213
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2214
		return null;
2215
	}
2216
	$fd = @fopen($filename, 'r');
2217
	if (!$fd) {
2218
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2219
		return null;
2220
	}
2221
	$items = array();
2222
	$comments = array();
2223
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2224
	while (($fc = fgetss($fd)) !== FALSE) {
2225
		$tmp = trim($fc, " \t\n\r");
2226
		if (empty($tmp)) {
2227
			continue;
2228
		}
2229
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2230
			$comments[] = $tmp;
2231
		} else {
2232
			$tmp_str = strstr($tmp, '#', true);
2233
			if (!empty($tmp_str)) {
2234
				$tmp = $tmp_str;
2235
			}
2236
			$tmp_str = strstr($tmp, ' ', true);
2237
			if (!empty($tmp_str)) {
2238
				$tmp = $tmp_str;
2239
			}
2240
			$valid = (($type == "url" || $type == "urltable") && (is_ipaddr($tmp) || is_subnet($tmp))) ||
2241
				(($type == "url_ports" || $type == "urltable_ports") && (is_port($tmp) || is_portrange($tmp)));
2242
			if ($valid) {
2243
				$items[] = $tmp;
2244
				if (count($items) == $max_items) {
2245
					break;
2246
				}
2247
			}
2248
		}
2249
	}
2250
	fclose($fd);
2251
	return array_merge($comments, $items);
2252
}
2253

    
2254
function update_alias_url_data() {
2255
	global $config, $g;
2256

    
2257
	$updated = false;
2258

    
2259
	/* item is a url type */
2260
	$lockkey = lock('aliasurl');
2261
	if (is_array($config['aliases']['alias'])) {
2262
		foreach ($config['aliases']['alias'] as $x => $alias) {
2263
			if (empty($alias['aliasurl'])) {
2264
				continue;
2265
			}
2266

    
2267
			$address = null;
2268
			foreach ($alias['aliasurl'] as $alias_url) {
2269
				/* fetch down and add in */
2270
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2271
				unlink($temp_filename);
2272
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2273
				mkdir($temp_filename);
2274
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2275
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2276
					continue;
2277
				}
2278

    
2279
				/* if the item is tar gzipped then extract */
2280
				if (stripos($alias_url, '.tgz')) {
2281
					if (!process_alias_tgz($temp_filename)) {
2282
						continue;
2283
					}
2284
				}
2285
				if (file_exists("{$temp_filename}/aliases")) {
2286
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2287
					mwexec("/bin/rm -rf {$temp_filename}");
2288
				}
2289
			}
2290
			if ($address != null) {
2291
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2292
				$updated = true;
2293
			}
2294
		}
2295
	}
2296
	unlock($lockkey);
2297

    
2298
	/* Report status to callers as well */
2299
	return $updated;
2300
}
2301

    
2302
function process_alias_tgz($temp_filename) {
2303
	if (!file_exists('/usr/bin/tar')) {
2304
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2305
		return false;
2306
	}
2307
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2308
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2309
	unlink("{$temp_filename}/aliases.tgz");
2310
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2311
	/* foreach through all extracted files and build up aliases file */
2312
	$fd = @fopen("{$temp_filename}/aliases", "w");
2313
	if (!$fd) {
2314
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2315
		return false;
2316
	}
2317
	foreach ($files_to_process as $f2p) {
2318
		$tmpfd = @fopen($f2p, 'r');
2319
		if (!$tmpfd) {
2320
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2321
			continue;
2322
		}
2323
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2324
			fwrite($fd, $tmpbuf);
2325
		}
2326
		fclose($tmpfd);
2327
		unlink($f2p);
2328
	}
2329
	fclose($fd);
2330
	unset($tmpbuf);
2331

    
2332
	return true;
2333
}
2334

    
2335
function version_compare_dates($a, $b) {
2336
	$a_time = strtotime($a);
2337
	$b_time = strtotime($b);
2338

    
2339
	if ((!$a_time) || (!$b_time)) {
2340
		return FALSE;
2341
	} else {
2342
		if ($a_time < $b_time) {
2343
			return -1;
2344
		} elseif ($a_time == $b_time) {
2345
			return 0;
2346
		} else {
2347
			return 1;
2348
		}
2349
	}
2350
}
2351
function version_get_string_value($a) {
2352
	$strs = array(
2353
		0 => "ALPHA-ALPHA",
2354
		2 => "ALPHA",
2355
		3 => "BETA",
2356
		4 => "B",
2357
		5 => "C",
2358
		6 => "D",
2359
		7 => "RC",
2360
		8 => "RELEASE",
2361
		9 => "*"			// Matches all release levels
2362
	);
2363
	$major = 0;
2364
	$minor = 0;
2365
	foreach ($strs as $num => $str) {
2366
		if (substr($a, 0, strlen($str)) == $str) {
2367
			$major = $num;
2368
			$n = substr($a, strlen($str));
2369
			if (is_numeric($n)) {
2370
				$minor = $n;
2371
			}
2372
			break;
2373
		}
2374
	}
2375
	return "{$major}.{$minor}";
2376
}
2377
function version_compare_string($a, $b) {
2378
	// Only compare string parts if both versions give a specific release
2379
	// (If either version lacks a string part, assume intended to match all release levels)
2380
	if (isset($a) && isset($b)) {
2381
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2382
	} else {
2383
		return 0;
2384
	}
2385
}
2386
function version_compare_numeric($a, $b) {
2387
	$a_arr = explode('.', rtrim($a, '.'));
2388
	$b_arr = explode('.', rtrim($b, '.'));
2389

    
2390
	foreach ($a_arr as $n => $val) {
2391
		if (array_key_exists($n, $b_arr)) {
2392
			// So far so good, both have values at this minor version level. Compare.
2393
			if ($val > $b_arr[$n]) {
2394
				return 1;
2395
			} elseif ($val < $b_arr[$n]) {
2396
				return -1;
2397
			}
2398
		} else {
2399
			// a is greater, since b doesn't have any minor version here.
2400
			return 1;
2401
		}
2402
	}
2403
	if (count($b_arr) > count($a_arr)) {
2404
		// b is longer than a, so it must be greater.
2405
		return -1;
2406
	} else {
2407
		// Both a and b are of equal length and value.
2408
		return 0;
2409
	}
2410
}
2411
function pfs_version_compare($cur_time, $cur_text, $remote) {
2412
	// First try date compare
2413
	$v = version_compare_dates($cur_time, $remote);
2414
	if ($v === FALSE) {
2415
		// If that fails, try to compare by string
2416
		// Before anything else, simply test if the strings are equal
2417
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2418
			return 0;
2419
		}
2420
		list($cur_num, $cur_str) = explode('-', $cur_text);
2421
		list($rem_num, $rem_str) = explode('-', $remote);
2422

    
2423
		// First try to compare the numeric parts of the version string.
2424
		$v = version_compare_numeric($cur_num, $rem_num);
2425

    
2426
		// If the numeric parts are the same, compare the string parts.
2427
		if ($v == 0) {
2428
			return version_compare_string($cur_str, $rem_str);
2429
		}
2430
	}
2431
	return $v;
2432
}
2433
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2434
	global $g, $config;
2435

    
2436
	$urltable_prefix = "/var/db/aliastables/";
2437
	$urltable_filename = $urltable_prefix . $name . ".txt";
2438
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2439

    
2440
	// Make the aliases directory if it doesn't exist
2441
	if (!file_exists($urltable_prefix)) {
2442
		mkdir($urltable_prefix);
2443
	} elseif (!is_dir($urltable_prefix)) {
2444
		unlink($urltable_prefix);
2445
		mkdir($urltable_prefix);
2446
	}
2447

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

    
2453
		// Try to fetch the URL supplied
2454
		conf_mount_rw();
2455
		unlink_if_exists($tmp_urltable_filename);
2456
		$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2457
		if (download_file($url, $tmp_urltable_filename, $verify_ssl)) {
2458
			// Convert lines that begin with '$' or ';' to comments '#' instead of deleting them.
2459
			mwexec("/usr/bin/sed -i \"\" -E 's/^[[:space:]]*($|#|;)/#/g; /^#/!s/\;.*//g;' ". escapeshellarg($tmp_urltable_filename));
2460

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

    
2463
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2464
			if ($type == "urltable_ports") {
2465
				$parsed_contents = group_ports($parsed_contents, true);
2466
			}
2467
			if (is_array($parsed_contents)) {
2468
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2469
			} else {
2470
				touch($urltable_filename);
2471
			}
2472

    
2473
			/* 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. */
2474
			if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
2475
				unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz");
2476
			} else {
2477
				/* Update the RAM disk store with the new/updated table file. */
2478
				mwexec("cd / && /usr/bin/tar -czf \"{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz\" -C / \"{$urltable_filename}\"");
2479
			}
2480
			unlink_if_exists($tmp_urltable_filename);
2481
		} else {
2482
			if (!$validateonly) {
2483
				touch($urltable_filename);
2484
			}
2485
			conf_mount_ro();
2486
			return false;
2487
		}
2488
		conf_mount_ro();
2489
		return true;
2490
	} else {
2491
		// File exists, and it doesn't need to be updated.
2492
		return -1;
2493
	}
2494
}
2495
function get_real_slice_from_glabel($label) {
2496
	$label = escapeshellarg($label);
2497
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/{$label} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`);
2498
}
2499
function nanobsd_get_boot_slice() {
2500
	return trim(`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`);
2501
}
2502
function nanobsd_get_boot_drive() {
2503
	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`);
2504
}
2505
function nanobsd_get_active_slice() {
2506
	$boot_drive = nanobsd_get_boot_drive();
2507
	$active = trim(`gpart show $boot_drive | grep '\[active\]' | awk '{print $3;}'`);
2508

    
2509
	return "{$boot_drive}s{$active}";
2510
}
2511
function nanobsd_get_size() {
2512
	return strtoupper(file_get_contents("/etc/nanosize.txt"));
2513
}
2514
function nanobsd_switch_boot_slice() {
2515
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2516
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2517
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2518
	nanobsd_detect_slice_info();
2519

    
2520
	if ($BOOTFLASH == $ACTIVE_SLICE) {
2521
		$slice = $TOFLASH;
2522
	} else {
2523
		$slice = $BOOTFLASH;
2524
	}
2525

    
2526
	for ($i = 0; $i < ob_get_level(); $i++) {
2527
		ob_end_flush();
2528
	}
2529
	ob_implicit_flush(1);
2530
	if (strstr($slice, "s2")) {
2531
		$ASLICE = "2";
2532
		$AOLDSLICE = "1";
2533
		$AGLABEL_SLICE = "pfsense1";
2534
		$AUFS_ID = "1";
2535
		$AOLD_UFS_ID = "0";
2536
	} else {
2537
		$ASLICE = "1";
2538
		$AOLDSLICE = "2";
2539
		$AGLABEL_SLICE = "pfsense0";
2540
		$AUFS_ID = "0";
2541
		$AOLD_UFS_ID = "1";
2542
	}
2543
	$ATOFLASH = "{$BOOT_DRIVE}s{$ASLICE}";
2544
	$ACOMPLETE_PATH = "{$BOOT_DRIVE}s{$ASLICE}a";
2545
	$ABOOTFLASH = "{$BOOT_DRIVE}s{$AOLDSLICE}";
2546
	conf_mount_rw();
2547
	set_single_sysctl("kern.geom.debugflags", "16");
2548
	exec("/sbin/gpart set -a active -i {$ASLICE} {$BOOT_DRIVE}");
2549
	exec("/usr/sbin/boot0cfg -s {$ASLICE} -v /dev/{$BOOT_DRIVE}");
2550
	// We can't update these if they are mounted now.
2551
	if ($BOOTFLASH != $slice) {
2552
		exec("/sbin/tunefs -L ${AGLABEL_SLICE} /dev/$ACOMPLETE_PATH");
2553
		nanobsd_update_fstab($AGLABEL_SLICE, $ACOMPLETE_PATH, $AOLD_UFS_ID, $AUFS_ID);
2554
	}
2555
	set_single_sysctl("kern.geom.debugflags", "0");
2556
	conf_mount_ro();
2557
}
2558
function nanobsd_clone_slice() {
2559
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2560
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2561
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2562
	nanobsd_detect_slice_info();
2563

    
2564
	for ($i = 0; $i < ob_get_level(); $i++) {
2565
		ob_end_flush();
2566
	}
2567
	ob_implicit_flush(1);
2568
	set_single_sysctl("kern.geom.debugflags", "16");
2569
	exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
2570
	exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
2571
	exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
2572
	$status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
2573
	set_single_sysctl("kern.geom.debugflags", "0");
2574
	if ($status) {
2575
		return false;
2576
	} else {
2577
		return true;
2578
	}
2579
}
2580
function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
2581
	$tmppath = "/tmp/{$gslice}";
2582
	$fstabpath = "/tmp/{$gslice}/etc/fstab";
2583

    
2584
	mkdir($tmppath);
2585
	exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
2586
	exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
2587
	copy("/etc/fstab", $fstabpath);
2588

    
2589
	if (!file_exists($fstabpath)) {
2590
		$fstab = <<<EOF
2591
/dev/ufs/{$gslice} / ufs ro,noatime 1 1
2592
/dev/ufs/cf /cf ufs ro,noatime 1 1
2593
EOF;
2594
		if (file_put_contents($fstabpath, $fstab)) {
2595
			$status = true;
2596
		} else {
2597
			$status = false;
2598
		}
2599
	} else {
2600
		$status = exec("/usr/bin/sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
2601
	}
2602
	exec("/sbin/umount {$tmppath}");
2603
	rmdir($tmppath);
2604

    
2605
	return $status;
2606
}
2607
function nanobsd_detect_slice_info() {
2608
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2609
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2610
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2611

    
2612
	$BOOT_DEVICE=nanobsd_get_boot_slice();
2613
	$REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
2614
	$BOOT_DRIVE=nanobsd_get_boot_drive();
2615
	$ACTIVE_SLICE=nanobsd_get_active_slice();
2616

    
2617
	// Detect which slice is active and set information.
2618
	if (strstr($REAL_BOOT_DEVICE, "s1")) {
2619
		$SLICE = "2";
2620
		$OLDSLICE = "1";
2621
		$GLABEL_SLICE = "pfsense1";
2622
		$UFS_ID = "1";
2623
		$OLD_UFS_ID = "0";
2624

    
2625
	} else {
2626
		$SLICE = "1";
2627
		$OLDSLICE = "2";
2628
		$GLABEL_SLICE = "pfsense0";
2629
		$UFS_ID = "0";
2630
		$OLD_UFS_ID = "1";
2631
	}
2632
	$TOFLASH = "{$BOOT_DRIVE}s{$SLICE}";
2633
	$COMPLETE_PATH = "{$BOOT_DRIVE}s{$SLICE}a";
2634
	$COMPLETE_BOOT_PATH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2635
	$BOOTFLASH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2636
}
2637

    
2638
function nanobsd_friendly_slice_name($slicename) {
2639
	global $g;
2640
	return strtolower(str_ireplace('pfsense', $g['product_name'], $slicename));
2641
}
2642

    
2643
function get_include_contents($filename) {
2644
	if (is_file($filename)) {
2645
		ob_start();
2646
		include $filename;
2647
		$contents = ob_get_contents();
2648
		ob_end_clean();
2649
		return $contents;
2650
	}
2651
	return false;
2652
}
2653

    
2654
/* This xml 2 array function is courtesy of the php.net comment section on xml_parse.
2655
 * it is roughly 4 times faster then our existing pfSense parser but due to the large
2656
 * size of the RRD xml dumps this is required.
2657
 * The reason we do not use it for pfSense is that it does not know about array fields
2658
 * which causes it to fail on array fields with single items. Possible Todo?
2659
 */
2660
function xml2array($contents, $get_attributes = 1, $priority = 'tag') {
2661
	if (!function_exists('xml_parser_create')) {
2662
		return array ();
2663
	}
2664
	$parser = xml_parser_create('');
2665
	xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
2666
	xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2667
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2668
	xml_parse_into_struct($parser, trim($contents), $xml_values);
2669
	xml_parser_free($parser);
2670
	if (!$xml_values) {
2671
		return; //Hmm...
2672
	}
2673
	$xml_array = array ();
2674
	$parents = array ();
2675
	$opened_tags = array ();
2676
	$arr = array ();
2677
	$current = & $xml_array;
2678
	$repeated_tag_index = array ();
2679
	foreach ($xml_values as $data) {
2680
		unset ($attributes, $value);
2681
		extract($data);
2682
		$result = array ();
2683
		$attributes_data = array ();
2684
		if (isset ($value)) {
2685
			if ($priority == 'tag') {
2686
				$result = $value;
2687
			} else {
2688
				$result['value'] = $value;
2689
			}
2690
		}
2691
		if (isset ($attributes) and $get_attributes) {
2692
			foreach ($attributes as $attr => $val) {
2693
				if ($priority == 'tag') {
2694
					$attributes_data[$attr] = $val;
2695
				} else {
2696
					$result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
2697
				}
2698
			}
2699
		}
2700
		if ($type == "open") {
2701
			$parent[$level -1] = & $current;
2702
			if (!is_array($current) or (!in_array($tag, array_keys($current)))) {
2703
				$current[$tag] = $result;
2704
				if ($attributes_data) {
2705
					$current[$tag . '_attr'] = $attributes_data;
2706
				}
2707
				$repeated_tag_index[$tag . '_' . $level] = 1;
2708
				$current = & $current[$tag];
2709
			} else {
2710
				if (isset ($current[$tag][0])) {
2711
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2712
					$repeated_tag_index[$tag . '_' . $level]++;
2713
				} else {
2714
					$current[$tag] = array (
2715
						$current[$tag],
2716
						$result
2717
						);
2718
					$repeated_tag_index[$tag . '_' . $level] = 2;
2719
					if (isset ($current[$tag . '_attr'])) {
2720
						$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2721
						unset ($current[$tag . '_attr']);
2722
					}
2723
				}
2724
				$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
2725
				$current = & $current[$tag][$last_item_index];
2726
			}
2727
		} elseif ($type == "complete") {
2728
			if (!isset ($current[$tag])) {
2729
				$current[$tag] = $result;
2730
				$repeated_tag_index[$tag . '_' . $level] = 1;
2731
				if ($priority == 'tag' and $attributes_data) {
2732
					$current[$tag . '_attr'] = $attributes_data;
2733
				}
2734
			} else {
2735
				if (isset ($current[$tag][0]) and is_array($current[$tag])) {
2736
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2737
					if ($priority == 'tag' and $get_attributes and $attributes_data) {
2738
						$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2739
					}
2740
					$repeated_tag_index[$tag . '_' . $level]++;
2741
				} else {
2742
					$current[$tag] = array (
2743
						$current[$tag],
2744
						$result
2745
						);
2746
					$repeated_tag_index[$tag . '_' . $level] = 1;
2747
					if ($priority == 'tag' and $get_attributes) {
2748
						if (isset ($current[$tag . '_attr'])) {
2749
							$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2750
							unset ($current[$tag . '_attr']);
2751
						}
2752
						if ($attributes_data) {
2753
							$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2754
						}
2755
					}
2756
					$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
2757
				}
2758
			}
2759
		} elseif ($type == 'close') {
2760
			$current = & $parent[$level -1];
2761
		}
2762
	}
2763
	return ($xml_array);
2764
}
2765

    
2766
function get_country_name($country_code) {
2767
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2768
		return "";
2769
	}
2770

    
2771
	$country_names_xml = "/usr/local/share/mobile-broadband-provider-info/iso_3166-1_list_en.xml";
2772
	$country_names_contents = file_get_contents($country_names_xml);
2773
	$country_names = xml2array($country_names_contents);
2774

    
2775
	if ($country_code == "ALL") {
2776
		$country_list = array();
2777
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2778
			$country_list[] = array(
2779
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2780
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2781
		}
2782
		return $country_list;
2783
	}
2784

    
2785
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2786
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2787
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2788
		}
2789
	}
2790
	return "";
2791
}
2792

    
2793
/* sort by interface only, retain the original order of rules that apply to
2794
   the same interface */
2795
function filter_rules_sort() {
2796
	global $config;
2797

    
2798
	/* mark each rule with the sequence number (to retain the order while sorting) */
2799
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2800
		$config['filter']['rule'][$i]['seq'] = $i;
2801
	}
2802

    
2803
	usort($config['filter']['rule'], "filter_rules_compare");
2804

    
2805
	/* strip the sequence numbers again */
2806
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2807
		unset($config['filter']['rule'][$i]['seq']);
2808
	}
2809
}
2810
function filter_rules_compare($a, $b) {
2811
	if (isset($a['floating']) && isset($b['floating'])) {
2812
		return $a['seq'] - $b['seq'];
2813
	} else if (isset($a['floating'])) {
2814
		return -1;
2815
	} else if (isset($b['floating'])) {
2816
		return 1;
2817
	} else if ($a['interface'] == $b['interface']) {
2818
		return $a['seq'] - $b['seq'];
2819
	} else {
2820
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2821
	}
2822
}
2823

    
2824
function generate_ipv6_from_mac($mac) {
2825
	$elements = explode(":", $mac);
2826
	if (count($elements) <> 6) {
2827
		return false;
2828
	}
2829

    
2830
	$i = 0;
2831
	$ipv6 = "fe80::";
2832
	foreach ($elements as $byte) {
2833
		if ($i == 0) {
2834
			$hexadecimal = substr($byte, 1, 2);
2835
			$bitmap = base_convert($hexadecimal, 16, 2);
2836
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2837
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2838
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2839
		}
2840
		$ipv6 .= $byte;
2841
		if ($i == 1) {
2842
			$ipv6 .= ":";
2843
		}
2844
		if ($i == 3) {
2845
			$ipv6 .= ":";
2846
		}
2847
		if ($i == 2) {
2848
			$ipv6 .= "ff:fe";
2849
		}
2850

    
2851
		$i++;
2852
	}
2853
	return $ipv6;
2854
}
2855

    
2856
/****f* pfsense-utils/load_mac_manufacturer_table
2857
 * NAME
2858
 *   load_mac_manufacturer_table
2859
 * INPUTS
2860
 *   none
2861
 * RESULT
2862
 *   returns associative array with MAC-Manufacturer pairs
2863
 ******/
2864
function load_mac_manufacturer_table() {
2865
	/* load MAC-Manufacture data from the file */
2866
	$macs = false;
2867
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2868
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2869
	}
2870
	if ($macs) {
2871
		foreach ($macs as $line) {
2872
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2873
				/* store values like this $mac_man['000C29']='VMware' */
2874
				$mac_man["$matches[1]"] = $matches[2];
2875
			}
2876
		}
2877
		return $mac_man;
2878
	} else {
2879
		return -1;
2880
	}
2881

    
2882
}
2883

    
2884
/****f* pfsense-utils/is_ipaddr_configured
2885
 * NAME
2886
 *   is_ipaddr_configured
2887
 * INPUTS
2888
 *   IP Address to check.
2889
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2890
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2891
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2892
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2893
 *     If check_subnets is true and cidrprefix is specified,
2894
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2895
 * RESULT
2896
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2897
*/
2898
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2899
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2900
		return true;
2901
	}
2902
	return false;
2903
}
2904

    
2905
/****f* pfsense-utils/where_is_ipaddr_configured
2906
 * NAME
2907
 *   where_is_ipaddr_configured
2908
 * INPUTS
2909
 *   IP Address to check.
2910
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2911
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2912
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2913
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2914
 *     If check_subnets is true and cidrprefix is specified,
2915
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2916
 * RESULT
2917
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2918
 *   If there are no matches then an empty array is returned.
2919
*/
2920
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2921
	global $config;
2922

    
2923
	$where_configured = array();
2924

    
2925
	$pos = strpos($ignore_if, '_virtualip');
2926
	if ($pos !== false) {
2927
		$ignore_vip_id = substr($ignore_if, $pos+10);
2928
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2929
	} else {
2930
		$ignore_vip_id = -1;
2931
		$ignore_vip_if = $ignore_if;
2932
	}
2933

    
2934
	$isipv6 = is_ipaddrv6($ipaddr);
2935

    
2936
	if ($isipv6) {
2937
		$ipaddr = text_to_compressed_ip6($ipaddr);
2938
	}
2939

    
2940
	if ($check_subnets) {
2941
		$cidrprefix = intval($cidrprefix);
2942
		if ($isipv6) {
2943
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2944
				$cidrprefix = 128;
2945
			}
2946
		} else {
2947
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2948
				$cidrprefix = 32;
2949
			}
2950
		}
2951
		$iflist = get_configured_interface_list();
2952
		foreach ($iflist as $if => $ifname) {
2953
			if ($ignore_if == $if) {
2954
				continue;
2955
			}
2956

    
2957
			if ($isipv6) {
2958
				$if_ipv6 = get_interface_ipv6($if);
2959
				$if_snbitsv6 = get_interface_subnetv6($if);
2960
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2961
					$where_entry = array();
2962
					$where_entry['if'] = $if;
2963
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2964
					$where_configured[] = $where_entry;
2965
				}
2966
			} else {
2967
				$if_ipv4 = get_interface_ip($if);
2968
				$if_snbitsv4 = get_interface_subnet($if);
2969
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2970
					$where_entry = array();
2971
					$where_entry['if'] = $if;
2972
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2973
					$where_configured[] = $where_entry;
2974
				}
2975
			}
2976
		}
2977
	} else {
2978
		if ($isipv6) {
2979
			$interface_list_ips = get_configured_ipv6_addresses();
2980
		} else {
2981
			$interface_list_ips = get_configured_ip_addresses();
2982
		}
2983

    
2984
		foreach ($interface_list_ips as $if => $ilips) {
2985
			if ($ignore_if == $if) {
2986
				continue;
2987
			}
2988
			if (strcasecmp($ipaddr, $ilips) == 0) {
2989
				$where_entry = array();
2990
				$where_entry['if'] = $if;
2991
				$where_entry['ip_or_subnet'] = $ilips;
2992
				$where_configured[] = $where_entry;
2993
			}
2994
		}
2995
	}
2996

    
2997
	if ($check_localip) {
2998
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
2999
			$where_entry = array();
3000
			$where_entry['if'] = 'l2tp';
3001
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3002
			$where_configured[] = $where_entry;
3003
		}
3004
	}
3005

    
3006
	return $where_configured;
3007
}
3008

    
3009
/****f* pfsense-utils/pfSense_handle_custom_code
3010
 * NAME
3011
 *   pfSense_handle_custom_code
3012
 * INPUTS
3013
 *   directory name to process
3014
 * RESULT
3015
 *   globs the directory and includes the files
3016
 */
3017
function pfSense_handle_custom_code($src_dir) {
3018
	// Allow extending of the nat edit page and include custom input validation
3019
	if (is_dir("$src_dir")) {
3020
		$cf = glob($src_dir . "/*.inc");
3021
		foreach ($cf as $nf) {
3022
			if ($nf == "." || $nf == "..") {
3023
				continue;
3024
			}
3025
			// Include the extra handler
3026
			include_once("$nf");
3027
		}
3028
	}
3029
}
3030

    
3031
function set_language() {
3032
	global $config, $g;
3033

    
3034
	if (!empty($config['system']['language'])) {
3035
		$lang = $config['system']['language'];
3036
	} elseif (!empty($g['language'])) {
3037
		$lang = $g['language'];
3038
	}
3039
	$lang .= ".UTF-8";
3040

    
3041
	putenv("LANG={$lang}");
3042
	setlocale(LC_ALL, $lang);
3043
	textdomain("pfSense");
3044
	bindtextdomain("pfSense", "/usr/local/share/locale");
3045
	bind_textdomain_codeset("pfSense", $lang);
3046
}
3047

    
3048
function get_locale_list() {
3049
	$locales = array(
3050
		"en_US" => gettext("English"),
3051
		"pt_BR" => gettext("Portuguese (Brazil)"),
3052
		"tr" => gettext("Turkish"),
3053
	);
3054
	asort($locales);
3055
	return $locales;
3056
}
3057

    
3058
function return_hex_ipv4($ipv4) {
3059
	if (!is_ipaddrv4($ipv4)) {
3060
		return(false);
3061
	}
3062

    
3063
	/* we need the hex form of the interface IPv4 address */
3064
	$ip4arr = explode(".", $ipv4);
3065
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3066
}
3067

    
3068
function convert_ipv6_to_128bit($ipv6) {
3069
	if (!is_ipaddrv6($ipv6)) {
3070
		return(false);
3071
	}
3072

    
3073
	$ip6arr = array();
3074
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3075
	$ip6arr = explode(":", $ip6prefix);
3076
	/* binary presentation of the prefix for all 128 bits. */
3077
	$ip6prefixbin = "";
3078
	foreach ($ip6arr as $element) {
3079
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3080
	}
3081
	return($ip6prefixbin);
3082
}
3083

    
3084
function convert_128bit_to_ipv6($ip6bin) {
3085
	if (strlen($ip6bin) <> 128) {
3086
		return(false);
3087
	}
3088

    
3089
	$ip6arr = array();
3090
	$ip6binarr = array();
3091
	$ip6binarr = str_split($ip6bin, 16);
3092
	foreach ($ip6binarr as $binpart) {
3093
		$ip6arr[] = dechex(bindec($binpart));
3094
	}
3095
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3096

    
3097
	return($ip6addr);
3098
}
3099

    
3100

    
3101
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3102
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3103
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3104
/* 6to4 is 16 bits, e.g. 65535 */
3105
function calculate_ipv6_delegation_length($if) {
3106
	global $config;
3107

    
3108
	if (!is_array($config['interfaces'][$if])) {
3109
		return false;
3110
	}
3111

    
3112
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3113
		case "6to4":
3114
			$pdlen = 16;
3115
			break;
3116
		case "6rd":
3117
			$rd6cfg = $config['interfaces'][$if];
3118
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3119
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
3120
			break;
3121
		case "dhcp6":
3122
			$dhcp6cfg = $config['interfaces'][$if];
3123
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3124
			break;
3125
		default:
3126
			$pdlen = 0;
3127
			break;
3128
	}
3129
	return($pdlen);
3130
}
3131

    
3132
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3133
	$prefix = Net_IPv6::uncompress($prefix, true);
3134
	$suffix = Net_IPv6::uncompress($suffix, true);
3135

    
3136
	/*
3137
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3138
	 *                ^^^^ ^
3139
	 *                |||| \-> 64
3140
	 *                |||\---> 63, 62, 61, 60
3141
	 *                ||\----> 56
3142
	 *                |\-----> 52
3143
	 *                \------> 48
3144
	 */
3145

    
3146
	switch ($len) {
3147
	case 48:
3148
		$prefix_len = 15;
3149
		break;
3150
	case 52:
3151
		$prefix_len = 16;
3152
		break;
3153
	case 56:
3154
		$prefix_len = 17;
3155
		break;
3156
	case 59:
3157
	case 60:
3158
		$prefix_len = 18;
3159
		break;
3160
	/*
3161
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3162
	 * we let user chose this bit it can end up out of PD network
3163
	 *
3164
	 * Leave this with 20 for now until we find a way to let user
3165
	 * chose it. The side-effect is users with PD with one of these
3166
	 * lengths will not be able to setup DHCP server range for full
3167
	 * PD size, only for last /64 network
3168
	 */
3169
	case 63:
3170
	case 62:
3171
	case 61:
3172
	default:
3173
		$prefix_len = 20;
3174
		break;
3175
	}
3176

    
3177
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3178
	    substr($suffix, $prefix_len));
3179
}
3180

    
3181
function dhcpv6_pd_str_help($pdlen) {
3182
	$result = '';
3183

    
3184
	switch ($pdlen) {
3185
	case 48:
3186
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3187
		break;
3188
	case 52:
3189
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3190
		break;
3191
	case 56:
3192
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3193
		break;
3194
	case 59:
3195
	case 60:
3196
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3197
		break;
3198
	/*
3199
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3200
	 * we let the user choose this bit it can end up out of PD network
3201
	 *
3202
	 * Leave this with the same as 64 for now until we find a way to
3203
	 * let the user choose it. The side-effect is users with PD with one
3204
	 * of these lengths will not be able to setup DHCP server ranges
3205
	 * for full PD size, only for last /64 network
3206
	 */
3207
	case 61:
3208
	case 62:
3209
	case 63:
3210
	case 64:
3211
	default:
3212
		$result = '::xxxx:xxxx:xxxx:xxxx';
3213
		break;
3214
	}
3215

    
3216
	return $result;
3217
}
3218

    
3219
function huawei_rssi_to_string($rssi) {
3220
	$dbm = array();
3221
	$i = 0;
3222
	$dbstart = -113;
3223
	while ($i < 32) {
3224
		$dbm[$i] = $dbstart + ($i * 2);
3225
		$i++;
3226
	}
3227
	$percent = round(($rssi / 31) * 100);
3228
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3229
	return $string;
3230
}
3231

    
3232
function huawei_mode_to_string($mode, $submode) {
3233
	$modes[0] = gettext("None");
3234
	$modes[1] = "AMPS";
3235
	$modes[2] = "CDMA";
3236
	$modes[3] = "GSM/GPRS";
3237
	$modes[4] = "HDR";
3238
	$modes[5] = "WCDMA";
3239
	$modes[6] = "GPS";
3240

    
3241
	$submodes[0] = gettext("No Service");
3242
	$submodes[1] = "GSM";
3243
	$submodes[2] = "GPRS";
3244
	$submodes[3] = "EDGE";
3245
	$submodes[4] = "WCDMA";
3246
	$submodes[5] = "HSDPA";
3247
	$submodes[6] = "HSUPA";
3248
	$submodes[7] = "HSDPA+HSUPA";
3249
	$submodes[8] = "TD-SCDMA";
3250
	$submodes[9] = "HSPA+";
3251
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3252
	return $string;
3253
}
3254

    
3255
function huawei_service_to_string($state) {
3256
	$modes[0] = gettext("No Service");
3257
	$modes[1] = gettext("Restricted Service");
3258
	$modes[2] = gettext("Valid Service");
3259
	$modes[3] = gettext("Restricted Regional Service");
3260
	$modes[4] = gettext("Powersaving Service");
3261
	$string = $modes[$state];
3262
	return $string;
3263
}
3264

    
3265
function huawei_simstate_to_string($state) {
3266
	$modes[0] = gettext("Invalid SIM/locked State");
3267
	$modes[1] = gettext("Valid SIM State");
3268
	$modes[2] = gettext("Invalid SIM CS State");
3269
	$modes[3] = gettext("Invalid SIM PS State");
3270
	$modes[4] = gettext("Invalid SIM CS/PS State");
3271
	$modes[255] = gettext("Missing SIM State");
3272
	$string = $modes[$state];
3273
	return $string;
3274
}
3275

    
3276
function zte_rssi_to_string($rssi) {
3277
	return huawei_rssi_to_string($rssi);
3278
}
3279

    
3280
function zte_mode_to_string($mode, $submode) {
3281
	$modes[0] = gettext("No Service");
3282
	$modes[1] = gettext("Limited Service");
3283
	$modes[2] = "GPRS";
3284
	$modes[3] = "GSM";
3285
	$modes[4] = "UMTS";
3286
	$modes[5] = "EDGE";
3287
	$modes[6] = "HSDPA";
3288

    
3289
	$submodes[0] = "CS_ONLY";
3290
	$submodes[1] = "PS_ONLY";
3291
	$submodes[2] = "CS_PS";
3292
	$submodes[3] = "CAMPED";
3293
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3294
	return $string;
3295
}
3296

    
3297
function zte_service_to_string($service) {
3298
	$modes[0] = gettext("Initializing Service");
3299
	$modes[1] = gettext("Network Lock error Service");
3300
	$modes[2] = gettext("Network Locked Service");
3301
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3302
	$string = $modes[$service];
3303
	return $string;
3304
}
3305

    
3306
function zte_simstate_to_string($state) {
3307
	$modes[0] = gettext("No action State");
3308
	$modes[1] = gettext("Network lock State");
3309
	$modes[2] = gettext("(U)SIM card lock State");
3310
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3311
	$string = $modes[$state];
3312
	return $string;
3313
}
3314

    
3315
function get_configured_pppoe_server_interfaces() {
3316
	global $config;
3317
	$iflist = array();
3318
	if (is_array($config['pppoes']['pppoe'])) {
3319
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3320
			if ($pppoe['mode'] == "server") {
3321
				$int = "poes". $pppoe['pppoeid'];
3322
				$iflist[$int] = strtoupper($int);
3323
			}
3324
		}
3325
	}
3326
	return $iflist;
3327
}
3328

    
3329
function get_pppoes_child_interfaces($ifpattern) {
3330
	$if_arr = array();
3331
	if ($ifpattern == "") {
3332
		return;
3333
	}
3334

    
3335
	exec("/sbin/ifconfig", $out, $ret);
3336
	foreach ($out as $line) {
3337
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3338
			$if_arr[] = $match[1];
3339
		}
3340
	}
3341
	return $if_arr;
3342

    
3343
}
3344

    
3345
/****f* pfsense-utils/pkg_call_plugins
3346
 * NAME
3347
 *   pkg_call_plugins
3348
 * INPUTS
3349
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3350
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3351
 * RESULT
3352
 *   returns associative array results from the plugin calls for each package
3353
 * NOTES
3354
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3355
 ******/
3356
function pkg_call_plugins($plugin_type, $plugin_params) {
3357
	global $g, $config;
3358
	$results = array();
3359
	if (!is_array($config['installedpackages']['package'])) {
3360
		return $results;
3361
	}
3362
	foreach ($config['installedpackages']['package'] as $package) {
3363
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
3364
			continue;
3365
		}
3366
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
3367
		$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3368
		if (is_array($pkg_config['plugins']['item'])) {
3369
			foreach ($pkg_config['plugins']['item'] as $plugin) {
3370
				if ($plugin['type'] == $plugin_type) {
3371
					if (file_exists($pkg_config['include_file'])) {
3372
						require_once($pkg_config['include_file']);
3373
					} else {
3374
						continue;
3375
					}
3376
					$plugin_function = $pkgname . '_'. $plugin_type;
3377
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3378
				}
3379
			}
3380
		}
3381
	}
3382
	return $results;
3383
}
3384

    
3385
function restore_aliastables() {
3386
	global $g, $config;
3387

    
3388
	$dbpath = "{$g['vardb_path']}/aliastables/";
3389

    
3390
	/* restore the alias tables, if we have them */
3391
	$files = glob("{$g['cf_conf_path']}/RAM_Disk_Store{$dbpath}*.tgz");
3392
	if (count($files)) {
3393
		echo "Restoring alias tables...";
3394
		foreach ($files as $file) {
3395
			if (file_exists($file)) {
3396
				$aliastablesrestore = "";
3397
				$aliastablesreturn = "";
3398
				exec("cd /;LANG=C /usr/bin/tar -xzf {$file} 2>&1", $aliastablesrestore, $aliastablesreturn);
3399
				$aliastablesrestore = implode(" ", $aliastablesrestore);
3400
				if ($aliastablesreturn <> 0) {
3401
					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"));
3402
				} else {
3403
					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"));
3404
				}
3405
			}
3406
			/* 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. */
3407
			if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
3408
				unlink_if_exists("{$file}");
3409
			}
3410
		}
3411
		echo "done.\n";
3412
		return true;
3413
	}
3414
	return false;
3415
}
3416

    
3417
// Convert IPv6 addresses to lower case
3418
function addrtolower($ip) {
3419
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3420
		return(strtolower($ip));
3421
	} else {
3422
		return($ip);
3423
	}
3424
}
3425
?>
(39-39/65)