Project

General

Profile

Download (104 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-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2022 Rubicon Communications, LLC (Netgate)
9
 * All rights reserved.
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 * http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23

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

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

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

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

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

    
111
/* Stub for deprecated function
112
 * See https://redmine.pfsense.org/issues/10931 */
113
function get_dns_servers() {
114
	return get_dns_nameservers(false, true);
115
}
116

    
117
/****f* pfsense-utils/pfSenseHeader
118
 * NAME
119
 *   pfSenseHeader
120
 * INPUTS
121
 *   none
122
 * RESULT
123
 *   Javascript header change or browser Location:
124
 ******/
125
function pfSenseHeader($text) {
126
	global $_SERVER;
127
	if (isAjax()) {
128
		if ($_SERVER['HTTPS'] == "on") {
129
			$protocol = "https";
130
		} else {
131
			$protocol = "http";
132
		}
133

    
134
		$port = ":{$_SERVER['SERVER_PORT']}";
135
		if ($_SERVER['SERVER_PORT'] == "80" && $protocol == "http") {
136
			$port = "";
137
		}
138
		if ($_SERVER['SERVER_PORT'] == "443" && $protocol == "https") {
139
			$port = "";
140
		}
141
		$complete_url = "{$protocol}://{$_SERVER['HTTP_HOST']}{$port}/{$text}";
142
		echo "\ndocument.location.href = '{$complete_url}';\n";
143
	} else {
144
		header("Location: $text");
145
	}
146
}
147

    
148
/****f* pfsense-utils/get_css_files
149
 * NAME
150
 *   get_css_files - get a list of the available CSS files (themes)
151
 * INPUTS
152
 *   none
153
 * RESULT
154
 *   $csslist - an array of the CSS files
155
 ******/
156
function get_css_files() {
157
	$csslist = array();
158

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

    
162
	if (is_array($cssfiles)) {
163
		arsort($cssfiles);
164
		$usrcss = $pfscss = $betacss = array();
165

    
166
		foreach ($cssfiles as $css) {
167
			// Don't display any login/logo page related CSS files
168
			if (strpos($css, "login") == 0 &&
169
			    strpos($css, "logo") == 0) {
170
				if (strpos($css, "BETA") != 0) {
171
					array_push($betacss, $css);
172
				} else if (strpos($css, "pfSense") != 0) {
173
					array_push($pfscss, $css);
174
				} else {
175
					array_push($usrcss, $css);
176
				}
177
			}
178
		}
179

    
180
		$css = array_merge($pfscss, $betacss, $usrcss);
181

    
182
		foreach ($css as $file) {
183
			$file = basename($file);
184
			$csslist[$file] = pathinfo($file, PATHINFO_FILENAME);
185
		}
186
	}
187
	return $csslist;
188
}
189

    
190
/****f* pfsense-utils/gen_webguicss_field
191
 * NAME
192
 *   gen_webguicss_field
193
 * INPUTS
194
 *   Pointer to section object
195
 *   Initial value for the field
196
 * RESULT
197
 *   no return value, section object is updated
198
 ******/
199
function gen_webguicss_field(&$section, $value) {
200

    
201
	$csslist = get_css_files();
202

    
203
	if (!isset($csslist[$value])) {
204
		$value = "pfSense.css";
205
	}
206

    
207
	$section->addInput(new Form_Select(
208
		'webguicss',
209
		'Theme',
210
		$value,
211
		$csslist
212
	))->setHelp('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>');
213
}
214
function validate_webguicss_field(&$input_errors, $value) {
215
	$csslist = get_css_files();
216
	if (!isset($csslist[$value])) {
217
		$input_errors[] = gettext("The submitted Theme could not be found. Pick a different theme.");
218
	}
219
}
220

    
221
/****f* pfsense-utils/gen_webguifixedmenu_field
222
 * NAME
223
 *   gen_webguifixedmenu_field
224
 * INPUTS
225
 *   Pointer to section object
226
 *   Initial value for the field
227
 * RESULT
228
 *   no return value, section object is updated
229
 ******/
230
function gen_webguifixedmenu_field(&$section, $value) {
231

    
232
	$section->addInput(new Form_Select(
233
		'webguifixedmenu',
234
		'Top Navigation',
235
		$value,
236
		["" => gettext("Scrolls with page"), "fixed" => gettext("Fixed (Remains visible at top of page)")]
237
	))->setHelp("The fixed option is intended for large screens only.");
238
}
239
function validate_webguifixedmenu_field(&$input_errors, $value) {
240
	$valid_values = array("", "fixed");
241
	if (!in_array($value, $valid_values)) {
242
		$input_errors[] = gettext("The submitted Top Navigation value is invalid.");
243
	}
244
}
245

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

    
257
	$section->addInput(new Form_Select(
258
		'webguihostnamemenu',
259
		'Hostname in Menu',
260
		$value,
261
		["" => gettext("Default (No hostname)"), "hostonly" => gettext("Hostname only"), "fqdn" => gettext("Fully Qualified Domain Name")]
262
	))->setHelp("Replaces the Help menu title in the Navbar with the system hostname or FQDN.");
263
}
264
function validate_webguihostnamemenu_field(&$input_errors, $value) {
265
	$valid_values = array("", "hostonly", "fqdn");
266
	if (!in_array($value, $valid_values)) {
267
		$input_errors[] = gettext("The submitted Hostname in Menu value is invalid.");
268
	}
269
}
270

    
271
/****f* pfsense-utils/gen_dashboardcolumns_field
272
 * NAME
273
 *   gen_dashboardcolumns_field
274
 * INPUTS
275
 *   Pointer to section object
276
 *   Initial value for the field
277
 * RESULT
278
 *   no return value, section object is updated
279
 ******/
280
function gen_dashboardcolumns_field(&$section, $value) {
281

    
282
	if (((int) $value < 1) || ((int) $value > 6)) {
283
		$value = 2;
284
	}
285

    
286
	$section->addInput(new Form_Input(
287
		'dashboardcolumns',
288
		'Dashboard Columns',
289
		'number',
290
		$value,
291
		['min' => 1, 'max' => 6]
292
	));
293
}
294
function validate_dashboardcolumns_field(&$input_errors, $value) {
295
	if (!is_numericint($value) || ((int) $value < 1) || ((int) $value > 6)) {
296
		$input_errors[] = gettext("The submitted Dashboard Columns value is invalid.");
297
	}
298
}
299

    
300
/****f* pfsense-utils/gen_interfacessort_field
301
 * NAME
302
 *   gen_interfacessort_field
303
 * INPUTS
304
 *   Pointer to section object
305
 *   Initial value for the field
306
 * RESULT
307
 *   no return value, section object is updated
308
 ******/
309
function gen_interfacessort_field(&$section, $value) {
310

    
311
	$section->addInput(new Form_Checkbox(
312
		'interfacessort',
313
		'Interfaces Sort',
314
		'Sort Alphabetically',
315
		$value
316
	))->setHelp('If selected, lists of interfaces will be sorted by description, otherwise they are listed wan,lan,optn...');
317
}
318

    
319
/****f* pfsense-utils/gen_associatedpanels_fields
320
 * NAME
321
 *   gen_associatedpanels_fields
322
 * INPUTS
323
 *   Pointer to section object
324
 *   Initial value for each of the fields
325
 * RESULT
326
 *   no return value, section object is updated
327
 ******/
328
function gen_associatedpanels_fields(&$section, $value1, $value2, $value3, $value4) {
329

    
330
	$group = new Form_Group('Associated Panels Show/Hide');
331

    
332
	$group->add(new Form_Checkbox(
333
		'dashboardavailablewidgetspanel',
334
		null,
335
		'Available Widgets',
336
		$value1
337
		))->setHelp('Show the Available Widgets panel on the Dashboard.');
338

    
339
	$group->add(new Form_Checkbox(
340
		'systemlogsfilterpanel',
341
		null,
342
		'Log Filter',
343
		$value2
344
	))->setHelp('Show the Log Filter panel in System Logs.');
345

    
346
	$group->add(new Form_Checkbox(
347
		'systemlogsmanagelogpanel',
348
		null,
349
		'Manage Log',
350
		$value3
351
	))->setHelp('Show the Manage Log panel in System Logs.');
352

    
353
	$group->add(new Form_Checkbox(
354
		'statusmonitoringsettingspanel',
355
		null,
356
		'Monitoring Settings',
357
		$value4
358
	))->setHelp('Show the Settings panel in Status Monitoring.');
359

    
360
	$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.');
361

    
362
	$section->add($group);
363
}
364

    
365
/****f* pfsense-utils/gen_webguileftcolumnhyper_field
366
 * NAME
367
 *   gen_webguileftcolumnhyper_field
368
 * INPUTS
369
 *   Pointer to section object
370
 *   Initial value for the field
371
 * RESULT
372
 *   no return value, section object is updated
373
 ******/
374
function gen_webguileftcolumnhyper_field(&$section, $value) {
375

    
376
	$section->addInput(new Form_Checkbox(
377
		'webguileftcolumnhyper',
378
		'Left Column Labels',
379
		'Active',
380
		$value
381
	))->setHelp('If selected, clicking a label in the left column will select/toggle the first item of the group.');
382
}
383

    
384
/****f* pfsense-utils/gen_disablealiaspopupdetail_field
385
 * NAME
386
 *   gen_disablealiaspopupdetail_field
387
 * INPUTS
388
 *   Pointer to section object
389
 *   Initial value for the field
390
 * RESULT
391
 *   no return value, section object is updated
392
 ******/
393
function gen_disablealiaspopupdetail_field(&$section, $value) {
394

    
395
	$section->addInput(new Form_Checkbox(
396
		'disablealiaspopupdetail',
397
		'Alias Popups',
398
		'Disable details in alias popups',
399
		$value
400
	))->setHelp('If selected, the details in alias popups will not be shown, just the alias description (e.g. in Firewall Rules).');
401
}
402

    
403
/****f* pfsense-utils/gen_pagenamefirst_field
404
 * NAME
405
 *   gen_pagenamefirst_field
406
 * INPUTS
407
 *   Pointer to section object
408
 *   Initial value for the field
409
 * RESULT
410
 *   no return value, section object is updated
411
 ******/
412
function gen_pagenamefirst_field(&$section, $value) {
413

    
414
	$section->addInput(new Form_Checkbox(
415
		'pagenamefirst',
416
		'Browser tab text',
417
		'Display page name first in browser tab',
418
		$value
419
	))->setHelp('When this is unchecked, the browser tab shows the host name followed '.
420
		'by the current page. Check this box to display the current page followed by the '.
421
		'host name.');
422
}
423

    
424
/****f* pfsense-utils/gen_user_settings_fields
425
 * NAME
426
 *   gen_user_settings_fields
427
 * INPUTS
428
 *   Pointer to section object
429
 *   Array of initial values for the fields
430
 * RESULT
431
 *   no return value, section object is updated
432
 ******/
433
function gen_user_settings_fields(&$section, $pconfig) {
434

    
435
	gen_webguicss_field($section, $pconfig['webguicss']);
436
	gen_webguifixedmenu_field($section, $pconfig['webguifixedmenu']);
437
	gen_webguihostnamemenu_field($section, $pconfig['webguihostnamemenu']);
438
	gen_dashboardcolumns_field($section, $pconfig['dashboardcolumns']);
439
	gen_interfacessort_field($section, $pconfig['interfacessort']);
440
	gen_associatedpanels_fields(
441
		$section,
442
		$pconfig['dashboardavailablewidgetspanel'],
443
		$pconfig['systemlogsfilterpanel'],
444
		$pconfig['systemlogsmanagelogpanel'],
445
		$pconfig['statusmonitoringsettingspanel']);
446
	gen_webguileftcolumnhyper_field($section, $pconfig['webguileftcolumnhyper']);
447
	gen_disablealiaspopupdetail_field($section, $pconfig['disablealiaspopupdetail']);
448
	gen_pagenamefirst_field($section, $pconfig['pagenamefirst']);
449
}
450

    
451
/****f* pfsense-utils/gen_requirestatefilter_field
452
 * NAME
453
 *   gen_requirestatefilter_field
454
 * INPUTS
455
 *   Pointer to section object
456
 *   Initial value for the field
457
 * RESULT
458
 *   no return value, section object is updated
459
 ******/
460
function gen_requirestatefilter_field(&$section, $value) {
461
	$section->addInput(new Form_Checkbox(
462
		'requirestatefilter',
463
		'Require State Filter',
464
		'Do not display state table without a filter',
465
		$value
466
	))->setHelp('By default, the entire state table is displayed when entering '.
467
		'Diagnostics > States. This option requires a filter to be entered '.
468
		'before the states are displayed. Useful for systems with large state tables.');
469
}
470

    
471
/****f* pfsense-utils/gen_created_updated_fields
472
 * NAME
473
 *   gen_created_updated_fields
474
 * INPUTS
475
 *   Pointer to form object
476
 *   Array of created time and username
477
 *   Array of updated time and username
478
 * RESULT
479
 *   no return value, section object is added to form if needed
480
 ******/
481
function gen_created_updated_fields(&$form, $created, $updated, $tracker = 0) {
482
	$has_created_time = (isset($created['time']) && isset($created['username']));
483
	$has_updated_time = (isset($updated['time']) && isset($updated['username']));
484

    
485
	if ($has_created_time || $has_updated_time) {
486
		$section = new Form_Section('Rule Information');
487

    
488
		if (!empty($tracker)) {
489
			$section->addInput(new Form_StaticText(
490
				'Tracking ID',
491
				htmlspecialchars($tracker)
492
			));
493
		}
494

    
495
		if ($has_created_time) {
496
			$section->addInput(new Form_StaticText(
497
				'Created',
498
				htmlspecialchars(sprintf(
499
					gettext('%1$s by %2$s'),
500
					date(gettext("n/j/y H:i:s"), $created['time']),
501
					$created['username']))
502
			));
503
		}
504

    
505
		if ($has_updated_time) {
506
			$section->addInput(new Form_StaticText(
507
				'Updated',
508
				htmlspecialchars(sprintf(
509
					gettext('%1$s by %2$s'),
510
					date(gettext("n/j/y H:i:s"), $updated['time']),
511
					$updated['username']))
512
			));
513
		}
514

    
515
		$form->add($section);
516
	}
517
}
518

    
519
function hardware_offloading_applyflags($iface) {
520
	global $config;
521

    
522
	$flags_on = 0;
523
	$flags_off = 0;
524
	$options = pfSense_get_interface_addresses($iface);
525

    
526
	/* disable hardware checksum offloading for VirtIO network drivers,
527
	 * see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=165059 */
528
	if (isset($config['system']['disablechecksumoffloading']) ||
529
	    stristr($iface, "vtnet") || stristr($iface, "ena")) { 
530
		if (isset($options['encaps']['txcsum'])) {
531
			$flags_off |= IFCAP_TXCSUM;
532
		}
533
		if (isset($options['encaps']['rxcsum'])) {
534
			$flags_off |= IFCAP_RXCSUM;
535
		}
536
		if (isset($options['encaps']['txcsum6'])) {
537
			$flags_off |= IFCAP_TXCSUM_IPV6;
538
		}
539
		if (isset($options['encaps']['rxcsum6'])) {
540
			$flags_off |= IFCAP_RXCSUM_IPV6;
541
		}
542
	} else {
543
		if (isset($options['caps']['txcsum'])) {
544
			$flags_on |= IFCAP_TXCSUM;
545
		}
546
		if (isset($options['caps']['rxcsum'])) {
547
			$flags_on |= IFCAP_RXCSUM;
548
		}
549
		if (isset($options['caps']['txcsum6'])) {
550
			$flags_on |= IFCAP_TXCSUM_IPV6;
551
		}
552
		if (isset($options['caps']['rxcsum6'])) {
553
			$flags_on |= IFCAP_RXCSUM_IPV6;
554
		}
555
	}
556

    
557
	if (isset($config['system']['disablesegmentationoffloading'])) {
558
		$flags_off |= IFCAP_TSO;
559
		$flags_off |= IFCAP_VLAN_HWTSO;
560
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
561
		$flags_on |= IFCAP_TSO;
562
		$flags_on |= IFCAP_VLAN_HWTSO;
563
	}
564

    
565
	if (isset($config['system']['disablelargereceiveoffloading'])) {
566
		$flags_off |= IFCAP_LRO;
567
	} else if (isset($options['caps']['lro'])) {
568
		$flags_on |= IFCAP_LRO;
569
	}
570

    
571
	pfSense_interface_capabilities($iface, -$flags_off);
572
	pfSense_interface_capabilities($iface, $flags_on);
573
}
574

    
575
/****f* pfsense-utils/enable_hardware_offloading
576
 * NAME
577
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
578
 * INPUTS
579
 *   $interface	- string containing the physical interface to work on.
580
 * RESULT
581
 *   null
582
 * NOTES
583
 *   This function only supports the fxp driver's loadable microcode.
584
 ******/
585
function enable_hardware_offloading($interface) {
586
	global $g, $config;
587

    
588
	$int = get_real_interface($interface);
589
	if (empty($int)) {
590
		return;
591
	}
592

    
593
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
594
		/* translate wan, lan, opt -> real interface if needed */
595
		$int_family = preg_split("/[0-9]+/", $int);
596
		$supported_ints = array('fxp');
597
		if (in_array($int_family, $supported_ints)) {
598
			if (does_interface_exist($int)) {
599
				pfSense_interface_flags($int, IFF_LINK0);
600
			}
601
		}
602
	}
603

    
604
	/* This is mostly for vlans and ppp types */
605
	$realhwif = get_parent_interface($interface);
606
	if ($realhwif[0] == $int) {
607
		hardware_offloading_applyflags($int);
608
	} else {
609
		hardware_offloading_applyflags($realhwif[0]);
610
		hardware_offloading_applyflags($int);
611
	}
612
}
613

    
614
/****f* pfsense-utils/is_alias_inuse
615
 * NAME
616
 *   checks to see if an alias is currently in use by a rule
617
 * INPUTS
618
 *
619
 * RESULT
620
 *   true or false
621
 * NOTES
622
 *
623
 ******/
624
function is_alias_inuse($alias) {
625
	global $g, $config;
626

    
627
	if ($alias == "") {
628
		return false;
629
	}
630
	/* loop through firewall rules looking for alias in use */
631
	if (is_array($config['filter']['rule'])) {
632
		foreach ($config['filter']['rule'] as $rule) {
633
			if ($rule['source']['address']) {
634
				if ($rule['source']['address'] == $alias) {
635
					return true;
636
				}
637
			}
638
			if ($rule['destination']['address']) {
639
				if ($rule['destination']['address'] == $alias) {
640
					return true;
641
				}
642
			}
643
		}
644
	}
645
	/* loop through nat rules looking for alias in use */
646
	if (is_array($config['nat']['rule'])) {
647
		foreach ($config['nat']['rule'] as $rule) {
648
			if ($rule['target'] && $rule['target'] == $alias) {
649
				return true;
650
			}
651
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
652
				return true;
653
			}
654
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
655
				return true;
656
			}
657
		}
658
	}
659
	return false;
660
}
661

    
662
/****f* pfsense-utils/is_schedule_inuse
663
 * NAME
664
 *   checks to see if a schedule is currently in use by a rule
665
 * INPUTS
666
 *
667
 * RESULT
668
 *   true or false
669
 * NOTES
670
 *
671
 ******/
672
function is_schedule_inuse($schedule) {
673
	global $g, $config;
674

    
675
	if ($schedule == "") {
676
		return false;
677
	}
678
	/* loop through firewall rules looking for schedule in use */
679
	if (is_array($config['filter']['rule'])) {
680
		foreach ($config['filter']['rule'] as $rule) {
681
			if ($rule['sched'] == $schedule) {
682
				return true;
683
			}
684
		}
685
	}
686
	return false;
687
}
688

    
689
/****f* pfsense-utils/setup_microcode
690
 * NAME
691
 *   enumerates all interfaces and calls enable_hardware_offloading which
692
 *   enables a NIC's supported hardware features.
693
 * INPUTS
694
 *
695
 * RESULT
696
 *   null
697
 * NOTES
698
 *   This function only supports the fxp driver's loadable microcode.
699
 ******/
700
function setup_microcode() {
701

    
702
	/* if list */
703
	$iflist = get_configured_interface_list(true);
704
	foreach ($iflist as $if => $ifdescr) {
705
		enable_hardware_offloading($if);
706
	}
707
	unset($iflist);
708
}
709

    
710
/****f* pfsense-utils/get_carp_status
711
 * NAME
712
 *   get_carp_status - Return whether CARP is enabled or disabled.
713
 * RESULT
714
 *   boolean	- true if CARP is enabled, false if otherwise.
715
 ******/
716
function get_carp_status() {
717
	/* grab the current status of carp */
718
	$status = get_single_sysctl('net.inet.carp.allow');
719
	return (intval($status) > 0);
720
}
721

    
722
/*
723
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
724

    
725
 */
726
function convert_ip_to_network_format($ip, $subnet) {
727
	$ipsplit = explode('.', $ip);
728
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
729
	return $string;
730
}
731

    
732
/*
733
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
734
 */
735
function get_carp_interface_status($carpid) {
736

    
737
	$carpiface = get_configured_vip_interface($carpid);
738
	if ($carpiface == NULL)
739
		return "";
740
	$interface = get_real_interface($carpiface);
741
	if ($interface == NULL)
742
		return "";
743
	$vip = get_configured_vip($carpid);
744
	if ($vip == NULL || !isset($vip['vhid']))
745
		return "";
746

    
747
	$vhid = $vip['vhid'];
748
	$carp_query = '';
749
	$_gb = exec("/sbin/ifconfig {$interface} | /usr/bin/grep \"carp:.* vhid {$vhid} \"", $carp_query);
750
	foreach ($carp_query as $int) {
751
		if (stripos($int, "MASTER"))
752
			return "MASTER";
753
		elseif (stripos($int, "BACKUP"))
754
			return "BACKUP";
755
		elseif (stripos($int, "INIT"))
756
			return "INIT";
757
	}
758

    
759
	return "";
760
}
761

    
762
function get_carp_bind_status($interface) {
763
	global $config;
764

    
765
	$carpstatus = get_carp_interface_status($interface);
766
	if (!empty($carpstatus)) {
767
		return $carpstatus;
768
	} else {
769
		foreach ($config['virtualip']['vip'] as $vip) {
770
			if ($interface == "_vip{$vip['uniqid']}") { 
771
				return get_carp_interface_status($vip['interface']);
772
			}
773
		}
774
	}
775
}
776

    
777
/*
778
 * Return true if the CARP status of at least one interface of a captive portal zone is in backup mode
779
 * This function return false if CARP is not enabled on any interface of the captive portal zone
780
 */
781
function captiveportal_ha_is_node_in_backup_mode($cpzone) {
782
	global $config;
783

    
784
	$cpinterfaces = explode(",", $config['captiveportal'][$cpzone]['interface']);
785

    
786
	if (is_array($config['virtualip']['vip'])) {
787
		foreach ($cpinterfaces as $interface) {
788
			foreach ($config['virtualip']['vip'] as $vip) {
789
				if (($vip['interface'] == $interface) && ($vip['mode'] == "carp")) {
790
					if (get_carp_interface_status("_vip{$vip['uniqid']}") != "MASTER") {
791
						return true;
792
					}
793
				}
794
			}
795
		}
796
	}
797
	return false;
798
}
799

    
800
/****f* pfsense-utils/WakeOnLan
801
 * NAME
802
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
803
 * RESULT
804
 *   true/false - true if the operation was successful
805
 ******/
806
function WakeOnLan($addr, $mac) {
807
	$addr_byte = explode(':', $mac);
808
	$hw_addr = '';
809

    
810
	for ($a = 0; $a < 6; $a++) {
811
		$hw_addr .= chr(hexdec($addr_byte[$a]));
812
	}
813

    
814
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
815

    
816
	for ($a = 1; $a <= 16; $a++) {
817
		$msg .= $hw_addr;
818
	}
819

    
820
	// send it to the broadcast address using UDP
821
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
822
	if ($s == false) {
823
		log_error(gettext("Error creating socket!"));
824
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
825
	} else {
826
		// setting a broadcast option to socket:
827
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
828
		if ($opt_ret < 0) {
829
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
830
		}
831
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
832
		socket_close($s);
833
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
834
		return true;
835
	}
836

    
837
	return false;
838
}
839

    
840
/*
841
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
842
 *					 Useful for finding paths and stripping file extensions.
843
 */
844
function reverse_strrchr($haystack, $needle) {
845
	if (!is_string($haystack)) {
846
		return;
847
	}
848
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
849
}
850

    
851
/*
852
 *  backup_config_section($section): returns as an xml file string of
853
 *                                   the configuration section
854
 */
855
function backup_config_section($section_name) {
856
	global $config;
857
	$new_section = &$config[$section_name];
858
	/* generate configuration XML */
859
	$xmlconfig = dump_xml_config($new_section, $section_name);
860
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
861
	return $xmlconfig;
862
}
863

    
864
/*
865
 *  restore_config_section($section_name, new_contents): restore a configuration section,
866
 *                                                  and write the configuration out
867
 *                                                  to disk/cf.
868
 */
869
function restore_config_section($section_name, $new_contents) {
870
	global $config, $g;
871
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
872
	fwrite($fout, $new_contents);
873
	fclose($fout);
874

    
875
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
876
	if ($xml['pfsense']) {
877
		$xml = $xml['pfsense'];
878
	}
879
	if ($xml[$section_name]) {
880
		$section_xml = $xml[$section_name];
881
	} else {
882
		$section_xml = -1;
883
	}
884

    
885
	@unlink($g['tmp_path'] . "/tmpxml");
886
	if ($section_xml === -1) {
887
		return false;
888
	}
889

    
890
	/* Save current pkg repo to re-add on new config */
891
	unset($pkg_repo_conf_path);
892
	if ($section_name == "system" &&
893
	    isset($config['system']['pkg_repo_conf_path'])) {
894
		$pkg_repo_conf_path = $config['system']['pkg_repo_conf_path'];
895
	}
896

    
897
	$config[$section_name] = &$section_xml;
898
	if (file_exists("{$g['tmp_path']}/config.cache")) {
899
		unlink("{$g['tmp_path']}/config.cache");
900
	}
901

    
902
	/* Restore previously pkg repo configured */
903
	if ($section_name == "system") {
904
		if (isset($pkg_repo_conf_path)) {
905
			$config['system']['pkg_repo_conf_path'] =
906
			    $pkg_repo_conf_path;
907
		} elseif (isset($config['system']['pkg_repo_conf_path'])) {
908
			unset($config['system']['pkg_repo_conf_path']);
909
		}
910
	}
911

    
912
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
913
	disable_security_checks();
914
	return true;
915
}
916

    
917
/*
918
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
919
 *                                                  and write the configuration out
920
 *                                                  to disk/cf.  But preserve the prior
921
 * 													structure if needed
922
 */
923
function merge_config_section($section_name, $new_contents) {
924
	global $config;
925
	$fname = get_tmp_filename();
926
	$fout = fopen($fname, "w");
927
	fwrite($fout, $new_contents);
928
	fclose($fout);
929
	$section_xml = parse_xml_config($fname, $section_name);
930
	$config[$section_name] = $section_xml;
931
	unlink($fname);
932
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
933
	disable_security_checks();
934
	return;
935
}
936

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

    
968
/*
969
 * host_firmware_version(): Return the versions used in this install
970
 */
971
function host_firmware_version($tocheck = "") {
972
	global $g, $config;
973

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

    
976
	return array(
977
		"firmware" => array("version" => $g['product_version']),
978
		"kernel"   => array("version" => $os_version),
979
		"base"     => array("version" => $os_version),
980
		"platform" => $g['product_label'],
981
		"config_version" => $config['version']
982
	);
983
}
984

    
985
function get_disk_info() {
986
	$diskout = "";
987
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
988
	return explode(' ', $diskout[0]);
989
}
990

    
991
/****f* pfsense-utils/strncpy
992
 * NAME
993
 *   strncpy - copy strings
994
 * INPUTS
995
 *   &$dst, $src, $length
996
 * RESULT
997
 *   none
998
 ******/
999
function strncpy(&$dst, $src, $length) {
1000
	if (strlen($src) > $length) {
1001
		$dst = substr($src, 0, $length);
1002
	} else {
1003
		$dst = $src;
1004
	}
1005
}
1006

    
1007
/****f* pfsense-utils/reload_interfaces_sync
1008
 * NAME
1009
 *   reload_interfaces - reload all interfaces
1010
 * INPUTS
1011
 *   none
1012
 * RESULT
1013
 *   none
1014
 ******/
1015
function reload_interfaces_sync() {
1016
	global $config, $g;
1017

    
1018
	if ($g['debug']) {
1019
		log_error(gettext("reload_interfaces_sync() is starting."));
1020
	}
1021

    
1022
	/* parse config.xml again */
1023
	$config = parse_config(true);
1024

    
1025
	/* enable routing */
1026
	system_routing_enable();
1027
	if ($g['debug']) {
1028
		log_error(gettext("Enabling system routing"));
1029
	}
1030

    
1031
	if ($g['debug']) {
1032
		log_error(gettext("Cleaning up Interfaces"));
1033
	}
1034

    
1035
	/* set up interfaces */
1036
	interfaces_configure();
1037
}
1038

    
1039
/****f* pfsense-utils/reload_all
1040
 * NAME
1041
 *   reload_all - triggers a reload of all settings
1042
 *   * INPUTS
1043
 *   none
1044
 * RESULT
1045
 *   none
1046
 ******/
1047
function reload_all() {
1048
	send_event("service reload all");
1049
}
1050

    
1051
/****f* pfsense-utils/reload_interfaces
1052
 * NAME
1053
 *   reload_interfaces - triggers a reload of all interfaces
1054
 * INPUTS
1055
 *   none
1056
 * RESULT
1057
 *   none
1058
 ******/
1059
function reload_interfaces() {
1060
	send_event("interface all reload");
1061
}
1062

    
1063
/****f* pfsense-utils/reload_all_sync
1064
 * NAME
1065
 *   reload_all - reload all settings
1066
 *   * INPUTS
1067
 *   none
1068
 * RESULT
1069
 *   none
1070
 ******/
1071
function reload_all_sync() {
1072
	global $config, $g;
1073

    
1074
	/* parse config.xml again */
1075
	$config = parse_config(true);
1076

    
1077
	/* set up our timezone */
1078
	system_timezone_configure();
1079

    
1080
	/* set up our hostname */
1081
	system_hostname_configure();
1082

    
1083
	/* make hosts file */
1084
	system_hosts_generate();
1085

    
1086
	/* generate resolv.conf */
1087
	system_resolvconf_generate();
1088

    
1089
	/* enable routing */
1090
	system_routing_enable();
1091

    
1092
	/* set up interfaces */
1093
	interfaces_configure();
1094

    
1095
	/* start dyndns service */
1096
	services_dyndns_configure();
1097

    
1098
	/* configure cron service */
1099
	configure_cron();
1100

    
1101
	/* start the NTP client */
1102
	system_ntp_configure();
1103

    
1104
	/* sync pw database */
1105
	unlink_if_exists("/etc/spwd.db.tmp");
1106
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1107

    
1108
	/* restart sshd */
1109
	send_event("service restart sshd");
1110

    
1111
	/* restart webConfigurator if needed */
1112
	send_event("service restart webgui");
1113
}
1114

    
1115
function load_loader_conf($loader_conf = NULL, $local = false) {
1116

    
1117
	if ($loader_conf == NULL) {
1118
		return (NULL);
1119
	}
1120
	if (file_exists($loader_conf)) {
1121
		$input = file_get_contents($loader_conf);
1122
	} else {
1123
		$input = "";
1124
	}
1125

    
1126
	$input_split = explode("\n", $input);
1127

    
1128
	/*
1129
	 * Loop through and only add lines that are not empty and not
1130
	 * managed by us.
1131
	 */
1132
	$data = array();
1133
	/* These values should be removed from loader.conf and loader.conf.local
1134
	 * As they will be replaced when necessary. */
1135
	$remove = array("hw.usb.no_pf", "hint.mdio.0.at", "hint.e6000sw.0",
1136
	    "hw.e6000sw.default_disabled", "vm.pmap.pti",
1137
	    "net.pf.request_maxcount", "hw.hn.vf_transparent",
1138
	    "hw.hn.use_if_start");
1139
	if (!$local) {
1140
		/* These values should only be filtered in loader.conf, not .local */
1141
		$remove = array_merge($remove,
1142
		    array("autoboot_delay", "console", "comconsole_speed", "comconsole_port",
1143
		    "boot_multicons", "boot_serial", "hint.uart.0.flags",
1144
		    "hint.uart.1.flags", "net.link.ifqmaxlen"));
1145
	}
1146
	foreach ($input_split as $line) {
1147
		if (empty($line)) {
1148
			continue;
1149
		}
1150
		$skip = false;
1151
		list($name, $value) = explode('=', $line, 2);
1152
		foreach($remove as $rid => $rkey) {
1153
			if (strncasecmp(trim($name), $rkey, strlen($rkey)) == 0) {
1154
				$skip = true;
1155
				break;
1156
			}
1157
		}
1158
		if (!$skip) {
1159
			$data[] = $line;
1160
		}
1161
	}
1162

    
1163
	return ($data);
1164
}
1165

    
1166
function setup_loader_settings($path = "", $upgrade = false) {
1167
	global $g, $config;
1168

    
1169
	$boot_config_file = "{$path}/boot.config";
1170
	$loader_conf_file = "{$path}/boot/loader.conf";
1171

    
1172
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1173

    
1174
	$vga_only = false;
1175
	$serial_only = false;
1176
	$specific_platform = system_identify_specific_platform();
1177
	$video_console_type = (get_single_sysctl("machdep.bootmethod") == "UEFI") ? "efi" : "vidconsole";
1178
	if ($specific_platform['name'] == '1540') {
1179
		$vga_only = true;
1180
	} elseif ($specific_platform['name'] == 'Turbot Dual-E') {
1181
		$g['primaryconsole_force'] = "video";
1182
	} elseif ($specific_platform['name'] == 'RCC-VE' ||
1183
	    $specific_platform['name'] == 'RCC' ||
1184
	    $specific_platform['name'] == 'SG-2220' ||
1185
	    $specific_platform['name'] == 'apu2') {
1186
		$serial_only = true;
1187
	}
1188

    
1189
	/* Serial console - write out /boot.config */
1190
	if (file_exists($boot_config_file)) {
1191
		$boot_config = file_get_contents($boot_config_file);
1192
	} else {
1193
		$boot_config = "";
1194
	}
1195
	$boot_config_split = explode("\n", $boot_config);
1196
	$data = array();
1197
	foreach ($boot_config_split as $bcs) {
1198
		/* Ignore -D and -h lines now */
1199
		if (!empty($bcs) && !stristr($bcs, "-D") &&
1200
		    !stristr($bcs, "-h")) {
1201
			$data[] = $bcs;
1202
		}
1203
	}
1204
	if ($serial_only === true) {
1205
		$data[] = "-S{$serialspeed} -h";
1206
	} elseif (is_serial_enabled()) {
1207
		$data[] = "-S{$serialspeed} -D";
1208
	}
1209

    
1210
	if (empty($data)) {
1211
		@unlink($boot_conf_file);
1212
	} else {
1213
		safe_write_file($boot_config_file, $data);
1214
	}
1215
	unset($data, $boot_config, $boot_config_file, $boot_config_split);
1216

    
1217
	/* Serial console - write out /boot/loader.conf */
1218
	if ($upgrade) {
1219
		system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1220
	}
1221

    
1222
	$data = load_loader_conf($loader_conf_file, false);
1223
	if ($serial_only === true) {
1224
		$data[] = 'boot_serial="YES"';
1225
		$data[] = 'console="comconsole"';
1226
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1227
	} elseif ($vga_only === true) {
1228
		$data[] = "console=\"{$video_console_type}\"";
1229
	} elseif (is_serial_enabled()) {
1230
		$data[] = 'boot_multicons="YES"';
1231
		$data[] = 'boot_serial="YES"';
1232
		$primaryconsole = isset($g['primaryconsole_force']) ?
1233
		    $g['primaryconsole_force'] :
1234
		    $config['system']['primaryconsole'];
1235
		switch ($primaryconsole) {
1236
			case "video":
1237
				$data[] = "console=\"{$video_console_type},comconsole\"";
1238
				break;
1239
			case "serial":
1240
			default:
1241
				$data[] = "console=\"comconsole,{$video_console_type}\"";
1242
		}
1243
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1244
	}
1245

    
1246
	if ($specific_platform['name'] == 'RCC-VE' ||
1247
	    $specific_platform['name'] == 'RCC' ||
1248
	    $specific_platform['name'] == 'SG-2220') {
1249
		$data[] = 'comconsole_port="0x2F8"';
1250
		$data[] = 'hint.uart.0.flags="0x00"';
1251
		$data[] = 'hint.uart.1.flags="0x10"';
1252
	}
1253
	$data[] = 'autoboot_delay="3"';
1254
	if (isset($config['system']['pti_disabled'])) {
1255
		$data[] = 'vm.pmap.pti="0"';
1256
	}
1257

    
1258
	/* Enable ALTQ support for hnX NICs. */
1259
	if (isset($config['system']['hn_altq_enable'])) {
1260
		$data[] = 'hw.hn.vf_transparent="0"';
1261
		$data[] = 'hw.hn.use_if_start="1"';
1262
	}
1263

    
1264
	/* Set maximum send queue length. */
1265
	$data[] = 'net.link.ifqmaxlen="128"';
1266

    
1267
	safe_write_file($loader_conf_file, $data);
1268

    
1269
	/* Filter loader.conf.local to avoid duplicate settings. */
1270
	$loader_conf_file = "{$path}/boot/loader.conf.local";
1271
	$data = load_loader_conf($loader_conf_file, true);
1272
	if (empty($data)) {
1273
		@unlink($loader_conf_file);
1274
	} else {
1275
		safe_write_file($loader_conf_file, $data);
1276
	}
1277

    
1278
}
1279

    
1280
function console_configure($when = "save", $path = "") {
1281
	global $config;
1282
	$ttys_file = "{$path}/etc/ttys";
1283

    
1284
	/* Update the loader settings. */
1285
	setup_loader_settings($path, ($when == "upgrade"));
1286

    
1287
	$ttys = file_get_contents($ttys_file);
1288
	$ttys_split = explode("\n", $ttys);
1289

    
1290
	$data = array();
1291

    
1292
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1293

    
1294
	if (isset($config['system']['disableconsolemenu'])) {
1295
		$console_type = 'Pc';
1296
		$serial_type = '3wire';
1297
	} else {
1298
		$console_type = 'al.Pc';
1299
		$serial_type = 'al.3wire';
1300
	}
1301

    
1302
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1303
	$virt_line =
1304
	    "\"/usr/libexec/getty {$console_type}\"\txterm\tonifexists secure";
1305
	$ttyu_line =
1306
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1307

    
1308
	$found = array();
1309

    
1310
	foreach ($ttys_split as $tty) {
1311
		/* Ignore blank lines */
1312
		if (empty($tty)) {
1313
			continue;
1314
		}
1315

    
1316
		if (stristr($tty, "ttyv0")) {
1317
			$found['ttyv0'] = 1;
1318
			$data[] = "ttyv0\t{$virt_line}";
1319
		} elseif (stristr($tty, "xc0")) {
1320
			$found['xc0'] = 1;
1321
			$data[] = "xc0\t{$virt_line}";
1322
		} elseif (stristr($tty, "ttyu")) {
1323
			$ttyn = substr($tty, 0, 5);
1324
			$found[$ttyn] = 1;
1325
			$data[] = "{$ttyn}\t{$ttyu_line}";
1326
		} elseif (substr($tty, 0, 7) == 'console') {
1327
			$found['console'] = 1;
1328
			$data[] = $tty;
1329
		} else {
1330
			$data[] = $tty;
1331
		}
1332
	}
1333
	unset($on_off, $console_type, $serial_type);
1334

    
1335
	/* Detect missing main lines on original file and try to rebuild it */
1336
	$items = array(
1337
		'console',
1338
		'ttyv0',
1339
		'ttyu0',
1340
		'ttyu1',
1341
		'ttyu2',
1342
		'ttyu3',
1343
		'xc0'
1344
	);
1345

    
1346
	foreach ($items as $item) {
1347
		if (isset($found[$item])) {
1348
			continue;
1349
		}
1350

    
1351
		if ($item == 'console') {
1352
			$data[] = $console_line;
1353
		} elseif (($item == 'ttyv0') || ($item == 'xc0')) {
1354
			/* xc0 - Xen console, see https://redmine.pfsense.org/issues/11402 */
1355
			$data[] = "{$item}\t{$virt_line}";
1356
		} else {
1357
			$data[] = "{$item}\t{$ttyu_line}";
1358
		}
1359
	}
1360

    
1361
	safe_write_file($ttys_file, $data);
1362

    
1363
	unset($ttys, $ttys_file, $ttys_split, $data);
1364

    
1365
	if ($when != "upgrade") {
1366
		reload_ttys();
1367
	}
1368

    
1369
	return;
1370
}
1371

    
1372
function is_serial_enabled() {
1373
	global $g, $config;
1374

    
1375
	if (!isset($g['enableserial_force']) &&
1376
	    !isset($config['system']['enableserial'])) {
1377
		return false;
1378
	}
1379

    
1380
	return true;
1381
}
1382

    
1383
function reload_ttys() {
1384
	// Send a HUP signal to init will make it reload /etc/ttys
1385
	posix_kill(1, SIGHUP);
1386
}
1387

    
1388
function print_value_list($list, $count = 10, $separator = ",") {
1389
	$list = implode($separator, array_slice($list, 0, $count));
1390
	if (count($list) < $count) {
1391
		$list .= ".";
1392
	} else {
1393
		$list .= "...";
1394
	}
1395
	return $list;
1396
}
1397

    
1398
/* DHCP enabled on any interfaces? */
1399
function is_dhcp_server_enabled() {
1400
	global $config;
1401

    
1402
	if (!is_array($config['dhcpd'])) {
1403
		return false;
1404
	}
1405

    
1406
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1407
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1408
			return true;
1409
		}
1410
	}
1411

    
1412
	return false;
1413
}
1414

    
1415
/* DHCP enabled on any interfaces? */
1416
function is_dhcpv6_server_enabled() {
1417
	global $config;
1418

    
1419
	if (is_array($config['interfaces'])) {
1420
		foreach ($config['interfaces'] as $ifcfg) {
1421
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1422
				return true;
1423
			}
1424
		}
1425
	}
1426

    
1427
	if (!is_array($config['dhcpdv6'])) {
1428
		return false;
1429
	}
1430

    
1431
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1432
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1433
			return true;
1434
		}
1435
	}
1436

    
1437
	return false;
1438
}
1439

    
1440
/* radvd enabled on any interfaces? */
1441
function is_radvd_enabled() {
1442
	global $config;
1443

    
1444
	if (!is_array($config['dhcpdv6'])) {
1445
		$config['dhcpdv6'] = array();
1446
	}
1447

    
1448
	$dhcpdv6cfg = $config['dhcpdv6'];
1449
	$Iflist = get_configured_interface_list();
1450

    
1451
	/* handle manually configured DHCP6 server settings first */
1452
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1453
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1454
			continue;
1455
		}
1456

    
1457
		if (!isset($dhcpv6ifconf['ramode'])) {
1458
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1459
		}
1460

    
1461
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1462
			continue;
1463
		}
1464

    
1465
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1466
		if (!is_ipaddrv6($ifcfgipv6)) {
1467
			continue;
1468
		}
1469

    
1470
		return true;
1471
	}
1472

    
1473
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1474
	foreach ($Iflist as $if => $ifdescr) {
1475
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1476
			continue;
1477
		}
1478
		if (!isset($config['interfaces'][$if]['enable'])) {
1479
			continue;
1480
		}
1481

    
1482
		$ifcfgipv6 = get_interface_ipv6($if);
1483
		if (!is_ipaddrv6($ifcfgipv6)) {
1484
			continue;
1485
		}
1486

    
1487
		$ifcfgsnv6 = get_interface_subnetv6($if);
1488
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1489

    
1490
		if (!is_ipaddrv6($subnetv6)) {
1491
			continue;
1492
		}
1493

    
1494
		return true;
1495
	}
1496

    
1497
	return false;
1498
}
1499

    
1500
/* Any PPPoE servers enabled? */
1501
function is_pppoe_server_enabled() {
1502
	global $config;
1503

    
1504
	$pppoeenable = false;
1505

    
1506
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1507
		return false;
1508
	}
1509

    
1510
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1511
		if ($pppoes['mode'] == 'server') {
1512
			$pppoeenable = true;
1513
		}
1514
	}
1515

    
1516
	return $pppoeenable;
1517
}
1518

    
1519
/* Optional arg forces hh:mm:ss without days */
1520
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1521
	if (!is_numericint($sec)) {
1522
		return '-';
1523
	}
1524
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1525
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1526
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1527
					(int)(($sec % 3600)/60),
1528
					$sec % 60
1529
				);
1530
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1531
}
1532

    
1533
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1534

    
1535
function get_ppp_uptime($port) {
1536
	if (file_exists("/conf/{$port}.log")) {
1537
		$saved_time = file_get_contents("/conf/{$port}.log");
1538
		$uptime_data = explode("\n", $saved_time);
1539
		$sec = 0;
1540
		foreach ($uptime_data as $upt) {
1541
			$sec += substr($upt, 1 + strpos($upt, " "));
1542
		}
1543
		return convert_seconds_to_dhms($sec);
1544
	} else {
1545
		$total_time = gettext("No history data found!");
1546
		return $total_time;
1547
	}
1548
}
1549

    
1550
//returns interface information
1551
function get_interface_info($ifdescr) {
1552
	global $config, $g;
1553

    
1554
	$ifinfo = array();
1555
	if (empty($config['interfaces'][$ifdescr])) {
1556
		return;
1557
	}
1558
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1559
	$ifinfo['enable'] = isset($config['interfaces'][$ifdescr]['enable']);
1560
	$ifinfo['if'] = get_real_interface($ifdescr);
1561

    
1562
	$chkif = $ifinfo['if'];
1563
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1564
	$ifinfo['status'] = $ifinfotmp['status'];
1565
	if (empty($ifinfo['status'])) {
1566
		$ifinfo['status'] = "down";
1567
	}
1568
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1569
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1570
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1571
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1572
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1573
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1574
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1575
	if (isset($ifinfotmp['link0'])) {
1576
		$link0 = "down";
1577
	}
1578
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1579
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1580
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1581
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1582
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1583
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1584

    
1585
	/* Use pfctl for non wrapping 64 bit counters */
1586
	/* Pass */
1587
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1588
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1589
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1590
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1591
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1592
	$in4_pass = $pf_in4_pass[5];
1593
	$out4_pass = $pf_out4_pass[5];
1594
	$in4_pass_packets = $pf_in4_pass[3];
1595
	$out4_pass_packets = $pf_out4_pass[3];
1596
	$in6_pass = $pf_in6_pass[5];
1597
	$out6_pass = $pf_out6_pass[5];
1598
	$in6_pass_packets = $pf_in6_pass[3];
1599
	$out6_pass_packets = $pf_out6_pass[3];
1600
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1601
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1602
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1603
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1604

    
1605
	/* Block */
1606
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1607
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1608
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1609
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1610
	$in4_block = $pf_in4_block[5];
1611
	$out4_block = $pf_out4_block[5];
1612
	$in4_block_packets = $pf_in4_block[3];
1613
	$out4_block_packets = $pf_out4_block[3];
1614
	$in6_block = $pf_in6_block[5];
1615
	$out6_block = $pf_out6_block[5];
1616
	$in6_block_packets = $pf_in6_block[3];
1617
	$out6_block_packets = $pf_out6_block[3];
1618
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1619
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1620
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1621
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1622

    
1623
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1624
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1625
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1626
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1627

    
1628
	$ifconfiginfo = "";
1629
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1630
	switch ($link_type) {
1631
		/* DHCP? -> see if dhclient is up */
1632
		case "dhcp":
1633
			/* see if dhclient is up */
1634
			if (find_dhclient_process($ifinfo['if']) != 0) {
1635
				$ifinfo['dhcplink'] = "up";
1636
			} else {
1637
				$ifinfo['dhcplink'] = "down";
1638
			}
1639

    
1640
			break;
1641
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1642
		case "pppoe":
1643
		case "pptp":
1644
		case "l2tp":
1645
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1646
				/* get PPPoE link status for dial on demand */
1647
				$ifinfo["{$link_type}link"] = "up";
1648
			} else {
1649
				$ifinfo["{$link_type}link"] = "down";
1650
			}
1651

    
1652
			break;
1653
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1654
		case "ppp":
1655
			if ($ifinfo['status'] == "up") {
1656
				$ifinfo['ppplink'] = "up";
1657
			} else {
1658
				$ifinfo['ppplink'] = "down" ;
1659
			}
1660

    
1661
			if (empty($ifinfo['status'])) {
1662
				$ifinfo['status'] = "down";
1663
			}
1664

    
1665
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1666
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1667
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1668
						break;
1669
					}
1670
				}
1671
			}
1672
			$dev = $ppp['ports'];
1673
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1674
				break;
1675
			}
1676
			if (!file_exists($dev)) {
1677
				$ifinfo['nodevice'] = 1;
1678
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1679
			}
1680

    
1681
			$usbmodemoutput = array();
1682
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1683
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1684
			if (file_exists($mondev)) {
1685
				$cellstats = file($mondev);
1686
				/* skip header */
1687
				$a_cellstats = explode(",", $cellstats[1]);
1688
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1689
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1690
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1691
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1692
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1693
				}
1694
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1695
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1696
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1697
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1698
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1699
				}
1700
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1701
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1702
				$ifinfo['cell_sent'] = $a_cellstats[6];
1703
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1704
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1705
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1706
			}
1707
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1708
			if (isset($ppp['uptime'])) {
1709
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1710
			}
1711
			break;
1712
		default:
1713
			break;
1714
	}
1715

    
1716
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1717
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1718
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1719
	}
1720

    
1721
	if ($ifinfo['status'] == "up") {
1722
		/* try to determine media with ifconfig */
1723
		unset($ifconfiginfo);
1724
		exec("/sbin/ifconfig -v " . $ifinfo['if'], $ifconfiginfo);
1725
		$wifconfiginfo = array();
1726
		if (is_interface_wireless($ifdescr)) {
1727
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1728
			array_shift($wifconfiginfo);
1729
		}
1730
		$matches = "";
1731
		foreach ($ifconfiginfo as $ici) {
1732

    
1733
			/* don't list media/speed for wireless cards, as it always
1734
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1735
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1736
				$ifinfo['media'] = $matches[1];
1737
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1738
				$ifinfo['media'] = $matches[1];
1739
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1740
				$ifinfo['media'] = $matches[1];
1741
			}
1742

    
1743
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1744
				if ($matches[1] != "active") {
1745
					$ifinfo['status'] = $matches[1];
1746
				}
1747
				if ($ifinfo['status'] == gettext("running")) {
1748
					$ifinfo['status'] = gettext("up");
1749
				}
1750
			}
1751
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1752
				$ifinfo['channel'] = $matches[1];
1753
			}
1754
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1755
				if ($matches[1][0] == '"') {
1756
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1757
				}
1758
				else {
1759
					$ifinfo['ssid'] = $matches[1];
1760
				}
1761
			}
1762
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1763
				$ifinfo['laggproto'] = $matches[1];
1764
			}
1765
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1766
				$ifinfo['laggport'][] = $matches[1];
1767
			}
1768
			if (preg_match("/plugged: (.*)$/", $ici, $matches)) {
1769
				$ifinfo['plugged'] = $matches[1];
1770
			}
1771
			if (preg_match("/vendor: (.*)$/", $ici, $matches)) {
1772
				$ifinfo['vendor'] = $matches[1];
1773
			}
1774
			if (preg_match("/module temperature: (.*) Voltage: (.*)$/", $ici, $matches)) {
1775
				$ifinfo['temperature'] = $matches[1];
1776
				$ifinfo['voltage'] = $matches[2];
1777
			}
1778
			if (preg_match("/RX: (.*) TX: (.*)$/", $ici, $matches)) {
1779
				$ifinfo['rx'] = $matches[1];
1780
				$ifinfo['tx'] = $matches[2];
1781
			}
1782
		}
1783
		foreach ($wifconfiginfo as $ici) {
1784
			$elements = preg_split("/[ ]+/i", $ici);
1785
			if ($elements[0] != "") {
1786
				$ifinfo['bssid'] = $elements[0];
1787
			}
1788
			if ($elements[3] != "") {
1789
				$ifinfo['rate'] = $elements[3];
1790
			}
1791
			if ($elements[4] != "") {
1792
				$ifinfo['rssi'] = $elements[4];
1793
			}
1794
		}
1795
		/* lookup the gateway */
1796
		if (interface_has_gateway($ifdescr)) {
1797
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1798
		}
1799
		if (interface_has_gatewayv6($ifdescr)) {
1800
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1801
		}
1802
	}
1803

    
1804
	$bridge = "";
1805
	$bridge = link_interface_to_bridge($ifdescr);
1806
	if ($bridge) {
1807
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1808
		if (stristr($bridge_text, "blocking") <> false) {
1809
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1810
			$ifinfo['bridgeint'] = $bridge;
1811
		} else if (stristr($bridge_text, "learning") <> false) {
1812
			$ifinfo['bridge'] = gettext("learning");
1813
			$ifinfo['bridgeint'] = $bridge;
1814
		} else if (stristr($bridge_text, "forwarding") <> false) {
1815
			$ifinfo['bridge'] = gettext("forwarding");
1816
			$ifinfo['bridgeint'] = $bridge;
1817
		}
1818
	}
1819

    
1820
	return $ifinfo;
1821
}
1822

    
1823
//returns cpu speed of processor. Good for determining capabilities of machine
1824
function get_cpu_speed() {
1825
	return get_single_sysctl("hw.clockrate");
1826
}
1827

    
1828
function get_uptime_sec() {
1829
	$boottime = "";
1830
	$matches = "";
1831
	$boottime = get_single_sysctl("kern.boottime");
1832
	preg_match("/sec = (\d+)/", $boottime, $matches);
1833
	$boottime = $matches[1];
1834
	if (intval($boottime) == 0) {
1835
		return 0;
1836
	}
1837

    
1838
	$uptime = time() - $boottime;
1839
	return $uptime;
1840
}
1841

    
1842
function resolve_host_addresses($host, $recordtypes = array(DNS_A, DNS_AAAA, DNS_CNAME), $index = true) {
1843
	$dnsresult = array();
1844
	$resolved = array();
1845
	$errreporting = error_reporting();
1846
	error_reporting($errreporting & ~E_WARNING);// dns_get_record throws a warning if nothing is resolved..
1847
	foreach ($recordtypes as $recordtype) {
1848
		$tmp = dns_get_record($host, $recordtype);
1849
		if (is_array($tmp)) {
1850
			$dnsresult = array_merge($dnsresult, $tmp);
1851
		}
1852
	}
1853
	error_reporting($errreporting);// restore original php warning/error settings.
1854
	foreach ($dnsresult as $item) {
1855
		$newitem = array();
1856
		$newitem['type'] = $item['type'];
1857
		switch ($item['type']) {
1858
			case 'CNAME':
1859
				$newitem['data'] = $item['target'];
1860
				$resolved[] = $newitem;
1861
				break;
1862
			case 'A':
1863
				$newitem['data'] = $item['ip'];
1864
				$resolved[] = $newitem;
1865
				break;
1866
			case 'AAAA':
1867
				$newitem['data'] = $item['ipv6'];
1868
				$resolved[] = $newitem;
1869
				break;
1870
		}
1871
	}
1872
	if ($index == false) {
1873
		foreach ($resolved as $res) {
1874
			$noind[] = $res['data'];
1875
		}
1876
		$resolved = $noind;
1877
	}
1878
	return $resolved;
1879
}
1880

    
1881
function add_hostname_to_watch($hostname) {
1882
	if (!is_dir("/var/db/dnscache")) {
1883
		mkdir("/var/db/dnscache");
1884
	}
1885
	$result = array();
1886
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1887
		$contents = "";
1888
		$domips = resolve_host_addresses($hostname, array(DNS_A), false);
1889
		if (!empty($domips)) {
1890
			foreach ($domips as $ip) {
1891
				$contents .= "$ip\n";
1892
			}
1893
		}
1894
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1895
		/* Remove empty elements */
1896
		$result = array_filter(explode("\n", $contents), 'strlen');
1897
	}
1898
	return $result;
1899
}
1900

    
1901
function is_fqdn($fqdn) {
1902
	return (bool) preg_match('/^(?:(?!-)[-_a-z0-9]+(?<!-)\.)*(?!-)[a-z0-9\-]+(?<!-)\.(?:xn--)?[a-z]+[\.]?$/i', $fqdn);
1903
}
1904

    
1905
function pfsense_default_state_size() {
1906
	/* get system memory amount */
1907
	$memory = get_memory();
1908
	$physmem = $memory[0];
1909
	/* Be cautious and only allocate 10% of system memory to the state table */
1910
	$max_states = (int) ($physmem/10)*1000;
1911
	return $max_states;
1912
}
1913

    
1914
function pfsense_default_tables_size() {
1915
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1916
	return $current;
1917
}
1918

    
1919
function pfsense_default_table_entries_size() {
1920
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1921
	return (trim($current));
1922
}
1923

    
1924
/* Compare the current hostname DNS to the DNS cache we made
1925
 * if it has changed we return the old records
1926
 * if no change we return false */
1927
function compare_hostname_to_dnscache($hostname) {
1928
	if (!is_dir("/var/db/dnscache")) {
1929
		mkdir("/var/db/dnscache");
1930
	}
1931
	$hostname = trim($hostname);
1932
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1933
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1934
	} else {
1935
		$oldcontents = "";
1936
	}
1937
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1938
		$contents = "";
1939
		$domips = resolve_host_addresses($hostname, array(DNS_A), false);
1940
		if (!empty($domips)) {
1941
			foreach ($domips as $ip) {
1942
				$contents .= "$ip\n";
1943
			}
1944
		}
1945
	}
1946

    
1947
	if (trim($oldcontents) != trim($contents)) {
1948
		if ($g['debug']) {
1949
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1950
		}
1951
		return ($oldcontents);
1952
	} else {
1953
		return false;
1954
	}
1955
}
1956

    
1957
/*
1958
 * load_crypto() - Load crypto modules if enabled in config.
1959
 */
1960
function load_crypto() {
1961
	global $config, $g;
1962
	$crypto_modules = array('aesni', 'cryptodev');
1963

    
1964
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
1965

    
1966
	foreach ($enabled_modules as $enmod) {
1967
		if (empty($enmod) || !in_array($enmod, $crypto_modules)) {
1968
			continue;
1969
		}
1970
		if (!is_module_loaded($enmod)) {
1971
			log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $enmod));
1972
			mute_kernel_msgs();
1973
			mwexec("/sbin/kldload " . escapeshellarg($enmod));
1974
			unmute_kernel_msgs();
1975
		}
1976
	}
1977
}
1978

    
1979
/*
1980
 * load_thermal_hardware() - Load temperature monitor kernel module
1981
 */
1982
function load_thermal_hardware() {
1983
	global $config, $g;
1984
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1985

    
1986
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1987
		return false;
1988
	}
1989

    
1990
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1991
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1992
		mute_kernel_msgs();
1993
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1994
		unmute_kernel_msgs();
1995
	}
1996
}
1997

    
1998
/****f* pfsense-utils/isvm
1999
 * NAME
2000
 *   isvm
2001
 * INPUTS
2002
 *	none
2003
 * RESULT
2004
 *   returns true if machine is running under a virtual environment
2005
 ******/
2006
function isvm() {
2007
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
2008
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
2009

    
2010
	if ($rc != 0 || !isset($output[0])) {
2011
		return false;
2012
	}
2013

    
2014
	foreach ($virtualenvs as $virtualenv) {
2015
		if (stripos($output[0], $virtualenv) !== false) {
2016
			return true;
2017
		}
2018
	}
2019

    
2020
	return false;
2021
}
2022

    
2023
function get_freebsd_version() {
2024
	$version = explode(".", php_uname("r"));
2025
	return $version[0];
2026
}
2027

    
2028
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
2029
	global $config, $g;
2030

    
2031
	$fp = fopen($destination, "wb");
2032

    
2033
	if (!$fp) {
2034
		return false;
2035
	}
2036

    
2037
	$ch = curl_init();
2038
	curl_setopt($ch, CURLOPT_URL, $url);
2039
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2040
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2041
	curl_setopt($ch, CURLOPT_FILE, $fp);
2042
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2043
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2044
	curl_setopt($ch, CURLOPT_HEADER, false);
2045
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2046
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2047
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_label'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2048
	} else {
2049
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_label'] . '/' . $g['product_version']);
2050
	}
2051

    
2052
	set_curlproxy($ch);
2053

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

    
2067
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
2068
	global $config, $g;
2069
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
2070
	$file_size = 1;
2071
	$downloaded = 1;
2072
	$first_progress_update = TRUE;
2073
	/* open destination file */
2074
	$fout = fopen($destination, "wb");
2075

    
2076
	if (!$fout) {
2077
		return false;
2078
	}
2079
	/*
2080
	 *      Originally by Author: Keyvan Minoukadeh
2081
	 *      Modified by Scott Ullrich to return Content-Length size
2082
	 */
2083
	$ch = curl_init();
2084
	curl_setopt($ch, CURLOPT_URL, $url);
2085
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2086
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2087
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
2088
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2089
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
2090
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
2091
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2092
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2093
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2094
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_label'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2095
	} else {
2096
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_label'] . '/' . $g['product_version']);
2097
	}
2098

    
2099
	set_curlproxy($ch);
2100

    
2101
	@curl_exec($ch);
2102
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2103
	fclose($fout);
2104
	curl_close($ch);
2105
	if ($http_code == 200) {
2106
		return true;
2107
	} else {
2108
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2109
		unlink_if_exists($destination);
2110
		return false;
2111
	}
2112
}
2113

    
2114
function read_header($ch, $string) {
2115
	global $file_size, $fout;
2116
	$length = strlen($string);
2117
	$regs = "";
2118
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2119
	if ($regs[2] <> "") {
2120
		$file_size = intval($regs[2]);
2121
	}
2122
	ob_flush();
2123
	return $length;
2124
}
2125

    
2126
function read_body($ch, $string) {
2127
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2128
	global $pkg_interface;
2129
	$length = strlen($string);
2130
	$downloaded += intval($length);
2131
	if ($file_size > 0) {
2132
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2133
		$downloadProgress = 100 - $downloadProgress;
2134
	} else {
2135
		$downloadProgress = 0;
2136
	}
2137
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2138
		if ($sendto == "status") {
2139
			if ($pkg_interface == "console") {
2140
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2141
					$tostatus = $static_status . $downloadProgress . "%";
2142
					if ($downloadProgress == 100) {
2143
						$tostatus = $tostatus . "\r";
2144
					}
2145
					update_status($tostatus);
2146
				}
2147
			} else {
2148
				$tostatus = $static_status . $downloadProgress . "%";
2149
				update_status($tostatus);
2150
			}
2151
		} else {
2152
			if ($pkg_interface == "console") {
2153
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2154
					$tooutput = $static_output . $downloadProgress . "%";
2155
					if ($downloadProgress == 100) {
2156
						$tooutput = $tooutput . "\r";
2157
					}
2158
					update_output_window($tooutput);
2159
				}
2160
			} else {
2161
				$tooutput = $static_output . $downloadProgress . "%";
2162
				update_output_window($tooutput);
2163
			}
2164
		}
2165
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2166
			update_progress_bar($downloadProgress, $first_progress_update);
2167
			$first_progress_update = FALSE;
2168
		}
2169
		$lastseen = $downloadProgress;
2170
	}
2171
	if ($fout) {
2172
		fwrite($fout, $string);
2173
	}
2174
	ob_flush();
2175
	return $length;
2176
}
2177

    
2178
/*
2179
 *   update_output_window: update bottom textarea dynamically.
2180
 */
2181
function update_output_window($text) {
2182
	global $pkg_interface;
2183
	$log = preg_replace("/\n/", "\\n", $text);
2184
	if ($pkg_interface != "console") {
2185
?>
2186
<script type="text/javascript">
2187
//<![CDATA[
2188
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2189
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2190
//]]>
2191
</script>
2192
<?php
2193
	}
2194
	/* ensure that contents are written out */
2195
	ob_flush();
2196
}
2197

    
2198
/*
2199
 *   update_status: update top textarea dynamically.
2200
 */
2201
function update_status($status) {
2202
	global $pkg_interface;
2203

    
2204
	if ($pkg_interface == "console") {
2205
		print ("{$status}");
2206
	}
2207

    
2208
	/* ensure that contents are written out */
2209
	ob_flush();
2210
}
2211

    
2212
/*
2213
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2214
 */
2215
function update_progress_bar($percent, $first_time) {
2216
	global $pkg_interface;
2217
	if ($percent > 100) {
2218
		$percent = 1;
2219
	}
2220
	if ($pkg_interface <> "console") {
2221
		echo '<script type="text/javascript">';
2222
		echo "\n//<![CDATA[\n";
2223
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2224
		echo "\n//]]>\n";
2225
		echo '</script>';
2226
	} else {
2227
		if (!($first_time)) {
2228
			echo "\x08\x08\x08\x08\x08";
2229
		}
2230
		echo sprintf("%4d%%", $percent);
2231
	}
2232
}
2233

    
2234
function update_alias_name($new_alias_name, $orig_alias_name) {
2235
	if (!$orig_alias_name) {
2236
		return;
2237
	}
2238

    
2239
	// Firewall rules
2240
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2241
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2242
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2243
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2244
	// NAT Rules
2245
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2246
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2247
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2248
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2249
	update_alias_names_upon_change(array('nat', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2250
	update_alias_names_upon_change(array('nat', 'rule'), array('local-port'), $new_alias_name, $orig_alias_name);
2251
	// NAT 1:1 Rules
2252
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('external'), $new_alias_name, $orig_alias_name);
2253
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2254
	update_alias_names_upon_change(array('nat', 'onetoone'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2255
	// NAT Outbound Rules
2256
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('source', 'network'), $new_alias_name, $orig_alias_name);
2257
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('sourceport'), $new_alias_name, $orig_alias_name);
2258
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2259
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('dstport'), $new_alias_name, $orig_alias_name);
2260
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2261
	// Alias in an alias
2262
	update_alias_names_upon_change(array('aliases', 'alias'), array('address'), $new_alias_name, $orig_alias_name);
2263
	// Static routes
2264
	update_alias_names_upon_change(array('staticroutes', 'route'), array('network'), $new_alias_name, $orig_alias_name);
2265
	// OpenVPN
2266
	update_alias_names_upon_change(array('openvpn', 'openvpn-server'), array('tunnel_network'), $new_alias_name, $orig_alias_name);
2267
	update_alias_names_upon_change(array('openvpn', 'openvpn-server'), array('tunnel_networkv6'), $new_alias_name, $orig_alias_name);
2268
	update_alias_names_upon_change(array('openvpn', 'openvpn-server'), array('local_network'), $new_alias_name, $orig_alias_name);
2269
	update_alias_names_upon_change(array('openvpn', 'openvpn-server'), array('local_networkv6'), $new_alias_name, $orig_alias_name);
2270
	update_alias_names_upon_change(array('openvpn', 'openvpn-server'), array('remote_network'), $new_alias_name, $orig_alias_name);
2271
	update_alias_names_upon_change(array('openvpn', 'openvpn-server'), array('remote_networkv6'), $new_alias_name, $orig_alias_name);
2272
	update_alias_names_upon_change(array('openvpn', 'openvpn-client'), array('tunnel_network'), $new_alias_name, $orig_alias_name);
2273
	update_alias_names_upon_change(array('openvpn', 'openvpn-client'), array('tunnel_networkv6'), $new_alias_name, $orig_alias_name);
2274
	update_alias_names_upon_change(array('openvpn', 'openvpn-client'), array('remote_network'), $new_alias_name, $orig_alias_name);
2275
	update_alias_names_upon_change(array('openvpn', 'openvpn-client'), array('remote_networkv6'), $new_alias_name, $orig_alias_name);
2276
	update_alias_names_upon_change(array('openvpn', 'openvpn-csc'), array('tunnel_network'), $new_alias_name, $orig_alias_name);
2277
	update_alias_names_upon_change(array('openvpn', 'openvpn-csc'), array('tunnel_networkv6'), $new_alias_name, $orig_alias_name);
2278
	update_alias_names_upon_change(array('openvpn', 'openvpn-csc'), array('local_network'), $new_alias_name, $orig_alias_name);
2279
	update_alias_names_upon_change(array('openvpn', 'openvpn-csc'), array('local_networkv6'), $new_alias_name, $orig_alias_name);
2280
	update_alias_names_upon_change(array('openvpn', 'openvpn-csc'), array('remote_network'), $new_alias_name, $orig_alias_name);
2281
	update_alias_names_upon_change(array('openvpn', 'openvpn-csc'), array('remote_networkv6'), $new_alias_name, $orig_alias_name);
2282
}
2283

    
2284
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2285
	global $g, $config, $pconfig, $debug;
2286
	if (!$origname) {
2287
		return;
2288
	}
2289

    
2290
	$sectionref = &$config;
2291
	foreach ($section as $sectionname) {
2292
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2293
			$sectionref = &$sectionref[$sectionname];
2294
		} else {
2295
			return;
2296
		}
2297
	}
2298

    
2299
	if ($debug) {
2300
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2301
		fwrite($fd, print_r($pconfig, true));
2302
	}
2303

    
2304
	if (is_array($sectionref)) {
2305
		foreach ($sectionref as $itemkey => $item) {
2306
			if ($debug) {
2307
				fwrite($fd, "$itemkey\n");
2308
			}
2309

    
2310
			$fieldfound = true;
2311
			$fieldref = &$sectionref[$itemkey];
2312
			foreach ($field as $fieldname) {
2313
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2314
					$fieldref = &$fieldref[$fieldname];
2315
				} else {
2316
					$fieldfound = false;
2317
					break;
2318
				}
2319
			}
2320
			if ($fieldfound && $fieldref == $origname) {
2321
				if ($debug) {
2322
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2323
				}
2324
				$fieldref = $new_alias_name;
2325
			}
2326
		}
2327
	}
2328

    
2329
	if ($debug) {
2330
		fclose($fd);
2331
	}
2332

    
2333
}
2334

    
2335
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2336
	/*
2337
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2338
	 * $type = if set to 'url' then subnets and ips will be returned,
2339
	 *         if set to 'url_ports' port-ranges and ports will be returned
2340
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2341
	 *
2342
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2343
	 */
2344

    
2345
	if (!file_exists($filename)) {
2346
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2347
		return null;
2348
	}
2349

    
2350
	if (filesize($filename) == 0) {
2351
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2352
		return null;
2353
	}
2354
	$fd = @fopen($filename, 'r');
2355
	if (!$fd) {
2356
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2357
		return null;
2358
	}
2359
	$items = array();
2360
	$comments = array();
2361
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2362
	while (($fc = fgetss($fd)) !== FALSE) {
2363
		$tmp = alias_idn_to_ascii(trim($fc, " \t\n\r"));
2364
		if (empty($tmp)) {
2365
			continue;
2366
		}
2367
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2368
			$comments[] = $tmp;
2369
		} else {
2370
			$tmp_str = strstr($tmp, '#', true);
2371
			if (!empty($tmp_str)) {
2372
				$tmp = $tmp_str;
2373
			}
2374
			$tmp_str = strstr($tmp, ' ', true);
2375
			if (!empty($tmp_str)) {
2376
				$tmp = $tmp_str;
2377
			}
2378
			switch ($type) {
2379
				case "url":
2380
				case "urltable":
2381
					if (is_ipaddr($tmp) || is_subnet($tmp)) {
2382
						$items[] = $tmp;
2383
						break;
2384
					}
2385
					if (is_fqdn($tmp)) {
2386
						$results = resolve_host_addresses($tmp, array(DNS_A, DNS_AAAA), false);
2387
						if (!empty($results)) {
2388
							foreach ($results as $ip) {
2389
								if (is_ipaddr($ip)) {
2390
									$items[] = $ip;
2391
								}
2392
							}
2393
						}
2394
					}
2395
					break;
2396
				case "url_ports":
2397
				case "urltable_ports":
2398
					if (is_port_or_range($tmp)) {
2399
						$items[] = $tmp;
2400
					}
2401
					break;
2402
				default:
2403
					/* unknown type */
2404
					break;
2405
				}
2406
			if (count($items) == $max_items) {
2407
				break;
2408
			}
2409
		}
2410
	}
2411
	fclose($fd);
2412
	return array_merge($comments, $items);
2413
}
2414

    
2415
function update_alias_url_data() {
2416
	global $config, $g, $aliastable;
2417

    
2418
	$updated = false;
2419

    
2420
	/* item is a url type */
2421
	$lockkey = lock('aliasurl');
2422
	if (is_array($config['aliases']['alias'])) {
2423
		$aliases = array();
2424
		$aliases_nested = array();
2425

    
2426
		foreach ($config['aliases']['alias'] as $x => $alias) {
2427
			if (empty($alias['aliasurl'])) {
2428
				continue;
2429
			}
2430
			foreach ($alias['aliasurl'] as $alias_url) {
2431
				if (is_alias($alias_url)) {
2432
					// process nested URL aliases after URL-only aliases
2433
					$aliases_nested[] = $x;
2434
					continue 2;
2435
				}
2436
			}
2437
			$aliases[] = $x;
2438
		}
2439

    
2440
		foreach (array_merge($aliases, $aliases_nested) as $x) {
2441

    
2442
			$address = array();
2443
			$type = $config['aliases']['alias'][$x]['type'];
2444
			foreach ($config['aliases']['alias'][$x]['aliasurl'] as $alias_url) {
2445
				/* fetch down and add in */
2446
				if (is_URL($alias_url)) {
2447
					$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2448
					rmdir_recursive($temp_filename);
2449
					$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2450
					mkdir($temp_filename);
2451
					if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2452
						log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2453
						rmdir_recursive($temp_filename);
2454
						continue;
2455
					}
2456

    
2457
					/* if the item is tar gzipped then extract */
2458
					if (stripos($alias_url, '.tgz') && !process_alias_tgz($temp_filename)) {
2459
						log_error(sprintf(gettext("Could not unpack tgz from the URL '%s'."), $alias_url));
2460
						rmdir_recursive($temp_filename);
2461
						continue;
2462
					}
2463
					if (file_exists("{$temp_filename}/aliases")) {
2464
						$t_address = parse_aliases_file("{$temp_filename}/aliases", $type, 5000);
2465
						if ($t_address == null) {
2466
							/* nothing was found */
2467
							log_error(sprintf(gettext("Could not fetch usable data from '%s'."), $alias_url));
2468
							//rmdir_recursive($temp_filename);
2469
							continue;
2470
						} else {
2471
							array_push($address, ...$t_address);
2472
						}
2473
						unset($t_address);
2474
					}
2475
					rmdir_recursive($temp_filename);
2476
				} elseif (is_alias($alias_url)) {
2477
					/* nested URL alias, see https://redmine.pfsense.org/issues/11863 */
2478
					if (!$aliastable) {
2479
						alias_make_table();
2480
					}
2481
					$t_address = explode(" ", $aliastable[$alias_url]);
2482
					if ($t_address == null) {
2483
						log_error(sprintf(gettext("Could not get usable data from '%s' URL alias."), $alias_url));
2484
						continue;
2485
					}
2486
					array_push($address, ...$t_address);
2487
				}
2488
				if (!empty($address)) {
2489
					$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2490
					$updated = true;
2491
				}
2492
			}
2493
		}
2494
	}
2495
	unlock($lockkey);
2496

    
2497
	/* Report status to callers as well */
2498
	return $updated;
2499
}
2500

    
2501
function process_alias_tgz($temp_filename) {
2502
	if (!file_exists('/usr/bin/tar')) {
2503
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2504
		return false;
2505
	}
2506
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2507
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2508
	unlink("{$temp_filename}/aliases.tgz");
2509
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2510
	/* foreach through all extracted files and build up aliases file */
2511
	$fd = @fopen("{$temp_filename}/aliases", "w");
2512
	if (!$fd) {
2513
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2514
		return false;
2515
	}
2516
	foreach ($files_to_process as $f2p) {
2517
		$tmpfd = @fopen($f2p, 'r');
2518
		if (!$tmpfd) {
2519
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2520
			continue;
2521
		}
2522
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2523
			fwrite($fd, $tmpbuf);
2524
		}
2525
		fclose($tmpfd);
2526
		unlink($f2p);
2527
	}
2528
	fclose($fd);
2529
	unset($tmpbuf);
2530

    
2531
	return true;
2532
}
2533

    
2534
function version_compare_dates($a, $b) {
2535
	$a_time = strtotime($a);
2536
	$b_time = strtotime($b);
2537

    
2538
	if ((!$a_time) || (!$b_time)) {
2539
		return FALSE;
2540
	} else {
2541
		if ($a_time < $b_time) {
2542
			return -1;
2543
		} elseif ($a_time == $b_time) {
2544
			return 0;
2545
		} else {
2546
			return 1;
2547
		}
2548
	}
2549
}
2550
function version_get_string_value($a) {
2551
	$strs = array(
2552
		0 => "ALPHA-ALPHA",
2553
		2 => "ALPHA",
2554
		3 => "BETA",
2555
		4 => "B",
2556
		5 => "C",
2557
		6 => "D",
2558
		7 => "RC",
2559
		8 => "RELEASE",
2560
		9 => "*"			// Matches all release levels
2561
	);
2562
	$major = 0;
2563
	$minor = 0;
2564
	foreach ($strs as $num => $str) {
2565
		if (substr($a, 0, strlen($str)) == $str) {
2566
			$major = $num;
2567
			$n = substr($a, strlen($str));
2568
			if (is_numeric($n)) {
2569
				$minor = $n;
2570
			}
2571
			break;
2572
		}
2573
	}
2574
	return "{$major}.{$minor}";
2575
}
2576
function version_compare_string($a, $b) {
2577
	// Only compare string parts if both versions give a specific release
2578
	// (If either version lacks a string part, assume intended to match all release levels)
2579
	if (isset($a) && isset($b)) {
2580
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2581
	} else {
2582
		return 0;
2583
	}
2584
}
2585
function version_compare_numeric($a, $b) {
2586
	$a_arr = explode('.', rtrim($a, '.'));
2587
	$b_arr = explode('.', rtrim($b, '.'));
2588

    
2589
	foreach ($a_arr as $n => $val) {
2590
		if (array_key_exists($n, $b_arr)) {
2591
			// So far so good, both have values at this minor version level. Compare.
2592
			if ($val > $b_arr[$n]) {
2593
				return 1;
2594
			} elseif ($val < $b_arr[$n]) {
2595
				return -1;
2596
			}
2597
		} else {
2598
			// a is greater, since b doesn't have any minor version here.
2599
			return 1;
2600
		}
2601
	}
2602
	if (count($b_arr) > count($a_arr)) {
2603
		// b is longer than a, so it must be greater.
2604
		return -1;
2605
	} else {
2606
		// Both a and b are of equal length and value.
2607
		return 0;
2608
	}
2609
}
2610
function pfs_version_compare($cur_time, $cur_text, $remote) {
2611
	// First try date compare
2612
	$v = version_compare_dates($cur_time, $remote);
2613
	if ($v === FALSE) {
2614
		// If that fails, try to compare by string
2615
		// Before anything else, simply test if the strings are equal
2616
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2617
			return 0;
2618
		}
2619
		list($cur_num, $cur_str) = explode('-', $cur_text);
2620
		list($rem_num, $rem_str) = explode('-', $remote);
2621

    
2622
		// First try to compare the numeric parts of the version string.
2623
		$v = version_compare_numeric($cur_num, $rem_num);
2624

    
2625
		// If the numeric parts are the same, compare the string parts.
2626
		if ($v == 0) {
2627
			return version_compare_string($cur_str, $rem_str);
2628
		}
2629
	}
2630
	return $v;
2631
}
2632
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2633
	global $g, $config;
2634

    
2635
	$urltable_prefix = "/var/db/aliastables/";
2636
	$urltable_filename = $urltable_prefix . $name . ".txt";
2637
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2638

    
2639
	// Make the aliases directory if it doesn't exist
2640
	if (!file_exists($urltable_prefix)) {
2641
		mkdir($urltable_prefix);
2642
	} elseif (!is_dir($urltable_prefix)) {
2643
		unlink($urltable_prefix);
2644
		mkdir($urltable_prefix);
2645
	}
2646

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

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

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

    
2661
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2662
			if ($type == "urltable_ports") {
2663
				$parsed_contents = group_ports($parsed_contents, true);
2664
			}
2665
			if (is_array($parsed_contents)) {
2666
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2667
			} else {
2668
				touch($urltable_filename);
2669
			}
2670

    
2671
			/* Remove existing archive and create an up to date archive if RAM disk is enabled. */
2672
			unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz");
2673
			if (isset($config['system']['use_mfs_tmpvar']) && !file_exists("/conf/ram_disks_failed")) {
2674
				mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename));
2675
			}
2676

    
2677
			unlink_if_exists($tmp_urltable_filename);
2678
		} else {
2679
			if (!$validateonly) {
2680
				touch($urltable_filename);
2681
			}
2682
			return false;
2683
		}
2684
		return true;
2685
	} else {
2686
		// File exists, and it doesn't need to be updated.
2687
		return -1;
2688
	}
2689
}
2690

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

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

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

    
2819
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2820
	$country_names_contents = file_get_contents($country_names_xml);
2821
	$country_names = xml2array($country_names_contents);
2822

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

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

    
2841
/* Return the list of country codes to be used on CAs and certs */
2842
function get_cert_country_codes() {
2843
	$countries = get_country_name();
2844

    
2845
	$country_codes = array();
2846
	foreach ($countries as $country) {
2847
		$country_codes[$country['code']] = $country['code'];
2848
	}
2849
	ksort($country_codes);
2850

    
2851
	/* Preserve historical order: None, US, CA, other countries */
2852
	$first_items[''] = gettext("None");
2853
	$first_items['US'] = $country_codes['US'];
2854
	$first_items['CA'] = $country_codes['CA'];
2855
	unset($country_codes['US']);
2856
	unset($country_codes['CA']);
2857

    
2858
	return array_merge($first_items, $country_codes);
2859
}
2860

    
2861
/* sort by interface only, retain the original order of rules that apply to
2862
   the same interface */
2863
function filter_rules_sort() {
2864
	global $config;
2865

    
2866
	init_config_arr(array('filter', 'rule'));
2867
	/* mark each rule with the sequence number (to retain the order while sorting) */
2868
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2869
		if (!is_array($config['filter']['rule'][$i])) {
2870
			$config['filter']['rule'][$i] = array();
2871
		}
2872
		$config['filter']['rule'][$i]['seq'] = $i;
2873
	}
2874

    
2875
	usort($config['filter']['rule'], "filter_rules_compare");
2876

    
2877
	/* strip the sequence numbers again */
2878
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2879
		unset($config['filter']['rule'][$i]['seq']);
2880
	}
2881
}
2882
function filter_rules_compare($a, $b) {
2883
	if (isset($a['floating']) && isset($b['floating'])) {
2884
		return $a['seq'] - $b['seq'];
2885
	} else if (isset($a['floating'])) {
2886
		return -1;
2887
	} else if (isset($b['floating'])) {
2888
		return 1;
2889
	} else if ($a['interface'] == $b['interface']) {
2890
		return $a['seq'] - $b['seq'];
2891
	} else {
2892
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2893
	}
2894
}
2895

    
2896
function generate_ipv6_from_mac($mac) {
2897
	$elements = explode(":", $mac);
2898
	if (count($elements) <> 6) {
2899
		return false;
2900
	}
2901

    
2902
	$i = 0;
2903
	$ipv6 = "fe80::";
2904
	foreach ($elements as $byte) {
2905
		if ($i == 0) {
2906
			$hexadecimal = substr($byte, 1, 2);
2907
			$bitmap = base_convert($hexadecimal, 16, 2);
2908
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2909
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2910
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2911
		}
2912
		$ipv6 .= $byte;
2913
		if ($i == 1) {
2914
			$ipv6 .= ":";
2915
		}
2916
		if ($i == 3) {
2917
			$ipv6 .= ":";
2918
		}
2919
		if ($i == 2) {
2920
			$ipv6 .= "ff:fe";
2921
		}
2922

    
2923
		$i++;
2924
	}
2925
	return $ipv6;
2926
}
2927

    
2928
/****f* pfsense-utils/load_mac_manufacturer_table
2929
 * NAME
2930
 *   load_mac_manufacturer_table
2931
 * INPUTS
2932
 *   none
2933
 * RESULT
2934
 *   returns associative array with MAC-Manufacturer pairs
2935
 ******/
2936
function load_mac_manufacturer_table() {
2937
	/* load MAC-Manufacture data from the file */
2938
	$macs = false;
2939
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2940
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2941
	}
2942
	if ($macs) {
2943
		foreach ($macs as $line) {
2944
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2945
				/* store values like this $mac_man['000C29']='VMware' */
2946
				$mac_man["$matches[1]"] = $matches[2];
2947
			}
2948
		}
2949
		return $mac_man;
2950
	} else {
2951
		return -1;
2952
	}
2953

    
2954
}
2955

    
2956
/****f* pfsense-utils/is_ipaddr_configured
2957
 * NAME
2958
 *   is_ipaddr_configured
2959
 * INPUTS
2960
 *   IP Address to check.
2961
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2962
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2963
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2964
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2965
 *     If check_subnets is true and cidrprefix is specified,
2966
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2967
 * RESULT
2968
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2969
*/
2970
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2971
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2972
		return true;
2973
	}
2974
	return false;
2975
}
2976

    
2977
/****f* pfsense-utils/where_is_ipaddr_configured
2978
 * NAME
2979
 *   where_is_ipaddr_configured
2980
 * INPUTS
2981
 *   IP Address to check.
2982
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2983
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2984
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2985
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2986
 *     If check_subnets is true and cidrprefix is specified,
2987
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2988
 * RESULT
2989
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2990
 *   If there are no matches then an empty array is returned.
2991
*/
2992
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2993
	global $config;
2994

    
2995
	$where_configured = array();
2996

    
2997
	$pos = strpos($ignore_if, '_virtualip');
2998
	if ($pos !== false) {
2999
		$ignore_vip_id = substr($ignore_if, $pos+10);
3000
		$ignore_vip_if = substr($ignore_if, 0, $pos);
3001
	} else {
3002
		$ignore_vip_id = -1;
3003
		$ignore_vip_if = $ignore_if;
3004
	}
3005

    
3006
	$isipv6 = is_ipaddrv6($ipaddr);
3007

    
3008
	if ($isipv6) {
3009
		$ipaddr = text_to_compressed_ip6($ipaddr);
3010
	}
3011

    
3012
	if ($check_subnets) {
3013
		$cidrprefix = intval($cidrprefix);
3014
		if ($isipv6) {
3015
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
3016
				$cidrprefix = 128;
3017
			}
3018
		} else {
3019
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
3020
				$cidrprefix = 32;
3021
			}
3022
		}
3023
		$iflist = get_configured_interface_list();
3024
		foreach ($iflist as $if => $ifname) {
3025
			if ($ignore_if == $if) {
3026
				continue;
3027
			}
3028

    
3029
			if ($isipv6) {
3030
				$if_ipv6 = get_interface_ipv6($if);
3031
				$if_snbitsv6 = get_interface_subnetv6($if);
3032
				/* do not check subnet overlapping on 6rd interfaces,
3033
				 * see https://redmine.pfsense.org/issues/12371 */ 
3034
				if ($if_ipv6 && $if_snbitsv6 &&
3035
				    (($config['interfaces'][$if]['ipaddrv6'] != '6rd') || ($cidrprefix > $if_snbitsv6)) &&
3036
				    check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
3037
					$where_entry = array();
3038
					$where_entry['if'] = $if;
3039
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
3040
					$where_configured[] = $where_entry;
3041
				}
3042
			} else {
3043
				$if_ipv4 = get_interface_ip($if);
3044
				$if_snbitsv4 = get_interface_subnet($if);
3045
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
3046
					$where_entry = array();
3047
					$where_entry['if'] = $if;
3048
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
3049
					$where_configured[] = $where_entry;
3050
				}
3051
			}
3052
		}
3053
	} else {
3054
		if ($isipv6) {
3055
			$interface_list_ips = get_configured_ipv6_addresses();
3056
		} else {
3057
			$interface_list_ips = get_configured_ip_addresses();
3058
		}
3059

    
3060
		foreach ($interface_list_ips as $if => $ilips) {
3061
			if ($ignore_if == $if) {
3062
				continue;
3063
			}
3064
			if (strcasecmp($ipaddr, $ilips) == 0) {
3065
				$where_entry = array();
3066
				$where_entry['if'] = $if;
3067
				$where_entry['ip_or_subnet'] = $ilips;
3068
				$where_configured[] = $where_entry;
3069
			}
3070
		}
3071
	}
3072

    
3073
	if ($check_localip) {
3074
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
3075
			$where_entry = array();
3076
			$where_entry['if'] = 'l2tp';
3077
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3078
			$where_configured[] = $where_entry;
3079
		}
3080
	}
3081

    
3082
	return $where_configured;
3083
}
3084

    
3085
/****f* pfsense-utils/pfSense_handle_custom_code
3086
 * NAME
3087
 *   pfSense_handle_custom_code
3088
 * INPUTS
3089
 *   directory name to process
3090
 * RESULT
3091
 *   globs the directory and includes the files
3092
 */
3093
function pfSense_handle_custom_code($src_dir) {
3094
	// Allow extending of the nat edit page and include custom input validation
3095
	if (is_dir("$src_dir")) {
3096
		$cf = glob($src_dir . "/*.inc");
3097
		foreach ($cf as $nf) {
3098
			if ($nf == "." || $nf == "..") {
3099
				continue;
3100
			}
3101
			// Include the extra handler
3102
			include_once("$nf");
3103
		}
3104
	}
3105
}
3106

    
3107
function set_language() {
3108
	global $config, $g;
3109

    
3110
	if (!empty($config['system']['language'])) {
3111
		$lang = $config['system']['language'];
3112
	} elseif (!empty($g['language'])) {
3113
		$lang = $g['language'];
3114
	}
3115
	$lang .= ".UTF-8";
3116

    
3117
	putenv("LANG={$lang}");
3118
	setlocale(LC_ALL, $lang);
3119
	textdomain("pfSense");
3120
	bindtextdomain("pfSense", "/usr/local/share/locale");
3121
	bind_textdomain_codeset("pfSense", $lang);
3122
}
3123

    
3124
function get_locale_list() {
3125
	$locales = array(
3126
		"bs" => gettext("Bosnian"),
3127
		"zh_CN" => gettext("Chinese"),
3128
		"zh_Hans_CN" => gettext("Chinese (Simplified, China)"),
3129
		"zh_Hans_HK" => gettext("Chinese (Simplified, Hong Kong SAR China)"),
3130
		"zh_Hant_TW" => gettext("Chinese (Traditional, Taiwan)"),
3131
		"nl" => gettext("Dutch"),
3132
		"en_US" => gettext("English"),
3133
		"fr" => gettext("French"),
3134
		"de_DE" => gettext("German (Germany)"),
3135
		"it" => gettext("Italian"),
3136
		"ko" => gettext("Korean"),
3137
		"nb" => gettext("Norwegian Bokmål"),
3138
		"pl" => gettext("Polish"),
3139
		"pt_PT" => gettext("Portuguese"),
3140
		"pt_BR" => gettext("Portuguese (Brazil)"),
3141
		"ru" => gettext("Russian"),
3142
		"es" => gettext("Spanish"),
3143
		"es_AR" => gettext("Spanish (Argentina)"),
3144
	);
3145

    
3146
	// If the locales are sorted, the order changes depending on the language selected. If the user accidentally
3147
	// selects the wrong language, this makes it very difficult to guess the intended language. NOT sorting
3148
	// allows the user to remember that English (say) is the seventh on the list and to get back to it more easily
3149

    
3150
	//asort($locales);
3151

    
3152
	return $locales;
3153
}
3154

    
3155
function return_hex_ipv4($ipv4) {
3156
	if (!is_ipaddrv4($ipv4)) {
3157
		return(false);
3158
	}
3159

    
3160
	/* we need the hex form of the interface IPv4 address */
3161
	$ip4arr = explode(".", $ipv4);
3162
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3163
}
3164

    
3165
function convert_ipv6_to_128bit($ipv6) {
3166
	if (!is_ipaddrv6($ipv6)) {
3167
		return(false);
3168
	}
3169

    
3170
	$ip6arr = array();
3171
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3172
	$ip6arr = explode(":", $ip6prefix);
3173
	/* binary presentation of the prefix for all 128 bits. */
3174
	$ip6prefixbin = "";
3175
	foreach ($ip6arr as $element) {
3176
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3177
	}
3178
	return($ip6prefixbin);
3179
}
3180

    
3181
function convert_128bit_to_ipv6($ip6bin) {
3182
	if (strlen($ip6bin) <> 128) {
3183
		return(false);
3184
	}
3185

    
3186
	$ip6arr = array();
3187
	$ip6binarr = array();
3188
	$ip6binarr = str_split($ip6bin, 16);
3189
	foreach ($ip6binarr as $binpart) {
3190
		$ip6arr[] = dechex(bindec($binpart));
3191
	}
3192
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3193

    
3194
	return($ip6addr);
3195
}
3196

    
3197

    
3198
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3199
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3200
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3201
/* 6to4 is 16 bits, e.g. 65535 */
3202
function calculate_ipv6_delegation_length($if) {
3203
	global $config;
3204

    
3205
	if (!is_array($config['interfaces'][$if])) {
3206
		return false;
3207
	}
3208

    
3209
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3210
		case "6to4":
3211
			$pdlen = 16;
3212
			break;
3213
		case "6rd":
3214
			$rd6cfg = $config['interfaces'][$if];
3215
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3216
			$pdlen = (64 - ((int) $rd6plen[1] + (32 - (int) $rd6cfg['prefix-6rd-v4plen'])));
3217
			break;
3218
		case "dhcp6":
3219
			$dhcp6cfg = $config['interfaces'][$if];
3220
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3221
			break;
3222
		default:
3223
			$pdlen = 0;
3224
			break;
3225
	}
3226
	return($pdlen);
3227
}
3228

    
3229
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3230
	/* convert zero-value prefix IPv6 addresses with IPv4 mapping to hex
3231
	 * see https://redmine.pfsense.org/issues/12440 */
3232
	$suffix_list = explode(':', $suffix);
3233
	if (is_ipaddrv4($suffix_list[count($suffix_list) - 1])) {
3234
		$hexsuffix = dechex(ip2long($suffix_list[count($suffix_list) - 1]));
3235
		$suffix_list[count($suffix_list) - 1] = substr($hexsuffix, 0, 4);
3236
		$suffix_list[] = substr($hexsuffix, 4, 8);
3237
		$suffix = implode(':', $suffix_list);
3238
	}	
3239
	$prefix = Net_IPv6::uncompress($prefix, true);
3240
	$suffix = Net_IPv6::uncompress($suffix, true);
3241

    
3242
	/*
3243
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3244
	 *                ^^^^ ^
3245
	 *                |||| \-> 64
3246
	 *                |||\---> 63, 62, 61, 60
3247
	 *                ||\----> 56
3248
	 *                |\-----> 52
3249
	 *                \------> 48
3250
	 */
3251

    
3252
	switch ($len) {
3253
	case 48:
3254
		$prefix_len = 15;
3255
		break;
3256
	case 52:
3257
		$prefix_len = 16;
3258
		break;
3259
	case 56:
3260
		$prefix_len = 17;
3261
		break;
3262
	case 59:
3263
	case 60:
3264
		$prefix_len = 18;
3265
		break;
3266
	/*
3267
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3268
	 * we let user chose this bit it can end up out of PD network
3269
	 *
3270
	 * Leave this with 20 for now until we find a way to let user
3271
	 * chose it. The side-effect is users with PD with one of these
3272
	 * lengths will not be able to setup DHCP server range for full
3273
	 * PD size, only for last /64 network
3274
	 */
3275
	case 63:
3276
	case 62:
3277
	case 61:
3278
	default:
3279
		$prefix_len = 20;
3280
		break;
3281
	}
3282

    
3283
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3284
	    substr($suffix, $prefix_len));
3285
}
3286

    
3287
function dhcpv6_pd_str_help($pdlen) {
3288
	$result = '';
3289

    
3290
	switch ($pdlen) {
3291
	case 48:
3292
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3293
		break;
3294
	case 52:
3295
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3296
		break;
3297
	case 56:
3298
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3299
		break;
3300
	case 59:
3301
	case 60:
3302
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3303
		break;
3304
	/*
3305
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3306
	 * we let the user choose this bit it can end up out of PD network
3307
	 *
3308
	 * Leave this with the same as 64 for now until we find a way to
3309
	 * let the user choose it. The side-effect is users with PD with one
3310
	 * of these lengths will not be able to setup DHCP server ranges
3311
	 * for full PD size, only for last /64 network
3312
	 */
3313
	case 61:
3314
	case 62:
3315
	case 63:
3316
	case 64:
3317
	default:
3318
		$result = '::xxxx:xxxx:xxxx:xxxx';
3319
		break;
3320
	}
3321

    
3322
	return $result;
3323
}
3324

    
3325
function huawei_rssi_to_string($rssi) {
3326
	$dbm = array();
3327
	$i = 0;
3328
	$dbstart = -113;
3329
	while ($i < 32) {
3330
		$dbm[$i] = $dbstart + ($i * 2);
3331
		$i++;
3332
	}
3333
	$percent = round(($rssi / 31) * 100);
3334
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3335
	return $string;
3336
}
3337

    
3338
function huawei_mode_to_string($mode, $submode) {
3339
	$modes[0] = gettext("None");
3340
	$modes[1] = "AMPS";
3341
	$modes[2] = "CDMA";
3342
	$modes[3] = "GSM/GPRS";
3343
	$modes[4] = "HDR";
3344
	$modes[5] = "WCDMA";
3345
	$modes[6] = "GPS";
3346

    
3347
	$submodes[0] = gettext("No Service");
3348
	$submodes[1] = "GSM";
3349
	$submodes[2] = "GPRS";
3350
	$submodes[3] = "EDGE";
3351
	$submodes[4] = "WCDMA";
3352
	$submodes[5] = "HSDPA";
3353
	$submodes[6] = "HSUPA";
3354
	$submodes[7] = "HSDPA+HSUPA";
3355
	$submodes[8] = "TD-SCDMA";
3356
	$submodes[9] = "HSPA+";
3357
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3358
	return $string;
3359
}
3360

    
3361
function huawei_service_to_string($state) {
3362
	$modes[0] = gettext("No Service");
3363
	$modes[1] = gettext("Restricted Service");
3364
	$modes[2] = gettext("Valid Service");
3365
	$modes[3] = gettext("Restricted Regional Service");
3366
	$modes[4] = gettext("Powersaving Service");
3367
	$modes[255] = gettext("Unknown Service");
3368
	$string = $modes[$state];
3369
	return $string;
3370
}
3371

    
3372
function huawei_simstate_to_string($state) {
3373
	$modes[0] = gettext("Invalid SIM/locked State");
3374
	$modes[1] = gettext("Valid SIM State");
3375
	$modes[2] = gettext("Invalid SIM CS State");
3376
	$modes[3] = gettext("Invalid SIM PS State");
3377
	$modes[4] = gettext("Invalid SIM CS/PS State");
3378
	$modes[255] = gettext("Missing SIM State");
3379
	$string = $modes[$state];
3380
	return $string;
3381
}
3382

    
3383
function zte_rssi_to_string($rssi) {
3384
	return huawei_rssi_to_string($rssi);
3385
}
3386

    
3387
function zte_mode_to_string($mode, $submode) {
3388
	$modes[0] = gettext("No Service");
3389
	$modes[1] = gettext("Limited Service");
3390
	$modes[2] = "GPRS";
3391
	$modes[3] = "GSM";
3392
	$modes[4] = "UMTS";
3393
	$modes[5] = "EDGE";
3394
	$modes[6] = "HSDPA";
3395

    
3396
	$submodes[0] = "CS_ONLY";
3397
	$submodes[1] = "PS_ONLY";
3398
	$submodes[2] = "CS_PS";
3399
	$submodes[3] = "CAMPED";
3400
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3401
	return $string;
3402
}
3403

    
3404
function zte_service_to_string($service) {
3405
	$modes[0] = gettext("Initializing Service");
3406
	$modes[1] = gettext("Network Lock error Service");
3407
	$modes[2] = gettext("Network Locked Service");
3408
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3409
	$string = $modes[$service];
3410
	return $string;
3411
}
3412

    
3413
function zte_simstate_to_string($state) {
3414
	$modes[0] = gettext("No action State");
3415
	$modes[1] = gettext("Network lock State");
3416
	$modes[2] = gettext("(U)SIM card lock State");
3417
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3418
	$string = $modes[$state];
3419
	return $string;
3420
}
3421

    
3422
function get_configured_pppoe_server_interfaces() {
3423
	global $config;
3424
	$iflist = array();
3425
	if (is_array($config['pppoes']['pppoe'])) {
3426
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3427
			if ($pppoe['mode'] == "server") {
3428
				$int = "poes". $pppoe['pppoeid'];
3429
				$iflist[$int] = strtoupper($int);
3430
			}
3431
		}
3432
	}
3433
	return $iflist;
3434
}
3435

    
3436
function get_pppoes_child_interfaces($ifpattern) {
3437
	$if_arr = array();
3438
	if ($ifpattern == "") {
3439
		return;
3440
	}
3441

    
3442
	exec("/sbin/ifconfig", $out, $ret);
3443
	foreach ($out as $line) {
3444
		if (preg_match("/^({$ifpattern}-[0-9]+):/i", $line, $match)) {
3445
			$if_arr[] = $match[1];
3446
		}
3447
	}
3448
	return $if_arr;
3449

    
3450
}
3451

    
3452
/****f* pfsense-utils/pkg_call_plugins
3453
 * NAME
3454
 *   pkg_call_plugins
3455
 * INPUTS
3456
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3457
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3458
 * RESULT
3459
 *   returns associative array results from the plugin calls for each package
3460
 * NOTES
3461
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3462
 ******/
3463
function pkg_call_plugins($plugin_type, $plugin_params) {
3464
	global $g, $config;
3465
	$results = array();
3466
	if (!is_array($config['installedpackages']['package'])) {
3467
		return $results;
3468
	}
3469
	foreach ($config['installedpackages']['package'] as $package) {
3470
		if (is_array($package['plugins']['item'])) {
3471
			foreach ($package['plugins']['item'] as $plugin) {
3472
				if ($plugin['type'] == $plugin_type) {
3473
					if (file_exists($package['include_file'])) {
3474
						require_once($package['include_file']);
3475
					} else {
3476
						continue;
3477
					}
3478
					$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3479
					$plugin_function = $pkgname . '_'. $plugin_type;
3480
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3481
				}
3482
			}
3483
		}
3484
	}
3485
	return $results;
3486
}
3487

    
3488
// Convert IPv6 addresses to lower case
3489
function addrtolower($ip) {
3490
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3491
		return(strtolower($ip));
3492
	} else {
3493
		return($ip);
3494
	}
3495
}
3496

    
3497
function compare_by_name($a, $b) {
3498
	return strcasecmp($a['name'], $b['name']);
3499
}
3500

    
3501
/****f* pfsense-utils/getarraybyref
3502
 * NAME
3503
 *   getarraybyref
3504
 * INPUTS
3505
 *   $array the array of which a items array needs to be found.
3506
 *   $args.. the sub-items to be retrieved/created
3507
 * RESULT
3508
 *   returns the array that was retrieved from configuration, its created if it does not exist
3509
 * NOTES
3510
 *   Used by haproxy / acme / others.?. .
3511
 *   can be used like this:  $a_certificates = getarraybyref($config, 'installedpackages', 'acme', 'certificates', 'item');
3512
 ******/
3513
function &getarraybyref(&$array) {
3514
	if (!isset($array)) {
3515
		return false;
3516
	}
3517
	if (!is_array($array)) {
3518
		$array = array();
3519
	}
3520
	$item = &$array;
3521
	$arg = func_get_args();
3522
	for($i = 1; $i < count($arg); $i++) {
3523
		$itemindex = $arg[$i];
3524
		if (!is_array($item[$itemindex])) {
3525
			$item[$itemindex] = array();
3526
		}
3527
		$item = &$item[$itemindex];
3528
	}
3529
	return $item;
3530
}
3531

    
3532
/****f* pfsense-utils/send_download_data
3533
 * NAME
3534
 *   send_download_data - Send content to a user's browser as a file to download
3535
 * INPUTS
3536
 *   $type        : The type of download, either 'data' to send the contents of
3537
 *                    a variable or 'file' to send the contents of a file on the
3538
 *                    filesystem.
3539
 *   $content     : For 'data' type, the content to send the user. For 'file'
3540
 *                    type, the full path to the file to send.
3541
 *   $userfilename: The filename presented to the user when downloading. For
3542
 *                    'file' type, this may be omitted and the basename of
3543
 *                    $content will be used instead.
3544
 *   $contenttype : MIME content type of the data. Default "application/octet-stream"
3545
 * RESULT
3546
 *   Sends the data to the browser as a file to download.
3547
 ******/
3548

    
3549
function send_user_download($type = 'data', $content, $userfilename = "", $contenttype = "application/octet-stream") {
3550
	/* If the type is 'file', then use the file size, otherwise use the size of the data to send */
3551
	$size = ($type == 'file') ? filesize($content) : strlen($content);
3552

    
3553
	/* If the filename to pass to the user is empty, assume it to be the filename being read. */
3554
	$name = basename((($type == 'file') && empty($userfilename)) ? $content : $userfilename);
3555

    
3556
	/* Cannot determine the filename, so bail. */
3557
	if (empty($name)) {
3558
		exit;
3559
	}
3560

    
3561
	/* Send basic download headers */
3562
	header("Content-Type: {$contenttype}");
3563
	header("Content-Length: {$size}");
3564
	header("Content-Disposition: attachment; filename=" . urlencode($name));
3565

    
3566
	/* Send cache headers */
3567
	if (isset($_SERVER['HTTPS'])) {
3568
		header('Pragma: ');
3569
		header('Cache-Control: ');
3570
	} else {
3571
		header("Pragma: private");
3572
		header("Cache-Control: private, must-revalidate");
3573
	}
3574

    
3575
	/* Ensure output buffering is off so PHP does not consume
3576
	 * memory in readfile(). https://redmine.pfsense.org/issues/9239 */
3577
	while (ob_get_level()) {
3578
		@ob_end_clean();
3579
	}
3580

    
3581
	/* Send the data to the user */
3582
	if ($type == 'file') {
3583
		readfile($content);
3584
	} else {
3585
		echo $content;
3586
	}
3587

    
3588
	/* Flush any remaining output buffer */
3589
	@ob_end_flush();
3590
	exit;
3591
}
3592

    
3593
// Test whether the hostname in a URL can be resolved with a very short timeout
3594
function is_url_hostname_resolvable($url) {
3595
	$urlhostname = parse_url($url, PHP_URL_HOST);
3596
	if (empty($urlhostname)) {
3597
		return false;
3598
	}
3599
	putenv("RES_OPTIONS=timeout:3 attempts:1");
3600
	$resolvable = ($urlhostname !== gethostbyname($urlhostname));
3601
	putenv("RES_OPTIONS");
3602
	return $resolvable;
3603
}
3604

    
3605
function get_pf_timeouts () {
3606
	$pftimeout = array();
3607
	exec("/sbin/pfctl -st", $pfctlst, $retval);
3608
	if ($retval == 0) {
3609
		foreach ($pfctlst as $pfst) {
3610
			preg_match('/([a-z]+)\.([a-z]+)\s+([0-9]+)/', $pfst, $timeout);
3611
			if ($timeout[1] == "other") {
3612
				$proto = "Other";
3613
			} else {
3614
				$proto = strtoupper($timeout[1]);
3615
			}
3616
			if ($timeout[2] == "finwait") {
3617
				$type = "FIN Wait";
3618
			} else {
3619
				$type = ucfirst($timeout[2]);
3620
			}
3621
			$pftimeout[$proto][$type]['name'] = $proto . " " . $type;
3622
			$pftimeout[$proto][$type]['keyname'] = $timeout[1] . $timeout[2] . "timeout";
3623
			$pftimeout[$proto][$type]['value'] = $timeout[3];
3624
		}
3625
	}
3626
	return $pftimeout;
3627
}
3628

    
3629
function set_curlproxy(&$ch) {
3630
	global $config;
3631

    
3632
	if (!empty($config['system']['proxyurl'])) {
3633
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
3634
		if (!empty($config['system']['proxyport'])) {
3635
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
3636
		}
3637
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
3638
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
3639
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
3640
		}
3641
	}
3642
}
3643

    
3644
?>
(38-38/61)