Project

General

Profile

Download (94.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * pfsense-utils.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Electric Sheep Fencing, LLC
7
 * All rights reserved.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions are met:
11
 *
12
 * 1. Redistributions of source code must retain the above copyright notice,
13
 *    this list of conditions and the following disclaimer.
14
 *
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in
17
 *    the documentation and/or other materials provided with the
18
 *    distribution.
19
 *
20
 * 3. All advertising materials mentioning features or use of this software
21
 *    must display the following acknowledgment:
22
 *    "This product includes software developed by the pfSense Project
23
 *    for use in the pfSense® software distribution. (http://www.pfsense.org/).
24
 *
25
 * 4. The names "pfSense" and "pfSense Project" must not be used to
26
 *    endorse or promote products derived from this software without
27
 *    prior written permission. For written permission, please contact
28
 *    coreteam@pfsense.org.
29
 *
30
 * 5. Products derived from this software may not be called "pfSense"
31
 *    nor may "pfSense" appear in their names without prior written
32
 *    permission of the Electric Sheep Fencing, LLC.
33
 *
34
 * 6. Redistributions of any form whatsoever must retain the following
35
 *    acknowledgment:
36
 *
37
 * "This product includes software developed by the pfSense Project
38
 * for use in the pfSense software distribution (http://www.pfsense.org/).
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
41
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
44
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51
 * OF THE POSSIBILITY OF SUCH DAMAGE.
52
 */
53

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

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

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

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

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

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

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

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

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

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

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

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

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

    
214
	$csslist = get_css_files();
215

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
502
	return false;
503
}
504

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

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

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

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

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

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

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

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

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

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

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

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

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

    
658
	$carpiface = get_configured_vip_interface($carpid);
659
	if ($carpiface == NULL)
660
		return "";
661
	$interface = get_real_interface($carpiface);
662
	if ($interface == NULL)
663
		return "";
664
	$vip = get_configured_vip($carpid);
665
	if ($vip == NULL || !isset($vip['vhid']))
666
		return "";
667

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

    
680
	return "";
681
}
682

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

    
691
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
692
}
693

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

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

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

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

    
739
/*
740
 *   get_dir: return an array of $dir
741
 */
742
function get_dir($dir) {
743
	$dir_array = array();
744
	$d = dir($dir);
745
	if (!is_object($d)) {
746
		return array();
747
	}
748
	while (false !== ($entry = $d->read())) {
749
		array_push($dir_array, $entry);
750
	}
751
	$d->close();
752
	return $dir_array;
753
}
754

    
755
/****f* pfsense-utils/WakeOnLan
756
 * NAME
757
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
758
 * RESULT
759
 *   true/false - true if the operation was successful
760
 ******/
761
function WakeOnLan($addr, $mac) {
762
	$addr_byte = explode(':', $mac);
763
	$hw_addr = '';
764

    
765
	for ($a = 0; $a < 6; $a++) {
766
		$hw_addr .= chr(hexdec($addr_byte[$a]));
767
	}
768

    
769
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
770

    
771
	for ($a = 1; $a <= 16; $a++) {
772
		$msg .= $hw_addr;
773
	}
774

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

    
792
	return false;
793
}
794

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

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

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

    
831
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
832
	if ($xml['pfsense']) {
833
		$xml = $xml['pfsense'];
834
	}
835
	else if ($xml['m0n0wall']) {
836
		$xml = $xml['m0n0wall'];
837
	}
838
	if ($xml[$section_name]) {
839
		$section_xml = $xml[$section_name];
840
	} else {
841
		$section_xml = -1;
842
	}
843

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

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

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

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

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

    
958
/*
959
 * host_firmware_version(): Return the versions used in this install
960
 */
961
function host_firmware_version($tocheck = "") {
962
	global $g, $config;
963

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

    
966
	return array(
967
		"firmware" => array("version" => $g['product_version']),
968
		"kernel"   => array("version" => $os_version),
969
		"base"     => array("version" => $os_version),
970
		"platform" => trim(file_get_contents('/etc/platform', " \n")),
971
		"config_version" => $config['version']
972
	);
973
}
974

    
975
function get_disk_info() {
976
	$diskout = "";
977
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
978
	return explode(' ', $diskout[0]);
979
}
980

    
981
/****f* pfsense-utils/strncpy
982
 * NAME
983
 *   strncpy - copy strings
984
 * INPUTS
985
 *   &$dst, $src, $length
986
 * RESULT
987
 *   none
988
 ******/
989
function strncpy(&$dst, $src, $length) {
990
	if (strlen($src) > $length) {
991
		$dst = substr($src, 0, $length);
992
	} else {
993
		$dst = $src;
994
	}
995
}
996

    
997
/****f* pfsense-utils/reload_interfaces_sync
998
 * NAME
999
 *   reload_interfaces - reload all interfaces
1000
 * INPUTS
1001
 *   none
1002
 * RESULT
1003
 *   none
1004
 ******/
1005
function reload_interfaces_sync() {
1006
	global $config, $g;
1007

    
1008
	if ($g['debug']) {
1009
		log_error(gettext("reload_interfaces_sync() is starting."));
1010
	}
1011

    
1012
	/* parse config.xml again */
1013
	$config = parse_config(true);
1014

    
1015
	/* enable routing */
1016
	system_routing_enable();
1017
	if ($g['debug']) {
1018
		log_error(gettext("Enabling system routing"));
1019
	}
1020

    
1021
	if ($g['debug']) {
1022
		log_error(gettext("Cleaning up Interfaces"));
1023
	}
1024

    
1025
	/* set up interfaces */
1026
	interfaces_configure();
1027
}
1028

    
1029
/****f* pfsense-utils/reload_all
1030
 * NAME
1031
 *   reload_all - triggers a reload of all settings
1032
 *   * INPUTS
1033
 *   none
1034
 * RESULT
1035
 *   none
1036
 ******/
1037
function reload_all() {
1038
	send_event("service reload all");
1039
}
1040

    
1041
/****f* pfsense-utils/reload_interfaces
1042
 * NAME
1043
 *   reload_interfaces - triggers a reload of all interfaces
1044
 * INPUTS
1045
 *   none
1046
 * RESULT
1047
 *   none
1048
 ******/
1049
function reload_interfaces() {
1050
	send_event("interface all reload");
1051
}
1052

    
1053
/****f* pfsense-utils/reload_all_sync
1054
 * NAME
1055
 *   reload_all - reload all settings
1056
 *   * INPUTS
1057
 *   none
1058
 * RESULT
1059
 *   none
1060
 ******/
1061
function reload_all_sync() {
1062
	global $config, $g;
1063

    
1064
	/* parse config.xml again */
1065
	$config = parse_config(true);
1066

    
1067
	/* set up our timezone */
1068
	system_timezone_configure();
1069

    
1070
	/* set up our hostname */
1071
	system_hostname_configure();
1072

    
1073
	/* make hosts file */
1074
	system_hosts_generate();
1075

    
1076
	/* generate resolv.conf */
1077
	system_resolvconf_generate();
1078

    
1079
	/* enable routing */
1080
	system_routing_enable();
1081

    
1082
	/* set up interfaces */
1083
	interfaces_configure();
1084

    
1085
	/* start dyndns service */
1086
	services_dyndns_configure();
1087

    
1088
	/* configure cron service */
1089
	configure_cron();
1090

    
1091
	/* start the NTP client */
1092
	system_ntp_configure();
1093

    
1094
	/* sync pw database */
1095
	conf_mount_rw();
1096
	unlink_if_exists("/etc/spwd.db.tmp");
1097
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1098
	conf_mount_ro();
1099

    
1100
	/* restart sshd */
1101
	send_event("service restart sshd");
1102

    
1103
	/* restart webConfigurator if needed */
1104
	send_event("service restart webgui");
1105
}
1106

    
1107
function setup_serial_port($when = "save", $path = "") {
1108
	global $g, $config;
1109
	conf_mount_rw();
1110
	$ttys_file = "{$path}/etc/ttys";
1111
	$boot_config_file = "{$path}/boot.config";
1112
	$loader_conf_file = "{$path}/boot/loader.conf";
1113
	/* serial console - write out /boot.config */
1114
	if (file_exists($boot_config_file)) {
1115
		$boot_config = file_get_contents($boot_config_file);
1116
	} else {
1117
		$boot_config = "";
1118
	}
1119

    
1120
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1121
	if ($g['platform'] != "cdrom") {
1122
		$serial_only = false;
1123

    
1124
		if (($g['platform'] == "nanobsd") && isset($g['enableserial_force'])) {
1125
			$serial_only = true;
1126
		} else {
1127
			$specific_platform = system_identify_specific_platform();
1128
			if ($specific_platform['name'] == 'RCC-VE' ||
1129
			    $specific_platform['name'] == 'RCC' ||
1130
			    $specific_platform['name'] == 'RCC-DFF') {
1131
				$serial_only = true;
1132
			}
1133
		}
1134

    
1135
		$boot_config_split = explode("\n", $boot_config);
1136
		$data = array();
1137
		foreach ($boot_config_split as $bcs) {
1138
			/* Ignore -D and -h lines now */
1139
			if (!empty($bcs) && !stristr($bcs, "-D") &&
1140
			    !stristr($bcs, "-h")) {
1141
				$data[] = $bcs;
1142
			}
1143
		}
1144
		if ($serial_only === true) {
1145
			$data[] = "-S{$serialspeed} -h";
1146
		} elseif (is_serial_enabled()) {
1147
			$data[] = "-S{$serialspeed} -D";
1148
		}
1149

    
1150
		if (empty($data)) {
1151
			@unlink($boot_conf_file);
1152
		} else {
1153
			safe_write_file($boot_config_file, $data);
1154
		}
1155

    
1156
		unset($boot_config, $boot_config_file, $boot_config_split);
1157

    
1158
		/* serial console - write out /boot/loader.conf */
1159
		if ($when == "upgrade") {
1160
			system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1161
		}
1162

    
1163
		$loader_conf = file_get_contents($loader_conf_file);
1164
		$loader_conf_split = explode("\n", $loader_conf);
1165

    
1166
		$data = array();
1167
		// Loop through and only add lines that are not empty, and which
1168
		//  do not contain a console directive.
1169
		foreach ($loader_conf_split as $bcs) {
1170
			if (!empty($bcs) &&
1171
			    (stripos($bcs, "console") === false) &&
1172
			    (stripos($bcs, "boot_multicons") === false) &&
1173
			    (stripos($bcs, "boot_serial") === false) &&
1174
			    (stripos($bcs, "hw.usb.no_pf") === false) &&
1175
			    (stripos($bcs, "hint.uart.0.flags") === false) &&
1176
			    (stripos($bcs, "hint.uart.1.flags") === false)) {
1177
				$data[] = $bcs;
1178
			}
1179
		}
1180

    
1181
		if ($serial_only === true) {
1182
			$data[] = 'boot_serial="YES"';
1183
			$data[] = 'console="comconsole"';
1184
		} else if (is_serial_enabled()) {
1185
			$data[] = 'boot_multicons="YES"';
1186
			$data[] = 'boot_serial="YES"';
1187
			$primaryconsole = isset($g['primaryconsole_force']) ?
1188
			    $g['primaryconsole_force'] :
1189
			    $config['system']['primaryconsole'];
1190
			switch ($primaryconsole) {
1191
				case "video":
1192
					$data[] = 'console="vidconsole,comconsole"';
1193
					break;
1194
				case "serial":
1195
				default:
1196
					$data[] = 'console="comconsole,vidconsole"';
1197
			}
1198
		}
1199
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1200

    
1201
		$specplatform = system_identify_specific_platform();
1202
		if ($specplatform['name'] == 'RCC-VE' ||
1203
		    $specplatform['name'] == 'RCC' ||
1204
		    $specplatform['name'] == 'RCC-DFF') {
1205
			$data[] = 'comconsole_port="0x2F8"';
1206
			$data[] = 'hint.uart.0.flags="0x00"';
1207
			$data[] = 'hint.uart.1.flags="0x10"';
1208
		}
1209
		$data[] = 'hw.usb.no_pf="1"';
1210

    
1211
		safe_write_file($loader_conf_file, $data);
1212

    
1213
		unset($loader_conf, $loader_conf_split, $loader_config_file);
1214
	}
1215

    
1216
	$ttys = file_get_contents($ttys_file);
1217
	$ttys_split = explode("\n", $ttys);
1218

    
1219
	$data = array();
1220

    
1221
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1222

    
1223
	if (isset($config['system']['disableconsolemenu'])) {
1224
		$console_type = 'Pc';
1225
		$serial_type = 'std.' . $serialspeed;
1226
	} else {
1227
		$console_type = 'al.Pc';
1228
		$serial_type = 'al.' . $serialspeed;
1229
	}
1230

    
1231
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1232
	$ttyv0_line =
1233
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\tcons25\ton\tsecure";
1234
	$ttyu_line =
1235
	    "\"/usr/libexec/getty {$serial_type}\"\tcons25\t{$on_off}\tsecure";
1236

    
1237
	$found = array();
1238

    
1239
	foreach ($ttys_split as $tty) {
1240
		/* Ignore blank lines */
1241
		if (empty($tty)) {
1242
			continue;
1243
		}
1244

    
1245
		if (stristr($tty, "ttyv0")) {
1246
			$found['ttyv0'] = 1;
1247
			$data[] = $ttyv0_line;
1248
		} elseif (stristr($tty, "ttyu")) {
1249
			$ttyn = substr($tty, 0, 5);
1250
			$found[$ttyn] = 1;
1251
			$data[] = "{$ttyn}\t{$ttyu_line}";
1252
		} elseif (substr($tty, 0, 7) == 'console') {
1253
			$found['console'] = 1;
1254
			$data[] = $tty;
1255
		} else {
1256
			$data[] = $tty;
1257
		}
1258
	}
1259
	unset($on_off, $console_type, $serial_type);
1260

    
1261
	/* Detect missing main lines on original file and try to rebuild it */
1262
	$items = array(
1263
		'console',
1264
		'ttyv0',
1265
		'ttyu0',
1266
		'ttyu1',
1267
		'ttyu2',
1268
		'ttyu3'
1269
	);
1270

    
1271
	foreach ($items as $item) {
1272
		if (isset($found[$item])) {
1273
			continue;
1274
		}
1275

    
1276
		if ($item == 'console') {
1277
			$data[] = $console_line;
1278
		} elseif ($item == 'ttyv0') {
1279
			$data[] = $ttyv0_line;
1280
		} else {
1281
			$data[] = "{$item}\t{$ttyu_line}";
1282
		}
1283
	}
1284

    
1285
	safe_write_file($ttys_file, $data);
1286

    
1287
	unset($ttys, $ttys_file, $ttys_split, $data);
1288

    
1289
	if ($when != "upgrade") {
1290
		reload_ttys();
1291
	}
1292

    
1293
	conf_mount_ro();
1294
	return;
1295
}
1296

    
1297
function is_serial_enabled() {
1298
	global $g, $config;
1299

    
1300
	if (!isset($g['enableserial_force']) &&
1301
	    !isset($config['system']['enableserial']) &&
1302
	    ($g['platform'] == $g['product_name'] || $g['platform'] == "cdrom")) {
1303
		return false;
1304
	}
1305

    
1306
	return true;
1307
}
1308

    
1309
function reload_ttys() {
1310
	// Send a HUP signal to init will make it reload /etc/ttys
1311
	posix_kill(1, SIGHUP);
1312
}
1313

    
1314
function print_value_list($list, $count = 10, $separator = ",") {
1315
	$list = implode($separator, array_slice($list, 0, $count));
1316
	if (count($list) < $count) {
1317
		$list .= ".";
1318
	} else {
1319
		$list .= "...";
1320
	}
1321
	return $list;
1322
}
1323

    
1324
/* DHCP enabled on any interfaces? */
1325
function is_dhcp_server_enabled() {
1326
	global $config;
1327

    
1328
	if (!is_array($config['dhcpd'])) {
1329
		return false;
1330
	}
1331

    
1332
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1333
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1334
			return true;
1335
		}
1336
	}
1337

    
1338
	return false;
1339
}
1340

    
1341
/* DHCP enabled on any interfaces? */
1342
function is_dhcpv6_server_enabled() {
1343
	global $config;
1344

    
1345
	if (is_array($config['interfaces'])) {
1346
		foreach ($config['interfaces'] as $ifcfg) {
1347
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1348
				return true;
1349
			}
1350
		}
1351
	}
1352

    
1353
	if (!is_array($config['dhcpdv6'])) {
1354
		return false;
1355
	}
1356

    
1357
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1358
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1359
			return true;
1360
		}
1361
	}
1362

    
1363
	return false;
1364
}
1365

    
1366
/* radvd enabled on any interfaces? */
1367
function is_radvd_enabled() {
1368
	global $config;
1369

    
1370
	if (!is_array($config['dhcpdv6'])) {
1371
		$config['dhcpdv6'] = array();
1372
	}
1373

    
1374
	$dhcpdv6cfg = $config['dhcpdv6'];
1375
	$Iflist = get_configured_interface_list();
1376

    
1377
	/* handle manually configured DHCP6 server settings first */
1378
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1379
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1380
			continue;
1381
		}
1382

    
1383
		if (!isset($dhcpv6ifconf['ramode'])) {
1384
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1385
		}
1386

    
1387
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1388
			continue;
1389
		}
1390

    
1391
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1392
		if (!is_ipaddrv6($ifcfgipv6)) {
1393
			continue;
1394
		}
1395

    
1396
		return true;
1397
	}
1398

    
1399
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1400
	foreach ($Iflist as $if => $ifdescr) {
1401
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1402
			continue;
1403
		}
1404
		if (!isset($config['interfaces'][$if]['enable'])) {
1405
			continue;
1406
		}
1407

    
1408
		$ifcfgipv6 = get_interface_ipv6($if);
1409
		if (!is_ipaddrv6($ifcfgipv6)) {
1410
			continue;
1411
		}
1412

    
1413
		$ifcfgsnv6 = get_interface_subnetv6($if);
1414
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1415

    
1416
		if (!is_ipaddrv6($subnetv6)) {
1417
			continue;
1418
		}
1419

    
1420
		return true;
1421
	}
1422

    
1423
	return false;
1424
}
1425

    
1426
/* Any PPPoE servers enabled? */
1427
function is_pppoe_server_enabled() {
1428
	global $config;
1429

    
1430
	$pppoeenable = false;
1431

    
1432
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1433
		return false;
1434
	}
1435

    
1436
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1437
		if ($pppoes['mode'] == 'server') {
1438
			$pppoeenable = true;
1439
		}
1440
	}
1441

    
1442
	return $pppoeenable;
1443
}
1444

    
1445
/* Optional arg forces hh:mm:ss without days */
1446
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1447
	if (!is_numericint($sec)) {
1448
		return '-';
1449
	}
1450
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1451
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1452
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1453
					(int)(($sec % 3600)/60),
1454
					$sec % 60
1455
				);
1456
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1457
}
1458

    
1459
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1460

    
1461
function get_ppp_uptime($port) {
1462
	if (file_exists("/conf/{$port}.log")) {
1463
		$saved_time = file_get_contents("/conf/{$port}.log");
1464
		$uptime_data = explode("\n", $saved_time);
1465
		$sec = 0;
1466
		foreach ($uptime_data as $upt) {
1467
			$sec += substr($upt, 1 + strpos($upt, " "));
1468
		}
1469
		return convert_seconds_to_dhms($sec);
1470
	} else {
1471
		$total_time = gettext("No history data found!");
1472
		return $total_time;
1473
	}
1474
}
1475

    
1476
//returns interface information
1477
function get_interface_info($ifdescr) {
1478
	global $config, $g;
1479

    
1480
	$ifinfo = array();
1481
	if (empty($config['interfaces'][$ifdescr])) {
1482
		return;
1483
	}
1484
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1485
	$ifinfo['if'] = get_real_interface($ifdescr);
1486

    
1487
	$chkif = $ifinfo['if'];
1488
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1489
	$ifinfo['status'] = $ifinfotmp['status'];
1490
	if (empty($ifinfo['status'])) {
1491
		$ifinfo['status'] = "down";
1492
	}
1493
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1494
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1495
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1496
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1497
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1498
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1499
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1500
	if (isset($ifinfotmp['link0'])) {
1501
		$link0 = "down";
1502
	}
1503
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1504
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1505
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1506
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1507
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1508
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1509

    
1510
	/* Use pfctl for non wrapping 64 bit counters */
1511
	/* Pass */
1512
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1513
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1514
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1515
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1516
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1517
	$in4_pass = $pf_in4_pass[5];
1518
	$out4_pass = $pf_out4_pass[5];
1519
	$in4_pass_packets = $pf_in4_pass[3];
1520
	$out4_pass_packets = $pf_out4_pass[3];
1521
	$in6_pass = $pf_in6_pass[5];
1522
	$out6_pass = $pf_out6_pass[5];
1523
	$in6_pass_packets = $pf_in6_pass[3];
1524
	$out6_pass_packets = $pf_out6_pass[3];
1525
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1526
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1527
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1528
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1529

    
1530
	/* Block */
1531
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1532
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1533
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1534
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1535
	$in4_block = $pf_in4_block[5];
1536
	$out4_block = $pf_out4_block[5];
1537
	$in4_block_packets = $pf_in4_block[3];
1538
	$out4_block_packets = $pf_out4_block[3];
1539
	$in6_block = $pf_in6_block[5];
1540
	$out6_block = $pf_out6_block[5];
1541
	$in6_block_packets = $pf_in6_block[3];
1542
	$out6_block_packets = $pf_out6_block[3];
1543
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1544
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1545
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1546
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1547

    
1548
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1549
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1550
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1551
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1552

    
1553
	$ifconfiginfo = "";
1554
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1555
	switch ($link_type) {
1556
		/* DHCP? -> see if dhclient is up */
1557
		case "dhcp":
1558
			/* see if dhclient is up */
1559
			if (find_dhclient_process($ifinfo['if']) != 0) {
1560
				$ifinfo['dhcplink'] = "up";
1561
			} else {
1562
				$ifinfo['dhcplink'] = "down";
1563
			}
1564

    
1565
			break;
1566
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1567
		case "pppoe":
1568
		case "pptp":
1569
		case "l2tp":
1570
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1571
				/* get PPPoE link status for dial on demand */
1572
				$ifinfo["{$link_type}link"] = "up";
1573
			} else {
1574
				$ifinfo["{$link_type}link"] = "down";
1575
			}
1576

    
1577
			break;
1578
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1579
		case "ppp":
1580
			if ($ifinfo['status'] == "up") {
1581
				$ifinfo['ppplink'] = "up";
1582
			} else {
1583
				$ifinfo['ppplink'] = "down" ;
1584
			}
1585

    
1586
			if (empty($ifinfo['status'])) {
1587
				$ifinfo['status'] = "down";
1588
			}
1589

    
1590
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1591
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1592
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1593
						break;
1594
					}
1595
				}
1596
			}
1597
			$dev = $ppp['ports'];
1598
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1599
				break;
1600
			}
1601
			if (!file_exists($dev)) {
1602
				$ifinfo['nodevice'] = 1;
1603
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1604
			}
1605

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

    
1641
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1642
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1643
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1644
	}
1645

    
1646
	if ($ifinfo['status'] == "up") {
1647
		/* try to determine media with ifconfig */
1648
		unset($ifconfiginfo);
1649
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1650
		$wifconfiginfo = array();
1651
		if (is_interface_wireless($ifdescr)) {
1652
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1653
			array_shift($wifconfiginfo);
1654
		}
1655
		$matches = "";
1656
		foreach ($ifconfiginfo as $ici) {
1657

    
1658
			/* don't list media/speed for wireless cards, as it always
1659
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1660
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1661
				$ifinfo['media'] = $matches[1];
1662
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1663
				$ifinfo['media'] = $matches[1];
1664
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1665
				$ifinfo['media'] = $matches[1];
1666
			}
1667

    
1668
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1669
				if ($matches[1] != "active") {
1670
					$ifinfo['status'] = $matches[1];
1671
				}
1672
				if ($ifinfo['status'] == gettext("running")) {
1673
					$ifinfo['status'] = gettext("up");
1674
				}
1675
			}
1676
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1677
				$ifinfo['channel'] = $matches[1];
1678
			}
1679
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1680
				if ($matches[1][0] == '"') {
1681
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1682
				}
1683
				else {
1684
					$ifinfo['ssid'] = $matches[1];
1685
				}
1686
			}
1687
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1688
				$ifinfo['laggproto'] = $matches[1];
1689
			}
1690
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1691
				$ifinfo['laggport'][] = $matches[1];
1692
			}
1693
		}
1694
		foreach ($wifconfiginfo as $ici) {
1695
			$elements = preg_split("/[ ]+/i", $ici);
1696
			if ($elements[0] != "") {
1697
				$ifinfo['bssid'] = $elements[0];
1698
			}
1699
			if ($elements[3] != "") {
1700
				$ifinfo['rate'] = $elements[3];
1701
			}
1702
			if ($elements[4] != "") {
1703
				$ifinfo['rssi'] = $elements[4];
1704
			}
1705
		}
1706
		/* lookup the gateway */
1707
		if (interface_has_gateway($ifdescr)) {
1708
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1709
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1710
		}
1711
	}
1712

    
1713
	$bridge = "";
1714
	$bridge = link_interface_to_bridge($ifdescr);
1715
	if ($bridge) {
1716
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1717
		if (stristr($bridge_text, "blocking") <> false) {
1718
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1719
			$ifinfo['bridgeint'] = $bridge;
1720
		} else if (stristr($bridge_text, "learning") <> false) {
1721
			$ifinfo['bridge'] = gettext("learning");
1722
			$ifinfo['bridgeint'] = $bridge;
1723
		} else if (stristr($bridge_text, "forwarding") <> false) {
1724
			$ifinfo['bridge'] = gettext("forwarding");
1725
			$ifinfo['bridgeint'] = $bridge;
1726
		}
1727
	}
1728

    
1729
	return $ifinfo;
1730
}
1731

    
1732
//returns cpu speed of processor. Good for determining capabilities of machine
1733
function get_cpu_speed() {
1734
	return get_single_sysctl("hw.clockrate");
1735
}
1736

    
1737
function get_uptime_sec() {
1738
	$boottime = "";
1739
	$matches = "";
1740
	$boottime = get_single_sysctl("kern.boottime");
1741
	preg_match("/sec = (\d+)/", $boottime, $matches);
1742
	$boottime = $matches[1];
1743
	if (intval($boottime) == 0) {
1744
		return 0;
1745
	}
1746

    
1747
	$uptime = time() - $boottime;
1748
	return $uptime;
1749
}
1750

    
1751
function add_hostname_to_watch($hostname) {
1752
	if (!is_dir("/var/db/dnscache")) {
1753
		mkdir("/var/db/dnscache");
1754
	}
1755
	$result = array();
1756
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1757
		$domrecords = array();
1758
		$domips = array();
1759
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1760
		if ($rethost == 0) {
1761
			foreach ($domrecords as $domr) {
1762
				$doml = explode(" ", $domr);
1763
				$domip = $doml[3];
1764
				/* fill array with domain ip addresses */
1765
				if (is_ipaddr($domip)) {
1766
					$domips[] = $domip;
1767
				}
1768
			}
1769
		}
1770
		sort($domips);
1771
		$contents = "";
1772
		if (!empty($domips)) {
1773
			foreach ($domips as $ip) {
1774
				$contents .= "$ip\n";
1775
			}
1776
		}
1777
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1778
		/* Remove empty elements */
1779
		$result = array_filter(explode("\n", $contents), 'strlen');
1780
	}
1781
	return $result;
1782
}
1783

    
1784
function is_fqdn($fqdn) {
1785
	$hostname = false;
1786
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1787
		$hostname = true;
1788
	}
1789
	if (preg_match("/\.\./", $fqdn)) {
1790
		$hostname = false;
1791
	}
1792
	if (preg_match("/^\./i", $fqdn)) {
1793
		$hostname = false;
1794
	}
1795
	if (preg_match("/\//i", $fqdn)) {
1796
		$hostname = false;
1797
	}
1798
	return($hostname);
1799
}
1800

    
1801
function pfsense_default_state_size() {
1802
	/* get system memory amount */
1803
	$memory = get_memory();
1804
	$physmem = $memory[0];
1805
	/* Be cautious and only allocate 10% of system memory to the state table */
1806
	$max_states = (int) ($physmem/10)*1000;
1807
	return $max_states;
1808
}
1809

    
1810
function pfsense_default_tables_size() {
1811
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1812
	return $current;
1813
}
1814

    
1815
function pfsense_default_table_entries_size() {
1816
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1817
	return (trim($current));
1818
}
1819

    
1820
/* Compare the current hostname DNS to the DNS cache we made
1821
 * if it has changed we return the old records
1822
 * if no change we return false */
1823
function compare_hostname_to_dnscache($hostname) {
1824
	if (!is_dir("/var/db/dnscache")) {
1825
		mkdir("/var/db/dnscache");
1826
	}
1827
	$hostname = trim($hostname);
1828
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1829
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1830
	} else {
1831
		$oldcontents = "";
1832
	}
1833
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1834
		$domrecords = array();
1835
		$domips = array();
1836
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1837
		if ($rethost == 0) {
1838
			foreach ($domrecords as $domr) {
1839
				$doml = explode(" ", $domr);
1840
				$domip = $doml[3];
1841
				/* fill array with domain ip addresses */
1842
				if (is_ipaddr($domip)) {
1843
					$domips[] = $domip;
1844
				}
1845
			}
1846
		}
1847
		sort($domips);
1848
		$contents = "";
1849
		if (!empty($domips)) {
1850
			foreach ($domips as $ip) {
1851
				$contents .= "$ip\n";
1852
			}
1853
		}
1854
	}
1855

    
1856
	if (trim($oldcontents) != trim($contents)) {
1857
		if ($g['debug']) {
1858
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1859
		}
1860
		return ($oldcontents);
1861
	} else {
1862
		return false;
1863
	}
1864
}
1865

    
1866
/*
1867
 * load_crypto() - Load crypto modules if enabled in config.
1868
 */
1869
function load_crypto() {
1870
	global $config, $g;
1871
	$crypto_modules = array('glxsb', 'aesni');
1872

    
1873
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1874
		return false;
1875
	}
1876

    
1877
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1878
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1879
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1880
	}
1881
}
1882

    
1883
/*
1884
 * load_thermal_hardware() - Load temperature monitor kernel module
1885
 */
1886
function load_thermal_hardware() {
1887
	global $config, $g;
1888
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1889

    
1890
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1891
		return false;
1892
	}
1893

    
1894
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1895
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1896
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1897
	}
1898
}
1899

    
1900
/****f* pfsense-utils/isvm
1901
 * NAME
1902
 *   isvm
1903
 * INPUTS
1904
 *	none
1905
 * RESULT
1906
 *   returns true if machine is running under a virtual environment
1907
 ******/
1908
function isvm() {
1909
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1910
	$_gb = exec('/bin/kenv smbios.system.product 2>/dev/null', $output, $rc);
1911

    
1912
	if ($rc != 0 || !isset($output[0])) {
1913
		return false;
1914
	}
1915

    
1916
	foreach ($virtualenvs as $virtualenv) {
1917
		if (stripos($output[0], $virtualenv) !== false) {
1918
			return true;
1919
		}
1920
	}
1921

    
1922
	return false;
1923
}
1924

    
1925
function get_freebsd_version() {
1926
	$version = explode(".", php_uname("r"));
1927
	return $version[0];
1928
}
1929

    
1930
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1931
	global $config, $g;
1932

    
1933
	$fp = fopen($destination, "wb");
1934

    
1935
	if (!$fp) {
1936
		return false;
1937
	}
1938

    
1939
	$ch = curl_init();
1940
	curl_setopt($ch, CURLOPT_URL, $url);
1941
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1942
	curl_setopt($ch, CURLOPT_FILE, $fp);
1943
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1944
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1945
	curl_setopt($ch, CURLOPT_HEADER, false);
1946
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1947
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1948
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1949
	} else {
1950
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1951
	}
1952

    
1953
	if (!empty($config['system']['proxyurl'])) {
1954
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1955
		if (!empty($config['system']['proxyport'])) {
1956
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1957
		}
1958
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1959
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1960
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1961
		}
1962
	}
1963

    
1964
	@curl_exec($ch);
1965
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1966
	fclose($fp);
1967
	curl_close($ch);
1968
	if ($http_code == 200) {
1969
		return true;
1970
	} else {
1971
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1972
		unlink_if_exists($destination);
1973
		return false;
1974
	}
1975
}
1976

    
1977
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1978
	global $config, $g;
1979
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1980
	$file_size = 1;
1981
	$downloaded = 1;
1982
	$first_progress_update = TRUE;
1983
	/* open destination file */
1984
	$fout = fopen($destination, "wb");
1985

    
1986
	if (!$fout) {
1987
		return false;
1988
	}
1989
	/*
1990
	 *      Originally by Author: Keyvan Minoukadeh
1991
	 *      Modified by Scott Ullrich to return Content-Length size
1992
	 */
1993
	$ch = curl_init();
1994
	curl_setopt($ch, CURLOPT_URL, $url);
1995
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1996
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
1997
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1998
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
1999
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
2000
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2001
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2002
	if (!isset($config['system']['do_not_send_host_uuid'])) {
2003
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
2004
	} else {
2005
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2006
	}
2007

    
2008
	if (!empty($config['system']['proxyurl'])) {
2009
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2010
		if (!empty($config['system']['proxyport'])) {
2011
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2012
		}
2013
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2014
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2015
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2016
		}
2017
	}
2018

    
2019
	@curl_exec($ch);
2020
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2021
	fclose($fout);
2022
	curl_close($ch);
2023
	if ($http_code == 200) {
2024
		return true;
2025
	} else {
2026
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2027
		unlink_if_exists($destination);
2028
		return false;
2029
	}
2030
}
2031

    
2032
function read_header($ch, $string) {
2033
	global $file_size, $fout;
2034
	$length = strlen($string);
2035
	$regs = "";
2036
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2037
	if ($regs[2] <> "") {
2038
		$file_size = intval($regs[2]);
2039
	}
2040
	ob_flush();
2041
	return $length;
2042
}
2043

    
2044
function read_body($ch, $string) {
2045
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2046
	global $pkg_interface;
2047
	$length = strlen($string);
2048
	$downloaded += intval($length);
2049
	if ($file_size > 0) {
2050
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2051
		$downloadProgress = 100 - $downloadProgress;
2052
	} else {
2053
		$downloadProgress = 0;
2054
	}
2055
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2056
		if ($sendto == "status") {
2057
			if ($pkg_interface == "console") {
2058
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2059
					$tostatus = $static_status . $downloadProgress . "%";
2060
					if ($downloadProgress == 100) {
2061
						$tostatus = $tostatus . "\r";
2062
					}
2063
					update_status($tostatus);
2064
				}
2065
			} else {
2066
				$tostatus = $static_status . $downloadProgress . "%";
2067
				update_status($tostatus);
2068
			}
2069
		} else {
2070
			if ($pkg_interface == "console") {
2071
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2072
					$tooutput = $static_output . $downloadProgress . "%";
2073
					if ($downloadProgress == 100) {
2074
						$tooutput = $tooutput . "\r";
2075
					}
2076
					update_output_window($tooutput);
2077
				}
2078
			} else {
2079
				$tooutput = $static_output . $downloadProgress . "%";
2080
				update_output_window($tooutput);
2081
			}
2082
		}
2083
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2084
			update_progress_bar($downloadProgress, $first_progress_update);
2085
			$first_progress_update = FALSE;
2086
		}
2087
		$lastseen = $downloadProgress;
2088
	}
2089
	if ($fout) {
2090
		fwrite($fout, $string);
2091
	}
2092
	ob_flush();
2093
	return $length;
2094
}
2095

    
2096
/*
2097
 *   update_output_window: update bottom textarea dynamically.
2098
 */
2099
function update_output_window($text) {
2100
	global $pkg_interface;
2101
	$log = preg_replace("/\n/", "\\n", $text);
2102
	if ($pkg_interface != "console") {
2103
?>
2104
<script type="text/javascript">
2105
//<![CDATA[
2106
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2107
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2108
//]]>
2109
</script>
2110
<?php
2111
	}
2112
	/* ensure that contents are written out */
2113
	ob_flush();
2114
}
2115

    
2116
/*
2117
 *   update_status: update top textarea dynamically.
2118
 */
2119
function update_status($status) {
2120
	global $pkg_interface;
2121

    
2122
	if ($pkg_interface == "console") {
2123
		print ("{$status}");
2124
	}
2125

    
2126
	/* ensure that contents are written out */
2127
	ob_flush();
2128
}
2129

    
2130
/*
2131
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2132
 */
2133
function update_progress_bar($percent, $first_time) {
2134
	global $pkg_interface;
2135
	if ($percent > 100) {
2136
		$percent = 1;
2137
	}
2138
	if ($pkg_interface <> "console") {
2139
		echo '<script type="text/javascript">';
2140
		echo "\n//<![CDATA[\n";
2141
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2142
		echo "\n//]]>\n";
2143
		echo '</script>';
2144
	} else {
2145
		if (!($first_time)) {
2146
			echo "\x08\x08\x08\x08\x08";
2147
		}
2148
		echo sprintf("%4d%%", $percent);
2149
	}
2150
}
2151

    
2152
/* 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. */
2153
if (!function_exists("split")) {
2154
	function split($separator, $haystack, $limit = null) {
2155
		log_error("deprecated split() call with separator '{$separator}'");
2156
		return preg_split($separator, $haystack, $limit);
2157
	}
2158
}
2159

    
2160
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2161
	global $g, $config, $pconfig, $debug;
2162
	if (!$origname) {
2163
		return;
2164
	}
2165

    
2166
	$sectionref = &$config;
2167
	foreach ($section as $sectionname) {
2168
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2169
			$sectionref = &$sectionref[$sectionname];
2170
		} else {
2171
			return;
2172
		}
2173
	}
2174

    
2175
	if ($debug) {
2176
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2177
		fwrite($fd, print_r($pconfig, true));
2178
	}
2179

    
2180
	if (is_array($sectionref)) {
2181
		foreach ($sectionref as $itemkey => $item) {
2182
			if ($debug) {
2183
				fwrite($fd, "$itemkey\n");
2184
			}
2185

    
2186
			$fieldfound = true;
2187
			$fieldref = &$sectionref[$itemkey];
2188
			foreach ($field as $fieldname) {
2189
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2190
					$fieldref = &$fieldref[$fieldname];
2191
				} else {
2192
					$fieldfound = false;
2193
					break;
2194
				}
2195
			}
2196
			if ($fieldfound && $fieldref == $origname) {
2197
				if ($debug) {
2198
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2199
				}
2200
				$fieldref = $new_alias_name;
2201
			}
2202
		}
2203
	}
2204

    
2205
	if ($debug) {
2206
		fclose($fd);
2207
	}
2208

    
2209
}
2210

    
2211
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2212
	/*
2213
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2214
	 * $type = if set to 'url' then subnets and ips will be returned,
2215
	 *         if set to 'url_ports' port-ranges and ports will be returned
2216
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2217
	 *
2218
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2219
	 */
2220

    
2221
	if (!file_exists($filename)) {
2222
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2223
		return null;
2224
	}
2225

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

    
2268
function update_alias_url_data() {
2269
	global $config, $g;
2270

    
2271
	$updated = false;
2272

    
2273
	/* item is a url type */
2274
	$lockkey = lock('aliasurl');
2275
	if (is_array($config['aliases']['alias'])) {
2276
		foreach ($config['aliases']['alias'] as $x => $alias) {
2277
			if (empty($alias['aliasurl'])) {
2278
				continue;
2279
			}
2280

    
2281
			$address = null;
2282
			foreach ($alias['aliasurl'] as $alias_url) {
2283
				/* fetch down and add in */
2284
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2285
				unlink($temp_filename);
2286
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2287
				mkdir($temp_filename);
2288
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2289
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2290
					continue;
2291
				}
2292

    
2293
				/* if the item is tar gzipped then extract */
2294
				if (stripos($alias_url, '.tgz')) {
2295
					if (!process_alias_tgz($temp_filename)) {
2296
						continue;
2297
					}
2298
				}
2299
				if (file_exists("{$temp_filename}/aliases")) {
2300
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2301
					mwexec("/bin/rm -rf {$temp_filename}");
2302
				}
2303
			}
2304
			if ($address != null) {
2305
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2306
				$updated = true;
2307
			}
2308
		}
2309
	}
2310
	unlock($lockkey);
2311

    
2312
	/* Report status to callers as well */
2313
	return $updated;
2314
}
2315

    
2316
function process_alias_tgz($temp_filename) {
2317
	if (!file_exists('/usr/bin/tar')) {
2318
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2319
		return false;
2320
	}
2321
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2322
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2323
	unlink("{$temp_filename}/aliases.tgz");
2324
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2325
	/* foreach through all extracted files and build up aliases file */
2326
	$fd = @fopen("{$temp_filename}/aliases", "w");
2327
	if (!$fd) {
2328
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2329
		return false;
2330
	}
2331
	foreach ($files_to_process as $f2p) {
2332
		$tmpfd = @fopen($f2p, 'r');
2333
		if (!$tmpfd) {
2334
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2335
			continue;
2336
		}
2337
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2338
			fwrite($fd, $tmpbuf);
2339
		}
2340
		fclose($tmpfd);
2341
		unlink($f2p);
2342
	}
2343
	fclose($fd);
2344
	unset($tmpbuf);
2345

    
2346
	return true;
2347
}
2348

    
2349
function version_compare_dates($a, $b) {
2350
	$a_time = strtotime($a);
2351
	$b_time = strtotime($b);
2352

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

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

    
2437
		// First try to compare the numeric parts of the version string.
2438
		$v = version_compare_numeric($cur_num, $rem_num);
2439

    
2440
		// If the numeric parts are the same, compare the string parts.
2441
		if ($v == 0) {
2442
			return version_compare_string($cur_str, $rem_str);
2443
		}
2444
	}
2445
	return $v;
2446
}
2447
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2448
	global $g, $config;
2449

    
2450
	$urltable_prefix = "/var/db/aliastables/";
2451
	$urltable_filename = $urltable_prefix . $name . ".txt";
2452
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2453

    
2454
	// Make the aliases directory if it doesn't exist
2455
	if (!file_exists($urltable_prefix)) {
2456
		mkdir($urltable_prefix);
2457
	} elseif (!is_dir($urltable_prefix)) {
2458
		unlink($urltable_prefix);
2459
		mkdir($urltable_prefix);
2460
	}
2461

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

    
2467
		// Try to fetch the URL supplied
2468
		conf_mount_rw();
2469
		unlink_if_exists($tmp_urltable_filename);
2470
		$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2471
		if (download_file($url, $tmp_urltable_filename, $verify_ssl)) {
2472
			// Convert lines that begin with '$' or ';' to comments '#' instead of deleting them.
2473
			mwexec("/usr/bin/sed -i \"\" -E 's/^[[:space:]]*($|#|;)/#/g; /^#/!s/\;.*//g;' ". escapeshellarg($tmp_urltable_filename));
2474

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

    
2477
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2478
			if ($type == "urltable_ports") {
2479
				$parsed_contents = group_ports($parsed_contents, true);
2480
			}
2481
			if (is_array($parsed_contents)) {
2482
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2483
			} else {
2484
				touch($urltable_filename);
2485
			}
2486

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

    
2523
	return "{$boot_drive}s{$active}";
2524
}
2525
function nanobsd_get_size() {
2526
	return strtoupper(file_get_contents("/etc/nanosize.txt"));
2527
}
2528
function nanobsd_switch_boot_slice() {
2529
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2530
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2531
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2532
	nanobsd_detect_slice_info();
2533

    
2534
	if ($BOOTFLASH == $ACTIVE_SLICE) {
2535
		$slice = $TOFLASH;
2536
	} else {
2537
		$slice = $BOOTFLASH;
2538
	}
2539

    
2540
	for ($i = 0; $i < ob_get_level(); $i++) {
2541
		ob_end_flush();
2542
	}
2543
	ob_implicit_flush(1);
2544
	if (strstr($slice, "s2")) {
2545
		$ASLICE = "2";
2546
		$AOLDSLICE = "1";
2547
		$AGLABEL_SLICE = "pfsense1";
2548
		$AUFS_ID = "1";
2549
		$AOLD_UFS_ID = "0";
2550
	} else {
2551
		$ASLICE = "1";
2552
		$AOLDSLICE = "2";
2553
		$AGLABEL_SLICE = "pfsense0";
2554
		$AUFS_ID = "0";
2555
		$AOLD_UFS_ID = "1";
2556
	}
2557
	$ATOFLASH = "{$BOOT_DRIVE}s{$ASLICE}";
2558
	$ACOMPLETE_PATH = "{$BOOT_DRIVE}s{$ASLICE}a";
2559
	$ABOOTFLASH = "{$BOOT_DRIVE}s{$AOLDSLICE}";
2560
	conf_mount_rw();
2561
	set_single_sysctl("kern.geom.debugflags", "16");
2562
	exec("/sbin/gpart set -a active -i {$ASLICE} {$BOOT_DRIVE}");
2563
	exec("/usr/sbin/boot0cfg -s {$ASLICE} -v /dev/{$BOOT_DRIVE}");
2564
	// We can't update these if they are mounted now.
2565
	if ($BOOTFLASH != $slice) {
2566
		exec("/sbin/tunefs -L ${AGLABEL_SLICE} /dev/$ACOMPLETE_PATH");
2567
		nanobsd_update_fstab($AGLABEL_SLICE, $ACOMPLETE_PATH, $AOLD_UFS_ID, $AUFS_ID);
2568
	}
2569
	set_single_sysctl("kern.geom.debugflags", "0");
2570
	conf_mount_ro();
2571
}
2572
function nanobsd_clone_slice() {
2573
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2574
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2575
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2576
	nanobsd_detect_slice_info();
2577

    
2578
	for ($i = 0; $i < ob_get_level(); $i++) {
2579
		ob_end_flush();
2580
	}
2581
	ob_implicit_flush(1);
2582
	set_single_sysctl("kern.geom.debugflags", "16");
2583
	exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
2584
	exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
2585
	exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
2586
	$status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
2587
	set_single_sysctl("kern.geom.debugflags", "0");
2588
	if ($status) {
2589
		return false;
2590
	} else {
2591
		return true;
2592
	}
2593
}
2594
function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
2595
	$tmppath = "/tmp/{$gslice}";
2596
	$fstabpath = "/tmp/{$gslice}/etc/fstab";
2597

    
2598
	mkdir($tmppath);
2599
	exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
2600
	exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
2601
	copy("/etc/fstab", $fstabpath);
2602

    
2603
	if (!file_exists($fstabpath)) {
2604
		$fstab = <<<EOF
2605
/dev/ufs/{$gslice} / ufs ro,noatime 1 1
2606
/dev/ufs/cf /cf ufs ro,noatime 1 1
2607
EOF;
2608
		if (file_put_contents($fstabpath, $fstab)) {
2609
			$status = true;
2610
		} else {
2611
			$status = false;
2612
		}
2613
	} else {
2614
		$status = exec("/usr/bin/sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
2615
	}
2616
	exec("/sbin/umount {$tmppath}");
2617
	rmdir($tmppath);
2618

    
2619
	return $status;
2620
}
2621
function nanobsd_detect_slice_info() {
2622
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2623
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2624
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2625

    
2626
	$BOOT_DEVICE=nanobsd_get_boot_slice();
2627
	$REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
2628
	$BOOT_DRIVE=nanobsd_get_boot_drive();
2629
	$ACTIVE_SLICE=nanobsd_get_active_slice();
2630

    
2631
	// Detect which slice is active and set information.
2632
	if (strstr($REAL_BOOT_DEVICE, "s1")) {
2633
		$SLICE = "2";
2634
		$OLDSLICE = "1";
2635
		$GLABEL_SLICE = "pfsense1";
2636
		$UFS_ID = "1";
2637
		$OLD_UFS_ID = "0";
2638

    
2639
	} else {
2640
		$SLICE = "1";
2641
		$OLDSLICE = "2";
2642
		$GLABEL_SLICE = "pfsense0";
2643
		$UFS_ID = "0";
2644
		$OLD_UFS_ID = "1";
2645
	}
2646
	$TOFLASH = "{$BOOT_DRIVE}s{$SLICE}";
2647
	$COMPLETE_PATH = "{$BOOT_DRIVE}s{$SLICE}a";
2648
	$COMPLETE_BOOT_PATH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2649
	$BOOTFLASH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2650
}
2651

    
2652
function nanobsd_friendly_slice_name($slicename) {
2653
	global $g;
2654
	return strtolower(str_ireplace('pfsense', $g['product_name'], $slicename));
2655
}
2656

    
2657
function get_include_contents($filename) {
2658
	if (is_file($filename)) {
2659
		ob_start();
2660
		include $filename;
2661
		$contents = ob_get_contents();
2662
		ob_end_clean();
2663
		return $contents;
2664
	}
2665
	return false;
2666
}
2667

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

    
2780
function get_country_name($country_code) {
2781
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2782
		return "";
2783
	}
2784

    
2785
	$country_names_xml = "/usr/local/share/mobile-broadband-provider-info/iso_3166-1_list_en.xml";
2786
	$country_names_contents = file_get_contents($country_names_xml);
2787
	$country_names = xml2array($country_names_contents);
2788

    
2789
	if ($country_code == "ALL") {
2790
		$country_list = array();
2791
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2792
			$country_list[] = array(
2793
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2794
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2795
		}
2796
		return $country_list;
2797
	}
2798

    
2799
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2800
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2801
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2802
		}
2803
	}
2804
	return "";
2805
}
2806

    
2807
/* sort by interface only, retain the original order of rules that apply to
2808
   the same interface */
2809
function filter_rules_sort() {
2810
	global $config;
2811

    
2812
	/* mark each rule with the sequence number (to retain the order while sorting) */
2813
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2814
		$config['filter']['rule'][$i]['seq'] = $i;
2815
	}
2816

    
2817
	usort($config['filter']['rule'], "filter_rules_compare");
2818

    
2819
	/* strip the sequence numbers again */
2820
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2821
		unset($config['filter']['rule'][$i]['seq']);
2822
	}
2823
}
2824
function filter_rules_compare($a, $b) {
2825
	if (isset($a['floating']) && isset($b['floating'])) {
2826
		return $a['seq'] - $b['seq'];
2827
	} else if (isset($a['floating'])) {
2828
		return -1;
2829
	} else if (isset($b['floating'])) {
2830
		return 1;
2831
	} else if ($a['interface'] == $b['interface']) {
2832
		return $a['seq'] - $b['seq'];
2833
	} else {
2834
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2835
	}
2836
}
2837

    
2838
function generate_ipv6_from_mac($mac) {
2839
	$elements = explode(":", $mac);
2840
	if (count($elements) <> 6) {
2841
		return false;
2842
	}
2843

    
2844
	$i = 0;
2845
	$ipv6 = "fe80::";
2846
	foreach ($elements as $byte) {
2847
		if ($i == 0) {
2848
			$hexadecimal = substr($byte, 1, 2);
2849
			$bitmap = base_convert($hexadecimal, 16, 2);
2850
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2851
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2852
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2853
		}
2854
		$ipv6 .= $byte;
2855
		if ($i == 1) {
2856
			$ipv6 .= ":";
2857
		}
2858
		if ($i == 3) {
2859
			$ipv6 .= ":";
2860
		}
2861
		if ($i == 2) {
2862
			$ipv6 .= "ff:fe";
2863
		}
2864

    
2865
		$i++;
2866
	}
2867
	return $ipv6;
2868
}
2869

    
2870
/****f* pfsense-utils/load_mac_manufacturer_table
2871
 * NAME
2872
 *   load_mac_manufacturer_table
2873
 * INPUTS
2874
 *   none
2875
 * RESULT
2876
 *   returns associative array with MAC-Manufacturer pairs
2877
 ******/
2878
function load_mac_manufacturer_table() {
2879
	/* load MAC-Manufacture data from the file */
2880
	$macs = false;
2881
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2882
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2883
	}
2884
	if ($macs) {
2885
		foreach ($macs as $line) {
2886
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2887
				/* store values like this $mac_man['000C29']='VMware' */
2888
				$mac_man["$matches[1]"] = $matches[2];
2889
			}
2890
		}
2891
		return $mac_man;
2892
	} else {
2893
		return -1;
2894
	}
2895

    
2896
}
2897

    
2898
/****f* pfsense-utils/is_ipaddr_configured
2899
 * NAME
2900
 *   is_ipaddr_configured
2901
 * INPUTS
2902
 *   IP Address to check.
2903
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2904
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2905
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2906
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2907
 *     If check_subnets is true and cidrprefix is specified,
2908
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2909
 * RESULT
2910
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2911
*/
2912
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2913
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2914
		return true;
2915
	}
2916
	return false;
2917
}
2918

    
2919
/****f* pfsense-utils/where_is_ipaddr_configured
2920
 * NAME
2921
 *   where_is_ipaddr_configured
2922
 * INPUTS
2923
 *   IP Address to check.
2924
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2925
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2926
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2927
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2928
 *     If check_subnets is true and cidrprefix is specified,
2929
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2930
 * RESULT
2931
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2932
 *   If there are no matches then an empty array is returned.
2933
*/
2934
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2935
	global $config;
2936

    
2937
	$where_configured = array();
2938

    
2939
	$pos = strpos($ignore_if, '_virtualip');
2940
	if ($pos !== false) {
2941
		$ignore_vip_id = substr($ignore_if, $pos+10);
2942
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2943
	} else {
2944
		$ignore_vip_id = -1;
2945
		$ignore_vip_if = $ignore_if;
2946
	}
2947

    
2948
	$isipv6 = is_ipaddrv6($ipaddr);
2949

    
2950
	if ($check_subnets) {
2951
		$cidrprefix = intval($cidrprefix);
2952
		if ($isipv6) {
2953
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2954
				$cidrprefix = 128;
2955
			}
2956
		} else {
2957
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2958
				$cidrprefix = 32;
2959
			}
2960
		}
2961
		$iflist = get_configured_interface_list();
2962
		foreach ($iflist as $if => $ifname) {
2963
			if ($ignore_if == $if) {
2964
				continue;
2965
			}
2966

    
2967
			if ($isipv6) {
2968
				$if_ipv6 = get_interface_ipv6($if);
2969
				$if_snbitsv6 = get_interface_subnetv6($if);
2970
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2971
					$where_entry = array();
2972
					$where_entry['if'] = $if;
2973
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2974
					$where_configured[] = $where_entry;
2975
				}
2976
			} else {
2977
				$if_ipv4 = get_interface_ip($if);
2978
				$if_snbitsv4 = get_interface_subnet($if);
2979
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2980
					$where_entry = array();
2981
					$where_entry['if'] = $if;
2982
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2983
					$where_configured[] = $where_entry;
2984
				}
2985
			}
2986
		}
2987
	} else {
2988
		if ($isipv6) {
2989
			$interface_list_ips = get_configured_ipv6_addresses();
2990
		} else {
2991
			$interface_list_ips = get_configured_ip_addresses();
2992
		}
2993

    
2994
		foreach ($interface_list_ips as $if => $ilips) {
2995
			if ($ignore_if == $if) {
2996
				continue;
2997
			}
2998
			if (strcasecmp($ipaddr, $ilips) == 0) {
2999
				$where_entry = array();
3000
				$where_entry['if'] = $if;
3001
				$where_entry['ip_or_subnet'] = $ilips;
3002
				$where_configured[] = $where_entry;
3003
			}
3004
		}
3005
	}
3006

    
3007
	if ($check_localip) {
3008
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, $config['l2tp']['localip']) == 0)) {
3009
			$where_entry = array();
3010
			$where_entry['if'] = 'l2tp';
3011
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3012
			$where_configured[] = $where_entry;
3013
		}
3014
	}
3015

    
3016
	return $where_configured;
3017
}
3018

    
3019
/****f* pfsense-utils/pfSense_handle_custom_code
3020
 * NAME
3021
 *   pfSense_handle_custom_code
3022
 * INPUTS
3023
 *   directory name to process
3024
 * RESULT
3025
 *   globs the directory and includes the files
3026
 */
3027
function pfSense_handle_custom_code($src_dir) {
3028
	// Allow extending of the nat edit page and include custom input validation
3029
	if (is_dir("$src_dir")) {
3030
		$cf = glob($src_dir . "/*.inc");
3031
		foreach ($cf as $nf) {
3032
			if ($nf == "." || $nf == "..") {
3033
				continue;
3034
			}
3035
			// Include the extra handler
3036
			include_once("$nf");
3037
		}
3038
	}
3039
}
3040

    
3041
function set_language() {
3042
	global $config, $g;
3043

    
3044
	if (!empty($config['system']['language'])) {
3045
		$lang = $config['system']['language'];
3046
	} elseif (!empty($g['language'])) {
3047
		$lang = $g['language'];
3048
	}
3049
	$lang .= ".UTF-8";
3050

    
3051
	putenv("LANG={$lang}");
3052
	setlocale(LC_ALL, $lang);
3053
	textdomain("pfSense");
3054
	bindtextdomain("pfSense", "/usr/local/share/locale");
3055
	bind_textdomain_codeset("pfSense", $lang);
3056
}
3057

    
3058
function get_locale_list() {
3059
	$locales = array(
3060
		"en_US" => gettext("English"),
3061
		"pt_BR" => gettext("Portuguese (Brazil)"),
3062
		"tr" => gettext("Turkish"),
3063
	);
3064
	asort($locales);
3065
	return $locales;
3066
}
3067

    
3068
function return_hex_ipv4($ipv4) {
3069
	if (!is_ipaddrv4($ipv4)) {
3070
		return(false);
3071
	}
3072

    
3073
	/* we need the hex form of the interface IPv4 address */
3074
	$ip4arr = explode(".", $ipv4);
3075
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3076
}
3077

    
3078
function convert_ipv6_to_128bit($ipv6) {
3079
	if (!is_ipaddrv6($ipv6)) {
3080
		return(false);
3081
	}
3082

    
3083
	$ip6arr = array();
3084
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3085
	$ip6arr = explode(":", $ip6prefix);
3086
	/* binary presentation of the prefix for all 128 bits. */
3087
	$ip6prefixbin = "";
3088
	foreach ($ip6arr as $element) {
3089
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3090
	}
3091
	return($ip6prefixbin);
3092
}
3093

    
3094
function convert_128bit_to_ipv6($ip6bin) {
3095
	if (strlen($ip6bin) <> 128) {
3096
		return(false);
3097
	}
3098

    
3099
	$ip6arr = array();
3100
	$ip6binarr = array();
3101
	$ip6binarr = str_split($ip6bin, 16);
3102
	foreach ($ip6binarr as $binpart) {
3103
		$ip6arr[] = dechex(bindec($binpart));
3104
	}
3105
	$ip6addr = Net_IPv6::compress(implode(":", $ip6arr));
3106

    
3107
	return($ip6addr);
3108
}
3109

    
3110

    
3111
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3112
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3113
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3114
/* 6to4 is 16 bits, e.g. 65535 */
3115
function calculate_ipv6_delegation_length($if) {
3116
	global $config;
3117

    
3118
	if (!is_array($config['interfaces'][$if])) {
3119
		return false;
3120
	}
3121

    
3122
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3123
		case "6to4":
3124
			$pdlen = 16;
3125
			break;
3126
		case "6rd":
3127
			$rd6cfg = $config['interfaces'][$if];
3128
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3129
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
3130
			break;
3131
		case "dhcp6":
3132
			$dhcp6cfg = $config['interfaces'][$if];
3133
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3134
			break;
3135
		default:
3136
			$pdlen = 0;
3137
			break;
3138
	}
3139
	return($pdlen);
3140
}
3141

    
3142
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3143
	$prefix = Net_IPv6::uncompress($prefix, true);
3144
	$suffix = Net_IPv6::uncompress($suffix, true);
3145

    
3146
	/*
3147
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3148
	 *                ^^^^ ^
3149
	 *                |||| \-> 64
3150
	 *                |||\---> 63, 62, 61, 60
3151
	 *                ||\----> 56
3152
	 *                |\-----> 52
3153
	 *                \------> 48
3154
	 */
3155

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

    
3186
	return Net_IPv6::compress(substr($prefix, 0, $prefix_len) .
3187
	    substr($suffix, $prefix_len));
3188
}
3189

    
3190
function dhcpv6_pd_str_help($pdlen) {
3191
	$result = '';
3192

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

    
3223
	return $result;
3224
}
3225

    
3226
function huawei_rssi_to_string($rssi) {
3227
	$dbm = array();
3228
	$i = 0;
3229
	$dbstart = -113;
3230
	while ($i < 32) {
3231
		$dbm[$i] = $dbstart + ($i * 2);
3232
		$i++;
3233
	}
3234
	$percent = round(($rssi / 31) * 100);
3235
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3236
	return $string;
3237
}
3238

    
3239
function huawei_mode_to_string($mode, $submode) {
3240
	$modes[0] = gettext("None");
3241
	$modes[1] = "AMPS";
3242
	$modes[2] = "CDMA";
3243
	$modes[3] = "GSM/GPRS";
3244
	$modes[4] = "HDR";
3245
	$modes[5] = "WCDMA";
3246
	$modes[6] = "GPS";
3247

    
3248
	$submodes[0] = gettext("No Service");
3249
	$submodes[1] = "GSM";
3250
	$submodes[2] = "GPRS";
3251
	$submodes[3] = "EDGE";
3252
	$submodes[4] = "WCDMA";
3253
	$submodes[5] = "HSDPA";
3254
	$submodes[6] = "HSUPA";
3255
	$submodes[7] = "HSDPA+HSUPA";
3256
	$submodes[8] = "TD-SCDMA";
3257
	$submodes[9] = "HSPA+";
3258
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3259
	return $string;
3260
}
3261

    
3262
function huawei_service_to_string($state) {
3263
	$modes[0] = gettext("No Service");
3264
	$modes[1] = gettext("Restricted Service");
3265
	$modes[2] = gettext("Valid Service");
3266
	$modes[3] = gettext("Restricted Regional Service");
3267
	$modes[4] = gettext("Powersaving Service");
3268
	$string = $modes[$state];
3269
	return $string;
3270
}
3271

    
3272
function huawei_simstate_to_string($state) {
3273
	$modes[0] = gettext("Invalid SIM/locked State");
3274
	$modes[1] = gettext("Valid SIM State");
3275
	$modes[2] = gettext("Invalid SIM CS State");
3276
	$modes[3] = gettext("Invalid SIM PS State");
3277
	$modes[4] = gettext("Invalid SIM CS/PS State");
3278
	$modes[255] = gettext("Missing SIM State");
3279
	$string = $modes[$state];
3280
	return $string;
3281
}
3282

    
3283
function zte_rssi_to_string($rssi) {
3284
	return huawei_rssi_to_string($rssi);
3285
}
3286

    
3287
function zte_mode_to_string($mode, $submode) {
3288
	$modes[0] = gettext("No Service");
3289
	$modes[1] = gettext("Limited Service");
3290
	$modes[2] = "GPRS";
3291
	$modes[3] = "GSM";
3292
	$modes[4] = "UMTS";
3293
	$modes[5] = "EDGE";
3294
	$modes[6] = "HSDPA";
3295

    
3296
	$submodes[0] = "CS_ONLY";
3297
	$submodes[1] = "PS_ONLY";
3298
	$submodes[2] = "CS_PS";
3299
	$submodes[3] = "CAMPED";
3300
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3301
	return $string;
3302
}
3303

    
3304
function zte_service_to_string($service) {
3305
	$modes[0] = gettext("Initializing Service");
3306
	$modes[1] = gettext("Network Lock error Service");
3307
	$modes[2] = gettext("Network Locked Service");
3308
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3309
	$string = $modes[$service];
3310
	return $string;
3311
}
3312

    
3313
function zte_simstate_to_string($state) {
3314
	$modes[0] = gettext("No action State");
3315
	$modes[1] = gettext("Network lock State");
3316
	$modes[2] = gettext("(U)SIM card lock State");
3317
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3318
	$string = $modes[$state];
3319
	return $string;
3320
}
3321

    
3322
function get_configured_pppoe_server_interfaces() {
3323
	global $config;
3324
	$iflist = array();
3325
	if (is_array($config['pppoes']['pppoe'])) {
3326
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3327
			if ($pppoe['mode'] == "server") {
3328
				$int = "poes". $pppoe['pppoeid'];
3329
				$iflist[$int] = strtoupper($int);
3330
			}
3331
		}
3332
	}
3333
	return $iflist;
3334
}
3335

    
3336
function get_pppoes_child_interfaces($ifpattern) {
3337
	$if_arr = array();
3338
	if ($ifpattern == "") {
3339
		return;
3340
	}
3341

    
3342
	exec("/sbin/ifconfig", $out, $ret);
3343
	foreach ($out as $line) {
3344
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3345
			$if_arr[] = $match[1];
3346
		}
3347
	}
3348
	return $if_arr;
3349

    
3350
}
3351

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

    
3392
function restore_aliastables() {
3393
	global $g, $config;
3394

    
3395
	$dbpath = "{$g['vardb_path']}/aliastables/";
3396

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

    
3424
?>
(39-39/65)