Project

General

Profile

Download (87.3 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
	pfSense_interface_capabilities($iface, -$flags_off);
417
	pfSense_interface_capabilities($iface, $flags_on);
418
}
419

    
420
/****f* pfsense-utils/enable_hardware_offloading
421
 * NAME
422
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
423
 * INPUTS
424
 *   $interface	- string containing the physical interface to work on.
425
 * RESULT
426
 *   null
427
 * NOTES
428
 *   This function only supports the fxp driver's loadable microcode.
429
 ******/
430
function enable_hardware_offloading($interface) {
431
	global $g, $config;
432

    
433
	$int = get_real_interface($interface);
434
	if (empty($int)) {
435
		return;
436
	}
437

    
438
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
439
		/* translate wan, lan, opt -> real interface if needed */
440
		$int_family = preg_split("/[0-9]+/", $int);
441
		$supported_ints = array('fxp');
442
		if (in_array($int_family, $supported_ints)) {
443
			if (does_interface_exist($int)) {
444
				pfSense_interface_flags($int, IFF_LINK0);
445
			}
446
		}
447
	}
448

    
449
	/* This is mostly for vlans and ppp types */
450
	$realhwif = get_parent_interface($interface);
451
	if ($realhwif[0] == $int) {
452
		hardware_offloading_applyflags($int);
453
	} else {
454
		hardware_offloading_applyflags($realhwif[0]);
455
		hardware_offloading_applyflags($int);
456
	}
457
}
458

    
459
/****f* pfsense-utils/is_alias_inuse
460
 * NAME
461
 *   checks to see if an alias is currently in use by a rule
462
 * INPUTS
463
 *
464
 * RESULT
465
 *   true or false
466
 * NOTES
467
 *
468
 ******/
469
function is_alias_inuse($alias) {
470
	global $g, $config;
471

    
472
	if ($alias == "") {
473
		return false;
474
	}
475
	/* loop through firewall rules looking for alias in use */
476
	if (is_array($config['filter']['rule'])) {
477
		foreach ($config['filter']['rule'] as $rule) {
478
			if ($rule['source']['address']) {
479
				if ($rule['source']['address'] == $alias) {
480
					return true;
481
				}
482
			}
483
			if ($rule['destination']['address']) {
484
				if ($rule['destination']['address'] == $alias) {
485
					return true;
486
				}
487
			}
488
		}
489
	}
490
	/* loop through nat rules looking for alias in use */
491
	if (is_array($config['nat']['rule'])) {
492
		foreach ($config['nat']['rule'] as $rule) {
493
			if ($rule['target'] && $rule['target'] == $alias) {
494
				return true;
495
			}
496
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
497
				return true;
498
			}
499
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
500
				return true;
501
			}
502
		}
503
	}
504
	return false;
505
}
506

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

    
520
	if ($schedule == "") {
521
		return false;
522
	}
523
	/* loop through firewall rules looking for schedule in use */
524
	if (is_array($config['filter']['rule'])) {
525
		foreach ($config['filter']['rule'] as $rule) {
526
			if ($rule['sched'] == $schedule) {
527
				return true;
528
			}
529
		}
530
	}
531
	return false;
532
}
533

    
534
/****f* pfsense-utils/setup_microcode
535
 * NAME
536
 *   enumerates all interfaces and calls enable_hardware_offloading which
537
 *   enables a NIC's supported hardware features.
538
 * INPUTS
539
 *
540
 * RESULT
541
 *   null
542
 * NOTES
543
 *   This function only supports the fxp driver's loadable microcode.
544
 ******/
545
function setup_microcode() {
546

    
547
	/* if list */
548
	$iflist = get_configured_interface_list(false, true);
549
	foreach ($iflist as $if => $ifdescr) {
550
		enable_hardware_offloading($if);
551
	}
552
	unset($iflist);
553
}
554

    
555
/****f* pfsense-utils/get_carp_status
556
 * NAME
557
 *   get_carp_status - Return whether CARP is enabled or disabled.
558
 * RESULT
559
 *   boolean	- true if CARP is enabled, false if otherwise.
560
 ******/
561
function get_carp_status() {
562
	/* grab the current status of carp */
563
	$status = get_single_sysctl('net.inet.carp.allow');
564
	return (intval($status) > 0);
565
}
566

    
567
/*
568
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
569

    
570
 */
571
function convert_ip_to_network_format($ip, $subnet) {
572
	$ipsplit = explode('.', $ip);
573
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
574
	return $string;
575
}
576

    
577
/*
578
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
579
 */
580
function get_carp_interface_status($carpid) {
581

    
582
	$carpiface = get_configured_vip_interface($carpid);
583
	if ($carpiface == NULL)
584
		return "";
585
	$interface = get_real_interface($carpiface);
586
	if ($interface == NULL)
587
		return "";
588
	$vip = get_configured_vip($carpid);
589
	if ($vip == NULL || !isset($vip['vhid']))
590
		return "";
591

    
592
	$vhid = $vip['vhid'];
593
	$carp_query = '';
594
	$_gb = exec("/sbin/ifconfig $interface | /usr/bin/grep carp: | /usr/bin/grep \"vhid $vhid\"", $carp_query);
595
	foreach ($carp_query as $int) {
596
		if (stripos($int, "MASTER"))
597
			return "MASTER";
598
		elseif (stripos($int, "BACKUP"))
599
			return "BACKUP";
600
		elseif (stripos($int, "INIT"))
601
			return "INIT";
602
	}
603

    
604
	return "";
605
}
606

    
607
/*
608
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
609
 */
610
function get_pfsync_interface_status($pfsyncinterface) {
611
	if (!does_interface_exist($pfsyncinterface)) {
612
		return;
613
	}
614

    
615
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
616
}
617

    
618
/*
619
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
620
 */
621
function add_rule_to_anchor($anchor, $rule, $label) {
622
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
623
}
624

    
625
/*
626
 * remove_text_from_file
627
 * remove $text from file $file
628
 */
629
function remove_text_from_file($file, $text) {
630
	if (!file_exists($file) && !is_writable($file)) {
631
		return;
632
	}
633
	$filecontents = file_get_contents($file);
634
	$text = str_replace($text, "", $filecontents);
635
	@file_put_contents($file, $text);
636
}
637

    
638
/*
639
 *   after_sync_bump_adv_skew(): create skew values by 1S
640
 */
641
function after_sync_bump_adv_skew() {
642
	global $config, $g;
643
	$processed_skew = 1;
644
	$a_vip = &$config['virtualip']['vip'];
645
	foreach ($a_vip as $vipent) {
646
		if ($vipent['advskew'] <> "") {
647
			$processed_skew = 1;
648
			$vipent['advskew'] = $vipent['advskew']+1;
649
		}
650
	}
651
	if ($processed_skew == 1) {
652
		write_config(gettext("After synch increase advertising skew"));
653
	}
654
}
655

    
656
/*
657
 * get_filename_from_url($url): converts a url to its filename.
658
 */
659
function get_filename_from_url($url) {
660
	return basename($url);
661
}
662

    
663
/*
664
 *   get_dir: return an array of $dir
665
 */
666
function get_dir($dir) {
667
	$dir_array = array();
668
	$d = dir($dir);
669
	if (!is_object($d)) {
670
		return array();
671
	}
672
	while (false !== ($entry = $d->read())) {
673
		array_push($dir_array, $entry);
674
	}
675
	$d->close();
676
	return $dir_array;
677
}
678

    
679
/****f* pfsense-utils/WakeOnLan
680
 * NAME
681
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
682
 * RESULT
683
 *   true/false - true if the operation was successful
684
 ******/
685
function WakeOnLan($addr, $mac) {
686
	$addr_byte = explode(':', $mac);
687
	$hw_addr = '';
688

    
689
	for ($a = 0; $a < 6; $a++) {
690
		$hw_addr .= chr(hexdec($addr_byte[$a]));
691
	}
692

    
693
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
694

    
695
	for ($a = 1; $a <= 16; $a++) {
696
		$msg .= $hw_addr;
697
	}
698

    
699
	// send it to the broadcast address using UDP
700
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
701
	if ($s == false) {
702
		log_error(gettext("Error creating socket!"));
703
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
704
	} else {
705
		// setting a broadcast option to socket:
706
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
707
		if ($opt_ret < 0) {
708
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
709
		}
710
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
711
		socket_close($s);
712
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
713
		return true;
714
	}
715

    
716
	return false;
717
}
718

    
719
/*
720
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
721
 *					 Useful for finding paths and stripping file extensions.
722
 */
723
function reverse_strrchr($haystack, $needle) {
724
	if (!is_string($haystack)) {
725
		return;
726
	}
727
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
728
}
729

    
730
/*
731
 *  backup_config_section($section): returns as an xml file string of
732
 *                                   the configuration section
733
 */
734
function backup_config_section($section_name) {
735
	global $config;
736
	$new_section = &$config[$section_name];
737
	/* generate configuration XML */
738
	$xmlconfig = dump_xml_config($new_section, $section_name);
739
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
740
	return $xmlconfig;
741
}
742

    
743
/*
744
 *  restore_config_section($section_name, new_contents): restore a configuration section,
745
 *                                                  and write the configuration out
746
 *                                                  to disk/cf.
747
 */
748
function restore_config_section($section_name, $new_contents) {
749
	global $config, $g;
750
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
751
	fwrite($fout, $new_contents);
752
	fclose($fout);
753

    
754
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
755
	if ($xml['pfsense']) {
756
		$xml = $xml['pfsense'];
757
	}
758
	else if ($xml['m0n0wall']) {
759
		$xml = $xml['m0n0wall'];
760
	}
761
	if ($xml[$section_name]) {
762
		$section_xml = $xml[$section_name];
763
	} else {
764
		$section_xml = -1;
765
	}
766

    
767
	@unlink($g['tmp_path'] . "/tmpxml");
768
	if ($section_xml === -1) {
769
		return false;
770
	}
771
	$config[$section_name] = &$section_xml;
772
	if (file_exists("{$g['tmp_path']}/config.cache")) {
773
		unlink("{$g['tmp_path']}/config.cache");
774
	}
775
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
776
	disable_security_checks();
777
	return true;
778
}
779

    
780
/*
781
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
782
 *                                                  and write the configuration out
783
 *                                                  to disk/cf.  But preserve the prior
784
 * 													structure if needed
785
 */
786
function merge_config_section($section_name, $new_contents) {
787
	global $config;
788
	$fname = get_tmp_filename();
789
	$fout = fopen($fname, "w");
790
	fwrite($fout, $new_contents);
791
	fclose($fout);
792
	$section_xml = parse_xml_config($fname, $section_name);
793
	$config[$section_name] = $section_xml;
794
	unlink($fname);
795
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
796
	disable_security_checks();
797
	return;
798
}
799

    
800
/*
801
 *  php_check_syntax($code_tocheck, $errormessage): checks $code_to_check for errors
802
 */
803
if (!function_exists('php_check_syntax')) {
804
	global $g;
805
	function php_check_syntax($code_to_check, &$errormessage) {
806
		return false;
807
		$fout = fopen("{$g['tmp_path']}/codetocheck.php", "w");
808
		$code = $_POST['content'];
809
		$code = str_replace("<?php", "", $code);
810
		$code = str_replace("?>", "", $code);
811
		fwrite($fout, "<?php\n\n");
812
		fwrite($fout, $code_to_check);
813
		fwrite($fout, "\n\n?>\n");
814
		fclose($fout);
815
		$command = "/usr/local/bin/php-cgi -l {$g['tmp_path']}/codetocheck.php";
816
		$output = exec_command($command);
817
		if (stristr($output, "Errors parsing") == false) {
818
			echo "false\n";
819
			$errormessage = '';
820
			return(false);
821
		} else {
822
			$errormessage = $output;
823
			return(true);
824
		}
825
	}
826
}
827

    
828
/*
829
 *  php_check_filename_syntax($filename, $errormessage): checks the file $filename for errors
830
 */
831
if (!function_exists('php_check_syntax')) {
832
	function php_check_syntax($code_to_check, &$errormessage) {
833
		return false;
834
		$command = "/usr/local/bin/php-cgi -l " . escapeshellarg($code_to_check);
835
		$output = exec_command($command);
836
		if (stristr($output, "Errors parsing") == false) {
837
			echo "false\n";
838
			$errormessage = '';
839
			return(false);
840
		} else {
841
			$errormessage = $output;
842
			return(true);
843
		}
844
	}
845
}
846

    
847
/*
848
 * rmdir_recursive($path, $follow_links=false)
849
 * Recursively remove a directory tree (rm -rf path)
850
 * This is for directories _only_
851
 */
852
function rmdir_recursive($path, $follow_links=false) {
853
	$to_do = glob($path);
854
	if (!is_array($to_do)) {
855
		$to_do = array($to_do);
856
	}
857
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
858
		if (file_exists($workingdir)) {
859
			if (is_dir($workingdir)) {
860
				$dir = opendir($workingdir);
861
				while ($entry = readdir($dir)) {
862
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
863
						unlink("$workingdir/$entry");
864
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
865
						rmdir_recursive("$workingdir/$entry");
866
					}
867
				}
868
				closedir($dir);
869
				rmdir($workingdir);
870
			} elseif (is_file($workingdir)) {
871
				unlink($workingdir);
872
			}
873
		}
874
	}
875
	return;
876
}
877

    
878
/*
879
 * host_firmware_version(): Return the versions used in this install
880
 */
881
function host_firmware_version($tocheck = "") {
882
	global $g, $config;
883

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

    
886
	return array(
887
		"firmware" => array("version" => $g['product_version']),
888
		"kernel"   => array("version" => $os_version),
889
		"base"     => array("version" => $os_version),
890
		"platform" => $g['platform'],
891
		"config_version" => $config['version']
892
	);
893
}
894

    
895
function get_disk_info() {
896
	$diskout = "";
897
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
898
	return explode(' ', $diskout[0]);
899
}
900

    
901
/****f* pfsense-utils/strncpy
902
 * NAME
903
 *   strncpy - copy strings
904
 * INPUTS
905
 *   &$dst, $src, $length
906
 * RESULT
907
 *   none
908
 ******/
909
function strncpy(&$dst, $src, $length) {
910
	if (strlen($src) > $length) {
911
		$dst = substr($src, 0, $length);
912
	} else {
913
		$dst = $src;
914
	}
915
}
916

    
917
/****f* pfsense-utils/reload_interfaces_sync
918
 * NAME
919
 *   reload_interfaces - reload all interfaces
920
 * INPUTS
921
 *   none
922
 * RESULT
923
 *   none
924
 ******/
925
function reload_interfaces_sync() {
926
	global $config, $g;
927

    
928
	if ($g['debug']) {
929
		log_error(gettext("reload_interfaces_sync() is starting."));
930
	}
931

    
932
	/* parse config.xml again */
933
	$config = parse_config(true);
934

    
935
	/* enable routing */
936
	system_routing_enable();
937
	if ($g['debug']) {
938
		log_error(gettext("Enabling system routing"));
939
	}
940

    
941
	if ($g['debug']) {
942
		log_error(gettext("Cleaning up Interfaces"));
943
	}
944

    
945
	/* set up interfaces */
946
	interfaces_configure();
947
}
948

    
949
/****f* pfsense-utils/reload_all
950
 * NAME
951
 *   reload_all - triggers a reload of all settings
952
 *   * INPUTS
953
 *   none
954
 * RESULT
955
 *   none
956
 ******/
957
function reload_all() {
958
	send_event("service reload all");
959
}
960

    
961
/****f* pfsense-utils/reload_interfaces
962
 * NAME
963
 *   reload_interfaces - triggers a reload of all interfaces
964
 * INPUTS
965
 *   none
966
 * RESULT
967
 *   none
968
 ******/
969
function reload_interfaces() {
970
	send_event("interface all reload");
971
}
972

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

    
984
	/* parse config.xml again */
985
	$config = parse_config(true);
986

    
987
	/* set up our timezone */
988
	system_timezone_configure();
989

    
990
	/* set up our hostname */
991
	system_hostname_configure();
992

    
993
	/* make hosts file */
994
	system_hosts_generate();
995

    
996
	/* generate resolv.conf */
997
	system_resolvconf_generate();
998

    
999
	/* enable routing */
1000
	system_routing_enable();
1001

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

    
1005
	/* start dyndns service */
1006
	services_dyndns_configure();
1007

    
1008
	/* configure cron service */
1009
	configure_cron();
1010

    
1011
	/* start the NTP client */
1012
	system_ntp_configure();
1013

    
1014
	/* sync pw database */
1015
	unlink_if_exists("/etc/spwd.db.tmp");
1016
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1017

    
1018
	/* restart sshd */
1019
	send_event("service restart sshd");
1020

    
1021
	/* restart webConfigurator if needed */
1022
	send_event("service restart webgui");
1023
}
1024

    
1025
function setup_serial_port($when = "save", $path = "") {
1026
	global $g, $config;
1027
	$ttys_file = "{$path}/etc/ttys";
1028
	$boot_config_file = "{$path}/boot.config";
1029
	$loader_conf_file = "{$path}/boot/loader.conf";
1030
	/* serial console - write out /boot.config */
1031
	if (file_exists($boot_config_file)) {
1032
		$boot_config = file_get_contents($boot_config_file);
1033
	} else {
1034
		$boot_config = "";
1035
	}
1036

    
1037
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1038
	$serial_only = false;
1039

    
1040
	$specific_platform = system_identify_specific_platform();
1041
	if ($specific_platform['name'] == 'RCC-VE' ||
1042
	    $specific_platform['name'] == 'RCC' ||
1043
	    $specific_platform['name'] == 'RCC-DFF' ||
1044
	    $specific_platform['name'] == 'apu2') {
1045
		$serial_only = true;
1046
	}
1047

    
1048
	$boot_config_split = explode("\n", $boot_config);
1049
	$data = array();
1050
	foreach ($boot_config_split as $bcs) {
1051
		/* Ignore -D and -h lines now */
1052
		if (!empty($bcs) && !stristr($bcs, "-D") &&
1053
		    !stristr($bcs, "-h")) {
1054
			$data[] = $bcs;
1055
		}
1056
	}
1057
	if ($serial_only === true) {
1058
		$data[] = "-S{$serialspeed} -h";
1059
	} elseif (is_serial_enabled()) {
1060
		$data[] = "-S{$serialspeed} -D";
1061
	}
1062

    
1063
	if (empty($data)) {
1064
		@unlink($boot_conf_file);
1065
	} else {
1066
		safe_write_file($boot_config_file, $data);
1067
	}
1068

    
1069
	unset($boot_config, $boot_config_file, $boot_config_split);
1070

    
1071
	/* serial console - write out /boot/loader.conf */
1072
	if ($when == "upgrade") {
1073
		system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1074
	}
1075

    
1076
	$loader_conf = file_get_contents($loader_conf_file);
1077
	$loader_conf_split = explode("\n", $loader_conf);
1078

    
1079
	$data = array();
1080
	// Loop through and only add lines that are not empty, and which
1081
	//  do not contain a console directive.
1082
	foreach ($loader_conf_split as $bcs) {
1083
		if (!empty($bcs) &&
1084
		    (stripos($bcs, "console") === false) &&
1085
		    (stripos($bcs, "boot_multicons") === false) &&
1086
		    (stripos($bcs, "boot_serial") === false) &&
1087
		    (stripos($bcs, "hw.usb.no_pf") === false) &&
1088
		    (stripos($bcs, "hint.uart.0.flags") === false) &&
1089
		    (stripos($bcs, "hint.uart.1.flags") === false)) {
1090
			$data[] = $bcs;
1091
		}
1092
	}
1093

    
1094
	if ($serial_only === true) {
1095
		$data[] = 'boot_serial="YES"';
1096
		$data[] = 'console="comconsole"';
1097
	} else if (is_serial_enabled()) {
1098
		$data[] = 'boot_multicons="YES"';
1099
		$data[] = 'boot_serial="YES"';
1100
		$primaryconsole = isset($g['primaryconsole_force']) ?
1101
		    $g['primaryconsole_force'] :
1102
		    $config['system']['primaryconsole'];
1103
		switch ($primaryconsole) {
1104
			case "video":
1105
				$data[] = 'console="vidconsole,comconsole"';
1106
				break;
1107
			case "serial":
1108
			default:
1109
				$data[] = 'console="comconsole,vidconsole"';
1110
		}
1111
	}
1112
	$data[] = 'comconsole_speed="' . $serialspeed . '"';
1113

    
1114
	$specplatform = system_identify_specific_platform();
1115
	if ($specplatform['name'] == 'RCC-VE' ||
1116
	    $specplatform['name'] == 'RCC' ||
1117
	    $specplatform['name'] == 'RCC-DFF') {
1118
		$data[] = 'comconsole_port="0x2F8"';
1119
		$data[] = 'hint.uart.0.flags="0x00"';
1120
		$data[] = 'hint.uart.1.flags="0x10"';
1121
	}
1122
	$data[] = 'hw.usb.no_pf="1"';
1123

    
1124
	safe_write_file($loader_conf_file, $data);
1125

    
1126
	unset($loader_conf, $loader_conf_split, $loader_config_file);
1127

    
1128
	$ttys = file_get_contents($ttys_file);
1129
	$ttys_split = explode("\n", $ttys);
1130

    
1131
	$data = array();
1132

    
1133
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1134

    
1135
	if (isset($config['system']['disableconsolemenu'])) {
1136
		$console_type = 'Pc';
1137
		$serial_type = '3wire';
1138
	} else {
1139
		$console_type = 'al.Pc';
1140
		$serial_type = 'al.3wire';
1141
	}
1142

    
1143
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1144
	$ttyv0_line =
1145
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\ton\tsecure";
1146
	$ttyu_line =
1147
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1148

    
1149
	$found = array();
1150

    
1151
	foreach ($ttys_split as $tty) {
1152
		/* Ignore blank lines */
1153
		if (empty($tty)) {
1154
			continue;
1155
		}
1156

    
1157
		if (stristr($tty, "ttyv0")) {
1158
			$found['ttyv0'] = 1;
1159
			$data[] = $ttyv0_line;
1160
		} elseif (stristr($tty, "ttyu")) {
1161
			$ttyn = substr($tty, 0, 5);
1162
			$found[$ttyn] = 1;
1163
			$data[] = "{$ttyn}\t{$ttyu_line}";
1164
		} elseif (substr($tty, 0, 7) == 'console') {
1165
			$found['console'] = 1;
1166
			$data[] = $tty;
1167
		} else {
1168
			$data[] = $tty;
1169
		}
1170
	}
1171
	unset($on_off, $console_type, $serial_type);
1172

    
1173
	/* Detect missing main lines on original file and try to rebuild it */
1174
	$items = array(
1175
		'console',
1176
		'ttyv0',
1177
		'ttyu0',
1178
		'ttyu1',
1179
		'ttyu2',
1180
		'ttyu3'
1181
	);
1182

    
1183
	foreach ($items as $item) {
1184
		if (isset($found[$item])) {
1185
			continue;
1186
		}
1187

    
1188
		if ($item == 'console') {
1189
			$data[] = $console_line;
1190
		} elseif ($item == 'ttyv0') {
1191
			$data[] = $ttyv0_line;
1192
		} else {
1193
			$data[] = "{$item}\t{$ttyu_line}";
1194
		}
1195
	}
1196

    
1197
	safe_write_file($ttys_file, $data);
1198

    
1199
	unset($ttys, $ttys_file, $ttys_split, $data);
1200

    
1201
	if ($when != "upgrade") {
1202
		reload_ttys();
1203
	}
1204

    
1205
	return;
1206
}
1207

    
1208
function is_serial_enabled() {
1209
	global $g, $config;
1210

    
1211
	if (!isset($g['enableserial_force']) &&
1212
	    !isset($config['system']['enableserial'])) {
1213
		return false;
1214
	}
1215

    
1216
	return true;
1217
}
1218

    
1219
function reload_ttys() {
1220
	// Send a HUP signal to init will make it reload /etc/ttys
1221
	posix_kill(1, SIGHUP);
1222
}
1223

    
1224
function print_value_list($list, $count = 10, $separator = ",") {
1225
	$list = implode($separator, array_slice($list, 0, $count));
1226
	if (count($list) < $count) {
1227
		$list .= ".";
1228
	} else {
1229
		$list .= "...";
1230
	}
1231
	return $list;
1232
}
1233

    
1234
/* DHCP enabled on any interfaces? */
1235
function is_dhcp_server_enabled() {
1236
	global $config;
1237

    
1238
	if (!is_array($config['dhcpd'])) {
1239
		return false;
1240
	}
1241

    
1242
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1243
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1244
			return true;
1245
		}
1246
	}
1247

    
1248
	return false;
1249
}
1250

    
1251
/* DHCP enabled on any interfaces? */
1252
function is_dhcpv6_server_enabled() {
1253
	global $config;
1254

    
1255
	if (is_array($config['interfaces'])) {
1256
		foreach ($config['interfaces'] as $ifcfg) {
1257
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1258
				return true;
1259
			}
1260
		}
1261
	}
1262

    
1263
	if (!is_array($config['dhcpdv6'])) {
1264
		return false;
1265
	}
1266

    
1267
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1268
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1269
			return true;
1270
		}
1271
	}
1272

    
1273
	return false;
1274
}
1275

    
1276
/* radvd enabled on any interfaces? */
1277
function is_radvd_enabled() {
1278
	global $config;
1279

    
1280
	if (!is_array($config['dhcpdv6'])) {
1281
		$config['dhcpdv6'] = array();
1282
	}
1283

    
1284
	$dhcpdv6cfg = $config['dhcpdv6'];
1285
	$Iflist = get_configured_interface_list();
1286

    
1287
	/* handle manually configured DHCP6 server settings first */
1288
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1289
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1290
			continue;
1291
		}
1292

    
1293
		if (!isset($dhcpv6ifconf['ramode'])) {
1294
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1295
		}
1296

    
1297
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1298
			continue;
1299
		}
1300

    
1301
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1302
		if (!is_ipaddrv6($ifcfgipv6)) {
1303
			continue;
1304
		}
1305

    
1306
		return true;
1307
	}
1308

    
1309
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1310
	foreach ($Iflist as $if => $ifdescr) {
1311
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1312
			continue;
1313
		}
1314
		if (!isset($config['interfaces'][$if]['enable'])) {
1315
			continue;
1316
		}
1317

    
1318
		$ifcfgipv6 = get_interface_ipv6($if);
1319
		if (!is_ipaddrv6($ifcfgipv6)) {
1320
			continue;
1321
		}
1322

    
1323
		$ifcfgsnv6 = get_interface_subnetv6($if);
1324
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1325

    
1326
		if (!is_ipaddrv6($subnetv6)) {
1327
			continue;
1328
		}
1329

    
1330
		return true;
1331
	}
1332

    
1333
	return false;
1334
}
1335

    
1336
/* Any PPPoE servers enabled? */
1337
function is_pppoe_server_enabled() {
1338
	global $config;
1339

    
1340
	$pppoeenable = false;
1341

    
1342
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1343
		return false;
1344
	}
1345

    
1346
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1347
		if ($pppoes['mode'] == 'server') {
1348
			$pppoeenable = true;
1349
		}
1350
	}
1351

    
1352
	return $pppoeenable;
1353
}
1354

    
1355
/* Optional arg forces hh:mm:ss without days */
1356
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1357
	if (!is_numericint($sec)) {
1358
		return '-';
1359
	}
1360
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1361
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1362
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1363
					(int)(($sec % 3600)/60),
1364
					$sec % 60
1365
				);
1366
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1367
}
1368

    
1369
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1370

    
1371
function get_ppp_uptime($port) {
1372
	if (file_exists("/conf/{$port}.log")) {
1373
		$saved_time = file_get_contents("/conf/{$port}.log");
1374
		$uptime_data = explode("\n", $saved_time);
1375
		$sec = 0;
1376
		foreach ($uptime_data as $upt) {
1377
			$sec += substr($upt, 1 + strpos($upt, " "));
1378
		}
1379
		return convert_seconds_to_dhms($sec);
1380
	} else {
1381
		$total_time = gettext("No history data found!");
1382
		return $total_time;
1383
	}
1384
}
1385

    
1386
//returns interface information
1387
function get_interface_info($ifdescr) {
1388
	global $config, $g;
1389

    
1390
	$ifinfo = array();
1391
	if (empty($config['interfaces'][$ifdescr])) {
1392
		return;
1393
	}
1394
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1395
	$ifinfo['if'] = get_real_interface($ifdescr);
1396

    
1397
	$chkif = $ifinfo['if'];
1398
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1399
	$ifinfo['status'] = $ifinfotmp['status'];
1400
	if (empty($ifinfo['status'])) {
1401
		$ifinfo['status'] = "down";
1402
	}
1403
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1404
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1405
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1406
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1407
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1408
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1409
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1410
	if (isset($ifinfotmp['link0'])) {
1411
		$link0 = "down";
1412
	}
1413
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1414
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1415
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1416
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1417
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1418
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1419

    
1420
	/* Use pfctl for non wrapping 64 bit counters */
1421
	/* Pass */
1422
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1423
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1424
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1425
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1426
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1427
	$in4_pass = $pf_in4_pass[5];
1428
	$out4_pass = $pf_out4_pass[5];
1429
	$in4_pass_packets = $pf_in4_pass[3];
1430
	$out4_pass_packets = $pf_out4_pass[3];
1431
	$in6_pass = $pf_in6_pass[5];
1432
	$out6_pass = $pf_out6_pass[5];
1433
	$in6_pass_packets = $pf_in6_pass[3];
1434
	$out6_pass_packets = $pf_out6_pass[3];
1435
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1436
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1437
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1438
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1439

    
1440
	/* Block */
1441
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1442
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1443
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1444
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1445
	$in4_block = $pf_in4_block[5];
1446
	$out4_block = $pf_out4_block[5];
1447
	$in4_block_packets = $pf_in4_block[3];
1448
	$out4_block_packets = $pf_out4_block[3];
1449
	$in6_block = $pf_in6_block[5];
1450
	$out6_block = $pf_out6_block[5];
1451
	$in6_block_packets = $pf_in6_block[3];
1452
	$out6_block_packets = $pf_out6_block[3];
1453
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1454
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1455
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1456
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1457

    
1458
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1459
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1460
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1461
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1462

    
1463
	$ifconfiginfo = "";
1464
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1465
	switch ($link_type) {
1466
		/* DHCP? -> see if dhclient is up */
1467
		case "dhcp":
1468
			/* see if dhclient is up */
1469
			if (find_dhclient_process($ifinfo['if']) != 0) {
1470
				$ifinfo['dhcplink'] = "up";
1471
			} else {
1472
				$ifinfo['dhcplink'] = "down";
1473
			}
1474

    
1475
			break;
1476
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1477
		case "pppoe":
1478
		case "pptp":
1479
		case "l2tp":
1480
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1481
				/* get PPPoE link status for dial on demand */
1482
				$ifinfo["{$link_type}link"] = "up";
1483
			} else {
1484
				$ifinfo["{$link_type}link"] = "down";
1485
			}
1486

    
1487
			break;
1488
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1489
		case "ppp":
1490
			if ($ifinfo['status'] == "up") {
1491
				$ifinfo['ppplink'] = "up";
1492
			} else {
1493
				$ifinfo['ppplink'] = "down" ;
1494
			}
1495

    
1496
			if (empty($ifinfo['status'])) {
1497
				$ifinfo['status'] = "down";
1498
			}
1499

    
1500
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1501
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1502
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1503
						break;
1504
					}
1505
				}
1506
			}
1507
			$dev = $ppp['ports'];
1508
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1509
				break;
1510
			}
1511
			if (!file_exists($dev)) {
1512
				$ifinfo['nodevice'] = 1;
1513
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1514
			}
1515

    
1516
			$usbmodemoutput = array();
1517
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1518
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1519
			if (file_exists($mondev)) {
1520
				$cellstats = file($mondev);
1521
				/* skip header */
1522
				$a_cellstats = explode(",", $cellstats[1]);
1523
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1524
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1525
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1526
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1527
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1528
				}
1529
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1530
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1531
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1532
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1533
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1534
				}
1535
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1536
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1537
				$ifinfo['cell_sent'] = $a_cellstats[6];
1538
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1539
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1540
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1541
			}
1542
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1543
			if (isset($ppp['uptime'])) {
1544
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1545
			}
1546
			break;
1547
		default:
1548
			break;
1549
	}
1550

    
1551
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1552
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1553
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1554
	}
1555

    
1556
	if ($ifinfo['status'] == "up") {
1557
		/* try to determine media with ifconfig */
1558
		unset($ifconfiginfo);
1559
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1560
		$wifconfiginfo = array();
1561
		if (is_interface_wireless($ifdescr)) {
1562
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1563
			array_shift($wifconfiginfo);
1564
		}
1565
		$matches = "";
1566
		foreach ($ifconfiginfo as $ici) {
1567

    
1568
			/* don't list media/speed for wireless cards, as it always
1569
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1570
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1571
				$ifinfo['media'] = $matches[1];
1572
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1573
				$ifinfo['media'] = $matches[1];
1574
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1575
				$ifinfo['media'] = $matches[1];
1576
			}
1577

    
1578
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1579
				if ($matches[1] != "active") {
1580
					$ifinfo['status'] = $matches[1];
1581
				}
1582
				if ($ifinfo['status'] == gettext("running")) {
1583
					$ifinfo['status'] = gettext("up");
1584
				}
1585
			}
1586
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1587
				$ifinfo['channel'] = $matches[1];
1588
			}
1589
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1590
				if ($matches[1][0] == '"') {
1591
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1592
				}
1593
				else {
1594
					$ifinfo['ssid'] = $matches[1];
1595
				}
1596
			}
1597
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1598
				$ifinfo['laggproto'] = $matches[1];
1599
			}
1600
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1601
				$ifinfo['laggport'][] = $matches[1];
1602
			}
1603
		}
1604
		foreach ($wifconfiginfo as $ici) {
1605
			$elements = preg_split("/[ ]+/i", $ici);
1606
			if ($elements[0] != "") {
1607
				$ifinfo['bssid'] = $elements[0];
1608
			}
1609
			if ($elements[3] != "") {
1610
				$ifinfo['rate'] = $elements[3];
1611
			}
1612
			if ($elements[4] != "") {
1613
				$ifinfo['rssi'] = $elements[4];
1614
			}
1615
		}
1616
		/* lookup the gateway */
1617
		if (interface_has_gateway($ifdescr)) {
1618
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1619
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1620
		}
1621
	}
1622

    
1623
	$bridge = "";
1624
	$bridge = link_interface_to_bridge($ifdescr);
1625
	if ($bridge) {
1626
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1627
		if (stristr($bridge_text, "blocking") <> false) {
1628
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1629
			$ifinfo['bridgeint'] = $bridge;
1630
		} else if (stristr($bridge_text, "learning") <> false) {
1631
			$ifinfo['bridge'] = gettext("learning");
1632
			$ifinfo['bridgeint'] = $bridge;
1633
		} else if (stristr($bridge_text, "forwarding") <> false) {
1634
			$ifinfo['bridge'] = gettext("forwarding");
1635
			$ifinfo['bridgeint'] = $bridge;
1636
		}
1637
	}
1638

    
1639
	return $ifinfo;
1640
}
1641

    
1642
//returns cpu speed of processor. Good for determining capabilities of machine
1643
function get_cpu_speed() {
1644
	return get_single_sysctl("hw.clockrate");
1645
}
1646

    
1647
function get_uptime_sec() {
1648
	$boottime = "";
1649
	$matches = "";
1650
	$boottime = get_single_sysctl("kern.boottime");
1651
	preg_match("/sec = (\d+)/", $boottime, $matches);
1652
	$boottime = $matches[1];
1653
	if (intval($boottime) == 0) {
1654
		return 0;
1655
	}
1656

    
1657
	$uptime = time() - $boottime;
1658
	return $uptime;
1659
}
1660

    
1661
function add_hostname_to_watch($hostname) {
1662
	if (!is_dir("/var/db/dnscache")) {
1663
		mkdir("/var/db/dnscache");
1664
	}
1665
	$result = array();
1666
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1667
		$domrecords = array();
1668
		$domips = array();
1669
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1670
		if ($rethost == 0) {
1671
			foreach ($domrecords as $domr) {
1672
				$doml = explode(" ", $domr);
1673
				$domip = $doml[3];
1674
				/* fill array with domain ip addresses */
1675
				if (is_ipaddr($domip)) {
1676
					$domips[] = $domip;
1677
				}
1678
			}
1679
		}
1680
		sort($domips);
1681
		$contents = "";
1682
		if (!empty($domips)) {
1683
			foreach ($domips as $ip) {
1684
				$contents .= "$ip\n";
1685
			}
1686
		}
1687
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1688
		/* Remove empty elements */
1689
		$result = array_filter(explode("\n", $contents), 'strlen');
1690
	}
1691
	return $result;
1692
}
1693

    
1694
function is_fqdn($fqdn) {
1695
	$hostname = false;
1696
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1697
		$hostname = true;
1698
	}
1699
	if (preg_match("/\.\./", $fqdn)) {
1700
		$hostname = false;
1701
	}
1702
	if (preg_match("/^\./i", $fqdn)) {
1703
		$hostname = false;
1704
	}
1705
	if (preg_match("/\//i", $fqdn)) {
1706
		$hostname = false;
1707
	}
1708
	return($hostname);
1709
}
1710

    
1711
function pfsense_default_state_size() {
1712
	/* get system memory amount */
1713
	$memory = get_memory();
1714
	$physmem = $memory[0];
1715
	/* Be cautious and only allocate 10% of system memory to the state table */
1716
	$max_states = (int) ($physmem/10)*1000;
1717
	return $max_states;
1718
}
1719

    
1720
function pfsense_default_tables_size() {
1721
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1722
	return $current;
1723
}
1724

    
1725
function pfsense_default_table_entries_size() {
1726
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1727
	return (trim($current));
1728
}
1729

    
1730
/* Compare the current hostname DNS to the DNS cache we made
1731
 * if it has changed we return the old records
1732
 * if no change we return false */
1733
function compare_hostname_to_dnscache($hostname) {
1734
	if (!is_dir("/var/db/dnscache")) {
1735
		mkdir("/var/db/dnscache");
1736
	}
1737
	$hostname = trim($hostname);
1738
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1739
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1740
	} else {
1741
		$oldcontents = "";
1742
	}
1743
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1744
		$domrecords = array();
1745
		$domips = array();
1746
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1747
		if ($rethost == 0) {
1748
			foreach ($domrecords as $domr) {
1749
				$doml = explode(" ", $domr);
1750
				$domip = $doml[3];
1751
				/* fill array with domain ip addresses */
1752
				if (is_ipaddr($domip)) {
1753
					$domips[] = $domip;
1754
				}
1755
			}
1756
		}
1757
		sort($domips);
1758
		$contents = "";
1759
		if (!empty($domips)) {
1760
			foreach ($domips as $ip) {
1761
				$contents .= "$ip\n";
1762
			}
1763
		}
1764
	}
1765

    
1766
	if (trim($oldcontents) != trim($contents)) {
1767
		if ($g['debug']) {
1768
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1769
		}
1770
		return ($oldcontents);
1771
	} else {
1772
		return false;
1773
	}
1774
}
1775

    
1776
/*
1777
 * load_crypto() - Load crypto modules if enabled in config.
1778
 */
1779
function load_crypto() {
1780
	global $config, $g;
1781
	$crypto_modules = array('aesni');
1782

    
1783
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1784
		return false;
1785
	}
1786

    
1787
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1788
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1789
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1790
	}
1791
}
1792

    
1793
/*
1794
 * load_thermal_hardware() - Load temperature monitor kernel module
1795
 */
1796
function load_thermal_hardware() {
1797
	global $config, $g;
1798
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1799

    
1800
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1801
		return false;
1802
	}
1803

    
1804
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1805
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1806
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1807
	}
1808
}
1809

    
1810
/****f* pfsense-utils/isvm
1811
 * NAME
1812
 *   isvm
1813
 * INPUTS
1814
 *	none
1815
 * RESULT
1816
 *   returns true if machine is running under a virtual environment
1817
 ******/
1818
function isvm() {
1819
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1820
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
1821

    
1822
	if ($rc != 0 || !isset($output[0])) {
1823
		return false;
1824
	}
1825

    
1826
	foreach ($virtualenvs as $virtualenv) {
1827
		if (stripos($output[0], $virtualenv) !== false) {
1828
			return true;
1829
		}
1830
	}
1831

    
1832
	return false;
1833
}
1834

    
1835
function get_freebsd_version() {
1836
	$version = explode(".", php_uname("r"));
1837
	return $version[0];
1838
}
1839

    
1840
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1841
	global $config, $g;
1842

    
1843
	$fp = fopen($destination, "wb");
1844

    
1845
	if (!$fp) {
1846
		return false;
1847
	}
1848

    
1849
	$ch = curl_init();
1850
	curl_setopt($ch, CURLOPT_URL, $url);
1851
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
1852
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1853
	curl_setopt($ch, CURLOPT_FILE, $fp);
1854
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1855
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1856
	curl_setopt($ch, CURLOPT_HEADER, false);
1857
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1858
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1859
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1860
	} else {
1861
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1862
	}
1863

    
1864
	if (!empty($config['system']['proxyurl'])) {
1865
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1866
		if (!empty($config['system']['proxyport'])) {
1867
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1868
		}
1869
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1870
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1871
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1872
		}
1873
	}
1874

    
1875
	@curl_exec($ch);
1876
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1877
	fclose($fp);
1878
	curl_close($ch);
1879
	if ($http_code == 200) {
1880
		return true;
1881
	} else {
1882
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1883
		unlink_if_exists($destination);
1884
		return false;
1885
	}
1886
}
1887

    
1888
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1889
	global $config, $g;
1890
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1891
	$file_size = 1;
1892
	$downloaded = 1;
1893
	$first_progress_update = TRUE;
1894
	/* open destination file */
1895
	$fout = fopen($destination, "wb");
1896

    
1897
	if (!$fout) {
1898
		return false;
1899
	}
1900
	/*
1901
	 *      Originally by Author: Keyvan Minoukadeh
1902
	 *      Modified by Scott Ullrich to return Content-Length size
1903
	 */
1904
	$ch = curl_init();
1905
	curl_setopt($ch, CURLOPT_URL, $url);
1906
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
1907
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1908
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
1909
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1910
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
1911
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1912
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1913
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1914
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1915
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1916
	} else {
1917
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1918
	}
1919

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

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

    
1944
function read_header($ch, $string) {
1945
	global $file_size, $fout;
1946
	$length = strlen($string);
1947
	$regs = "";
1948
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
1949
	if ($regs[2] <> "") {
1950
		$file_size = intval($regs[2]);
1951
	}
1952
	ob_flush();
1953
	return $length;
1954
}
1955

    
1956
function read_body($ch, $string) {
1957
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
1958
	global $pkg_interface;
1959
	$length = strlen($string);
1960
	$downloaded += intval($length);
1961
	if ($file_size > 0) {
1962
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
1963
		$downloadProgress = 100 - $downloadProgress;
1964
	} else {
1965
		$downloadProgress = 0;
1966
	}
1967
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
1968
		if ($sendto == "status") {
1969
			if ($pkg_interface == "console") {
1970
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
1971
					$tostatus = $static_status . $downloadProgress . "%";
1972
					if ($downloadProgress == 100) {
1973
						$tostatus = $tostatus . "\r";
1974
					}
1975
					update_status($tostatus);
1976
				}
1977
			} else {
1978
				$tostatus = $static_status . $downloadProgress . "%";
1979
				update_status($tostatus);
1980
			}
1981
		} else {
1982
			if ($pkg_interface == "console") {
1983
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
1984
					$tooutput = $static_output . $downloadProgress . "%";
1985
					if ($downloadProgress == 100) {
1986
						$tooutput = $tooutput . "\r";
1987
					}
1988
					update_output_window($tooutput);
1989
				}
1990
			} else {
1991
				$tooutput = $static_output . $downloadProgress . "%";
1992
				update_output_window($tooutput);
1993
			}
1994
		}
1995
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
1996
			update_progress_bar($downloadProgress, $first_progress_update);
1997
			$first_progress_update = FALSE;
1998
		}
1999
		$lastseen = $downloadProgress;
2000
	}
2001
	if ($fout) {
2002
		fwrite($fout, $string);
2003
	}
2004
	ob_flush();
2005
	return $length;
2006
}
2007

    
2008
/*
2009
 *   update_output_window: update bottom textarea dynamically.
2010
 */
2011
function update_output_window($text) {
2012
	global $pkg_interface;
2013
	$log = preg_replace("/\n/", "\\n", $text);
2014
	if ($pkg_interface != "console") {
2015
?>
2016
<script type="text/javascript">
2017
//<![CDATA[
2018
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2019
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2020
//]]>
2021
</script>
2022
<?php
2023
	}
2024
	/* ensure that contents are written out */
2025
	ob_flush();
2026
}
2027

    
2028
/*
2029
 *   update_status: update top textarea dynamically.
2030
 */
2031
function update_status($status) {
2032
	global $pkg_interface;
2033

    
2034
	if ($pkg_interface == "console") {
2035
		print ("{$status}");
2036
	}
2037

    
2038
	/* ensure that contents are written out */
2039
	ob_flush();
2040
}
2041

    
2042
/*
2043
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2044
 */
2045
function update_progress_bar($percent, $first_time) {
2046
	global $pkg_interface;
2047
	if ($percent > 100) {
2048
		$percent = 1;
2049
	}
2050
	if ($pkg_interface <> "console") {
2051
		echo '<script type="text/javascript">';
2052
		echo "\n//<![CDATA[\n";
2053
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2054
		echo "\n//]]>\n";
2055
		echo '</script>';
2056
	} else {
2057
		if (!($first_time)) {
2058
			echo "\x08\x08\x08\x08\x08";
2059
		}
2060
		echo sprintf("%4d%%", $percent);
2061
	}
2062
}
2063

    
2064
/* 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. */
2065
if (!function_exists("split")) {
2066
	function split($separator, $haystack, $limit = null) {
2067
		log_error("deprecated split() call with separator '{$separator}'");
2068
		return preg_split($separator, $haystack, $limit);
2069
	}
2070
}
2071

    
2072
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2073
	global $g, $config, $pconfig, $debug;
2074
	if (!$origname) {
2075
		return;
2076
	}
2077

    
2078
	$sectionref = &$config;
2079
	foreach ($section as $sectionname) {
2080
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2081
			$sectionref = &$sectionref[$sectionname];
2082
		} else {
2083
			return;
2084
		}
2085
	}
2086

    
2087
	if ($debug) {
2088
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2089
		fwrite($fd, print_r($pconfig, true));
2090
	}
2091

    
2092
	if (is_array($sectionref)) {
2093
		foreach ($sectionref as $itemkey => $item) {
2094
			if ($debug) {
2095
				fwrite($fd, "$itemkey\n");
2096
			}
2097

    
2098
			$fieldfound = true;
2099
			$fieldref = &$sectionref[$itemkey];
2100
			foreach ($field as $fieldname) {
2101
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2102
					$fieldref = &$fieldref[$fieldname];
2103
				} else {
2104
					$fieldfound = false;
2105
					break;
2106
				}
2107
			}
2108
			if ($fieldfound && $fieldref == $origname) {
2109
				if ($debug) {
2110
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2111
				}
2112
				$fieldref = $new_alias_name;
2113
			}
2114
		}
2115
	}
2116

    
2117
	if ($debug) {
2118
		fclose($fd);
2119
	}
2120

    
2121
}
2122

    
2123
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2124
	/*
2125
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2126
	 * $type = if set to 'url' then subnets and ips will be returned,
2127
	 *         if set to 'url_ports' port-ranges and ports will be returned
2128
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2129
	 *
2130
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2131
	 */
2132

    
2133
	if (!file_exists($filename)) {
2134
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2135
		return null;
2136
	}
2137

    
2138
	if (filesize($filename) == 0) {
2139
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2140
		return null;
2141
	}
2142
	$fd = @fopen($filename, 'r');
2143
	if (!$fd) {
2144
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2145
		return null;
2146
	}
2147
	$items = array();
2148
	$comments = array();
2149
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2150
	while (($fc = fgetss($fd)) !== FALSE) {
2151
		$tmp = trim($fc, " \t\n\r");
2152
		if (empty($tmp)) {
2153
			continue;
2154
		}
2155
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2156
			$comments[] = $tmp;
2157
		} else {
2158
			$tmp_str = strstr($tmp, '#', true);
2159
			if (!empty($tmp_str)) {
2160
				$tmp = $tmp_str;
2161
			}
2162
			$tmp_str = strstr($tmp, ' ', true);
2163
			if (!empty($tmp_str)) {
2164
				$tmp = $tmp_str;
2165
			}
2166
			$valid = (($type == "url" || $type == "urltable") && (is_ipaddr($tmp) || is_subnet($tmp))) ||
2167
				(($type == "url_ports" || $type == "urltable_ports") && (is_port($tmp) || is_portrange($tmp)));
2168
			if ($valid) {
2169
				$items[] = $tmp;
2170
				if (count($items) == $max_items) {
2171
					break;
2172
				}
2173
			}
2174
		}
2175
	}
2176
	fclose($fd);
2177
	return array_merge($comments, $items);
2178
}
2179

    
2180
function update_alias_url_data() {
2181
	global $config, $g;
2182

    
2183
	$updated = false;
2184

    
2185
	/* item is a url type */
2186
	$lockkey = lock('aliasurl');
2187
	if (is_array($config['aliases']['alias'])) {
2188
		foreach ($config['aliases']['alias'] as $x => $alias) {
2189
			if (empty($alias['aliasurl'])) {
2190
				continue;
2191
			}
2192

    
2193
			$address = null;
2194
			foreach ($alias['aliasurl'] as $alias_url) {
2195
				/* fetch down and add in */
2196
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2197
				unlink($temp_filename);
2198
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2199
				mkdir($temp_filename);
2200
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2201
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2202
					continue;
2203
				}
2204

    
2205
				/* if the item is tar gzipped then extract */
2206
				if (stripos($alias_url, '.tgz')) {
2207
					if (!process_alias_tgz($temp_filename)) {
2208
						continue;
2209
					}
2210
				}
2211
				if (file_exists("{$temp_filename}/aliases")) {
2212
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2213
					mwexec("/bin/rm -rf {$temp_filename}");
2214
				}
2215
			}
2216
			if ($address != null) {
2217
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2218
				$updated = true;
2219
			}
2220
		}
2221
	}
2222
	unlock($lockkey);
2223

    
2224
	/* Report status to callers as well */
2225
	return $updated;
2226
}
2227

    
2228
function process_alias_tgz($temp_filename) {
2229
	if (!file_exists('/usr/bin/tar')) {
2230
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2231
		return false;
2232
	}
2233
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2234
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2235
	unlink("{$temp_filename}/aliases.tgz");
2236
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2237
	/* foreach through all extracted files and build up aliases file */
2238
	$fd = @fopen("{$temp_filename}/aliases", "w");
2239
	if (!$fd) {
2240
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2241
		return false;
2242
	}
2243
	foreach ($files_to_process as $f2p) {
2244
		$tmpfd = @fopen($f2p, 'r');
2245
		if (!$tmpfd) {
2246
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2247
			continue;
2248
		}
2249
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2250
			fwrite($fd, $tmpbuf);
2251
		}
2252
		fclose($tmpfd);
2253
		unlink($f2p);
2254
	}
2255
	fclose($fd);
2256
	unset($tmpbuf);
2257

    
2258
	return true;
2259
}
2260

    
2261
function version_compare_dates($a, $b) {
2262
	$a_time = strtotime($a);
2263
	$b_time = strtotime($b);
2264

    
2265
	if ((!$a_time) || (!$b_time)) {
2266
		return FALSE;
2267
	} else {
2268
		if ($a_time < $b_time) {
2269
			return -1;
2270
		} elseif ($a_time == $b_time) {
2271
			return 0;
2272
		} else {
2273
			return 1;
2274
		}
2275
	}
2276
}
2277
function version_get_string_value($a) {
2278
	$strs = array(
2279
		0 => "ALPHA-ALPHA",
2280
		2 => "ALPHA",
2281
		3 => "BETA",
2282
		4 => "B",
2283
		5 => "C",
2284
		6 => "D",
2285
		7 => "RC",
2286
		8 => "RELEASE",
2287
		9 => "*"			// Matches all release levels
2288
	);
2289
	$major = 0;
2290
	$minor = 0;
2291
	foreach ($strs as $num => $str) {
2292
		if (substr($a, 0, strlen($str)) == $str) {
2293
			$major = $num;
2294
			$n = substr($a, strlen($str));
2295
			if (is_numeric($n)) {
2296
				$minor = $n;
2297
			}
2298
			break;
2299
		}
2300
	}
2301
	return "{$major}.{$minor}";
2302
}
2303
function version_compare_string($a, $b) {
2304
	// Only compare string parts if both versions give a specific release
2305
	// (If either version lacks a string part, assume intended to match all release levels)
2306
	if (isset($a) && isset($b)) {
2307
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2308
	} else {
2309
		return 0;
2310
	}
2311
}
2312
function version_compare_numeric($a, $b) {
2313
	$a_arr = explode('.', rtrim($a, '.'));
2314
	$b_arr = explode('.', rtrim($b, '.'));
2315

    
2316
	foreach ($a_arr as $n => $val) {
2317
		if (array_key_exists($n, $b_arr)) {
2318
			// So far so good, both have values at this minor version level. Compare.
2319
			if ($val > $b_arr[$n]) {
2320
				return 1;
2321
			} elseif ($val < $b_arr[$n]) {
2322
				return -1;
2323
			}
2324
		} else {
2325
			// a is greater, since b doesn't have any minor version here.
2326
			return 1;
2327
		}
2328
	}
2329
	if (count($b_arr) > count($a_arr)) {
2330
		// b is longer than a, so it must be greater.
2331
		return -1;
2332
	} else {
2333
		// Both a and b are of equal length and value.
2334
		return 0;
2335
	}
2336
}
2337
function pfs_version_compare($cur_time, $cur_text, $remote) {
2338
	// First try date compare
2339
	$v = version_compare_dates($cur_time, $remote);
2340
	if ($v === FALSE) {
2341
		// If that fails, try to compare by string
2342
		// Before anything else, simply test if the strings are equal
2343
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2344
			return 0;
2345
		}
2346
		list($cur_num, $cur_str) = explode('-', $cur_text);
2347
		list($rem_num, $rem_str) = explode('-', $remote);
2348

    
2349
		// First try to compare the numeric parts of the version string.
2350
		$v = version_compare_numeric($cur_num, $rem_num);
2351

    
2352
		// If the numeric parts are the same, compare the string parts.
2353
		if ($v == 0) {
2354
			return version_compare_string($cur_str, $rem_str);
2355
		}
2356
	}
2357
	return $v;
2358
}
2359
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2360
	global $g, $config;
2361

    
2362
	$urltable_prefix = "/var/db/aliastables/";
2363
	$urltable_filename = $urltable_prefix . $name . ".txt";
2364
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2365

    
2366
	// Make the aliases directory if it doesn't exist
2367
	if (!file_exists($urltable_prefix)) {
2368
		mkdir($urltable_prefix);
2369
	} elseif (!is_dir($urltable_prefix)) {
2370
		unlink($urltable_prefix);
2371
		mkdir($urltable_prefix);
2372
	}
2373

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

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

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

    
2388
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2389
			if ($type == "urltable_ports") {
2390
				$parsed_contents = group_ports($parsed_contents, true);
2391
			}
2392
			if (is_array($parsed_contents)) {
2393
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2394
			} else {
2395
				touch($urltable_filename);
2396
			}
2397

    
2398
			/* 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. */
2399
			if (!isset($config['system']['use_mfs_tmpvar'])) {
2400
				unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz");
2401
			} else {
2402
				/* Update the RAM disk store with the new/updated table file. */
2403
				mwexec("cd / && /usr/bin/tar -czf \"{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz\" -C / \"{$urltable_filename}\"");
2404
			}
2405
			unlink_if_exists($tmp_urltable_filename);
2406
		} else {
2407
			if (!$validateonly) {
2408
				touch($urltable_filename);
2409
			}
2410
			return false;
2411
		}
2412
		return true;
2413
	} else {
2414
		// File exists, and it doesn't need to be updated.
2415
		return -1;
2416
	}
2417
}
2418

    
2419
function get_include_contents($filename) {
2420
	if (is_file($filename)) {
2421
		ob_start();
2422
		include $filename;
2423
		$contents = ob_get_contents();
2424
		ob_end_clean();
2425
		return $contents;
2426
	}
2427
	return false;
2428
}
2429

    
2430
/* This xml 2 array function is courtesy of the php.net comment section on xml_parse.
2431
 * it is roughly 4 times faster then our existing pfSense parser but due to the large
2432
 * size of the RRD xml dumps this is required.
2433
 * The reason we do not use it for pfSense is that it does not know about array fields
2434
 * which causes it to fail on array fields with single items. Possible Todo?
2435
 */
2436
function xml2array($contents, $get_attributes = 1, $priority = 'tag') {
2437
	if (!function_exists('xml_parser_create')) {
2438
		return array ();
2439
	}
2440
	$parser = xml_parser_create('');
2441
	xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
2442
	xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2443
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2444
	xml_parse_into_struct($parser, trim($contents), $xml_values);
2445
	xml_parser_free($parser);
2446
	if (!$xml_values) {
2447
		return; //Hmm...
2448
	}
2449
	$xml_array = array ();
2450
	$parents = array ();
2451
	$opened_tags = array ();
2452
	$arr = array ();
2453
	$current = & $xml_array;
2454
	$repeated_tag_index = array ();
2455
	foreach ($xml_values as $data) {
2456
		unset ($attributes, $value);
2457
		extract($data);
2458
		$result = array ();
2459
		$attributes_data = array ();
2460
		if (isset ($value)) {
2461
			if ($priority == 'tag') {
2462
				$result = $value;
2463
			} else {
2464
				$result['value'] = $value;
2465
			}
2466
		}
2467
		if (isset ($attributes) and $get_attributes) {
2468
			foreach ($attributes as $attr => $val) {
2469
				if ($priority == 'tag') {
2470
					$attributes_data[$attr] = $val;
2471
				} else {
2472
					$result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
2473
				}
2474
			}
2475
		}
2476
		if ($type == "open") {
2477
			$parent[$level -1] = & $current;
2478
			if (!is_array($current) or (!in_array($tag, array_keys($current)))) {
2479
				$current[$tag] = $result;
2480
				if ($attributes_data) {
2481
					$current[$tag . '_attr'] = $attributes_data;
2482
				}
2483
				$repeated_tag_index[$tag . '_' . $level] = 1;
2484
				$current = & $current[$tag];
2485
			} else {
2486
				if (isset ($current[$tag][0])) {
2487
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2488
					$repeated_tag_index[$tag . '_' . $level]++;
2489
				} else {
2490
					$current[$tag] = array (
2491
						$current[$tag],
2492
						$result
2493
						);
2494
					$repeated_tag_index[$tag . '_' . $level] = 2;
2495
					if (isset ($current[$tag . '_attr'])) {
2496
						$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2497
						unset ($current[$tag . '_attr']);
2498
					}
2499
				}
2500
				$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
2501
				$current = & $current[$tag][$last_item_index];
2502
			}
2503
		} elseif ($type == "complete") {
2504
			if (!isset ($current[$tag])) {
2505
				$current[$tag] = $result;
2506
				$repeated_tag_index[$tag . '_' . $level] = 1;
2507
				if ($priority == 'tag' and $attributes_data) {
2508
					$current[$tag . '_attr'] = $attributes_data;
2509
				}
2510
			} else {
2511
				if (isset ($current[$tag][0]) and is_array($current[$tag])) {
2512
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2513
					if ($priority == 'tag' and $get_attributes and $attributes_data) {
2514
						$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2515
					}
2516
					$repeated_tag_index[$tag . '_' . $level]++;
2517
				} else {
2518
					$current[$tag] = array (
2519
						$current[$tag],
2520
						$result
2521
						);
2522
					$repeated_tag_index[$tag . '_' . $level] = 1;
2523
					if ($priority == 'tag' and $get_attributes) {
2524
						if (isset ($current[$tag . '_attr'])) {
2525
							$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2526
							unset ($current[$tag . '_attr']);
2527
						}
2528
						if ($attributes_data) {
2529
							$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2530
						}
2531
					}
2532
					$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
2533
				}
2534
			}
2535
		} elseif ($type == 'close') {
2536
			$current = & $parent[$level -1];
2537
		}
2538
	}
2539
	return ($xml_array);
2540
}
2541

    
2542
function get_country_name($country_code) {
2543
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2544
		return "";
2545
	}
2546

    
2547
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2548
	$country_names_contents = file_get_contents($country_names_xml);
2549
	$country_names = xml2array($country_names_contents);
2550

    
2551
	if ($country_code == "ALL") {
2552
		$country_list = array();
2553
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2554
			$country_list[] = array(
2555
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2556
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2557
		}
2558
		return $country_list;
2559
	}
2560

    
2561
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2562
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2563
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2564
		}
2565
	}
2566
	return "";
2567
}
2568

    
2569
/* sort by interface only, retain the original order of rules that apply to
2570
   the same interface */
2571
function filter_rules_sort() {
2572
	global $config;
2573

    
2574
	/* mark each rule with the sequence number (to retain the order while sorting) */
2575
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2576
		$config['filter']['rule'][$i]['seq'] = $i;
2577
	}
2578

    
2579
	usort($config['filter']['rule'], "filter_rules_compare");
2580

    
2581
	/* strip the sequence numbers again */
2582
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2583
		unset($config['filter']['rule'][$i]['seq']);
2584
	}
2585
}
2586
function filter_rules_compare($a, $b) {
2587
	if (isset($a['floating']) && isset($b['floating'])) {
2588
		return $a['seq'] - $b['seq'];
2589
	} else if (isset($a['floating'])) {
2590
		return -1;
2591
	} else if (isset($b['floating'])) {
2592
		return 1;
2593
	} else if ($a['interface'] == $b['interface']) {
2594
		return $a['seq'] - $b['seq'];
2595
	} else {
2596
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2597
	}
2598
}
2599

    
2600
function generate_ipv6_from_mac($mac) {
2601
	$elements = explode(":", $mac);
2602
	if (count($elements) <> 6) {
2603
		return false;
2604
	}
2605

    
2606
	$i = 0;
2607
	$ipv6 = "fe80::";
2608
	foreach ($elements as $byte) {
2609
		if ($i == 0) {
2610
			$hexadecimal = substr($byte, 1, 2);
2611
			$bitmap = base_convert($hexadecimal, 16, 2);
2612
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2613
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2614
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2615
		}
2616
		$ipv6 .= $byte;
2617
		if ($i == 1) {
2618
			$ipv6 .= ":";
2619
		}
2620
		if ($i == 3) {
2621
			$ipv6 .= ":";
2622
		}
2623
		if ($i == 2) {
2624
			$ipv6 .= "ff:fe";
2625
		}
2626

    
2627
		$i++;
2628
	}
2629
	return $ipv6;
2630
}
2631

    
2632
/****f* pfsense-utils/load_mac_manufacturer_table
2633
 * NAME
2634
 *   load_mac_manufacturer_table
2635
 * INPUTS
2636
 *   none
2637
 * RESULT
2638
 *   returns associative array with MAC-Manufacturer pairs
2639
 ******/
2640
function load_mac_manufacturer_table() {
2641
	/* load MAC-Manufacture data from the file */
2642
	$macs = false;
2643
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2644
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2645
	}
2646
	if ($macs) {
2647
		foreach ($macs as $line) {
2648
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2649
				/* store values like this $mac_man['000C29']='VMware' */
2650
				$mac_man["$matches[1]"] = $matches[2];
2651
			}
2652
		}
2653
		return $mac_man;
2654
	} else {
2655
		return -1;
2656
	}
2657

    
2658
}
2659

    
2660
/****f* pfsense-utils/is_ipaddr_configured
2661
 * NAME
2662
 *   is_ipaddr_configured
2663
 * INPUTS
2664
 *   IP Address to check.
2665
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2666
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2667
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2668
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2669
 *     If check_subnets is true and cidrprefix is specified,
2670
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2671
 * RESULT
2672
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2673
*/
2674
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2675
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2676
		return true;
2677
	}
2678
	return false;
2679
}
2680

    
2681
/****f* pfsense-utils/where_is_ipaddr_configured
2682
 * NAME
2683
 *   where_is_ipaddr_configured
2684
 * INPUTS
2685
 *   IP Address to check.
2686
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2687
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2688
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2689
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2690
 *     If check_subnets is true and cidrprefix is specified,
2691
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2692
 * RESULT
2693
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2694
 *   If there are no matches then an empty array is returned.
2695
*/
2696
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2697
	global $config;
2698

    
2699
	$where_configured = array();
2700

    
2701
	$pos = strpos($ignore_if, '_virtualip');
2702
	if ($pos !== false) {
2703
		$ignore_vip_id = substr($ignore_if, $pos+10);
2704
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2705
	} else {
2706
		$ignore_vip_id = -1;
2707
		$ignore_vip_if = $ignore_if;
2708
	}
2709

    
2710
	$isipv6 = is_ipaddrv6($ipaddr);
2711

    
2712
	if ($check_subnets) {
2713
		$cidrprefix = intval($cidrprefix);
2714
		if ($isipv6) {
2715
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2716
				$cidrprefix = 128;
2717
			}
2718
		} else {
2719
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2720
				$cidrprefix = 32;
2721
			}
2722
		}
2723
		$iflist = get_configured_interface_list();
2724
		foreach ($iflist as $if => $ifname) {
2725
			if ($ignore_if == $if) {
2726
				continue;
2727
			}
2728

    
2729
			if ($isipv6) {
2730
				$if_ipv6 = get_interface_ipv6($if);
2731
				$if_snbitsv6 = get_interface_subnetv6($if);
2732
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2733
					$where_entry = array();
2734
					$where_entry['if'] = $if;
2735
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2736
					$where_configured[] = $where_entry;
2737
				}
2738
			} else {
2739
				$if_ipv4 = get_interface_ip($if);
2740
				$if_snbitsv4 = get_interface_subnet($if);
2741
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2742
					$where_entry = array();
2743
					$where_entry['if'] = $if;
2744
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2745
					$where_configured[] = $where_entry;
2746
				}
2747
			}
2748
		}
2749
	} else {
2750
		if ($isipv6) {
2751
			$interface_list_ips = get_configured_ipv6_addresses();
2752
		} else {
2753
			$interface_list_ips = get_configured_ip_addresses();
2754
		}
2755

    
2756
		foreach ($interface_list_ips as $if => $ilips) {
2757
			if ($ignore_if == $if) {
2758
				continue;
2759
			}
2760
			if (strcasecmp($ipaddr, $ilips) == 0) {
2761
				$where_entry = array();
2762
				$where_entry['if'] = $if;
2763
				$where_entry['ip_or_subnet'] = $ilips;
2764
				$where_configured[] = $where_entry;
2765
			}
2766
		}
2767
	}
2768

    
2769
	if ($check_localip) {
2770
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, $config['l2tp']['localip']) == 0)) {
2771
			$where_entry = array();
2772
			$where_entry['if'] = 'l2tp';
2773
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2774
			$where_configured[] = $where_entry;
2775
		}
2776
	}
2777

    
2778
	return $where_configured;
2779
}
2780

    
2781
/****f* pfsense-utils/pfSense_handle_custom_code
2782
 * NAME
2783
 *   pfSense_handle_custom_code
2784
 * INPUTS
2785
 *   directory name to process
2786
 * RESULT
2787
 *   globs the directory and includes the files
2788
 */
2789
function pfSense_handle_custom_code($src_dir) {
2790
	// Allow extending of the nat edit page and include custom input validation
2791
	if (is_dir("$src_dir")) {
2792
		$cf = glob($src_dir . "/*.inc");
2793
		foreach ($cf as $nf) {
2794
			if ($nf == "." || $nf == "..") {
2795
				continue;
2796
			}
2797
			// Include the extra handler
2798
			include_once("$nf");
2799
		}
2800
	}
2801
}
2802

    
2803
function set_language() {
2804
	global $config, $g;
2805

    
2806
	if (!empty($config['system']['language'])) {
2807
		$lang = $config['system']['language'];
2808
	} elseif (!empty($g['language'])) {
2809
		$lang = $g['language'];
2810
	}
2811
	$lang .= ".UTF-8";
2812

    
2813
	putenv("LANG={$lang}");
2814
	setlocale(LC_ALL, $lang);
2815
	textdomain("pfSense");
2816
	bindtextdomain("pfSense", "/usr/local/share/locale");
2817
	bind_textdomain_codeset("pfSense", $lang);
2818
}
2819

    
2820
function get_locale_list() {
2821
	$locales = array(
2822
		"en_US" => gettext("English"),
2823
		"pt_BR" => gettext("Portuguese (Brazil)"),
2824
		"tr" => gettext("Turkish"),
2825
	);
2826
	asort($locales);
2827
	return $locales;
2828
}
2829

    
2830
function return_hex_ipv4($ipv4) {
2831
	if (!is_ipaddrv4($ipv4)) {
2832
		return(false);
2833
	}
2834

    
2835
	/* we need the hex form of the interface IPv4 address */
2836
	$ip4arr = explode(".", $ipv4);
2837
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
2838
}
2839

    
2840
function convert_ipv6_to_128bit($ipv6) {
2841
	if (!is_ipaddrv6($ipv6)) {
2842
		return(false);
2843
	}
2844

    
2845
	$ip6arr = array();
2846
	$ip6prefix = Net_IPv6::uncompress($ipv6);
2847
	$ip6arr = explode(":", $ip6prefix);
2848
	/* binary presentation of the prefix for all 128 bits. */
2849
	$ip6prefixbin = "";
2850
	foreach ($ip6arr as $element) {
2851
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
2852
	}
2853
	return($ip6prefixbin);
2854
}
2855

    
2856
function convert_128bit_to_ipv6($ip6bin) {
2857
	if (strlen($ip6bin) <> 128) {
2858
		return(false);
2859
	}
2860

    
2861
	$ip6arr = array();
2862
	$ip6binarr = array();
2863
	$ip6binarr = str_split($ip6bin, 16);
2864
	foreach ($ip6binarr as $binpart) {
2865
		$ip6arr[] = dechex(bindec($binpart));
2866
	}
2867
	$ip6addr = Net_IPv6::compress(implode(":", $ip6arr));
2868

    
2869
	return($ip6addr);
2870
}
2871

    
2872

    
2873
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
2874
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
2875
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
2876
/* 6to4 is 16 bits, e.g. 65535 */
2877
function calculate_ipv6_delegation_length($if) {
2878
	global $config;
2879

    
2880
	if (!is_array($config['interfaces'][$if])) {
2881
		return false;
2882
	}
2883

    
2884
	switch ($config['interfaces'][$if]['ipaddrv6']) {
2885
		case "6to4":
2886
			$pdlen = 16;
2887
			break;
2888
		case "6rd":
2889
			$rd6cfg = $config['interfaces'][$if];
2890
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
2891
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
2892
			break;
2893
		case "dhcp6":
2894
			$dhcp6cfg = $config['interfaces'][$if];
2895
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
2896
			break;
2897
		default:
2898
			$pdlen = 0;
2899
			break;
2900
	}
2901
	return($pdlen);
2902
}
2903

    
2904
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
2905
	$prefix = Net_IPv6::uncompress($prefix, true);
2906
	$suffix = Net_IPv6::uncompress($suffix, true);
2907

    
2908
	/*
2909
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
2910
	 *                ^^^^ ^
2911
	 *                |||| \-> 64
2912
	 *                |||\---> 63, 62, 61, 60
2913
	 *                ||\----> 56
2914
	 *                |\-----> 52
2915
	 *                \------> 48
2916
	 */
2917

    
2918
	switch ($len) {
2919
	case 48:
2920
		$prefix_len = 15;
2921
		break;
2922
	case 52:
2923
		$prefix_len = 16;
2924
		break;
2925
	case 56:
2926
		$prefix_len = 17;
2927
		break;
2928
	case 59:
2929
	case 60:
2930
		$prefix_len = 18;
2931
		break;
2932
	/*
2933
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
2934
	 * we let user chose this bit it can end up out of PD network
2935
	 *
2936
	 * Leave this with 20 for now until we find a way to let user
2937
	 * chose it. The side-effect is users with PD with one of these
2938
	 * lengths will not be able to setup DHCP server range for full
2939
	 * PD size, only for last /64 network
2940
	 */
2941
	case 63:
2942
	case 62:
2943
	case 61:
2944
	default:
2945
		$prefix_len = 20;
2946
		break;
2947
	}
2948

    
2949
	return Net_IPv6::compress(substr($prefix, 0, $prefix_len) .
2950
	    substr($suffix, $prefix_len));
2951
}
2952

    
2953
function dhcpv6_pd_str_help($pdlen) {
2954
	$result = '';
2955

    
2956
	switch ($pdlen) {
2957
	case 48:
2958
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
2959
		break;
2960
	case 52:
2961
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
2962
		break;
2963
	case 56:
2964
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
2965
		break;
2966
	case 59:
2967
	case 60:
2968
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
2969
		break;
2970
	/*
2971
	 * XXX 63, 62 and 61 should use same mask as 60 but if
2972
	 * we let the user choose this bit it can end up out of PD network
2973
	 *
2974
	 * Leave this with the same as 64 for now until we find a way to
2975
	 * let the user choose it. The side-effect is users with PD with one
2976
	 * of these lengths will not be able to setup DHCP server ranges
2977
	 * for full PD size, only for last /64 network
2978
	 */
2979
	case 61:
2980
	case 62:
2981
	case 63:
2982
	case 64:
2983
	default:
2984
		$result = '::xxxx:xxxx:xxxx:xxxx';
2985
		break;
2986
	}
2987

    
2988
	return $result;
2989
}
2990

    
2991
function huawei_rssi_to_string($rssi) {
2992
	$dbm = array();
2993
	$i = 0;
2994
	$dbstart = -113;
2995
	while ($i < 32) {
2996
		$dbm[$i] = $dbstart + ($i * 2);
2997
		$i++;
2998
	}
2999
	$percent = round(($rssi / 31) * 100);
3000
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3001
	return $string;
3002
}
3003

    
3004
function huawei_mode_to_string($mode, $submode) {
3005
	$modes[0] = gettext("None");
3006
	$modes[1] = "AMPS";
3007
	$modes[2] = "CDMA";
3008
	$modes[3] = "GSM/GPRS";
3009
	$modes[4] = "HDR";
3010
	$modes[5] = "WCDMA";
3011
	$modes[6] = "GPS";
3012

    
3013
	$submodes[0] = gettext("No Service");
3014
	$submodes[1] = "GSM";
3015
	$submodes[2] = "GPRS";
3016
	$submodes[3] = "EDGE";
3017
	$submodes[4] = "WCDMA";
3018
	$submodes[5] = "HSDPA";
3019
	$submodes[6] = "HSUPA";
3020
	$submodes[7] = "HSDPA+HSUPA";
3021
	$submodes[8] = "TD-SCDMA";
3022
	$submodes[9] = "HSPA+";
3023
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3024
	return $string;
3025
}
3026

    
3027
function huawei_service_to_string($state) {
3028
	$modes[0] = gettext("No Service");
3029
	$modes[1] = gettext("Restricted Service");
3030
	$modes[2] = gettext("Valid Service");
3031
	$modes[3] = gettext("Restricted Regional Service");
3032
	$modes[4] = gettext("Powersaving Service");
3033
	$string = $modes[$state];
3034
	return $string;
3035
}
3036

    
3037
function huawei_simstate_to_string($state) {
3038
	$modes[0] = gettext("Invalid SIM/locked State");
3039
	$modes[1] = gettext("Valid SIM State");
3040
	$modes[2] = gettext("Invalid SIM CS State");
3041
	$modes[3] = gettext("Invalid SIM PS State");
3042
	$modes[4] = gettext("Invalid SIM CS/PS State");
3043
	$modes[255] = gettext("Missing SIM State");
3044
	$string = $modes[$state];
3045
	return $string;
3046
}
3047

    
3048
function zte_rssi_to_string($rssi) {
3049
	return huawei_rssi_to_string($rssi);
3050
}
3051

    
3052
function zte_mode_to_string($mode, $submode) {
3053
	$modes[0] = gettext("No Service");
3054
	$modes[1] = gettext("Limited Service");
3055
	$modes[2] = "GPRS";
3056
	$modes[3] = "GSM";
3057
	$modes[4] = "UMTS";
3058
	$modes[5] = "EDGE";
3059
	$modes[6] = "HSDPA";
3060

    
3061
	$submodes[0] = "CS_ONLY";
3062
	$submodes[1] = "PS_ONLY";
3063
	$submodes[2] = "CS_PS";
3064
	$submodes[3] = "CAMPED";
3065
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3066
	return $string;
3067
}
3068

    
3069
function zte_service_to_string($service) {
3070
	$modes[0] = gettext("Initializing Service");
3071
	$modes[1] = gettext("Network Lock error Service");
3072
	$modes[2] = gettext("Network Locked Service");
3073
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3074
	$string = $modes[$service];
3075
	return $string;
3076
}
3077

    
3078
function zte_simstate_to_string($state) {
3079
	$modes[0] = gettext("No action State");
3080
	$modes[1] = gettext("Network lock State");
3081
	$modes[2] = gettext("(U)SIM card lock State");
3082
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3083
	$string = $modes[$state];
3084
	return $string;
3085
}
3086

    
3087
function get_configured_pppoe_server_interfaces() {
3088
	global $config;
3089
	$iflist = array();
3090
	if (is_array($config['pppoes']['pppoe'])) {
3091
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3092
			if ($pppoe['mode'] == "server") {
3093
				$int = "poes". $pppoe['pppoeid'];
3094
				$iflist[$int] = strtoupper($int);
3095
			}
3096
		}
3097
	}
3098
	return $iflist;
3099
}
3100

    
3101
function get_pppoes_child_interfaces($ifpattern) {
3102
	$if_arr = array();
3103
	if ($ifpattern == "") {
3104
		return;
3105
	}
3106

    
3107
	exec("/sbin/ifconfig", $out, $ret);
3108
	foreach ($out as $line) {
3109
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3110
			$if_arr[] = $match[1];
3111
		}
3112
	}
3113
	return $if_arr;
3114

    
3115
}
3116

    
3117
/****f* pfsense-utils/pkg_call_plugins
3118
 * NAME
3119
 *   pkg_call_plugins
3120
 * INPUTS
3121
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3122
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3123
 * RESULT
3124
 *   returns associative array results from the plugin calls for each package
3125
 * NOTES
3126
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3127
 ******/
3128
function pkg_call_plugins($plugin_type, $plugin_params) {
3129
	global $g, $config;
3130
	$results = array();
3131
	if (!is_array($config['installedpackages']['package'])) {
3132
		return $results;
3133
	}
3134
	foreach ($config['installedpackages']['package'] as $package) {
3135
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
3136
			continue;
3137
		}
3138
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
3139
		$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3140
		if (is_array($pkg_config['plugins']['item'])) {
3141
			foreach ($pkg_config['plugins']['item'] as $plugin) {
3142
				if ($plugin['type'] == $plugin_type) {
3143
					if (file_exists($pkg_config['include_file'])) {
3144
						require_once($pkg_config['include_file']);
3145
					} else {
3146
						continue;
3147
					}
3148
					$plugin_function = $pkgname . '_'. $plugin_type;
3149
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3150
				}
3151
			}
3152
		}
3153
	}
3154
	return $results;
3155
}
3156

    
3157
function restore_aliastables() {
3158
	global $g, $config;
3159

    
3160
	$dbpath = "{$g['vardb_path']}/aliastables/";
3161

    
3162
	/* restore the alias tables, if we have them */
3163
	$files = glob("{$g['cf_conf_path']}/RAM_Disk_Store{$dbpath}*.tgz");
3164
	if (count($files)) {
3165
		echo "Restoring alias tables...";
3166
		foreach ($files as $file) {
3167
			if (file_exists($file)) {
3168
				$aliastablesrestore = "";
3169
				$aliastablesreturn = "";
3170
				exec("cd /;LANG=C /usr/bin/tar -xzf {$file} 2>&1", $aliastablesrestore, $aliastablesreturn);
3171
				$aliastablesrestore = implode(" ", $aliastablesrestore);
3172
				if ($aliastablesreturn <> 0) {
3173
					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"));
3174
				} else {
3175
					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"));
3176
				}
3177
			}
3178
			/* 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. */
3179
			if (!isset($config['system']['use_mfs_tmpvar'])) {
3180
				unlink_if_exists("{$file}");
3181
			}
3182
		}
3183
		echo "done.\n";
3184
		return true;
3185
	}
3186
	return false;
3187
}
3188

    
3189
// Convert IPv6 addresses to lower case
3190
function addrtolower($ip) {
3191
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3192
		return(strtolower($ip));
3193
	} else {
3194
		return($ip);
3195
	}
3196
}
3197
?>
(30-30/51)