Project

General

Profile

Download (86.6 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
/****f* pfsense-utils/gen_requirestatefilter_field
370
 * NAME
371
 *   gen_requirestatefilter_field
372
 * INPUTS
373
 *   Pointer to section object
374
 *   Initial value for the field
375
 * RESULT
376
 *   no return value, section object is updated
377
 ******/
378
function gen_requirestatefilter_field(&$section, $value) {
379
	$section->addInput(new Form_Checkbox(
380
		'requirestatefilter',
381
		'Require State Filter',
382
		'Do not display state table without a filter',
383
		$value
384
	))->setHelp('By default, the entire state table is displayed when entering '.
385
		'Diagnostics > States. This option requires a filter to be entered '.
386
		'before the states are displayed. Useful for systems with large state tables.');
387
}
388

    
389
function hardware_offloading_applyflags($iface) {
390
	global $config;
391

    
392
	$flags_on = 0;
393
	$flags_off = 0;
394
	$options = pfSense_get_interface_addresses($iface);
395

    
396
	if (isset($config['system']['disablechecksumoffloading'])) {
397
		if (isset($options['encaps']['txcsum'])) {
398
			$flags_off |= IFCAP_TXCSUM;
399
		}
400
		if (isset($options['encaps']['rxcsum'])) {
401
			$flags_off |= IFCAP_RXCSUM;
402
		}
403
		if (isset($options['encaps']['txcsum6'])) {
404
			$flags_off |= IFCAP_TXCSUM_IPV6;
405
		}
406
		if (isset($options['encaps']['rxcsum6'])) {
407
			$flags_off |= IFCAP_RXCSUM_IPV6;
408
		}
409
	} else {
410
		if (isset($options['caps']['txcsum'])) {
411
			$flags_on |= IFCAP_TXCSUM;
412
		}
413
		if (isset($options['caps']['rxcsum'])) {
414
			$flags_on |= IFCAP_RXCSUM;
415
		}
416
		if (isset($options['caps']['txcsum6'])) {
417
			$flags_on |= IFCAP_TXCSUM_IPV6;
418
		}
419
		if (isset($options['caps']['rxcsum6'])) {
420
			$flags_on |= IFCAP_RXCSUM_IPV6;
421
		}
422
	}
423

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

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

    
436
	pfSense_interface_capabilities($iface, -$flags_off);
437
	pfSense_interface_capabilities($iface, $flags_on);
438
}
439

    
440
/****f* pfsense-utils/enable_hardware_offloading
441
 * NAME
442
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
443
 * INPUTS
444
 *   $interface	- string containing the physical interface to work on.
445
 * RESULT
446
 *   null
447
 * NOTES
448
 *   This function only supports the fxp driver's loadable microcode.
449
 ******/
450
function enable_hardware_offloading($interface) {
451
	global $g, $config;
452

    
453
	$int = get_real_interface($interface);
454
	if (empty($int)) {
455
		return;
456
	}
457

    
458
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
459
		/* translate wan, lan, opt -> real interface if needed */
460
		$int_family = preg_split("/[0-9]+/", $int);
461
		$supported_ints = array('fxp');
462
		if (in_array($int_family, $supported_ints)) {
463
			if (does_interface_exist($int)) {
464
				pfSense_interface_flags($int, IFF_LINK0);
465
			}
466
		}
467
	}
468

    
469
	/* This is mostly for vlans and ppp types */
470
	$realhwif = get_parent_interface($interface);
471
	if ($realhwif[0] == $int) {
472
		hardware_offloading_applyflags($int);
473
	} else {
474
		hardware_offloading_applyflags($realhwif[0]);
475
		hardware_offloading_applyflags($int);
476
	}
477
}
478

    
479
/****f* pfsense-utils/is_alias_inuse
480
 * NAME
481
 *   checks to see if an alias is currently in use by a rule
482
 * INPUTS
483
 *
484
 * RESULT
485
 *   true or false
486
 * NOTES
487
 *
488
 ******/
489
function is_alias_inuse($alias) {
490
	global $g, $config;
491

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

    
527
/****f* pfsense-utils/is_schedule_inuse
528
 * NAME
529
 *   checks to see if a schedule is currently in use by a rule
530
 * INPUTS
531
 *
532
 * RESULT
533
 *   true or false
534
 * NOTES
535
 *
536
 ******/
537
function is_schedule_inuse($schedule) {
538
	global $g, $config;
539

    
540
	if ($schedule == "") {
541
		return false;
542
	}
543
	/* loop through firewall rules looking for schedule in use */
544
	if (is_array($config['filter']['rule'])) {
545
		foreach ($config['filter']['rule'] as $rule) {
546
			if ($rule['sched'] == $schedule) {
547
				return true;
548
			}
549
		}
550
	}
551
	return false;
552
}
553

    
554
/****f* pfsense-utils/setup_microcode
555
 * NAME
556
 *   enumerates all interfaces and calls enable_hardware_offloading which
557
 *   enables a NIC's supported hardware features.
558
 * INPUTS
559
 *
560
 * RESULT
561
 *   null
562
 * NOTES
563
 *   This function only supports the fxp driver's loadable microcode.
564
 ******/
565
function setup_microcode() {
566

    
567
	/* if list */
568
	$iflist = get_configured_interface_list(false, true);
569
	foreach ($iflist as $if => $ifdescr) {
570
		enable_hardware_offloading($if);
571
	}
572
	unset($iflist);
573
}
574

    
575
/****f* pfsense-utils/get_carp_status
576
 * NAME
577
 *   get_carp_status - Return whether CARP is enabled or disabled.
578
 * RESULT
579
 *   boolean	- true if CARP is enabled, false if otherwise.
580
 ******/
581
function get_carp_status() {
582
	/* grab the current status of carp */
583
	$status = get_single_sysctl('net.inet.carp.allow');
584
	return (intval($status) > 0);
585
}
586

    
587
/*
588
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
589

    
590
 */
591
function convert_ip_to_network_format($ip, $subnet) {
592
	$ipsplit = explode('.', $ip);
593
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
594
	return $string;
595
}
596

    
597
/*
598
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
599
 */
600
function get_carp_interface_status($carpid) {
601

    
602
	$carpiface = get_configured_vip_interface($carpid);
603
	if ($carpiface == NULL)
604
		return "";
605
	$interface = get_real_interface($carpiface);
606
	if ($interface == NULL)
607
		return "";
608
	$vip = get_configured_vip($carpid);
609
	if ($vip == NULL || !isset($vip['vhid']))
610
		return "";
611

    
612
	$vhid = $vip['vhid'];
613
	$carp_query = '';
614
	$_gb = exec("/sbin/ifconfig $interface | /usr/bin/grep carp: | /usr/bin/grep \"vhid $vhid\"", $carp_query);
615
	foreach ($carp_query as $int) {
616
		if (stripos($int, "MASTER"))
617
			return "MASTER";
618
		elseif (stripos($int, "BACKUP"))
619
			return "BACKUP";
620
		elseif (stripos($int, "INIT"))
621
			return "INIT";
622
	}
623

    
624
	return "";
625
}
626

    
627
/*
628
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
629
 */
630
function get_pfsync_interface_status($pfsyncinterface) {
631
	if (!does_interface_exist($pfsyncinterface)) {
632
		return;
633
	}
634

    
635
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
636
}
637

    
638
/*
639
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
640
 */
641
function add_rule_to_anchor($anchor, $rule, $label) {
642
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
643
}
644

    
645
/*
646
 * remove_text_from_file
647
 * remove $text from file $file
648
 */
649
function remove_text_from_file($file, $text) {
650
	if (!file_exists($file) && !is_writable($file)) {
651
		return;
652
	}
653
	$filecontents = file_get_contents($file);
654
	$text = str_replace($text, "", $filecontents);
655
	@file_put_contents($file, $text);
656
}
657

    
658
/*
659
 *   after_sync_bump_adv_skew(): create skew values by 1S
660
 */
661
function after_sync_bump_adv_skew() {
662
	global $config, $g;
663
	$processed_skew = 1;
664
	$a_vip = &$config['virtualip']['vip'];
665
	foreach ($a_vip as $vipent) {
666
		if ($vipent['advskew'] <> "") {
667
			$processed_skew = 1;
668
			$vipent['advskew'] = $vipent['advskew']+1;
669
		}
670
	}
671
	if ($processed_skew == 1) {
672
		write_config(gettext("After synch increase advertising skew"));
673
	}
674
}
675

    
676
/*
677
 * get_filename_from_url($url): converts a url to its filename.
678
 */
679
function get_filename_from_url($url) {
680
	return basename($url);
681
}
682

    
683
/*
684
 *   get_dir: return an array of $dir
685
 */
686
function get_dir($dir) {
687
	$dir_array = array();
688
	$d = dir($dir);
689
	if (!is_object($d)) {
690
		return array();
691
	}
692
	while (false !== ($entry = $d->read())) {
693
		array_push($dir_array, $entry);
694
	}
695
	$d->close();
696
	return $dir_array;
697
}
698

    
699
/****f* pfsense-utils/WakeOnLan
700
 * NAME
701
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
702
 * RESULT
703
 *   true/false - true if the operation was successful
704
 ******/
705
function WakeOnLan($addr, $mac) {
706
	$addr_byte = explode(':', $mac);
707
	$hw_addr = '';
708

    
709
	for ($a = 0; $a < 6; $a++) {
710
		$hw_addr .= chr(hexdec($addr_byte[$a]));
711
	}
712

    
713
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
714

    
715
	for ($a = 1; $a <= 16; $a++) {
716
		$msg .= $hw_addr;
717
	}
718

    
719
	// send it to the broadcast address using UDP
720
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
721
	if ($s == false) {
722
		log_error(gettext("Error creating socket!"));
723
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
724
	} else {
725
		// setting a broadcast option to socket:
726
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
727
		if ($opt_ret < 0) {
728
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
729
		}
730
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
731
		socket_close($s);
732
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
733
		return true;
734
	}
735

    
736
	return false;
737
}
738

    
739
/*
740
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
741
 *					 Useful for finding paths and stripping file extensions.
742
 */
743
function reverse_strrchr($haystack, $needle) {
744
	if (!is_string($haystack)) {
745
		return;
746
	}
747
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
748
}
749

    
750
/*
751
 *  backup_config_section($section): returns as an xml file string of
752
 *                                   the configuration section
753
 */
754
function backup_config_section($section_name) {
755
	global $config;
756
	$new_section = &$config[$section_name];
757
	/* generate configuration XML */
758
	$xmlconfig = dump_xml_config($new_section, $section_name);
759
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
760
	return $xmlconfig;
761
}
762

    
763
/*
764
 *  restore_config_section($section_name, new_contents): restore a configuration section,
765
 *                                                  and write the configuration out
766
 *                                                  to disk/cf.
767
 */
768
function restore_config_section($section_name, $new_contents) {
769
	global $config, $g;
770
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
771
	fwrite($fout, $new_contents);
772
	fclose($fout);
773

    
774
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
775
	if ($xml['pfsense']) {
776
		$xml = $xml['pfsense'];
777
	}
778
	else if ($xml['m0n0wall']) {
779
		$xml = $xml['m0n0wall'];
780
	}
781
	if ($xml[$section_name]) {
782
		$section_xml = $xml[$section_name];
783
	} else {
784
		$section_xml = -1;
785
	}
786

    
787
	@unlink($g['tmp_path'] . "/tmpxml");
788
	if ($section_xml === -1) {
789
		return false;
790
	}
791
	$config[$section_name] = &$section_xml;
792
	if (file_exists("{$g['tmp_path']}/config.cache")) {
793
		unlink("{$g['tmp_path']}/config.cache");
794
	}
795
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
796
	disable_security_checks();
797
	return true;
798
}
799

    
800
/*
801
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
802
 *                                                  and write the configuration out
803
 *                                                  to disk/cf.  But preserve the prior
804
 * 													structure if needed
805
 */
806
function merge_config_section($section_name, $new_contents) {
807
	global $config;
808
	$fname = get_tmp_filename();
809
	$fout = fopen($fname, "w");
810
	fwrite($fout, $new_contents);
811
	fclose($fout);
812
	$section_xml = parse_xml_config($fname, $section_name);
813
	$config[$section_name] = $section_xml;
814
	unlink($fname);
815
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
816
	disable_security_checks();
817
	return;
818
}
819

    
820
/*
821
 *  php_check_syntax($code_tocheck, $errormessage): checks $code_to_check for errors
822
 */
823
if (!function_exists('php_check_syntax')) {
824
	global $g;
825
	function php_check_syntax($code_to_check, &$errormessage) {
826
		return false;
827
		$fout = fopen("{$g['tmp_path']}/codetocheck.php", "w");
828
		$code = $_POST['content'];
829
		$code = str_replace("<?php", "", $code);
830
		$code = str_replace("?>", "", $code);
831
		fwrite($fout, "<?php\n\n");
832
		fwrite($fout, $code_to_check);
833
		fwrite($fout, "\n\n?>\n");
834
		fclose($fout);
835
		$command = "/usr/local/bin/php-cgi -l {$g['tmp_path']}/codetocheck.php";
836
		$output = exec_command($command);
837
		if (stristr($output, "Errors parsing") == false) {
838
			echo "false\n";
839
			$errormessage = '';
840
			return(false);
841
		} else {
842
			$errormessage = $output;
843
			return(true);
844
		}
845
	}
846
}
847

    
848
/*
849
 *  php_check_filename_syntax($filename, $errormessage): checks the file $filename for errors
850
 */
851
if (!function_exists('php_check_syntax')) {
852
	function php_check_syntax($code_to_check, &$errormessage) {
853
		return false;
854
		$command = "/usr/local/bin/php-cgi -l " . escapeshellarg($code_to_check);
855
		$output = exec_command($command);
856
		if (stristr($output, "Errors parsing") == false) {
857
			echo "false\n";
858
			$errormessage = '';
859
			return(false);
860
		} else {
861
			$errormessage = $output;
862
			return(true);
863
		}
864
	}
865
}
866

    
867
/*
868
 * rmdir_recursive($path, $follow_links=false)
869
 * Recursively remove a directory tree (rm -rf path)
870
 * This is for directories _only_
871
 */
872
function rmdir_recursive($path, $follow_links=false) {
873
	$to_do = glob($path);
874
	if (!is_array($to_do)) {
875
		$to_do = array($to_do);
876
	}
877
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
878
		if (file_exists($workingdir)) {
879
			if (is_dir($workingdir)) {
880
				$dir = opendir($workingdir);
881
				while ($entry = readdir($dir)) {
882
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
883
						unlink("$workingdir/$entry");
884
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
885
						rmdir_recursive("$workingdir/$entry");
886
					}
887
				}
888
				closedir($dir);
889
				rmdir($workingdir);
890
			} elseif (is_file($workingdir)) {
891
				unlink($workingdir);
892
			}
893
		}
894
	}
895
	return;
896
}
897

    
898
/*
899
 * host_firmware_version(): Return the versions used in this install
900
 */
901
function host_firmware_version($tocheck = "") {
902
	global $g, $config;
903

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

    
906
	return array(
907
		"firmware" => array("version" => $g['product_version']),
908
		"kernel"   => array("version" => $os_version),
909
		"base"     => array("version" => $os_version),
910
		"platform" => $g['platform'],
911
		"config_version" => $config['version']
912
	);
913
}
914

    
915
function get_disk_info() {
916
	$diskout = "";
917
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
918
	return explode(' ', $diskout[0]);
919
}
920

    
921
/****f* pfsense-utils/strncpy
922
 * NAME
923
 *   strncpy - copy strings
924
 * INPUTS
925
 *   &$dst, $src, $length
926
 * RESULT
927
 *   none
928
 ******/
929
function strncpy(&$dst, $src, $length) {
930
	if (strlen($src) > $length) {
931
		$dst = substr($src, 0, $length);
932
	} else {
933
		$dst = $src;
934
	}
935
}
936

    
937
/****f* pfsense-utils/reload_interfaces_sync
938
 * NAME
939
 *   reload_interfaces - reload all interfaces
940
 * INPUTS
941
 *   none
942
 * RESULT
943
 *   none
944
 ******/
945
function reload_interfaces_sync() {
946
	global $config, $g;
947

    
948
	if ($g['debug']) {
949
		log_error(gettext("reload_interfaces_sync() is starting."));
950
	}
951

    
952
	/* parse config.xml again */
953
	$config = parse_config(true);
954

    
955
	/* enable routing */
956
	system_routing_enable();
957
	if ($g['debug']) {
958
		log_error(gettext("Enabling system routing"));
959
	}
960

    
961
	if ($g['debug']) {
962
		log_error(gettext("Cleaning up Interfaces"));
963
	}
964

    
965
	/* set up interfaces */
966
	interfaces_configure();
967
}
968

    
969
/****f* pfsense-utils/reload_all
970
 * NAME
971
 *   reload_all - triggers a reload of all settings
972
 *   * INPUTS
973
 *   none
974
 * RESULT
975
 *   none
976
 ******/
977
function reload_all() {
978
	send_event("service reload all");
979
}
980

    
981
/****f* pfsense-utils/reload_interfaces
982
 * NAME
983
 *   reload_interfaces - triggers a reload of all interfaces
984
 * INPUTS
985
 *   none
986
 * RESULT
987
 *   none
988
 ******/
989
function reload_interfaces() {
990
	send_event("interface all reload");
991
}
992

    
993
/****f* pfsense-utils/reload_all_sync
994
 * NAME
995
 *   reload_all - reload all settings
996
 *   * INPUTS
997
 *   none
998
 * RESULT
999
 *   none
1000
 ******/
1001
function reload_all_sync() {
1002
	global $config, $g;
1003

    
1004
	/* parse config.xml again */
1005
	$config = parse_config(true);
1006

    
1007
	/* set up our timezone */
1008
	system_timezone_configure();
1009

    
1010
	/* set up our hostname */
1011
	system_hostname_configure();
1012

    
1013
	/* make hosts file */
1014
	system_hosts_generate();
1015

    
1016
	/* generate resolv.conf */
1017
	system_resolvconf_generate();
1018

    
1019
	/* enable routing */
1020
	system_routing_enable();
1021

    
1022
	/* set up interfaces */
1023
	interfaces_configure();
1024

    
1025
	/* start dyndns service */
1026
	services_dyndns_configure();
1027

    
1028
	/* configure cron service */
1029
	configure_cron();
1030

    
1031
	/* start the NTP client */
1032
	system_ntp_configure();
1033

    
1034
	/* sync pw database */
1035
	unlink_if_exists("/etc/spwd.db.tmp");
1036
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1037

    
1038
	/* restart sshd */
1039
	send_event("service restart sshd");
1040

    
1041
	/* restart webConfigurator if needed */
1042
	send_event("service restart webgui");
1043
}
1044

    
1045
function setup_serial_port($when = "save", $path = "") {
1046
	global $g, $config;
1047
	$ttys_file = "{$path}/etc/ttys";
1048
	$boot_config_file = "{$path}/boot.config";
1049
	$loader_conf_file = "{$path}/boot/loader.conf";
1050
	/* serial console - write out /boot.config */
1051
	if (file_exists($boot_config_file)) {
1052
		$boot_config = file_get_contents($boot_config_file);
1053
	} else {
1054
		$boot_config = "";
1055
	}
1056

    
1057
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1058
	$serial_only = false;
1059

    
1060
	$specific_platform = system_identify_specific_platform();
1061
	if ($specific_platform['name'] == 'RCC-VE' ||
1062
	    $specific_platform['name'] == 'RCC' ||
1063
	    $specific_platform['name'] == 'RCC-DFF' ||
1064
	    $specific_platform['name'] == 'apu2') {
1065
		$serial_only = true;
1066
	}
1067

    
1068
	$boot_config_split = explode("\n", $boot_config);
1069
	$data = array();
1070
	foreach ($boot_config_split as $bcs) {
1071
		/* Ignore -D and -h lines now */
1072
		if (!empty($bcs) && !stristr($bcs, "-D") &&
1073
		    !stristr($bcs, "-h")) {
1074
			$data[] = $bcs;
1075
		}
1076
	}
1077
	if ($serial_only === true) {
1078
		$data[] = "-S{$serialspeed} -h";
1079
	} elseif (is_serial_enabled()) {
1080
		$data[] = "-S{$serialspeed} -D";
1081
	}
1082

    
1083
	if (empty($data)) {
1084
		@unlink($boot_conf_file);
1085
	} else {
1086
		safe_write_file($boot_config_file, $data);
1087
	}
1088

    
1089
	unset($boot_config, $boot_config_file, $boot_config_split);
1090

    
1091
	/* serial console - write out /boot/loader.conf */
1092
	if ($when == "upgrade") {
1093
		system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1094
	}
1095

    
1096
	$loader_conf = file_get_contents($loader_conf_file);
1097
	$loader_conf_split = explode("\n", $loader_conf);
1098

    
1099
	$data = array();
1100
	// Loop through and only add lines that are not empty, and which
1101
	//  do not contain a console directive.
1102
	foreach ($loader_conf_split as $bcs) {
1103
		if (!empty($bcs) &&
1104
		    (stripos($bcs, "console") === false) &&
1105
		    (stripos($bcs, "boot_multicons") === false) &&
1106
		    (stripos($bcs, "boot_serial") === false) &&
1107
		    (stripos($bcs, "hw.usb.no_pf") === false) &&
1108
		    (stripos($bcs, "hint.uart.0.flags") === false) &&
1109
		    (stripos($bcs, "hint.uart.1.flags") === false)) {
1110
			$data[] = $bcs;
1111
		}
1112
	}
1113

    
1114
	if ($serial_only === true) {
1115
		$data[] = 'boot_serial="YES"';
1116
		$data[] = 'console="comconsole"';
1117
	} else if (is_serial_enabled()) {
1118
		$data[] = 'boot_multicons="YES"';
1119
		$data[] = 'boot_serial="YES"';
1120
		$primaryconsole = isset($g['primaryconsole_force']) ?
1121
		    $g['primaryconsole_force'] :
1122
		    $config['system']['primaryconsole'];
1123
		switch ($primaryconsole) {
1124
			case "video":
1125
				$data[] = 'console="vidconsole,comconsole"';
1126
				break;
1127
			case "serial":
1128
			default:
1129
				$data[] = 'console="comconsole,vidconsole"';
1130
		}
1131
	}
1132
	$data[] = 'comconsole_speed="' . $serialspeed . '"';
1133

    
1134
	$specplatform = system_identify_specific_platform();
1135
	if ($specplatform['name'] == 'RCC-VE' ||
1136
	    $specplatform['name'] == 'RCC' ||
1137
	    $specplatform['name'] == 'RCC-DFF') {
1138
		$data[] = 'comconsole_port="0x2F8"';
1139
		$data[] = 'hint.uart.0.flags="0x00"';
1140
		$data[] = 'hint.uart.1.flags="0x10"';
1141
	}
1142
	$data[] = 'hw.usb.no_pf="1"';
1143

    
1144
	safe_write_file($loader_conf_file, $data);
1145

    
1146
	unset($loader_conf, $loader_conf_split, $loader_config_file);
1147

    
1148
	$ttys = file_get_contents($ttys_file);
1149
	$ttys_split = explode("\n", $ttys);
1150

    
1151
	$data = array();
1152

    
1153
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1154

    
1155
	if (isset($config['system']['disableconsolemenu'])) {
1156
		$console_type = 'Pc';
1157
		$serial_type = '3wire';
1158
	} else {
1159
		$console_type = 'al.Pc';
1160
		$serial_type = 'al.3wire';
1161
	}
1162

    
1163
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1164
	$ttyv0_line =
1165
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\ton\tsecure";
1166
	$ttyu_line =
1167
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1168

    
1169
	$found = array();
1170

    
1171
	foreach ($ttys_split as $tty) {
1172
		/* Ignore blank lines */
1173
		if (empty($tty)) {
1174
			continue;
1175
		}
1176

    
1177
		if (stristr($tty, "ttyv0")) {
1178
			$found['ttyv0'] = 1;
1179
			$data[] = $ttyv0_line;
1180
		} elseif (stristr($tty, "ttyu")) {
1181
			$ttyn = substr($tty, 0, 5);
1182
			$found[$ttyn] = 1;
1183
			$data[] = "{$ttyn}\t{$ttyu_line}";
1184
		} elseif (substr($tty, 0, 7) == 'console') {
1185
			$found['console'] = 1;
1186
			$data[] = $tty;
1187
		} else {
1188
			$data[] = $tty;
1189
		}
1190
	}
1191
	unset($on_off, $console_type, $serial_type);
1192

    
1193
	/* Detect missing main lines on original file and try to rebuild it */
1194
	$items = array(
1195
		'console',
1196
		'ttyv0',
1197
		'ttyu0',
1198
		'ttyu1',
1199
		'ttyu2',
1200
		'ttyu3'
1201
	);
1202

    
1203
	foreach ($items as $item) {
1204
		if (isset($found[$item])) {
1205
			continue;
1206
		}
1207

    
1208
		if ($item == 'console') {
1209
			$data[] = $console_line;
1210
		} elseif ($item == 'ttyv0') {
1211
			$data[] = $ttyv0_line;
1212
		} else {
1213
			$data[] = "{$item}\t{$ttyu_line}";
1214
		}
1215
	}
1216

    
1217
	safe_write_file($ttys_file, $data);
1218

    
1219
	unset($ttys, $ttys_file, $ttys_split, $data);
1220

    
1221
	if ($when != "upgrade") {
1222
		reload_ttys();
1223
	}
1224

    
1225
	return;
1226
}
1227

    
1228
function is_serial_enabled() {
1229
	global $g, $config;
1230

    
1231
	if (!isset($g['enableserial_force']) &&
1232
	    !isset($config['system']['enableserial'])) {
1233
		return false;
1234
	}
1235

    
1236
	return true;
1237
}
1238

    
1239
function reload_ttys() {
1240
	// Send a HUP signal to init will make it reload /etc/ttys
1241
	posix_kill(1, SIGHUP);
1242
}
1243

    
1244
function print_value_list($list, $count = 10, $separator = ",") {
1245
	$list = implode($separator, array_slice($list, 0, $count));
1246
	if (count($list) < $count) {
1247
		$list .= ".";
1248
	} else {
1249
		$list .= "...";
1250
	}
1251
	return $list;
1252
}
1253

    
1254
/* DHCP enabled on any interfaces? */
1255
function is_dhcp_server_enabled() {
1256
	global $config;
1257

    
1258
	if (!is_array($config['dhcpd'])) {
1259
		return false;
1260
	}
1261

    
1262
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1263
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1264
			return true;
1265
		}
1266
	}
1267

    
1268
	return false;
1269
}
1270

    
1271
/* DHCP enabled on any interfaces? */
1272
function is_dhcpv6_server_enabled() {
1273
	global $config;
1274

    
1275
	if (is_array($config['interfaces'])) {
1276
		foreach ($config['interfaces'] as $ifcfg) {
1277
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1278
				return true;
1279
			}
1280
		}
1281
	}
1282

    
1283
	if (!is_array($config['dhcpdv6'])) {
1284
		return false;
1285
	}
1286

    
1287
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1288
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1289
			return true;
1290
		}
1291
	}
1292

    
1293
	return false;
1294
}
1295

    
1296
/* radvd enabled on any interfaces? */
1297
function is_radvd_enabled() {
1298
	global $config;
1299

    
1300
	if (!is_array($config['dhcpdv6'])) {
1301
		$config['dhcpdv6'] = array();
1302
	}
1303

    
1304
	$dhcpdv6cfg = $config['dhcpdv6'];
1305
	$Iflist = get_configured_interface_list();
1306

    
1307
	/* handle manually configured DHCP6 server settings first */
1308
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1309
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1310
			continue;
1311
		}
1312

    
1313
		if (!isset($dhcpv6ifconf['ramode'])) {
1314
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1315
		}
1316

    
1317
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1318
			continue;
1319
		}
1320

    
1321
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1322
		if (!is_ipaddrv6($ifcfgipv6)) {
1323
			continue;
1324
		}
1325

    
1326
		return true;
1327
	}
1328

    
1329
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1330
	foreach ($Iflist as $if => $ifdescr) {
1331
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1332
			continue;
1333
		}
1334
		if (!isset($config['interfaces'][$if]['enable'])) {
1335
			continue;
1336
		}
1337

    
1338
		$ifcfgipv6 = get_interface_ipv6($if);
1339
		if (!is_ipaddrv6($ifcfgipv6)) {
1340
			continue;
1341
		}
1342

    
1343
		$ifcfgsnv6 = get_interface_subnetv6($if);
1344
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1345

    
1346
		if (!is_ipaddrv6($subnetv6)) {
1347
			continue;
1348
		}
1349

    
1350
		return true;
1351
	}
1352

    
1353
	return false;
1354
}
1355

    
1356
/* Any PPPoE servers enabled? */
1357
function is_pppoe_server_enabled() {
1358
	global $config;
1359

    
1360
	$pppoeenable = false;
1361

    
1362
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1363
		return false;
1364
	}
1365

    
1366
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1367
		if ($pppoes['mode'] == 'server') {
1368
			$pppoeenable = true;
1369
		}
1370
	}
1371

    
1372
	return $pppoeenable;
1373
}
1374

    
1375
/* Optional arg forces hh:mm:ss without days */
1376
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1377
	if (!is_numericint($sec)) {
1378
		return '-';
1379
	}
1380
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1381
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1382
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1383
					(int)(($sec % 3600)/60),
1384
					$sec % 60
1385
				);
1386
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1387
}
1388

    
1389
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1390

    
1391
function get_ppp_uptime($port) {
1392
	if (file_exists("/conf/{$port}.log")) {
1393
		$saved_time = file_get_contents("/conf/{$port}.log");
1394
		$uptime_data = explode("\n", $saved_time);
1395
		$sec = 0;
1396
		foreach ($uptime_data as $upt) {
1397
			$sec += substr($upt, 1 + strpos($upt, " "));
1398
		}
1399
		return convert_seconds_to_dhms($sec);
1400
	} else {
1401
		$total_time = gettext("No history data found!");
1402
		return $total_time;
1403
	}
1404
}
1405

    
1406
//returns interface information
1407
function get_interface_info($ifdescr) {
1408
	global $config, $g;
1409

    
1410
	$ifinfo = array();
1411
	if (empty($config['interfaces'][$ifdescr])) {
1412
		return;
1413
	}
1414
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1415
	$ifinfo['if'] = get_real_interface($ifdescr);
1416

    
1417
	$chkif = $ifinfo['if'];
1418
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1419
	$ifinfo['status'] = $ifinfotmp['status'];
1420
	if (empty($ifinfo['status'])) {
1421
		$ifinfo['status'] = "down";
1422
	}
1423
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1424
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1425
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1426
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1427
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1428
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1429
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1430
	if (isset($ifinfotmp['link0'])) {
1431
		$link0 = "down";
1432
	}
1433
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1434
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1435
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1436
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1437
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1438
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1439

    
1440
	/* Use pfctl for non wrapping 64 bit counters */
1441
	/* Pass */
1442
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1443
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1444
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1445
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1446
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1447
	$in4_pass = $pf_in4_pass[5];
1448
	$out4_pass = $pf_out4_pass[5];
1449
	$in4_pass_packets = $pf_in4_pass[3];
1450
	$out4_pass_packets = $pf_out4_pass[3];
1451
	$in6_pass = $pf_in6_pass[5];
1452
	$out6_pass = $pf_out6_pass[5];
1453
	$in6_pass_packets = $pf_in6_pass[3];
1454
	$out6_pass_packets = $pf_out6_pass[3];
1455
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1456
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1457
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1458
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1459

    
1460
	/* Block */
1461
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1462
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1463
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1464
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1465
	$in4_block = $pf_in4_block[5];
1466
	$out4_block = $pf_out4_block[5];
1467
	$in4_block_packets = $pf_in4_block[3];
1468
	$out4_block_packets = $pf_out4_block[3];
1469
	$in6_block = $pf_in6_block[5];
1470
	$out6_block = $pf_out6_block[5];
1471
	$in6_block_packets = $pf_in6_block[3];
1472
	$out6_block_packets = $pf_out6_block[3];
1473
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1474
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1475
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1476
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1477

    
1478
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1479
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1480
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1481
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1482

    
1483
	$ifconfiginfo = "";
1484
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1485
	switch ($link_type) {
1486
		/* DHCP? -> see if dhclient is up */
1487
		case "dhcp":
1488
			/* see if dhclient is up */
1489
			if (find_dhclient_process($ifinfo['if']) != 0) {
1490
				$ifinfo['dhcplink'] = "up";
1491
			} else {
1492
				$ifinfo['dhcplink'] = "down";
1493
			}
1494

    
1495
			break;
1496
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1497
		case "pppoe":
1498
		case "pptp":
1499
		case "l2tp":
1500
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1501
				/* get PPPoE link status for dial on demand */
1502
				$ifinfo["{$link_type}link"] = "up";
1503
			} else {
1504
				$ifinfo["{$link_type}link"] = "down";
1505
			}
1506

    
1507
			break;
1508
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1509
		case "ppp":
1510
			if ($ifinfo['status'] == "up") {
1511
				$ifinfo['ppplink'] = "up";
1512
			} else {
1513
				$ifinfo['ppplink'] = "down" ;
1514
			}
1515

    
1516
			if (empty($ifinfo['status'])) {
1517
				$ifinfo['status'] = "down";
1518
			}
1519

    
1520
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1521
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1522
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1523
						break;
1524
					}
1525
				}
1526
			}
1527
			$dev = $ppp['ports'];
1528
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1529
				break;
1530
			}
1531
			if (!file_exists($dev)) {
1532
				$ifinfo['nodevice'] = 1;
1533
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1534
			}
1535

    
1536
			$usbmodemoutput = array();
1537
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1538
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1539
			if (file_exists($mondev)) {
1540
				$cellstats = file($mondev);
1541
				/* skip header */
1542
				$a_cellstats = explode(",", $cellstats[1]);
1543
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1544
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1545
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1546
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1547
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1548
				}
1549
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1550
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1551
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1552
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1553
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1554
				}
1555
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1556
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1557
				$ifinfo['cell_sent'] = $a_cellstats[6];
1558
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1559
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1560
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1561
			}
1562
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1563
			if (isset($ppp['uptime'])) {
1564
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1565
			}
1566
			break;
1567
		default:
1568
			break;
1569
	}
1570

    
1571
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1572
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1573
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1574
	}
1575

    
1576
	if ($ifinfo['status'] == "up") {
1577
		/* try to determine media with ifconfig */
1578
		unset($ifconfiginfo);
1579
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1580
		$wifconfiginfo = array();
1581
		if (is_interface_wireless($ifdescr)) {
1582
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1583
			array_shift($wifconfiginfo);
1584
		}
1585
		$matches = "";
1586
		foreach ($ifconfiginfo as $ici) {
1587

    
1588
			/* don't list media/speed for wireless cards, as it always
1589
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1590
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1591
				$ifinfo['media'] = $matches[1];
1592
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1593
				$ifinfo['media'] = $matches[1];
1594
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1595
				$ifinfo['media'] = $matches[1];
1596
			}
1597

    
1598
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1599
				if ($matches[1] != "active") {
1600
					$ifinfo['status'] = $matches[1];
1601
				}
1602
				if ($ifinfo['status'] == gettext("running")) {
1603
					$ifinfo['status'] = gettext("up");
1604
				}
1605
			}
1606
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1607
				$ifinfo['channel'] = $matches[1];
1608
			}
1609
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1610
				if ($matches[1][0] == '"') {
1611
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1612
				}
1613
				else {
1614
					$ifinfo['ssid'] = $matches[1];
1615
				}
1616
			}
1617
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1618
				$ifinfo['laggproto'] = $matches[1];
1619
			}
1620
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1621
				$ifinfo['laggport'][] = $matches[1];
1622
			}
1623
		}
1624
		foreach ($wifconfiginfo as $ici) {
1625
			$elements = preg_split("/[ ]+/i", $ici);
1626
			if ($elements[0] != "") {
1627
				$ifinfo['bssid'] = $elements[0];
1628
			}
1629
			if ($elements[3] != "") {
1630
				$ifinfo['rate'] = $elements[3];
1631
			}
1632
			if ($elements[4] != "") {
1633
				$ifinfo['rssi'] = $elements[4];
1634
			}
1635
		}
1636
		/* lookup the gateway */
1637
		if (interface_has_gateway($ifdescr)) {
1638
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1639
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1640
		}
1641
	}
1642

    
1643
	$bridge = "";
1644
	$bridge = link_interface_to_bridge($ifdescr);
1645
	if ($bridge) {
1646
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1647
		if (stristr($bridge_text, "blocking") <> false) {
1648
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1649
			$ifinfo['bridgeint'] = $bridge;
1650
		} else if (stristr($bridge_text, "learning") <> false) {
1651
			$ifinfo['bridge'] = gettext("learning");
1652
			$ifinfo['bridgeint'] = $bridge;
1653
		} else if (stristr($bridge_text, "forwarding") <> false) {
1654
			$ifinfo['bridge'] = gettext("forwarding");
1655
			$ifinfo['bridgeint'] = $bridge;
1656
		}
1657
	}
1658

    
1659
	return $ifinfo;
1660
}
1661

    
1662
//returns cpu speed of processor. Good for determining capabilities of machine
1663
function get_cpu_speed() {
1664
	return get_single_sysctl("hw.clockrate");
1665
}
1666

    
1667
function get_uptime_sec() {
1668
	$boottime = "";
1669
	$matches = "";
1670
	$boottime = get_single_sysctl("kern.boottime");
1671
	preg_match("/sec = (\d+)/", $boottime, $matches);
1672
	$boottime = $matches[1];
1673
	if (intval($boottime) == 0) {
1674
		return 0;
1675
	}
1676

    
1677
	$uptime = time() - $boottime;
1678
	return $uptime;
1679
}
1680

    
1681
function add_hostname_to_watch($hostname) {
1682
	if (!is_dir("/var/db/dnscache")) {
1683
		mkdir("/var/db/dnscache");
1684
	}
1685
	$result = array();
1686
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1687
		$domrecords = array();
1688
		$domips = array();
1689
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1690
		if ($rethost == 0) {
1691
			foreach ($domrecords as $domr) {
1692
				$doml = explode(" ", $domr);
1693
				$domip = $doml[3];
1694
				/* fill array with domain ip addresses */
1695
				if (is_ipaddr($domip)) {
1696
					$domips[] = $domip;
1697
				}
1698
			}
1699
		}
1700
		sort($domips);
1701
		$contents = "";
1702
		if (!empty($domips)) {
1703
			foreach ($domips as $ip) {
1704
				$contents .= "$ip\n";
1705
			}
1706
		}
1707
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1708
		/* Remove empty elements */
1709
		$result = array_filter(explode("\n", $contents), 'strlen');
1710
	}
1711
	return $result;
1712
}
1713

    
1714
function is_fqdn($fqdn) {
1715
	$hostname = false;
1716
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1717
		$hostname = true;
1718
	}
1719
	if (preg_match("/\.\./", $fqdn)) {
1720
		$hostname = false;
1721
	}
1722
	if (preg_match("/^\./i", $fqdn)) {
1723
		$hostname = false;
1724
	}
1725
	if (preg_match("/\//i", $fqdn)) {
1726
		$hostname = false;
1727
	}
1728
	return($hostname);
1729
}
1730

    
1731
function pfsense_default_state_size() {
1732
	/* get system memory amount */
1733
	$memory = get_memory();
1734
	$physmem = $memory[0];
1735
	/* Be cautious and only allocate 10% of system memory to the state table */
1736
	$max_states = (int) ($physmem/10)*1000;
1737
	return $max_states;
1738
}
1739

    
1740
function pfsense_default_tables_size() {
1741
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1742
	return $current;
1743
}
1744

    
1745
function pfsense_default_table_entries_size() {
1746
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1747
	return (trim($current));
1748
}
1749

    
1750
/* Compare the current hostname DNS to the DNS cache we made
1751
 * if it has changed we return the old records
1752
 * if no change we return false */
1753
function compare_hostname_to_dnscache($hostname) {
1754
	if (!is_dir("/var/db/dnscache")) {
1755
		mkdir("/var/db/dnscache");
1756
	}
1757
	$hostname = trim($hostname);
1758
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1759
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1760
	} else {
1761
		$oldcontents = "";
1762
	}
1763
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1764
		$domrecords = array();
1765
		$domips = array();
1766
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1767
		if ($rethost == 0) {
1768
			foreach ($domrecords as $domr) {
1769
				$doml = explode(" ", $domr);
1770
				$domip = $doml[3];
1771
				/* fill array with domain ip addresses */
1772
				if (is_ipaddr($domip)) {
1773
					$domips[] = $domip;
1774
				}
1775
			}
1776
		}
1777
		sort($domips);
1778
		$contents = "";
1779
		if (!empty($domips)) {
1780
			foreach ($domips as $ip) {
1781
				$contents .= "$ip\n";
1782
			}
1783
		}
1784
	}
1785

    
1786
	if (trim($oldcontents) != trim($contents)) {
1787
		if ($g['debug']) {
1788
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1789
		}
1790
		return ($oldcontents);
1791
	} else {
1792
		return false;
1793
	}
1794
}
1795

    
1796
/*
1797
 * load_crypto() - Load crypto modules if enabled in config.
1798
 */
1799
function load_crypto() {
1800
	global $config, $g;
1801
	$crypto_modules = array('aesni');
1802

    
1803
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1804
		return false;
1805
	}
1806

    
1807
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1808
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1809
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1810
	}
1811
}
1812

    
1813
/*
1814
 * load_thermal_hardware() - Load temperature monitor kernel module
1815
 */
1816
function load_thermal_hardware() {
1817
	global $config, $g;
1818
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1819

    
1820
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1821
		return false;
1822
	}
1823

    
1824
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1825
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1826
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1827
	}
1828
}
1829

    
1830
/****f* pfsense-utils/isvm
1831
 * NAME
1832
 *   isvm
1833
 * INPUTS
1834
 *	none
1835
 * RESULT
1836
 *   returns true if machine is running under a virtual environment
1837
 ******/
1838
function isvm() {
1839
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1840
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
1841

    
1842
	if ($rc != 0 || !isset($output[0])) {
1843
		return false;
1844
	}
1845

    
1846
	foreach ($virtualenvs as $virtualenv) {
1847
		if (stripos($output[0], $virtualenv) !== false) {
1848
			return true;
1849
		}
1850
	}
1851

    
1852
	return false;
1853
}
1854

    
1855
function get_freebsd_version() {
1856
	$version = explode(".", php_uname("r"));
1857
	return $version[0];
1858
}
1859

    
1860
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1861
	global $config, $g;
1862

    
1863
	$fp = fopen($destination, "wb");
1864

    
1865
	if (!$fp) {
1866
		return false;
1867
	}
1868

    
1869
	$ch = curl_init();
1870
	curl_setopt($ch, CURLOPT_URL, $url);
1871
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
1872
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1873
	curl_setopt($ch, CURLOPT_FILE, $fp);
1874
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1875
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1876
	curl_setopt($ch, CURLOPT_HEADER, false);
1877
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1878
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1879
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1880
	} else {
1881
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1882
	}
1883

    
1884
	if (!empty($config['system']['proxyurl'])) {
1885
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1886
		if (!empty($config['system']['proxyport'])) {
1887
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1888
		}
1889
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1890
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1891
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1892
		}
1893
	}
1894

    
1895
	@curl_exec($ch);
1896
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1897
	fclose($fp);
1898
	curl_close($ch);
1899
	if ($http_code == 200) {
1900
		return true;
1901
	} else {
1902
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1903
		unlink_if_exists($destination);
1904
		return false;
1905
	}
1906
}
1907

    
1908
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1909
	global $config, $g;
1910
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1911
	$file_size = 1;
1912
	$downloaded = 1;
1913
	$first_progress_update = TRUE;
1914
	/* open destination file */
1915
	$fout = fopen($destination, "wb");
1916

    
1917
	if (!$fout) {
1918
		return false;
1919
	}
1920
	/*
1921
	 *      Originally by Author: Keyvan Minoukadeh
1922
	 *      Modified by Scott Ullrich to return Content-Length size
1923
	 */
1924
	$ch = curl_init();
1925
	curl_setopt($ch, CURLOPT_URL, $url);
1926
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
1927
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1928
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
1929
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1930
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
1931
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1932
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1933
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1934
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1935
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1936
	} else {
1937
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1938
	}
1939

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

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

    
1964
function read_header($ch, $string) {
1965
	global $file_size, $fout;
1966
	$length = strlen($string);
1967
	$regs = "";
1968
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
1969
	if ($regs[2] <> "") {
1970
		$file_size = intval($regs[2]);
1971
	}
1972
	ob_flush();
1973
	return $length;
1974
}
1975

    
1976
function read_body($ch, $string) {
1977
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
1978
	global $pkg_interface;
1979
	$length = strlen($string);
1980
	$downloaded += intval($length);
1981
	if ($file_size > 0) {
1982
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
1983
		$downloadProgress = 100 - $downloadProgress;
1984
	} else {
1985
		$downloadProgress = 0;
1986
	}
1987
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
1988
		if ($sendto == "status") {
1989
			if ($pkg_interface == "console") {
1990
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
1991
					$tostatus = $static_status . $downloadProgress . "%";
1992
					if ($downloadProgress == 100) {
1993
						$tostatus = $tostatus . "\r";
1994
					}
1995
					update_status($tostatus);
1996
				}
1997
			} else {
1998
				$tostatus = $static_status . $downloadProgress . "%";
1999
				update_status($tostatus);
2000
			}
2001
		} else {
2002
			if ($pkg_interface == "console") {
2003
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2004
					$tooutput = $static_output . $downloadProgress . "%";
2005
					if ($downloadProgress == 100) {
2006
						$tooutput = $tooutput . "\r";
2007
					}
2008
					update_output_window($tooutput);
2009
				}
2010
			} else {
2011
				$tooutput = $static_output . $downloadProgress . "%";
2012
				update_output_window($tooutput);
2013
			}
2014
		}
2015
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2016
			update_progress_bar($downloadProgress, $first_progress_update);
2017
			$first_progress_update = FALSE;
2018
		}
2019
		$lastseen = $downloadProgress;
2020
	}
2021
	if ($fout) {
2022
		fwrite($fout, $string);
2023
	}
2024
	ob_flush();
2025
	return $length;
2026
}
2027

    
2028
/*
2029
 *   update_output_window: update bottom textarea dynamically.
2030
 */
2031
function update_output_window($text) {
2032
	global $pkg_interface;
2033
	$log = preg_replace("/\n/", "\\n", $text);
2034
	if ($pkg_interface != "console") {
2035
?>
2036
<script type="text/javascript">
2037
//<![CDATA[
2038
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2039
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2040
//]]>
2041
</script>
2042
<?php
2043
	}
2044
	/* ensure that contents are written out */
2045
	ob_flush();
2046
}
2047

    
2048
/*
2049
 *   update_status: update top textarea dynamically.
2050
 */
2051
function update_status($status) {
2052
	global $pkg_interface;
2053

    
2054
	if ($pkg_interface == "console") {
2055
		print ("{$status}");
2056
	}
2057

    
2058
	/* ensure that contents are written out */
2059
	ob_flush();
2060
}
2061

    
2062
/*
2063
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2064
 */
2065
function update_progress_bar($percent, $first_time) {
2066
	global $pkg_interface;
2067
	if ($percent > 100) {
2068
		$percent = 1;
2069
	}
2070
	if ($pkg_interface <> "console") {
2071
		echo '<script type="text/javascript">';
2072
		echo "\n//<![CDATA[\n";
2073
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2074
		echo "\n//]]>\n";
2075
		echo '</script>';
2076
	} else {
2077
		if (!($first_time)) {
2078
			echo "\x08\x08\x08\x08\x08";
2079
		}
2080
		echo sprintf("%4d%%", $percent);
2081
	}
2082
}
2083

    
2084
/* 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. */
2085
if (!function_exists("split")) {
2086
	function split($separator, $haystack, $limit = null) {
2087
		log_error("deprecated split() call with separator '{$separator}'");
2088
		return preg_split($separator, $haystack, $limit);
2089
	}
2090
}
2091

    
2092
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2093
	global $g, $config, $pconfig, $debug;
2094
	if (!$origname) {
2095
		return;
2096
	}
2097

    
2098
	$sectionref = &$config;
2099
	foreach ($section as $sectionname) {
2100
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2101
			$sectionref = &$sectionref[$sectionname];
2102
		} else {
2103
			return;
2104
		}
2105
	}
2106

    
2107
	if ($debug) {
2108
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2109
		fwrite($fd, print_r($pconfig, true));
2110
	}
2111

    
2112
	if (is_array($sectionref)) {
2113
		foreach ($sectionref as $itemkey => $item) {
2114
			if ($debug) {
2115
				fwrite($fd, "$itemkey\n");
2116
			}
2117

    
2118
			$fieldfound = true;
2119
			$fieldref = &$sectionref[$itemkey];
2120
			foreach ($field as $fieldname) {
2121
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2122
					$fieldref = &$fieldref[$fieldname];
2123
				} else {
2124
					$fieldfound = false;
2125
					break;
2126
				}
2127
			}
2128
			if ($fieldfound && $fieldref == $origname) {
2129
				if ($debug) {
2130
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2131
				}
2132
				$fieldref = $new_alias_name;
2133
			}
2134
		}
2135
	}
2136

    
2137
	if ($debug) {
2138
		fclose($fd);
2139
	}
2140

    
2141
}
2142

    
2143
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2144
	/*
2145
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2146
	 * $type = if set to 'url' then subnets and ips will be returned,
2147
	 *         if set to 'url_ports' port-ranges and ports will be returned
2148
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2149
	 *
2150
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2151
	 */
2152

    
2153
	if (!file_exists($filename)) {
2154
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2155
		return null;
2156
	}
2157

    
2158
	if (filesize($filename) == 0) {
2159
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2160
		return null;
2161
	}
2162
	$fd = @fopen($filename, 'r');
2163
	if (!$fd) {
2164
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2165
		return null;
2166
	}
2167
	$items = array();
2168
	$comments = array();
2169
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2170
	while (($fc = fgetss($fd)) !== FALSE) {
2171
		$tmp = trim($fc, " \t\n\r");
2172
		if (empty($tmp)) {
2173
			continue;
2174
		}
2175
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2176
			$comments[] = $tmp;
2177
		} else {
2178
			$tmp_str = strstr($tmp, '#', true);
2179
			if (!empty($tmp_str)) {
2180
				$tmp = $tmp_str;
2181
			}
2182
			$tmp_str = strstr($tmp, ' ', true);
2183
			if (!empty($tmp_str)) {
2184
				$tmp = $tmp_str;
2185
			}
2186
			$valid = (($type == "url" || $type == "urltable") && (is_ipaddr($tmp) || is_subnet($tmp))) ||
2187
				(($type == "url_ports" || $type == "urltable_ports") && (is_port($tmp) || is_portrange($tmp)));
2188
			if ($valid) {
2189
				$items[] = $tmp;
2190
				if (count($items) == $max_items) {
2191
					break;
2192
				}
2193
			}
2194
		}
2195
	}
2196
	fclose($fd);
2197
	return array_merge($comments, $items);
2198
}
2199

    
2200
function update_alias_url_data() {
2201
	global $config, $g;
2202

    
2203
	$updated = false;
2204

    
2205
	/* item is a url type */
2206
	$lockkey = lock('aliasurl');
2207
	if (is_array($config['aliases']['alias'])) {
2208
		foreach ($config['aliases']['alias'] as $x => $alias) {
2209
			if (empty($alias['aliasurl'])) {
2210
				continue;
2211
			}
2212

    
2213
			$address = null;
2214
			foreach ($alias['aliasurl'] as $alias_url) {
2215
				/* fetch down and add in */
2216
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2217
				unlink($temp_filename);
2218
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2219
				mkdir($temp_filename);
2220
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2221
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2222
					continue;
2223
				}
2224

    
2225
				/* if the item is tar gzipped then extract */
2226
				if (stripos($alias_url, '.tgz')) {
2227
					if (!process_alias_tgz($temp_filename)) {
2228
						continue;
2229
					}
2230
				}
2231
				if (file_exists("{$temp_filename}/aliases")) {
2232
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2233
					mwexec("/bin/rm -rf {$temp_filename}");
2234
				}
2235
			}
2236
			if ($address != null) {
2237
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2238
				$updated = true;
2239
			}
2240
		}
2241
	}
2242
	unlock($lockkey);
2243

    
2244
	/* Report status to callers as well */
2245
	return $updated;
2246
}
2247

    
2248
function process_alias_tgz($temp_filename) {
2249
	if (!file_exists('/usr/bin/tar')) {
2250
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2251
		return false;
2252
	}
2253
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2254
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2255
	unlink("{$temp_filename}/aliases.tgz");
2256
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2257
	/* foreach through all extracted files and build up aliases file */
2258
	$fd = @fopen("{$temp_filename}/aliases", "w");
2259
	if (!$fd) {
2260
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2261
		return false;
2262
	}
2263
	foreach ($files_to_process as $f2p) {
2264
		$tmpfd = @fopen($f2p, 'r');
2265
		if (!$tmpfd) {
2266
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2267
			continue;
2268
		}
2269
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2270
			fwrite($fd, $tmpbuf);
2271
		}
2272
		fclose($tmpfd);
2273
		unlink($f2p);
2274
	}
2275
	fclose($fd);
2276
	unset($tmpbuf);
2277

    
2278
	return true;
2279
}
2280

    
2281
function version_compare_dates($a, $b) {
2282
	$a_time = strtotime($a);
2283
	$b_time = strtotime($b);
2284

    
2285
	if ((!$a_time) || (!$b_time)) {
2286
		return FALSE;
2287
	} else {
2288
		if ($a_time < $b_time) {
2289
			return -1;
2290
		} elseif ($a_time == $b_time) {
2291
			return 0;
2292
		} else {
2293
			return 1;
2294
		}
2295
	}
2296
}
2297
function version_get_string_value($a) {
2298
	$strs = array(
2299
		0 => "ALPHA-ALPHA",
2300
		2 => "ALPHA",
2301
		3 => "BETA",
2302
		4 => "B",
2303
		5 => "C",
2304
		6 => "D",
2305
		7 => "RC",
2306
		8 => "RELEASE",
2307
		9 => "*"			// Matches all release levels
2308
	);
2309
	$major = 0;
2310
	$minor = 0;
2311
	foreach ($strs as $num => $str) {
2312
		if (substr($a, 0, strlen($str)) == $str) {
2313
			$major = $num;
2314
			$n = substr($a, strlen($str));
2315
			if (is_numeric($n)) {
2316
				$minor = $n;
2317
			}
2318
			break;
2319
		}
2320
	}
2321
	return "{$major}.{$minor}";
2322
}
2323
function version_compare_string($a, $b) {
2324
	// Only compare string parts if both versions give a specific release
2325
	// (If either version lacks a string part, assume intended to match all release levels)
2326
	if (isset($a) && isset($b)) {
2327
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2328
	} else {
2329
		return 0;
2330
	}
2331
}
2332
function version_compare_numeric($a, $b) {
2333
	$a_arr = explode('.', rtrim($a, '.'));
2334
	$b_arr = explode('.', rtrim($b, '.'));
2335

    
2336
	foreach ($a_arr as $n => $val) {
2337
		if (array_key_exists($n, $b_arr)) {
2338
			// So far so good, both have values at this minor version level. Compare.
2339
			if ($val > $b_arr[$n]) {
2340
				return 1;
2341
			} elseif ($val < $b_arr[$n]) {
2342
				return -1;
2343
			}
2344
		} else {
2345
			// a is greater, since b doesn't have any minor version here.
2346
			return 1;
2347
		}
2348
	}
2349
	if (count($b_arr) > count($a_arr)) {
2350
		// b is longer than a, so it must be greater.
2351
		return -1;
2352
	} else {
2353
		// Both a and b are of equal length and value.
2354
		return 0;
2355
	}
2356
}
2357
function pfs_version_compare($cur_time, $cur_text, $remote) {
2358
	// First try date compare
2359
	$v = version_compare_dates($cur_time, $remote);
2360
	if ($v === FALSE) {
2361
		// If that fails, try to compare by string
2362
		// Before anything else, simply test if the strings are equal
2363
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2364
			return 0;
2365
		}
2366
		list($cur_num, $cur_str) = explode('-', $cur_text);
2367
		list($rem_num, $rem_str) = explode('-', $remote);
2368

    
2369
		// First try to compare the numeric parts of the version string.
2370
		$v = version_compare_numeric($cur_num, $rem_num);
2371

    
2372
		// If the numeric parts are the same, compare the string parts.
2373
		if ($v == 0) {
2374
			return version_compare_string($cur_str, $rem_str);
2375
		}
2376
	}
2377
	return $v;
2378
}
2379
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2380
	global $g, $config;
2381

    
2382
	$urltable_prefix = "/var/db/aliastables/";
2383
	$urltable_filename = $urltable_prefix . $name . ".txt";
2384
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2385

    
2386
	// Make the aliases directory if it doesn't exist
2387
	if (!file_exists($urltable_prefix)) {
2388
		mkdir($urltable_prefix);
2389
	} elseif (!is_dir($urltable_prefix)) {
2390
		unlink($urltable_prefix);
2391
		mkdir($urltable_prefix);
2392
	}
2393

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

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

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

    
2408
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2409
			if ($type == "urltable_ports") {
2410
				$parsed_contents = group_ports($parsed_contents, true);
2411
			}
2412
			if (is_array($parsed_contents)) {
2413
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2414
			} else {
2415
				touch($urltable_filename);
2416
			}
2417

    
2418
			/* Remove existing archive and create an up to date archive if RAM disk is enabled. */
2419
			unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz");
2420
			if (isset($config['system']['use_mfs_tmpvar'])) {
2421
				mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename));
2422
			}
2423

    
2424
			unlink_if_exists($tmp_urltable_filename);
2425
		} else {
2426
			if (!$validateonly) {
2427
				touch($urltable_filename);
2428
			}
2429
			return false;
2430
		}
2431
		return true;
2432
	} else {
2433
		// File exists, and it doesn't need to be updated.
2434
		return -1;
2435
	}
2436
}
2437

    
2438
function get_include_contents($filename) {
2439
	if (is_file($filename)) {
2440
		ob_start();
2441
		include $filename;
2442
		$contents = ob_get_contents();
2443
		ob_end_clean();
2444
		return $contents;
2445
	}
2446
	return false;
2447
}
2448

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

    
2561
function get_country_name($country_code) {
2562
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2563
		return "";
2564
	}
2565

    
2566
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2567
	$country_names_contents = file_get_contents($country_names_xml);
2568
	$country_names = xml2array($country_names_contents);
2569

    
2570
	if ($country_code == "ALL") {
2571
		$country_list = array();
2572
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2573
			$country_list[] = array(
2574
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2575
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2576
		}
2577
		return $country_list;
2578
	}
2579

    
2580
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2581
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2582
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2583
		}
2584
	}
2585
	return "";
2586
}
2587

    
2588
/* sort by interface only, retain the original order of rules that apply to
2589
   the same interface */
2590
function filter_rules_sort() {
2591
	global $config;
2592

    
2593
	/* mark each rule with the sequence number (to retain the order while sorting) */
2594
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2595
		$config['filter']['rule'][$i]['seq'] = $i;
2596
	}
2597

    
2598
	usort($config['filter']['rule'], "filter_rules_compare");
2599

    
2600
	/* strip the sequence numbers again */
2601
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2602
		unset($config['filter']['rule'][$i]['seq']);
2603
	}
2604
}
2605
function filter_rules_compare($a, $b) {
2606
	if (isset($a['floating']) && isset($b['floating'])) {
2607
		return $a['seq'] - $b['seq'];
2608
	} else if (isset($a['floating'])) {
2609
		return -1;
2610
	} else if (isset($b['floating'])) {
2611
		return 1;
2612
	} else if ($a['interface'] == $b['interface']) {
2613
		return $a['seq'] - $b['seq'];
2614
	} else {
2615
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2616
	}
2617
}
2618

    
2619
function generate_ipv6_from_mac($mac) {
2620
	$elements = explode(":", $mac);
2621
	if (count($elements) <> 6) {
2622
		return false;
2623
	}
2624

    
2625
	$i = 0;
2626
	$ipv6 = "fe80::";
2627
	foreach ($elements as $byte) {
2628
		if ($i == 0) {
2629
			$hexadecimal = substr($byte, 1, 2);
2630
			$bitmap = base_convert($hexadecimal, 16, 2);
2631
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2632
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2633
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2634
		}
2635
		$ipv6 .= $byte;
2636
		if ($i == 1) {
2637
			$ipv6 .= ":";
2638
		}
2639
		if ($i == 3) {
2640
			$ipv6 .= ":";
2641
		}
2642
		if ($i == 2) {
2643
			$ipv6 .= "ff:fe";
2644
		}
2645

    
2646
		$i++;
2647
	}
2648
	return $ipv6;
2649
}
2650

    
2651
/****f* pfsense-utils/load_mac_manufacturer_table
2652
 * NAME
2653
 *   load_mac_manufacturer_table
2654
 * INPUTS
2655
 *   none
2656
 * RESULT
2657
 *   returns associative array with MAC-Manufacturer pairs
2658
 ******/
2659
function load_mac_manufacturer_table() {
2660
	/* load MAC-Manufacture data from the file */
2661
	$macs = false;
2662
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2663
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2664
	}
2665
	if ($macs) {
2666
		foreach ($macs as $line) {
2667
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2668
				/* store values like this $mac_man['000C29']='VMware' */
2669
				$mac_man["$matches[1]"] = $matches[2];
2670
			}
2671
		}
2672
		return $mac_man;
2673
	} else {
2674
		return -1;
2675
	}
2676

    
2677
}
2678

    
2679
/****f* pfsense-utils/is_ipaddr_configured
2680
 * NAME
2681
 *   is_ipaddr_configured
2682
 * INPUTS
2683
 *   IP Address to check.
2684
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2685
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2686
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2687
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2688
 *     If check_subnets is true and cidrprefix is specified,
2689
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2690
 * RESULT
2691
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2692
*/
2693
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2694
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2695
		return true;
2696
	}
2697
	return false;
2698
}
2699

    
2700
/****f* pfsense-utils/where_is_ipaddr_configured
2701
 * NAME
2702
 *   where_is_ipaddr_configured
2703
 * INPUTS
2704
 *   IP Address to check.
2705
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2706
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2707
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2708
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2709
 *     If check_subnets is true and cidrprefix is specified,
2710
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2711
 * RESULT
2712
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2713
 *   If there are no matches then an empty array is returned.
2714
*/
2715
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2716
	global $config;
2717

    
2718
	$where_configured = array();
2719

    
2720
	$pos = strpos($ignore_if, '_virtualip');
2721
	if ($pos !== false) {
2722
		$ignore_vip_id = substr($ignore_if, $pos+10);
2723
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2724
	} else {
2725
		$ignore_vip_id = -1;
2726
		$ignore_vip_if = $ignore_if;
2727
	}
2728

    
2729
	$isipv6 = is_ipaddrv6($ipaddr);
2730

    
2731
	if ($check_subnets) {
2732
		$cidrprefix = intval($cidrprefix);
2733
		if ($isipv6) {
2734
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2735
				$cidrprefix = 128;
2736
			}
2737
		} else {
2738
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2739
				$cidrprefix = 32;
2740
			}
2741
		}
2742
		$iflist = get_configured_interface_list();
2743
		foreach ($iflist as $if => $ifname) {
2744
			if ($ignore_if == $if) {
2745
				continue;
2746
			}
2747

    
2748
			if ($isipv6) {
2749
				$if_ipv6 = get_interface_ipv6($if);
2750
				$if_snbitsv6 = get_interface_subnetv6($if);
2751
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2752
					$where_entry = array();
2753
					$where_entry['if'] = $if;
2754
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2755
					$where_configured[] = $where_entry;
2756
				}
2757
			} else {
2758
				$if_ipv4 = get_interface_ip($if);
2759
				$if_snbitsv4 = get_interface_subnet($if);
2760
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2761
					$where_entry = array();
2762
					$where_entry['if'] = $if;
2763
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2764
					$where_configured[] = $where_entry;
2765
				}
2766
			}
2767
		}
2768
	} else {
2769
		if ($isipv6) {
2770
			$interface_list_ips = get_configured_ipv6_addresses();
2771
		} else {
2772
			$interface_list_ips = get_configured_ip_addresses();
2773
		}
2774

    
2775
		foreach ($interface_list_ips as $if => $ilips) {
2776
			if ($ignore_if == $if) {
2777
				continue;
2778
			}
2779
			if (strcasecmp($ipaddr, $ilips) == 0) {
2780
				$where_entry = array();
2781
				$where_entry['if'] = $if;
2782
				$where_entry['ip_or_subnet'] = $ilips;
2783
				$where_configured[] = $where_entry;
2784
			}
2785
		}
2786
	}
2787

    
2788
	if ($check_localip) {
2789
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, $config['l2tp']['localip']) == 0)) {
2790
			$where_entry = array();
2791
			$where_entry['if'] = 'l2tp';
2792
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2793
			$where_configured[] = $where_entry;
2794
		}
2795
	}
2796

    
2797
	return $where_configured;
2798
}
2799

    
2800
/****f* pfsense-utils/pfSense_handle_custom_code
2801
 * NAME
2802
 *   pfSense_handle_custom_code
2803
 * INPUTS
2804
 *   directory name to process
2805
 * RESULT
2806
 *   globs the directory and includes the files
2807
 */
2808
function pfSense_handle_custom_code($src_dir) {
2809
	// Allow extending of the nat edit page and include custom input validation
2810
	if (is_dir("$src_dir")) {
2811
		$cf = glob($src_dir . "/*.inc");
2812
		foreach ($cf as $nf) {
2813
			if ($nf == "." || $nf == "..") {
2814
				continue;
2815
			}
2816
			// Include the extra handler
2817
			include_once("$nf");
2818
		}
2819
	}
2820
}
2821

    
2822
function set_language() {
2823
	global $config, $g;
2824

    
2825
	if (!empty($config['system']['language'])) {
2826
		$lang = $config['system']['language'];
2827
	} elseif (!empty($g['language'])) {
2828
		$lang = $g['language'];
2829
	}
2830
	$lang .= ".UTF-8";
2831

    
2832
	putenv("LANG={$lang}");
2833
	setlocale(LC_ALL, $lang);
2834
	textdomain("pfSense");
2835
	bindtextdomain("pfSense", "/usr/local/share/locale");
2836
	bind_textdomain_codeset("pfSense", $lang);
2837
}
2838

    
2839
function get_locale_list() {
2840
	$locales = array(
2841
		"en_US" => gettext("English"),
2842
		"pt_BR" => gettext("Portuguese (Brazil)"),
2843
		"tr" => gettext("Turkish"),
2844
	);
2845
	asort($locales);
2846
	return $locales;
2847
}
2848

    
2849
function return_hex_ipv4($ipv4) {
2850
	if (!is_ipaddrv4($ipv4)) {
2851
		return(false);
2852
	}
2853

    
2854
	/* we need the hex form of the interface IPv4 address */
2855
	$ip4arr = explode(".", $ipv4);
2856
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
2857
}
2858

    
2859
function convert_ipv6_to_128bit($ipv6) {
2860
	if (!is_ipaddrv6($ipv6)) {
2861
		return(false);
2862
	}
2863

    
2864
	$ip6arr = array();
2865
	$ip6prefix = Net_IPv6::uncompress($ipv6);
2866
	$ip6arr = explode(":", $ip6prefix);
2867
	/* binary presentation of the prefix for all 128 bits. */
2868
	$ip6prefixbin = "";
2869
	foreach ($ip6arr as $element) {
2870
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
2871
	}
2872
	return($ip6prefixbin);
2873
}
2874

    
2875
function convert_128bit_to_ipv6($ip6bin) {
2876
	if (strlen($ip6bin) <> 128) {
2877
		return(false);
2878
	}
2879

    
2880
	$ip6arr = array();
2881
	$ip6binarr = array();
2882
	$ip6binarr = str_split($ip6bin, 16);
2883
	foreach ($ip6binarr as $binpart) {
2884
		$ip6arr[] = dechex(bindec($binpart));
2885
	}
2886
	$ip6addr = Net_IPv6::compress(implode(":", $ip6arr));
2887

    
2888
	return($ip6addr);
2889
}
2890

    
2891

    
2892
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
2893
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
2894
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
2895
/* 6to4 is 16 bits, e.g. 65535 */
2896
function calculate_ipv6_delegation_length($if) {
2897
	global $config;
2898

    
2899
	if (!is_array($config['interfaces'][$if])) {
2900
		return false;
2901
	}
2902

    
2903
	switch ($config['interfaces'][$if]['ipaddrv6']) {
2904
		case "6to4":
2905
			$pdlen = 16;
2906
			break;
2907
		case "6rd":
2908
			$rd6cfg = $config['interfaces'][$if];
2909
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
2910
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
2911
			break;
2912
		case "dhcp6":
2913
			$dhcp6cfg = $config['interfaces'][$if];
2914
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
2915
			break;
2916
		default:
2917
			$pdlen = 0;
2918
			break;
2919
	}
2920
	return($pdlen);
2921
}
2922

    
2923
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
2924
	$prefix = Net_IPv6::uncompress($prefix, true);
2925
	$suffix = Net_IPv6::uncompress($suffix, true);
2926

    
2927
	/*
2928
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
2929
	 *                ^^^^ ^
2930
	 *                |||| \-> 64
2931
	 *                |||\---> 63, 62, 61, 60
2932
	 *                ||\----> 56
2933
	 *                |\-----> 52
2934
	 *                \------> 48
2935
	 */
2936

    
2937
	switch ($len) {
2938
	case 48:
2939
		$prefix_len = 15;
2940
		break;
2941
	case 52:
2942
		$prefix_len = 16;
2943
		break;
2944
	case 56:
2945
		$prefix_len = 17;
2946
		break;
2947
	case 59:
2948
	case 60:
2949
		$prefix_len = 18;
2950
		break;
2951
	/*
2952
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
2953
	 * we let user chose this bit it can end up out of PD network
2954
	 *
2955
	 * Leave this with 20 for now until we find a way to let user
2956
	 * chose it. The side-effect is users with PD with one of these
2957
	 * lengths will not be able to setup DHCP server range for full
2958
	 * PD size, only for last /64 network
2959
	 */
2960
	case 63:
2961
	case 62:
2962
	case 61:
2963
	default:
2964
		$prefix_len = 20;
2965
		break;
2966
	}
2967

    
2968
	return Net_IPv6::compress(substr($prefix, 0, $prefix_len) .
2969
	    substr($suffix, $prefix_len));
2970
}
2971

    
2972
function dhcpv6_pd_str_help($pdlen) {
2973
	$result = '';
2974

    
2975
	switch ($pdlen) {
2976
	case 48:
2977
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
2978
		break;
2979
	case 52:
2980
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
2981
		break;
2982
	case 56:
2983
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
2984
		break;
2985
	case 59:
2986
	case 60:
2987
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
2988
		break;
2989
	/*
2990
	 * XXX 63, 62 and 61 should use same mask as 60 but if
2991
	 * we let the user choose this bit it can end up out of PD network
2992
	 *
2993
	 * Leave this with the same as 64 for now until we find a way to
2994
	 * let the user choose it. The side-effect is users with PD with one
2995
	 * of these lengths will not be able to setup DHCP server ranges
2996
	 * for full PD size, only for last /64 network
2997
	 */
2998
	case 61:
2999
	case 62:
3000
	case 63:
3001
	case 64:
3002
	default:
3003
		$result = '::xxxx:xxxx:xxxx:xxxx';
3004
		break;
3005
	}
3006

    
3007
	return $result;
3008
}
3009

    
3010
function huawei_rssi_to_string($rssi) {
3011
	$dbm = array();
3012
	$i = 0;
3013
	$dbstart = -113;
3014
	while ($i < 32) {
3015
		$dbm[$i] = $dbstart + ($i * 2);
3016
		$i++;
3017
	}
3018
	$percent = round(($rssi / 31) * 100);
3019
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3020
	return $string;
3021
}
3022

    
3023
function huawei_mode_to_string($mode, $submode) {
3024
	$modes[0] = gettext("None");
3025
	$modes[1] = "AMPS";
3026
	$modes[2] = "CDMA";
3027
	$modes[3] = "GSM/GPRS";
3028
	$modes[4] = "HDR";
3029
	$modes[5] = "WCDMA";
3030
	$modes[6] = "GPS";
3031

    
3032
	$submodes[0] = gettext("No Service");
3033
	$submodes[1] = "GSM";
3034
	$submodes[2] = "GPRS";
3035
	$submodes[3] = "EDGE";
3036
	$submodes[4] = "WCDMA";
3037
	$submodes[5] = "HSDPA";
3038
	$submodes[6] = "HSUPA";
3039
	$submodes[7] = "HSDPA+HSUPA";
3040
	$submodes[8] = "TD-SCDMA";
3041
	$submodes[9] = "HSPA+";
3042
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3043
	return $string;
3044
}
3045

    
3046
function huawei_service_to_string($state) {
3047
	$modes[0] = gettext("No Service");
3048
	$modes[1] = gettext("Restricted Service");
3049
	$modes[2] = gettext("Valid Service");
3050
	$modes[3] = gettext("Restricted Regional Service");
3051
	$modes[4] = gettext("Powersaving Service");
3052
	$string = $modes[$state];
3053
	return $string;
3054
}
3055

    
3056
function huawei_simstate_to_string($state) {
3057
	$modes[0] = gettext("Invalid SIM/locked State");
3058
	$modes[1] = gettext("Valid SIM State");
3059
	$modes[2] = gettext("Invalid SIM CS State");
3060
	$modes[3] = gettext("Invalid SIM PS State");
3061
	$modes[4] = gettext("Invalid SIM CS/PS State");
3062
	$modes[255] = gettext("Missing SIM State");
3063
	$string = $modes[$state];
3064
	return $string;
3065
}
3066

    
3067
function zte_rssi_to_string($rssi) {
3068
	return huawei_rssi_to_string($rssi);
3069
}
3070

    
3071
function zte_mode_to_string($mode, $submode) {
3072
	$modes[0] = gettext("No Service");
3073
	$modes[1] = gettext("Limited Service");
3074
	$modes[2] = "GPRS";
3075
	$modes[3] = "GSM";
3076
	$modes[4] = "UMTS";
3077
	$modes[5] = "EDGE";
3078
	$modes[6] = "HSDPA";
3079

    
3080
	$submodes[0] = "CS_ONLY";
3081
	$submodes[1] = "PS_ONLY";
3082
	$submodes[2] = "CS_PS";
3083
	$submodes[3] = "CAMPED";
3084
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3085
	return $string;
3086
}
3087

    
3088
function zte_service_to_string($service) {
3089
	$modes[0] = gettext("Initializing Service");
3090
	$modes[1] = gettext("Network Lock error Service");
3091
	$modes[2] = gettext("Network Locked Service");
3092
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3093
	$string = $modes[$service];
3094
	return $string;
3095
}
3096

    
3097
function zte_simstate_to_string($state) {
3098
	$modes[0] = gettext("No action State");
3099
	$modes[1] = gettext("Network lock State");
3100
	$modes[2] = gettext("(U)SIM card lock State");
3101
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3102
	$string = $modes[$state];
3103
	return $string;
3104
}
3105

    
3106
function get_configured_pppoe_server_interfaces() {
3107
	global $config;
3108
	$iflist = array();
3109
	if (is_array($config['pppoes']['pppoe'])) {
3110
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3111
			if ($pppoe['mode'] == "server") {
3112
				$int = "poes". $pppoe['pppoeid'];
3113
				$iflist[$int] = strtoupper($int);
3114
			}
3115
		}
3116
	}
3117
	return $iflist;
3118
}
3119

    
3120
function get_pppoes_child_interfaces($ifpattern) {
3121
	$if_arr = array();
3122
	if ($ifpattern == "") {
3123
		return;
3124
	}
3125

    
3126
	exec("/sbin/ifconfig", $out, $ret);
3127
	foreach ($out as $line) {
3128
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3129
			$if_arr[] = $match[1];
3130
		}
3131
	}
3132
	return $if_arr;
3133

    
3134
}
3135

    
3136
/****f* pfsense-utils/pkg_call_plugins
3137
 * NAME
3138
 *   pkg_call_plugins
3139
 * INPUTS
3140
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3141
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3142
 * RESULT
3143
 *   returns associative array results from the plugin calls for each package
3144
 * NOTES
3145
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3146
 ******/
3147
function pkg_call_plugins($plugin_type, $plugin_params) {
3148
	global $g, $config;
3149
	$results = array();
3150
	if (!is_array($config['installedpackages']['package'])) {
3151
		return $results;
3152
	}
3153
	foreach ($config['installedpackages']['package'] as $package) {
3154
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
3155
			continue;
3156
		}
3157
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
3158
		$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3159
		if (is_array($pkg_config['plugins']['item'])) {
3160
			foreach ($pkg_config['plugins']['item'] as $plugin) {
3161
				if ($plugin['type'] == $plugin_type) {
3162
					if (file_exists($pkg_config['include_file'])) {
3163
						require_once($pkg_config['include_file']);
3164
					} else {
3165
						continue;
3166
					}
3167
					$plugin_function = $pkgname . '_'. $plugin_type;
3168
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3169
				}
3170
			}
3171
		}
3172
	}
3173
	return $results;
3174
}
3175

    
3176
// Convert IPv6 addresses to lower case
3177
function addrtolower($ip) {
3178
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3179
		return(strtolower($ip));
3180
	} else {
3181
		return($ip);
3182
	}
3183
}
3184
?>
(30-30/51)