Project

General

Profile

Download (96.2 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
 *  php_check_syntax($code_tocheck, $errormessage): checks $code_to_check for errors
914
 */
915
if (!function_exists('php_check_syntax')) {
916
	global $g;
917
	function php_check_syntax($code_to_check, &$errormessage) {
918
		return false;
919
		$fout = fopen("{$g['tmp_path']}/codetocheck.php", "w");
920
		$code = $_POST['content'];
921
		$code = str_replace("<?php", "", $code);
922
		$code = str_replace("?>", "", $code);
923
		fwrite($fout, "<?php\n\n");
924
		fwrite($fout, $code_to_check);
925
		fwrite($fout, "\n\n?>\n");
926
		fclose($fout);
927
		$command = "/usr/local/bin/php-cgi -l {$g['tmp_path']}/codetocheck.php";
928
		$output = exec_command($command);
929
		if (stristr($output, "Errors parsing") == false) {
930
			echo "false\n";
931
			$errormessage = '';
932
			return(false);
933
		} else {
934
			$errormessage = $output;
935
			return(true);
936
		}
937
	}
938
}
939

    
940
/*
941
 *  php_check_filename_syntax($filename, $errormessage): checks the file $filename for errors
942
 */
943
if (!function_exists('php_check_syntax')) {
944
	function php_check_syntax($code_to_check, &$errormessage) {
945
		return false;
946
		$command = "/usr/local/bin/php-cgi -l " . escapeshellarg($code_to_check);
947
		$output = exec_command($command);
948
		if (stristr($output, "Errors parsing") == false) {
949
			echo "false\n";
950
			$errormessage = '';
951
			return(false);
952
		} else {
953
			$errormessage = $output;
954
			return(true);
955
		}
956
	}
957
}
958

    
959
/*
960
 * rmdir_recursive($path, $follow_links=false)
961
 * Recursively remove a directory tree (rm -rf path)
962
 * This is for directories _only_
963
 */
964
function rmdir_recursive($path, $follow_links=false) {
965
	$to_do = glob($path);
966
	if (!is_array($to_do)) {
967
		$to_do = array($to_do);
968
	}
969
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
970
		if (file_exists($workingdir)) {
971
			if (is_dir($workingdir)) {
972
				$dir = opendir($workingdir);
973
				while ($entry = readdir($dir)) {
974
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
975
						unlink("$workingdir/$entry");
976
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
977
						rmdir_recursive("$workingdir/$entry");
978
					}
979
				}
980
				closedir($dir);
981
				rmdir($workingdir);
982
			} elseif (is_file($workingdir)) {
983
				unlink($workingdir);
984
			}
985
		}
986
	}
987
	return;
988
}
989

    
990
/*
991
 * host_firmware_version(): Return the versions used in this install
992
 */
993
function host_firmware_version($tocheck = "") {
994
	global $g, $config;
995

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

    
998
	return array(
999
		"firmware" => array("version" => $g['product_version']),
1000
		"kernel"   => array("version" => $os_version),
1001
		"base"     => array("version" => $os_version),
1002
		"platform" => trim(file_get_contents('/etc/platform', " \n")),
1003
		"config_version" => $config['version']
1004
	);
1005
}
1006

    
1007
function get_disk_info() {
1008
	$diskout = "";
1009
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
1010
	return explode(' ', $diskout[0]);
1011
}
1012

    
1013
/****f* pfsense-utils/strncpy
1014
 * NAME
1015
 *   strncpy - copy strings
1016
 * INPUTS
1017
 *   &$dst, $src, $length
1018
 * RESULT
1019
 *   none
1020
 ******/
1021
function strncpy(&$dst, $src, $length) {
1022
	if (strlen($src) > $length) {
1023
		$dst = substr($src, 0, $length);
1024
	} else {
1025
		$dst = $src;
1026
	}
1027
}
1028

    
1029
/****f* pfsense-utils/reload_interfaces_sync
1030
 * NAME
1031
 *   reload_interfaces - reload all interfaces
1032
 * INPUTS
1033
 *   none
1034
 * RESULT
1035
 *   none
1036
 ******/
1037
function reload_interfaces_sync() {
1038
	global $config, $g;
1039

    
1040
	if ($g['debug']) {
1041
		log_error(gettext("reload_interfaces_sync() is starting."));
1042
	}
1043

    
1044
	/* parse config.xml again */
1045
	$config = parse_config(true);
1046

    
1047
	/* enable routing */
1048
	system_routing_enable();
1049
	if ($g['debug']) {
1050
		log_error(gettext("Enabling system routing"));
1051
	}
1052

    
1053
	if ($g['debug']) {
1054
		log_error(gettext("Cleaning up Interfaces"));
1055
	}
1056

    
1057
	/* set up interfaces */
1058
	interfaces_configure();
1059
}
1060

    
1061
/****f* pfsense-utils/reload_all
1062
 * NAME
1063
 *   reload_all - triggers a reload of all settings
1064
 *   * INPUTS
1065
 *   none
1066
 * RESULT
1067
 *   none
1068
 ******/
1069
function reload_all() {
1070
	send_event("service reload all");
1071
}
1072

    
1073
/****f* pfsense-utils/reload_interfaces
1074
 * NAME
1075
 *   reload_interfaces - triggers a reload of all interfaces
1076
 * INPUTS
1077
 *   none
1078
 * RESULT
1079
 *   none
1080
 ******/
1081
function reload_interfaces() {
1082
	send_event("interface all reload");
1083
}
1084

    
1085
/****f* pfsense-utils/reload_all_sync
1086
 * NAME
1087
 *   reload_all - reload all settings
1088
 *   * INPUTS
1089
 *   none
1090
 * RESULT
1091
 *   none
1092
 ******/
1093
function reload_all_sync() {
1094
	global $config, $g;
1095

    
1096
	/* parse config.xml again */
1097
	$config = parse_config(true);
1098

    
1099
	/* set up our timezone */
1100
	system_timezone_configure();
1101

    
1102
	/* set up our hostname */
1103
	system_hostname_configure();
1104

    
1105
	/* make hosts file */
1106
	system_hosts_generate();
1107

    
1108
	/* generate resolv.conf */
1109
	system_resolvconf_generate();
1110

    
1111
	/* enable routing */
1112
	system_routing_enable();
1113

    
1114
	/* set up interfaces */
1115
	interfaces_configure();
1116

    
1117
	/* start dyndns service */
1118
	services_dyndns_configure();
1119

    
1120
	/* configure cron service */
1121
	configure_cron();
1122

    
1123
	/* start the NTP client */
1124
	system_ntp_configure();
1125

    
1126
	/* sync pw database */
1127
	conf_mount_rw();
1128
	unlink_if_exists("/etc/spwd.db.tmp");
1129
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1130
	conf_mount_ro();
1131

    
1132
	/* restart sshd */
1133
	send_event("service restart sshd");
1134

    
1135
	/* restart webConfigurator if needed */
1136
	send_event("service restart webgui");
1137
}
1138

    
1139
function setup_serial_port($when = "save", $path = "") {
1140
	global $g, $config;
1141
	conf_mount_rw();
1142
	$ttys_file = "{$path}/etc/ttys";
1143
	$boot_config_file = "{$path}/boot.config";
1144
	$loader_conf_file = "{$path}/boot/loader.conf";
1145
	/* serial console - write out /boot.config */
1146
	if (file_exists($boot_config_file)) {
1147
		$boot_config = file_get_contents($boot_config_file);
1148
	} else {
1149
		$boot_config = "";
1150
	}
1151

    
1152
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1153
	if ($g['platform'] != "cdrom") {
1154
		$serial_only = false;
1155

    
1156
		if (($g['platform'] == "nanobsd") && isset($g['enableserial_force'])) {
1157
			$serial_only = true;
1158
		} else {
1159
			$specific_platform = system_identify_specific_platform();
1160
			if ($specific_platform['name'] == 'RCC-VE' ||
1161
			    $specific_platform['name'] == 'RCC' ||
1162
			    $specific_platform['name'] == 'RCC-DFF' ||
1163
			    $specific_platform['name'] == 'apu2') {
1164
				$serial_only = true;
1165
			}
1166
		}
1167

    
1168
		$boot_config_split = explode("\n", $boot_config);
1169
		$data = array();
1170
		foreach ($boot_config_split as $bcs) {
1171
			/* Ignore -D and -h lines now */
1172
			if (!empty($bcs) && !stristr($bcs, "-D") &&
1173
			    !stristr($bcs, "-h")) {
1174
				$data[] = $bcs;
1175
			}
1176
		}
1177
		if ($serial_only === true) {
1178
			$data[] = "-S{$serialspeed} -h";
1179
		} elseif (is_serial_enabled()) {
1180
			$data[] = "-S{$serialspeed} -D";
1181
		}
1182

    
1183
		if (empty($data)) {
1184
			@unlink($boot_conf_file);
1185
		} else {
1186
			safe_write_file($boot_config_file, $data);
1187
		}
1188

    
1189
		unset($boot_config, $boot_config_file, $boot_config_split);
1190

    
1191
		/* serial console - write out /boot/loader.conf */
1192
		if ($when == "upgrade") {
1193
			system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1194
		}
1195

    
1196
		$loader_conf = file_get_contents($loader_conf_file);
1197
		$loader_conf_split = explode("\n", $loader_conf);
1198

    
1199
		$data = array();
1200
		// Loop through and only add lines that are not empty, and which
1201
		//  do not contain a console directive.
1202
		foreach ($loader_conf_split as $bcs) {
1203
			if (!empty($bcs) &&
1204
			    (stripos($bcs, "console") === false) &&
1205
			    (stripos($bcs, "boot_multicons") === false) &&
1206
			    (stripos($bcs, "boot_serial") === false) &&
1207
			    (stripos($bcs, "hw.usb.no_pf") === false) &&
1208
			    (stripos($bcs, "hint.uart.0.flags") === false) &&
1209
			    (stripos($bcs, "hint.uart.1.flags") === false)) {
1210
				$data[] = $bcs;
1211
			}
1212
		}
1213

    
1214
		if ($serial_only === true) {
1215
			$data[] = 'boot_serial="YES"';
1216
			$data[] = 'console="comconsole"';
1217
		} else if (is_serial_enabled()) {
1218
			$data[] = 'boot_multicons="YES"';
1219
			$data[] = 'boot_serial="YES"';
1220
			$primaryconsole = isset($g['primaryconsole_force']) ?
1221
			    $g['primaryconsole_force'] :
1222
			    $config['system']['primaryconsole'];
1223
			switch ($primaryconsole) {
1224
				case "video":
1225
					$data[] = 'console="vidconsole,comconsole"';
1226
					break;
1227
				case "serial":
1228
				default:
1229
					$data[] = 'console="comconsole,vidconsole"';
1230
			}
1231
		}
1232
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1233

    
1234
		$specplatform = system_identify_specific_platform();
1235
		if ($specplatform['name'] == 'RCC-VE' ||
1236
		    $specplatform['name'] == 'RCC' ||
1237
		    $specplatform['name'] == 'RCC-DFF') {
1238
			$data[] = 'comconsole_port="0x2F8"';
1239
			$data[] = 'hint.uart.0.flags="0x00"';
1240
			$data[] = 'hint.uart.1.flags="0x10"';
1241
		}
1242
		$data[] = 'hw.usb.no_pf="1"';
1243

    
1244
		safe_write_file($loader_conf_file, $data);
1245

    
1246
		unset($loader_conf, $loader_conf_split, $loader_config_file);
1247
	}
1248

    
1249
	$ttys = file_get_contents($ttys_file);
1250
	$ttys_split = explode("\n", $ttys);
1251

    
1252
	$data = array();
1253

    
1254
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1255

    
1256
	if (isset($config['system']['disableconsolemenu'])) {
1257
		$console_type = 'Pc';
1258
		$serial_type = 'std.' . $serialspeed;
1259
	} else {
1260
		$console_type = 'al.Pc';
1261
		$serial_type = 'al.' . $serialspeed;
1262
	}
1263

    
1264
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1265
	$ttyv0_line =
1266
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\tcons25\ton\tsecure";
1267
	$ttyu_line =
1268
	    "\"/usr/libexec/getty {$serial_type}\"\tcons25\t{$on_off}\tsecure";
1269

    
1270
	$found = array();
1271

    
1272
	foreach ($ttys_split as $tty) {
1273
		/* Ignore blank lines */
1274
		if (empty($tty)) {
1275
			continue;
1276
		}
1277

    
1278
		if (stristr($tty, "ttyv0")) {
1279
			$found['ttyv0'] = 1;
1280
			$data[] = $ttyv0_line;
1281
		} elseif (stristr($tty, "ttyu")) {
1282
			$ttyn = substr($tty, 0, 5);
1283
			$found[$ttyn] = 1;
1284
			$data[] = "{$ttyn}\t{$ttyu_line}";
1285
		} elseif (substr($tty, 0, 7) == 'console') {
1286
			$found['console'] = 1;
1287
			$data[] = $tty;
1288
		} else {
1289
			$data[] = $tty;
1290
		}
1291
	}
1292
	unset($on_off, $console_type, $serial_type);
1293

    
1294
	/* Detect missing main lines on original file and try to rebuild it */
1295
	$items = array(
1296
		'console',
1297
		'ttyv0',
1298
		'ttyu0',
1299
		'ttyu1',
1300
		'ttyu2',
1301
		'ttyu3'
1302
	);
1303

    
1304
	foreach ($items as $item) {
1305
		if (isset($found[$item])) {
1306
			continue;
1307
		}
1308

    
1309
		if ($item == 'console') {
1310
			$data[] = $console_line;
1311
		} elseif ($item == 'ttyv0') {
1312
			$data[] = $ttyv0_line;
1313
		} else {
1314
			$data[] = "{$item}\t{$ttyu_line}";
1315
		}
1316
	}
1317

    
1318
	safe_write_file($ttys_file, $data);
1319

    
1320
	unset($ttys, $ttys_file, $ttys_split, $data);
1321

    
1322
	if ($when != "upgrade") {
1323
		reload_ttys();
1324
	}
1325

    
1326
	conf_mount_ro();
1327
	return;
1328
}
1329

    
1330
function is_serial_enabled() {
1331
	global $g, $config;
1332

    
1333
	if (!isset($g['enableserial_force']) &&
1334
	    !isset($config['system']['enableserial']) &&
1335
	    ($g['platform'] == $g['product_name'] || $g['platform'] == "cdrom")) {
1336
		return false;
1337
	}
1338

    
1339
	return true;
1340
}
1341

    
1342
function reload_ttys() {
1343
	// Send a HUP signal to init will make it reload /etc/ttys
1344
	posix_kill(1, SIGHUP);
1345
}
1346

    
1347
function print_value_list($list, $count = 10, $separator = ",") {
1348
	$list = implode($separator, array_slice($list, 0, $count));
1349
	if (count($list) < $count) {
1350
		$list .= ".";
1351
	} else {
1352
		$list .= "...";
1353
	}
1354
	return $list;
1355
}
1356

    
1357
/* DHCP enabled on any interfaces? */
1358
function is_dhcp_server_enabled() {
1359
	global $config;
1360

    
1361
	if (!is_array($config['dhcpd'])) {
1362
		return false;
1363
	}
1364

    
1365
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1366
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1367
			return true;
1368
		}
1369
	}
1370

    
1371
	return false;
1372
}
1373

    
1374
/* DHCP enabled on any interfaces? */
1375
function is_dhcpv6_server_enabled() {
1376
	global $config;
1377

    
1378
	if (is_array($config['interfaces'])) {
1379
		foreach ($config['interfaces'] as $ifcfg) {
1380
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1381
				return true;
1382
			}
1383
		}
1384
	}
1385

    
1386
	if (!is_array($config['dhcpdv6'])) {
1387
		return false;
1388
	}
1389

    
1390
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1391
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1392
			return true;
1393
		}
1394
	}
1395

    
1396
	return false;
1397
}
1398

    
1399
/* radvd enabled on any interfaces? */
1400
function is_radvd_enabled() {
1401
	global $config;
1402

    
1403
	if (!is_array($config['dhcpdv6'])) {
1404
		$config['dhcpdv6'] = array();
1405
	}
1406

    
1407
	$dhcpdv6cfg = $config['dhcpdv6'];
1408
	$Iflist = get_configured_interface_list();
1409

    
1410
	/* handle manually configured DHCP6 server settings first */
1411
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1412
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1413
			continue;
1414
		}
1415

    
1416
		if (!isset($dhcpv6ifconf['ramode'])) {
1417
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1418
		}
1419

    
1420
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1421
			continue;
1422
		}
1423

    
1424
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1425
		if (!is_ipaddrv6($ifcfgipv6)) {
1426
			continue;
1427
		}
1428

    
1429
		return true;
1430
	}
1431

    
1432
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1433
	foreach ($Iflist as $if => $ifdescr) {
1434
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1435
			continue;
1436
		}
1437
		if (!isset($config['interfaces'][$if]['enable'])) {
1438
			continue;
1439
		}
1440

    
1441
		$ifcfgipv6 = get_interface_ipv6($if);
1442
		if (!is_ipaddrv6($ifcfgipv6)) {
1443
			continue;
1444
		}
1445

    
1446
		$ifcfgsnv6 = get_interface_subnetv6($if);
1447
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1448

    
1449
		if (!is_ipaddrv6($subnetv6)) {
1450
			continue;
1451
		}
1452

    
1453
		return true;
1454
	}
1455

    
1456
	return false;
1457
}
1458

    
1459
/* Any PPPoE servers enabled? */
1460
function is_pppoe_server_enabled() {
1461
	global $config;
1462

    
1463
	$pppoeenable = false;
1464

    
1465
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1466
		return false;
1467
	}
1468

    
1469
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1470
		if ($pppoes['mode'] == 'server') {
1471
			$pppoeenable = true;
1472
		}
1473
	}
1474

    
1475
	return $pppoeenable;
1476
}
1477

    
1478
/* Optional arg forces hh:mm:ss without days */
1479
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1480
	if (!is_numericint($sec)) {
1481
		return '-';
1482
	}
1483
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1484
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1485
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1486
					(int)(($sec % 3600)/60),
1487
					$sec % 60
1488
				);
1489
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1490
}
1491

    
1492
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1493

    
1494
function get_ppp_uptime($port) {
1495
	if (file_exists("/conf/{$port}.log")) {
1496
		$saved_time = file_get_contents("/conf/{$port}.log");
1497
		$uptime_data = explode("\n", $saved_time);
1498
		$sec = 0;
1499
		foreach ($uptime_data as $upt) {
1500
			$sec += substr($upt, 1 + strpos($upt, " "));
1501
		}
1502
		return convert_seconds_to_dhms($sec);
1503
	} else {
1504
		$total_time = gettext("No history data found!");
1505
		return $total_time;
1506
	}
1507
}
1508

    
1509
//returns interface information
1510
function get_interface_info($ifdescr) {
1511
	global $config, $g;
1512

    
1513
	$ifinfo = array();
1514
	if (empty($config['interfaces'][$ifdescr])) {
1515
		return;
1516
	}
1517
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1518
	$ifinfo['if'] = get_real_interface($ifdescr);
1519

    
1520
	$chkif = $ifinfo['if'];
1521
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1522
	$ifinfo['status'] = $ifinfotmp['status'];
1523
	if (empty($ifinfo['status'])) {
1524
		$ifinfo['status'] = "down";
1525
	}
1526
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1527
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1528
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1529
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1530
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1531
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1532
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1533
	if (isset($ifinfotmp['link0'])) {
1534
		$link0 = "down";
1535
	}
1536
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1537
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1538
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1539
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1540
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1541
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1542

    
1543
	/* Use pfctl for non wrapping 64 bit counters */
1544
	/* Pass */
1545
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1546
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1547
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1548
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1549
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1550
	$in4_pass = $pf_in4_pass[5];
1551
	$out4_pass = $pf_out4_pass[5];
1552
	$in4_pass_packets = $pf_in4_pass[3];
1553
	$out4_pass_packets = $pf_out4_pass[3];
1554
	$in6_pass = $pf_in6_pass[5];
1555
	$out6_pass = $pf_out6_pass[5];
1556
	$in6_pass_packets = $pf_in6_pass[3];
1557
	$out6_pass_packets = $pf_out6_pass[3];
1558
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1559
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1560
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1561
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1562

    
1563
	/* Block */
1564
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1565
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1566
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1567
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1568
	$in4_block = $pf_in4_block[5];
1569
	$out4_block = $pf_out4_block[5];
1570
	$in4_block_packets = $pf_in4_block[3];
1571
	$out4_block_packets = $pf_out4_block[3];
1572
	$in6_block = $pf_in6_block[5];
1573
	$out6_block = $pf_out6_block[5];
1574
	$in6_block_packets = $pf_in6_block[3];
1575
	$out6_block_packets = $pf_out6_block[3];
1576
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1577
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1578
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1579
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1580

    
1581
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1582
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1583
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1584
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1585

    
1586
	$ifconfiginfo = "";
1587
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1588
	switch ($link_type) {
1589
		/* DHCP? -> see if dhclient is up */
1590
		case "dhcp":
1591
			/* see if dhclient is up */
1592
			if (find_dhclient_process($ifinfo['if']) != 0) {
1593
				$ifinfo['dhcplink'] = "up";
1594
			} else {
1595
				$ifinfo['dhcplink'] = "down";
1596
			}
1597

    
1598
			break;
1599
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1600
		case "pppoe":
1601
		case "pptp":
1602
		case "l2tp":
1603
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1604
				/* get PPPoE link status for dial on demand */
1605
				$ifinfo["{$link_type}link"] = "up";
1606
			} else {
1607
				$ifinfo["{$link_type}link"] = "down";
1608
			}
1609

    
1610
			break;
1611
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1612
		case "ppp":
1613
			if ($ifinfo['status'] == "up") {
1614
				$ifinfo['ppplink'] = "up";
1615
			} else {
1616
				$ifinfo['ppplink'] = "down" ;
1617
			}
1618

    
1619
			if (empty($ifinfo['status'])) {
1620
				$ifinfo['status'] = "down";
1621
			}
1622

    
1623
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1624
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1625
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1626
						break;
1627
					}
1628
				}
1629
			}
1630
			$dev = $ppp['ports'];
1631
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1632
				break;
1633
			}
1634
			if (!file_exists($dev)) {
1635
				$ifinfo['nodevice'] = 1;
1636
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1637
			}
1638

    
1639
			$usbmodemoutput = array();
1640
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1641
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1642
			if (file_exists($mondev)) {
1643
				$cellstats = file($mondev);
1644
				/* skip header */
1645
				$a_cellstats = explode(",", $cellstats[1]);
1646
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1647
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1648
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1649
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1650
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1651
				}
1652
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1653
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1654
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1655
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1656
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1657
				}
1658
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1659
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1660
				$ifinfo['cell_sent'] = $a_cellstats[6];
1661
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1662
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1663
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1664
			}
1665
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1666
			if (isset($ppp['uptime'])) {
1667
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1668
			}
1669
			break;
1670
		default:
1671
			break;
1672
	}
1673

    
1674
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1675
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1676
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1677
	}
1678

    
1679
	if ($ifinfo['status'] == "up") {
1680
		/* try to determine media with ifconfig */
1681
		unset($ifconfiginfo);
1682
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1683
		$wifconfiginfo = array();
1684
		if (is_interface_wireless($ifdescr)) {
1685
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1686
			array_shift($wifconfiginfo);
1687
		}
1688
		$matches = "";
1689
		foreach ($ifconfiginfo as $ici) {
1690

    
1691
			/* don't list media/speed for wireless cards, as it always
1692
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1693
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1694
				$ifinfo['media'] = $matches[1];
1695
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1696
				$ifinfo['media'] = $matches[1];
1697
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1698
				$ifinfo['media'] = $matches[1];
1699
			}
1700

    
1701
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1702
				if ($matches[1] != "active") {
1703
					$ifinfo['status'] = $matches[1];
1704
				}
1705
				if ($ifinfo['status'] == gettext("running")) {
1706
					$ifinfo['status'] = gettext("up");
1707
				}
1708
			}
1709
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1710
				$ifinfo['channel'] = $matches[1];
1711
			}
1712
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1713
				if ($matches[1][0] == '"') {
1714
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1715
				}
1716
				else {
1717
					$ifinfo['ssid'] = $matches[1];
1718
				}
1719
			}
1720
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1721
				$ifinfo['laggproto'] = $matches[1];
1722
			}
1723
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1724
				$ifinfo['laggport'][] = $matches[1];
1725
			}
1726
		}
1727
		foreach ($wifconfiginfo as $ici) {
1728
			$elements = preg_split("/[ ]+/i", $ici);
1729
			if ($elements[0] != "") {
1730
				$ifinfo['bssid'] = $elements[0];
1731
			}
1732
			if ($elements[3] != "") {
1733
				$ifinfo['rate'] = $elements[3];
1734
			}
1735
			if ($elements[4] != "") {
1736
				$ifinfo['rssi'] = $elements[4];
1737
			}
1738
		}
1739
		/* lookup the gateway */
1740
		if (interface_has_gateway($ifdescr)) {
1741
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1742
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1743
		}
1744
	}
1745

    
1746
	$bridge = "";
1747
	$bridge = link_interface_to_bridge($ifdescr);
1748
	if ($bridge) {
1749
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1750
		if (stristr($bridge_text, "blocking") <> false) {
1751
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1752
			$ifinfo['bridgeint'] = $bridge;
1753
		} else if (stristr($bridge_text, "learning") <> false) {
1754
			$ifinfo['bridge'] = gettext("learning");
1755
			$ifinfo['bridgeint'] = $bridge;
1756
		} else if (stristr($bridge_text, "forwarding") <> false) {
1757
			$ifinfo['bridge'] = gettext("forwarding");
1758
			$ifinfo['bridgeint'] = $bridge;
1759
		}
1760
	}
1761

    
1762
	return $ifinfo;
1763
}
1764

    
1765
//returns cpu speed of processor. Good for determining capabilities of machine
1766
function get_cpu_speed() {
1767
	return get_single_sysctl("hw.clockrate");
1768
}
1769

    
1770
function get_uptime_sec() {
1771
	$boottime = "";
1772
	$matches = "";
1773
	$boottime = get_single_sysctl("kern.boottime");
1774
	preg_match("/sec = (\d+)/", $boottime, $matches);
1775
	$boottime = $matches[1];
1776
	if (intval($boottime) == 0) {
1777
		return 0;
1778
	}
1779

    
1780
	$uptime = time() - $boottime;
1781
	return $uptime;
1782
}
1783

    
1784
function add_hostname_to_watch($hostname) {
1785
	if (!is_dir("/var/db/dnscache")) {
1786
		mkdir("/var/db/dnscache");
1787
	}
1788
	$result = array();
1789
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1790
		$domrecords = array();
1791
		$domips = array();
1792
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1793
		if ($rethost == 0) {
1794
			foreach ($domrecords as $domr) {
1795
				$doml = explode(" ", $domr);
1796
				$domip = $doml[3];
1797
				/* fill array with domain ip addresses */
1798
				if (is_ipaddr($domip)) {
1799
					$domips[] = $domip;
1800
				}
1801
			}
1802
		}
1803
		sort($domips);
1804
		$contents = "";
1805
		if (!empty($domips)) {
1806
			foreach ($domips as $ip) {
1807
				$contents .= "$ip\n";
1808
			}
1809
		}
1810
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1811
		/* Remove empty elements */
1812
		$result = array_filter(explode("\n", $contents), 'strlen');
1813
	}
1814
	return $result;
1815
}
1816

    
1817
function is_fqdn($fqdn) {
1818
	$hostname = false;
1819
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1820
		$hostname = true;
1821
	}
1822
	if (preg_match("/\.\./", $fqdn)) {
1823
		$hostname = false;
1824
	}
1825
	if (preg_match("/^\./i", $fqdn)) {
1826
		$hostname = false;
1827
	}
1828
	if (preg_match("/\//i", $fqdn)) {
1829
		$hostname = false;
1830
	}
1831
	return($hostname);
1832
}
1833

    
1834
function pfsense_default_state_size() {
1835
	/* get system memory amount */
1836
	$memory = get_memory();
1837
	$physmem = $memory[0];
1838
	/* Be cautious and only allocate 10% of system memory to the state table */
1839
	$max_states = (int) ($physmem/10)*1000;
1840
	return $max_states;
1841
}
1842

    
1843
function pfsense_default_tables_size() {
1844
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1845
	return $current;
1846
}
1847

    
1848
function pfsense_default_table_entries_size() {
1849
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1850
	return (trim($current));
1851
}
1852

    
1853
/* Compare the current hostname DNS to the DNS cache we made
1854
 * if it has changed we return the old records
1855
 * if no change we return false */
1856
function compare_hostname_to_dnscache($hostname) {
1857
	if (!is_dir("/var/db/dnscache")) {
1858
		mkdir("/var/db/dnscache");
1859
	}
1860
	$hostname = trim($hostname);
1861
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1862
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1863
	} else {
1864
		$oldcontents = "";
1865
	}
1866
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1867
		$domrecords = array();
1868
		$domips = array();
1869
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1870
		if ($rethost == 0) {
1871
			foreach ($domrecords as $domr) {
1872
				$doml = explode(" ", $domr);
1873
				$domip = $doml[3];
1874
				/* fill array with domain ip addresses */
1875
				if (is_ipaddr($domip)) {
1876
					$domips[] = $domip;
1877
				}
1878
			}
1879
		}
1880
		sort($domips);
1881
		$contents = "";
1882
		if (!empty($domips)) {
1883
			foreach ($domips as $ip) {
1884
				$contents .= "$ip\n";
1885
			}
1886
		}
1887
	}
1888

    
1889
	if (trim($oldcontents) != trim($contents)) {
1890
		if ($g['debug']) {
1891
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1892
		}
1893
		return ($oldcontents);
1894
	} else {
1895
		return false;
1896
	}
1897
}
1898

    
1899
/*
1900
 * load_crypto() - Load crypto modules if enabled in config.
1901
 */
1902
function load_crypto() {
1903
	global $config, $g;
1904
	$crypto_modules = array('glxsb', 'aesni');
1905

    
1906
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1907
		return false;
1908
	}
1909

    
1910
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1911
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1912
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1913
	}
1914
}
1915

    
1916
/*
1917
 * load_thermal_hardware() - Load temperature monitor kernel module
1918
 */
1919
function load_thermal_hardware() {
1920
	global $config, $g;
1921
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1922

    
1923
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1924
		return false;
1925
	}
1926

    
1927
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1928
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1929
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1930
	}
1931
}
1932

    
1933
/****f* pfsense-utils/isvm
1934
 * NAME
1935
 *   isvm
1936
 * INPUTS
1937
 *	none
1938
 * RESULT
1939
 *   returns true if machine is running under a virtual environment
1940
 ******/
1941
function isvm() {
1942
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1943
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
1944

    
1945
	if ($rc != 0 || !isset($output[0])) {
1946
		return false;
1947
	}
1948

    
1949
	foreach ($virtualenvs as $virtualenv) {
1950
		if (stripos($output[0], $virtualenv) !== false) {
1951
			return true;
1952
		}
1953
	}
1954

    
1955
	return false;
1956
}
1957

    
1958
function get_freebsd_version() {
1959
	$version = explode(".", php_uname("r"));
1960
	return $version[0];
1961
}
1962

    
1963
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1964
	global $config, $g;
1965

    
1966
	$fp = fopen($destination, "wb");
1967

    
1968
	if (!$fp) {
1969
		return false;
1970
	}
1971

    
1972
	$ch = curl_init();
1973
	curl_setopt($ch, CURLOPT_URL, $url);
1974
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1975
	curl_setopt($ch, CURLOPT_FILE, $fp);
1976
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1977
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1978
	curl_setopt($ch, CURLOPT_HEADER, false);
1979
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1980
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1981
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1982
	} else {
1983
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1984
	}
1985

    
1986
	if (!empty($config['system']['proxyurl'])) {
1987
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1988
		if (!empty($config['system']['proxyport'])) {
1989
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1990
		}
1991
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1992
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1993
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1994
		}
1995
	}
1996

    
1997
	@curl_exec($ch);
1998
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1999
	fclose($fp);
2000
	curl_close($ch);
2001
	if ($http_code == 200) {
2002
		return true;
2003
	} else {
2004
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2005
		unlink_if_exists($destination);
2006
		return false;
2007
	}
2008
}
2009

    
2010
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
2011
	global $config, $g;
2012
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
2013
	$file_size = 1;
2014
	$downloaded = 1;
2015
	$first_progress_update = TRUE;
2016
	/* open destination file */
2017
	$fout = fopen($destination, "wb");
2018

    
2019
	if (!$fout) {
2020
		return false;
2021
	}
2022
	/*
2023
	 *      Originally by Author: Keyvan Minoukadeh
2024
	 *      Modified by Scott Ullrich to return Content-Length size
2025
	 */
2026
	$ch = curl_init();
2027
	curl_setopt($ch, CURLOPT_URL, $url);
2028
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2029
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
2030
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2031
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
2032
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
2033
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2034
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2035
	if (!isset($config['system']['do_not_send_host_uuid'])) {
2036
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
2037
	} else {
2038
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2039
	}
2040

    
2041
	if (!empty($config['system']['proxyurl'])) {
2042
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2043
		if (!empty($config['system']['proxyport'])) {
2044
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2045
		}
2046
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2047
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2048
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2049
		}
2050
	}
2051

    
2052
	@curl_exec($ch);
2053
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2054
	fclose($fout);
2055
	curl_close($ch);
2056
	if ($http_code == 200) {
2057
		return true;
2058
	} else {
2059
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2060
		unlink_if_exists($destination);
2061
		return false;
2062
	}
2063
}
2064

    
2065
function read_header($ch, $string) {
2066
	global $file_size, $fout;
2067
	$length = strlen($string);
2068
	$regs = "";
2069
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2070
	if ($regs[2] <> "") {
2071
		$file_size = intval($regs[2]);
2072
	}
2073
	ob_flush();
2074
	return $length;
2075
}
2076

    
2077
function read_body($ch, $string) {
2078
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2079
	global $pkg_interface;
2080
	$length = strlen($string);
2081
	$downloaded += intval($length);
2082
	if ($file_size > 0) {
2083
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2084
		$downloadProgress = 100 - $downloadProgress;
2085
	} else {
2086
		$downloadProgress = 0;
2087
	}
2088
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2089
		if ($sendto == "status") {
2090
			if ($pkg_interface == "console") {
2091
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2092
					$tostatus = $static_status . $downloadProgress . "%";
2093
					if ($downloadProgress == 100) {
2094
						$tostatus = $tostatus . "\r";
2095
					}
2096
					update_status($tostatus);
2097
				}
2098
			} else {
2099
				$tostatus = $static_status . $downloadProgress . "%";
2100
				update_status($tostatus);
2101
			}
2102
		} else {
2103
			if ($pkg_interface == "console") {
2104
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2105
					$tooutput = $static_output . $downloadProgress . "%";
2106
					if ($downloadProgress == 100) {
2107
						$tooutput = $tooutput . "\r";
2108
					}
2109
					update_output_window($tooutput);
2110
				}
2111
			} else {
2112
				$tooutput = $static_output . $downloadProgress . "%";
2113
				update_output_window($tooutput);
2114
			}
2115
		}
2116
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2117
			update_progress_bar($downloadProgress, $first_progress_update);
2118
			$first_progress_update = FALSE;
2119
		}
2120
		$lastseen = $downloadProgress;
2121
	}
2122
	if ($fout) {
2123
		fwrite($fout, $string);
2124
	}
2125
	ob_flush();
2126
	return $length;
2127
}
2128

    
2129
/*
2130
 *   update_output_window: update bottom textarea dynamically.
2131
 */
2132
function update_output_window($text) {
2133
	global $pkg_interface;
2134
	$log = preg_replace("/\n/", "\\n", $text);
2135
	if ($pkg_interface != "console") {
2136
?>
2137
<script type="text/javascript">
2138
//<![CDATA[
2139
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2140
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2141
//]]>
2142
</script>
2143
<?php
2144
	}
2145
	/* ensure that contents are written out */
2146
	ob_flush();
2147
}
2148

    
2149
/*
2150
 *   update_status: update top textarea dynamically.
2151
 */
2152
function update_status($status) {
2153
	global $pkg_interface;
2154

    
2155
	if ($pkg_interface == "console") {
2156
		print ("{$status}");
2157
	}
2158

    
2159
	/* ensure that contents are written out */
2160
	ob_flush();
2161
}
2162

    
2163
/*
2164
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2165
 */
2166
function update_progress_bar($percent, $first_time) {
2167
	global $pkg_interface;
2168
	if ($percent > 100) {
2169
		$percent = 1;
2170
	}
2171
	if ($pkg_interface <> "console") {
2172
		echo '<script type="text/javascript">';
2173
		echo "\n//<![CDATA[\n";
2174
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2175
		echo "\n//]]>\n";
2176
		echo '</script>';
2177
	} else {
2178
		if (!($first_time)) {
2179
			echo "\x08\x08\x08\x08\x08";
2180
		}
2181
		echo sprintf("%4d%%", $percent);
2182
	}
2183
}
2184

    
2185
/* 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. */
2186
if (!function_exists("split")) {
2187
	function split($separator, $haystack, $limit = null) {
2188
		log_error("deprecated split() call with separator '{$separator}'");
2189
		return preg_split($separator, $haystack, $limit);
2190
	}
2191
}
2192

    
2193
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2194
	global $g, $config, $pconfig, $debug;
2195
	if (!$origname) {
2196
		return;
2197
	}
2198

    
2199
	$sectionref = &$config;
2200
	foreach ($section as $sectionname) {
2201
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2202
			$sectionref = &$sectionref[$sectionname];
2203
		} else {
2204
			return;
2205
		}
2206
	}
2207

    
2208
	if ($debug) {
2209
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2210
		fwrite($fd, print_r($pconfig, true));
2211
	}
2212

    
2213
	if (is_array($sectionref)) {
2214
		foreach ($sectionref as $itemkey => $item) {
2215
			if ($debug) {
2216
				fwrite($fd, "$itemkey\n");
2217
			}
2218

    
2219
			$fieldfound = true;
2220
			$fieldref = &$sectionref[$itemkey];
2221
			foreach ($field as $fieldname) {
2222
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2223
					$fieldref = &$fieldref[$fieldname];
2224
				} else {
2225
					$fieldfound = false;
2226
					break;
2227
				}
2228
			}
2229
			if ($fieldfound && $fieldref == $origname) {
2230
				if ($debug) {
2231
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2232
				}
2233
				$fieldref = $new_alias_name;
2234
			}
2235
		}
2236
	}
2237

    
2238
	if ($debug) {
2239
		fclose($fd);
2240
	}
2241

    
2242
}
2243

    
2244
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2245
	/*
2246
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2247
	 * $type = if set to 'url' then subnets and ips will be returned,
2248
	 *         if set to 'url_ports' port-ranges and ports will be returned
2249
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2250
	 *
2251
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2252
	 */
2253

    
2254
	if (!file_exists($filename)) {
2255
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2256
		return null;
2257
	}
2258

    
2259
	if (filesize($filename) == 0) {
2260
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2261
		return null;
2262
	}
2263
	$fd = @fopen($filename, 'r');
2264
	if (!$fd) {
2265
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2266
		return null;
2267
	}
2268
	$items = array();
2269
	$comments = array();
2270
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2271
	while (($fc = fgetss($fd)) !== FALSE) {
2272
		$tmp = trim($fc, " \t\n\r");
2273
		if (empty($tmp)) {
2274
			continue;
2275
		}
2276
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2277
			$comments[] = $tmp;
2278
		} else {
2279
			$tmp_str = strstr($tmp, '#', true);
2280
			if (!empty($tmp_str)) {
2281
				$tmp = $tmp_str;
2282
			}
2283
			$tmp_str = strstr($tmp, ' ', true);
2284
			if (!empty($tmp_str)) {
2285
				$tmp = $tmp_str;
2286
			}
2287
			$valid = (($type == "url" || $type == "urltable") && (is_ipaddr($tmp) || is_subnet($tmp))) ||
2288
				(($type == "url_ports" || $type == "urltable_ports") && (is_port($tmp) || is_portrange($tmp)));
2289
			if ($valid) {
2290
				$items[] = $tmp;
2291
				if (count($items) == $max_items) {
2292
					break;
2293
				}
2294
			}
2295
		}
2296
	}
2297
	fclose($fd);
2298
	return array_merge($comments, $items);
2299
}
2300

    
2301
function update_alias_url_data() {
2302
	global $config, $g;
2303

    
2304
	$updated = false;
2305

    
2306
	/* item is a url type */
2307
	$lockkey = lock('aliasurl');
2308
	if (is_array($config['aliases']['alias'])) {
2309
		foreach ($config['aliases']['alias'] as $x => $alias) {
2310
			if (empty($alias['aliasurl'])) {
2311
				continue;
2312
			}
2313

    
2314
			$address = null;
2315
			foreach ($alias['aliasurl'] as $alias_url) {
2316
				/* fetch down and add in */
2317
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2318
				unlink($temp_filename);
2319
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2320
				mkdir($temp_filename);
2321
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2322
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2323
					continue;
2324
				}
2325

    
2326
				/* if the item is tar gzipped then extract */
2327
				if (stripos($alias_url, '.tgz')) {
2328
					if (!process_alias_tgz($temp_filename)) {
2329
						continue;
2330
					}
2331
				}
2332
				if (file_exists("{$temp_filename}/aliases")) {
2333
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2334
					mwexec("/bin/rm -rf {$temp_filename}");
2335
				}
2336
			}
2337
			if ($address != null) {
2338
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2339
				$updated = true;
2340
			}
2341
		}
2342
	}
2343
	unlock($lockkey);
2344

    
2345
	/* Report status to callers as well */
2346
	return $updated;
2347
}
2348

    
2349
function process_alias_tgz($temp_filename) {
2350
	if (!file_exists('/usr/bin/tar')) {
2351
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2352
		return false;
2353
	}
2354
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2355
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2356
	unlink("{$temp_filename}/aliases.tgz");
2357
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2358
	/* foreach through all extracted files and build up aliases file */
2359
	$fd = @fopen("{$temp_filename}/aliases", "w");
2360
	if (!$fd) {
2361
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2362
		return false;
2363
	}
2364
	foreach ($files_to_process as $f2p) {
2365
		$tmpfd = @fopen($f2p, 'r');
2366
		if (!$tmpfd) {
2367
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2368
			continue;
2369
		}
2370
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2371
			fwrite($fd, $tmpbuf);
2372
		}
2373
		fclose($tmpfd);
2374
		unlink($f2p);
2375
	}
2376
	fclose($fd);
2377
	unset($tmpbuf);
2378

    
2379
	return true;
2380
}
2381

    
2382
function version_compare_dates($a, $b) {
2383
	$a_time = strtotime($a);
2384
	$b_time = strtotime($b);
2385

    
2386
	if ((!$a_time) || (!$b_time)) {
2387
		return FALSE;
2388
	} else {
2389
		if ($a_time < $b_time) {
2390
			return -1;
2391
		} elseif ($a_time == $b_time) {
2392
			return 0;
2393
		} else {
2394
			return 1;
2395
		}
2396
	}
2397
}
2398
function version_get_string_value($a) {
2399
	$strs = array(
2400
		0 => "ALPHA-ALPHA",
2401
		2 => "ALPHA",
2402
		3 => "BETA",
2403
		4 => "B",
2404
		5 => "C",
2405
		6 => "D",
2406
		7 => "RC",
2407
		8 => "RELEASE",
2408
		9 => "*"			// Matches all release levels
2409
	);
2410
	$major = 0;
2411
	$minor = 0;
2412
	foreach ($strs as $num => $str) {
2413
		if (substr($a, 0, strlen($str)) == $str) {
2414
			$major = $num;
2415
			$n = substr($a, strlen($str));
2416
			if (is_numeric($n)) {
2417
				$minor = $n;
2418
			}
2419
			break;
2420
		}
2421
	}
2422
	return "{$major}.{$minor}";
2423
}
2424
function version_compare_string($a, $b) {
2425
	// Only compare string parts if both versions give a specific release
2426
	// (If either version lacks a string part, assume intended to match all release levels)
2427
	if (isset($a) && isset($b)) {
2428
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2429
	} else {
2430
		return 0;
2431
	}
2432
}
2433
function version_compare_numeric($a, $b) {
2434
	$a_arr = explode('.', rtrim($a, '.'));
2435
	$b_arr = explode('.', rtrim($b, '.'));
2436

    
2437
	foreach ($a_arr as $n => $val) {
2438
		if (array_key_exists($n, $b_arr)) {
2439
			// So far so good, both have values at this minor version level. Compare.
2440
			if ($val > $b_arr[$n]) {
2441
				return 1;
2442
			} elseif ($val < $b_arr[$n]) {
2443
				return -1;
2444
			}
2445
		} else {
2446
			// a is greater, since b doesn't have any minor version here.
2447
			return 1;
2448
		}
2449
	}
2450
	if (count($b_arr) > count($a_arr)) {
2451
		// b is longer than a, so it must be greater.
2452
		return -1;
2453
	} else {
2454
		// Both a and b are of equal length and value.
2455
		return 0;
2456
	}
2457
}
2458
function pfs_version_compare($cur_time, $cur_text, $remote) {
2459
	// First try date compare
2460
	$v = version_compare_dates($cur_time, $remote);
2461
	if ($v === FALSE) {
2462
		// If that fails, try to compare by string
2463
		// Before anything else, simply test if the strings are equal
2464
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2465
			return 0;
2466
		}
2467
		list($cur_num, $cur_str) = explode('-', $cur_text);
2468
		list($rem_num, $rem_str) = explode('-', $remote);
2469

    
2470
		// First try to compare the numeric parts of the version string.
2471
		$v = version_compare_numeric($cur_num, $rem_num);
2472

    
2473
		// If the numeric parts are the same, compare the string parts.
2474
		if ($v == 0) {
2475
			return version_compare_string($cur_str, $rem_str);
2476
		}
2477
	}
2478
	return $v;
2479
}
2480
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2481
	global $g, $config;
2482

    
2483
	$urltable_prefix = "/var/db/aliastables/";
2484
	$urltable_filename = $urltable_prefix . $name . ".txt";
2485
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2486

    
2487
	// Make the aliases directory if it doesn't exist
2488
	if (!file_exists($urltable_prefix)) {
2489
		mkdir($urltable_prefix);
2490
	} elseif (!is_dir($urltable_prefix)) {
2491
		unlink($urltable_prefix);
2492
		mkdir($urltable_prefix);
2493
	}
2494

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

    
2500
		// Try to fetch the URL supplied
2501
		conf_mount_rw();
2502
		unlink_if_exists($tmp_urltable_filename);
2503
		$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2504
		if (download_file($url, $tmp_urltable_filename, $verify_ssl)) {
2505
			// Convert lines that begin with '$' or ';' to comments '#' instead of deleting them.
2506
			mwexec("/usr/bin/sed -i \"\" -E 's/^[[:space:]]*($|#|;)/#/g; /^#/!s/\;.*//g;' ". escapeshellarg($tmp_urltable_filename));
2507

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

    
2510
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2511
			if ($type == "urltable_ports") {
2512
				$parsed_contents = group_ports($parsed_contents, true);
2513
			}
2514
			if (is_array($parsed_contents)) {
2515
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2516
			} else {
2517
				touch($urltable_filename);
2518
			}
2519

    
2520
			/* 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. */
2521
			if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
2522
				unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz");
2523
			} else {
2524
				/* Update the RAM disk store with the new/updated table file. */
2525
				mwexec("cd / && /usr/bin/tar -czf \"{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz\" -C / \"{$urltable_filename}\"");
2526
			}
2527
			unlink_if_exists($tmp_urltable_filename);
2528
		} else {
2529
			if (!$validateonly) {
2530
				touch($urltable_filename);
2531
			}
2532
			conf_mount_ro();
2533
			return false;
2534
		}
2535
		conf_mount_ro();
2536
		return true;
2537
	} else {
2538
		// File exists, and it doesn't need to be updated.
2539
		return -1;
2540
	}
2541
}
2542
function get_real_slice_from_glabel($label) {
2543
	$label = escapeshellarg($label);
2544
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/{$label} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`);
2545
}
2546
function nanobsd_get_boot_slice() {
2547
	return trim(`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`);
2548
}
2549
function nanobsd_get_boot_drive() {
2550
	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`);
2551
}
2552
function nanobsd_get_active_slice() {
2553
	$boot_drive = nanobsd_get_boot_drive();
2554
	$active = trim(`gpart show $boot_drive | grep '\[active\]' | awk '{print $3;}'`);
2555

    
2556
	return "{$boot_drive}s{$active}";
2557
}
2558
function nanobsd_get_size() {
2559
	return strtoupper(file_get_contents("/etc/nanosize.txt"));
2560
}
2561
function nanobsd_switch_boot_slice() {
2562
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2563
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2564
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2565
	nanobsd_detect_slice_info();
2566

    
2567
	if ($BOOTFLASH == $ACTIVE_SLICE) {
2568
		$slice = $TOFLASH;
2569
	} else {
2570
		$slice = $BOOTFLASH;
2571
	}
2572

    
2573
	for ($i = 0; $i < ob_get_level(); $i++) {
2574
		ob_end_flush();
2575
	}
2576
	ob_implicit_flush(1);
2577
	if (strstr($slice, "s2")) {
2578
		$ASLICE = "2";
2579
		$AOLDSLICE = "1";
2580
		$AGLABEL_SLICE = "pfsense1";
2581
		$AUFS_ID = "1";
2582
		$AOLD_UFS_ID = "0";
2583
	} else {
2584
		$ASLICE = "1";
2585
		$AOLDSLICE = "2";
2586
		$AGLABEL_SLICE = "pfsense0";
2587
		$AUFS_ID = "0";
2588
		$AOLD_UFS_ID = "1";
2589
	}
2590
	$ATOFLASH = "{$BOOT_DRIVE}s{$ASLICE}";
2591
	$ACOMPLETE_PATH = "{$BOOT_DRIVE}s{$ASLICE}a";
2592
	$ABOOTFLASH = "{$BOOT_DRIVE}s{$AOLDSLICE}";
2593
	conf_mount_rw();
2594
	set_single_sysctl("kern.geom.debugflags", "16");
2595
	exec("/sbin/gpart set -a active -i {$ASLICE} {$BOOT_DRIVE}");
2596
	exec("/usr/sbin/boot0cfg -s {$ASLICE} -v /dev/{$BOOT_DRIVE}");
2597
	// We can't update these if they are mounted now.
2598
	if ($BOOTFLASH != $slice) {
2599
		exec("/sbin/tunefs -L ${AGLABEL_SLICE} /dev/$ACOMPLETE_PATH");
2600
		nanobsd_update_fstab($AGLABEL_SLICE, $ACOMPLETE_PATH, $AOLD_UFS_ID, $AUFS_ID);
2601
	}
2602
	set_single_sysctl("kern.geom.debugflags", "0");
2603
	conf_mount_ro();
2604
}
2605
function nanobsd_clone_slice() {
2606
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2607
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2608
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2609
	nanobsd_detect_slice_info();
2610

    
2611
	for ($i = 0; $i < ob_get_level(); $i++) {
2612
		ob_end_flush();
2613
	}
2614
	ob_implicit_flush(1);
2615
	set_single_sysctl("kern.geom.debugflags", "16");
2616
	exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
2617
	exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
2618
	exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
2619
	$status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
2620
	set_single_sysctl("kern.geom.debugflags", "0");
2621
	if ($status) {
2622
		return false;
2623
	} else {
2624
		return true;
2625
	}
2626
}
2627
function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
2628
	$tmppath = "/tmp/{$gslice}";
2629
	$fstabpath = "/tmp/{$gslice}/etc/fstab";
2630

    
2631
	mkdir($tmppath);
2632
	exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
2633
	exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
2634
	copy("/etc/fstab", $fstabpath);
2635

    
2636
	if (!file_exists($fstabpath)) {
2637
		$fstab = <<<EOF
2638
/dev/ufs/{$gslice} / ufs ro,noatime 1 1
2639
/dev/ufs/cf /cf ufs ro,noatime 1 1
2640
EOF;
2641
		if (file_put_contents($fstabpath, $fstab)) {
2642
			$status = true;
2643
		} else {
2644
			$status = false;
2645
		}
2646
	} else {
2647
		$status = exec("/usr/bin/sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
2648
	}
2649
	exec("/sbin/umount {$tmppath}");
2650
	rmdir($tmppath);
2651

    
2652
	return $status;
2653
}
2654
function nanobsd_detect_slice_info() {
2655
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2656
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2657
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2658

    
2659
	$BOOT_DEVICE=nanobsd_get_boot_slice();
2660
	$REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
2661
	$BOOT_DRIVE=nanobsd_get_boot_drive();
2662
	$ACTIVE_SLICE=nanobsd_get_active_slice();
2663

    
2664
	// Detect which slice is active and set information.
2665
	if (strstr($REAL_BOOT_DEVICE, "s1")) {
2666
		$SLICE = "2";
2667
		$OLDSLICE = "1";
2668
		$GLABEL_SLICE = "pfsense1";
2669
		$UFS_ID = "1";
2670
		$OLD_UFS_ID = "0";
2671

    
2672
	} else {
2673
		$SLICE = "1";
2674
		$OLDSLICE = "2";
2675
		$GLABEL_SLICE = "pfsense0";
2676
		$UFS_ID = "0";
2677
		$OLD_UFS_ID = "1";
2678
	}
2679
	$TOFLASH = "{$BOOT_DRIVE}s{$SLICE}";
2680
	$COMPLETE_PATH = "{$BOOT_DRIVE}s{$SLICE}a";
2681
	$COMPLETE_BOOT_PATH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2682
	$BOOTFLASH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2683
}
2684

    
2685
function nanobsd_friendly_slice_name($slicename) {
2686
	global $g;
2687
	return strtolower(str_ireplace('pfsense', $g['product_name'], $slicename));
2688
}
2689

    
2690
function get_include_contents($filename) {
2691
	if (is_file($filename)) {
2692
		ob_start();
2693
		include $filename;
2694
		$contents = ob_get_contents();
2695
		ob_end_clean();
2696
		return $contents;
2697
	}
2698
	return false;
2699
}
2700

    
2701
/* This xml 2 array function is courtesy of the php.net comment section on xml_parse.
2702
 * it is roughly 4 times faster then our existing pfSense parser but due to the large
2703
 * size of the RRD xml dumps this is required.
2704
 * The reason we do not use it for pfSense is that it does not know about array fields
2705
 * which causes it to fail on array fields with single items. Possible Todo?
2706
 */
2707
function xml2array($contents, $get_attributes = 1, $priority = 'tag') {
2708
	if (!function_exists('xml_parser_create')) {
2709
		return array ();
2710
	}
2711
	$parser = xml_parser_create('');
2712
	xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
2713
	xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2714
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2715
	xml_parse_into_struct($parser, trim($contents), $xml_values);
2716
	xml_parser_free($parser);
2717
	if (!$xml_values) {
2718
		return; //Hmm...
2719
	}
2720
	$xml_array = array ();
2721
	$parents = array ();
2722
	$opened_tags = array ();
2723
	$arr = array ();
2724
	$current = & $xml_array;
2725
	$repeated_tag_index = array ();
2726
	foreach ($xml_values as $data) {
2727
		unset ($attributes, $value);
2728
		extract($data);
2729
		$result = array ();
2730
		$attributes_data = array ();
2731
		if (isset ($value)) {
2732
			if ($priority == 'tag') {
2733
				$result = $value;
2734
			} else {
2735
				$result['value'] = $value;
2736
			}
2737
		}
2738
		if (isset ($attributes) and $get_attributes) {
2739
			foreach ($attributes as $attr => $val) {
2740
				if ($priority == 'tag') {
2741
					$attributes_data[$attr] = $val;
2742
				} else {
2743
					$result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
2744
				}
2745
			}
2746
		}
2747
		if ($type == "open") {
2748
			$parent[$level -1] = & $current;
2749
			if (!is_array($current) or (!in_array($tag, array_keys($current)))) {
2750
				$current[$tag] = $result;
2751
				if ($attributes_data) {
2752
					$current[$tag . '_attr'] = $attributes_data;
2753
				}
2754
				$repeated_tag_index[$tag . '_' . $level] = 1;
2755
				$current = & $current[$tag];
2756
			} else {
2757
				if (isset ($current[$tag][0])) {
2758
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2759
					$repeated_tag_index[$tag . '_' . $level]++;
2760
				} else {
2761
					$current[$tag] = array (
2762
						$current[$tag],
2763
						$result
2764
						);
2765
					$repeated_tag_index[$tag . '_' . $level] = 2;
2766
					if (isset ($current[$tag . '_attr'])) {
2767
						$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2768
						unset ($current[$tag . '_attr']);
2769
					}
2770
				}
2771
				$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
2772
				$current = & $current[$tag][$last_item_index];
2773
			}
2774
		} elseif ($type == "complete") {
2775
			if (!isset ($current[$tag])) {
2776
				$current[$tag] = $result;
2777
				$repeated_tag_index[$tag . '_' . $level] = 1;
2778
				if ($priority == 'tag' and $attributes_data) {
2779
					$current[$tag . '_attr'] = $attributes_data;
2780
				}
2781
			} else {
2782
				if (isset ($current[$tag][0]) and is_array($current[$tag])) {
2783
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2784
					if ($priority == 'tag' and $get_attributes and $attributes_data) {
2785
						$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2786
					}
2787
					$repeated_tag_index[$tag . '_' . $level]++;
2788
				} else {
2789
					$current[$tag] = array (
2790
						$current[$tag],
2791
						$result
2792
						);
2793
					$repeated_tag_index[$tag . '_' . $level] = 1;
2794
					if ($priority == 'tag' and $get_attributes) {
2795
						if (isset ($current[$tag . '_attr'])) {
2796
							$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2797
							unset ($current[$tag . '_attr']);
2798
						}
2799
						if ($attributes_data) {
2800
							$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2801
						}
2802
					}
2803
					$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
2804
				}
2805
			}
2806
		} elseif ($type == 'close') {
2807
			$current = & $parent[$level -1];
2808
		}
2809
	}
2810
	return ($xml_array);
2811
}
2812

    
2813
function get_country_name($country_code) {
2814
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2815
		return "";
2816
	}
2817

    
2818
	$country_names_xml = "/usr/local/share/mobile-broadband-provider-info/iso_3166-1_list_en.xml";
2819
	$country_names_contents = file_get_contents($country_names_xml);
2820
	$country_names = xml2array($country_names_contents);
2821

    
2822
	if ($country_code == "ALL") {
2823
		$country_list = array();
2824
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2825
			$country_list[] = array(
2826
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2827
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2828
		}
2829
		return $country_list;
2830
	}
2831

    
2832
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2833
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2834
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2835
		}
2836
	}
2837
	return "";
2838
}
2839

    
2840
/* sort by interface only, retain the original order of rules that apply to
2841
   the same interface */
2842
function filter_rules_sort() {
2843
	global $config;
2844

    
2845
	/* mark each rule with the sequence number (to retain the order while sorting) */
2846
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2847
		$config['filter']['rule'][$i]['seq'] = $i;
2848
	}
2849

    
2850
	usort($config['filter']['rule'], "filter_rules_compare");
2851

    
2852
	/* strip the sequence numbers again */
2853
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2854
		unset($config['filter']['rule'][$i]['seq']);
2855
	}
2856
}
2857
function filter_rules_compare($a, $b) {
2858
	if (isset($a['floating']) && isset($b['floating'])) {
2859
		return $a['seq'] - $b['seq'];
2860
	} else if (isset($a['floating'])) {
2861
		return -1;
2862
	} else if (isset($b['floating'])) {
2863
		return 1;
2864
	} else if ($a['interface'] == $b['interface']) {
2865
		return $a['seq'] - $b['seq'];
2866
	} else {
2867
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2868
	}
2869
}
2870

    
2871
function generate_ipv6_from_mac($mac) {
2872
	$elements = explode(":", $mac);
2873
	if (count($elements) <> 6) {
2874
		return false;
2875
	}
2876

    
2877
	$i = 0;
2878
	$ipv6 = "fe80::";
2879
	foreach ($elements as $byte) {
2880
		if ($i == 0) {
2881
			$hexadecimal = substr($byte, 1, 2);
2882
			$bitmap = base_convert($hexadecimal, 16, 2);
2883
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2884
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2885
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2886
		}
2887
		$ipv6 .= $byte;
2888
		if ($i == 1) {
2889
			$ipv6 .= ":";
2890
		}
2891
		if ($i == 3) {
2892
			$ipv6 .= ":";
2893
		}
2894
		if ($i == 2) {
2895
			$ipv6 .= "ff:fe";
2896
		}
2897

    
2898
		$i++;
2899
	}
2900
	return $ipv6;
2901
}
2902

    
2903
/****f* pfsense-utils/load_mac_manufacturer_table
2904
 * NAME
2905
 *   load_mac_manufacturer_table
2906
 * INPUTS
2907
 *   none
2908
 * RESULT
2909
 *   returns associative array with MAC-Manufacturer pairs
2910
 ******/
2911
function load_mac_manufacturer_table() {
2912
	/* load MAC-Manufacture data from the file */
2913
	$macs = false;
2914
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2915
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2916
	}
2917
	if ($macs) {
2918
		foreach ($macs as $line) {
2919
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2920
				/* store values like this $mac_man['000C29']='VMware' */
2921
				$mac_man["$matches[1]"] = $matches[2];
2922
			}
2923
		}
2924
		return $mac_man;
2925
	} else {
2926
		return -1;
2927
	}
2928

    
2929
}
2930

    
2931
/****f* pfsense-utils/is_ipaddr_configured
2932
 * NAME
2933
 *   is_ipaddr_configured
2934
 * INPUTS
2935
 *   IP Address to check.
2936
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2937
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2938
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2939
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2940
 *     If check_subnets is true and cidrprefix is specified,
2941
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2942
 * RESULT
2943
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2944
*/
2945
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2946
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2947
		return true;
2948
	}
2949
	return false;
2950
}
2951

    
2952
/****f* pfsense-utils/where_is_ipaddr_configured
2953
 * NAME
2954
 *   where_is_ipaddr_configured
2955
 * INPUTS
2956
 *   IP Address to check.
2957
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2958
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2959
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2960
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2961
 *     If check_subnets is true and cidrprefix is specified,
2962
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2963
 * RESULT
2964
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2965
 *   If there are no matches then an empty array is returned.
2966
*/
2967
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2968
	global $config;
2969

    
2970
	$where_configured = array();
2971

    
2972
	$pos = strpos($ignore_if, '_virtualip');
2973
	if ($pos !== false) {
2974
		$ignore_vip_id = substr($ignore_if, $pos+10);
2975
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2976
	} else {
2977
		$ignore_vip_id = -1;
2978
		$ignore_vip_if = $ignore_if;
2979
	}
2980

    
2981
	$isipv6 = is_ipaddrv6($ipaddr);
2982

    
2983
	if ($check_subnets) {
2984
		$cidrprefix = intval($cidrprefix);
2985
		if ($isipv6) {
2986
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2987
				$cidrprefix = 128;
2988
			}
2989
		} else {
2990
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2991
				$cidrprefix = 32;
2992
			}
2993
		}
2994
		$iflist = get_configured_interface_list();
2995
		foreach ($iflist as $if => $ifname) {
2996
			if ($ignore_if == $if) {
2997
				continue;
2998
			}
2999

    
3000
			if ($isipv6) {
3001
				$if_ipv6 = get_interface_ipv6($if);
3002
				$if_snbitsv6 = get_interface_subnetv6($if);
3003
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
3004
					$where_entry = array();
3005
					$where_entry['if'] = $if;
3006
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
3007
					$where_configured[] = $where_entry;
3008
				}
3009
			} else {
3010
				$if_ipv4 = get_interface_ip($if);
3011
				$if_snbitsv4 = get_interface_subnet($if);
3012
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
3013
					$where_entry = array();
3014
					$where_entry['if'] = $if;
3015
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
3016
					$where_configured[] = $where_entry;
3017
				}
3018
			}
3019
		}
3020
	} else {
3021
		if ($isipv6) {
3022
			$interface_list_ips = get_configured_ipv6_addresses();
3023
		} else {
3024
			$interface_list_ips = get_configured_ip_addresses();
3025
		}
3026

    
3027
		foreach ($interface_list_ips as $if => $ilips) {
3028
			if ($ignore_if == $if) {
3029
				continue;
3030
			}
3031
			if (strcasecmp($ipaddr, $ilips) == 0) {
3032
				$where_entry = array();
3033
				$where_entry['if'] = $if;
3034
				$where_entry['ip_or_subnet'] = $ilips;
3035
				$where_configured[] = $where_entry;
3036
			}
3037
		}
3038
	}
3039

    
3040
	if ($check_localip) {
3041
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, $config['l2tp']['localip']) == 0)) {
3042
			$where_entry = array();
3043
			$where_entry['if'] = 'l2tp';
3044
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3045
			$where_configured[] = $where_entry;
3046
		}
3047
	}
3048

    
3049
	return $where_configured;
3050
}
3051

    
3052
/****f* pfsense-utils/pfSense_handle_custom_code
3053
 * NAME
3054
 *   pfSense_handle_custom_code
3055
 * INPUTS
3056
 *   directory name to process
3057
 * RESULT
3058
 *   globs the directory and includes the files
3059
 */
3060
function pfSense_handle_custom_code($src_dir) {
3061
	// Allow extending of the nat edit page and include custom input validation
3062
	if (is_dir("$src_dir")) {
3063
		$cf = glob($src_dir . "/*.inc");
3064
		foreach ($cf as $nf) {
3065
			if ($nf == "." || $nf == "..") {
3066
				continue;
3067
			}
3068
			// Include the extra handler
3069
			include_once("$nf");
3070
		}
3071
	}
3072
}
3073

    
3074
function set_language() {
3075
	global $config, $g;
3076

    
3077
	if (!empty($config['system']['language'])) {
3078
		$lang = $config['system']['language'];
3079
	} elseif (!empty($g['language'])) {
3080
		$lang = $g['language'];
3081
	}
3082
	$lang .= ".UTF-8";
3083

    
3084
	putenv("LANG={$lang}");
3085
	setlocale(LC_ALL, $lang);
3086
	textdomain("pfSense");
3087
	bindtextdomain("pfSense", "/usr/local/share/locale");
3088
	bind_textdomain_codeset("pfSense", $lang);
3089
}
3090

    
3091
function get_locale_list() {
3092
	$locales = array(
3093
		"en_US" => gettext("English"),
3094
		"pt_BR" => gettext("Portuguese (Brazil)"),
3095
		"tr" => gettext("Turkish"),
3096
	);
3097
	asort($locales);
3098
	return $locales;
3099
}
3100

    
3101
function return_hex_ipv4($ipv4) {
3102
	if (!is_ipaddrv4($ipv4)) {
3103
		return(false);
3104
	}
3105

    
3106
	/* we need the hex form of the interface IPv4 address */
3107
	$ip4arr = explode(".", $ipv4);
3108
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3109
}
3110

    
3111
function convert_ipv6_to_128bit($ipv6) {
3112
	if (!is_ipaddrv6($ipv6)) {
3113
		return(false);
3114
	}
3115

    
3116
	$ip6arr = array();
3117
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3118
	$ip6arr = explode(":", $ip6prefix);
3119
	/* binary presentation of the prefix for all 128 bits. */
3120
	$ip6prefixbin = "";
3121
	foreach ($ip6arr as $element) {
3122
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3123
	}
3124
	return($ip6prefixbin);
3125
}
3126

    
3127
function convert_128bit_to_ipv6($ip6bin) {
3128
	if (strlen($ip6bin) <> 128) {
3129
		return(false);
3130
	}
3131

    
3132
	$ip6arr = array();
3133
	$ip6binarr = array();
3134
	$ip6binarr = str_split($ip6bin, 16);
3135
	foreach ($ip6binarr as $binpart) {
3136
		$ip6arr[] = dechex(bindec($binpart));
3137
	}
3138
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3139

    
3140
	return($ip6addr);
3141
}
3142

    
3143

    
3144
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3145
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3146
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3147
/* 6to4 is 16 bits, e.g. 65535 */
3148
function calculate_ipv6_delegation_length($if) {
3149
	global $config;
3150

    
3151
	if (!is_array($config['interfaces'][$if])) {
3152
		return false;
3153
	}
3154

    
3155
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3156
		case "6to4":
3157
			$pdlen = 16;
3158
			break;
3159
		case "6rd":
3160
			$rd6cfg = $config['interfaces'][$if];
3161
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3162
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
3163
			break;
3164
		case "dhcp6":
3165
			$dhcp6cfg = $config['interfaces'][$if];
3166
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3167
			break;
3168
		default:
3169
			$pdlen = 0;
3170
			break;
3171
	}
3172
	return($pdlen);
3173
}
3174

    
3175
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3176
	$prefix = Net_IPv6::uncompress($prefix, true);
3177
	$suffix = Net_IPv6::uncompress($suffix, true);
3178

    
3179
	/*
3180
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3181
	 *                ^^^^ ^
3182
	 *                |||| \-> 64
3183
	 *                |||\---> 63, 62, 61, 60
3184
	 *                ||\----> 56
3185
	 *                |\-----> 52
3186
	 *                \------> 48
3187
	 */
3188

    
3189
	switch ($len) {
3190
	case 48:
3191
		$prefix_len = 15;
3192
		break;
3193
	case 52:
3194
		$prefix_len = 16;
3195
		break;
3196
	case 56:
3197
		$prefix_len = 17;
3198
		break;
3199
	case 59:
3200
	case 60:
3201
		$prefix_len = 18;
3202
		break;
3203
	/*
3204
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3205
	 * we let user chose this bit it can end up out of PD network
3206
	 *
3207
	 * Leave this with 20 for now until we find a way to let user
3208
	 * chose it. The side-effect is users with PD with one of these
3209
	 * lengths will not be able to setup DHCP server range for full
3210
	 * PD size, only for last /64 network
3211
	 */
3212
	case 63:
3213
	case 62:
3214
	case 61:
3215
	default:
3216
		$prefix_len = 20;
3217
		break;
3218
	}
3219

    
3220
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3221
	    substr($suffix, $prefix_len));
3222
}
3223

    
3224
function dhcpv6_pd_str_help($pdlen) {
3225
	$result = '';
3226

    
3227
	switch ($pdlen) {
3228
	case 48:
3229
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3230
		break;
3231
	case 52:
3232
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3233
		break;
3234
	case 56:
3235
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3236
		break;
3237
	case 59:
3238
	case 60:
3239
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3240
		break;
3241
	/*
3242
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3243
	 * we let the user choose this bit it can end up out of PD network
3244
	 *
3245
	 * Leave this with the same as 64 for now until we find a way to
3246
	 * let the user choose it. The side-effect is users with PD with one
3247
	 * of these lengths will not be able to setup DHCP server ranges
3248
	 * for full PD size, only for last /64 network
3249
	 */
3250
	case 61:
3251
	case 62:
3252
	case 63:
3253
	case 64:
3254
	default:
3255
		$result = '::xxxx:xxxx:xxxx:xxxx';
3256
		break;
3257
	}
3258

    
3259
	return $result;
3260
}
3261

    
3262
function huawei_rssi_to_string($rssi) {
3263
	$dbm = array();
3264
	$i = 0;
3265
	$dbstart = -113;
3266
	while ($i < 32) {
3267
		$dbm[$i] = $dbstart + ($i * 2);
3268
		$i++;
3269
	}
3270
	$percent = round(($rssi / 31) * 100);
3271
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3272
	return $string;
3273
}
3274

    
3275
function huawei_mode_to_string($mode, $submode) {
3276
	$modes[0] = gettext("None");
3277
	$modes[1] = "AMPS";
3278
	$modes[2] = "CDMA";
3279
	$modes[3] = "GSM/GPRS";
3280
	$modes[4] = "HDR";
3281
	$modes[5] = "WCDMA";
3282
	$modes[6] = "GPS";
3283

    
3284
	$submodes[0] = gettext("No Service");
3285
	$submodes[1] = "GSM";
3286
	$submodes[2] = "GPRS";
3287
	$submodes[3] = "EDGE";
3288
	$submodes[4] = "WCDMA";
3289
	$submodes[5] = "HSDPA";
3290
	$submodes[6] = "HSUPA";
3291
	$submodes[7] = "HSDPA+HSUPA";
3292
	$submodes[8] = "TD-SCDMA";
3293
	$submodes[9] = "HSPA+";
3294
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3295
	return $string;
3296
}
3297

    
3298
function huawei_service_to_string($state) {
3299
	$modes[0] = gettext("No Service");
3300
	$modes[1] = gettext("Restricted Service");
3301
	$modes[2] = gettext("Valid Service");
3302
	$modes[3] = gettext("Restricted Regional Service");
3303
	$modes[4] = gettext("Powersaving Service");
3304
	$string = $modes[$state];
3305
	return $string;
3306
}
3307

    
3308
function huawei_simstate_to_string($state) {
3309
	$modes[0] = gettext("Invalid SIM/locked State");
3310
	$modes[1] = gettext("Valid SIM State");
3311
	$modes[2] = gettext("Invalid SIM CS State");
3312
	$modes[3] = gettext("Invalid SIM PS State");
3313
	$modes[4] = gettext("Invalid SIM CS/PS State");
3314
	$modes[255] = gettext("Missing SIM State");
3315
	$string = $modes[$state];
3316
	return $string;
3317
}
3318

    
3319
function zte_rssi_to_string($rssi) {
3320
	return huawei_rssi_to_string($rssi);
3321
}
3322

    
3323
function zte_mode_to_string($mode, $submode) {
3324
	$modes[0] = gettext("No Service");
3325
	$modes[1] = gettext("Limited Service");
3326
	$modes[2] = "GPRS";
3327
	$modes[3] = "GSM";
3328
	$modes[4] = "UMTS";
3329
	$modes[5] = "EDGE";
3330
	$modes[6] = "HSDPA";
3331

    
3332
	$submodes[0] = "CS_ONLY";
3333
	$submodes[1] = "PS_ONLY";
3334
	$submodes[2] = "CS_PS";
3335
	$submodes[3] = "CAMPED";
3336
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3337
	return $string;
3338
}
3339

    
3340
function zte_service_to_string($service) {
3341
	$modes[0] = gettext("Initializing Service");
3342
	$modes[1] = gettext("Network Lock error Service");
3343
	$modes[2] = gettext("Network Locked Service");
3344
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3345
	$string = $modes[$service];
3346
	return $string;
3347
}
3348

    
3349
function zte_simstate_to_string($state) {
3350
	$modes[0] = gettext("No action State");
3351
	$modes[1] = gettext("Network lock State");
3352
	$modes[2] = gettext("(U)SIM card lock State");
3353
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3354
	$string = $modes[$state];
3355
	return $string;
3356
}
3357

    
3358
function get_configured_pppoe_server_interfaces() {
3359
	global $config;
3360
	$iflist = array();
3361
	if (is_array($config['pppoes']['pppoe'])) {
3362
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3363
			if ($pppoe['mode'] == "server") {
3364
				$int = "poes". $pppoe['pppoeid'];
3365
				$iflist[$int] = strtoupper($int);
3366
			}
3367
		}
3368
	}
3369
	return $iflist;
3370
}
3371

    
3372
function get_pppoes_child_interfaces($ifpattern) {
3373
	$if_arr = array();
3374
	if ($ifpattern == "") {
3375
		return;
3376
	}
3377

    
3378
	exec("/sbin/ifconfig", $out, $ret);
3379
	foreach ($out as $line) {
3380
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3381
			$if_arr[] = $match[1];
3382
		}
3383
	}
3384
	return $if_arr;
3385

    
3386
}
3387

    
3388
/****f* pfsense-utils/pkg_call_plugins
3389
 * NAME
3390
 *   pkg_call_plugins
3391
 * INPUTS
3392
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3393
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3394
 * RESULT
3395
 *   returns associative array results from the plugin calls for each package
3396
 * NOTES
3397
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3398
 ******/
3399
function pkg_call_plugins($plugin_type, $plugin_params) {
3400
	global $g, $config;
3401
	$results = array();
3402
	if (!is_array($config['installedpackages']['package'])) {
3403
		return $results;
3404
	}
3405
	foreach ($config['installedpackages']['package'] as $package) {
3406
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
3407
			continue;
3408
		}
3409
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
3410
		$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3411
		if (is_array($pkg_config['plugins']['item'])) {
3412
			foreach ($pkg_config['plugins']['item'] as $plugin) {
3413
				if ($plugin['type'] == $plugin_type) {
3414
					if (file_exists($pkg_config['include_file'])) {
3415
						require_once($pkg_config['include_file']);
3416
					} else {
3417
						continue;
3418
					}
3419
					$plugin_function = $pkgname . '_'. $plugin_type;
3420
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3421
				}
3422
			}
3423
		}
3424
	}
3425
	return $results;
3426
}
3427

    
3428
function restore_aliastables() {
3429
	global $g, $config;
3430

    
3431
	$dbpath = "{$g['vardb_path']}/aliastables/";
3432

    
3433
	/* restore the alias tables, if we have them */
3434
	$files = glob("{$g['cf_conf_path']}/RAM_Disk_Store{$dbpath}*.tgz");
3435
	if (count($files)) {
3436
		echo "Restoring alias tables...";
3437
		foreach ($files as $file) {
3438
			if (file_exists($file)) {
3439
				$aliastablesrestore = "";
3440
				$aliastablesreturn = "";
3441
				exec("cd /;LANG=C /usr/bin/tar -xzf {$file} 2>&1", $aliastablesrestore, $aliastablesreturn);
3442
				$aliastablesrestore = implode(" ", $aliastablesrestore);
3443
				if ($aliastablesreturn <> 0) {
3444
					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"));
3445
				} else {
3446
					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"));
3447
				}
3448
			}
3449
			/* 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. */
3450
			if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
3451
				unlink_if_exists("{$file}");
3452
			}
3453
		}
3454
		echo "done.\n";
3455
		return true;
3456
	}
3457
	return false;
3458
}
3459

    
3460
// Convert IPv6 addresses to lower case
3461
function addrtolower($ip) {
3462
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3463
		return(strtolower($ip));
3464
	} else {
3465
		return($ip);
3466
	}
3467
}
3468
?>
(39-39/65)