Project

General

Profile

Download (88.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * pfsense-utils.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 * http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21

    
22
/****f* pfsense-utils/have_natpfruleint_access
23
 * NAME
24
 *   have_natpfruleint_access
25
 * INPUTS
26
 *	none
27
 * RESULT
28
 *   returns true if user has access to edit a specific firewall nat port forward interface
29
 ******/
30
function have_natpfruleint_access($if) {
31
	$security_url = "firewall_nat_edit.php?if=". strtolower($if);
32
	if (isAllowedPage($security_url, $allowed)) {
33
		return true;
34
	}
35
	return false;
36
}
37

    
38
/****f* pfsense-utils/have_ruleint_access
39
 * NAME
40
 *   have_ruleint_access
41
 * INPUTS
42
 *	none
43
 * RESULT
44
 *   returns true if user has access to edit a specific firewall interface
45
 ******/
46
function have_ruleint_access($if) {
47
	$security_url = "firewall_rules.php?if=". strtolower($if);
48
	if (isAllowedPage($security_url)) {
49
		return true;
50
	}
51
	return false;
52
}
53

    
54
/****f* pfsense-utils/does_url_exist
55
 * NAME
56
 *   does_url_exist
57
 * INPUTS
58
 *	none
59
 * RESULT
60
 *   returns true if a url is available
61
 ******/
62
function does_url_exist($url) {
63
	$fd = fopen("$url", "r");
64
	if ($fd) {
65
		fclose($fd);
66
		return true;
67
	} else {
68
		return false;
69
	}
70
}
71

    
72
/****f* pfsense-utils/is_private_ip
73
 * NAME
74
 *   is_private_ip
75
 * INPUTS
76
 *	none
77
 * RESULT
78
 *   returns true if an ip address is in a private range
79
 ******/
80
function is_private_ip($iptocheck) {
81
	$isprivate = false;
82
	$ip_private_list = array(
83
		"10.0.0.0/8",
84
		"100.64.0.0/10",
85
		"172.16.0.0/12",
86
		"192.168.0.0/16",
87
	);
88
	foreach ($ip_private_list as $private) {
89
		if (ip_in_subnet($iptocheck, $private) == true) {
90
			$isprivate = true;
91
		}
92
	}
93
	return $isprivate;
94
}
95

    
96
/****f* pfsense-utils/get_tmp_file
97
 * NAME
98
 *   get_tmp_file
99
 * INPUTS
100
 *	none
101
 * RESULT
102
 *   returns a temporary filename
103
 ******/
104
function get_tmp_file() {
105
	global $g;
106
	return "{$g['tmp_path']}/tmp-" . time();
107
}
108

    
109
/****f* pfsense-utils/get_dns_servers
110
 * NAME
111
 *   get_dns_servers - get system dns servers
112
 * INPUTS
113
 *   none
114
 * RESULT
115
 *   $dns_servers - an array of the dns servers
116
 ******/
117
function get_dns_servers() {
118
	$dns_servers = array();
119
	if (file_exists("/etc/resolv.conf")) {
120
		$dns_s = file("/etc/resolv.conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
121
	}
122
	if (is_array($dns_s)) {
123
		foreach ($dns_s as $dns) {
124
			$matches = "";
125
			if (preg_match("/nameserver (.*)/", $dns, $matches)) {
126
				$dns_servers[] = $matches[1];
127
			}
128
		}
129
	}
130
	return array_unique($dns_servers);
131
}
132

    
133
/****f* pfsense-utils/get_css_files
134
 * NAME
135
 *   get_css_files - get a list of the available CSS files (themes)
136
 * INPUTS
137
 *   none
138
 * RESULT
139
 *   $csslist - an array of the CSS files
140
 ******/
141
function get_css_files() {
142
	$csslist = array();
143

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

    
147
	if (is_array($cssfiles)) {
148
		arsort($cssfiles);
149
		$usrcss = $pfscss = $betacss = array();
150

    
151
		foreach ($cssfiles as $css) {
152
			if (strpos($css, "BETA") != 0) {
153
				array_push($betacss, $css);
154
			} else if (strpos($css, "pfSense") != 0) {
155
				array_push($pfscss, $css);
156
			} else {
157
				array_push($usrcss, $css);
158
			}
159
		}
160

    
161
		$css = array_merge($pfscss, $betacss, $usrcss);
162

    
163
		foreach ($css as $file) {
164
			$file = basename($file);
165
			$csslist[$file] = pathinfo($file, PATHINFO_FILENAME);
166
		}
167
	}
168
	return $csslist;
169
}
170

    
171
/****f* pfsense-utils/gen_webguicss_field
172
 * NAME
173
 *   gen_webguicss_field
174
 * INPUTS
175
 *   Pointer to section object
176
 *   Initial value for the field
177
 * RESULT
178
 *   no return value, section object is updated
179
 ******/
180
function gen_webguicss_field(&$section, $value) {
181

    
182
	$csslist = get_css_files();
183

    
184
	if (!isset($csslist[$value])) {
185
		$value = "pfSense.css";
186
	}
187

    
188
	$section->addInput(new Form_Select(
189
		'webguicss',
190
		'Theme',
191
		$value,
192
		$csslist
193
	))->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>'));
194
}
195

    
196
/****f* pfsense-utils/gen_webguifixedmenu_field
197
 * NAME
198
 *   gen_webguifixedmenu_field
199
 * INPUTS
200
 *   Pointer to section object
201
 *   Initial value for the field
202
 * RESULT
203
 *   no return value, section object is updated
204
 ******/
205
function gen_webguifixedmenu_field(&$section, $value) {
206

    
207
	$section->addInput(new Form_Select(
208
		'webguifixedmenu',
209
		'Top Navigation',
210
		$value,
211
		["" => gettext("Scrolls with page"), "fixed" => gettext("Fixed (Remains visible at top of page)")]
212
	))->setHelp("The fixed option is intended for large screens only.");
213
}
214

    
215
/****f* pfsense-utils/gen_webguihostnamemenu_field
216
 * NAME
217
 *   gen_webguihostnamemenu_field
218
 * INPUTS
219
 *   Pointer to section object
220
 *   Initial value for the field
221
 * RESULT
222
 *   no return value, section object is updated
223
 ******/
224
function gen_webguihostnamemenu_field(&$section, $value) {
225

    
226
	$section->addInput(new Form_Select(
227
		'webguihostnamemenu',
228
		'Hostname in Menu',
229
		$value,
230
		["" => gettext("Default (No hostname)"), "hostonly" => gettext("Hostname only"), "fqdn" => gettext("Fully Qualified Domain Name")]
231
	))->setHelp("Replaces the Help menu title in the Navbar with the system hostname or FQDN.");
232
}
233

    
234
/****f* pfsense-utils/gen_dashboardcolumns_field
235
 * NAME
236
 *   gen_dashboardcolumns_field
237
 * INPUTS
238
 *   Pointer to section object
239
 *   Initial value for the field
240
 * RESULT
241
 *   no return value, section object is updated
242
 ******/
243
function gen_dashboardcolumns_field(&$section, $value) {
244

    
245
	if (($value < 1) || ($value > 4)) {
246
		$value = 2;
247
	}
248

    
249
	$section->addInput(new Form_Input(
250
		'dashboardcolumns',
251
		'Dashboard Columns',
252
		'number',
253
		$value,
254
		[min => 1, max => 4]
255
	));
256
}
257

    
258
/****f* pfsense-utils/gen_associatedpanels_fields
259
 * NAME
260
 *   gen_associatedpanels_fields
261
 * INPUTS
262
 *   Pointer to section object
263
 *   Initial value for each of the fields
264
 * RESULT
265
 *   no return value, section object is updated
266
 ******/
267
function gen_associatedpanels_fields(&$section, $value1, $value2, $value3, $value4) {
268

    
269
	$group = new Form_Group('Associated Panels Show/Hide');
270

    
271
	$group->add(new Form_Checkbox(
272
		'dashboardavailablewidgetspanel',
273
		null,
274
		'Available Widgets',
275
		$value1
276
		))->setHelp('Show the Available Widgets panel on the Dashboard.');
277

    
278
	$group->add(new Form_Checkbox(
279
		'systemlogsfilterpanel',
280
		null,
281
		'Log Filter',
282
		$value2
283
	))->setHelp('Show the Log Filter panel in System Logs.');
284

    
285
	$group->add(new Form_Checkbox(
286
		'systemlogsmanagelogpanel',
287
		null,
288
		'Manage Log',
289
		$value3
290
	))->setHelp('Show the Manage Log panel in System Logs.');
291

    
292
	$group->add(new Form_Checkbox(
293
		'statusmonitoringsettingspanel',
294
		null,
295
		'Monitoring Settings',
296
		$value4
297
	))->setHelp('Show the Settings panel in Status Monitoring.');
298

    
299
	$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.');
300

    
301
	$section->add($group);
302
}
303

    
304
/****f* pfsense-utils/gen_webguileftcolumnhyper_field
305
 * NAME
306
 *   gen_webguileftcolumnhyper_field
307
 * INPUTS
308
 *   Pointer to section object
309
 *   Initial value for the field
310
 * RESULT
311
 *   no return value, section object is updated
312
 ******/
313
function gen_webguileftcolumnhyper_field(&$section, $value) {
314

    
315
	$section->addInput(new Form_Checkbox(
316
		'webguileftcolumnhyper',
317
		'Left Column Labels',
318
		'Active',
319
		$value
320
	))->setHelp('If selected, clicking a label in the left column will select/toggle the first item of the group.');
321
}
322

    
323
/****f* pfsense-utils/gen_pagenamefirst_field
324
 * NAME
325
 *   gen_pagenamefirst_field
326
 * INPUTS
327
 *   Pointer to section object
328
 *   Initial value for the field
329
 * RESULT
330
 *   no return value, section object is updated
331
 ******/
332
function gen_pagenamefirst_field(&$section, $value) {
333

    
334
	$section->addInput(new Form_Checkbox(
335
		'pagenamefirst',
336
		'Browser tab text',
337
		'Display page name first in browser tab',
338
		$value
339
	))->setHelp('When this is unchecked, the browser tab shows the host name followed '.
340
		'by the current page. Check this box to display the current page followed by the '.
341
		'host name.');
342
}
343

    
344
/****f* pfsense-utils/gen_user_settings_fields
345
 * NAME
346
 *   gen_user_settings_fields
347
 * INPUTS
348
 *   Pointer to section object
349
 *   Array of initial values for the fields
350
 * RESULT
351
 *   no return value, section object is updated
352
 ******/
353
function gen_user_settings_fields(&$section, $pconfig) {
354

    
355
	gen_webguicss_field($section, $pconfig['webguicss']);
356
	gen_webguifixedmenu_field($section, $pconfig['webguifixedmenu']);
357
	gen_webguihostnamemenu_field($section, $pconfig['webguihostnamemenu']);
358
	gen_dashboardcolumns_field($section, $pconfig['dashboardcolumns']);
359
	gen_associatedpanels_fields(
360
		$section,
361
		$pconfig['dashboardavailablewidgetspanel'],
362
		$pconfig['systemlogsfilterpanel'],
363
		$pconfig['systemlogsmanagelogpanel'],
364
		$pconfig['statusmonitoringsettingspanel']);
365
	gen_webguileftcolumnhyper_field($section, $pconfig['webguileftcolumnhyper']);
366
	gen_pagenamefirst_field($section, $pconfig['pagenamefirst']);
367
}
368

    
369
function hardware_offloading_applyflags($iface) {
370
	global $config;
371

    
372
	$flags_on = 0;
373
	$flags_off = 0;
374
	$options = pfSense_get_interface_addresses($iface);
375

    
376
	if (isset($config['system']['disablechecksumoffloading'])) {
377
		if (isset($options['encaps']['txcsum'])) {
378
			$flags_off |= IFCAP_TXCSUM;
379
		}
380
		if (isset($options['encaps']['rxcsum'])) {
381
			$flags_off |= IFCAP_RXCSUM;
382
		}
383
		if (isset($options['encaps']['txcsum6'])) {
384
			$flags_off |= IFCAP_TXCSUM_IPV6;
385
		}
386
		if (isset($options['encaps']['rxcsum6'])) {
387
			$flags_off |= IFCAP_RXCSUM_IPV6;
388
		}
389
	} else {
390
		if (isset($options['caps']['txcsum'])) {
391
			$flags_on |= IFCAP_TXCSUM;
392
		}
393
		if (isset($options['caps']['rxcsum'])) {
394
			$flags_on |= IFCAP_RXCSUM;
395
		}
396
		if (isset($options['caps']['txcsum6'])) {
397
			$flags_on |= IFCAP_TXCSUM_IPV6;
398
		}
399
		if (isset($options['caps']['rxcsum6'])) {
400
			$flags_on |= IFCAP_RXCSUM_IPV6;
401
		}
402
	}
403

    
404
	if (isset($config['system']['disablesegmentationoffloading'])) {
405
		$flags_off |= IFCAP_TSO;
406
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
407
		$flags_on |= IFCAP_TSO;
408
	}
409

    
410
	if (isset($config['system']['disablelargereceiveoffloading'])) {
411
		$flags_off |= IFCAP_LRO;
412
	} else if (isset($options['caps']['lro'])) {
413
		$flags_on |= IFCAP_LRO;
414
	}
415

    
416
	/* if the NIC supports polling *AND* it is enabled in the GUI */
417
	if (!isset($config['system']['polling'])) {
418
		$flags_off |= IFCAP_POLLING;
419
	} else if (isset($options['caps']['polling'])) {
420
		$flags_on |= IFCAP_POLLING;
421
	}
422

    
423
	pfSense_interface_capabilities($iface, -$flags_off);
424
	pfSense_interface_capabilities($iface, $flags_on);
425
}
426

    
427
/****f* pfsense-utils/enable_hardware_offloading
428
 * NAME
429
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
430
 * INPUTS
431
 *   $interface	- string containing the physical interface to work on.
432
 * RESULT
433
 *   null
434
 * NOTES
435
 *   This function only supports the fxp driver's loadable microcode.
436
 ******/
437
function enable_hardware_offloading($interface) {
438
	global $g, $config;
439

    
440
	$int = get_real_interface($interface);
441
	if (empty($int)) {
442
		return;
443
	}
444

    
445
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
446
		/* translate wan, lan, opt -> real interface if needed */
447
		$int_family = preg_split("/[0-9]+/", $int);
448
		$supported_ints = array('fxp');
449
		if (in_array($int_family, $supported_ints)) {
450
			if (does_interface_exist($int)) {
451
				pfSense_interface_flags($int, IFF_LINK0);
452
			}
453
		}
454
	}
455

    
456
	/* This is mostly for vlans and ppp types */
457
	$realhwif = get_parent_interface($interface);
458
	if ($realhwif[0] == $int) {
459
		hardware_offloading_applyflags($int);
460
	} else {
461
		hardware_offloading_applyflags($realhwif[0]);
462
		hardware_offloading_applyflags($int);
463
	}
464
}
465

    
466
/****f* pfsense-utils/interface_supports_polling
467
 * NAME
468
 *   checks to see if an interface supports polling according to man polling
469
 * INPUTS
470
 *
471
 * RESULT
472
 *   true or false
473
 * NOTES
474
 *
475
 ******/
476
function interface_supports_polling($iface) {
477
	$opts = pfSense_get_interface_addresses($iface);
478
	if (is_array($opts) && isset($opts['caps']['polling'])) {
479
		return true;
480
	}
481

    
482
	return false;
483
}
484

    
485
/****f* pfsense-utils/is_alias_inuse
486
 * NAME
487
 *   checks to see if an alias is currently in use by a rule
488
 * INPUTS
489
 *
490
 * RESULT
491
 *   true or false
492
 * NOTES
493
 *
494
 ******/
495
function is_alias_inuse($alias) {
496
	global $g, $config;
497

    
498
	if ($alias == "") {
499
		return false;
500
	}
501
	/* loop through firewall rules looking for alias in use */
502
	if (is_array($config['filter']['rule'])) {
503
		foreach ($config['filter']['rule'] as $rule) {
504
			if ($rule['source']['address']) {
505
				if ($rule['source']['address'] == $alias) {
506
					return true;
507
				}
508
			}
509
			if ($rule['destination']['address']) {
510
				if ($rule['destination']['address'] == $alias) {
511
					return true;
512
				}
513
			}
514
		}
515
	}
516
	/* loop through nat rules looking for alias in use */
517
	if (is_array($config['nat']['rule'])) {
518
		foreach ($config['nat']['rule'] as $rule) {
519
			if ($rule['target'] && $rule['target'] == $alias) {
520
				return true;
521
			}
522
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
523
				return true;
524
			}
525
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
526
				return true;
527
			}
528
		}
529
	}
530
	return false;
531
}
532

    
533
/****f* pfsense-utils/is_schedule_inuse
534
 * NAME
535
 *   checks to see if a schedule is currently in use by a rule
536
 * INPUTS
537
 *
538
 * RESULT
539
 *   true or false
540
 * NOTES
541
 *
542
 ******/
543
function is_schedule_inuse($schedule) {
544
	global $g, $config;
545

    
546
	if ($schedule == "") {
547
		return false;
548
	}
549
	/* loop through firewall rules looking for schedule in use */
550
	if (is_array($config['filter']['rule'])) {
551
		foreach ($config['filter']['rule'] as $rule) {
552
			if ($rule['sched'] == $schedule) {
553
				return true;
554
			}
555
		}
556
	}
557
	return false;
558
}
559

    
560
/****f* pfsense-utils/setup_polling
561
 * NAME
562
 *   sets up polling
563
 * INPUTS
564
 *
565
 * RESULT
566
 *   null
567
 * NOTES
568
 *
569
 ******/
570
function setup_polling() {
571
	global $g, $config;
572

    
573
	if (isset($config['system']['polling'])) {
574
		set_single_sysctl("kern.polling.idle_poll", "1");
575
	} else {
576
		set_single_sysctl("kern.polling.idle_poll", "0");
577
	}
578

    
579
	if ($config['system']['polling_each_burst']) {
580
		set_single_sysctl("kern.polling.each_burst", $config['system']['polling_each_burst']);
581
	}
582
	if ($config['system']['polling_burst_max']) {
583
		set_single_sysctl("kern.polling.burst_max", $config['system']['polling_burst_max']);
584
	}
585
	if ($config['system']['polling_user_frac']) {
586
		set_single_sysctl("kern.polling.user_frac", $config['system']['polling_user_frac']);
587
	}
588
}
589

    
590
/****f* pfsense-utils/setup_microcode
591
 * NAME
592
 *   enumerates all interfaces and calls enable_hardware_offloading which
593
 *   enables a NIC's supported hardware features.
594
 * INPUTS
595
 *
596
 * RESULT
597
 *   null
598
 * NOTES
599
 *   This function only supports the fxp driver's loadable microcode.
600
 ******/
601
function setup_microcode() {
602

    
603
	/* if list */
604
	$iflist = get_configured_interface_list(false, true);
605
	foreach ($iflist as $if => $ifdescr) {
606
		enable_hardware_offloading($if);
607
	}
608
	unset($iflist);
609
}
610

    
611
/****f* pfsense-utils/get_carp_status
612
 * NAME
613
 *   get_carp_status - Return whether CARP is enabled or disabled.
614
 * RESULT
615
 *   boolean	- true if CARP is enabled, false if otherwise.
616
 ******/
617
function get_carp_status() {
618
	/* grab the current status of carp */
619
	$status = get_single_sysctl('net.inet.carp.allow');
620
	return (intval($status) > 0);
621
}
622

    
623
/*
624
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
625

    
626
 */
627
function convert_ip_to_network_format($ip, $subnet) {
628
	$ipsplit = explode('.', $ip);
629
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
630
	return $string;
631
}
632

    
633
/*
634
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
635
 */
636
function get_carp_interface_status($carpid) {
637

    
638
	$carpiface = get_configured_vip_interface($carpid);
639
	if ($carpiface == NULL)
640
		return "";
641
	$interface = get_real_interface($carpiface);
642
	if ($interface == NULL)
643
		return "";
644
	$vip = get_configured_vip($carpid);
645
	if ($vip == NULL || !isset($vip['vhid']))
646
		return "";
647

    
648
	$vhid = $vip['vhid'];
649
	$carp_query = '';
650
	$_gb = exec("/sbin/ifconfig $interface | /usr/bin/grep carp: | /usr/bin/grep \"vhid $vhid\"", $carp_query);
651
	foreach ($carp_query as $int) {
652
		if (stripos($int, "MASTER"))
653
			return "MASTER";
654
		elseif (stripos($int, "BACKUP"))
655
			return "BACKUP";
656
		elseif (stripos($int, "INIT"))
657
			return "INIT";
658
	}
659

    
660
	return "";
661
}
662

    
663
/*
664
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
665
 */
666
function get_pfsync_interface_status($pfsyncinterface) {
667
	if (!does_interface_exist($pfsyncinterface)) {
668
		return;
669
	}
670

    
671
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
672
}
673

    
674
/*
675
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
676
 */
677
function add_rule_to_anchor($anchor, $rule, $label) {
678
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
679
}
680

    
681
/*
682
 * remove_text_from_file
683
 * remove $text from file $file
684
 */
685
function remove_text_from_file($file, $text) {
686
	if (!file_exists($file) && !is_writable($file)) {
687
		return;
688
	}
689
	$filecontents = file_get_contents($file);
690
	$text = str_replace($text, "", $filecontents);
691
	@file_put_contents($file, $text);
692
}
693

    
694
/*
695
 *   after_sync_bump_adv_skew(): create skew values by 1S
696
 */
697
function after_sync_bump_adv_skew() {
698
	global $config, $g;
699
	$processed_skew = 1;
700
	$a_vip = &$config['virtualip']['vip'];
701
	foreach ($a_vip as $vipent) {
702
		if ($vipent['advskew'] <> "") {
703
			$processed_skew = 1;
704
			$vipent['advskew'] = $vipent['advskew']+1;
705
		}
706
	}
707
	if ($processed_skew == 1) {
708
		write_config(gettext("After synch increase advertising skew"));
709
	}
710
}
711

    
712
/*
713
 * get_filename_from_url($url): converts a url to its filename.
714
 */
715
function get_filename_from_url($url) {
716
	return basename($url);
717
}
718

    
719
/*
720
 *   get_dir: return an array of $dir
721
 */
722
function get_dir($dir) {
723
	$dir_array = array();
724
	$d = dir($dir);
725
	if (!is_object($d)) {
726
		return array();
727
	}
728
	while (false !== ($entry = $d->read())) {
729
		array_push($dir_array, $entry);
730
	}
731
	$d->close();
732
	return $dir_array;
733
}
734

    
735
/****f* pfsense-utils/WakeOnLan
736
 * NAME
737
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
738
 * RESULT
739
 *   true/false - true if the operation was successful
740
 ******/
741
function WakeOnLan($addr, $mac) {
742
	$addr_byte = explode(':', $mac);
743
	$hw_addr = '';
744

    
745
	for ($a = 0; $a < 6; $a++) {
746
		$hw_addr .= chr(hexdec($addr_byte[$a]));
747
	}
748

    
749
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
750

    
751
	for ($a = 1; $a <= 16; $a++) {
752
		$msg .= $hw_addr;
753
	}
754

    
755
	// send it to the broadcast address using UDP
756
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
757
	if ($s == false) {
758
		log_error(gettext("Error creating socket!"));
759
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
760
	} else {
761
		// setting a broadcast option to socket:
762
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
763
		if ($opt_ret < 0) {
764
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
765
		}
766
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
767
		socket_close($s);
768
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
769
		return true;
770
	}
771

    
772
	return false;
773
}
774

    
775
/*
776
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
777
 *					 Useful for finding paths and stripping file extensions.
778
 */
779
function reverse_strrchr($haystack, $needle) {
780
	if (!is_string($haystack)) {
781
		return;
782
	}
783
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
784
}
785

    
786
/*
787
 *  backup_config_section($section): returns as an xml file string of
788
 *                                   the configuration section
789
 */
790
function backup_config_section($section_name) {
791
	global $config;
792
	$new_section = &$config[$section_name];
793
	/* generate configuration XML */
794
	$xmlconfig = dump_xml_config($new_section, $section_name);
795
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
796
	return $xmlconfig;
797
}
798

    
799
/*
800
 *  restore_config_section($section_name, new_contents): restore a configuration section,
801
 *                                                  and write the configuration out
802
 *                                                  to disk/cf.
803
 */
804
function restore_config_section($section_name, $new_contents) {
805
	global $config, $g;
806
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
807
	fwrite($fout, $new_contents);
808
	fclose($fout);
809

    
810
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
811
	if ($xml['pfsense']) {
812
		$xml = $xml['pfsense'];
813
	}
814
	else if ($xml['m0n0wall']) {
815
		$xml = $xml['m0n0wall'];
816
	}
817
	if ($xml[$section_name]) {
818
		$section_xml = $xml[$section_name];
819
	} else {
820
		$section_xml = -1;
821
	}
822

    
823
	@unlink($g['tmp_path'] . "/tmpxml");
824
	if ($section_xml === -1) {
825
		return false;
826
	}
827
	$config[$section_name] = &$section_xml;
828
	if (file_exists("{$g['tmp_path']}/config.cache")) {
829
		unlink("{$g['tmp_path']}/config.cache");
830
	}
831
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
832
	disable_security_checks();
833
	return true;
834
}
835

    
836
/*
837
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
838
 *                                                  and write the configuration out
839
 *                                                  to disk/cf.  But preserve the prior
840
 * 													structure if needed
841
 */
842
function merge_config_section($section_name, $new_contents) {
843
	global $config;
844
	$fname = get_tmp_filename();
845
	$fout = fopen($fname, "w");
846
	fwrite($fout, $new_contents);
847
	fclose($fout);
848
	$section_xml = parse_xml_config($fname, $section_name);
849
	$config[$section_name] = $section_xml;
850
	unlink($fname);
851
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
852
	disable_security_checks();
853
	return;
854
}
855

    
856
/*
857
 *  php_check_syntax($code_tocheck, $errormessage): checks $code_to_check for errors
858
 */
859
if (!function_exists('php_check_syntax')) {
860
	global $g;
861
	function php_check_syntax($code_to_check, &$errormessage) {
862
		return false;
863
		$fout = fopen("{$g['tmp_path']}/codetocheck.php", "w");
864
		$code = $_POST['content'];
865
		$code = str_replace("<?php", "", $code);
866
		$code = str_replace("?>", "", $code);
867
		fwrite($fout, "<?php\n\n");
868
		fwrite($fout, $code_to_check);
869
		fwrite($fout, "\n\n?>\n");
870
		fclose($fout);
871
		$command = "/usr/local/bin/php-cgi -l {$g['tmp_path']}/codetocheck.php";
872
		$output = exec_command($command);
873
		if (stristr($output, "Errors parsing") == false) {
874
			echo "false\n";
875
			$errormessage = '';
876
			return(false);
877
		} else {
878
			$errormessage = $output;
879
			return(true);
880
		}
881
	}
882
}
883

    
884
/*
885
 *  php_check_filename_syntax($filename, $errormessage): checks the file $filename for errors
886
 */
887
if (!function_exists('php_check_syntax')) {
888
	function php_check_syntax($code_to_check, &$errormessage) {
889
		return false;
890
		$command = "/usr/local/bin/php-cgi -l " . escapeshellarg($code_to_check);
891
		$output = exec_command($command);
892
		if (stristr($output, "Errors parsing") == false) {
893
			echo "false\n";
894
			$errormessage = '';
895
			return(false);
896
		} else {
897
			$errormessage = $output;
898
			return(true);
899
		}
900
	}
901
}
902

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

    
934
/*
935
 * host_firmware_version(): Return the versions used in this install
936
 */
937
function host_firmware_version($tocheck = "") {
938
	global $g, $config;
939

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

    
942
	return array(
943
		"firmware" => array("version" => $g['product_version']),
944
		"kernel"   => array("version" => $os_version),
945
		"base"     => array("version" => $os_version),
946
		"platform" => $g['platform'],
947
		"config_version" => $config['version']
948
	);
949
}
950

    
951
function get_disk_info() {
952
	$diskout = "";
953
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
954
	return explode(' ', $diskout[0]);
955
}
956

    
957
/****f* pfsense-utils/strncpy
958
 * NAME
959
 *   strncpy - copy strings
960
 * INPUTS
961
 *   &$dst, $src, $length
962
 * RESULT
963
 *   none
964
 ******/
965
function strncpy(&$dst, $src, $length) {
966
	if (strlen($src) > $length) {
967
		$dst = substr($src, 0, $length);
968
	} else {
969
		$dst = $src;
970
	}
971
}
972

    
973
/****f* pfsense-utils/reload_interfaces_sync
974
 * NAME
975
 *   reload_interfaces - reload all interfaces
976
 * INPUTS
977
 *   none
978
 * RESULT
979
 *   none
980
 ******/
981
function reload_interfaces_sync() {
982
	global $config, $g;
983

    
984
	if ($g['debug']) {
985
		log_error(gettext("reload_interfaces_sync() is starting."));
986
	}
987

    
988
	/* parse config.xml again */
989
	$config = parse_config(true);
990

    
991
	/* enable routing */
992
	system_routing_enable();
993
	if ($g['debug']) {
994
		log_error(gettext("Enabling system routing"));
995
	}
996

    
997
	if ($g['debug']) {
998
		log_error(gettext("Cleaning up Interfaces"));
999
	}
1000

    
1001
	/* set up interfaces */
1002
	interfaces_configure();
1003
}
1004

    
1005
/****f* pfsense-utils/reload_all
1006
 * NAME
1007
 *   reload_all - triggers a reload of all settings
1008
 *   * INPUTS
1009
 *   none
1010
 * RESULT
1011
 *   none
1012
 ******/
1013
function reload_all() {
1014
	send_event("service reload all");
1015
}
1016

    
1017
/****f* pfsense-utils/reload_interfaces
1018
 * NAME
1019
 *   reload_interfaces - triggers a reload of all interfaces
1020
 * INPUTS
1021
 *   none
1022
 * RESULT
1023
 *   none
1024
 ******/
1025
function reload_interfaces() {
1026
	send_event("interface all reload");
1027
}
1028

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

    
1040
	/* parse config.xml again */
1041
	$config = parse_config(true);
1042

    
1043
	/* set up our timezone */
1044
	system_timezone_configure();
1045

    
1046
	/* set up our hostname */
1047
	system_hostname_configure();
1048

    
1049
	/* make hosts file */
1050
	system_hosts_generate();
1051

    
1052
	/* generate resolv.conf */
1053
	system_resolvconf_generate();
1054

    
1055
	/* enable routing */
1056
	system_routing_enable();
1057

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

    
1061
	/* start dyndns service */
1062
	services_dyndns_configure();
1063

    
1064
	/* configure cron service */
1065
	configure_cron();
1066

    
1067
	/* start the NTP client */
1068
	system_ntp_configure();
1069

    
1070
	/* sync pw database */
1071
	unlink_if_exists("/etc/spwd.db.tmp");
1072
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1073

    
1074
	/* restart sshd */
1075
	send_event("service restart sshd");
1076

    
1077
	/* restart webConfigurator if needed */
1078
	send_event("service restart webgui");
1079
}
1080

    
1081
function setup_serial_port($when = "save", $path = "") {
1082
	global $g, $config;
1083
	$ttys_file = "{$path}/etc/ttys";
1084
	$boot_config_file = "{$path}/boot.config";
1085
	$loader_conf_file = "{$path}/boot/loader.conf";
1086
	/* serial console - write out /boot.config */
1087
	if (file_exists($boot_config_file)) {
1088
		$boot_config = file_get_contents($boot_config_file);
1089
	} else {
1090
		$boot_config = "";
1091
	}
1092

    
1093
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1094
	$serial_only = false;
1095

    
1096
	$specific_platform = system_identify_specific_platform();
1097
	if ($specific_platform['name'] == 'RCC-VE' ||
1098
	    $specific_platform['name'] == 'RCC' ||
1099
	    $specific_platform['name'] == 'RCC-DFF') {
1100
		$serial_only = true;
1101
	}
1102

    
1103
	$boot_config_split = explode("\n", $boot_config);
1104
	$data = array();
1105
	foreach ($boot_config_split as $bcs) {
1106
		/* Ignore -D and -h lines now */
1107
		if (!empty($bcs) && !stristr($bcs, "-D") &&
1108
		    !stristr($bcs, "-h")) {
1109
			$data[] = $bcs;
1110
		}
1111
	}
1112
	if ($serial_only === true) {
1113
		$data[] = "-S{$serialspeed} -h";
1114
	} elseif (is_serial_enabled()) {
1115
		$data[] = "-S{$serialspeed} -D";
1116
	}
1117

    
1118
	if (empty($data)) {
1119
		@unlink($boot_conf_file);
1120
	} else {
1121
		safe_write_file($boot_config_file, $data);
1122
	}
1123

    
1124
	unset($boot_config, $boot_config_file, $boot_config_split);
1125

    
1126
	/* serial console - write out /boot/loader.conf */
1127
	if ($when == "upgrade") {
1128
		system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1129
	}
1130

    
1131
	$loader_conf = file_get_contents($loader_conf_file);
1132
	$loader_conf_split = explode("\n", $loader_conf);
1133

    
1134
	$data = array();
1135
	// Loop through and only add lines that are not empty, and which
1136
	//  do not contain a console directive.
1137
	foreach ($loader_conf_split as $bcs) {
1138
		if (!empty($bcs) &&
1139
		    (stripos($bcs, "console") === false) &&
1140
		    (stripos($bcs, "boot_multicons") === false) &&
1141
		    (stripos($bcs, "boot_serial") === false) &&
1142
		    (stripos($bcs, "hw.usb.no_pf") === false) &&
1143
		    (stripos($bcs, "hint.uart.0.flags") === false) &&
1144
		    (stripos($bcs, "hint.uart.1.flags") === false)) {
1145
			$data[] = $bcs;
1146
		}
1147
	}
1148

    
1149
	if ($serial_only === true) {
1150
		$data[] = 'boot_serial="YES"';
1151
		$data[] = 'console="comconsole"';
1152
	} else if (is_serial_enabled()) {
1153
		$data[] = 'boot_multicons="YES"';
1154
		$data[] = 'boot_serial="YES"';
1155
		$primaryconsole = isset($g['primaryconsole_force']) ?
1156
		    $g['primaryconsole_force'] :
1157
		    $config['system']['primaryconsole'];
1158
		switch ($primaryconsole) {
1159
			case "video":
1160
				$data[] = 'console="vidconsole,comconsole"';
1161
				break;
1162
			case "serial":
1163
			default:
1164
				$data[] = 'console="comconsole,vidconsole"';
1165
		}
1166
	}
1167
	$data[] = 'comconsole_speed="' . $serialspeed . '"';
1168

    
1169
	$specplatform = system_identify_specific_platform();
1170
	if ($specplatform['name'] == 'RCC-VE' ||
1171
	    $specplatform['name'] == 'RCC' ||
1172
	    $specplatform['name'] == 'RCC-DFF') {
1173
		$data[] = 'comconsole_port="0x2F8"';
1174
		$data[] = 'hint.uart.0.flags="0x00"';
1175
		$data[] = 'hint.uart.1.flags="0x10"';
1176
	}
1177
	$data[] = 'hw.usb.no_pf="1"';
1178

    
1179
	safe_write_file($loader_conf_file, $data);
1180

    
1181
	unset($loader_conf, $loader_conf_split, $loader_config_file);
1182

    
1183
	$ttys = file_get_contents($ttys_file);
1184
	$ttys_split = explode("\n", $ttys);
1185

    
1186
	$data = array();
1187

    
1188
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1189

    
1190
	if (isset($config['system']['disableconsolemenu'])) {
1191
		$console_type = 'Pc';
1192
		$serial_type = '3wire';
1193
	} else {
1194
		$console_type = 'al.Pc';
1195
		$serial_type = 'al.3wire';
1196
	}
1197

    
1198
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1199
	$ttyv0_line =
1200
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\ton\tsecure";
1201
	$ttyu_line =
1202
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1203

    
1204
	$found = array();
1205

    
1206
	foreach ($ttys_split as $tty) {
1207
		/* Ignore blank lines */
1208
		if (empty($tty)) {
1209
			continue;
1210
		}
1211

    
1212
		if (stristr($tty, "ttyv0")) {
1213
			$found['ttyv0'] = 1;
1214
			$data[] = $ttyv0_line;
1215
		} elseif (stristr($tty, "ttyu")) {
1216
			$ttyn = substr($tty, 0, 5);
1217
			$found[$ttyn] = 1;
1218
			$data[] = "{$ttyn}\t{$ttyu_line}";
1219
		} elseif (substr($tty, 0, 7) == 'console') {
1220
			$found['console'] = 1;
1221
			$data[] = $tty;
1222
		} else {
1223
			$data[] = $tty;
1224
		}
1225
	}
1226
	unset($on_off, $console_type, $serial_type);
1227

    
1228
	/* Detect missing main lines on original file and try to rebuild it */
1229
	$items = array(
1230
		'console',
1231
		'ttyv0',
1232
		'ttyu0',
1233
		'ttyu1',
1234
		'ttyu2',
1235
		'ttyu3'
1236
	);
1237

    
1238
	foreach ($items as $item) {
1239
		if (isset($found[$item])) {
1240
			continue;
1241
		}
1242

    
1243
		if ($item == 'console') {
1244
			$data[] = $console_line;
1245
		} elseif ($item == 'ttyv0') {
1246
			$data[] = $ttyv0_line;
1247
		} else {
1248
			$data[] = "{$item}\t{$ttyu_line}";
1249
		}
1250
	}
1251

    
1252
	safe_write_file($ttys_file, $data);
1253

    
1254
	unset($ttys, $ttys_file, $ttys_split, $data);
1255

    
1256
	if ($when != "upgrade") {
1257
		reload_ttys();
1258
	}
1259

    
1260
	return;
1261
}
1262

    
1263
function is_serial_enabled() {
1264
	global $g, $config;
1265

    
1266
	if (!isset($g['enableserial_force']) &&
1267
	    !isset($config['system']['enableserial'])) {
1268
		return false;
1269
	}
1270

    
1271
	return true;
1272
}
1273

    
1274
function reload_ttys() {
1275
	// Send a HUP signal to init will make it reload /etc/ttys
1276
	posix_kill(1, SIGHUP);
1277
}
1278

    
1279
function print_value_list($list, $count = 10, $separator = ",") {
1280
	$list = implode($separator, array_slice($list, 0, $count));
1281
	if (count($list) < $count) {
1282
		$list .= ".";
1283
	} else {
1284
		$list .= "...";
1285
	}
1286
	return $list;
1287
}
1288

    
1289
/* DHCP enabled on any interfaces? */
1290
function is_dhcp_server_enabled() {
1291
	global $config;
1292

    
1293
	if (!is_array($config['dhcpd'])) {
1294
		return false;
1295
	}
1296

    
1297
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1298
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1299
			return true;
1300
		}
1301
	}
1302

    
1303
	return false;
1304
}
1305

    
1306
/* DHCP enabled on any interfaces? */
1307
function is_dhcpv6_server_enabled() {
1308
	global $config;
1309

    
1310
	if (is_array($config['interfaces'])) {
1311
		foreach ($config['interfaces'] as $ifcfg) {
1312
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1313
				return true;
1314
			}
1315
		}
1316
	}
1317

    
1318
	if (!is_array($config['dhcpdv6'])) {
1319
		return false;
1320
	}
1321

    
1322
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1323
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1324
			return true;
1325
		}
1326
	}
1327

    
1328
	return false;
1329
}
1330

    
1331
/* radvd enabled on any interfaces? */
1332
function is_radvd_enabled() {
1333
	global $config;
1334

    
1335
	if (!is_array($config['dhcpdv6'])) {
1336
		$config['dhcpdv6'] = array();
1337
	}
1338

    
1339
	$dhcpdv6cfg = $config['dhcpdv6'];
1340
	$Iflist = get_configured_interface_list();
1341

    
1342
	/* handle manually configured DHCP6 server settings first */
1343
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1344
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1345
			continue;
1346
		}
1347

    
1348
		if (!isset($dhcpv6ifconf['ramode'])) {
1349
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1350
		}
1351

    
1352
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1353
			continue;
1354
		}
1355

    
1356
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1357
		if (!is_ipaddrv6($ifcfgipv6)) {
1358
			continue;
1359
		}
1360

    
1361
		return true;
1362
	}
1363

    
1364
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1365
	foreach ($Iflist as $if => $ifdescr) {
1366
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1367
			continue;
1368
		}
1369
		if (!isset($config['interfaces'][$if]['enable'])) {
1370
			continue;
1371
		}
1372

    
1373
		$ifcfgipv6 = get_interface_ipv6($if);
1374
		if (!is_ipaddrv6($ifcfgipv6)) {
1375
			continue;
1376
		}
1377

    
1378
		$ifcfgsnv6 = get_interface_subnetv6($if);
1379
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1380

    
1381
		if (!is_ipaddrv6($subnetv6)) {
1382
			continue;
1383
		}
1384

    
1385
		return true;
1386
	}
1387

    
1388
	return false;
1389
}
1390

    
1391
/* Any PPPoE servers enabled? */
1392
function is_pppoe_server_enabled() {
1393
	global $config;
1394

    
1395
	$pppoeenable = false;
1396

    
1397
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1398
		return false;
1399
	}
1400

    
1401
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1402
		if ($pppoes['mode'] == 'server') {
1403
			$pppoeenable = true;
1404
		}
1405
	}
1406

    
1407
	return $pppoeenable;
1408
}
1409

    
1410
/* Optional arg forces hh:mm:ss without days */
1411
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1412
	if (!is_numericint($sec)) {
1413
		return '-';
1414
	}
1415
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1416
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1417
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1418
					(int)(($sec % 3600)/60),
1419
					$sec % 60
1420
				);
1421
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1422
}
1423

    
1424
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1425

    
1426
function get_ppp_uptime($port) {
1427
	if (file_exists("/conf/{$port}.log")) {
1428
		$saved_time = file_get_contents("/conf/{$port}.log");
1429
		$uptime_data = explode("\n", $saved_time);
1430
		$sec = 0;
1431
		foreach ($uptime_data as $upt) {
1432
			$sec += substr($upt, 1 + strpos($upt, " "));
1433
		}
1434
		return convert_seconds_to_dhms($sec);
1435
	} else {
1436
		$total_time = gettext("No history data found!");
1437
		return $total_time;
1438
	}
1439
}
1440

    
1441
//returns interface information
1442
function get_interface_info($ifdescr) {
1443
	global $config, $g;
1444

    
1445
	$ifinfo = array();
1446
	if (empty($config['interfaces'][$ifdescr])) {
1447
		return;
1448
	}
1449
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1450
	$ifinfo['if'] = get_real_interface($ifdescr);
1451

    
1452
	$chkif = $ifinfo['if'];
1453
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1454
	$ifinfo['status'] = $ifinfotmp['status'];
1455
	if (empty($ifinfo['status'])) {
1456
		$ifinfo['status'] = "down";
1457
	}
1458
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1459
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1460
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1461
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1462
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1463
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1464
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1465
	if (isset($ifinfotmp['link0'])) {
1466
		$link0 = "down";
1467
	}
1468
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1469
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1470
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1471
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1472
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1473
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1474

    
1475
	/* Use pfctl for non wrapping 64 bit counters */
1476
	/* Pass */
1477
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1478
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1479
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1480
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1481
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1482
	$in4_pass = $pf_in4_pass[5];
1483
	$out4_pass = $pf_out4_pass[5];
1484
	$in4_pass_packets = $pf_in4_pass[3];
1485
	$out4_pass_packets = $pf_out4_pass[3];
1486
	$in6_pass = $pf_in6_pass[5];
1487
	$out6_pass = $pf_out6_pass[5];
1488
	$in6_pass_packets = $pf_in6_pass[3];
1489
	$out6_pass_packets = $pf_out6_pass[3];
1490
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1491
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1492
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1493
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1494

    
1495
	/* Block */
1496
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1497
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1498
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1499
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1500
	$in4_block = $pf_in4_block[5];
1501
	$out4_block = $pf_out4_block[5];
1502
	$in4_block_packets = $pf_in4_block[3];
1503
	$out4_block_packets = $pf_out4_block[3];
1504
	$in6_block = $pf_in6_block[5];
1505
	$out6_block = $pf_out6_block[5];
1506
	$in6_block_packets = $pf_in6_block[3];
1507
	$out6_block_packets = $pf_out6_block[3];
1508
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1509
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1510
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1511
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1512

    
1513
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1514
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1515
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1516
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1517

    
1518
	$ifconfiginfo = "";
1519
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1520
	switch ($link_type) {
1521
		/* DHCP? -> see if dhclient is up */
1522
		case "dhcp":
1523
			/* see if dhclient is up */
1524
			if (find_dhclient_process($ifinfo['if']) != 0) {
1525
				$ifinfo['dhcplink'] = "up";
1526
			} else {
1527
				$ifinfo['dhcplink'] = "down";
1528
			}
1529

    
1530
			break;
1531
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1532
		case "pppoe":
1533
		case "pptp":
1534
		case "l2tp":
1535
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1536
				/* get PPPoE link status for dial on demand */
1537
				$ifinfo["{$link_type}link"] = "up";
1538
			} else {
1539
				$ifinfo["{$link_type}link"] = "down";
1540
			}
1541

    
1542
			break;
1543
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1544
		case "ppp":
1545
			if ($ifinfo['status'] == "up") {
1546
				$ifinfo['ppplink'] = "up";
1547
			} else {
1548
				$ifinfo['ppplink'] = "down" ;
1549
			}
1550

    
1551
			if (empty($ifinfo['status'])) {
1552
				$ifinfo['status'] = "down";
1553
			}
1554

    
1555
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1556
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1557
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1558
						break;
1559
					}
1560
				}
1561
			}
1562
			$dev = $ppp['ports'];
1563
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1564
				break;
1565
			}
1566
			if (!file_exists($dev)) {
1567
				$ifinfo['nodevice'] = 1;
1568
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1569
			}
1570

    
1571
			$usbmodemoutput = array();
1572
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1573
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1574
			if (file_exists($mondev)) {
1575
				$cellstats = file($mondev);
1576
				/* skip header */
1577
				$a_cellstats = explode(",", $cellstats[1]);
1578
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1579
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1580
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1581
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1582
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1583
				}
1584
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1585
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1586
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1587
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1588
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1589
				}
1590
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1591
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1592
				$ifinfo['cell_sent'] = $a_cellstats[6];
1593
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1594
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1595
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1596
			}
1597
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1598
			if (isset($ppp['uptime'])) {
1599
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1600
			}
1601
			break;
1602
		default:
1603
			break;
1604
	}
1605

    
1606
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1607
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1608
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1609
	}
1610

    
1611
	if ($ifinfo['status'] == "up") {
1612
		/* try to determine media with ifconfig */
1613
		unset($ifconfiginfo);
1614
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1615
		$wifconfiginfo = array();
1616
		if (is_interface_wireless($ifdescr)) {
1617
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1618
			array_shift($wifconfiginfo);
1619
		}
1620
		$matches = "";
1621
		foreach ($ifconfiginfo as $ici) {
1622

    
1623
			/* don't list media/speed for wireless cards, as it always
1624
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1625
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1626
				$ifinfo['media'] = $matches[1];
1627
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1628
				$ifinfo['media'] = $matches[1];
1629
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1630
				$ifinfo['media'] = $matches[1];
1631
			}
1632

    
1633
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1634
				if ($matches[1] != "active") {
1635
					$ifinfo['status'] = $matches[1];
1636
				}
1637
				if ($ifinfo['status'] == gettext("running")) {
1638
					$ifinfo['status'] = gettext("up");
1639
				}
1640
			}
1641
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1642
				$ifinfo['channel'] = $matches[1];
1643
			}
1644
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1645
				if ($matches[1][0] == '"') {
1646
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1647
				}
1648
				else {
1649
					$ifinfo['ssid'] = $matches[1];
1650
				}
1651
			}
1652
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1653
				$ifinfo['laggproto'] = $matches[1];
1654
			}
1655
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1656
				$ifinfo['laggport'][] = $matches[1];
1657
			}
1658
		}
1659
		foreach ($wifconfiginfo as $ici) {
1660
			$elements = preg_split("/[ ]+/i", $ici);
1661
			if ($elements[0] != "") {
1662
				$ifinfo['bssid'] = $elements[0];
1663
			}
1664
			if ($elements[3] != "") {
1665
				$ifinfo['rate'] = $elements[3];
1666
			}
1667
			if ($elements[4] != "") {
1668
				$ifinfo['rssi'] = $elements[4];
1669
			}
1670
		}
1671
		/* lookup the gateway */
1672
		if (interface_has_gateway($ifdescr)) {
1673
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1674
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1675
		}
1676
	}
1677

    
1678
	$bridge = "";
1679
	$bridge = link_interface_to_bridge($ifdescr);
1680
	if ($bridge) {
1681
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1682
		if (stristr($bridge_text, "blocking") <> false) {
1683
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1684
			$ifinfo['bridgeint'] = $bridge;
1685
		} else if (stristr($bridge_text, "learning") <> false) {
1686
			$ifinfo['bridge'] = gettext("learning");
1687
			$ifinfo['bridgeint'] = $bridge;
1688
		} else if (stristr($bridge_text, "forwarding") <> false) {
1689
			$ifinfo['bridge'] = gettext("forwarding");
1690
			$ifinfo['bridgeint'] = $bridge;
1691
		}
1692
	}
1693

    
1694
	return $ifinfo;
1695
}
1696

    
1697
//returns cpu speed of processor. Good for determining capabilities of machine
1698
function get_cpu_speed() {
1699
	return get_single_sysctl("hw.clockrate");
1700
}
1701

    
1702
function get_uptime_sec() {
1703
	$boottime = "";
1704
	$matches = "";
1705
	$boottime = get_single_sysctl("kern.boottime");
1706
	preg_match("/sec = (\d+)/", $boottime, $matches);
1707
	$boottime = $matches[1];
1708
	if (intval($boottime) == 0) {
1709
		return 0;
1710
	}
1711

    
1712
	$uptime = time() - $boottime;
1713
	return $uptime;
1714
}
1715

    
1716
function add_hostname_to_watch($hostname) {
1717
	if (!is_dir("/var/db/dnscache")) {
1718
		mkdir("/var/db/dnscache");
1719
	}
1720
	$result = array();
1721
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1722
		$domrecords = array();
1723
		$domips = array();
1724
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1725
		if ($rethost == 0) {
1726
			foreach ($domrecords as $domr) {
1727
				$doml = explode(" ", $domr);
1728
				$domip = $doml[3];
1729
				/* fill array with domain ip addresses */
1730
				if (is_ipaddr($domip)) {
1731
					$domips[] = $domip;
1732
				}
1733
			}
1734
		}
1735
		sort($domips);
1736
		$contents = "";
1737
		if (!empty($domips)) {
1738
			foreach ($domips as $ip) {
1739
				$contents .= "$ip\n";
1740
			}
1741
		}
1742
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1743
		/* Remove empty elements */
1744
		$result = array_filter(explode("\n", $contents), 'strlen');
1745
	}
1746
	return $result;
1747
}
1748

    
1749
function is_fqdn($fqdn) {
1750
	$hostname = false;
1751
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1752
		$hostname = true;
1753
	}
1754
	if (preg_match("/\.\./", $fqdn)) {
1755
		$hostname = false;
1756
	}
1757
	if (preg_match("/^\./i", $fqdn)) {
1758
		$hostname = false;
1759
	}
1760
	if (preg_match("/\//i", $fqdn)) {
1761
		$hostname = false;
1762
	}
1763
	return($hostname);
1764
}
1765

    
1766
function pfsense_default_state_size() {
1767
	/* get system memory amount */
1768
	$memory = get_memory();
1769
	$physmem = $memory[0];
1770
	/* Be cautious and only allocate 10% of system memory to the state table */
1771
	$max_states = (int) ($physmem/10)*1000;
1772
	return $max_states;
1773
}
1774

    
1775
function pfsense_default_tables_size() {
1776
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1777
	return $current;
1778
}
1779

    
1780
function pfsense_default_table_entries_size() {
1781
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1782
	return (trim($current));
1783
}
1784

    
1785
/* Compare the current hostname DNS to the DNS cache we made
1786
 * if it has changed we return the old records
1787
 * if no change we return false */
1788
function compare_hostname_to_dnscache($hostname) {
1789
	if (!is_dir("/var/db/dnscache")) {
1790
		mkdir("/var/db/dnscache");
1791
	}
1792
	$hostname = trim($hostname);
1793
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1794
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1795
	} else {
1796
		$oldcontents = "";
1797
	}
1798
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1799
		$domrecords = array();
1800
		$domips = array();
1801
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1802
		if ($rethost == 0) {
1803
			foreach ($domrecords as $domr) {
1804
				$doml = explode(" ", $domr);
1805
				$domip = $doml[3];
1806
				/* fill array with domain ip addresses */
1807
				if (is_ipaddr($domip)) {
1808
					$domips[] = $domip;
1809
				}
1810
			}
1811
		}
1812
		sort($domips);
1813
		$contents = "";
1814
		if (!empty($domips)) {
1815
			foreach ($domips as $ip) {
1816
				$contents .= "$ip\n";
1817
			}
1818
		}
1819
	}
1820

    
1821
	if (trim($oldcontents) != trim($contents)) {
1822
		if ($g['debug']) {
1823
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1824
		}
1825
		return ($oldcontents);
1826
	} else {
1827
		return false;
1828
	}
1829
}
1830

    
1831
/*
1832
 * load_crypto() - Load crypto modules if enabled in config.
1833
 */
1834
function load_crypto() {
1835
	global $config, $g;
1836
	$crypto_modules = array('aesni');
1837

    
1838
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1839
		return false;
1840
	}
1841

    
1842
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1843
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1844
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1845
	}
1846
}
1847

    
1848
/*
1849
 * load_thermal_hardware() - Load temperature monitor kernel module
1850
 */
1851
function load_thermal_hardware() {
1852
	global $config, $g;
1853
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1854

    
1855
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1856
		return false;
1857
	}
1858

    
1859
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1860
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1861
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1862
	}
1863
}
1864

    
1865
/****f* pfsense-utils/isvm
1866
 * NAME
1867
 *   isvm
1868
 * INPUTS
1869
 *	none
1870
 * RESULT
1871
 *   returns true if machine is running under a virtual environment
1872
 ******/
1873
function isvm() {
1874
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1875
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
1876

    
1877
	if ($rc != 0 || !isset($output[0])) {
1878
		return false;
1879
	}
1880

    
1881
	foreach ($virtualenvs as $virtualenv) {
1882
		if (stripos($output[0], $virtualenv) !== false) {
1883
			return true;
1884
		}
1885
	}
1886

    
1887
	return false;
1888
}
1889

    
1890
function get_freebsd_version() {
1891
	$version = explode(".", php_uname("r"));
1892
	return $version[0];
1893
}
1894

    
1895
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1896
	global $config, $g;
1897

    
1898
	$fp = fopen($destination, "wb");
1899

    
1900
	if (!$fp) {
1901
		return false;
1902
	}
1903

    
1904
	$ch = curl_init();
1905
	curl_setopt($ch, CURLOPT_URL, $url);
1906
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1907
	curl_setopt($ch, CURLOPT_FILE, $fp);
1908
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1909
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1910
	curl_setopt($ch, CURLOPT_HEADER, false);
1911
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1912
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1913
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1914
	} else {
1915
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1916
	}
1917

    
1918
	if (!empty($config['system']['proxyurl'])) {
1919
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1920
		if (!empty($config['system']['proxyport'])) {
1921
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1922
		}
1923
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1924
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1925
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1926
		}
1927
	}
1928

    
1929
	@curl_exec($ch);
1930
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1931
	fclose($fp);
1932
	curl_close($ch);
1933
	if ($http_code == 200) {
1934
		return true;
1935
	} else {
1936
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1937
		unlink_if_exists($destination);
1938
		return false;
1939
	}
1940
}
1941

    
1942
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1943
	global $config, $g;
1944
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1945
	$file_size = 1;
1946
	$downloaded = 1;
1947
	$first_progress_update = TRUE;
1948
	/* open destination file */
1949
	$fout = fopen($destination, "wb");
1950

    
1951
	if (!$fout) {
1952
		return false;
1953
	}
1954
	/*
1955
	 *      Originally by Author: Keyvan Minoukadeh
1956
	 *      Modified by Scott Ullrich to return Content-Length size
1957
	 */
1958
	$ch = curl_init();
1959
	curl_setopt($ch, CURLOPT_URL, $url);
1960
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1961
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
1962
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1963
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
1964
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1965
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1966
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1967
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1968
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1969
	} else {
1970
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1971
	}
1972

    
1973
	if (!empty($config['system']['proxyurl'])) {
1974
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1975
		if (!empty($config['system']['proxyport'])) {
1976
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1977
		}
1978
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1979
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1980
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1981
		}
1982
	}
1983

    
1984
	@curl_exec($ch);
1985
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1986
	fclose($fout);
1987
	curl_close($ch);
1988
	if ($http_code == 200) {
1989
		return true;
1990
	} else {
1991
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1992
		unlink_if_exists($destination);
1993
		return false;
1994
	}
1995
}
1996

    
1997
function read_header($ch, $string) {
1998
	global $file_size, $fout;
1999
	$length = strlen($string);
2000
	$regs = "";
2001
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2002
	if ($regs[2] <> "") {
2003
		$file_size = intval($regs[2]);
2004
	}
2005
	ob_flush();
2006
	return $length;
2007
}
2008

    
2009
function read_body($ch, $string) {
2010
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2011
	global $pkg_interface;
2012
	$length = strlen($string);
2013
	$downloaded += intval($length);
2014
	if ($file_size > 0) {
2015
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2016
		$downloadProgress = 100 - $downloadProgress;
2017
	} else {
2018
		$downloadProgress = 0;
2019
	}
2020
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2021
		if ($sendto == "status") {
2022
			if ($pkg_interface == "console") {
2023
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2024
					$tostatus = $static_status . $downloadProgress . "%";
2025
					if ($downloadProgress == 100) {
2026
						$tostatus = $tostatus . "\r";
2027
					}
2028
					update_status($tostatus);
2029
				}
2030
			} else {
2031
				$tostatus = $static_status . $downloadProgress . "%";
2032
				update_status($tostatus);
2033
			}
2034
		} else {
2035
			if ($pkg_interface == "console") {
2036
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2037
					$tooutput = $static_output . $downloadProgress . "%";
2038
					if ($downloadProgress == 100) {
2039
						$tooutput = $tooutput . "\r";
2040
					}
2041
					update_output_window($tooutput);
2042
				}
2043
			} else {
2044
				$tooutput = $static_output . $downloadProgress . "%";
2045
				update_output_window($tooutput);
2046
			}
2047
		}
2048
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2049
			update_progress_bar($downloadProgress, $first_progress_update);
2050
			$first_progress_update = FALSE;
2051
		}
2052
		$lastseen = $downloadProgress;
2053
	}
2054
	if ($fout) {
2055
		fwrite($fout, $string);
2056
	}
2057
	ob_flush();
2058
	return $length;
2059
}
2060

    
2061
/*
2062
 *   update_output_window: update bottom textarea dynamically.
2063
 */
2064
function update_output_window($text) {
2065
	global $pkg_interface;
2066
	$log = preg_replace("/\n/", "\\n", $text);
2067
	if ($pkg_interface != "console") {
2068
?>
2069
<script type="text/javascript">
2070
//<![CDATA[
2071
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2072
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2073
//]]>
2074
</script>
2075
<?php
2076
	}
2077
	/* ensure that contents are written out */
2078
	ob_flush();
2079
}
2080

    
2081
/*
2082
 *   update_status: update top textarea dynamically.
2083
 */
2084
function update_status($status) {
2085
	global $pkg_interface;
2086

    
2087
	if ($pkg_interface == "console") {
2088
		print ("{$status}");
2089
	}
2090

    
2091
	/* ensure that contents are written out */
2092
	ob_flush();
2093
}
2094

    
2095
/*
2096
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2097
 */
2098
function update_progress_bar($percent, $first_time) {
2099
	global $pkg_interface;
2100
	if ($percent > 100) {
2101
		$percent = 1;
2102
	}
2103
	if ($pkg_interface <> "console") {
2104
		echo '<script type="text/javascript">';
2105
		echo "\n//<![CDATA[\n";
2106
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2107
		echo "\n//]]>\n";
2108
		echo '</script>';
2109
	} else {
2110
		if (!($first_time)) {
2111
			echo "\x08\x08\x08\x08\x08";
2112
		}
2113
		echo sprintf("%4d%%", $percent);
2114
	}
2115
}
2116

    
2117
/* 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. */
2118
if (!function_exists("split")) {
2119
	function split($separator, $haystack, $limit = null) {
2120
		log_error("deprecated split() call with separator '{$separator}'");
2121
		return preg_split($separator, $haystack, $limit);
2122
	}
2123
}
2124

    
2125
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2126
	global $g, $config, $pconfig, $debug;
2127
	if (!$origname) {
2128
		return;
2129
	}
2130

    
2131
	$sectionref = &$config;
2132
	foreach ($section as $sectionname) {
2133
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2134
			$sectionref = &$sectionref[$sectionname];
2135
		} else {
2136
			return;
2137
		}
2138
	}
2139

    
2140
	if ($debug) {
2141
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2142
		fwrite($fd, print_r($pconfig, true));
2143
	}
2144

    
2145
	if (is_array($sectionref)) {
2146
		foreach ($sectionref as $itemkey => $item) {
2147
			if ($debug) {
2148
				fwrite($fd, "$itemkey\n");
2149
			}
2150

    
2151
			$fieldfound = true;
2152
			$fieldref = &$sectionref[$itemkey];
2153
			foreach ($field as $fieldname) {
2154
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2155
					$fieldref = &$fieldref[$fieldname];
2156
				} else {
2157
					$fieldfound = false;
2158
					break;
2159
				}
2160
			}
2161
			if ($fieldfound && $fieldref == $origname) {
2162
				if ($debug) {
2163
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2164
				}
2165
				$fieldref = $new_alias_name;
2166
			}
2167
		}
2168
	}
2169

    
2170
	if ($debug) {
2171
		fclose($fd);
2172
	}
2173

    
2174
}
2175

    
2176
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2177
	/*
2178
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2179
	 * $type = if set to 'url' then subnets and ips will be returned,
2180
	 *         if set to 'url_ports' port-ranges and ports will be returned
2181
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2182
	 *
2183
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2184
	 */
2185

    
2186
	if (!file_exists($filename)) {
2187
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2188
		return null;
2189
	}
2190

    
2191
	if (filesize($filename) == 0) {
2192
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2193
		return null;
2194
	}
2195
	$fd = @fopen($filename, 'r');
2196
	if (!$fd) {
2197
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2198
		return null;
2199
	}
2200
	$items = array();
2201
	$comments = array();
2202
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2203
	while (($fc = fgetss($fd)) !== FALSE) {
2204
		$tmp = trim($fc, " \t\n\r");
2205
		if (empty($tmp)) {
2206
			continue;
2207
		}
2208
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2209
			$comments[] = $tmp;
2210
		} else {
2211
			$tmp_str = strstr($tmp, '#', true);
2212
			if (!empty($tmp_str)) {
2213
				$tmp = $tmp_str;
2214
			}
2215
			$tmp_str = strstr($tmp, ' ', true);
2216
			if (!empty($tmp_str)) {
2217
				$tmp = $tmp_str;
2218
			}
2219
			$valid = (($type == "url" || $type == "urltable") && (is_ipaddr($tmp) || is_subnet($tmp))) ||
2220
				(($type == "url_ports" || $type == "urltable_ports") && (is_port($tmp) || is_portrange($tmp)));
2221
			if ($valid) {
2222
				$items[] = $tmp;
2223
				if (count($items) == $max_items) {
2224
					break;
2225
				}
2226
			}
2227
		}
2228
	}
2229
	fclose($fd);
2230
	return array_merge($comments, $items);
2231
}
2232

    
2233
function update_alias_url_data() {
2234
	global $config, $g;
2235

    
2236
	$updated = false;
2237

    
2238
	/* item is a url type */
2239
	$lockkey = lock('aliasurl');
2240
	if (is_array($config['aliases']['alias'])) {
2241
		foreach ($config['aliases']['alias'] as $x => $alias) {
2242
			if (empty($alias['aliasurl'])) {
2243
				continue;
2244
			}
2245

    
2246
			$address = null;
2247
			foreach ($alias['aliasurl'] as $alias_url) {
2248
				/* fetch down and add in */
2249
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2250
				unlink($temp_filename);
2251
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2252
				mkdir($temp_filename);
2253
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2254
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2255
					continue;
2256
				}
2257

    
2258
				/* if the item is tar gzipped then extract */
2259
				if (stripos($alias_url, '.tgz')) {
2260
					if (!process_alias_tgz($temp_filename)) {
2261
						continue;
2262
					}
2263
				}
2264
				if (file_exists("{$temp_filename}/aliases")) {
2265
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2266
					mwexec("/bin/rm -rf {$temp_filename}");
2267
				}
2268
			}
2269
			if ($address != null) {
2270
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2271
				$updated = true;
2272
			}
2273
		}
2274
	}
2275
	unlock($lockkey);
2276

    
2277
	/* Report status to callers as well */
2278
	return $updated;
2279
}
2280

    
2281
function process_alias_tgz($temp_filename) {
2282
	if (!file_exists('/usr/bin/tar')) {
2283
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2284
		return false;
2285
	}
2286
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2287
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2288
	unlink("{$temp_filename}/aliases.tgz");
2289
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2290
	/* foreach through all extracted files and build up aliases file */
2291
	$fd = @fopen("{$temp_filename}/aliases", "w");
2292
	if (!$fd) {
2293
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2294
		return false;
2295
	}
2296
	foreach ($files_to_process as $f2p) {
2297
		$tmpfd = @fopen($f2p, 'r');
2298
		if (!$tmpfd) {
2299
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2300
			continue;
2301
		}
2302
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2303
			fwrite($fd, $tmpbuf);
2304
		}
2305
		fclose($tmpfd);
2306
		unlink($f2p);
2307
	}
2308
	fclose($fd);
2309
	unset($tmpbuf);
2310

    
2311
	return true;
2312
}
2313

    
2314
function version_compare_dates($a, $b) {
2315
	$a_time = strtotime($a);
2316
	$b_time = strtotime($b);
2317

    
2318
	if ((!$a_time) || (!$b_time)) {
2319
		return FALSE;
2320
	} else {
2321
		if ($a_time < $b_time) {
2322
			return -1;
2323
		} elseif ($a_time == $b_time) {
2324
			return 0;
2325
		} else {
2326
			return 1;
2327
		}
2328
	}
2329
}
2330
function version_get_string_value($a) {
2331
	$strs = array(
2332
		0 => "ALPHA-ALPHA",
2333
		2 => "ALPHA",
2334
		3 => "BETA",
2335
		4 => "B",
2336
		5 => "C",
2337
		6 => "D",
2338
		7 => "RC",
2339
		8 => "RELEASE",
2340
		9 => "*"			// Matches all release levels
2341
	);
2342
	$major = 0;
2343
	$minor = 0;
2344
	foreach ($strs as $num => $str) {
2345
		if (substr($a, 0, strlen($str)) == $str) {
2346
			$major = $num;
2347
			$n = substr($a, strlen($str));
2348
			if (is_numeric($n)) {
2349
				$minor = $n;
2350
			}
2351
			break;
2352
		}
2353
	}
2354
	return "{$major}.{$minor}";
2355
}
2356
function version_compare_string($a, $b) {
2357
	// Only compare string parts if both versions give a specific release
2358
	// (If either version lacks a string part, assume intended to match all release levels)
2359
	if (isset($a) && isset($b)) {
2360
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2361
	} else {
2362
		return 0;
2363
	}
2364
}
2365
function version_compare_numeric($a, $b) {
2366
	$a_arr = explode('.', rtrim($a, '.'));
2367
	$b_arr = explode('.', rtrim($b, '.'));
2368

    
2369
	foreach ($a_arr as $n => $val) {
2370
		if (array_key_exists($n, $b_arr)) {
2371
			// So far so good, both have values at this minor version level. Compare.
2372
			if ($val > $b_arr[$n]) {
2373
				return 1;
2374
			} elseif ($val < $b_arr[$n]) {
2375
				return -1;
2376
			}
2377
		} else {
2378
			// a is greater, since b doesn't have any minor version here.
2379
			return 1;
2380
		}
2381
	}
2382
	if (count($b_arr) > count($a_arr)) {
2383
		// b is longer than a, so it must be greater.
2384
		return -1;
2385
	} else {
2386
		// Both a and b are of equal length and value.
2387
		return 0;
2388
	}
2389
}
2390
function pfs_version_compare($cur_time, $cur_text, $remote) {
2391
	// First try date compare
2392
	$v = version_compare_dates($cur_time, $remote);
2393
	if ($v === FALSE) {
2394
		// If that fails, try to compare by string
2395
		// Before anything else, simply test if the strings are equal
2396
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2397
			return 0;
2398
		}
2399
		list($cur_num, $cur_str) = explode('-', $cur_text);
2400
		list($rem_num, $rem_str) = explode('-', $remote);
2401

    
2402
		// First try to compare the numeric parts of the version string.
2403
		$v = version_compare_numeric($cur_num, $rem_num);
2404

    
2405
		// If the numeric parts are the same, compare the string parts.
2406
		if ($v == 0) {
2407
			return version_compare_string($cur_str, $rem_str);
2408
		}
2409
	}
2410
	return $v;
2411
}
2412
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2413
	global $g, $config;
2414

    
2415
	$urltable_prefix = "/var/db/aliastables/";
2416
	$urltable_filename = $urltable_prefix . $name . ".txt";
2417
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2418

    
2419
	// Make the aliases directory if it doesn't exist
2420
	if (!file_exists($urltable_prefix)) {
2421
		mkdir($urltable_prefix);
2422
	} elseif (!is_dir($urltable_prefix)) {
2423
		unlink($urltable_prefix);
2424
		mkdir($urltable_prefix);
2425
	}
2426

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

    
2432
		// Try to fetch the URL supplied
2433
		unlink_if_exists($tmp_urltable_filename);
2434
		$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2435
		if (download_file($url, $tmp_urltable_filename, $verify_ssl)) {
2436
			// Convert lines that begin with '$' or ';' to comments '#' instead of deleting them.
2437
			mwexec("/usr/bin/sed -i \"\" -E 's/^[[:space:]]*($|#|;)/#/g; /^#/!s/\;.*//g;' ". escapeshellarg($tmp_urltable_filename));
2438

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

    
2441
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2442
			if ($type == "urltable_ports") {
2443
				$parsed_contents = group_ports($parsed_contents, true);
2444
			}
2445
			if (is_array($parsed_contents)) {
2446
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2447
			} else {
2448
				touch($urltable_filename);
2449
			}
2450

    
2451
			/* 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. */
2452
			if (!isset($config['system']['use_mfs_tmpvar'])) {
2453
				unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz");
2454
			} else {
2455
				/* Update the RAM disk store with the new/updated table file. */
2456
				mwexec("cd / && /usr/bin/tar -czf \"{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz\" -C / \"{$urltable_filename}\"");
2457
			}
2458
			unlink_if_exists($tmp_urltable_filename);
2459
		} else {
2460
			if (!$validateonly) {
2461
				touch($urltable_filename);
2462
			}
2463
			return false;
2464
		}
2465
		return true;
2466
	} else {
2467
		// File exists, and it doesn't need to be updated.
2468
		return -1;
2469
	}
2470
}
2471

    
2472
function get_include_contents($filename) {
2473
	if (is_file($filename)) {
2474
		ob_start();
2475
		include $filename;
2476
		$contents = ob_get_contents();
2477
		ob_end_clean();
2478
		return $contents;
2479
	}
2480
	return false;
2481
}
2482

    
2483
/* This xml 2 array function is courtesy of the php.net comment section on xml_parse.
2484
 * it is roughly 4 times faster then our existing pfSense parser but due to the large
2485
 * size of the RRD xml dumps this is required.
2486
 * The reason we do not use it for pfSense is that it does not know about array fields
2487
 * which causes it to fail on array fields with single items. Possible Todo?
2488
 */
2489
function xml2array($contents, $get_attributes = 1, $priority = 'tag') {
2490
	if (!function_exists('xml_parser_create')) {
2491
		return array ();
2492
	}
2493
	$parser = xml_parser_create('');
2494
	xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
2495
	xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2496
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2497
	xml_parse_into_struct($parser, trim($contents), $xml_values);
2498
	xml_parser_free($parser);
2499
	if (!$xml_values) {
2500
		return; //Hmm...
2501
	}
2502
	$xml_array = array ();
2503
	$parents = array ();
2504
	$opened_tags = array ();
2505
	$arr = array ();
2506
	$current = & $xml_array;
2507
	$repeated_tag_index = array ();
2508
	foreach ($xml_values as $data) {
2509
		unset ($attributes, $value);
2510
		extract($data);
2511
		$result = array ();
2512
		$attributes_data = array ();
2513
		if (isset ($value)) {
2514
			if ($priority == 'tag') {
2515
				$result = $value;
2516
			} else {
2517
				$result['value'] = $value;
2518
			}
2519
		}
2520
		if (isset ($attributes) and $get_attributes) {
2521
			foreach ($attributes as $attr => $val) {
2522
				if ($priority == 'tag') {
2523
					$attributes_data[$attr] = $val;
2524
				} else {
2525
					$result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
2526
				}
2527
			}
2528
		}
2529
		if ($type == "open") {
2530
			$parent[$level -1] = & $current;
2531
			if (!is_array($current) or (!in_array($tag, array_keys($current)))) {
2532
				$current[$tag] = $result;
2533
				if ($attributes_data) {
2534
					$current[$tag . '_attr'] = $attributes_data;
2535
				}
2536
				$repeated_tag_index[$tag . '_' . $level] = 1;
2537
				$current = & $current[$tag];
2538
			} else {
2539
				if (isset ($current[$tag][0])) {
2540
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2541
					$repeated_tag_index[$tag . '_' . $level]++;
2542
				} else {
2543
					$current[$tag] = array (
2544
						$current[$tag],
2545
						$result
2546
						);
2547
					$repeated_tag_index[$tag . '_' . $level] = 2;
2548
					if (isset ($current[$tag . '_attr'])) {
2549
						$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2550
						unset ($current[$tag . '_attr']);
2551
					}
2552
				}
2553
				$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
2554
				$current = & $current[$tag][$last_item_index];
2555
			}
2556
		} elseif ($type == "complete") {
2557
			if (!isset ($current[$tag])) {
2558
				$current[$tag] = $result;
2559
				$repeated_tag_index[$tag . '_' . $level] = 1;
2560
				if ($priority == 'tag' and $attributes_data) {
2561
					$current[$tag . '_attr'] = $attributes_data;
2562
				}
2563
			} else {
2564
				if (isset ($current[$tag][0]) and is_array($current[$tag])) {
2565
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2566
					if ($priority == 'tag' and $get_attributes and $attributes_data) {
2567
						$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2568
					}
2569
					$repeated_tag_index[$tag . '_' . $level]++;
2570
				} else {
2571
					$current[$tag] = array (
2572
						$current[$tag],
2573
						$result
2574
						);
2575
					$repeated_tag_index[$tag . '_' . $level] = 1;
2576
					if ($priority == 'tag' and $get_attributes) {
2577
						if (isset ($current[$tag . '_attr'])) {
2578
							$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2579
							unset ($current[$tag . '_attr']);
2580
						}
2581
						if ($attributes_data) {
2582
							$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2583
						}
2584
					}
2585
					$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
2586
				}
2587
			}
2588
		} elseif ($type == 'close') {
2589
			$current = & $parent[$level -1];
2590
		}
2591
	}
2592
	return ($xml_array);
2593
}
2594

    
2595
function get_country_name($country_code) {
2596
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2597
		return "";
2598
	}
2599

    
2600
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2601
	$country_names_contents = file_get_contents($country_names_xml);
2602
	$country_names = xml2array($country_names_contents);
2603

    
2604
	if ($country_code == "ALL") {
2605
		$country_list = array();
2606
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2607
			$country_list[] = array(
2608
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2609
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2610
		}
2611
		return $country_list;
2612
	}
2613

    
2614
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2615
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2616
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2617
		}
2618
	}
2619
	return "";
2620
}
2621

    
2622
/* sort by interface only, retain the original order of rules that apply to
2623
   the same interface */
2624
function filter_rules_sort() {
2625
	global $config;
2626

    
2627
	/* mark each rule with the sequence number (to retain the order while sorting) */
2628
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2629
		$config['filter']['rule'][$i]['seq'] = $i;
2630
	}
2631

    
2632
	usort($config['filter']['rule'], "filter_rules_compare");
2633

    
2634
	/* strip the sequence numbers again */
2635
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2636
		unset($config['filter']['rule'][$i]['seq']);
2637
	}
2638
}
2639
function filter_rules_compare($a, $b) {
2640
	if (isset($a['floating']) && isset($b['floating'])) {
2641
		return $a['seq'] - $b['seq'];
2642
	} else if (isset($a['floating'])) {
2643
		return -1;
2644
	} else if (isset($b['floating'])) {
2645
		return 1;
2646
	} else if ($a['interface'] == $b['interface']) {
2647
		return $a['seq'] - $b['seq'];
2648
	} else {
2649
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2650
	}
2651
}
2652

    
2653
function generate_ipv6_from_mac($mac) {
2654
	$elements = explode(":", $mac);
2655
	if (count($elements) <> 6) {
2656
		return false;
2657
	}
2658

    
2659
	$i = 0;
2660
	$ipv6 = "fe80::";
2661
	foreach ($elements as $byte) {
2662
		if ($i == 0) {
2663
			$hexadecimal = substr($byte, 1, 2);
2664
			$bitmap = base_convert($hexadecimal, 16, 2);
2665
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2666
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2667
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2668
		}
2669
		$ipv6 .= $byte;
2670
		if ($i == 1) {
2671
			$ipv6 .= ":";
2672
		}
2673
		if ($i == 3) {
2674
			$ipv6 .= ":";
2675
		}
2676
		if ($i == 2) {
2677
			$ipv6 .= "ff:fe";
2678
		}
2679

    
2680
		$i++;
2681
	}
2682
	return $ipv6;
2683
}
2684

    
2685
/****f* pfsense-utils/load_mac_manufacturer_table
2686
 * NAME
2687
 *   load_mac_manufacturer_table
2688
 * INPUTS
2689
 *   none
2690
 * RESULT
2691
 *   returns associative array with MAC-Manufacturer pairs
2692
 ******/
2693
function load_mac_manufacturer_table() {
2694
	/* load MAC-Manufacture data from the file */
2695
	$macs = false;
2696
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2697
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2698
	}
2699
	if ($macs) {
2700
		foreach ($macs as $line) {
2701
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2702
				/* store values like this $mac_man['000C29']='VMware' */
2703
				$mac_man["$matches[1]"] = $matches[2];
2704
			}
2705
		}
2706
		return $mac_man;
2707
	} else {
2708
		return -1;
2709
	}
2710

    
2711
}
2712

    
2713
/****f* pfsense-utils/is_ipaddr_configured
2714
 * NAME
2715
 *   is_ipaddr_configured
2716
 * INPUTS
2717
 *   IP Address to check.
2718
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2719
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2720
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2721
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2722
 *     If check_subnets is true and cidrprefix is specified,
2723
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2724
 * RESULT
2725
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2726
*/
2727
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2728
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2729
		return true;
2730
	}
2731
	return false;
2732
}
2733

    
2734
/****f* pfsense-utils/where_is_ipaddr_configured
2735
 * NAME
2736
 *   where_is_ipaddr_configured
2737
 * INPUTS
2738
 *   IP Address to check.
2739
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2740
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2741
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2742
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2743
 *     If check_subnets is true and cidrprefix is specified,
2744
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2745
 * RESULT
2746
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2747
 *   If there are no matches then an empty array is returned.
2748
*/
2749
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2750
	global $config;
2751

    
2752
	$where_configured = array();
2753

    
2754
	$pos = strpos($ignore_if, '_virtualip');
2755
	if ($pos !== false) {
2756
		$ignore_vip_id = substr($ignore_if, $pos+10);
2757
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2758
	} else {
2759
		$ignore_vip_id = -1;
2760
		$ignore_vip_if = $ignore_if;
2761
	}
2762

    
2763
	$isipv6 = is_ipaddrv6($ipaddr);
2764

    
2765
	if ($check_subnets) {
2766
		$cidrprefix = intval($cidrprefix);
2767
		if ($isipv6) {
2768
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2769
				$cidrprefix = 128;
2770
			}
2771
		} else {
2772
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2773
				$cidrprefix = 32;
2774
			}
2775
		}
2776
		$iflist = get_configured_interface_list();
2777
		foreach ($iflist as $if => $ifname) {
2778
			if ($ignore_if == $if) {
2779
				continue;
2780
			}
2781

    
2782
			if ($isipv6) {
2783
				$if_ipv6 = get_interface_ipv6($if);
2784
				$if_snbitsv6 = get_interface_subnetv6($if);
2785
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2786
					$where_entry = array();
2787
					$where_entry['if'] = $if;
2788
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2789
					$where_configured[] = $where_entry;
2790
				}
2791
			} else {
2792
				$if_ipv4 = get_interface_ip($if);
2793
				$if_snbitsv4 = get_interface_subnet($if);
2794
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2795
					$where_entry = array();
2796
					$where_entry['if'] = $if;
2797
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2798
					$where_configured[] = $where_entry;
2799
				}
2800
			}
2801
		}
2802
	} else {
2803
		if ($isipv6) {
2804
			$interface_list_ips = get_configured_ipv6_addresses();
2805
		} else {
2806
			$interface_list_ips = get_configured_ip_addresses();
2807
		}
2808

    
2809
		foreach ($interface_list_ips as $if => $ilips) {
2810
			if ($ignore_if == $if) {
2811
				continue;
2812
			}
2813
			if (strcasecmp($ipaddr, $ilips) == 0) {
2814
				$where_entry = array();
2815
				$where_entry['if'] = $if;
2816
				$where_entry['ip_or_subnet'] = $ilips;
2817
				$where_configured[] = $where_entry;
2818
			}
2819
		}
2820
	}
2821

    
2822
	if ($check_localip) {
2823
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, $config['l2tp']['localip']) == 0)) {
2824
			$where_entry = array();
2825
			$where_entry['if'] = 'l2tp';
2826
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2827
			$where_configured[] = $where_entry;
2828
		}
2829
	}
2830

    
2831
	return $where_configured;
2832
}
2833

    
2834
/****f* pfsense-utils/pfSense_handle_custom_code
2835
 * NAME
2836
 *   pfSense_handle_custom_code
2837
 * INPUTS
2838
 *   directory name to process
2839
 * RESULT
2840
 *   globs the directory and includes the files
2841
 */
2842
function pfSense_handle_custom_code($src_dir) {
2843
	// Allow extending of the nat edit page and include custom input validation
2844
	if (is_dir("$src_dir")) {
2845
		$cf = glob($src_dir . "/*.inc");
2846
		foreach ($cf as $nf) {
2847
			if ($nf == "." || $nf == "..") {
2848
				continue;
2849
			}
2850
			// Include the extra handler
2851
			include_once("$nf");
2852
		}
2853
	}
2854
}
2855

    
2856
function set_language() {
2857
	global $config, $g;
2858

    
2859
	if (!empty($config['system']['language'])) {
2860
		$lang = $config['system']['language'];
2861
	} elseif (!empty($g['language'])) {
2862
		$lang = $g['language'];
2863
	}
2864
	$lang .= ".UTF-8";
2865

    
2866
	putenv("LANG={$lang}");
2867
	setlocale(LC_ALL, $lang);
2868
	textdomain("pfSense");
2869
	bindtextdomain("pfSense", "/usr/local/share/locale");
2870
	bind_textdomain_codeset("pfSense", $lang);
2871
}
2872

    
2873
function get_locale_list() {
2874
	$locales = array(
2875
		"en_US" => gettext("English"),
2876
		"pt_BR" => gettext("Portuguese (Brazil)"),
2877
		"tr" => gettext("Turkish"),
2878
	);
2879
	asort($locales);
2880
	return $locales;
2881
}
2882

    
2883
function return_hex_ipv4($ipv4) {
2884
	if (!is_ipaddrv4($ipv4)) {
2885
		return(false);
2886
	}
2887

    
2888
	/* we need the hex form of the interface IPv4 address */
2889
	$ip4arr = explode(".", $ipv4);
2890
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
2891
}
2892

    
2893
function convert_ipv6_to_128bit($ipv6) {
2894
	if (!is_ipaddrv6($ipv6)) {
2895
		return(false);
2896
	}
2897

    
2898
	$ip6arr = array();
2899
	$ip6prefix = Net_IPv6::uncompress($ipv6);
2900
	$ip6arr = explode(":", $ip6prefix);
2901
	/* binary presentation of the prefix for all 128 bits. */
2902
	$ip6prefixbin = "";
2903
	foreach ($ip6arr as $element) {
2904
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
2905
	}
2906
	return($ip6prefixbin);
2907
}
2908

    
2909
function convert_128bit_to_ipv6($ip6bin) {
2910
	if (strlen($ip6bin) <> 128) {
2911
		return(false);
2912
	}
2913

    
2914
	$ip6arr = array();
2915
	$ip6binarr = array();
2916
	$ip6binarr = str_split($ip6bin, 16);
2917
	foreach ($ip6binarr as $binpart) {
2918
		$ip6arr[] = dechex(bindec($binpart));
2919
	}
2920
	$ip6addr = Net_IPv6::compress(implode(":", $ip6arr));
2921

    
2922
	return($ip6addr);
2923
}
2924

    
2925

    
2926
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
2927
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
2928
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
2929
/* 6to4 is 16 bits, e.g. 65535 */
2930
function calculate_ipv6_delegation_length($if) {
2931
	global $config;
2932

    
2933
	if (!is_array($config['interfaces'][$if])) {
2934
		return false;
2935
	}
2936

    
2937
	switch ($config['interfaces'][$if]['ipaddrv6']) {
2938
		case "6to4":
2939
			$pdlen = 16;
2940
			break;
2941
		case "6rd":
2942
			$rd6cfg = $config['interfaces'][$if];
2943
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
2944
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
2945
			break;
2946
		case "dhcp6":
2947
			$dhcp6cfg = $config['interfaces'][$if];
2948
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
2949
			break;
2950
		default:
2951
			$pdlen = 0;
2952
			break;
2953
	}
2954
	return($pdlen);
2955
}
2956

    
2957
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
2958
	$prefix = Net_IPv6::uncompress($prefix, true);
2959
	$suffix = Net_IPv6::uncompress($suffix, true);
2960

    
2961
	/*
2962
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
2963
	 *                ^^^^ ^
2964
	 *                |||| \-> 64
2965
	 *                |||\---> 63, 62, 61, 60
2966
	 *                ||\----> 56
2967
	 *                |\-----> 52
2968
	 *                \------> 48
2969
	 */
2970

    
2971
	switch ($len) {
2972
	case 48:
2973
		$prefix_len = 15;
2974
		break;
2975
	case 52:
2976
		$prefix_len = 16;
2977
		break;
2978
	case 56:
2979
		$prefix_len = 17;
2980
		break;
2981
	case 60:
2982
		$prefix_len = 18;
2983
		break;
2984
	/*
2985
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
2986
	 * we let user chose this bit it can end up out of PD network
2987
	 *
2988
	 * Leave this with 20 for now until we find a way to let user
2989
	 * chose it. The side-effect is users with PD with one of these
2990
	 * lengths will not be able to setup DHCP server range for full
2991
	 * PD size, only for last /64 network
2992
	 */
2993
	case 63:
2994
	case 62:
2995
	case 61:
2996
	default:
2997
		$prefix_len = 20;
2998
		break;
2999
	}
3000

    
3001
	return Net_IPv6::compress(substr($prefix, 0, $prefix_len) .
3002
	    substr($suffix, $prefix_len));
3003
}
3004

    
3005
function dhcpv6_pd_str_help($pdlen) {
3006
	$result = '';
3007

    
3008
	switch ($pdlen) {
3009
	case 48:
3010
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3011
		break;
3012
	case 52:
3013
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3014
		break;
3015
	case 56:
3016
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3017
		break;
3018
	case 60:
3019
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3020
		break;
3021
	/*
3022
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3023
	 * we let the user choose this bit it can end up out of PD network
3024
	 *
3025
	 * Leave this with the same as 64 for now until we find a way to
3026
	 * let the user choose it. The side-effect is users with PD with one
3027
	 * of these lengths will not be able to setup DHCP server ranges
3028
	 * for full PD size, only for last /64 network
3029
	 */
3030
	case 61:
3031
	case 62:
3032
	case 63:
3033
	case 64:
3034
	default:
3035
		$result = '::xxxx:xxxx:xxxx:xxxx';
3036
		break;
3037
	}
3038

    
3039
	return $result;
3040
}
3041

    
3042
function huawei_rssi_to_string($rssi) {
3043
	$dbm = array();
3044
	$i = 0;
3045
	$dbstart = -113;
3046
	while ($i < 32) {
3047
		$dbm[$i] = $dbstart + ($i * 2);
3048
		$i++;
3049
	}
3050
	$percent = round(($rssi / 31) * 100);
3051
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3052
	return $string;
3053
}
3054

    
3055
function huawei_mode_to_string($mode, $submode) {
3056
	$modes[0] = gettext("None");
3057
	$modes[1] = "AMPS";
3058
	$modes[2] = "CDMA";
3059
	$modes[3] = "GSM/GPRS";
3060
	$modes[4] = "HDR";
3061
	$modes[5] = "WCDMA";
3062
	$modes[6] = "GPS";
3063

    
3064
	$submodes[0] = gettext("No Service");
3065
	$submodes[1] = "GSM";
3066
	$submodes[2] = "GPRS";
3067
	$submodes[3] = "EDGE";
3068
	$submodes[4] = "WCDMA";
3069
	$submodes[5] = "HSDPA";
3070
	$submodes[6] = "HSUPA";
3071
	$submodes[7] = "HSDPA+HSUPA";
3072
	$submodes[8] = "TD-SCDMA";
3073
	$submodes[9] = "HSPA+";
3074
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3075
	return $string;
3076
}
3077

    
3078
function huawei_service_to_string($state) {
3079
	$modes[0] = gettext("No Service");
3080
	$modes[1] = gettext("Restricted Service");
3081
	$modes[2] = gettext("Valid Service");
3082
	$modes[3] = gettext("Restricted Regional Service");
3083
	$modes[4] = gettext("Powersaving Service");
3084
	$string = $modes[$state];
3085
	return $string;
3086
}
3087

    
3088
function huawei_simstate_to_string($state) {
3089
	$modes[0] = gettext("Invalid SIM/locked State");
3090
	$modes[1] = gettext("Valid SIM State");
3091
	$modes[2] = gettext("Invalid SIM CS State");
3092
	$modes[3] = gettext("Invalid SIM PS State");
3093
	$modes[4] = gettext("Invalid SIM CS/PS State");
3094
	$modes[255] = gettext("Missing SIM State");
3095
	$string = $modes[$state];
3096
	return $string;
3097
}
3098

    
3099
function zte_rssi_to_string($rssi) {
3100
	return huawei_rssi_to_string($rssi);
3101
}
3102

    
3103
function zte_mode_to_string($mode, $submode) {
3104
	$modes[0] = gettext("No Service");
3105
	$modes[1] = gettext("Limited Service");
3106
	$modes[2] = "GPRS";
3107
	$modes[3] = "GSM";
3108
	$modes[4] = "UMTS";
3109
	$modes[5] = "EDGE";
3110
	$modes[6] = "HSDPA";
3111

    
3112
	$submodes[0] = "CS_ONLY";
3113
	$submodes[1] = "PS_ONLY";
3114
	$submodes[2] = "CS_PS";
3115
	$submodes[3] = "CAMPED";
3116
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3117
	return $string;
3118
}
3119

    
3120
function zte_service_to_string($service) {
3121
	$modes[0] = gettext("Initializing Service");
3122
	$modes[1] = gettext("Network Lock error Service");
3123
	$modes[2] = gettext("Network Locked Service");
3124
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3125
	$string = $modes[$service];
3126
	return $string;
3127
}
3128

    
3129
function zte_simstate_to_string($state) {
3130
	$modes[0] = gettext("No action State");
3131
	$modes[1] = gettext("Network lock State");
3132
	$modes[2] = gettext("(U)SIM card lock State");
3133
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3134
	$string = $modes[$state];
3135
	return $string;
3136
}
3137

    
3138
function get_configured_pppoe_server_interfaces() {
3139
	global $config;
3140
	$iflist = array();
3141
	if (is_array($config['pppoes']['pppoe'])) {
3142
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3143
			if ($pppoe['mode'] == "server") {
3144
				$int = "poes". $pppoe['pppoeid'];
3145
				$iflist[$int] = strtoupper($int);
3146
			}
3147
		}
3148
	}
3149
	return $iflist;
3150
}
3151

    
3152
function get_pppoes_child_interfaces($ifpattern) {
3153
	$if_arr = array();
3154
	if ($ifpattern == "") {
3155
		return;
3156
	}
3157

    
3158
	exec("/sbin/ifconfig", $out, $ret);
3159
	foreach ($out as $line) {
3160
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3161
			$if_arr[] = $match[1];
3162
		}
3163
	}
3164
	return $if_arr;
3165

    
3166
}
3167

    
3168
/****f* pfsense-utils/pkg_call_plugins
3169
 * NAME
3170
 *   pkg_call_plugins
3171
 * INPUTS
3172
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3173
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3174
 * RESULT
3175
 *   returns associative array results from the plugin calls for each package
3176
 * NOTES
3177
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3178
 ******/
3179
function pkg_call_plugins($plugin_type, $plugin_params) {
3180
	global $g, $config;
3181
	$results = array();
3182
	if (!is_array($config['installedpackages']['package'])) {
3183
		return $results;
3184
	}
3185
	foreach ($config['installedpackages']['package'] as $package) {
3186
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
3187
			continue;
3188
		}
3189
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
3190
		$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3191
		if (is_array($pkg_config['plugins']['item'])) {
3192
			foreach ($pkg_config['plugins']['item'] as $plugin) {
3193
				if ($plugin['type'] == $plugin_type) {
3194
					if (file_exists($pkg_config['include_file'])) {
3195
						require_once($pkg_config['include_file']);
3196
					} else {
3197
						continue;
3198
					}
3199
					$plugin_function = $pkgname . '_'. $plugin_type;
3200
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3201
				}
3202
			}
3203
		}
3204
	}
3205
	return $results;
3206
}
3207

    
3208
function restore_aliastables() {
3209
	global $g, $config;
3210

    
3211
	$dbpath = "{$g['vardb_path']}/aliastables/";
3212

    
3213
	/* restore the alias tables, if we have them */
3214
	$files = glob("{$g['cf_conf_path']}/RAM_Disk_Store{$dbpath}*.tgz");
3215
	if (count($files)) {
3216
		echo "Restoring alias tables...";
3217
		foreach ($files as $file) {
3218
			if (file_exists($file)) {
3219
				$aliastablesrestore = "";
3220
				$aliastablesreturn = "";
3221
				exec("cd /;LANG=C /usr/bin/tar -xzf {$file} 2>&1", $aliastablesrestore, $aliastablesreturn);
3222
				$aliastablesrestore = implode(" ", $aliastablesrestore);
3223
				if ($aliastablesreturn <> 0) {
3224
					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"));
3225
				} else {
3226
					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"));
3227
				}
3228
			}
3229
			/* 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. */
3230
			if (!isset($config['system']['use_mfs_tmpvar'])) {
3231
				unlink_if_exists("{$file}");
3232
			}
3233
		}
3234
		echo "done.\n";
3235
		return true;
3236
	}
3237
	return false;
3238
}
3239

    
3240
// Convert IPv6 addresses to lower case
3241
function addrtolower($ip) {
3242
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3243
		return(strtolower($ip));
3244
	} else {
3245
		return($ip);
3246
	}
3247
}
3248
?>
(30-30/51)